From 3e31b93c195b45accc0096814cec8bc783417aee Mon Sep 17 00:00:00 2001 From: Alexandre Levy Date: Wed, 13 Mar 2024 22:00:33 +0000 Subject: [PATCH 01/16] Implement ETM for general purpose timers --- esp-hal/src/embassy/time_driver_timg.rs | 10 +- esp-hal/src/soc/esp32c6/mod.rs | 4 +- esp-hal/src/timer.rs | 140 ++++++++++++++++++------ examples/src/bin/timer_interrupt.rs | 19 +++- 4 files changed, 133 insertions(+), 40 deletions(-) diff --git a/esp-hal/src/embassy/time_driver_timg.rs b/esp-hal/src/embassy/time_driver_timg.rs index e0df9fe8a9f..06e3b95ddb2 100644 --- a/esp-hal/src/embassy/time_driver_timg.rs +++ b/esp-hal/src/embassy/time_driver_timg.rs @@ -16,7 +16,7 @@ pub const ALARM_COUNT: usize = 1; #[cfg(any(esp32, esp32s2, esp32s3))] pub const ALARM_COUNT: usize = 2; -pub type TimerType = TimerGroup<'static, TIMG0>; +pub type TimerType = TimerGroup<'static, TIMG0, 0>; pub struct EmbassyTimer { pub(crate) alarms: Mutex<[AlarmState; ALARM_COUNT]>, @@ -30,7 +30,7 @@ embassy_time_driver::time_driver_impl!(static DRIVER: EmbassyTimer = EmbassyTime impl EmbassyTimer { pub(crate) fn now() -> u64 { - unsafe { Timer0::::steal() }.now() + unsafe { Timer0::::steal() }.now() } fn trigger_alarm(&self, n: usize, cs: CriticalSection) { @@ -77,7 +77,7 @@ impl EmbassyTimer { #[interrupt] fn TG0_T0_LEVEL() { - let timer = unsafe { Timer0::::steal() }; + let timer = unsafe { Timer0::::steal() }; DRIVER.on_interrupt(0, timer); } @@ -100,12 +100,12 @@ impl EmbassyTimer { // critical section. #[cfg(any(esp32, esp32s2, esp32s3))] if _alarm.id() == 1 { - let mut tg = unsafe { Timer1::::steal() }; + let mut tg = unsafe { Timer1::::steal() }; Self::arm(&mut tg, timestamp); return; } - let mut tg = unsafe { Timer0::::steal() }; + let mut tg = unsafe { Timer0::::steal() }; Self::arm(&mut tg, timestamp); }); diff --git a/esp-hal/src/soc/esp32c6/mod.rs b/esp-hal/src/soc/esp32c6/mod.rs index 5e839472323..24bf3917611 100644 --- a/esp-hal/src/soc/esp32c6/mod.rs +++ b/esp-hal/src/soc/esp32c6/mod.rs @@ -49,6 +49,6 @@ unsafe fn post_init() { rtc.swd.disable(); rtc.rwdt.disable(); - Wdt::::set_wdt_enabled(false); - Wdt::::set_wdt_enabled(false); + Wdt::::set_wdt_enabled(false); + Wdt::::set_wdt_enabled(false); } diff --git a/esp-hal/src/timer.rs b/esp-hal/src/timer.rs index e4e293674c0..2918fc46c12 100644 --- a/esp-hal/src/timer.rs +++ b/esp-hal/src/timer.rs @@ -68,24 +68,24 @@ pub enum Error { // A timergroup consisting of up to 2 timers (chip dependent) and a watchdog // timer -pub struct TimerGroup<'d, T> +pub struct TimerGroup<'d, T, const G: u8> where - T: TimerGroupInstance, + T: TimerGroupInstance, { _timer_group: PeripheralRef<'d, T>, - pub timer0: Timer>, + pub timer0: Timer>, #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] pub timer1: Timer>, - pub wdt: Wdt, + pub wdt: Wdt, } -pub trait TimerGroupInstance { +pub trait TimerGroupInstance { fn register_block() -> *const RegisterBlock; fn configure_src_clk(); fn configure_wdt_src_clk(); } -impl TimerGroupInstance for TIMG0 { +impl TimerGroupInstance<0> for TIMG0 { #[inline(always)] fn register_block() -> *const RegisterBlock { crate::peripherals::TIMG0::PTR @@ -135,7 +135,7 @@ impl TimerGroupInstance for TIMG0 { } #[cfg(timg1)] -impl TimerGroupInstance for TIMG1 { +impl TimerGroupInstance<1> for TIMG1 { #[inline(always)] fn register_block() -> *const RegisterBlock { crate::peripherals::TIMG1::PTR @@ -177,9 +177,9 @@ impl TimerGroupInstance for TIMG1 { } } -impl<'d, T> TimerGroup<'d, T> +impl<'d, T, const G: u8> TimerGroup<'d, T, G> where - T: TimerGroupInstance, + T: TimerGroupInstance, { pub fn new(timer_group: impl Peripheral

