From 6e706c5f113b7d2a05678f326b88d20c385b222d Mon Sep 17 00:00:00 2001 From: Dominic Fischer <14130965+Dominaezzz@users.noreply.github.com> Date: Fri, 16 Aug 2024 15:59:34 +0100 Subject: [PATCH] Improve SYSTIMER API (#1871) * Improve SYSTIMER API * Remove config object * fix things * Allow erasure of unit and comparator numbers * Merge fail --------- Co-authored-by: Dominic Fischer --- esp-hal/CHANGELOG.md | 1 + esp-hal/src/timer/mod.rs | 64 +- esp-hal/src/timer/systimer.rs | 954 ++++++++++++------ 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 | 46 +- 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 +- hil-test/tests/embassy_timers_executors.rs | 19 +- 16 files changed, 743 insertions(+), 386 deletions(-) diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 9c3f28757b7..f2b5a0044d5 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -19,6 +19,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) - DMA: don't require `Sealed` to implement `ReadBuffer` and `WriteBuffer` (#1921) - 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 4946d0111e6..99efaf8838e 100644 --- a/esp-hal/src/timer/mod.rs +++ b/esp-hal/src/timer/mod.rs @@ -374,17 +374,9 @@ pub enum ErasedTimer { #[cfg(all(timg1, timg_timer1))] Timg1Timer1(timg::Timer, Blocking>), #[cfg(systimer)] - SystimerAlarm0Periodic(systimer::Alarm), + SystimerAlarmPeriodic(systimer::Alarm<'static, systimer::Periodic, Blocking>), #[cfg(systimer)] - SystimerAlarm1Periodic(systimer::Alarm), - #[cfg(systimer)] - SystimerAlarm2Periodic(systimer::Alarm), - #[cfg(systimer)] - SystimerAlarm0Target(systimer::Alarm), - #[cfg(systimer)] - SystimerAlarm1Target(systimer::Alarm), - #[cfg(systimer)] - SystimerAlarm2Target(systimer::Alarm), + SystimerAlarmTarget(systimer::Alarm<'static, systimer::Target, Blocking>), } impl crate::private::Sealed for ErasedTimer {} @@ -417,44 +409,16 @@ impl From, Blocking>> for Er } #[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm) -> Self { - Self::SystimerAlarm0Periodic(value) - } -} - -#[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm) -> Self { - Self::SystimerAlarm1Periodic(value) - } -} - -#[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm) -> 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) -> Self { - Self::SystimerAlarm0Target(value) - } -} - -#[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm) -> Self { - Self::SystimerAlarm1Target(value) - } -} - -#[cfg(systimer)] -impl From> for ErasedTimer { - fn from(value: systimer::Alarm) -> Self { - Self::SystimerAlarm2Target(value) +impl From> for ErasedTimer { + fn from(value: systimer::Alarm<'static, systimer::Target, Blocking>) -> Self { + Self::SystimerAlarmTarget(value) } } @@ -473,17 +437,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 aac957bfe81..43df2e8e494 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -68,7 +68,11 @@ //! } //! ``` -use core::marker::PhantomData; +use core::{ + fmt::{Debug, Formatter}, + marker::PhantomData, + ptr::addr_of_mut, +}; use fugit::{Instant, MicrosDurationU32, MicrosDurationU64}; @@ -76,32 +80,34 @@ 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> { + /// Unit 0 + pub unit0: SpecificUnit<'d, 0>, + + #[cfg(not(esp32s2))] + /// Unit 1 + pub unit1: SpecificUnit<'d, 1>, + + /// Comparator 0. + pub comparator0: SpecificComparator<'d, 0>, + + /// Comparator 1. + pub comparator1: SpecificComparator<'d, 1>, + + /// Comparator 2. + pub comparator2: SpecificComparator<'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 +126,18 @@ 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(), + unit0: SpecificUnit::new(), + #[cfg(not(esp32s2))] + unit1: SpecificUnit::new(), + comparator0: SpecificComparator::new(), + comparator1: SpecificComparator::new(), + comparator2: SpecificComparator::new(), } } @@ -138,33 +146,516 @@ 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 unit = unsafe { SpecificUnit::<'_, 0>::conjure() }; + + unit.update(); + loop { + if let Some(value) = unit.poll_count() { + break value; + } + } + } +} + +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 mut UNIT0: Option> = None; + let unit0 = unsafe { &mut *addr_of_mut!(UNIT0) }; + + let unit0 = unit0.insert(self.unit0.into()); + let unit = FrozenUnit::new(unit0); + + SysTimerAlarms { + 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, + } + } + + /// 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 mut UNIT0: Option> = None; + let unit0 = unsafe { &mut *addr_of_mut!(UNIT0) }; + + let unit0 = unit0.insert(self.unit0.into()); + let unit = FrozenUnit::new(unit0); + + SysTimerAlarms { + 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, + } + } +} + +/// A +#[cfg_attr(esp32s2, doc = "64-bit")] +#[cfg_attr(not(esp32s2), doc = "52-bit")] +/// counter. +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 + fn configure(&self, config: UnitConfig) { let systimer = unsafe { &*SYSTIMER::ptr() }; - systimer.unit0_op().modify(|_, w| w.update().set_bit()); + let conf = systimer.conf(); + + critical_section::with(|_| { + conf.modify(|_, w| match config { + 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 self.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 self.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!(), + }, + }); + }); + } - while !systimer.unit0_op().read().value_valid().bit_is_set() {} + /// 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 + fn set_count(&self, value: u64) { + let systimer = unsafe { &*SYSTIMER::ptr() }; + #[cfg(not(esp32s2))] + { + let unitload = systimer.unitload(self.channel() as _); + let unit_load = systimer.unit_load(self.channel() as _); - let value_lo = systimer.unit0_value().lo().read().bits(); - let value_hi = systimer.unit0_value().hi().read().bits(); + unitload.hi().write(|w| w.load_hi().set((value << 32) as _)); + unitload + .lo() + .write(|w| w.load_lo().set((value & 0xFFFF_FFFF) as _)); - ((value_hi as u64) << 32) | value_lo as u64 + 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. + fn update(&self) { + let systimer = unsafe { &*SYSTIMER::ptr() }; + systimer + .unit_op(self.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. + fn poll_count(&self) -> Option { + let systimer = unsafe { &*SYSTIMER::ptr() }; + if systimer + .unit_op(self.channel() as _) + .read() + .value_valid() + .bit_is_set() + { + let unit_value = systimer.unit_value(self.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]. + 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<'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(); +/// A specific [Unit]. i.e. Either unit 0 or unit 1. +#[derive(Debug)] +pub struct SpecificUnit<'d, const CHANNEL: u8>(PhantomData<&'d ()>); - Self { - alarm0: Alarm::new(), - alarm1: Alarm::new(), - alarm2: Alarm::new(), - _phantom: PhantomData, +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. + fn set_enable(&self, enable: bool) { + let systimer = unsafe { &*SYSTIMER::ptr() }; + + #[cfg(not(esp32s2))] + critical_section::with(|_| { + 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), + _ => unreachable!(), + }); + }); + + #[cfg(esp32s2)] + systimer + .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. + fn is_enabled(&self) -> bool { + #[cfg(not(esp32s2))] + { + let systimer = unsafe { &*SYSTIMER::ptr() }; + let conf = systimer.conf().read(); + match self.channel() { + 0 => conf.target0_work_en().bit(), + 1 => conf.target1_work_en().bit(), + 2 => conf.target2_work_en().bit(), + _ => unreachable!(), + } + } + + #[cfg(esp32s2)] + { + let tconf = unsafe { + let systimer = &*SYSTIMER::ptr(); + systimer.target_conf(self.channel() as usize) + }; + tconf.read().work_en().bit() + } + } + + /// Sets the unit this comparator uses as a reference count. + #[cfg(not(esp32s2))] + fn set_unit(&self, is_unit0: bool) { + let tconf = unsafe { + let systimer = &*SYSTIMER::ptr(); + 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. + fn set_mode(&self, mode: ComparatorMode) { + let tconf = unsafe { + let systimer = &*SYSTIMER::ptr(); + systimer.target_conf(self.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. + fn get_mode(&self) -> ComparatorMode { + let tconf = unsafe { + let systimer = &*SYSTIMER::ptr(); + systimer.target_conf(self.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. + fn set_period(&self, value: u32) { + unsafe { + let systimer = &*SYSTIMER::ptr(); + 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(self.channel() as usize); + comp_load.write(|w| w.load().set_bit()); + } + } + } + + /// Set when the comparator should generate an interrupt in target mode. + fn set_target(&self, value: u64) { + let systimer = unsafe { &*SYSTIMER::ptr() }; + 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(self.channel() as usize); + comp_load.write(|w| w.load().set_bit()); + } + } + + /// Get the actual target value of the comparator. + fn get_actual_target(&self) -> u64 { + let target = unsafe { + let systimer = &*SYSTIMER::ptr(); + systimer.trgt(self.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. + fn set_interrupt_handler(&self, handler: InterruptHandler) { + let interrupt = match self.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())); + } +} + +/// 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 { + /// 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 SpecificUnit<'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 SpecificUnit<'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) + } +} + +/// A unit whose value cannot be updated. +pub struct FrozenUnit<'d, U: Unit>(&'d U); + +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 U) -> Self { + Self(unit) + } + + fn borrow(&self) -> &'d U { + self.0 + } +} + +/// Alarms created from the System Timer peripheral. +pub struct SysTimerAlarms { + /// Alarm 0 + pub alarm0: Alarm<'static, MODE, DM>, + /// Alarm 1 + pub alarm1: Alarm<'static, MODE, DM>, + /// Alarm 2 + pub alarm2: Alarm<'static, MODE, DM>, + + /// Unit 1 + /// + /// Leftover unit which wasn't used to create the three alarms. + #[cfg(not(esp32s2))] + pub unit1: SpecificUnit<'static, 1>, +} + /// A marker for a [Alarm] in target mode. #[derive(Debug)] pub struct Target; @@ -174,114 +665,73 @@ pub struct Target; pub struct Periodic; /// A single alarm. -#[derive(Debug)] -pub struct Alarm +pub struct Alarm<'d, MODE, DM, COMP = AnyComparator<'d>, UNIT = AnyUnit<'d>> where DM: Mode, { + comparator: COMP, + unit: &'d UNIT, _pd: PhantomData<(MODE, DM)>, } -impl Alarm +impl<'d, T, DM, COMP: Comparator, UNIT: Unit> Debug for Alarm<'d, T, DM, COMP, UNIT> where DM: Mode, { - fn new() -> Self { - Self { _pd: PhantomData } + fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result { + f.debug_struct("Alarm") + .field("comparator", &self.comparator.channel()) + .field("unit", &self.unit.channel()) + .finish() } +} - 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); - - #[cfg(esp32s2)] - systimer.step().write(|w| w.xtal_step().bits(0x1)); // run at XTAL freq, not 80 * XTAL freq - - #[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()); - } - - conf(tconf, target); - - #[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!(), - }); - } - - #[cfg(esp32s2)] - tconf.modify(|_r, w| w.work_en().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(), - )); - }, - _ => unreachable!(), +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: COMP, unit: &FrozenUnit<'d, UNIT>) -> Self { + Self { + comparator, + unit: unit.borrow(), + _pd: PhantomData, } } } -impl Alarm { - /// Set the interrupt handler for this alarm. - pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { - self.set_interrupt_handler_internal(handler) +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: COMP, unit: &FrozenUnit<'d, UNIT>) -> Self { + Self { + comparator, + unit: unit.0, + _pd: PhantomData, + } } } -impl InterruptConfigurable for Alarm { +impl<'d, T, COMP: Comparator, UNIT: Unit> 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, COMP: Comparator, UNIT: Unit> 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); + self.comparator.set_enable(true); } /// Block waiting until the timer reaches the `timestamp` @@ -291,123 +741,70 @@ where let r = unsafe { &*crate::peripherals::SYSTIMER::PTR }.int_raw(); loop { - if r.read().target(CHANNEL).bit_is_set() { + if r.read().target(self.comparator.channel()).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, + _pd: PhantomData, + } } } -impl Alarm +impl<'d, DM, COMP: Comparator, UNIT: Unit> 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); + 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 } - } -} - -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, + _pd: PhantomData, + } } } -impl Alarm +impl<'d, T, DM, COMP: Comparator, UNIT: Unit> 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 crate::private::Sealed for Alarm where DM: Mode {} - -impl super::Timer for Alarm +impl<'d, T, DM, COMP: Comparator, UNIT: Unit> 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!(), - }); + 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!(), - }); + self.comparator.set_enable(false); } fn reset(&self) { @@ -421,9 +818,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 +825,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 }; - - systimer.unit0_op().modify(|_, w| w.update().set_bit()); - while !systimer.unit0_op().read().value_valid().bit_is_set() { - // Wait - } + self.unit.update(); - 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 +861,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 +883,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 +894,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(self.comparator.channel()).bit(state)); } fn clear_interrupt(&self) { unsafe { &*SYSTIMER::PTR } .int_clr() - .write(|w| w.target(CHANNEL).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(CHANNEL) + .target(self.comparator.channel()) .bit_is_set() } @@ -582,11 +927,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, COMP: Comparator, UNIT: Unit> Peripheral for Alarm<'d, T, DM, COMP, UNIT> where DM: Mode, { @@ -617,15 +962,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, COMP: Comparator, UNIT: Unit> { + alarm: &'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, 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 N { + let (interrupt, handler) = match alarm.comparator.channel() { 0 => (Interrupt::SYSTIMER_TARGET0, target0_handler), 1 => (Interrupt::SYSTIMER_TARGET1, target1_handler), _ => (Interrupt::SYSTIMER_TARGET2, target2_handler), @@ -638,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(N) + .target(self.alarm.comparator.channel()) .bit_is_clear() } } - impl<'a, const N: u8> core::future::Future for AlarmFuture<'a, N> { + 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[N as usize].register(ctx.waker()); + WAKERS[self.alarm.comparator.channel() as usize].register(ctx.waker()); if self.event_bit_is_clear() { Poll::Ready(()) @@ -666,8 +1009,8 @@ mod asynch { } } - impl embedded_hal_async::delay::DelayNs - for Alarm + 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) { let period = MicrosDurationU32::from_ticks(ns / 1000); @@ -731,7 +1074,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 +1085,35 @@ 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, COMP, UNIT> { + alarm: &'a mut Alarm<'d, M, DM, COMP, UNIT>, } - impl<'a, M, DM: crate::Mode, const N: u8> SysTimerEtmEvent<'a, M, DM, N> { + 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) -> 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) -> 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, M, DM: crate::Mode, const N: u8> crate::private::Sealed - for SysTimerEtmEvent<'a, M, DM, N> + impl<'a, 'd, M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> crate::private::Sealed + for SysTimerEtmEvent<'a, 'd, M, DM, COMP, UNIT> { } - 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, COMP: Comparator, UNIT: Unit> crate::etm::EtmEvent + for SysTimerEtmEvent<'a, 'd, M, DM, COMP, UNIT> + { fn id(&self) -> u8 { - 50 + N + 50 + self.alarm.comparator.channel() } } 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..455af18be48 100644 --- a/examples/src/bin/systimer.rs +++ b/examples/src/bin/systimer.rs @@ -18,16 +18,36 @@ use esp_hal::{ peripherals::{Interrupt, Peripherals}, prelude::*, system::SystemControl, - timer::systimer::{Alarm, Periodic, SystemTimer, Target}, + timer::systimer::{ + Alarm, + FrozenUnit, + Periodic, + SpecificComparator, + SpecificUnit, + SystemTimer, + Target, + }, Blocking, }; use esp_println::println; use fugit::ExtU32; - -static ALARM0: Mutex>>> = - Mutex::new(RefCell::new(None)); -static ALARM1: Mutex>>> = Mutex::new(RefCell::new(None)); -static ALARM2: Mutex>>> = Mutex::new(RefCell::new(None)); +use static_cell::StaticCell; + +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() -> ! { @@ -38,18 +58,26 @@ fn main() -> ! { let systimer = SystemTimer::new(peripherals.SYSTIMER); println!("SYSTIMER Current value = {}", SystemTimer::now()); + static UNIT0: StaticCell> = StaticCell::new(); + + let unit0 = UNIT0.init(systimer.unit0); + + let frozen_unit = FrozenUnit::new(unit0); + + 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 = 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); diff --git a/hil-test/tests/embassy_timers_executors.rs b/hil-test/tests/embassy_timers_executors.rs index 301a71d5de3..e24533c89dd 100644 --- a/hil-test/tests/embassy_timers_executors.rs +++ b/hil-test/tests/embassy_timers_executors.rs @@ -17,7 +17,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; @@ -124,7 +127,7 @@ impl Resources { #[cfg(not(feature = "esp32"))] fn set_up_embassy_with_systimer(self) { - let systimer = SystemTimer::new(self.systimer); + let systimer = SystemTimer::new(self.systimer).split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timers = mk_static!(OneShotTimer, OneShotTimer::new(alarm0)); esp_hal_embassy::init(&self.clocks, core::slice::from_mut(timers)); @@ -180,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); } @@ -200,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] @@ -232,7 +239,7 @@ mod test { let timer0: ErasedTimer = timg0.timer0.into(); let timer0 = OneShotTimer::new(timer0); - let systimer = SystemTimer::new(resources.systimer); + let systimer = SystemTimer::new(resources.systimer).split::(); let alarm0: ErasedTimer = systimer.alarm0.into(); let timer1 = OneShotTimer::new(alarm0);