diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index 47734e434b9..31797fc802d 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -42,6 +42,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - Changed the parameters of `Spi::with_pins` to no longer be optional (#2133) - Renamed `DummyPin` to `NoPin` and removed all internal logic from it. (#2133) - The `NO_PIN` constant has been removed. (#2133) +- `PeriodicTimer` and `OneShotTimer` are now type-erased by default. Use the new `new_typed` constructor to keep using the ZST pin types. (#?) ### Fixed diff --git a/esp-hal/MIGRATING-0.20.md b/esp-hal/MIGRATING-0.20.md index 1e6c6509e2c..2e5277fc05a 100644 --- a/esp-hal/MIGRATING-0.20.md +++ b/esp-hal/MIGRATING-0.20.md @@ -112,6 +112,18 @@ have been removed. Use `new` or `new_async` instead. The `ErasedTimer` has been renamed to `AnyTimer`. +### Type-erased timers + +`PeriodicTimer` and `OneShotTimer` are now type-erased by default. This unfortunately requires the +timer to implement `Into`. In case you want to use a timer that does not (for example +because you've used the async timer APIs of the same instance before), you can use the `new_typed` +constructor. + +```rust +let timer = PeriodicTimer::new(timg0.timer0); // timer will have the type `PeriodicTimer<'some>` (or `PeriodicTimer<'some, AnyTimer>` if you want to be explicit about it) +let timer = PeriodicTimer::new_typed(timg0.timer0); // timer will have the type `PeriodicTimer<'some, Timer, Blocking>>` +``` + ### `esp_hal::time::current_time` rename To avoid confusion with the `Rtc::current_time` wall clock time APIs, we've renamed `esp_hal::time::current_time` to `esp_hal::time::now()`. diff --git a/esp-hal/src/timer/mod.rs b/esp-hal/src/timer/mod.rs index e9134357f1d..295bd69f7fa 100644 --- a/esp-hal/src/timer/mod.rs +++ b/esp-hal/src/timer/mod.rs @@ -111,16 +111,26 @@ pub trait Timer: crate::private::Sealed { } /// A one-shot timer. -pub struct OneShotTimer<'d, T> { +pub struct OneShotTimer<'d, T = AnyTimer> { inner: PeripheralRef<'d, T>, } +impl<'d> OneShotTimer<'d, AnyTimer> { + /// Construct a new instance of [`OneShotTimer`] with the timer + /// type-erased. + pub fn new>(mut inner: impl Peripheral

+ 'd) -> Self { + let inner = unsafe { inner.clone_unchecked() }.into(); + + Self::new_typed(inner) + } +} + impl<'d, T> OneShotTimer<'d, T> where T: Timer, { /// Construct a new instance of [`OneShotTimer`]. - pub fn new(inner: impl Peripheral

+ 'd) -> Self { + pub fn new_typed(inner: impl Peripheral

+ 'd) -> Self { crate::into_ref!(inner); Self { inner } @@ -242,16 +252,26 @@ where } /// A periodic timer. -pub struct PeriodicTimer<'d, T> { +pub struct PeriodicTimer<'d, T = AnyTimer> { inner: PeripheralRef<'d, T>, } +impl<'d> PeriodicTimer<'d, AnyTimer> { + /// Construct a new instance of [`PeriodicTimer`] with the timer + /// type-erased. + pub fn new>(mut inner: impl Peripheral

+ 'd) -> Self { + let inner = unsafe { inner.clone_unchecked() }.into(); + + Self::new_typed(inner) + } +} + impl<'d, T> PeriodicTimer<'d, T> where T: Timer, { /// Construct a new instance of [`PeriodicTimer`]. - pub fn new(inner: impl Peripheral

+ 'd) -> Self { + pub fn new_typed(inner: impl Peripheral

+ 'd) -> Self { crate::into_ref!(inner); Self { inner } @@ -357,25 +377,79 @@ where impl<'d, T> embedded_hal_02::timer::Periodic for PeriodicTimer<'d, 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. +macro_rules! any_timer { + ($ty:path => $var:ident) => { + impl $ty { + /// Convert this timer into an [`AnyTimer`]. + pub fn degrade(self) -> AnyTimer { + AnyTimer(AnyTimerInner::$var(self)) + } + } + + impl From<$ty> for AnyTimer { + fn from(value: $ty) -> Self { + value.degrade() + } + } + }; + + ( + $( + $(#[$cfg:meta])? + $ty:path => $var:ident, + )* + ) => { + /// An enum of all timer types + enum AnyTimerInner { + $( + $(#[$cfg])? + $var($ty), + )* + } + + $( + $(#[$cfg])? + any_timer!($ty => $var); + )* + + impl Timer for AnyTimer { + delegate::delegate! { + to match &self.0 { + $( + $(#[$cfg])? + AnyTimerInner::$var(inner) => inner, + )* + } { + fn start(&self); + fn stop(&self); + fn reset(&self); + fn is_running(&self) -> bool; + fn now(&self) -> Instant; + fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error>; + fn enable_auto_reload(&self, auto_reload: bool); + fn enable_interrupt(&self, state: bool); + fn clear_interrupt(&self); + fn set_interrupt_handler(&self, handler: InterruptHandler); + fn is_interrupt_set(&self) -> bool; + fn set_alarm_active(&self, state: bool); + } + } + } + }; +} + +any_timer! { + timg::Timer, Blocking> => Timg0Timer0, #[cfg(timg_timer1)] - Timg0Timer1(timg::Timer, Blocking>), - /// Timer 0 of the TIMG1 peripheral in blocking mode. + timg::Timer, Blocking> => Timg0Timer1, #[cfg(timg1)] - Timg1Timer0(timg::Timer, Blocking>), - /// Timer 1 of the TIMG1 peripheral in blocking mode. + timg::Timer, Blocking> => Timg1Timer0, #[cfg(all(timg1, timg_timer1))] - Timg1Timer1(timg::Timer, Blocking>), - /// Systimer Alarm in periodic mode with blocking behavior. + timg::Timer, Blocking> => Timg1Timer1, #[cfg(systimer)] - SystimerAlarmPeriodic(systimer::Alarm<'static, systimer::Periodic, Blocking>), - /// Systimer Target in periodic mode with blocking behavior. + systimer::Alarm<'static, systimer::Periodic, Blocking> => SystimerAlarmPeriodic, #[cfg(systimer)] - SystimerAlarmTarget(systimer::Alarm<'static, systimer::Target, Blocking>), + systimer::Alarm<'static, systimer::Target, Blocking> => SystimerAlarmTarget, } /// A type-erased timer @@ -385,78 +459,6 @@ 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)) - } -} - -#[cfg(systimer)] -impl From> for AnyTimer { - fn from(value: systimer::Alarm<'static, systimer::Periodic, Blocking>) -> Self { - Self(AnyTimerInner::SystimerAlarmPeriodic(value)) - } -} - -#[cfg(systimer)] -impl From> for AnyTimer { - fn from(value: systimer::Alarm<'static, systimer::Target, Blocking>) -> Self { - Self(AnyTimerInner::SystimerAlarmTarget(value)) - } -} - -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, - #[cfg(systimer)] - AnyTimerInner::SystimerAlarmPeriodic(inner) => inner, - #[cfg(systimer)] - AnyTimerInner::SystimerAlarmTarget(inner) => inner, - } { - fn start(&self); - fn stop(&self); - fn reset(&self); - fn is_running(&self) -> bool; - fn now(&self) -> Instant; - fn load_value(&self, value: MicrosDurationU64) -> Result<(), Error>; - fn enable_auto_reload(&self, auto_reload: bool); - fn enable_interrupt(&self, state: bool); - fn clear_interrupt(&self); - fn set_interrupt_handler(&self, handler: InterruptHandler); - fn is_interrupt_set(&self) -> bool; - fn set_alarm_active(&self, state: bool); - } - } -} - impl Peripheral for AnyTimer { type P = Self; diff --git a/examples/src/bin/embassy_multicore.rs b/examples/src/bin/embassy_multicore.rs index 8ca327d018b..677f91adebe 100644 --- a/examples/src/bin/embassy_multicore.rs +++ b/examples/src/bin/embassy_multicore.rs @@ -22,7 +22,7 @@ use esp_hal::{ cpu_control::{CpuControl, Stack}, get_core, gpio::{Io, Level, Output, Pin}, - timer::{timg::TimerGroup, AnyTimer}, + timer::timg::TimerGroup, }; use esp_hal_embassy::Executor; use esp_println::println; @@ -56,9 +56,7 @@ async fn main(_spawner: Spawner) { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let timg0 = TimerGroup::new(peripherals.TIMG0); - let timer0: AnyTimer = timg0.timer0.into(); - let timer1: AnyTimer = timg0.timer1.into(); - esp_hal_embassy::init([timer0, timer1]); + esp_hal_embassy::init([timg0.timer0.degrade(), timg0.timer1.degrade()]); let mut cpu_control = CpuControl::new(peripherals.CPU_CTRL); diff --git a/examples/src/bin/embassy_multicore_interrupt.rs b/examples/src/bin/embassy_multicore_interrupt.rs index a4c2cbf2665..339f8e16121 100644 --- a/examples/src/bin/embassy_multicore_interrupt.rs +++ b/examples/src/bin/embassy_multicore_interrupt.rs @@ -23,7 +23,7 @@ use esp_hal::{ gpio::{Io, Level, Output, Pin}, interrupt::{software::SoftwareInterruptControl, Priority}, prelude::*, - timer::{timg::TimerGroup, AnyTimer}, + timer::timg::TimerGroup, }; use esp_hal_embassy::InterruptExecutor; use esp_println::println; @@ -78,9 +78,7 @@ fn main() -> ! { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let timg0 = TimerGroup::new(peripherals.TIMG0); - let timer0: AnyTimer = timg0.timer0.into(); - let timer1: AnyTimer = timg0.timer1.into(); - esp_hal_embassy::init([timer0, timer1]); + esp_hal_embassy::init([timg0.timer0.degrade(), timg0.timer1.degrade()]); let mut cpu_control = CpuControl::new(peripherals.CPU_CTRL); diff --git a/examples/src/bin/embassy_multiprio.rs b/examples/src/bin/embassy_multiprio.rs index 2a4f5de8a4f..4e555eb2e5b 100644 --- a/examples/src/bin/embassy_multiprio.rs +++ b/examples/src/bin/embassy_multiprio.rs @@ -25,7 +25,7 @@ use embassy_time::{Duration, Instant, Ticker, Timer}; use esp_backtrace as _; use esp_hal::{ interrupt::{software::SoftwareInterruptControl, Priority}, - timer::{timg::TimerGroup, AnyTimer}, + timer::timg::TimerGroup, }; use esp_hal_embassy::InterruptExecutor; use esp_println::println; @@ -76,20 +76,19 @@ async fn main(low_prio_spawner: Spawner) { let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT); let timg0 = TimerGroup::new(peripherals.TIMG0); - let timer0: AnyTimer = timg0.timer0.into(); cfg_if::cfg_if! { if #[cfg(feature = "esp32c2")] { use esp_hal::timer::systimer::{SystemTimer, Target}; let systimer = SystemTimer::new(peripherals.SYSTIMER).split::(); - let timer1: AnyTimer = systimer.alarm0.into(); + let timer1 = systimer.alarm0; } else { let timg1 = TimerGroup::new(peripherals.TIMG1); - let timer1: AnyTimer = timg1.timer0.into(); + let timer1 = timg1.timer0; } } - esp_hal_embassy::init([timer0, timer1]); + esp_hal_embassy::init([timg0.timer0.degrade(), timer1.degrade()]); static EXECUTOR: StaticCell> = StaticCell::new(); let executor = InterruptExecutor::new(sw_ints.software_interrupt2); diff --git a/examples/src/bin/wifi_80211_tx.rs b/examples/src/bin/wifi_80211_tx.rs index cc607b2d258..0fa98bddcae 100644 --- a/examples/src/bin/wifi_80211_tx.rs +++ b/examples/src/bin/wifi_80211_tx.rs @@ -12,12 +12,7 @@ use core::marker::PhantomData; use esp_alloc as _; use esp_backtrace as _; -use esp_hal::{ - delay::Delay, - prelude::*, - rng::Rng, - timer::{timg::TimerGroup, AnyTimer, PeriodicTimer}, -}; +use esp_hal::{delay::Delay, prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_wifi::{initialize, wifi, EspWifiInitFor}; use ieee80211::{ common::{CapabilitiesInformation, FCFFlags}, @@ -46,12 +41,9 @@ fn main() -> ! { let delay = Delay::new(); let timg0 = TimerGroup::new(peripherals.TIMG0); - let timer0: AnyTimer = timg0.timer0.into(); - let timer = PeriodicTimer::new(timer0); - let init = initialize( EspWifiInitFor::Wifi, - timer, + timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, ) diff --git a/examples/src/bin/wifi_sniffer.rs b/examples/src/bin/wifi_sniffer.rs index 0bf84b4d333..f9376ce3214 100644 --- a/examples/src/bin/wifi_sniffer.rs +++ b/examples/src/bin/wifi_sniffer.rs @@ -18,11 +18,7 @@ use core::cell::RefCell; use critical_section::Mutex; use esp_backtrace as _; -use esp_hal::{ - prelude::*, - rng::Rng, - timer::{timg::TimerGroup, AnyTimer, PeriodicTimer}, -}; +use esp_hal::{prelude::*, rng::Rng, timer::timg::TimerGroup}; use esp_println::println; use esp_wifi::{initialize, wifi, EspWifiInitFor}; use ieee80211::{match_frames, mgmt_frame::BeaconFrame}; @@ -41,12 +37,9 @@ fn main() -> ! { esp_alloc::heap_allocator!(72 * 1024); let timg0 = TimerGroup::new(peripherals.TIMG0); - let timer0: AnyTimer = timg0.timer0.into(); - let timer = PeriodicTimer::new(timer0); - let init = initialize( EspWifiInitFor::Wifi, - timer, + timg0.timer0, Rng::new(peripherals.RNG), peripherals.RADIO_CLK, ) diff --git a/hil-test/tests/embassy_timers_executors.rs b/hil-test/tests/embassy_timers_executors.rs index 24cb26954d9..23a943c382c 100644 --- a/hil-test/tests/embassy_timers_executors.rs +++ b/hil-test/tests/embassy_timers_executors.rs @@ -64,7 +64,7 @@ mod test_cases { } pub fn run_test_periodic_timer(timer: impl Peripheral

) { - let mut periodic = PeriodicTimer::new(timer); + let mut periodic = PeriodicTimer::new_typed(timer); let t1 = esp_hal::time::now(); periodic.start(100.millis()).unwrap(); @@ -81,7 +81,7 @@ mod test_cases { } pub fn run_test_oneshot_timer(timer: impl Peripheral

) { - let timer = OneShotTimer::new(timer); + let timer = OneShotTimer::new_typed(timer); let t1 = esp_hal::time::now(); timer.delay_millis(50); @@ -216,12 +216,9 @@ mod test { #[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::(); - let alarm0: AnyTimer = systimer.alarm0.into(); - esp_hal_embassy::init([timer0, alarm0]); + esp_hal_embassy::init([timg0.timer0.degrade(), systimer.alarm0.degrade()]); let sw_ints = SoftwareInterruptControl::new(peripherals.SW_INTERRUPT);