Skip to content

Commit

Permalink
Add ETM support for general purpose timers (esp-rs#1287)
Browse files Browse the repository at this point in the history
* Implement ETM for general purpose timers

* Revert changes to timer_interrupt example

* Add an example for ETM for general purpose timers

* Add newly introduced generic const param for Timer0

* Use id function on TimerGroupInstance instead of const parameter

* Revert const parameter on Timer1

* Specify supported chips

* Update CHANGELOG.md

* Update CHANGELOG.md

* Fix example

* Assign configured ETM channel to a variable to prevent drop

* Fix comments

* Move declaration of delay after critical section

* Use delay_millis instead of delay_ms

* Remove mut from delay

* Add documentation
  • Loading branch information
sisoteuz authored and yanshay committed Mar 16, 2024
1 parent e15c7d7 commit e2d82b7
Show file tree
Hide file tree
Showing 3 changed files with 187 additions and 0 deletions.
2 changes: 2 additions & 0 deletions esp-hal/CHANGELOG.md
Original file line number Diff line number Diff line change
Expand Up @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0

### Added

- ESP32-C6 / ESP32-H2: Implement `ETM` for general purpose timers (#1274)

### Fixed

- Reserve `esp32` ROM stacks to prevent the trashing of dram2 section (#1289)
Expand Down
95 changes: 95 additions & 0 deletions esp-hal/src/timer.rs
Original file line number Diff line number Diff line change
Expand Up @@ -79,9 +79,13 @@ pub trait TimerGroupInstance {
fn register_block() -> *const RegisterBlock;
fn configure_src_clk();
fn configure_wdt_src_clk();
fn id() -> u8;
}

impl TimerGroupInstance for TIMG0 {
fn id() -> u8 {
0
}
#[inline(always)]
fn register_block() -> *const RegisterBlock {
crate::peripherals::TIMG0::PTR
Expand Down Expand Up @@ -132,6 +136,9 @@ impl TimerGroupInstance for TIMG0 {

#[cfg(timg1)]
impl TimerGroupInstance for TIMG1 {
fn id() -> u8 {
1
}
#[inline(always)]
fn register_block() -> *const RegisterBlock {
crate::peripherals::TIMG1::PTR
Expand Down Expand Up @@ -878,3 +885,91 @@ where
self.feed();
}
}

#[cfg(soc_etm)]
pub mod etm {
use super::*;
use crate::{
etm::{EtmEvent, EtmTask},
private::Sealed,
};

pub struct TimerEtmEvent {
id: u8,
}

pub struct TimerEtmTask {
id: u8,
}

impl EtmEvent for TimerEtmEvent {
fn id(&self) -> u8 {
self.id
}
}

impl Sealed for TimerEtmEvent {}

impl EtmTask for TimerEtmTask {
fn id(&self) -> u8 {
self.id
}
}

impl Sealed for TimerEtmTask {}

/// General purpose timer ETM events
pub trait TimerEtmEvents<TG> {
fn on_alarm(&self) -> TimerEtmEvent;
}

/// General purpose timer ETM tasks
pub trait TimerEtmTasks<TG> {
fn cnt_start(&self) -> TimerEtmTask;
fn cnt_stop(&self) -> TimerEtmTask;
fn cnt_reload(&self) -> TimerEtmTask;
fn cnt_cap(&self) -> TimerEtmTask;
fn alarm_start(&self) -> TimerEtmTask;
}

impl<TG> TimerEtmEvents<TG> for Timer0<TG>
where
TG: TimerGroupInstance,
{
/// ETM event triggered on alarm
fn on_alarm(&self) -> TimerEtmEvent {
TimerEtmEvent { id: 48 + TG::id() }
}
}

impl<TG> TimerEtmTasks<TG> for Timer0<TG>
where
TG: TimerGroupInstance,
{
/// ETM task to start the counter
fn cnt_start(&self) -> TimerEtmTask {
TimerEtmTask { id: 88 + TG::id() }
}

/// ETM task to start the alarm
fn alarm_start(&self) -> TimerEtmTask {
TimerEtmTask { id: 90 + TG::id() }
}

/// ETM task to stop the counter
fn cnt_stop(&self) -> TimerEtmTask {
TimerEtmTask { id: 92 + TG::id() }
}

/// ETM task to reload the counter
fn cnt_reload(&self) -> TimerEtmTask {
TimerEtmTask { id: 94 + TG::id() }
}

/// ETM task to load the counter with the value stored when the last
/// `now()` was called
fn cnt_cap(&self) -> TimerEtmTask {
TimerEtmTask { id: 96 + TG::id() }
}
}
}
90 changes: 90 additions & 0 deletions examples/src/bin/etm_timer.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,90 @@
//! This shows how to use the general purpose timers ETM tasks and events
//! Notice you need to import the traits esp_hal::timer::etm::{TimerEtmEvents, TimerEtmTasks}
//% CHIPS: esp32c6 esp32h2

#![no_std]
#![no_main]

use core::cell::RefCell;

use critical_section::Mutex;
use esp_backtrace as _;
use esp_hal::{
clock::ClockControl,
delay::Delay,
etm::Etm,
interrupt::{self, Priority},
peripherals::{Interrupt, Peripherals, TIMG0},
prelude::*,
timer::{
etm::{TimerEtmEvents, TimerEtmTasks},
Timer,
Timer0,
TimerGroup,
},
};

static TIMER0: Mutex<RefCell<Option<Timer<Timer0<TIMG0>>>>> = Mutex::new(RefCell::new(None));

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

let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks);
let mut timer0 = timg0.timer0;

// Configure ETM to stop timer0 when alarm is triggered
let event = timer0.on_alarm();
let task = timer0.cnt_stop();

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

let channel0 = etm.channel0;

let _configured_channel = channel0.setup(&event, &task);

// Setup alarm at 100ms
// 80 / 2 (default divider) timer clock cycles == 1 us
timer0.load_alarm_value(100 * 1_000 * 40);
timer0.set_alarm_active(true);

// Enable interrupt that will be triggered by the alarm
interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap();

timer0.listen();
timer0.set_counter_active(true);

critical_section::with(|cs| {
TIMER0.borrow_ref_mut(cs).replace(timer0);
});

let delay = Delay::new(&clocks);

loop {
delay.delay_millis(500u32);

critical_section::with(|cs| {
let mut timer0 = TIMER0.borrow_ref_mut(cs);
let timer0 = timer0.as_mut().unwrap();
// Counter value should be the same than in interrupt
esp_println::println!("counter in main: {}", timer0.now());
});
}
}

#[interrupt]
fn TG0_T0_LEVEL() {
critical_section::with(|cs| {
let mut timer0 = TIMER0.borrow_ref_mut(cs);
let timer0 = timer0.as_mut().unwrap();

timer0.clear_interrupt();

// Counter value should be a very small number as the alarm triggered a counter reload to 0
// and ETM stopped the counter quickly after
esp_println::println!("counter in interrupt: {}", timer0.now());
});
}

0 comments on commit e2d82b7

Please sign in to comment.