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
Next Next commit
Add SYSTIMER ETM
  • Loading branch information
bjoernQ committed Sep 28, 2023
commit fd46802be2c0eba00b577a57cdc1f355f33b7084
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 {}
}