rtic_monotonics/rp2040.rs
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168
//! [`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<TimerBackend> = 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_sub` 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<Self> {
&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.
pub 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<
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
1,
1_000_000,
>;
type Duration = $crate::fugit::Duration<
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
1,
1_000_000,
>;
}
$crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
$crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
};
}