From a8eb124e47e633cd81e0863253d5f6bdd7545260 Mon Sep 17 00:00:00 2001 From: Felipe Balbi Date: Wed, 19 Nov 2025 09:11:54 -0800 Subject: OSTimer updates (#24) * Initialize OSTIMER0 during HAL initialization Provide the user with a working time driver. Signed-off-by: Felipe Balbi * Handle time_driver interrupt internally Signed-off-by: Felipe Balbi * Gate `time-driver` impl behind a `time` flag Also prevents creation of an `Ostimer` instance if the `time` feature is active. * Remove some dead code --------- Signed-off-by: Felipe Balbi Co-authored-by: James Munns --- src/clocks/mod.rs | 6 +++- src/config.rs | 2 ++ src/lib.rs | 11 ++++++- src/ostimer.rs | 88 ++++++++++++++++++++++++++++++++++++++++--------------- 4 files changed, 81 insertions(+), 26 deletions(-) (limited to 'src') diff --git a/src/clocks/mod.rs b/src/clocks/mod.rs index 558fb0278..a12e125c6 100644 --- a/src/clocks/mod.rs +++ b/src/clocks/mod.rs @@ -867,7 +867,9 @@ macro_rules! impl_cc_gate { /// This module contains implementations of MRCC APIs, specifically of the [`Gate`] trait, /// for various low level peripherals. pub(crate) mod gate { - use super::periph_helpers::{AdcConfig, LpuartConfig, NoConfig, OsTimerConfig}; + #[cfg(not(feature = "time"))] + use super::periph_helpers::OsTimerConfig; + use super::periph_helpers::{AdcConfig, LpuartConfig, NoConfig}; use super::*; // These peripherals have no additional upstream clocks or configuration required @@ -888,7 +890,9 @@ pub(crate) mod gate { // These peripherals DO have meaningful configuration, and could fail if the system // clocks do not match their needs. + #[cfg(not(feature = "time"))] impl_cc_gate!(OSTIMER0, mrcc_glb_cc1, mrcc_glb_rst1, ostimer0, OsTimerConfig); + impl_cc_gate!(LPUART2, mrcc_glb_cc0, mrcc_glb_rst0, lpuart2, LpuartConfig); impl_cc_gate!(ADC1, mrcc_glb_cc1, mrcc_glb_rst1, adc1, AdcConfig); } diff --git a/src/config.rs b/src/config.rs index 0939c11f1..9c0d47ecb 100644 --- a/src/config.rs +++ b/src/config.rs @@ -5,6 +5,7 @@ use crate::interrupt::Priority; #[non_exhaustive] pub struct Config { + #[cfg(feature = "time")] pub time_interrupt_priority: Priority, pub rtc_interrupt_priority: Priority, pub adc_interrupt_priority: Priority, @@ -14,6 +15,7 @@ pub struct Config { impl Default for Config { fn default() -> Self { Self { + #[cfg(feature = "time")] time_interrupt_priority: Priority::from(0), rtc_interrupt_priority: Priority::from(0), adc_interrupt_priority: Priority::from(0), diff --git a/src/lib.rs b/src/lib.rs index c885ecc50..e93ff61a6 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -14,6 +14,9 @@ pub mod lpuart; pub mod ostimer; pub mod rtc; +#[cfg(feature = "rt")] +pub use crate::pac::NVIC_PRIO_BITS; + #[rustfmt::skip] embassy_hal_internal::peripherals!( ADC0, @@ -83,6 +86,8 @@ embassy_hal_internal::peripherals!( MBC0, MRCC0, OPAMP0, + + #[cfg(not(feature = "time"))] OSTIMER0, P0_0, @@ -335,7 +340,6 @@ pub use interrupt::InterruptExt; pub use mcxa_pac as pac; #[cfg(not(feature = "unstable-pac"))] pub(crate) use mcxa_pac as pac; -pub use ostimer::Ostimer0 as Ostimer0Token; pub use rtc::Rtc0 as Rtc0Token; /// Initialize HAL with configuration (mirrors embassy-imxrt style). Minimal: just take peripherals. @@ -343,6 +347,7 @@ pub use rtc::Rtc0 as Rtc0Token; pub fn init(cfg: crate::config::Config) -> Peripherals { let peripherals = Peripherals::take(); // Apply user-configured priority early; enabling is left to examples/apps + #[cfg(feature = "time")] crate::interrupt::OS_EVENT.set_priority(cfg.time_interrupt_priority); // Apply user-configured priority early; enabling is left to examples/apps crate::interrupt::RTC.set_priority(cfg.rtc_interrupt_priority); @@ -352,6 +357,10 @@ pub fn init(cfg: crate::config::Config) -> Peripherals { // Configure clocks crate::clocks::init(cfg.clock_cfg).unwrap(); + // Initialize embassy-time global driver backed by OSTIMER0 + #[cfg(feature = "time")] + crate::ostimer::time_driver::init(crate::config::Config::default().time_interrupt_priority, 1_000_000); + // Enable GPIO clocks unsafe { _ = crate::clocks::enable_and_reset::(&crate::clocks::periph_helpers::NoConfig); diff --git a/src/ostimer.rs b/src/ostimer.rs index cd5451b53..c51812e3d 100644 --- a/src/ostimer.rs +++ b/src/ostimer.rs @@ -35,7 +35,6 @@ use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel}; use crate::clocks::{assert_reset, enable_and_reset, is_reset_released, release_reset, Gate, PoweredClock}; use crate::interrupt::InterruptExt; use crate::pac; -use crate::peripherals::OSTIMER0; // PAC defines the shared RegisterBlock under `ostimer0`. type Regs = pac::ostimer0::RegisterBlock; @@ -283,15 +282,15 @@ impl<'d, I: Instance> Ostimer<'d, I> { .write(|w| w.ostimer_intrflag().clear_bit_by_one().ostimer_intena().clear_bit()); unsafe { - assert_reset::(); + assert_reset::(); for _ in 0..RESET_STABILIZE_SPINS { cortex_m::asm::nop(); } - release_reset::(); + release_reset::(); - while !is_reset_released::() { + while !is_reset_released::() { cortex_m::asm::nop(); } } @@ -490,9 +489,7 @@ pub trait Instance: Gate + PeripheralType { fn ptr() -> *const Regs; } -// Token for OSTIMER0 provided by embassy-hal-internal peripherals macro. -pub type Ostimer0 = crate::peripherals::OSTIMER0; - +#[cfg(not(feature = "time"))] impl Instance for crate::peripherals::OSTIMER0 { #[inline(always)] fn ptr() -> *const Regs { @@ -500,14 +497,6 @@ impl Instance for crate::peripherals::OSTIMER0 { } } -// Also implement Instance for the Peri wrapper type -// impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::OSTIMER0> { -// #[inline(always)] -// fn ptr() -> *const Regs { -// pac::Ostimer0::ptr() -// } -// } - #[inline(always)] fn bin_to_gray(x: u64) -> u64 { x ^ (x >> 1) @@ -523,6 +512,7 @@ fn gray_to_bin(gray: u64) -> u64 { bin } +#[cfg(feature = "time")] pub mod time_driver { use core::sync::atomic::Ordering; use core::task::Waker; @@ -537,7 +527,55 @@ pub mod time_driver { use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel}; use crate::clocks::{enable_and_reset, PoweredClock}; use crate::pac; - use crate::peripherals::OSTIMER0; + + #[allow(non_camel_case_types)] + pub(crate) struct _OSTIMER0_TIME_DRIVER { + _x: (), + } + + // #[cfg(feature = "time")] + // impl_cc_gate!(_OSTIMER0_TIME_DRIVER, mrcc_glb_cc1, mrcc_glb_rst1, ostimer0, OsTimerConfig); + + impl crate::clocks::Gate for _OSTIMER0_TIME_DRIVER { + type MrccPeriphConfig = crate::clocks::periph_helpers::OsTimerConfig; + + #[inline] + unsafe fn enable_clock() { + let mrcc = unsafe { pac::Mrcc0::steal() }; + mrcc.mrcc_glb_cc1().modify(|_, w| w.ostimer0().enabled()); + } + + #[inline] + unsafe fn disable_clock() { + let mrcc = unsafe { pac::Mrcc0::steal() }; + mrcc.mrcc_glb_cc1().modify(|_r, w| w.ostimer0().disabled()); + } + + #[inline] + fn is_clock_enabled() -> bool { + let mrcc = unsafe { pac::Mrcc0::steal() }; + mrcc.mrcc_glb_cc1().read().ostimer0().is_enabled() + } + + #[inline] + unsafe fn release_reset() { + let mrcc = unsafe { pac::Mrcc0::steal() }; + mrcc.mrcc_glb_rst1().modify(|_, w| w.ostimer0().enabled()); + } + + #[inline] + unsafe fn assert_reset() { + let mrcc = unsafe { pac::Mrcc0::steal() }; + mrcc.mrcc_glb_rst1().modify(|_, w| w.ostimer0().disabled()); + } + + #[inline] + fn is_reset_released() -> bool { + let mrcc = unsafe { pac::Mrcc0::steal() }; + mrcc.mrcc_glb_rst1().read().ostimer0().is_enabled() + } + } + pub struct Driver; static TIMER_WAKER: AtomicWaker = AtomicWaker::new(); @@ -625,7 +663,7 @@ pub mod time_driver { /// The embassy_time_driver macro handles driver registration automatically. pub fn init(priority: crate::interrupt::Priority, frequency_hz: u64) { let _clock_freq = unsafe { - enable_and_reset::(&OsTimerConfig { + enable_and_reset::<_OSTIMER0_TIME_DRIVER>(&OsTimerConfig { power: PoweredClock::AlwaysEnabled, source: OstimerClockSel::Clk1M, }) @@ -694,12 +732,14 @@ pub mod time_driver { } }); } +} - /// Type-level handler to be used with bind_interrupts! for OS_EVENT. - pub struct OsEventHandler; - impl crate::interrupt::typelevel::Handler for OsEventHandler { - unsafe fn on_interrupt() { - on_interrupt(); - } - } +#[cfg(feature = "time")] +use crate::pac::interrupt; + +#[cfg(feature = "time")] +#[allow(non_snake_case)] +#[interrupt] +fn OS_EVENT() { + time_driver::on_interrupt() } -- cgit