diff --git a/embassy-nrf/src/chips/nrf52805.rs b/embassy-nrf/src/chips/nrf52805.rs index 14c3f9b1a..b51b0c93e 100644 --- a/embassy-nrf/src/chips/nrf52805.rs +++ b/embassy-nrf/src/chips/nrf52805.rs @@ -132,6 +132,10 @@ embassy_hal_internal::peripherals! { // Radio RADIO, + + // EGU + EGU0, + EGU1, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -214,6 +218,9 @@ impl_saadc_input!(P0_05, ANALOG_INPUT3); impl_radio!(RADIO, RADIO, RADIO); +impl_egu!(EGU0, EGU0, SWI0_EGU0); +impl_egu!(EGU1, EGU1, SWI1_EGU1); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52810.rs b/embassy-nrf/src/chips/nrf52810.rs index c607586db..273098d9b 100644 --- a/embassy-nrf/src/chips/nrf52810.rs +++ b/embassy-nrf/src/chips/nrf52810.rs @@ -138,6 +138,10 @@ embassy_hal_internal::peripherals! { // Radio RADIO, + + // EGU + EGU0, + EGU1, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -240,6 +244,9 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_radio!(RADIO, RADIO, RADIO); +impl_egu!(EGU0, EGU0, SWI0_EGU0); +impl_egu!(EGU1, EGU1, SWI1_EGU1); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52811.rs b/embassy-nrf/src/chips/nrf52811.rs index 5f70365b4..9bce38636 100644 --- a/embassy-nrf/src/chips/nrf52811.rs +++ b/embassy-nrf/src/chips/nrf52811.rs @@ -138,6 +138,10 @@ embassy_hal_internal::peripherals! { // Radio RADIO, + + // EGU + EGU0, + EGU1, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -242,6 +246,9 @@ impl_saadc_input!(P0_31, ANALOG_INPUT7); impl_radio!(RADIO, RADIO, RADIO); +impl_egu!(EGU0, EGU0, SWI0_EGU0); +impl_egu!(EGU1, EGU1, SWI1_EGU1); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52820.rs b/embassy-nrf/src/chips/nrf52820.rs index 82d097407..2acae2c8f 100644 --- a/embassy-nrf/src/chips/nrf52820.rs +++ b/embassy-nrf/src/chips/nrf52820.rs @@ -133,6 +133,14 @@ embassy_hal_internal::peripherals! { // Radio RADIO, + + // EGU + EGU0, + EGU1, + EGU2, + EGU3, + EGU4, + EGU5, } impl_usb!(USBD, USBD, USBD); @@ -229,6 +237,13 @@ impl_ppi_channel!(PPI_CH31, 31 => static); impl_radio!(RADIO, RADIO, RADIO); +impl_egu!(EGU0, EGU0, SWI0_EGU0); +impl_egu!(EGU1, EGU1, SWI1_EGU1); +impl_egu!(EGU2, EGU2, SWI2_EGU2); +impl_egu!(EGU3, EGU3, SWI3_EGU3); +impl_egu!(EGU4, EGU4, SWI4_EGU4); +impl_egu!(EGU5, EGU5, SWI5_EGU5); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52832.rs b/embassy-nrf/src/chips/nrf52832.rs index 67b32fe5f..94b373ab3 100644 --- a/embassy-nrf/src/chips/nrf52832.rs +++ b/embassy-nrf/src/chips/nrf52832.rs @@ -153,6 +153,14 @@ embassy_hal_internal::peripherals! { // Radio RADIO, + + // EGU + EGU0, + EGU1, + EGU2, + EGU3, + EGU4, + EGU5, } impl_uarte!(UARTE0, UARTE0, UARTE0_UART0); @@ -269,6 +277,13 @@ impl_i2s!(I2S, I2S, I2S); impl_radio!(RADIO, RADIO, RADIO); +impl_egu!(EGU0, EGU0, SWI0_EGU0); +impl_egu!(EGU1, EGU1, SWI1_EGU1); +impl_egu!(EGU2, EGU2, SWI2_EGU2); +impl_egu!(EGU3, EGU3, SWI3_EGU3); +impl_egu!(EGU4, EGU4, SWI4_EGU4); +impl_egu!(EGU5, EGU5, SWI5_EGU5); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52833.rs b/embassy-nrf/src/chips/nrf52833.rs index 20f14e2d6..09cde1ac1 100644 --- a/embassy-nrf/src/chips/nrf52833.rs +++ b/embassy-nrf/src/chips/nrf52833.rs @@ -173,6 +173,14 @@ embassy_hal_internal::peripherals! { // Radio RADIO, + + // EGU + EGU0, + EGU1, + EGU2, + EGU3, + EGU4, + EGU5, } impl_usb!(USBD, USBD, USBD); @@ -311,6 +319,13 @@ impl_i2s!(I2S, I2S, I2S); impl_radio!(RADIO, RADIO, RADIO); +impl_egu!(EGU0, EGU0, SWI0_EGU0); +impl_egu!(EGU1, EGU1, SWI1_EGU1); +impl_egu!(EGU2, EGU2, SWI2_EGU2); +impl_egu!(EGU3, EGU3, SWI3_EGU3); +impl_egu!(EGU4, EGU4, SWI4_EGU4); +impl_egu!(EGU5, EGU5, SWI5_EGU5); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf52840.rs b/embassy-nrf/src/chips/nrf52840.rs index d3272b2e8..0f3d1b250 100644 --- a/embassy-nrf/src/chips/nrf52840.rs +++ b/embassy-nrf/src/chips/nrf52840.rs @@ -176,6 +176,14 @@ embassy_hal_internal::peripherals! { // Radio RADIO, + + // EGU + EGU0, + EGU1, + EGU2, + EGU3, + EGU4, + EGU5, } impl_usb!(USBD, USBD, USBD); @@ -316,6 +324,13 @@ impl_i2s!(I2S, I2S, I2S); impl_radio!(RADIO, RADIO, RADIO); +impl_egu!(EGU0, EGU0, SWI0_EGU0); +impl_egu!(EGU1, EGU1, SWI1_EGU1); +impl_egu!(EGU2, EGU2, SWI2_EGU2); +impl_egu!(EGU3, EGU3, SWI3_EGU3); +impl_egu!(EGU4, EGU4, SWI4_EGU4); +impl_egu!(EGU5, EGU5, SWI5_EGU5); + embassy_hal_internal::interrupt_mod!( POWER_CLOCK, RADIO, diff --git a/embassy-nrf/src/chips/nrf5340_app.rs b/embassy-nrf/src/chips/nrf5340_app.rs index 62c74bb6f..584f6e43c 100644 --- a/embassy-nrf/src/chips/nrf5340_app.rs +++ b/embassy-nrf/src/chips/nrf5340_app.rs @@ -380,6 +380,14 @@ embassy_hal_internal::peripherals! { P1_13, P1_14, P1_15, + + // EGU + EGU0, + EGU1, + EGU2, + EGU3, + EGU4, + EGU5, } impl_usb!(USBD, USBD, USBD); @@ -519,6 +527,13 @@ impl_saadc_input!(P0_18, ANALOG_INPUT5); impl_saadc_input!(P0_19, ANALOG_INPUT6); impl_saadc_input!(P0_20, ANALOG_INPUT7); +impl_egu!(EGU0, EGU0, EGU0); +impl_egu!(EGU1, EGU1, EGU1); +impl_egu!(EGU2, EGU2, EGU2); +impl_egu!(EGU3, EGU3, EGU3); +impl_egu!(EGU4, EGU4, EGU4); +impl_egu!(EGU5, EGU5, EGU5); + embassy_hal_internal::interrupt_mod!( FPU, CACHE, diff --git a/embassy-nrf/src/chips/nrf5340_net.rs b/embassy-nrf/src/chips/nrf5340_net.rs index 65e8f9653..d772c9a49 100644 --- a/embassy-nrf/src/chips/nrf5340_net.rs +++ b/embassy-nrf/src/chips/nrf5340_net.rs @@ -251,6 +251,9 @@ embassy_hal_internal::peripherals! { // Radio RADIO, + + // EGU + EGU0, } impl_uarte!(SERIAL0, UARTE0, SERIAL0); @@ -350,6 +353,8 @@ impl_ppi_channel!(PPI_CH31, 31 => configurable); impl_radio!(RADIO, RADIO, RADIO); +impl_egu!(EGU0, EGU0, EGU0); + embassy_hal_internal::interrupt_mod!( CLOCK_POWER, RADIO, diff --git a/embassy-nrf/src/chips/nrf9160.rs b/embassy-nrf/src/chips/nrf9160.rs index 8b1356ef8..8107ca175 100644 --- a/embassy-nrf/src/chips/nrf9160.rs +++ b/embassy-nrf/src/chips/nrf9160.rs @@ -283,6 +283,14 @@ embassy_hal_internal::peripherals! { // PDM PDM, + + // EGU + EGU0, + EGU1, + EGU2, + EGU3, + EGU4, + EGU5, } impl_uarte!(SERIAL0, UARTE0, UARTE0_SPIM0_SPIS0_TWIM0_TWIS0); @@ -380,6 +388,13 @@ impl_saadc_input!(P0_18, ANALOG_INPUT5); impl_saadc_input!(P0_19, ANALOG_INPUT6); impl_saadc_input!(P0_20, ANALOG_INPUT7); +impl_egu!(EGU0, EGU0, EGU0); +impl_egu!(EGU1, EGU1, EGU1); +impl_egu!(EGU2, EGU2, EGU2); +impl_egu!(EGU3, EGU3, EGU3); +impl_egu!(EGU4, EGU4, EGU4); +impl_egu!(EGU5, EGU5, EGU5); + embassy_hal_internal::interrupt_mod!( SPU, CLOCK_POWER, diff --git a/embassy-nrf/src/egu.rs b/embassy-nrf/src/egu.rs new file mode 100644 index 000000000..c0cde8330 --- /dev/null +++ b/embassy-nrf/src/egu.rs @@ -0,0 +1,103 @@ +//! EGU driver. +//! +//! The event generator driver provides a higher level API for task triggering +//! and events to use with PPI. + +#![macro_use] + +use core::marker::PhantomData; + +use embassy_hal_internal::into_ref; + +use crate::ppi::{Event, Task}; +use crate::{interrupt, pac, Peripheral, PeripheralRef}; + +/// An instance of the EGU. +pub struct Egu<'d, T: Instance> { + _p: PeripheralRef<'d, T>, +} + +impl<'d, T: Instance> Egu<'d, T> { + /// Create a new EGU instance. + pub fn new(_p: impl Peripheral

+ 'd) -> Self { + into_ref!(_p); + Self { _p } + } + + /// Get a handle to a trigger for the EGU. + pub fn trigger(&mut self, number: TriggerNumber) -> Trigger<'d, T> { + Trigger { + number, + _p: PhantomData, + } + } +} + +pub(crate) trait SealedInstance { + fn regs() -> &'static pac::egu0::RegisterBlock; +} + +/// Basic Egu instance. +#[allow(private_bounds)] +pub trait Instance: Peripheral

+ SealedInstance + 'static + Send { + /// Interrupt for this peripheral. + type Interrupt: interrupt::typelevel::Interrupt; +} + +macro_rules! impl_egu { + ($type:ident, $pac_type:ident, $irq:ident) => { + impl crate::egu::SealedInstance for peripherals::$type { + fn regs() -> &'static pac::egu0::RegisterBlock { + unsafe { &*pac::$pac_type::ptr() } + } + } + impl crate::egu::Instance for peripherals::$type { + type Interrupt = crate::interrupt::typelevel::$irq; + } + }; +} + +/// Represents a trigger within the EGU. +pub struct Trigger<'d, T: Instance> { + number: TriggerNumber, + _p: PhantomData<&'d T>, +} + +impl<'d, T: Instance> Trigger<'d, T> { + /// Get task for this trigger to use with PPI. + pub fn task(&self) -> Task<'d> { + let nr = self.number as usize; + let regs = T::regs(); + Task::from_reg(®s.tasks_trigger[nr]) + } + + /// Get event for this trigger to use with PPI. + pub fn event(&self) -> Event<'d> { + let nr = self.number as usize; + let regs = T::regs(); + Event::from_reg(®s.events_triggered[nr]) + } +} + +/// Represents a trigger within an EGU. +#[allow(missing_docs)] +#[derive(Clone, Copy, PartialEq)] +#[repr(u8)] +pub enum TriggerNumber { + Trigger0 = 0, + Trigger1 = 1, + Trigger2 = 2, + Trigger3 = 3, + Trigger4 = 4, + Trigger5 = 5, + Trigger6 = 6, + Trigger7 = 7, + Trigger8 = 8, + Trigger9 = 9, + Trigger10 = 10, + Trigger11 = 11, + Trigger12 = 12, + Trigger13 = 13, + Trigger14 = 14, + Trigger15 = 15, +} diff --git a/embassy-nrf/src/lib.rs b/embassy-nrf/src/lib.rs index 3457dd933..05b52f687 100644 --- a/embassy-nrf/src/lib.rs +++ b/embassy-nrf/src/lib.rs @@ -50,6 +50,8 @@ pub mod gpiote; #[cfg(not(any(feature = "_nrf9160", feature = "_nrf5340-app")))] pub mod radio; +#[cfg(not(feature = "nrf51"))] +pub mod egu; #[cfg(any(feature = "nrf52832", feature = "nrf52833", feature = "nrf52840"))] pub mod i2s; pub mod nvmc; diff --git a/examples/nrf52840/src/bin/egu.rs b/examples/nrf52840/src/bin/egu.rs new file mode 100644 index 000000000..8bf712697 --- /dev/null +++ b/examples/nrf52840/src/bin/egu.rs @@ -0,0 +1,43 @@ +//! This example shows the use of the EGU peripheral combined with PPI. +//! +//! It chains events from button -> egu0-trigger0 -> egu0-trigger1 -> led +#![no_std] +#![no_main] + +use embassy_executor::Spawner; +use embassy_nrf::egu::{Egu, TriggerNumber}; +use embassy_nrf::gpio::{Input, Level, Output, OutputDrive, Pull}; +use embassy_nrf::gpiote::{InputChannel, InputChannelPolarity, OutputChannel, OutputChannelPolarity}; +use embassy_nrf::peripherals::{PPI_CH0, PPI_CH1, PPI_CH2}; +use embassy_nrf::ppi::Ppi; +use embassy_time::{Duration, Timer}; +use {defmt_rtt as _, panic_probe as _}; + +#[embassy_executor::main] +async fn main(_spawner: Spawner) { + let p = embassy_nrf::init(Default::default()); + + let led1 = Output::new(p.P0_13, Level::High, OutputDrive::Standard); + let btn1 = Input::new(p.P0_11, Pull::Up); + + let mut egu1 = Egu::new(p.EGU0); + let led1 = OutputChannel::new(p.GPIOTE_CH0, led1, OutputChannelPolarity::Toggle); + let btn1 = InputChannel::new(p.GPIOTE_CH1, btn1, InputChannelPolarity::LoToHi); + + let trigger0 = egu1.trigger(TriggerNumber::Trigger0); + let trigger1 = egu1.trigger(TriggerNumber::Trigger1); + + let mut ppi1: Ppi = Ppi::new_one_to_one(p.PPI_CH0, btn1.event_in(), trigger0.task()); + ppi1.enable(); + + let mut ppi2: Ppi = Ppi::new_one_to_one(p.PPI_CH1, trigger0.event(), trigger1.task()); + ppi2.enable(); + + let mut ppi3: Ppi = Ppi::new_one_to_one(p.PPI_CH2, trigger1.event(), led1.task_out()); + ppi3.enable(); + + defmt::info!("Push the button to toggle the LED"); + loop { + Timer::after(Duration::from_secs(60)).await; + } +}