[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"))]
|
||||
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
|
||||
|
||||
@ -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
|
||||
|
||||
|
||||
@ -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());
|
||||
```
|
||||
|
||||
@ -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)
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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()
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
@ -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 {}
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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);
|
||||
|
||||
@ -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},
|
||||
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);
|
||||
|
||||
@ -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);
|
||||
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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
@ -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);
|
||||
}
|
||||
|
||||
|
||||
@ -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"
|
||||
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
|
||||
|
||||
@ -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),
|
||||
]);
|
||||
} 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),
|
||||
|
||||
@ -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),
|
||||
|
||||
@ -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