nrf/gpiote: new api: switch to owned structs, implement WaitForHigh/WaitForLow.
This commit is contained in:
parent
1879703153
commit
a7797a918d
3 changed files with 324 additions and 329 deletions
|
@ -12,7 +12,7 @@ use nrf52840_hal::gpio;
|
|||
|
||||
use embassy::executor::{task, Executor};
|
||||
use embassy::util::Forever;
|
||||
use embassy_nrf::gpiote;
|
||||
use embassy_nrf::gpiote::{Channels, Gpiote, InputChannel, InputChannelPolarity};
|
||||
use embassy_nrf::interrupt;
|
||||
|
||||
#[task]
|
||||
|
@ -20,46 +20,44 @@ async fn run() {
|
|||
let p = unwrap!(embassy_nrf::pac::Peripherals::take());
|
||||
let port0 = gpio::p0::Parts::new(p.P0);
|
||||
|
||||
let g = gpiote::Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE));
|
||||
let (g, chs) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE));
|
||||
|
||||
info!("Starting!");
|
||||
|
||||
let pin1 = port0.p0_11.into_pullup_input().degrade();
|
||||
let button1 = async {
|
||||
let ch = unwrap!(g.new_input_channel(pin1, gpiote::InputChannelPolarity::HiToLo));
|
||||
let pin2 = port0.p0_12.into_pullup_input().degrade();
|
||||
let pin3 = port0.p0_24.into_pullup_input().degrade();
|
||||
let pin4 = port0.p0_25.into_pullup_input().degrade();
|
||||
|
||||
let ch1 = InputChannel::new(g, chs.ch0, pin1, InputChannelPolarity::HiToLo);
|
||||
let ch2 = InputChannel::new(g, chs.ch1, pin2, InputChannelPolarity::LoToHi);
|
||||
let ch3 = InputChannel::new(g, chs.ch2, pin3, InputChannelPolarity::Toggle);
|
||||
let ch4 = InputChannel::new(g, chs.ch3, pin4, InputChannelPolarity::Toggle);
|
||||
|
||||
let button1 = async {
|
||||
loop {
|
||||
ch.wait().await;
|
||||
ch1.wait().await;
|
||||
info!("Button 1 pressed")
|
||||
}
|
||||
};
|
||||
|
||||
let pin2 = port0.p0_12.into_pullup_input().degrade();
|
||||
let button2 = async {
|
||||
let ch = unwrap!(g.new_input_channel(pin2, gpiote::InputChannelPolarity::LoToHi));
|
||||
|
||||
loop {
|
||||
ch.wait().await;
|
||||
ch2.wait().await;
|
||||
info!("Button 2 released")
|
||||
}
|
||||
};
|
||||
|
||||
let pin3 = port0.p0_24.into_pullup_input().degrade();
|
||||
let button3 = async {
|
||||
let ch = unwrap!(g.new_input_channel(pin3, gpiote::InputChannelPolarity::Toggle));
|
||||
|
||||
loop {
|
||||
ch.wait().await;
|
||||
ch3.wait().await;
|
||||
info!("Button 3 toggled")
|
||||
}
|
||||
};
|
||||
|
||||
let pin4 = port0.p0_25.into_pullup_input().degrade();
|
||||
let button4 = async {
|
||||
let ch = unwrap!(g.new_input_channel(pin4, gpiote::InputChannelPolarity::Toggle));
|
||||
|
||||
loop {
|
||||
ch.wait().await;
|
||||
ch4.wait().await;
|
||||
info!("Button 4 toggled")
|
||||
}
|
||||
};
|
|
@ -7,20 +7,22 @@ mod example_common;
|
|||
use example_common::*;
|
||||
|
||||
use core::mem;
|
||||
use core::pin::Pin;
|
||||
use cortex_m_rt::entry;
|
||||
use defmt::panic;
|
||||
use nrf52840_hal::gpio;
|
||||
|
||||
use embassy::executor::{task, Executor};
|
||||
use embassy::gpio::{WaitForHigh, WaitForLow};
|
||||
use embassy::util::Forever;
|
||||
use embassy_nrf::gpiote::{Gpiote, PortInputPolarity};
|
||||
use embassy_nrf::gpiote::{Gpiote, GpiotePin};
|
||||
use embassy_nrf::interrupt;
|
||||
|
||||
async fn button(g: &Gpiote, n: usize, pin: gpio::Pin<gpio::Input<gpio::PullUp>>) {
|
||||
async fn button(n: usize, mut pin: GpiotePin<gpio::PullUp>) {
|
||||
loop {
|
||||
g.wait_port_input(&pin, PortInputPolarity::Low).await;
|
||||
Pin::new(&mut pin).wait_for_low().await;
|
||||
info!("Button {:?} pressed!", n);
|
||||
g.wait_port_input(&pin, PortInputPolarity::High).await;
|
||||
Pin::new(&mut pin).wait_for_high().await;
|
||||
info!("Button {:?} released!", n);
|
||||
}
|
||||
}
|
||||
|
@ -30,19 +32,24 @@ async fn run() {
|
|||
let p = unwrap!(embassy_nrf::pac::Peripherals::take());
|
||||
let port0 = gpio::p0::Parts::new(p.P0);
|
||||
|
||||
let g = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE));
|
||||
info!(
|
||||
"sizeof Signal<()> = {:usize}",
|
||||
mem::size_of::<embassy::util::Signal<()>>()
|
||||
let (g, _) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE));
|
||||
|
||||
let button1 = button(
|
||||
1,
|
||||
GpiotePin::new(g, port0.p0_11.into_pullup_input().degrade()),
|
||||
);
|
||||
let button2 = button(
|
||||
2,
|
||||
GpiotePin::new(g, port0.p0_12.into_pullup_input().degrade()),
|
||||
);
|
||||
let button3 = button(
|
||||
3,
|
||||
GpiotePin::new(g, port0.p0_24.into_pullup_input().degrade()),
|
||||
);
|
||||
let button4 = button(
|
||||
4,
|
||||
GpiotePin::new(g, port0.p0_25.into_pullup_input().degrade()),
|
||||
);
|
||||
info!("sizeof gpiote = {:usize}", mem::size_of::<Gpiote>());
|
||||
|
||||
info!("Starting!");
|
||||
|
||||
let button1 = button(&g, 1, port0.p0_11.into_pullup_input().degrade());
|
||||
let button2 = button(&g, 2, port0.p0_12.into_pullup_input().degrade());
|
||||
let button3 = button(&g, 3, port0.p0_24.into_pullup_input().degrade());
|
||||
let button4 = button(&g, 4, port0.p0_25.into_pullup_input().degrade());
|
||||
futures::join!(button1, button2, button3, button4);
|
||||
}
|
||||
|
||||
|
|
|
@ -1,18 +1,20 @@
|
|||
use crate::fmt::{panic, *};
|
||||
use core::cell::Cell;
|
||||
use core::future::Future;
|
||||
use core::mem::ManuallyDrop;
|
||||
use core::ops::Deref;
|
||||
use core::pin::Pin;
|
||||
use core::ptr;
|
||||
use core::task::{Context, Poll};
|
||||
use embassy::gpio::{WaitForHigh, WaitForLow};
|
||||
use embassy::util::Signal;
|
||||
|
||||
use crate::hal::gpio::{Input, Level, Output, Pin, Port};
|
||||
use crate::fmt::{panic, *};
|
||||
use crate::hal::gpio::{Input, Level, Output, Pin as GpioPin, Port};
|
||||
use crate::interrupt;
|
||||
use crate::interrupt::OwnedInterrupt;
|
||||
use crate::pac;
|
||||
use crate::pac::generic::Reg;
|
||||
use crate::pac::gpiote::_TASKS_OUT;
|
||||
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||
use crate::pac::P1;
|
||||
use crate::pac::{p0 as gpio, GPIOTE, P0};
|
||||
use crate::pac::{p0 as pac_gpio, GPIOTE};
|
||||
|
||||
#[cfg(not(feature = "51"))]
|
||||
use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET};
|
||||
|
@ -24,20 +26,51 @@ pub const PIN_COUNT: usize = 48;
|
|||
#[cfg(not(any(feature = "52833", feature = "52840")))]
|
||||
pub const PIN_COUNT: usize = 32;
|
||||
|
||||
pub struct Gpiote {
|
||||
inner: GPIOTE,
|
||||
free_channels: Cell<u8>, // 0 = used, 1 = free. 8 bits for 8 channelself.
|
||||
channel_signals: [Signal<()>; CHANNEL_COUNT],
|
||||
port_signals: [Signal<()>; PIN_COUNT],
|
||||
pub trait ChannelID {
|
||||
fn number(&self) -> usize;
|
||||
}
|
||||
|
||||
static mut INSTANCE: *const Gpiote = ptr::null_mut();
|
||||
macro_rules! impl_channel {
|
||||
($ChX:ident, $n:expr) => {
|
||||
pub struct $ChX(());
|
||||
impl $ChX {
|
||||
pub fn degrade(self) -> ChAny {
|
||||
ChAny($n)
|
||||
}
|
||||
}
|
||||
|
||||
pub enum PortInputPolarity {
|
||||
High,
|
||||
Low,
|
||||
impl ChannelID for $ChX {
|
||||
fn number(&self) -> usize {
|
||||
$n
|
||||
}
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
impl_channel!(Ch0, 0);
|
||||
impl_channel!(Ch1, 1);
|
||||
impl_channel!(Ch2, 2);
|
||||
impl_channel!(Ch3, 3);
|
||||
impl_channel!(Ch4, 4);
|
||||
impl_channel!(Ch5, 5);
|
||||
impl_channel!(Ch6, 6);
|
||||
impl_channel!(Ch7, 7);
|
||||
|
||||
pub struct ChAny(u8);
|
||||
|
||||
impl ChannelID for ChAny {
|
||||
fn number(&self) -> usize {
|
||||
self.0 as usize
|
||||
}
|
||||
}
|
||||
|
||||
#[derive(Clone, Copy)]
|
||||
pub struct Gpiote(());
|
||||
|
||||
const NEW_SIGNAL: Signal<()> = Signal::new();
|
||||
static CHANNEL_SIGNALS: [Signal<()>; CHANNEL_COUNT] = [NEW_SIGNAL; CHANNEL_COUNT];
|
||||
static PORT_SIGNALS: [Signal<()>; PIN_COUNT] = [NEW_SIGNAL; PIN_COUNT];
|
||||
|
||||
pub enum InputChannelPolarity {
|
||||
None,
|
||||
HiToLo,
|
||||
|
@ -58,12 +91,23 @@ pub enum NewChannelError {
|
|||
NoFreeChannels,
|
||||
}
|
||||
|
||||
pub struct Channels {
|
||||
pub ch0: Ch0,
|
||||
pub ch1: Ch1,
|
||||
pub ch2: Ch2,
|
||||
pub ch3: Ch3,
|
||||
pub ch4: Ch4,
|
||||
pub ch5: Ch5,
|
||||
pub ch6: Ch6,
|
||||
pub ch7: Ch7,
|
||||
}
|
||||
|
||||
impl Gpiote {
|
||||
pub fn new(gpiote: GPIOTE, irq: interrupt::GPIOTEInterrupt) -> Self {
|
||||
pub fn new(gpiote: GPIOTE, irq: interrupt::GPIOTEInterrupt) -> (Self, Channels) {
|
||||
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||
let ports = unsafe { &[&*P0::ptr(), &*P1::ptr()] };
|
||||
let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] };
|
||||
#[cfg(not(any(feature = "52833", feature = "52840")))]
|
||||
let ports = unsafe { &[&*P0::ptr()] };
|
||||
let ports = unsafe { &[&*pac::P0::ptr()] };
|
||||
|
||||
for &p in ports {
|
||||
// Enable latched detection
|
||||
|
@ -79,240 +123,38 @@ impl Gpiote {
|
|||
irq.unpend();
|
||||
irq.enable();
|
||||
|
||||
Self {
|
||||
inner: gpiote,
|
||||
free_channels: Cell::new(0xFF), // all 8 channels free
|
||||
channel_signals: [
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
],
|
||||
// This is just horrible
|
||||
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||
port_signals: [
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
],
|
||||
#[cfg(not(any(feature = "52833", feature = "52840")))]
|
||||
port_signals: [
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
Signal::new(),
|
||||
],
|
||||
}
|
||||
}
|
||||
|
||||
fn allocate_channel(&self) -> Result<u8, NewChannelError> {
|
||||
interrupt::free(|_| {
|
||||
let chs = self.free_channels.get();
|
||||
let index = chs.trailing_zeros() as usize;
|
||||
if index == 8 {
|
||||
return Err(NewChannelError::NoFreeChannels);
|
||||
}
|
||||
self.free_channels.set(chs & !(1 << index));
|
||||
Ok(index as u8)
|
||||
})
|
||||
}
|
||||
|
||||
fn free_channel(&self, index: u8) {
|
||||
interrupt::free(|_| {
|
||||
self.inner.config[index as usize].write(|w| w.mode().disabled());
|
||||
self.inner.intenclr.write(|w| unsafe { w.bits(1 << index) });
|
||||
|
||||
self.free_channels
|
||||
.set(self.free_channels.get() | 1 << index);
|
||||
trace!("freed ch {:?}", index);
|
||||
})
|
||||
}
|
||||
|
||||
pub fn wait_port_input<'a, T>(
|
||||
&'a self,
|
||||
pin: &'a Pin<Input<T>>,
|
||||
polarity: PortInputPolarity,
|
||||
) -> PortInputFuture<'a, T> {
|
||||
interrupt::free(|_| {
|
||||
unsafe { INSTANCE = self };
|
||||
PortInputFuture {
|
||||
gpiote: self,
|
||||
pin,
|
||||
polarity,
|
||||
}
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_input_channel<'a, T>(
|
||||
&'a self,
|
||||
pin: Pin<Input<T>>,
|
||||
polarity: InputChannelPolarity,
|
||||
) -> Result<InputChannel<'a, T>, NewChannelError> {
|
||||
interrupt::free(|_| {
|
||||
unsafe { INSTANCE = self };
|
||||
let index = self.allocate_channel()?;
|
||||
trace!("allocated in ch {:?}", index as u8);
|
||||
|
||||
self.inner.config[index as usize].write(|w| {
|
||||
match polarity {
|
||||
InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(),
|
||||
InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(),
|
||||
InputChannelPolarity::None => w.mode().event().polarity().none(),
|
||||
InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(),
|
||||
};
|
||||
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||
w.port().bit(match pin.port() {
|
||||
Port::Port0 => false,
|
||||
Port::Port1 => true,
|
||||
});
|
||||
unsafe { w.psel().bits(pin.pin()) }
|
||||
});
|
||||
|
||||
// Enable interrupt
|
||||
self.inner.intenset.write(|w| unsafe { w.bits(1 << index) });
|
||||
|
||||
Ok(InputChannel {
|
||||
gpiote: self,
|
||||
index,
|
||||
pin,
|
||||
})
|
||||
})
|
||||
}
|
||||
|
||||
pub fn new_output_channel<'a, T>(
|
||||
&'a self,
|
||||
pin: Pin<Output<T>>,
|
||||
level: Level,
|
||||
polarity: OutputChannelPolarity,
|
||||
) -> Result<OutputChannel<'a>, NewChannelError> {
|
||||
interrupt::free(|_| {
|
||||
unsafe { INSTANCE = self };
|
||||
let index = self.allocate_channel()?;
|
||||
trace!("allocated out ch {:?}", index);
|
||||
|
||||
self.inner.config[index as usize].write(|w| {
|
||||
w.mode().task();
|
||||
match level {
|
||||
Level::High => w.outinit().high(),
|
||||
Level::Low => w.outinit().low(),
|
||||
};
|
||||
match polarity {
|
||||
OutputChannelPolarity::Set => w.polarity().lo_to_hi(),
|
||||
OutputChannelPolarity::Clear => w.polarity().hi_to_lo(),
|
||||
OutputChannelPolarity::Toggle => w.polarity().toggle(),
|
||||
};
|
||||
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||
w.port().bit(match pin.port() {
|
||||
Port::Port0 => false,
|
||||
Port::Port1 => true,
|
||||
});
|
||||
unsafe { w.psel().bits(pin.pin()) }
|
||||
});
|
||||
|
||||
// Enable interrupt
|
||||
self.inner.intenset.write(|w| unsafe { w.bits(1 << index) });
|
||||
|
||||
Ok(OutputChannel {
|
||||
gpiote: self,
|
||||
index,
|
||||
})
|
||||
})
|
||||
(
|
||||
Self(()),
|
||||
Channels {
|
||||
ch0: Ch0(()),
|
||||
ch1: Ch1(()),
|
||||
ch2: Ch2(()),
|
||||
ch3: Ch3(()),
|
||||
ch4: Ch4(()),
|
||||
ch5: Ch5(()),
|
||||
ch6: Ch6(()),
|
||||
ch7: Ch7(()),
|
||||
},
|
||||
)
|
||||
}
|
||||
|
||||
unsafe fn on_irq(_ctx: *mut ()) {
|
||||
let s = &(*INSTANCE);
|
||||
let g = &*GPIOTE::ptr();
|
||||
|
||||
for i in 0..8 {
|
||||
if s.inner.events_in[i].read().bits() != 0 {
|
||||
s.inner.events_in[i].write(|w| w);
|
||||
s.channel_signals[i].signal(());
|
||||
if g.events_in[i].read().bits() != 0 {
|
||||
g.events_in[i].write(|w| w);
|
||||
CHANNEL_SIGNALS[i].signal(());
|
||||
}
|
||||
}
|
||||
|
||||
if s.inner.events_port.read().bits() != 0 {
|
||||
s.inner.events_port.write(|w| w);
|
||||
if g.events_port.read().bits() != 0 {
|
||||
g.events_port.write(|w| w);
|
||||
|
||||
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||
let ports = &[&*P0::ptr(), &*P1::ptr()];
|
||||
let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()];
|
||||
#[cfg(not(any(feature = "52833", feature = "52840")))]
|
||||
let ports = &[&*P0::ptr()];
|
||||
let ports = &[&*pac::P0::ptr()];
|
||||
|
||||
let mut work = true;
|
||||
while work {
|
||||
|
@ -322,7 +164,7 @@ impl Gpiote {
|
|||
work = true;
|
||||
p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled());
|
||||
p.latch.write(|w| w.bits(1 << pin));
|
||||
s.port_signals[port * 32 + pin as usize].signal(());
|
||||
PORT_SIGNALS[port * 32 + pin as usize].signal(());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -330,32 +172,7 @@ impl Gpiote {
|
|||
}
|
||||
}
|
||||
|
||||
pub struct PortInputFuture<'a, T> {
|
||||
gpiote: &'a Gpiote,
|
||||
pin: &'a Pin<Input<T>>,
|
||||
polarity: PortInputPolarity,
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for PortInputFuture<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
pin_conf(&self.pin).modify(|_, w| w.sense().disabled());
|
||||
self.gpiote.port_signals[pin_num(&self.pin)].reset();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Future for PortInputFuture<'a, T> {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
pin_conf(&self.pin).modify(|_, w| match self.polarity {
|
||||
PortInputPolarity::Low => w.sense().low(),
|
||||
PortInputPolarity::High => w.sense().high(),
|
||||
});
|
||||
self.gpiote.port_signals[pin_num(&self.pin)].poll_wait(cx)
|
||||
}
|
||||
}
|
||||
|
||||
fn pin_num<T>(pin: &Pin<T>) -> usize {
|
||||
fn pin_num<T>(pin: &GpioPin<T>) -> usize {
|
||||
let port = match pin.port() {
|
||||
Port::Port0 => 0,
|
||||
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||
|
@ -365,86 +182,189 @@ fn pin_num<T>(pin: &Pin<T>) -> usize {
|
|||
port + pin.pin() as usize
|
||||
}
|
||||
|
||||
fn pin_block<T>(pin: &Pin<T>) -> &gpio::RegisterBlock {
|
||||
fn pin_block<T>(pin: &GpioPin<T>) -> &pac_gpio::RegisterBlock {
|
||||
let ptr = match pin.port() {
|
||||
Port::Port0 => P0::ptr(),
|
||||
Port::Port0 => pac::P0::ptr(),
|
||||
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||
Port::Port1 => P1::ptr(),
|
||||
Port::Port1 => pac::P1::ptr(),
|
||||
};
|
||||
|
||||
unsafe { &*ptr }
|
||||
}
|
||||
|
||||
fn pin_conf<T>(pin: &Pin<T>) -> &gpio::PIN_CNF {
|
||||
fn pin_conf<T>(pin: &GpioPin<T>) -> &pac_gpio::PIN_CNF {
|
||||
&pin_block(pin).pin_cnf[pin.pin() as usize]
|
||||
}
|
||||
|
||||
pub struct InputChannel<'a, T> {
|
||||
gpiote: &'a Gpiote,
|
||||
pin: Pin<Input<T>>,
|
||||
index: u8,
|
||||
pub struct InputChannel<C: ChannelID, T> {
|
||||
ch: C,
|
||||
pin: GpioPin<Input<T>>,
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for InputChannel<'a, T> {
|
||||
impl<C: ChannelID, T> Drop for InputChannel<C, T> {
|
||||
fn drop(&mut self) {
|
||||
self.gpiote.free_channel(self.index);
|
||||
let g = unsafe { &*GPIOTE::ptr() };
|
||||
let index = self.ch.number();
|
||||
g.config[index].write(|w| w.mode().disabled());
|
||||
g.intenclr.write(|w| unsafe { w.bits(1 << index) });
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> InputChannel<'a, T> {
|
||||
pub async fn wait(&self) {
|
||||
self.gpiote.channel_signals[self.index as usize]
|
||||
.wait()
|
||||
.await;
|
||||
impl<C: ChannelID, T> InputChannel<C, T> {
|
||||
pub fn new(
|
||||
_gpiote: Gpiote,
|
||||
ch: C,
|
||||
pin: GpioPin<Input<T>>,
|
||||
polarity: InputChannelPolarity,
|
||||
) -> Self {
|
||||
let g = unsafe { &*GPIOTE::ptr() };
|
||||
let index = ch.number();
|
||||
|
||||
g.config[index].write(|w| {
|
||||
match polarity {
|
||||
InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(),
|
||||
InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(),
|
||||
InputChannelPolarity::None => w.mode().event().polarity().none(),
|
||||
InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(),
|
||||
};
|
||||
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||
w.port().bit(match pin.port() {
|
||||
Port::Port0 => false,
|
||||
Port::Port1 => true,
|
||||
});
|
||||
unsafe { w.psel().bits(pin.pin()) }
|
||||
});
|
||||
|
||||
CHANNEL_SIGNALS[index].reset();
|
||||
|
||||
// Enable interrupt
|
||||
g.intenset.write(|w| unsafe { w.bits(1 << index) });
|
||||
|
||||
InputChannel { ch, pin }
|
||||
}
|
||||
|
||||
pub fn pin(&self) -> &Pin<Input<T>> {
|
||||
pub fn free(self) -> (C, GpioPin<Input<T>>) {
|
||||
let m = ManuallyDrop::new(self);
|
||||
let ch = unsafe { ptr::read(&m.ch) };
|
||||
let pin = unsafe { ptr::read(&m.pin) };
|
||||
(ch, pin)
|
||||
}
|
||||
|
||||
pub async fn wait(&self) {
|
||||
let index = self.ch.number();
|
||||
CHANNEL_SIGNALS[index].wait().await;
|
||||
}
|
||||
|
||||
pub fn pin(&self) -> &GpioPin<Input<T>> {
|
||||
&self.pin
|
||||
}
|
||||
}
|
||||
|
||||
pub struct OutputChannel<'a> {
|
||||
gpiote: &'a Gpiote,
|
||||
index: u8,
|
||||
pub struct OutputChannel<C: ChannelID, T> {
|
||||
ch: C,
|
||||
pin: GpioPin<Output<T>>,
|
||||
}
|
||||
|
||||
impl<'a> Drop for OutputChannel<'a> {
|
||||
impl<C: ChannelID, T> Drop for OutputChannel<C, T> {
|
||||
fn drop(&mut self) {
|
||||
self.gpiote.free_channel(self.index);
|
||||
let g = unsafe { &*GPIOTE::ptr() };
|
||||
let index = self.ch.number();
|
||||
g.config[index].write(|w| w.mode().disabled());
|
||||
g.intenclr.write(|w| unsafe { w.bits(1 << index) });
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a> OutputChannel<'a> {
|
||||
impl<C: ChannelID, T> OutputChannel<C, T> {
|
||||
pub fn new(
|
||||
_gpiote: Gpiote,
|
||||
ch: C,
|
||||
pin: GpioPin<Output<T>>,
|
||||
level: Level,
|
||||
polarity: OutputChannelPolarity,
|
||||
) -> Self {
|
||||
let g = unsafe { &*GPIOTE::ptr() };
|
||||
let index = ch.number();
|
||||
|
||||
g.config[index].write(|w| {
|
||||
w.mode().task();
|
||||
match level {
|
||||
Level::High => w.outinit().high(),
|
||||
Level::Low => w.outinit().low(),
|
||||
};
|
||||
match polarity {
|
||||
OutputChannelPolarity::Set => w.polarity().lo_to_hi(),
|
||||
OutputChannelPolarity::Clear => w.polarity().hi_to_lo(),
|
||||
OutputChannelPolarity::Toggle => w.polarity().toggle(),
|
||||
};
|
||||
#[cfg(any(feature = "52833", feature = "52840"))]
|
||||
w.port().bit(match pin.port() {
|
||||
Port::Port0 => false,
|
||||
Port::Port1 => true,
|
||||
});
|
||||
unsafe { w.psel().bits(pin.pin()) }
|
||||
});
|
||||
|
||||
// Enable interrupt
|
||||
g.intenset.write(|w| unsafe { w.bits(1 << index) });
|
||||
|
||||
OutputChannel { ch, pin }
|
||||
}
|
||||
|
||||
pub fn free(self) -> (C, GpioPin<Output<T>>) {
|
||||
let m = ManuallyDrop::new(self);
|
||||
let ch = unsafe { ptr::read(&m.ch) };
|
||||
let pin = unsafe { ptr::read(&m.pin) };
|
||||
(ch, pin)
|
||||
}
|
||||
|
||||
/// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle).
|
||||
pub fn out(&self) {
|
||||
self.gpiote.inner.tasks_out[self.index as usize].write(|w| unsafe { w.bits(1) });
|
||||
let g = unsafe { &*GPIOTE::ptr() };
|
||||
let index = self.ch.number();
|
||||
|
||||
g.tasks_out[index].write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
/// Triggers `task set` (set associated pin high).
|
||||
#[cfg(not(feature = "51"))]
|
||||
pub fn set(&self) {
|
||||
self.gpiote.inner.tasks_set[self.index as usize].write(|w| unsafe { w.bits(1) });
|
||||
let g = unsafe { &*GPIOTE::ptr() };
|
||||
let index = self.ch.number();
|
||||
|
||||
g.tasks_set[index].write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
/// Triggers `task clear` (set associated pin low).
|
||||
#[cfg(not(feature = "51"))]
|
||||
pub fn clear(&self) {
|
||||
self.gpiote.inner.tasks_clr[self.index as usize].write(|w| unsafe { w.bits(1) });
|
||||
let g = unsafe { &*GPIOTE::ptr() };
|
||||
let index = self.ch.number();
|
||||
|
||||
g.tasks_clr[index].write(|w| unsafe { w.bits(1) });
|
||||
}
|
||||
|
||||
/// Returns reference to task_out endpoint for PPI.
|
||||
pub fn task_out(&self) -> &Reg<u32, _TASKS_OUT> {
|
||||
&self.gpiote.inner.tasks_out[self.index as usize]
|
||||
let g = unsafe { &*GPIOTE::ptr() };
|
||||
let index = self.ch.number();
|
||||
|
||||
&g.tasks_out[index]
|
||||
}
|
||||
|
||||
/// Returns reference to task_clr endpoint for PPI.
|
||||
#[cfg(not(feature = "51"))]
|
||||
pub fn task_clr(&self) -> &Reg<u32, _TASKS_CLR> {
|
||||
&self.gpiote.inner.tasks_clr[self.index as usize]
|
||||
let g = unsafe { &*GPIOTE::ptr() };
|
||||
let index = self.ch.number();
|
||||
|
||||
&g.tasks_clr[index]
|
||||
}
|
||||
|
||||
/// Returns reference to task_set endpoint for PPI.
|
||||
#[cfg(not(feature = "51"))]
|
||||
pub fn task_set(&self) -> &Reg<u32, _TASKS_SET> {
|
||||
&self.gpiote.inner.tasks_set[self.index as usize]
|
||||
let g = unsafe { &*GPIOTE::ptr() };
|
||||
let index = self.ch.number();
|
||||
|
||||
&g.tasks_set[index]
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -463,3 +383,73 @@ impl Iterator for BitIter {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
pub struct GpiotePin<T> {
|
||||
pin: GpioPin<Input<T>>,
|
||||
}
|
||||
|
||||
impl<T> Unpin for GpiotePin<T> {}
|
||||
|
||||
impl<T> GpiotePin<T> {
|
||||
pub fn new(_gpiote: Gpiote, pin: GpioPin<Input<T>>) -> Self {
|
||||
Self { pin }
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> WaitForHigh for GpiotePin<T> {
|
||||
type Future<'a> = PortInputFuture<'a, T>;
|
||||
|
||||
fn wait_for_high<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
||||
PortInputFuture {
|
||||
pin: &self.get_mut().pin,
|
||||
polarity: PortInputPolarity::High,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T: 'static> WaitForLow for GpiotePin<T> {
|
||||
type Future<'a> = PortInputFuture<'a, T>;
|
||||
|
||||
fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> {
|
||||
PortInputFuture {
|
||||
pin: &self.get_mut().pin,
|
||||
polarity: PortInputPolarity::Low,
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
impl<T> Deref for GpiotePin<T> {
|
||||
type Target = GpioPin<Input<T>>;
|
||||
fn deref(&self) -> &Self::Target {
|
||||
&self.pin
|
||||
}
|
||||
}
|
||||
|
||||
enum PortInputPolarity {
|
||||
High,
|
||||
Low,
|
||||
}
|
||||
|
||||
pub struct PortInputFuture<'a, T> {
|
||||
pin: &'a GpioPin<Input<T>>,
|
||||
polarity: PortInputPolarity,
|
||||
}
|
||||
|
||||
impl<'a, T> Drop for PortInputFuture<'a, T> {
|
||||
fn drop(&mut self) {
|
||||
pin_conf(&self.pin).modify(|_, w| w.sense().disabled());
|
||||
PORT_SIGNALS[pin_num(&self.pin)].reset();
|
||||
}
|
||||
}
|
||||
|
||||
impl<'a, T> Future for PortInputFuture<'a, T> {
|
||||
type Output = ();
|
||||
|
||||
fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> {
|
||||
pin_conf(&self.pin).modify(|_, w| match self.polarity {
|
||||
PortInputPolarity::Low => w.sense().low(),
|
||||
PortInputPolarity::High => w.sense().high(),
|
||||
});
|
||||
PORT_SIGNALS[pin_num(&self.pin)].poll_wait(cx)
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in a new issue