diff options
Diffstat (limited to 'embassy-nrf/src/gpiote.rs')
| -rw-r--r-- | embassy-nrf/src/gpiote.rs | 492 |
1 files changed, 400 insertions, 92 deletions
diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index 43e43f0bf..1f6000b13 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs | |||
| @@ -1,13 +1,14 @@ | |||
| 1 | //! GPIO task/event (GPIOTE) driver. | 1 | //! GPIO task/event (GPIOTE) driver. |
| 2 | #![macro_use] | ||
| 2 | 3 | ||
| 3 | use core::convert::Infallible; | 4 | use core::convert::Infallible; |
| 4 | use core::future::{poll_fn, Future}; | 5 | use core::future::{Future, poll_fn}; |
| 5 | use core::task::{Context, Poll}; | 6 | use core::task::{Context, Poll}; |
| 6 | 7 | ||
| 7 | use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; | 8 | use embassy_hal_internal::{Peri, PeripheralType, impl_peripheral}; |
| 8 | use embassy_sync::waitqueue::AtomicWaker; | 9 | use embassy_sync::waitqueue::AtomicWaker; |
| 9 | 10 | ||
| 10 | use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin, SealedPin as _}; | 11 | use crate::gpio::{AnyPin, Flex, Input, Level, Output, OutputDrive, Pin as GpioPin, Pull, SealedPin as _}; |
| 11 | use crate::interrupt::InterruptExt; | 12 | use crate::interrupt::InterruptExt; |
| 12 | #[cfg(not(feature = "_nrf51"))] | 13 | #[cfg(not(feature = "_nrf51"))] |
| 13 | use crate::pac::gpio::vals::Detectmode; | 14 | use crate::pac::gpio::vals::Detectmode; |
| @@ -19,13 +20,32 @@ use crate::{interrupt, pac, peripherals}; | |||
| 19 | #[cfg(feature = "_nrf51")] | 20 | #[cfg(feature = "_nrf51")] |
| 20 | /// Amount of GPIOTE channels in the chip. | 21 | /// Amount of GPIOTE channels in the chip. |
| 21 | const CHANNEL_COUNT: usize = 4; | 22 | const CHANNEL_COUNT: usize = 4; |
| 22 | #[cfg(not(feature = "_nrf51"))] | 23 | #[cfg(not(any(feature = "_nrf51", feature = "_nrf54l")))] |
| 23 | /// Amount of GPIOTE channels in the chip. | 24 | /// Amount of GPIOTE channels in the chip. |
| 24 | const CHANNEL_COUNT: usize = 8; | 25 | const CHANNEL_COUNT: usize = 8; |
| 25 | 26 | #[cfg(any(feature = "_nrf54l"))] | |
| 26 | #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] | 27 | /// Amount of GPIOTE channels in the chip. |
| 28 | const CHANNEL_COUNT: usize = 12; | ||
| 29 | /// Max channels per port | ||
| 30 | const CHANNELS_PER_PORT: usize = 8; | ||
| 31 | |||
| 32 | #[cfg(any( | ||
| 33 | feature = "nrf52833", | ||
| 34 | feature = "nrf52840", | ||
| 35 | feature = "_nrf5340", | ||
| 36 | feature = "_nrf54l15", | ||
| 37 | feature = "_nrf54l10", | ||
| 38 | feature = "_nrf54l05" | ||
| 39 | ))] | ||
| 27 | const PIN_COUNT: usize = 48; | 40 | const PIN_COUNT: usize = 48; |
| 28 | #[cfg(not(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))] | 41 | #[cfg(feature = "_nrf54lm20")] |
| 42 | const PIN_COUNT: usize = 66; | ||
| 43 | #[cfg(not(any( | ||
| 44 | feature = "nrf52833", | ||
| 45 | feature = "nrf52840", | ||
| 46 | feature = "_nrf5340", | ||
| 47 | feature = "_nrf54l", | ||
| 48 | )))] | ||
| 29 | const PIN_COUNT: usize = 32; | 49 | const PIN_COUNT: usize = 32; |
| 30 | 50 | ||
| 31 | #[allow(clippy::declare_interior_mutable_const)] | 51 | #[allow(clippy::declare_interior_mutable_const)] |
| @@ -54,18 +74,6 @@ pub enum OutputChannelPolarity { | |||
| 54 | Toggle, | 74 | Toggle, |
| 55 | } | 75 | } |
| 56 | 76 | ||
| 57 | fn regs() -> pac::gpiote::Gpiote { | ||
| 58 | cfg_if::cfg_if! { | ||
| 59 | if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s", feature="nrf9120-s"))] { | ||
| 60 | pac::GPIOTE0 | ||
| 61 | } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns", feature="nrf9120-ns"))] { | ||
| 62 | pac::GPIOTE1 | ||
| 63 | } else { | ||
| 64 | pac::GPIOTE | ||
| 65 | } | ||
| 66 | } | ||
| 67 | } | ||
| 68 | |||
| 69 | pub(crate) fn init(irq_prio: crate::interrupt::Priority) { | 77 | pub(crate) fn init(irq_prio: crate::interrupt::Priority) { |
| 70 | // no latched GPIO detect in nrf51. | 78 | // no latched GPIO detect in nrf51. |
| 71 | #[cfg(not(feature = "_nrf51"))] | 79 | #[cfg(not(feature = "_nrf51"))] |
| @@ -77,6 +85,9 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { | |||
| 77 | 85 | ||
| 78 | for &p in ports { | 86 | for &p in ports { |
| 79 | // Enable latched detection | 87 | // Enable latched detection |
| 88 | #[cfg(all(feature = "_s", not(feature = "_nrf54l")))] | ||
| 89 | p.detectmode_sec().write(|w| w.set_detectmode(Detectmode::LDETECT)); | ||
| 90 | #[cfg(any(not(feature = "_s"), all(feature = "_s", feature = "_nrf54l")))] | ||
| 80 | p.detectmode().write(|w| w.set_detectmode(Detectmode::LDETECT)); | 91 | p.detectmode().write(|w| w.set_detectmode(Detectmode::LDETECT)); |
| 81 | // Clear latch | 92 | // Clear latch |
| 82 | p.latch().write(|w| w.0 = 0xFFFFFFFF) | 93 | p.latch().write(|w| w.0 = 0xFFFFFFFF) |
| @@ -85,57 +96,130 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { | |||
| 85 | 96 | ||
| 86 | // Enable interrupts | 97 | // Enable interrupts |
| 87 | #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))] | 98 | #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))] |
| 88 | let irq = interrupt::GPIOTE0; | 99 | let irqs = &[(pac::GPIOTE0, interrupt::GPIOTE0)]; |
| 89 | #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))] | 100 | #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))] |
| 90 | let irq = interrupt::GPIOTE1; | 101 | let irqs = &[(pac::GPIOTE1, interrupt::GPIOTE1)]; |
| 91 | #[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))] | 102 | #[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))] |
| 92 | let irq = interrupt::GPIOTE; | 103 | let irqs = &[(pac::GPIOTE, interrupt::GPIOTE)]; |
| 104 | #[cfg(any(feature = "_nrf54l"))] | ||
| 105 | let irqs = &[ | ||
| 106 | #[cfg(feature = "_s")] | ||
| 107 | (pac::GPIOTE20, interrupt::GPIOTE20_0), | ||
| 108 | #[cfg(feature = "_s")] | ||
| 109 | (pac::GPIOTE30, interrupt::GPIOTE30_0), | ||
| 110 | #[cfg(feature = "_ns")] | ||
| 111 | (pac::GPIOTE20, interrupt::GPIOTE20_1), | ||
| 112 | #[cfg(feature = "_ns")] | ||
| 113 | (pac::GPIOTE30, interrupt::GPIOTE30_1), | ||
| 114 | ]; | ||
| 115 | |||
| 116 | for (inst, irq) in irqs { | ||
| 117 | irq.unpend(); | ||
| 118 | irq.set_priority(irq_prio); | ||
| 119 | unsafe { irq.enable() }; | ||
| 93 | 120 | ||
| 94 | irq.unpend(); | 121 | let g = inst; |
| 95 | irq.set_priority(irq_prio); | 122 | #[cfg(not(feature = "_nrf54l"))] |
| 96 | unsafe { irq.enable() }; | 123 | g.intenset(INTNUM).write(|w| w.set_port(true)); |
| 97 | 124 | ||
| 98 | let g = regs(); | 125 | #[cfg(all(feature = "_nrf54l", feature = "_ns"))] |
| 99 | g.intenset().write(|w| w.set_port(true)); | 126 | g.intenset(INTNUM).write(|w| w.set_port0nonsecure(true)); |
| 127 | |||
| 128 | #[cfg(all(feature = "_nrf54l", feature = "_s"))] | ||
| 129 | g.intenset(INTNUM).write(|w| w.set_port0secure(true)); | ||
| 130 | } | ||
| 100 | } | 131 | } |
| 101 | 132 | ||
| 133 | #[cfg(all(feature = "_nrf54l", feature = "_ns"))] | ||
| 134 | const INTNUM: usize = 1; | ||
| 135 | |||
| 136 | #[cfg(any(not(feature = "_nrf54l"), feature = "_s"))] | ||
| 137 | const INTNUM: usize = 0; | ||
| 138 | |||
| 102 | #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))] | 139 | #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))] |
| 103 | #[cfg(feature = "rt")] | 140 | #[cfg(feature = "rt")] |
| 104 | #[interrupt] | 141 | #[interrupt] |
| 105 | fn GPIOTE0() { | 142 | fn GPIOTE0() { |
| 106 | unsafe { handle_gpiote_interrupt() }; | 143 | unsafe { handle_gpiote_interrupt(pac::GPIOTE0) }; |
| 107 | } | 144 | } |
| 108 | 145 | ||
| 109 | #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))] | 146 | #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))] |
| 110 | #[cfg(feature = "rt")] | 147 | #[cfg(feature = "rt")] |
| 111 | #[interrupt] | 148 | #[interrupt] |
| 112 | fn GPIOTE1() { | 149 | fn GPIOTE1() { |
| 113 | unsafe { handle_gpiote_interrupt() }; | 150 | unsafe { handle_gpiote_interrupt(pac::GPIOTE1) }; |
| 114 | } | 151 | } |
| 115 | 152 | ||
| 116 | #[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))] | 153 | #[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))] |
| 117 | #[cfg(feature = "rt")] | 154 | #[cfg(feature = "rt")] |
| 118 | #[interrupt] | 155 | #[interrupt] |
| 119 | fn GPIOTE() { | 156 | fn GPIOTE() { |
| 120 | unsafe { handle_gpiote_interrupt() }; | 157 | unsafe { handle_gpiote_interrupt(pac::GPIOTE) }; |
| 158 | } | ||
| 159 | |||
| 160 | #[cfg(all(feature = "_nrf54l", feature = "_s"))] | ||
| 161 | #[cfg(feature = "rt")] | ||
| 162 | #[interrupt] | ||
| 163 | fn GPIOTE20_0() { | ||
| 164 | unsafe { handle_gpiote_interrupt(pac::GPIOTE20) }; | ||
| 165 | } | ||
| 166 | |||
| 167 | #[cfg(all(feature = "_nrf54l", feature = "_s"))] | ||
| 168 | #[cfg(feature = "rt")] | ||
| 169 | #[interrupt] | ||
| 170 | fn GPIOTE30_0() { | ||
| 171 | unsafe { handle_gpiote_interrupt(pac::GPIOTE30) }; | ||
| 172 | } | ||
| 173 | |||
| 174 | #[cfg(all(feature = "_nrf54l", feature = "_ns"))] | ||
| 175 | #[cfg(feature = "rt")] | ||
| 176 | #[interrupt] | ||
| 177 | fn GPIOTE20_1() { | ||
| 178 | unsafe { handle_gpiote_interrupt(pac::GPIOTE20) }; | ||
| 121 | } | 179 | } |
| 122 | 180 | ||
| 123 | unsafe fn handle_gpiote_interrupt() { | 181 | #[cfg(all(feature = "_nrf54l", feature = "_ns"))] |
| 124 | let g = regs(); | 182 | #[cfg(feature = "rt")] |
| 183 | #[interrupt] | ||
| 184 | fn GPIOTE30_1() { | ||
| 185 | unsafe { handle_gpiote_interrupt(pac::GPIOTE30) }; | ||
| 186 | } | ||
| 125 | 187 | ||
| 126 | for i in 0..CHANNEL_COUNT { | 188 | unsafe fn handle_gpiote_interrupt(g: pac::gpiote::Gpiote) { |
| 189 | for c in 0..CHANNEL_COUNT { | ||
| 190 | let i = c % CHANNELS_PER_PORT; | ||
| 127 | if g.events_in(i).read() != 0 { | 191 | if g.events_in(i).read() != 0 { |
| 128 | g.intenclr().write(|w| w.0 = 1 << i); | 192 | g.intenclr(INTNUM).write(|w| w.0 = 1 << i); |
| 129 | CHANNEL_WAKERS[i].wake(); | 193 | CHANNEL_WAKERS[c].wake(); |
| 130 | } | 194 | } |
| 131 | } | 195 | } |
| 132 | 196 | ||
| 133 | if g.events_port().read() != 0 { | 197 | #[cfg(not(feature = "_nrf54l"))] |
| 134 | g.events_port().write_value(0); | 198 | let eport = g.events_port(0); |
| 135 | 199 | ||
| 136 | #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] | 200 | #[cfg(all(feature = "_nrf54l", feature = "_ns"))] |
| 201 | let eport = g.events_port(0).nonsecure(); | ||
| 202 | |||
| 203 | #[cfg(all(feature = "_nrf54l", feature = "_s"))] | ||
| 204 | let eport = g.events_port(0).secure(); | ||
| 205 | |||
| 206 | if eport.read() != 0 { | ||
| 207 | eport.write_value(0); | ||
| 208 | |||
| 209 | #[cfg(any( | ||
| 210 | feature = "nrf52833", | ||
| 211 | feature = "nrf52840", | ||
| 212 | feature = "_nrf5340", | ||
| 213 | feature = "_nrf54l" | ||
| 214 | ))] | ||
| 137 | let ports = &[pac::P0, pac::P1]; | 215 | let ports = &[pac::P0, pac::P1]; |
| 138 | #[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))] | 216 | #[cfg(not(any( |
| 217 | feature = "_nrf51", | ||
| 218 | feature = "nrf52833", | ||
| 219 | feature = "nrf52840", | ||
| 220 | feature = "_nrf5340", | ||
| 221 | feature = "_nrf54l" | ||
| 222 | )))] | ||
| 139 | let ports = &[pac::P0]; | 223 | let ports = &[pac::P0]; |
| 140 | #[cfg(feature = "_nrf51")] | 224 | #[cfg(feature = "_nrf51")] |
| 141 | let ports = &[pac::GPIO]; | 225 | let ports = &[pac::GPIO]; |
| @@ -204,19 +288,43 @@ impl InputChannel<'static> { | |||
| 204 | 288 | ||
| 205 | impl<'d> Drop for InputChannel<'d> { | 289 | impl<'d> Drop for InputChannel<'d> { |
| 206 | fn drop(&mut self) { | 290 | fn drop(&mut self) { |
| 207 | let g = regs(); | 291 | let g = self.ch.regs(); |
| 208 | let num = self.ch.number(); | 292 | let num = self.ch.number(); |
| 209 | g.config(num).write(|w| w.set_mode(Mode::DISABLED)); | 293 | g.config(num).write(|w| w.set_mode(Mode::DISABLED)); |
| 210 | g.intenclr().write(|w| w.0 = 1 << num); | 294 | g.intenclr(INTNUM).write(|w| w.0 = 1 << num); |
| 211 | } | 295 | } |
| 212 | } | 296 | } |
| 213 | 297 | ||
| 214 | impl<'d> InputChannel<'d> { | 298 | impl<'d> InputChannel<'d> { |
| 215 | /// Create a new GPIOTE input channel driver. | 299 | /// Create a new GPIOTE input channel driver. |
| 216 | pub fn new(ch: Peri<'d, impl Channel>, pin: Input<'d>, polarity: InputChannelPolarity) -> Self { | 300 | #[cfg(feature = "_nrf54l")] |
| 217 | let g = regs(); | 301 | pub fn new<C: Channel, T: GpiotePin<Instance = C::Instance>>( |
| 218 | let num = ch.number(); | 302 | ch: Peri<'d, C>, |
| 303 | pin: Peri<'d, T>, | ||
| 304 | pull: Pull, | ||
| 305 | polarity: InputChannelPolarity, | ||
| 306 | ) -> Self { | ||
| 307 | let pin = Input::new(pin, pull); | ||
| 308 | let ch = ch.into(); | ||
| 309 | Self::new_inner(ch, pin, polarity) | ||
| 310 | } | ||
| 219 | 311 | ||
| 312 | /// Create a new GPIOTE output channel driver. | ||
| 313 | #[cfg(not(feature = "_nrf54l"))] | ||
| 314 | pub fn new<C: Channel, T: GpioPin>( | ||
| 315 | ch: Peri<'d, C>, | ||
| 316 | pin: Peri<'d, T>, | ||
| 317 | pull: Pull, | ||
| 318 | polarity: InputChannelPolarity, | ||
| 319 | ) -> Self { | ||
| 320 | let pin = Input::new(pin, pull); | ||
| 321 | let ch = ch.into(); | ||
| 322 | Self::new_inner(ch, pin, polarity) | ||
| 323 | } | ||
| 324 | |||
| 325 | fn new_inner(ch: Peri<'d, AnyChannel>, pin: Input<'d>, polarity: InputChannelPolarity) -> Self { | ||
| 326 | let g = ch.regs(); | ||
| 327 | let num = ch.number(); | ||
| 220 | g.config(num).write(|w| { | 328 | g.config(num).write(|w| { |
| 221 | w.set_mode(Mode::EVENT); | 329 | w.set_mode(Mode::EVENT); |
| 222 | match polarity { | 330 | match polarity { |
| @@ -225,30 +333,94 @@ impl<'d> InputChannel<'d> { | |||
| 225 | InputChannelPolarity::None => w.set_polarity(Polarity::NONE), | 333 | InputChannelPolarity::None => w.set_polarity(Polarity::NONE), |
| 226 | InputChannelPolarity::Toggle => w.set_polarity(Polarity::TOGGLE), | 334 | InputChannelPolarity::Toggle => w.set_polarity(Polarity::TOGGLE), |
| 227 | }; | 335 | }; |
| 228 | #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] | 336 | #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340",))] |
| 229 | w.set_port(match pin.pin.pin.port() { | 337 | w.set_port(match pin.pin.pin.port() { |
| 230 | crate::gpio::Port::Port0 => false, | 338 | crate::gpio::Port::Port0 => false, |
| 231 | crate::gpio::Port::Port1 => true, | 339 | crate::gpio::Port::Port1 => true, |
| 232 | }); | 340 | }); |
| 341 | #[cfg(any(feature = "_nrf54l"))] | ||
| 342 | w.set_port(match pin.pin.pin.port() { | ||
| 343 | crate::gpio::Port::Port0 => 0, | ||
| 344 | crate::gpio::Port::Port1 => 1, | ||
| 345 | crate::gpio::Port::Port2 => 2, | ||
| 346 | }); | ||
| 233 | w.set_psel(pin.pin.pin.pin()); | 347 | w.set_psel(pin.pin.pin.pin()); |
| 234 | }); | 348 | }); |
| 235 | 349 | ||
| 236 | g.events_in(num).write_value(0); | 350 | g.events_in(num).write_value(0); |
| 237 | 351 | ||
| 238 | InputChannel { ch: ch.into(), pin } | 352 | InputChannel { ch, pin } |
| 239 | } | 353 | } |
| 240 | 354 | ||
| 241 | /// Asynchronously wait for an event in this channel. | 355 | /// Asynchronously wait for an event in this channel. |
| 242 | pub async fn wait(&self) { | 356 | /// |
| 243 | let g = regs(); | 357 | /// It is possible to call this function and await the returned future later. |
| 244 | let num = self.ch.number(); | 358 | /// If an even occurs in the mean time, the future will immediately report ready. |
| 359 | pub fn wait(&mut self) -> impl Future<Output = ()> { | ||
| 360 | // NOTE: This is `-> impl Future` and not an `async fn` on purpose. | ||
| 361 | // Otherwise, events will only be detected starting at the first poll of the returned future. | ||
| 362 | Self::wait_internal(&mut self.ch) | ||
| 363 | } | ||
| 364 | |||
| 365 | /// Asynchronously wait for the pin to become high. | ||
| 366 | /// | ||
| 367 | /// The channel must be configured with [`InputChannelPolarity::LoToHi`] or [`InputChannelPolarity::Toggle`]. | ||
| 368 | /// If the channel is not configured to detect rising edges, it is unspecified when the returned future completes. | ||
| 369 | /// | ||
| 370 | /// It is possible to call this function and await the returned future later. | ||
| 371 | /// If an even occurs in the mean time, the future will immediately report ready. | ||
| 372 | pub fn wait_for_high(&mut self) -> impl Future<Output = ()> { | ||
| 373 | // NOTE: This is `-> impl Future` and not an `async fn` on purpose. | ||
| 374 | // Otherwise, events will only be detected starting at the first poll of the returned future. | ||
| 375 | |||
| 376 | // Subscribe to the event before checking the pin level. | ||
| 377 | let wait = Self::wait_internal(&mut self.ch); | ||
| 378 | let pin = &self.pin; | ||
| 379 | async move { | ||
| 380 | if pin.is_high() { | ||
| 381 | return; | ||
| 382 | } | ||
| 383 | wait.await; | ||
| 384 | } | ||
| 385 | } | ||
| 386 | |||
| 387 | /// Asynchronously wait for the pin to become low. | ||
| 388 | /// | ||
| 389 | /// The channel must be configured with [`InputChannelPolarity::HiToLo`] or [`InputChannelPolarity::Toggle`]. | ||
| 390 | /// If the channel is not configured to detect falling edges, it is unspecified when the returned future completes. | ||
| 391 | /// | ||
| 392 | /// It is possible to call this function and await the returned future later. | ||
| 393 | /// If an even occurs in the mean time, the future will immediately report ready. | ||
| 394 | pub fn wait_for_low(&mut self) -> impl Future<Output = ()> { | ||
| 395 | // NOTE: This is `-> impl Future` and not an `async fn` on purpose. | ||
| 396 | // Otherwise, events will only be detected starting at the first poll of the returned future. | ||
| 397 | |||
| 398 | // Subscribe to the event before checking the pin level. | ||
| 399 | let wait = Self::wait_internal(&mut self.ch); | ||
| 400 | let pin = &self.pin; | ||
| 401 | async move { | ||
| 402 | if pin.is_low() { | ||
| 403 | return; | ||
| 404 | } | ||
| 405 | wait.await; | ||
| 406 | } | ||
| 407 | } | ||
| 408 | |||
| 409 | /// Internal implementation for `wait()` and friends. | ||
| 410 | fn wait_internal(channel: &mut Peri<'_, AnyChannel>) -> impl Future<Output = ()> { | ||
| 411 | // NOTE: This is `-> impl Future` and not an `async fn` on purpose. | ||
| 412 | // Otherwise, events will only be detected starting at the first poll of the returned future. | ||
| 413 | |||
| 414 | let g = channel.regs(); | ||
| 415 | let num = channel.number(); | ||
| 416 | let waker = channel.waker(); | ||
| 245 | 417 | ||
| 246 | // Enable interrupt | 418 | // Enable interrupt |
| 247 | g.events_in(num).write_value(0); | 419 | g.events_in(num).write_value(0); |
| 248 | g.intenset().write(|w| w.0 = 1 << num); | 420 | g.intenset(INTNUM).write(|w| w.0 = 1 << num); |
| 249 | 421 | ||
| 250 | poll_fn(|cx| { | 422 | poll_fn(move |cx| { |
| 251 | CHANNEL_WAKERS[num].register(cx.waker()); | 423 | CHANNEL_WAKERS[waker].register(cx.waker()); |
| 252 | 424 | ||
| 253 | if g.events_in(num).read() != 0 { | 425 | if g.events_in(num).read() != 0 { |
| 254 | Poll::Ready(()) | 426 | Poll::Ready(()) |
| @@ -256,12 +428,16 @@ impl<'d> InputChannel<'d> { | |||
| 256 | Poll::Pending | 428 | Poll::Pending |
| 257 | } | 429 | } |
| 258 | }) | 430 | }) |
| 259 | .await; | 431 | } |
| 432 | |||
| 433 | /// Get the associated input pin. | ||
| 434 | pub fn pin(&self) -> &Input<'_> { | ||
| 435 | &self.pin | ||
| 260 | } | 436 | } |
| 261 | 437 | ||
| 262 | /// Returns the IN event, for use with PPI. | 438 | /// Returns the IN event, for use with PPI. |
| 263 | pub fn event_in(&self) -> Event<'d> { | 439 | pub fn event_in(&self) -> Event<'d> { |
| 264 | let g = regs(); | 440 | let g = self.ch.regs(); |
| 265 | Event::from_reg(g.events_in(self.ch.number())) | 441 | Event::from_reg(g.events_in(self.ch.number())) |
| 266 | } | 442 | } |
| 267 | } | 443 | } |
| @@ -283,17 +459,44 @@ impl OutputChannel<'static> { | |||
| 283 | 459 | ||
| 284 | impl<'d> Drop for OutputChannel<'d> { | 460 | impl<'d> Drop for OutputChannel<'d> { |
| 285 | fn drop(&mut self) { | 461 | fn drop(&mut self) { |
| 286 | let g = regs(); | 462 | let g = self.ch.regs(); |
| 287 | let num = self.ch.number(); | 463 | let num = self.ch.number(); |
| 288 | g.config(num).write(|w| w.set_mode(Mode::DISABLED)); | 464 | g.config(num).write(|w| w.set_mode(Mode::DISABLED)); |
| 289 | g.intenclr().write(|w| w.0 = 1 << num); | 465 | g.intenclr(INTNUM).write(|w| w.0 = 1 << num); |
| 290 | } | 466 | } |
| 291 | } | 467 | } |
| 292 | 468 | ||
| 293 | impl<'d> OutputChannel<'d> { | 469 | impl<'d> OutputChannel<'d> { |
| 294 | /// Create a new GPIOTE output channel driver. | 470 | /// Create a new GPIOTE output channel driver. |
| 295 | pub fn new(ch: Peri<'d, impl Channel>, pin: Output<'d>, polarity: OutputChannelPolarity) -> Self { | 471 | #[cfg(feature = "_nrf54l")] |
| 296 | let g = regs(); | 472 | pub fn new<C: Channel, T: GpiotePin<Instance = C::Instance>>( |
| 473 | ch: Peri<'d, C>, | ||
| 474 | pin: Peri<'d, T>, | ||
| 475 | initial_output: Level, | ||
| 476 | drive: OutputDrive, | ||
| 477 | polarity: OutputChannelPolarity, | ||
| 478 | ) -> Self { | ||
| 479 | let pin = Output::new(pin, initial_output, drive); | ||
| 480 | let ch = ch.into(); | ||
| 481 | Self::new_inner(ch, pin, polarity) | ||
| 482 | } | ||
| 483 | |||
| 484 | /// Create a new GPIOTE output channel driver. | ||
| 485 | #[cfg(not(feature = "_nrf54l"))] | ||
| 486 | pub fn new<C: Channel, T: GpioPin>( | ||
| 487 | ch: Peri<'d, C>, | ||
| 488 | pin: Peri<'d, T>, | ||
| 489 | initial_output: Level, | ||
| 490 | drive: OutputDrive, | ||
| 491 | polarity: OutputChannelPolarity, | ||
| 492 | ) -> Self { | ||
| 493 | let pin = Output::new(pin, initial_output, drive); | ||
| 494 | let ch = ch.into(); | ||
| 495 | Self::new_inner(ch, pin, polarity) | ||
| 496 | } | ||
| 497 | |||
| 498 | fn new_inner(ch: Peri<'d, AnyChannel>, pin: Output<'d>, polarity: OutputChannelPolarity) -> Self { | ||
| 499 | let g = ch.regs(); | ||
| 297 | let num = ch.number(); | 500 | let num = ch.number(); |
| 298 | 501 | ||
| 299 | g.config(num).write(|w| { | 502 | g.config(num).write(|w| { |
| @@ -312,52 +515,55 @@ impl<'d> OutputChannel<'d> { | |||
| 312 | crate::gpio::Port::Port0 => false, | 515 | crate::gpio::Port::Port0 => false, |
| 313 | crate::gpio::Port::Port1 => true, | 516 | crate::gpio::Port::Port1 => true, |
| 314 | }); | 517 | }); |
| 518 | #[cfg(any(feature = "_nrf54l"))] | ||
| 519 | w.set_port(match pin.pin.pin.port() { | ||
| 520 | crate::gpio::Port::Port0 => 0, | ||
| 521 | crate::gpio::Port::Port1 => 1, | ||
| 522 | crate::gpio::Port::Port2 => 2, | ||
| 523 | }); | ||
| 315 | w.set_psel(pin.pin.pin.pin()); | 524 | w.set_psel(pin.pin.pin.pin()); |
| 316 | }); | 525 | }); |
| 317 | 526 | ||
| 318 | OutputChannel { | 527 | OutputChannel { ch, _pin: pin } |
| 319 | ch: ch.into(), | ||
| 320 | _pin: pin, | ||
| 321 | } | ||
| 322 | } | 528 | } |
| 323 | 529 | ||
| 324 | /// Triggers the OUT task (does the action as configured with task_out_polarity, defaults to Toggle). | 530 | /// Triggers the OUT task (does the action as configured with task_out_polarity, defaults to Toggle). |
| 325 | pub fn out(&self) { | 531 | pub fn out(&self) { |
| 326 | let g = regs(); | 532 | let g = self.ch.regs(); |
| 327 | g.tasks_out(self.ch.number()).write_value(1); | 533 | g.tasks_out(self.ch.number()).write_value(1); |
| 328 | } | 534 | } |
| 329 | 535 | ||
| 330 | /// Triggers the SET task (set associated pin high). | 536 | /// Triggers the SET task (set associated pin high). |
| 331 | #[cfg(not(feature = "_nrf51"))] | 537 | #[cfg(not(feature = "_nrf51"))] |
| 332 | pub fn set(&self) { | 538 | pub fn set(&self) { |
| 333 | let g = regs(); | 539 | let g = self.ch.regs(); |
| 334 | g.tasks_set(self.ch.number()).write_value(1); | 540 | g.tasks_set(self.ch.number()).write_value(1); |
| 335 | } | 541 | } |
| 336 | 542 | ||
| 337 | /// Triggers the CLEAR task (set associated pin low). | 543 | /// Triggers the CLEAR task (set associated pin low). |
| 338 | #[cfg(not(feature = "_nrf51"))] | 544 | #[cfg(not(feature = "_nrf51"))] |
| 339 | pub fn clear(&self) { | 545 | pub fn clear(&self) { |
| 340 | let g = regs(); | 546 | let g = self.ch.regs(); |
| 341 | g.tasks_clr(self.ch.number()).write_value(1); | 547 | g.tasks_clr(self.ch.number()).write_value(1); |
| 342 | } | 548 | } |
| 343 | 549 | ||
| 344 | /// Returns the OUT task, for use with PPI. | 550 | /// Returns the OUT task, for use with PPI. |
| 345 | pub fn task_out(&self) -> Task<'d> { | 551 | pub fn task_out(&self) -> Task<'d> { |
| 346 | let g = regs(); | 552 | let g = self.ch.regs(); |
| 347 | Task::from_reg(g.tasks_out(self.ch.number())) | 553 | Task::from_reg(g.tasks_out(self.ch.number())) |
| 348 | } | 554 | } |
| 349 | 555 | ||
| 350 | /// Returns the CLR task, for use with PPI. | 556 | /// Returns the CLR task, for use with PPI. |
| 351 | #[cfg(not(feature = "_nrf51"))] | 557 | #[cfg(not(feature = "_nrf51"))] |
| 352 | pub fn task_clr(&self) -> Task<'d> { | 558 | pub fn task_clr(&self) -> Task<'d> { |
| 353 | let g = regs(); | 559 | let g = self.ch.regs(); |
| 354 | Task::from_reg(g.tasks_clr(self.ch.number())) | 560 | Task::from_reg(g.tasks_clr(self.ch.number())) |
| 355 | } | 561 | } |
| 356 | 562 | ||
| 357 | /// Returns the SET task, for use with PPI. | 563 | /// Returns the SET task, for use with PPI. |
| 358 | #[cfg(not(feature = "_nrf51"))] | 564 | #[cfg(not(feature = "_nrf51"))] |
| 359 | pub fn task_set(&self) -> Task<'d> { | 565 | pub fn task_set(&self) -> Task<'d> { |
| 360 | let g = regs(); | 566 | let g = self.ch.regs(); |
| 361 | Task::from_reg(g.tasks_set(self.ch.number())) | 567 | Task::from_reg(g.tasks_set(self.ch.number())) |
| 362 | } | 568 | } |
| 363 | } | 569 | } |
| @@ -459,31 +665,52 @@ impl<'d> Flex<'d> { | |||
| 459 | PortInputFuture::new(self.pin.reborrow()).await | 665 | PortInputFuture::new(self.pin.reborrow()).await |
| 460 | } | 666 | } |
| 461 | } | 667 | } |
| 462 | |||
| 463 | // ======================= | 668 | // ======================= |
| 669 | // | ||
| 464 | 670 | ||
| 465 | trait SealedChannel {} | 671 | trait SealedChannel { |
| 672 | fn waker(&self) -> usize; | ||
| 673 | fn regs(&self) -> pac::gpiote::Gpiote; | ||
| 674 | } | ||
| 466 | 675 | ||
| 467 | /// GPIOTE channel trait. | 676 | /// GPIOTE channel trait. |
| 468 | /// | 677 | /// |
| 469 | /// Implemented by all GPIOTE channels. | 678 | /// Implemented by all GPIOTE channels. |
| 470 | #[allow(private_bounds)] | 679 | #[allow(private_bounds)] |
| 471 | pub trait Channel: PeripheralType + SealedChannel + Into<AnyChannel> + Sized + 'static { | 680 | pub trait Channel: PeripheralType + SealedChannel + Into<AnyChannel> + Sized + 'static { |
| 681 | #[cfg(feature = "_nrf54l")] | ||
| 682 | /// GPIOTE instance this channel belongs to. | ||
| 683 | type Instance: GpioteInstance; | ||
| 472 | /// Get the channel number. | 684 | /// Get the channel number. |
| 473 | fn number(&self) -> usize; | 685 | fn number(&self) -> usize; |
| 474 | } | 686 | } |
| 475 | 687 | ||
| 476 | /// Type-erased channel. | 688 | struct AnyChannel { |
| 477 | /// | ||
| 478 | /// Obtained by calling `Channel::into()`. | ||
| 479 | /// | ||
| 480 | /// This allows using several channels in situations that might require | ||
| 481 | /// them to be the same type, like putting them in an array. | ||
| 482 | pub struct AnyChannel { | ||
| 483 | number: u8, | 689 | number: u8, |
| 690 | regs: pac::gpiote::Gpiote, | ||
| 691 | waker: u8, | ||
| 484 | } | 692 | } |
| 693 | |||
| 485 | impl_peripheral!(AnyChannel); | 694 | impl_peripheral!(AnyChannel); |
| 486 | impl SealedChannel for AnyChannel {} | 695 | |
| 696 | impl SealedChannel for AnyChannel { | ||
| 697 | fn waker(&self) -> usize { | ||
| 698 | self.waker as usize | ||
| 699 | } | ||
| 700 | |||
| 701 | fn regs(&self) -> pac::gpiote::Gpiote { | ||
| 702 | self.regs | ||
| 703 | } | ||
| 704 | } | ||
| 705 | |||
| 706 | #[cfg(feature = "_nrf54l")] | ||
| 707 | impl AnyChannel { | ||
| 708 | fn number(&self) -> usize { | ||
| 709 | self.number as usize | ||
| 710 | } | ||
| 711 | } | ||
| 712 | |||
| 713 | #[cfg(not(feature = "_nrf54l"))] | ||
| 487 | impl Channel for AnyChannel { | 714 | impl Channel for AnyChannel { |
| 488 | fn number(&self) -> usize { | 715 | fn number(&self) -> usize { |
| 489 | self.number as usize | 716 | self.number as usize |
| @@ -491,9 +718,19 @@ impl Channel for AnyChannel { | |||
| 491 | } | 718 | } |
| 492 | 719 | ||
| 493 | macro_rules! impl_channel { | 720 | macro_rules! impl_channel { |
| 494 | ($type:ident, $number:expr) => { | 721 | ($type:ident, $inst:ident, $number:expr, $waker:expr) => { |
| 495 | impl SealedChannel for peripherals::$type {} | 722 | impl SealedChannel for peripherals::$type { |
| 723 | fn waker(&self) -> usize { | ||
| 724 | $waker as usize | ||
| 725 | } | ||
| 726 | |||
| 727 | fn regs(&self) -> pac::gpiote::Gpiote { | ||
| 728 | pac::$inst | ||
| 729 | } | ||
| 730 | } | ||
| 496 | impl Channel for peripherals::$type { | 731 | impl Channel for peripherals::$type { |
| 732 | #[cfg(feature = "_nrf54l")] | ||
| 733 | type Instance = peripherals::$inst; | ||
| 497 | fn number(&self) -> usize { | 734 | fn number(&self) -> usize { |
| 498 | $number as usize | 735 | $number as usize |
| 499 | } | 736 | } |
| @@ -503,24 +740,95 @@ macro_rules! impl_channel { | |||
| 503 | fn from(val: peripherals::$type) -> Self { | 740 | fn from(val: peripherals::$type) -> Self { |
| 504 | Self { | 741 | Self { |
| 505 | number: val.number() as u8, | 742 | number: val.number() as u8, |
| 743 | waker: val.waker() as u8, | ||
| 744 | regs: val.regs(), | ||
| 506 | } | 745 | } |
| 507 | } | 746 | } |
| 508 | } | 747 | } |
| 509 | }; | 748 | }; |
| 510 | } | 749 | } |
| 511 | 750 | ||
| 512 | impl_channel!(GPIOTE_CH0, 0); | 751 | cfg_if::cfg_if! { |
| 513 | impl_channel!(GPIOTE_CH1, 1); | 752 | if #[cfg(feature = "_nrf54l")] { |
| 514 | impl_channel!(GPIOTE_CH2, 2); | 753 | trait SealedGpioteInstance {} |
| 515 | impl_channel!(GPIOTE_CH3, 3); | 754 | /// Represents a GPIOTE instance. |
| 516 | #[cfg(not(feature = "_nrf51"))] | 755 | #[allow(private_bounds)] |
| 517 | impl_channel!(GPIOTE_CH4, 4); | 756 | pub trait GpioteInstance: PeripheralType + SealedGpioteInstance + Sized + 'static {} |
| 518 | #[cfg(not(feature = "_nrf51"))] | 757 | |
| 519 | impl_channel!(GPIOTE_CH5, 5); | 758 | macro_rules! impl_gpiote { |
| 520 | #[cfg(not(feature = "_nrf51"))] | 759 | ($type:ident) => { |
| 521 | impl_channel!(GPIOTE_CH6, 6); | 760 | impl SealedGpioteInstance for peripherals::$type {} |
| 522 | #[cfg(not(feature = "_nrf51"))] | 761 | impl GpioteInstance for peripherals::$type {} |
| 523 | impl_channel!(GPIOTE_CH7, 7); | 762 | }; |
| 763 | } | ||
| 764 | |||
| 765 | pub(crate) trait SealedGpiotePin {} | ||
| 766 | |||
| 767 | /// Represents a GPIO pin that can be used with GPIOTE. | ||
| 768 | #[allow(private_bounds)] | ||
| 769 | pub trait GpiotePin: GpioPin + SealedGpiotePin { | ||
| 770 | /// The GPIOTE instance this pin belongs to. | ||
| 771 | type Instance: GpioteInstance; | ||
| 772 | } | ||
| 773 | |||
| 774 | macro_rules! impl_gpiote_pin { | ||
| 775 | ($type:ident, $inst:ident) => { | ||
| 776 | impl crate::gpiote::SealedGpiotePin for peripherals::$type {} | ||
| 777 | impl crate::gpiote::GpiotePin for peripherals::$type { | ||
| 778 | type Instance = peripherals::$inst; | ||
| 779 | } | ||
| 780 | }; | ||
| 781 | } | ||
| 782 | |||
| 783 | impl_gpiote!(GPIOTE20); | ||
| 784 | impl_gpiote!(GPIOTE30); | ||
| 785 | impl_channel!(GPIOTE20_CH0, GPIOTE20, 0, 0); | ||
| 786 | impl_channel!(GPIOTE20_CH1, GPIOTE20, 1, 1); | ||
| 787 | impl_channel!(GPIOTE20_CH2, GPIOTE20, 2, 2); | ||
| 788 | impl_channel!(GPIOTE20_CH3, GPIOTE20, 3, 3); | ||
| 789 | impl_channel!(GPIOTE20_CH4, GPIOTE20, 4, 4); | ||
| 790 | impl_channel!(GPIOTE20_CH5, GPIOTE20, 5, 5); | ||
| 791 | impl_channel!(GPIOTE20_CH6, GPIOTE20, 6, 6); | ||
| 792 | impl_channel!(GPIOTE20_CH7, GPIOTE20, 7, 7); | ||
| 793 | |||
| 794 | impl_channel!(GPIOTE30_CH0, GPIOTE30, 0, 8); | ||
| 795 | impl_channel!(GPIOTE30_CH1, GPIOTE30, 1, 9); | ||
| 796 | impl_channel!(GPIOTE30_CH2, GPIOTE30, 2, 10); | ||
| 797 | impl_channel!(GPIOTE30_CH3, GPIOTE30, 3, 11); | ||
| 798 | } else if #[cfg(feature = "_nrf51")] { | ||
| 799 | impl_channel!(GPIOTE_CH0, GPIOTE, 0, 0); | ||
| 800 | impl_channel!(GPIOTE_CH1, GPIOTE, 1, 1); | ||
| 801 | impl_channel!(GPIOTE_CH2, GPIOTE, 2, 2); | ||
| 802 | impl_channel!(GPIOTE_CH3, GPIOTE, 3, 3); | ||
| 803 | } else if #[cfg(all(feature = "_s", any(feature = "_nrf91", feature = "_nrf5340")))] { | ||
| 804 | impl_channel!(GPIOTE_CH0, GPIOTE0, 0, 0); | ||
| 805 | impl_channel!(GPIOTE_CH1, GPIOTE0, 1, 1); | ||
| 806 | impl_channel!(GPIOTE_CH2, GPIOTE0, 2, 2); | ||
| 807 | impl_channel!(GPIOTE_CH3, GPIOTE0, 3, 3); | ||
| 808 | impl_channel!(GPIOTE_CH4, GPIOTE0, 4, 4); | ||
| 809 | impl_channel!(GPIOTE_CH5, GPIOTE0, 5, 5); | ||
| 810 | impl_channel!(GPIOTE_CH6, GPIOTE0, 6, 6); | ||
| 811 | impl_channel!(GPIOTE_CH7, GPIOTE0, 7, 7); | ||
| 812 | } else if #[cfg(all(feature = "_ns", any(feature = "_nrf91", feature = "_nrf5340")))] { | ||
| 813 | impl_channel!(GPIOTE_CH0, GPIOTE1, 0, 0); | ||
| 814 | impl_channel!(GPIOTE_CH1, GPIOTE1, 1, 1); | ||
| 815 | impl_channel!(GPIOTE_CH2, GPIOTE1, 2, 2); | ||
| 816 | impl_channel!(GPIOTE_CH3, GPIOTE1, 3, 3); | ||
| 817 | impl_channel!(GPIOTE_CH4, GPIOTE1, 4, 4); | ||
| 818 | impl_channel!(GPIOTE_CH5, GPIOTE1, 5, 5); | ||
| 819 | impl_channel!(GPIOTE_CH6, GPIOTE1, 6, 6); | ||
| 820 | impl_channel!(GPIOTE_CH7, GPIOTE1, 7, 7); | ||
| 821 | } else { | ||
| 822 | impl_channel!(GPIOTE_CH0, GPIOTE, 0, 0); | ||
| 823 | impl_channel!(GPIOTE_CH1, GPIOTE, 1, 1); | ||
| 824 | impl_channel!(GPIOTE_CH2, GPIOTE, 2, 2); | ||
| 825 | impl_channel!(GPIOTE_CH3, GPIOTE, 3, 3); | ||
| 826 | impl_channel!(GPIOTE_CH4, GPIOTE, 4, 4); | ||
| 827 | impl_channel!(GPIOTE_CH5, GPIOTE, 5, 5); | ||
| 828 | impl_channel!(GPIOTE_CH6, GPIOTE, 6, 6); | ||
| 829 | impl_channel!(GPIOTE_CH7, GPIOTE, 7, 7); | ||
| 830 | } | ||
| 831 | } | ||
| 524 | 832 | ||
| 525 | // ==================== | 833 | // ==================== |
| 526 | 834 | ||
