Merge pull request #3705 from embassy-rs/time-driver-fix

Ensure alarm is re-scheduled if timetamp is in the past
This commit is contained in:
Dario Nieuwenhuis 2025-01-02 12:39:23 +00:00 committed by GitHub
commit eaa44c3d3f
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194

View File

@ -209,6 +209,7 @@ impl RtcDriver {
let r = rtc();
loop {
let t = self.now();
if timestamp <= t {
// If alarm timestamp has passed the alarm will not fire.
@ -230,9 +231,9 @@ impl RtcDriver {
// To workaround this, we never write a timestamp smaller than N+3.
// N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc.
//
// It is impossible for rtc to tick more than once because
// - this code takes less time than 1 tick
// - it runs with interrupts disabled so nothing else can preempt it.
// Since the critical section does not guarantee that a higher prio interrupt causes
// this to be delayed, we need to re-check how much time actually passed after setting the
// alarm, and retry if we are within the unsafe interval still.
//
// This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed
// by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
@ -243,13 +244,19 @@ impl RtcDriver {
let diff = timestamp - t;
if diff < 0xc00000 {
r.intenset().write(|w| w.0 = compare_n(n));
// If we have not passed the timestamp, we can be sure the alarm will be invoked. Otherwise,
// we need to retry setting the alarm.
if self.now() + 2 <= timestamp {
return true;
}
} else {
// If it's too far in the future, don't setup the compare channel yet.
// It will be setup later by `next_period`.
r.intenclr().write(|w| w.0 = compare_n(n));
return true;
}
}
true
}
}