Created
October 7, 2021 19:57
-
-
Save andresv/d2d3a13402055d94fcb5f658dc190c1a to your computer and use it in GitHub Desktop.
rtic 0.6 monotonic timer for stm32L0
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#![no_main] | |
#![no_std] | |
use rtic::rtic_monotonic::{embedded_time, Clock, Fraction, Instant, Monotonic}; | |
use stm32l0xx_hal::pac::TIM21; | |
use stm32l0xx_hal::timer::Timer; | |
/// Extended TIM21/16 to 64 bits | |
pub struct ExtendedMonotonicTimer<TIM> { | |
_tim: Timer<TIM>, | |
ovf: u64, | |
} | |
impl ExtendedMonotonicTimer<TIM21> { | |
pub fn new(tim: Timer<TIM21>) -> Self { | |
ExtendedMonotonicTimer { _tim: tim, ovf: 0 } | |
} | |
fn is_overflow(&self) -> bool { | |
let tim = unsafe { &*TIM21::ptr() }; | |
tim.sr.read().uif().bit_is_set() | |
} | |
pub fn count(&self) -> u16 { | |
let cnt = unsafe { (*TIM21::ptr()).cnt.read() }; | |
//defmt::info!("cnt {}", cnt.cnt().bits()); | |
cnt.cnt().bits() | |
} | |
} | |
impl Clock for ExtendedMonotonicTimer<TIM21> { | |
const SCALING_FACTOR: Fraction = Fraction::new(1, 64_000_000); | |
type T = u64; | |
fn try_now(&self) -> Result<Instant<Self>, embedded_time::clock::Error> { | |
let cnt = self.count(); | |
// If the overflow bit is set, we add this to the timer value. It means the `on_interrupt` | |
// has not yet happened, and we need to compensate here. | |
let ovf = if self.is_overflow() { 0x10000 } else { 0 }; | |
Ok(Instant::new(cnt as u64 + ovf as u64 + self.ovf)) | |
} | |
} | |
/// Use Compare channel 1 for Monotonic | |
impl Monotonic for ExtendedMonotonicTimer<TIM21> { | |
// Since we are counting overflows we can't let RTIC disable the interrupt. | |
const DISABLE_INTERRUPT_ON_EMPTY_QUEUE: bool = false; | |
unsafe fn reset(&mut self) { | |
// Since reset is only called once, we use it to enable the interrupt generation bit. | |
let tim = &*TIM21::ptr(); | |
tim.dier.modify(|_, w| w.cc1ie().set_bit()); | |
tim.cnt.write(|w| w.bits(0)); | |
} | |
fn set_compare(&mut self, instant: &Instant<Self>) { | |
let now = self.try_now().unwrap(); | |
// Since the timer may or may not overflow based on the requested compare val, we check | |
// how many ticks are left. | |
let val = match instant.checked_duration_since(&now) { | |
None => self.count().wrapping_add(1), // In the past | |
Some(x) if x.integer() <= 0xffff => instant.duration_since_epoch().integer() as u16, // Will not overflow | |
Some(_x) => self.count().wrapping_add(0xffff), // Will overflow | |
}; | |
unsafe { (*TIM21::ptr()).ccr1.write(|w| w.ccr().bits(val)) }; | |
} | |
fn clear_compare_flag(&mut self) { | |
let tim = unsafe { &*TIM21::ptr() }; | |
tim.sr.modify(|_, w| w.cc1if().clear_bit()); | |
} | |
fn on_interrupt(&mut self) { | |
// If there was an overflow, increment the overflow counter. | |
if self.is_overflow() { | |
let tim = unsafe { &*TIM21::ptr() }; | |
tim.sr.modify(|_, w| w.uif().clear_bit()); | |
self.ovf += 0x10000; | |
} | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Here is a version for newer rtic 0.6 which uses fugit for timing: https://github.com/kalkyl/f411-rtic/blob/main/src/bin/mono.rs