2021-05-06 18:33:07 +08:00
|
|
|
///! System timer used for RTIC scheduling
|
|
|
|
///!
|
|
|
|
///! # Design
|
|
|
|
///! The SystemTimer is an RTIC monotonic timer that can be used for scheduling tasks in RTIC.
|
|
|
|
///! This timer is used in place of the cycle counter to allow the timer to tick at a slower rate
|
|
|
|
///! than the CPU clock. This allows for longer scheduling periods with less resolution. This is
|
|
|
|
///! needed for infrequent (e.g. multiple second) telemetry periods.
|
|
|
|
///!
|
|
|
|
///! # Limitations
|
|
|
|
///! This implementation relies on sufficient timer polling to not miss timer counter overflows. If
|
|
|
|
///! the timer is not polled often enough, it's possible that an overflow would be missed and time
|
|
|
|
///! would "halt" for a shore period of time. This could be fixed in the future by instead
|
|
|
|
///! listening for the overflow interrupt instead of polling the overflow state.
|
2021-04-15 20:40:47 +08:00
|
|
|
use hal::prelude::*;
|
|
|
|
use stm32h7xx_hal as hal;
|
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
// A global buffer indicating how many times the internal counter has overflowed.
|
2021-04-15 20:40:47 +08:00
|
|
|
static mut OVERFLOWS: u32 = 0;
|
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
/// System timer used for implementing RTIC scheduling.
|
|
|
|
///
|
|
|
|
/// # Note
|
|
|
|
/// The system timer must be initialized before being used.
|
2021-04-15 20:40:47 +08:00
|
|
|
pub struct SystemTimer {}
|
|
|
|
|
|
|
|
impl SystemTimer {
|
2021-05-06 18:33:07 +08:00
|
|
|
/// Initialize the system timer.
|
|
|
|
///
|
|
|
|
/// # Args
|
|
|
|
/// * `timer` - The hardware timer used for implementing the RTIC monotonic.
|
2021-04-15 20:40:47 +08:00
|
|
|
pub fn initialize(mut timer: hal::timer::Timer<hal::device::TIM15>) {
|
|
|
|
timer.pause();
|
|
|
|
// Have the system timer operate at a tick rate of 10KHz (100uS per tick). With this
|
|
|
|
// configuration and a 65535 period, we get an overflow once every 6.5 seconds.
|
2021-04-15 21:43:40 +08:00
|
|
|
timer.set_tick_freq(10.khz());
|
2021-04-15 20:40:47 +08:00
|
|
|
timer.apply_freq();
|
|
|
|
|
|
|
|
timer.resume();
|
|
|
|
}
|
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
/// Convert a provided number of seconds into timer ticks.
|
2021-04-15 20:40:47 +08:00
|
|
|
pub fn ticks_from_secs(secs: u32) -> i32 {
|
2021-04-15 21:43:40 +08:00
|
|
|
(secs * 10_000) as i32
|
2021-04-15 20:40:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
impl rtic::Monotonic for SystemTimer {
|
2021-07-15 19:28:19 +08:00
|
|
|
/// Instants are stored in 32-bit signed integers. With a 10KHz tick rate, this means an
|
|
|
|
/// instant can store up to ~59 hours of time before overflowing.
|
2021-04-15 20:40:47 +08:00
|
|
|
type Instant = i32;
|
|
|
|
|
2021-07-15 19:28:19 +08:00
|
|
|
/// The ratio of the CPU clock to the system timer.
|
2021-04-15 20:40:47 +08:00
|
|
|
fn ratio() -> rtic::Fraction {
|
|
|
|
rtic::Fraction {
|
2021-05-06 18:33:07 +08:00
|
|
|
// At 10KHz with a 400MHz CPU clock, the CPU clock runs 40,000 times faster than
|
|
|
|
// the system timer.
|
2021-04-15 21:43:40 +08:00
|
|
|
numerator: 40_000,
|
|
|
|
denominator: 1,
|
2021-04-15 20:40:47 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
/// Get the current time instant.
|
|
|
|
///
|
|
|
|
/// # Note
|
|
|
|
/// The time will overflow into -59 hours after the first 59 hours. This time value is intended
|
|
|
|
/// for use in calculating time delta, and should not be used for timestamping purposes due to
|
|
|
|
/// roll-over.
|
2021-04-15 20:40:47 +08:00
|
|
|
fn now() -> i32 {
|
2021-05-06 18:33:07 +08:00
|
|
|
// Note(unsafe): Multiple interrupt contexts have access to the underlying timer, so care
|
|
|
|
// is taken when reading and modifying register values.
|
2021-04-15 20:40:47 +08:00
|
|
|
let regs = unsafe { &*hal::device::TIM15::ptr() };
|
|
|
|
|
2021-05-07 19:02:14 +08:00
|
|
|
cortex_m::interrupt::free(|_cs| {
|
|
|
|
loop {
|
|
|
|
// Checking for overflows of the current counter must be performed atomically. Any
|
|
|
|
// other task that is accessing the current time could potentially race for the
|
|
|
|
// registers. Note that this is only required for writing to global state (e.g. timer
|
|
|
|
// registers and overflow counter)
|
2021-05-06 18:33:07 +08:00
|
|
|
// Check for overflows and clear the overflow bit atomically. This must be done in
|
|
|
|
// a critical section to prevent race conditions on the status register.
|
|
|
|
if regs.sr.read().uif().bit_is_set() {
|
|
|
|
regs.sr.modify(|_, w| w.uif().clear_bit());
|
|
|
|
unsafe {
|
|
|
|
OVERFLOWS += 1;
|
|
|
|
}
|
2021-04-15 20:40:47 +08:00
|
|
|
}
|
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
let current_value = regs.cnt.read().bits();
|
2021-04-15 20:40:47 +08:00
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
// Check that an overflow didn't occur since we just cleared the overflow bit. If
|
|
|
|
// it did, loop around and retry.
|
|
|
|
if regs.sr.read().uif().bit_is_clear() {
|
2021-05-06 18:45:13 +08:00
|
|
|
// Note(unsafe): We are in a critical section, so it is safe to read the
|
|
|
|
// global variable.
|
2021-05-07 19:02:14 +08:00
|
|
|
return unsafe {
|
|
|
|
((OVERFLOWS << 16) + current_value) as i32
|
|
|
|
};
|
2021-04-15 20:40:47 +08:00
|
|
|
}
|
2021-05-06 18:45:13 +08:00
|
|
|
}
|
2021-05-07 19:02:14 +08:00
|
|
|
})
|
2021-04-15 20:40:47 +08:00
|
|
|
}
|
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
/// Reset the timer count.
|
2021-04-15 20:40:47 +08:00
|
|
|
unsafe fn reset() {
|
|
|
|
// Note: The timer must be safely configured in `SystemTimer::initialize()`.
|
|
|
|
let regs = &*hal::device::TIM15::ptr();
|
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
OVERFLOWS = 0;
|
2021-04-15 20:40:47 +08:00
|
|
|
regs.cnt.reset();
|
|
|
|
}
|
|
|
|
|
2021-05-06 18:33:07 +08:00
|
|
|
/// Get a timestamp correlating to zero time.
|
2021-04-15 20:40:47 +08:00
|
|
|
fn zero() -> i32 {
|
|
|
|
0
|
|
|
|
}
|
|
|
|
}
|