add HAL and example for using nRF EGU peripheral

This commit is contained in:
Ulf Lilleengen 2024-06-18 13:00:28 +02:00
parent 3c414e99cb
commit a44ee963ef
13 changed files with 276 additions and 0 deletions

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

View file

@ -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,

103
embassy-nrf/src/egu.rs Normal file
View file

@ -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<P = T> + '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<P = Self> + 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(&regs.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(&regs.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,
}

View file

@ -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;

View file

@ -0,0 +1,55 @@
//! 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::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_nrf::egu::{Egu, TriggerNumber};
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_CH0, 1, 1> = Ppi::new_one_to_one(
p.PPI_CH0,
btn1.event_in(),
trigger0.task(),
);
ppi1.enable();
let mut ppi2: Ppi<PPI_CH1, 1, 1> = Ppi::new_one_to_one(
p.PPI_CH1,
trigger0.event(),
trigger1.task(),
);
ppi2.enable();
let mut ppi3: Ppi<PPI_CH2, 1, 1> = 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;
}
}