embassy_stm32/
time_driver.rs

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 = regs_gp16();
495
496        let period = self.period.load(Ordering::Relaxed);
497        compiler_fence(Ordering::Acquire);
498        let counter = 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| {
504            let mut queue = self.queue.borrow(cs).borrow_mut();
505
506            if queue.schedule_wake(at, waker) {
507                let mut next = queue.next_expiration(self.now());
508                while !self.set_alarm(cs, 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}