Fix monotonics race

This commit is contained in:
Emil Fresk 2023-04-05 20:20:55 +02:00
parent 72ae46083e
commit 0bb5814443
2 changed files with 20 additions and 4 deletions

View file

@ -189,13 +189,18 @@ macro_rules! make_rtc {
// and the flag here.
critical_section::with(|_| {
let rtc = unsafe { &*$rtc::PTR };
let cnt = rtc.counter.read().bits() as u64;
let cnt = rtc.counter.read().bits();
// OVERFLOW HAPPENS HERE race needs to be handled
let ovf = if Self::is_overflow() {
$overflow.load(Ordering::Relaxed) + 1
} else {
$overflow.load(Ordering::Relaxed)
} as u64;
// Check and fix if above race happened
let new_cnt = rtc.counter.read().bits();
let cnt = if new_cnt >= cnt { cnt } else { new_cnt } as u64;
Self::Instant::from_ticks((ovf << 24) | cnt)
})
}

View file

@ -182,6 +182,12 @@ macro_rules! make_timer {
pub async fn delay_until(instant: <Self as Monotonic>::Instant) {
$tq.delay_until(instant).await;
}
#[inline(always)]
fn is_overflow() -> bool {
let timer = unsafe { &*$timer::PTR };
timer.events_compare[1].read().bits() & 1 != 0
}
}
#[cfg(feature = "embedded-hal-async")]
@ -213,17 +219,22 @@ macro_rules! make_timer {
critical_section::with(|_| {
let timer = unsafe { &*$timer::PTR };
timer.tasks_capture[2].write(|w| unsafe { w.bits(1) });
let cnt = timer.cc[2].read().bits();
let unhandled_overflow = if timer.events_compare[1].read().bits() & 1 != 0 {
let unhandled_overflow = if Self::is_overflow() {
// The overflow has not been handled yet, so add an extra to the read overflow.
1
} else {
0
};
timer.tasks_capture[2].write(|w| unsafe { w.bits(1) });
let new_cnt = timer.cc[2].read().bits();
let cnt = if new_cnt >= cnt { cnt } else { new_cnt } as u64;
Self::Instant::from_ticks(
(unhandled_overflow + $overflow.load(Ordering::Relaxed) as u64) << 32
| timer.cc[2].read().bits() as u64,
| cnt as u64,
)
})
}
@ -232,7 +243,7 @@ macro_rules! make_timer {
let timer = unsafe { &*$timer::PTR };
// If there is a compare match on channel 1, it is an overflow
if timer.events_compare[1].read().bits() & 1 != 0 {
if Self::is_overflow() {
timer.events_compare[1].write(|w| w);
$overflow.fetch_add(1, Ordering::SeqCst);
}