[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:
parent
9c1d99d9b4
commit
60a2c76005
@ -83,12 +83,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "esp32"))]
|
#[cfg(not(feature = "esp32"))]
|
||||||
impl<T, DM, COMP, UNIT> IntoAnyTimer for Alarm<'_, T, DM, COMP, UNIT>
|
impl IntoAnyTimer for Alarm where Self: Into<AnyTimer> {}
|
||||||
where
|
|
||||||
DM: esp_hal::Mode,
|
|
||||||
Self: Into<AnyTimer>,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<T> TimerCollection for T
|
impl<T> TimerCollection for T
|
||||||
where
|
where
|
||||||
|
|||||||
@ -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 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)
|
- 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)
|
- 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
|
### 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 `configure` and `configure_for_async` DMA channel functions has been removed (#2403)
|
||||||
- The DMA channel objects no longer have `tx` and `rx` fields. (#2526)
|
- 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
|
## [0.22.0] - 2024-11-20
|
||||||
|
|
||||||
|
|||||||
@ -26,3 +26,21 @@
|
|||||||
-.with_dma(dma_channel.configure(false, DmaPriority::Priority1));
|
-.with_dma(dma_channel.configure(false, DmaPriority::Priority1));
|
||||||
+.with_dma(dma_channel);
|
+.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());
|
||||||
|
```
|
||||||
|
|||||||
@ -47,12 +47,10 @@ pub fn now() -> Instant {
|
|||||||
|
|
||||||
#[cfg(not(esp32))]
|
#[cfg(not(esp32))]
|
||||||
let (ticks, div) = {
|
let (ticks, div) = {
|
||||||
|
use crate::timer::systimer::{SystemTimer, Unit};
|
||||||
// otherwise use SYSTIMER
|
// otherwise use SYSTIMER
|
||||||
let ticks = crate::timer::systimer::SystemTimer::now();
|
let ticks = SystemTimer::unit_value(Unit::Unit0);
|
||||||
(
|
(ticks, (SystemTimer::ticks_per_second() / 1_000_000))
|
||||||
ticks,
|
|
||||||
(crate::timer::systimer::SystemTimer::ticks_per_second() / 1_000_000),
|
|
||||||
)
|
|
||||||
};
|
};
|
||||||
|
|
||||||
Instant::from_ticks(ticks / div)
|
Instant::from_ticks(ticks / div)
|
||||||
|
|||||||
@ -370,12 +370,9 @@ enum AnyTimerInner {
|
|||||||
/// Timer 1 of the TIMG1 peripheral in blocking mode.
|
/// Timer 1 of the TIMG1 peripheral in blocking mode.
|
||||||
#[cfg(all(timg1, timg_timer1))]
|
#[cfg(all(timg1, timg_timer1))]
|
||||||
Timg1Timer1(timg::Timer<timg::Timer1<crate::peripherals::TIMG1>, Blocking>),
|
Timg1Timer1(timg::Timer<timg::Timer1<crate::peripherals::TIMG1>, Blocking>),
|
||||||
/// Systimer Alarm in periodic mode with blocking behavior.
|
/// Systimer Alarm
|
||||||
#[cfg(systimer)]
|
#[cfg(systimer)]
|
||||||
SystimerAlarmPeriodic(systimer::Alarm<'static, systimer::Periodic, Blocking>),
|
SystimerAlarm(systimer::Alarm),
|
||||||
/// Systimer Target in periodic mode with blocking behavior.
|
|
||||||
#[cfg(systimer)]
|
|
||||||
SystimerAlarmTarget(systimer::Alarm<'static, systimer::Target, Blocking>),
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// A type-erased timer
|
/// A type-erased timer
|
||||||
@ -413,16 +410,9 @@ impl From<timg::Timer<timg::Timer1<crate::peripherals::TIMG1>, Blocking>> for An
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(systimer)]
|
#[cfg(systimer)]
|
||||||
impl From<systimer::Alarm<'static, systimer::Periodic, Blocking>> for AnyTimer {
|
impl From<systimer::Alarm> for AnyTimer {
|
||||||
fn from(value: systimer::Alarm<'static, systimer::Periodic, Blocking>) -> Self {
|
fn from(value: systimer::Alarm) -> Self {
|
||||||
Self(AnyTimerInner::SystimerAlarmPeriodic(value))
|
Self(AnyTimerInner::SystimerAlarm(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))
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -437,9 +427,7 @@ impl Timer for AnyTimer {
|
|||||||
#[cfg(all(timg1,timg_timer1))]
|
#[cfg(all(timg1,timg_timer1))]
|
||||||
AnyTimerInner::Timg1Timer1(inner) => inner,
|
AnyTimerInner::Timg1Timer1(inner) => inner,
|
||||||
#[cfg(systimer)]
|
#[cfg(systimer)]
|
||||||
AnyTimerInner::SystimerAlarmPeriodic(inner) => inner,
|
AnyTimerInner::SystimerAlarm(inner) => inner,
|
||||||
#[cfg(systimer)]
|
|
||||||
AnyTimerInner::SystimerAlarmTarget(inner) => inner,
|
|
||||||
} {
|
} {
|
||||||
fn start(&self);
|
fn start(&self);
|
||||||
fn stop(&self);
|
fn stop(&self);
|
||||||
|
|||||||
@ -9,72 +9,17 @@
|
|||||||
//!
|
//!
|
||||||
//! ## Configuration
|
//! ## Configuration
|
||||||
//!
|
//!
|
||||||
//! The timer consists of two counters, `UNIT0` and `UNIT1`. The counter values
|
//! The timer consists of two counters, `Unit0` and `Unit1`. The counter values
|
||||||
//! can be monitored by 3 comparators, `COMP0`, `COMP1`, and `COMP2`.
|
//! can be monitored by 3 [`Alarm`]s
|
||||||
//!
|
//!
|
||||||
//! [Alarm]s can be configured in two modes: [Target] (one-shot) and [Periodic].
|
//! It is recommended to pass the [`Alarm`]s into a high level driver like
|
||||||
//!
|
//! [`OneShotTimer`](super::OneShotTimer) and
|
||||||
//! ## Examples
|
//! [`PeriodicTimer`](super::PeriodicTimer). Using the System timer directly is
|
||||||
//!
|
//! only possible through the low level [`Timer`](crate::timer::Timer) trait.
|
||||||
//! ### 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();
|
|
||||||
//! # }
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
use core::{
|
use core::fmt::Debug;
|
||||||
fmt::{Debug, Formatter},
|
|
||||||
marker::PhantomData,
|
|
||||||
ptr::addr_of_mut,
|
|
||||||
};
|
|
||||||
|
|
||||||
use fugit::{Instant, MicrosDurationU32, MicrosDurationU64};
|
use fugit::{Instant, MicrosDurationU64};
|
||||||
|
|
||||||
use super::{Error, Timer as _};
|
use super::{Error, Timer as _};
|
||||||
use crate::{
|
use crate::{
|
||||||
@ -83,33 +28,35 @@ use crate::{
|
|||||||
peripherals::{Interrupt, SYSTIMER},
|
peripherals::{Interrupt, SYSTIMER},
|
||||||
sync::{lock, Lock},
|
sync::{lock, Lock},
|
||||||
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
|
system::{Peripheral as PeripheralEnable, PeripheralClockControl},
|
||||||
Async,
|
|
||||||
Blocking,
|
|
||||||
Cpu,
|
Cpu,
|
||||||
InterruptConfigurable,
|
|
||||||
Mode,
|
|
||||||
};
|
};
|
||||||
|
|
||||||
/// System Timer driver.
|
/// The configuration of a unit.
|
||||||
pub struct SystemTimer<'d> {
|
#[derive(Copy, Clone)]
|
||||||
/// Unit 0
|
pub enum UnitConfig {
|
||||||
pub unit0: SpecificUnit<'d, 0>,
|
/// Unit is not counting.
|
||||||
|
Disabled,
|
||||||
|
|
||||||
#[cfg(not(esp32s2))]
|
/// Unit is counting unless the Cpu is stalled.
|
||||||
/// Unit 1
|
DisabledIfCpuIsStalled(Cpu),
|
||||||
pub unit1: SpecificUnit<'d, 1>,
|
|
||||||
|
|
||||||
/// Comparator 0.
|
/// Unit is counting.
|
||||||
pub comparator0: SpecificComparator<'d, 0>,
|
Enabled,
|
||||||
|
|
||||||
/// Comparator 1.
|
|
||||||
pub comparator1: SpecificComparator<'d, 1>,
|
|
||||||
|
|
||||||
/// Comparator 2.
|
|
||||||
pub comparator2: SpecificComparator<'d, 2>,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
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! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(esp32s2)] {
|
if #[cfg(esp32s2)] {
|
||||||
/// Bitmask to be applied to the raw register value.
|
/// Bitmask to be applied to the raw register value.
|
||||||
@ -146,7 +93,7 @@ impl<'d> SystemTimer<'d> {
|
|||||||
}
|
}
|
||||||
|
|
||||||
/// Create a new instance.
|
/// 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
|
// Don't reset Systimer as it will break `time::now`, only enable it
|
||||||
PeripheralClockControl::enable(PeripheralEnable::Systimer);
|
PeripheralClockControl::enable(PeripheralEnable::Systimer);
|
||||||
|
|
||||||
@ -154,67 +101,49 @@ impl<'d> SystemTimer<'d> {
|
|||||||
etm::enable_etm();
|
etm::enable_etm();
|
||||||
|
|
||||||
Self {
|
Self {
|
||||||
unit0: SpecificUnit::new(),
|
alarm0: Alarm::new(0),
|
||||||
#[cfg(not(esp32s2))]
|
alarm1: Alarm::new(1),
|
||||||
unit1: SpecificUnit::new(),
|
alarm2: Alarm::new(2),
|
||||||
comparator0: SpecificComparator::new(),
|
|
||||||
comparator1: SpecificComparator::new(),
|
|
||||||
comparator2: SpecificComparator::new(),
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the current count of Unit 0 in the System Timer.
|
/// Get the current count of the given unit in the System Timer.
|
||||||
pub fn now() -> u64 {
|
pub fn unit_value(unit: Unit) -> u64 {
|
||||||
// This should be safe to access from multiple contexts
|
// This should be safe to access from multiple contexts
|
||||||
// worst case scenario the second accessor ends up reading
|
// worst case scenario the second accessor ends up reading
|
||||||
// an older time stamp
|
// an older time stamp
|
||||||
|
|
||||||
let unit = unsafe { SpecificUnit::<'_, 0>::conjure() };
|
|
||||||
unit.read_count()
|
unit.read_count()
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
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<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))]
|
#[cfg(not(esp32s2))]
|
||||||
unit1: self.unit1,
|
/// Configures when this counter can run.
|
||||||
}
|
/// It can be configured to stall or continue running when CPU stalls
|
||||||
}
|
/// or enters on-chip-debugging mode.
|
||||||
|
|
||||||
/// Split the System Timer into three alarms.
|
|
||||||
///
|
///
|
||||||
/// This is a convenience method to create `'static` alarms of the same
|
/// # Safety
|
||||||
/// type. You are encouraged to use [Alarm::new_async] over this very
|
///
|
||||||
/// specific helper.
|
/// - Disabling a `Unit` whilst [`Alarm`]s are using it will affect the
|
||||||
pub fn split_async<MODE>(self) -> SysTimerAlarms<MODE, Async> {
|
/// [`Alarm`]s operation.
|
||||||
static mut UNIT0: Option<AnyUnit<'static>> = None;
|
/// - Disabling Unit0 will affect [`now`](crate::time::now).
|
||||||
let unit0 = unsafe { &mut *addr_of_mut!(UNIT0) };
|
pub unsafe fn configure_unit(unit: Unit, config: UnitConfig) {
|
||||||
|
unit.configure(config)
|
||||||
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,
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// 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
|
||||||
|
///
|
||||||
|
/// # 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(esp32s2, doc = "64-bit")]
|
||||||
#[cfg_attr(not(esp32s2), doc = "52-bit")]
|
#[cfg_attr(not(esp32s2), doc = "52-bit")]
|
||||||
/// counter.
|
/// counter.
|
||||||
pub trait Unit {
|
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||||
/// Returns the unit number.
|
pub enum Unit {
|
||||||
fn channel(&self) -> u8;
|
/// Unit 0
|
||||||
|
Unit0 = 0,
|
||||||
|
#[cfg(not(esp32s2))]
|
||||||
|
/// Unit 1
|
||||||
|
Unit1 = 1,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Unit {
|
||||||
|
#[inline]
|
||||||
|
fn channel(&self) -> u8 {
|
||||||
|
*self as _
|
||||||
|
}
|
||||||
|
|
||||||
#[cfg(not(esp32s2))]
|
#[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) {
|
fn configure(&self, config: UnitConfig) {
|
||||||
let systimer = unsafe { &*SYSTIMER::ptr() };
|
let systimer = unsafe { &*SYSTIMER::ptr() };
|
||||||
let conf = systimer.conf();
|
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) {
|
fn set_count(&self, value: u64) {
|
||||||
let systimer = unsafe { &*SYSTIMER::ptr() };
|
let systimer = unsafe { &*SYSTIMER::ptr() };
|
||||||
#[cfg(not(esp32s2))]
|
#[cfg(not(esp32s2))]
|
||||||
@ -303,7 +235,6 @@ pub trait Unit {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Reads the current counter value.
|
|
||||||
fn read_count(&self) -> u64 {
|
fn read_count(&self) -> u64 {
|
||||||
// This can be a shared reference as long as this type isn't Sync.
|
// 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)]
|
#[derive(Debug)]
|
||||||
pub struct SpecificUnit<'d, const CHANNEL: u8>(PhantomData<&'d ()>);
|
pub struct Alarm {
|
||||||
|
comp: u8,
|
||||||
impl<const CHANNEL: u8> SpecificUnit<'_, CHANNEL> {
|
unit: Unit,
|
||||||
fn new() -> Self {
|
|
||||||
Self(PhantomData)
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<const CHANNEL: u8> Unit for SpecificUnit<'_, CHANNEL> {
|
impl Alarm {
|
||||||
|
const fn new(comp: u8) -> Self {
|
||||||
|
Alarm {
|
||||||
|
comp,
|
||||||
|
unit: Unit::Unit0,
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Returns the comparator's number.
|
||||||
|
#[inline]
|
||||||
fn channel(&self) -> u8 {
|
fn channel(&self) -> u8 {
|
||||||
CHANNEL
|
self.comp
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// 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)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
/// 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
|
/// Enables/disables the comparator. If enabled, this means
|
||||||
/// it will generate interrupt based on its configuration.
|
/// 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.
|
/// Sets the unit this comparator uses as a reference count.
|
||||||
#[cfg(not(esp32s2))]
|
#[cfg(not(esp32s2))]
|
||||||
fn set_unit(&self, is_unit0: bool) {
|
pub fn set_unit(&self, unit: Unit) {
|
||||||
let tconf = unsafe {
|
let tconf = unsafe {
|
||||||
let systimer = &*SYSTIMER::ptr();
|
let systimer = &*SYSTIMER::ptr();
|
||||||
systimer.target_conf(self.channel() as usize)
|
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.
|
/// 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.
|
/// Set the interrupt handler for this comparator.
|
||||||
fn set_interrupt_handler(&self, handler: InterruptHandler) {
|
fn set_interrupt_handler(&self, handler: InterruptHandler) {
|
||||||
let interrupt = match self.channel() {
|
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.
|
/// The modes of a comparator.
|
||||||
#[derive(Copy, Clone)]
|
#[derive(Copy, Clone)]
|
||||||
pub enum ComparatorMode {
|
enum ComparatorMode {
|
||||||
/// The comparator will generate interrupts periodically.
|
/// The comparator will generate interrupts periodically.
|
||||||
Period,
|
Period,
|
||||||
|
|
||||||
@ -634,208 +468,13 @@ pub enum ComparatorMode {
|
|||||||
Target,
|
Target,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl SpecificUnit<'static, 0> {
|
impl super::Timer for Alarm {
|
||||||
/// 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,
|
|
||||||
{
|
|
||||||
fn start(&self) {
|
fn start(&self) {
|
||||||
self.comparator.set_enable(true);
|
self.set_enable(true);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn stop(&self) {
|
fn stop(&self) {
|
||||||
self.comparator.set_enable(false);
|
self.set_enable(false);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn reset(&self) {
|
fn reset(&self) {
|
||||||
@ -856,7 +495,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn is_running(&self) -> bool {
|
fn is_running(&self) -> bool {
|
||||||
self.comparator.is_enabled()
|
self.is_enabled()
|
||||||
}
|
}
|
||||||
|
|
||||||
fn now(&self) -> Instant<u64, 1, 1_000_000> {
|
fn now(&self) -> Instant<u64, 1, 1_000_000> {
|
||||||
@ -871,7 +510,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error> {
|
fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error> {
|
||||||
let mode = self.comparator.mode();
|
let mode = self.mode();
|
||||||
|
|
||||||
let us = value.ticks();
|
let us = value.ticks();
|
||||||
let ticks = us * (SystemTimer::ticks_per_second() / 1_000_000);
|
let ticks = us * (SystemTimer::ticks_per_second() / 1_000_000);
|
||||||
@ -886,12 +525,12 @@ where
|
|||||||
return Err(Error::InvalidTimeout);
|
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
|
// Clear and then set SYSTIMER_TARGETx_PERIOD_MODE to configure COMPx into
|
||||||
// period mode
|
// period mode
|
||||||
self.comparator.set_mode(ComparatorMode::Target);
|
self.set_mode(ComparatorMode::Target);
|
||||||
self.comparator.set_mode(ComparatorMode::Period);
|
self.set_mode(ComparatorMode::Period);
|
||||||
} else {
|
} else {
|
||||||
// Target mode
|
// Target mode
|
||||||
|
|
||||||
@ -906,7 +545,7 @@ where
|
|||||||
let v = self.unit.read_count();
|
let v = self.unit.read_count();
|
||||||
let t = v + ticks;
|
let t = v + ticks;
|
||||||
|
|
||||||
self.comparator.set_target(t);
|
self.set_target(t);
|
||||||
}
|
}
|
||||||
|
|
||||||
Ok(())
|
Ok(())
|
||||||
@ -919,28 +558,28 @@ where
|
|||||||
} else {
|
} else {
|
||||||
ComparatorMode::Target
|
ComparatorMode::Target
|
||||||
};
|
};
|
||||||
self.comparator.set_mode(mode)
|
self.set_mode(mode)
|
||||||
}
|
}
|
||||||
|
|
||||||
fn enable_interrupt(&self, state: bool) {
|
fn enable_interrupt(&self, state: bool) {
|
||||||
lock(&INT_ENA_LOCK, || {
|
lock(&INT_ENA_LOCK, || {
|
||||||
unsafe { &*SYSTIMER::PTR }
|
unsafe { &*SYSTIMER::PTR }
|
||||||
.int_ena()
|
.int_ena()
|
||||||
.modify(|_, w| w.target(self.comparator.channel()).bit(state));
|
.modify(|_, w| w.target(self.channel()).bit(state));
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn clear_interrupt(&self) {
|
fn clear_interrupt(&self) {
|
||||||
unsafe { &*SYSTIMER::PTR }
|
unsafe { &*SYSTIMER::PTR }
|
||||||
.int_clr()
|
.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 {
|
fn is_interrupt_set(&self) -> bool {
|
||||||
unsafe { &*SYSTIMER::PTR }
|
unsafe { &*SYSTIMER::PTR }
|
||||||
.int_raw()
|
.int_raw()
|
||||||
.read()
|
.read()
|
||||||
.target(self.comparator.channel())
|
.target(self.channel())
|
||||||
.bit_is_set()
|
.bit_is_set()
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -949,27 +588,30 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
fn set_interrupt_handler(&self, handler: InterruptHandler) {
|
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>
|
impl Peripheral for Alarm {
|
||||||
where
|
|
||||||
DM: Mode,
|
|
||||||
{
|
|
||||||
type P = Self;
|
type P = Self;
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
unsafe fn clone_unchecked(&self) -> Self::P {
|
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 CONF_LOCK: Lock = Lock::new();
|
||||||
static INT_ENA_LOCK: Lock = Lock::new();
|
static INT_ENA_LOCK: Lock = Lock::new();
|
||||||
|
|
||||||
// Async functionality of the system timer.
|
// Async functionality of the system timer.
|
||||||
mod asynch {
|
mod asynch {
|
||||||
|
#![allow(unused)] // FIXME (mabez)
|
||||||
use core::{
|
use core::{
|
||||||
pin::Pin,
|
pin::Pin,
|
||||||
task::{Context, Poll},
|
task::{Context, Poll},
|
||||||
@ -985,15 +627,15 @@ mod asynch {
|
|||||||
static WAKERS: [AtomicWaker; NUM_ALARMS] = [const { AtomicWaker::new() }; NUM_ALARMS];
|
static WAKERS: [AtomicWaker; NUM_ALARMS] = [const { AtomicWaker::new() }; NUM_ALARMS];
|
||||||
|
|
||||||
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
#[must_use = "futures do nothing unless you `.await` or poll them"]
|
||||||
pub(crate) struct AlarmFuture<'a, COMP: Comparator, UNIT: Unit> {
|
pub(crate) struct AlarmFuture<'a> {
|
||||||
alarm: &'a Alarm<'a, Target, crate::Async, COMP, UNIT>,
|
alarm: &'a Alarm,
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<'a, COMP: Comparator, UNIT: Unit> AlarmFuture<'a, COMP, UNIT> {
|
impl<'a> AlarmFuture<'a> {
|
||||||
pub(crate) fn new(alarm: &'a Alarm<'a, Target, crate::Async, COMP, UNIT>) -> Self {
|
pub(crate) fn new(alarm: &'a Alarm) -> Self {
|
||||||
alarm.clear_interrupt();
|
alarm.clear_interrupt();
|
||||||
|
|
||||||
let (interrupt, handler) = match alarm.comparator.channel() {
|
let (interrupt, handler) = match alarm.channel() {
|
||||||
0 => (Interrupt::SYSTIMER_TARGET0, target0_handler),
|
0 => (Interrupt::SYSTIMER_TARGET0, target0_handler),
|
||||||
1 => (Interrupt::SYSTIMER_TARGET1, target1_handler),
|
1 => (Interrupt::SYSTIMER_TARGET1, target1_handler),
|
||||||
_ => (Interrupt::SYSTIMER_TARGET2, target2_handler),
|
_ => (Interrupt::SYSTIMER_TARGET2, target2_handler),
|
||||||
@ -1015,16 +657,16 @@ mod asynch {
|
|||||||
unsafe { &*crate::peripherals::SYSTIMER::PTR }
|
unsafe { &*crate::peripherals::SYSTIMER::PTR }
|
||||||
.int_ena()
|
.int_ena()
|
||||||
.read()
|
.read()
|
||||||
.target(self.alarm.comparator.channel())
|
.target(self.alarm.channel())
|
||||||
.bit_is_clear()
|
.bit_is_clear()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<COMP: Comparator, UNIT: Unit> core::future::Future for AlarmFuture<'_, COMP, UNIT> {
|
impl core::future::Future for AlarmFuture<'_> {
|
||||||
type Output = ();
|
type Output = ();
|
||||||
|
|
||||||
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::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() {
|
if self.event_bit_is_clear() {
|
||||||
Poll::Ready(())
|
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]
|
#[handler]
|
||||||
fn target0_handler() {
|
pub(crate) fn target0_handler() {
|
||||||
lock(&INT_ENA_LOCK, || {
|
lock(&INT_ENA_LOCK, || {
|
||||||
unsafe { &*crate::peripherals::SYSTIMER::PTR }
|
unsafe { &*crate::peripherals::SYSTIMER::PTR }
|
||||||
.int_ena()
|
.int_ena()
|
||||||
@ -1065,7 +688,7 @@ mod asynch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[handler]
|
#[handler]
|
||||||
fn target1_handler() {
|
pub(crate) fn target1_handler() {
|
||||||
lock(&INT_ENA_LOCK, || {
|
lock(&INT_ENA_LOCK, || {
|
||||||
unsafe { &*crate::peripherals::SYSTIMER::PTR }
|
unsafe { &*crate::peripherals::SYSTIMER::PTR }
|
||||||
.int_ena()
|
.int_ena()
|
||||||
@ -1076,7 +699,7 @@ mod asynch {
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[handler]
|
#[handler]
|
||||||
fn target2_handler() {
|
pub(crate) fn target2_handler() {
|
||||||
lock(&INT_ENA_LOCK, || {
|
lock(&INT_ENA_LOCK, || {
|
||||||
unsafe { &*crate::peripherals::SYSTIMER::PTR }
|
unsafe { &*crate::peripherals::SYSTIMER::PTR }
|
||||||
.int_ena()
|
.int_ena()
|
||||||
@ -1100,51 +723,33 @@ pub mod etm {
|
|||||||
//! The system timer can generate the following ETM events:
|
//! The system timer can generate the following ETM events:
|
||||||
//! - SYSTIMER_EVT_CNT_CMPx: Indicates the alarm pulses generated by
|
//! - SYSTIMER_EVT_CNT_CMPx: Indicates the alarm pulses generated by
|
||||||
//! COMPx
|
//! COMPx
|
||||||
//!
|
// FIXME(mabez)
|
||||||
//! ## 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);
|
|
||||||
//! # }
|
|
||||||
//! ```
|
|
||||||
|
|
||||||
use super::*;
|
use super::*;
|
||||||
|
|
||||||
/// An ETM controlled SYSTIMER event
|
/// An ETM controlled SYSTIMER event
|
||||||
pub struct Event<'a, 'd, M, DM: crate::Mode, COMP, UNIT> {
|
pub struct Event<'a> {
|
||||||
alarm: &'a mut Alarm<'d, M, DM, COMP, UNIT>,
|
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]
|
/// 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 }
|
Self { alarm }
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Execute closure f with mutable access to the wrapped [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;
|
let alarm = &self.alarm;
|
||||||
f(alarm)
|
f(alarm)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
impl<M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> crate::private::Sealed
|
impl crate::private::Sealed for Event<'_> {}
|
||||||
for Event<'_, '_, M, DM, COMP, UNIT>
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl<M, DM: crate::Mode, COMP: Comparator, UNIT: Unit> crate::etm::EtmEvent
|
impl crate::etm::EtmEvent for Event<'_> {
|
||||||
for Event<'_, '_, M, DM, COMP, UNIT>
|
|
||||||
{
|
|
||||||
fn id(&self) -> u8 {
|
fn id(&self) -> u8 {
|
||||||
50 + self.alarm.comparator.channel()
|
50 + self.alarm.channel()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -293,12 +293,7 @@ where
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[cfg(not(feature = "esp32"))]
|
#[cfg(not(feature = "esp32"))]
|
||||||
impl<T, DM, COMP, UNIT> IntoAnyTimer for Alarm<'_, T, DM, COMP, UNIT>
|
impl IntoAnyTimer for Alarm where Self: Into<AnyTimer> {}
|
||||||
where
|
|
||||||
DM: esp_hal::Mode,
|
|
||||||
Self: Into<AnyTimer>,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
impl private::Sealed for AnyTimer {}
|
impl private::Sealed for AnyTimer {}
|
||||||
impl IntoAnyTimer for AnyTimer {}
|
impl IntoAnyTimer for AnyTimer {}
|
||||||
@ -326,12 +321,7 @@ where
|
|||||||
{
|
{
|
||||||
}
|
}
|
||||||
#[cfg(not(feature = "esp32"))]
|
#[cfg(not(feature = "esp32"))]
|
||||||
impl<T, DM, COMP, UNIT> private::Sealed for Alarm<'_, T, DM, COMP, UNIT>
|
impl private::Sealed for Alarm where Self: Into<AnyTimer> {}
|
||||||
where
|
|
||||||
DM: esp_hal::Mode,
|
|
||||||
Self: Into<AnyTimer>,
|
|
||||||
{
|
|
||||||
}
|
|
||||||
|
|
||||||
/// A marker trait for suitable Rng sources for esp-wifi
|
/// A marker trait for suitable Rng sources for esp-wifi
|
||||||
pub trait EspWifiRngSource: rand_core::RngCore + private::Sealed {}
|
pub trait EspWifiRngSource: rand_core::RngCore + private::Sealed {}
|
||||||
|
|||||||
@ -80,8 +80,8 @@ async fn main(low_prio_spawner: Spawner) {
|
|||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(feature = "esp32c2")] {
|
if #[cfg(feature = "esp32c2")] {
|
||||||
use esp_hal::timer::systimer::{SystemTimer, Target};
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
let timer1: AnyTimer = systimer.alarm0.into();
|
let timer1: AnyTimer = systimer.alarm0.into();
|
||||||
} else {
|
} else {
|
||||||
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
||||||
|
|||||||
@ -19,7 +19,7 @@ use esp_hal::{
|
|||||||
gpio::NoPin,
|
gpio::NoPin,
|
||||||
parl_io::{BitPackOrder, ParlIoRxOnly, RxFourBits},
|
parl_io::{BitPackOrder, ParlIoRxOnly, RxFourBits},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
timer::systimer::{SystemTimer, Target},
|
timer::systimer::SystemTimer,
|
||||||
};
|
};
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
|
|
||||||
@ -28,7 +28,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
esp_println::println!("Init!");
|
esp_println::println!("Init!");
|
||||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
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);
|
esp_hal_embassy::init(systimer.alarm0);
|
||||||
|
|
||||||
let (rx_buffer, rx_descriptors, _, _) = dma_buffers!(32000, 0);
|
let (rx_buffer, rx_descriptors, _, _) = dma_buffers!(32000, 0);
|
||||||
|
|||||||
@ -29,7 +29,7 @@ use esp_hal::{
|
|||||||
TxPinConfigWithValidPin,
|
TxPinConfigWithValidPin,
|
||||||
},
|
},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
timer::systimer::{SystemTimer, Target},
|
timer::systimer::SystemTimer,
|
||||||
};
|
};
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
|
|
||||||
@ -38,7 +38,7 @@ async fn main(_spawner: Spawner) {
|
|||||||
esp_println::println!("Init!");
|
esp_println::println!("Init!");
|
||||||
let peripherals = esp_hal::init(esp_hal::Config::default());
|
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);
|
esp_hal_embassy::init(systimer.alarm0);
|
||||||
|
|
||||||
let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000);
|
let (_, _, tx_buffer, tx_descriptors) = dma_buffers!(0, 32000);
|
||||||
|
|||||||
@ -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 {}
|
|
||||||
}
|
|
||||||
@ -62,7 +62,6 @@ use esp_hal::{
|
|||||||
hmac::{Hmac, HmacPurpose, KeyId},
|
hmac::{Hmac, HmacPurpose, KeyId},
|
||||||
prelude::*,
|
prelude::*,
|
||||||
rng::Rng,
|
rng::Rng,
|
||||||
timer::systimer::SystemTimer,
|
|
||||||
};
|
};
|
||||||
use esp_println::println;
|
use esp_println::println;
|
||||||
use hmac::{Hmac as HmacSw, Mac};
|
use hmac::{Hmac as HmacSw, Mac};
|
||||||
@ -94,18 +93,18 @@ fn main() -> ! {
|
|||||||
let mut remaining = nsrc;
|
let mut remaining = nsrc;
|
||||||
hw_hmac.init();
|
hw_hmac.init();
|
||||||
block!(hw_hmac.configure(HmacPurpose::ToUser, KeyId::Key0)).expect("Key purpose mismatch");
|
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 {
|
while remaining.len() > 0 {
|
||||||
remaining = block!(hw_hmac.update(remaining)).unwrap();
|
remaining = block!(hw_hmac.update(remaining)).unwrap();
|
||||||
}
|
}
|
||||||
block!(hw_hmac.finalize(output.as_mut_slice())).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 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 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);
|
sw_hmac.update(nsrc);
|
||||||
let soft_result = sw_hmac.finalize().into_bytes();
|
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;
|
let soft_time = post_sw_hash - pre_sw_hash;
|
||||||
for (a, b) in output.iter().zip(soft_result) {
|
for (a, b) in output.iter().zip(soft_result) {
|
||||||
assert_eq!(*a, b);
|
assert_eq!(*a, b);
|
||||||
|
|||||||
@ -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()
|
|
||||||
});
|
|
||||||
}
|
|
||||||
@ -86,8 +86,8 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
||||||
esp_hal_embassy::init(timg1.timer0);
|
esp_hal_embassy::init(timg1.timer0);
|
||||||
} else {
|
} else {
|
||||||
use esp_hal::timer::systimer::{SystemTimer, Target};
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
esp_hal_embassy::init(systimer.alarm0);
|
esp_hal_embassy::init(systimer.alarm0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -94,8 +94,8 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
||||||
esp_hal_embassy::init(timg1.timer0);
|
esp_hal_embassy::init(timg1.timer0);
|
||||||
} else {
|
} else {
|
||||||
use esp_hal::timer::systimer::{SystemTimer, Target};
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
esp_hal_embassy::init(systimer.alarm0);
|
esp_hal_embassy::init(systimer.alarm0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -117,8 +117,8 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
||||||
esp_hal_embassy::init(timg1.timer0);
|
esp_hal_embassy::init(timg1.timer0);
|
||||||
} else {
|
} else {
|
||||||
use esp_hal::timer::systimer::{SystemTimer, Target};
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
esp_hal_embassy::init(systimer.alarm0);
|
esp_hal_embassy::init(systimer.alarm0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -83,8 +83,8 @@ async fn main(_spawner: Spawner) -> ! {
|
|||||||
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
||||||
esp_hal_embassy::init(timg1.timer0);
|
esp_hal_embassy::init(timg1.timer0);
|
||||||
} else {
|
} else {
|
||||||
use esp_hal::timer::systimer::{SystemTimer, Target};
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
esp_hal_embassy::init(systimer.alarm0);
|
esp_hal_embassy::init(systimer.alarm0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -79,8 +79,8 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
||||||
esp_hal_embassy::init(timg1.timer0);
|
esp_hal_embassy::init(timg1.timer0);
|
||||||
} else {
|
} else {
|
||||||
use esp_hal::timer::systimer::{SystemTimer, Target};
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
esp_hal_embassy::init(systimer.alarm0);
|
esp_hal_embassy::init(systimer.alarm0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,8 +65,8 @@ async fn main(_spawner: Spawner) -> ! {
|
|||||||
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
||||||
esp_hal_embassy::init(timg1.timer0);
|
esp_hal_embassy::init(timg1.timer0);
|
||||||
} else {
|
} else {
|
||||||
use esp_hal::timer::systimer::{SystemTimer, Target};
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
esp_hal_embassy::init(systimer.alarm0);
|
esp_hal_embassy::init(systimer.alarm0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -65,8 +65,8 @@ async fn main(spawner: Spawner) -> ! {
|
|||||||
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
let timg1 = TimerGroup::new(peripherals.TIMG1);
|
||||||
esp_hal_embassy::init(timg1.timer0);
|
esp_hal_embassy::init(timg1.timer0);
|
||||||
} else {
|
} else {
|
||||||
use esp_hal::timer::systimer::{SystemTimer, Target};
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
esp_hal_embassy::init(systimer.alarm0);
|
esp_hal_embassy::init(systimer.alarm0);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@ -72,8 +72,7 @@ async fn main(_s: Spawner) {
|
|||||||
|
|
||||||
#[cfg(not(feature = "esp32"))]
|
#[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::<esp_hal::timer::systimer::Target>();
|
|
||||||
esp_hal_embassy::init(systimer.alarm0);
|
esp_hal_embassy::init(systimer.alarm0);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
@ -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()
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -31,10 +31,6 @@ harness = false
|
|||||||
name = "delay"
|
name = "delay"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "delay_async"
|
|
||||||
harness = false
|
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "dma_macros"
|
name = "dma_macros"
|
||||||
harness = false
|
harness = false
|
||||||
@ -111,10 +107,6 @@ harness = false
|
|||||||
name = "spi_slave"
|
name = "spi_slave"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "systimer"
|
|
||||||
harness = false
|
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "parl_io_tx"
|
name = "parl_io_tx"
|
||||||
harness = false
|
harness = false
|
||||||
@ -168,11 +160,6 @@ harness = false
|
|||||||
name = "uart_tx_rx_async"
|
name = "uart_tx_rx_async"
|
||||||
harness = false
|
harness = false
|
||||||
|
|
||||||
[[test]]
|
|
||||||
name = "embassy_timers_executors"
|
|
||||||
harness = false
|
|
||||||
required-features = ["embassy"]
|
|
||||||
|
|
||||||
[[test]]
|
[[test]]
|
||||||
name = "embassy_interrupt_executor"
|
name = "embassy_interrupt_executor"
|
||||||
harness = false
|
harness = false
|
||||||
|
|||||||
@ -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;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -73,8 +73,8 @@ mod test {
|
|||||||
AnyTimer::from(timg1.timer0),
|
AnyTimer::from(timg1.timer0),
|
||||||
]);
|
]);
|
||||||
} else if #[cfg(systimer)] {
|
} else if #[cfg(systimer)] {
|
||||||
use esp_hal::timer::systimer::{SystemTimer, Target};
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
esp_hal_embassy::init([
|
esp_hal_embassy::init([
|
||||||
AnyTimer::from(systimer.alarm0),
|
AnyTimer::from(systimer.alarm0),
|
||||||
AnyTimer::from(systimer.alarm1),
|
AnyTimer::from(systimer.alarm1),
|
||||||
|
|||||||
@ -87,8 +87,8 @@ mod test {
|
|||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(systimer)] {
|
if #[cfg(systimer)] {
|
||||||
use esp_hal::timer::systimer::{SystemTimer, Target};
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
esp_hal_embassy::init([
|
esp_hal_embassy::init([
|
||||||
AnyTimer::from(systimer.alarm0),
|
AnyTimer::from(systimer.alarm0),
|
||||||
AnyTimer::from(systimer.alarm1),
|
AnyTimer::from(systimer.alarm1),
|
||||||
@ -257,8 +257,8 @@ mod test {
|
|||||||
|
|
||||||
cfg_if::cfg_if! {
|
cfg_if::cfg_if! {
|
||||||
if #[cfg(systimer)] {
|
if #[cfg(systimer)] {
|
||||||
use esp_hal::timer::systimer::{SystemTimer, Target};
|
use esp_hal::timer::systimer::SystemTimer;
|
||||||
let systimer = SystemTimer::new(peripherals.SYSTIMER).split::<Target>();
|
let systimer = SystemTimer::new(peripherals.SYSTIMER);
|
||||||
esp_hal_embassy::init([
|
esp_hal_embassy::init([
|
||||||
AnyTimer::from(systimer.alarm0),
|
AnyTimer::from(systimer.alarm0),
|
||||||
AnyTimer::from(systimer.alarm1),
|
AnyTimer::from(systimer.alarm1),
|
||||||
|
|||||||
@ -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");
|
|
||||||
}
|
|
||||||
}
|
|
||||||
@ -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 {}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
Loading…
Reference in New Issue
Block a user