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#[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
176fn 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 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 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 r.ccr(0).write(|w| w.set_ccr(0x8000));
255
256 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 r.sr().write_value(regs::SrGp16(!sr.0));
279
280 if sr.uif() {
282 self.next_period();
283 }
284
285 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 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 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 #[cfg(feature = "low-power")]
331 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 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 let period = if period & 1 == 1 && cnt < u16::MAX as u32 / 2 {
347 period + 1
348 } else {
349 period
350 };
351
352 let period = (period / 2) * 2;
354
355 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 let alarm = self.alarm.borrow(cs);
372
373 if !self.set_alarm(cs, alarm.timestamp.get()) {
374 self.trigger_alarm(cs);
376 }
377 }
378
379 #[cfg(feature = "low-power")]
380 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 #[cfg(feature = "low-power")]
391 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 pub(crate) const MIN_STOP_PAUSE: embassy_time::Duration = embassy_time::Duration::from_millis(250);
403
404 #[cfg(feature = "low-power")]
405 pub(crate) fn pause_time(&self) -> Result<(), ()> {
407 critical_section::with(|cs| {
408 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 pub(crate) fn resume_time(&self) {
435 if regs_gp16().cr1().read().cen() {
436 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 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 r.ccr(n + 1).write(|w| w.set_ccr(timestamp as u16));
468
469 let diff = timestamp - t;
471 r.dier().modify(|w| w.set_ccie(n + 1, diff < 0xc000));
472
473 let t = self.now();
475 if timestamp <= t {
476 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 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}