1#![allow(non_snake_case)]
2
3use core::cell::{Cell, RefCell};
4use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
5
6use critical_section::CriticalSection;
7use embassy_sync::blocking_mutex::raw::CriticalSectionRawMutex;
8use embassy_sync::blocking_mutex::Mutex;
9use embassy_time_driver::{Driver, TICK_HZ};
10use embassy_time_queue_utils::Queue;
11use stm32_metapac::timer::{regs, TimGp16};
12
13use crate::interrupt::typelevel::Interrupt;
14use crate::pac::timer::vals;
15use crate::rcc::{self, SealedRccPeripheral};
16#[cfg(feature = "low-power")]
17use crate::rtc::Rtc;
18use crate::timer::{CoreInstance, GeneralInstance1Channel};
19use crate::{interrupt, peripherals};
20
21// NOTE regarding ALARM_COUNT:
22//
23// As of 2023-12-04, this driver is implemented using CC1 as the halfway rollover interrupt, and any
24// additional CC capabilities to provide timer alarms to embassy-time. embassy-time requires AT LEAST
25// one alarm to be allocatable, which means timers that only have CC1, such as TIM16/TIM17, are not
26// candidates for use as an embassy-time driver provider. (a.k.a 1CH and 1CH_CMP are not, others are good.)
27
28#[cfg(time_driver_tim1)]
29type T = peripherals::TIM1;
30#[cfg(time_driver_tim2)]
31type T = peripherals::TIM2;
32#[cfg(time_driver_tim3)]
33type T = peripherals::TIM3;
34#[cfg(time_driver_tim4)]
35type T = peripherals::TIM4;
36#[cfg(time_driver_tim5)]
37type T = peripherals::TIM5;
38#[cfg(time_driver_tim8)]
39type T = peripherals::TIM8;
40#[cfg(time_driver_tim9)]
41type T = peripherals::TIM9;
42#[cfg(time_driver_tim12)]
43type T = peripherals::TIM12;
44#[cfg(time_driver_tim15)]
45type T = peripherals::TIM15;
46#[cfg(time_driver_tim20)]
47type T = peripherals::TIM20;
48#[cfg(time_driver_tim21)]
49type T = peripherals::TIM21;
50#[cfg(time_driver_tim22)]
51type T = peripherals::TIM22;
52#[cfg(time_driver_tim23)]
53type T = peripherals::TIM23;
54#[cfg(time_driver_tim24)]
55type T = peripherals::TIM24;
56
57foreach_interrupt! {
58 (TIM1, timer, $block:ident, CC, $irq:ident) => {
59 #[cfg(time_driver_tim1)]
60 #[cfg(feature = "rt")]
61 #[interrupt]
62 fn $irq() {
63 DRIVER.on_interrupt()
64 }
65 };
66 (TIM2, timer, $block:ident, CC, $irq:ident) => {
67 #[cfg(time_driver_tim2)]
68 #[cfg(feature = "rt")]
69 #[interrupt]
70 fn $irq() {
71 DRIVER.on_interrupt()
72 }
73 };
74 (TIM3, timer, $block:ident, CC, $irq:ident) => {
75 #[cfg(time_driver_tim3)]
76 #[cfg(feature = "rt")]
77 #[interrupt]
78 fn $irq() {
79 DRIVER.on_interrupt()
80 }
81 };
82 (TIM4, timer, $block:ident, CC, $irq:ident) => {
83 #[cfg(time_driver_tim4)]
84 #[cfg(feature = "rt")]
85 #[interrupt]
86 fn $irq() {
87 DRIVER.on_interrupt()
88 }
89 };
90 (TIM5, timer, $block:ident, CC, $irq:ident) => {
91 #[cfg(time_driver_tim5)]
92 #[cfg(feature = "rt")]
93 #[interrupt]
94 fn $irq() {
95 DRIVER.on_interrupt()
96 }
97 };
98 (TIM8, timer, $block:ident, CC, $irq:ident) => {
99 #[cfg(time_driver_tim8)]
100 #[cfg(feature = "rt")]
101 #[interrupt]
102 fn $irq() {
103 DRIVER.on_interrupt()
104 }
105 };
106 (TIM9, timer, $block:ident, CC, $irq:ident) => {
107 #[cfg(time_driver_tim9)]
108 #[cfg(feature = "rt")]
109 #[interrupt]
110 fn $irq() {
111 DRIVER.on_interrupt()
112 }
113 };
114 (TIM12, timer, $block:ident, CC, $irq:ident) => {
115 #[cfg(time_driver_tim12)]
116 #[cfg(feature = "rt")]
117 #[interrupt]
118 fn $irq() {
119 DRIVER.on_interrupt()
120 }
121 };
122 (TIM15, timer, $block:ident, CC, $irq:ident) => {
123 #[cfg(time_driver_tim15)]
124 #[cfg(feature = "rt")]
125 #[interrupt]
126 fn $irq() {
127 DRIVER.on_interrupt()
128 }
129 };
130 (TIM20, timer, $block:ident, CC, $irq:ident) => {
131 #[cfg(time_driver_tim20)]
132 #[cfg(feature = "rt")]
133 #[interrupt]
134 fn $irq() {
135 DRIVER.on_interrupt()
136 }
137 };
138 (TIM21, timer, $block:ident, CC, $irq:ident) => {
139 #[cfg(time_driver_tim21)]
140 #[cfg(feature = "rt")]
141 #[interrupt]
142 fn $irq() {
143 DRIVER.on_interrupt()
144 }
145 };
146 (TIM22, timer, $block:ident, CC, $irq:ident) => {
147 #[cfg(time_driver_tim22)]
148 #[cfg(feature = "rt")]
149 #[interrupt]
150 fn $irq() {
151 DRIVER.on_interrupt()
152 }
153 };
154 (TIM23, timer, $block:ident, CC, $irq:ident) => {
155 #[cfg(time_driver_tim23)]
156 #[cfg(feature = "rt")]
157 #[interrupt]
158 fn $irq() {
159 DRIVER.on_interrupt()
160 }
161 };
162 (TIM24, timer, $block:ident, CC, $irq:ident) => {
163 #[cfg(time_driver_tim24)]
164 #[cfg(feature = "rt")]
165 #[interrupt]
166 fn $irq() {
167 DRIVER.on_interrupt()
168 }
169 };
170}
171
172fn regs_gp16() -> TimGp16 {
173 unsafe { TimGp16::from_ptr(T::regs()) }
174}
175
176// Clock timekeeping works with something we call "periods", which are time intervals
177// of 2^15 ticks. The Clock counter value is 16 bits, so one "overflow cycle" is 2 periods.
178//
179// A `period` count is maintained in parallel to the Timer hardware `counter`, like this:
180// - `period` and `counter` start at 0
181// - `period` is incremented on overflow (at counter value 0)
182// - `period` is incremented "midway" between overflows (at counter value 0x8000)
183//
184// Therefore, when `period` is even, counter is in 0..0x7FFF. When odd, counter is in 0x8000..0xFFFF
185// This allows for now() to return the correct value even if it races an overflow.
186//
187// To get `now()`, `period` is read first, then `counter` is read. If the counter value matches
188// the expected range for the `period` parity, we're done. If it doesn't, this means that
189// a new period start has raced us between reading `period` and `counter`, so we assume the `counter` value
190// corresponds to the next period.
191//
192// `period` is a 32bit integer, so It overflows on 2^32 * 2^15 / 32768 seconds of uptime, which is 136 years.
193fn calc_now(period: u32, counter: u16) -> u64 {
194 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64)
195}
196
197struct AlarmState {
198 timestamp: Cell<u64>,
199}
200
201unsafe impl Send for AlarmState {}
202
203impl AlarmState {
204 const fn new() -> Self {
205 Self {
206 timestamp: Cell::new(u64::MAX),
207 }
208 }
209}
210
211pub(crate) struct RtcDriver {
212 /// Number of 2^15 periods elapsed since boot.
213 period: AtomicU32,
214 alarm: Mutex<CriticalSectionRawMutex, AlarmState>,
215 #[cfg(feature = "low-power")]
216 rtc: Mutex<CriticalSectionRawMutex, Cell<Option<&'static Rtc>>>,
217 queue: Mutex<CriticalSectionRawMutex, RefCell<Queue>>,
218}
219
220embassy_time_driver::time_driver_impl!(static DRIVER: RtcDriver = RtcDriver {
221 period: AtomicU32::new(0),
222 alarm: Mutex::const_new(CriticalSectionRawMutex::new(), AlarmState::new()),
223 #[cfg(feature = "low-power")]
224 rtc: Mutex::const_new(CriticalSectionRawMutex::new(), Cell::new(None)),
225 queue: Mutex::new(RefCell::new(Queue::new()))
226});
227
228impl RtcDriver {
229 fn init(&'static self, cs: critical_section::CriticalSection) {
230 let r = regs_gp16();
231
232 rcc::enable_and_reset_with_cs::<T>(cs);
233
234 let timer_freq = T::frequency();
235
236 r.cr1().modify(|w| w.set_cen(false));
237 r.cnt().write(|w| w.set_cnt(0));
238
239 let psc = timer_freq.0 / TICK_HZ as u32 - 1;
240 let psc: u16 = match psc.try_into() {
241 Err(_) => panic!("psc division overflow: {}", psc),
242 Ok(n) => n,
243 };
244
245 r.psc().write_value(psc);
246 r.arr().write(|w| w.set_arr(u16::MAX));
247
248 // Set URS, generate update and clear URS
249 r.cr1().modify(|w| w.set_urs(vals::Urs::COUNTER_ONLY));
250 r.egr().write(|w| w.set_ug(true));
251 r.cr1().modify(|w| w.set_urs(vals::Urs::ANY_EVENT));
252
253 // Mid-way point
254 r.ccr(0).write(|w| w.set_ccr(0x8000));
255
256 // Enable overflow and half-overflow interrupts
257 r.dier().write(|w| {
258 w.set_uie(true);
259 w.set_ccie(0, true);
260 });
261
262 <T as GeneralInstance1Channel>::CaptureCompareInterrupt::unpend();
263 unsafe { <T as GeneralInstance1Channel>::CaptureCompareInterrupt::enable() };
264
265 r.cr1().modify(|w| w.set_cen(true));
266 }
267
268 fn on_interrupt(&self) {
269 let r = regs_gp16();
270
271 critical_section::with(|cs| {
272 let sr = r.sr().read();
273 let dier = r.dier().read();
274
275 // Clear all interrupt flags. Bits in SR are "write 0 to clear", so write the bitwise NOT.
276 // Other approaches such as writing all zeros, or RMWing won't work, they can
277 // miss interrupts.
278 r.sr().write_value(regs::SrGp16(!sr.0));
279
280 // Overflow
281 if sr.uif() {
282 self.next_period();
283 }
284
285 // Half overflow
286 if sr.ccif(0) {
287 self.next_period();
288 }
289
290 let n = 0;
291 if sr.ccif(n + 1) && dier.ccie(n + 1) {
292 self.trigger_alarm(cs);
293 }
294 })
295 }
296
297 fn next_period(&self) {
298 let r = regs_gp16();
299
300 // We only modify the period from the timer interrupt, so we know this can't race.
301 let period = self.period.load(Ordering::Relaxed) + 1;
302 self.period.store(period, Ordering::Relaxed);
303 let t = (period as u64) << 15;
304
305 critical_section::with(move |cs| {
306 r.dier().modify(move |w| {
307 let n = 0;
308 let alarm = self.alarm.borrow(cs);
309 let at = alarm.timestamp.get();
310
311 if at < t + 0xc000 {
312 // just enable it. `set_alarm` has already set the correct CCR val.
313 w.set_ccie(n + 1, true);
314 }
315 })
316 })
317 }
318
319 fn trigger_alarm(&self, cs: CriticalSection) {
320 let mut next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
321 while !self.set_alarm(cs, next) {
322 next = self.queue.borrow(cs).borrow_mut().next_expiration(self.now());
323 }
324 }
325
326 /*
327 Low-power private functions: all operate within a critical seciton
328 */
329
330 #[cfg(feature = "low-power")]
331 /// Compute the approximate amount of time until the next alarm
332 fn time_until_next_alarm(&self, cs: CriticalSection) -> embassy_time::Duration {
333 let now = self.now() + 32;
334
335 embassy_time::Duration::from_ticks(self.alarm.borrow(cs).timestamp.get().saturating_sub(now))
336 }
337
338 #[cfg(feature = "low-power")]
339 /// Add the given offset to the current time
340 fn add_time(&self, offset: embassy_time::Duration, cs: CriticalSection) {
341 let offset = offset.as_ticks();
342 let cnt = regs_gp16().cnt().read().cnt() as u32;
343 let period = self.period.load(Ordering::SeqCst);
344
345 // Correct the race, if it exists
346 let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 {
347 period + 1
348 } else {
349 period
350 };
351
352 // Normalize to the full overflow
353 let period = (period / 2) * 2;
354
355 // Add the offset
356 let period = period + 2 * (offset / u16::MAX as u64) as u32;
357 let cnt = cnt + (offset % u16::MAX as u64) as u32;
358
359 let (cnt, period) = if cnt > u16::MAX as u32 {
360 (cnt - u16::MAX as u32, period + 2)
361 } else {
362 (cnt, period)
363 };
364
365 let period = if cnt > u16::MAX as u32 / 2 { period + 1 } else { period };
366
367 self.period.store(period, Ordering::SeqCst);
368 regs_gp16().cnt().write(|w| w.set_cnt(cnt as u16));
369
370 // Now, recompute alarm
371 let alarm = self.alarm.borrow(cs);
372
373 if !self.set_alarm(cs, alarm.timestamp.get()) {
374 // If the alarm timestamp has passed, we need to trigger it
375 self.trigger_alarm(cs);
376 }
377 }
378
379 #[cfg(feature = "low-power")]
380 /// Stop the wakeup alarm, if enabled, and add the appropriate offset
381 fn stop_wakeup_alarm(&self, cs: CriticalSection) {
382 if let Some(offset) = self.rtc.borrow(cs).get().unwrap().stop_wakeup_alarm(cs) {
383 self.add_time(offset, cs);
384 }
385 }
386
387 /*
388 Low-power public functions: all create a critical section
389 */
390 #[cfg(feature = "low-power")]
391 /// Set the rtc but panic if it's already been set
392 pub(crate) fn set_rtc(&self, rtc: &'static Rtc) {
393 critical_section::with(|cs| {
394 rtc.stop_wakeup_alarm(cs);
395
396 assert!(self.rtc.borrow(cs).replace(Some(rtc)).is_none())
397 });
398 }
399
400 #[cfg(feature = "low-power")]
401 /// The minimum pause time beyond which the executor will enter a low-power state.
402 pub(crate) const MIN_STOP_PAUSE: embassy_time::Duration = embassy_time::Duration::from_millis(250);
403
404 #[cfg(feature = "low-power")]
405 /// Pause the timer if ready; return err if not
406 pub(crate) fn pause_time(&self) -> Result<(), ()> {
407 critical_section::with(|cs| {
408 /*
409 If the wakeup timer is currently running, then we need to stop it and
410 add the elapsed time to the current time, as this will impact the result
411 of `time_until_next_alarm`.
412 */
413 self.stop_wakeup_alarm(cs);
414
415 let time_until_next_alarm = self.time_until_next_alarm(cs);
416 if time_until_next_alarm < Self::MIN_STOP_PAUSE {
417 Err(())
418 } else {
419 self.rtc
420 .borrow(cs)
421 .get()
422 .unwrap()
423 .start_wakeup_alarm(time_until_next_alarm, cs);
424
425 regs_gp16().cr1().modify(|w| w.set_cen(false));
426
427 Ok(())
428 }
429 })
430 }
431
432 #[cfg(feature = "low-power")]
433 /// Resume the timer with the given offset
434 pub(crate) fn resume_time(&self) {
435 if regs_gp16().cr1().read().cen() {
436 // Time isn't currently stopped
437
438 return;
439 }
440
441 critical_section::with(|cs| {
442 self.stop_wakeup_alarm(cs);
443
444 regs_gp16().cr1().modify(|w| w.set_cen(true));
445 })
446 }
447
448 fn set_alarm(&self, cs: CriticalSection, timestamp: u64) -> bool {
449 let r = regs_gp16();
450
451 let n = 0;
452 self.alarm.borrow(cs).timestamp.set(timestamp);
453
454 let t = self.now();
455 if timestamp <= t {
456 // If alarm timestamp has passed the alarm will not fire.
457 // Disarm the alarm and return `false` to indicate that.
458 r.dier().modify(|w| w.set_ccie(n + 1, false));
459
460 self.alarm.borrow(cs).timestamp.set(u64::MAX);
461
462 return false;
463 }
464
465 // Write the CCR value regardless of whether we're going to enable it now or not.
466 // This way, when we enable it later, the right value is already set.
467 r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16));
468
469 // Enable it if it'll happen soon. Otherwise, `next_period` will enable it.
470 let diff = timestamp - t;
471 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
472
473 // Reevaluate if the alarm timestamp is still in the future
474 let t = self.now();
475 if timestamp <= t {
476 // If alarm timestamp has passed since we set it, we have a race condition and
477 // the alarm may or may not have fired.
478 // Disarm the alarm and return `false` to indicate that.
479 // It is the caller's responsibility to handle this ambiguity.
480 r.dier().modify(|w| w.set_ccie(n + 1, false));
481
482 self.alarm.borrow(cs).timestamp.set(u64::MAX);
483
484 return false;
485 }
486
487 // We're confident the alarm will ring in the future.
488 true
489 }
490}
491
492impl Driver for RtcDriver {
493 fn now(&self) -> u64 {
494 let r: TimGp16 = regs_gp16();
495
496 let period: u32 = self.period.load(order:Ordering::Relaxed);
497 compiler_fence(order:Ordering::Acquire);
498 let counter: u16 = r.cnt().read().cnt();
499 calc_now(period, counter)
500 }
501
502 fn schedule_wake(&self, at: u64, waker: &core::task::Waker) {
503 critical_section::with(|cs: CriticalSection<'_>| {
504 let mut queue: RefMut<'_, Queue> = self.queue.borrow(cs).borrow_mut();
505
506 if queue.schedule_wake(at, waker) {
507 let mut next: u64 = queue.next_expiration(self.now());
508 while !self.set_alarm(cs, timestamp:next) {
509 next = queue.next_expiration(self.now());
510 }
511 }
512 })
513 }
514}
515
516#[cfg(feature = "low-power")]
517pub(crate) fn get_driver() -> &'static RtcDriver {
518 &DRIVER
519}
520
521pub(crate) fn init(cs: CriticalSection) {
522 DRIVER.init(cs)
523}
524