[1/4] Timer refactor: system timer (#2576)

* system timer simplfication

* Removes _all_ type params on Alarm
* Systimer no longer implements peripheral ref, the peripheral ref
  pattern is instead intended to be used on the higher level timer
  drivers
* Removed `Unit` as a type, in favour of an enum
* Alarms are back in the main `SystemTimer` "driver"
* Made all `Unit` modification methods unsafe, it's not possible to
  modify the `Unit`'s safely whilst timers and or the `time::now` API is
  in use

* fix examples and tests (by removing them :D)

* changelog and migration

* /unit_count/unit_value/g

* etm doctest

* Review feedback
This commit is contained in:
Scott Mabin 2024-11-22 11:24:06 +00:00 committed by GitHub
parent 9c1d99d9b4
commit 60a2c76005
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
28 changed files with 204 additions and 1459 deletions

View File

@ -83,12 +83,7 @@ where
}
#[cfg(not(feature = "esp32"))]
impl<T, DM, COMP, UNIT> IntoAnyTimer for Alarm<'_, T, DM, COMP, UNIT>
where
DM: esp_hal::Mode,
Self: Into<AnyTimer>,
{
}
impl IntoAnyTimer for Alarm where Self: Into<AnyTimer> {}
impl<T> TimerCollection for T
where

View File

