mirror of
https://github.com/rtic-rs/rtic.git
synced 2024-11-27 14:04:56 +01:00
Simplify Systick Monotonic by integrating the TQ
This commit is contained in:
parent
1c2d9de9c0
commit
21e60427cf
3 changed files with 68 additions and 53 deletions
|
@ -3,7 +3,7 @@
|
||||||
use super::Monotonic;
|
use super::Monotonic;
|
||||||
pub use super::{TimeoutError, TimerQueue};
|
pub use super::{TimeoutError, TimerQueue};
|
||||||
use atomic_polyfill::{AtomicU32, Ordering};
|
use atomic_polyfill::{AtomicU32, Ordering};
|
||||||
use core::ops::Deref;
|
use core::future::Future;
|
||||||
use cortex_m::peripheral::SYST;
|
use cortex_m::peripheral::SYST;
|
||||||
use embedded_hal_async::delay::DelayUs;
|
use embedded_hal_async::delay::DelayUs;
|
||||||
pub use fugit::ExtU32;
|
pub use fugit::ExtU32;
|
||||||
|
@ -30,8 +30,7 @@ impl Systick {
|
||||||
/// `sysclk` and `TIMER_HZ`.
|
/// `sysclk` and `TIMER_HZ`.
|
||||||
///
|
///
|
||||||
/// Note: Give the return value to `TimerQueue::initialize()` to initialize the timer queue.
|
/// 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) {
|
||||||
pub fn start(mut systick: cortex_m::peripheral::SYST, sysclk: u32) -> Self {
|
|
||||||
// + TIMER_HZ / 2 provides round to nearest instead of round to 0.
|
// + TIMER_HZ / 2 provides round to nearest instead of round to 0.
|
||||||
// - 1 as the counter range is inclusive [0, reload]
|
// - 1 as the counter range is inclusive [0, reload]
|
||||||
let reload = (sysclk + TIMER_HZ / 2) / TIMER_HZ - 1;
|
let reload = (sysclk + TIMER_HZ / 2) / TIMER_HZ - 1;
|
||||||
|
@ -45,7 +44,7 @@ impl Systick {
|
||||||
systick.enable_interrupt();
|
systick.enable_interrupt();
|
||||||
systick.enable_counter();
|
systick.enable_counter();
|
||||||
|
|
||||||
Systick {}
|
SYSTICK_TIMER_QUEUE.initialize(Systick {});
|
||||||
}
|
}
|
||||||
|
|
||||||
fn systick() -> SYST {
|
fn systick() -> SYST {
|
||||||
|
@ -54,6 +53,44 @@ impl Systick {
|
||||||
}
|
}
|
||||||
|
|
||||||
static SYSTICK_CNT: AtomicU32 = AtomicU32::new(0);
|
static SYSTICK_CNT: AtomicU32 = AtomicU32::new(0);
|
||||||
|
static SYSTICK_TIMER_QUEUE: TimerQueue<Systick> = TimerQueue::new();
|
||||||
|
|
||||||
|
// Forward timerqueue interface
|
||||||
|
impl Systick {
|
||||||
|
/// Used to access the underlying timer queue
|
||||||
|
#[doc(hidden)]
|
||||||
|
pub fn __tq() -> &'static TimerQueue<Systick> {
|
||||||
|
&SYSTICK_TIMER_QUEUE
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Timeout at a specific time.
|
||||||
|
pub async fn timeout_at<F: Future>(
|
||||||
|
instant: <Self as Monotonic>::Instant,
|
||||||
|
future: F,
|
||||||
|
) -> Result<F::Output, TimeoutError> {
|
||||||
|
SYSTICK_TIMER_QUEUE.timeout_at(instant, future).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Timeout after a specific duration.
|
||||||
|
#[inline]
|
||||||
|
pub async fn timeout_after<F: Future>(
|
||||||
|
duration: <Self as Monotonic>::Duration,
|
||||||
|
future: F,
|
||||||
|
) -> Result<F::Output, TimeoutError> {
|
||||||
|
SYSTICK_TIMER_QUEUE.timeout_after(duration, future).await
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delay for some duration of time.
|
||||||
|
#[inline]
|
||||||
|
pub async fn delay(duration: <Self as Monotonic>::Duration) {
|
||||||
|
SYSTICK_TIMER_QUEUE.delay(duration).await;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Delay to some specific time instant.
|
||||||
|
pub async fn delay_until(instant: <Self as Monotonic>::Instant) {
|
||||||
|
SYSTICK_TIMER_QUEUE.delay_until(instant).await;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
impl Monotonic for Systick {
|
impl Monotonic for Systick {
|
||||||
type Instant = fugit::TimerInstantU32<TIMER_HZ>;
|
type Instant = fugit::TimerInstantU32<TIMER_HZ>;
|
||||||
|
@ -92,49 +129,28 @@ impl Monotonic for Systick {
|
||||||
fn disable_timer() {}
|
fn disable_timer() {}
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Timer queue wrapper to implement traits on
|
impl DelayUs for Systick {
|
||||||
pub struct SystickTimerQueue(TimerQueue<Systick>);
|
|
||||||
|
|
||||||
impl SystickTimerQueue {
|
|
||||||
/// Create a new timer queue.
|
|
||||||
pub const fn new() -> Self {
|
|
||||||
Self(TimerQueue::new())
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl Deref for SystickTimerQueue {
|
|
||||||
type Target = TimerQueue<Systick>;
|
|
||||||
|
|
||||||
#[inline(always)]
|
|
||||||
fn deref(&self) -> &Self::Target {
|
|
||||||
&self.0
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
impl DelayUs for SystickTimerQueue {
|
|
||||||
type Error = core::convert::Infallible;
|
type Error = core::convert::Infallible;
|
||||||
|
|
||||||
async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
|
async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
|
||||||
self.delay(us.micros()).await;
|
SYSTICK_TIMER_QUEUE.delay(us.micros()).await;
|
||||||
Ok(())
|
Ok(())
|
||||||
}
|
}
|
||||||
|
|
||||||
async fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
|
async fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
|
||||||
self.delay(ms.millis()).await;
|
SYSTICK_TIMER_QUEUE.delay(ms.millis()).await;
|
||||||
Ok(())
|
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_export]
|
||||||
macro_rules! make_systick_timer_queue {
|
macro_rules! make_systick_handler {
|
||||||
($timer_queue_name:ident) => {
|
() => {
|
||||||
static $timer_queue_name: SystickTimerQueue = SystickTimerQueue::new();
|
|
||||||
|
|
||||||
#[no_mangle]
|
#[no_mangle]
|
||||||
#[allow(non_snake_case)]
|
#[allow(non_snake_case)]
|
||||||
unsafe extern "C" fn SysTick() {
|
unsafe extern "C" fn SysTick() {
|
||||||
$timer_queue_name.on_monotonic_interrupt();
|
Systick::__tq().on_monotonic_interrupt();
|
||||||
}
|
}
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
|
@ -11,7 +11,7 @@ mod app {
|
||||||
use cortex_m_semihosting::{debug, hprintln};
|
use cortex_m_semihosting::{debug, hprintln};
|
||||||
use rtic_monotonics::systick_monotonic::*;
|
use rtic_monotonics::systick_monotonic::*;
|
||||||
|
|
||||||
rtic_monotonics::make_systick_timer_queue!(TIMER);
|
rtic_monotonics::make_systick_handler!();
|
||||||
|
|
||||||
#[shared]
|
#[shared]
|
||||||
struct Shared {}
|
struct Shared {}
|
||||||
|
@ -23,8 +23,7 @@ mod app {
|
||||||
fn init(cx: init::Context) -> (Shared, Local) {
|
fn init(cx: init::Context) -> (Shared, Local) {
|
||||||
hprintln!("init");
|
hprintln!("init");
|
||||||
|
|
||||||
let systick = Systick::start(cx.core.SYST, 12_000_000);
|
Systick::start(cx.core.SYST, 12_000_000);
|
||||||
TIMER.initialize(systick);
|
|
||||||
|
|
||||||
foo::spawn().ok();
|
foo::spawn().ok();
|
||||||
bar::spawn().ok();
|
bar::spawn().ok();
|
||||||
|
@ -45,21 +44,21 @@ mod app {
|
||||||
#[task]
|
#[task]
|
||||||
async fn foo(_cx: foo::Context) {
|
async fn foo(_cx: foo::Context) {
|
||||||
hprintln!("hello from foo");
|
hprintln!("hello from foo");
|
||||||
TIMER.delay(100.millis()).await;
|
Systick::delay(100.millis()).await;
|
||||||
hprintln!("bye from foo");
|
hprintln!("bye from foo");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
async fn bar(_cx: bar::Context) {
|
async fn bar(_cx: bar::Context) {
|
||||||
hprintln!("hello from bar");
|
hprintln!("hello from bar");
|
||||||
TIMER.delay(200.millis()).await;
|
Systick::delay(200.millis()).await;
|
||||||
hprintln!("bye from bar");
|
hprintln!("bye from bar");
|
||||||
}
|
}
|
||||||
|
|
||||||
#[task]
|
#[task]
|
||||||
async fn baz(_cx: baz::Context) {
|
async fn baz(_cx: baz::Context) {
|
||||||
hprintln!("hello from baz");
|
hprintln!("hello from baz");
|
||||||
TIMER.delay(300.millis()).await;
|
Systick::delay(300.millis()).await;
|
||||||
hprintln!("bye from baz");
|
hprintln!("bye from baz");
|
||||||
|
|
||||||
debug::exit(debug::EXIT_SUCCESS);
|
debug::exit(debug::EXIT_SUCCESS);
|
||||||
|
|
|
@ -12,8 +12,9 @@ use rtic_monotonics::systick_monotonic::*;
|
||||||
mod app {
|
mod app {
|
||||||
use super::*;
|
use super::*;
|
||||||
use futures::{future::FutureExt, select_biased};
|
use futures::{future::FutureExt, select_biased};
|
||||||
|
use rtic_monotonics::Monotonic;
|
||||||
|
|
||||||
rtic_monotonics::make_systick_timer_queue!(TIMER);
|
rtic_monotonics::make_systick_handler!();
|
||||||
|
|
||||||
#[shared]
|
#[shared]
|
||||||
struct Shared {}
|
struct Shared {}
|
||||||
|
@ -25,8 +26,7 @@ mod app {
|
||||||
fn init(cx: init::Context) -> (Shared, Local) {
|
fn init(cx: init::Context) -> (Shared, Local) {
|
||||||
hprintln!("init");
|
hprintln!("init");
|
||||||
|
|
||||||
let systick = Systick::start(cx.core.SYST, 12_000_000);
|
Systick::start(cx.core.SYST, 12_000_000);
|
||||||
TIMER.initialize(systick);
|
|
||||||
|
|
||||||
foo::spawn().ok();
|
foo::spawn().ok();
|
||||||
|
|
||||||
|
@ -37,37 +37,37 @@ mod app {
|
||||||
async fn foo(_cx: foo::Context) {
|
async fn foo(_cx: foo::Context) {
|
||||||
// Call hal with short relative timeout using `select_biased`
|
// Call hal with short relative timeout using `select_biased`
|
||||||
select_biased! {
|
select_biased! {
|
||||||
v = hal_get(&TIMER, 1).fuse() => hprintln!("hal returned {}", v),
|
v = hal_get(1).fuse() => hprintln!("hal returned {}", v),
|
||||||
_ = TIMER.delay(200.millis()).fuse() => hprintln!("timeout", ), // this will finish first
|
_ = Systick::delay(200.millis()).fuse() => hprintln!("timeout", ), // this will finish first
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call hal with long relative timeout using `select_biased`
|
// Call hal with long relative timeout using `select_biased`
|
||||||
select_biased! {
|
select_biased! {
|
||||||
v = hal_get(&TIMER, 1).fuse() => hprintln!("hal returned {}", v), // hal finish first
|
v = hal_get(1).fuse() => hprintln!("hal returned {}", v), // hal finish first
|
||||||
_ = TIMER.delay(1000.millis()).fuse() => hprintln!("timeout", ),
|
_ = Systick::delay(1000.millis()).fuse() => hprintln!("timeout", ),
|
||||||
}
|
}
|
||||||
|
|
||||||
// Call hal with long relative timeout using monotonic `timeout_after`
|
// 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),
|
Ok(v) => hprintln!("hal returned {}", v),
|
||||||
_ => hprintln!("timeout"),
|
_ => hprintln!("timeout"),
|
||||||
}
|
}
|
||||||
|
|
||||||
// get the current time instance
|
// get the current time instance
|
||||||
let mut instant = TIMER.now();
|
let mut instant = Systick::now();
|
||||||
|
|
||||||
// do this 3 times
|
// do this 3 times
|
||||||
for n in 0..3 {
|
for n in 0..3 {
|
||||||
// exact point in time without drift
|
// exact point in time without drift
|
||||||
instant += 1000.millis();
|
instant += 1000.millis();
|
||||||
TIMER.delay_until(instant).await;
|
Systick::delay_until(instant).await;
|
||||||
|
|
||||||
// exact point it time for timeout
|
// exact point it time for timeout
|
||||||
let timeout = instant + 500.millis();
|
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 {
|
match Systick::timeout_at(timeout, hal_get(n)).await {
|
||||||
Ok(v) => hprintln!("hal returned {} at time {:?}", v, TIMER.now()),
|
Ok(v) => hprintln!("hal returned {} at time {:?}", v, Systick::now()),
|
||||||
_ => hprintln!("timeout"),
|
_ => hprintln!("timeout"),
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -77,11 +77,11 @@ mod app {
|
||||||
}
|
}
|
||||||
|
|
||||||
// Emulate some hal
|
// 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
|
// emulate some delay time dependent on n
|
||||||
let d = 350.millis() + n * 100.millis();
|
let d = 350.millis() + n * 100.millis();
|
||||||
hprintln!("the hal takes a duration of {:?}", d);
|
hprintln!("the hal takes a duration of {:?}", d);
|
||||||
timer.delay(d).await;
|
Systick::delay(d).await;
|
||||||
// emulate some return value
|
// emulate some return value
|
||||||
5
|
5
|
||||||
}
|
}
|
||||||
|
|
Loading…
Reference in a new issue