1#[cfg(not(any(
5 feature = "stm32l412",
6 feature = "stm32l422",
7 feature = "stm32l4p5",
8 feature = "stm32l4q5"
9)))]
10pub mod rtc2;
11#[cfg(not(any(
12 feature = "stm32l412",
13 feature = "stm32l422",
14 feature = "stm32l4p5",
15 feature = "stm32l4q5"
16)))]
17pub use rtc2 as rtc_registers;
18
19#[cfg(any(
21 feature = "stm32l412",
22 feature = "stm32l422",
23 feature = "stm32l4p5",
24 feature = "stm32l4q5"
25))]
26pub mod rtc3;
27#[cfg(any(
28 feature = "stm32l412",
29 feature = "stm32l422",
30 feature = "stm32l4p5",
31 feature = "stm32l4q5"
32))]
33pub use rtc3 as rtc_registers;
34
35use fugit::ExtU32;
36use void::Void;
37
38use crate::{
39 datetime::*,
40 hal::timer::{self, Cancel as _},
41 pwr,
42 rcc::{APB1R1, BDCR},
43 stm32::{EXTI, RTC},
44};
45
46pub enum Event {
48 WakeupTimer,
49 AlarmA,
50 AlarmB,
51 Timestamp,
52}
53
54pub enum Alarm {
55 AlarmA,
56 AlarmB,
57}
58
59impl From<Alarm> for Event {
60 fn from(a: Alarm) -> Self {
61 match a {
62 Alarm::AlarmA => Event::AlarmA,
63 Alarm::AlarmB => Event::AlarmB,
64 }
65 }
66}
67
68pub struct Rtc {
70 rtc: RTC,
71 rtc_config: RtcConfig,
72}
73
74#[derive(Copy, Clone, Debug, PartialEq)]
75#[repr(u8)]
76pub enum RtcClockSource {
77 NoClock = 0b00,
79 LSE = 0b01,
81 LSI = 0b10,
83 HSE = 0b11,
85}
86
87#[derive(Copy, Clone, Debug, PartialEq)]
88#[repr(u8)]
89pub enum RtcWakeupClockSource {
90 RtcClkDiv16 = 0b000,
92 RtcClkDiv8 = 0b001,
94 RtcClkDiv4 = 0b010,
96 RtcClkDiv2 = 0b011,
98 CkSpre = 0b100,
101}
102
103#[derive(Copy, Clone, Debug, PartialEq)]
104pub struct RtcConfig {
105 clock_config: RtcClockSource,
107 wakeup_clock_config: RtcWakeupClockSource,
109 async_prescaler: u8,
114 sync_prescaler: u16,
119}
120
121impl Default for RtcConfig {
122 fn default() -> Self {
125 RtcConfig {
126 clock_config: RtcClockSource::LSI,
127 wakeup_clock_config: RtcWakeupClockSource::CkSpre,
128 async_prescaler: 127,
129 sync_prescaler: 255,
130 }
131 }
132}
133
134impl RtcConfig {
135 pub fn clock_config(mut self, cfg: RtcClockSource) -> Self {
137 self.clock_config = cfg;
138 self
139 }
140
141 pub fn async_prescaler(mut self, prescaler: u8) -> Self {
143 self.async_prescaler = prescaler;
144 self
145 }
146
147 pub fn sync_prescaler(mut self, prescaler: u16) -> Self {
149 self.sync_prescaler = prescaler;
150 self
151 }
152
153 pub fn wakeup_clock_config(mut self, cfg: RtcWakeupClockSource) -> Self {
155 self.wakeup_clock_config = cfg;
156 self
157 }
158}
159
160impl Rtc {
161 pub fn rtc(
162 rtc: RTC,
163 apb1r1: &mut APB1R1,
164 bdcr: &mut BDCR,
165 pwrcr1: &mut pwr::CR1,
166 rtc_config: RtcConfig,
167 ) -> Self {
168 apb1r1.enr().modify(|_, w| w.rtcapben().set_bit());
171 pwrcr1.reg().read(); let mut rtc_struct = Self { rtc, rtc_config };
174 rtc_struct.set_config(bdcr, pwrcr1, rtc_config);
175
176 rtc_struct
177 }
178
179 pub fn get_date_time(&self) -> (Date, Time) {
181 let time;
182 let date;
183
184 let sync_p = self.rtc_config.sync_prescaler as u32;
185 let micros =
186 1_000_000u32 / (sync_p + 1) * (sync_p - self.rtc.ssr.read().ss().bits() as u32);
187 let timer = self.rtc.tr.read();
188 let cr = self.rtc.cr.read();
189
190 let dater = self.rtc.dr.read();
193
194 time = Time::new(
195 (bcd2_to_byte((timer.ht().bits(), timer.hu().bits())) as u32).hours(),
196 (bcd2_to_byte((timer.mnt().bits(), timer.mnu().bits())) as u32).minutes(),
197 (bcd2_to_byte((timer.st().bits(), timer.su().bits())) as u32).secs(),
198 micros.micros(),
199 cr.bkp().bit(),
200 );
201
202 date = Date::new(
203 dater.wdu().bits().into(),
204 bcd2_to_byte((dater.dt().bits(), dater.du().bits())).into(),
205 bcd2_to_byte((dater.mt().bit() as u8, dater.mu().bits())).into(),
206 (bcd2_to_byte((dater.yt().bits(), dater.yu().bits())) as u16 + 1970_u16).into(),
207 );
208
209 (date, time)
210 }
211
212 pub fn set_date_time(&mut self, date: Date, time: Time) {
214 self.write(true, |rtc| {
215 set_time_raw(rtc, time);
216 set_date_raw(rtc, date);
217 })
218 }
219
220 pub fn set_time(&mut self, time: Time) {
223 self.write(true, |rtc| {
224 set_time_raw(rtc, time);
225 })
226 }
227
228 pub fn set_date(&mut self, date: Date) {
231 self.write(true, |rtc| {
232 set_date_raw(rtc, date);
233 })
234 }
235
236 pub fn get_config(&self) -> RtcConfig {
237 self.rtc_config
238 }
239
240 pub fn set_alarm(&mut self, alarm: Alarm, date: Date, time: Time) {
243 let (dt, du) = byte_to_bcd2(date.date as u8);
244 let (ht, hu) = byte_to_bcd2(time.hours as u8);
245 let (mnt, mnu) = byte_to_bcd2(time.minutes as u8);
246 let (st, su) = byte_to_bcd2(time.seconds as u8);
247
248 self.write(false, |rtc| match alarm {
249 Alarm::AlarmA => {
250 rtc.cr.modify(|_, w| w.alrae().clear_bit()); rtc_registers::clear_alarm_a_flag(rtc);
252 while !rtc_registers::is_alarm_a_accessible(rtc) {}
253
254 rtc.alrmar.modify(|_, w| unsafe {
255 w.dt()
256 .bits(dt)
257 .du()
258 .bits(du)
259 .ht()
260 .bits(ht)
261 .hu()
262 .bits(hu)
263 .mnt()
264 .bits(mnt)
265 .mnu()
266 .bits(mnu)
267 .st()
268 .bits(st)
269 .su()
270 .bits(su)
271 .pm()
272 .clear_bit()
273 .wdsel()
274 .clear_bit()
275 });
276 rtc.cr.modify(|_, w| w.alrae().set_bit());
283 }
284 Alarm::AlarmB => {
285 rtc.cr.modify(|_, w| w.alrbe().clear_bit());
286
287 rtc_registers::clear_alarm_b_flag(rtc);
288 while !rtc_registers::is_alarm_b_accessible(rtc) {}
289
290 rtc.alrmbr.modify(|_, w| unsafe {
291 w.dt()
292 .bits(dt)
293 .du()
294 .bits(du)
295 .ht()
296 .bits(ht)
297 .hu()
298 .bits(hu)
299 .mnt()
300 .bits(mnt)
301 .mnu()
302 .bits(mnu)
303 .st()
304 .bits(st)
305 .su()
306 .bits(su)
307 .pm()
308 .clear_bit()
309 .wdsel()
310 .clear_bit()
311 });
312 rtc.cr.modify(|_, w| w.alrbe().set_bit());
319 }
320 });
321 }
322
323 pub fn listen(&mut self, exti: &mut EXTI, event: Event) {
325 self.write(false, |rtc| match event {
326 Event::WakeupTimer => {
327 exti.rtsr1.modify(|_, w| w.tr20().set_bit());
328 exti.imr1.modify(|_, w| w.mr20().set_bit());
329 rtc.cr.modify(|_, w| w.wutie().set_bit())
330 }
331 Event::AlarmA => {
332 exti.rtsr1.modify(|_, w| w.tr18().set_bit());
334 exti.imr1.modify(|_, w| w.mr18().set_bit());
335 rtc.cr.modify(|_, w| w.alraie().set_bit())
336 }
337 Event::AlarmB => {
338 exti.rtsr1.modify(|_, w| w.tr18().set_bit());
339 exti.imr1.modify(|_, w| w.mr18().set_bit());
340 rtc.cr.modify(|_, w| w.alrbie().set_bit())
341 }
342 Event::Timestamp => {
343 exti.rtsr1.modify(|_, w| w.tr19().set_bit());
344 exti.imr1.modify(|_, w| w.mr19().set_bit());
345 rtc.cr.modify(|_, w| w.tsie().set_bit())
346 }
347 })
348 }
349
350 pub fn unlisten(&mut self, exti: &mut EXTI, event: Event) {
352 self.write(false, |rtc| match event {
353 Event::WakeupTimer => {
354 exti.rtsr1.modify(|_, w| w.tr20().clear_bit());
355 exti.imr1.modify(|_, w| w.mr20().clear_bit());
356 rtc.cr.modify(|_, w| w.wutie().clear_bit())
357 }
358 Event::AlarmA => {
359 exti.rtsr1.modify(|_, w| w.tr18().clear_bit());
361 exti.imr1.modify(|_, w| w.mr18().clear_bit());
362 rtc.cr.modify(|_, w| w.alraie().clear_bit())
363 }
364 Event::AlarmB => {
365 exti.rtsr1.modify(|_, w| w.tr18().clear_bit());
366 exti.imr1.modify(|_, w| w.mr18().clear_bit());
367 rtc.cr.modify(|_, w| w.alrbie().clear_bit())
368 }
369 Event::Timestamp => {
370 exti.rtsr1.modify(|_, w| w.tr19().clear_bit());
371 exti.imr1.modify(|_, w| w.mr19().clear_bit());
372 rtc.cr.modify(|_, w| w.tsie().clear_bit())
373 }
374 })
375 }
376
377 pub fn check_interrupt(&mut self, event: Event, clear: bool) -> bool {
379 let result = match event {
380 Event::WakeupTimer => rtc_registers::is_wakeup_timer_flag_set(&self.rtc),
381 Event::AlarmA => rtc_registers::is_alarm_a_flag_set(&self.rtc),
382 Event::AlarmB => rtc_registers::is_alarm_b_flag_set(&self.rtc),
383 Event::Timestamp => rtc_registers::is_timestamp_flag_set(&self.rtc),
384 };
385 if clear {
386 self.write(false, |rtc| match event {
387 Event::WakeupTimer => {
388 rtc_registers::clear_wakeup_timer_flag(rtc);
389 unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << 20)) };
390 }
391 Event::AlarmA => {
392 rtc_registers::clear_alarm_a_flag(rtc);
393 unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << 18)) };
394 }
395 Event::AlarmB => {
396 rtc_registers::clear_alarm_b_flag(rtc);
397 unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << 18)) };
398 }
399 Event::Timestamp => {
400 rtc_registers::clear_timestamp_flag(rtc);
401 unsafe { (*EXTI::ptr()).pr1.write(|w| w.bits(1 << 19)) };
402 }
403 })
404 }
405
406 result
407 }
408
409 pub fn set_config(&mut self, bdcr: &mut BDCR, pwrcr1: &mut pwr::CR1, rtc_config: RtcConfig) {
412 pwrcr1.reg().modify(|_, w| w.dbp().set_bit());
414 while pwrcr1.reg().read().dbp().bit_is_clear() {}
415
416 let reg = bdcr.enr().read();
417 assert!(
418 !reg.lsecsson().bit(),
419 "RTC is not compatible with LSE CSS, yet."
420 );
421
422 if !reg.rtcen().bit() || reg.rtcsel().bits() != rtc_config.clock_config as u8 {
423 bdcr.enr().modify(|_, w| w.bdrst().set_bit());
424
425 bdcr.enr().modify(|_, w| unsafe {
426 w.bdrst().clear_bit();
428 w.rtcsel()
430 .bits(rtc_config.clock_config as u8)
431 .rtcen()
432 .set_bit();
433
434 w.lscosel()
436 .bit(reg.lscosel().bit())
437 .lscoen()
438 .bit(reg.lscoen().bit());
439
440 w.lseon()
441 .bit(reg.lseon().bit())
442 .lsedrv()
443 .bits(reg.lsedrv().bits())
444 .lsebyp()
445 .bit(reg.lsebyp().bit())
446 });
447 }
448
449 self.write(true, |rtc| {
450 rtc.cr.modify(|_, w| unsafe {
451 w.fmt()
452 .clear_bit() .osel()
454 .bits(0b00)
461 .pol()
462 .clear_bit() });
464
465 rtc.prer.modify(|_, w| unsafe {
466 w.prediv_s()
467 .bits(rtc_config.sync_prescaler)
468 .prediv_a()
469 .bits(rtc_config.async_prescaler)
470 });
471
472 rtc_registers::reset_gpio(rtc);
474 });
475
476 self.rtc_config = rtc_config;
477 }
478
479 pub fn wakeup_timer(&mut self) -> WakeupTimer {
481 WakeupTimer { rtc: self }
482 }
483
484 fn write<F, R>(&mut self, init_mode: bool, f: F) -> R
485 where
486 F: FnOnce(&RTC) -> R,
487 {
488 self.rtc.wpr.write(|w| unsafe { w.key().bits(0xca) });
491 self.rtc.wpr.write(|w| unsafe { w.key().bits(0x53) });
492
493 if init_mode && !rtc_registers::is_init_mode(&self.rtc) {
494 rtc_registers::enter_init_mode(&self.rtc);
495 while !rtc_registers::is_init_mode(&self.rtc) {}
498 }
499
500 let result = f(&self.rtc);
501 if init_mode {
502 rtc_registers::exit_init_mode(&self.rtc);
503 }
504
505 self.rtc.wpr.write(|w| unsafe { w.key().bits(0xff) });
508
509 result
510 }
511
512 pub const BACKUP_REGISTER_COUNT: usize = rtc_registers::BACKUP_REGISTER_COUNT;
513
514 pub fn read_backup_register(&self, register: usize) -> Option<u32> {
519 rtc_registers::read_backup_register(&self.rtc, register)
520 }
521
522 pub fn write_backup_register(&self, register: usize, value: u32) {
527 rtc_registers::write_backup_register(&self.rtc, register, value)
528 }
529}
530
531pub struct WakeupTimer<'r> {
545 rtc: &'r mut Rtc,
546}
547
548impl timer::Periodic for WakeupTimer<'_> {}
549
550impl timer::CountDown for WakeupTimer<'_> {
551 type Time = u32;
552
553 fn start<T>(&mut self, delay: T)
565 where
566 T: Into<Self::Time>,
567 {
568 let delay = delay.into();
569 assert!(1 <= delay);
570
571 if self.rtc.rtc_config.wakeup_clock_config == RtcWakeupClockSource::CkSpre {
572 assert!(delay <= 1 << 17);
573 } else {
574 assert!(delay <= 1 << 16);
575 }
576
577 let wucksel = self.rtc.rtc_config.wakeup_clock_config as u8;
579 let wucksel = wucksel
580 | if self.rtc.rtc_config.wakeup_clock_config == RtcWakeupClockSource::CkSpre
581 && delay & 0x1_00_00 != 0
582 {
583 0b010
584 } else {
585 0b000
586 };
587
588 let delay = delay - 1;
589
590 self.cancel().unwrap();
592
593 self.rtc.write(false, |rtc| {
594 rtc.wutr.write(|w|
596 unsafe { w.wut().bits(delay as u16) });
600
601 rtc.cr.modify(|_, w| {
602 unsafe {
604 w.wucksel().bits(wucksel);
605 }
606 w.wute().set_bit()
608 });
609 });
610
611 while rtc_registers::is_wakeup_timer_write_flag_set(&self.rtc.rtc) {}
614 }
615
616 fn wait(&mut self) -> nb::Result<(), Void> {
617 if self.rtc.check_interrupt(Event::WakeupTimer, true) {
618 return Ok(());
619 }
620
621 Err(nb::Error::WouldBlock)
622 }
623}
624
625impl timer::Cancel for WakeupTimer<'_> {
626 type Error = Void;
627
628 fn cancel(&mut self) -> Result<(), Self::Error> {
629 self.rtc.write(false, |rtc| {
630 rtc.cr.modify(|_, w| w.wute().clear_bit());
632 while !rtc_registers::is_wakeup_timer_write_flag_set(rtc) {}
633 rtc_registers::clear_wakeup_timer_flag(rtc);
634
635 });
647
648 Ok(())
649 }
650}
651
652fn set_time_raw(rtc: &RTC, time: Time) {
655 let (ht, hu) = byte_to_bcd2(time.hours as u8);
656 let (mnt, mnu) = byte_to_bcd2(time.minutes as u8);
657 let (st, su) = byte_to_bcd2(time.seconds as u8);
658
659 rtc.tr.write(|w| unsafe {
660 w.ht()
661 .bits(ht)
662 .hu()
663 .bits(hu)
664 .mnt()
665 .bits(mnt)
666 .mnu()
667 .bits(mnu)
668 .st()
669 .bits(st)
670 .su()
671 .bits(su)
672 .pm()
673 .clear_bit()
674 });
675
676 rtc.cr.modify(|_, w| w.bkp().bit(time.daylight_savings));
677}
678
679fn set_date_raw(rtc: &RTC, date: Date) {
682 let (dt, du) = byte_to_bcd2(date.date as u8);
683 let (mt, mu) = byte_to_bcd2(date.month as u8);
684 let yr = date.year as u16;
685 let yr_offset = (yr - 1970_u16) as u8;
686 let (yt, yu) = byte_to_bcd2(yr_offset);
687
688 rtc.dr.write(|w| unsafe {
689 w.dt()
690 .bits(dt)
691 .du()
692 .bits(du)
693 .mt()
694 .bit(mt > 0)
695 .mu()
696 .bits(mu)
697 .yt()
698 .bits(yt)
699 .yu()
700 .bits(yu)
701 .wdu()
702 .bits(date.day as u8)
703 });
704}
705
706fn byte_to_bcd2(byte: u8) -> (u8, u8) {
707 let mut bcd_high: u8 = 0;
708 let mut value = byte;
709
710 while value >= 10 {
711 bcd_high += 1;
712 value -= 10;
713 }
714
715 (bcd_high, ((bcd_high << 4) | value) as u8)
716}
717
718fn bcd2_to_byte(bcd: (u8, u8)) -> u8 {
719 let value = bcd.1 | bcd.0 << 4;
720
721 let tmp = ((value & 0xF0) >> 0x4) * 10;
722
723 tmp + (value & 0x0F)
724}