Skip to content
Merged
Show file tree
Hide file tree
Changes from 1 commit
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());
}
}
45 changes: 45 additions & 0 deletions esp32c6-hal/examples/etm_blinky_systimer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//! 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() -> ! {
esp_println::logger::init_logger_from_env();
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please put these behind a #[cfg(feature = "log")]. I just cleaned up like 26 of these in #810 and that isn't a fun activity

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Also please add the examples to CI

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

ah I keep forgetting about the log vs defmt thing 👍 most probably will just remove it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Normally this should fail in CI but these examples aren't checked (yet) ;)

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

we do cargo build --examples? there are no features needed so it should build it

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

True enough. esp-println's log is currently enabled by default right now which makes this pass...

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 {}
}
45 changes: 45 additions & 0 deletions esp32h2-hal/examples/etm_blinky_systimer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,45 @@
//! 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() -> ! {
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();

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 {}
}