From ba7b3974bb0092f0a9d3bf5e02fb5d4c41c53083 Mon Sep 17 00:00:00 2001 From: Dario Nieuwenhuis Date: Sat, 20 Mar 2021 03:09:42 +0100 Subject: [PATCH] nrf/gpiote: update to new gpio --- embassy-nrf-examples/src/bin/gpiote_port.rs | 19 +- embassy-nrf/src/gpio.rs | 8 +- embassy-nrf/src/gpiote.rs | 291 +++++++++----------- 3 files changed, 142 insertions(+), 176 deletions(-) diff --git a/embassy-nrf-examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs index 36ee1c8e..273cd124 100644 --- a/embassy-nrf-examples/src/bin/gpiote_port.rs +++ b/embassy-nrf-examples/src/bin/gpiote_port.rs @@ -6,7 +6,9 @@ #[path = "../example_common.rs"] mod example_common; +use embassy_nrf::gpio::{AnyPin, Input, Pin as _, Pull}; use example_common::*; +use gpiote::GpioteInput; use core::pin::Pin; use cortex_m_rt::entry; @@ -16,10 +18,10 @@ use nrf52840_hal::gpio; use embassy::executor::{task, Executor}; use embassy::traits::gpio::{WaitForHigh, WaitForLow}; use embassy::util::Forever; -use embassy_nrf::gpiote::{Gpiote, GpiotePin}; +use embassy_nrf::gpiote; use embassy_nrf::interrupt; -async fn button(n: usize, mut pin: GpiotePin) { +async fn button(n: usize, mut pin: GpioteInput) { loop { Pin::new(&mut pin).wait_for_low().await; info!("Button {:?} pressed!", n); @@ -30,26 +32,25 @@ async fn button(n: usize, mut pin: GpiotePin) { #[task] async fn run() { - let p = unwrap!(embassy_nrf::pac::Peripherals::take()); - let port0 = gpio::p0::Parts::new(p.P0); + let p = unsafe { embassy_nrf::peripherals::Peripherals::steal() }; - let (g, _) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); + let g = gpiote::initialize(p.gpiote, interrupt::take!(GPIOTE)); let button1 = button( 1, - GpiotePin::new(g, port0.p0_11.into_pullup_input().degrade()), + GpioteInput::new(g, Input::new(p.p0_11.degrade(), Pull::Up)), ); let button2 = button( 2, - GpiotePin::new(g, port0.p0_12.into_pullup_input().degrade()), + GpioteInput::new(g, Input::new(p.p0_12.degrade(), Pull::Up)), ); let button3 = button( 3, - GpiotePin::new(g, port0.p0_24.into_pullup_input().degrade()), + GpioteInput::new(g, Input::new(p.p0_24.degrade(), Pull::Up)), ); let button4 = button( 4, - GpiotePin::new(g, port0.p0_25.into_pullup_input().degrade()), + GpioteInput::new(g, Input::new(p.p0_25.degrade(), Pull::Up)), ); futures::join!(button1, button2, button3, button4); } diff --git a/embassy-nrf/src/gpio.rs b/embassy-nrf/src/gpio.rs index 52cb5731..dd334c63 100644 --- a/embassy-nrf/src/gpio.rs +++ b/embassy-nrf/src/gpio.rs @@ -30,7 +30,7 @@ pub enum Pull { /// GPIO input driver. pub struct Input { - pin: T, + pub(crate) pin: T, } impl Input { @@ -273,10 +273,8 @@ pub struct AnyPin { } impl AnyPin { - pub unsafe fn steal_from_psel_bits(psel_bits: u32) -> Self { - Self { - pin_port: psel_bits as u8, - } + pub unsafe fn steal(pin_port: u8) -> Self { + Self { pin_port } } } diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 5dc80a63..2b603c4c 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -1,19 +1,24 @@ +use core::convert::Infallible; use core::future::Future; -use core::mem::ManuallyDrop; +use core::intrinsics::transmute; +use core::marker::PhantomData; +use core::mem::{self, ManuallyDrop}; use core::ops::Deref; use core::pin::Pin; use core::ptr; use core::task::{Context, Poll}; use embassy::interrupt::InterruptExt; use embassy::traits::gpio::{WaitForHigh, WaitForLow}; -use embassy::util::Signal; +use embassy::util::{AtomicWakerRegistration, Signal}; +use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; -use crate::hal::gpio::{Input, Level, Output, Pin as GpioPin, Port}; -use crate::interrupt; +use crate::gpio::sealed::Pin as _; +use crate::gpio::{AnyPin, Input, Pin as GpioPin, Pull}; use crate::pac; use crate::pac::generic::Reg; use crate::pac::gpiote::_TASKS_OUT; -use crate::pac::{p0 as pac_gpio, GPIOTE}; +use crate::pac::p0 as pac_gpio; +use crate::{interrupt, peripherals}; #[cfg(not(feature = "51"))] use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET}; @@ -63,12 +68,9 @@ impl ChannelID for ChAny { } } -#[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]; +const NEW_AWR: AtomicWakerRegistration = AtomicWakerRegistration::new(); +static CHANNEL_WAKERS: [AtomicWakerRegistration; CHANNEL_COUNT] = [NEW_AWR; CHANNEL_COUNT]; +static PORT_WAKERS: [AtomicWakerRegistration; PIN_COUNT] = [NEW_AWR; PIN_COUNT]; pub enum InputChannelPolarity { None, @@ -84,117 +86,84 @@ pub enum OutputChannelPolarity { Toggle, } -#[derive(Debug, Copy, Clone, Eq, PartialEq)] -#[cfg_attr(feature = "defmt", derive(defmt::Format))] -pub enum NewChannelError { - NoFreeChannels, +/// Token indicating GPIOTE has been correctly initialized. +/// +/// This is not an owned singleton, it is Copy. Drivers that make use of GPIOTE require it. +#[derive(Clone, Copy)] +pub struct Initialized { + _private: (), } -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, +pub fn initialize(gpiote: peripherals::GPIOTE, irq: interrupt::GPIOTE) -> Initialized { + #[cfg(any(feature = "52833", feature = "52840"))] + let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; + #[cfg(not(any(feature = "52833", feature = "52840")))] + let ports = unsafe { &[&*pac::P0::ptr()] }; + + for &p in ports { + // Enable latched detection + p.detectmode.write(|w| w.detectmode().ldetect()); + // Clear latch + p.latch.write(|w| unsafe { w.bits(0xFFFFFFFF) }) + } + + // Enable interrupts + let g = unsafe { &*pac::GPIOTE::ptr() }; + g.events_port.write(|w| w); + g.intenset.write(|w| w.port().set()); + irq.set_handler(on_irq); + irq.unpend(); + irq.enable(); + + Initialized { _private: () } } -impl Gpiote { - pub fn new(gpiote: GPIOTE, irq: interrupt::GPIOTE) -> (Self, Channels) { +unsafe fn on_irq(_ctx: *mut ()) { + let g = &*pac::GPIOTE::ptr(); + + for i in 0..CHANNEL_COUNT { + if g.events_in[i].read().bits() != 0 { + g.events_in[i].write(|w| w); + CHANNEL_WAKERS[i].wake(); + } + } + + if g.events_port.read().bits() != 0 { + g.events_port.write(|w| w); + #[cfg(any(feature = "52833", feature = "52840"))] - let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; + let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()]; #[cfg(not(any(feature = "52833", feature = "52840")))] - let ports = unsafe { &[&*pac::P0::ptr()] }; + let ports = &[&*pac::P0::ptr()]; - for &p in ports { - // Enable latched detection - p.detectmode.write(|w| w.detectmode().ldetect()); - // Clear latch - p.latch.write(|w| unsafe { w.bits(0xFFFFFFFF) }) - } - - // Enable interrupts - gpiote.events_port.write(|w| w); - gpiote.intenset.write(|w| w.port().set()); - irq.set_handler(Self::on_irq); - irq.unpend(); - irq.enable(); - - ( - 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 g = &*GPIOTE::ptr(); - - for (event_in, signal) in g.events_in.iter().zip(CHANNEL_SIGNALS.iter()) { - if event_in.read().bits() != 0 { - event_in.write(|w| w); - signal.signal(()); + for (port, &p) in ports.iter().enumerate() { + let bits = p.latch.read().bits(); + for pin in BitIter(bits) { + p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); + PORT_WAKERS[port * 32 + pin as usize].wake(); } + p.latch.write(|w| w.bits(bits)); } + } +} - if g.events_port.read().bits() != 0 { - g.events_port.write(|w| w); +struct BitIter(u32); - #[cfg(any(feature = "52833", feature = "52840"))] - let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()]; - #[cfg(not(any(feature = "52833", feature = "52840")))] - let ports = &[&*pac::P0::ptr()]; +impl Iterator for BitIter { + type Item = u32; - let mut work = true; - while work { - work = false; - for (port, &p) in ports.iter().enumerate() { - for pin in BitIter(p.latch.read().bits()) { - work = true; - p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); - p.latch.write(|w| w.bits(1 << pin)); - PORT_SIGNALS[port * 32 + pin as usize].signal(()); - } - } + fn next(&mut self) -> Option { + match self.0.trailing_zeros() { + 32 => None, + b => { + self.0 &= !(1 << b); + Some(b) } } } } -fn pin_num(pin: &GpioPin) -> usize { - let port = match pin.port() { - Port::Port0 => 0, - #[cfg(any(feature = "52833", feature = "52840"))] - Port::Port1 => 32, - }; - - port + pin.pin() as usize -} - -fn pin_block(pin: &GpioPin) -> &pac_gpio::RegisterBlock { - let ptr = match pin.port() { - Port::Port0 => pac::P0::ptr(), - #[cfg(any(feature = "52833", feature = "52840"))] - Port::Port1 => pac::P1::ptr(), - }; - - unsafe { &*ptr } -} - -fn pin_conf(pin: &GpioPin) -> &pac_gpio::PIN_CNF { - &pin_block(pin).pin_cnf[pin.pin() as usize] -} - +/* pub struct InputChannel { ch: C, pin: GpioPin>, @@ -211,7 +180,7 @@ impl Drop for InputChannel { impl InputChannel { pub fn new( - _gpiote: Gpiote, + _init: Initialized, ch: C, pin: GpioPin>, polarity: InputChannelPolarity, @@ -234,7 +203,7 @@ impl InputChannel { unsafe { w.psel().bits(pin.pin()) } }); - CHANNEL_SIGNALS[index].reset(); + CHANNEL_WAKERS[index].reset(); // Enable interrupt g.intenset.write(|w| unsafe { w.bits(1 << index) }); @@ -251,7 +220,7 @@ impl InputChannel { pub async fn wait(&self) { let index = self.ch.number(); - CHANNEL_SIGNALS[index].wait().await; + CHANNEL_WAKERS[index].wait().await; } pub fn pin(&self) -> &GpioPin> { @@ -366,89 +335,87 @@ impl OutputChannel { &g.tasks_set[index] } } + */ -struct BitIter(u32); - -impl Iterator for BitIter { - type Item = u32; - - fn next(&mut self) -> Option { - match self.0.trailing_zeros() { - 32 => None, - b => { - self.0 &= !(1 << b); - Some(b) - } - } - } +/// GPIO input driver with support +pub struct GpioteInput { + pin: Input, } +impl Unpin for GpioteInput {} -pub struct GpiotePin { - pin: GpioPin>, -} - -impl Unpin for GpiotePin {} - -impl GpiotePin { - pub fn new(_gpiote: Gpiote, pin: GpioPin>) -> Self { +impl GpioteInput { + pub fn new(_init: Initialized, pin: Input) -> Self { Self { pin } } } -impl WaitForHigh for GpiotePin { - type Future<'a> = PortInputFuture<'a, T>; +impl InputPin for GpioteInput { + type Error = Infallible; + + fn is_high(&self) -> Result { + self.pin.is_high() + } + + fn is_low(&self) -> Result { + self.pin.is_low() + } +} + +impl WaitForHigh for GpioteInput { + type Future<'a> = PortInputFuture<'a>; fn wait_for_high<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> { + self.pin.pin.conf().modify(|_, w| w.sense().high()); + PortInputFuture { - pin: &self.get_mut().pin, - polarity: PortInputPolarity::High, + pin_port: self.pin.pin.pin_port(), + phantom: PhantomData, } } } -impl WaitForLow for GpiotePin { - type Future<'a> = PortInputFuture<'a, T>; +impl WaitForLow for GpioteInput { + type Future<'a> = PortInputFuture<'a>; fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> { + self.pin.pin.conf().modify(|_, w| w.sense().low()); + PortInputFuture { - pin: &self.get_mut().pin, - polarity: PortInputPolarity::Low, + pin_port: self.pin.pin.pin_port(), + phantom: PhantomData, } } } -impl Deref for GpiotePin { - type Target = GpioPin>; - fn deref(&self) -> &Self::Target { - &self.pin - } +pub struct PortInputFuture<'a> { + pin_port: u8, + phantom: PhantomData<&'a mut AnyPin>, } -enum PortInputPolarity { - High, - Low, -} - -pub struct PortInputFuture<'a, T> { - pin: &'a GpioPin>, - polarity: PortInputPolarity, -} - -impl<'a, T> Drop for PortInputFuture<'a, T> { +impl<'a> Drop for PortInputFuture<'a> { fn drop(&mut self) { - pin_conf(&self.pin).modify(|_, w| w.sense().disabled()); - PORT_SIGNALS[pin_num(&self.pin)].reset(); + unsafe { AnyPin::steal(self.pin_port) } + .conf() + .modify(|_, w| w.sense().disabled()); } } -impl<'a, T> Future for PortInputFuture<'a, T> { +impl<'a> Future for PortInputFuture<'a> { 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) + let dis = unsafe { AnyPin::steal(self.pin_port) } + .conf() + .read() + .sense() + .is_disabled(); + + if dis { + return Poll::Ready(()); + } + + PORT_WAKERS[self.pin_port as usize].register(cx.waker()); + + Poll::Pending } }