aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--embassy-stm32/src/time_driver.rs19
-rw-r--r--embassy-time/src/driver.rs4
2 files changed, 20 insertions, 3 deletions
diff --git a/embassy-stm32/src/time_driver.rs b/embassy-stm32/src/time_driver.rs
index ea9c22d87..9981800b2 100644
--- a/embassy-stm32/src/time_driver.rs
+++ b/embassy-stm32/src/time_driver.rs
@@ -474,16 +474,29 @@ impl Driver for RtcDriver {
474 return false; 474 return false;
475 } 475 }
476 476
477 let safe_timestamp = timestamp.max(t + 3);
478
479 // Write the CCR value regardless of whether we're going to enable it now or not. 477 // Write the CCR value regardless of whether we're going to enable it now or not.
480 // This way, when we enable it later, the right value is already set. 478 // This way, when we enable it later, the right value is already set.
481 r.ccr(n + 1).write(|w| w.set_ccr(safe_timestamp as u16)); 479 r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16));
482 480
483 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it. 481 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
484 let diff = timestamp - t; 482 let diff = timestamp - t;
485 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000)); 483 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
486 484
485 // Reevaluate if the alarm timestamp is still in the future
486 let t = self.now();
487 if timestamp <= t {
488 // If alarm timestamp has passed since we set it, we have a race condition and
489 // the alarm may or may not have fired.
490 // Disarm the alarm and return `false` to indicate that.
491 // It is the caller's responsibility to handle this ambiguity.
492 r.dier().modify(|w| w.set_ccie(n + 1, false));
493
494 alarm.timestamp.set(u64::MAX);
495
496 return false;
497 }
498
499 // We're confident the alarm will ring in the future.
487 true 500 true
488 }) 501 })
489 } 502 }
diff --git a/embassy-time/src/driver.rs b/embassy-time/src/driver.rs
index 5fe7becaf..81ee1b0f5 100644
--- a/embassy-time/src/driver.rs
+++ b/embassy-time/src/driver.rs
@@ -108,6 +108,10 @@ pub trait Driver: Send + Sync + 'static {
108 /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`. 108 /// The `Driver` implementation should guarantee that the alarm callback is never called synchronously from `set_alarm`.
109 /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set, 109 /// Rather - if `timestamp` is already in the past - `false` should be returned and alarm should not be set,
110 /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously. 110 /// or alternatively, the driver should return `true` and arrange to call the alarm callback as soon as possible, but not synchronously.
111 /// There is a rare third possibility that the alarm was barely in the future, and by the time it was enabled, it had slipped into the
112 /// past. This is can be detected by double-checking that the alarm is still in the future after enabling it; if it isn't, `false`
113 /// should also be returned to indicate that the callback may have been called already by the alarm, but it is not guaranteed, so the
114 /// caller should also call the callback, just like in the more common `false` case. (Note: This requires idempotency of the callback.)
111 /// 115 ///
112 /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp. 116 /// When callback is called, it is guaranteed that now() will return a value greater or equal than timestamp.
113 /// 117 ///