aboutsummaryrefslogtreecommitdiff
path: root/embassy-nrf
diff options
context:
space:
mode:
authorUlf Lilleengen <[email protected]>2025-01-01 19:47:39 +0100
committerUlf Lilleengen <[email protected]>2025-01-01 19:47:39 +0100
commite012e1385814647e1c17cb64175a19745c18bb8f (patch)
treeaaa7abf2a5db062ef899ed85f9e85674e8cb138a /embassy-nrf
parent0733bee926ef117ad99e54194b009d7345051414 (diff)
Ensure alarm is re-scheduled if timetamp is in the past
Fixes #3672
Diffstat (limited to 'embassy-nrf')
-rw-r--r--embassy-nrf/src/time_driver.rs80
1 files changed, 43 insertions, 37 deletions
diff --git a/embassy-nrf/src/time_driver.rs b/embassy-nrf/src/time_driver.rs
index ade6fd2a1..01079e26a 100644
--- a/embassy-nrf/src/time_driver.rs
+++ b/embassy-nrf/src/time_driver.rs
@@ -209,47 +209,53 @@ impl RtcDriver {
209 209
210 let r = rtc(); 210 let r = rtc();
211 211
212 let t = self.now(); 212 loop {
213 if timestamp <= t { 213 let t = self.now();
214 // If alarm timestamp has passed the alarm will not fire. 214 if timestamp <= t {
215 // Disarm the alarm and return `false` to indicate that. 215 // If alarm timestamp has passed the alarm will not fire.
216 r.intenclr().write(|w| w.0 = compare_n(n)); 216 // Disarm the alarm and return `false` to indicate that.
217 r.intenclr().write(|w| w.0 = compare_n(n));
217 218
218 alarm.timestamp.set(u64::MAX); 219 alarm.timestamp.set(u64::MAX);
219 220
220 return false; 221 return false;
221 } 222 }
222 223
223 // If it hasn't triggered yet, setup it in the compare channel. 224 // If it hasn't triggered yet, setup it in the compare channel.
224 225
225 // Write the CC value regardless of whether we're going to enable it now or not. 226 // 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 // This way, when we enable it later, the right value is already set.
227 228
228 // nrf52 docs say: 229 // 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 // 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 // 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 // N+2 is not safe because rtc can tick from N to N+1 between calling now() and writing cc.
232 // 233 //
233 // It is impossible for rtc to tick more than once because 234 // It is impossible for rtc to tick more than once because
234 // - this code takes less time than 1 tick 235 // - this code takes less time than 1 tick
235 // - it runs with interrupts disabled so nothing else can preempt it. 236 // - it runs with interrupts disabled so nothing else can preempt it.
236 // 237 //
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 // 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 // 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 // and we don't do that here.
240 let safe_timestamp = timestamp.max(t + 3); 241 let safe_timestamp = timestamp.max(t + 3);
241 r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF)); 242 r.cc(n).write(|w| w.set_compare(safe_timestamp as u32 & 0xFFFFFF));
242 243
243 let diff = timestamp - t; 244 let diff = timestamp - t;
244 if diff < 0xc00000 { 245 if diff < 0xc00000 {
245 r.intenset().write(|w| w.0 = compare_n(n)); 246 r.intenset().write(|w| w.0 = compare_n(n));
246 } else { 247 } else {
247 // If it's too far in the future, don't setup the compare channel yet. 248 // 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 // It will be setup later by `next_period`.
249 r.intenclr().write(|w| w.0 = compare_n(n)); 250 r.intenclr().write(|w| w.0 = compare_n(n));
250 } 251 }
251 252
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 }
253 } 259 }
254} 260}
255 261