Skip to content

Commit e012e13

Browse files
committed
Ensure alarm is re-scheduled if timetamp is in the past
Fixes #3672
1 parent 0733bee commit e012e13

File tree

1 file changed

+43
-37
lines changed

1 file changed

+43
-37
lines changed

embassy-nrf/src/time_driver.rs

Lines changed: 43 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -209,47 +209,53 @@ impl RtcDriver {
209209

210210
let r = rtc();
211211

212-
let t = self.now();
213-
if timestamp <= t {
214-
// If alarm timestamp has passed the alarm will not fire.
215-
// Disarm the alarm and return `false` to indicate that.
216-
r.intenclr().write(|w| w.0 = compare_n(n));
212+
loop {
213+
let t = self.now();
214+
if timestamp <= t {
215+
// If alarm timestamp has passed the alarm will not fire.
216+
// Disarm the alarm and return `false` to indicate that.
217+
r.intenclr().write(|w| w.0 = compare_n(n));
217218

218-
alarm.timestamp.set(u64::MAX);
219+
alarm.timestamp.set(u64::MAX);
219220

220-
return false;
221-
}
221+
return false;
222+
}
222223

223-
// If it hasn't triggered yet, setup it in the compare channel.
224-
225-
// Write the CC value regardless of whether we're going to enable it now or not.
226-
// This way, when we enable it later, the right value is already set.
227-
228-
// nrf52 docs say:
229-
// If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event.
230-
// To workaround this, we never write a timestamp smaller than N+3.
231-
// N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc.
232-
//
233-
// It is impossible for rtc to tick more than once because
234-
// - this code takes less time than 1 tick
235-
// - it runs with interrupts disabled so nothing else can preempt it.
236-
//
237-
// This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed
238-
// by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
239-
// and we don't do that here.
240-
let safe_timestamp = timestamp.max(t + 3);
241-
r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF));
242-
243-
let diff = timestamp - t;
244-
if diff < 0xc00000 {
245-
r.intenset().write(|w| w.0 = compare_n(n));
246-
} else {
247-
// If it's too far in the future, don't setup the compare channel yet.
248-
// It will be setup later by `next_period`.
249-
r.intenclr().write(|w| w.0 = compare_n(n));
250-
}
224+
// If it hasn't triggered yet, setup it in the compare channel.
225+
226+
// Write the CC value regardless of whether we're going to enable it now or not.
227+
// This way, when we enable it later, the right value is already set.
228+
229+
// nrf52 docs say:
230+
// If the COUNTER is N, writing N or N+1 to a CC register may not trigger a COMPARE event.
231+
// To workaround this, we never write a timestamp smaller than N+3.
232+
// N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc.
233+
//
234+
// It is impossible for rtc to tick more than once because
235+
// - this code takes less time than 1 tick
236+
// - it runs with interrupts disabled so nothing else can preempt it.
237+
//
238+
// This means that an alarm can be delayed for up to 2 ticks (from t+1 to t+3), but this is allowed
239+
// by the Alarm trait contract. What's not allowed is triggering alarms *before* their scheduled time,
240+
// and we don't do that here.
241+
let safe_timestamp = timestamp.max(t + 3);
242+
r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF));
243+
244+
let diff = timestamp - t;
245+
if diff < 0xc00000 {
246+
r.intenset().write(|w| w.0 = compare_n(n));
247+
} else {
248+
// If it's too far in the future, don't setup the compare channel yet.
249+
// It will be setup later by `next_period`.
250+
r.intenclr().write(|w| w.0 = compare_n(n));
251+
}
251252

252-
true
253+
// If we have not passed the safe timestamp, we can be sure the alarm will be invoked. Otherwise,
254+
// we need to retry setting the alarm.
255+
if self.now() <= safe_timestamp {
256+
return true;
257+
}
258+
}
253259
}
254260
}
255261

0 commit comments

Comments
 (0)