pub mod prelude {
pub use crate::systick_monotonic;
pub use crate::Monotonic;
cfg_if::cfg_if! {
if #[cfg(feature = "systick-64bit")] {
pub use fugit::{self, ExtU64, ExtU64Ceil};
} else {
pub use fugit::{self, ExtU32, ExtU32Ceil};
}
}
}
pub use cortex_m::peripheral::{syst::SystClkSource, SYST};
use portable_atomic::Ordering;
use rtic_time::timer_queue::TimerQueue;
use crate::TimerQueueBackend;
cfg_if::cfg_if! {
if #[cfg(feature = "systick-64bit")] {
use portable_atomic::AtomicU64;
static SYSTICK_CNT: AtomicU64 = AtomicU64::new(0);
} else {
use portable_atomic::AtomicU32;
static SYSTICK_CNT: AtomicU32 = AtomicU32::new(0);
}
}
static SYSTICK_TIMER_QUEUE: TimerQueue<SystickBackend> = TimerQueue::new();
pub struct SystickBackend;
impl SystickBackend {
pub fn _start(mut systick: SYST, sysclk: u32, timer_hz: u32, clk_source: SystClkSource) {
assert!(
sysclk.is_multiple_of(timer_hz),
"timer_hz cannot evenly divide sysclk! Please adjust the timer or sysclk frequency."
);
let reload = sysclk / timer_hz - 1;
assert!(reload <= 0x00ff_ffff);
assert!(reload > 0);
systick.disable_counter();
systick.set_clock_source(clk_source);
systick.set_reload(reload);
systick.enable_interrupt();
systick.enable_counter();
SYSTICK_TIMER_QUEUE.initialize(SystickBackend {});
}
fn systick() -> SYST {
unsafe { core::mem::transmute::<(), SYST>(()) }
}
}
impl TimerQueueBackend for SystickBackend {
cfg_if::cfg_if! {
if #[cfg(feature = "systick-64bit")] {
type Ticks = u64;
} else {
type Ticks = u32;
}
}
fn now() -> Self::Ticks {
if Self::systick().has_wrapped() {
SYSTICK_CNT.fetch_add(1, Ordering::AcqRel);
}
SYSTICK_CNT.load(Ordering::Relaxed)
}
fn set_compare(_: Self::Ticks) {
}
fn clear_compare_flag() {
}
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 timer_queue() -> &'static TimerQueue<Self> {
&SYSTICK_TIMER_QUEUE
}
}
#[macro_export]
macro_rules! systick_monotonic {
($name:ident) => {
$crate::systick_monotonic!($name, 1_000);
};
($name:ident, $tick_rate_hz:expr) => {
pub struct $name;
impl $name {
pub fn start(systick: $crate::systick::SYST, sysclk: u32) {
Self::start_with_clock_source(systick, sysclk, $crate::systick::SystClkSource::Core)
}
pub fn start_with_clock_source(
systick: $crate::systick::SYST,
sysclk: u32,
clk_source: $crate::systick::SystClkSource,
) {
#[no_mangle]
#[allow(non_snake_case)]
unsafe extern "C" fn SysTick() {
use $crate::TimerQueueBackend;
$crate::systick::SystickBackend::timer_queue().on_monotonic_interrupt();
}
$crate::systick::SystickBackend::_start(systick, sysclk, $tick_rate_hz, clk_source);
}
}
impl $crate::TimerQueueBasedMonotonic for $name {
type Backend = $crate::systick::SystickBackend;
type Instant = $crate::fugit::Instant<
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
1,
{ $tick_rate_hz },
>;
type Duration = $crate::fugit::Duration<
<Self::Backend as $crate::TimerQueueBackend>::Ticks,
1,
{ $tick_rate_hz },
>;
}
$crate::rtic_time::impl_embedded_hal_delay_fugit!($name);
$crate::rtic_time::impl_embedded_hal_async_delay_fugit!($name);
};
}