2023-01-23 20:05:47 +01:00
|
|
|
//! ...
|
2023-01-23 20:57:56 +01:00
|
|
|
|
|
|
|
use super::Monotonic;
|
|
|
|
pub use super::{TimeoutError, TimerQueue};
|
2023-01-27 20:20:14 +01:00
|
|
|
use atomic_polyfill::{AtomicU32, Ordering};
|
2023-02-02 21:00:41 +01:00
|
|
|
use core::future::Future;
|
2023-01-23 20:57:56 +01:00
|
|
|
use cortex_m::peripheral::SYST;
|
|
|
|
use embedded_hal_async::delay::DelayUs;
|
2023-01-27 20:20:14 +01:00
|
|
|
pub use fugit::ExtU32;
|
2023-01-23 20:57:56 +01:00
|
|
|
|
2023-02-02 20:14:41 +01:00
|
|
|
#[cfg(feature = "systick_100hz")]
|
|
|
|
const TIMER_HZ: u32 = 100;
|
|
|
|
|
|
|
|
#[cfg(feature = "systick_1khz")]
|
2023-01-24 12:34:11 +01:00
|
|
|
const TIMER_HZ: u32 = 1_000;
|
2023-01-23 20:57:56 +01:00
|
|
|
|
2023-02-02 20:14:41 +01:00
|
|
|
#[cfg(feature = "systick_10khz")]
|
|
|
|
const TIMER_HZ: u32 = 10_000;
|
|
|
|
|
2023-01-24 12:34:11 +01:00
|
|
|
/// Systick implementing `rtic_monotonic::Monotonic` which runs at 1 kHz.
|
|
|
|
pub struct Systick;
|
|
|
|
|
|
|
|
impl Systick {
|
2023-01-23 20:57:56 +01:00
|
|
|
/// 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.
|
2023-02-02 21:00:41 +01:00
|
|
|
pub fn start(mut systick: cortex_m::peripheral::SYST, sysclk: u32) {
|
2023-01-23 20:57:56 +01:00
|
|
|
// + 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();
|
|
|
|
|
2023-02-02 21:00:41 +01:00
|
|
|
SYSTICK_TIMER_QUEUE.initialize(Systick {});
|
2023-01-23 20:57:56 +01:00
|
|
|
}
|
|
|
|
|
|
|
|
fn systick() -> SYST {
|
|
|
|
unsafe { core::mem::transmute::<(), SYST>(()) }
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static SYSTICK_CNT: AtomicU32 = AtomicU32::new(0);
|
2023-02-02 21:00:41 +01:00
|
|
|
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;
|
|
|
|
}
|
|
|
|
}
|
2023-01-23 20:57:56 +01:00
|
|
|
|
2023-01-24 12:34:11 +01:00
|
|
|
impl Monotonic for Systick {
|
2023-01-23 20:57:56 +01:00
|
|
|
type Instant = fugit::TimerInstantU32<TIMER_HZ>;
|
|
|
|
type Duration = fugit::TimerDurationU32<TIMER_HZ>;
|
|
|
|
|
|
|
|
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() {}
|
|
|
|
}
|
|
|
|
|
2023-02-02 21:00:41 +01:00
|
|
|
impl DelayUs for Systick {
|
2023-01-23 20:57:56 +01:00
|
|
|
type Error = core::convert::Infallible;
|
|
|
|
|
|
|
|
async fn delay_us(&mut self, us: u32) -> Result<(), Self::Error> {
|
2023-02-02 21:00:41 +01:00
|
|
|
SYSTICK_TIMER_QUEUE.delay(us.micros()).await;
|
2023-01-23 20:57:56 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
|
|
|
|
async fn delay_ms(&mut self, ms: u32) -> Result<(), Self::Error> {
|
2023-02-02 21:00:41 +01:00
|
|
|
SYSTICK_TIMER_QUEUE.delay(ms.millis()).await;
|
2023-01-23 20:57:56 +01:00
|
|
|
Ok(())
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2023-02-02 21:00:41 +01:00
|
|
|
/// Register the Systick interrupt for the monotonic.
|
2023-01-23 20:57:56 +01:00
|
|
|
#[macro_export]
|
2023-02-02 21:00:41 +01:00
|
|
|
macro_rules! make_systick_handler {
|
|
|
|
() => {
|
2023-01-23 20:57:56 +01:00
|
|
|
#[no_mangle]
|
|
|
|
#[allow(non_snake_case)]
|
|
|
|
unsafe extern "C" fn SysTick() {
|
2023-02-02 21:00:41 +01:00
|
|
|
Systick::__tq().on_monotonic_interrupt();
|
2023-01-23 20:57:56 +01:00
|
|
|
}
|
|
|
|
};
|
|
|
|
}
|