aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorThales Fragoso <[email protected]>2021-05-22 23:58:40 -0300
committerThales Fragoso <[email protected]>2021-05-22 23:58:40 -0300
commite49e3723a81a2fe6359b503fbe96640ec57c949c (patch)
treeb79d9c43e58ab45985649a711b0efb18f6b05617
parent212d90581646238635adfd9d6978486029142cf2 (diff)
wip timers for embassy rtc
-rw-r--r--embassy-stm32/src/lib.rs2
-rw-r--r--embassy-stm32/src/rtc.rs585
2 files changed, 587 insertions, 0 deletions
diff --git a/embassy-stm32/src/lib.rs b/embassy-stm32/src/lib.rs
index 8f8dd753b..7bcae9f90 100644
--- a/embassy-stm32/src/lib.rs
+++ b/embassy-stm32/src/lib.rs
@@ -17,6 +17,8 @@ pub mod pwr;
17pub mod rcc; 17pub mod rcc;
18#[cfg(feature = "_rng")] 18#[cfg(feature = "_rng")]
19pub mod rng; 19pub mod rng;
20#[cfg(feature = "_timer")]
21pub mod rtc;
20#[cfg(feature = "_sdmmc")] 22#[cfg(feature = "_sdmmc")]
21pub mod sdmmc; 23pub mod sdmmc;
22#[cfg(feature = "_spi")] 24#[cfg(feature = "_spi")]
diff --git a/embassy-stm32/src/rtc.rs b/embassy-stm32/src/rtc.rs
new file mode 100644
index 000000000..1ccac0e2d
--- /dev/null
+++ b/embassy-stm32/src/rtc.rs
@@ -0,0 +1,585 @@
1use core::cell::Cell;
2use core::convert::TryInto;
3use core::sync::atomic::{compiler_fence, AtomicU32, Ordering};
4
5use embassy::interrupt::InterruptExt;
6use embassy::time::{Clock, TICKS_PER_SECOND};
7use embassy::util::AtomicWaker;
8
9use crate::interrupt::{CriticalSection, Interrupt, Mutex};
10use crate::pac::timer::TimGp16;
11use crate::time::Hertz;
12
13// RTC timekeeping works with something we call "periods", which are time intervals
14// of 2^15 ticks. The RTC counter value is 16 bits, so one "overflow cycle" is 2 periods.
15//
16// A `period` count is maintained in parallel to the RTC hardware `counter`, like this:
17// - `period` and `counter` start at 0
18// - `period` is incremented on overflow (at counter value 0)
19// - `period` is incremented "midway" between overflows (at counter value 0x8000)
20//
21// Therefore, when `period` is even, counter is in 0..0x7FFF. When odd, counter is in 0x8000..0xFFFF
22// This allows for now() to return the correct value even if it races an overflow.
23//
24// To get `now()`, `period` is read first, then `counter` is read. If the counter value matches
25// the expected range for the `period` parity, we're done. If it doesn't, this means that
26// a new period start has raced us between reading `period` and `counter`, so we assume the `counter` value
27// corresponds to the next period.
28//
29// `period` is a 32bit integer, so It overflows on 2^32 * 2^15 / 32768 seconds of uptime, which is 136 years.
30fn calc_now(period: u32, counter: u16) -> u64 {
31 ((period as u64) << 15) + ((counter as u32 ^ ((period & 1) << 15)) as u64)
32}
33
34struct AlarmState {
35 timestamp: Cell<u64>,
36 #[allow(clippy::type_complexity)]
37 callback: Cell<Option<(fn(*mut ()), *mut ())>>,
38}
39
40impl AlarmState {
41 fn new() -> Self {
42 Self {
43 timestamp: Cell::new(u64::MAX),
44 callback: Cell::new(None),
45 }
46 }
47}
48
49// TODO: This is sometimes wasteful, try to find a better way
50const ALARM_COUNT: usize = 3;
51
52/// RTC timer that can be used by the executor and to set alarms.
53///
54/// It can work with Timers 2, 3, 4, 5, 9 and 12. Timers 9 and 12 only have one alarm available,
55/// while the others have three each.
56/// This timer works internally with a unit of 2^15 ticks, which means that if a call to
57/// [`embassy::time::Clock::now`] is blocked for that amount of ticks the returned value will be
58/// wrong (an old value). The current default tick rate is 32768 ticks per second.
59pub struct RTC<T: Instance> {
60 _inner: T,
61 irq: T::Interrupt,
62 /// Number of 2^23 periods elapsed since boot.
63 period: AtomicU32,
64 /// Timestamp at which to fire alarm. u64::MAX if no alarm is scheduled.
65 alarms: Mutex<[AlarmState; ALARM_COUNT]>,
66}
67
68impl<T: Instance> RTC<T> {
69 pub fn new(peripheral: T, irq: T::Interrupt) -> Self {
70 Self {
71 _inner: peripheral,
72 irq,
73 period: AtomicU32::new(0),
74 alarms: Mutex::new([AlarmState::new(), AlarmState::new(), AlarmState::new()]),
75 }
76 }
77
78 pub fn start(&'static self, pfreq: Hertz, ppre: u8) {
79 let inner = T::inner();
80
81 // NOTE(unsafe) Critical section to use the unsafe methods
82 critical_section::with(|_| {
83 unsafe {
84 inner.prepare(pfreq, ppre);
85 }
86
87 self.irq.set_handler_context(self as *const _ as *mut _);
88 self.irq.set_handler(|ptr| unsafe {
89 let this = &*(ptr as *const () as *const Self);
90 this.on_interrupt();
91 });
92 self.irq.unpend();
93 self.irq.enable();
94
95 unsafe {
96 inner.start_counter();
97 }
98 })
99 }
100
101 fn on_interrupt(&self) {
102 let inner = T::inner();
103
104 // NOTE(unsafe) Use critical section to access the methods
105 // XXX: reduce the size of this critical section ?
106 critical_section::with(|cs| unsafe {
107 if inner.overflow_interrupt_status() {
108 inner.overflow_clear_flag();
109 self.next_period();
110 }
111
112 // Half overflow
113 if inner.compare_interrupt_status(0) {
114 inner.compare_clear_flag(0);
115 self.next_period();
116 }
117
118 for n in 1..=ALARM_COUNT {
119 if inner.compare_interrupt_status(n) {
120 inner.compare_clear_flag(n);
121 self.trigger_alarm(n, cs);
122 }
123 }
124 })
125 }
126
127 fn next_period(&self) {
128 let inner = T::inner();
129
130 let period = self.period.fetch_add(1, Ordering::Relaxed) + 1;
131 let t = (period as u64) << 15;
132
133 critical_section::with(move |cs| {
134 for n in 1..=ALARM_COUNT {
135 let alarm = &self.alarms.borrow(cs)[n - 1];
136 let at = alarm.timestamp.get();
137
138 let diff = at - t;
139 if diff < 0xc000 {
140 inner.set_compare(n, at as u16);
141 // NOTE(unsafe) We're in a critical section
142 unsafe {
143 inner.set_compare_interrupt(n, true);
144 }
145 }
146 }
147 })
148 }
149
150 fn trigger_alarm(&self, n: usize, cs: CriticalSection) {
151 let inner = T::inner();
152 // NOTE(unsafe) We have a critical section
153 unsafe {
154 inner.set_compare_interrupt(n, false);
155 }
156
157 let alarm = &self.alarms.borrow(cs)[n - 1];
158 alarm.timestamp.set(u64::MAX);
159
160 // Call after clearing alarm, so the callback can set another alarm.
161 if let Some((f, ctx)) = alarm.callback.get() {
162 f(ctx);
163 }
164 }
165
166 fn set_alarm_callback(&self, n: usize, callback: fn(*mut ()), ctx: *mut ()) {
167 critical_section::with(|cs| {
168 let alarm = &self.alarms.borrow(cs)[n - 1];
169 alarm.callback.set(Some((callback, ctx)));
170 })
171 }
172
173 fn set_alarm(&self, n: usize, timestamp: u64) {
174 critical_section::with(|cs| {
175 let inner = T::inner();
176
177 let alarm = &self.alarms.borrow(cs)[n - 1];
178 alarm.timestamp.set(timestamp);
179
180 let t = self.now();
181 if timestamp <= t {
182 self.trigger_alarm(n, cs);
183 return;
184 }
185
186 let diff = timestamp - t;
187 if diff < 0xc000 {
188 let safe_timestamp = timestamp.max(t + 3);
189 inner.set_compare(n, safe_timestamp as u16);
190
191 // NOTE(unsafe) We're in a critical section
192 unsafe {
193 inner.set_compare_interrupt(n, true);
194 }
195 } else {
196 unsafe {
197 inner.set_compare_interrupt(n, false);
198 }
199 }
200 })
201 }
202
203 pub fn alarm1(&'static self) -> Alarm<T> {
204 Alarm { n: 1, rtc: self }
205 }
206 pub fn alarm2(&'static self) -> Alarm<T> {
207 Alarm { n: 2, rtc: self }
208 }
209 pub fn alarm3(&'static self) -> Alarm<T> {
210 Alarm { n: 3, rtc: self }
211 }
212}
213
214impl<T: Instance> embassy::time::Clock for RTC<T> {
215 fn now(&self) -> u64 {
216 let inner = T::inner();
217
218 let period = self.period.load(Ordering::Relaxed);
219 compiler_fence(Ordering::Acquire);
220 let counter = inner.counter();
221 calc_now(period, counter)
222 }
223}
224
225pub struct Alarm<T: Instance> {
226 n: usize,
227 rtc: &'static RTC<T>,
228}
229
230impl<T: Instance> embassy::time::Alarm for Alarm<T> {
231 fn set_callback(&self, callback: fn(*mut ()), ctx: *mut ()) {
232 self.rtc.set_alarm_callback(self.n, callback, ctx);
233 }
234
235 fn set(&self, timestamp: u64) {
236 self.rtc.set_alarm(self.n, timestamp);
237 }
238
239 fn clear(&self) {
240 self.rtc.set_alarm(self.n, u64::MAX);
241 }
242}
243
244pub struct TimerInner(pub(crate) TimGp16);
245
246impl TimerInner {
247 unsafe fn prepare(&self, pfreq: Hertz, ppre: u8) {
248 self.stop_and_reset();
249
250 let multiplier = if ppre == 1 { 1 } else { 2 };
251 let freq = pfreq.0 * multiplier;
252 let psc = freq / TICKS_PER_SECOND as u32 - 1;
253 let psc: u16 = psc.try_into().unwrap();
254
255 self.set_psc_arr(psc, u16::MAX);
256 // Mid-way point
257 self.set_compare(0, 0x8000);
258 self.set_compare_interrupt(0, true);
259 }
260
261 unsafe fn start_counter(&self) {
262 self.0.cr1().modify(|w| w.set_cen(true));
263 }
264
265 unsafe fn stop_and_reset(&self) {
266 let regs = self.0;
267
268 regs.cr1().modify(|w| w.set_cen(false));
269 regs.cnt().write(|w| w.set_cnt(0));
270 }
271
272 fn overflow_interrupt_status(&self) -> bool {
273 // NOTE(unsafe) Atomic read with no side-effects
274 unsafe { self.0.sr().read().uif() }
275 }
276
277 unsafe fn overflow_clear_flag(&self) {
278 self.0.sr().modify(|w| w.set_uif(false));
279 }
280
281 unsafe fn set_psc_arr(&self, psc: u16, arr: u16) {
282 use crate::pac::timer::vals::Urs;
283
284 let regs = self.0;
285
286 regs.psc().write(|w| w.set_psc(psc));
287 regs.arr().write(|w| w.set_arr(arr));
288
289 // Set URS, generate update and clear URS
290 regs.cr1().modify(|w| w.set_urs(Urs::COUNTERONLY));
291 regs.egr().write(|w| w.set_ug(true));
292 regs.cr1().modify(|w| w.set_urs(Urs::ANYEVENT));
293 }
294
295 fn compare_interrupt_status(&self, n: usize) -> bool {
296 if n > 3 {
297 false
298 } else {
299 // NOTE(unsafe) Atomic read with no side-effects
300 unsafe { self.0.sr().read().ccif(n) }
301 }
302 }
303
304 unsafe fn compare_clear_flag(&self, n: usize) {
305 if n > 3 {
306 return;
307 }
308 self.0.sr().modify(|w| w.set_ccif(n, false));
309 }
310
311 fn set_compare(&self, n: usize, value: u16) {
312 if n > 3 {
313 return;
314 }
315 // NOTE(unsafe) Atomic write
316 unsafe {
317 self.0.ccr(n).write(|w| w.set_ccr(value));
318 }
319 }
320
321 unsafe fn set_compare_interrupt(&self, n: usize, enable: bool) {
322 if n > 3 {
323 return;
324 }
325 self.0.dier().modify(|w| w.set_ccie(n, enable));
326 }
327
328 fn counter(&self) -> u16 {
329 // NOTE(unsafe) Atomic read with no side-effects
330 unsafe { self.0.cnt().read().cnt() }
331 }
332}
333
334// ------------------------------------------------------
335
336pub(crate) mod sealed {
337 use super::*;
338 pub trait Instance {
339 type Interrupt: Interrupt;
340
341 fn inner() -> TimerInner;
342 fn state() -> &'static AtomicWaker;
343 }
344}
345
346pub trait Instance: sealed::Instance + Sized + 'static {}
347
348/*
349
350#[allow(unused_macros)]
351macro_rules! impl_timer {
352 ($module:ident: ($TYPE:ident, $INT:ident, $apbenr:ident, $enrbit:expr, $apbrstr:ident, $rstrbit:expr, $ppre:ident, $pclk: ident), 3) => {
353 mod $module {
354 use super::*;
355
356 impl sealed::Instance for $TYPE {}
357
358 impl Instance for $TYPE {
359 type Interrupt = interrupt::$INT;
360
361 fn set_compare(&self, n: usize, value: u16) {
362 // NOTE(unsafe) these registers accept all the range of u16 values
363 match n {
364 0 => self.ccr1.write(|w| unsafe { w.bits(value.into()) }),
365 1 => self.ccr2.write(|w| unsafe { w.bits(value.into()) }),
366 2 => self.ccr3.write(|w| unsafe { w.bits(value.into()) }),
367 3 => self.ccr4.write(|w| unsafe { w.bits(value.into()) }),
368 _ => {}
369 }
370 }
371
372 fn set_compare_interrupt(&self, n: usize, enable: bool) {
373 if n > 3 {
374 return;
375 }
376 let bit = n as u8 + 1;
377 unsafe {
378 if enable {
379 bb::set(&self.dier, bit);
380 } else {
381 bb::clear(&self.dier, bit);
382 }
383 }
384 }
385
386 fn compare_interrupt_status(&self, n: usize) -> bool {
387 let status = self.sr.read();
388 match n {
389 0 => status.cc1if().bit_is_set(),
390 1 => status.cc2if().bit_is_set(),
391 2 => status.cc3if().bit_is_set(),
392 3 => status.cc4if().bit_is_set(),
393 _ => false,
394 }
395 }
396
397 fn compare_clear_flag(&self, n: usize) {
398 if n > 3 {
399 return;
400 }
401 let bit = n as u8 + 1;
402 unsafe {
403 bb::clear(&self.sr, bit);
404 }
405 }
406
407 fn overflow_interrupt_status(&self) -> bool {
408 self.sr.read().uif().bit_is_set()
409 }
410
411 fn overflow_clear_flag(&self) {
412 unsafe {
413 bb::clear(&self.sr, 0);
414 }
415 }
416
417 fn set_psc_arr(&self, psc: u16, arr: u16) {
418 // NOTE(unsafe) All u16 values are valid
419 self.psc.write(|w| unsafe { w.bits(psc.into()) });
420 self.arr.write(|w| unsafe { w.bits(arr.into()) });
421
422 unsafe {
423 // Set URS, generate update, clear URS
424 bb::set(&self.cr1, 2);
425 self.egr.write(|w| w.ug().set_bit());
426 bb::clear(&self.cr1, 2);
427 }
428 }
429
430 fn stop_and_reset(&self) {
431 unsafe {
432 bb::clear(&self.cr1, 0);
433 }
434 self.cnt.reset();
435 }
436
437 fn start(&self) {
438 unsafe { bb::set(&self.cr1, 0) }
439 }
440
441 fn counter(&self) -> u16 {
442 self.cnt.read().bits() as u16
443 }
444
445 fn ppre(clocks: &Clocks) -> u8 {
446 clocks.$ppre()
447 }
448
449 fn pclk(clocks: &Clocks) -> u32 {
450 clocks.$pclk().0
451 }
452 }
453 }
454 };
455
456 ($module:ident: ($TYPE:ident, $INT:ident, $apbenr:ident, $enrbit:expr, $apbrstr:ident, $rstrbit:expr, $ppre:ident, $pclk: ident), 1) => {
457 mod $module {
458 use super::*;
459 use crate::hal::pac::{$TYPE, RCC};
460
461 impl sealed::Sealed for $TYPE {}
462
463 impl Instance for $TYPE {
464 type Interrupt = interrupt::$INT;
465 const REAL_ALARM_COUNT: usize = 1;
466
467 fn enable_clock(&self) {
468 // NOTE(unsafe) It will only be used for atomic operations
469 unsafe {
470 let rcc = &*RCC::ptr();
471
472 bb::set(&rcc.$apbenr, $enrbit);
473 bb::set(&rcc.$apbrstr, $rstrbit);
474 bb::clear(&rcc.$apbrstr, $rstrbit);
475 }
476 }
477
478 fn set_compare(&self, n: usize, value: u16) {
479 // NOTE(unsafe) these registers accept all the range of u16 values
480 match n {
481 0 => self.ccr1.write(|w| unsafe { w.bits(value.into()) }),
482 1 => self.ccr2.write(|w| unsafe { w.bits(value.into()) }),
483 _ => {}
484 }
485 }
486
487 fn set_compare_interrupt(&self, n: usize, enable: bool) {
488 if n > 1 {
489 return;
490 }
491 let bit = n as u8 + 1;
492 unsafe {
493 if enable {
494 bb::set(&self.dier, bit);
495 } else {
496 bb::clear(&self.dier, bit);
497 }
498 }
499 }
500
501 fn compare_interrupt_status(&self, n: usize) -> bool {
502 let status = self.sr.read();
503 match n {
504 0 => status.cc1if().bit_is_set(),
505 1 => status.cc2if().bit_is_set(),
506 _ => false,
507 }
508 }
509
510 fn compare_clear_flag(&self, n: usize) {
511 if n > 1 {
512 return;
513 }
514 let bit = n as u8 + 1;
515 unsafe {
516 bb::clear(&self.sr, bit);
517 }
518 }
519
520 fn overflow_interrupt_status(&self) -> bool {
521 self.sr.read().uif().bit_is_set()
522 }
523
524 fn overflow_clear_flag(&self) {
525 unsafe {
526 bb::clear(&self.sr, 0);
527 }
528 }
529
530 fn set_psc_arr(&self, psc: u16, arr: u16) {
531 // NOTE(unsafe) All u16 values are valid
532 self.psc.write(|w| unsafe { w.bits(psc.into()) });
533 self.arr.write(|w| unsafe { w.bits(arr.into()) });
534
535 unsafe {
536 // Set URS, generate update, clear URS
537 bb::set(&self.cr1, 2);
538 self.egr.write(|w| w.ug().set_bit());
539 bb::clear(&self.cr1, 2);
540 }
541 }
542
543 fn stop_and_reset(&self) {
544 unsafe {
545 bb::clear(&self.cr1, 0);
546 }
547 self.cnt.reset();
548 }
549
550 fn start(&self) {
551 unsafe { bb::set(&self.cr1, 0) }
552 }
553
554 fn counter(&self) -> u16 {
555 self.cnt.read().bits() as u16
556 }
557
558 fn ppre(clocks: &Clocks) -> u8 {
559 clocks.$ppre()
560 }
561
562 fn pclk(clocks: &Clocks) -> u32 {
563 clocks.$pclk().0
564 }
565 }
566 }
567 };
568}
569*/
570
571/*
572impl_timer!(tim2: (TIM2, TIM2, apb1enr, 0, apb1rstr, 0, ppre1, pclk1), 3);
573
574impl_timer!(tim3: (TIM3, TIM3, apb1enr, 1, apb1rstr, 1, ppre1, pclk1), 3);
575
576
577impl_timer!(tim4: (TIM4, TIM4, apb1enr, 2, apb1rstr, 2, ppre1, pclk1), 3);
578
579impl_timer!(tim5: (TIM5, TIM5, apb1enr, 3, apb1rstr, 3, ppre1, pclk1), 3);
580
581impl_timer!(tim9: (TIM9, TIM1_BRK_TIM9, apb2enr, 16, apb2rstr, 16, ppre2, pclk2), 1);
582
583#[cfg(not(any(feature = "stm32f401", feature = "stm32f410", feature = "stm32f411")))]
584impl_timer!(tim12: (TIM12, TIM8_BRK_TIM12, apb1enr, 6, apb1rstr, 6, ppre1, pclk1), 1);
585*/