diff options
| author | Dario Nieuwenhuis <[email protected]> | 2021-02-04 23:56:17 +0100 |
|---|---|---|
| committer | Dario Nieuwenhuis <[email protected]> | 2021-02-04 23:56:17 +0100 |
| commit | a7797a918d3a42f9244a853d2a47aced0ceb900a (patch) | |
| tree | 4ef025641efec64892caf82a710782bb88e84095 | |
| parent | 18797031533c11ace18160c5917d5131709397ce (diff) | |
nrf/gpiote: new api: switch to owned structs, implement WaitForHigh/WaitForLow.
| -rw-r--r-- | embassy-nrf-examples/src/bin/gpiote_channel.rs (renamed from embassy-nrf-examples/src/bin/gpiote.rs) | 32 | ||||
| -rw-r--r-- | embassy-nrf-examples/src/bin/gpiote_port.rs | 39 | ||||
| -rw-r--r-- | embassy-nrf/src/gpiote.rs | 580 |
3 files changed, 323 insertions, 328 deletions
diff --git a/embassy-nrf-examples/src/bin/gpiote.rs b/embassy-nrf-examples/src/bin/gpiote_channel.rs index f5315d6a6..5470c47cd 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; | |||
| 12 | 12 | ||
| 13 | use embassy::executor::{task, Executor}; | 13 | use embassy::executor::{task, Executor}; |
| 14 | use embassy::util::Forever; | 14 | use embassy::util::Forever; |
| 15 | use embassy_nrf::gpiote; | 15 | use embassy_nrf::gpiote::{Channels, Gpiote, InputChannel, InputChannelPolarity}; |
| 16 | use embassy_nrf::interrupt; | 16 | use embassy_nrf::interrupt; |
| 17 | 17 | ||
| 18 | #[task] | 18 | #[task] |
| @@ -20,46 +20,44 @@ async fn run() { | |||
| 20 | let p = unwrap!(embassy_nrf::pac::Peripherals::take()); | 20 | let p = unwrap!(embassy_nrf::pac::Peripherals::take()); |
| 21 | let port0 = gpio::p0::Parts::new(p.P0); | 21 | let port0 = gpio::p0::Parts::new(p.P0); |
| 22 | 22 | ||
| 23 | let g = gpiote::Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); | 23 | let (g, chs) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); |
| 24 | 24 | ||
| 25 | info!("Starting!"); | 25 | info!("Starting!"); |
| 26 | 26 | ||
| 27 | let pin1 = port0.p0_11.into_pullup_input().degrade(); | 27 | let pin1 = port0.p0_11.into_pullup_input().degrade(); |
| 28 | let button1 = async { | 28 | let pin2 = port0.p0_12.into_pullup_input().degrade(); |
| 29 | let ch = unwrap!(g.new_input_channel(pin1, gpiote::InputChannelPolarity::HiToLo)); | 29 | let pin3 = port0.p0_24.into_pullup_input().degrade(); |
| 30 | let pin4 = port0.p0_25.into_pullup_input().degrade(); | ||
| 31 | |||
| 32 | let ch1 = InputChannel::new(g, chs.ch0, pin1, InputChannelPolarity::HiToLo); | ||
| 33 | let ch2 = InputChannel::new(g, chs.ch1, pin2, InputChannelPolarity::LoToHi); | ||
| 34 | let ch3 = InputChannel::new(g, chs.ch2, pin3, InputChannelPolarity::Toggle); | ||
| 35 | let ch4 = InputChannel::new(g, chs.ch3, pin4, InputChannelPolarity::Toggle); | ||
| 30 | 36 | ||
| 37 | let button1 = async { | ||
| 31 | loop { | 38 | loop { |
| 32 | ch.wait().await; | 39 | ch1.wait().await; |
| 33 | info!("Button 1 pressed") | 40 | info!("Button 1 pressed") |
| 34 | } | 41 | } |
| 35 | }; | 42 | }; |
| 36 | 43 | ||
| 37 | let pin2 = port0.p0_12.into_pullup_input().degrade(); | ||
| 38 | let button2 = async { | 44 | let button2 = async { |
| 39 | let ch = unwrap!(g.new_input_channel(pin2, gpiote::InputChannelPolarity::LoToHi)); | ||
| 40 | |||
| 41 | loop { | 45 | loop { |
| 42 | ch.wait().await; | 46 | ch2.wait().await; |
| 43 | info!("Button 2 released") | 47 | info!("Button 2 released") |
| 44 | } | 48 | } |
| 45 | }; | 49 | }; |
| 46 | 50 | ||
| 47 | let pin3 = port0.p0_24.into_pullup_input().degrade(); | ||
| 48 | let button3 = async { | 51 | let button3 = async { |
| 49 | let ch = unwrap!(g.new_input_channel(pin3, gpiote::InputChannelPolarity::Toggle)); | ||
| 50 | |||
| 51 | loop { | 52 | loop { |
| 52 | ch.wait().await; | 53 | ch3.wait().await; |
| 53 | info!("Button 3 toggled") | 54 | info!("Button 3 toggled") |
| 54 | } | 55 | } |
| 55 | }; | 56 | }; |
| 56 | 57 | ||
| 57 | let pin4 = port0.p0_25.into_pullup_input().degrade(); | ||
| 58 | let button4 = async { | 58 | let button4 = async { |
| 59 | let ch = unwrap!(g.new_input_channel(pin4, gpiote::InputChannelPolarity::Toggle)); | ||
| 60 | |||
| 61 | loop { | 59 | loop { |
| 62 | ch.wait().await; | 60 | ch4.wait().await; |
| 63 | info!("Button 4 toggled") | 61 | info!("Button 4 toggled") |
| 64 | } | 62 | } |
| 65 | }; | 63 | }; |
diff --git a/embassy-nrf-examples/src/bin/gpiote_port.rs b/embassy-nrf-examples/src/bin/gpiote_port.rs index 833096f3a..9d999f951 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; | |||
| 7 | use example_common::*; | 7 | use example_common::*; |
| 8 | 8 | ||
| 9 | use core::mem; | 9 | use core::mem; |
| 10 | use core::pin::Pin; | ||
| 10 | use cortex_m_rt::entry; | 11 | use cortex_m_rt::entry; |
| 11 | use defmt::panic; | 12 | use defmt::panic; |
| 12 | use nrf52840_hal::gpio; | 13 | use nrf52840_hal::gpio; |
| 13 | 14 | ||
| 14 | use embassy::executor::{task, Executor}; | 15 | use embassy::executor::{task, Executor}; |
| 16 | use embassy::gpio::{WaitForHigh, WaitForLow}; | ||
| 15 | use embassy::util::Forever; | 17 | use embassy::util::Forever; |
| 16 | use embassy_nrf::gpiote::{Gpiote, PortInputPolarity}; | 18 | use embassy_nrf::gpiote::{Gpiote, GpiotePin}; |
| 17 | use embassy_nrf::interrupt; | 19 | use embassy_nrf::interrupt; |
| 18 | 20 | ||
| 19 | async fn button(g: &Gpiote, n: usize, pin: gpio::Pin<gpio::Input<gpio::PullUp>>) { | 21 | async fn button(n: usize, mut pin: GpiotePin<gpio::PullUp>) { |
| 20 | loop { | 22 | loop { |
| 21 | g.wait_port_input(&pin, PortInputPolarity::Low).await; | 23 | Pin::new(&mut pin).wait_for_low().await; |
| 22 | info!("Button {:?} pressed!", n); | 24 | info!("Button {:?} pressed!", n); |
| 23 | g.wait_port_input(&pin, PortInputPolarity::High).await; | 25 | Pin::new(&mut pin).wait_for_high().await; |
| 24 | info!("Button {:?} released!", n); | 26 | info!("Button {:?} released!", n); |
| 25 | } | 27 | } |
| 26 | } | 28 | } |
| @@ -30,19 +32,24 @@ async fn run() { | |||
| 30 | let p = unwrap!(embassy_nrf::pac::Peripherals::take()); | 32 | let p = unwrap!(embassy_nrf::pac::Peripherals::take()); |
| 31 | let port0 = gpio::p0::Parts::new(p.P0); | 33 | let port0 = gpio::p0::Parts::new(p.P0); |
| 32 | 34 | ||
| 33 | let g = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); | 35 | let (g, _) = Gpiote::new(p.GPIOTE, interrupt::take!(GPIOTE)); |
| 34 | info!( | ||
| 35 | "sizeof Signal<()> = {:usize}", | ||
| 36 | mem::size_of::<embassy::util::Signal<()>>() | ||
| 37 | ); | ||
| 38 | info!("sizeof gpiote = {:usize}", mem::size_of::<Gpiote>()); | ||
| 39 | |||
| 40 | info!("Starting!"); | ||
| 41 | 36 | ||
| 42 | let button1 = button(&g, 1, port0.p0_11.into_pullup_input().degrade()); | 37 | let button1 = button( |
| 43 | let button2 = button(&g, 2, port0.p0_12.into_pullup_input().degrade()); | 38 | 1, |
| 44 | let button3 = button(&g, 3, port0.p0_24.into_pullup_input().degrade()); | 39 | GpiotePin::new(g, port0.p0_11.into_pullup_input().degrade()), |
| 45 | let button4 = button(&g, 4, port0.p0_25.into_pullup_input().degrade()); | 40 | ); |
| 41 | let button2 = button( | ||
| 42 | 2, | ||
| 43 | GpiotePin::new(g, port0.p0_12.into_pullup_input().degrade()), | ||
| 44 | ); | ||
| 45 | let button3 = button( | ||
| 46 | 3, | ||
| 47 | GpiotePin::new(g, port0.p0_24.into_pullup_input().degrade()), | ||
| 48 | ); | ||
| 49 | let button4 = button( | ||
| 50 | 4, | ||
| 51 | GpiotePin::new(g, port0.p0_25.into_pullup_input().degrade()), | ||
| 52 | ); | ||
| 46 | futures::join!(button1, button2, button3, button4); | 53 | futures::join!(button1, button2, button3, button4); |
| 47 | } | 54 | } |
| 48 | 55 | ||
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 65a584c78..89aab5bc6 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs | |||
| @@ -1,18 +1,20 @@ | |||
| 1 | use crate::fmt::{panic, *}; | ||
| 2 | use core::cell::Cell; | ||
| 3 | use core::future::Future; | 1 | use core::future::Future; |
| 2 | use core::mem::ManuallyDrop; | ||
| 3 | use core::ops::Deref; | ||
| 4 | use core::pin::Pin; | ||
| 4 | use core::ptr; | 5 | use core::ptr; |
| 5 | use core::task::{Context, Poll}; | 6 | use core::task::{Context, Poll}; |
| 7 | use embassy::gpio::{WaitForHigh, WaitForLow}; | ||
| 6 | use embassy::util::Signal; | 8 | use embassy::util::Signal; |
| 7 | 9 | ||
| 8 | use crate::hal::gpio::{Input, Level, Output, Pin, Port}; | 10 | use crate::fmt::{panic, *}; |
| 11 | use crate::hal::gpio::{Input, Level, Output, Pin as GpioPin, Port}; | ||
| 9 | use crate::interrupt; | 12 | use crate::interrupt; |
| 10 | use crate::interrupt::OwnedInterrupt; | 13 | use crate::interrupt::OwnedInterrupt; |
| 14 | use crate::pac; | ||
| 11 | use crate::pac::generic::Reg; | 15 | use crate::pac::generic::Reg; |
| 12 | use crate::pac::gpiote::_TASKS_OUT; | 16 | use crate::pac::gpiote::_TASKS_OUT; |
| 13 | #[cfg(any(feature = "52833", feature = "52840"))] | 17 | use crate::pac::{p0 as pac_gpio, GPIOTE}; |
| 14 | use crate::pac::P1; | ||
| 15 | use crate::pac::{p0 as gpio, GPIOTE, P0}; | ||
| 16 | 18 | ||
| 17 | #[cfg(not(feature = "51"))] | 19 | #[cfg(not(feature = "51"))] |
| 18 | use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET}; | 20 | use crate::pac::gpiote::{_TASKS_CLR, _TASKS_SET}; |
| @@ -24,20 +26,51 @@ pub const PIN_COUNT: usize = 48; | |||
| 24 | #[cfg(not(any(feature = "52833", feature = "52840")))] | 26 | #[cfg(not(any(feature = "52833", feature = "52840")))] |
| 25 | pub const PIN_COUNT: usize = 32; | 27 | pub const PIN_COUNT: usize = 32; |
| 26 | 28 | ||
| 27 | pub struct Gpiote { | 29 | pub trait ChannelID { |
| 28 | inner: GPIOTE, | 30 | fn number(&self) -> usize; |
| 29 | free_channels: Cell<u8>, // 0 = used, 1 = free. 8 bits for 8 channelself. | ||
| 30 | channel_signals: [Signal<()>; CHANNEL_COUNT], | ||
| 31 | port_signals: [Signal<()>; PIN_COUNT], | ||
| 32 | } | 31 | } |
| 33 | 32 | ||
| 34 | static mut INSTANCE: *const Gpiote = ptr::null_mut(); | 33 | macro_rules! impl_channel { |
| 34 | ($ChX:ident, $n:expr) => { | ||
| 35 | pub struct $ChX(()); | ||
| 36 | impl $ChX { | ||
| 37 | pub fn degrade(self) -> ChAny { | ||
| 38 | ChAny($n) | ||
| 39 | } | ||
| 40 | } | ||
| 35 | 41 | ||
| 36 | pub enum PortInputPolarity { | 42 | impl ChannelID for $ChX { |
| 37 | High, | 43 | fn number(&self) -> usize { |
| 38 | Low, | 44 | $n |
| 45 | } | ||
| 46 | } | ||
| 47 | }; | ||
| 39 | } | 48 | } |
| 40 | 49 | ||
| 50 | impl_channel!(Ch0, 0); | ||
| 51 | impl_channel!(Ch1, 1); | ||
| 52 | impl_channel!(Ch2, 2); | ||
| 53 | impl_channel!(Ch3, 3); | ||
| 54 | impl_channel!(Ch4, 4); | ||
| 55 | impl_channel!(Ch5, 5); | ||
| 56 | impl_channel!(Ch6, 6); | ||
| 57 | impl_channel!(Ch7, 7); | ||
| 58 | |||
| 59 | pub struct ChAny(u8); | ||
| 60 | |||
| 61 | impl ChannelID for ChAny { | ||
| 62 | fn number(&self) -> usize { | ||
| 63 | self.0 as usize | ||
| 64 | } | ||
| 65 | } | ||
| 66 | |||
| 67 | #[derive(Clone, Copy)] | ||
| 68 | pub struct Gpiote(()); | ||
| 69 | |||
| 70 | const NEW_SIGNAL: Signal<()> = Signal::new(); | ||
| 71 | static CHANNEL_SIGNALS: [Signal<()>; CHANNEL_COUNT] = [NEW_SIGNAL; CHANNEL_COUNT]; | ||
| 72 | static PORT_SIGNALS: [Signal<()>; PIN_COUNT] = [NEW_SIGNAL; PIN_COUNT]; | ||
| 73 | |||
| 41 | pub enum InputChannelPolarity { | 74 | pub enum InputChannelPolarity { |
| 42 | None, | 75 | None, |
| 43 | HiToLo, | 76 | HiToLo, |
| @@ -58,12 +91,23 @@ pub enum NewChannelError { | |||
| 58 | NoFreeChannels, | 91 | NoFreeChannels, |
| 59 | } | 92 | } |
| 60 | 93 | ||
| 94 | pub struct Channels { | ||
| 95 | pub ch0: Ch0, | ||
| 96 | pub ch1: Ch1, | ||
| 97 | pub ch2: Ch2, | ||
| 98 | pub ch3: Ch3, | ||
| 99 | pub ch4: Ch4, | ||
| 100 | pub ch5: Ch5, | ||
| 101 | pub ch6: Ch6, | ||
| 102 | pub ch7: Ch7, | ||
| 103 | } | ||
| 104 | |||
| 61 | impl Gpiote { | 105 | impl Gpiote { |
| 62 | pub fn new(gpiote: GPIOTE, irq: interrupt::GPIOTEInterrupt) -> Self { | 106 | pub fn new(gpiote: GPIOTE, irq: interrupt::GPIOTEInterrupt) -> (Self, Channels) { |
| 63 | #[cfg(any(feature = "52833", feature = "52840"))] | 107 | #[cfg(any(feature = "52833", feature = "52840"))] |
| 64 | let ports = unsafe { &[&*P0::ptr(), &*P1::ptr()] }; | 108 | let ports = unsafe { &[&*pac::P0::ptr(), &*pac::P1::ptr()] }; |
| 65 | #[cfg(not(any(feature = "52833", feature = "52840")))] | 109 | #[cfg(not(any(feature = "52833", feature = "52840")))] |
| 66 | let ports = unsafe { &[&*P0::ptr()] }; | 110 | let ports = unsafe { &[&*pac::P0::ptr()] }; |
| 67 | 111 | ||
| 68 | for &p in ports { | 112 | for &p in ports { |
| 69 | // Enable latched detection | 113 | // Enable latched detection |
| @@ -79,240 +123,38 @@ impl Gpiote { | |||
| 79 | irq.unpend(); | 123 | irq.unpend(); |
| 80 | irq.enable(); | 124 | irq.enable(); |
| 81 | 125 | ||
| 82 | Self { | 126 | ( |
| 83 | inner: gpiote, | 127 | Self(()), |
| 84 | free_channels: Cell::new(0xFF), // all 8 channels free | 128 | Channels { |
| 85 | channel_signals: [ | 129 | ch0: Ch0(()), |
| 86 | Signal::new(), | 130 | ch1: Ch1(()), |
| 87 | Signal::new(), | 131 | ch2: Ch2(()), |
| 88 | Signal::new(), | 132 | ch3: Ch3(()), |
| 89 | Signal::new(), | 133 | ch4: Ch4(()), |
| 90 | Signal::new(), | 134 | ch5: Ch5(()), |
| 91 | Signal::new(), | 135 | ch6: Ch6(()), |
| 92 | Signal::new(), | 136 | ch7: Ch7(()), |
| 93 | Signal::new(), | 137 | }, |
| 94 | ], | 138 | ) |
| 95 | // This is just horrible | ||
| 96 | #[cfg(any(feature = "52833", feature = "52840"))] | ||
| 97 | port_signals: [ | ||
| 98 | Signal::new(), | ||
| 99 | Signal::new(), | ||
| 100 | Signal::new(), | ||
| 101 | Signal::new(), | ||
| 102 | Signal::new(), | ||
| 103 | Signal::new(), | ||
| 104 | Signal::new(), | ||
| 105 | Signal::new(), | ||
| 106 | Signal::new(), | ||
| 107 | Signal::new(), | ||
| 108 | Signal::new(), | ||
| 109 | Signal::new(), | ||
| 110 | Signal::new(), | ||
| 111 | Signal::new(), | ||
| 112 | Signal::new(), | ||
| 113 | Signal::new(), | ||
| 114 | Signal::new(), | ||
| 115 | Signal::new(), | ||
| 116 | Signal::new(), | ||
| 117 | Signal::new(), | ||
| 118 | Signal::new(), | ||
| 119 | Signal::new(), | ||
| 120 | Signal::new(), | ||
| 121 | Signal::new(), | ||
| 122 | Signal::new(), | ||
| 123 | Signal::new(), | ||
| 124 | Signal::new(), | ||
| 125 | Signal::new(), | ||
| 126 | Signal::new(), | ||
| 127 | Signal::new(), | ||
| 128 | Signal::new(), | ||
| 129 | Signal::new(), | ||
| 130 | Signal::new(), | ||
| 131 | Signal::new(), | ||
| 132 | Signal::new(), | ||
| 133 | Signal::new(), | ||
| 134 | Signal::new(), | ||
| 135 | Signal::new(), | ||
| 136 | Signal::new(), | ||
| 137 | Signal::new(), | ||
| 138 | Signal::new(), | ||
| 139 | Signal::new(), | ||
| 140 | Signal::new(), | ||
| 141 | Signal::new(), | ||
| 142 | Signal::new(), | ||
| 143 | Signal::new(), | ||
| 144 | Signal::new(), | ||
| 145 | Signal::new(), | ||
| 146 | ], | ||
| 147 | #[cfg(not(any(feature = "52833", feature = "52840")))] | ||
| 148 | port_signals: [ | ||
| 149 | Signal::new(), | ||
| 150 | Signal::new(), | ||
| 151 | Signal::new(), | ||
| 152 | Signal::new(), | ||
| 153 | Signal::new(), | ||
| 154 | Signal::new(), | ||
| 155 | Signal::new(), | ||
| 156 | Signal::new(), | ||
| 157 | Signal::new(), | ||
| 158 | Signal::new(), | ||
| 159 | Signal::new(), | ||
| 160 | Signal::new(), | ||
| 161 | Signal::new(), | ||
| 162 | Signal::new(), | ||
| 163 | Signal::new(), | ||
| 164 | Signal::new(), | ||
| 165 | Signal::new(), | ||
| 166 | Signal::new(), | ||
| 167 | Signal::new(), | ||
| 168 | Signal::new(), | ||
| 169 | Signal::new(), | ||
| 170 | Signal::new(), | ||
| 171 | Signal::new(), | ||
| 172 | Signal::new(), | ||
| 173 | Signal::new(), | ||
| 174 | Signal::new(), | ||
| 175 | Signal::new(), | ||
| 176 | Signal::new(), | ||
| 177 | Signal::new(), | ||
| 178 | Signal::new(), | ||
| 179 | Signal::new(), | ||
| 180 | Signal::new(), | ||
| 181 | ], | ||
| 182 | } | ||
| 183 | } | ||
| 184 | |||
| 185 | fn allocate_channel(&self) -> Result<u8, NewChannelError> { | ||
| 186 | interrupt::free(|_| { | ||
| 187 | let chs = self.free_channels.get(); | ||
| 188 | let index = chs.trailing_zeros() as usize; | ||
| 189 | if index == 8 { | ||
| 190 | return Err(NewChannelError::NoFreeChannels); | ||
| 191 | } | ||
| 192 | self.free_channels.set(chs & !(1 << index)); | ||
| 193 | Ok(index as u8) | ||
| 194 | }) | ||
| 195 | } | ||
| 196 | |||
| 197 | fn free_channel(&self, index: u8) { | ||
| 198 | interrupt::free(|_| { | ||
| 199 | self.inner.config[index as usize].write(|w| w.mode().disabled()); | ||
| 200 | self.inner.intenclr.write(|w| unsafe { w.bits(1 << index) }); | ||
| 201 | |||
| 202 | self.free_channels | ||
| 203 | .set(self.free_channels.get() | 1 << index); | ||
| 204 | trace!("freed ch {:?}", index); | ||
| 205 | }) | ||
| 206 | } | ||
| 207 | |||
| 208 | pub fn wait_port_input<'a, T>( | ||
| 209 | &'a self, | ||
| 210 | pin: &'a Pin<Input<T>>, | ||
| 211 | polarity: PortInputPolarity, | ||
| 212 | ) -> PortInputFuture<'a, T> { | ||
| 213 | interrupt::free(|_| { | ||
| 214 | unsafe { INSTANCE = self }; | ||
| 215 | PortInputFuture { | ||
| 216 | gpiote: self, | ||
| 217 | pin, | ||
| 218 | polarity, | ||
| 219 | } | ||
| 220 | }) | ||
| 221 | } | ||
| 222 | |||
| 223 | pub fn new_input_channel<'a, T>( | ||
| 224 | &'a self, | ||
| 225 | pin: Pin<Input<T>>, | ||
| 226 | polarity: InputChannelPolarity, | ||
| 227 | ) -> Result<InputChannel<'a, T>, NewChannelError> { | ||
| 228 | interrupt::free(|_| { | ||
| 229 | unsafe { INSTANCE = self }; | ||
| 230 | let index = self.allocate_channel()?; | ||
| 231 | trace!("allocated in ch {:?}", index as u8); | ||
| 232 | |||
| 233 | self.inner.config[index as usize].write(|w| { | ||
| 234 | match polarity { | ||
| 235 | InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(), | ||
| 236 | InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(), | ||
| 237 | InputChannelPolarity::None => w.mode().event().polarity().none(), | ||
| 238 | InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(), | ||
| 239 | }; | ||
| 240 | #[cfg(any(feature = "52833", feature = "52840"))] | ||
| 241 | w.port().bit(match pin.port() { | ||
| 242 | Port::Port0 => false, | ||
| 243 | Port::Port1 => true, | ||
| 244 | }); | ||
| 245 | unsafe { w.psel().bits(pin.pin()) } | ||
| 246 | }); | ||
| 247 | |||
| 248 | // Enable interrupt | ||
| 249 | self.inner.intenset.write(|w| unsafe { w.bits(1 << index) }); | ||
| 250 | |||
| 251 | Ok(InputChannel { | ||
| 252 | gpiote: self, | ||
| 253 | index, | ||
| 254 | pin, | ||
| 255 | }) | ||
| 256 | }) | ||
| 257 | } | ||
| 258 | |||
| 259 | pub fn new_output_channel<'a, T>( | ||
| 260 | &'a self, | ||
| 261 | pin: Pin<Output<T>>, | ||
| 262 | level: Level, | ||
| 263 | polarity: OutputChannelPolarity, | ||
| 264 | ) -> Result<OutputChannel<'a>, NewChannelError> { | ||
| 265 | interrupt::free(|_| { | ||
| 266 | unsafe { INSTANCE = self }; | ||
| 267 | let index = self.allocate_channel()?; | ||
| 268 | trace!("allocated out ch {:?}", index); | ||
| 269 | |||
| 270 | self.inner.config[index as usize].write(|w| { | ||
| 271 | w.mode().task(); | ||
| 272 | match level { | ||
| 273 | Level::High => w.outinit().high(), | ||
| 274 | Level::Low => w.outinit().low(), | ||
| 275 | }; | ||
| 276 | match polarity { | ||
| 277 | OutputChannelPolarity::Set => w.polarity().lo_to_hi(), | ||
| 278 | OutputChannelPolarity::Clear => w.polarity().hi_to_lo(), | ||
| 279 | OutputChannelPolarity::Toggle => w.polarity().toggle(), | ||
| 280 | }; | ||
| 281 | #[cfg(any(feature = "52833", feature = "52840"))] | ||
| 282 | w.port().bit(match pin.port() { | ||
| 283 | Port::Port0 => false, | ||
| 284 | Port::Port1 => true, | ||
| 285 | }); | ||
| 286 | unsafe { w.psel().bits(pin.pin()) } | ||
| 287 | }); | ||
| 288 | |||
| 289 | // Enable interrupt | ||
| 290 | self.inner.intenset.write(|w| unsafe { w.bits(1 << index) }); | ||
| 291 | |||
| 292 | Ok(OutputChannel { | ||
| 293 | gpiote: self, | ||
| 294 | index, | ||
| 295 | }) | ||
| 296 | }) | ||
| 297 | } | 139 | } |
| 298 | 140 | ||
| 299 | unsafe fn on_irq(_ctx: *mut ()) { | 141 | unsafe fn on_irq(_ctx: *mut ()) { |
| 300 | let s = &(*INSTANCE); | 142 | let g = &*GPIOTE::ptr(); |
| 301 | 143 | ||
| 302 | for i in 0..8 { | 144 | for i in 0..8 { |
| 303 | if s.inner.events_in[i].read().bits() != 0 { | 145 | if g.events_in[i].read().bits() != 0 { |
| 304 | s.inner.events_in[i].write(|w| w); | 146 | g.events_in[i].write(|w| w); |
| 305 | s.channel_signals[i].signal(()); | 147 | CHANNEL_SIGNALS[i].signal(()); |
| 306 | } | 148 | } |
| 307 | } | 149 | } |
| 308 | 150 | ||
| 309 | if s.inner.events_port.read().bits() != 0 { | 151 | if g.events_port.read().bits() != 0 { |
| 310 | s.inner.events_port.write(|w| w); | 152 | g.events_port.write(|w| w); |
| 311 | 153 | ||
| 312 | #[cfg(any(feature = "52833", feature = "52840"))] | 154 | #[cfg(any(feature = "52833", feature = "52840"))] |
| 313 | let ports = &[&*P0::ptr(), &*P1::ptr()]; | 155 | let ports = &[&*pac::P0::ptr(), &*pac::P1::ptr()]; |
| 314 | #[cfg(not(any(feature = "52833", feature = "52840")))] | 156 | #[cfg(not(any(feature = "52833", feature = "52840")))] |
| 315 | let ports = &[&*P0::ptr()]; | 157 | let ports = &[&*pac::P0::ptr()]; |
| 316 | 158 | ||
| 317 | let mut work = true; | 159 | let mut work = true; |
| 318 | while work { | 160 | while work { |
| @@ -322,7 +164,7 @@ impl Gpiote { | |||
| 322 | work = true; | 164 | work = true; |
| 323 | p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); | 165 | p.pin_cnf[pin as usize].modify(|_, w| w.sense().disabled()); |
| 324 | p.latch.write(|w| w.bits(1 << pin)); | 166 | p.latch.write(|w| w.bits(1 << pin)); |
| 325 | s.port_signals[port * 32 + pin as usize].signal(()); | 167 | PORT_SIGNALS[port * 32 + pin as usize].signal(()); |
| 326 | } | 168 | } |
| 327 | } | 169 | } |
| 328 | } | 170 | } |
| @@ -330,32 +172,7 @@ impl Gpiote { | |||
| 330 | } | 172 | } |
| 331 | } | 173 | } |
| 332 | 174 | ||
| 333 | pub struct PortInputFuture<'a, T> { | 175 | fn pin_num<T>(pin: &GpioPin<T>) -> usize { |
| 334 | gpiote: &'a Gpiote, | ||
| 335 | pin: &'a Pin<Input<T>>, | ||
| 336 | polarity: PortInputPolarity, | ||
| 337 | } | ||
| 338 | |||
| 339 | impl<'a, T> Drop for PortInputFuture<'a, T> { | ||
| 340 | fn drop(&mut self) { | ||
| 341 | pin_conf(&self.pin).modify(|_, w| w.sense().disabled()); | ||
| 342 | self.gpiote.port_signals[pin_num(&self.pin)].reset(); | ||
| 343 | } | ||
| 344 | } | ||
| 345 | |||
| 346 | impl<'a, T> Future for PortInputFuture<'a, T> { | ||
| 347 | type Output = (); | ||
| 348 | |||
| 349 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 350 | pin_conf(&self.pin).modify(|_, w| match self.polarity { | ||
| 351 | PortInputPolarity::Low => w.sense().low(), | ||
| 352 | PortInputPolarity::High => w.sense().high(), | ||
| 353 | }); | ||
| 354 | self.gpiote.port_signals[pin_num(&self.pin)].poll_wait(cx) | ||
| 355 | } | ||
| 356 | } | ||
| 357 | |||
| 358 | fn pin_num<T>(pin: &Pin<T>) -> usize { | ||
| 359 | let port = match pin.port() { | 176 | let port = match pin.port() { |
| 360 | Port::Port0 => 0, | 177 | Port::Port0 => 0, |
| 361 | #[cfg(any(feature = "52833", feature = "52840"))] | 178 | #[cfg(any(feature = "52833", feature = "52840"))] |
| @@ -365,86 +182,189 @@ fn pin_num<T>(pin: &Pin<T>) -> usize { | |||
| 365 | port + pin.pin() as usize | 182 | port + pin.pin() as usize |
| 366 | } | 183 | } |
| 367 | 184 | ||
| 368 | fn pin_block<T>(pin: &Pin<T>) -> &gpio::RegisterBlock { | 185 | fn pin_block<T>(pin: &GpioPin<T>) -> &pac_gpio::RegisterBlock { |
| 369 | let ptr = match pin.port() { | 186 | let ptr = match pin.port() { |
| 370 | Port::Port0 => P0::ptr(), | 187 | Port::Port0 => pac::P0::ptr(), |
| 371 | #[cfg(any(feature = "52833", feature = "52840"))] | 188 | #[cfg(any(feature = "52833", feature = "52840"))] |
| 372 | Port::Port1 => P1::ptr(), | 189 | Port::Port1 => pac::P1::ptr(), |
| 373 | }; | 190 | }; |
| 374 | 191 | ||
| 375 | unsafe { &*ptr } | 192 | unsafe { &*ptr } |
| 376 | } | 193 | } |
| 377 | 194 | ||
| 378 | fn pin_conf<T>(pin: &Pin<T>) -> &gpio::PIN_CNF { | 195 | fn pin_conf<T>(pin: &GpioPin<T>) -> &pac_gpio::PIN_CNF { |
| 379 | &pin_block(pin).pin_cnf[pin.pin() as usize] | 196 | &pin_block(pin).pin_cnf[pin.pin() as usize] |
| 380 | } | 197 | } |
| 381 | 198 | ||
| 382 | pub struct InputChannel<'a, T> { | 199 | pub struct InputChannel<C: ChannelID, T> { |
| 383 | gpiote: &'a Gpiote, | 200 | ch: C, |
| 384 | pin: Pin<Input<T>>, | 201 | pin: GpioPin<Input<T>>, |
| 385 | index: u8, | ||
| 386 | } | 202 | } |
| 387 | 203 | ||
| 388 | impl<'a, T> Drop for InputChannel<'a, T> { | 204 | impl<C: ChannelID, T> Drop for InputChannel<C, T> { |
| 389 | fn drop(&mut self) { | 205 | fn drop(&mut self) { |
| 390 | self.gpiote.free_channel(self.index); | 206 | let g = unsafe { &*GPIOTE::ptr() }; |
| 207 | let index = self.ch.number(); | ||
| 208 | g.config[index].write(|w| w.mode().disabled()); | ||
| 209 | g.intenclr.write(|w| unsafe { w.bits(1 << index) }); | ||
| 391 | } | 210 | } |
| 392 | } | 211 | } |
| 393 | 212 | ||
| 394 | impl<'a, T> InputChannel<'a, T> { | 213 | impl<C: ChannelID, T> InputChannel<C, T> { |
| 214 | pub fn new( | ||
| 215 | _gpiote: Gpiote, | ||
| 216 | ch: C, | ||
| 217 | pin: GpioPin<Input<T>>, | ||
| 218 | polarity: InputChannelPolarity, | ||
| 219 | ) -> Self { | ||
| 220 | let g = unsafe { &*GPIOTE::ptr() }; | ||
| 221 | let index = ch.number(); | ||
| 222 | |||
| 223 | g.config[index].write(|w| { | ||
| 224 | match polarity { | ||
| 225 | InputChannelPolarity::HiToLo => w.mode().event().polarity().hi_to_lo(), | ||
| 226 | InputChannelPolarity::LoToHi => w.mode().event().polarity().lo_to_hi(), | ||
| 227 | InputChannelPolarity::None => w.mode().event().polarity().none(), | ||
| 228 | InputChannelPolarity::Toggle => w.mode().event().polarity().toggle(), | ||
| 229 | }; | ||
| 230 | #[cfg(any(feature = "52833", feature = "52840"))] | ||
| 231 | w.port().bit(match pin.port() { | ||
| 232 | Port::Port0 => false, | ||
| 233 | Port::Port1 => true, | ||
| 234 | }); | ||
| 235 | unsafe { w.psel().bits(pin.pin()) } | ||
| 236 | }); | ||
| 237 | |||
| 238 | CHANNEL_SIGNALS[index].reset(); | ||
| 239 | |||
| 240 | // Enable interrupt | ||
| 241 | g.intenset.write(|w| unsafe { w.bits(1 << index) }); | ||
| 242 | |||
| 243 | InputChannel { ch, pin } | ||
| 244 | } | ||
| 245 | |||
| 246 | pub fn free(self) -> (C, GpioPin<Input<T>>) { | ||
| 247 | let m = ManuallyDrop::new(self); | ||
| 248 | let ch = unsafe { ptr::read(&m.ch) }; | ||
| 249 | let pin = unsafe { ptr::read(&m.pin) }; | ||
| 250 | (ch, pin) | ||
| 251 | } | ||
| 252 | |||
| 395 | pub async fn wait(&self) { | 253 | pub async fn wait(&self) { |
| 396 | self.gpiote.channel_signals[self.index as usize] | 254 | let index = self.ch.number(); |
| 397 | .wait() | 255 | CHANNEL_SIGNALS[index].wait().await; |
| 398 | .await; | ||
| 399 | } | 256 | } |
| 400 | 257 | ||
| 401 | pub fn pin(&self) -> &Pin<Input<T>> { | 258 | pub fn pin(&self) -> &GpioPin<Input<T>> { |
| 402 | &self.pin | 259 | &self.pin |
| 403 | } | 260 | } |
| 404 | } | 261 | } |
| 405 | 262 | ||
| 406 | pub struct OutputChannel<'a> { | 263 | pub struct OutputChannel<C: ChannelID, T> { |
| 407 | gpiote: &'a Gpiote, | 264 | ch: C, |
| 408 | index: u8, | 265 | pin: GpioPin<Output<T>>, |
| 409 | } | 266 | } |
| 410 | 267 | ||
| 411 | impl<'a> Drop for OutputChannel<'a> { | 268 | impl<C: ChannelID, T> Drop for OutputChannel<C, T> { |
| 412 | fn drop(&mut self) { | 269 | fn drop(&mut self) { |
| 413 | self.gpiote.free_channel(self.index); | 270 | let g = unsafe { &*GPIOTE::ptr() }; |
| 271 | let index = self.ch.number(); | ||
| 272 | g.config[index].write(|w| w.mode().disabled()); | ||
| 273 | g.intenclr.write(|w| unsafe { w.bits(1 << index) }); | ||
| 414 | } | 274 | } |
| 415 | } | 275 | } |
| 416 | 276 | ||
| 417 | impl<'a> OutputChannel<'a> { | 277 | impl<C: ChannelID, T> OutputChannel<C, T> { |
| 278 | pub fn new( | ||
| 279 | _gpiote: Gpiote, | ||
| 280 | ch: C, | ||
| 281 | pin: GpioPin<Output<T>>, | ||
| 282 | level: Level, | ||
| 283 | polarity: OutputChannelPolarity, | ||
| 284 | ) -> Self { | ||
| 285 | let g = unsafe { &*GPIOTE::ptr() }; | ||
| 286 | let index = ch.number(); | ||
| 287 | |||
| 288 | g.config[index].write(|w| { | ||
| 289 | w.mode().task(); | ||
| 290 | match level { | ||
| 291 | Level::High => w.outinit().high(), | ||
| 292 | Level::Low => w.outinit().low(), | ||
| 293 | }; | ||
| 294 | match polarity { | ||
| 295 | OutputChannelPolarity::Set => w.polarity().lo_to_hi(), | ||
| 296 | OutputChannelPolarity::Clear => w.polarity().hi_to_lo(), | ||
| 297 | OutputChannelPolarity::Toggle => w.polarity().toggle(), | ||
| 298 | }; | ||
| 299 | #[cfg(any(feature = "52833", feature = "52840"))] | ||
| 300 | w.port().bit(match pin.port() { | ||
| 301 | Port::Port0 => false, | ||
| 302 | Port::Port1 => true, | ||
| 303 | }); | ||
| 304 | unsafe { w.psel().bits(pin.pin()) } | ||
| 305 | }); | ||
| 306 | |||
| 307 | // Enable interrupt | ||
| 308 | g.intenset.write(|w| unsafe { w.bits(1 << index) }); | ||
| 309 | |||
| 310 | OutputChannel { ch, pin } | ||
| 311 | } | ||
| 312 | |||
| 313 | pub fn free(self) -> (C, GpioPin<Output<T>>) { | ||
| 314 | let m = ManuallyDrop::new(self); | ||
| 315 | let ch = unsafe { ptr::read(&m.ch) }; | ||
| 316 | let pin = unsafe { ptr::read(&m.pin) }; | ||
| 317 | (ch, pin) | ||
| 318 | } | ||
| 319 | |||
| 418 | /// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle). | 320 | /// Triggers `task out` (as configured with task_out_polarity, defaults to Toggle). |
| 419 | pub fn out(&self) { | 321 | pub fn out(&self) { |
| 420 | self.gpiote.inner.tasks_out[self.index as usize].write(|w| unsafe { w.bits(1) }); | 322 | let g = unsafe { &*GPIOTE::ptr() }; |
| 323 | let index = self.ch.number(); | ||
| 324 | |||
| 325 | g.tasks_out[index].write(|w| unsafe { w.bits(1) }); | ||
| 421 | } | 326 | } |
| 422 | /// Triggers `task set` (set associated pin high). | 327 | /// Triggers `task set` (set associated pin high). |
| 423 | #[cfg(not(feature = "51"))] | 328 | #[cfg(not(feature = "51"))] |
| 424 | pub fn set(&self) { | 329 | pub fn set(&self) { |
| 425 | self.gpiote.inner.tasks_set[self.index as usize].write(|w| unsafe { w.bits(1) }); | 330 | let g = unsafe { &*GPIOTE::ptr() }; |
| 331 | let index = self.ch.number(); | ||
| 332 | |||
| 333 | g.tasks_set[index].write(|w| unsafe { w.bits(1) }); | ||
| 426 | } | 334 | } |
| 427 | /// Triggers `task clear` (set associated pin low). | 335 | /// Triggers `task clear` (set associated pin low). |
| 428 | #[cfg(not(feature = "51"))] | 336 | #[cfg(not(feature = "51"))] |
| 429 | pub fn clear(&self) { | 337 | pub fn clear(&self) { |
| 430 | self.gpiote.inner.tasks_clr[self.index as usize].write(|w| unsafe { w.bits(1) }); | 338 | let g = unsafe { &*GPIOTE::ptr() }; |
| 339 | let index = self.ch.number(); | ||
| 340 | |||
| 341 | g.tasks_clr[index].write(|w| unsafe { w.bits(1) }); | ||
| 431 | } | 342 | } |
| 432 | 343 | ||
| 433 | /// Returns reference to task_out endpoint for PPI. | 344 | /// Returns reference to task_out endpoint for PPI. |
| 434 | pub fn task_out(&self) -> &Reg<u32, _TASKS_OUT> { | 345 | pub fn task_out(&self) -> &Reg<u32, _TASKS_OUT> { |
| 435 | &self.gpiote.inner.tasks_out[self.index as usize] | 346 | let g = unsafe { &*GPIOTE::ptr() }; |
| 347 | let index = self.ch.number(); | ||
| 348 | |||
| 349 | &g.tasks_out[index] | ||
| 436 | } | 350 | } |
| 437 | 351 | ||
| 438 | /// Returns reference to task_clr endpoint for PPI. | 352 | /// Returns reference to task_clr endpoint for PPI. |
| 439 | #[cfg(not(feature = "51"))] | 353 | #[cfg(not(feature = "51"))] |
| 440 | pub fn task_clr(&self) -> &Reg<u32, _TASKS_CLR> { | 354 | pub fn task_clr(&self) -> &Reg<u32, _TASKS_CLR> { |
| 441 | &self.gpiote.inner.tasks_clr[self.index as usize] | 355 | let g = unsafe { &*GPIOTE::ptr() }; |
| 356 | let index = self.ch.number(); | ||
| 357 | |||
| 358 | &g.tasks_clr[index] | ||
| 442 | } | 359 | } |
| 443 | 360 | ||
| 444 | /// Returns reference to task_set endpoint for PPI. | 361 | /// Returns reference to task_set endpoint for PPI. |
| 445 | #[cfg(not(feature = "51"))] | 362 | #[cfg(not(feature = "51"))] |
| 446 | pub fn task_set(&self) -> &Reg<u32, _TASKS_SET> { | 363 | pub fn task_set(&self) -> &Reg<u32, _TASKS_SET> { |
| 447 | &self.gpiote.inner.tasks_set[self.index as usize] | 364 | let g = unsafe { &*GPIOTE::ptr() }; |
| 365 | let index = self.ch.number(); | ||
| 366 | |||
| 367 | &g.tasks_set[index] | ||
| 448 | } | 368 | } |
| 449 | } | 369 | } |
| 450 | 370 | ||
| @@ -463,3 +383,73 @@ impl Iterator for BitIter { | |||
| 463 | } | 383 | } |
| 464 | } | 384 | } |
| 465 | } | 385 | } |
| 386 | |||
| 387 | pub struct GpiotePin<T> { | ||
| 388 | pin: GpioPin<Input<T>>, | ||
| 389 | } | ||
| 390 | |||
| 391 | impl<T> Unpin for GpiotePin<T> {} | ||
| 392 | |||
| 393 | impl<T> GpiotePin<T> { | ||
| 394 | pub fn new(_gpiote: Gpiote, pin: GpioPin<Input<T>>) -> Self { | ||
| 395 | Self { pin } | ||
| 396 | } | ||
| 397 | } | ||
| 398 | |||
| 399 | impl<T: 'static> WaitForHigh for GpiotePin<T> { | ||
| 400 | type Future<'a> = PortInputFuture<'a, T>; | ||
| 401 | |||
| 402 | fn wait_for_high<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> { | ||
| 403 | PortInputFuture { | ||
| 404 | pin: &self.get_mut().pin, | ||
| 405 | polarity: PortInputPolarity::High, | ||
| 406 | } | ||
| 407 | } | ||
| 408 | } | ||
| 409 | |||
| 410 | impl<T: 'static> WaitForLow for GpiotePin<T> { | ||
| 411 | type Future<'a> = PortInputFuture<'a, T>; | ||
| 412 | |||
| 413 | fn wait_for_low<'a>(self: Pin<&'a mut Self>) -> Self::Future<'a> { | ||
| 414 | PortInputFuture { | ||
| 415 | pin: &self.get_mut().pin, | ||
| 416 | polarity: PortInputPolarity::Low, | ||
| 417 | } | ||
| 418 | } | ||
| 419 | } | ||
| 420 | |||
| 421 | impl<T> Deref for GpiotePin<T> { | ||
| 422 | type Target = GpioPin<Input<T>>; | ||
| 423 | fn deref(&self) -> &Self::Target { | ||
| 424 | &self.pin | ||
| 425 | } | ||
| 426 | } | ||
| 427 | |||
| 428 | enum PortInputPolarity { | ||
| 429 | High, | ||
| 430 | Low, | ||
| 431 | } | ||
| 432 | |||
| 433 | pub struct PortInputFuture<'a, T> { | ||
| 434 | pin: &'a GpioPin<Input<T>>, | ||
| 435 | polarity: PortInputPolarity, | ||
| 436 | } | ||
| 437 | |||
| 438 | impl<'a, T> Drop for PortInputFuture<'a, T> { | ||
| 439 | fn drop(&mut self) { | ||
| 440 | pin_conf(&self.pin).modify(|_, w| w.sense().disabled()); | ||
| 441 | PORT_SIGNALS[pin_num(&self.pin)].reset(); | ||
| 442 | } | ||
| 443 | } | ||
| 444 | |||
| 445 | impl<'a, T> Future for PortInputFuture<'a, T> { | ||
| 446 | type Output = (); | ||
| 447 | |||
| 448 | fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll<Self::Output> { | ||
| 449 | pin_conf(&self.pin).modify(|_, w| match self.polarity { | ||
| 450 | PortInputPolarity::Low => w.sense().low(), | ||
| 451 | PortInputPolarity::High => w.sense().high(), | ||
| 452 | }); | ||
| 453 | PORT_SIGNALS[pin_num(&self.pin)].poll_wait(cx) | ||
| 454 | } | ||
| 455 | } | ||
