2 releases
new 0.1.1 | Mar 9, 2025 |
---|---|
0.1.0 | Mar 8, 2025 |
#471 in Hardware support
23KB
336 lines
64-bit SysTick timer for Cortex-M0
Implements a 64-bit SysTick based timer, that tracks overflows and provides as single monotonic 64-bit value at the desired resolution. The only dependencies are cortex-m and cortex-m-rt crates.
Optionally wraps this in an embassy-time-driver.
Example included for Qemu Cortex-M0
To run the demos with Qemu:
cargo runq --example basic_time
Embassy version:
cargo runq --example embassy_time
lib.rs
:
Provides a SysTick based 64-bit timer implementation.
In addition, optionally wraps this into a basic Embassy time driver.
The timer is a standalone implementation that can be used from any Cortex-M0/M3/M4/M7 code.
Usage:
// Set up timer with 1ms resolution, reload at 100us, 8MHz clock
static INSTANCE : Timer = Timer::new(1_000, 799, 8_000_000);
#[cortex_m_rt::entry]
fn main() -> ! {
// Configure and start SYST
INSTANCE.start(&mut cortex_m::Peripherals::take().unwrap().SYST);
// Get the current time in milliseconds
let now = timer.now();
}
Call the timer from your Systick handler:
#[exception]
fn SysTick() {
INSTANCE.systick_handler();
}
To reduce the frequency of overflow interrupts, you can use the maximum reload value:
let timer = Timer::new(1_000, 16_777_215, 48_000_000);
This generates an interrupt and reloads the timer every ~350ms, but the resolution is still 1ms
To use the Embassy driver, the setup needs to look as follows. First, create a static instance of the timer, passing in SysTick frequency and reload value. The constant <4> determines the number of concurrent wait tasks supported.
embassy_time_driver::time_driver_impl!(static DRIVER: SystickDriver<4>
= SystickDriver::new(8_000_000, 7999));
Next, you must have a SysTick interrupt handler that calls the driver's
systick_interrupt()
method on its static instance.
#[exception]
fn SysTick() {
DRIVER.systick_interrupt();
}
And in main, before using any timer calls, initialize the driver with the actual SysTick peripheral:
#[embassy_executor::main]
async fn main(_s: embassy_executor::Spawner) {
let mut periph = Peripherals::take().unwrap();
DRIVER.start(&mut periph.SYST);
// .. can use Timer::now() etc.
}
Dependencies
~0.8–1.3MB
~21K SLoC