From 8963e0e27ae57f7a8c3a666fe9e5a993cdd09275 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Fri, 10 Feb 2023 07:52:50 +0100 Subject: RP2040 monotonic, rename systick monotonic to not have double name --- rtic-monotonics/src/rp2040.rs | 143 ++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 143 insertions(+) create mode 100644 rtic-monotonics/src/rp2040.rs (limited to 'rtic-monotonics/src/rp2040.rs') diff --git a/rtic-monotonics/src/rp2040.rs b/rtic-monotonics/src/rp2040.rs new file mode 100644 index 0000000..448c388 --- /dev/null +++ b/rtic-monotonics/src/rp2040.rs @@ -0,0 +1,143 @@ +//! A monotonic implementation for RP2040's Timer peripheral. + +use super::Monotonic; +pub use super::{TimeoutError, TimerQueue}; +use core::future::Future; +use embedded_hal_async::delay::DelayUs; +pub use fugit::ExtU64; +use rp2040_pac::{timer, Interrupt, RESETS, TIMER}; + +/// Timer implementing `rtic_monotonic::Monotonic` which runs at 1 MHz. +pub struct Timer; + +impl Timer { + /// Start a `Monotonic` based on RP2040's Timer. + pub fn start(timer: TIMER, resets: &mut 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().set_bit()); + + TIMER_QUEUE.initialize(Self {}); + } + + fn timer() -> &'static timer::RegisterBlock { + unsafe { &*TIMER::ptr() } + } +} + +static TIMER_QUEUE: TimerQueue = TimerQueue::new(); + +// Forward timerqueue interface +impl Timer { + /// Used to access the underlying timer queue + #[doc(hidden)] + pub fn __tq() -> &'static TimerQueue { + &TIMER_QUEUE + } + + /// Timeout at a specific time. + pub async fn timeout_at( + instant: ::Instant, + future: F, + ) -> Result { + TIMER_QUEUE.timeout_at(instant, future).await + } + + /// Timeout after a specific duration. + #[inline] + pub async fn timeout_after( + duration: ::Duration, + future: F, + ) -> Result { + TIMER_QUEUE.timeout_after(duration, future).await + } + + /// Delay for some duration of time. + #[inline] + pub async fn delay(duration: ::Duration) { + TIMER_QUEUE.delay(duration).await; + } + + /// Delay to some specific time instant. + pub async fn delay_until(instant: ::Instant) { + TIMER_QUEUE.delay_until(instant).await; + } +} + +impl Monotonic for Timer { + type Instant = fugit::TimerInstantU64<1_000_000>; + type Duration = fugit::TimerDurationU64<1_000_000>; + + const ZERO: Self::Instant = Self::Instant::from_ticks(0); + + fn now() -> Self::Instant { + 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 Self::Instant::from_ticks((u64::from(hi0) << 32) | u64::from(low)); + } + hi0 = hi1; + } + } + + fn set_compare(instant: Self::Instant) { + let now = Self::now(); + + let max = 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. + let val = match instant.checked_duration_since(now) { + Some(x) if x.ticks() <= max => instant.duration_since_epoch().ticks() & max, // Will not overflow + _ => 0, // Will overflow or in the past, set the same value as after overflow to not get extra interrupts + }; + + Self::timer() + .alarm0 + .write(|w| unsafe { w.bits(val as u32) }); + } + + fn clear_compare_flag() { + Self::timer().intr.modify(|_, w| w.alarm_0().set_bit()); + } + + fn pend_interrupt() { + cortex_m::peripheral::NVIC::pend(Interrupt::TIMER_IRQ_0); + } + + fn on_interrupt() {} + + fn enable_timer() {} + + fn disable_timer() {} +} + +impl DelayUs for Timer { + type Error = core::convert::Infallible; + + async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { + TIMER_QUEUE.delay((us as u64).micros()).await; + Ok(()) + } + + async fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { + TIMER_QUEUE.delay((ms as u64).millis()).await; + Ok(()) + } +} + +/// Register the Timer interrupt for the monotonic. +#[macro_export] +macro_rules! make_rp2040_monotonic_handler { + () => { + #[no_mangle] + #[allow(non_snake_case)] + unsafe extern "C" fn TIMER_IRQ_0() { + rtic_monotonics::rp2040::Timer::__tq().on_monotonic_interrupt(); + } + }; +} -- cgit v1.2.3 From b566a893930f36cb4ee9a03743a04de34e8f0445 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Sat, 11 Feb 2023 07:55:08 +0100 Subject: rtic-monotonics: Feature gate monotonics correctly to support multiple MCUs --- rtic-monotonics/src/rp2040.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rtic-monotonics/src/rp2040.rs') diff --git a/rtic-monotonics/src/rp2040.rs b/rtic-monotonics/src/rp2040.rs index 448c388..064a50d 100644 --- a/rtic-monotonics/src/rp2040.rs +++ b/rtic-monotonics/src/rp2040.rs @@ -106,7 +106,7 @@ impl Monotonic for Timer { } fn pend_interrupt() { - cortex_m::peripheral::NVIC::pend(Interrupt::TIMER_IRQ_0); + rp2040_pac::NVIC::pend(Interrupt::TIMER_IRQ_0); } fn on_interrupt() {} -- cgit v1.2.3 From 002d0b0d1685473f0f81cd17346d119fc671ad9c Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Wed, 15 Feb 2023 23:21:52 +0100 Subject: Make embedded-hal-async dependency optional for better compatibility with HALs Some hals implement traits for embedded-hal version `=1.0.0.alpha.`, which is explicitly incompatible with the version `=1.0.0.alpha.9` which embedded-hal-async depends on. Making the dependency optional allows downstream projects to include rtic-monotonic without requiring that all of their other libraries also implement that specific version of embedded-hal 1.0 --- rtic-monotonics/src/rp2040.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'rtic-monotonics/src/rp2040.rs') diff --git a/rtic-monotonics/src/rp2040.rs b/rtic-monotonics/src/rp2040.rs index 064a50d..e42c148 100644 --- a/rtic-monotonics/src/rp2040.rs +++ b/rtic-monotonics/src/rp2040.rs @@ -3,7 +3,6 @@ use super::Monotonic; pub use super::{TimeoutError, TimerQueue}; use core::future::Future; -use embedded_hal_async::delay::DelayUs; pub use fugit::ExtU64; use rp2040_pac::{timer, Interrupt, RESETS, TIMER}; @@ -116,7 +115,8 @@ impl Monotonic for Timer { fn disable_timer() {} } -impl DelayUs for Timer { +#[cfg(feature = "embedded-hal-async")] +impl embedded_hal_async::delay::DelayUs for Timer { type Error = core::convert::Infallible; async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { -- cgit v1.2.3