systick_timer/lib.rs
1// SPDX-License-Identifier: Apache-2.0
2
3#![cfg_attr(not(test), no_std)]
4
5//! Provides a SysTick based 64-bit timer implementation.
6//!
7//! In addition, optionally wraps this into a basic Embassy time
8//! driver.
9//!
10//! The timer is a standalone implementation that can be used from
11//! any Cortex-M0/M3/M4/M7 code.
12//!
13//! The timer does not use critical sections or locking, only atomic
14//! operations.
15//!
16//! Usage:
17//! ```ignore
18//! // Set up timer with 1ms resolution, reload at 100us, 8MHz clock
19//! static INSTANCE : Timer = Timer::new(1_000, 799, 8_000_000);
20//!
21//! #[cortex_m_rt::entry]
22//! fn main() -> ! {
23//! // Configure and start SYST
24//! INSTANCE.start(&mut cortex_m::Peripherals::take().unwrap().SYST);
25//! // Get the current time in milliseconds
26//! let now = timer.now();
27//! }
28//! ```
29//! Call the timer from your Systick handler:
30//! ```ignore
31//! #[exception]
32//! fn SysTick() {
33//! INSTANCE.systick_handler();
34//! }
35//! ```
36//!
37//! To reduce the frequency of overflow interrupts,
38//! you can use the maximum reload value:
39//! ```ignore
40//! let timer = Timer::new(1_000, 16_777_215, 48_000_000);
41//! ```
42//! This generates an interrupt and reloads the timer every ~350ms, but
43//! the resolution is still 1ms
44//!
45//! ----------------------------------------------------------------
46//!
47//! To use the Embassy driver, the setup needs to look as follows. First,
48//! create a static instance of the timer, passing in SysTick frequency
49//! and reload value. The constant <4> determines the number of concurrent
50//! wait tasks supported.
51//!
52//! ```ignore
53//! embassy_time_driver::time_driver_impl!(static DRIVER: SystickDriver<4>
54//! = SystickDriver::new(8_000_000, 7999));
55//! ```
56//!
57//! Next, you must have a SysTick interrupt handler that calls the driver's
58//! `systick_interrupt()` method on its static instance.
59//!
60//! ```ignore
61//! #[exception]
62//! fn SysTick() {
63//! DRIVER.systick_interrupt();
64//! }
65//! ```
66//!
67//! And in main, before using any timer calls, initialize the driver with
68//! the actual SysTick peripheral:
69//!
70//! ```ignore
71//! #[embassy_executor::main]
72//! async fn main(_s: embassy_executor::Spawner) {
73//! let mut periph = Peripherals::take().unwrap();
74//! DRIVER.start(&mut periph.SYST);
75//! // .. can use Timer::now() etc.
76//! }
77//! ```
78
79pub mod timer;
80pub use timer::Timer;
81
82#[cfg(feature = "embassy-time-driver")]
83mod embassy_driver;
84#[cfg(feature = "embassy-time-driver")]
85pub use embassy_driver::SystickDriver;