@ -19,6 +19,14 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- DMA channel objects now implement `Peripheral` (#2526)
- DMA channel objects are no longer wrapped in `Channel`. The `Channel` drivers are now managed by DMA enabled peripheral drivers. (#2526)
- The `Dpi` driver and `DpiTransfer` now have a `Mode` type parameter. The driver's asyncness is determined by the asyncness of the `Lcd` used to create it. (#2526)
- `dma::{Channel, ChannelRx, ChannelTx}::set_priority` for GDMA devices (#2403)
- `SystemTimer::set_unit_count` & `SystemTimer::configure_unit` (#2576)
- `SystemTimer::set_unit_value` & `SystemTimer::configure_unit` (#2576)
### Changed
- `SystemTimer` no longer uses peripheral ref (#2576)
- `SystemTimer::now` has been renamed `SystemTimer::unit_value(Unit)` (#2576)
### Fixed
@ -26,6 +34,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- The `configure` and `configure_for_async` DMA channel functions has been removed (#2403)
- The DMA channel objects no longer have `tx` and `rx` fields. (#2526)
- `SysTimerAlarms` has been removed, alarms are now part of the `SystemTimer` struct (#2576)
- `FrozenUnit`, `AnyUnit`, `SpecificUnit`, `SpecificComparator`, `AnyComparator` have been removed from `systimer` (#2576)
## [0.22.0] - 2024-11-20

View File

@ -26,3 +26,21 @@
-.with_dma(dma_channel.configure(false, DmaPriority::Priority1));
+.with_dma(dma_channel);
```
## Timer changes
The low level timers, `SystemTimer` and `TimerGroup` are now "dumb". They contain no logic for operating modes or trait implementations (except the low level `Timer` trait).
### SystemTimer
```diff
let systimer = SystemTimer::new(peripherals.SYSTIMER);
- static UNIT0: StaticCell<SpecificUnit<'static, 0>> = StaticCell::new();
- let unit0 = UNIT0.init(systimer.unit0);
- let frozen_unit = FrozenUnit::new(unit0);
- let alarm0 = Alarm::new(systimer.comparator0, &frozen_unit);
- alarm0.set_period(1u32.secs());
+ let alarm0 = systimer.alarm0;
+ let mut timer = PeriodicTimer::new(alarm0);
+ timer.start(1u64.secs());
```

View File

@ -47,12 +47,10 @@ pub fn now() -> Instant {
#[cfg(not(esp32))]
let (ticks, div) = {
use crate::timer::systimer::{SystemTimer, Unit};
// otherwise use SYSTIMER
let ticks = crate::timer::systimer::SystemTimer::now();
(
ticks,
(crate::timer::systimer::SystemTimer::ticks_per_second() / 1_000_000),
)
let ticks = SystemTimer::unit_value(Unit::Unit0);
(ticks, (SystemTimer::ticks_per_second() / 1_000_000))
};
Instant::from_ticks(ticks / div)

View File

@ -370,12 +370,9 @@ enum AnyTimerInner {
/// Timer 1 of the TIMG1 peripheral in blocking mode.
#[cfg(all(timg1, timg_timer1))]
Timg1Timer1(timg::Timer<timg::Timer1<crate::peripherals::TIMG1>, Blocking>),
/// Systimer Alarm in periodic mode with blocking behavior.
/// Systimer Alarm
#[cfg(systimer)]
SystimerAlarmPeriodic(systimer::Alarm<'static, systimer::Periodic, Blocking>),
/// Systimer Target in periodic mode with blocking behavior.
#[cfg(systimer)]
SystimerAlarmTarget(systimer::Alarm<'static, systimer::Target, Blocking>),
SystimerAlarm(systimer::Alarm),
}
/// A type-erased timer
@ -413,16 +410,9 @@ impl From<timg::Timer<timg::Timer1<crate::peripherals::TIMG1>, Blocking>> for An
}
#[cfg(systimer)]
impl From<systimer::Alarm<'static, systimer::Periodic, Blocking>> for AnyTimer {
fn from(value: systimer::Alarm<'static, systimer::Periodic, Blocking>) -> Self {
Self(AnyTimerInner::SystimerAlarmPeriodic(value))
}
}
#[cfg(systimer)]
impl From<systimer::Alarm<'static, systimer::Target, Blocking>> for AnyTimer {
fn from(value: systimer::Alarm<'static, systimer::Target, Blocking>) -> Self {
Self(AnyTimerInner::SystimerAlarmTarget(value))
impl From<systimer::Alarm> for AnyTimer {
fn from(value: systimer::Alarm) -> Self {
Self(AnyTimerInner::SystimerAlarm(value))
}
}
@ -437,9 +427,7 @@ impl Timer for AnyTimer {
#[cfg(all(timg1,timg_timer1))]
AnyTimerInner::Timg1Timer1(inner) => inner,
#[cfg(systimer)]
AnyTimerInner::SystimerAlarmPeriodic(inner) => inner,
#[cfg(systimer)]
AnyTimerInner::SystimerAlarmTarget(inner) => inner,
AnyTimerInner::SystimerAlarm(inner) => inner,
} {
fn start(&self);
fn stop(&self);

View File

@ -9,72 +9,17 @@
//!
//! ## Configuration
//!
//! The timer consists of two counters, `UNIT0` and `UNIT1`. The counter values
//! can be monitored by 3 comparators, `COMP0`, `COMP1`, and `COMP2`.
//! The timer consists of two counters, `Unit0` and `Unit1`. The counter values
//! can be monitored by 3 [`Alarm`]s
//!
//! [Alarm]s can be configured in two modes: [Target] (one-shot) and [Periodic].
//!
//! ## Examples
//!
//! ### Splitting up the System Timer into three alarms
//!
//! Use the [split][SystemTimer::split] method to create three alarms from the
//! System Timer, contained in a [SysTimerAlarms] struct.
//!
//! ```rust, no_run
#![doc = crate::before_snippet!()]
//! use esp_hal::timer::systimer::{
//! SystemTimer,
//! Periodic,
//! };
//!
//! let systimer = SystemTimer::new(
//! peripherals.SYSTIMER,
//! ).split::<Periodic>();
//!
//! // Reconfigure a periodic alarm to be a target alarm
//! let target_alarm = systimer.alarm0.into_target();
//! # }
//! ```
//!
//! ### General-purpose Timer
//! ```rust, no_run
#![doc = crate::before_snippet!()]
//! use esp_hal::timer::systimer::{
//! Alarm,
//! FrozenUnit,
//! SpecificUnit,
//! SystemTimer,
//! };
//!
//! let mut systimer = SystemTimer::new(peripherals.SYSTIMER);
//!
//! // Get the current tick count:
//! let now = SystemTimer::now();
//!
//! let frozen_unit = FrozenUnit::new(&mut systimer.unit0);
//! let alarm0 = Alarm::new(systimer.comparator0, &frozen_unit);
//!
//! alarm0.set_target(
//! SystemTimer::now() + SystemTimer::ticks_per_second() * 2
//! );
//! alarm0.enable_interrupt(true);
//!
//! while !alarm0.is_interrupt_set() {
//! // Wait for the interrupt to be set
//! }
//!
//! alarm0.clear_interrupt();
//! # }
//! ```
//! It is recommended to pass the [`Alarm`]s into a high level driver like
//! [`OneShotTimer`](super::OneShotTimer) and
//! [`PeriodicTimer`](super::PeriodicTimer). Using the System timer directly is
//! only possible through the low level [`Timer`](crate::timer::Timer) trait.
use core::{
fmt::{Debug, Formatter},
marker::PhantomData,
ptr::addr_of_mut,
};
use core::fmt::Debug;
use fugit::{Instant, MicrosDurationU32, MicrosDurationU64};
use fugit::{Instant, MicrosDurationU64};
use super::{Error, Timer as _};
use crate::{
@ -83,33 +28,35 @@ use crate::{
peripherals::{Interrupt, SYSTIMER},
sync::{lock, Lock},
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
Async,
Blocking,
Cpu,
InterruptConfigurable,
Mode,
};
/// System Timer driver.
pub struct SystemTimer<'d> {
/// Unit 0
pub unit0: SpecificUnit<'d, 0>,
/// The configuration of a unit.
#[derive(Copy, Clone)]
pub enum UnitConfig {
/// Unit is not counting.
Disabled,
#[cfg(not(esp32s2))]
/// Unit 1
pub unit1: SpecificUnit<'d, 1>,
/// Unit is counting unless the Cpu is stalled.
DisabledIfCpuIsStalled(Cpu),
/// Comparator 0.
pub comparator0: SpecificComparator<'d, 0>,
/// Comparator 1.
pub comparator1: SpecificComparator<'d, 1>,
/// Comparator 2.
pub comparator2: SpecificComparator<'d, 2>,
/// Unit is counting.
Enabled,
}
impl<'d> SystemTimer<'d> {
/// System Timer driver.
pub struct SystemTimer {
/// Alarm 0.
pub alarm0: Alarm,
/// Alarm 1.
pub alarm1: Alarm,
/// Alarm 2.
pub alarm2: Alarm,
}
impl SystemTimer {
cfg_if::cfg_if! {
if #[cfg(esp32s2)] {
/// Bitmask to be applied to the raw register value.
@ -146,7 +93,7 @@ impl<'d> SystemTimer<'d> {
}
/// Create a new instance.
pub fn new(_systimer: impl Peripheral<P = SYSTIMER> + 'd) -> Self {
pub fn new(_systimer: SYSTIMER) -> Self {
// Don't reset Systimer as it will break `time::now`, only enable it
PeripheralClockControl::enable(PeripheralEnable::Systimer);
@ -154,67 +101,49 @@ impl<'d> SystemTimer<'d> {
etm::enable_etm();
Self {
unit0: SpecificUnit::new(),
#[cfg(not(esp32s2))]
unit1: SpecificUnit::new(),
comparator0: SpecificComparator::new(),
comparator1: SpecificComparator::new(),
comparator2: SpecificComparator::new(),
alarm0: Alarm::new(0),
alarm1: Alarm::new(1),
alarm2: Alarm::new(2),
}
}
/// Get the current count of Unit 0 in the System Timer.
pub fn now() -> u64 {
/// Get the current count of the given unit in the System Timer.
pub fn unit_value(unit: Unit) -> u64 {
// 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.read_count()
}
}
impl SystemTimer<'static> {
/// Split the System Timer into three alarms.
#[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.
///
/// 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<MODE>(self) -> SysTimerAlarms<MODE, Blocking> {
static mut UNIT0: Option<AnyUnit<'static>> = 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,
}
/// # Safety
///
/// - Disabling a `Unit` whilst [`Alarm`]s are using it will affect the
/// [`Alarm`]s operation.
/// - Disabling Unit0 will affect [`now`](crate::time::now).
pub unsafe fn configure_unit(unit: Unit, config: UnitConfig) {
unit.configure(config)
}
/// Split the System Timer into three alarms.
/// 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 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<MODE>(self) -> SysTimerAlarms<MODE, Async> {
static mut UNIT0: Option<AnyUnit<'static>> = 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,
}
/// This can be used to load back the sleep time recorded by RTC timer
/// via software after Light-sleep
///
/// # Safety
///
/// - Modifying a unit's count whilst [`Alarm`]s are using it may cause
/// unexpected behaviour
/// - Any modification of the unit0 count will affect
/// [`now`](crate::time::now).
pub unsafe fn set_unit_value(unit: Unit, value: u64) {
unit.set_count(value)
}
}
@ -222,14 +151,22 @@ impl SystemTimer<'static> {
#[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;
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
pub enum Unit {
/// Unit 0
Unit0 = 0,
#[cfg(not(esp32s2))]
/// Unit 1
Unit1 = 1,
}
impl Unit {
#[inline]
fn channel(&self) -> u8 {
*self as _
}
#[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() };
let conf = systimer.conf();
@ -271,11 +208,6 @@ pub trait Unit {
});
}
/// 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))]
@ -303,7 +235,6 @@ pub trait Unit {
}
}
/// Reads the current counter value.
fn read_count(&self) -> u64 {
// This can be a shared reference as long as this type isn't Sync.
@ -332,54 +263,26 @@ pub trait Unit {
}
}
/// A specific [Unit]. i.e. Either unit 0 or unit 1.
/// An alarm unit
#[derive(Debug)]
pub struct SpecificUnit<'d, const CHANNEL: u8>(PhantomData<&'d ()>);
impl<const CHANNEL: u8> SpecificUnit<'_, CHANNEL> {
fn new() -> Self {
Self(PhantomData)
}
pub struct Alarm {
comp: u8,
unit: Unit,
}
impl<const CHANNEL: u8> Unit for SpecificUnit<'_, 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 Unit for AnyUnit<'_> {
fn channel(&self) -> u8 {
self.1
}
}
impl<'d, const CHANNEL: u8> From<SpecificUnit<'d, CHANNEL>> for AnyUnit<'d> {
fn from(_value: SpecificUnit<'d, CHANNEL>) -> Self {
Self(PhantomData, CHANNEL)
}
}
impl<'d, const CHANNEL: u8> TryFrom<AnyUnit<'d>> for SpecificUnit<'d, CHANNEL> {
type Error = u8;
fn try_from(value: AnyUnit<'d>) -> Result<Self, Self::Error> {
if value.1 == CHANNEL {
Ok(SpecificUnit::new())
} else {
Err(value.1)
impl Alarm {
const fn new(comp: u8) -> Self {
Alarm {
comp,
unit: Unit::Unit0,
}
}
}
/// A comparator that can generate alarms/interrupts based on values of a unit.
pub trait Comparator {
/// Returns the comparators number.
fn channel(&self) -> u8;
/// Returns the comparator's number.
#[inline]
fn channel(&self) -> u8 {
self.comp
}
/// Enables/disables the comparator. If enabled, this means
/// it will generate interrupt based on its configuration.
@ -431,12 +334,12 @@ pub trait Comparator {
/// Sets the unit this comparator uses as a reference count.
#[cfg(not(esp32s2))]
fn set_unit(&self, is_unit0: bool) {
pub fn set_unit(&self, unit: Unit) {
let tconf = unsafe {
let systimer = &*SYSTIMER::ptr();
systimer.target_conf(self.channel() as usize)
};
tconf.modify(|_, w| w.timer_unit_sel().bit(is_unit0));
tconf.modify(|_, w| w.timer_unit_sel().bit(matches!(unit, Unit::Unit1)));
}
/// Set the mode of the comparator to be either target or periodic.
@ -496,18 +399,6 @@ pub trait Comparator {
}
}
/// Get the actual target value of the comparator.
fn 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() {
@ -566,66 +457,9 @@ pub trait Comparator {
}
}
/// A specific [Comparator]. i.e. Either comparator 0, comparator 1, etc.
#[derive(Debug)]
pub struct SpecificComparator<'d, const CHANNEL: u8>(PhantomData<&'d ()>);
impl<const CHANNEL: u8> SpecificComparator<'_, CHANNEL> {
fn new() -> Self {
Self(PhantomData)
}
}
impl<const CHANNEL: u8> Comparator for SpecificComparator<'_, 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 Comparator for AnyComparator<'_> {
fn channel(&self) -> u8 {
self.1
}
}
impl<'d, const CHANNEL: u8> From<SpecificComparator<'d, CHANNEL>> for AnyComparator<'d> {
fn from(_value: SpecificComparator<'d, CHANNEL>) -> Self {
Self(PhantomData, CHANNEL)
}
}
impl<'d, const CHANNEL: u8> TryFrom<AnyComparator<'d>> for SpecificComparator<'d, CHANNEL> {
type Error = u8;
fn try_from(value: AnyComparator<'d>) -> Result<Self, Self::Error> {
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 {
enum ComparatorMode {
/// The comparator will generate interrupts periodically.
Period,
@ -634,208 +468,13 @@ pub enum ComparatorMode {
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<MODE, DM: Mode> {
/// 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;
/// A marker for a [Alarm] in periodic mode.
#[derive(Debug)]
pub struct Periodic;
/// A single 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<T, DM, COMP: Comparator, UNIT: Unit> Debug for Alarm<'_, T, DM, COMP, UNIT>
where
DM: Mode,
{
fn fmt(&self, f: &mut Formatter<'_>) -> core::fmt::Result {
f.debug_struct("Alarm")
.field("comparator", &self.comparator.channel())
.field("unit", &self.unit.channel())
.finish()
}
}
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<'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<T, COMP: Comparator, UNIT: Unit> InterruptConfigurable for Alarm<'_, T, Blocking, COMP, UNIT> {
fn set_interrupt_handler(&mut self, handler: InterruptHandler) {
self.comparator.set_interrupt_handler(handler)
}
}
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) {
#[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`
pub fn wait_until(&self, timestamp: u64) {
self.clear_interrupt();
self.set_target(timestamp);
let r = unsafe { &*crate::peripherals::SYSTIMER::PTR }.int_raw();
loop {
if r.read().target(self.comparator.channel()).bit_is_set() {
break;
}
}
}
/// Converts this [Alarm] into [Periodic] mode
pub fn into_periodic(self) -> Alarm<'d, Periodic, DM, COMP, UNIT> {
Alarm {
comparator: self.comparator,
unit: self.unit,
_pd: PhantomData,
}
}
}
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.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<'d, Target, DM, COMP, UNIT> {
Alarm {
comparator: self.comparator,
unit: self.unit,
_pd: PhantomData,
}
}
}
impl<T, DM, COMP: Comparator, UNIT: Unit> crate::private::Sealed for Alarm<'_, T, DM, COMP, UNIT> where
DM: Mode
{
}
impl<T, DM, COMP: Comparator, UNIT: Unit> super::Timer for Alarm<'_, T, DM, COMP, UNIT>
where
DM: Mode,
{
impl super::Timer for Alarm {
fn start(&self) {
self.comparator.set_enable(true);
self.set_enable(true);
}
fn stop(&self) {
self.comparator.set_enable(false);
self.set_enable(false);
}
fn reset(&self) {
@ -856,7 +495,7 @@ where
}
fn is_running(&self) -> bool {
self.comparator.is_enabled()
self.is_enabled()
}
fn now(&self) -> Instant<u64, 1, 1_000_000> {
@ -871,7 +510,7 @@ where
}
fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error> {
let mode = self.comparator.mode();
let mode = self.mode();
let us = value.ticks();
let ticks = us * (SystemTimer::ticks_per_second() / 1_000_000);
@ -886,12 +525,12 @@ where
return Err(Error::InvalidTimeout);
}
self.comparator.set_period(ticks as u32);
self.set_period(ticks as u32);
// Clear and then set SYSTIMER_TARGETx_PERIOD_MODE to configure COMPx into
// period mode
self.comparator.set_mode(ComparatorMode::Target);
self.comparator.set_mode(ComparatorMode::Period);
self.set_mode(ComparatorMode::Target);
self.set_mode(ComparatorMode::Period);
} else {
// Target mode
@ -906,7 +545,7 @@ where
let v = self.unit.read_count();
let t = v + ticks;
self.comparator.set_target(t);
self.set_target(t);
}
Ok(())
@ -919,28 +558,28 @@ where
} else {
ComparatorMode::Target
};
self.comparator.set_mode(mode)
self.set_mode(mode)
}
fn enable_interrupt(&self, state: bool) {
lock(&INT_ENA_LOCK, || {
unsafe { &*SYSTIMER::PTR }
.int_ena()
.modify(|_, w| w.target(self.comparator.channel()).bit(state));
.modify(|_, w| w.target(self.channel()).bit(state));
});
}
fn clear_interrupt(&self) {
unsafe { &*SYSTIMER::PTR }
.int_clr()
.write(|w| w.target(self.comparator.channel()).clear_bit_by_one());
.write(|w| w.target(self.channel()).clear_bit_by_one());
}
fn is_interrupt_set(&self) -> bool {
unsafe { &*SYSTIMER::PTR }
.int_raw()
.read()
.target(self.comparator.channel())
.target(self.channel())
.bit_is_set()
}
@ -949,27 +588,30 @@ where
}
fn set_interrupt_handler(&self, handler: InterruptHandler) {
self.comparator.set_interrupt_handler(handler);
self.set_interrupt_handler(handler);
}
}
impl<T, DM, COMP: Comparator, UNIT: Unit> Peripheral for Alarm<'_, T, DM, COMP, UNIT>
where
DM: Mode,
{
impl Peripheral for Alarm {
type P = Self;
#[inline]
unsafe fn clone_unchecked(&self) -> Self::P {
core::ptr::read(self as *const _)
Alarm {
comp: self.comp,
unit: self.unit,
}
}
}
impl crate::private::Sealed for Alarm {}
static CONF_LOCK: Lock = Lock::new();
static INT_ENA_LOCK: Lock = Lock::new();
// Async functionality of the system timer.
mod asynch {
#![allow(unused)] // FIXME (mabez)
use core::{
pin::Pin,
task::{Context, Poll},
@ -985,15 +627,15 @@ mod asynch {
static WAKERS: [AtomicWaker; NUM_ALARMS] = [const { AtomicWaker::new() }; NUM_ALARMS];
#[must_use = "futures do nothing unless you `.await` or poll them"]
pub(crate) struct AlarmFuture<'a, COMP: Comparator, UNIT: Unit> {
alarm: &'a Alarm<'a, Target, crate::Async, COMP, UNIT>,
pub(crate) struct AlarmFuture<'a> {
alarm: &'a Alarm,
}
impl<'a, COMP: Comparator, UNIT: Unit> AlarmFuture<'a, COMP, UNIT> {
pub(crate) fn new(alarm: &'a Alarm<'a, Target, crate::Async, COMP, UNIT>) -> Self {
impl<'a> AlarmFuture<'a> {
pub(crate) fn new(alarm: &'a Alarm) -> Self {
alarm.clear_interrupt();
let (interrupt, handler) = match alarm.comparator.channel() {
let (interrupt, handler) = match alarm.channel() {
0 => (Interrupt::SYSTIMER_TARGET0, target0_handler),
1 => (Interrupt::SYSTIMER_TARGET1, target1_handler),
_ => (Interrupt::SYSTIMER_TARGET2, target2_handler),
@ -1015,16 +657,16 @@ mod asynch {
unsafe { &*crate::peripherals::SYSTIMER::PTR }
.int_ena()
.read()
.target(self.alarm.comparator.channel())
.target(self.alarm.channel())
.bit_is_clear()
}
}
impl<COMP: Comparator, UNIT: Unit> core::future::Future for AlarmFuture<'_, COMP, UNIT> {
impl core::future::Future for AlarmFuture<'_> {
type Output = ();
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
WAKERS[self.alarm.comparator.channel() as usize].register(ctx.waker());
WAKERS[self.alarm.channel() as usize].register(ctx.waker());
if self.event_bit_is_clear() {
Poll::Ready(())
@ -1034,27 +676,8 @@ mod asynch {
}
}
impl<COMP: Comparator, UNIT: Unit> embedded_hal_async::delay::DelayNs
for Alarm<'_, Target, crate::Async, COMP, UNIT>
{
async fn delay_ns(&mut self, nanos: u32) {
self.set_target(
self.unit.read_count()
+ (nanos as u64 * SystemTimer::ticks_per_second()).div_ceil(1_000_000_000),
);
AlarmFuture::new(self).await;
}
async fn delay_ms(&mut self, ms: u32) {
for _ in 0..ms {
self.delay_us(1000).await;
}
}
}
#[handler]
fn target0_handler() {
pub(crate) fn target0_handler() {
lock(&INT_ENA_LOCK, || {
unsafe { &*crate::peripherals::SYSTIMER::PTR }
.int_ena()
@ -1065,7 +688,7 @@ mod asynch {
}
#[handler]
fn target1_handler() {
pub(crate) fn target1_handler() {
lock(&INT_ENA_LOCK, || {
unsafe { &*crate::peripherals::SYSTIMER::PTR }
.int_ena()
@ -1076,7 +699,7 @@ mod asynch {
}
#[handler]
fn target2_handler() {
pub(crate) fn target2_handler() {
lock(&INT_ENA_LOCK, || {
unsafe { &*crate::peripherals::SYSTIMER::PTR }
.int_ena()
@ -1100,51 +723,33 @@ pub mod etm {
//! The system timer can generate the following ETM events:
//! - SYSTIMER_EVT_CNT_CMPx: Indicates the alarm pulses generated by
//! COMPx
//!
//! ## Example
//! ```rust, no_run
#![doc = crate::before_snippet!()]
//! # use esp_hal::timer::systimer::{etm::Event, SystemTimer};
//! # use fugit::ExtU32;
//! let syst = SystemTimer::new(peripherals.SYSTIMER);
//! let syst_alarms = syst.split();
//! let mut alarm0 = syst_alarms.alarm0.into_periodic();
//! alarm0.set_period(1u32.secs());
//!
//! let timer_event = Event::new(&mut alarm0);
//! # }
//! ```
// FIXME(mabez)
use super::*;
/// An ETM controlled SYSTIMER event
pub struct Event<'a, 'd, M, DM: crate::Mode, COMP, UNIT> {
alarm: &'a mut Alarm<'d, M, DM, COMP, UNIT>,
pub struct Event<'a> {
alarm: &'a mut Alarm,
}
impl<'a, 'd, M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> Event<'a, 'd, M, DM, COMP, UNIT> {
impl<'a> Event<'a> {
/// Creates an ETM event from the given [Alarm]
pub fn new(alarm: &'a mut Alarm<'d, M, DM, COMP, UNIT>) -> Self {
pub fn new(alarm: &'a mut Alarm) -> Self {
Self { alarm }
}
/// Execute closure f with mutable access to the wrapped [Alarm].
pub fn with<R>(&self, f: impl FnOnce(&&'a mut Alarm<'d, M, DM, COMP, UNIT>) -> R) -> R {
pub fn with<R>(&self, f: impl FnOnce(&&'a mut Alarm) -> R) -> R {
let alarm = &self.alarm;
f(alarm)
}
}
impl<M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> crate::private::Sealed
for Event<'_, '_, M, DM, COMP, UNIT>
{
}
impl crate::private::Sealed for Event<'_> {}
impl<M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> crate::etm::EtmEvent
for Event<'_, '_, M, DM, COMP, UNIT>
{
impl crate::etm::EtmEvent for Event<'_> {
fn id(&self) -> u8 {
50 + self.alarm.comparator.channel()
50 + self.alarm.channel()
}
}

View File

@ -293,12 +293,7 @@ where
}
#[cfg(not(feature = "esp32"))]
impl<T, DM, COMP, UNIT> IntoAnyTimer for Alarm<'_, T, DM, COMP, UNIT>
where
DM: esp_hal::Mode,
Self: Into<AnyTimer>,
{
}
impl IntoAnyTimer for Alarm where Self: Into<AnyTimer> {}
impl private::Sealed for AnyTimer {}
impl IntoAnyTimer for AnyTimer {}
@ -326,12 +321,7 @@ where
{
}
#[cfg(not(feature = "esp32"))]
impl<T, DM, COMP, UNIT> private::Sealed for Alarm<'_, T, DM, COMP, UNIT>
where
DM: esp_hal::Mode,
Self: Into<AnyTimer>,
{
}
impl private::Sealed for Alarm where Self: Into<AnyTimer> {}
/// A marker trait for suitable Rng sources for esp-wifi
pub trait EspWifiRngSource: rand_core::RngCore + private::Sealed {}

View File

@ -80,8 +80,8 @@ async fn main(low_prio_spawner: Spawner) {
cfg_if::cfg_if! {
if #[cfg(feature = "esp32c2")] {
use esp_hal::timer::systimer::{SystemTimer, Target};
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
use esp_hal::timer::systimer::SystemTimer;
let systimer = SystemTimer::new(peripherals.SYSTIMER);
let timer1: AnyTimer = systimer.alarm0.into();
} else {
let timg1 = TimerGroup::new(peripherals.TIMG1);

View File

@ -19,7 +19,7 @@ use esp_hal::{
gpio::NoPin,
parl_io::{BitPackOrder, ParlIoRxOnly, RxFourBits},
prelude::*,
timer::systimer::{SystemTimer, Target},
timer::systimer::SystemTimer,
};
use esp_println::println;
@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
esp_println::println!("Init!");
let peripherals = esp_hal::init(esp_hal::Config::default());
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(systimer.alarm0);
let (rx_buffer, rx_descriptors, _, _) = dma_buffers!(32000, 0);

View File

@ -29,7 +29,7 @@ use esp_hal::{
TxPinConfigWithValidPin,
},
prelude::*,
timer::systimer::{SystemTimer, Target},
timer::systimer::SystemTimer,
};
use esp_println::println;
@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) {
esp_println::println!("Init!");
let peripherals = esp_hal::init(esp_hal::Config::default());
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(systimer.alarm0);
let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000);

View File

@ -1,57 +0,0 @@
//! Control LED by the systimer via ETM without involving the CPU.
//! The following wiring is assumed:
//! - LED => GPIO1
//% CHIPS: esp32c6 esp32h2
#![no_std]
#![no_main]
use esp_backtrace as _;
use esp_hal::{
etm::Etm,
gpio::{
etm::{Channels, OutputConfig},
Level,
Pull,
},
prelude::*,
timer::systimer::{etm::Event, Periodic, SystemTimer},
};
use fugit::ExtU32;
#[entry]
fn main() -> ! {
let peripherals = esp_hal::init(esp_hal::Config::default());
let syst = SystemTimer::new(peripherals.SYSTIMER);
let syst_alarms = syst.split::<Periodic>();
let mut alarm0 = syst_alarms.alarm0;
alarm0.set_period(1u32.secs());
let mut led = peripherals.GPIO1;
// setup ETM
let gpio_ext = Channels::new(peripherals.GPIO_SD);
let led_task = gpio_ext.channel0_task.toggle(
&mut led,
OutputConfig {
open_drain: false,
pull: Pull::None,
initial_state: Level::High,
},
);
let timer_event = Event::new(&mut alarm0);
let etm = Etm::new(peripherals.SOC_ETM);
let channel0 = etm.channel0;
// make sure the configured channel doesn't get dropped - dropping it will
// disable the channel
let _configured_channel = channel0.setup(&timer_event, &led_task);
// the LED is controlled by the timer without involving the CPU
loop {}
}

View File

@ -62,7 +62,6 @@ use esp_hal::{
hmac::{Hmac, HmacPurpose, KeyId},
prelude::*,
rng::Rng,
timer::systimer::SystemTimer,
};
use esp_println::println;
use hmac::{Hmac as HmacSw, Mac};
@ -94,18 +93,18 @@ fn main() -> ! {
let mut remaining = nsrc;
hw_hmac.init();
block!(hw_hmac.configure(HmacPurpose::ToUser, KeyId::Key0)).expect("Key purpose mismatch");
let pre_hw_hmac = SystemTimer::now();
let pre_hw_hmac = esp_hal::time::now();
while remaining.len() > 0 {
remaining = block!(hw_hmac.update(remaining)).unwrap();
}
block!(hw_hmac.finalize(output.as_mut_slice())).unwrap();
let post_hw_hmac = SystemTimer::now();
let post_hw_hmac = esp_hal::time::now();
let hw_time = post_hw_hmac - pre_hw_hmac;
let mut sw_hmac = HmacSha256::new_from_slice(key).expect("HMAC can take key of any size");
let pre_sw_hash = SystemTimer::now();
let pre_sw_hash = esp_hal::time::now();
sw_hmac.update(nsrc);
let soft_result = sw_hmac.finalize().into_bytes();
let post_sw_hash = SystemTimer::now();
let post_sw_hash = esp_hal::time::now();
let soft_time = post_sw_hash - pre_sw_hash;
for (a, b) in output.iter().zip(soft_result) {
assert_eq!(*a, b);

View File

@ -1,125 +0,0 @@
//! This shows how to use the SYSTIMER peripheral including interrupts.
//!
//! It's an additional timer besides the TIMG peripherals.
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
#![no_std]
#![no_main]
use core::cell::RefCell;
use critical_section::Mutex;
use esp_backtrace as _;
use esp_hal::{
delay::Delay,
prelude::*,
timer::systimer::{
Alarm,
FrozenUnit,
Periodic,
SpecificComparator,
SpecificUnit,
SystemTimer,
Target,
},
Blocking,
};
use esp_println::println;
use fugit::ExtU32;
use static_cell::StaticCell;
static ALARM0: Mutex<
RefCell<
Option<Alarm<Periodic, Blocking, SpecificComparator<'static, 0>, SpecificUnit<'static, 0>>>,
>,
> = Mutex::new(RefCell::new(None));
static ALARM1: Mutex<
RefCell<
Option<Alarm<Target, Blocking, SpecificComparator<'static, 1>, SpecificUnit<'static, 0>>>,
>,
> = Mutex::new(RefCell::new(None));
static ALARM2: Mutex<
RefCell<
Option<Alarm<Target, Blocking, SpecificComparator<'static, 2>, SpecificUnit<'static, 0>>>,
>,
> = Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
let peripherals = esp_hal::init(esp_hal::Config::default());
let systimer = SystemTimer::new(peripherals.SYSTIMER);
println!("SYSTIMER Current value = {}", SystemTimer::now());
static UNIT0: StaticCell<SpecificUnit<'static, 0>> = 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 = alarm0.into_periodic();
alarm0.set_interrupt_handler(systimer_target0);
alarm0.set_period(1u32.secs());
alarm0.enable_interrupt(true);
alarm1.set_interrupt_handler(systimer_target1);
alarm1.set_target(SystemTimer::now() + (SystemTimer::ticks_per_second() * 2));
alarm1.enable_interrupt(true);
alarm2.set_interrupt_handler(systimer_target2);
alarm2.set_target(SystemTimer::now() + (SystemTimer::ticks_per_second() * 3));
alarm2.enable_interrupt(true);
ALARM0.borrow_ref_mut(cs).replace(alarm0);
ALARM1.borrow_ref_mut(cs).replace(alarm1);
ALARM2.borrow_ref_mut(cs).replace(alarm2);
});
let delay = Delay::new();
loop {
delay.delay_millis(500);
}
}
#[handler(priority = esp_hal::interrupt::Priority::min())]
fn systimer_target0() {
println!("Interrupt lvl1 (alarm0)");
critical_section::with(|cs| {
ALARM0
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
});
}
#[handler(priority = esp_hal::interrupt::Priority::Priority1)]
fn systimer_target1() {
println!("Interrupt lvl2 (alarm1)");
critical_section::with(|cs| {
ALARM1
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
});
}
#[handler(priority = esp_hal::interrupt::Priority::max())]
fn systimer_target2() {
println!("Interrupt lvl2 (alarm2)");
critical_section::with(|cs| {
ALARM2
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
});
}

View File

@ -86,8 +86,8 @@ async fn main(spawner: Spawner) -> ! {
let timg1 = TimerGroup::new(peripherals.TIMG1);
esp_hal_embassy::init(timg1.timer0);
} else {
use esp_hal::timer::systimer::{SystemTimer, Target};
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
use esp_hal::timer::systimer::SystemTimer;
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(systimer.alarm0);
}
}

View File

@ -94,8 +94,8 @@ async fn main(spawner: Spawner) -> ! {
let timg1 = TimerGroup::new(peripherals.TIMG1);
esp_hal_embassy::init(timg1.timer0);
} else {
use esp_hal::timer::systimer::{SystemTimer, Target};
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
use esp_hal::timer::systimer::SystemTimer;
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(systimer.alarm0);
}
}

View File

@ -117,8 +117,8 @@ async fn main(spawner: Spawner) -> ! {
let timg1 = TimerGroup::new(peripherals.TIMG1);
esp_hal_embassy::init(timg1.timer0);
} else {
use esp_hal::timer::systimer::{SystemTimer, Target};
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
use esp_hal::timer::systimer::SystemTimer;
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(systimer.alarm0);
}
}

View File

@ -83,8 +83,8 @@ async fn main(_spawner: Spawner) -> ! {
let timg1 = TimerGroup::new(peripherals.TIMG1);
esp_hal_embassy::init(timg1.timer0);
} else {
use esp_hal::timer::systimer::{SystemTimer, Target};
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
use esp_hal::timer::systimer::SystemTimer;
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(systimer.alarm0);
}
}

View File

@ -79,8 +79,8 @@ async fn main(spawner: Spawner) -> ! {
let timg1 = TimerGroup::new(peripherals.TIMG1);
esp_hal_embassy::init(timg1.timer0);
} else {
use esp_hal::timer::systimer::{SystemTimer, Target};
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
use esp_hal::timer::systimer::SystemTimer;
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(systimer.alarm0);
}
}

View File

@ -65,8 +65,8 @@ async fn main(_spawner: Spawner) -> ! {
let timg1 = TimerGroup::new(peripherals.TIMG1);
esp_hal_embassy::init(timg1.timer0);
} else {
use esp_hal::timer::systimer::{SystemTimer, Target};
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
use esp_hal::timer::systimer::SystemTimer;
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(systimer.alarm0);
}
}

View File

@ -65,8 +65,8 @@ async fn main(spawner: Spawner) -> ! {
let timg1 = TimerGroup::new(peripherals.TIMG1);
esp_hal_embassy::init(timg1.timer0);
} else {
use esp_hal::timer::systimer::{SystemTimer, Target};
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
use esp_hal::timer::systimer::SystemTimer;
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(systimer.alarm0);
}
}

View File

@ -72,8 +72,7 @@ async fn main(_s: Spawner) {
#[cfg(not(feature = "esp32"))]
{
let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER)
.split::<esp_hal::timer::systimer::Target>();
let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init(systimer.alarm0);
}

View File

@ -1,13 +0,0 @@
#![no_std]
pub fn cycles() -> u64 {
#[cfg(feature = "esp32")]
{
esp_hal::xtensa_lx::timer::get_cycle_count() as u64
}
#[cfg(not(feature = "esp32"))]
{
esp_hal::timer::systimer::SystemTimer::now()
}
}

View File

@ -31,10 +31,6 @@ harness = false
name = "delay"
harness = false
[[test]]
name = "delay_async"
harness = false
[[test]]
name = "dma_macros"
harness = false
@ -111,10 +107,6 @@ harness = false
name = "spi_slave"
harness = false
[[test]]
name = "systimer"
harness = false
[[test]]
name = "parl_io_tx"
harness = false
@ -168,11 +160,6 @@ harness = false
name = "uart_tx_rx_async"
harness = false
[[test]]
name = "embassy_timers_executors"
harness = false
required-features = ["embassy"]
[[test]]
name = "embassy_interrupt_executor"
harness = false

View File

@ -1,173 +0,0 @@
//! Async Delay Test
//!
//! Specifically tests the various implementations of the
//! `embedded_hal_async::delay::DelayNs` trait.
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
#![no_std]
#![no_main]
use embedded_hal_async::delay::DelayNs;
#[cfg(systimer)]
use esp_hal::timer::systimer::{Alarm, FrozenUnit, SystemTimer};
use esp_hal::{peripherals::Peripherals, timer::timg::TimerGroup};
use hil_test as _;
struct Context {
peripherals: Peripherals,
}
async fn test_async_delay_ns(mut timer: impl DelayNs, duration: u32) {
for _ in 1..5 {
let t1 = esp_hal::time::now();
timer.delay_ns(duration).await;
let t2 = esp_hal::time::now();
assert!(t2 > t1);
assert!(
(t2 - t1).to_nanos() >= duration as u64,
"diff: {:?}",
(t2 - t1).to_nanos()
);
}
}
async fn test_async_delay_us(mut timer: impl DelayNs, duration: u32) {
for _ in 1..5 {
let t1 = esp_hal::time::now();
timer.delay_us(duration).await;
let t2 = esp_hal::time::now();
assert!(t2 > t1);
assert!(
(t2 - t1).to_nanos() >= duration as u64,
"diff: {:?}",
(t2 - t1).to_nanos()
);
}
}
async fn test_async_delay_ms(mut timer: impl DelayNs, duration: u32) {
for _ in 1..5 {
let t1 = esp_hal::time::now();
timer.delay_ms(duration).await;
let t2 = esp_hal::time::now();
assert!(t2 > t1);
assert!(
(t2 - t1).to_nanos() >= duration as u64,
"diff: {:?}",
(t2 - t1).to_nanos()
);
}
}
#[cfg(test)]
#[embedded_test::tests(executor = esp_hal_embassy::Executor::new())]
mod tests {
use super::*;
#[init]
fn init() -> Context {
Context {
peripherals: esp_hal::init(esp_hal::Config::default()),
}
}
#[cfg(systimer)]
#[test]
#[timeout(2)]
async fn test_systimer_async_delay_ns(ctx: Context) {
let mut alarms = SystemTimer::new(ctx.peripherals.SYSTIMER);
let unit = FrozenUnit::new(&mut alarms.unit0);
let alarm0 = Alarm::new_async(alarms.comparator0, &unit);
test_async_delay_ns(alarm0, 10_000_000).await;
}
#[test]
#[timeout(2)]
async fn test_timg0_async_delay_ns(ctx: Context) {
let timg0 = TimerGroup::new_async(ctx.peripherals.TIMG0);
test_async_delay_ns(timg0.timer0, 10_000_000).await;
#[cfg(timg_timer1)]
test_async_delay_ns(timg0.timer1, 10_000_000).await;
}
#[cfg(timg1)]
#[test]
#[timeout(2)]
async fn test_timg1_async_delay_ns(ctx: Context) {
let timg1 = TimerGroup::new_async(ctx.peripherals.TIMG1);
test_async_delay_ns(timg1.timer0, 10_000_000).await;
#[cfg(timg_timer1)]
test_async_delay_ns(timg1.timer1, 10_000_000).await;
}
#[cfg(systimer)]
#[test]
#[timeout(2)]
async fn test_systimer_async_delay_us(ctx: Context) {
let mut alarms = SystemTimer::new(ctx.peripherals.SYSTIMER);
let unit = FrozenUnit::new(&mut alarms.unit0);
let alarm0 = Alarm::new_async(alarms.comparator0, &unit);
test_async_delay_us(alarm0, 10_000).await;
}
#[test]
#[timeout(2)]
async fn test_timg0_async_delay_us(ctx: Context) {
let timg0 = TimerGroup::new_async(ctx.peripherals.TIMG0);
test_async_delay_us(timg0.timer0, 10_000).await;
#[cfg(timg_timer1)]
test_async_delay_us(timg0.timer1, 10_000).await;
}
#[cfg(timg1)]
#[test]
#[timeout(2)]
async fn test_timg1_async_delay_us(ctx: Context) {
let timg1 = TimerGroup::new_async(ctx.peripherals.TIMG1);
test_async_delay_us(timg1.timer0, 10_000).await;
#[cfg(timg_timer1)]
test_async_delay_us(timg1.timer1, 10_000).await;
}
#[cfg(systimer)]
#[test]
#[timeout(2)]
async fn test_systimer_async_delay_ms(ctx: Context) {
let mut alarms = SystemTimer::new(ctx.peripherals.SYSTIMER);
let unit = FrozenUnit::new(&mut alarms.unit0);
let alarm0 = Alarm::new_async(alarms.comparator0, &unit);
test_async_delay_ms(alarm0, 10).await;
}
#[test]
#[timeout(2)]
async fn test_timg0_async_delay_ms(ctx: Context) {
let timg0 = TimerGroup::new_async(ctx.peripherals.TIMG0);
test_async_delay_ms(timg0.timer0, 10).await;
#[cfg(timg_timer1)]
test_async_delay_ms(timg0.timer1, 10).await;
}
#[cfg(timg1)]
#[test]
#[timeout(2)]
async fn test_timg1_async_delay_ms(ctx: Context) {
let timg1 = TimerGroup::new_async(ctx.peripherals.TIMG1);
test_async_delay_ms(timg1.timer0, 10).await;
#[cfg(timg_timer1)]
test_async_delay_ms(timg1.timer1, 10).await;
}
}

View File

@ -73,8 +73,8 @@ mod test {
AnyTimer::from(timg1.timer0),
]);
} else if #[cfg(systimer)] {
use esp_hal::timer::systimer::{SystemTimer, Target};
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
use esp_hal::timer::systimer::SystemTimer;
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init([
AnyTimer::from(systimer.alarm0),
AnyTimer::from(systimer.alarm1),

View File

@ -87,8 +87,8 @@ mod test {
cfg_if::cfg_if! {
if #[cfg(systimer)] {
use esp_hal::timer::systimer::{SystemTimer, Target};
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
use esp_hal::timer::systimer::SystemTimer;
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init([
AnyTimer::from(systimer.alarm0),
AnyTimer::from(systimer.alarm1),
@ -257,8 +257,8 @@ mod test {
cfg_if::cfg_if! {
if #[cfg(systimer)] {
use esp_hal::timer::systimer::{SystemTimer, Target};
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
use esp_hal::timer::systimer::SystemTimer;
let systimer = SystemTimer::new(peripherals.SYSTIMER);
esp_hal_embassy::init([
AnyTimer::from(systimer.alarm0),
AnyTimer::from(systimer.alarm1),

View File

@ -1,294 +0,0 @@
//! Embassy timer and executor Test
//% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
//% FEATURES: integrated-timers
//% FEATURES: generic-queue
#![no_std]
#![no_main]
use embassy_time::{Duration, Ticker, Timer};
#[cfg(not(feature = "esp32"))]
use esp_hal::{
interrupt::software::SoftwareInterruptControl,
interrupt::Priority,
timer::systimer::{Alarm, FrozenUnit, Periodic, SystemTimer, Target},
timer::AnyTimer,
};
use esp_hal::{
peripherals::Peripherals,
prelude::*,
timer::{timg::TimerGroup, OneShotTimer, PeriodicTimer},
};
#[cfg(not(feature = "esp32"))]
use esp_hal_embassy::InterruptExecutor;
use hil_test as _;
#[cfg(not(feature = "esp32"))]
macro_rules! mk_static {
($t:ty,$val:expr) => {{
static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new();
#[deny(unused_attributes)]
let x = STATIC_CELL.uninit().write(($val));
x
}};
}
// List of the functions that are ACTUALLY TESTS but are called in the invokers
mod test_helpers {
use super::*;
#[embassy_executor::task]
pub async fn e_task30ms() {
Timer::after_millis(30).await;
}
}
mod test_cases {
use esp_hal::peripheral::Peripheral;
use super::*;
pub async fn run_test_one_shot_async() {
let t1 = esp_hal::time::now();
Timer::after_millis(50).await;
Timer::after_millis(30).await;
let t2 = esp_hal::time::now();
assert!(t2 > t1, "t2: {:?}, t1: {:?}", t2, t1);
assert!(
(t2 - t1).to_millis() >= 80u64,
"diff: {:?}",
(t2 - t1).to_millis()
);
}
pub fn run_test_periodic_timer<T: esp_hal::timer::Timer>(timer: impl Peripheral<P = T>) {
let mut periodic = PeriodicTimer::new(timer);
let t1 = esp_hal::time::now();
periodic.start(100.millis()).unwrap();
nb::block!(periodic.wait()).unwrap();
let t2 = esp_hal::time::now();
assert!(t2 > t1, "t2: {:?}, t1: {:?}", t2, t1);
assert!(
(t2 - t1).to_millis() >= 100u64,
"diff: {:?}",
(t2 - t1).to_millis()
);
}
pub fn run_test_oneshot_timer<T: esp_hal::timer::Timer>(timer: impl Peripheral<P = T>) {
let timer = OneShotTimer::new(timer);
let t1 = esp_hal::time::now();
timer.delay_millis(50);
let t2 = esp_hal::time::now();
assert!(t2 > t1, "t2: {:?}, t1: {:?}", t2, t1);
assert!(
(t2 - t1).to_millis() >= 50u64,
"diff: {:?}",
(t2 - t1).to_millis()
);
}
pub async fn run_join_test() {
let t1 = esp_hal::time::now();
embassy_futures::join::join(Timer::after_millis(50), Timer::after_millis(30)).await;
Timer::after_millis(50).await;
let t2 = esp_hal::time::now();
assert!(t2 > t1, "t2: {:?}, t1: {:?}", t2, t1);
assert!(
(t2 - t1).to_millis() >= 100u64,
"diff: {:?}",
(t2 - t1).to_millis()
);
}
}
fn set_up_embassy_with_timg0(peripherals: Peripherals) {
let timg0 = TimerGroup::new(peripherals.TIMG0);
esp_hal_embassy::init(timg0.timer0);
}
#[cfg(not(feature = "esp32"))]
fn set_up_embassy_with_systimer(peripherals: Peripherals) {
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
esp_hal_embassy::init(systimer.alarm0);
}
#[cfg(test)]
#[embedded_test::tests(executor = esp_hal_embassy::Executor::new())]
mod test {
use super::*;
use crate::test_cases::*;
#[cfg(not(feature = "esp32"))]
use crate::test_helpers::*;
#[init]
fn init() -> Peripherals {
esp_hal::init(esp_hal::Config::default())
}
#[test]
#[timeout(3)]
async fn test_one_shot_timg(peripherals: Peripherals) {
set_up_embassy_with_timg0(peripherals);
run_test_one_shot_async().await;
}
#[test]
#[timeout(3)]
#[cfg(not(feature = "esp32"))]
async fn test_one_shot_systimer(peripherals: Peripherals) {
set_up_embassy_with_systimer(peripherals);
run_test_one_shot_async().await;
}
#[test]
#[timeout(3)]
fn test_periodic_timg(peripherals: Peripherals) {
let timg0 = TimerGroup::new(peripherals.TIMG0);
run_test_periodic_timer(timg0.timer0);
}
#[test]
#[timeout(3)]
#[cfg(not(feature = "esp32"))]
fn test_periodic_systimer(peripherals: Peripherals) {
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Periodic>();
run_test_periodic_timer(systimer.alarm0);
}
#[test]
#[timeout(3)]
fn test_periodic_oneshot_timg(mut peripherals: Peripherals) {
let mut timg0 = TimerGroup::new(&mut peripherals.TIMG0);
run_test_periodic_timer(&mut timg0.timer0);
let mut timg0 = TimerGroup::new(&mut peripherals.TIMG0);
run_test_oneshot_timer(&mut timg0.timer0);
}
#[test]
#[timeout(3)]
#[cfg(not(feature = "esp32"))]
fn test_periodic_oneshot_systimer(mut peripherals: Peripherals) {
let mut systimer = SystemTimer::new(&mut peripherals.SYSTIMER);
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 peripherals.SYSTIMER);
let unit = FrozenUnit::new(&mut systimer.unit0);
let mut alarm: Alarm<'_, Target, _, _, _> = Alarm::new(systimer.comparator0, &unit);
run_test_oneshot_timer(&mut alarm);
}
#[test]
#[timeout(3)]
async fn test_join_timg(peripherals: Peripherals) {
set_up_embassy_with_timg0(peripherals);
run_join_test().await;
}
#[test]
#[timeout(3)]
#[cfg(not(feature = "esp32"))]
async fn test_join_systimer(peripherals: Peripherals) {
set_up_embassy_with_systimer(peripherals);
run_join_test().await;
}
/// Test that the ticker works in tasks ran by the interrupt executors.
#[test]
#[timeout(3)]
#[cfg(not(feature = "esp32"))]
async fn test_interrupt_executor(peripherals: Peripherals) {
let timg0 = TimerGroup::new(peripherals.TIMG0);
let timer0: AnyTimer = timg0.timer0.into();
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
let alarm0: AnyTimer = systimer.alarm0.into();
esp_hal_embassy::init([timer0, alarm0]);
let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);
let executor = mk_static!(
InterruptExecutor<2>,
InterruptExecutor::new(sw_ints.software_interrupt2)
);
#[embassy_executor::task]
#[cfg(not(feature = "esp32"))]
async fn test_interrupt_executor_invoker() {
let outcome = async {
let mut ticker = Ticker::every(Duration::from_millis(30));
let t1 = esp_hal::time::now();
ticker.next().await;
ticker.next().await;
ticker.next().await;
let t2 = esp_hal::time::now();
assert!(t2 > t1, "t2: {:?}, t1: {:?}", t2, t1);
assert!(
(t2 - t1).to_micros() >= 85000u64,
"diff: {:?}",
(t2 - t1).to_micros()
);
};
embedded_test::export::check_outcome(outcome.await);
}
let spawner_int = executor.start(Priority::Priority3);
spawner_int.must_spawn(test_interrupt_executor_invoker());
let spawner = embassy_executor::Spawner::for_current_executor().await;
spawner.must_spawn(e_task30ms());
// The test ends once the interrupt executor's task has finished
loop {}
}
/// Test that timg0 and systimer don't have vastly different tick rates.
#[test]
#[timeout(3)]
async fn tick_test_timer_tick_rates(peripherals: Peripherals) {
set_up_embassy_with_timg0(peripherals);
// We are retrying 5 times because probe-rs polling RTT may introduce some
// jitter.
for _ in 0..5 {
let t1 = esp_hal::time::now();
let mut ticker = Ticker::every(Duration::from_hz(100_000));
for _ in 0..2000 {
ticker.next().await;
}
let t2 = esp_hal::time::now();
assert!(t2 > t1, "t2: {:?}, t1: {:?}", t2, t1);
let duration = (t2 - t1).to_micros();
assert!(duration >= 19000, "diff: {:?}", (t2 - t1).to_micros());
if duration <= 21000 {
return;
}
}
assert!(false, "Test failed after 5 retries");
}
}

View File

@ -1,182 +0,0 @@
//! System Timer Test
// esp32 disabled as it does not have a systimer
//% CHIPS: esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3
#![no_std]
#![no_main]
use core::cell::RefCell;
use critical_section::Mutex;
use embedded_hal::delay::DelayNs;
use esp_hal::{
delay::Delay,
prelude::*,
timer::systimer::{
Alarm,
FrozenUnit,
Periodic,
SpecificComparator,
SpecificUnit,
SystemTimer,
Target,
},
Blocking,
};
use fugit::ExtU32;
use hil_test as _;
use portable_atomic::{AtomicUsize, Ordering};
use static_cell::StaticCell;
type TestAlarm<M, const C: u8> =
Alarm<'static, M, Blocking, SpecificComparator<'static, C>, SpecificUnit<'static, 0>>;
static ALARM_TARGET: Mutex<RefCell<Option<TestAlarm<Target, 0>>>> = Mutex::new(RefCell::new(None));
static ALARM_PERIODIC: Mutex<RefCell<Option<TestAlarm<Periodic, 1>>>> =
Mutex::new(RefCell::new(None));
struct Context {
unit: FrozenUnit<'static, SpecificUnit<'static, 0>>,
comparator0: SpecificComparator<'static, 0>,
comparator1: SpecificComparator<'static, 1>,
}
#[handler(priority = esp_hal::interrupt::Priority::min())]
fn pass_test_if_called() {
critical_section::with(|cs| {
ALARM_TARGET
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
});
embedded_test::export::check_outcome(());
}
#[handler(priority = esp_hal::interrupt::Priority::min())]
fn handle_periodic_interrupt() {
critical_section::with(|cs| {
ALARM_PERIODIC
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
});
}
static COUNTER: AtomicUsize = AtomicUsize::new(0);
#[handler(priority = esp_hal::interrupt::Priority::min())]
fn pass_test_if_called_twice() {
critical_section::with(|cs| {
ALARM_PERIODIC
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
});
COUNTER.fetch_add(1, Ordering::Relaxed);
if COUNTER.load(Ordering::Relaxed) == 2 {
embedded_test::export::check_outcome(());
}
}
#[handler(priority = esp_hal::interrupt::Priority::min())]
fn target_fail_test_if_called_twice() {
critical_section::with(|cs| {
ALARM_TARGET
.borrow_ref_mut(cs)
.as_mut()
.unwrap()
.clear_interrupt()
});
COUNTER.fetch_add(1, Ordering::Relaxed);
assert!(COUNTER.load(Ordering::Relaxed) != 2);
}
#[cfg(test)]
#[embedded_test::tests]
mod tests {
use super::*;
#[init]
fn init() -> Context {
let peripherals = esp_hal::init(esp_hal::Config::default());
let systimer = SystemTimer::new(peripherals.SYSTIMER);
static UNIT0: StaticCell<SpecificUnit<'static, 0>> = StaticCell::new();
let unit0 = UNIT0.init(systimer.unit0);
let frozen_unit = FrozenUnit::new(unit0);
Context {
unit: frozen_unit,
comparator0: systimer.comparator0,
comparator1: systimer.comparator1,
}
}
#[test]
#[timeout(3)]
fn target_interrupt_is_handled(ctx: Context) {
let alarm0 = Alarm::new(ctx.comparator0, &ctx.unit);
critical_section::with(|cs| {
alarm0.set_interrupt_handler(pass_test_if_called);
alarm0.set_target(SystemTimer::now() + SystemTimer::ticks_per_second() / 10);
alarm0.enable_interrupt(true);
ALARM_TARGET.borrow_ref_mut(cs).replace(alarm0);
});
// We'll end the test in the interrupt handler.
loop {}
}
#[test]
#[timeout(3)]
fn target_interrupt_is_handled_once(ctx: Context) {
let alarm0 = Alarm::new(ctx.comparator0, &ctx.unit);
let alarm1 = Alarm::new(ctx.comparator1, &ctx.unit);
COUNTER.store(0, Ordering::Relaxed);
critical_section::with(|cs| {
alarm0.set_interrupt_handler(target_fail_test_if_called_twice);
alarm0.set_target(SystemTimer::now() + SystemTimer::ticks_per_second() / 10);
alarm0.enable_interrupt(true);
let alarm1 = alarm1.into_periodic();
alarm1.set_interrupt_handler(handle_periodic_interrupt);
alarm1.set_period(100u32.millis());
alarm1.enable_interrupt(true);
ALARM_TARGET.borrow_ref_mut(cs).replace(alarm0);
ALARM_PERIODIC.borrow_ref_mut(cs).replace(alarm1);
});
let mut delay = Delay::new();
delay.delay_ms(300);
}
#[test]
#[timeout(3)]
fn periodic_interrupt_is_handled(ctx: Context) {
let alarm1 = Alarm::new(ctx.comparator1, &ctx.unit);
COUNTER.store(0, Ordering::Relaxed);
critical_section::with(|cs| {
let alarm1 = alarm1.into_periodic();
alarm1.set_interrupt_handler(pass_test_if_called_twice);
alarm1.set_period(100u32.millis());
alarm1.enable_interrupt(true);
ALARM_PERIODIC.borrow_ref_mut(cs).replace(alarm1);
});
// We'll end the test in the interrupt handler.
loop {}
}
}