From 1cf6c2e7cc326242d927cc7ae39eed46bb788252 Mon Sep 17 00:00:00 2001 From: Dominic Fischer Date: Sun, 28 Jul 2024 17:18:22 +0100 Subject: [PATCH 1/5] Improve SYSTIMER API --- esp-hal/CHANGELOG.md | 2 +- esp-hal/src/timer/mod.rs | 36 +- esp-hal/src/timer/systimer.rs | 928 ++++++++++++------ examples/src/bin/embassy_multiprio.rs | 3 +- examples/src/bin/embassy_parl_io_rx.rs | 8 +- examples/src/bin/embassy_parl_io_tx.rs | 8 +- examples/src/bin/etm_blinky_systimer.rs | 5 +- examples/src/bin/systimer.rs | 29 +- examples/src/bin/wifi_embassy_access_point.rs | 3 +- .../bin/wifi_embassy_access_point_with_sta.rs | 3 +- examples/src/bin/wifi_embassy_bench.rs | 3 +- examples/src/bin/wifi_embassy_ble.rs | 3 +- examples/src/bin/wifi_embassy_dhcp.rs | 3 +- examples/src/bin/wifi_embassy_esp_now.rs | 3 +- .../src/bin/wifi_embassy_esp_now_duplex.rs | 3 +- 15 files changed, 705 insertions(+), 335 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 593a808ff83..1ad69f6685d 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -15,7 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Peripheral driver constructors don't take `InterruptHandler`s anymore. Use `set_interrupt_handler` to explicitly set the interrupt handler now. (#1819) - Use the peripheral ref pattern for `OneShotTimer` and `PeriodicTimer` (#1855) - +- Improve SYSTIMER API (#1870) - Allow DMA to/from psram for esp32s3 (#1827) - DMA buffers now don't require a static lifetime. Make sure to never `mem::forget` an in-progress DMA transfer (consider using `#[deny(clippy::mem_forget)]`) (#1837) diff --git a/esp-hal/src/timer/mod.rs b/esp-hal/src/timer/mod.rs index 5cf4391105f..58f581fd3a7 100644 --- a/esp-hal/src/timer/mod.rs +++ b/esp-hal/src/timer/mod.rs @@ -376,17 +376,17 @@ pub enum ErasedTimer { #[cfg(all(timg1, timg_timer1))] Timg1Timer1(timg::Timer, Blocking>), #[cfg(systimer)] - SystimerAlarm0Periodic(systimer::Alarm), + SystimerAlarm0Periodic(systimer::Alarm<'static, systimer::Periodic, Blocking, 0, 0>), #[cfg(systimer)] - SystimerAlarm1Periodic(systimer::Alarm), + SystimerAlarm1Periodic(systimer::Alarm<'static, systimer::Periodic, Blocking, 1, 0>), #[cfg(systimer)] - SystimerAlarm2Periodic(systimer::Alarm), + SystimerAlarm2Periodic(systimer::Alarm<'static, systimer::Periodic, Blocking, 2, 0>), #[cfg(systimer)] - SystimerAlarm0Target(systimer::Alarm), + SystimerAlarm0Target(systimer::Alarm<'static, systimer::Target, Blocking, 0, 0>), #[cfg(systimer)] - SystimerAlarm1Target(systimer::Alarm), + SystimerAlarm1Target(systimer::Alarm<'static, systimer::Target, Blocking, 1, 0>), #[cfg(systimer)] - SystimerAlarm2Target(systimer::Alarm), + SystimerAlarm2Target(systimer::Alarm<'static, systimer::Target, Blocking, 2, 0>), } impl crate::private::Sealed for ErasedTimer {} @@ -419,43 +419,43 @@ impl From, Blocking>> for Er } #[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm) -> Self { +impl From> for ErasedTimer { + fn from(value: systimer::Alarm<'static, systimer::Periodic, Blocking, 0, 0>) -> Self { Self::SystimerAlarm0Periodic(value) } } #[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm) -> Self { +impl From> for ErasedTimer { + fn from(value: systimer::Alarm<'static, systimer::Periodic, Blocking, 1, 0>) -> Self { Self::SystimerAlarm1Periodic(value) } } #[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm) -> Self { +impl From> for ErasedTimer { + fn from(value: systimer::Alarm<'static, systimer::Periodic, Blocking, 2, 0>) -> Self { Self::SystimerAlarm2Periodic(value) } } #[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm) -> Self { +impl From> for ErasedTimer { + fn from(value: systimer::Alarm<'static, systimer::Target, Blocking, 0, 0>) -> Self { Self::SystimerAlarm0Target(value) } } #[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm) -> Self { +impl From> for ErasedTimer { + fn from(value: systimer::Alarm<'static, systimer::Target, Blocking, 1, 0>) -> Self { Self::SystimerAlarm1Target(value) } } #[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm) -> Self { +impl From> for ErasedTimer { + fn from(value: systimer::Alarm<'static, systimer::Target, Blocking, 2, 0>) -> Self { Self::SystimerAlarm2Target(value) } } diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index aac957bfe81..9507c48ea7e 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -68,40 +68,51 @@ //! } //! ``` -use core::marker::PhantomData; +use core::{ + cell::Cell, + fmt::{Debug, Formatter}, + marker::PhantomData, + ptr::addr_of_mut, +}; +use critical_section::Mutex; use fugit::{Instant, MicrosDurationU32, MicrosDurationU64}; use super::{Error, Timer as _}; use crate::{ interrupt::{self, InterruptHandler}, peripheral::Peripheral, - peripherals::{ - systimer::{TARGET_CONF, TRGT}, - Interrupt, - SYSTIMER, - }, + peripherals::{Interrupt, SYSTIMER}, Async, Blocking, + Cpu, InterruptConfigurable, Mode, }; /// System Timer driver. -pub struct SystemTimer<'d, DM> -where - DM: Mode, -{ - _phantom: PhantomData<&'d ()>, - /// Alarm 0. - pub alarm0: Alarm, - /// Alarm 1. - pub alarm1: Alarm, - /// Alarm 2. - pub alarm2: Alarm, +pub struct SystemTimer<'d> { + /// Shared configuration + pub config: Config<'d>, + + /// Unit 0 + pub unit0: Unit<'d, 0>, + + #[cfg(not(esp32s2))] + /// Unit 1 + pub unit1: Unit<'d, 1>, + + /// Comparator 0. + pub comparator0: Comparator<'d, 0>, + + /// Comparator 1. + pub comparator1: Comparator<'d, 1>, + + /// Comparator 2. + pub comparator2: Comparator<'d, 2>, } -impl<'d> SystemTimer<'d, Blocking> { +impl<'d> SystemTimer<'d> { cfg_if::cfg_if! { if #[cfg(esp32s2)] { /// Bitmask to be applied to the raw register value. @@ -120,16 +131,19 @@ impl<'d> SystemTimer<'d, Blocking> { } } - /// Create a new instance in [crate::Blocking] mode. + /// Create a new instance. pub fn new(_systimer: impl Peripheral

+ 'd) -> Self { #[cfg(soc_etm)] etm::enable_etm(); Self { - _phantom: PhantomData, - alarm0: Alarm::new(), - alarm1: Alarm::new(), - alarm2: Alarm::new(), + config: Config::new(), + unit0: Unit::new(), + #[cfg(not(esp32s2))] + unit1: Unit::new(), + comparator0: Comparator::new(), + comparator1: Comparator::new(), + comparator2: Comparator::new(), } } @@ -138,150 +152,551 @@ impl<'d> SystemTimer<'d, Blocking> { // This should be safe to access from multiple contexts // worst case scenario the second accessor ends up reading // an older time stamp - let systimer = unsafe { &*SYSTIMER::ptr() }; - systimer.unit0_op().modify(|_, w| w.update().set_bit()); - - while !systimer.unit0_op().read().value_valid().bit_is_set() {} - let value_lo = systimer.unit0_value().lo().read().bits(); - let value_hi = systimer.unit0_value().hi().read().bits(); + let unit = unsafe { Unit::<'_, 0>::conjure() }; - ((value_hi as u64) << 32) | value_lo as u64 + unit.update(); + loop { + if let Some(value) = unit.poll_count() { + break value; + } + } } } -impl<'d> SystemTimer<'d, Async> { - /// Create a new instance in [crate::Async] mode. - pub fn new_async(_systimer: impl Peripheral

+ 'd) -> Self { - #[cfg(soc_etm)] - etm::enable_etm(); +impl SystemTimer<'static> { + /// Split the System Timer into three alarms. + /// + /// This is a convenience method to create `'static` alarms of the same + /// type. You are encouraged to use [Alarm::new] over this very specific + /// helper. + pub fn split(self) -> SysTimerAlarms { + static CONFIG: Mutex>> = Mutex::new(Cell::new(None)); + static mut UNIT0: Option> = None; + let unit0 = unsafe { &mut *addr_of_mut!(UNIT0) }; + + critical_section::with(|cs| CONFIG.borrow(cs).set(Some(self.config))); + + let unit0 = unit0.insert(self.unit0); + let unit = FrozenUnit::new(unit0); + + SysTimerAlarms { + alarm0: Alarm::new(self.comparator0, &unit, &CONFIG), + alarm1: Alarm::new(self.comparator1, &unit, &CONFIG), + alarm2: Alarm::new(self.comparator2, &unit, &CONFIG), + #[cfg(not(esp32s2))] + unit1: self.unit1, + } + } - Self { - alarm0: Alarm::new(), - alarm1: Alarm::new(), - alarm2: Alarm::new(), - _phantom: PhantomData, + /// Split the System Timer into three alarms. + /// + /// This is a convenience method to create `'static` alarms of the same + /// type. You are encouraged to use [Alarm::new_async] over this very + /// specific helper. + pub fn split_async(self) -> SysTimerAlarms { + static CONFIG: Mutex>> = Mutex::new(Cell::new(None)); + static mut UNIT0: Option> = None; + let unit0 = unsafe { &mut *addr_of_mut!(UNIT0) }; + + critical_section::with(|cs| CONFIG.borrow(cs).set(Some(self.config))); + + let unit0 = unit0.insert(self.unit0); + let unit = FrozenUnit::new(unit0); + + SysTimerAlarms { + alarm0: Alarm::new_async(self.comparator0, &unit, &CONFIG), + alarm1: Alarm::new_async(self.comparator1, &unit, &CONFIG), + alarm2: Alarm::new_async(self.comparator2, &unit, &CONFIG), + #[cfg(not(esp32s2))] + unit1: self.unit1, } } } -/// A marker for a [Alarm] in target mode. +/// Represents the shared configuration between the units and comparators. #[derive(Debug)] -pub struct Target; +pub struct Config<'d>(PhantomData<&'d ()>); -/// A marker for a [Alarm] in periodic mode. -#[derive(Debug)] -pub struct Periodic; +impl<'d> Config<'d> { + fn new() -> Self { + Self(PhantomData) + } +} -/// A single alarm. +/// A +#[cfg_attr(esp32s2, doc = "64-bit")] +#[cfg_attr(not(esp32s2), doc = "52-bit")] +/// counter. #[derive(Debug)] -pub struct Alarm -where - DM: Mode, -{ - _pd: PhantomData<(MODE, DM)>, +pub struct Unit<'d, const CHANNEL: u8>(PhantomData<&'d ()>); + +impl<'d, const CHANNEL: u8> Unit<'d, CHANNEL> { + fn new() -> Self { + Self(PhantomData) + } + + #[cfg(not(esp32s2))] + /// Configures when this counter can run. + /// It can be configured to stall or continue running when CPU stalls + /// or enters on-chip-debugging mode + pub fn configure(&self, _config: &mut Config, config: UnitConfig) { + let systimer = unsafe { &*SYSTIMER::ptr() }; + let conf = systimer.conf(); + + conf.modify(|_, w| match config { + UnitConfig::Disabled => match CHANNEL { + 0 => w.timer_unit0_work_en().clear_bit(), + 1 => w.timer_unit1_work_en().clear_bit(), + _ => unreachable!(), + }, + UnitConfig::DisabledIfCpuIsStalled(cpu) => match CHANNEL { + 0 => w + .timer_unit0_work_en() + .set_bit() + .timer_unit0_core0_stall_en() + .bit(cpu == Cpu::ProCpu) + .timer_unit0_core1_stall_en() + .bit(cpu != Cpu::ProCpu), + 1 => w + .timer_unit1_work_en() + .set_bit() + .timer_unit1_core0_stall_en() + .bit(cpu == Cpu::ProCpu) + .timer_unit1_core1_stall_en() + .bit(cpu != Cpu::ProCpu), + _ => unreachable!(), + }, + UnitConfig::Enabled => match CHANNEL { + 0 => w + .timer_unit0_work_en() + .set_bit() + .timer_unit0_core0_stall_en() + .clear_bit() + .timer_unit0_core1_stall_en() + .clear_bit(), + 1 => w + .timer_unit1_work_en() + .set_bit() + .timer_unit1_core0_stall_en() + .clear_bit() + .timer_unit1_core1_stall_en() + .clear_bit(), + _ => unreachable!(), + }, + }); + } + + /// Set the value of the counter immediately. If the unit is at work, + /// the counter will continue to count up from the new reloaded value. + /// + /// This can be used to load back the sleep time recorded by RTC timer + /// via software after Light-sleep + pub fn set_count(&self, value: u64) { + let systimer = unsafe { &*SYSTIMER::ptr() }; + #[cfg(not(esp32s2))] + { + let unitload = systimer.unitload(CHANNEL as _); + let unit_load = systimer.unit_load(CHANNEL as _); + + unitload.hi().write(|w| w.load_hi().set((value << 32) as _)); + unitload + .lo() + .write(|w| w.load_lo().set((value & 0xFFFF_FFFF) as _)); + + unit_load.write(|w| w.load().set_bit()); + } + #[cfg(esp32s2)] + { + systimer + .load_hi() + .write(|w| w.load_hi().set((value << 32) as _)); + systimer + .load_lo() + .write(|w| w.load_lo().set((value & 0xFFFF_FFFF) as _)); + + systimer.load().write(|w| w.load().set_bit()); + } + } + + /// Update the value returned by [Self::poll_count] to be the current value + /// of the counter. + /// + /// This can be used to read the current value of the timer. + pub fn update(&self) { + let systimer = unsafe { &*SYSTIMER::ptr() }; + systimer + .unit_op(CHANNEL as _) + .modify(|_, w| w.update().set_bit()); + } + + /// Return the count value at the time of the last call to [Self::update]. + /// + /// Returns None if the update isn't ready to read if update has never been + /// called. + pub fn poll_count(&self) -> Option { + let systimer = unsafe { &*SYSTIMER::ptr() }; + if systimer + .unit_op(CHANNEL as _) + .read() + .value_valid() + .bit_is_set() + { + let unit_value = systimer.unit_value(CHANNEL as _); + + let lo = unit_value.lo().read().bits(); + let hi = unit_value.hi().read().bits(); + + Some(((hi as u64) << 32) | lo as u64) + } else { + None + } + } + + /// Convenience method to call [Self::update] and [Self::poll_count]. + pub fn read_count(&self) -> u64 { + // This can be a shared reference as long as this type isn't Sync. + + self.update(); + loop { + if let Some(count) = self.poll_count() { + break count; + } + } + } } -impl Alarm -where - DM: Mode, -{ +/// A comparator that can generate alarms/interrupts based on values of a unit. +#[derive(Debug)] +pub struct Comparator<'d, const CHANNEL: u8>(PhantomData<&'d ()>); + +impl<'d, const CHANNEL: u8> Comparator<'d, CHANNEL> { fn new() -> Self { - Self { _pd: PhantomData } + Self(PhantomData) } - fn configure(&self, conf: impl FnOnce(&TARGET_CONF, &TRGT)) { - unsafe { - let systimer = &*SYSTIMER::ptr(); - let tconf = systimer.target_conf(CHANNEL as usize); - let target = systimer.trgt(CHANNEL as usize); + /// Enables/disables the comparator. If enabled, this means + /// it will generate interrupt based on its configuration. + /// + /// Note: This requires an exclusive reference to config as the register + /// is shared between all units and comparators. + #[cfg(not(esp32s2))] + pub fn set_enable(&self, _config: &mut Config<'d>, enable: bool) { + let systimer = unsafe { &*SYSTIMER::ptr() }; + systimer.conf().modify(|_, w| match CHANNEL { + 0 => w.target0_work_en().bit(enable), + 1 => w.target1_work_en().bit(enable), + 2 => w.target2_work_en().bit(enable), + _ => unreachable!(), + }); + } - #[cfg(esp32s2)] - systimer.step().write(|w| w.xtal_step().bits(0x1)); // run at XTAL freq, not 80 * XTAL freq + /// Enables/disables the comparator. If enabled, this means + /// it will generate interrupt based on its configuration. + #[cfg(esp32s2)] + pub fn set_enable(&self, enable: bool) { + let tconf = unsafe { + let systimer = &*SYSTIMER::ptr(); + systimer.target_conf(CHANNEL as usize) + }; + tconf.modify(|_r, w| w.work_en().bit(enable)); + } - #[cfg(not(esp32s2))] - { - tconf.write(|w| w.timer_unit_sel().clear_bit()); // default, use unit 0 - systimer - .conf() - .modify(|_, w| w.timer_unit0_core0_stall_en().clear_bit()); + /// Returns true if the comparator has been enabled. This means + /// it will generate interrupt based on its configuration. + pub fn is_enabled(&self) -> bool { + #[cfg(not(esp32s2))] + { + let systimer = unsafe { &*SYSTIMER::ptr() }; + let conf = systimer.conf().read(); + match CHANNEL { + 0 => conf.target0_work_en().bit(), + 1 => conf.target1_work_en().bit(), + 2 => conf.target2_work_en().bit(), + _ => unreachable!(), } + } - conf(tconf, target); + #[cfg(esp32s2)] + { + let tconf = unsafe { + let systimer = &*SYSTIMER::ptr(); + systimer.target_conf(CHANNEL as usize) + }; + tconf.read().work_en().bit() + } + } + /// Sets the unit this comparator uses as a reference count. + #[cfg(not(esp32s2))] + pub fn set_unit(&self, is_unit0: bool) { + let tconf = unsafe { + let systimer = &*SYSTIMER::ptr(); + systimer.target_conf(CHANNEL as usize) + }; + tconf.modify(|_, w| w.timer_unit_sel().bit(is_unit0)); + } + + /// Set the mode of the comparator to be either target or periodic. + pub fn set_mode(&self, mode: ComparatorMode) { + let tconf = unsafe { + let systimer = &*SYSTIMER::ptr(); + systimer.target_conf(CHANNEL as usize) + }; + let is_period_mode = match mode { + ComparatorMode::Period => true, + ComparatorMode::Target => false, + }; + tconf.modify(|_, w| w.period_mode().bit(is_period_mode)); + } + + /// Get the current mode of the comparator, which is either target or + /// periodic. + pub fn get_mode(&self) -> ComparatorMode { + let tconf = unsafe { + let systimer = &*SYSTIMER::ptr(); + systimer.target_conf(CHANNEL as usize) + }; + if tconf.read().period_mode().bit() { + ComparatorMode::Period + } else { + ComparatorMode::Target + } + } + + /// Set how often the comparator should generate an interrupt when in + /// periodic mode. + pub fn set_period(&self, value: u32) { + unsafe { + let systimer = &*SYSTIMER::ptr(); + let tconf = systimer.target_conf(CHANNEL as usize); + tconf.modify(|_, w| w.period().bits(value)); #[cfg(not(esp32s2))] { - systimer - .comp_load(CHANNEL as usize) - .write(|w| w.load().set_bit()); - - systimer.conf().modify(|_r, w| match CHANNEL { - 0 => w.target0_work_en().set_bit(), - 1 => w.target1_work_en().set_bit(), - 2 => w.target2_work_en().set_bit(), - _ => unreachable!(), - }); + let comp_load = systimer.comp_load(CHANNEL as usize); + comp_load.write(|w| w.load().set_bit()); } + } + } - #[cfg(esp32s2)] - tconf.modify(|_r, w| w.work_en().set_bit()); + /// Set when the comparator should generate an interrupt in target mode. + pub fn set_target(&self, value: u64) { + let systimer = unsafe { &*SYSTIMER::ptr() }; + let target = systimer.trgt(CHANNEL as usize); + target.hi().write(|w| w.hi().set((value >> 32) as u32)); + target + .lo() + .write(|w| w.lo().set((value & 0xFFFF_FFFF) as u32)); + #[cfg(not(esp32s2))] + { + let comp_load = systimer.comp_load(CHANNEL as usize); + comp_load.write(|w| w.load().set_bit()); } } - fn set_interrupt_handler_internal(&self, handler: InterruptHandler) { - match CHANNEL { - 0 => unsafe { - interrupt::bind_interrupt(Interrupt::SYSTIMER_TARGET0, handler.handler()); - unwrap!(interrupt::enable( - Interrupt::SYSTIMER_TARGET0, - handler.priority(), - )); - }, - 1 => unsafe { - interrupt::bind_interrupt(Interrupt::SYSTIMER_TARGET1, handler.handler()); - unwrap!(interrupt::enable( - Interrupt::SYSTIMER_TARGET1, - handler.priority(), - )); - }, - 2 => unsafe { - interrupt::bind_interrupt(Interrupt::SYSTIMER_TARGET2, handler.handler()); - unwrap!(interrupt::enable( - Interrupt::SYSTIMER_TARGET2, - handler.priority(), - )); - }, + /// Get the actual target value of the comparator. + pub fn get_actual_target(&self) -> u64 { + let target = unsafe { + let systimer = &*SYSTIMER::ptr(); + systimer.trgt(CHANNEL as usize) + }; + let hi = target.hi().read().hi().bits(); + let lo = target.lo().read().lo().bits(); + + ((hi as u64) << 32) | (lo as u64) + } + + /// Set the interrupt handler for this comparator. + pub fn set_interrupt_handler(&self, handler: InterruptHandler) { + let interrupt = match CHANNEL { + 0 => Interrupt::SYSTIMER_TARGET0, + 1 => Interrupt::SYSTIMER_TARGET1, + 2 => Interrupt::SYSTIMER_TARGET2, _ => unreachable!(), + }; + unsafe { + interrupt::bind_interrupt(interrupt, handler.handler()); } + unwrap!(interrupt::enable(interrupt, handler.priority())); } } -impl Alarm { - /// Set the interrupt handler for this alarm. - pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - self.set_interrupt_handler_internal(handler) +/// The configuration of a unit. +#[derive(Copy, Clone)] +pub enum UnitConfig { + /// Unit is not counting. + Disabled, + + /// Unit is counting unless the Cpu is stalled. + DisabledIfCpuIsStalled(Cpu), + + /// Unit is counting. + Enabled, +} + +/// The modes of a comparator. +#[derive(Copy, Clone)] +pub enum ComparatorMode { + /// The comparator will generate interrupts periodically. + Period, + + /// The comparator will generate an interrupt when the unit reaches the + /// target. + Target, +} + +impl Unit<'static, 0> { + /// Conjure a system timer unit out of thin air. + /// + /// # Safety + /// + /// Users must take care to ensure that only one reference to the unit is + /// in scope at any given time. + pub const unsafe fn conjure() -> Self { + Self(PhantomData) + } +} + +#[cfg(not(esp32s2))] +impl Unit<'static, 1> { + /// Conjure a system timer unit out of thin air. + /// + /// # Safety + /// + /// Users must take care to ensure that only one reference to the unit is + /// in scope at any given time. + pub const unsafe fn conjure() -> Self { + Self(PhantomData) } } -impl InterruptConfigurable for Alarm { +/// A unit whose value cannot be updated. +pub struct FrozenUnit<'d, const CHANNEL: u8>(&'d Unit<'d, CHANNEL>); + +impl<'d, const CHANNEL: u8> FrozenUnit<'d, CHANNEL> { + /// Creates a frozen unit. You will no longer be allowed + /// direct access to this unit until all the alarms created + /// from the unit are dropped. + pub fn new(unit: &'d mut Unit<'d, CHANNEL>) -> Self { + Self(unit) + } + + fn borrow(&self) -> &'d Unit<'d, CHANNEL> { + self.0 + } +} + +/// Alarms created from the System Timer peripheral. +pub struct SysTimerAlarms { + /// Alarm 0 + pub alarm0: Alarm<'static, MODE, DM, 0, 0>, + /// Alarm 1 + pub alarm1: Alarm<'static, MODE, DM, 1, 0>, + /// Alarm 2 + pub alarm2: Alarm<'static, MODE, DM, 2, 0>, + + /// Unit 1 + /// + /// Leftover unit which wasn't used to create the three alarms. + #[cfg(not(esp32s2))] + pub unit1: Unit<'static, 1>, +} + +/// A marker for a [Alarm] in target mode. +#[derive(Debug)] +pub struct Target; + +/// A marker for a [Alarm] in periodic mode. +#[derive(Debug)] +pub struct Periodic; + +/// A single alarm. +pub struct Alarm<'d, MODE, DM, const COMP: u8, const UNIT: u8> +where + DM: Mode, +{ + comparator: Comparator<'d, COMP>, + unit: &'d Unit<'d, UNIT>, + config: &'d Mutex>>>, + _pd: PhantomData<(MODE, DM)>, +} + +impl<'d, T, DM, const COMP: u8, const UNIT: u8> Debug for Alarm<'d, T, DM, COMP, UNIT> +where + DM: Mode, +{ + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Alarm") + .field("comparator", &COMP) + .field("unit", &UNIT) + .finish() + } +} + +impl<'d, T, const COMP: u8, const UNIT: u8> Alarm<'d, T, Blocking, COMP, UNIT> { + /// Creates a new alarm from a comparator and unit, in blocking mode. + pub fn new( + comparator: Comparator<'d, COMP>, + unit: &FrozenUnit<'d, UNIT>, + config: &'d Mutex>>>, + ) -> Self { + Self { + comparator, + unit: unit.borrow(), + config, + _pd: PhantomData, + } + } +} + +impl<'d, T, const COMP: u8, const UNIT: u8> Alarm<'d, T, Async, COMP, UNIT> { + /// Creates a new alarm from a comparator and unit, in async mode. + pub fn new_async( + comparator: Comparator<'d, COMP>, + unit: &FrozenUnit<'d, UNIT>, + config: &'d Mutex>>>, + ) -> Self { + Self { + comparator, + unit: unit.0, + config, + _pd: PhantomData, + } + } +} + +impl<'d, T, const COMP: u8, const UNIT: u8> InterruptConfigurable + for Alarm<'d, T, Blocking, COMP, UNIT> +{ fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - self.set_interrupt_handler_internal(handler) + self.comparator.set_interrupt_handler(handler) } } -impl Alarm +impl<'d, DM, const COMP: u8, const UNIT: u8> Alarm<'d, Target, DM, COMP, UNIT> where DM: Mode, { /// Set the target value of this [Alarm] pub fn set_target(&self, timestamp: u64) { - self.configure(|tconf, target| unsafe { - tconf.write(|w| w.period_mode().clear_bit()); // target mode - target.hi().write(|w| w.hi().bits((timestamp >> 32) as u32)); - target - .lo() - .write(|w| w.lo().set((timestamp & 0xFFFF_FFFF) as u32)); + #[cfg(esp32s2)] + unsafe { + let systimer = &*SYSTIMER::ptr(); + // run at XTAL freq, not 80 * XTAL freq + systimer.step().write(|w| w.xtal_step().bits(0x1)); + } + + self.comparator.set_mode(ComparatorMode::Target); + self.comparator.set_target(timestamp); + #[cfg(not(esp32s2))] + critical_section::with(|cs| { + let config_cell = self.config.borrow(cs); + let mut config = config_cell.take().unwrap(); + self.comparator.set_enable(&mut config, true); + config_cell.set(Some(config)); }); + #[cfg(esp32s2)] + self.comparator.set_enable(true); } /// Block waiting until the timer reaches the `timestamp` @@ -291,123 +706,97 @@ where let r = unsafe { &*crate::peripherals::SYSTIMER::PTR }.int_raw(); loop { - if r.read().target(CHANNEL).bit_is_set() { + if r.read().target(COMP).bit_is_set() { break; } } } /// Converts this [Alarm] into [Periodic] mode - pub fn into_periodic(self) -> Alarm { - Alarm { _pd: PhantomData } + pub fn into_periodic(self) -> Alarm<'d, Periodic, DM, COMP, UNIT> { + Alarm { + comparator: self.comparator, + unit: self.unit, + config: self.config, + _pd: PhantomData, + } } } -impl Alarm +impl<'d, DM, const COMP: u8, const UNIT: u8> Alarm<'d, Periodic, DM, COMP, UNIT> where DM: Mode, { /// Set the period of this [Alarm] pub fn set_period(&self, period: MicrosDurationU32) { + #[cfg(esp32s2)] + unsafe { + let systimer = &*SYSTIMER::ptr(); + // run at XTAL freq, not 80 * XTAL freq + systimer.step().write(|w| w.xtal_step().bits(0x1)); + } + let us = period.ticks(); let ticks = us * (SystemTimer::TICKS_PER_SECOND / 1_000_000) as u32; - self.configure(|tconf, target| { - tconf.write(|w| unsafe { w.period_mode().set_bit().period().bits(ticks) }); - target.hi().write(|w| w.hi().set(0)); - target.lo().write(|w| w.lo().set(0)); + self.comparator.set_mode(ComparatorMode::Period); + self.comparator.set_period(ticks); + + #[cfg(not(esp32s2))] + critical_section::with(|cs| { + let config_cell = self.config.borrow(cs); + let mut config = config_cell.take().unwrap(); + self.comparator.set_enable(&mut config, true); + config_cell.set(Some(config)); }); + #[cfg(esp32s2)] + self.comparator.set_enable(true); } /// Converts this [Alarm] into [Target] mode - pub fn into_target(self) -> Alarm { - Alarm { _pd: PhantomData } - } -} - -impl Alarm -where - DM: Mode, -{ - /// Conjure an alarm out of thin air. - /// - /// # Safety - /// - /// Users must take care to ensure that only one reference to the timer is - /// in scope at any given time. - pub const unsafe fn conjure() -> Self { - Self { _pd: PhantomData } + pub fn into_target(self) -> Alarm<'d, Target, DM, COMP, UNIT> { + Alarm { + comparator: self.comparator, + unit: self.unit, + config: self.config, + _pd: PhantomData, + } } } -impl Alarm +impl<'d, T, DM, const COMP: u8, const UNIT: u8> crate::private::Sealed + for Alarm<'d, T, DM, COMP, UNIT> where DM: Mode, { - /// Conjure an alarm out of thin air. - /// - /// # Safety - /// - /// Users must take care to ensure that only one reference to the timer is - /// in scope at any given time. - pub const unsafe fn conjure() -> Self { - Self { _pd: PhantomData } - } } -impl Alarm -where - DM: Mode, -{ - /// Conjure an alarm out of thin air. - /// - /// # Safety - /// - /// Users must take care to ensure that only one reference to the timer is - /// in scope at any given time. - pub const unsafe fn conjure() -> Self { - Self { _pd: PhantomData } - } -} - -impl crate::private::Sealed for Alarm where DM: Mode {} - -impl super::Timer for Alarm +impl<'d, T, DM, const COMP: u8, const UNIT: u8> super::Timer for Alarm<'d, T, DM, COMP, UNIT> where DM: Mode, { fn start(&self) { - let systimer = unsafe { &*SYSTIMER::PTR }; - - #[cfg(esp32s2)] - systimer - .target_conf(CHANNEL as usize) - .modify(|_, w| w.work_en().set_bit()); - #[cfg(not(esp32s2))] - systimer.conf().modify(|_, w| match CHANNEL { - 0 => w.target0_work_en().set_bit(), - 1 => w.target1_work_en().set_bit(), - 2 => w.target2_work_en().set_bit(), - _ => unreachable!(), + critical_section::with(|cs| { + let config_cell = self.config.borrow(cs); + let mut config = config_cell.take().unwrap(); + self.comparator.set_enable(&mut config, true); + config_cell.set(Some(config)); }); + #[cfg(esp32s2)] + self.comparator.set_enable(true); } fn stop(&self) { - let systimer = unsafe { &*SYSTIMER::PTR }; - - #[cfg(esp32s2)] - systimer - .target_conf(CHANNEL as usize) - .modify(|_, w| w.work_en().clear_bit()); - #[cfg(not(esp32s2))] - systimer.conf().modify(|_, w| match CHANNEL { - 0 => w.target0_work_en().clear_bit(), - 1 => w.target1_work_en().clear_bit(), - 2 => w.target2_work_en().clear_bit(), - _ => unreachable!(), + critical_section::with(|cs| { + let config_cell = self.config.borrow(cs); + let mut config = config_cell.take().unwrap(); + self.comparator.set_enable(&mut config, false); + config_cell.set(Some(config)); }); + #[cfg(esp32s2)] + self.comparator.set_enable(false); } fn reset(&self) { @@ -421,9 +810,6 @@ where #[cfg(not(esp32s2))] { - systimer - .target_conf(CHANNEL as usize) - .modify(|_, w| w.timer_unit_sel().clear_bit()); // default, use unit 0 systimer .conf() .modify(|_, w| w.timer_unit0_core0_stall_en().clear_bit()); @@ -431,59 +817,33 @@ where } fn is_running(&self) -> bool { - let systimer = unsafe { &*SYSTIMER::PTR }; - - #[cfg(esp32s2)] - { - systimer - .target_conf(CHANNEL as usize) - .read() - .work_en() - .bit_is_set() - } - - #[cfg(not(esp32s2))] - match CHANNEL { - 0 => systimer.conf().read().target0_work_en().bit_is_set(), - 1 => systimer.conf().read().target1_work_en().bit_is_set(), - 2 => systimer.conf().read().target2_work_en().bit_is_set(), - _ => unreachable!(), - } + self.comparator.is_enabled() } fn now(&self) -> Instant { // This should be safe to access from multiple contexts; worst case // scenario the second accessor ends up reading an older time stamp. - let systimer = unsafe { &*SYSTIMER::PTR }; + self.unit.update(); - systimer.unit0_op().modify(|_, w| w.update().set_bit()); - while !systimer.unit0_op().read().value_valid().bit_is_set() { - // Wait - } - - let value_lo = systimer.unit0_value().lo().read().bits(); - let value_hi = systimer.unit0_value().hi().read().bits(); + let ticks = loop { + if let Some(value) = self.unit.poll_count() { + break value; + } + }; - let ticks = ((value_hi as u64) << 32) | value_lo as u64; let us = ticks / (SystemTimer::TICKS_PER_SECOND / 1_000_000); Instant::::from_ticks(us) } fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error> { - let systimer = unsafe { &*SYSTIMER::PTR }; - - let auto_reload = systimer - .target_conf(CHANNEL as usize) - .read() - .period_mode() - .bit_is_set(); + let mode = self.comparator.get_mode(); let us = value.ticks(); let ticks = us * (SystemTimer::TICKS_PER_SECOND / 1_000_000); - if auto_reload { + if matches!(mode, ComparatorMode::Period) { // Period mode // The `SYSTIMER_TARGETx_PERIOD` field is 26-bits wide (or @@ -493,28 +853,17 @@ where return Err(Error::InvalidTimeout); } - systimer - .target_conf(CHANNEL as usize) - .modify(|_, w| unsafe { w.period().bits(ticks as u32) }); - - #[cfg(not(esp32s2))] - systimer - .comp_load(CHANNEL as usize) - .write(|w| w.load().set_bit()); + self.comparator.set_period(ticks as u32); // Clear and then set SYSTIMER_TARGETx_PERIOD_MODE to configure COMPx into // period mode - systimer - .target_conf(CHANNEL as usize) - .modify(|_, w| w.period_mode().clear_bit()); - systimer - .target_conf(CHANNEL as usize) - .modify(|_, w| w.period_mode().set_bit()); + self.comparator.set_mode(ComparatorMode::Target); + self.comparator.set_mode(ComparatorMode::Period); } else { // Target mode - systimer.unit0_op().modify(|_, w| w.update().set_bit()); - while !systimer.unit0_op().read().value_valid().bit_is_set() { + self.unit.update(); + while self.unit.poll_count().is_none() { // Wait for value registers to update } @@ -526,25 +875,10 @@ where return Err(Error::InvalidTimeout); } - let hi = systimer.unit0_value().hi().read().bits(); - let lo = systimer.unit0_value().lo().read().bits(); - - let v = (((hi & 0xF_FFFF) as u64) << 32) | lo as u64; + let v = self.unit.poll_count().unwrap(); let t = v + ticks; - systimer - .trgt(CHANNEL as usize) - .hi() - .write(|w| unsafe { w.hi().bits((t >> 32) as u32) }); - systimer - .trgt(CHANNEL as usize) - .lo() - .write(|w| unsafe { w.lo().bits(t as u32) }); - - #[cfg(not(esp32s2))] - systimer - .comp_load(CHANNEL as usize) - .write(|w| w.load().set_bit()); + self.comparator.set_target(t); } Ok(()) @@ -552,28 +886,31 @@ where fn enable_auto_reload(&self, auto_reload: bool) { // If `auto_reload` is true use Period Mode, otherwise use Target Mode: - unsafe { &*SYSTIMER::PTR } - .target_conf(CHANNEL as usize) - .modify(|_, w| w.period_mode().bit(auto_reload)); + let mode = if auto_reload { + ComparatorMode::Period + } else { + ComparatorMode::Target + }; + self.comparator.set_mode(mode) } fn enable_interrupt(&self, state: bool) { unsafe { &*SYSTIMER::PTR } .int_ena() - .modify(|_, w| w.target(CHANNEL).bit(state)); + .modify(|_, w| w.target(COMP).bit(state)); } fn clear_interrupt(&self) { unsafe { &*SYSTIMER::PTR } .int_clr() - .write(|w| w.target(CHANNEL).clear_bit_by_one()); + .write(|w| w.target(COMP).clear_bit_by_one()); } fn is_interrupt_set(&self) -> bool { unsafe { &*SYSTIMER::PTR } .int_raw() .read() - .target(CHANNEL) + .target(COMP) .bit_is_set() } @@ -582,11 +919,11 @@ where } fn set_interrupt_handler(&self, handler: InterruptHandler) { - Alarm::set_interrupt_handler_internal(self, handler); + self.comparator.set_interrupt_handler(handler); } } -impl Peripheral for Alarm +impl<'d, T, DM, const COMP: u8, const UNIT: u8> Peripheral for Alarm<'d, T, DM, COMP, UNIT> where DM: Mode, { @@ -617,15 +954,15 @@ mod asynch { const INIT: AtomicWaker = AtomicWaker::new(); static WAKERS: [AtomicWaker; NUM_ALARMS] = [INIT; NUM_ALARMS]; - pub(crate) struct AlarmFuture<'a, const N: u8> { - phantom: PhantomData<&'a Alarm>, + pub(crate) struct AlarmFuture<'a, const COMP: u8, const UNIT: u8> { + phantom: PhantomData<&'a Alarm<'a, Periodic, crate::Async, COMP, UNIT>>, } - impl<'a, const N: u8> AlarmFuture<'a, N> { - pub(crate) fn new(alarm: &'a Alarm) -> Self { + impl<'a, const COMP: u8, const UNIT: u8> AlarmFuture<'a, COMP, UNIT> { + pub(crate) fn new(alarm: &'a Alarm) -> Self { alarm.clear_interrupt(); - let (interrupt, handler) = match N { + let (interrupt, handler) = match COMP { 0 => (Interrupt::SYSTIMER_TARGET0, target0_handler), 1 => (Interrupt::SYSTIMER_TARGET1, target1_handler), _ => (Interrupt::SYSTIMER_TARGET2, target2_handler), @@ -647,16 +984,16 @@ mod asynch { unsafe { &*crate::peripherals::SYSTIMER::PTR } .int_ena() .read() - .target(N) + .target(COMP) .bit_is_clear() } } - impl<'a, const N: u8> core::future::Future for AlarmFuture<'a, N> { + impl<'a, const COMP: u8, const UNIT: u8> core::future::Future for AlarmFuture<'a, COMP, UNIT> { type Output = (); fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { - WAKERS[N as usize].register(ctx.waker()); + WAKERS[COMP as usize].register(ctx.waker()); if self.event_bit_is_clear() { Poll::Ready(()) @@ -666,8 +1003,8 @@ mod asynch { } } - impl embedded_hal_async::delay::DelayNs - for Alarm + impl<'d, const COMP: u8, const UNIT: u8> embedded_hal_async::delay::DelayNs + for Alarm<'d, Periodic, crate::Async, COMP, UNIT> { async fn delay_ns(&mut self, ns: u32) { let period = MicrosDurationU32::from_ticks(ns / 1000); @@ -731,7 +1068,8 @@ pub mod etm { //! # use esp_hal::timer::systimer::{etm::SysTimerEtmEvent, SystemTimer}; //! # use fugit::ExtU32; //! let syst = SystemTimer::new(peripherals.SYSTIMER); - //! let mut alarm0 = syst.alarm0.into_periodic(); + //! let syst_alarms = syst.split(); + //! let mut alarm0 = syst_alarms.alarm0.into_periodic(); //! alarm0.set_period(1.secs()); //! //! let timer_event = SysTimerEtmEvent::new(&mut alarm0); @@ -741,31 +1079,33 @@ pub mod etm { use super::*; /// An ETM controlled SYSTIMER event - pub struct SysTimerEtmEvent<'a, M, DM: crate::Mode, const N: u8> { - alarm: &'a mut Alarm, + pub struct SysTimerEtmEvent<'a, 'd, M, DM: crate::Mode, const COMP: u8> { + alarm: &'a mut Alarm<'d, M, DM, COMP, 0>, } - impl<'a, M, DM: crate::Mode, const N: u8> SysTimerEtmEvent<'a, M, DM, N> { + impl<'a, 'd, M, DM: crate::Mode, const COMP: u8> SysTimerEtmEvent<'a, 'd, M, DM, COMP> { /// Creates an ETM event from the given [Alarm] - pub fn new(alarm: &'a mut Alarm) -> Self { + pub fn new(alarm: &'a mut Alarm<'d, M, DM, COMP, 0>) -> Self { Self { alarm } } /// Execute closure f with mutable access to the wrapped [Alarm]. - pub fn with(&self, f: impl FnOnce(&&'a mut Alarm) -> R) -> R { + pub fn with(&self, f: impl FnOnce(&&'a mut Alarm<'d, M, DM, COMP, 0>) -> R) -> R { let alarm = &self.alarm; f(alarm) } } - impl<'a, M, DM: crate::Mode, const N: u8> crate::private::Sealed - for SysTimerEtmEvent<'a, M, DM, N> + impl<'a, 'd, M, DM: crate::Mode, const COMP: u8> crate::private::Sealed + for SysTimerEtmEvent<'a, 'd, M, DM, COMP> { } - impl<'a, M, DM: crate::Mode, const N: u8> crate::etm::EtmEvent for SysTimerEtmEvent<'a, M, DM, N> { + impl<'a, 'd, M, DM: crate::Mode, const COMP: u8> crate::etm::EtmEvent + for SysTimerEtmEvent<'a, 'd, M, DM, COMP> + { fn id(&self) -> u8 { - 50 + N + 50 + COMP } } diff --git a/examples/src/bin/embassy_multiprio.rs b/examples/src/bin/embassy_multiprio.rs index 36386c0d4da..472b79323e8 100644 --- a/examples/src/bin/embassy_multiprio.rs +++ b/examples/src/bin/embassy_multiprio.rs @@ -99,7 +99,8 @@ async fn main(low_prio_spawner: Spawner) { }; #[cfg(feature = "esp32c2")] let timer1 = { - let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER) + .split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); OneShotTimer::new(alarm0) }; diff --git a/examples/src/bin/embassy_parl_io_rx.rs b/examples/src/bin/embassy_parl_io_rx.rs index ef74d3a7e7e..8e419cb8ad7 100644 --- a/examples/src/bin/embassy_parl_io_rx.rs +++ b/examples/src/bin/embassy_parl_io_rx.rs @@ -22,7 +22,11 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::{systimer::SystemTimer, ErasedTimer, OneShotTimer}, + timer::{ + systimer::{SystemTimer, Target}, + ErasedTimer, + OneShotTimer, + }, }; use esp_println::println; @@ -43,7 +47,7 @@ async fn main(_spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let systimer = SystemTimer::new(peripherals.SYSTIMER); + let systimer = SystemTimer::new(peripherals.SYSTIMER).split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timers = [OneShotTimer::new(alarm0)]; let timers = mk_static!([OneShotTimer; 1], timers); diff --git a/examples/src/bin/embassy_parl_io_tx.rs b/examples/src/bin/embassy_parl_io_tx.rs index 7e7a6165e0e..e692ca64b19 100644 --- a/examples/src/bin/embassy_parl_io_tx.rs +++ b/examples/src/bin/embassy_parl_io_tx.rs @@ -33,7 +33,11 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::{systimer::SystemTimer, ErasedTimer, OneShotTimer}, + timer::{ + systimer::{SystemTimer, Target}, + ErasedTimer, + OneShotTimer, + }, }; use esp_println::println; @@ -54,7 +58,7 @@ async fn main(_spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let systimer = SystemTimer::new(peripherals.SYSTIMER); + let systimer = SystemTimer::new(peripherals.SYSTIMER).split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timers = [OneShotTimer::new(alarm0)]; let timers = mk_static!([OneShotTimer; 1], timers); diff --git a/examples/src/bin/etm_blinky_systimer.rs b/examples/src/bin/etm_blinky_systimer.rs index b72ea29ea43..89d5ce953ee 100644 --- a/examples/src/bin/etm_blinky_systimer.rs +++ b/examples/src/bin/etm_blinky_systimer.rs @@ -19,7 +19,7 @@ use esp_hal::{ }, peripherals::Peripherals, prelude::*, - timer::systimer::{etm::SysTimerEtmEvent, SystemTimer}, + timer::systimer::{etm::SysTimerEtmEvent, Periodic, SystemTimer}, }; use fugit::ExtU32; @@ -28,7 +28,8 @@ fn main() -> ! { let peripherals = Peripherals::take(); let syst = SystemTimer::new(peripherals.SYSTIMER); - let mut alarm0 = syst.alarm0.into_periodic(); + let syst_alarms = syst.split::(); + let mut alarm0 = syst_alarms.alarm0; alarm0.set_period(1u32.secs()); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); diff --git a/examples/src/bin/systimer.rs b/examples/src/bin/systimer.rs index 8c738033ac5..650d84c773a 100644 --- a/examples/src/bin/systimer.rs +++ b/examples/src/bin/systimer.rs @@ -7,7 +7,7 @@ #![no_std] #![no_main] -use core::cell::RefCell; +use core::cell::{Cell, RefCell}; use critical_section::Mutex; use esp_backtrace as _; @@ -18,16 +18,19 @@ use esp_hal::{ peripherals::{Interrupt, Peripherals}, prelude::*, system::SystemControl, - timer::systimer::{Alarm, Periodic, SystemTimer, Target}, + timer::systimer::{Alarm, Config, FrozenUnit, Periodic, SystemTimer, Target, Unit}, Blocking, }; use esp_println::println; use fugit::ExtU32; +use static_cell::StaticCell; -static ALARM0: Mutex>>> = +static ALARM0: Mutex>>> = + Mutex::new(RefCell::new(None)); +static ALARM1: Mutex>>> = + Mutex::new(RefCell::new(None)); +static ALARM2: Mutex>>> = Mutex::new(RefCell::new(None)); -static ALARM1: Mutex>>> = Mutex::new(RefCell::new(None)); -static ALARM2: Mutex>>> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { @@ -38,18 +41,28 @@ fn main() -> ! { let systimer = SystemTimer::new(peripherals.SYSTIMER); println!("SYSTIMER Current value = {}", SystemTimer::now()); + static CONFIG: Mutex>> = Mutex::new(Cell::new(None)); + static UNIT0: StaticCell> = StaticCell::new(); + + let unit0 = UNIT0.init(systimer.unit0); + critical_section::with(|cs| CONFIG.borrow(cs).set(Some(systimer.config))); + + let frozen_unit = FrozenUnit::new(unit0); + + let alarm0 = Alarm::new(systimer.comparator0, &frozen_unit, &CONFIG); + let alarm1 = Alarm::new(systimer.comparator1, &frozen_unit, &CONFIG); + let alarm2 = Alarm::new(systimer.comparator2, &frozen_unit, &CONFIG); + critical_section::with(|cs| { - let alarm0 = systimer.alarm0.into_periodic(); + let alarm0 = alarm0.into_periodic(); alarm0.set_interrupt_handler(systimer_target0); alarm0.set_period(1u32.secs()); alarm0.enable_interrupt(true); - let alarm1 = systimer.alarm1; alarm1.set_interrupt_handler(systimer_target1); alarm1.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 2)); alarm1.enable_interrupt(true); - let alarm2 = systimer.alarm2; alarm2.set_interrupt_handler(systimer_target2); alarm2.set_target(SystemTimer::now() + (SystemTimer::TICKS_PER_SECOND * 3)); alarm2.enable_interrupt(true); diff --git a/examples/src/bin/wifi_embassy_access_point.rs b/examples/src/bin/wifi_embassy_access_point.rs index 9d1f9f1c800..16a4edd1aa8 100644 --- a/examples/src/bin/wifi_embassy_access_point.rs +++ b/examples/src/bin/wifi_embassy_access_point.rs @@ -96,7 +96,8 @@ async fn main(spawner: Spawner) -> ! { #[cfg(not(feature = "esp32"))] { - let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER) + .split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timers = [OneShotTimer::new(alarm0)]; let timers = mk_static!([OneShotTimer; 1], timers); diff --git a/examples/src/bin/wifi_embassy_access_point_with_sta.rs b/examples/src/bin/wifi_embassy_access_point_with_sta.rs index 360a2d60a0e..b7fdb2b9bf7 100644 --- a/examples/src/bin/wifi_embassy_access_point_with_sta.rs +++ b/examples/src/bin/wifi_embassy_access_point_with_sta.rs @@ -104,7 +104,8 @@ async fn main(spawner: Spawner) -> ! { #[cfg(not(feature = "esp32"))] { - let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER) + .split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timers = [OneShotTimer::new(alarm0)]; let timers = mk_static!([OneShotTimer; 1], timers); diff --git a/examples/src/bin/wifi_embassy_bench.rs b/examples/src/bin/wifi_embassy_bench.rs index bebb4795695..09f306c5fad 100644 --- a/examples/src/bin/wifi_embassy_bench.rs +++ b/examples/src/bin/wifi_embassy_bench.rs @@ -108,7 +108,8 @@ async fn main(spawner: Spawner) -> ! { #[cfg(not(feature = "esp32"))] { - let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER) + .split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timers = [OneShotTimer::new(alarm0)]; let timers = mk_static!([OneShotTimer; 1], timers); diff --git a/examples/src/bin/wifi_embassy_ble.rs b/examples/src/bin/wifi_embassy_ble.rs index 606e18eda28..76eb5d2fffa 100644 --- a/examples/src/bin/wifi_embassy_ble.rs +++ b/examples/src/bin/wifi_embassy_ble.rs @@ -91,7 +91,8 @@ async fn main(_spawner: Spawner) -> ! { #[cfg(not(feature = "esp32"))] { - let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER) + .split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timers = [OneShotTimer::new(alarm0)]; let timers = mk_static!([OneShotTimer; 1], timers); diff --git a/examples/src/bin/wifi_embassy_dhcp.rs b/examples/src/bin/wifi_embassy_dhcp.rs index 66636de046a..6e72eb7af49 100644 --- a/examples/src/bin/wifi_embassy_dhcp.rs +++ b/examples/src/bin/wifi_embassy_dhcp.rs @@ -89,7 +89,8 @@ async fn main(spawner: Spawner) -> ! { #[cfg(not(feature = "esp32"))] { - let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER) + .split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timers = [OneShotTimer::new(alarm0)]; let timers = mk_static!([OneShotTimer; 1], timers); diff --git a/examples/src/bin/wifi_embassy_esp_now.rs b/examples/src/bin/wifi_embassy_esp_now.rs index c3d42f881de..2d30dda13d0 100644 --- a/examples/src/bin/wifi_embassy_esp_now.rs +++ b/examples/src/bin/wifi_embassy_esp_now.rs @@ -75,7 +75,8 @@ async fn main(_spawner: Spawner) -> ! { #[cfg(not(feature = "esp32"))] { - let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER) + .split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timers = [OneShotTimer::new(alarm0)]; let timers = mk_static!([OneShotTimer; 1], timers); diff --git a/examples/src/bin/wifi_embassy_esp_now_duplex.rs b/examples/src/bin/wifi_embassy_esp_now_duplex.rs index 5ef0efe17fe..f03d7428730 100644 --- a/examples/src/bin/wifi_embassy_esp_now_duplex.rs +++ b/examples/src/bin/wifi_embassy_esp_now_duplex.rs @@ -75,7 +75,8 @@ async fn main(spawner: Spawner) -> ! { #[cfg(not(feature = "esp32"))] { - let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER) + .split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timers = [OneShotTimer::new(alarm0)]; let timers = mk_static!([OneShotTimer; 1], timers); From 765133fb4854900679fa5d34ff0b7341a6947778 Mon Sep 17 00:00:00 2001 From: Dominic Fischer Date: Thu, 8 Aug 2024 23:18:53 +0100 Subject: [PATCH 2/5] Remove config object --- esp-hal/src/timer/systimer.rs | 202 +++++++++++----------------------- examples/src/bin/systimer.rs | 12 +- 2 files changed, 70 insertions(+), 144 deletions(-) diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index 9507c48ea7e..9506a1e3bdf 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -69,13 +69,11 @@ //! ``` use core::{ - cell::Cell, fmt::{Debug, Formatter}, marker::PhantomData, ptr::addr_of_mut, }; -use critical_section::Mutex; use fugit::{Instant, MicrosDurationU32, MicrosDurationU64}; use super::{Error, Timer as _}; @@ -92,9 +90,6 @@ use crate::{ /// System Timer driver. pub struct SystemTimer<'d> { - /// Shared configuration - pub config: Config<'d>, - /// Unit 0 pub unit0: Unit<'d, 0>, @@ -137,7 +132,6 @@ impl<'d> SystemTimer<'d> { etm::enable_etm(); Self { - config: Config::new(), unit0: Unit::new(), #[cfg(not(esp32s2))] unit1: Unit::new(), @@ -171,19 +165,16 @@ impl SystemTimer<'static> { /// type. You are encouraged to use [Alarm::new] over this very specific /// helper. pub fn split(self) -> SysTimerAlarms { - static CONFIG: Mutex>> = Mutex::new(Cell::new(None)); static mut UNIT0: Option> = None; let unit0 = unsafe { &mut *addr_of_mut!(UNIT0) }; - critical_section::with(|cs| CONFIG.borrow(cs).set(Some(self.config))); - let unit0 = unit0.insert(self.unit0); let unit = FrozenUnit::new(unit0); SysTimerAlarms { - alarm0: Alarm::new(self.comparator0, &unit, &CONFIG), - alarm1: Alarm::new(self.comparator1, &unit, &CONFIG), - alarm2: Alarm::new(self.comparator2, &unit, &CONFIG), + alarm0: Alarm::new(self.comparator0, &unit), + alarm1: Alarm::new(self.comparator1, &unit), + alarm2: Alarm::new(self.comparator2, &unit), #[cfg(not(esp32s2))] unit1: self.unit1, } @@ -195,35 +186,22 @@ impl SystemTimer<'static> { /// type. You are encouraged to use [Alarm::new_async] over this very /// specific helper. pub fn split_async(self) -> SysTimerAlarms { - static CONFIG: Mutex>> = Mutex::new(Cell::new(None)); static mut UNIT0: Option> = None; let unit0 = unsafe { &mut *addr_of_mut!(UNIT0) }; - critical_section::with(|cs| CONFIG.borrow(cs).set(Some(self.config))); - let unit0 = unit0.insert(self.unit0); let unit = FrozenUnit::new(unit0); SysTimerAlarms { - alarm0: Alarm::new_async(self.comparator0, &unit, &CONFIG), - alarm1: Alarm::new_async(self.comparator1, &unit, &CONFIG), - alarm2: Alarm::new_async(self.comparator2, &unit, &CONFIG), + alarm0: Alarm::new_async(self.comparator0, &unit), + alarm1: Alarm::new_async(self.comparator1, &unit), + alarm2: Alarm::new_async(self.comparator2, &unit), #[cfg(not(esp32s2))] unit1: self.unit1, } } } -/// Represents the shared configuration between the units and comparators. -#[derive(Debug)] -pub struct Config<'d>(PhantomData<&'d ()>); - -impl<'d> Config<'d> { - fn new() -> Self { - Self(PhantomData) - } -} - /// A #[cfg_attr(esp32s2, doc = "64-bit")] #[cfg_attr(not(esp32s2), doc = "52-bit")] @@ -240,50 +218,52 @@ impl<'d, const CHANNEL: u8> Unit<'d, CHANNEL> { /// Configures when this counter can run. /// It can be configured to stall or continue running when CPU stalls /// or enters on-chip-debugging mode - pub fn configure(&self, _config: &mut Config, config: UnitConfig) { + pub fn configure(&self, config: UnitConfig) { let systimer = unsafe { &*SYSTIMER::ptr() }; let conf = systimer.conf(); - conf.modify(|_, w| match config { - UnitConfig::Disabled => match CHANNEL { - 0 => w.timer_unit0_work_en().clear_bit(), - 1 => w.timer_unit1_work_en().clear_bit(), - _ => unreachable!(), - }, - UnitConfig::DisabledIfCpuIsStalled(cpu) => match CHANNEL { - 0 => w - .timer_unit0_work_en() - .set_bit() - .timer_unit0_core0_stall_en() - .bit(cpu == Cpu::ProCpu) - .timer_unit0_core1_stall_en() - .bit(cpu != Cpu::ProCpu), - 1 => w - .timer_unit1_work_en() - .set_bit() - .timer_unit1_core0_stall_en() - .bit(cpu == Cpu::ProCpu) - .timer_unit1_core1_stall_en() - .bit(cpu != Cpu::ProCpu), - _ => unreachable!(), - }, - UnitConfig::Enabled => match CHANNEL { - 0 => w - .timer_unit0_work_en() - .set_bit() - .timer_unit0_core0_stall_en() - .clear_bit() - .timer_unit0_core1_stall_en() - .clear_bit(), - 1 => w - .timer_unit1_work_en() - .set_bit() - .timer_unit1_core0_stall_en() - .clear_bit() - .timer_unit1_core1_stall_en() - .clear_bit(), - _ => unreachable!(), - }, + critical_section::with(|_| { + conf.modify(|_, w| match config { + UnitConfig::Disabled => match CHANNEL { + 0 => w.timer_unit0_work_en().clear_bit(), + 1 => w.timer_unit1_work_en().clear_bit(), + _ => unreachable!(), + }, + UnitConfig::DisabledIfCpuIsStalled(cpu) => match CHANNEL { + 0 => w + .timer_unit0_work_en() + .set_bit() + .timer_unit0_core0_stall_en() + .bit(cpu == Cpu::ProCpu) + .timer_unit0_core1_stall_en() + .bit(cpu != Cpu::ProCpu), + 1 => w + .timer_unit1_work_en() + .set_bit() + .timer_unit1_core0_stall_en() + .bit(cpu == Cpu::ProCpu) + .timer_unit1_core1_stall_en() + .bit(cpu != Cpu::ProCpu), + _ => unreachable!(), + }, + UnitConfig::Enabled => match CHANNEL { + 0 => w + .timer_unit0_work_en() + .set_bit() + .timer_unit0_core0_stall_en() + .clear_bit() + .timer_unit0_core1_stall_en() + .clear_bit(), + 1 => w + .timer_unit1_work_en() + .set_bit() + .timer_unit1_core0_stall_en() + .clear_bit() + .timer_unit1_core1_stall_en() + .clear_bit(), + _ => unreachable!(), + }, + }); }); } @@ -377,29 +357,23 @@ impl<'d, const CHANNEL: u8> Comparator<'d, CHANNEL> { /// Enables/disables the comparator. If enabled, this means /// it will generate interrupt based on its configuration. - /// - /// Note: This requires an exclusive reference to config as the register - /// is shared between all units and comparators. - #[cfg(not(esp32s2))] - pub fn set_enable(&self, _config: &mut Config<'d>, enable: bool) { + pub fn set_enable(&self, enable: bool) { let systimer = unsafe { &*SYSTIMER::ptr() }; - systimer.conf().modify(|_, w| match CHANNEL { - 0 => w.target0_work_en().bit(enable), - 1 => w.target1_work_en().bit(enable), - 2 => w.target2_work_en().bit(enable), - _ => unreachable!(), + + #[cfg(not(esp32s2))] + critical_section::with(|_| { + systimer.conf().modify(|_, w| match CHANNEL { + 0 => w.target0_work_en().bit(enable), + 1 => w.target1_work_en().bit(enable), + 2 => w.target2_work_en().bit(enable), + _ => unreachable!(), + }); }); - } - /// Enables/disables the comparator. If enabled, this means - /// it will generate interrupt based on its configuration. - #[cfg(esp32s2)] - pub fn set_enable(&self, enable: bool) { - let tconf = unsafe { - let systimer = &*SYSTIMER::ptr(); - systimer.target_conf(CHANNEL as usize) - }; - tconf.modify(|_r, w| w.work_en().bit(enable)); + #[cfg(esp32s2)] + systimer + .target_conf(CHANNEL as usize) + .modify(|_r, w| w.work_en().bit(enable)); } /// Returns true if the comparator has been enabled. This means @@ -617,7 +591,6 @@ where { comparator: Comparator<'d, COMP>, unit: &'d Unit<'d, UNIT>, - config: &'d Mutex>>>, _pd: PhantomData<(MODE, DM)>, } @@ -635,15 +608,10 @@ where impl<'d, T, const COMP: u8, const UNIT: u8> Alarm<'d, T, Blocking, COMP, UNIT> { /// Creates a new alarm from a comparator and unit, in blocking mode. - pub fn new( - comparator: Comparator<'d, COMP>, - unit: &FrozenUnit<'d, UNIT>, - config: &'d Mutex>>>, - ) -> Self { + pub fn new(comparator: Comparator<'d, COMP>, unit: &FrozenUnit<'d, UNIT>) -> Self { Self { comparator, unit: unit.borrow(), - config, _pd: PhantomData, } } @@ -651,15 +619,10 @@ impl<'d, T, const COMP: u8, const UNIT: u8> Alarm<'d, T, Blocking, COMP, UNIT> { impl<'d, T, const COMP: u8, const UNIT: u8> Alarm<'d, T, Async, COMP, UNIT> { /// Creates a new alarm from a comparator and unit, in async mode. - pub fn new_async( - comparator: Comparator<'d, COMP>, - unit: &FrozenUnit<'d, UNIT>, - config: &'d Mutex>>>, - ) -> Self { + pub fn new_async(comparator: Comparator<'d, COMP>, unit: &FrozenUnit<'d, UNIT>) -> Self { Self { comparator, unit: unit.0, - config, _pd: PhantomData, } } @@ -688,14 +651,6 @@ where self.comparator.set_mode(ComparatorMode::Target); self.comparator.set_target(timestamp); - #[cfg(not(esp32s2))] - critical_section::with(|cs| { - let config_cell = self.config.borrow(cs); - let mut config = config_cell.take().unwrap(); - self.comparator.set_enable(&mut config, true); - config_cell.set(Some(config)); - }); - #[cfg(esp32s2)] self.comparator.set_enable(true); } @@ -717,7 +672,6 @@ where Alarm { comparator: self.comparator, unit: self.unit, - config: self.config, _pd: PhantomData, } } @@ -741,15 +695,6 @@ where self.comparator.set_mode(ComparatorMode::Period); self.comparator.set_period(ticks); - - #[cfg(not(esp32s2))] - critical_section::with(|cs| { - let config_cell = self.config.borrow(cs); - let mut config = config_cell.take().unwrap(); - self.comparator.set_enable(&mut config, true); - config_cell.set(Some(config)); - }); - #[cfg(esp32s2)] self.comparator.set_enable(true); } @@ -758,7 +703,6 @@ where Alarm { comparator: self.comparator, unit: self.unit, - config: self.config, _pd: PhantomData, } } @@ -776,26 +720,10 @@ where DM: Mode, { fn start(&self) { - #[cfg(not(esp32s2))] - critical_section::with(|cs| { - let config_cell = self.config.borrow(cs); - let mut config = config_cell.take().unwrap(); - self.comparator.set_enable(&mut config, true); - config_cell.set(Some(config)); - }); - #[cfg(esp32s2)] self.comparator.set_enable(true); } fn stop(&self) { - #[cfg(not(esp32s2))] - critical_section::with(|cs| { - let config_cell = self.config.borrow(cs); - let mut config = config_cell.take().unwrap(); - self.comparator.set_enable(&mut config, false); - config_cell.set(Some(config)); - }); - #[cfg(esp32s2)] self.comparator.set_enable(false); } diff --git a/examples/src/bin/systimer.rs b/examples/src/bin/systimer.rs index 650d84c773a..3124ea8e22c 100644 --- a/examples/src/bin/systimer.rs +++ b/examples/src/bin/systimer.rs @@ -7,7 +7,7 @@ #![no_std] #![no_main] -use core::cell::{Cell, RefCell}; +use core::cell::RefCell; use critical_section::Mutex; use esp_backtrace as _; @@ -18,7 +18,7 @@ use esp_hal::{ peripherals::{Interrupt, Peripherals}, prelude::*, system::SystemControl, - timer::systimer::{Alarm, Config, FrozenUnit, Periodic, SystemTimer, Target, Unit}, + timer::systimer::{Alarm, FrozenUnit, Periodic, SystemTimer, Target, Unit}, Blocking, }; use esp_println::println; @@ -41,17 +41,15 @@ fn main() -> ! { let systimer = SystemTimer::new(peripherals.SYSTIMER); println!("SYSTIMER Current value = {}", SystemTimer::now()); - static CONFIG: Mutex>> = Mutex::new(Cell::new(None)); static UNIT0: StaticCell> = StaticCell::new(); let unit0 = UNIT0.init(systimer.unit0); - critical_section::with(|cs| CONFIG.borrow(cs).set(Some(systimer.config))); let frozen_unit = FrozenUnit::new(unit0); - let alarm0 = Alarm::new(systimer.comparator0, &frozen_unit, &CONFIG); - let alarm1 = Alarm::new(systimer.comparator1, &frozen_unit, &CONFIG); - let alarm2 = Alarm::new(systimer.comparator2, &frozen_unit, &CONFIG); + let alarm0 = Alarm::new(systimer.comparator0, &frozen_unit); + let alarm1 = Alarm::new(systimer.comparator1, &frozen_unit); + let alarm2 = Alarm::new(systimer.comparator2, &frozen_unit); critical_section::with(|cs| { let alarm0 = alarm0.into_periodic(); From 2394d7dd7278b8ccc26bf4d9e5d584c3eb60bd2d Mon Sep 17 00:00:00 2001 From: Dominic Fischer Date: Thu, 8 Aug 2024 23:34:17 +0100 Subject: [PATCH 3/5] fix things --- esp-hal/src/timer/systimer.rs | 2 +- hil-test/tests/embassy_timers_executors.rs | 27 +++++++++++++++------- 2 files changed, 20 insertions(+), 9 deletions(-) diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index 9506a1e3bdf..48838889dc0 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -887,7 +887,7 @@ mod asynch { } impl<'a, const COMP: u8, const UNIT: u8> AlarmFuture<'a, COMP, UNIT> { - pub(crate) fn new(alarm: &'a Alarm) -> Self { + pub(crate) fn new(alarm: &'a Alarm<'a, Periodic, crate::Async, COMP, UNIT>) -> Self { alarm.clear_interrupt(); let (interrupt, handler) = match COMP { diff --git a/hil-test/tests/embassy_timers_executors.rs b/hil-test/tests/embassy_timers_executors.rs index c5cd4861bc5..6befbda0a3c 100644 --- a/hil-test/tests/embassy_timers_executors.rs +++ b/hil-test/tests/embassy_timers_executors.rs @@ -36,7 +36,10 @@ use esp_hal::{ timer::{timg::TimerGroup, ErasedTimer, OneShotTimer, PeriodicTimer}, }; #[cfg(not(feature = "esp32"))] -use esp_hal::{interrupt::Priority, timer::systimer::SystemTimer}; +use esp_hal::{ + interrupt::Priority, + timer::systimer::{Alarm, FrozenUnit, Periodic, SystemTimer, Target}, +}; #[cfg(not(feature = "esp32"))] use esp_hal_embassy::InterruptExecutor; #[cfg(not(feature = "esp32"))] @@ -121,6 +124,9 @@ mod task_invokers { // List of the functions that are ACTUALLY TESTS but are called in the invokers mod test_helpers { + #[cfg(not(feature = "esp32"))] + use esp_hal::timer::systimer::Target; + use crate::*; pub async fn test_one_shot_timg() { let peripherals = unsafe { Peripherals::steal() }; @@ -148,7 +154,7 @@ mod test_helpers { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let systimer = SystemTimer::new(peripherals.SYSTIMER); + let systimer = SystemTimer::new(peripherals.SYSTIMER).split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timers = [OneShotTimer::new(alarm0)]; let timers = mk_static!([OneShotTimer; 1], timers); @@ -189,7 +195,7 @@ mod test_helpers { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let systimer = SystemTimer::new(peripherals.SYSTIMER); + let systimer = SystemTimer::new(peripherals.SYSTIMER).split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timers = [OneShotTimer::new(alarm0)]; let timers = mk_static!([OneShotTimer; 1], timers); @@ -322,7 +328,7 @@ mod test { fn run_test_periodic_systimer() { let peripherals = Peripherals::take(); - let systimer = SystemTimer::new(peripherals.SYSTIMER); + let systimer = SystemTimer::new(peripherals.SYSTIMER).split::(); let mut periodic = PeriodicTimer::new(systimer.alarm0); @@ -384,7 +390,9 @@ mod test { let mut systimer = SystemTimer::new(&mut peripherals.SYSTIMER); - let mut periodic = PeriodicTimer::new(&mut systimer.alarm0); + let unit = FrozenUnit::new(&mut systimer.unit0); + let mut alarm: Alarm<'_, Periodic, _, 0, 0> = Alarm::new(systimer.comparator0, &unit); + let mut periodic = PeriodicTimer::new(&mut alarm); let t1 = esp_hal::time::current_time(); periodic.start(1.secs()).unwrap(); @@ -400,9 +408,11 @@ mod test { core::mem::drop(periodic); - let systimer = SystemTimer::new(&mut peripherals.SYSTIMER); + let mut systimer = SystemTimer::new(&mut peripherals.SYSTIMER); - let timer0 = OneShotTimer::new(systimer.alarm0); + let unit = FrozenUnit::new(&mut systimer.unit0); + let alarm: Alarm<'_, Target, _, 0, 0> = Alarm::new(systimer.comparator0, &unit); + let timer0 = OneShotTimer::new(alarm); let t1 = esp_hal::time::current_time(); timer0.delay_millis(500); @@ -448,7 +458,8 @@ mod test { let timer0 = OneShotTimer::new(timer0); let timer1 = { - let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + let systimer = + esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); OneShotTimer::new(alarm0) }; From 527ca988d89cba5e13120a202ef5f2f1b2514e02 Mon Sep 17 00:00:00 2001 From: Dominic Fischer Date: Sat, 10 Aug 2024 02:14:58 +0100 Subject: [PATCH 4/5] Allow erasure of unit and comparator numbers --- esp-hal/src/timer/mod.rs | 64 +---- esp-hal/src/timer/systimer.rs | 314 +++++++++++++-------- examples/src/bin/systimer.rs | 33 ++- hil-test/tests/embassy_timers_executors.rs | 4 +- 4 files changed, 234 insertions(+), 181 deletions(-) diff --git a/esp-hal/src/timer/mod.rs b/esp-hal/src/timer/mod.rs index 58f581fd3a7..2bcc477bd6a 100644 --- a/esp-hal/src/timer/mod.rs +++ b/esp-hal/src/timer/mod.rs @@ -376,17 +376,9 @@ pub enum ErasedTimer { #[cfg(all(timg1, timg_timer1))] Timg1Timer1(timg::Timer, Blocking>), #[cfg(systimer)] - SystimerAlarm0Periodic(systimer::Alarm<'static, systimer::Periodic, Blocking, 0, 0>), + SystimerAlarmPeriodic(systimer::Alarm<'static, systimer::Periodic, Blocking>), #[cfg(systimer)] - SystimerAlarm1Periodic(systimer::Alarm<'static, systimer::Periodic, Blocking, 1, 0>), - #[cfg(systimer)] - SystimerAlarm2Periodic(systimer::Alarm<'static, systimer::Periodic, Blocking, 2, 0>), - #[cfg(systimer)] - SystimerAlarm0Target(systimer::Alarm<'static, systimer::Target, Blocking, 0, 0>), - #[cfg(systimer)] - SystimerAlarm1Target(systimer::Alarm<'static, systimer::Target, Blocking, 1, 0>), - #[cfg(systimer)] - SystimerAlarm2Target(systimer::Alarm<'static, systimer::Target, Blocking, 2, 0>), + SystimerAlarmTarget(systimer::Alarm<'static, systimer::Target, Blocking>), } impl crate::private::Sealed for ErasedTimer {} @@ -419,44 +411,16 @@ impl From, Blocking>> for Er } #[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm<'static, systimer::Periodic, Blocking, 0, 0>) -> Self { - Self::SystimerAlarm0Periodic(value) - } -} - -#[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm<'static, systimer::Periodic, Blocking, 1, 0>) -> Self { - Self::SystimerAlarm1Periodic(value) - } -} - -#[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm<'static, systimer::Periodic, Blocking, 2, 0>) -> Self { - Self::SystimerAlarm2Periodic(value) +impl From> for ErasedTimer { + fn from(value: systimer::Alarm<'static, systimer::Periodic, Blocking>) -> Self { + Self::SystimerAlarmPeriodic(value) } } #[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm<'static, systimer::Target, Blocking, 0, 0>) -> Self { - Self::SystimerAlarm0Target(value) - } -} - -#[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm<'static, systimer::Target, Blocking, 1, 0>) -> Self { - Self::SystimerAlarm1Target(value) - } -} - -#[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm<'static, systimer::Target, Blocking, 2, 0>) -> Self { - Self::SystimerAlarm2Target(value) +impl From> for ErasedTimer { + fn from(value: systimer::Alarm<'static, systimer::Target, Blocking>) -> Self { + Self::SystimerAlarmTarget(value) } } @@ -475,17 +439,9 @@ impl Timer for ErasedTimer { #[cfg(all(timg1,timg_timer1))] ErasedTimer::Timg1Timer1(inner) => inner, #[cfg(systimer)] - ErasedTimer::SystimerAlarm0Periodic(inner) => inner, - #[cfg(systimer)] - ErasedTimer::SystimerAlarm1Periodic(inner) => inner, - #[cfg(systimer)] - ErasedTimer::SystimerAlarm2Periodic(inner) => inner, - #[cfg(systimer)] - ErasedTimer::SystimerAlarm0Target(inner) => inner, - #[cfg(systimer)] - ErasedTimer::SystimerAlarm1Target(inner) => inner, + ErasedTimer::SystimerAlarmPeriodic(inner) => inner, #[cfg(systimer)] - ErasedTimer::SystimerAlarm2Target(inner) => inner, + ErasedTimer::SystimerAlarmTarget(inner) => inner, } { fn start(&self); fn stop(&self); diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index 48838889dc0..43df2e8e494 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -91,20 +91,20 @@ use crate::{ /// System Timer driver. pub struct SystemTimer<'d> { /// Unit 0 - pub unit0: Unit<'d, 0>, + pub unit0: SpecificUnit<'d, 0>, #[cfg(not(esp32s2))] /// Unit 1 - pub unit1: Unit<'d, 1>, + pub unit1: SpecificUnit<'d, 1>, /// Comparator 0. - pub comparator0: Comparator<'d, 0>, + pub comparator0: SpecificComparator<'d, 0>, /// Comparator 1. - pub comparator1: Comparator<'d, 1>, + pub comparator1: SpecificComparator<'d, 1>, /// Comparator 2. - pub comparator2: Comparator<'d, 2>, + pub comparator2: SpecificComparator<'d, 2>, } impl<'d> SystemTimer<'d> { @@ -132,12 +132,12 @@ impl<'d> SystemTimer<'d> { etm::enable_etm(); Self { - unit0: Unit::new(), + unit0: SpecificUnit::new(), #[cfg(not(esp32s2))] - unit1: Unit::new(), - comparator0: Comparator::new(), - comparator1: Comparator::new(), - comparator2: Comparator::new(), + unit1: SpecificUnit::new(), + comparator0: SpecificComparator::new(), + comparator1: SpecificComparator::new(), + comparator2: SpecificComparator::new(), } } @@ -147,7 +147,7 @@ impl<'d> SystemTimer<'d> { // worst case scenario the second accessor ends up reading // an older time stamp - let unit = unsafe { Unit::<'_, 0>::conjure() }; + let unit = unsafe { SpecificUnit::<'_, 0>::conjure() }; unit.update(); loop { @@ -165,16 +165,16 @@ impl SystemTimer<'static> { /// type. You are encouraged to use [Alarm::new] over this very specific /// helper. pub fn split(self) -> SysTimerAlarms { - static mut UNIT0: Option> = None; + static mut UNIT0: Option> = None; let unit0 = unsafe { &mut *addr_of_mut!(UNIT0) }; - let unit0 = unit0.insert(self.unit0); + let unit0 = unit0.insert(self.unit0.into()); let unit = FrozenUnit::new(unit0); SysTimerAlarms { - alarm0: Alarm::new(self.comparator0, &unit), - alarm1: Alarm::new(self.comparator1, &unit), - alarm2: Alarm::new(self.comparator2, &unit), + alarm0: Alarm::new(self.comparator0.into(), &unit), + alarm1: Alarm::new(self.comparator1.into(), &unit), + alarm2: Alarm::new(self.comparator2.into(), &unit), #[cfg(not(esp32s2))] unit1: self.unit1, } @@ -186,16 +186,16 @@ impl SystemTimer<'static> { /// type. You are encouraged to use [Alarm::new_async] over this very /// specific helper. pub fn split_async(self) -> SysTimerAlarms { - static mut UNIT0: Option> = None; + static mut UNIT0: Option> = None; let unit0 = unsafe { &mut *addr_of_mut!(UNIT0) }; - let unit0 = unit0.insert(self.unit0); + let unit0 = unit0.insert(self.unit0.into()); let unit = FrozenUnit::new(unit0); SysTimerAlarms { - alarm0: Alarm::new_async(self.comparator0, &unit), - alarm1: Alarm::new_async(self.comparator1, &unit), - alarm2: Alarm::new_async(self.comparator2, &unit), + alarm0: Alarm::new_async(self.comparator0.into(), &unit), + alarm1: Alarm::new_async(self.comparator1.into(), &unit), + alarm2: Alarm::new_async(self.comparator2.into(), &unit), #[cfg(not(esp32s2))] unit1: self.unit1, } @@ -206,30 +206,26 @@ impl SystemTimer<'static> { #[cfg_attr(esp32s2, doc = "64-bit")] #[cfg_attr(not(esp32s2), doc = "52-bit")] /// counter. -#[derive(Debug)] -pub struct Unit<'d, const CHANNEL: u8>(PhantomData<&'d ()>); - -impl<'d, const CHANNEL: u8> Unit<'d, CHANNEL> { - fn new() -> Self { - Self(PhantomData) - } +pub trait Unit { + /// Returns the unit number. + fn channel(&self) -> u8; #[cfg(not(esp32s2))] /// Configures when this counter can run. /// It can be configured to stall or continue running when CPU stalls /// or enters on-chip-debugging mode - pub fn configure(&self, config: UnitConfig) { + fn configure(&self, config: UnitConfig) { let systimer = unsafe { &*SYSTIMER::ptr() }; let conf = systimer.conf(); critical_section::with(|_| { conf.modify(|_, w| match config { - UnitConfig::Disabled => match CHANNEL { + UnitConfig::Disabled => match self.channel() { 0 => w.timer_unit0_work_en().clear_bit(), 1 => w.timer_unit1_work_en().clear_bit(), _ => unreachable!(), }, - UnitConfig::DisabledIfCpuIsStalled(cpu) => match CHANNEL { + UnitConfig::DisabledIfCpuIsStalled(cpu) => match self.channel() { 0 => w .timer_unit0_work_en() .set_bit() @@ -246,7 +242,7 @@ impl<'d, const CHANNEL: u8> Unit<'d, CHANNEL> { .bit(cpu != Cpu::ProCpu), _ => unreachable!(), }, - UnitConfig::Enabled => match CHANNEL { + UnitConfig::Enabled => match self.channel() { 0 => w .timer_unit0_work_en() .set_bit() @@ -272,12 +268,12 @@ impl<'d, const CHANNEL: u8> Unit<'d, CHANNEL> { /// /// This can be used to load back the sleep time recorded by RTC timer /// via software after Light-sleep - pub fn set_count(&self, value: u64) { + fn set_count(&self, value: u64) { let systimer = unsafe { &*SYSTIMER::ptr() }; #[cfg(not(esp32s2))] { - let unitload = systimer.unitload(CHANNEL as _); - let unit_load = systimer.unit_load(CHANNEL as _); + let unitload = systimer.unitload(self.channel() as _); + let unit_load = systimer.unit_load(self.channel() as _); unitload.hi().write(|w| w.load_hi().set((value << 32) as _)); unitload @@ -303,10 +299,10 @@ impl<'d, const CHANNEL: u8> Unit<'d, CHANNEL> { /// of the counter. /// /// This can be used to read the current value of the timer. - pub fn update(&self) { + fn update(&self) { let systimer = unsafe { &*SYSTIMER::ptr() }; systimer - .unit_op(CHANNEL as _) + .unit_op(self.channel() as _) .modify(|_, w| w.update().set_bit()); } @@ -314,15 +310,15 @@ impl<'d, const CHANNEL: u8> Unit<'d, CHANNEL> { /// /// Returns None if the update isn't ready to read if update has never been /// called. - pub fn poll_count(&self) -> Option { + fn poll_count(&self) -> Option { let systimer = unsafe { &*SYSTIMER::ptr() }; if systimer - .unit_op(CHANNEL as _) + .unit_op(self.channel() as _) .read() .value_valid() .bit_is_set() { - let unit_value = systimer.unit_value(CHANNEL as _); + let unit_value = systimer.unit_value(self.channel() as _); let lo = unit_value.lo().read().bits(); let hi = unit_value.hi().read().bits(); @@ -334,7 +330,7 @@ impl<'d, const CHANNEL: u8> Unit<'d, CHANNEL> { } /// Convenience method to call [Self::update] and [Self::poll_count]. - pub fn read_count(&self) -> u64 { + fn read_count(&self) -> u64 { // This can be a shared reference as long as this type isn't Sync. self.update(); @@ -346,23 +342,63 @@ impl<'d, const CHANNEL: u8> Unit<'d, CHANNEL> { } } -/// A comparator that can generate alarms/interrupts based on values of a unit. +/// A specific [Unit]. i.e. Either unit 0 or unit 1. #[derive(Debug)] -pub struct Comparator<'d, const CHANNEL: u8>(PhantomData<&'d ()>); +pub struct SpecificUnit<'d, const CHANNEL: u8>(PhantomData<&'d ()>); -impl<'d, const CHANNEL: u8> Comparator<'d, CHANNEL> { +impl<'d, const CHANNEL: u8> SpecificUnit<'d, CHANNEL> { fn new() -> Self { Self(PhantomData) } +} + +impl<'d, const CHANNEL: u8> Unit for SpecificUnit<'d, CHANNEL> { + fn channel(&self) -> u8 { + CHANNEL + } +} + +/// Any [Unit]. Could be either unit 0 or unit 1. +#[derive(Debug)] +pub struct AnyUnit<'d>(PhantomData<&'d ()>, u8); + +impl<'d> Unit for AnyUnit<'d> { + fn channel(&self) -> u8 { + self.1 + } +} + +impl<'d, const CHANNEL: u8> From> for AnyUnit<'d> { + fn from(_value: SpecificUnit<'d, CHANNEL>) -> Self { + Self(PhantomData, CHANNEL) + } +} + +impl<'d, const CHANNEL: u8> TryFrom> for SpecificUnit<'d, CHANNEL> { + type Error = u8; + + fn try_from(value: AnyUnit<'d>) -> Result { + if value.1 == CHANNEL { + Ok(SpecificUnit::new()) + } else { + Err(value.1) + } + } +} + +/// A comparator that can generate alarms/interrupts based on values of a unit. +pub trait Comparator { + /// Returns the comparators number. + fn channel(&self) -> u8; /// Enables/disables the comparator. If enabled, this means /// it will generate interrupt based on its configuration. - pub fn set_enable(&self, enable: bool) { + fn set_enable(&self, enable: bool) { let systimer = unsafe { &*SYSTIMER::ptr() }; #[cfg(not(esp32s2))] critical_section::with(|_| { - systimer.conf().modify(|_, w| match CHANNEL { + systimer.conf().modify(|_, w| match self.channel() { 0 => w.target0_work_en().bit(enable), 1 => w.target1_work_en().bit(enable), 2 => w.target2_work_en().bit(enable), @@ -372,18 +408,18 @@ impl<'d, const CHANNEL: u8> Comparator<'d, CHANNEL> { #[cfg(esp32s2)] systimer - .target_conf(CHANNEL as usize) + .target_conf(self.channel() as usize) .modify(|_r, w| w.work_en().bit(enable)); } /// Returns true if the comparator has been enabled. This means /// it will generate interrupt based on its configuration. - pub fn is_enabled(&self) -> bool { + fn is_enabled(&self) -> bool { #[cfg(not(esp32s2))] { let systimer = unsafe { &*SYSTIMER::ptr() }; let conf = systimer.conf().read(); - match CHANNEL { + match self.channel() { 0 => conf.target0_work_en().bit(), 1 => conf.target1_work_en().bit(), 2 => conf.target2_work_en().bit(), @@ -395,7 +431,7 @@ impl<'d, const CHANNEL: u8> Comparator<'d, CHANNEL> { { let tconf = unsafe { let systimer = &*SYSTIMER::ptr(); - systimer.target_conf(CHANNEL as usize) + systimer.target_conf(self.channel() as usize) }; tconf.read().work_en().bit() } @@ -403,19 +439,19 @@ impl<'d, const CHANNEL: u8> Comparator<'d, CHANNEL> { /// Sets the unit this comparator uses as a reference count. #[cfg(not(esp32s2))] - pub fn set_unit(&self, is_unit0: bool) { + fn set_unit(&self, is_unit0: bool) { let tconf = unsafe { let systimer = &*SYSTIMER::ptr(); - systimer.target_conf(CHANNEL as usize) + systimer.target_conf(self.channel() as usize) }; tconf.modify(|_, w| w.timer_unit_sel().bit(is_unit0)); } /// Set the mode of the comparator to be either target or periodic. - pub fn set_mode(&self, mode: ComparatorMode) { + fn set_mode(&self, mode: ComparatorMode) { let tconf = unsafe { let systimer = &*SYSTIMER::ptr(); - systimer.target_conf(CHANNEL as usize) + systimer.target_conf(self.channel() as usize) }; let is_period_mode = match mode { ComparatorMode::Period => true, @@ -426,10 +462,10 @@ impl<'d, const CHANNEL: u8> Comparator<'d, CHANNEL> { /// Get the current mode of the comparator, which is either target or /// periodic. - pub fn get_mode(&self) -> ComparatorMode { + fn get_mode(&self) -> ComparatorMode { let tconf = unsafe { let systimer = &*SYSTIMER::ptr(); - systimer.target_conf(CHANNEL as usize) + systimer.target_conf(self.channel() as usize) }; if tconf.read().period_mode().bit() { ComparatorMode::Period @@ -440,39 +476,39 @@ impl<'d, const CHANNEL: u8> Comparator<'d, CHANNEL> { /// Set how often the comparator should generate an interrupt when in /// periodic mode. - pub fn set_period(&self, value: u32) { + fn set_period(&self, value: u32) { unsafe { let systimer = &*SYSTIMER::ptr(); - let tconf = systimer.target_conf(CHANNEL as usize); + let tconf = systimer.target_conf(self.channel() as usize); tconf.modify(|_, w| w.period().bits(value)); #[cfg(not(esp32s2))] { - let comp_load = systimer.comp_load(CHANNEL as usize); + let comp_load = systimer.comp_load(self.channel() as usize); comp_load.write(|w| w.load().set_bit()); } } } /// Set when the comparator should generate an interrupt in target mode. - pub fn set_target(&self, value: u64) { + fn set_target(&self, value: u64) { let systimer = unsafe { &*SYSTIMER::ptr() }; - let target = systimer.trgt(CHANNEL as usize); + let target = systimer.trgt(self.channel() as usize); target.hi().write(|w| w.hi().set((value >> 32) as u32)); target .lo() .write(|w| w.lo().set((value & 0xFFFF_FFFF) as u32)); #[cfg(not(esp32s2))] { - let comp_load = systimer.comp_load(CHANNEL as usize); + let comp_load = systimer.comp_load(self.channel() as usize); comp_load.write(|w| w.load().set_bit()); } } /// Get the actual target value of the comparator. - pub fn get_actual_target(&self) -> u64 { + fn get_actual_target(&self) -> u64 { let target = unsafe { let systimer = &*SYSTIMER::ptr(); - systimer.trgt(CHANNEL as usize) + systimer.trgt(self.channel() as usize) }; let hi = target.hi().read().hi().bits(); let lo = target.lo().read().lo().bits(); @@ -481,8 +517,8 @@ impl<'d, const CHANNEL: u8> Comparator<'d, CHANNEL> { } /// Set the interrupt handler for this comparator. - pub fn set_interrupt_handler(&self, handler: InterruptHandler) { - let interrupt = match CHANNEL { + fn set_interrupt_handler(&self, handler: InterruptHandler) { + let interrupt = match self.channel() { 0 => Interrupt::SYSTIMER_TARGET0, 1 => Interrupt::SYSTIMER_TARGET1, 2 => Interrupt::SYSTIMER_TARGET2, @@ -495,6 +531,50 @@ impl<'d, const CHANNEL: u8> Comparator<'d, CHANNEL> { } } +/// A specific [Comparator]. i.e. Either comparator 0, comparator 1, etc. +#[derive(Debug)] +pub struct SpecificComparator<'d, const CHANNEL: u8>(PhantomData<&'d ()>); + +impl<'d, const CHANNEL: u8> SpecificComparator<'d, CHANNEL> { + fn new() -> Self { + Self(PhantomData) + } +} + +impl<'d, const CHANNEL: u8> Comparator for SpecificComparator<'d, CHANNEL> { + fn channel(&self) -> u8 { + CHANNEL + } +} + +/// Any [Comparator]. Could be either comparator 0, comparator 1, etc. +#[derive(Debug)] +pub struct AnyComparator<'d>(PhantomData<&'d ()>, u8); + +impl<'d> Comparator for AnyComparator<'d> { + fn channel(&self) -> u8 { + self.1 + } +} + +impl<'d, const CHANNEL: u8> From> for AnyComparator<'d> { + fn from(_value: SpecificComparator<'d, CHANNEL>) -> Self { + Self(PhantomData, CHANNEL) + } +} + +impl<'d, const CHANNEL: u8> TryFrom> for SpecificComparator<'d, CHANNEL> { + type Error = u8; + + fn try_from(value: AnyComparator<'d>) -> Result { + if value.1 == CHANNEL { + Ok(SpecificComparator::new()) + } else { + Err(value.1) + } + } +} + /// The configuration of a unit. #[derive(Copy, Clone)] pub enum UnitConfig { @@ -519,7 +599,7 @@ pub enum ComparatorMode { Target, } -impl Unit<'static, 0> { +impl SpecificUnit<'static, 0> { /// Conjure a system timer unit out of thin air. /// /// # Safety @@ -532,7 +612,7 @@ impl Unit<'static, 0> { } #[cfg(not(esp32s2))] -impl Unit<'static, 1> { +impl SpecificUnit<'static, 1> { /// Conjure a system timer unit out of thin air. /// /// # Safety @@ -545,17 +625,17 @@ impl Unit<'static, 1> { } /// A unit whose value cannot be updated. -pub struct FrozenUnit<'d, const CHANNEL: u8>(&'d Unit<'d, CHANNEL>); +pub struct FrozenUnit<'d, U: Unit>(&'d U); -impl<'d, const CHANNEL: u8> FrozenUnit<'d, CHANNEL> { +impl<'d, U: Unit> FrozenUnit<'d, U> { /// Creates a frozen unit. You will no longer be allowed /// direct access to this unit until all the alarms created /// from the unit are dropped. - pub fn new(unit: &'d mut Unit<'d, CHANNEL>) -> Self { + pub fn new(unit: &'d mut U) -> Self { Self(unit) } - fn borrow(&self) -> &'d Unit<'d, CHANNEL> { + fn borrow(&self) -> &'d U { self.0 } } @@ -563,17 +643,17 @@ impl<'d, const CHANNEL: u8> FrozenUnit<'d, CHANNEL> { /// Alarms created from the System Timer peripheral. pub struct SysTimerAlarms { /// Alarm 0 - pub alarm0: Alarm<'static, MODE, DM, 0, 0>, + pub alarm0: Alarm<'static, MODE, DM>, /// Alarm 1 - pub alarm1: Alarm<'static, MODE, DM, 1, 0>, + pub alarm1: Alarm<'static, MODE, DM>, /// Alarm 2 - pub alarm2: Alarm<'static, MODE, DM, 2, 0>, + pub alarm2: Alarm<'static, MODE, DM>, /// Unit 1 /// /// Leftover unit which wasn't used to create the three alarms. #[cfg(not(esp32s2))] - pub unit1: Unit<'static, 1>, + pub unit1: SpecificUnit<'static, 1>, } /// A marker for a [Alarm] in target mode. @@ -585,30 +665,30 @@ pub struct Target; pub struct Periodic; /// A single alarm. -pub struct Alarm<'d, MODE, DM, const COMP: u8, const UNIT: u8> +pub struct Alarm<'d, MODE, DM, COMP = AnyComparator<'d>, UNIT = AnyUnit<'d>> where DM: Mode, { - comparator: Comparator<'d, COMP>, - unit: &'d Unit<'d, UNIT>, + comparator: COMP, + unit: &'d UNIT, _pd: PhantomData<(MODE, DM)>, } -impl<'d, T, DM, const COMP: u8, const UNIT: u8> Debug for Alarm<'d, T, DM, COMP, UNIT> +impl<'d, T, DM, COMP: Comparator, UNIT: Unit> Debug for Alarm<'d, T, DM, COMP, UNIT> where DM: Mode, { fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { f.debug_struct("Alarm") - .field("comparator", &COMP) - .field("unit", &UNIT) + .field("comparator", &self.comparator.channel()) + .field("unit", &self.unit.channel()) .finish() } } -impl<'d, T, const COMP: u8, const UNIT: u8> Alarm<'d, T, Blocking, COMP, UNIT> { +impl<'d, T, COMP: Comparator, UNIT: Unit> Alarm<'d, T, Blocking, COMP, UNIT> { /// Creates a new alarm from a comparator and unit, in blocking mode. - pub fn new(comparator: Comparator<'d, COMP>, unit: &FrozenUnit<'d, UNIT>) -> Self { + pub fn new(comparator: COMP, unit: &FrozenUnit<'d, UNIT>) -> Self { Self { comparator, unit: unit.borrow(), @@ -617,9 +697,9 @@ impl<'d, T, const COMP: u8, const UNIT: u8> Alarm<'d, T, Blocking, COMP, UNIT> { } } -impl<'d, T, const COMP: u8, const UNIT: u8> Alarm<'d, T, Async, COMP, UNIT> { +impl<'d, T, COMP: Comparator, UNIT: Unit> Alarm<'d, T, Async, COMP, UNIT> { /// Creates a new alarm from a comparator and unit, in async mode. - pub fn new_async(comparator: Comparator<'d, COMP>, unit: &FrozenUnit<'d, UNIT>) -> Self { + pub fn new_async(comparator: COMP, unit: &FrozenUnit<'d, UNIT>) -> Self { Self { comparator, unit: unit.0, @@ -628,7 +708,7 @@ impl<'d, T, const COMP: u8, const UNIT: u8> Alarm<'d, T, Async, COMP, UNIT> { } } -impl<'d, T, const COMP: u8, const UNIT: u8> InterruptConfigurable +impl<'d, T, COMP: Comparator, UNIT: Unit> InterruptConfigurable for Alarm<'d, T, Blocking, COMP, UNIT> { fn set_interrupt_handler(&mut self, handler: InterruptHandler) { @@ -636,7 +716,7 @@ impl<'d, T, const COMP: u8, const UNIT: u8> InterruptConfigurable } } -impl<'d, DM, const COMP: u8, const UNIT: u8> Alarm<'d, Target, DM, COMP, UNIT> +impl<'d, DM, COMP: Comparator, UNIT: Unit> Alarm<'d, Target, DM, COMP, UNIT> where DM: Mode, { @@ -661,7 +741,7 @@ where let r = unsafe { &*crate::peripherals::SYSTIMER::PTR }.int_raw(); loop { - if r.read().target(COMP).bit_is_set() { + if r.read().target(self.comparator.channel()).bit_is_set() { break; } } @@ -677,7 +757,7 @@ where } } -impl<'d, DM, const COMP: u8, const UNIT: u8> Alarm<'d, Periodic, DM, COMP, UNIT> +impl<'d, DM, COMP: Comparator, UNIT: Unit> Alarm<'d, Periodic, DM, COMP, UNIT> where DM: Mode, { @@ -708,14 +788,14 @@ where } } -impl<'d, T, DM, const COMP: u8, const UNIT: u8> crate::private::Sealed +impl<'d, T, DM, COMP: Comparator, UNIT: Unit> crate::private::Sealed for Alarm<'d, T, DM, COMP, UNIT> where DM: Mode, { } -impl<'d, T, DM, const COMP: u8, const UNIT: u8> super::Timer for Alarm<'d, T, DM, COMP, UNIT> +impl<'d, T, DM, COMP: Comparator, UNIT: Unit> super::Timer for Alarm<'d, T, DM, COMP, UNIT> where DM: Mode, { @@ -825,20 +905,20 @@ where fn enable_interrupt(&self, state: bool) { unsafe { &*SYSTIMER::PTR } .int_ena() - .modify(|_, w| w.target(COMP).bit(state)); + .modify(|_, w| w.target(self.comparator.channel()).bit(state)); } fn clear_interrupt(&self) { unsafe { &*SYSTIMER::PTR } .int_clr() - .write(|w| w.target(COMP).clear_bit_by_one()); + .write(|w| w.target(self.comparator.channel()).clear_bit_by_one()); } fn is_interrupt_set(&self) -> bool { unsafe { &*SYSTIMER::PTR } .int_raw() .read() - .target(COMP) + .target(self.comparator.channel()) .bit_is_set() } @@ -851,7 +931,7 @@ where } } -impl<'d, T, DM, const COMP: u8, const UNIT: u8> Peripheral for Alarm<'d, T, DM, COMP, UNIT> +impl<'d, T, DM, COMP: Comparator, UNIT: Unit> Peripheral for Alarm<'d, T, DM, COMP, UNIT> where DM: Mode, { @@ -882,15 +962,15 @@ mod asynch { const INIT: AtomicWaker = AtomicWaker::new(); static WAKERS: [AtomicWaker; NUM_ALARMS] = [INIT; NUM_ALARMS]; - pub(crate) struct AlarmFuture<'a, const COMP: u8, const UNIT: u8> { - phantom: PhantomData<&'a Alarm<'a, Periodic, crate::Async, COMP, UNIT>>, + pub(crate) struct AlarmFuture<'a, COMP: Comparator, UNIT: Unit> { + alarm: &'a Alarm<'a, Periodic, crate::Async, COMP, UNIT>, } - impl<'a, const COMP: u8, const UNIT: u8> AlarmFuture<'a, COMP, UNIT> { + impl<'a, COMP: Comparator, UNIT: Unit> AlarmFuture<'a, COMP, UNIT> { pub(crate) fn new(alarm: &'a Alarm<'a, Periodic, crate::Async, COMP, UNIT>) -> Self { alarm.clear_interrupt(); - let (interrupt, handler) = match COMP { + let (interrupt, handler) = match alarm.comparator.channel() { 0 => (Interrupt::SYSTIMER_TARGET0, target0_handler), 1 => (Interrupt::SYSTIMER_TARGET1, target1_handler), _ => (Interrupt::SYSTIMER_TARGET2, target2_handler), @@ -903,25 +983,23 @@ mod asynch { alarm.enable_interrupt(true); - Self { - phantom: PhantomData, - } + Self { alarm } } fn event_bit_is_clear(&self) -> bool { unsafe { &*crate::peripherals::SYSTIMER::PTR } .int_ena() .read() - .target(COMP) + .target(self.alarm.comparator.channel()) .bit_is_clear() } } - impl<'a, const COMP: u8, const UNIT: u8> core::future::Future for AlarmFuture<'a, COMP, UNIT> { + impl<'a, COMP: Comparator, UNIT: Unit> core::future::Future for AlarmFuture<'a, COMP, UNIT> { type Output = (); fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll { - WAKERS[COMP as usize].register(ctx.waker()); + WAKERS[self.alarm.comparator.channel() as usize].register(ctx.waker()); if self.event_bit_is_clear() { Poll::Ready(()) @@ -931,7 +1009,7 @@ mod asynch { } } - impl<'d, const COMP: u8, const UNIT: u8> embedded_hal_async::delay::DelayNs + impl<'d, COMP: Comparator, UNIT: Unit> embedded_hal_async::delay::DelayNs for Alarm<'d, Periodic, crate::Async, COMP, UNIT> { async fn delay_ns(&mut self, ns: u32) { @@ -1007,33 +1085,35 @@ pub mod etm { use super::*; /// An ETM controlled SYSTIMER event - pub struct SysTimerEtmEvent<'a, 'd, M, DM: crate::Mode, const COMP: u8> { - alarm: &'a mut Alarm<'d, M, DM, COMP, 0>, + pub struct SysTimerEtmEvent<'a, 'd, M, DM: crate::Mode, COMP, UNIT> { + alarm: &'a mut Alarm<'d, M, DM, COMP, UNIT>, } - impl<'a, 'd, M, DM: crate::Mode, const COMP: u8> SysTimerEtmEvent<'a, 'd, M, DM, COMP> { + impl<'a, 'd, M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> + SysTimerEtmEvent<'a, 'd, M, DM, COMP, UNIT> + { /// Creates an ETM event from the given [Alarm] - pub fn new(alarm: &'a mut Alarm<'d, M, DM, COMP, 0>) -> Self { + pub fn new(alarm: &'a mut Alarm<'d, M, DM, COMP, UNIT>) -> Self { Self { alarm } } /// Execute closure f with mutable access to the wrapped [Alarm]. - pub fn with(&self, f: impl FnOnce(&&'a mut Alarm<'d, M, DM, COMP, 0>) -> R) -> R { + pub fn with(&self, f: impl FnOnce(&&'a mut Alarm<'d, M, DM, COMP, UNIT>) -> R) -> R { let alarm = &self.alarm; f(alarm) } } - impl<'a, 'd, M, DM: crate::Mode, const COMP: u8> crate::private::Sealed - for SysTimerEtmEvent<'a, 'd, M, DM, COMP> + impl<'a, 'd, M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> crate::private::Sealed + for SysTimerEtmEvent<'a, 'd, M, DM, COMP, UNIT> { } - impl<'a, 'd, M, DM: crate::Mode, const COMP: u8> crate::etm::EtmEvent - for SysTimerEtmEvent<'a, 'd, M, DM, COMP> + impl<'a, 'd, M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> crate::etm::EtmEvent + for SysTimerEtmEvent<'a, 'd, M, DM, COMP, UNIT> { fn id(&self) -> u8 { - 50 + COMP + 50 + self.alarm.comparator.channel() } } diff --git a/examples/src/bin/systimer.rs b/examples/src/bin/systimer.rs index 3124ea8e22c..455af18be48 100644 --- a/examples/src/bin/systimer.rs +++ b/examples/src/bin/systimer.rs @@ -18,19 +18,36 @@ use esp_hal::{ peripherals::{Interrupt, Peripherals}, prelude::*, system::SystemControl, - timer::systimer::{Alarm, FrozenUnit, Periodic, SystemTimer, Target, Unit}, + timer::systimer::{ + Alarm, + FrozenUnit, + Periodic, + SpecificComparator, + SpecificUnit, + SystemTimer, + Target, + }, Blocking, }; use esp_println::println; use fugit::ExtU32; use static_cell::StaticCell; -static ALARM0: Mutex>>> = - Mutex::new(RefCell::new(None)); -static ALARM1: Mutex>>> = - Mutex::new(RefCell::new(None)); -static ALARM2: Mutex>>> = - Mutex::new(RefCell::new(None)); +static ALARM0: Mutex< + RefCell< + Option, SpecificUnit<'static, 0>>>, + >, +> = Mutex::new(RefCell::new(None)); +static ALARM1: Mutex< + RefCell< + Option, SpecificUnit<'static, 0>>>, + >, +> = Mutex::new(RefCell::new(None)); +static ALARM2: Mutex< + RefCell< + Option, SpecificUnit<'static, 0>>>, + >, +> = Mutex::new(RefCell::new(None)); #[entry] fn main() -> ! { @@ -41,7 +58,7 @@ fn main() -> ! { let systimer = SystemTimer::new(peripherals.SYSTIMER); println!("SYSTIMER Current value = {}", SystemTimer::now()); - static UNIT0: StaticCell> = StaticCell::new(); + static UNIT0: StaticCell> = StaticCell::new(); let unit0 = UNIT0.init(systimer.unit0); diff --git a/hil-test/tests/embassy_timers_executors.rs b/hil-test/tests/embassy_timers_executors.rs index 6befbda0a3c..9f6b59114ab 100644 --- a/hil-test/tests/embassy_timers_executors.rs +++ b/hil-test/tests/embassy_timers_executors.rs @@ -391,7 +391,7 @@ mod test { let mut systimer = SystemTimer::new(&mut peripherals.SYSTIMER); let unit = FrozenUnit::new(&mut systimer.unit0); - let mut alarm: Alarm<'_, Periodic, _, 0, 0> = Alarm::new(systimer.comparator0, &unit); + let mut alarm: Alarm<'_, Periodic, _, _, _> = Alarm::new(systimer.comparator0, &unit); let mut periodic = PeriodicTimer::new(&mut alarm); let t1 = esp_hal::time::current_time(); @@ -411,7 +411,7 @@ mod test { let mut systimer = SystemTimer::new(&mut peripherals.SYSTIMER); let unit = FrozenUnit::new(&mut systimer.unit0); - let alarm: Alarm<'_, Target, _, 0, 0> = Alarm::new(systimer.comparator0, &unit); + let alarm: Alarm<'_, Target, _, _, _> = Alarm::new(systimer.comparator0, &unit); let timer0 = OneShotTimer::new(alarm); let t1 = esp_hal::time::current_time(); From 624b79c0e52ee77c814bf949a90eab4d26d4015e Mon Sep 17 00:00:00 2001 From: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> Date: Fri, 16 Aug 2024 15:41:50 +0100 Subject: [PATCH 5/5] Merge fail --- hil-test/tests/embassy_timers_executors.rs | 10 +++++++--- 1 file changed, 7 insertions(+), 3 deletions(-) diff --git a/hil-test/tests/embassy_timers_executors.rs b/hil-test/tests/embassy_timers_executors.rs index a9a9781359a..e24533c89dd 100644 --- a/hil-test/tests/embassy_timers_executors.rs +++ b/hil-test/tests/embassy_timers_executors.rs @@ -183,7 +183,7 @@ mod test { #[timeout(3)] #[cfg(not(feature = "esp32"))] fn test_periodic_systimer(resources: Resources) { - let systimer = SystemTimer::new(resources.systimer); + let systimer = SystemTimer::new(resources.systimer).split::(); run_test_periodic_timer(systimer.alarm0); } @@ -203,10 +203,14 @@ mod test { #[cfg(not(feature = "esp32"))] fn test_periodic_oneshot_systimer(mut resources: Resources) { let mut systimer = SystemTimer::new(&mut resources.systimer); - run_test_periodic_timer(&mut systimer.alarm0); + let unit = FrozenUnit::new(&mut systimer.unit0); + let mut alarm: Alarm<'_, Periodic, _, _, _> = Alarm::new(systimer.comparator0, &unit); + run_test_periodic_timer(&mut alarm); let mut systimer = SystemTimer::new(&mut resources.systimer); - run_test_oneshot_timer(&mut systimer.alarm0); + let unit = FrozenUnit::new(&mut systimer.unit0); + let mut alarm: Alarm<'_, Target, _, _, _> = Alarm::new(systimer.comparator0, &unit); + run_test_oneshot_timer(&mut alarm); } #[test]