Skip to content

Instantly share code, notes, and snippets.

@andresv
Created October 7, 2021 19:57
Show Gist options
  • Save andresv/d2d3a13402055d94fcb5f658dc190c1a to your computer and use it in GitHub Desktop.
Save andresv/d2d3a13402055d94fcb5f658dc190c1a to your computer and use it in GitHub Desktop.
rtic 0.6 monotonic timer for stm32L0
#![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;
}
}
}
@andresv
Copy link
Author

andresv commented Dec 14, 2021

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

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment