nrf/gpiote: new api: switch to owned structs, implement WaitForHigh/WaitForLow.
This commit is contained in:
		| @@ -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) | ||||
|     } | ||||
| } | ||||
|   | ||||
		Reference in New Issue
	
	Block a user