aboutsummaryrefslogtreecommitdiff
path: root/src/ostimer.rs
diff options
context:
space:
mode:
authorJames Munns <[email protected]>2025-11-18 14:19:09 +0100
committerGitHub <[email protected]>2025-11-18 14:19:09 +0100
commit5b1149a52dbec9e3bdd10dc341dc0751ab4798a6 (patch)
tree3ff7098471cf660a54a707464a0e2feb2080b09e /src/ostimer.rs
parent62e297c130ac26afe4d7d5752bb79709bd370e39 (diff)
parentc8942aec2478ff077b55da0e86801f8a6a88a7de (diff)
Merge pull request #11 from jamesmunns/james/impl-clocks
Implement initial `clock` driver. This PR introduces an initial two-phase clock driver system: 1. The first stage is responsible for initializing the core/system clocks at the time of `embassy_mcxa::init()` 2. The second stage is done on creation of peripherals This work is limited to currently used clocks and peripherals, but has room for expansion for later peripherals. This model is based on the preliminary refactoring performed for the `embassy-imxrt` crate.
Diffstat (limited to 'src/ostimer.rs')
-rw-r--r--src/ostimer.rs73
1 files changed, 47 insertions, 26 deletions
diff --git a/src/ostimer.rs b/src/ostimer.rs
index 8bc68389a..cd5451b53 100644
--- a/src/ostimer.rs
+++ b/src/ostimer.rs
@@ -29,8 +29,13 @@
29 29
30use core::sync::atomic::{AtomicBool, Ordering}; 30use core::sync::atomic::{AtomicBool, Ordering};
31 31
32use embassy_hal_internal::{Peri, PeripheralType};
33
34use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel};
35use crate::clocks::{assert_reset, enable_and_reset, is_reset_released, release_reset, Gate, PoweredClock};
32use crate::interrupt::InterruptExt; 36use crate::interrupt::InterruptExt;
33use crate::pac; 37use crate::pac;
38use crate::peripherals::OSTIMER0;
34 39
35// PAC defines the shared RegisterBlock under `ostimer0`. 40// PAC defines the shared RegisterBlock under `ostimer0`.
36type Regs = pac::ostimer0::RegisterBlock; 41type Regs = pac::ostimer0::RegisterBlock;
@@ -197,16 +202,16 @@ impl<'d> Alarm<'d> {
197pub struct Config { 202pub struct Config {
198 /// Initialize MATCH registers to their max values and mask/clear the interrupt flag. 203 /// Initialize MATCH registers to their max values and mask/clear the interrupt flag.
199 pub init_match_max: bool, 204 pub init_match_max: bool,
200 /// OSTIMER clock frequency in Hz (must match the actual hardware clock) 205 pub power: PoweredClock,
201 pub clock_frequency_hz: u64, 206 pub source: OstimerClockSel,
202} 207}
203 208
204impl Default for Config { 209impl Default for Config {
205 fn default() -> Self { 210 fn default() -> Self {
206 Self { 211 Self {
207 init_match_max: true, 212 init_match_max: true,
208 // Default to 1MHz - user should override this with actual frequency 213 power: PoweredClock::NormalEnabledDeepSleepDisabled,
209 clock_frequency_hz: 1_000_000, 214 source: OstimerClockSel::Clk1M,
210 } 215 }
211 } 216 }
212} 217}
@@ -222,8 +227,16 @@ impl<'d, I: Instance> Ostimer<'d, I> {
222 /// Construct OSTIMER handle. 227 /// Construct OSTIMER handle.
223 /// Requires clocks for the instance to be enabled by the board before calling. 228 /// Requires clocks for the instance to be enabled by the board before calling.
224 /// Does not enable NVIC or INTENA; use time_driver::init() for async operation. 229 /// Does not enable NVIC or INTENA; use time_driver::init() for async operation.
225 pub fn new(_inst: impl Instance, cfg: Config, _p: &'d crate::pac::Peripherals) -> Self { 230 pub fn new(_inst: Peri<'d, I>, cfg: Config) -> Self {
226 assert!(cfg.clock_frequency_hz > 0, "OSTIMER frequency must be greater than 0"); 231 let clock_freq = unsafe {
232 enable_and_reset::<I>(&OsTimerConfig {
233 power: cfg.power,
234 source: cfg.source,
235 })
236 .expect("Enabling OsTimer clock should not fail")
237 };
238
239 assert!(clock_freq > 0, "OSTIMER frequency must be greater than 0");
227 240
228 if cfg.init_match_max { 241 if cfg.init_match_max {
229 let r: &Regs = unsafe { &*I::ptr() }; 242 let r: &Regs = unsafe { &*I::ptr() };
@@ -233,7 +246,7 @@ impl<'d, I: Instance> Ostimer<'d, I> {
233 246
234 Self { 247 Self {
235 _inst: core::marker::PhantomData, 248 _inst: core::marker::PhantomData,
236 clock_frequency_hz: cfg.clock_frequency_hz, 249 clock_frequency_hz: clock_freq as u64,
237 _phantom: core::marker::PhantomData, 250 _phantom: core::marker::PhantomData,
238 } 251 }
239 } 252 }
@@ -260,7 +273,7 @@ impl<'d, I: Instance> Ostimer<'d, I> {
260 /// # Safety 273 /// # Safety
261 /// This operation will reset the entire OSTIMER peripheral. Any active alarms 274 /// This operation will reset the entire OSTIMER peripheral. Any active alarms
262 /// or time_driver operations will be disrupted. Use with caution. 275 /// or time_driver operations will be disrupted. Use with caution.
263 pub fn reset(&self, peripherals: &crate::pac::Peripherals) { 276 pub fn reset(&self, _peripherals: &crate::pac::Peripherals) {
264 critical_section::with(|_| { 277 critical_section::with(|_| {
265 let r: &Regs = unsafe { &*I::ptr() }; 278 let r: &Regs = unsafe { &*I::ptr() };
266 279
@@ -270,19 +283,17 @@ impl<'d, I: Instance> Ostimer<'d, I> {
270 .write(|w| w.ostimer_intrflag().clear_bit_by_one().ostimer_intena().clear_bit()); 283 .write(|w| w.ostimer_intrflag().clear_bit_by_one().ostimer_intena().clear_bit());
271 284
272 unsafe { 285 unsafe {
273 crate::reset::assert::<crate::reset::line::Ostimer0>(peripherals); 286 assert_reset::<OSTIMER0>();
274 }
275 287
276 for _ in 0..RESET_STABILIZE_SPINS { 288 for _ in 0..RESET_STABILIZE_SPINS {
277 cortex_m::asm::nop(); 289 cortex_m::asm::nop();
278 } 290 }
279 291
280 unsafe { 292 release_reset::<OSTIMER0>();
281 crate::reset::release::<crate::reset::line::Ostimer0>(peripherals);
282 }
283 293
284 while !<crate::reset::line::Ostimer0 as crate::reset::ResetLine>::is_released(&peripherals.mrcc0) { 294 while !is_reset_released::<OSTIMER0>() {
285 cortex_m::asm::nop(); 295 cortex_m::asm::nop();
296 }
286 } 297 }
287 298
288 for _ in 0..RESET_STABILIZE_SPINS { 299 for _ in 0..RESET_STABILIZE_SPINS {
@@ -469,14 +480,13 @@ fn now_ticks_read() -> u64 {
469 // Read high then low to minimize incoherent snapshots 480 // Read high then low to minimize incoherent snapshots
470 let hi = (r.evtimerh().read().evtimer_count_value().bits() as u64) & (EVTIMER_HI_MASK as u64); 481 let hi = (r.evtimerh().read().evtimer_count_value().bits() as u64) & (EVTIMER_HI_MASK as u64);
471 let lo = r.evtimerl().read().evtimer_count_value().bits() as u64; 482 let lo = r.evtimerl().read().evtimer_count_value().bits() as u64;
472
473 // Combine and convert from Gray code to binary 483 // Combine and convert from Gray code to binary
474 let gray = lo | (hi << EVTIMER_HI_SHIFT); 484 let gray = lo | (hi << EVTIMER_HI_SHIFT);
475 gray_to_bin(gray) 485 gray_to_bin(gray)
476} 486}
477 487
478// Instance trait like other drivers, providing a PAC pointer for this OSTIMER instance 488// Instance trait like other drivers, providing a PAC pointer for this OSTIMER instance
479pub trait Instance { 489pub trait Instance: Gate<MrccPeriphConfig = OsTimerConfig> + PeripheralType {
480 fn ptr() -> *const Regs; 490 fn ptr() -> *const Regs;
481} 491}
482 492
@@ -491,12 +501,12 @@ impl Instance for crate::peripherals::OSTIMER0 {
491} 501}
492 502
493// Also implement Instance for the Peri wrapper type 503// Also implement Instance for the Peri wrapper type
494impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::OSTIMER0> { 504// impl Instance for embassy_hal_internal::Peri<'_, crate::peripherals::OSTIMER0> {
495 #[inline(always)] 505// #[inline(always)]
496 fn ptr() -> *const Regs { 506// fn ptr() -> *const Regs {
497 pac::Ostimer0::ptr() 507// pac::Ostimer0::ptr()
498 } 508// }
499} 509// }
500 510
501#[inline(always)] 511#[inline(always)]
502fn bin_to_gray(x: u64) -> u64 { 512fn bin_to_gray(x: u64) -> u64 {
@@ -524,7 +534,10 @@ pub mod time_driver {
524 bin_to_gray, now_ticks_read, Regs, ALARM_ACTIVE, ALARM_CALLBACK, ALARM_FLAG, ALARM_TARGET_TIME, 534 bin_to_gray, now_ticks_read, Regs, ALARM_ACTIVE, ALARM_CALLBACK, ALARM_FLAG, ALARM_TARGET_TIME,
525 EVTIMER_HI_MASK, EVTIMER_HI_SHIFT, LOW_32_BIT_MASK, 535 EVTIMER_HI_MASK, EVTIMER_HI_SHIFT, LOW_32_BIT_MASK,
526 }; 536 };
537 use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel};
538 use crate::clocks::{enable_and_reset, PoweredClock};
527 use crate::pac; 539 use crate::pac;
540 use crate::peripherals::OSTIMER0;
528 pub struct Driver; 541 pub struct Driver;
529 static TIMER_WAKER: AtomicWaker = AtomicWaker::new(); 542 static TIMER_WAKER: AtomicWaker = AtomicWaker::new();
530 543
@@ -611,6 +624,14 @@ pub mod time_driver {
611 /// Note: The frequency parameter is currently accepted for API compatibility. 624 /// Note: The frequency parameter is currently accepted for API compatibility.
612 /// The embassy_time_driver macro handles driver registration automatically. 625 /// The embassy_time_driver macro handles driver registration automatically.
613 pub fn init(priority: crate::interrupt::Priority, frequency_hz: u64) { 626 pub fn init(priority: crate::interrupt::Priority, frequency_hz: u64) {
627 let _clock_freq = unsafe {
628 enable_and_reset::<OSTIMER0>(&OsTimerConfig {
629 power: PoweredClock::AlwaysEnabled,
630 source: OstimerClockSel::Clk1M,
631 })
632 .expect("Enabling OsTimer clock should not fail")
633 };
634
614 // Mask/clear at peripheral and set default MATCH 635 // Mask/clear at peripheral and set default MATCH
615 let r: &Regs = unsafe { &*pac::Ostimer0::ptr() }; 636 let r: &Regs = unsafe { &*pac::Ostimer0::ptr() };
616 super::prime_match_registers(r); 637 super::prime_match_registers(r);