[2/3] Timer refactor: TIMG (#2581)

* 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

* Review feedback

* changelog and migration

* /unit_count/unit_value/g

* changelog and migration

* /unit_count/unit_value/g

* 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

* Make TimerGroup Timer's dumb and untyped

* changelog

* review

* review
This commit is contained in:
Scott Mabin 2024-11-22 16:14:14 +00:00 committed by GitHub
parent e98674e8fa
commit 79ca9d07aa
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
9 changed files with 145 additions and 726 deletions

View File

@ -75,12 +75,7 @@ trait IntoAnyTimer: Into<AnyTimer> {}
impl IntoAnyTimer for AnyTimer {}
impl<T, DM> IntoAnyTimer for TimgTimer<T, DM>
where
DM: esp_hal::Mode,
Self: Into<AnyTimer>,
{
}
impl IntoAnyTimer for TimgTimer where Self: Into<AnyTimer> {}
#[cfg(not(feature = "esp32"))]
impl IntoAnyTimer for Alarm where Self: Into<AnyTimer> {}

View File

@ -21,13 +21,13 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
- 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)
- `TIMGX` no longer uses peripheral ref (#2581)
- `SystemTimer::now` has been renamed `SystemTimer::unit_value(Unit)` (#2576)
- `dma::{Channel, ChannelRx, ChannelTx}::set_priority` for GDMA devices (#2403)
- `SystemTimer`s `Alarm`s are now type erased (#2576)
- `TimerGroup` `Timer`s are now type erased (#2581)
### Fixed

View File

@ -116,3 +116,12 @@ let systimer = SystemTimer::new(peripherals.SYSTIMER);
+ let mut timer = PeriodicTimer::new(alarm0);
+ timer.start(1u64.secs());
```
### TIMG
Timer group timers have been type erased.
```diff
- timg::Timer<timg::Timer0<crate::peripherals::TIMG0>, Blocking>
+ timg::Timer
```

View File

@ -33,10 +33,7 @@ mod imp {
},
};
#[cfg(any(timg0, timg1))]
pub use crate::timer::timg::{
Instance as _esp_hal_timer_timg_Instance,
TimerGroupInstance as _esp_hal_timer_timg_TimerGroupInstance,
};
pub use crate::timer::timg::TimerGroupInstance as _esp_hal_timer_timg_TimerGroupInstance;
#[cfg(any(systimer, timg0, timg1))]
pub use crate::timer::Timer as _esp_hal_timer_Timer;
pub use crate::{clock::CpuClock, entry, macros::*, InterruptConfigurable};

View File

@ -45,7 +45,6 @@ use fugit::{ExtU64, Instant, MicrosDurationU64};
use crate::{
interrupt::InterruptHandler,
peripheral::{Peripheral, PeripheralRef},
Blocking,
InterruptConfigurable,
};
@ -360,16 +359,7 @@ impl<T> embedded_hal_02::timer::Periodic for PeriodicTimer<'_, T> where T: Timer
/// An enum of all timer types
enum AnyTimerInner {
/// Timer 0 of the TIMG0 peripheral in blocking mode.
Timg0Timer0(timg::Timer<timg::Timer0<crate::peripherals::TIMG0>, Blocking>),
/// Timer 1 of the TIMG0 peripheral in blocking mode.
#[cfg(timg_timer1)]
Timg0Timer1(timg::Timer<timg::Timer1<crate::peripherals::TIMG0>, Blocking>),
/// Timer 0 of the TIMG1 peripheral in blocking mode.
#[cfg(timg1)]
Timg1Timer0(timg::Timer<timg::Timer0<crate::peripherals::TIMG1>, Blocking>),
/// Timer 1 of the TIMG1 peripheral in blocking mode.
#[cfg(all(timg1, timg_timer1))]
Timg1Timer1(timg::Timer<timg::Timer1<crate::peripherals::TIMG1>, Blocking>),
TimgTimer(timg::Timer),
/// Systimer Alarm
#[cfg(systimer)]
SystimerAlarm(systimer::Alarm),
@ -382,30 +372,9 @@ pub struct AnyTimer(AnyTimerInner);
impl crate::private::Sealed for AnyTimer {}
impl From<timg::Timer<timg::Timer0<crate::peripherals::TIMG0>, Blocking>> for AnyTimer {
fn from(value: timg::Timer<timg::Timer0<crate::peripherals::TIMG0>, Blocking>) -> Self {
Self(AnyTimerInner::Timg0Timer0(value))
}
}
#[cfg(timg_timer1)]
impl From<timg::Timer<timg::Timer1<crate::peripherals::TIMG0>, Blocking>> for AnyTimer {
fn from(value: timg::Timer<timg::Timer1<crate::peripherals::TIMG0>, Blocking>) -> Self {
Self(AnyTimerInner::Timg0Timer1(value))
}
}
#[cfg(timg1)]
impl From<timg::Timer<timg::Timer0<crate::peripherals::TIMG1>, Blocking>> for AnyTimer {
fn from(value: timg::Timer<timg::Timer0<crate::peripherals::TIMG1>, Blocking>) -> Self {
Self(AnyTimerInner::Timg1Timer0(value))
}
}
#[cfg(all(timg1, timg_timer1))]
impl From<timg::Timer<timg::Timer1<crate::peripherals::TIMG1>, Blocking>> for AnyTimer {
fn from(value: timg::Timer<timg::Timer1<crate::peripherals::TIMG1>, Blocking>) -> Self {
Self(AnyTimerInner::Timg1Timer1(value))
impl From<timg::Timer> for AnyTimer {
fn from(value: timg::Timer) -> Self {
Self(AnyTimerInner::TimgTimer(value))
}
}
@ -419,13 +388,7 @@ impl From<systimer::Alarm> for AnyTimer {
impl Timer for AnyTimer {
delegate::delegate! {
to match &self.0 {
AnyTimerInner::Timg0Timer0(inner) => inner,
#[cfg(timg_timer1)]
AnyTimerInner::Timg0Timer1(inner) => inner,
#[cfg(timg1)]
AnyTimerInner::Timg1Timer0(inner) => inner,
#[cfg(all(timg1,timg_timer1))]
AnyTimerInner::Timg1Timer1(inner) => inner,
AnyTimerInner::TimgTimer(inner) => inner,
#[cfg(systimer)]
AnyTimerInner::SystimerAlarm(inner) => inner,
} {

View File

@ -64,10 +64,7 @@
//! # }
//! ```
use core::{
marker::PhantomData,
ops::{Deref, DerefMut},
};
use core::marker::PhantomData;
use fugit::{HertzU32, Instant, MicrosDurationU64};
@ -77,15 +74,12 @@ use crate::soc::constants::TIMG_DEFAULT_CLK_SRC;
use crate::{
clock::Clocks,
interrupt::{self, InterruptHandler},
peripheral::{Peripheral, PeripheralRef},
peripheral::Peripheral,
peripherals::{timg0::RegisterBlock, Interrupt, TIMG0},
private::Sealed,
sync::{lock, Lock},
system::PeripheralClockControl,
Async,
Blocking,
InterruptConfigurable,
Mode,
};
const NUM_TIMG: usize = 1 + cfg!(timg1) as usize;
@ -96,17 +90,16 @@ static INT_ENA_LOCK: [Lock; NUM_TIMG] = [const { Lock::new() }; NUM_TIMG];
#[cfg_attr(not(timg_timer1), doc = "a general purpose timer")]
#[cfg_attr(timg_timer1, doc = "2 timers")]
/// and a watchdog timer.
pub struct TimerGroup<'d, T, DM>
pub struct TimerGroup<T>
where
T: TimerGroupInstance,
DM: Mode,
{
_timer_group: PeripheralRef<'d, T>,
_timer_group: PhantomData<T>,
/// Timer 0
pub timer0: Timer<Timer0<T>, DM>,
pub timer0: Timer,
/// Timer 1
#[cfg(timg_timer1)]
pub timer1: Timer<Timer1<T>, DM>,
pub timer1: Timer,
/// Watchdog timer
pub wdt: Wdt<T>,
}
@ -240,283 +233,69 @@ impl TimerGroupInstance for crate::peripherals::TIMG1 {
}
}
impl<'d, T, DM> TimerGroup<'d, T, DM>
impl<T> TimerGroup<T>
where
T: TimerGroupInstance,
DM: Mode,
{
/// Construct a new instance of [`TimerGroup`] in blocking mode
pub fn new_inner(_timer_group: impl Peripheral<P = T> + 'd) -> Self {
crate::into_ref!(_timer_group);
pub fn new(_timer_group: T) -> Self {
T::reset_peripheral();
T::enable_peripheral();
T::configure_src_clk();
let clocks = Clocks::get();
cfg_if::cfg_if! {
if #[cfg(esp32h2)] {
// ESP32-H2 is using PLL_48M_CLK source instead of APB_CLK
let apb_clk_freq = clocks.pll_48m_clock;
} else {
let apb_clk_freq = clocks.apb_clock;
}
}
let timer0 = Timer::new(
Timer0 {
phantom: PhantomData,
},
apb_clk_freq,
);
#[cfg(timg_timer1)]
let timer1 = Timer::new(
Timer1 {
phantom: PhantomData,
},
apb_clk_freq,
);
Self {
_timer_group,
timer0,
_timer_group: PhantomData,
timer0: Timer {
timer: 0,
tg: T::id(),
register_block: T::register_block(),
},
#[cfg(timg_timer1)]
timer1,
timer1: Timer {
timer: 1,
tg: T::id(),
register_block: T::register_block(),
},
wdt: Wdt::new(),
}
}
}
impl<'d, T> TimerGroup<'d, T, Blocking>
where
T: TimerGroupInstance,
{
/// Construct a new instance of [`TimerGroup`] in blocking mode
pub fn new(_timer_group: impl Peripheral<P = T> + 'd) -> Self {
Self::new_inner(_timer_group)
}
}
impl<'d, T> TimerGroup<'d, T, Async>
where
T: TimerGroupInstance,
{
/// Construct a new instance of [`TimerGroup`] in asynchronous mode
pub fn new_async(_timer_group: impl Peripheral<P = T> + 'd) -> Self {
match T::id() {
0 => {
use crate::timer::timg::asynch::timg0_timer0_handler;
unsafe {
interrupt::bind_interrupt(
Interrupt::TG0_T0_LEVEL,
timg0_timer0_handler.handler(),
);
interrupt::enable(Interrupt::TG0_T0_LEVEL, timg0_timer0_handler.priority())
.unwrap();
#[cfg(timg_timer1)]
{
use crate::timer::timg::asynch::timg0_timer1_handler;
interrupt::bind_interrupt(
Interrupt::TG0_T1_LEVEL,
timg0_timer1_handler.handler(),
);
interrupt::enable(Interrupt::TG0_T1_LEVEL, timg0_timer1_handler.priority())
.unwrap();
}
}
}
#[cfg(timg1)]
1 => {
use crate::timer::timg::asynch::timg1_timer0_handler;
unsafe {
{
interrupt::bind_interrupt(
Interrupt::TG1_T0_LEVEL,
timg1_timer0_handler.handler(),
);
interrupt::enable(Interrupt::TG1_T0_LEVEL, timg1_timer0_handler.priority())
.unwrap();
}
#[cfg(timg_timer1)]
{
use crate::timer::timg::asynch::timg1_timer1_handler;
interrupt::bind_interrupt(
Interrupt::TG1_T1_LEVEL,
timg1_timer1_handler.handler(),
);
interrupt::enable(Interrupt::TG1_T1_LEVEL, timg1_timer1_handler.priority())
.unwrap();
}
}
}
_ => unreachable!(),
}
Self::new_inner(_timer_group)
}
}
/// General-purpose timer.
pub struct Timer<T, DM>
where
DM: Mode,
{
timg: T,
apb_clk_freq: HertzU32,
phantom: PhantomData<DM>,
}
impl<T, DM> Timer<T, DM>
where
T: Instance,
DM: Mode,
{
/// Construct a new instance of [`Timer`]
pub fn new(timg: T, apb_clk_freq: HertzU32) -> Self {
timg.set_counter_active(true);
Self {
timg,
apb_clk_freq,
phantom: PhantomData,
}
}
/// Check if the timer has elapsed
pub fn has_elapsed(&mut self) -> bool {
if !self.timg.is_counter_active() {
panic!("Called wait on an inactive timer!")
}
if self.timg.is_interrupt_set() {
self.timg.clear_interrupt();
self.timg.set_alarm_active(true);
true
} else {
false
}
}
/// Block until the timer has elapsed.
pub fn wait(&mut self) {
while !self.has_elapsed() {}
}
}
impl<T, DM> Deref for Timer<T, DM>
where
T: Instance,
DM: Mode,
{
type Target = T;
fn deref(&self) -> &Self::Target {
&self.timg
}
}
impl<T, DM> DerefMut for Timer<T, DM>
where
T: Instance,
DM: Mode,
{
fn deref_mut(&mut self) -> &mut Self::Target {
&mut self.timg
}
}
impl<T, DM> Sealed for Timer<T, DM>
where
T: Instance,
DM: Mode,
{
}
impl<T, DM> super::Timer for Timer<T, DM>
where
T: Instance,
DM: Mode,
{
impl super::Timer for Timer {
fn start(&self) {
self.timg.set_counter_active(false);
self.timg.set_alarm_active(false);
self.set_counter_active(false);
self.set_alarm_active(false);
self.timg.reset_counter();
self.timg.set_counter_decrementing(false);
self.reset_counter();
self.set_counter_decrementing(false);
self.timg.set_counter_active(true);
self.timg.set_alarm_active(true);
self.set_counter_active(true);
self.set_alarm_active(true);
}
fn stop(&self) {
self.timg.set_counter_active(false);
self.set_counter_active(false);
}
fn reset(&self) {
let t = self.register_block().t(self.timer_number().into());
t.loadlo().write(|w| unsafe { w.load_lo().bits(0) });
t.loadhi().write(|w| unsafe { w.load_hi().bits(0) });
t.load().write(|w| unsafe { w.load().bits(1) });
self.reset_counter()
}
fn is_running(&self) -> bool {
self.register_block()
.t(self.timer_number().into())
.config()
.read()
.en()
.bit_is_set()
self.is_counter_active()
}
fn now(&self) -> Instant<u64, 1, 1_000_000> {
let t = self.register_block().t(self.timer_number().into());
t.update().write(|w| w.update().set_bit());
while t.update().read().update().bit_is_set() {
// Wait for the update to complete
}
let value_lo = t.lo().read().bits() as u64;
let value_hi = t.hi().read().bits() as u64;
let ticks = (value_hi << 32) | value_lo;
let micros = ticks_to_timeout(ticks, self.apb_clk_freq, self.timg.divider());
Instant::<u64, 1, 1_000_000>::from_ticks(micros)
self.now()
}
fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error> {
let ticks = timeout_to_ticks(value, self.apb_clk_freq, self.timg.divider());
// The counter is 54-bits wide, so we must ensure that the provided
// value is not too wide:
if (ticks & !0x3F_FFFF_FFFF_FFFF) != 0 {
return Err(Error::InvalidTimeout);
}
let high = (ticks >> 32) as u32;
let low = (ticks & 0xFFFF_FFFF) as u32;
let t = self.register_block().t(self.timer_number().into());
t.alarmlo().write(|w| unsafe { w.alarm_lo().bits(low) });
t.alarmhi().write(|w| unsafe { w.alarm_hi().bits(high) });
Ok(())
self.load_value(value)
}
fn enable_auto_reload(&self, auto_reload: bool) {
self.register_block()
.t(self.timer_number().into())
.config()
.modify(|_, w| w.autoreload().bit(auto_reload));
self.set_auto_reload(auto_reload)
}
fn enable_interrupt(&self, state: bool) {
@ -535,9 +314,7 @@ where
}
fn clear_interrupt(&self) {
self.register_block()
.int_clr()
.write(|w| w.t(self.timer_number()).clear_bit_by_one());
self.clear_interrupt()
}
fn set_interrupt_handler(&self, handler: InterruptHandler) {
@ -560,35 +337,15 @@ where
}
fn is_interrupt_set(&self) -> bool {
self.register_block()
.int_raw()
.read()
.t(self.timer_number())
.bit_is_set()
self.is_interrupt_set()
}
fn set_alarm_active(&self, state: bool) {
self.register_block()
.t(self.timer_number().into())
.config()
.modify(|_, w| w.alarm_en().bit(state));
self.set_alarm_active(state)
}
}
impl<T> InterruptConfigurable for Timer<T, Blocking>
where
T: Instance,
{
fn set_interrupt_handler(&mut self, handler: interrupt::InterruptHandler) {
<Self as super::Timer>::set_interrupt_handler(self, handler);
}
}
impl<T, DM> Peripheral for Timer<T, DM>
where
T: Instance,
DM: Mode,
{
impl Peripheral for Timer {
type P = Self;
#[inline]
@ -597,92 +354,41 @@ where
}
}
#[doc(hidden)]
pub trait Instance: Sealed {
fn register_block(&self) -> &RegisterBlock;
fn timer_group(&self) -> u8;
fn timer_number(&self) -> u8;
fn reset_counter(&self);
fn set_counter_active(&self, state: bool);
fn is_counter_active(&self) -> bool;
fn set_counter_decrementing(&self, decrementing: bool);
fn set_auto_reload(&self, auto_reload: bool);
fn set_alarm_active(&self, state: bool);
fn is_alarm_active(&self) -> bool;
fn load_alarm_value(&self, value: u64);
fn listen(&self);
fn unlisten(&self);
fn clear_interrupt(&self);
fn now(&self) -> u64;
fn divider(&self) -> u32;
fn set_divider(&self, divider: u16);
fn is_interrupt_set(&self) -> bool;
}
/// A timer within a Timer Group.
pub struct TimerX<TG, const T: u8 = 0> {
phantom: PhantomData<TG>,
pub struct Timer {
/// Pointer to the register block for this TimerGroup instance.
pub register_block: *const RegisterBlock,
/// The timer number inside the TimerGroup
pub timer: u8,
/// The TimerGroup number
pub tg: u8,
}
impl<TG, const T: u8> Sealed for TimerX<TG, T> {}
impl<TG, const T: u8> TimerX<TG, T>
where
TG: TimerGroupInstance,
{
/// Unsafely create an instance of this peripheral out of thin air.
///
/// # Safety
///
/// You must ensure that you're only using one instance of this type at a
/// time.
pub unsafe fn steal() -> Self {
Self {
phantom: PhantomData,
}
}
unsafe fn t() -> &'static crate::peripherals::timg0::T {
(*TG::register_block()).t(T as usize)
}
}
impl Sealed for Timer {}
unsafe impl Send for Timer {}
/// Timer peripheral instance
impl<TG, const T: u8> Instance for TimerX<TG, T>
where
TG: TimerGroupInstance,
{
impl Timer {
fn register_block(&self) -> &RegisterBlock {
unsafe { &*TG::register_block() }
unsafe { &*self.register_block }
}
fn timer_group(&self) -> u8 {
TG::id()
self.tg
}
fn timer_number(&self) -> u8 {
T
self.timer
}
fn t(&self) -> &crate::peripherals::timg0::T {
self.register_block().t(self.timer_number().into())
}
fn reset_counter(&self) {
let t = unsafe { Self::t() };
let t = self.t();
t.loadlo().write(|w| unsafe { w.load_lo().bits(0) });
t.loadhi().write(|w| unsafe { w.load_hi().bits(0) });
@ -691,91 +397,74 @@ where
}
fn set_counter_active(&self, state: bool) {
unsafe { Self::t() }
.config()
.modify(|_, w| w.en().bit(state));
self.t().config().modify(|_, w| w.en().bit(state));
}
fn is_counter_active(&self) -> bool {
unsafe { Self::t() }.config().read().en().bit_is_set()
self.t().config().read().en().bit_is_set()
}
fn set_counter_decrementing(&self, decrementing: bool) {
unsafe { Self::t() }
self.t()
.config()
.modify(|_, w| w.increase().bit(!decrementing));
}
fn set_auto_reload(&self, auto_reload: bool) {
unsafe { Self::t() }
self.t()
.config()
.modify(|_, w| w.autoreload().bit(auto_reload));
}
fn set_alarm_active(&self, state: bool) {
unsafe { Self::t() }
.config()
.modify(|_, w| w.alarm_en().bit(state));
self.t().config().modify(|_, w| w.alarm_en().bit(state));
}
fn is_alarm_active(&self) -> bool {
unsafe { Self::t() }.config().read().alarm_en().bit_is_set()
}
fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error> {
let ticks = timeout_to_ticks(value, Clocks::get().apb_clock, self.divider());
fn load_alarm_value(&self, value: u64) {
let value = value & 0x3F_FFFF_FFFF_FFFF;
let high = (value >> 32) as u32;
let low = (value & 0xFFFF_FFFF) as u32;
// The counter is 54-bits wide, so we must ensure that the provided
// value is not too wide:
if (ticks & !0x3F_FFFF_FFFF_FFFF) != 0 {
return Err(Error::InvalidTimeout);
}
let t = unsafe { Self::t() };
let high = (ticks >> 32) as u32;
let low = (ticks & 0xFFFF_FFFF) as u32;
let t = self.t();
t.alarmlo().write(|w| unsafe { w.alarm_lo().bits(low) });
t.alarmhi().write(|w| unsafe { w.alarm_hi().bits(high) });
}
fn listen(&self) {
// always use level interrupt
#[cfg(any(esp32, esp32s2))]
unsafe { Self::t() }
.config()
.modify(|_, w| w.level_int_en().set_bit());
lock(&INT_ENA_LOCK[self.timer_group() as usize], || {
self.register_block()
.int_ena()
.modify(|_, w| w.t(T).set_bit());
});
}
fn unlisten(&self) {
lock(&INT_ENA_LOCK[self.timer_group() as usize], || {
self.register_block()
.int_ena()
.modify(|_, w| w.t(T).clear_bit());
});
Ok(())
}
fn clear_interrupt(&self) {
self.register_block()
.int_clr()
.write(|w| w.t(T).clear_bit_by_one());
.write(|w| w.t(self.timer).clear_bit_by_one());
}
fn now(&self) -> u64 {
let t = unsafe { Self::t() };
fn now(&self) -> Instant<u64, 1, 1_000_000> {
let t = self.t();
t.update().write(|w| w.update().set_bit());
while t.update().read().update().bit_is_set() {}
while t.update().read().update().bit_is_set() {
// Wait for the update to complete
}
let value_lo = t.lo().read().bits() as u64;
let value_hi = (t.hi().read().bits() as u64) << 32;
let value_hi = t.hi().read().bits() as u64;
value_lo | value_hi
let ticks = (value_hi << 32) | value_lo;
let micros = ticks_to_timeout(ticks, Clocks::get().apb_clock, self.divider());
Instant::<u64, 1, 1_000_000>::from_ticks(micros)
}
fn divider(&self) -> u32 {
let t = unsafe { Self::t() };
let t = self.t();
// From the ESP32 TRM, "11.2.1 16­-bit Prescaler and Clock Selection":
//
@ -791,23 +480,14 @@ where
}
fn is_interrupt_set(&self) -> bool {
self.register_block().int_raw().read().t(T).bit_is_set()
}
fn set_divider(&self, divider: u16) {
unsafe { Self::t() }
.config()
.modify(|_, w| unsafe { w.divider().bits(divider) });
self.register_block()
.int_raw()
.read()
.t(self.timer)
.bit_is_set()
}
}
/// Timer 0 in the Timer Group.
pub type Timer0<TG> = TimerX<TG, 0>;
/// Timer 1 in the Timer Group.
#[cfg(timg_timer1)]
pub type Timer1<TG> = TimerX<TG, 1>;
fn ticks_to_timeout<F>(ticks: u64, clock: F, divider: u32) -> u64
where
F: Into<HertzU32>,
@ -836,57 +516,6 @@ where
(1_000_000 * micros / period as u64) as u64
}
impl<T, DM> embedded_hal_02::timer::CountDown for Timer<T, DM>
where
T: Instance + super::Timer,
DM: Mode,
{
type Time = MicrosDurationU64;
fn start<Time>(&mut self, timeout: Time)
where
Time: Into<Self::Time>,
{
self.timg.load_value(timeout.into()).unwrap();
self.timg.start();
}
fn wait(&mut self) -> nb::Result<(), void::Void> {
if self.has_elapsed() {
Ok(())
} else {
Err(nb::Error::WouldBlock)
}
}
}
impl<T, DM> embedded_hal_02::timer::Cancel for Timer<T, DM>
where
T: Instance + super::Timer,
DM: Mode,
{
type Error = super::Error;
fn cancel(&mut self) -> Result<(), super::Error> {
if !self.timg.is_counter_active() {
return Err(super::Error::TimerInactive);
} else if !self.timg.is_alarm_active() {
return Err(super::Error::AlarmInactive);
}
self.timg.set_counter_active(false);
Ok(())
}
}
impl<T, DM> embedded_hal_02::timer::Periodic for Timer<T, DM>
where
T: Instance + super::Timer,
DM: Mode,
{
}
/// Behavior of the MWDT stage if it times out.
#[allow(unused)]
#[derive(Debug, Clone, Copy)]
@ -1153,6 +782,7 @@ where
// Async functionality of the timer groups.
mod asynch {
#![allow(unused)] // FIXME(mabez)
use core::{
pin::Pin,
task::{Context, Poll},
@ -1175,18 +805,12 @@ mod asynch {
static WAKERS: [AtomicWaker; NUM_WAKERS] = [const { AtomicWaker::new() }; NUM_WAKERS];
pub(crate) struct TimerFuture<'a, T>
where
T: Instance,
{
timer: &'a Timer<T, crate::Async>,
pub(crate) struct TimerFuture<'a> {
timer: &'a Timer,
}
impl<'a, T> TimerFuture<'a, T>
where
T: Instance,
{
pub(crate) fn new(timer: &'a Timer<T, crate::Async>) -> Self {
impl<'a> TimerFuture<'a> {
pub(crate) fn new(timer: &'a Timer) -> Self {
use crate::timer::Timer;
timer.enable_interrupt(true);
@ -1204,10 +828,7 @@ mod asynch {
}
}
impl<T> core::future::Future for TimerFuture<'_, T>
where
T: Instance,
{
impl core::future::Future for TimerFuture<'_> {
type Output = ();
fn poll(self: Pin<&mut Self>, ctx: &mut Context<'_>) -> Poll<Self::Output> {
@ -1222,35 +843,16 @@ mod asynch {
}
}
impl<T> Drop for TimerFuture<'_, T>
where
T: Instance,
{
impl Drop for TimerFuture<'_> {
fn drop(&mut self) {
self.timer.clear_interrupt();
}
}
impl<T> embedded_hal_async::delay::DelayNs for Timer<T, crate::Async>
where
T: Instance,
{
async fn delay_ns(&mut self, ns: u32) {
use crate::timer::Timer as _;
let period = MicrosDurationU64::from_ticks(ns.div_ceil(1000) as u64);
self.load_value(period).unwrap();
self.start();
self.listen();
TimerFuture::new(self).await;
}
}
// INT_ENA means that when the interrupt occurs, it will show up in the INT_ST.
// Clearing INT_ENA that it won't show up on INT_ST but if interrupt is
// already there, it won't clear it - that's why we need to clear the INT_CLR as
// well.
// INT_ENA means that when the interrupt occurs, it will show up in the
// INT_ST. Clearing INT_ENA that it won't show up on INT_ST but if
// interrupt is already there, it won't clear it - that's why we need to
// clear the INT_CLR as well.
#[handler]
pub(crate) fn timg0_timer0_handler() {
lock(&INT_ENA_LOCK[0], || {
@ -1346,13 +948,13 @@ pub mod etm {
impl Sealed for Task {}
/// General purpose timer ETM events.
pub trait Events<TG> {
pub trait Events {
/// ETM event triggered on alarm
fn on_alarm(&self) -> Event;
}
/// General purpose timer ETM tasks
pub trait Tasks<TG> {
pub trait Tasks {
/// ETM task to start the counter
fn cnt_start(&self) -> Task;
@ -1370,37 +972,43 @@ pub mod etm {
fn alarm_start(&self) -> Task;
}
impl<TG> Events<TG> for Timer0<TG>
where
TG: TimerGroupInstance,
{
impl Events for Timer {
fn on_alarm(&self) -> Event {
Event { id: 48 + TG::id() }
Event {
id: 48 + self.timer_group(),
}
}
}
impl<TG> Tasks<TG> for Timer0<TG>
where
TG: TimerGroupInstance,
{
impl Tasks for Timer {
fn cnt_start(&self) -> Task {
Task { id: 88 + TG::id() }
Task {
id: 88 + self.timer_group(),
}
}
fn alarm_start(&self) -> Task {
Task { id: 90 + TG::id() }
Task {
id: 90 + self.timer_group(),
}
}
fn cnt_stop(&self) -> Task {
Task { id: 92 + TG::id() }
Task {
id: 92 + self.timer_group(),
}
}
fn cnt_reload(&self) -> Task {
Task { id: 94 + TG::id() }
Task {
id: 94 + self.timer_group(),
}
}
fn cnt_cap(&self) -> Task {
Task { id: 96 + TG::id() }
Task {
id: 96 + self.timer_group(),
}
}
}
}

View File

@ -285,12 +285,7 @@ pub trait EspWifiTimerSource: private::Sealed {
/// conflicting implementations.
trait IntoAnyTimer: Into<AnyTimer> {}
impl<T, DM> IntoAnyTimer for TimgTimer<T, DM>
where
DM: esp_hal::Mode,
Self: Into<AnyTimer>,
{
}
impl IntoAnyTimer for TimgTimer where Self: Into<AnyTimer> {}
#[cfg(not(feature = "esp32"))]
impl IntoAnyTimer for Alarm where Self: Into<AnyTimer> {}
@ -314,12 +309,7 @@ impl EspWifiTimerSource for TimeBase {
}
impl private::Sealed for TimeBase {}
impl<T, DM> private::Sealed for TimgTimer<T, DM>
where
DM: esp_hal::Mode,
Self: Into<AnyTimer>,
{
}
impl private::Sealed for TimgTimer where Self: Into<AnyTimer> {}
#[cfg(not(feature = "esp32"))]
impl private::Sealed for Alarm where Self: Into<AnyTimer> {}

View File

@ -1,84 +0,0 @@
//! This shows how to use the general purpose timers ETM tasks and events
//! Notice you need to import the traits esp_hal::timer::etm::{Events, Tasks}
//% CHIPS: esp32c6 esp32h2
#![no_std]
#![no_main]
use core::cell::RefCell;
use critical_section::Mutex;
use esp_backtrace as _;
use esp_hal::{
delay::Delay,
etm::Etm,
peripherals::TIMG0,
prelude::*,
timer::timg::{
etm::{Events, Tasks},
Timer,
Timer0,
TimerGroup,
},
};
static TIMER0: Mutex<RefCell<Option<Timer<Timer0<TIMG0>, esp_hal::Blocking>>>> =
Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
let peripherals = esp_hal::init(esp_hal::Config::default());
let timg0 = TimerGroup::new(peripherals.TIMG0);
let timer0 = timg0.timer0;
timer0.set_interrupt_handler(tg0_t0_level);
// Configure ETM to stop timer0 when alarm is triggered
let event = timer0.on_alarm();
let task = timer0.cnt_stop();
let etm = Etm::new(peripherals.SOC_ETM);
let channel0 = etm.channel0;
let _configured_channel = channel0.setup(&event, &task);
// Setup alarm at 100ms
// 80 / 2 (default divider) timer clock cycles == 1 us
timer0.load_alarm_value(100 * 1_000 * 40);
timer0.set_alarm_active(true);
timer0.set_counter_active(true);
critical_section::with(|cs| {
timer0.listen();
TIMER0.borrow_ref_mut(cs).replace(timer0);
});
let delay = Delay::new();
loop {
delay.delay_millis(500u32);
critical_section::with(|cs| {
let mut timer0 = TIMER0.borrow_ref_mut(cs);
let timer0 = timer0.as_mut().unwrap();
// Counter value should be the same than in interrupt
esp_println::println!("counter in main: {}", timer0.now());
});
}
}
#[handler]
fn tg0_t0_level() {
critical_section::with(|cs| {
let mut timer0 = TIMER0.borrow_ref_mut(cs);
let timer0 = timer0.as_mut().unwrap();
timer0.clear_interrupt();
// Counter value should be a very small number as the alarm triggered a counter reload to 0
// and ETM stopped the counter quickly after
esp_println::println!("counter in interrupt: {}", timer0.now());
});
}

View File

@ -1,59 +0,0 @@
//! This shows how to use the TIMG peripheral interrupts.
//!
//! There is TIMG0 which contains a general purpose timer and a watchdog timer.
//% CHIPS: esp32 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::{
interrupt::{self, Priority},
peripherals::{Interrupt, TIMG0},
prelude::*,
timer::timg::{Timer, Timer0, TimerGroup},
};
static TIMER0: Mutex<RefCell<Option<Timer<Timer0<TIMG0>, esp_hal::Blocking>>>> =
Mutex::new(RefCell::new(None));
#[entry]
fn main() -> ! {
let peripherals = esp_hal::init(esp_hal::Config::default());
let timg0 = TimerGroup::new(peripherals.TIMG0);
let timer0 = timg0.timer0;
timer0.set_interrupt_handler(tg0_t0_level);
interrupt::enable(Interrupt::TG0_T0_LEVEL, Priority::Priority1).unwrap();
timer0.load_value(500u64.millis()).unwrap();
timer0.start();
timer0.listen();
critical_section::with(|cs| {
TIMER0.borrow_ref_mut(cs).replace(timer0);
});
loop {}
}
#[handler]
fn tg0_t0_level() {
critical_section::with(|cs| {
esp_println::println!(
"Interrupt at {} ms",
esp_hal::time::now().duration_since_epoch().to_millis()
);
let mut timer0 = TIMER0.borrow_ref_mut(cs);
let timer0 = timer0.as_mut().unwrap();
timer0.clear_interrupt();
timer0.load_value(500u64.millis()).unwrap();
timer0.start();
});
}