//! [`Monotonic`](rtic_time::Monotonic) implementation for RP2040's Timer peripheral. //! //! Always runs at a fixed rate of 1 MHz. //! //! # Example //! //! ``` //! use rtic_monotonics::rp2040::prelude::*; //! //! rp2040_timer_monotonic!(Mono); //! //! fn init() { //! # // This is normally provided by the selected PAC //! # let timer = unsafe { core::mem::transmute(()) }; //! # let mut resets = unsafe { core::mem::transmute(()) }; //! # //! // Start the monotonic //! Mono::start(timer, &mut resets); //! } //! //! async fn usage() { //! loop { //! // Use the monotonic //! let timestamp = Mono::now(); //! Mono::delay(100.millis()).await; //! } //! } //! ``` /// Common definitions and traits for using the RP2040 timer monotonic pub mod prelude { pub use crate::rp2040_timer_monotonic; pub use crate::Monotonic; pub use fugit::{self, ExtU64, ExtU64Ceil}; } use crate::TimerQueueBackend; use rp2040_pac::{timer, Interrupt, NVIC}; pub use rp2040_pac::{RESETS, TIMER}; use rtic_time::timer_queue::TimerQueue; /// Timer implementing [`TimerQueueBackend`]. pub struct TimerBackend; impl TimerBackend { /// Starts the monotonic timer. /// /// **Do not use this function directly.** /// /// Use the prelude macros instead. pub fn _start(timer: TIMER, resets: &RESETS) { resets.reset().modify(|_, w| w.timer().clear_bit()); while resets.reset_done().read().timer().bit_is_clear() {} timer.inte().modify(|_, w| w.alarm_0().bit(true)); TIMER_QUEUE.initialize(Self {}); unsafe { crate::set_monotonic_prio(rp2040_pac::NVIC_PRIO_BITS, Interrupt::TIMER_IRQ_0); NVIC::unmask(Interrupt::TIMER_IRQ_0); } } fn timer() -> &'static timer::RegisterBlock { unsafe { &*TIMER::ptr() } } } static TIMER_QUEUE: TimerQueue = TimerQueue::new(); impl TimerQueueBackend for TimerBackend { type Ticks = u64; fn now() -> Self::Ticks { let timer = Self::timer(); let mut hi0 = timer.timerawh().read().bits(); loop { let low = timer.timerawl().read().bits(); let hi1 = timer.timerawh().read().bits(); if hi0 == hi1 { break ((u64::from(hi0) << 32) | u64::from(low)); } hi0 = hi1; } } fn set_compare(instant: Self::Ticks) { let now = Self::now(); const MAX: u64 = u32::MAX as u64; // Since the timer may or may not overflow based on the requested compare val, we check // how many ticks are left. // `wrapping_sup` takes care of the u64 integer overflow special case. let val = if instant.wrapping_sub(now) <= MAX { instant & MAX } else { 0 }; Self::timer() .alarm0() .write(|w| unsafe { w.bits(val as u32) }); } fn clear_compare_flag() { Self::timer().intr().modify(|_, w| w.alarm_0().bit(true)); } fn pend_interrupt() { rp2040_pac::NVIC::pend(Interrupt::TIMER_IRQ_0); } fn timer_queue() -> &'static TimerQueue { &TIMER_QUEUE } } /// Create an RP2040 timer based monotonic and register the necessary interrupt for it. /// /// See [`crate::rp2040`] for more details. /// /// # Arguments /// /// * `name` - The name that the monotonic type will have. #[macro_export] macro_rules! rp2040_timer_monotonic { ($name:ident) => { /// A `Monotonic` based on the RP2040 Timer peripheral. struct $name; impl $name { /// Starts the `Monotonic`. /// /// This method must be called only once. pub fn start(timer: $crate::rp2040::TIMER, resets: &$crate::rp2040::RESETS) { #[no_mangle] #[allow(non_snake_case)] unsafe extern "C" fn TIMER_IRQ_0() { use $crate::TimerQueueBackend; $crate::rp2040::TimerBackend::timer_queue().on_monotonic_interrupt(); } $crate::rp2040::TimerBackend::_start(timer, resets); } } impl $crate::TimerQueueBasedMonotonic for $name { type Backend = $crate::rp2040::TimerBackend; type Instant = $crate::fugit::Instant< ::Ticks, 1, 1_000_000, >; type Duration = $crate::fugit::Duration< ::Ticks, 1, 1_000_000, >; } $crate::rtic_time::impl_embedded_hal_delay_fugit!($name); $crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name); }; }