rtic-monotonics: Add interrupt tokens to make sure users bind interrupts

This commit is contained in:
Emil Fresk 2023-03-11 20:47:39 +01:00
parent 7c7d6558f6
commit e4d9284e25
6 changed files with 49 additions and 9 deletions

View file

@ -9,6 +9,8 @@ For each category, *Added*, *Changed*, *Fixed* add new entries at the top!
### Added ### Added
- Interrupt tokens for `Systick` and `rp2040` to make sure an interrupt handler exists
### Changed ### Changed
### Fixed ### Fixed

View file

@ -13,3 +13,13 @@ pub mod systick;
#[cfg(feature = "rp2040")] #[cfg(feature = "rp2040")]
pub mod rp2040; pub mod rp2040;
/// This marker is implemented on an interrupt token to enforce that the right tokens
/// are given to the correct monotonic implementation.
///
/// This trait is implemented by this crate and not intended for user implementation.
///
/// # Safety
///
/// This is only safely implemented by this crate.
pub unsafe trait InterruptToken<Periperhal> {}

View file

@ -4,14 +4,18 @@ use super::Monotonic;
pub use super::{TimeoutError, TimerQueue}; pub use super::{TimeoutError, TimerQueue};
use core::future::Future; use core::future::Future;
pub use fugit::ExtU64; pub use fugit::ExtU64;
use rp2040_pac::{timer, Interrupt, RESETS, TIMER}; use rp2040_pac::{timer, Interrupt, NVIC, RESETS, TIMER};
/// Timer implementing `rtic_monotonic::Monotonic` which runs at 1 MHz. /// Timer implementing `rtic_monotonic::Monotonic` which runs at 1 MHz.
pub struct Timer; pub struct Timer;
impl Timer { impl Timer {
/// Start a `Monotonic` based on RP2040's Timer. /// Start a `Monotonic` based on RP2040's Timer.
pub fn start(timer: TIMER, resets: &mut RESETS) { pub fn start(
timer: TIMER,
resets: &mut RESETS,
_interrupt_token: impl crate::InterruptToken<Self>,
) {
resets.reset.modify(|_, w| w.timer().clear_bit()); resets.reset.modify(|_, w| w.timer().clear_bit());
while resets.reset_done.read().timer().bit_is_clear() {} while resets.reset_done.read().timer().bit_is_clear() {}
timer.inte.modify(|_, w| w.alarm_0().set_bit()); timer.inte.modify(|_, w| w.alarm_0().set_bit());
@ -134,10 +138,21 @@ impl embedded_hal_async::delay::DelayUs for Timer {
#[macro_export] #[macro_export]
macro_rules! make_rp2040_monotonic_handler { macro_rules! make_rp2040_monotonic_handler {
() => { () => {
{
#[no_mangle] #[no_mangle]
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe extern "C" fn TIMER_IRQ_0() { unsafe extern "C" fn TIMER_IRQ_0() {
rtic_monotonics::rp2040::Timer::__tq().on_monotonic_interrupt(); rtic_monotonics::rp2040::Timer::__tq().on_monotonic_interrupt();
} }
pub struct Rp2040Token;
unsafe impl rtic_monotonics::InterruptToken<rtic_monotonics::rp2040::Timer>
for Rp2040Token
{
}
Rp2040Token
}
}; };
} }

View file

@ -36,7 +36,11 @@ impl Systick {
/// `sysclk` and `TIMER_HZ`. /// `sysclk` and `TIMER_HZ`.
/// ///
/// Note: Give the return value to `TimerQueue::initialize()` to initialize the timer queue. /// Note: Give the return value to `TimerQueue::initialize()` to initialize the timer queue.
pub fn start(mut systick: cortex_m::peripheral::SYST, sysclk: u32) { pub fn start(
mut systick: cortex_m::peripheral::SYST,
sysclk: u32,
_interrupt_token: impl crate::InterruptToken<Self>,
) {
// + TIMER_HZ / 2 provides round to nearest instead of round to 0. // + TIMER_HZ / 2 provides round to nearest instead of round to 0.
// - 1 as the counter range is inclusive [0, reload] // - 1 as the counter range is inclusive [0, reload]
let reload = (sysclk + TIMER_HZ / 2) / TIMER_HZ - 1; let reload = (sysclk + TIMER_HZ / 2) / TIMER_HZ - 1;
@ -154,10 +158,21 @@ impl embedded_hal_async::delay::DelayUs for Systick {
#[macro_export] #[macro_export]
macro_rules! make_systick_handler { macro_rules! make_systick_handler {
() => { () => {
{
#[no_mangle] #[no_mangle]
#[allow(non_snake_case)] #[allow(non_snake_case)]
unsafe extern "C" fn SysTick() { unsafe extern "C" fn SysTick() {
rtic_monotonics::systick::Systick::__tq().on_monotonic_interrupt(); rtic_monotonics::systick::Systick::__tq().on_monotonic_interrupt();
} }
pub struct SystickToken;
unsafe impl rtic_monotonics::InterruptToken<rtic_monotonics::systick::Systick>
for SystickToken
{
}
SystickToken
}
}; };
} }

View file

@ -14,8 +14,6 @@ mod app {
use cortex_m_semihosting::{debug, hprintln}; use cortex_m_semihosting::{debug, hprintln};
use rtic_monotonics::systick::*; use rtic_monotonics::systick::*;
rtic_monotonics::make_systick_handler!();
#[shared] #[shared]
struct Shared {} struct Shared {}
@ -26,7 +24,8 @@ mod app {
fn init(cx: init::Context) -> (Shared, Local) { fn init(cx: init::Context) -> (Shared, Local) {
hprintln!("init"); hprintln!("init");
Systick::start(cx.core.SYST, 12_000_000); let systick_token = rtic_monotonics::make_systick_handler!();
Systick::start(cx.core.SYST, 12_000_000, systick_token);
foo::spawn().ok(); foo::spawn().ok();
bar::spawn().ok(); bar::spawn().ok();

View file

@ -17,8 +17,6 @@ mod app {
use futures::{future::FutureExt, select_biased}; use futures::{future::FutureExt, select_biased};
use rtic_monotonics::Monotonic; use rtic_monotonics::Monotonic;
rtic_monotonics::make_systick_handler!();
#[shared] #[shared]
struct Shared {} struct Shared {}
@ -29,7 +27,8 @@ mod app {
fn init(cx: init::Context) -> (Shared, Local) { fn init(cx: init::Context) -> (Shared, Local) {
hprintln!("init"); hprintln!("init");
Systick::start(cx.core.SYST, 12_000_000); let systick_token = rtic_monotonics::make_systick_handler!();
Systick::start(cx.core.SYST, 12_000_000, systick_token);
foo::spawn().ok(); foo::spawn().ok();