diff --git a/esp-hal-embassy/src/lib.rs b/esp-hal-embassy/src/lib.rs index 5efbd02fb5..e2de84fcc9 100644 --- a/esp-hal-embassy/src/lib.rs +++ b/esp-hal-embassy/src/lib.rs @@ -75,12 +75,7 @@ trait IntoAnyTimer: Into {} impl IntoAnyTimer for AnyTimer {} -impl IntoAnyTimer for TimgTimer -where - DM: esp_hal::Mode, - Self: Into, -{ -} +impl IntoAnyTimer for TimgTimer where Self: Into {} #[cfg(not(feature = "esp32"))] impl IntoAnyTimer for Alarm where Self: Into {} diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index b058fffe6a..3353620d89 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -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 diff --git a/esp-hal/MIGRATING-0.22.md b/esp-hal/MIGRATING-0.22.md index 1e930faaee..8c18db3f46 100644 --- a/esp-hal/MIGRATING-0.22.md +++ b/esp-hal/MIGRATING-0.22.md @@ -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, Blocking> ++ timg::Timer +``` diff --git a/esp-hal/src/prelude.rs b/esp-hal/src/prelude.rs index 00dc7acb93..9824f700b0 100644 --- a/esp-hal/src/prelude.rs +++ b/esp-hal/src/prelude.rs @@ -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}; diff --git a/esp-hal/src/timer/mod.rs b/esp-hal/src/timer/mod.rs index e9c02ac10e..a05138a135 100644 --- a/esp-hal/src/timer/mod.rs +++ b/esp-hal/src/timer/mod.rs @@ -45,7 +45,6 @@ use fugit::{ExtU64, Instant, MicrosDurationU64}; use crate::{ interrupt::InterruptHandler, peripheral::{Peripheral, PeripheralRef}, - Blocking, InterruptConfigurable, }; @@ -360,16 +359,7 @@ impl 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, Blocking>), - /// Timer 1 of the TIMG0 peripheral in blocking mode. - #[cfg(timg_timer1)] - Timg0Timer1(timg::Timer, Blocking>), - /// Timer 0 of the TIMG1 peripheral in blocking mode. - #[cfg(timg1)] - Timg1Timer0(timg::Timer, Blocking>), - /// Timer 1 of the TIMG1 peripheral in blocking mode. - #[cfg(all(timg1, timg_timer1))] - Timg1Timer1(timg::Timer, 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, Blocking>> for AnyTimer { - fn from(value: timg::Timer, Blocking>) -> Self { - Self(AnyTimerInner::Timg0Timer0(value)) - } -} - -#[cfg(timg_timer1)] -impl From, Blocking>> for AnyTimer { - fn from(value: timg::Timer, Blocking>) -> Self { - Self(AnyTimerInner::Timg0Timer1(value)) - } -} - -#[cfg(timg1)] -impl From, Blocking>> for AnyTimer { - fn from(value: timg::Timer, Blocking>) -> Self { - Self(AnyTimerInner::Timg1Timer0(value)) - } -} - -#[cfg(all(timg1, timg_timer1))] -impl From, Blocking>> for AnyTimer { - fn from(value: timg::Timer, Blocking>) -> Self { - Self(AnyTimerInner::Timg1Timer1(value)) +impl From for AnyTimer { + fn from(value: timg::Timer) -> Self { + Self(AnyTimerInner::TimgTimer(value)) } } @@ -419,13 +388,7 @@ impl From 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, } { diff --git a/esp-hal/src/timer/timg.rs b/esp-hal/src/timer/timg.rs index bcbfc61939..ab20836afb 100644 --- a/esp-hal/src/timer/timg.rs +++ b/esp-hal/src/timer/timg.rs @@ -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 where T: TimerGroupInstance, - DM: Mode, { - _timer_group: PeripheralRef<'d, T>, + _timer_group: PhantomData, /// Timer 0 - pub timer0: Timer, DM>, + pub timer0: Timer, /// Timer 1 #[cfg(timg_timer1)] - pub timer1: Timer, DM>, + pub timer1: Timer, /// Watchdog timer pub wdt: Wdt, } @@ -240,283 +233,69 @@ impl TimerGroupInstance for crate::peripherals::TIMG1 { } } -impl<'d, T, DM> TimerGroup<'d, T, DM> +impl TimerGroup where T: TimerGroupInstance, - DM: Mode, { /// Construct a new instance of [`TimerGroup`] in blocking mode - pub fn new_inner(_timer_group: impl Peripheral

+ '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

+ '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

+ '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 -where - DM: Mode, -{ - timg: T, - apb_clk_freq: HertzU32, - phantom: PhantomData, -} - -impl Timer -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 Deref for Timer -where - T: Instance, - DM: Mode, -{ - type Target = T; - - fn deref(&self) -> &Self::Target { - &self.timg - } -} - -impl DerefMut for Timer -where - T: Instance, - DM: Mode, -{ - fn deref_mut(&mut self) -> &mut Self::Target { - &mut self.timg - } -} - -impl Sealed for Timer -where - T: Instance, - DM: Mode, -{ -} - -impl super::Timer for Timer -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 { - 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::::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 InterruptConfigurable for Timer -where - T: Instance, -{ - fn set_interrupt_handler(&mut self, handler: interrupt::InterruptHandler) { - ::set_interrupt_handler(self, handler); - } -} - -impl Peripheral for Timer -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 { - phantom: PhantomData, -} +pub struct Timer { + /// Pointer to the register block for this TimerGroup instance. + pub register_block: *const RegisterBlock, -impl Sealed for TimerX {} + /// The timer number inside the TimerGroup + pub timer: u8, -impl TimerX -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) - } + /// The TimerGroup number + pub tg: u8, } +impl Sealed for Timer {} +unsafe impl Send for Timer {} + /// Timer peripheral instance -impl Instance for TimerX -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 high = (ticks >> 32) as u32; + let low = (ticks & 0xFFFF_FFFF) as u32; - let t = unsafe { Self::t() }; + 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 { + 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::::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 = TimerX; - -/// Timer 1 in the Timer Group. -#[cfg(timg_timer1)] -pub type Timer1 = TimerX; - fn ticks_to_timeout(ticks: u64, clock: F, divider: u32) -> u64 where F: Into, @@ -836,57 +516,6 @@ where (1_000_000 * micros / period as u64) as u64 } -impl embedded_hal_02::timer::CountDown for Timer -where - T: Instance + super::Timer, - DM: Mode, -{ - type Time = MicrosDurationU64; - - fn start