From a5be31fadc9abc41ef5d9cfd02478abb8d1ec983 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Bj=C3=B6rn=20Quentin?= Date: Tue, 9 Jul 2024 17:59:38 +0200 Subject: [PATCH] Improve and use timer abstractions (#1753) * Make esp-wifi timer agnostic * Use timer-abstractions in embassy time driver * Refactor * Fix * Fix * Docs * Adapt examples * Adapt tests * Refactoring * Changelogs * Fix example * Adapt xtask * Make CI pass --------- Co-authored-by: Jesse Braham --- esp-hal-embassy/CHANGELOG.md | 1 + esp-hal-embassy/Cargo.toml | 15 +- esp-hal-embassy/build.rs | 12 -- esp-hal-embassy/src/lib.rs | 56 +---- esp-hal-embassy/src/time_driver/mod.rs | 187 +++++++++++++++- esp-hal-embassy/src/time_driver/systimer.rs | 135 ------------ esp-hal-embassy/src/time_driver/timg.rs | 126 ----------- esp-hal/CHANGELOG.md | 1 + esp-hal/src/timer/mod.rs | 200 ++++++++++++++++++ esp-hal/src/timer/systimer.rs | 16 +- esp-hal/src/timer/timg.rs | 33 ++- esp-wifi/CHANGELOG.md | 1 + esp-wifi/Cargo.toml | 1 - esp-wifi/src/lib.rs | 9 +- esp-wifi/src/timer/riscv.rs | 50 ++--- esp-wifi/src/timer/xtensa.rs | 41 ++-- examples/Cargo.toml | 2 - examples/README.md | 2 +- examples/src/bin/embassy_hello_world.rs | 23 +- examples/src/bin/embassy_i2c.rs | 21 +- .../embassy_i2c_bmp180_calibration_data.rs | 21 +- examples/src/bin/embassy_i2s_read.rs | 21 +- examples/src/bin/embassy_i2s_sound.rs | 21 +- examples/src/bin/embassy_multicore.rs | 22 +- .../src/bin/embassy_multicore_interrupt.rs | 22 +- examples/src/bin/embassy_multiprio.rs | 31 ++- examples/src/bin/embassy_parl_io_rx.rs | 20 +- examples/src/bin/embassy_parl_io_tx.rs | 22 +- examples/src/bin/embassy_rmt_rx.rs | 20 +- examples/src/bin/embassy_rmt_tx.rs | 21 +- examples/src/bin/embassy_serial.rs | 21 +- examples/src/bin/embassy_spi.rs | 22 +- examples/src/bin/embassy_twai.rs | 22 +- examples/src/bin/embassy_usb_serial.rs | 24 ++- examples/src/bin/embassy_usb_serial_jtag.rs | 23 +- examples/src/bin/embassy_wait.rs | 24 ++- examples/src/bin/esp_wifi_access_point.rs | 11 +- .../src/bin/esp_wifi_access_point_with_sta.rs | 11 +- examples/src/bin/esp_wifi_bench.rs | 11 +- examples/src/bin/esp_wifi_ble.rs | 11 +- examples/src/bin/esp_wifi_coex.rs | 11 +- examples/src/bin/esp_wifi_dhcp.rs | 11 +- .../src/bin/esp_wifi_embassy_access_point.rs | 40 +++- .../esp_wifi_embassy_access_point_with_sta.rs | 40 +++- examples/src/bin/esp_wifi_embassy_bench.rs | 40 +++- examples/src/bin/esp_wifi_embassy_ble.rs | 49 ++++- examples/src/bin/esp_wifi_embassy_dhcp.rs | 40 +++- examples/src/bin/esp_wifi_embassy_esp_now.rs | 49 ++++- .../bin/esp_wifi_embassy_esp_now_duplex.rs | 40 +++- examples/src/bin/esp_wifi_esp_now.rs | 11 +- examples/src/bin/esp_wifi_static_ip.rs | 11 +- hil-test/Cargo.toml | 6 +- hil-test/tests/gpio.rs | 21 +- xtask/src/main.rs | 22 +- 54 files changed, 1125 insertions(+), 599 deletions(-) delete mode 100644 esp-hal-embassy/src/time_driver/systimer.rs delete mode 100644 esp-hal-embassy/src/time_driver/timg.rs diff --git a/esp-hal-embassy/CHANGELOG.md b/esp-hal-embassy/CHANGELOG.md index 0c801483d..d74082510 100644 --- a/esp-hal-embassy/CHANGELOG.md +++ b/esp-hal-embassy/CHANGELOG.md @@ -10,6 +10,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Added ### Changed +- Removed the TIMG and SYSTIMER time-drivers, replaced by a generic time-driver taking `OneShotTimer` (#1753) ### Fixed diff --git a/esp-hal-embassy/Cargo.toml b/esp-hal-embassy/Cargo.toml index ab96c702b..a939a2504 100644 --- a/esp-hal-embassy/Cargo.toml +++ b/esp-hal-embassy/Cargo.toml @@ -9,16 +9,17 @@ license = "MIT OR Apache-2.0" [package.metadata.docs.rs] default-target = "riscv32imac-unknown-none-elf" -features = ["esp32c6", "time-timg0"] +features = ["esp32c6"] [dependencies] critical-section = "1.1.2" defmt = { version = "0.3.8", optional = true } document-features = "0.2.8" embassy-executor = { version = "0.5.0", optional = true } -embassy-time-driver = "0.1.0" +embassy-time-driver = { version = "0.1.0", features = [ "tick-hz-1_000_000" ] } esp-hal = { version = "0.18.0", path = "../esp-hal" } portable-atomic = "1.6.0" +log = { version = "0.4.22", optional = true } [build-dependencies] cfg-if = "1.0.0" @@ -38,15 +39,9 @@ esp32s3 = ["esp-hal/esp32s3"] ## Implement `defmt::Format` on certain types. defmt = ["dep:defmt", "embassy-executor?/defmt", "esp-hal/defmt"] +## Enable logging via the log crate +log = ["dep:log"] ## Provide `Executor` and `InterruptExecutor` executors = ["dep:embassy-executor"] ## Use the executor-integrated `embassy-time` timer queue. integrated-timers = ["embassy-executor?/integrated-timers"] - -#! ### Time Driver Feature Flags -## SYSTIMER (16MHz) -time-systimer-16mhz = ["embassy-time-driver/tick-hz-16_000_000"] -## SYSTIMER (80MHz) -time-systimer-80mhz = ["embassy-time-driver/tick-hz-80_000_000"] -## TIMG0 (1MHz) -time-timg0 = ["embassy-time-driver/tick-hz-1_000_000"] diff --git a/esp-hal-embassy/build.rs b/esp-hal-embassy/build.rs index c78fdab01..1c7ecfc2f 100644 --- a/esp-hal-embassy/build.rs +++ b/esp-hal-embassy/build.rs @@ -10,18 +10,6 @@ fn main() -> Result<(), Box> { "esp32", "esp32c2", "esp32c3", "esp32c6", "esp32h2", "esp32s2", "esp32s3" ); - // If the `embassy` feature is enabled, ensure that a time driver implementation - // is available: - cfg_if::cfg_if! { - if #[cfg(feature = "esp32")] { - assert_unique_used_features!("time-timg0"); - } else if #[cfg(feature = "esp32s2")] { - assert_unique_used_features!("time-systimer-80mhz", "time-timg0"); - } else { - assert_unique_used_features!("time-systimer-16mhz", "time-timg0"); - } - } - // NOTE: update when adding new device support! // Determine the name of the configured device: let device_name = if cfg!(feature = "esp32") { diff --git a/esp-hal-embassy/src/lib.rs b/esp-hal-embassy/src/lib.rs index 9781eff06..3848534c8 100644 --- a/esp-hal-embassy/src/lib.rs +++ b/esp-hal-embassy/src/lib.rs @@ -36,69 +36,17 @@ // MUST be the first module mod fmt; -use core::cell::Cell; - -use embassy_time_driver::{AlarmHandle, Driver}; use esp_hal::clock::Clocks; #[cfg(feature = "executors")] pub use self::executor::{Executor, InterruptExecutor}; -use self::time_driver::{EmbassyTimer, TimerType}; +use self::time_driver::{EmbassyTimer, Timer}; #[cfg(feature = "executors")] mod executor; mod time_driver; /// Initialize embassy -pub fn init(clocks: &Clocks, time_driver: TimerType) { +pub fn init(clocks: &Clocks, time_driver: &'static mut [Timer]) { EmbassyTimer::init(clocks, time_driver) } - -#[allow(clippy::type_complexity)] -pub(crate) struct AlarmState { - pub callback: Cell>, - pub allocated: Cell, -} - -unsafe impl Send for AlarmState {} - -impl AlarmState { - pub const fn new() -> Self { - Self { - callback: Cell::new(None), - allocated: Cell::new(false), - } - } -} - -impl Driver for EmbassyTimer { - fn now(&self) -> u64 { - EmbassyTimer::now() - } - - unsafe fn allocate_alarm(&self) -> Option { - critical_section::with(|cs| { - for (i, alarm) in self.alarms.borrow(cs).iter().enumerate() { - if !alarm.allocated.get() { - // set alarm so it is not overwritten - alarm.allocated.set(true); - self.on_alarm_allocated(i); - return Some(AlarmHandle::new(i as u8)); - } - } - None - }) - } - - fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { - let n = alarm.id() as usize; - critical_section::with(|cs| { - let alarm = &self.alarms.borrow(cs)[n]; - alarm.callback.set(Some((callback, ctx))); - }) - } - - fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { - self.set_alarm(alarm, timestamp) - } -} diff --git a/esp-hal-embassy/src/time_driver/mod.rs b/esp-hal-embassy/src/time_driver/mod.rs index b91741e42..1622e7d1f 100644 --- a/esp-hal-embassy/src/time_driver/mod.rs +++ b/esp-hal-embassy/src/time_driver/mod.rs @@ -1,9 +1,180 @@ -#[cfg(any(feature = "time-systimer-16mhz", feature = "time-systimer-80mhz"))] -pub use self::systimer::*; -#[cfg(feature = "time-timg0")] -pub use self::timg::*; +use core::cell::{Cell, RefCell}; -#[cfg(any(feature = "time-systimer-16mhz", feature = "time-systimer-80mhz"))] -mod systimer; -#[cfg(feature = "time-timg0")] -mod timg; +use critical_section::Mutex; +use embassy_time_driver::{AlarmHandle, Driver}; +use esp_hal::{ + clock::Clocks, + interrupt::{InterruptHandler, Priority}, + prelude::*, + time::current_time, + timer::{ErasedTimer, OneShotTimer}, +}; + +pub const MAX_SUPPORTED_ALARM_COUNT: usize = 7; + +pub type Timer = OneShotTimer; + +static TIMERS: Mutex>> = Mutex::new(RefCell::new(None)); + +#[allow(clippy::type_complexity)] +struct AlarmState { + pub callback: Cell>, + pub allocated: Cell, +} + +unsafe impl Send for AlarmState {} + +impl AlarmState { + pub const fn new() -> Self { + Self { + callback: Cell::new(None), + allocated: Cell::new(false), + } + } +} + +pub(super) struct EmbassyTimer { + alarms: Mutex<[AlarmState; MAX_SUPPORTED_ALARM_COUNT]>, +} + +#[allow(clippy::declare_interior_mutable_const)] +const ALARM_STATE_NONE: AlarmState = AlarmState::new(); + +embassy_time_driver::time_driver_impl!(static DRIVER: EmbassyTimer = EmbassyTimer { + alarms: Mutex::new([ALARM_STATE_NONE; MAX_SUPPORTED_ALARM_COUNT]), +}); + +impl EmbassyTimer { + pub(super) fn init(_clocks: &Clocks, timers: &'static mut [Timer]) { + if timers.len() > MAX_SUPPORTED_ALARM_COUNT { + panic!( + "Maximum of {} timers can be used.", + MAX_SUPPORTED_ALARM_COUNT + ); + } + + static HANDLERS: [InterruptHandler; MAX_SUPPORTED_ALARM_COUNT] = [ + handler0, handler1, handler2, handler3, handler4, handler5, handler6, + ]; + + timers + .iter_mut() + .enumerate() + .for_each(|(n, timer)| timer.set_interrupt_handler(HANDLERS[n])); + + critical_section::with(|cs| { + TIMERS.replace(cs, Some(timers)); + }); + + #[handler(priority = Priority::max())] + fn handler0() { + DRIVER.on_interrupt(0); + } + #[handler(priority = Priority::max())] + fn handler1() { + DRIVER.on_interrupt(1); + } + #[handler(priority = Priority::max())] + fn handler2() { + DRIVER.on_interrupt(2); + } + #[handler(priority = Priority::max())] + fn handler3() { + DRIVER.on_interrupt(3); + } + #[handler(priority = Priority::max())] + fn handler4() { + DRIVER.on_interrupt(4); + } + #[handler(priority = Priority::max())] + fn handler5() { + DRIVER.on_interrupt(5); + } + #[handler(priority = Priority::max())] + fn handler6() { + DRIVER.on_interrupt(6); + } + } + + fn on_interrupt(&self, id: usize) { + let cb = critical_section::with(|cs| { + let mut timers = TIMERS.borrow_ref_mut(cs); + let timers = timers.as_mut().unwrap(); + let timer = &mut timers[id]; + + timer.clear_interrupt(); + + let alarm = &self.alarms.borrow(cs)[id]; + + if let Some((f, ctx)) = alarm.callback.get() { + Some((f, ctx)) + } else { + None + } + }); + + if let Some((f, ctx)) = cb { + f(ctx); + } + } + + fn arm(timer: &mut Timer, timestamp: u64) { + let now = current_time().duration_since_epoch(); + let ts = timestamp.micros(); + let timeout = if ts > now { ts - now } else { now }; + timer.schedule(timeout).unwrap(); + timer.enable_interrupt(true); + } +} + +impl Driver for EmbassyTimer { + fn now(&self) -> u64 { + current_time().ticks() + } + + unsafe fn allocate_alarm(&self) -> Option { + critical_section::with(|cs| { + for (i, alarm) in self.alarms.borrow(cs).iter().enumerate() { + if !alarm.allocated.get() { + // set alarm so it is not overwritten + alarm.allocated.set(true); + return Some(AlarmHandle::new(i as u8)); + } + } + None + }) + } + + fn set_alarm_callback(&self, alarm: AlarmHandle, callback: fn(*mut ()), ctx: *mut ()) { + let n = alarm.id() as usize; + critical_section::with(|cs| { + let alarm = &self.alarms.borrow(cs)[n]; + alarm.callback.set(Some((callback, ctx))); + }) + } + + fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { + // we sometimes get called with `u64::MAX` for apparently not yet initialized + // timers which would fail later on + if timestamp == u64::MAX { + return false; + } + + // The hardware fires the alarm even if timestamp is lower than the current + // time. In this case the interrupt handler will pend a wake-up when we exit the + // critical section. + // + // This is correct behavior. See https://docs.rs/embassy-time-driver/0.1.0/embassy_time_driver/trait.Driver.html#tymethod.set_alarm + // (... the driver should return true and arrange to call the alarm callback as + // soon as possible, but not synchronously.) + critical_section::with(|cs| { + let mut timers = TIMERS.borrow_ref_mut(cs); + let timers = timers.as_mut().unwrap(); + let timer = &mut timers[alarm.id() as usize]; + + Self::arm(timer, timestamp); + }); + + true + } +} diff --git a/esp-hal-embassy/src/time_driver/systimer.rs b/esp-hal-embassy/src/time_driver/systimer.rs deleted file mode 100644 index b62fd53d6..000000000 --- a/esp-hal-embassy/src/time_driver/systimer.rs +++ /dev/null @@ -1,135 +0,0 @@ -use critical_section::{CriticalSection, Mutex}; -use embassy_time_driver::AlarmHandle; -use esp_hal::{ - clock::Clocks, - interrupt, - peripherals::Interrupt, - prelude::*, - timer::systimer::{Alarm, SystemTimer, Target}, - Async, -}; - -use crate::AlarmState; - -pub const ALARM_COUNT: usize = 3; - -pub type TimerType = SystemTimer<'static, Async>; - -pub struct EmbassyTimer { - pub(crate) alarms: Mutex<[AlarmState; ALARM_COUNT]>, - pub(crate) alarm0: Alarm, - pub(crate) alarm1: Alarm, - pub(crate) alarm2: Alarm, -} - -#[allow(clippy::declare_interior_mutable_const)] -const ALARM_STATE_NONE: AlarmState = AlarmState::new(); - -embassy_time_driver::time_driver_impl!(static DRIVER: EmbassyTimer = EmbassyTimer { - alarms: Mutex::new([ALARM_STATE_NONE; ALARM_COUNT]), - alarm0: unsafe { Alarm::<_, Async, 0>::conjure() }, - alarm1: unsafe { Alarm::<_, Async, 1>::conjure() }, - alarm2: unsafe { Alarm::<_, Async, 2>::conjure() }, -}); - -impl EmbassyTimer { - pub(crate) fn now() -> u64 { - SystemTimer::now() - } - - fn trigger_alarm(&self, n: usize, cs: CriticalSection) { - let alarm = &self.alarms.borrow(cs)[n]; - - if let Some((f, ctx)) = alarm.callback.get() { - f(ctx); - } - } - - pub(crate) fn on_alarm_allocated(&self, n: usize) { - match n { - 0 => self.alarm0.enable_interrupt(true), - 1 => self.alarm1.enable_interrupt(true), - 2 => self.alarm2.enable_interrupt(true), - _ => {} - } - } - - fn on_interrupt(&self, id: usize) { - critical_section::with(|cs| { - self.clear_interrupt(id); - self.trigger_alarm(id, cs); - }) - } - - pub fn init(_clocks: &Clocks, _systimer: TimerType) { - unsafe { - interrupt::bind_interrupt(Interrupt::SYSTIMER_TARGET0, target0_handler.handler()); - unwrap!(interrupt::enable( - Interrupt::SYSTIMER_TARGET0, - target0_handler.priority() - )); - - interrupt::bind_interrupt(Interrupt::SYSTIMER_TARGET1, target1_handler.handler()); - unwrap!(interrupt::enable( - Interrupt::SYSTIMER_TARGET1, - target1_handler.priority() - )); - - interrupt::bind_interrupt(Interrupt::SYSTIMER_TARGET2, target2_handler.handler()); - unwrap!(interrupt::enable( - Interrupt::SYSTIMER_TARGET2, - target2_handler.priority() - )); - } - - #[handler] - fn target0_handler() { - DRIVER.on_interrupt(0); - } - - #[handler] - fn target1_handler() { - DRIVER.on_interrupt(1); - } - - #[handler] - fn target2_handler() { - DRIVER.on_interrupt(2); - } - } - - pub(crate) fn set_alarm(&self, alarm: AlarmHandle, timestamp: u64) -> bool { - critical_section::with(|_cs| { - let n = alarm.id() as usize; - - // The hardware fires the alarm even if timestamp is lower than the current - // time. In this case the interrupt handler will pend a wakeup when we exit the - // critical section. - self.arm(n, timestamp); - }); - - // In theory, the above comment is true. However, in practice, we seem to be - // missing interrupt for very short timeouts, so let's make sure and catch - // timestamps that already passed. Returning `false` means embassy will - // run one more poll loop. - Self::now() < timestamp - } - - fn clear_interrupt(&self, id: usize) { - match id { - 0 => self.alarm0.clear_interrupt(), - 1 => self.alarm1.clear_interrupt(), - 2 => self.alarm2.clear_interrupt(), - _ => {} - } - } - - fn arm(&self, id: usize, timestamp: u64) { - match id { - 0 => self.alarm0.set_target(timestamp), - 1 => self.alarm1.set_target(timestamp), - 2 => self.alarm2.set_target(timestamp), - _ => {} - } - } -} diff --git a/esp-hal-embassy/src/time_driver/timg.rs b/esp-hal-embassy/src/time_driver/timg.rs deleted file mode 100644 index a046fba03..000000000 --- a/esp-hal-embassy/src/time_driver/timg.rs +++ /dev/null @@ -1,126 +0,0 @@ -use critical_section::{CriticalSection, Mutex}; -use embassy_time_driver::AlarmHandle; -#[cfg(any(esp32, esp32s2, esp32s3))] -use esp_hal::timer::timg::Timer1; -use esp_hal::{ - clock::Clocks, - interrupt::{self, Priority}, - peripherals::{Interrupt, TIMG0}, - prelude::*, - timer::timg::{Instance, Timer0, TimerGroup}, - Async, -}; - -use crate::AlarmState; - -#[cfg(not(any(esp32, esp32s2, esp32s3)))] -pub const ALARM_COUNT: usize = 1; -#[cfg(any(esp32, esp32s2, esp32s3))] -pub const ALARM_COUNT: usize = 2; - -pub type TimerType = TimerGroup<'static, TIMG0, Async>; - -pub struct EmbassyTimer { - pub(crate) alarms: Mutex<[AlarmState; ALARM_COUNT]>, -} - -#[allow(clippy::declare_interior_mutable_const)] -const ALARM_STATE_NONE: AlarmState = AlarmState::new(); - -embassy_time_driver::time_driver_impl!(static DRIVER: EmbassyTimer = EmbassyTimer { - alarms: Mutex::new([ALARM_STATE_NONE; ALARM_COUNT]), -}); - -impl EmbassyTimer { - pub(crate) fn now() -> u64 { - unsafe { Timer0::::steal() }.now() - } - - fn trigger_alarm(&self, n: usize, cs: CriticalSection) { - let alarm = &self.alarms.borrow(cs)[n]; - - if let Some((f, ctx)) = alarm.callback.get() { - f(ctx); - } - } - - pub(crate) fn on_alarm_allocated(&self, _n: usize) {} - - fn on_interrupt(&self, id: u8, timer: Timer) { - critical_section::with(|cs| { - timer.clear_interrupt(); - self.trigger_alarm(id as usize, cs); - }); - } - - pub fn init(clocks: &Clocks, timer: TimerType) { - // set divider to get a 1mhz clock. APB (80mhz) / 80 = 1mhz... - timer.timer0.set_divider(clocks.apb_clock.to_MHz() as u16); - timer.timer0.set_counter_active(true); - - #[cfg(any(esp32, esp32s2, esp32s3))] - { - timer.timer1.set_divider(clocks.apb_clock.to_MHz() as u16); - timer.timer1.set_counter_active(true); - } - - unsafe { - interrupt::bind_interrupt(Interrupt::TG0_T0_LEVEL, tg0_t0_level.handler()); - unwrap!(interrupt::enable( - Interrupt::TG0_T0_LEVEL, - tg0_t0_level.priority() - )); - } - #[cfg(any(esp32, esp32s2, esp32s3))] - unsafe { - interrupt::bind_interrupt(Interrupt::TG0_T1_LEVEL, tg0_t1_level.handler()); - unwrap!(interrupt::enable( - Interrupt::TG0_T1_LEVEL, - tg0_t1_level.priority() - )); - } - - #[handler(priority = Priority::max())] - fn tg0_t0_level() { - let timer = unsafe { Timer0::::steal() }; - DRIVER.on_interrupt(0, timer); - } - - #[cfg(any(esp32, esp32s2, esp32s3))] - #[handler(priority = Priority::max())] - fn tg0_t1_level() { - let timer = unsafe { Timer1::::steal() }; - DRIVER.on_interrupt(1, timer); - } - } - - pub(crate) fn set_alarm(&self, _alarm: AlarmHandle, timestamp: u64) -> bool { - critical_section::with(|_cs| { - // The hardware fires the alarm even if timestamp is lower than the current - // time. In this case the interrupt handler will pend a wakeup when we exit the - // critical section. - #[cfg(any(esp32, esp32s2, esp32s3))] - if _alarm.id() == 1 { - let mut tg = unsafe { Timer1::::steal() }; - Self::arm(&mut tg, timestamp); - return; - } - - let mut tg = unsafe { Timer0::::steal() }; - Self::arm(&mut tg, timestamp); - }); - - true - } - - fn arm(tg: &mut T, timestamp: u64) - where - T: Instance, - { - tg.load_alarm_value(timestamp); - tg.listen(); - tg.set_counter_decrementing(false); - tg.set_auto_reload(false); - tg.set_alarm_active(true); - } -} diff --git a/esp-hal/CHANGELOG.md b/esp-hal/CHANGELOG.md index dd21e9425..f3af55972 100644 --- a/esp-hal/CHANGELOG.md +++ b/esp-hal/CHANGELOG.md @@ -22,6 +22,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 - dma: add Mem2Mem to support memory to memory transfer (#1738) - Add `uart` wake source (#1727) - uart: Make `rx_timeout` optional in Config struct (#1759) +- Add interrupt related functions to `PeriodicTimer`/`OneShotTimer`, added `ErasedTimer` (#1753) ### Fixed diff --git a/esp-hal/src/timer/mod.rs b/esp-hal/src/timer/mod.rs index a4dbb8d22..e919453d6 100644 --- a/esp-hal/src/timer/mod.rs +++ b/esp-hal/src/timer/mod.rs @@ -42,6 +42,8 @@ use fugit::{ExtU64, Instant, MicrosDurationU64}; +use crate::{interrupt::InterruptHandler, private}; + #[cfg(systimer)] pub mod systimer; #[cfg(any(timg0, timg1))] @@ -90,6 +92,11 @@ pub trait Timer: crate::private::Sealed { /// Clear the timer's interrupt. fn clear_interrupt(&self); + /// Set the interrupt handler + /// + /// Note that this will replace any previously set interrupt handler + fn set_interrupt_handler(&self, handler: InterruptHandler); + /// Has the timer triggered? fn is_interrupt_set(&self) -> bool; @@ -146,6 +153,45 @@ where self.inner.stop(); self.inner.clear_interrupt(); } + + /// Start counting until the given timeout and raise an interrupt + pub fn schedule(&mut self, timeout: MicrosDurationU64) -> Result<(), Error> { + if self.inner.is_running() { + self.inner.stop(); + } + + self.inner.clear_interrupt(); + self.inner.reset(); + + self.inner.enable_auto_reload(false); + self.inner.load_value(timeout)?; + self.inner.start(); + + Ok(()) + } + + /// Stop the timer + pub fn stop(&mut self) { + self.inner.stop(); + } + + /// Set the interrupt handler + /// + /// Note that this will replace any previously set interrupt handler + pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + self.inner.set_interrupt_handler(handler); + } + + /// Enable listening for interrupts + pub fn enable_interrupt(&mut self, enable: bool) { + self.inner.enable_interrupt(enable); + } + + /// Clear the interrupt flag + pub fn clear_interrupt(&mut self) { + self.inner.clear_interrupt(); + self.inner.set_alarm_active(false); + } } #[cfg(feature = "embedded-hal-02")] @@ -232,6 +278,160 @@ where Ok(()) } + + /// Set the interrupt handler + /// + /// Note that this will replace any previously set interrupt handler + pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + self.inner.set_interrupt_handler(handler); + } + + /// Enable/disable listening for interrupts + pub fn enable_interrupt(&mut self, enable: bool) { + self.inner.enable_interrupt(enable); + } + + /// Clear the interrupt flag + pub fn clear_interrupt(&mut self) { + self.inner.clear_interrupt(); + self.inner.set_alarm_active(true); + } +} + +/// A type-erased timer +/// +/// You can create an instance of this by just calling `.into()` on a timer. +#[allow(missing_docs)] +pub enum ErasedTimer { + Timg0Timer0(timg::Timer, crate::Blocking>), + #[cfg(timg_timer1)] + Timg0Timer1(timg::Timer, crate::Blocking>), + #[cfg(timg1)] + Timg1Timer0(timg::Timer, crate::Blocking>), + #[cfg(all(timg1, timg_timer1))] + Timg1Timer1(timg::Timer, crate::Blocking>), + #[cfg(systimer)] + SystimerAlarm0Periodic(systimer::Alarm), + #[cfg(systimer)] + SystimerAlarm1Periodic(systimer::Alarm), + #[cfg(systimer)] + SystimerAlarm2Periodic(systimer::Alarm), + #[cfg(systimer)] + SystimerAlarm0Target(systimer::Alarm), + #[cfg(systimer)] + SystimerAlarm1Target(systimer::Alarm), + #[cfg(systimer)] + SystimerAlarm2Target(systimer::Alarm), +} + +impl private::Sealed for ErasedTimer {} + +impl From, crate::Blocking>> for ErasedTimer { + fn from(value: timg::Timer, crate::Blocking>) -> Self { + Self::Timg0Timer0(value) + } +} + +#[cfg(timg_timer1)] +impl From, crate::Blocking>> for ErasedTimer { + fn from(value: timg::Timer, crate::Blocking>) -> Self { + Self::Timg0Timer1(value) + } +} + +#[cfg(timg1)] +impl From, crate::Blocking>> for ErasedTimer { + fn from(value: timg::Timer, crate::Blocking>) -> Self { + Self::Timg1Timer0(value) + } +} + +#[cfg(all(timg1, timg_timer1))] +impl From, crate::Blocking>> for ErasedTimer { + fn from(value: timg::Timer, crate::Blocking>) -> Self { + Self::Timg1Timer1(value) + } +} + +#[cfg(systimer)] +impl From> for ErasedTimer { + fn from(value: systimer::Alarm) -> Self { + Self::SystimerAlarm0Periodic(value) + } +} + +#[cfg(systimer)] +impl From> for ErasedTimer { + fn from(value: systimer::Alarm) -> Self { + Self::SystimerAlarm1Periodic(value) + } +} + +#[cfg(systimer)] +impl From> for ErasedTimer { + fn from(value: systimer::Alarm) -> Self { + Self::SystimerAlarm2Periodic(value) + } +} + +#[cfg(systimer)] +impl From> for ErasedTimer { + fn from(value: systimer::Alarm) -> Self { + Self::SystimerAlarm0Target(value) + } +} + +#[cfg(systimer)] +impl From> for ErasedTimer { + fn from(value: systimer::Alarm) -> Self { + Self::SystimerAlarm1Target(value) + } +} + +#[cfg(systimer)] +impl From> for ErasedTimer { + fn from(value: systimer::Alarm) -> Self { + Self::SystimerAlarm2Target(value) + } +} + +impl Timer for ErasedTimer { + delegate::delegate! { + to match self { + ErasedTimer::Timg0Timer0(inner) => inner, + #[cfg(timg_timer1)] + ErasedTimer::Timg0Timer1(inner) => inner, + #[cfg(timg1)] + ErasedTimer::Timg1Timer0(inner) => inner, + #[cfg(all(timg1,timg_timer1))] + ErasedTimer::Timg1Timer1(inner) => inner, + #[cfg(systimer)] + ErasedTimer::SystimerAlarm0Periodic(inner) => inner, + #[cfg(systimer)] + ErasedTimer::SystimerAlarm1Periodic(inner) => inner, + #[cfg(systimer)] + ErasedTimer::SystimerAlarm2Periodic(inner) => inner, + #[cfg(systimer)] + ErasedTimer::SystimerAlarm0Target(inner) => inner, + #[cfg(systimer)] + ErasedTimer::SystimerAlarm1Target(inner) => inner, + #[cfg(systimer)] + ErasedTimer::SystimerAlarm2Target(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); + } + } } #[cfg(feature = "embedded-hal-02")] diff --git a/esp-hal/src/timer/systimer.rs b/esp-hal/src/timer/systimer.rs index 9d6bbfa1b..069c7a79d 100644 --- a/esp-hal/src/timer/systimer.rs +++ b/esp-hal/src/timer/systimer.rs @@ -229,11 +229,8 @@ where tconf.modify(|_r, w| w.work_en().set_bit()); } } -} -impl Alarm { - /// Set the interrupt handler for this alarm. - pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + fn set_interrupt_handler_internal(&self, handler: InterruptHandler) { match CHANNEL { 0 => unsafe { interrupt::bind_interrupt(Interrupt::SYSTIMER_TARGET0, handler.handler()); @@ -261,6 +258,13 @@ impl Alarm { } } +impl Alarm { + /// Set the interrupt handler for this alarm. + pub fn set_interrupt_handler(&mut self, handler: InterruptHandler) { + self.set_interrupt_handler_internal(handler) + } +} + impl Alarm where DM: Mode, @@ -572,6 +576,10 @@ where fn set_alarm_active(&self, _active: bool) { // Nothing to do } + + fn set_interrupt_handler(&self, handler: InterruptHandler) { + Alarm::set_interrupt_handler_internal(self, handler); + } } // Async functionality of the system timer. diff --git a/esp-hal/src/timer/timg.rs b/esp-hal/src/timer/timg.rs index ee08c1f60..0e24925df 100644 --- a/esp-hal/src/timer/timg.rs +++ b/esp-hal/src/timer/timg.rs @@ -518,9 +518,16 @@ where } fn enable_interrupt(&self, state: bool) { + // always use level interrupt + #[cfg(any(esp32, esp32s2))] + self.register_block() + .t(self.timer_number().into()) + .config() + .modify(|_, w| w.level_int_en().set_bit()); + self.register_block() .int_ena_timers() - .write(|w| w.t(self.timer_number()).bit(state)); + .modify(|_, w| w.t(self.timer_number()).bit(state)); } fn clear_interrupt(&self) { @@ -529,6 +536,24 @@ where .write(|w| w.t(self.timer_number()).clear_bit_by_one()); } + fn set_interrupt_handler(&self, handler: InterruptHandler) { + let interrupt = match (self.timer_group(), self.timer_number()) { + (0, 0) => Interrupt::TG0_T0_LEVEL, + #[cfg(timg_timer1)] + (0, 1) => Interrupt::TG0_T1_LEVEL, + #[cfg(timg1)] + (1, 0) => Interrupt::TG1_T0_LEVEL, + #[cfg(all(timg_timer1, timg1))] + (1, 1) => Interrupt::TG1_T1_LEVEL, + _ => unreachable!(), + }; + + unsafe { + interrupt::bind_interrupt(interrupt, handler.handler()); + } + interrupt::enable(interrupt, handler.priority()).unwrap(); + } + fn is_interrupt_set(&self) -> bool { self.register_block() .int_raw_timers() @@ -549,6 +574,8 @@ where pub trait Instance: Sealed + Enable { fn register_block(&self) -> &RegisterBlock; + fn timer_group(&self) -> u8; + fn timer_number(&self) -> u8; fn reset_counter(&self); @@ -633,6 +660,10 @@ where unsafe { &*TG::register_block() } } + fn timer_group(&self) -> u8 { + TG::id() + } + fn timer_number(&self) -> u8 { T } diff --git a/esp-wifi/CHANGELOG.md b/esp-wifi/CHANGELOG.md index dc4b89836..251400745 100644 --- a/esp-wifi/CHANGELOG.md +++ b/esp-wifi/CHANGELOG.md @@ -16,6 +16,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0 ### Changed - `esp_wifi::initialize` no longer requires running maximum CPU clock, instead check it runs above 80MHz. (#1688) - Rename `set_mode` to `set_protocol`, also available in esp-now API (#1742) +- `esp_wifi::initialize` now takes a `PeriodicTimer` (#1753) ### Removed diff --git a/esp-wifi/Cargo.toml b/esp-wifi/Cargo.toml index 5d9908442..57b920892 100644 --- a/esp-wifi/Cargo.toml +++ b/esp-wifi/Cargo.toml @@ -141,7 +141,6 @@ features = [ "coex", "async", "embassy-net", - "esp-hal-embassy/time-timg0", "esp-hal/default", ] default-target = "riscv32imc-unknown-none-elf" diff --git a/esp-wifi/src/lib.rs b/esp-wifi/src/lib.rs index 4c415ed6b..6accfc2b2 100644 --- a/esp-wifi/src/lib.rs +++ b/esp-wifi/src/lib.rs @@ -18,8 +18,6 @@ use common_adapter::{chip_specific::phy_mem_init, init_radio_clock_control, RADI use critical_section::Mutex; use esp_hal as hal; use fugit::MegahertzU32; -#[cfg(any(esp32c2, esp32c3, esp32c6, esp32h2))] -use hal::timer::systimer::{Alarm, Target}; use hal::{clock::Clocks, system::RadioClockController}; use linked_list_allocator::Heap; #[cfg(feature = "wifi")] @@ -144,12 +142,7 @@ fn init_heap() { }); } -#[cfg(any(esp32c3, esp32c2, esp32c6, esp32h2))] -pub(crate) type EspWifiTimer = Alarm; - -#[cfg(any(esp32, esp32s3, esp32s2))] -pub(crate) type EspWifiTimer = - hal::timer::timg::Timer, esp_hal::Blocking>; +pub(crate) type EspWifiTimer = crate::timer::TimeBase; #[derive(Debug, PartialEq, PartialOrd)] #[cfg_attr(feature = "defmt", derive(defmt::Format))] diff --git a/esp-wifi/src/timer/riscv.rs b/esp-wifi/src/timer/riscv.rs index 18cf8daae..2c4f98205 100644 --- a/esp-wifi/src/timer/riscv.rs +++ b/esp-wifi/src/timer/riscv.rs @@ -1,6 +1,10 @@ use core::cell::RefCell; use critical_section::Mutex; +use esp_hal::{ + interrupt::InterruptHandler, + timer::{ErasedTimer, PeriodicTimer}, +}; #[cfg(any(feature = "esp32c6", feature = "esp32h2"))] use peripherals::INTPRI as SystemPeripheral; #[cfg(not(any(feature = "esp32c6", feature = "esp32h2")))] @@ -10,46 +14,34 @@ use crate::{ hal::{ interrupt::{self, TrapFrame}, peripherals::{self, Interrupt}, - prelude::*, riscv, - timer::systimer::{Alarm, Periodic, Target}, }, preempt::preempt::task_switch, }; /// The timer responsible for time slicing. -pub type TimeBase = Alarm; -static ALARM0: Mutex>>> = - Mutex::new(RefCell::new(None)); -const TIMESLICE_FREQUENCY: fugit::HertzU32 = fugit::HertzU32::from_raw(crate::CONFIG.tick_rate_hz); +pub type TimeBase = PeriodicTimer; +static ALARM0: Mutex>> = Mutex::new(RefCell::new(None)); +const TIMESLICE_FREQUENCY: fugit::HertzU64 = + fugit::HertzU64::from_raw(crate::CONFIG.tick_rate_hz as u64); // Time keeping pub const TICKS_PER_SECOND: u64 = 1_000_000; -pub fn setup_timer(systimer: TimeBase) -> Result<(), esp_hal::timer::Error> { +pub fn setup_timer(mut alarm0: TimeBase) -> Result<(), esp_hal::timer::Error> { // make sure the scheduling won't start before everything is setup riscv::interrupt::disable(); - let alarm0 = systimer.into_periodic(); - alarm0.set_period(TIMESLICE_FREQUENCY.into_duration()); - alarm0.clear_interrupt(); - alarm0.enable_interrupt(true); - - critical_section::with(|cs| ALARM0.borrow_ref_mut(cs).replace(alarm0)); - - unsafe { - interrupt::bind_interrupt( - Interrupt::SYSTIMER_TARGET0, - core::mem::transmute::<*const (), unsafe extern "C" fn()>( - systimer_target0 as *const (), - ), - ); - } - - unwrap!(interrupt::enable( - Interrupt::SYSTIMER_TARGET0, + alarm0.set_interrupt_handler(InterruptHandler::new( + unsafe { core::mem::transmute(handler as *const ()) }, interrupt::Priority::Priority1, )); + alarm0.start(TIMESLICE_FREQUENCY.into_duration())?; + critical_section::with(|cs| { + alarm0.enable_interrupt(true); + ALARM0.borrow_ref_mut(cs).replace(alarm0); + }); + Ok(()) } @@ -64,7 +56,7 @@ pub fn setup_multitasking() { } } -extern "C" fn systimer_target0(trap_frame: &mut TrapFrame) { +extern "C" fn handler(trap_frame: &mut TrapFrame) { // clear the systimer intr critical_section::with(|cs| { unwrap!(ALARM0.borrow_ref_mut(cs).as_mut()).clear_interrupt(); @@ -83,10 +75,8 @@ extern "C" fn FROM_CPU_INTR3(trap_frame: &mut TrapFrame) { } critical_section::with(|cs| { - let alarm0 = ALARM0.borrow_ref(cs); - let alarm0 = unwrap!(alarm0.as_ref()); - - alarm0.set_period(TIMESLICE_FREQUENCY.into_duration()); + let mut alarm0 = ALARM0.borrow_ref_mut(cs); + let alarm0 = unwrap!(alarm0.as_mut()); alarm0.clear_interrupt(); }); diff --git a/esp-wifi/src/timer/xtensa.rs b/esp-wifi/src/timer/xtensa.rs index 37f423387..37e21ee0f 100644 --- a/esp-wifi/src/timer/xtensa.rs +++ b/esp-wifi/src/timer/xtensa.rs @@ -1,22 +1,18 @@ use core::cell::RefCell; use critical_section::Mutex; +use esp_hal::{ + interrupt::InterruptHandler, + timer::{ErasedTimer, PeriodicTimer}, +}; use crate::{ - hal::{ - interrupt, - peripherals::{self, TIMG1}, - prelude::*, - timer::timg::{Timer, Timer0}, - trapframe::TrapFrame, - xtensa_lx, - xtensa_lx_rt, - }, + hal::{interrupt, trapframe::TrapFrame, xtensa_lx, xtensa_lx_rt}, preempt::preempt::task_switch, }; /// The timer responsible for time slicing. -pub type TimeBase = Timer, esp_hal::Blocking>; +pub type TimeBase = PeriodicTimer; static TIMER1: Mutex>> = Mutex::new(RefCell::new(None)); const TIMESLICE_FREQUENCY: fugit::HertzU64 = fugit::HertzU64::from_raw(crate::CONFIG.tick_rate_hz as u64); @@ -30,23 +26,14 @@ pub fn get_systimer_count() -> u64 { esp_hal::time::current_time().ticks() } -pub fn setup_timer(timer1: TimeBase) -> Result<(), esp_hal::timer::Error> { - unsafe { - interrupt::bind_interrupt( - peripherals::Interrupt::TG1_T0_LEVEL, - core::mem::transmute(tg1_t0_level as *const ()), - ); - } - - unwrap!(interrupt::enable( - peripherals::Interrupt::TG1_T0_LEVEL, +pub fn setup_timer(mut timer1: TimeBase) -> Result<(), esp_hal::timer::Error> { + timer1.set_interrupt_handler(InterruptHandler::new( + unsafe { core::mem::transmute(handler as *const ()) }, interrupt::Priority::Priority2, )); - - timer1.listen(); - timer1.load_value(TIMESLICE_FREQUENCY.into_duration())?; - timer1.start(); + timer1.start(TIMESLICE_FREQUENCY.into_duration())?; critical_section::with(|cs| { + timer1.enable_interrupt(true); TIMER1.borrow_ref_mut(cs).replace(timer1); }); Ok(()) @@ -68,16 +55,12 @@ fn do_task_switch(context: &mut TrapFrame) { let mut timer = TIMER1.borrow_ref_mut(cs); let timer = unwrap!(timer.as_mut()); timer.clear_interrupt(); - timer - .load_value(TIMESLICE_FREQUENCY.into_duration()) - .unwrap(); - timer.start(); }); task_switch(context); } -extern "C" fn tg1_t0_level(context: &mut TrapFrame) { +extern "C" fn handler(context: &mut TrapFrame) { do_task_switch(context); } diff --git a/examples/Cargo.toml b/examples/Cargo.toml index f4d85a54a..3e9e4733a 100644 --- a/examples/Cargo.toml +++ b/examples/Cargo.toml @@ -74,8 +74,6 @@ embedded-hal = ["esp-hal/embedded-hal"] embassy = ["dep:esp-hal-embassy"] -embassy-time-systimer-16mhz = ["esp-hal-embassy/time-systimer-16mhz"] -embassy-time-timg0 = ["esp-hal-embassy/time-timg0"] embassy-generic-timers = ["embassy-time/generic-queue-8"] opsram-2m = ["esp-hal/opsram-2m"] diff --git a/examples/README.md b/examples/README.md index ba0f3ffc6..0ed4cb1ec 100644 --- a/examples/README.md +++ b/examples/README.md @@ -40,7 +40,7 @@ To demonstrated, in `src/bin/embassy_hello_world.rs` you will see the following: ```rust //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: embassy embassy-generic-timers embassy-time-timg0 +//% FEATURES: embassy esp-hal-embassy/integrated-timers ``` Another thing to be aware of is the GPIO pins being used. We have tried to use pins available the DevKit-C boards from Espressif, however this is being done on a best-effort basis. diff --git a/examples/src/bin/embassy_hello_world.rs b/examples/src/bin/embassy_hello_world.rs index 7065e8d82..953b2f64b 100644 --- a/examples/src/bin/embassy_hello_world.rs +++ b/examples/src/bin/embassy_hello_world.rs @@ -4,7 +4,7 @@ //! concurrently. //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: embassy esp-hal-embassy/integrated-timers #![no_std] #![no_main] @@ -17,9 +17,19 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[embassy_executor::task] async fn run() { loop { @@ -30,13 +40,18 @@ async fn run() { #[main] async fn main(spawner: Spawner) { + esp_println::logger::init_logger_from_env(); + esp_println::println!("Init!"); let peripherals = Peripherals::take(); let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timer0 = OneShotTimer::new(timg0.timer0.into()); + let timers = [timer0]; + let timers = mk_static!([OneShotTimer; 1], timers); + esp_hal_embassy::init(&clocks, timers); spawner.spawn(run()).ok(); diff --git a/examples/src/bin/embassy_i2c.rs b/examples/src/bin/embassy_i2c.rs index 679be82fc..1164dd9f9 100644 --- a/examples/src/bin/embassy_i2c.rs +++ b/examples/src/bin/embassy_i2c.rs @@ -11,7 +11,7 @@ //! LIS3DH to get accelerometer data. //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -26,18 +26,31 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; use lis3dh_async::{Lis3dh, Range, SlaveAddr}; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[main] async fn main(_spawner: Spawner) { let peripherals = Peripherals::take(); let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timer0 = OneShotTimer::new(timg0.timer0.into()); + let timers = [timer0]; + let timers = mk_static!([OneShotTimer; 1], timers); + esp_hal_embassy::init(&clocks, timers); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); diff --git a/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs b/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs index 3efb2192b..fc1305460 100644 --- a/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs +++ b/examples/src/bin/embassy_i2c_bmp180_calibration_data.rs @@ -12,7 +12,7 @@ //! //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -27,17 +27,30 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[main] async fn main(_spawner: Spawner) { let peripherals = Peripherals::take(); let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timer0 = OneShotTimer::new(timg0.timer0.into()); + let timers = [timer0]; + let timers = mk_static!([OneShotTimer; 1], timers); + esp_hal_embassy::init(&clocks, timers); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); diff --git a/examples/src/bin/embassy_i2s_read.rs b/examples/src/bin/embassy_i2s_read.rs index bbb567300..748aa23d9 100644 --- a/examples/src/bin/embassy_i2s_read.rs +++ b/examples/src/bin/embassy_i2s_read.rs @@ -12,7 +12,7 @@ //! You can also inspect the MCLK, BCLK and WS with a logic analyzer. //% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -28,10 +28,20 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; use esp_println::println; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[main] async fn main(_spawner: Spawner) { println!("Init!"); @@ -39,8 +49,11 @@ async fn main(_spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timer0 = OneShotTimer::new(timg0.timer0.into()); + let timers = [timer0]; + let timers = mk_static!([OneShotTimer; 1], timers); + esp_hal_embassy::init(&clocks, timers); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); diff --git a/examples/src/bin/embassy_i2s_sound.rs b/examples/src/bin/embassy_i2s_sound.rs index ffb60bad7..096ab8b55 100644 --- a/examples/src/bin/embassy_i2s_sound.rs +++ b/examples/src/bin/embassy_i2s_sound.rs @@ -27,7 +27,7 @@ //! | XSMT | +3V3 | //% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -43,7 +43,7 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; use esp_println::println; @@ -55,6 +55,16 @@ const SINE: [i16; 64] = [ -28897, -27244, -25329, -23169, -20787, -18204, -15446, -12539, -9511, -6392, -3211, ]; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[main] async fn main(_spawner: Spawner) { println!("Init!"); @@ -62,8 +72,11 @@ async fn main(_spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timer0 = OneShotTimer::new(timg0.timer0.into()); + let timers = [timer0]; + let timers = mk_static!([OneShotTimer; 1], timers); + esp_hal_embassy::init(&clocks, timers); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); diff --git a/examples/src/bin/embassy_multicore.rs b/examples/src/bin/embassy_multicore.rs index 47f14dfba..b5878cf5c 100644 --- a/examples/src/bin/embassy_multicore.rs +++ b/examples/src/bin/embassy_multicore.rs @@ -4,7 +4,7 @@ //! signal set by the task running on the other core. //% CHIPS: esp32 esp32s3 -//% FEATURES: embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: embassy embassy-generic-timers #![no_std] #![no_main] @@ -23,7 +23,7 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; use esp_hal_embassy::Executor; use esp_println::println; @@ -31,6 +31,16 @@ use static_cell::StaticCell; static mut APP_CORE_STACK: Stack<8192> = Stack::new(); +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + /// Waits for a message that contains a duration, then flashes a led for that /// duration of time. #[embassy_executor::task] @@ -58,8 +68,12 @@ async fn main(_spawner: Spawner) { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timer0 = OneShotTimer::new(timg0.timer0.into()); + let timer1 = OneShotTimer::new(timg0.timer1.into()); + let timers = [timer0, timer1]; + let timers = mk_static!([OneShotTimer; 2], timers); + esp_hal_embassy::init(&clocks, timers); 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 fb2bf4c8e..8176fb96c 100644 --- a/examples/src/bin/embassy_multicore_interrupt.rs +++ b/examples/src/bin/embassy_multicore_interrupt.rs @@ -4,7 +4,7 @@ //! signal set by the task running on the other core. //% CHIPS: esp32 esp32s3 -//% FEATURES: embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: embassy embassy-generic-timers #![no_std] #![no_main] @@ -23,7 +23,7 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; use esp_hal_embassy::InterruptExecutor; use esp_println::println; @@ -31,6 +31,16 @@ use static_cell::StaticCell; static mut APP_CORE_STACK: Stack<8192> = Stack::new(); +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + /// Waits for a message that contains a duration, then flashes a led for that /// duration of time. #[embassy_executor::task] @@ -77,8 +87,12 @@ fn main() -> ! { let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timer0 = OneShotTimer::new(timg0.timer0.into()); + let timer1 = OneShotTimer::new(timg0.timer1.into()); + let timers = [timer0, timer1]; + let timers = mk_static!([OneShotTimer; 2], timers); + esp_hal_embassy::init(&clocks, timers); 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 d4469b728..63121a7fc 100644 --- a/examples/src/bin/embassy_multiprio.rs +++ b/examples/src/bin/embassy_multiprio.rs @@ -15,7 +15,7 @@ // The interrupt-executor is created in `main` and is used to spawn `high_prio`. //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: embassy esp-hal-embassy/log esp-hal-embassy/integrated-timers #![no_std] #![no_main] @@ -29,12 +29,22 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{/*systimer::SystemTimer,*/ timg::TimerGroup, ErasedTimer, OneShotTimer}, }; use esp_hal_embassy::InterruptExecutor; use esp_println::println; use static_cell::StaticCell; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + /// Periodically print something. #[embassy_executor::task] async fn high_prio() { @@ -78,8 +88,21 @@ async fn main(low_prio_spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timer0 = OneShotTimer::new(timg0.timer0.into()); + #[cfg(not(feature = "esp32c2"))] + let timer1 = { + let timg1 = TimerGroup::new(peripherals.TIMG1, &clocks, None); + OneShotTimer::new(timg1.timer0.into()) + }; + #[cfg(feature = "esp32c2")] + let timer1 = { + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + OneShotTimer::new(systimer.alarm0.into()) + }; + let timers = [timer0, timer1]; + let timers = mk_static!([OneShotTimer; 2], timers); + esp_hal_embassy::init(&clocks, timers); static EXECUTOR: StaticCell> = StaticCell::new(); let executor = InterruptExecutor::new(system.software_interrupt_control.software_interrupt2); diff --git a/examples/src/bin/embassy_parl_io_rx.rs b/examples/src/bin/embassy_parl_io_rx.rs index b1f178f9c..9ecb65d74 100644 --- a/examples/src/bin/embassy_parl_io_rx.rs +++ b/examples/src/bin/embassy_parl_io_rx.rs @@ -4,7 +4,7 @@ //! Uses GPIO 1, 2, 3 and 4 as the data pins. //% CHIPS: esp32c6 esp32h2 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -21,10 +21,20 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{systimer::SystemTimer, ErasedTimer, OneShotTimer}, }; use esp_println::println; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[main] async fn main(_spawner: Spawner) { esp_println::println!("Init!"); @@ -32,8 +42,10 @@ async fn main(_spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let systimer = SystemTimer::new(peripherals.SYSTIMER); + let timers = [OneShotTimer::new(systimer.alarm0.into())]; + let timers = mk_static!([OneShotTimer; 1], timers); + esp_hal_embassy::init(&clocks, timers); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); diff --git a/examples/src/bin/embassy_parl_io_tx.rs b/examples/src/bin/embassy_parl_io_tx.rs index a39732322..84fc5d737 100644 --- a/examples/src/bin/embassy_parl_io_tx.rs +++ b/examples/src/bin/embassy_parl_io_tx.rs @@ -8,7 +8,7 @@ //! You can use a logic analyzer to see how the pins are used. //% CHIPS: esp32c6 esp32h2 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -32,10 +32,20 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{systimer::SystemTimer, ErasedTimer, OneShotTimer}, }; use esp_println::println; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[main] async fn main(_spawner: Spawner) { esp_println::println!("Init!"); @@ -43,12 +53,14 @@ async fn main(_spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let systimer = SystemTimer::new(peripherals.SYSTIMER); + let timers = [OneShotTimer::new(systimer.alarm0.into())]; + let timers = mk_static!([OneShotTimer; 1], timers); + esp_hal_embassy::init(&clocks, timers); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); - let (tx_buffer, mut tx_descriptors, _, _) = dma_buffers!(32000, 0); + let (tx_buffer, tx_descriptors, _, _) = dma_buffers!(32000, 0); let dma = Dma::new(peripherals.DMA); let dma_channel = dma.channel0; diff --git a/examples/src/bin/embassy_rmt_rx.rs b/examples/src/bin/embassy_rmt_rx.rs index d3039dc92..2a1a711c1 100644 --- a/examples/src/bin/embassy_rmt_rx.rs +++ b/examples/src/bin/embassy_rmt_rx.rs @@ -2,7 +2,7 @@ //! Connect GPIO5 to GPIO4 //% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -17,6 +17,7 @@ use esp_hal::{ prelude::*, rmt::{asynch::RxChannelAsync, PulseCode, Rmt, RxChannelConfig, RxChannelCreatorAsync}, system::SystemControl, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; use esp_println::{print, println}; @@ -25,6 +26,16 @@ const WIDTH: usize = 80; #[cfg(debug_assertions)] compile_error!("Run this example in release mode"); +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[embassy_executor::task] async fn signal_task(mut pin: Output<'static, Gpio5>) { loop { @@ -43,8 +54,11 @@ async fn main(spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timer_group0 = esp_hal::timer::timg::TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timer_group0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timer0 = OneShotTimer::new(timg0.timer0.into()); + let timers = [timer0]; + let timers = mk_static!([OneShotTimer; 1], timers); + esp_hal_embassy::init(&clocks, timers); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); diff --git a/examples/src/bin/embassy_rmt_tx.rs b/examples/src/bin/embassy_rmt_tx.rs index 81c88bf98..1ba8d0819 100644 --- a/examples/src/bin/embassy_rmt_tx.rs +++ b/examples/src/bin/embassy_rmt_tx.rs @@ -3,7 +3,7 @@ //! Connect a logic analyzer to GPIO4 to see the generated pulses. //% CHIPS: esp32 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -18,10 +18,20 @@ use esp_hal::{ prelude::*, rmt::{asynch::TxChannelAsync, PulseCode, Rmt, TxChannelConfig, TxChannelCreatorAsync}, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; use esp_println::println; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[main] async fn main(_spawner: Spawner) { println!("Init!"); @@ -29,8 +39,11 @@ async fn main(_spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timer0 = OneShotTimer::new(timg0.timer0.into()); + let timers = [timer0]; + let timers = mk_static!([OneShotTimer; 1], timers); + esp_hal_embassy::init(&clocks, timers); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); diff --git a/examples/src/bin/embassy_serial.rs b/examples/src/bin/embassy_serial.rs index e06ebfe8c..cfdda19aa 100644 --- a/examples/src/bin/embassy_serial.rs +++ b/examples/src/bin/embassy_serial.rs @@ -7,7 +7,7 @@ #![no_main] //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers use embassy_executor::Spawner; use embassy_sync::{blocking_mutex::raw::NoopRawMutex, signal::Signal}; @@ -18,7 +18,7 @@ use esp_hal::{ peripherals::{Peripherals, UART0}, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, uart::{ config::{AtCmdConfig, Config}, Uart, @@ -34,6 +34,16 @@ const READ_BUF_SIZE: usize = 64; // EOT (CTRL-D) const AT_CMD: u8 = 0x04; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[embassy_executor::task] async fn writer( mut tx: UartTx<'static, UART0, Async>, @@ -85,8 +95,11 @@ async fn main(spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timer0 = OneShotTimer::new(timg0.timer0.into()); + let timers = [timer0]; + let timers = mk_static!([OneShotTimer; 1], timers); + esp_hal_embassy::init(&clocks, timers); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); diff --git a/examples/src/bin/embassy_spi.rs b/examples/src/bin/embassy_spi.rs index 6e65ba904..9e363d7ac 100644 --- a/examples/src/bin/embassy_spi.rs +++ b/examples/src/bin/embassy_spi.rs @@ -15,7 +15,7 @@ //! This is an example of running the embassy executor with SPI. //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -35,9 +35,19 @@ use esp_hal::{ SpiMode, }, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[main] async fn main(_spawner: Spawner) { esp_println::println!("Init!"); @@ -45,8 +55,12 @@ async fn main(_spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timers = mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg0.timer0.into())] + ); + esp_hal_embassy::init(&clocks, timers); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let sclk = io.pins.gpio0; diff --git a/examples/src/bin/embassy_twai.rs b/examples/src/bin/embassy_twai.rs index 2f45b8376..aa9d64b40 100644 --- a/examples/src/bin/embassy_twai.rs +++ b/examples/src/bin/embassy_twai.rs @@ -11,7 +11,7 @@ //! with `IS_SENDER` set to `true`. //% CHIPS: esp32c3 esp32c6 esp32s2 esp32s3 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -27,7 +27,7 @@ use esp_hal::{ peripherals::{self, Peripherals, TWAI0}, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, twai::{self, EspTwaiFrame, TwaiRx, TwaiTx}, }; use esp_println::println; @@ -35,6 +35,16 @@ use static_cell::StaticCell; type TwaiOutbox = Channel; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[embassy_executor::task] async fn receiver( mut rx: TwaiRx<'static, TWAI0, esp_hal::Async>, @@ -85,8 +95,12 @@ async fn main(spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + let timers = mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg0.timer0.into())] + ); + esp_hal_embassy::init(&clocks, timers); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); diff --git a/examples/src/bin/embassy_usb_serial.rs b/examples/src/bin/embassy_usb_serial.rs index e92d338ff..1daeefbd7 100644 --- a/examples/src/bin/embassy_usb_serial.rs +++ b/examples/src/bin/embassy_usb_serial.rs @@ -3,7 +3,7 @@ //! This example should be built in release mode. //% CHIPS: esp32s2 esp32s3 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -26,9 +26,19 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[main] async fn main(_spawner: Spawner) -> () { esp_println::println!("Init!"); @@ -36,7 +46,15 @@ async fn main(_spawner: Spawner) -> () { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - esp_hal_embassy::init(&clocks, TimerGroup::new_async(peripherals.TIMG0, &clocks)); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg0.timer0.into())] + ), + ); + let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); let usb = Usb::new(peripherals.USB0, io.pins.gpio20, io.pins.gpio19); diff --git a/examples/src/bin/embassy_usb_serial_jtag.rs b/examples/src/bin/embassy_usb_serial_jtag.rs index 46e5bb711..b7d072ae7 100644 --- a/examples/src/bin/embassy_usb_serial_jtag.rs +++ b/examples/src/bin/embassy_usb_serial_jtag.rs @@ -3,7 +3,7 @@ //! Most dev-kits use a USB-UART-bridge - in that case you won't see any output. //% CHIPS: esp32c3 esp32c6 esp32h2 esp32s3 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -16,7 +16,7 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, usb_serial_jtag::{UsbSerialJtag, UsbSerialJtagRx, UsbSerialJtagTx}, Async, }; @@ -24,6 +24,16 @@ use static_cell::StaticCell; const MAX_BUFFER_SIZE: usize = 512; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[embassy_executor::task] async fn writer( mut tx: UsbSerialJtagTx<'static, Async>, @@ -70,7 +80,14 @@ async fn main(spawner: Spawner) -> () { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - esp_hal_embassy::init(&clocks, TimerGroup::new_async(peripherals.TIMG0, &clocks)); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg0.timer0.into())] + ), + ); let (tx, rx) = UsbSerialJtag::new_async(peripherals.USB_DEVICE).split(); diff --git a/examples/src/bin/embassy_wait.rs b/examples/src/bin/embassy_wait.rs index 5aff83fc4..33271a4d9 100644 --- a/examples/src/bin/embassy_wait.rs +++ b/examples/src/bin/embassy_wait.rs @@ -3,7 +3,7 @@ //! This is an example of asynchronously `Wait`ing for a pin state to change. //% CHIPS: esp32 esp32c2 esp32c3 esp32c6 esp32h2 esp32s2 esp32s3 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers +//% FEATURES: async embassy embassy-generic-timers #![no_std] #![no_main] @@ -17,9 +17,19 @@ use esp_hal::{ peripherals::Peripherals, prelude::*, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[main] async fn main(_spawner: Spawner) { esp_println::println!("Init!"); @@ -27,8 +37,14 @@ async fn main(_spawner: Spawner) { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::boot_defaults(system.clock_control).freeze(); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg0.timer0.into())] + ), + ); let io = Io::new(peripherals.GPIO, peripherals.IO_MUX); #[cfg(any(feature = "esp32", feature = "esp32s2", feature = "esp32s3"))] diff --git a/examples/src/bin/esp_wifi_access_point.rs b/examples/src/bin/esp_wifi_access_point.rs index f07db448a..85ddc5f8a 100644 --- a/examples/src/bin/esp_wifi_access_point.rs +++ b/examples/src/bin/esp_wifi_access_point.rs @@ -21,6 +21,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, + timer::PeriodicTimer, }; use esp_println::{print, println}; use esp_wifi::{ @@ -46,10 +47,12 @@ fn main() -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Wifi, timer, diff --git a/examples/src/bin/esp_wifi_access_point_with_sta.rs b/examples/src/bin/esp_wifi_access_point_with_sta.rs index a0d8537df..e812554c3 100644 --- a/examples/src/bin/esp_wifi_access_point_with_sta.rs +++ b/examples/src/bin/esp_wifi_access_point_with_sta.rs @@ -22,6 +22,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, + timer::PeriodicTimer, }; use esp_println::{print, println}; use esp_wifi::{ @@ -54,10 +55,12 @@ fn main() -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Wifi, timer, diff --git a/examples/src/bin/esp_wifi_bench.rs b/examples/src/bin/esp_wifi_bench.rs index 098a07755..b34a41e2a 100644 --- a/examples/src/bin/esp_wifi_bench.rs +++ b/examples/src/bin/esp_wifi_bench.rs @@ -22,6 +22,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, + timer::PeriodicTimer, }; use esp_println::println; use esp_wifi::{ @@ -66,10 +67,12 @@ fn main() -> ! { let server_address: Ipv4Address = HOST_IP.parse().expect("Invalid HOST_IP address"); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Wifi, timer, diff --git a/examples/src/bin/esp_wifi_ble.rs b/examples/src/bin/esp_wifi_ble.rs index 993dfb036..94ab0a826 100644 --- a/examples/src/bin/esp_wifi_ble.rs +++ b/examples/src/bin/esp_wifi_ble.rs @@ -30,6 +30,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, + timer::PeriodicTimer, }; use esp_println::println; use esp_wifi::{ble::controller::BleConnector, initialize, EspWifiInitFor}; @@ -43,10 +44,12 @@ fn main() -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Ble, timer, diff --git a/examples/src/bin/esp_wifi_coex.rs b/examples/src/bin/esp_wifi_coex.rs index 92d4806c5..5292d5748 100644 --- a/examples/src/bin/esp_wifi_coex.rs +++ b/examples/src/bin/esp_wifi_coex.rs @@ -32,6 +32,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, + timer::PeriodicTimer, }; use esp_println::{print, println}; use esp_wifi::{ @@ -59,10 +60,12 @@ fn main() -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::WifiBle, timer, diff --git a/examples/src/bin/esp_wifi_dhcp.rs b/examples/src/bin/esp_wifi_dhcp.rs index 970814025..a40414cc0 100644 --- a/examples/src/bin/esp_wifi_dhcp.rs +++ b/examples/src/bin/esp_wifi_dhcp.rs @@ -19,6 +19,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, + timer::PeriodicTimer, }; use esp_println::{print, println}; use esp_wifi::{ @@ -52,10 +53,12 @@ fn main() -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Wifi, timer, diff --git a/examples/src/bin/esp_wifi_embassy_access_point.rs b/examples/src/bin/esp_wifi_embassy_access_point.rs index c49f74932..228066928 100644 --- a/examples/src/bin/esp_wifi_embassy_access_point.rs +++ b/examples/src/bin/esp_wifi_embassy_access_point.rs @@ -8,7 +8,7 @@ //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: async embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] @@ -33,7 +33,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, - timer::timg::TimerGroup, + timer::{ErasedTimer, OneShotTimer, PeriodicTimer}, }; use esp_println::{print, println}; use esp_wifi::{ @@ -50,6 +50,7 @@ use esp_wifi::{ EspWifiInitFor, }; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html macro_rules! mk_static { ($t:ty,$val:expr) => {{ static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); @@ -68,10 +69,12 @@ async fn main(spawner: Spawner) -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Wifi, timer, @@ -85,8 +88,29 @@ async fn main(spawner: Spawner) -> ! { let (wifi_interface, controller) = esp_wifi::wifi::new_with_mode(&init, wifi, WifiApDevice).unwrap(); - let timer_group0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timer_group0); + #[cfg(feature = "esp32")] + { + let timg1 = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg1.timer0.into())] + ), + ); + } + + #[cfg(not(feature = "esp32"))] + { + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(systimer.alarm0.into())] + ), + ); + } let config = Config::ipv4_static(StaticConfigV4 { address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 2, 1), 24), diff --git a/examples/src/bin/esp_wifi_embassy_access_point_with_sta.rs b/examples/src/bin/esp_wifi_embassy_access_point_with_sta.rs index 955bd4a5e..fe06a9243 100644 --- a/examples/src/bin/esp_wifi_embassy_access_point_with_sta.rs +++ b/examples/src/bin/esp_wifi_embassy_access_point_with_sta.rs @@ -11,7 +11,7 @@ //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: async embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] @@ -36,7 +36,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, - timer::timg::TimerGroup, + timer::{ErasedTimer, OneShotTimer, PeriodicTimer}, }; use esp_println::{print, println}; use esp_wifi::{ @@ -58,6 +58,7 @@ use esp_wifi::{ const SSID: &str = env!("SSID"); const PASSWORD: &str = env!("PASSWORD"); +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html macro_rules! mk_static { ($t:ty,$val:expr) => {{ static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); @@ -76,10 +77,12 @@ async fn main(spawner: Spawner) -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Wifi, timer, @@ -93,8 +96,29 @@ async fn main(spawner: Spawner) -> ! { let (wifi_ap_interface, wifi_sta_interface, mut controller) = esp_wifi::wifi::new_ap_sta(&init, wifi).unwrap(); - let timer_group0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timer_group0); + #[cfg(feature = "esp32")] + { + let timg1 = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg1.timer0.into())] + ), + ); + } + + #[cfg(not(feature = "esp32"))] + { + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(systimer.alarm0.into())] + ), + ); + } let ap_config = Config::ipv4_static(StaticConfigV4 { address: Ipv4Cidr::new(Ipv4Address::new(192, 168, 2, 1), 24), diff --git a/examples/src/bin/esp_wifi_embassy_bench.rs b/examples/src/bin/esp_wifi_embassy_bench.rs index ff99b270a..75ef2ef6e 100644 --- a/examples/src/bin/esp_wifi_embassy_bench.rs +++ b/examples/src/bin/esp_wifi_embassy_bench.rs @@ -10,7 +10,7 @@ //! Because of the huge task-arena size configured this won't work on ESP32-S2 and ESP32-C2 //! -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: async embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s3 esp32c3 esp32c6 #![no_std] @@ -27,7 +27,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, - timer::timg::TimerGroup, + timer::{ErasedTimer, OneShotTimer, PeriodicTimer}, }; use esp_println::println; use esp_wifi::{ @@ -44,6 +44,7 @@ use esp_wifi::{ EspWifiInitFor, }; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html macro_rules! mk_static { ($t:ty,$val:expr) => {{ static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); @@ -80,10 +81,12 @@ async fn main(spawner: Spawner) -> ! { let server_address: Ipv4Address = HOST_IP.parse().expect("Invalid HOST_IP address"); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Wifi, timer, @@ -97,8 +100,29 @@ async fn main(spawner: Spawner) -> ! { let (wifi_interface, controller) = esp_wifi::wifi::new_with_mode(&init, wifi, WifiStaDevice).unwrap(); - let timer_group0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timer_group0); + #[cfg(feature = "esp32")] + { + let timg1 = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg1.timer0.into())] + ), + ); + } + + #[cfg(not(feature = "esp32"))] + { + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(systimer.alarm0.into())] + ), + ); + } let config = Config::dhcpv4(Default::default()); diff --git a/examples/src/bin/esp_wifi_embassy_ble.rs b/examples/src/bin/esp_wifi_embassy_ble.rs index a6037a173..11ae185e5 100644 --- a/examples/src/bin/esp_wifi_embassy_ble.rs +++ b/examples/src/bin/esp_wifi_embassy_ble.rs @@ -4,7 +4,7 @@ //! - offers one service with three characteristics (one is read/write, one is write only, one is read/write/notify) //! - pressing the boot-button on a dev-board will send a notification if it is subscribed -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/ble +//% FEATURES: async embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/ble //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 esp32h2 #![no_std] @@ -33,11 +33,21 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, - timer::timg::TimerGroup, + timer::{ErasedTimer, OneShotTimer, PeriodicTimer}, }; use esp_println::println; use esp_wifi::{ble::controller::asynch::BleConnector, initialize, EspWifiInitFor}; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[main] async fn main(_spawner: Spawner) -> ! { esp_println::logger::init_logger_from_env(); @@ -47,10 +57,12 @@ async fn main(_spawner: Spawner) -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Ble, timer, @@ -71,8 +83,29 @@ async fn main(_spawner: Spawner) -> ! { ))] let button = Input::new(io.pins.gpio9, Pull::Down); - let timer_group0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timer_group0); + #[cfg(feature = "esp32")] + { + let timg1 = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg1.timer0.into())] + ), + ); + } + + #[cfg(not(feature = "esp32"))] + { + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(systimer.alarm0.into())] + ), + ); + } let mut bluetooth = peripherals.BT; diff --git a/examples/src/bin/esp_wifi_embassy_dhcp.rs b/examples/src/bin/esp_wifi_embassy_dhcp.rs index 2526a48f7..7598eb2ea 100644 --- a/examples/src/bin/esp_wifi_embassy_dhcp.rs +++ b/examples/src/bin/esp_wifi_embassy_dhcp.rs @@ -7,7 +7,7 @@ //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils +//% FEATURES: async embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] @@ -23,7 +23,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, - timer::timg::TimerGroup, + timer::{ErasedTimer, OneShotTimer, PeriodicTimer}, }; use esp_println::println; use esp_wifi::{ @@ -40,6 +40,7 @@ use esp_wifi::{ EspWifiInitFor, }; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html macro_rules! mk_static { ($t:ty,$val:expr) => {{ static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); @@ -61,10 +62,12 @@ async fn main(spawner: Spawner) -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Wifi, timer, @@ -78,8 +81,29 @@ async fn main(spawner: Spawner) -> ! { let (wifi_interface, controller) = esp_wifi::wifi::new_with_mode(&init, wifi, WifiStaDevice).unwrap(); - let timer_group0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timer_group0); + #[cfg(feature = "esp32")] + { + let timg1 = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg1.timer0.into())] + ), + ); + } + + #[cfg(not(feature = "esp32"))] + { + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(systimer.alarm0.into())] + ), + ); + } let config = Config::dhcpv4(Default::default()); diff --git a/examples/src/bin/esp_wifi_embassy_esp_now.rs b/examples/src/bin/esp_wifi_embassy_esp_now.rs index b23c29dc9..64d139665 100644 --- a/examples/src/bin/esp_wifi_embassy_esp_now.rs +++ b/examples/src/bin/esp_wifi_embassy_esp_now.rs @@ -4,7 +4,7 @@ //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now +//% FEATURES: async embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] @@ -20,7 +20,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, - timer::timg::TimerGroup, + timer::{ErasedTimer, OneShotTimer, PeriodicTimer}, }; use esp_println::println; use esp_wifi::{ @@ -29,6 +29,16 @@ use esp_wifi::{ EspWifiInitFor, }; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html +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 + }}; +} + #[main] async fn main(_spawner: Spawner) -> ! { esp_println::logger::init_logger_from_env(); @@ -38,10 +48,12 @@ async fn main(_spawner: Spawner) -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Wifi, timer, @@ -55,8 +67,29 @@ async fn main(_spawner: Spawner) -> ! { let mut esp_now = esp_wifi::esp_now::EspNow::new(&init, wifi).unwrap(); println!("esp-now version {}", esp_now.get_version().unwrap()); - let timer_group0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timer_group0); + #[cfg(feature = "esp32")] + { + let timg1 = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg1.timer0.into())] + ), + ); + } + + #[cfg(not(feature = "esp32"))] + { + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(systimer.alarm0.into())] + ), + ); + } let mut ticker = Ticker::every(Duration::from_secs(5)); loop { diff --git a/examples/src/bin/esp_wifi_embassy_esp_now_duplex.rs b/examples/src/bin/esp_wifi_embassy_esp_now_duplex.rs index 9038a09ae..c48ccbe78 100644 --- a/examples/src/bin/esp_wifi_embassy_esp_now_duplex.rs +++ b/examples/src/bin/esp_wifi_embassy_esp_now_duplex.rs @@ -4,7 +4,7 @@ //! //! Because of the huge task-arena size configured this won't work on ESP32-S2 -//% FEATURES: async embassy embassy-time-timg0 embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now +//% FEATURES: async embassy embassy-generic-timers esp-wifi esp-wifi/async esp-wifi/embassy-net esp-wifi/wifi-default esp-wifi/wifi esp-wifi/utils esp-wifi/esp-now //% CHIPS: esp32 esp32s3 esp32c2 esp32c3 esp32c6 #![no_std] @@ -20,7 +20,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, - timer::timg::TimerGroup, + timer::{ErasedTimer, OneShotTimer, PeriodicTimer}, }; use esp_println::println; use esp_wifi::{ @@ -29,6 +29,7 @@ use esp_wifi::{ EspWifiInitFor, }; +// When you are okay with using a nightly compiler it's better to use https://docs.rs/static_cell/2.1.0/static_cell/macro.make_static.html macro_rules! mk_static { ($t:ty,$val:expr) => {{ static STATIC_CELL: static_cell::StaticCell<$t> = static_cell::StaticCell::new(); @@ -47,10 +48,12 @@ async fn main(spawner: Spawner) -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Wifi, timer, @@ -64,8 +67,29 @@ async fn main(spawner: Spawner) -> ! { let esp_now = esp_wifi::esp_now::EspNow::new(&init, wifi).unwrap(); println!("esp-now version {}", esp_now.get_version().unwrap()); - let timer_group0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timer_group0); + #[cfg(feature = "esp32")] + { + let timg1 = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg1.timer0.into())] + ), + ); + } + + #[cfg(not(feature = "esp32"))] + { + let systimer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(systimer.alarm0.into())] + ), + ); + } let (manager, sender, receiver) = esp_now.split(); let manager = mk_static!(EspNowManager<'static>, manager); diff --git a/examples/src/bin/esp_wifi_esp_now.rs b/examples/src/bin/esp_wifi_esp_now.rs index 7e2829e4c..5cf01d863 100644 --- a/examples/src/bin/esp_wifi_esp_now.rs +++ b/examples/src/bin/esp_wifi_esp_now.rs @@ -15,6 +15,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, + timer::PeriodicTimer, }; use esp_println::println; use esp_wifi::{ @@ -33,10 +34,12 @@ fn main() -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Wifi, timer, diff --git a/examples/src/bin/esp_wifi_static_ip.rs b/examples/src/bin/esp_wifi_static_ip.rs index c9b6e6af8..49829bcb2 100644 --- a/examples/src/bin/esp_wifi_static_ip.rs +++ b/examples/src/bin/esp_wifi_static_ip.rs @@ -20,6 +20,7 @@ use esp_hal::{ prelude::*, rng::Rng, system::SystemControl, + timer::PeriodicTimer, }; use esp_println::{print, println}; use esp_wifi::{ @@ -52,10 +53,12 @@ fn main() -> ! { let system = SystemControl::new(peripherals.SYSTEM); let clocks = ClockControl::max(system.clock_control).freeze(); - #[cfg(target_arch = "xtensa")] - let timer = esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG1, &clocks, None).timer0; - #[cfg(target_arch = "riscv32")] - let timer = esp_hal::timer::systimer::SystemTimer::new(peripherals.SYSTIMER).alarm0; + let timer = PeriodicTimer::new( + esp_hal::timer::timg::TimerGroup::new(peripherals.TIMG0, &clocks, None) + .timer0 + .into(), + ); + let init = initialize( EspWifiInitFor::Wifi, timer, diff --git a/hil-test/Cargo.toml b/hil-test/Cargo.toml index 9da5b2d3b..9e9bc7456 100644 --- a/hil-test/Cargo.toml +++ b/hil-test/Cargo.toml @@ -106,6 +106,7 @@ esp-backtrace = { path = "../esp-backtrace", default-features = false, feat esp-hal = { path = "../esp-hal", features = ["defmt", "embedded-hal", "embedded-hal-02"], optional = true } esp-hal-embassy = { path = "../esp-hal-embassy", optional = true } portable-atomic = "1.6.0" +static_cell = { version = "2.0.0", features = ["nightly"] } [dev-dependencies] crypto-bigint = { version = "0.5.5", default-features = false } @@ -122,7 +123,7 @@ p256 = { version = "0.13.2", default-features = false, features = semihosting = { git = "https://github.com/taiki-e/semihosting", tag = "v0.1.10" } [features] -default = ["async", "embassy", "embassy-time-timg0"] +default = ["async", "embassy"] # Device support (required!): esp32 = [ @@ -154,9 +155,6 @@ embassy = [ "embedded-test/external-executor", "dep:esp-hal-embassy", ] -embassy-time-systimer-16mhz = ["esp-hal-embassy/time-systimer-16mhz"] -embassy-time-systimer-80mhz = ["esp-hal-embassy/time-systimer-80mhz"] -embassy-time-timg0 = ["esp-hal-embassy/time-timg0"] # https://doc.rust-lang.org/cargo/reference/profiles.html#test # Test and bench profiles inherit from dev and release respectively. diff --git a/hil-test/tests/gpio.rs b/hil-test/tests/gpio.rs index 918ed4f65..271a89091 100644 --- a/hil-test/tests/gpio.rs +++ b/hil-test/tests/gpio.rs @@ -21,9 +21,18 @@ use esp_hal::{ macros::handler, peripherals::Peripherals, system::SystemControl, - timer::timg::TimerGroup, + timer::{timg::TimerGroup, ErasedTimer, OneShotTimer}, }; +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 + }}; +} + static COUNTER: Mutex> = Mutex::new(RefCell::new(0)); static INPUT_PIN: Mutex>>> = Mutex::new(RefCell::new(None)); @@ -44,8 +53,14 @@ impl<'d> Context<'d> { let delay = Delay::new(&clocks); - let timg0 = TimerGroup::new_async(peripherals.TIMG0, &clocks); - esp_hal_embassy::init(&clocks, timg0); + let timg0 = TimerGroup::new(peripherals.TIMG0, &clocks, None); + esp_hal_embassy::init( + &clocks, + mk_static!( + [OneShotTimer; 1], + [OneShotTimer::new(timg0.timer0.into())] + ), + ); Context { io2: Input::new(io.pins.gpio2, Pull::Down), diff --git a/xtask/src/main.rs b/xtask/src/main.rs index 806af762f..bc8eae358 100644 --- a/xtask/src/main.rs +++ b/xtask/src/main.rs @@ -487,18 +487,14 @@ fn lint_packages(workspace: &Path, _args: LintPackagesArgs) -> Result<()> { } Package::EspHalEmbassy => { - // We need to specify a time driver, so we will check all - // options here (as the modules themselves are feature-gated): - for feature in ["time-systimer-16mhz", "time-timg0"] { - lint_package( - &path, - &[ - "-Zbuild-std=core", - "--target=riscv32imac-unknown-none-elf", - &format!("--features=esp32c6,{feature}"), - ], - )?; - } + lint_package( + &path, + &[ + "-Zbuild-std=core", + "--target=riscv32imac-unknown-none-elf", + "--features=esp32c6", + ], + )?; } Package::EspHalProcmacros | Package::EspRiscvRt => lint_package( @@ -538,7 +534,7 @@ fn lint_packages(workspace: &Path, _args: LintPackagesArgs) -> Result<()> { &[ "-Zbuild-std=core", "--target=riscv32imc-unknown-none-elf", - "--features=esp32c3,wifi-default,ble,esp-now,async,embassy-net,esp-hal-embassy/time-timg0", + "--features=esp32c3,wifi-default,ble,esp-now,async,embassy-net", ], )?,