+ 'd, clocks: &Clocks) -> Self { crate::into_ref!(timer_group); @@ -296,13 +296,13 @@ pub trait Instance { fn enable_peripheral(&self); } -pub struct Timer0 { +pub struct Timer0 { phantom: PhantomData, } -impl Timer0 +impl Timer0 where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { #[allow(unused)] pub(crate) unsafe fn steal() -> Self { @@ -313,9 +313,9 @@ where } /// Timer peripheral instance -impl Instance for Timer0 +impl Instance for Timer0 where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { fn reset_counter(&mut self) { let reg_block = unsafe { &*TG::register_block() }; @@ -465,14 +465,14 @@ where } #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] -pub struct Timer1 { - phantom: PhantomData, +pub struct Timer1 { + phantom: PhantomData, } #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] -impl Timer1 +impl Timer1 where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { #[allow(unused)] pub(crate) unsafe fn steal() -> Self { @@ -484,9 +484,9 @@ where /// Timer peripheral instance #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] -impl Instance for Timer1 +impl Instance for Timer1 where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { fn reset_counter(&mut self) { let reg_block = unsafe { &*TG::register_block() }; @@ -715,14 +715,14 @@ where impl Periodic for Timer where T: Instance {} /// Watchdog timer -pub struct Wdt { +pub struct Wdt { phantom: PhantomData, } /// Watchdog driver -impl Wdt +impl Wdt where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { /// Create a new watchdog timer instance pub fn new() -> Self { @@ -835,27 +835,27 @@ where } } -impl Default for Wdt +impl Default for Wdt where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { fn default() -> Self { Self::new() } } -impl WatchdogDisable for Wdt +impl WatchdogDisable for Wdt where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { fn disable(&mut self) { self.disable(); } } -impl WatchdogEnable for Wdt +impl WatchdogEnable for Wdt where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { type Time = MicrosDurationU64; @@ -868,11 +868,89 @@ where } } -impl Watchdog for Wdt +impl Watchdog for Wdt where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { fn feed(&mut self) { 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 {} + + pub trait TimerEtmEvents { + fn on_alarm(&self) -> TimerEtmEvent; + } + + pub trait TimerEtmTasks { + 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 TimerEtmEvents for Timer0 + where + TG: TimerGroupInstance, + { + fn on_alarm(&self) -> TimerEtmEvent { + TimerEtmEvent { id: 48 + G } + } + } + + impl TimerEtmTasks for Timer0 + where + TG: TimerGroupInstance, + { + fn cnt_start(&self) -> TimerEtmTask { + TimerEtmTask { id: 88 + G } + } + + fn alarm_start(&self) -> TimerEtmTask { + TimerEtmTask { id: 90 + G } + } + + fn cnt_stop(&self) -> TimerEtmTask { + TimerEtmTask { id: 92 + G } + } + + fn cnt_reload(&self) -> TimerEtmTask { + TimerEtmTask { id: 94 + G } + } + fn cnt_cap(&self) -> TimerEtmTask { + TimerEtmTask { id: 96 + G } + } + } +} diff --git a/examples/src/bin/timer_interrupt.rs b/examples/src/bin/timer_interrupt.rs index 62e4194f94a..91cc3c68adf 100644 --- a/examples/src/bin/timer_interrupt.rs +++ b/examples/src/bin/timer_interrupt.rs @@ -13,13 +13,19 @@ use critical_section::Mutex; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, + etm::Etm, interrupt::{self, Priority}, peripherals::{Interrupt, Peripherals, TIMG0}, prelude::*, - timer::{Timer, Timer0, TimerGroup}, + timer::{ + etm::{TimerEtmEvents, TimerEtmTasks}, + Timer, + Timer0, + TimerGroup, + }, }; -static TIMER0: Mutex>>>> = Mutex::new(RefCell::new(None)); +static TIMER0: Mutex>>>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { @@ -30,6 +36,15 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let mut timer0 = timg0.timer0; + let ev = timer0.on_alarm(); + let tsk = timer0.cnt_start(); + + let etm = Etm::new(peripherals.SOC_ETM); + + let chan0 = etm.channel0; + + chan0.setup(&ev, &tsk); + interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap(); timer0.start(500u64.millis()); timer0.listen(); From c39d26ad12239a3640469704cb5714b681fe7646 Mon Sep 17 00:00:00 2001 From: Alexandre Levy Date: Wed, 13 Mar 2024 22:14:25 +0000 Subject: [PATCH 02/16] Revert changes to timer_interrupt example --- examples/src/bin/timer_interrupt.rs | 19 ++----------------- 1 file changed, 2 insertions(+), 17 deletions(-) diff --git a/examples/src/bin/timer_interrupt.rs b/examples/src/bin/timer_interrupt.rs index 91cc3c68adf..62e4194f94a 100644 --- a/examples/src/bin/timer_interrupt.rs +++ b/examples/src/bin/timer_interrupt.rs @@ -13,19 +13,13 @@ use critical_section::Mutex; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, - etm::Etm, interrupt::{self, Priority}, peripherals::{Interrupt, Peripherals, TIMG0}, prelude::*, - timer::{ - etm::{TimerEtmEvents, TimerEtmTasks}, - Timer, - Timer0, - TimerGroup, - }, + timer::{Timer, Timer0, TimerGroup}, }; -static TIMER0: Mutex>>>> = Mutex::new(RefCell::new(None)); +static TIMER0: Mutex>>>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { @@ -36,15 +30,6 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let mut timer0 = timg0.timer0; - let ev = timer0.on_alarm(); - let tsk = timer0.cnt_start(); - - let etm = Etm::new(peripherals.SOC_ETM); - - let chan0 = etm.channel0; - - chan0.setup(&ev, &tsk); - interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap(); timer0.start(500u64.millis()); timer0.listen(); From c17f93c44c15d0861686ad7a3906aa64c74a04e4 Mon Sep 17 00:00:00 2001 From: Alexandre Levy Date: Wed, 13 Mar 2024 22:41:22 +0000 Subject: [PATCH 03/16] Add an example for ETM for general purpose timers --- examples/src/bin/etm_timer.rs | 72 +++++++++++++++++++++++++++++++++++ 1 file changed, 72 insertions(+) create mode 100644 examples/src/bin/etm_timer.rs diff --git a/examples/src/bin/etm_timer.rs b/examples/src/bin/etm_timer.rs new file mode 100644 index 00000000000..ecefcc6ed76 --- /dev/null +++ b/examples/src/bin/etm_timer.rs @@ -0,0 +1,72 @@ +//! 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 + +#![no_std] +#![no_main] + +use core::cell::RefCell; + +use critical_section::{CriticalSection, Mutex}; +use esp_backtrace as _; +use esp_hal::{ + clock::ClockControl, + etm::Etm, + interrupt::{self, Priority}, + peripherals::{Interrupt, Peripherals, TIMG0}, + prelude::*, + timer::{ + etm::{TimerEtmEvents, TimerEtmTasks}, + Timer, + Timer0, + TimerGroup, + }, +}; + +static TIMER0: Mutex>>>> = 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; + + interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap(); + + // Alarm at 100ms (80 clock cycles in 1 us) + timer0.load_alarm_value(100 * 1_000 * 80); + timer0.set_alarm_active(true); + + let event = timer0.on_alarm(); + let task = timer0.cnt_stop(); + + let etm = Etm::new(peripherals.SOC_ETM); + + let channel0 = etm.channel0; + + channel0.setup(&event, &task); + + timer0.set_counter_active(true); + + critical_section::with(|cs| { + TIMER0.borrow_ref_mut(cs).replace(timer0); + }); + + loop {} +} + +#[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(); + + esp_println::println!("Counter: {}", timer0.now()); + }); +} From 218a321fb3acd847196a3f2c031d4a90331f331d Mon Sep 17 00:00:00 2001 From: Alexandre Levy Date: Wed, 13 Mar 2024 22:42:01 +0000 Subject: [PATCH 04/16] Add newly introduced generic const param for Timer0 --- examples/src/bin/timer_interrupt.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/bin/timer_interrupt.rs b/examples/src/bin/timer_interrupt.rs index 62e4194f94a..9de28ff8d74 100644 --- a/examples/src/bin/timer_interrupt.rs +++ b/examples/src/bin/timer_interrupt.rs @@ -19,7 +19,7 @@ use esp_hal::{ timer::{Timer, Timer0, TimerGroup}, }; -static TIMER0: Mutex>>>> = Mutex::new(RefCell::new(None)); +static TIMER0: Mutex>>>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { From 0d055c07e4ac59fb9333febec021720a07a0972a Mon Sep 17 00:00:00 2001 From: Alex Levy Date: Thu, 14 Mar 2024 12:34:57 +0000 Subject: [PATCH 05/16] Use id function on TimerGroupInstance instead of const parameter --- esp-hal/src/embassy/time_driver_timg.rs | 8 +-- esp-hal/src/soc/esp32c6/mod.rs | 4 +- esp-hal/src/timer.rs | 93 +++++++++++++------------ examples/src/bin/etm_timer.rs | 2 +- examples/src/bin/timer_interrupt.rs | 2 +- 5 files changed, 58 insertions(+), 51 deletions(-) diff --git a/esp-hal/src/embassy/time_driver_timg.rs b/esp-hal/src/embassy/time_driver_timg.rs index 06e3b95ddb2..fc4d4d491ab 100644 --- a/esp-hal/src/embassy/time_driver_timg.rs +++ b/esp-hal/src/embassy/time_driver_timg.rs @@ -16,7 +16,7 @@ pub const ALARM_COUNT: usize = 1; #[cfg(any(esp32, esp32s2, esp32s3))] pub const ALARM_COUNT: usize = 2; -pub type TimerType = TimerGroup<'static, TIMG0, 0>; +pub type TimerType = TimerGroup<'static, TIMG0>; pub struct EmbassyTimer { pub(crate) alarms: Mutex<[AlarmState; ALARM_COUNT]>, @@ -30,7 +30,7 @@ embassy_time_driver::time_driver_impl!(static DRIVER: EmbassyTimer = EmbassyTime impl EmbassyTimer { pub(crate) fn now() -> u64 { - unsafe { Timer0::::steal() }.now() + unsafe { Timer0::::steal() }.now() } fn trigger_alarm(&self, n: usize, cs: CriticalSection) { @@ -77,7 +77,7 @@ impl EmbassyTimer { #[interrupt] fn TG0_T0_LEVEL() { - let timer = unsafe { Timer0::::steal() }; + let timer = unsafe { Timer0::::steal() }; DRIVER.on_interrupt(0, timer); } @@ -105,7 +105,7 @@ impl EmbassyTimer { return; } - let mut tg = unsafe { Timer0::::steal() }; + let mut tg = unsafe { Timer0::::steal() }; Self::arm(&mut tg, timestamp); }); diff --git a/esp-hal/src/soc/esp32c6/mod.rs b/esp-hal/src/soc/esp32c6/mod.rs index 8efdb21244a..96e22cf7c28 100644 --- a/esp-hal/src/soc/esp32c6/mod.rs +++ b/esp-hal/src/soc/esp32c6/mod.rs @@ -49,6 +49,6 @@ unsafe fn post_init() { rtc.swd.disable(); rtc.rwdt.disable(); - Wdt::::set_wdt_enabled(false); - Wdt::::set_wdt_enabled(false); + Wdt::::set_wdt_enabled(false); + Wdt::::set_wdt_enabled(false); } diff --git a/esp-hal/src/timer.rs b/esp-hal/src/timer.rs index 2918fc46c12..3547dd72376 100644 --- a/esp-hal/src/timer.rs +++ b/esp-hal/src/timer.rs @@ -68,24 +68,28 @@ pub enum Error { // A timergroup consisting of up to 2 timers (chip dependent) and a watchdog // timer -pub struct TimerGroup<'d, T, const G: u8> +pub struct TimerGroup<'d, T> where - T: TimerGroupInstance, + T: TimerGroupInstance, { _timer_group: PeripheralRef<'d, T>, - pub timer0: Timer>, + pub timer0: Timer>, #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] pub timer1: Timer>, - pub wdt: Wdt, + pub wdt: Wdt, } -pub trait TimerGroupInstance { +pub trait TimerGroupInstance { fn register_block() -> *const RegisterBlock; fn configure_src_clk(); fn configure_wdt_src_clk(); + fn id() -> u8; } -impl TimerGroupInstance<0> for TIMG0 { +impl TimerGroupInstance for TIMG0 { + fn id() -> u8 { + 0 + } #[inline(always)] fn register_block() -> *const RegisterBlock { crate::peripherals::TIMG0::PTR @@ -135,7 +139,10 @@ impl TimerGroupInstance<0> for TIMG0 { } #[cfg(timg1)] -impl TimerGroupInstance<1> for TIMG1 { +impl TimerGroupInstance for TIMG1 { + fn id() -> u8 { + 1 + } #[inline(always)] fn register_block() -> *const RegisterBlock { crate::peripherals::TIMG1::PTR @@ -177,9 +184,9 @@ impl TimerGroupInstance<1> for TIMG1 { } } -impl<'d, T, const G: u8> TimerGroup<'d, T, G> +impl<'d, T> TimerGroup<'d, T> where - T: TimerGroupInstance, + T: TimerGroupInstance, { pub fn new(timer_group: impl Peripheral

