Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- Implement `embeded_hal_async::delay::DelayUs` trait for `SYSTIMER` alarms (#812)
- ETM driver, GPIO ETM (#819)
- (G)DMA AES support (#821)
- SYSTIMER ETM functionality (#828)

### Changed

Expand Down
61 changes: 61 additions & 0 deletions esp-hal-common/src/systimer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -65,6 +65,10 @@ impl<'d> SystemTimer<'d> {

pub fn new(p: impl Peripheral<P = SYSTIMER> + 'd) -> Self {
crate::into_ref!(p);

#[cfg(soc_etm)]
etm::enable_etm();

Self {
_inner: p,
alarm0: Alarm::new(),
Expand Down Expand Up @@ -365,3 +369,60 @@ mod asynch {
WAKERS[2].wake();
}
}

#[cfg(soc_etm)]
pub mod etm {
//! # Event Task Matrix Function
//!
//! ## Overview
//!
//! The system timer supports the Event Task Matrix (ETM) function, which
//! allows the system timer’s ETM events to trigger any
//! peripherals’ ETM tasks.
//!
//! The system timer can generate the following ETM events:
//! - SYSTIMER_EVT_CNT_CMPx: Indicates the alarm pulses generated by
//! COMPx
//!
//! ## Example
//! ```no_run
//! let syst = SystemTimer::new(peripherals.SYSTIMER);
//! let mut alarm0 = syst.alarm0.into_periodic();
//! alarm0.set_period(1u32.secs());
//!
//! let timer_event = SysTimerEtmEvent::new(&mut alarm0);
//! ```

use super::*;

/// An ETM controlled SYSTIMER event
pub struct SysTimerEtmEvent<'a, M, const N: u8> {
alarm: &'a mut Alarm<M, N>,
}

impl<'a, M, const N: u8> SysTimerEtmEvent<'a, M, N> {
/// Creates an ETM event from the given [Alarm]
pub fn new(alarm: &'a mut Alarm<M, N>) -> Self {
Self { alarm }
}

/// Execute closure f with mutable access to the wrapped [Alarm].
pub fn with<R>(&self, f: impl FnOnce(&&'a mut Alarm<M, N>) -> R) -> R {
let alarm = &self.alarm;
f(alarm)
}
}

impl<'a, M, const N: u8> crate::etm::private::Sealed for SysTimerEtmEvent<'a, M, N> {}

impl<'a, M, const N: u8> crate::etm::EtmEvent for SysTimerEtmEvent<'a, M, N> {
fn id(&self) -> u8 {
50 + N
}
}

pub(super) fn enable_etm() {
let syst = unsafe { crate::peripherals::SYSTIMER::steal() };
syst.conf.modify(|_, w| w.etm_en().set_bit());
}
}
44 changes: 44 additions & 0 deletions esp32c6-hal/examples/etm_blinky_systimer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//! Control LED on GPIO 1 by the systimer via ETM

#![no_std]
#![no_main]

use esp32c6_hal::{
clock::ClockControl,
etm::Etm,
gpio::{etm::GpioEtmChannels, IO},
peripherals::Peripherals,
prelude::*,
systimer::{etm::SysTimerEtmEvent, SystemTimer},
};
use esp_backtrace as _;

#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = peripherals.PCR.split();
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();

let syst = SystemTimer::new(peripherals.SYSTIMER);
let mut alarm0 = syst.alarm0.into_periodic();
alarm0.set_period(1u32.secs());

let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let mut led = io.pins.gpio1.into_push_pull_output();

// setup ETM
let gpio_ext = GpioEtmChannels::new(peripherals.GPIO_SD);
let led_task = gpio_ext.channel0_task.toggle(&mut led);

let timer_event = SysTimerEtmEvent::new(&mut alarm0);

let etm = Etm::new(peripherals.SOC_ETM);
let channel0 = etm.channel0;

// make sure the configured channel doesn't get dropped - dropping it will
// disable the channel
let _configured_channel = channel0.setup(&timer_event, &led_task);

// the LED is controlled by the timer without involving the CPU
loop {}
}
1 change: 0 additions & 1 deletion esp32c6-hal/examples/etm_gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use esp_backtrace as _;

#[entry]
fn main() -> ! {
esp_println::logger::init_logger_from_env();
let peripherals = Peripherals::take();
let system = peripherals.PCR.split();
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();
Expand Down
44 changes: 44 additions & 0 deletions esp32h2-hal/examples/etm_blinky_systimer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,44 @@
//! Control LED on GPIO 1 by the systimer via ETM

#![no_std]
#![no_main]

use esp32h2_hal::{
clock::ClockControl,
etm::Etm,
gpio::{etm::GpioEtmChannels, IO},
peripherals::Peripherals,
prelude::*,
systimer::{etm::SysTimerEtmEvent, SystemTimer},
};
use esp_backtrace as _;

#[entry]
fn main() -> ! {
let peripherals = Peripherals::take();
let system = peripherals.PCR.split();
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();

let syst = SystemTimer::new(peripherals.SYSTIMER);
let mut alarm0 = syst.alarm0.into_periodic();
alarm0.set_period(1u32.secs());

let io = IO::new(peripherals.GPIO, peripherals.IO_MUX);
let mut led = io.pins.gpio1.into_push_pull_output();

// setup ETM
let gpio_ext = GpioEtmChannels::new(peripherals.GPIO_SD);
let led_task = gpio_ext.channel0_task.toggle(&mut led);

let timer_event = SysTimerEtmEvent::new(&mut alarm0);

let etm = Etm::new(peripherals.SOC_ETM);
let channel0 = etm.channel0;

// make sure the configured channel doesn't get dropped - dropping it will
// disable the channel
let _configured_channel = channel0.setup(&timer_event, &led_task);

// the LED is controlled by the timer without involving the CPU
loop {}
}
1 change: 0 additions & 1 deletion esp32h2-hal/examples/etm_gpio.rs
Original file line number Diff line number Diff line change
Expand Up @@ -14,7 +14,6 @@ use esp_backtrace as _;

#[entry]
fn main() -> ! {
esp_println::logger::init_logger_from_env();
let peripherals = Peripherals::take();
let system = peripherals.PCR.split();
let _clocks = ClockControl::boot_defaults(system.clock_control).freeze();
Expand Down