From 306aa47170fd59369b7a184924e287dc3706d64d Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Mon, 23 Jan 2023 20:05:47 +0100 Subject: Add rtic-timer (timerqueue + monotonic) and rtic-monotonics (systick-monotonic) --- rtic-monotonics/src/lib.rs | 11 +++++++++++ rtic-monotonics/src/systick_monotonic.rs | 1 + 2 files changed, 12 insertions(+) create mode 100644 rtic-monotonics/src/lib.rs create mode 100644 rtic-monotonics/src/systick_monotonic.rs (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs new file mode 100644 index 0000000..88398ca --- /dev/null +++ b/rtic-monotonics/src/lib.rs @@ -0,0 +1,11 @@ +//! Crate + +#![no_std] +#![no_main] +#![deny(missing_docs)] +#![allow(incomplete_features)] +#![feature(async_fn_in_trait)] + +pub use rtic_timer::{Monotonic, TimeoutError, TimerQueue}; + +pub mod systick_monotonic; diff --git a/rtic-monotonics/src/systick_monotonic.rs b/rtic-monotonics/src/systick_monotonic.rs new file mode 100644 index 0000000..491cf81 --- /dev/null +++ b/rtic-monotonics/src/systick_monotonic.rs @@ -0,0 +1 @@ +//! ... -- cgit v1.2.3 From 71b5f9438e1beb5fe12b90415d9d6307e79c0cdf Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Mon, 23 Jan 2023 20:57:56 +0100 Subject: Fixed systick monotonic --- rtic-monotonics/src/lib.rs | 2 +- rtic-monotonics/src/systick_monotonic.rs | 133 +++++++++++++++++++++++++++++++ 2 files changed, 134 insertions(+), 1 deletion(-) (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs index 88398ca..ce30c36 100644 --- a/rtic-monotonics/src/lib.rs +++ b/rtic-monotonics/src/lib.rs @@ -6,6 +6,6 @@ #![allow(incomplete_features)] #![feature(async_fn_in_trait)] -pub use rtic_timer::{Monotonic, TimeoutError, TimerQueue}; +pub use rtic_time::{Monotonic, TimeoutError, TimerQueue}; pub mod systick_monotonic; diff --git a/rtic-monotonics/src/systick_monotonic.rs b/rtic-monotonics/src/systick_monotonic.rs index 491cf81..7c713b6 100644 --- a/rtic-monotonics/src/systick_monotonic.rs +++ b/rtic-monotonics/src/systick_monotonic.rs @@ -1 +1,134 @@ //! ... + +use super::Monotonic; +pub use super::{TimeoutError, TimerQueue}; +use core::{ + ops::Deref, + sync::atomic::{AtomicU32, Ordering}, +}; +use cortex_m::peripheral::SYST; +use embedded_hal_async::delay::DelayUs; +use fugit::ExtU32; + +/// Systick implementing `rtic_monotonic::Monotonic` which runs at a +/// settable rate using the `TIMER_HZ` parameter. +pub struct Systick; + +impl Systick { + /// Start a `Monotonic` based on SysTick. + /// + /// The `sysclk` parameter is the speed at which SysTick runs at. This value should come from + /// the clock generation function of the used HAL. + /// + /// Notice that the actual rate of the timer is a best approximation based on the given + /// `sysclk` and `TIMER_HZ`. + /// + /// Note: Give the return value to `TimerQueue::initialize()` to initialize the timer queue. + #[must_use] + pub fn start(mut systick: cortex_m::peripheral::SYST, sysclk: u32) -> Self { + // + TIMER_HZ / 2 provides round to nearest instead of round to 0. + // - 1 as the counter range is inclusive [0, reload] + let reload = (sysclk + TIMER_HZ / 2) / TIMER_HZ - 1; + + assert!(reload <= 0x00ff_ffff); + assert!(reload > 0); + + systick.disable_counter(); + systick.set_clock_source(cortex_m::peripheral::syst::SystClkSource::Core); + systick.set_reload(reload); + systick.enable_interrupt(); + systick.enable_counter(); + + Systick {} + } + + fn systick() -> SYST { + unsafe { core::mem::transmute::<(), SYST>(()) } + } +} + +static SYSTICK_CNT: AtomicU32 = AtomicU32::new(0); + +impl Monotonic for Systick { + type Instant = fugit::TimerInstantU32; + type Duration = fugit::TimerDurationU32; + + const ZERO: Self::Instant = Self::Instant::from_ticks(0); + + fn now() -> Self::Instant { + if Self::systick().has_wrapped() { + SYSTICK_CNT.fetch_add(1, Ordering::AcqRel); + } + + Self::Instant::from_ticks(SYSTICK_CNT.load(Ordering::Relaxed)) + } + + fn set_compare(_: Self::Instant) { + // No need to do something here, we get interrupts anyway. + } + + fn clear_compare_flag() { + // NOOP with SysTick interrupt + } + + fn pend_interrupt() { + cortex_m::peripheral::SCB::set_pendst(); + } + + fn on_interrupt() { + if Self::systick().has_wrapped() { + SYSTICK_CNT.fetch_add(1, Ordering::AcqRel); + } + } + + fn enable_timer() {} + + fn disable_timer() {} +} + +/// Timer queue wrapper to implement traits on +pub struct SystickTimerQueue(TimerQueue>); + +impl SystickTimerQueue { + /// Create a new timer queue. + pub const fn new() -> Self { + Self(TimerQueue::new()) + } +} + +impl Deref for SystickTimerQueue { + type Target = TimerQueue>; + + #[inline(always)] + fn deref(&self) -> &Self::Target { + &self.0 + } +} + +impl DelayUs for SystickTimerQueue { + type Error = core::convert::Infallible; + + async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { + self.delay(us.micros()).await; + Ok(()) + } + + async fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { + self.delay(ms.millis()).await; + Ok(()) + } +} + +/// Register the Systick interrupt and crate a timer queue with a specific name and speed. +#[macro_export] +macro_rules! make_systick_timer_queue { + ($timer_queue_name:ident, $systick_speed:expr) => { + static $timer_queue_name: SystickTimerQueue<$systick_speed> = SystickTimerQueue::new(); + + #[no_mangle] + #[allow(non_snake_case)] + unsafe extern "C" fn SysTick() { + $timer_queue_name.on_monotonic_interrupt(); + } + }; +} -- cgit v1.2.3 From bdf577c30800aedb0ab6b27768e228c057e18fb5 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Tue, 24 Jan 2023 12:34:11 +0100 Subject: Systick runs at 1 kHz --- rtic-monotonics/src/systick_monotonic.rs | 25 +++++++++++++------------ 1 file changed, 13 insertions(+), 12 deletions(-) (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/systick_monotonic.rs b/rtic-monotonics/src/systick_monotonic.rs index 7c713b6..af17f93 100644 --- a/rtic-monotonics/src/systick_monotonic.rs +++ b/rtic-monotonics/src/systick_monotonic.rs @@ -10,11 +10,12 @@ use cortex_m::peripheral::SYST; use embedded_hal_async::delay::DelayUs; use fugit::ExtU32; -/// Systick implementing `rtic_monotonic::Monotonic` which runs at a -/// settable rate using the `TIMER_HZ` parameter. -pub struct Systick; +const TIMER_HZ: u32 = 1_000; -impl Systick { +/// Systick implementing `rtic_monotonic::Monotonic` which runs at 1 kHz. +pub struct Systick; + +impl Systick { /// Start a `Monotonic` based on SysTick. /// /// The `sysclk` parameter is the speed at which SysTick runs at. This value should come from @@ -49,7 +50,7 @@ impl Systick { static SYSTICK_CNT: AtomicU32 = AtomicU32::new(0); -impl Monotonic for Systick { +impl Monotonic for Systick { type Instant = fugit::TimerInstantU32; type Duration = fugit::TimerDurationU32; @@ -87,17 +88,17 @@ impl Monotonic for Systick { } /// Timer queue wrapper to implement traits on -pub struct SystickTimerQueue(TimerQueue>); +pub struct SystickTimerQueue(TimerQueue); -impl SystickTimerQueue { +impl SystickTimerQueue { /// Create a new timer queue. pub const fn new() -> Self { Self(TimerQueue::new()) } } -impl Deref for SystickTimerQueue { - type Target = TimerQueue>; +impl Deref for SystickTimerQueue { + type Target = TimerQueue; #[inline(always)] fn deref(&self) -> &Self::Target { @@ -105,7 +106,7 @@ impl Deref for SystickTimerQueue { } } -impl DelayUs for SystickTimerQueue { +impl DelayUs for SystickTimerQueue { type Error = core::convert::Infallible; async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { @@ -122,8 +123,8 @@ impl DelayUs for SystickTimerQueue { /// Register the Systick interrupt and crate a timer queue with a specific name and speed. #[macro_export] macro_rules! make_systick_timer_queue { - ($timer_queue_name:ident, $systick_speed:expr) => { - static $timer_queue_name: SystickTimerQueue<$systick_speed> = SystickTimerQueue::new(); + ($timer_queue_name:ident) => { + static $timer_queue_name: SystickTimerQueue = SystickTimerQueue::new(); #[no_mangle] #[allow(non_snake_case)] -- cgit v1.2.3 From 1baa4a4228cae4576e194174618bf35f5c206959 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Tj=C3=A4der?= Date: Fri, 27 Jan 2023 13:18:29 +0100 Subject: CI: Don't let warnings get away --- rtic-monotonics/src/lib.rs | 1 + 1 file changed, 1 insertion(+) (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs index ce30c36..1e23088 100644 --- a/rtic-monotonics/src/lib.rs +++ b/rtic-monotonics/src/lib.rs @@ -3,6 +3,7 @@ #![no_std] #![no_main] #![deny(missing_docs)] +//deny_warnings_placeholder_for_ci #![allow(incomplete_features)] #![feature(async_fn_in_trait)] -- cgit v1.2.3 From 922f1ad0eb56d362e527ff28e456b6fa133e212b Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Fri, 27 Jan 2023 20:20:14 +0100 Subject: Added examples for async crates + fixed codegen for non-Copy arguments --- rtic-monotonics/src/systick_monotonic.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/systick_monotonic.rs b/rtic-monotonics/src/systick_monotonic.rs index af17f93..fec97f2 100644 --- a/rtic-monotonics/src/systick_monotonic.rs +++ b/rtic-monotonics/src/systick_monotonic.rs @@ -2,13 +2,11 @@ use super::Monotonic; pub use super::{TimeoutError, TimerQueue}; -use core::{ - ops::Deref, - sync::atomic::{AtomicU32, Ordering}, -}; +use atomic_polyfill::{AtomicU32, Ordering}; +use core::ops::Deref; use cortex_m::peripheral::SYST; use embedded_hal_async::delay::DelayUs; -use fugit::ExtU32; +pub use fugit::ExtU32; const TIMER_HZ: u32 = 1_000; -- cgit v1.2.3 From 82f2f0834943cd7f69130f30904f4372d39f92e7 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 2 Feb 2023 20:14:41 +0100 Subject: Make xtask pass, clean up rtic Cargo.toml --- rtic-monotonics/src/systick_monotonic.rs | 7 +++++++ 1 file changed, 7 insertions(+) (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/systick_monotonic.rs b/rtic-monotonics/src/systick_monotonic.rs index fec97f2..24deb54 100644 --- a/rtic-monotonics/src/systick_monotonic.rs +++ b/rtic-monotonics/src/systick_monotonic.rs @@ -8,8 +8,15 @@ use cortex_m::peripheral::SYST; use embedded_hal_async::delay::DelayUs; pub use fugit::ExtU32; +#[cfg(feature = "systick_100hz")] +const TIMER_HZ: u32 = 100; + +#[cfg(feature = "systick_1khz")] const TIMER_HZ: u32 = 1_000; +#[cfg(feature = "systick_10khz")] +const TIMER_HZ: u32 = 10_000; + /// Systick implementing `rtic_monotonic::Monotonic` which runs at 1 kHz. pub struct Systick; -- cgit v1.2.3 From b6fdb9060bc2f19308d864c934078d8160a17ca3 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 2 Feb 2023 21:00:41 +0100 Subject: Simplify Systick Monotonic by integrating the TQ --- rtic-monotonics/src/systick_monotonic.rs | 80 +++++++++++++++++++------------- 1 file changed, 48 insertions(+), 32 deletions(-) (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/systick_monotonic.rs b/rtic-monotonics/src/systick_monotonic.rs index 24deb54..a5a0aef 100644 --- a/rtic-monotonics/src/systick_monotonic.rs +++ b/rtic-monotonics/src/systick_monotonic.rs @@ -3,7 +3,7 @@ use super::Monotonic; pub use super::{TimeoutError, TimerQueue}; use atomic_polyfill::{AtomicU32, Ordering}; -use core::ops::Deref; +use core::future::Future; use cortex_m::peripheral::SYST; use embedded_hal_async::delay::DelayUs; pub use fugit::ExtU32; @@ -30,8 +30,7 @@ impl Systick { /// `sysclk` and `TIMER_HZ`. /// /// Note: Give the return value to `TimerQueue::initialize()` to initialize the timer queue. - #[must_use] - pub fn start(mut systick: cortex_m::peripheral::SYST, sysclk: u32) -> Self { + pub fn start(mut systick: cortex_m::peripheral::SYST, sysclk: u32) { // + TIMER_HZ / 2 provides round to nearest instead of round to 0. // - 1 as the counter range is inclusive [0, reload] let reload = (sysclk + TIMER_HZ / 2) / TIMER_HZ - 1; @@ -45,7 +44,7 @@ impl Systick { systick.enable_interrupt(); systick.enable_counter(); - Systick {} + SYSTICK_TIMER_QUEUE.initialize(Systick {}); } fn systick() -> SYST { @@ -54,6 +53,44 @@ impl Systick { } static SYSTICK_CNT: AtomicU32 = AtomicU32::new(0); +static SYSTICK_TIMER_QUEUE: TimerQueue = TimerQueue::new(); + +// Forward timerqueue interface +impl Systick { + /// Used to access the underlying timer queue + #[doc(hidden)] + pub fn __tq() -> &'static TimerQueue { + &SYSTICK_TIMER_QUEUE + } + + /// Timeout at a specific time. + pub async fn timeout_at( + instant: ::Instant, + future: F, + ) -> Result { + SYSTICK_TIMER_QUEUE.timeout_at(instant, future).await + } + + /// Timeout after a specific duration. + #[inline] + pub async fn timeout_after( + duration: ::Duration, + future: F, + ) -> Result { + SYSTICK_TIMER_QUEUE.timeout_after(duration, future).await + } + + /// Delay for some duration of time. + #[inline] + pub async fn delay(duration: ::Duration) { + SYSTICK_TIMER_QUEUE.delay(duration).await; + } + + /// Delay to some specific time instant. + pub async fn delay_until(instant: ::Instant) { + SYSTICK_TIMER_QUEUE.delay_until(instant).await; + } +} impl Monotonic for Systick { type Instant = fugit::TimerInstantU32; @@ -92,49 +129,28 @@ impl Monotonic for Systick { fn disable_timer() {} } -/// Timer queue wrapper to implement traits on -pub struct SystickTimerQueue(TimerQueue); - -impl SystickTimerQueue { - /// Create a new timer queue. - pub const fn new() -> Self { - Self(TimerQueue::new()) - } -} - -impl Deref for SystickTimerQueue { - type Target = TimerQueue; - - #[inline(always)] - fn deref(&self) -> &Self::Target { - &self.0 - } -} - -impl DelayUs for SystickTimerQueue { +impl DelayUs for Systick { type Error = core::convert::Infallible; async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { - self.delay(us.micros()).await; + SYSTICK_TIMER_QUEUE.delay(us.micros()).await; Ok(()) } async fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { - self.delay(ms.millis()).await; + SYSTICK_TIMER_QUEUE.delay(ms.millis()).await; Ok(()) } } -/// Register the Systick interrupt and crate a timer queue with a specific name and speed. +/// Register the Systick interrupt for the monotonic. #[macro_export] -macro_rules! make_systick_timer_queue { - ($timer_queue_name:ident) => { - static $timer_queue_name: SystickTimerQueue = SystickTimerQueue::new(); - +macro_rules! make_systick_handler { + () => { #[no_mangle] #[allow(non_snake_case)] unsafe extern "C" fn SysTick() { - $timer_queue_name.on_monotonic_interrupt(); + Systick::__tq().on_monotonic_interrupt(); } }; } -- cgit v1.2.3 From 858160a55d839bb4064006aa55ddb581259a3074 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Tj=C3=A4der?= Date: Sat, 4 Feb 2023 10:14:12 +0100 Subject: rtic-monotonics: Simplify features, default is 1kHz Make 100 Hz or 10 kHz opt in through features, which are meant for testing primarily. --- rtic-monotonics/src/systick_monotonic.rs | 25 ++++++++++++++++--------- 1 file changed, 16 insertions(+), 9 deletions(-) (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/systick_monotonic.rs b/rtic-monotonics/src/systick_monotonic.rs index a5a0aef..885da92 100644 --- a/rtic-monotonics/src/systick_monotonic.rs +++ b/rtic-monotonics/src/systick_monotonic.rs @@ -8,16 +8,23 @@ use cortex_m::peripheral::SYST; use embedded_hal_async::delay::DelayUs; pub use fugit::ExtU32; -#[cfg(feature = "systick_100hz")] -const TIMER_HZ: u32 = 100; - -#[cfg(feature = "systick_1khz")] -const TIMER_HZ: u32 = 1_000; - -#[cfg(feature = "systick_10khz")] -const TIMER_HZ: u32 = 10_000; +// Features should be additive, here systick_100hz gets picked if both +// `systick_100hz` and `systick_10khz` are enabled. + +cfg_if::cfg_if! { + if #[cfg(feature = "systick_100hz")] + { + const TIMER_HZ: u32 = 100; + } else if #[cfg(feature = "systick_10khz")] + { + const TIMER_HZ: u32 = 10_000; + } else { + // Default case is 1 kHz + const TIMER_HZ: u32 = 1_000; + } +} -/// Systick implementing `rtic_monotonic::Monotonic` which runs at 1 kHz. +/// Systick implementing `rtic_monotonic::Monotonic` which runs at 1 kHz, 100Hz or 10 kHz. pub struct Systick; impl Systick { -- cgit v1.2.3 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/lib.rs | 5 +- rtic-monotonics/src/rp2040.rs | 143 +++++++++++++++++++++++++++ rtic-monotonics/src/systick.rs | 163 +++++++++++++++++++++++++++++++ rtic-monotonics/src/systick_monotonic.rs | 163 ------------------------------- 4 files changed, 310 insertions(+), 164 deletions(-) create mode 100644 rtic-monotonics/src/rp2040.rs create mode 100644 rtic-monotonics/src/systick.rs delete mode 100644 rtic-monotonics/src/systick_monotonic.rs (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs index 1e23088..fb5dc8a 100644 --- a/rtic-monotonics/src/lib.rs +++ b/rtic-monotonics/src/lib.rs @@ -9,4 +9,7 @@ pub use rtic_time::{Monotonic, TimeoutError, TimerQueue}; -pub mod systick_monotonic; +pub mod systick; + +#[cfg(feature = "rp2040")] +pub mod rp2040; 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(); + } + }; +} diff --git a/rtic-monotonics/src/systick.rs b/rtic-monotonics/src/systick.rs new file mode 100644 index 0000000..885da92 --- /dev/null +++ b/rtic-monotonics/src/systick.rs @@ -0,0 +1,163 @@ +//! ... + +use super::Monotonic; +pub use super::{TimeoutError, TimerQueue}; +use atomic_polyfill::{AtomicU32, Ordering}; +use core::future::Future; +use cortex_m::peripheral::SYST; +use embedded_hal_async::delay::DelayUs; +pub use fugit::ExtU32; + +// Features should be additive, here systick_100hz gets picked if both +// `systick_100hz` and `systick_10khz` are enabled. + +cfg_if::cfg_if! { + if #[cfg(feature = "systick_100hz")] + { + const TIMER_HZ: u32 = 100; + } else if #[cfg(feature = "systick_10khz")] + { + const TIMER_HZ: u32 = 10_000; + } else { + // Default case is 1 kHz + const TIMER_HZ: u32 = 1_000; + } +} + +/// Systick implementing `rtic_monotonic::Monotonic` which runs at 1 kHz, 100Hz or 10 kHz. +pub struct Systick; + +impl Systick { + /// Start a `Monotonic` based on SysTick. + /// + /// The `sysclk` parameter is the speed at which SysTick runs at. This value should come from + /// the clock generation function of the used HAL. + /// + /// Notice that the actual rate of the timer is a best approximation based on the given + /// `sysclk` and `TIMER_HZ`. + /// + /// Note: Give the return value to `TimerQueue::initialize()` to initialize the timer queue. + pub fn start(mut systick: cortex_m::peripheral::SYST, sysclk: u32) { + // + TIMER_HZ / 2 provides round to nearest instead of round to 0. + // - 1 as the counter range is inclusive [0, reload] + let reload = (sysclk + TIMER_HZ / 2) / TIMER_HZ - 1; + + assert!(reload <= 0x00ff_ffff); + assert!(reload > 0); + + systick.disable_counter(); + systick.set_clock_source(cortex_m::peripheral::syst::SystClkSource::Core); + systick.set_reload(reload); + systick.enable_interrupt(); + systick.enable_counter(); + + SYSTICK_TIMER_QUEUE.initialize(Systick {}); + } + + fn systick() -> SYST { + unsafe { core::mem::transmute::<(), SYST>(()) } + } +} + +static SYSTICK_CNT: AtomicU32 = AtomicU32::new(0); +static SYSTICK_TIMER_QUEUE: TimerQueue = TimerQueue::new(); + +// Forward timerqueue interface +impl Systick { + /// Used to access the underlying timer queue + #[doc(hidden)] + pub fn __tq() -> &'static TimerQueue { + &SYSTICK_TIMER_QUEUE + } + + /// Timeout at a specific time. + pub async fn timeout_at( + instant: ::Instant, + future: F, + ) -> Result { + SYSTICK_TIMER_QUEUE.timeout_at(instant, future).await + } + + /// Timeout after a specific duration. + #[inline] + pub async fn timeout_after( + duration: ::Duration, + future: F, + ) -> Result { + SYSTICK_TIMER_QUEUE.timeout_after(duration, future).await + } + + /// Delay for some duration of time. + #[inline] + pub async fn delay(duration: ::Duration) { + SYSTICK_TIMER_QUEUE.delay(duration).await; + } + + /// Delay to some specific time instant. + pub async fn delay_until(instant: ::Instant) { + SYSTICK_TIMER_QUEUE.delay_until(instant).await; + } +} + +impl Monotonic for Systick { + type Instant = fugit::TimerInstantU32; + type Duration = fugit::TimerDurationU32; + + const ZERO: Self::Instant = Self::Instant::from_ticks(0); + + fn now() -> Self::Instant { + if Self::systick().has_wrapped() { + SYSTICK_CNT.fetch_add(1, Ordering::AcqRel); + } + + Self::Instant::from_ticks(SYSTICK_CNT.load(Ordering::Relaxed)) + } + + fn set_compare(_: Self::Instant) { + // No need to do something here, we get interrupts anyway. + } + + fn clear_compare_flag() { + // NOOP with SysTick interrupt + } + + fn pend_interrupt() { + cortex_m::peripheral::SCB::set_pendst(); + } + + fn on_interrupt() { + if Self::systick().has_wrapped() { + SYSTICK_CNT.fetch_add(1, Ordering::AcqRel); + } + } + + fn enable_timer() {} + + fn disable_timer() {} +} + +impl DelayUs for Systick { + type Error = core::convert::Infallible; + + async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { + SYSTICK_TIMER_QUEUE.delay(us.micros()).await; + Ok(()) + } + + async fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { + SYSTICK_TIMER_QUEUE.delay(ms.millis()).await; + Ok(()) + } +} + +/// Register the Systick interrupt for the monotonic. +#[macro_export] +macro_rules! make_systick_handler { + () => { + #[no_mangle] + #[allow(non_snake_case)] + unsafe extern "C" fn SysTick() { + Systick::__tq().on_monotonic_interrupt(); + } + }; +} diff --git a/rtic-monotonics/src/systick_monotonic.rs b/rtic-monotonics/src/systick_monotonic.rs deleted file mode 100644 index 885da92..0000000 --- a/rtic-monotonics/src/systick_monotonic.rs +++ /dev/null @@ -1,163 +0,0 @@ -//! ... - -use super::Monotonic; -pub use super::{TimeoutError, TimerQueue}; -use atomic_polyfill::{AtomicU32, Ordering}; -use core::future::Future; -use cortex_m::peripheral::SYST; -use embedded_hal_async::delay::DelayUs; -pub use fugit::ExtU32; - -// Features should be additive, here systick_100hz gets picked if both -// `systick_100hz` and `systick_10khz` are enabled. - -cfg_if::cfg_if! { - if #[cfg(feature = "systick_100hz")] - { - const TIMER_HZ: u32 = 100; - } else if #[cfg(feature = "systick_10khz")] - { - const TIMER_HZ: u32 = 10_000; - } else { - // Default case is 1 kHz - const TIMER_HZ: u32 = 1_000; - } -} - -/// Systick implementing `rtic_monotonic::Monotonic` which runs at 1 kHz, 100Hz or 10 kHz. -pub struct Systick; - -impl Systick { - /// Start a `Monotonic` based on SysTick. - /// - /// The `sysclk` parameter is the speed at which SysTick runs at. This value should come from - /// the clock generation function of the used HAL. - /// - /// Notice that the actual rate of the timer is a best approximation based on the given - /// `sysclk` and `TIMER_HZ`. - /// - /// Note: Give the return value to `TimerQueue::initialize()` to initialize the timer queue. - pub fn start(mut systick: cortex_m::peripheral::SYST, sysclk: u32) { - // + TIMER_HZ / 2 provides round to nearest instead of round to 0. - // - 1 as the counter range is inclusive [0, reload] - let reload = (sysclk + TIMER_HZ / 2) / TIMER_HZ - 1; - - assert!(reload <= 0x00ff_ffff); - assert!(reload > 0); - - systick.disable_counter(); - systick.set_clock_source(cortex_m::peripheral::syst::SystClkSource::Core); - systick.set_reload(reload); - systick.enable_interrupt(); - systick.enable_counter(); - - SYSTICK_TIMER_QUEUE.initialize(Systick {}); - } - - fn systick() -> SYST { - unsafe { core::mem::transmute::<(), SYST>(()) } - } -} - -static SYSTICK_CNT: AtomicU32 = AtomicU32::new(0); -static SYSTICK_TIMER_QUEUE: TimerQueue = TimerQueue::new(); - -// Forward timerqueue interface -impl Systick { - /// Used to access the underlying timer queue - #[doc(hidden)] - pub fn __tq() -> &'static TimerQueue { - &SYSTICK_TIMER_QUEUE - } - - /// Timeout at a specific time. - pub async fn timeout_at( - instant: ::Instant, - future: F, - ) -> Result { - SYSTICK_TIMER_QUEUE.timeout_at(instant, future).await - } - - /// Timeout after a specific duration. - #[inline] - pub async fn timeout_after( - duration: ::Duration, - future: F, - ) -> Result { - SYSTICK_TIMER_QUEUE.timeout_after(duration, future).await - } - - /// Delay for some duration of time. - #[inline] - pub async fn delay(duration: ::Duration) { - SYSTICK_TIMER_QUEUE.delay(duration).await; - } - - /// Delay to some specific time instant. - pub async fn delay_until(instant: ::Instant) { - SYSTICK_TIMER_QUEUE.delay_until(instant).await; - } -} - -impl Monotonic for Systick { - type Instant = fugit::TimerInstantU32; - type Duration = fugit::TimerDurationU32; - - const ZERO: Self::Instant = Self::Instant::from_ticks(0); - - fn now() -> Self::Instant { - if Self::systick().has_wrapped() { - SYSTICK_CNT.fetch_add(1, Ordering::AcqRel); - } - - Self::Instant::from_ticks(SYSTICK_CNT.load(Ordering::Relaxed)) - } - - fn set_compare(_: Self::Instant) { - // No need to do something here, we get interrupts anyway. - } - - fn clear_compare_flag() { - // NOOP with SysTick interrupt - } - - fn pend_interrupt() { - cortex_m::peripheral::SCB::set_pendst(); - } - - fn on_interrupt() { - if Self::systick().has_wrapped() { - SYSTICK_CNT.fetch_add(1, Ordering::AcqRel); - } - } - - fn enable_timer() {} - - fn disable_timer() {} -} - -impl DelayUs for Systick { - type Error = core::convert::Infallible; - - async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { - SYSTICK_TIMER_QUEUE.delay(us.micros()).await; - Ok(()) - } - - async fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> { - SYSTICK_TIMER_QUEUE.delay(ms.millis()).await; - Ok(()) - } -} - -/// Register the Systick interrupt for the monotonic. -#[macro_export] -macro_rules! make_systick_handler { - () => { - #[no_mangle] - #[allow(non_snake_case)] - unsafe extern "C" fn SysTick() { - Systick::__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/lib.rs | 1 + rtic-monotonics/src/rp2040.rs | 2 +- 2 files changed, 2 insertions(+), 1 deletion(-) (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs index fb5dc8a..4eb2261 100644 --- a/rtic-monotonics/src/lib.rs +++ b/rtic-monotonics/src/lib.rs @@ -9,6 +9,7 @@ pub use rtic_time::{Monotonic, TimeoutError, TimerQueue}; +#[cfg(feature = "cortex_m_sytick")] pub mod systick; #[cfg(feature = "rp2040")] 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 60d5e9e1db24fd1e0456949c90464e5fd52d20fe Mon Sep 17 00:00:00 2001 From: datdenkikniet Date: Wed, 15 Feb 2023 23:20:29 +0100 Subject: Fix spelling on "cortex_m_systick" --- rtic-monotonics/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs index 4eb2261..7e513f8 100644 --- a/rtic-monotonics/src/lib.rs +++ b/rtic-monotonics/src/lib.rs @@ -9,7 +9,7 @@ pub use rtic_time::{Monotonic, TimeoutError, TimerQueue}; -#[cfg(feature = "cortex_m_sytick")] +#[cfg(feature = "cortex_m_systick")] pub mod systick; #[cfg(feature = "rp2040")] -- 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 ++-- rtic-monotonics/src/systick.rs | 4 ++-- 2 files changed, 4 insertions(+), 4 deletions(-) (limited to 'rtic-monotonics/src') 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> { diff --git a/rtic-monotonics/src/systick.rs b/rtic-monotonics/src/systick.rs index 885da92..2711022 100644 --- a/rtic-monotonics/src/systick.rs +++ b/rtic-monotonics/src/systick.rs @@ -5,7 +5,6 @@ pub use super::{TimeoutError, TimerQueue}; use atomic_polyfill::{AtomicU32, Ordering}; use core::future::Future; use cortex_m::peripheral::SYST; -use embedded_hal_async::delay::DelayUs; pub use fugit::ExtU32; // Features should be additive, here systick_100hz gets picked if both @@ -136,7 +135,8 @@ impl Monotonic for Systick { fn disable_timer() {} } -impl DelayUs for Systick { +#[cfg(feature = "embedded-hal-async")] +impl embedded_hal_async::delay::DelayUs for Systick { type Error = core::convert::Infallible; async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> { -- cgit v1.2.3 From b9e0f36aff96ec4e39cf4f728777cbc808df2c78 Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Sun, 19 Feb 2023 14:30:49 +0100 Subject: Add feature flags --- rtic-monotonics/src/systick.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/systick.rs b/rtic-monotonics/src/systick.rs index 2711022..62d4e0c 100644 --- a/rtic-monotonics/src/systick.rs +++ b/rtic-monotonics/src/systick.rs @@ -157,7 +157,7 @@ macro_rules! make_systick_handler { #[no_mangle] #[allow(non_snake_case)] unsafe extern "C" fn SysTick() { - Systick::__tq().on_monotonic_interrupt(); + rtic_monotonics::systick::Systick::__tq().on_monotonic_interrupt(); } }; } -- cgit v1.2.3 From 44af1366056a06247b3ee0f153d5274cb4658c43 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Tj=C3=A4der?= Date: Sat, 4 Mar 2023 02:26:34 +0100 Subject: CFG: Align all crates to use hyphen --- rtic-monotonics/src/lib.rs | 2 +- rtic-monotonics/src/systick.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs index 7e513f8..a8068ce 100644 --- a/rtic-monotonics/src/lib.rs +++ b/rtic-monotonics/src/lib.rs @@ -9,7 +9,7 @@ pub use rtic_time::{Monotonic, TimeoutError, TimerQueue}; -#[cfg(feature = "cortex_m_systick")] +#[cfg(feature = "cortex-m-systick")] pub mod systick; #[cfg(feature = "rp2040")] diff --git a/rtic-monotonics/src/systick.rs b/rtic-monotonics/src/systick.rs index 62d4e0c..691d7c7 100644 --- a/rtic-monotonics/src/systick.rs +++ b/rtic-monotonics/src/systick.rs @@ -7,14 +7,14 @@ use core::future::Future; use cortex_m::peripheral::SYST; pub use fugit::ExtU32; -// Features should be additive, here systick_100hz gets picked if both -// `systick_100hz` and `systick_10khz` are enabled. +// Features should be additive, here systick-100hz gets picked if both +// `systick-100hz` and `systick-10khz` are enabled. cfg_if::cfg_if! { - if #[cfg(feature = "systick_100hz")] + if #[cfg(feature = "systick-100hz")] { const TIMER_HZ: u32 = 100; - } else if #[cfg(feature = "systick_10khz")] + } else if #[cfg(feature = "systick-10khz")] { const TIMER_HZ: u32 = 10_000; } else { -- cgit v1.2.3 From 98c5490d94950608d31cd5ad9dd260f2f853735c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Henrik=20Tj=C3=A4der?= Date: Sat, 4 Mar 2023 21:58:45 +0100 Subject: rtic-monotonics: Fix tests --- rtic-monotonics/src/lib.rs | 1 - 1 file changed, 1 deletion(-) (limited to 'rtic-monotonics/src') diff --git a/rtic-monotonics/src/lib.rs b/rtic-monotonics/src/lib.rs index a8068ce..a4a1f42 100644 --- a/rtic-monotonics/src/lib.rs +++ b/rtic-monotonics/src/lib.rs @@ -1,7 +1,6 @@ //! Crate #![no_std] -#![no_main] #![deny(missing_docs)] //deny_warnings_placeholder_for_ci #![allow(incomplete_features)] -- cgit v1.2.3