+ 'd, clocks: &Clocks) -> Self { crate::into_ref!(timer_group); @@ -296,13 +303,13 @@ pub trait Instance { fn enable_peripheral(&self); } -pub struct Timer0 { +pub struct Timer0 { phantom: PhantomData, } -impl Timer0 +impl Timer0 where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { #[allow(unused)] pub(crate) unsafe fn steal() -> Self { @@ -313,9 +320,9 @@ where } /// Timer peripheral instance -impl Instance for Timer0 +impl Instance for Timer0 where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { fn reset_counter(&mut self) { let reg_block = unsafe { &*TG::register_block() }; @@ -465,14 +472,14 @@ where } #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] -pub struct Timer1 { - phantom: PhantomData, +pub struct Timer1 { + phantom: PhantomData, } #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] -impl Timer1 +impl Timer1 where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { #[allow(unused)] pub(crate) unsafe fn steal() -> Self { @@ -484,9 +491,9 @@ where /// Timer peripheral instance #[cfg(not(any(esp32c2, esp32c3, esp32c6, esp32h2)))] -impl Instance for Timer1 +impl Instance for Timer1 where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { fn reset_counter(&mut self) { let reg_block = unsafe { &*TG::register_block() }; @@ -715,14 +722,14 @@ where impl Periodic for Timer where T: Instance {} /// Watchdog timer -pub struct Wdt { +pub struct Wdt { phantom: PhantomData, } /// Watchdog driver -impl Wdt +impl Wdt where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { /// Create a new watchdog timer instance pub fn new() -> Self { @@ -835,27 +842,27 @@ where } } -impl Default for Wdt +impl Default for Wdt where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { fn default() -> Self { Self::new() } } -impl WatchdogDisable for Wdt +impl WatchdogDisable for Wdt where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { fn disable(&mut self) { self.disable(); } } -impl WatchdogEnable for Wdt +impl WatchdogEnable for Wdt where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { type Time = MicrosDurationU64; @@ -868,9 +875,9 @@ where } } -impl Watchdog for Wdt +impl Watchdog for Wdt where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { fn feed(&mut self) { self.feed(); @@ -909,11 +916,11 @@ pub mod etm { impl Sealed for TimerEtmTask {} - pub trait TimerEtmEvents { + pub trait TimerEtmEvents { fn on_alarm(&self) -> TimerEtmEvent; } - pub trait TimerEtmTasks { + pub trait TimerEtmTasks { fn cnt_start(&self) -> TimerEtmTask; fn cnt_stop(&self) -> TimerEtmTask; fn cnt_reload(&self) -> TimerEtmTask; @@ -921,36 +928,36 @@ pub mod etm { fn alarm_start(&self) -> TimerEtmTask; } - impl TimerEtmEvents for Timer0 + impl TimerEtmEvents for Timer0 where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { fn on_alarm(&self) -> TimerEtmEvent { - TimerEtmEvent { id: 48 + G } + TimerEtmEvent { id: 48 + TG::id() } } } - impl TimerEtmTasks for Timer0 + impl TimerEtmTasks for Timer0 where - TG: TimerGroupInstance, + TG: TimerGroupInstance, { fn cnt_start(&self) -> TimerEtmTask { - TimerEtmTask { id: 88 + G } + TimerEtmTask { id: 88 + TG::id() } } fn alarm_start(&self) -> TimerEtmTask { - TimerEtmTask { id: 90 + G } + TimerEtmTask { id: 90 + TG::id() } } fn cnt_stop(&self) -> TimerEtmTask { - TimerEtmTask { id: 92 + G } + TimerEtmTask { id: 92 + TG::id() } } fn cnt_reload(&self) -> TimerEtmTask { - TimerEtmTask { id: 94 + G } + TimerEtmTask { id: 94 + TG::id() } } fn cnt_cap(&self) -> TimerEtmTask { - TimerEtmTask { id: 96 + G } + TimerEtmTask { id: 96 + TG::id() } } } } diff --git a/examples/src/bin/etm_timer.rs b/examples/src/bin/etm_timer.rs index ecefcc6ed76..b260e8362f4 100644 --- a/examples/src/bin/etm_timer.rs +++ b/examples/src/bin/etm_timer.rs @@ -24,7 +24,7 @@ use esp_hal::{ }, }; -static TIMER0: Mutex>>>> = Mutex::new(RefCell::new(None)); +static TIMER0: Mutex>>>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { diff --git a/examples/src/bin/timer_interrupt.rs b/examples/src/bin/timer_interrupt.rs index 9de28ff8d74..62e4194f94a 100644 --- a/examples/src/bin/timer_interrupt.rs +++ b/examples/src/bin/timer_interrupt.rs @@ -19,7 +19,7 @@ use esp_hal::{ timer::{Timer, Timer0, TimerGroup}, }; -static TIMER0: Mutex>>>> = Mutex::new(RefCell::new(None)); +static TIMER0: Mutex>>>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { From 799bf56bdf5728ca67da8515e62b6c0ae13289a2 Mon Sep 17 00:00:00 2001 From: Alex Levy Date: Thu, 14 Mar 2024 12:38:24 +0000 Subject: [PATCH 06/16] Revert const parameter on Timer1 --- esp-hal/src/embassy/time_driver_timg.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp-hal/src/embassy/time_driver_timg.rs b/esp-hal/src/embassy/time_driver_timg.rs index fc4d4d491ab..e0df9fe8a9f 100644 --- a/esp-hal/src/embassy/time_driver_timg.rs +++ b/esp-hal/src/embassy/time_driver_timg.rs @@ -100,7 +100,7 @@ impl EmbassyTimer { // critical section. #[cfg(any(esp32, esp32s2, esp32s3))] if _alarm.id() == 1 { - let mut tg = unsafe { Timer1::::steal() }; + let mut tg = unsafe { Timer1::::steal() }; Self::arm(&mut tg, timestamp); return; } From c1d79b50c29ab2a8f401c5d16d68a061fafae9c3 Mon Sep 17 00:00:00 2001 From: Alex Levy Date: Thu, 14 Mar 2024 12:44:21 +0000 Subject: [PATCH 07/16] Specify supported chips --- examples/src/bin/etm_timer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/bin/etm_timer.rs b/examples/src/bin/etm_timer.rs index b260e8362f4..dc7e645bee1 100644 --- a/examples/src/bin/etm_timer.rs +++ b/examples/src/bin/etm_timer.rs @@ -1,7 +1,7 @@ //! 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 +//% CHIPS: esp32h2 esp32c6 #![no_std] #![no_main] From a72c4147a30c22117226a538c4bdc5cff20db6a8 Mon Sep 17 00:00:00 2001 From: Alex Levy Date: Thu, 14 Mar 2024 12:48:25 +0000 Subject: [PATCH 08/16] Update CHANGELOG.md --- esp-hal/CHANGELOG.md | 2 ++ 1 file changed, 2 insertions(+) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 24f0b800884..5b1d372a264 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -9,6 +9,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added +- Support `ETM` for ESP32-C6 / ESP32-H2 general purpose timers (#1274) + ### Fixed - Fixing `esp-wifi` + `TRNG` issue on `ESP32-S2` (#1272) From 8ef64e6edce77517f79ab895c0d0470567960fac Mon Sep 17 00:00:00 2001 From: Alex Levy Date: Thu, 14 Mar 2024 12:51:37 +0000 Subject: [PATCH 09/16] Update CHANGELOG.md --- esp-hal/CHANGELOG.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 5b1d372a264..66960fc7287 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -9,7 +9,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added -- Support `ETM` for ESP32-C6 / ESP32-H2 general purpose timers (#1274) +- ESP32-C6 / ESP32-H2: Implement `ETM` for general purpose timers (#1274) ### Fixed From 27324503ee1c2cd8ad28f1caa9014740a64edf76 Mon Sep 17 00:00:00 2001 From: Alex Levy Date: Thu, 14 Mar 2024 13:19:14 +0000 Subject: [PATCH 10/16] Fix example --- examples/src/bin/etm_timer.rs | 19 +++++++++++++------ 1 file changed, 13 insertions(+), 6 deletions(-) diff --git a/examples/src/bin/etm_timer.rs b/examples/src/bin/etm_timer.rs index dc7e645bee1..59bd73b02e9 100644 --- a/examples/src/bin/etm_timer.rs +++ b/examples/src/bin/etm_timer.rs @@ -35,12 +35,7 @@ fn main() -> ! { let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let mut timer0 = timg0.timer0; - interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap(); - - // Alarm at 100ms (80 clock cycles in 1 us) - timer0.load_alarm_value(100 * 1_000 * 80); - timer0.set_alarm_active(true); - + // Configure ETM to stop timer0 when alarm is triggered let event = timer0.on_alarm(); let task = timer0.cnt_stop(); @@ -50,8 +45,19 @@ fn main() -> ! { channel0.setup(&event, &task); + timer0.set_counter_decrementing(false); + timer0.reset_counter(); timer0.set_counter_active(true); + // Setup alarm at 100ms + // 80 / 2 (default divider) timer clock cycles == 1 us + timer0.load_alarm_value(100 * 1_000 * 40); + + // Enable interrupt that will be triggered by the alarm + interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap(); + + timer0.set_alarm_active(true); + critical_section::with(|cs| { TIMER0.borrow_ref_mut(cs).replace(timer0); }); @@ -67,6 +73,7 @@ fn TG0_T0_LEVEL() { timer0.clear_interrupt(); + // This should display close to 4_000_000 esp_println::println!("Counter: {}", timer0.now()); }); } From 4a3e0921ff332f62e4e6ce12799690fc7a2e1a2e Mon Sep 17 00:00:00 2001 From: Alexandre Levy Date: Fri, 15 Mar 2024 01:32:45 +0000 Subject: [PATCH 11/16] Assign configured ETM channel to a variable to prevent drop --- examples/src/bin/etm_timer.rs | 34 ++++++++++++++++++++++------------ 1 file changed, 22 insertions(+), 12 deletions(-) diff --git a/examples/src/bin/etm_timer.rs b/examples/src/bin/etm_timer.rs index 59bd73b02e9..cadacbb13e3 100644 --- a/examples/src/bin/etm_timer.rs +++ b/examples/src/bin/etm_timer.rs @@ -1,17 +1,18 @@ //! 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: esp32h2 esp32c6 + +//% CHIPS: esp32c6 esp32h2 #![no_std] #![no_main] use core::cell::RefCell; -use critical_section::{CriticalSection, Mutex}; +use critical_section::Mutex; use esp_backtrace as _; use esp_hal::{ clock::ClockControl, + delay::Delay, etm::Etm, interrupt::{self, Priority}, peripherals::{Interrupt, Peripherals, TIMG0}, @@ -32,6 +33,8 @@ fn main() -> ! { let system = peripherals.SYSTEM.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); + let mut delay = Delay::new(&clocks); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let mut timer0 = timg0.timer0; @@ -43,26 +46,33 @@ fn main() -> ! { let channel0 = etm.channel0; - channel0.setup(&event, &task); - - timer0.set_counter_decrementing(false); - timer0.reset_counter(); - timer0.set_counter_active(true); + 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.set_alarm_active(true); + timer0.listen(); + timer0.set_counter_active(true); critical_section::with(|cs| { TIMER0.borrow_ref_mut(cs).replace(timer0); }); - loop {} + loop { + delay.delay_ms(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 because we configured ETM to stop the timer on alarm + esp_println::println!("counter in main: {}", timer0.now()); + }); + } } #[interrupt] @@ -73,7 +83,7 @@ fn TG0_T0_LEVEL() { timer0.clear_interrupt(); - // This should display close to 4_000_000 - esp_println::println!("Counter: {}", timer0.now()); + // Counter value should be a very small number + esp_println::println!("counter in interrupt: {}", timer0.now()); }); } From 228cebd543faa5108a447dcfb5ea956056fc06d4 Mon Sep 17 00:00:00 2001 From: Alexandre Levy Date: Fri, 15 Mar 2024 01:50:00 +0000 Subject: [PATCH 12/16] Fix comments --- examples/src/bin/etm_timer.rs | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/examples/src/bin/etm_timer.rs b/examples/src/bin/etm_timer.rs index cadacbb13e3..b7e50e8bda9 100644 --- a/examples/src/bin/etm_timer.rs +++ b/examples/src/bin/etm_timer.rs @@ -69,7 +69,7 @@ fn main() -> ! { 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 because we configured ETM to stop the timer on alarm + // Counter value should be the same than in interrupt esp_println::println!("counter in main: {}", timer0.now()); }); } @@ -83,7 +83,8 @@ fn TG0_T0_LEVEL() { timer0.clear_interrupt(); - // Counter value should be a very small number + // 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()); }); } From 73ca5d2e89d526aacb91a00f11f0d1efed8fd721 Mon Sep 17 00:00:00 2001 From: Alexandre Levy Date: Fri, 15 Mar 2024 02:03:54 +0000 Subject: [PATCH 13/16] Move declaration of delay after critical section --- examples/src/bin/etm_timer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/examples/src/bin/etm_timer.rs b/examples/src/bin/etm_timer.rs index b7e50e8bda9..7708f823a82 100644 --- a/examples/src/bin/etm_timer.rs +++ b/examples/src/bin/etm_timer.rs @@ -33,8 +33,6 @@ fn main() -> ! { let system = peripherals.SYSTEM.split(); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let mut delay = Delay::new(&clocks); - let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks); let mut timer0 = timg0.timer0; @@ -63,6 +61,8 @@ fn main() -> ! { TIMER0.borrow_ref_mut(cs).replace(timer0); }); + let mut delay = Delay::new(&clocks); + loop { delay.delay_ms(500u32); From 20ea0d193e2c6b4977bbab0405a5d39082085b3a Mon Sep 17 00:00:00 2001 From: Alexandre Levy Date: Fri, 15 Mar 2024 10:05:18 +0000 Subject: [PATCH 14/16] Use delay_millis instead of delay_ms --- examples/src/bin/etm_timer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/bin/etm_timer.rs b/examples/src/bin/etm_timer.rs index 7708f823a82..96296fb5cb1 100644 --- a/examples/src/bin/etm_timer.rs +++ b/examples/src/bin/etm_timer.rs @@ -64,7 +64,7 @@ fn main() -> ! { let mut delay = Delay::new(&clocks); loop { - delay.delay_ms(500u32); + delay.delay_millis(500u32); critical_section::with(|cs| { let mut timer0 = TIMER0.borrow_ref_mut(cs); From eb2d58c17fd86c150aafb4cf6b087933eb678ec1 Mon Sep 17 00:00:00 2001 From: Alexandre Levy Date: Fri, 15 Mar 2024 10:13:43 +0000 Subject: [PATCH 15/16] Remove mut from delay --- examples/src/bin/etm_timer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/examples/src/bin/etm_timer.rs b/examples/src/bin/etm_timer.rs index 96296fb5cb1..391e08942c3 100644 --- a/examples/src/bin/etm_timer.rs +++ b/examples/src/bin/etm_timer.rs @@ -61,7 +61,7 @@ fn main() -> ! { TIMER0.borrow_ref_mut(cs).replace(timer0); }); - let mut delay = Delay::new(&clocks); + let delay = Delay::new(&clocks); loop { delay.delay_millis(500u32); From b6d730268cde4ce98347420dd4f9f17ebf1e2d5e Mon Sep 17 00:00:00 2001 From: Alexandre Levy Date: Fri, 15 Mar 2024 10:24:15 +0000 Subject: [PATCH 16/16] Add documentation --- esp-hal/src/timer.rs | 10 ++++++++++ 1 file changed, 10 insertions(+) diff --git a/esp-hal/src/timer.rs b/esp-hal/src/timer.rs index f3721f45938..ad97998c5c9 100644 --- a/esp-hal/src/timer.rs +++ b/esp-hal/src/timer.rs @@ -918,10 +918,12 @@ pub mod etm { impl Sealed for TimerEtmTask {} + /// General purpose timer ETM events pub trait TimerEtmEvents { fn on_alarm(&self) -> TimerEtmEvent; } + /// General purpose timer ETM tasks pub trait TimerEtmTasks { fn cnt_start(&self) -> TimerEtmTask; fn cnt_stop(&self) -> TimerEtmTask; @@ -934,6 +936,7 @@ pub mod etm { where TG: TimerGroupInstance, { + /// ETM event triggered on alarm fn on_alarm(&self) -> TimerEtmEvent { TimerEtmEvent { id: 48 + TG::id() } } @@ -943,21 +946,28 @@ pub mod etm { 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() } }