diff options
Diffstat (limited to 'src/ostimer.rs')
| -rw-r--r-- | src/ostimer.rs | 62 |
1 files changed, 36 insertions, 26 deletions
diff --git a/src/ostimer.rs b/src/ostimer.rs index 8bc68389a..efa534194 100644 --- a/src/ostimer.rs +++ b/src/ostimer.rs | |||
| @@ -29,8 +29,13 @@ | |||
| 29 | 29 | ||
| 30 | use core::sync::atomic::{AtomicBool, Ordering}; | 30 | use core::sync::atomic::{AtomicBool, Ordering}; |
| 31 | 31 | ||
| 32 | use embassy_hal_internal::{Peri, PeripheralType}; | ||
| 33 | |||
| 34 | use crate::clocks::periph_helpers::{OsTimerConfig, OstimerClockSel}; | ||
| 35 | use crate::clocks::{assert_reset, enable_and_reset, is_reset_released, release_reset, Gate, PoweredClock}; | ||
| 32 | use crate::interrupt::InterruptExt; | 36 | use crate::interrupt::InterruptExt; |
| 33 | use crate::pac; | 37 | use crate::pac; |
| 38 | use crate::peripherals::OSTIMER0; | ||
| 34 | 39 | ||
| 35 | // PAC defines the shared RegisterBlock under `ostimer0`. | 40 | // PAC defines the shared RegisterBlock under `ostimer0`. |
| 36 | type Regs = pac::ostimer0::RegisterBlock; | 41 | type Regs = pac::ostimer0::RegisterBlock; |
| @@ -197,16 +202,16 @@ impl<'d> Alarm<'d> { | |||
| 197 | pub struct Config { | 202 | pub 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 | ||
| 204 | impl Default for Config { | 209 | impl 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 |
| 479 | pub trait Instance { | 489 | pub 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 |
| 494 | impl 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)] |
| 502 | fn bin_to_gray(x: u64) -> u64 { | 512 | fn bin_to_gray(x: u64) -> u64 { |
