From 21e60427cf2e971d977dff3abe9a67c3179881cb Mon Sep 17 00:00:00 2001 From: Emil Fresk Date: Thu, 2 Feb 2023 21:00:41 +0100 Subject: [PATCH] Simplify Systick Monotonic by integrating the TQ --- rtic-monotonics/src/systick_monotonic.rs | 80 ++++++++++++++---------- rtic/examples/async-delay.rs | 11 ++-- rtic/examples/async-timeout.rs | 30 ++++----- 3 files changed, 68 insertions(+), 53 deletions(-) diff --git a/rtic-monotonics/src/systick_monotonic.rs b/rtic-monotonics/src/systick_monotonic.rs index 24deb54747..a5a0aefaa4 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(); } }; } diff --git a/rtic/examples/async-delay.rs b/rtic/examples/async-delay.rs index aa673dd9e7..0988346709 100644 --- a/rtic/examples/async-delay.rs +++ b/rtic/examples/async-delay.rs @@ -11,7 +11,7 @@ mod app { use cortex_m_semihosting::{debug, hprintln}; use rtic_monotonics::systick_monotonic::*; - rtic_monotonics::make_systick_timer_queue!(TIMER); + rtic_monotonics::make_systick_handler!(); #[shared] struct Shared {} @@ -23,8 +23,7 @@ mod app { fn init(cx: init::Context) -> (Shared, Local) { hprintln!("init"); - let systick = Systick::start(cx.core.SYST, 12_000_000); - TIMER.initialize(systick); + Systick::start(cx.core.SYST, 12_000_000); foo::spawn().ok(); bar::spawn().ok(); @@ -45,21 +44,21 @@ mod app { #[task] async fn foo(_cx: foo::Context) { hprintln!("hello from foo"); - TIMER.delay(100.millis()).await; + Systick::delay(100.millis()).await; hprintln!("bye from foo"); } #[task] async fn bar(_cx: bar::Context) { hprintln!("hello from bar"); - TIMER.delay(200.millis()).await; + Systick::delay(200.millis()).await; hprintln!("bye from bar"); } #[task] async fn baz(_cx: baz::Context) { hprintln!("hello from baz"); - TIMER.delay(300.millis()).await; + Systick::delay(300.millis()).await; hprintln!("bye from baz"); debug::exit(debug::EXIT_SUCCESS); diff --git a/rtic/examples/async-timeout.rs b/rtic/examples/async-timeout.rs index 30fee43e2c..a850b106fc 100644 --- a/rtic/examples/async-timeout.rs +++ b/rtic/examples/async-timeout.rs @@ -12,8 +12,9 @@ use rtic_monotonics::systick_monotonic::*; mod app { use super::*; use futures::{future::FutureExt, select_biased}; + use rtic_monotonics::Monotonic; - rtic_monotonics::make_systick_timer_queue!(TIMER); + rtic_monotonics::make_systick_handler!(); #[shared] struct Shared {} @@ -25,8 +26,7 @@ mod app { fn init(cx: init::Context) -> (Shared, Local) { hprintln!("init"); - let systick = Systick::start(cx.core.SYST, 12_000_000); - TIMER.initialize(systick); + Systick::start(cx.core.SYST, 12_000_000); foo::spawn().ok(); @@ -37,37 +37,37 @@ mod app { async fn foo(_cx: foo::Context) { // Call hal with short relative timeout using `select_biased` select_biased! { - v = hal_get(&TIMER, 1).fuse() => hprintln!("hal returned {}", v), - _ = TIMER.delay(200.millis()).fuse() => hprintln!("timeout", ), // this will finish first + v = hal_get(1).fuse() => hprintln!("hal returned {}", v), + _ = Systick::delay(200.millis()).fuse() => hprintln!("timeout", ), // this will finish first } // Call hal with long relative timeout using `select_biased` select_biased! { - v = hal_get(&TIMER, 1).fuse() => hprintln!("hal returned {}", v), // hal finish first - _ = TIMER.delay(1000.millis()).fuse() => hprintln!("timeout", ), + v = hal_get(1).fuse() => hprintln!("hal returned {}", v), // hal finish first + _ = Systick::delay(1000.millis()).fuse() => hprintln!("timeout", ), } // Call hal with long relative timeout using monotonic `timeout_after` - match TIMER.timeout_after(1000.millis(), hal_get(&TIMER, 1)).await { + match Systick::timeout_after(1000.millis(), hal_get(1)).await { Ok(v) => hprintln!("hal returned {}", v), _ => hprintln!("timeout"), } // get the current time instance - let mut instant = TIMER.now(); + let mut instant = Systick::now(); // do this 3 times for n in 0..3 { // exact point in time without drift instant += 1000.millis(); - TIMER.delay_until(instant).await; + Systick::delay_until(instant).await; // exact point it time for timeout let timeout = instant + 500.millis(); - hprintln!("now is {:?}, timeout at {:?}", TIMER.now(), timeout); + hprintln!("now is {:?}, timeout at {:?}", Systick::now(), timeout); - match TIMER.timeout_at(timeout, hal_get(&TIMER, n)).await { - Ok(v) => hprintln!("hal returned {} at time {:?}", v, TIMER.now()), + match Systick::timeout_at(timeout, hal_get(n)).await { + Ok(v) => hprintln!("hal returned {} at time {:?}", v, Systick::now()), _ => hprintln!("timeout"), } } @@ -77,11 +77,11 @@ mod app { } // Emulate some hal -async fn hal_get(timer: &'static SystickTimerQueue, n: u32) -> u32 { +async fn hal_get(n: u32) -> u32 { // emulate some delay time dependent on n let d = 350.millis() + n * 100.millis(); hprintln!("the hal takes a duration of {:?}", d); - timer.delay(d).await; + Systick::delay(d).await; // emulate some return value 5 }