diff --git a/embassy-nrf-examples/src/bin/gpiote_channel.rs b/embassy-nrf-examples/src/bin/gpiote_channel.rs index 599882a9..d223df7a 100644 --- a/embassy-nrf-examples/src/bin/gpiote_channel.rs +++ b/embassy-nrf-examples/src/bin/gpiote_channel.rs @@ -11,31 +11,44 @@ use example_common::*; use cortex_m_rt::entry; use defmt::panic; -use nrf52840_hal::gpio; use embassy::executor::{task, Executor}; use embassy::util::Forever; -use embassy_nrf::gpiote::{Gpiote, InputChannel, InputChannelPolarity}; -use embassy_nrf::interrupt; +use embassy_nrf::gpio::{Input, Pull}; +use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; +use embassy_nrf::{interrupt, Peripherals}; #[task] async fn run() { - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - let port0 = gpio::p0::Parts::new(p.P0); - - let (g, chs) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); + let p = Peripherals::take().unwrap(); + let g = gpiote::initialize(p.GPIOTE, interrupt::take!(GPIOTE)); info!("Starting!"); - let pin1 = port0.p0_11.into_pullup_input().degrade(); - 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 ch1 = InputChannel::new( + g, + p.GPIOTE_CH0, + Input::new(p.P0_11, Pull::Up), + InputChannelPolarity::HiToLo, + ); + let ch2 = InputChannel::new( + g, + p.GPIOTE_CH1, + Input::new(p.P0_12, Pull::Up), + InputChannelPolarity::LoToHi, + ); + let ch3 = InputChannel::new( + g, + p.GPIOTE_CH2, + Input::new(p.P0_24, Pull::Up), + InputChannelPolarity::Toggle, + ); + let ch4 = InputChannel::new( + g, + p.GPIOTE_CH3, + Input::new(p.P0_25, Pull::Up), + InputChannelPolarity::Toggle, + ); let button1 = async { loop { diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 9ea008f0..95e49324 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -10,10 +10,12 @@ use core::task::{Context, Poll}; use embassy::interrupt::InterruptExt; use embassy::traits::gpio::{WaitForHigh, WaitForLow}; use embassy::util::{AtomicWaker, PeripheralBorrow, Signal}; +use embassy_extras::impl_unborrow; use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; +use futures::future::poll_fn; use crate::gpio::sealed::Pin as _; -use crate::gpio::{AnyPin, Input, Pin as GpioPin, Pull}; +use crate::gpio::{AnyPin, Input, Pin as GpioPin, Port, Pull}; use crate::pac; use crate::pac::generic::Reg; use crate::pac::gpiote::_TASKS_OUT; @@ -30,44 +32,6 @@ pub const PIN_COUNT: usize = 48; #[cfg(not(any(feature = "52833", feature = "52840")))] pub const PIN_COUNT: usize = 32; -pub trait ChannelID { - fn number(&self) -> usize; -} - -macro_rules! impl_channel { - ($ChX:ident, $n:expr) => { - pub struct $ChX(()); - impl $ChX { - pub fn degrade(self) -> ChAny { - ChAny($n) - } - } - - 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 - } -} - const NEW_AWR: AtomicWaker = AtomicWaker::new(); static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AWR; CHANNEL_COUNT]; static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AWR; PIN_COUNT]; @@ -123,7 +87,7 @@ unsafe fn on_irq(_ctx: *mut ()) { for i in 0..CHANNEL_COUNT { if g.events_in[i].read().bits() != 0 { - g.events_in[i].write(|w| w); + g.intenclr.write(|w| unsafe { w.bits(1 << i) }); CHANNEL_WAKERS[i].wake(); } } @@ -163,32 +127,31 @@ impl Iterator for BitIter { } } -/* -pub struct InputChannel { +pub struct InputChannel<'d, C: Channel, T: GpioPin> { ch: C, - pin: GpioPin>, + pin: Input<'d, T>, } -impl Drop for InputChannel { +impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> { fn drop(&mut self) { - 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) }); + let g = unsafe { &*pac::GPIOTE::ptr() }; + let num = self.ch.number() as usize; + g.config[num].write(|w| w.mode().disabled()); + g.intenclr.write(|w| unsafe { w.bits(1 << num) }); } } -impl InputChannel { +impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { pub fn new( _init: Initialized, ch: C, - pin: GpioPin>, + pin: Input<'d, T>, polarity: InputChannelPolarity, ) -> Self { - let g = unsafe { &*GPIOTE::ptr() }; - let index = ch.number(); + let g = unsafe { &*pac::GPIOTE::ptr() }; + let num = ch.number() as usize; - g.config[index].write(|w| { + g.config[num].write(|w| { match polarity { InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(), InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(), @@ -196,38 +159,52 @@ impl InputChannel { InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(), }; #[cfg(any(feature = "52833", feature = "52840"))] - w.port().bit(match pin.port() { + w.port().bit(match pin.pin.port() { Port::Port0 => false, Port::Port1 => true, }); - unsafe { w.psel().bits(pin.pin()) } + unsafe { w.psel().bits(pin.pin.pin()) } }); - CHANNEL_WAKERS[index].reset(); - - // Enable interrupt - g.intenset.write(|w| unsafe { w.bits(1 << index) }); + g.events_in[num].reset(); InputChannel { 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) - } - pub async fn wait(&self) { - let index = self.ch.number(); - CHANNEL_WAKERS[index].wait().await; - } + let g = unsafe { &*pac::GPIOTE::ptr() }; + let num = self.ch.number() as usize; - pub fn pin(&self) -> &GpioPin> { - &self.pin + // Enable interrupt + g.events_in[num].reset(); + g.intenset.write(|w| unsafe { w.bits(1 << num) }); + + poll_fn(|cx| { + CHANNEL_WAKERS[num].register(cx.waker()); + + if g.events_in[num].read().bits() != 0 { + Poll::Ready(()) + } else { + Poll::Pending + } + }) + .await; } } +impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> { + type Error = Infallible; + + fn is_high(&self) -> Result { + self.pin.is_high() + } + + fn is_low(&self) -> Result { + self.pin.is_low() + } +} + +/* pub struct OutputChannel { ch: C, pin: GpioPin>, @@ -414,3 +391,48 @@ impl<'a> Future for PortInputFuture<'a> { } } } + +mod sealed { + pub trait Channel { + fn number(&self) -> u8; + } +} + +pub trait Channel: sealed::Channel + Sized { + fn degrade(self) -> AnyChannel { + AnyChannel { + number: self.number(), + } + } +} + +pub struct AnyChannel { + number: u8, +} +impl_unborrow!(AnyChannel); +impl Channel for AnyChannel {} +impl sealed::Channel for AnyChannel { + fn number(&self) -> u8 { + self.number + } +} + +macro_rules! impl_channel { + ($type:ident, $number:expr) => { + impl sealed::Channel for peripherals::$type { + fn number(&self) -> u8 { + $number + } + } + impl Channel for peripherals::$type {} + }; +} + +impl_channel!(GPIOTE_CH0, 0); +impl_channel!(GPIOTE_CH1, 1); +impl_channel!(GPIOTE_CH2, 2); +impl_channel!(GPIOTE_CH3, 3); +impl_channel!(GPIOTE_CH4, 4); +impl_channel!(GPIOTE_CH5, 5); +impl_channel!(GPIOTE_CH6, 6); +impl_channel!(GPIOTE_CH7, 7);