From a7797a918d3a42f9244a853d2a47aced0ceb900a Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Thu, 4 Feb 2021 23:56:17 +0100 Subject: [PATCH] nrf/gpiote: new api: switch to owned structs, implement WaitForHigh/WaitForLow. --- .../src/bin/{gpiote.rs => gpiote_channel.rs} | 32 +- embassy-nrf-examples/src/bin/gpiote_port.rs | 39 +- embassy-nrf/src/gpiote.rs | 582 +++++++++--------- 3 files changed, 324 insertions(+), 329 deletions(-) rename embassy-nrf-examples/src/bin/{gpiote.rs => gpiote_channel.rs} (69%) diff --git a/embassy-nrf-examples/src/bin/gpiote.rs b/embassy-nrf-examples/src/bin/gpiote_channel.rs similarity index 69% rename from embassy-nrf-examples/src/bin/gpiote.rs rename to embassy-nrf-examples/src/bin/gpiote_channel.rs index f5315d6a..5470c47c 100644 --- a/embassy-nrf-examples/src/bin/gpiote.rs +++ b/embassy-nrf-examples/src/bin/gpiote_channel.rs @@ -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") } }; diff --git a/embassy-nrf-examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs index 833096f3..9d999f95 100644 --- a/embassy-nrf-examples/src/bin/gpiote_port.rs +++ b/embassy-nrf-examples/src/bin/gpiote_port.rs @@ -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>) { +async fn button(n: usize, mut pin: GpiotePin) { 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::>() + 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::()); - - 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); } diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 65a584c7..89aab5bc 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -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, // 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 { - 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>, - 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>, - polarity: InputChannelPolarity, - ) -> Result, 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>, - level: Level, - polarity: OutputChannelPolarity, - ) -> Result, 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>, - 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 { - 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(pin: &Pin) -> usize { +fn pin_num(pin: &GpioPin) -> usize { let port = match pin.port() { Port::Port0 => 0, #[cfg(any(feature = "52833", feature = "52840"))] @@ -365,86 +182,189 @@ fn pin_num(pin: &Pin) -> usize { port + pin.pin() as usize } -fn pin_block(pin: &Pin) -> &gpio::RegisterBlock { +fn pin_block(pin: &GpioPin) -> &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(pin: &Pin) -> &gpio::PIN_CNF { +fn pin_conf(pin: &GpioPin) -> &pac_gpio::PIN_CNF { &pin_block(pin).pin_cnf[pin.pin() as usize] } -pub struct InputChannel<'a, T> { - gpiote: &'a Gpiote, - pin: Pin>, - index: u8, +pub struct InputChannel { + ch: C, + pin: GpioPin>, } -impl<'a, T> Drop for InputChannel<'a, T> { +impl Drop for InputChannel { 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 InputChannel { + pub fn new( + _gpiote: Gpiote, + ch: C, + pin: GpioPin>, + 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> { + pub fn free(self) -> (C, GpioPin>) { + 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> { &self.pin } } -pub struct OutputChannel<'a> { - gpiote: &'a Gpiote, - index: u8, +pub struct OutputChannel { + ch: C, + pin: GpioPin>, } -impl<'a> Drop for OutputChannel<'a> { +impl Drop for OutputChannel { 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 OutputChannel { + pub fn new( + _gpiote: Gpiote, + ch: C, + pin: GpioPin>, + 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>) { + 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 { - &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 { - &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 { - &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 { + pin: GpioPin>, +} + +impl Unpin for GpiotePin {} + +impl GpiotePin { + pub fn new(_gpiote: Gpiote, pin: GpioPin>) -> Self { + Self { pin } + } +} + +impl WaitForHigh for GpiotePin { + 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 WaitForLow for GpiotePin { + 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 Deref for GpiotePin { + type Target = GpioPin>; + fn deref(&self) -> &Self::Target { + &self.pin + } +} + +enum PortInputPolarity { + High, + Low, +} + +pub struct PortInputFuture<'a, T> { + pin: &'a GpioPin>, + 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 { + 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) + } +}