diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-03-27 03:50:18 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-03-29 00:58:58 +0200 |
| commit | 2bd9323f28537da035692e48820ce8687e627c9e (patch) | |
| tree | 945934f7590590e2430a6c3bc61f191c82609d2d | |
| parent | a338841797e52e5a2032246ac63d29080014d16c (diff) | |
nrf/gpiote: update input channel to new API
| -rw-r--r-- | embassy-nrf-examples/src/bin/gpiote_channel.rs | 45 | ||||
| -rw-r--r-- | embassy-nrf/src/gpiote.rs | 160 |
2 files changed, 120 insertions, 85 deletions
diff --git a/embassy-nrf-examples/src/bin/gpiote_channel.rs b/embassy-nrf-examples/src/bin/gpiote_channel.rs index 599882a90..d223df7a3 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::*; | |||
| 11 | 11 | ||
| 12 | use cortex_m_rt::entry; | 12 | use cortex_m_rt::entry; |
| 13 | use defmt::panic; | 13 | use defmt::panic; |
| 14 | use nrf52840_hal::gpio; | ||
| 15 | 14 | ||
| 16 | use embassy::executor::{task, Executor}; | 15 | use embassy::executor::{task, Executor}; |
| 17 | use embassy::util::Forever; | 16 | use embassy::util::Forever; |
| 18 | use embassy_nrf::gpiote::{Gpiote, InputChannel, InputChannelPolarity}; | 17 | use embassy_nrf::gpio::{Input, Pull}; |
| 19 | use embassy_nrf::interrupt; | 18 | use embassy_nrf::gpiote::{self, InputChannel, InputChannelPolarity}; |
| 19 | use embassy_nrf::{interrupt, Peripherals}; | ||
| 20 | 20 | ||
| 21 | #[task] | 21 | #[task] |
| 22 | async fn run() { | 22 | async fn run() { |
| 23 | let p = unwrap!(embassy_nrf::pac::Peripherals::take()); | 23 | let p = Peripherals::take().unwrap(); |
| 24 | let port0 = gpio::p0::Parts::new(p.P0); | 24 | let g = gpiote::initialize(p.GPIOTE, interrupt::take!(GPIOTE)); |
| 25 | |||
| 26 | let (g, chs) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); | ||
| 27 | 25 | ||
| 28 | info!("Starting!"); | 26 | info!("Starting!"); |
| 29 | 27 | ||
| 30 | let pin1 = port0.p0_11.into_pullup_input().degrade(); | 28 | let ch1 = InputChannel::new( |
| 31 | let pin2 = port0.p0_12.into_pullup_input().degrade(); | 29 | g, |
| 32 | let pin3 = port0.p0_24.into_pullup_input().degrade(); | 30 | p.GPIOTE_CH0, |
| 33 | let pin4 = port0.p0_25.into_pullup_input().degrade(); | 31 | Input::new(p.P0_11, Pull::Up), |
| 34 | 32 | InputChannelPolarity::HiToLo, | |
| 35 | let ch1 = InputChannel::new(g, chs.ch0, pin1, InputChannelPolarity::HiToLo); | 33 | ); |
| 36 | let ch2 = InputChannel::new(g, chs.ch1, pin2, InputChannelPolarity::LoToHi); | 34 | let ch2 = InputChannel::new( |
| 37 | let ch3 = InputChannel::new(g, chs.ch2, pin3, InputChannelPolarity::Toggle); | 35 | g, |
| 38 | let ch4 = InputChannel::new(g, chs.ch3, pin4, InputChannelPolarity::Toggle); | 36 | p.GPIOTE_CH1, |
| 37 | Input::new(p.P0_12, Pull::Up), | ||
| 38 | InputChannelPolarity::LoToHi, | ||
| 39 | ); | ||
| 40 | let ch3 = InputChannel::new( | ||
| 41 | g, | ||
| 42 | p.GPIOTE_CH2, | ||
| 43 | Input::new(p.P0_24, Pull::Up), | ||
| 44 | InputChannelPolarity::Toggle, | ||
| 45 | ); | ||
| 46 | let ch4 = InputChannel::new( | ||
| 47 | g, | ||
| 48 | p.GPIOTE_CH3, | ||
| 49 | Input::new(p.P0_25, Pull::Up), | ||
| 50 | InputChannelPolarity::Toggle, | ||
| 51 | ); | ||
| 39 | 52 | ||
| 40 | let button1 = async { | 53 | let button1 = async { |
| 41 | loop { | 54 | loop { |
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 9ea008f01..95e49324d 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs | |||
| @@ -10,10 +10,12 @@ use core::task::{Context, Poll}; | |||
| 10 | use embassy::interrupt::InterruptExt; | 10 | use embassy::interrupt::InterruptExt; |
| 11 | use embassy::traits::gpio::{WaitForHigh, WaitForLow}; | 11 | use embassy::traits::gpio::{WaitForHigh, WaitForLow}; |
| 12 | use embassy::util::{AtomicWaker, PeripheralBorrow, Signal}; | 12 | use embassy::util::{AtomicWaker, PeripheralBorrow, Signal}; |
| 13 | use embassy_extras::impl_unborrow; | ||
| 13 | use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; | 14 | use embedded_hal::digital::v2::{InputPin, OutputPin, StatefulOutputPin}; |
| 15 | use futures::future::poll_fn; | ||
| 14 | 16 | ||
| 15 | use crate::gpio::sealed::Pin as _; | 17 | use crate::gpio::sealed::Pin as _; |
| 16 | use crate::gpio::{AnyPin, Input, Pin as GpioPin, Pull}; | 18 | use crate::gpio::{AnyPin, Input, Pin as GpioPin, Port, Pull}; |
| 17 | use crate::pac; | 19 | use crate::pac; |
| 18 | use crate::pac::generic::Reg; | 20 | use crate::pac::generic::Reg; |
| 19 | use crate::pac::gpiote::_TASKS_OUT; | 21 | use crate::pac::gpiote::_TASKS_OUT; |
| @@ -30,44 +32,6 @@ pub const PIN_COUNT: usize = 48; | |||
| 30 | #[cfg(not(any(feature = "52833", feature = "52840")))] | 32 | #[cfg(not(any(feature = "52833", feature = "52840")))] |
| 31 | pub const PIN_COUNT: usize = 32; | 33 | pub const PIN_COUNT: usize = 32; |
| 32 | 34 | ||
| 33 | pub trait ChannelID { | ||
| 34 | fn number(&self) -> usize; | ||
| 35 | } | ||
| 36 | |||
| 37 | macro_rules! impl_channel { | ||
| 38 | ($ChX:ident, $n:expr) => { | ||
| 39 | pub struct $ChX(()); | ||
| 40 | impl $ChX { | ||
| 41 | pub fn degrade(self) -> ChAny { | ||
| 42 | ChAny($n) | ||
| 43 | } | ||
| 44 | } | ||
| 45 | |||
| 46 | impl ChannelID for $ChX { | ||
| 47 | fn number(&self) -> usize { | ||
| 48 | $n | ||
| 49 | } | ||
| 50 | } | ||
| 51 | }; | ||
| 52 | } | ||
| 53 | |||
| 54 | impl_channel!(Ch0, 0); | ||
| 55 | impl_channel!(Ch1, 1); | ||
| 56 | impl_channel!(Ch2, 2); | ||
| 57 | impl_channel!(Ch3, 3); | ||
| 58 | impl_channel!(Ch4, 4); | ||
| 59 | impl_channel!(Ch5, 5); | ||
| 60 | impl_channel!(Ch6, 6); | ||
| 61 | impl_channel!(Ch7, 7); | ||
| 62 | |||
| 63 | pub struct ChAny(u8); | ||
| 64 | |||
| 65 | impl ChannelID for ChAny { | ||
| 66 | fn number(&self) -> usize { | ||
| 67 | self.0 as usize | ||
| 68 | } | ||
| 69 | } | ||
| 70 | |||
| 71 | const NEW_AWR: AtomicWaker = AtomicWaker::new(); | 35 | const NEW_AWR: AtomicWaker = AtomicWaker::new(); |
| 72 | static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AWR; CHANNEL_COUNT]; | 36 | static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [NEW_AWR; CHANNEL_COUNT]; |
| 73 | static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AWR; PIN_COUNT]; | 37 | static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [NEW_AWR; PIN_COUNT]; |
| @@ -123,7 +87,7 @@ unsafe fn on_irq(_ctx: *mut ()) { | |||
| 123 | 87 | ||
| 124 | for i in 0..CHANNEL_COUNT { | 88 | for i in 0..CHANNEL_COUNT { |
| 125 | if g.events_in[i].read().bits() != 0 { | 89 | if g.events_in[i].read().bits() != 0 { |
| 126 | g.events_in[i].write(|w| w); | 90 | g.intenclr.write(|w| unsafe { w.bits(1 << i) }); |
| 127 | CHANNEL_WAKERS[i].wake(); | 91 | CHANNEL_WAKERS[i].wake(); |
| 128 | } | 92 | } |
| 129 | } | 93 | } |
| @@ -163,32 +127,31 @@ impl Iterator for BitIter { | |||
| 163 | } | 127 | } |
| 164 | } | 128 | } |
| 165 | 129 | ||
| 166 | /* | 130 | pub struct InputChannel<'d, C: Channel, T: GpioPin> { |
| 167 | pub struct InputChannel<C: ChannelID, T> { | ||
| 168 | ch: C, | 131 | ch: C, |
| 169 | pin: GpioPin<Input<T>>, | 132 | pin: Input<'d, T>, |
| 170 | } | 133 | } |
| 171 | 134 | ||
| 172 | impl<C: ChannelID, T> Drop for InputChannel<C, T> { | 135 | impl<'d, C: Channel, T: GpioPin> Drop for InputChannel<'d, C, T> { |
| 173 | fn drop(&mut self) { | 136 | fn drop(&mut self) { |
| 174 | let g = unsafe { &*GPIOTE::ptr() }; | 137 | let g = unsafe { &*pac::GPIOTE::ptr() }; |
| 175 | let index = self.ch.number(); | 138 | let num = self.ch.number() as usize; |
| 176 | g.config[index].write(|w| w.mode().disabled()); | 139 | g.config[num].write(|w| w.mode().disabled()); |
| 177 | g.intenclr.write(|w| unsafe { w.bits(1 << index) }); | 140 | g.intenclr.write(|w| unsafe { w.bits(1 << num) }); |
| 178 | } | 141 | } |
| 179 | } | 142 | } |
| 180 | 143 | ||
| 181 | impl<C: ChannelID, T> InputChannel<C, T> { | 144 | impl<'d, C: Channel, T: GpioPin> InputChannel<'d, C, T> { |
| 182 | pub fn new( | 145 | pub fn new( |
| 183 | _init: Initialized, | 146 | _init: Initialized, |
| 184 | ch: C, | 147 | ch: C, |
| 185 | pin: GpioPin<Input<T>>, | 148 | pin: Input<'d, T>, |
| 186 | polarity: InputChannelPolarity, | 149 | polarity: InputChannelPolarity, |
| 187 | ) -> Self { | 150 | ) -> Self { |
| 188 | let g = unsafe { &*GPIOTE::ptr() }; | 151 | let g = unsafe { &*pac::GPIOTE::ptr() }; |
| 189 | let index = ch.number(); | 152 | let num = ch.number() as usize; |
| 190 | 153 | ||
| 191 | g.config[index].write(|w| { | 154 | g.config[num].write(|w| { |
| 192 | match polarity { | 155 | match polarity { |
| 193 | InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(), | 156 | InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(), |
| 194 | InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(), | 157 | InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(), |
| @@ -196,38 +159,52 @@ impl<C: ChannelID, T> InputChannel<C, T> { | |||
| 196 | InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(), | 159 | InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(), |
| 197 | }; | 160 | }; |
| 198 | #[cfg(any(feature = "52833", feature = "52840"))] | 161 | #[cfg(any(feature = "52833", feature = "52840"))] |
| 199 | w.port().bit(match pin.port() { | 162 | w.port().bit(match pin.pin.port() { |
| 200 | Port::Port0 => false, | 163 | Port::Port0 => false, |
| 201 | Port::Port1 => true, | 164 | Port::Port1 => true, |
| 202 | }); | 165 | }); |
| 203 | unsafe { w.psel().bits(pin.pin()) } | 166 | unsafe { w.psel().bits(pin.pin.pin()) } |
| 204 | }); | 167 | }); |
| 205 | 168 | ||
| 206 | CHANNEL_WAKERS[index].reset(); | 169 | g.events_in[num].reset(); |
| 207 | |||
| 208 | // Enable interrupt | ||
| 209 | g.intenset.write(|w| unsafe { w.bits(1 << index) }); | ||
| 210 | 170 | ||
| 211 | InputChannel { ch, pin } | 171 | InputChannel { ch, pin } |
| 212 | } | 172 | } |
| 213 | 173 | ||
| 214 | pub fn free(self) -> (C, GpioPin<Input<T>>) { | 174 | pub async fn wait(&self) { |
| 215 | let m = ManuallyDrop::new(self); | 175 | let g = unsafe { &*pac::GPIOTE::ptr() }; |
| 216 | let ch = unsafe { ptr::read(&m.ch) }; | 176 | let num = self.ch.number() as usize; |
| 217 | let pin = unsafe { ptr::read(&m.pin) }; | 177 | |
| 218 | (ch, pin) | 178 | // Enable interrupt |
| 179 | g.events_in[num].reset(); | ||
| 180 | g.intenset.write(|w| unsafe { w.bits(1 << num) }); | ||
| 181 | |||
| 182 | poll_fn(|cx| { | ||
| 183 | CHANNEL_WAKERS[num].register(cx.waker()); | ||
| 184 | |||
| 185 | if g.events_in[num].read().bits() != 0 { | ||
| 186 | Poll::Ready(()) | ||
| 187 | } else { | ||
| 188 | Poll::Pending | ||
| 189 | } | ||
| 190 | }) | ||
| 191 | .await; | ||
| 219 | } | 192 | } |
| 193 | } | ||
| 220 | 194 | ||
| 221 | pub async fn wait(&self) { | 195 | impl<'d, C: Channel, T: GpioPin> InputPin for InputChannel<'d, C, T> { |
| 222 | let index = self.ch.number(); | 196 | type Error = Infallible; |
| 223 | CHANNEL_WAKERS[index].wait().await; | 197 | |
| 198 | fn is_high(&self) -> Result<bool, Self::Error> { | ||
| 199 | self.pin.is_high() | ||
| 224 | } | 200 | } |
| 225 | 201 | ||
| 226 | pub fn pin(&self) -> &GpioPin<Input<T>> { | 202 | fn is_low(&self) -> Result<bool, Self::Error> { |
| 227 | &self.pin | 203 | self.pin.is_low() |
| 228 | } | 204 | } |
| 229 | } | 205 | } |
| 230 | 206 | ||
| 207 | /* | ||
| 231 | pub struct OutputChannel<C: ChannelID, T> { | 208 | pub struct OutputChannel<C: ChannelID, T> { |
| 232 | ch: C, | 209 | ch: C, |
| 233 | pin: GpioPin<Output<T>>, | 210 | pin: GpioPin<Output<T>>, |
| @@ -414,3 +391,48 @@ impl<'a> Future for PortInputFuture<'a> { | |||
| 414 | } | 391 | } |
| 415 | } | 392 | } |
| 416 | } | 393 | } |
| 394 | |||
| 395 | mod sealed { | ||
| 396 | pub trait Channel { | ||
| 397 | fn number(&self) -> u8; | ||
| 398 | } | ||
| 399 | } | ||
| 400 | |||
| 401 | pub trait Channel: sealed::Channel + Sized { | ||
| 402 | fn degrade(self) -> AnyChannel { | ||
| 403 | AnyChannel { | ||
| 404 | number: self.number(), | ||
| 405 | } | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | pub struct AnyChannel { | ||
| 410 | number: u8, | ||
| 411 | } | ||
| 412 | impl_unborrow!(AnyChannel); | ||
| 413 | impl Channel for AnyChannel {} | ||
| 414 | impl sealed::Channel for AnyChannel { | ||
| 415 | fn number(&self) -> u8 { | ||
| 416 | self.number | ||
| 417 | } | ||
| 418 | } | ||
| 419 | |||
| 420 | macro_rules! impl_channel { | ||
| 421 | ($type:ident, $number:expr) => { | ||
| 422 | impl sealed::Channel for peripherals::$type { | ||
| 423 | fn number(&self) -> u8 { | ||
| 424 | $number | ||
| 425 | } | ||
| 426 | } | ||
| 427 | impl Channel for peripherals::$type {} | ||
| 428 | }; | ||
| 429 | } | ||
| 430 | |||
| 431 | impl_channel!(GPIOTE_CH0, 0); | ||
| 432 | impl_channel!(GPIOTE_CH1, 1); | ||
| 433 | impl_channel!(GPIOTE_CH2, 2); | ||
| 434 | impl_channel!(GPIOTE_CH3, 3); | ||
| 435 | impl_channel!(GPIOTE_CH4, 4); | ||
| 436 | impl_channel!(GPIOTE_CH5, 5); | ||
| 437 | impl_channel!(GPIOTE_CH6, 6); | ||
| 438 | impl_channel!(GPIOTE_CH7, 7); | ||
