diff --git a/embassy-nrf/src/buffered_uarte.rs b/embassy-nrf/src/buffered_uarte.rs index 29e126903a..0d2002dca7 100644 --- a/embassy-nrf/src/buffered_uarte.rs +++ b/embassy-nrf/src/buffered_uarte.rs @@ -121,7 +121,7 @@ impl interrupt::typelevel::Handler for Interrupt // Enable endrx -> startrx PPI channel. // From this point on, if endrx happens, startrx is automatically fired. - ppi::regs().chenset().write(|w| w.0 = 1 << chn); + ppi::regs(()).chenset().write(|w| w.0 = 1 << chn); // It is possible that endrx happened BEFORE enabling the PPI. In this case // the PPI channel doesn't trigger, and we'd hang. We have to detect this @@ -145,7 +145,7 @@ impl interrupt::typelevel::Handler for Interrupt // Check if the PPI channel is still enabled. The PPI channel disables itself // when it fires, so if it's still enabled it hasn't fired. - let ppi_ch_enabled = ppi::regs().chen().read().ch(chn as _); + let ppi_ch_enabled = ppi::regs(()).chen().read().ch(chn as _); // if rxend happened, and the ppi channel hasn't fired yet, the rxend got missed. // this condition also naturally matches if `!started`, needed to kickstart the DMA. @@ -153,7 +153,7 @@ impl interrupt::typelevel::Handler for Interrupt //trace!("manually starting."); // disable the ppi ch, it's of no use anymore. - ppi::regs().chenclr().write(|w| w.set_ch(chn as _, true)); + ppi::regs(()).chenclr().write(|w| w.set_ch(chn as _, true)); // manually start r.tasks_startrx().write_value(1); diff --git a/embassy-nrf/src/chips/nrf54l15_app.rs b/embassy-nrf/src/chips/nrf54l15_app.rs index ff05bbec0c..a555f44eac 100644 --- a/embassy-nrf/src/chips/nrf54l15_app.rs +++ b/embassy-nrf/src/chips/nrf54l15_app.rs @@ -206,7 +206,22 @@ pub const EASY_DMA_SIZE: usize = (1 << 16) - 1; pub const FLASH_SIZE: usize = 1536 * 1024; embassy_hal_internal::peripherals! { - // GPIO port 0 + // GPIOTE + GPIOTE20_CH0, + GPIOTE20_CH1, + GPIOTE20_CH2, + GPIOTE20_CH3, + GPIOTE20_CH4, + GPIOTE20_CH5, + GPIOTE20_CH6, + GPIOTE20_CH7, + + GPIOTE30_CH0, + GPIOTE30_CH1, + GPIOTE30_CH2, + GPIOTE30_CH3, + + // GPIO port P0 P0_00, P0_01, P0_02, @@ -215,7 +230,7 @@ embassy_hal_internal::peripherals! { P0_05, P0_06, - // GPIO port 1 + // GPIO port P1 P1_00, P1_01, P1_02, @@ -234,8 +249,7 @@ embassy_hal_internal::peripherals! { P1_15, P1_16, - - // GPIO port 2 + // GPIO port P2 P2_00, P2_01, P2_02, @@ -248,6 +262,56 @@ embassy_hal_internal::peripherals! { P2_09, P2_10, + // PPI CHs + PPI00_CH0, + PPI00_CH1, + PPI00_CH2, + PPI00_CH3, + PPI00_CH4, + PPI00_CH5, + PPI00_CH6, + PPI00_CH7, + + // DPPI10 channels are dedicated to the radio. Do not implement. + + PPI20_CH0, + PPI20_CH1, + PPI20_CH2, + PPI20_CH3, + PPI20_CH4, + PPI20_CH5, + PPI20_CH6, + PPI20_CH7, + PPI20_CH8, + PPI20_CH9, + PPI20_CH10, + PPI20_CH11, + PPI20_CH12, + PPI20_CH13, + PPI20_CH14, + PPI20_CH15, + + PPI30_CH0, + PPI30_CH1, + PPI30_CH2, + PPI30_CH3, + + // PPI GROUPs + PPI00_GROUP0, + PPI00_GROUP1, + + // DPPI10 groups are dedicated to the radio. Do not implement. + + PPI20_GROUP0, + PPI20_GROUP1, + PPI20_GROUP2, + PPI20_GROUP3, + PPI20_GROUP4, + PPI20_GROUP5, + + PPI30_GROUP0, + PPI30_GROUP1, + #[cfg(feature = "_s")] // RRAMC RRAMC, @@ -302,6 +366,60 @@ impl_pin!(P2_08, 2, 8); impl_pin!(P2_09, 2, 9); impl_pin!(P2_10, 2, 10); +// DPPI00 channels +impl_ppi_channel!(PPI00_CH0, pac::DPPIC00, 0 => configurable); +impl_ppi_channel!(PPI00_CH1, pac::DPPIC00, 1 => configurable); +impl_ppi_channel!(PPI00_CH2, pac::DPPIC00, 2 => configurable); +impl_ppi_channel!(PPI00_CH3, pac::DPPIC00, 3 => configurable); +impl_ppi_channel!(PPI00_CH4, pac::DPPIC00, 4 => configurable); +impl_ppi_channel!(PPI00_CH5, pac::DPPIC00, 5 => configurable); +impl_ppi_channel!(PPI00_CH6, pac::DPPIC00, 6 => configurable); +impl_ppi_channel!(PPI00_CH7, pac::DPPIC00, 7 => configurable); + +// DPPI10 channels are dedicated to the radio. Do not implement. + +// DPPI20 channels +impl_ppi_channel!(PPI20_CH0, pac::DPPIC20, 0 => configurable); +impl_ppi_channel!(PPI20_CH1, pac::DPPIC20, 1 => configurable); +impl_ppi_channel!(PPI20_CH2, pac::DPPIC20, 2 => configurable); +impl_ppi_channel!(PPI20_CH3, pac::DPPIC20, 3 => configurable); +impl_ppi_channel!(PPI20_CH4, pac::DPPIC20, 4 => configurable); +impl_ppi_channel!(PPI20_CH5, pac::DPPIC20, 5 => configurable); +impl_ppi_channel!(PPI20_CH6, pac::DPPIC20, 6 => configurable); +impl_ppi_channel!(PPI20_CH7, pac::DPPIC20, 7 => configurable); +impl_ppi_channel!(PPI20_CH8, pac::DPPIC20, 8 => configurable); +impl_ppi_channel!(PPI20_CH9, pac::DPPIC20, 9 => configurable); +impl_ppi_channel!(PPI20_CH10, pac::DPPIC20, 10 => configurable); +impl_ppi_channel!(PPI20_CH11, pac::DPPIC20, 11 => configurable); +impl_ppi_channel!(PPI20_CH12, pac::DPPIC20, 12 => configurable); +impl_ppi_channel!(PPI20_CH13, pac::DPPIC20, 13 => configurable); +impl_ppi_channel!(PPI20_CH14, pac::DPPIC20, 14 => configurable); +impl_ppi_channel!(PPI20_CH15, pac::DPPIC20, 15 => configurable); + +// DPPI30 channels +impl_ppi_channel!(PPI30_CH0, pac::DPPIC30, 0 => configurable); +impl_ppi_channel!(PPI30_CH1, pac::DPPIC30, 1 => configurable); +impl_ppi_channel!(PPI30_CH2, pac::DPPIC30, 2 => configurable); +impl_ppi_channel!(PPI30_CH3, pac::DPPIC30, 3 => configurable); + +// DPPI00 groups +impl_ppi_group!(PPI00_GROUP0, pac::DPPIC00, 0); +impl_ppi_group!(PPI00_GROUP1, pac::DPPIC00, 1); + +// DPPI10 groups are dedicated to the radio. Do not implement. + +// DPPI20 groups +impl_ppi_group!(PPI20_GROUP0, pac::DPPIC20, 0); +impl_ppi_group!(PPI20_GROUP1, pac::DPPIC20, 1); +impl_ppi_group!(PPI20_GROUP2, pac::DPPIC20, 2); +impl_ppi_group!(PPI20_GROUP3, pac::DPPIC20, 3); +impl_ppi_group!(PPI20_GROUP4, pac::DPPIC20, 4); +impl_ppi_group!(PPI20_GROUP5, pac::DPPIC20, 5); + +// DPPI30 groups +impl_ppi_group!(PPI30_GROUP0, pac::DPPIC30, 0); +impl_ppi_group!(PPI30_GROUP1, pac::DPPIC30, 1); + #[cfg(feature = "_ns")] impl_wdt!(WDT, WDT31, WDT31, 0); #[cfg(feature = "_s")] diff --git a/embassy-nrf/src/gpiote.rs b/embassy-nrf/src/gpiote.rs index d169b49f91..d303bf0dd9 100644 --- a/embassy-nrf/src/gpiote.rs +++ b/embassy-nrf/src/gpiote.rs @@ -9,7 +9,7 @@ use embassy_sync::waitqueue::AtomicWaker; use crate::gpio::{AnyPin, Flex, Input, Output, Pin as GpioPin, SealedPin as _}; use crate::interrupt::InterruptExt; -#[cfg(not(feature = "_nrf51"))] +#[cfg(not(any(feature = "_nrf51", all(feature = "_nrf54l", feature = "_ns"))))] use crate::pac::gpio::vals::Detectmode; use crate::pac::gpio::vals::Sense; use crate::pac::gpiote::vals::{Mode, Outinit, Polarity}; @@ -19,19 +19,104 @@ use crate::{interrupt, pac, peripherals}; #[cfg(feature = "_nrf51")] /// Amount of GPIOTE channels in the chip. const CHANNEL_COUNT: usize = 4; -#[cfg(not(feature = "_nrf51"))] +#[cfg(feature = "_nrf54l")] +/// Amount of GPIOTE channels in the chip. +const CHANNEL_COUNT: usize = 8 /*P1: PERI PD*/ + 4 /*P0: LP PD*/; +#[cfg(not(any(feature = "_nrf51", feature = "_nrf54l")))] /// Amount of GPIOTE channels in the chip. const CHANNEL_COUNT: usize = 8; #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] const PIN_COUNT: usize = 48; -#[cfg(not(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))] +#[cfg(feature = "_nrf54l")] +const PIN_COUNT: usize = 16 /*P1: PERI PD*/ + 11 /*P0: LP PD*/; +#[cfg(not(any( + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340", + feature = "_nrf54l" +)))] const PIN_COUNT: usize = 32; #[allow(clippy::declare_interior_mutable_const)] static CHANNEL_WAKERS: [AtomicWaker; CHANNEL_COUNT] = [const { AtomicWaker::new() }; CHANNEL_COUNT]; static PORT_WAKERS: [AtomicWaker; PIN_COUNT] = [const { AtomicWaker::new() }; PIN_COUNT]; +#[cfg(feature = "_nrf54l")] +#[derive(Copy, Clone)] +/// GPIOTE instance +pub enum GpioteInstance { + /// GPIOTE_20 instance (GPIO port 1) + Gpiote20, + /// GPIOTE_30 instance (GPIO port 0) + Gpiote30, +} + +trait GpioteWakerResolver { + fn channel_waker(&self, ch: usize) -> &'static AtomicWaker; + fn port_waker(&self, pin: usize) -> &'static AtomicWaker; + fn channel_count(&self) -> usize; +} + +#[cfg(feature = "_nrf54l")] +type GpioteInstanceType = GpioteInstance; + +#[cfg(feature = "_nrf54l")] +impl From<&AnyPin> for GpioteInstance { + fn from(pin: &AnyPin) -> Self { + match pin.pin_port() { + 0..=31 => GpioteInstance::Gpiote30, + 32..=63 => GpioteInstance::Gpiote20, + _ => panic!("Invalid pin_port"), + } + } +} + +#[cfg(feature = "_nrf54l")] +impl GpioteWakerResolver for GpioteInstance { + fn channel_waker(&self, ch: usize) -> &'static AtomicWaker { + match self { + GpioteInstance::Gpiote20 => &CHANNEL_WAKERS[ch + 0], + GpioteInstance::Gpiote30 => &CHANNEL_WAKERS[ch + 8], + } + } + fn port_waker(&self, pin: usize) -> &'static AtomicWaker { + match self { + GpioteInstance::Gpiote20 => &PORT_WAKERS[pin + 0], + GpioteInstance::Gpiote30 => &PORT_WAKERS[pin + 16], + } + } + fn channel_count(&self) -> usize { + match self { + GpioteInstance::Gpiote20 => 8, + GpioteInstance::Gpiote30 => 4, + } + } +} + +#[cfg(not(feature = "_nrf54l"))] +type GpioteInstanceType = (); + +#[cfg(not(feature = "_nrf54l"))] +impl From<&AnyPin> for () { + fn from(_pin: &AnyPin) -> Self { + () + } +} + +#[cfg(not(feature = "_nrf54l"))] +impl GpioteWakerResolver for () { + fn channel_waker(&self, ch: usize) -> &'static AtomicWaker { + &CHANNEL_WAKERS[ch] + } + fn port_waker(&self, pin: usize) -> &'static AtomicWaker { + &PORT_WAKERS[pin] + } + fn channel_count(&self) -> usize { + CHANNEL_COUNT + } +} + /// Polarity for listening to events for GPIOTE input channels. pub enum InputChannelPolarity { /// Don't listen for any pin changes. @@ -54,12 +139,70 @@ pub enum OutputChannelPolarity { Toggle, } -fn regs() -> pac::gpiote::Gpiote { +// Helper to get the appropriate INTENSET register for the active GPIOTE peripheral. +fn intenset(g: &pac::gpiote::Gpiote) -> pac::common::Reg { + cfg_if::cfg_if! { + if #[cfg(all(feature = "_nrf54l", feature = "_s"))] { + g.intenset(0) + } else if #[cfg(all(feature = "_nrf54l", feature = "_ns"))] { + g.intenset(1) + } else { + g.intenset() + } + } +} + +// Helper to get the appropriate INTENCLR register for the active GPIOTE peripheral. +fn intenclr(g: &pac::gpiote::Gpiote) -> pac::common::Reg { + cfg_if::cfg_if! { + if #[cfg(all(feature = "_nrf54l", feature = "_s"))] { + g.intenclr(0) + } else if #[cfg(all(feature = "_nrf54l", feature = "_ns"))] { + g.intenclr(1) + } else { + g.intenclr() + } + } +} + +// Helper to get the appropriate port event register for the active GPIOTE peripheral. +fn events_port(g: &pac::gpiote::Gpiote) -> pac::common::Reg { + cfg_if::cfg_if! { + if #[cfg(all(feature = "_nrf54l", feature = "_s"))] { + g.events_port(0).secure() + } else if #[cfg(all(feature = "_nrf54l", feature = "_ns"))] { + g.events_port(0).nonsecure() + } else { + g.events_port() + } + } +} + +// Helper to enable or disabe port event interrupts for the active MCU +fn int_set_port(int: &mut pac::gpiote::regs::Int, val: bool) { + cfg_if::cfg_if! { + if #[cfg(all(feature = "_nrf54l", feature = "_s"))] { + int.set_port0secure(val); + } else if #[cfg(all(feature = "_nrf54l", feature = "_ns"))] { + int.set_port0nonsecure(val); + } else { + int.set_port(val); + } + } +} + +// Helper to get the GPIOTE peripheral’s register block for the active MCU and GPIOTE instance. +fn regs(_inst: GpioteInstanceType) -> pac::gpiote::Gpiote { cfg_if::cfg_if! { if #[cfg(any(feature="nrf5340-app-s", feature="nrf9160-s", feature="nrf9120-s"))] { pac::GPIOTE0 } else if #[cfg(any(feature="nrf5340-app-ns", feature="nrf9160-ns", feature="nrf9120-ns"))] { pac::GPIOTE1 + } else if #[cfg(feature="_nrf54l")] { + match _inst { + GpioteInstance::Gpiote20 => pac::GPIOTE20, + GpioteInstance::Gpiote30 => pac::GPIOTE30, + } } else { pac::GPIOTE } @@ -68,11 +211,23 @@ fn regs() -> pac::gpiote::Gpiote { pub(crate) fn init(irq_prio: crate::interrupt::Priority) { // no latched GPIO detect in nrf51. - #[cfg(not(feature = "_nrf51"))] + // in the nrf54l-ns, the detectmode register is inaccessible + #[cfg(not(any(feature = "_nrf51", all(feature = "_nrf54l", feature = "_ns"))))] { - #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] + #[cfg(any( + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340", + feature = "_nrf54l" + ))] let ports = &[pac::P0, pac::P1]; - #[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))] + #[cfg(not(any( + feature = "_nrf51", + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340", + feature = "_nrf54l" + )))] let ports = &[pac::P0]; for &p in ports { @@ -85,62 +240,114 @@ pub(crate) fn init(irq_prio: crate::interrupt::Priority) { // Enable interrupts #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))] - let irq = interrupt::GPIOTE0; + let irqs = &[interrupt::GPIOTE0]; #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))] - let irq = interrupt::GPIOTE1; + let irqs = &[interrupt::GPIOTE1]; #[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))] - let irq = interrupt::GPIOTE; + let irqs = &[interrupt::GPIOTE]; + #[cfg(all(feature = "_nrf54l", feature = "_s"))] + let irqs = &[interrupt::GPIOTE20_0, interrupt::GPIOTE30_0]; + #[cfg(all(feature = "_nrf54l", feature = "_ns"))] + let irqs = &[interrupt::GPIOTE20_1, interrupt::GPIOTE30_1]; + + for &irq in irqs { + irq.unpend(); + irq.set_priority(irq_prio); + unsafe { irq.enable() }; + } - irq.unpend(); - irq.set_priority(irq_prio); - unsafe { irq.enable() }; + #[cfg(not(feature = "_nrf54l"))] + let instances = &[()]; + #[cfg(feature = "_nrf54l")] + let instances = &[GpioteInstance::Gpiote20, GpioteInstance::Gpiote30]; - let g = regs(); - g.intenset().write(|w| w.set_port(true)); + for &inst in instances { + let g = regs(inst); + intenset(&g).write(|w| int_set_port(w, true)); + } } #[cfg(any(feature = "nrf5340-app-s", feature = "nrf9160-s", feature = "nrf9120-s"))] #[cfg(feature = "rt")] #[interrupt] fn GPIOTE0() { - unsafe { handle_gpiote_interrupt() }; + unsafe { handle_gpiote_interrupt(()) }; } #[cfg(any(feature = "nrf5340-app-ns", feature = "nrf9160-ns", feature = "nrf9120-ns"))] #[cfg(feature = "rt")] #[interrupt] fn GPIOTE1() { - unsafe { handle_gpiote_interrupt() }; + unsafe { handle_gpiote_interrupt(()) }; } #[cfg(any(feature = "_nrf51", feature = "_nrf52", feature = "nrf5340-net"))] #[cfg(feature = "rt")] #[interrupt] fn GPIOTE() { - unsafe { handle_gpiote_interrupt() }; + unsafe { handle_gpiote_interrupt(()) }; +} + +#[cfg(all(feature = "_nrf54l", feature = "_s"))] +#[cfg(feature = "rt")] +#[interrupt] +fn GPIOTE20_0() { + unsafe { handle_gpiote_interrupt(GpioteInstance::Gpiote20) }; } -unsafe fn handle_gpiote_interrupt() { - let g = regs(); +#[cfg(all(feature = "_nrf54l", feature = "_s"))] +#[cfg(feature = "rt")] +#[interrupt] +fn GPIOTE30_0() { + unsafe { handle_gpiote_interrupt(GpioteInstance::Gpiote30) }; +} + +#[cfg(all(feature = "_nrf54l", feature = "_ns"))] +#[cfg(feature = "rt")] +#[interrupt] +fn GPIOTE20_1() { + unsafe { handle_gpiote_interrupt(GpioteInstance::Gpiote20) }; +} + +#[cfg(all(feature = "_nrf54l", feature = "_ns"))] +#[cfg(feature = "rt")] +#[interrupt] +fn GPIOTE30_1() { + unsafe { handle_gpiote_interrupt(GpioteInstance::Gpiote30) }; +} - for i in 0..CHANNEL_COUNT { +unsafe fn handle_gpiote_interrupt(inst: GpioteInstanceType) { + let g = regs(inst); + + for i in 0..inst.channel_count() { if g.events_in(i).read() != 0 { - g.intenclr().write(|w| w.0 = 1 << i); - CHANNEL_WAKERS[i].wake(); + intenclr(&g).write(|w| w.0 = 1 << i); + inst.channel_waker(i).wake(); } } - if g.events_port().read() != 0 { - g.events_port().write_value(0); + if events_port(&g).read() != 0 { + events_port(&g).write_value(0); #[cfg(any(feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340"))] let ports = &[pac::P0, pac::P1]; - #[cfg(not(any(feature = "_nrf51", feature = "nrf52833", feature = "nrf52840", feature = "_nrf5340")))] + #[cfg(not(any( + feature = "_nrf51", + feature = "nrf52833", + feature = "nrf52840", + feature = "_nrf5340", + feature = "_nrf54l" + )))] let ports = &[pac::P0]; #[cfg(feature = "_nrf51")] let ports = &[pac::GPIO]; + #[cfg(feature = "_nrf54l")] + let ports = match inst { + GpioteInstanceType::Gpiote30 => &[pac::P0], + GpioteInstanceType::Gpiote20 => &[pac::P1], + }; - #[cfg(feature = "_nrf51")] + #[cfg(any(feature = "_nrf51", all(feature = "_nrf54l", feature = "_ns")))] for (port, &p) in ports.iter().enumerate() { let inp = p.in_().read(); for pin in 0..32 { @@ -151,28 +358,28 @@ unsafe fn handle_gpiote_interrupt() { }; if fired { - PORT_WAKERS[port * 32 + pin as usize].wake(); + inst.port_waker(port * 32 + pin as usize).wake(); p.pin_cnf(pin as usize).modify(|w| w.set_sense(Sense::DISABLED)); } } } - #[cfg(not(feature = "_nrf51"))] + #[cfg(not(any(feature = "_nrf51", all(feature = "_nrf54l", feature = "_ns"))))] for (port, &p) in ports.iter().enumerate() { let bits = p.latch().read().0; for pin in BitIter(bits) { p.pin_cnf(pin as usize).modify(|w| w.set_sense(Sense::DISABLED)); - PORT_WAKERS[port * 32 + pin as usize].wake(); + inst.port_waker(port * 32 + pin as usize).wake(); } p.latch().write(|w| w.0 = bits); } } } -#[cfg(not(feature = "_nrf51"))] +#[cfg(not(any(feature = "_nrf51", all(feature = "_nrf54l", feature = "_ns"))))] struct BitIter(u32); -#[cfg(not(feature = "_nrf51"))] +#[cfg(not(any(feature = "_nrf51", all(feature = "_nrf54l", feature = "_ns"))))] impl Iterator for BitIter { type Item = u32; @@ -195,17 +402,17 @@ pub struct InputChannel<'d> { impl<'d> Drop for InputChannel<'d> { fn drop(&mut self) { - let g = regs(); + let g = regs(self.ch.inst()); let num = self.ch.number(); g.config(num).write(|w| w.set_mode(Mode::DISABLED)); - g.intenclr().write(|w| w.0 = 1 << num); + intenclr(&g).write(|w| w.0 = 1 << num); } } impl<'d> InputChannel<'d> { /// Create a new GPIOTE input channel driver. pub fn new(ch: Peri<'d, impl Channel>, pin: Input<'d>, polarity: InputChannelPolarity) -> Self { - let g = regs(); + let g = regs(ch.inst()); let num = ch.number(); g.config(num).write(|w| { @@ -221,6 +428,12 @@ impl<'d> InputChannel<'d> { crate::gpio::Port::Port0 => false, crate::gpio::Port::Port1 => true, }); + #[cfg(feature = "_nrf54l")] + w.set_port(match pin.pin.pin.port() { + crate::gpio::Port::Port0 => 0, + crate::gpio::Port::Port1 => 1, + crate::gpio::Port::Port2 => 2, + }); w.set_psel(pin.pin.pin.pin()); }); @@ -231,15 +444,16 @@ impl<'d> InputChannel<'d> { /// Asynchronously wait for an event in this channel. pub async fn wait(&self) { - let g = regs(); + let inst = self.ch.inst(); + let g = regs(inst); let num = self.ch.number(); // Enable interrupt g.events_in(num).write_value(0); - g.intenset().write(|w| w.0 = 1 << num); + intenset(&g).write(|w| w.0 = 1 << num); poll_fn(|cx| { - CHANNEL_WAKERS[num].register(cx.waker()); + inst.channel_waker(num).register(cx.waker()); if g.events_in(num).read() != 0 { Poll::Ready(()) @@ -252,7 +466,7 @@ impl<'d> InputChannel<'d> { /// Returns the IN event, for use with PPI. pub fn event_in(&self) -> Event<'d> { - let g = regs(); + let g = regs(self.ch.inst()); Event::from_reg(g.events_in(self.ch.number())) } } @@ -265,17 +479,17 @@ pub struct OutputChannel<'d> { impl<'d> Drop for OutputChannel<'d> { fn drop(&mut self) { - let g = regs(); + let g = regs(self.ch.inst()); let num = self.ch.number(); g.config(num).write(|w| w.set_mode(Mode::DISABLED)); - g.intenclr().write(|w| w.0 = 1 << num); + intenclr(&g).write(|w| w.0 = 1 << num); } } impl<'d> OutputChannel<'d> { /// Create a new GPIOTE output channel driver. pub fn new(ch: Peri<'d, impl Channel>, pin: Output<'d>, polarity: OutputChannelPolarity) -> Self { - let g = regs(); + let g = regs(ch.inst()); let num = ch.number(); g.config(num).write(|w| { @@ -294,6 +508,12 @@ impl<'d> OutputChannel<'d> { crate::gpio::Port::Port0 => false, crate::gpio::Port::Port1 => true, }); + #[cfg(feature = "_nrf54l")] + w.set_port(match pin.pin.pin.port() { + crate::gpio::Port::Port0 => 0, + crate::gpio::Port::Port1 => 1, + crate::gpio::Port::Port2 => 2, + }); w.set_psel(pin.pin.pin.pin()); }); @@ -305,41 +525,41 @@ impl<'d> OutputChannel<'d> { /// Triggers the OUT task (does the action as configured with task_out_polarity, defaults to Toggle). pub fn out(&self) { - let g = regs(); + let g = regs(self.ch.inst()); g.tasks_out(self.ch.number()).write_value(1); } /// Triggers the SET task (set associated pin high). #[cfg(not(feature = "_nrf51"))] pub fn set(&self) { - let g = regs(); + let g = regs(self.ch.inst()); g.tasks_set(self.ch.number()).write_value(1); } /// Triggers the CLEAR task (set associated pin low). #[cfg(not(feature = "_nrf51"))] pub fn clear(&self) { - let g = regs(); + let g = regs(self.ch.inst()); g.tasks_clr(self.ch.number()).write_value(1); } /// Returns the OUT task, for use with PPI. pub fn task_out(&self) -> Task<'d> { - let g = regs(); + let g = regs(self.ch.inst()); Task::from_reg(g.tasks_out(self.ch.number())) } /// Returns the CLR task, for use with PPI. #[cfg(not(feature = "_nrf51"))] pub fn task_clr(&self) -> Task<'d> { - let g = regs(); + let g = regs(self.ch.inst()); Task::from_reg(g.tasks_clr(self.ch.number())) } /// Returns the SET task, for use with PPI. #[cfg(not(feature = "_nrf51"))] pub fn task_set(&self) -> Task<'d> { - let g = regs(); + let g = regs(self.ch.inst()); Task::from_reg(g.tasks_set(self.ch.number())) } } @@ -369,9 +589,11 @@ impl<'a> Future for PortInputFuture<'a> { type Output = (); fn poll(self: core::pin::Pin<&mut Self>, cx: &mut Context<'_>) -> Poll { - PORT_WAKERS[self.pin.pin_port() as usize].register(cx.waker()); + let pin: &AnyPin = &self.pin; + let inst: GpioteInstanceType = pin.into(); + inst.port_waker(pin._pin() as usize).register(cx.waker()); - if self.pin.conf().read().sense() == Sense::DISABLED { + if pin.conf().read().sense() == Sense::DISABLED { Poll::Ready(()) } else { Poll::Pending @@ -453,6 +675,8 @@ trait SealedChannel {} pub trait Channel: PeripheralType + SealedChannel + Into + Sized + 'static { /// Get the channel number. fn number(&self) -> usize; + /// Get the controller instance id. + fn inst(&self) -> GpioteInstanceType; } /// Type-erased channel. @@ -463,6 +687,7 @@ pub trait Channel: PeripheralType + SealedChannel + Into + Sized + ' /// them to be the same type, like putting them in an array. pub struct AnyChannel { number: u8, + inst: GpioteInstanceType, } impl_peripheral!(AnyChannel); impl SealedChannel for AnyChannel {} @@ -470,39 +695,80 @@ impl Channel for AnyChannel { fn number(&self) -> usize { self.number as usize } + fn inst(&self) -> GpioteInstanceType { + self.inst + } } macro_rules! impl_channel { - ($type:ident, $number:expr) => { + ($type:ident, $inst:expr, $number:expr) => { impl SealedChannel for peripherals::$type {} impl Channel for peripherals::$type { fn number(&self) -> usize { $number as usize } + fn inst(&self) -> GpioteInstanceType { + $inst + } } impl From for AnyChannel { fn from(val: peripherals::$type) -> Self { Self { number: val.number() as u8, + inst: val.inst(), } } } }; } -impl_channel!(GPIOTE_CH0, 0); -impl_channel!(GPIOTE_CH1, 1); -impl_channel!(GPIOTE_CH2, 2); -impl_channel!(GPIOTE_CH3, 3); +#[cfg(not(feature = "_nrf54l"))] +impl_channel!(GPIOTE_CH0, (), 0); +#[cfg(not(feature = "_nrf54l"))] +impl_channel!(GPIOTE_CH1, (), 1); +#[cfg(not(feature = "_nrf54l"))] +impl_channel!(GPIOTE_CH2, (), 2); +#[cfg(not(feature = "_nrf54l"))] +impl_channel!(GPIOTE_CH3, (), 3); #[cfg(not(feature = "_nrf51"))] -impl_channel!(GPIOTE_CH4, 4); +#[cfg(not(feature = "_nrf54l"))] +impl_channel!(GPIOTE_CH4, (), 4); #[cfg(not(feature = "_nrf51"))] -impl_channel!(GPIOTE_CH5, 5); +#[cfg(not(feature = "_nrf54l"))] +impl_channel!(GPIOTE_CH5, (), 5); #[cfg(not(feature = "_nrf51"))] -impl_channel!(GPIOTE_CH6, 6); +#[cfg(not(feature = "_nrf54l"))] +impl_channel!(GPIOTE_CH6, (), 6); #[cfg(not(feature = "_nrf51"))] -impl_channel!(GPIOTE_CH7, 7); +#[cfg(not(feature = "_nrf54l"))] +impl_channel!(GPIOTE_CH7, (), 7); + +#[cfg(feature = "_nrf54l")] +impl_channel!(GPIOTE20_CH0, GpioteInstance::Gpiote20, 0); +#[cfg(feature = "_nrf54l")] +impl_channel!(GPIOTE20_CH1, GpioteInstance::Gpiote20, 1); +#[cfg(feature = "_nrf54l")] +impl_channel!(GPIOTE20_CH2, GpioteInstance::Gpiote20, 2); +#[cfg(feature = "_nrf54l")] +impl_channel!(GPIOTE20_CH3, GpioteInstance::Gpiote20, 3); +#[cfg(feature = "_nrf54l")] +impl_channel!(GPIOTE20_CH4, GpioteInstance::Gpiote20, 4); +#[cfg(feature = "_nrf54l")] +impl_channel!(GPIOTE20_CH5, GpioteInstance::Gpiote20, 5); +#[cfg(feature = "_nrf54l")] +impl_channel!(GPIOTE20_CH6, GpioteInstance::Gpiote20, 6); +#[cfg(feature = "_nrf54l")] +impl_channel!(GPIOTE20_CH7, GpioteInstance::Gpiote20, 7); + +#[cfg(feature = "_nrf54l")] +impl_channel!(GPIOTE30_CH0, GpioteInstance::Gpiote30, 0); +#[cfg(feature = "_nrf54l")] +impl_channel!(GPIOTE30_CH1, GpioteInstance::Gpiote30, 1); +#[cfg(feature = "_nrf54l")] +impl_channel!(GPIOTE30_CH2, GpioteInstance::Gpiote30, 2); +#[cfg(feature = "_nrf54l")] +impl_channel!(GPIOTE30_CH3, GpioteInstance::Gpiote30, 3); // ==================== diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 2b72debebd..bb5e45cebf 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -82,7 +82,6 @@ pub mod buffered_uarte; #[cfg(not(feature = "_nrf51"))] pub mod egu; pub mod gpio; -#[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(feature = "gpiote")] pub mod gpiote; #[cfg(not(feature = "_nrf54l"))] // TODO @@ -118,7 +117,6 @@ pub mod pdm; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(any(feature = "nrf52840", feature = "nrf9160-s", feature = "nrf9160-ns"))] pub mod power; -#[cfg(not(feature = "_nrf54l"))] // TODO pub mod ppi; #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(not(any( @@ -1085,7 +1083,6 @@ pub fn init(config: config::Config) -> Peripherals { } // Init GPIOTE - #[cfg(not(feature = "_nrf54l"))] // TODO #[cfg(feature = "gpiote")] gpiote::init(config.gpiote_interrupt_priority); diff --git a/embassy-nrf/src/ppi/dppi.rs b/embassy-nrf/src/ppi/dppi.rs index 686f66987f..b35d9e9d3c 100644 --- a/embassy-nrf/src/ppi/dppi.rs +++ b/embassy-nrf/src/ppi/dppi.rs @@ -4,8 +4,48 @@ use crate::{pac, Peri}; const DPPI_ENABLE_BIT: u32 = 0x8000_0000; const DPPI_CHANNEL_MASK: u32 = 0x0000_00FF; -pub(crate) fn regs() -> pac::dppic::Dppic { - pac::DPPIC +#[cfg(feature = "_nrf54l")] +#[derive(Copy, Clone)] +/// DPPI instance +pub enum DppiInstance { + /// DPPI_00 instance + Dppi00, + /// DPPI_20 instance + Dppi20, + /// DPPI_30 instance + Dppi30, +} + +#[cfg(feature = "_nrf54l")] +impl From for DppiInstance { + fn from(dppic: pac::dppic::Dppic) -> Self { + match dppic { + pac::DPPIC00 => DppiInstance::Dppi00, + pac::DPPIC20 => DppiInstance::Dppi20, + pac::DPPIC30 => DppiInstance::Dppi30, + _ => panic!(), + } + } +} + +#[cfg(feature = "_nrf54l")] +pub(crate) type PpiInstanceType = DppiInstance; + +#[cfg(not(feature = "_nrf54l"))] +pub(crate) type PpiInstanceType = (); + +pub(crate) fn regs(_inst: PpiInstanceType) -> pac::dppic::Dppic { + #[cfg(not(feature = "_nrf54l"))] + { + pac::DPPIC + } + + #[cfg(feature = "_nrf54l")] + match _inst { + DppiInstance::Dppi00 => pac::DPPIC00, + DppiInstance::Dppi20 => pac::DPPIC20, + DppiInstance::Dppi30 => pac::DPPIC30, + } } impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { @@ -49,13 +89,15 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d, /// Enables the channel. pub fn enable(&mut self) { let n = self.ch.number(); - regs().chenset().write(|w| w.0 = 1 << n); + let inst = self.ch.inst(); + regs(inst).chenset().write(|w| w.0 = 1 << n); } /// Disables the channel. pub fn disable(&mut self) { let n = self.ch.number(); - regs().chenclr().write(|w| w.0 = 1 << n); + let inst = self.ch.inst(); + regs(inst).chenclr().write(|w| w.0 = 1 << n); } } diff --git a/embassy-nrf/src/ppi/mod.rs b/embassy-nrf/src/ppi/mod.rs index 5317772052..5e493e1360 100644 --- a/embassy-nrf/src/ppi/mod.rs +++ b/embassy-nrf/src/ppi/mod.rs @@ -21,6 +21,7 @@ use core::ptr::NonNull; use embassy_hal_internal::{impl_peripheral, Peri, PeripheralType}; use crate::pac::common::{Reg, RW, W}; +#[allow(unused_imports)] use crate::peripherals; #[cfg_attr(feature = "_dppi", path = "dppi.rs")] @@ -47,7 +48,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { /// /// The group is initialized as containing no channels. pub fn new(g: Peri<'d, G>) -> Self { - let r = regs(); + let r = regs(g.inst()); let n = g.number(); r.chg(n).write(|_| ()); @@ -61,7 +62,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { &mut self, ch: &Ppi<'_, C, EVENT_COUNT, TASK_COUNT>, ) { - let r = regs(); + let r = regs(self.g.inst()); let ng = self.g.number(); let nc = ch.ch.number(); r.chg(ng).modify(|w| w.set_ch(nc, true)); @@ -74,7 +75,7 @@ impl<'d, G: Group> PpiGroup<'d, G> { &mut self, ch: &Ppi<'_, C, EVENT_COUNT, TASK_COUNT>, ) { - let r = regs(); + let r = regs(self.g.inst()); let ng = self.g.number(); let nc = ch.ch.number(); r.chg(ng).modify(|w| w.set_ch(nc, false)); @@ -83,13 +84,15 @@ impl<'d, G: Group> PpiGroup<'d, G> { /// Enable all the channels in this group. pub fn enable_all(&mut self) { let n = self.g.number(); - regs().tasks_chg(n).en().write_value(1); + let inst = self.g.inst(); + regs(inst).tasks_chg(n).en().write_value(1); } /// Disable all the channels in this group. pub fn disable_all(&mut self) { let n = self.g.number(); - regs().tasks_chg(n).dis().write_value(1); + let inst = self.g.inst(); + regs(inst).tasks_chg(n).dis().write_value(1); } /// Get a reference to the "enable all" task. @@ -97,7 +100,8 @@ impl<'d, G: Group> PpiGroup<'d, G> { /// When triggered, it will enable all the channels in this group. pub fn task_enable_all(&self) -> Task<'d> { let n = self.g.number(); - Task::from_reg(regs().tasks_chg(n).en()) + let inst = self.g.inst(); + Task::from_reg(regs(inst).tasks_chg(n).en()) } /// Get a reference to the "disable all" task. @@ -105,13 +109,14 @@ impl<'d, G: Group> PpiGroup<'d, G> { /// When triggered, it will disable all the channels in this group. pub fn task_disable_all(&self) -> Task<'d> { let n = self.g.number(); - Task::from_reg(regs().tasks_chg(n).dis()) + let inst = self.g.inst(); + Task::from_reg(regs(inst).tasks_chg(n).dis()) } } impl<'d, G: Group> Drop for PpiGroup<'d, G> { fn drop(&mut self) { - let r = regs(); + let r = regs(self.g.inst()); let n = self.g.number(); r.chg(n).write(|_| ()); } @@ -211,6 +216,8 @@ pub(crate) trait SealedGroup {} pub trait Channel: SealedChannel + PeripheralType + Sized + 'static { /// Returns the number of the channel fn number(&self) -> usize; + /// Returns the instance of the (D)PPI controller + fn inst(&self) -> PpiInstanceType; } /// Interface for PPI channels that can be configured. @@ -224,6 +231,8 @@ pub trait StaticChannel: Channel + Into {} pub trait Group: SealedGroup + PeripheralType + Into + Sized + 'static { /// Returns the number of the group. fn number(&self) -> usize; + /// Returns the instance of the (D)PPI controller + fn inst(&self) -> PpiInstanceType; } // ====================== @@ -233,6 +242,7 @@ pub trait Group: SealedGroup + PeripheralType + Into + Sized + 'static /// This can be used to have fewer generic parameters in some places. pub struct AnyStaticChannel { pub(crate) number: u8, + pub(crate) inst: PpiInstanceType, } impl_peripheral!(AnyStaticChannel); impl SealedChannel for AnyStaticChannel {} @@ -240,6 +250,9 @@ impl Channel for AnyStaticChannel { fn number(&self) -> usize { self.number as usize } + fn inst(&self) -> PpiInstanceType { + self.inst + } } impl StaticChannel for AnyStaticChannel {} @@ -247,6 +260,7 @@ impl StaticChannel for AnyStaticChannel {} /// This can be used to have fewer generic parameters in some places. pub struct AnyConfigurableChannel { pub(crate) number: u8, + pub(crate) inst: PpiInstanceType, } impl_peripheral!(AnyConfigurableChannel); impl SealedChannel for AnyConfigurableChannel {} @@ -254,41 +268,58 @@ impl Channel for AnyConfigurableChannel { fn number(&self) -> usize { self.number as usize } + fn inst(&self) -> PpiInstanceType { + self.inst + } } impl ConfigurableChannel for AnyConfigurableChannel {} #[cfg(not(feature = "_nrf51"))] macro_rules! impl_ppi_channel { - ($type:ident, $number:expr) => { + ($type:ident, $inst:expr, $number:expr) => { impl crate::ppi::SealedChannel for peripherals::$type {} impl crate::ppi::Channel for peripherals::$type { fn number(&self) -> usize { $number } + fn inst(&self) -> crate::ppi::PpiInstanceType { + $inst.into() + } } }; - ($type:ident, $number:expr => static) => { - impl_ppi_channel!($type, $number); + ($type:ident, $inst:expr, $number:expr => static) => { + impl_ppi_channel!($type, $inst, $number); impl crate::ppi::StaticChannel for peripherals::$type {} impl From for crate::ppi::AnyStaticChannel { fn from(val: peripherals::$type) -> Self { Self { number: crate::ppi::Channel::number(&val) as u8, + inst: crate::ppi::Channel::inst(&val), } } } }; - ($type:ident, $number:expr => configurable) => { - impl_ppi_channel!($type, $number); + ($type:ident, $inst:expr, $number:expr => configurable) => { + impl_ppi_channel!($type, $inst, $number); impl crate::ppi::ConfigurableChannel for peripherals::$type {} impl From for crate::ppi::AnyConfigurableChannel { fn from(val: peripherals::$type) -> Self { Self { number: crate::ppi::Channel::number(&val) as u8, + inst: crate::ppi::Channel::inst(&val), } } } }; + ($type:ident, $number:expr) => { + impl_ppi_channel!($type, (), $number); + }; + ($type:ident, $number:expr => static) => { + impl_ppi_channel!($type, (), $number => static); + }; + ($type:ident, $number:expr => configurable) => { + impl_ppi_channel!($type, (), $number => configurable); + }; } // ====================== @@ -296,7 +327,8 @@ macro_rules! impl_ppi_channel { /// A type erased PPI group. pub struct AnyGroup { - number: u8, + pub(crate) number: u8, + pub(crate) inst: PpiInstanceType, } impl_peripheral!(AnyGroup); impl SealedGroup for AnyGroup {} @@ -304,32 +336,50 @@ impl Group for AnyGroup { fn number(&self) -> usize { self.number as usize } + fn inst(&self) -> PpiInstanceType { + self.inst + } } -macro_rules! impl_group { - ($type:ident, $number:expr) => { - impl SealedGroup for peripherals::$type {} - impl Group for peripherals::$type { +macro_rules! impl_ppi_group { + ($type:ident, $inst:expr, $number:expr) => { + impl crate::ppi::SealedGroup for peripherals::$type {} + impl crate::ppi::Group for peripherals::$type { fn number(&self) -> usize { $number } + fn inst(&self) -> crate::ppi::PpiInstanceType { + $inst.into() + } } impl From for crate::ppi::AnyGroup { fn from(val: peripherals::$type) -> Self { Self { number: crate::ppi::Group::number(&val) as u8, + inst: crate::ppi::Group::inst(&val), } } } }; } +#[allow(unused)] +macro_rules! impl_group { + ($type:ident, $number:expr) => { + impl_ppi_group!($type, (), $number); + }; +} + +#[cfg(not(feature = "_nrf54l"))] impl_group!(PPI_GROUP0, 0); +#[cfg(not(feature = "_nrf54l"))] impl_group!(PPI_GROUP1, 1); +#[cfg(not(feature = "_nrf54l"))] impl_group!(PPI_GROUP2, 2); +#[cfg(not(feature = "_nrf54l"))] impl_group!(PPI_GROUP3, 3); -#[cfg(not(feature = "_nrf51"))] +#[cfg(not(any(feature = "_nrf51", feature = "_nrf54l")))] impl_group!(PPI_GROUP4, 4); -#[cfg(not(feature = "_nrf51"))] +#[cfg(not(any(feature = "_nrf51", feature = "_nrf54l")))] impl_group!(PPI_GROUP5, 5); diff --git a/embassy-nrf/src/ppi/ppi.rs b/embassy-nrf/src/ppi/ppi.rs index e04dacbc06..c920e1ba28 100644 --- a/embassy-nrf/src/ppi/ppi.rs +++ b/embassy-nrf/src/ppi/ppi.rs @@ -12,7 +12,9 @@ impl<'d> Event<'d> { } } -pub(crate) fn regs() -> pac::ppi::Ppi { +pub(crate) type PpiInstanceType = (); + +pub(crate) fn regs(_inst: PpiInstanceType) -> pac::ppi::Ppi { pac::PPI } @@ -20,7 +22,8 @@ pub(crate) fn regs() -> pac::ppi::Ppi { impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> { /// Configure PPI channel to trigger `task`. pub fn new_zero_to_one(ch: Peri<'d, C>, task: Task) -> Self { - let r = regs(); + let inst = ch.inst(); + let r = regs(inst); let n = ch.number(); r.fork(n).tep().write_value(task.reg_val()); @@ -31,7 +34,8 @@ impl<'d, C: super::StaticChannel> Ppi<'d, C, 0, 1> { impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { /// Configure PPI channel to trigger `task` on `event`. pub fn new_one_to_one(ch: Peri<'d, C>, event: Event<'d>, task: Task<'d>) -> Self { - let r = regs(); + let inst = ch.inst(); + let r = regs(inst); let n = ch.number(); r.ch(n).eep().write_value(event.reg_val()); r.ch(n).tep().write_value(task.reg_val()); @@ -44,7 +48,8 @@ impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 1> { impl<'d, C: ConfigurableChannel> Ppi<'d, C, 1, 2> { /// Configure PPI channel to trigger both `task1` and `task2` on `event`. pub fn new_one_to_two(ch: Peri<'d, C>, event: Event<'d>, task1: Task<'d>, task2: Task<'d>) -> Self { - let r = regs(); + let inst = ch.inst(); + let r = regs(inst); let n = ch.number(); r.ch(n).eep().write_value(event.reg_val()); r.ch(n).tep().write_value(task1.reg_val()); @@ -58,13 +63,15 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Ppi<'d, /// Enables the channel. pub fn enable(&mut self) { let n = self.ch.number(); - regs().chenset().write(|w| w.set_ch(n, true)); + let inst = self.ch.inst(); + regs(inst).chenset().write(|w| w.set_ch(n, true)); } /// Disables the channel. pub fn disable(&mut self) { let n = self.ch.number(); - regs().chenclr().write(|w| w.set_ch(n, true)); + let inst = self.ch.inst(); + regs(inst).chenclr().write(|w| w.set_ch(n, true)); } } @@ -72,7 +79,8 @@ impl<'d, C: Channel, const EVENT_COUNT: usize, const TASK_COUNT: usize> Drop for fn drop(&mut self) { self.disable(); - let r = regs(); + let inst = self.ch.inst(); + let r = regs(inst); let n = self.ch.number(); r.ch(n).eep().write_value(0); r.ch(n).tep().write_value(0); diff --git a/examples/nrf54l15/Cargo.toml b/examples/nrf54l15/Cargo.toml index b794b217c1..ce2ebc055c 100644 --- a/examples/nrf54l15/Cargo.toml +++ b/examples/nrf54l15/Cargo.toml @@ -7,6 +7,7 @@ publish = false [dependencies] embassy-executor = { version = "0.8.0", path = "../../embassy-executor", features = ["arch-cortex-m", "executor-thread", "executor-interrupt", "defmt"] } +embassy-futures = { version = "0.1.0", path = "../../embassy-futures" } embassy-time = { version = "0.4.0", path = "../../embassy-time", features = ["defmt", "defmt-timestamp-uptime"] } embassy-nrf = { version = "0.6.0", path = "../../embassy-nrf", features = ["defmt", "nrf54l15-app-s", "time-driver-rtc1", "gpiote", "unstable-pac", "time"] } diff --git a/examples/nrf54l15/src/bin/gpiote.rs b/examples/nrf54l15/src/bin/gpiote.rs new file mode 100644 index 0000000000..7847d92ac5 --- /dev/null +++ b/examples/nrf54l15/src/bin/gpiote.rs @@ -0,0 +1,52 @@ +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_futures::select::{select4, Either4}; +use embassy_nrf::gpio::{Input, Pull}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + info!("Starting!"); + + // Buttons on nrf54l15 PDK + let mut button0 = Input::new(p.P1_13, Pull::Up); + let mut button1 = Input::new(p.P1_09, Pull::Up); + let mut button2 = Input::new(p.P1_08, Pull::Up); + let mut button3 = Input::new(p.P0_04, Pull::Up); + + loop { + match select4( + button0.wait_for_low(), + button1.wait_for_falling_edge(), + button2.wait_for_any_edge(), + button3.wait_for_low(), + ) + .await + { + Either4::First(_) => { + info!("Button 0 pressed"); + button0.wait_for_high().await; + info!("Button 0 released"); + } + Either4::Second(_) => { + info!("Button 1 pressed"); + button1.wait_for_rising_edge().await; + info!("Button 1 released"); + } + Either4::Third(_) => { + info!("Button 2 pressed"); + button2.wait_for_any_edge().await; + info!("Button 2 released"); + } + Either4::Fourth(_) => { + info!("Button 3 pressed"); + button3.wait_for_high().await; + info!("Button 3 released"); + } + } + } +} diff --git a/examples/nrf54l15/src/bin/gpiote_channel.rs b/examples/nrf54l15/src/bin/gpiote_channel.rs new file mode 100644 index 0000000000..8483cbae62 --- /dev/null +++ b/examples/nrf54l15/src/bin/gpiote_channel.rs @@ -0,0 +1,66 @@ +#![no_std] +#![no_main] + +use defmt::info; +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Input, Pull}; +use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + info!("Starting!"); + + // Buttons on nrf54l15 PDK + let ch1 = InputChannel::new( + p.GPIOTE20_CH0, + Input::new(p.P1_13, Pull::Up), + InputChannelPolarity::HiToLo, + ); + let ch2 = InputChannel::new( + p.GPIOTE20_CH1, + Input::new(p.P1_09, Pull::Up), + InputChannelPolarity::LoToHi, + ); + let ch3 = InputChannel::new( + p.GPIOTE20_CH2, + Input::new(p.P1_08, Pull::Up), + InputChannelPolarity::Toggle, + ); + let ch4 = InputChannel::new( + p.GPIOTE30_CH0, + Input::new(p.P0_04, Pull::Up), + InputChannelPolarity::Toggle, + ); + + let button1 = async { + loop { + ch1.wait().await; + info!("Button 1 pressed") + } + }; + + let button2 = async { + loop { + ch2.wait().await; + info!("Button 2 released") + } + }; + + let button3 = async { + loop { + ch3.wait().await; + info!("Button 3 toggled") + } + }; + + let button4 = async { + loop { + ch4.wait().await; + info!("Button 4 toggled") + } + }; + + embassy_futures::join::join4(button1, button2, button3, button4).await; +} diff --git a/examples/nrf54l15/src/bin/gpiote_port.rs b/examples/nrf54l15/src/bin/gpiote_port.rs new file mode 100644 index 0000000000..e57c05eabf --- /dev/null +++ b/examples/nrf54l15/src/bin/gpiote_port.rs @@ -0,0 +1,34 @@ +#![no_std] +#![no_main] + +use defmt::{info, unwrap}; +use embassy_executor::Spawner; +use embassy_nrf::gpio::{Input, Pull}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::task(pool_size = 4)] +async fn button_task(n: usize, mut pin: Input<'static>) { + loop { + pin.wait_for_low().await; + info!("Button {:?} pressed!", n); + pin.wait_for_high().await; + info!("Button {:?} released!", n); + } +} + +#[embassy_executor::main] +async fn main(spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + info!("Starting!"); + + // Buttons on nrf54l15 PDK + let button0 = Input::new(p.P1_13, Pull::Up); + let button1 = Input::new(p.P1_09, Pull::Up); + let button2 = Input::new(p.P1_08, Pull::Up); + let button3 = Input::new(p.P0_04, Pull::Up); + + unwrap!(spawner.spawn(button_task(0, button0))); + unwrap!(spawner.spawn(button_task(1, button1))); + unwrap!(spawner.spawn(button_task(2, button2))); + unwrap!(spawner.spawn(button_task(3, button3))); +}