3
3
//! [ST AN4759](https:/www.st.com%2Fresource%2Fen%2Fapplication_note%2Fdm00226326-using-the-hardware-realtime-clock-rtc-and-the-tamper-management-unit-tamp-with-stm32-microcontrollers-stmicroelectronics.pdf&usg=AOvVaw3PzvL2TfYtwS32fw-Uv37h)
4
4
5
5
use crate :: bb;
6
- use crate :: pac:: rtc:: { dr, tr} ;
7
- use crate :: pac:: { rcc:: RegisterBlock , PWR , RCC , RTC } ;
6
+ use crate :: pac:: rtc:: { dr, tr, tsdr , tstr } ;
7
+ use crate :: pac:: { self , rcc:: RegisterBlock , PWR , RCC , RTC } ;
8
8
use crate :: rcc:: Enable ;
9
- use core:: convert:: TryInto ;
9
+ use core:: convert:: { TryFrom , TryInto } ;
10
10
use core:: fmt;
11
11
use core:: marker:: PhantomData ;
12
12
use time:: { Date , PrimitiveDateTime , Time } ;
@@ -18,6 +18,15 @@ pub enum Error {
18
18
InvalidInputData ,
19
19
}
20
20
21
+ #[ cfg_attr( feature = "defmt" , derive( defmt:: Format ) ) ]
22
+ #[ derive( Debug , Eq , PartialEq , Copy , Clone ) ]
23
+ pub enum Event {
24
+ AlarmA ,
25
+ AlarmB ,
26
+ Wakeup ,
27
+ Timestamp ,
28
+ }
29
+
21
30
/// RTC clock source LSE oscillator clock (type state)
22
31
pub struct Lse ;
23
32
/// RTC clock source LSI oscillator clock (type state)
@@ -375,6 +384,7 @@ impl<CS> Rtc<CS> {
375
384
let ( yt, yu) = bcd2_encode ( ( date. year ( ) - 1970 ) as u32 ) ?;
376
385
let ( mt, mu) = bcd2_encode ( u8:: from ( date. month ( ) ) . into ( ) ) ?;
377
386
let ( dt, du) = bcd2_encode ( date. day ( ) . into ( ) ) ?;
387
+ let wdu = date. weekday ( ) . number_from_monday ( ) ;
378
388
379
389
self . modify ( |regs| {
380
390
regs. dr . write ( |w| {
@@ -383,7 +393,8 @@ impl<CS> Rtc<CS> {
383
393
w. mt ( ) . bit ( mt > 0 ) ;
384
394
w. mu ( ) . bits ( mu) ;
385
395
w. yt ( ) . bits ( yt) ;
386
- w. yu ( ) . bits ( yu)
396
+ w. yu ( ) . bits ( yu) ;
397
+ unsafe { w. wdu ( ) . bits ( wdu) }
387
398
} )
388
399
} ) ;
389
400
@@ -402,6 +413,7 @@ impl<CS> Rtc<CS> {
402
413
let ( yt, yu) = bcd2_encode ( ( date. year ( ) - 1970 ) as u32 ) ?;
403
414
let ( mt, mu) = bcd2_encode ( u8:: from ( date. month ( ) ) . into ( ) ) ?;
404
415
let ( dt, du) = bcd2_encode ( date. day ( ) . into ( ) ) ?;
416
+ let wdu = date. weekday ( ) . number_from_monday ( ) ;
405
417
406
418
let ( ht, hu) = bcd2_encode ( date. hour ( ) . into ( ) ) ?;
407
419
let ( mnt, mnu) = bcd2_encode ( date. minute ( ) . into ( ) ) ?;
@@ -414,7 +426,8 @@ impl<CS> Rtc<CS> {
414
426
w. mt ( ) . bit ( mt > 0 ) ;
415
427
w. mu ( ) . bits ( mu) ;
416
428
w. yt ( ) . bits ( yt) ;
417
- w. yu ( ) . bits ( yu)
429
+ w. yu ( ) . bits ( yu) ;
430
+ unsafe { w. wdu ( ) . bits ( wdu) }
418
431
} ) ;
419
432
regs. tr . write ( |w| {
420
433
w. ht ( ) . bits ( ht) ;
@@ -436,6 +449,7 @@ impl<CS> Rtc<CS> {
436
449
437
450
// Reading either RTC_SSR or RTC_TR locks the values in the higher-order calendar shadow registers until RTC_DR is read.
438
451
// So it is important to always read SSR, TR and then DR or TR and then DR.
452
+ let ss = self . regs . ssr . read ( ) . ss ( ) . bits ( ) ;
439
453
let tr = self . regs . tr . read ( ) ;
440
454
let dr = self . regs . dr . read ( ) ;
441
455
// In case the software makes read accesses to the calendar in a time interval smaller
@@ -448,12 +462,172 @@ impl<CS> Rtc<CS> {
448
462
let day = decode_day ( & dr) ;
449
463
let month = decode_month ( & dr) ;
450
464
let year = decode_year ( & dr) ;
465
+ let prediv_s = self . regs . prer . read ( ) . prediv_s ( ) . bits ( ) ;
466
+ let nano = ss_to_nano ( ss, prediv_s) ;
467
+
468
+ PrimitiveDateTime :: new (
469
+ Date :: from_calendar_date ( year. into ( ) , month. try_into ( ) . unwrap ( ) , day) . unwrap ( ) ,
470
+ Time :: from_hms_nano ( hours, minutes, seconds, nano) . unwrap ( ) ,
471
+ )
472
+ }
473
+
474
+ /// Configures the wakeup timer to trigger periodically every `interval` seconds
475
+ ///
476
+ /// # Panics
477
+ ///
478
+ /// Panics if interval is greater than 2¹⁷-1.
479
+ pub fn enable_wakeup ( & mut self , interval : u32 ) {
480
+ self . modify ( |regs| {
481
+ regs. cr . modify ( |_, w| w. wute ( ) . clear_bit ( ) ) ;
482
+ regs. isr . modify ( |_, w| w. wutf ( ) . clear_bit ( ) ) ;
483
+ while regs. isr . read ( ) . wutwf ( ) . bit_is_clear ( ) { }
484
+
485
+ if interval > 1 << 16 {
486
+ regs. cr . modify ( |_, w| unsafe { w. wucksel ( ) . bits ( 0b110 ) } ) ;
487
+ let interval = u16:: try_from ( interval - ( 1 << 16 ) - 1 )
488
+ . expect ( "Interval was too large for wakeup timer" ) ;
489
+ regs. wutr . write ( |w| w. wut ( ) . bits ( interval) ) ;
490
+ } else {
491
+ regs. cr . modify ( |_, w| unsafe { w. wucksel ( ) . bits ( 0b100 ) } ) ;
492
+ let interval =
493
+ u16:: try_from ( interval - 1 ) . expect ( "Interval was too large for wakeup timer" ) ;
494
+ regs. wutr . write ( |w| w. wut ( ) . bits ( interval) ) ;
495
+ }
496
+
497
+ regs. cr . modify ( |_, w| w. wute ( ) . set_bit ( ) ) ;
498
+ } ) ;
499
+ }
500
+
501
+ /// Disables the wakeup timer
502
+ pub fn disable_wakeup ( & mut self ) {
503
+ self . modify ( |regs| {
504
+ regs. cr . modify ( |_, w| w. wute ( ) . clear_bit ( ) ) ;
505
+ regs. isr . modify ( |_, w| w. wutf ( ) . clear_bit ( ) ) ;
506
+ } ) ;
507
+ }
508
+
509
+ /// Configures the timestamp to be captured when the RTC switches to Vbat power
510
+ pub fn enable_vbat_timestamp ( & mut self ) {
511
+ self . modify ( |regs| {
512
+ regs. cr . modify ( |_, w| w. tse ( ) . clear_bit ( ) ) ;
513
+ regs. isr . modify ( |_, w| w. tsf ( ) . clear_bit ( ) ) ;
514
+ regs. cr . modify ( |_, w| w. tse ( ) . set_bit ( ) ) ;
515
+ } ) ;
516
+ }
517
+
518
+ /// Disables the timestamp
519
+ pub fn disable_timestamp ( & mut self ) {
520
+ self . modify ( |regs| {
521
+ regs. cr . modify ( |_, w| w. tse ( ) . clear_bit ( ) ) ;
522
+ regs. isr . modify ( |_, w| w. tsf ( ) . clear_bit ( ) ) ;
523
+ } ) ;
524
+ }
525
+
526
+ /// Reads the stored value of the timestamp if present
527
+ ///
528
+ /// Clears the timestamp interrupt flags.
529
+ pub fn read_timestamp ( & self ) -> PrimitiveDateTime {
530
+ while self . regs . isr . read ( ) . rsf ( ) . bit_is_clear ( ) { }
531
+
532
+ // Timestamp doesn't include year, get it from the main calendar
533
+ let ss = self . regs . tsssr . read ( ) . ss ( ) . bits ( ) ;
534
+ let tr = self . regs . tstr . read ( ) ;
535
+ let dr = self . regs . tsdr . read ( ) ;
536
+ let dry = self . regs . dr . read ( ) ;
537
+
538
+ let seconds = decode_ts_seconds ( & tr) ;
539
+ let minutes = decode_ts_minutes ( & tr) ;
540
+ let hours = decode_ts_hours ( & tr) ;
541
+ let day = decode_ts_day ( & dr) ;
542
+ let month = decode_ts_month ( & dr) ;
543
+ let year = decode_year ( & dry) ;
544
+ let prediv_s = self . regs . prer . read ( ) . prediv_s ( ) . bits ( ) ;
545
+ let nano = ss_to_nano ( ss, prediv_s) ;
451
546
452
547
PrimitiveDateTime :: new (
453
548
Date :: from_calendar_date ( year. into ( ) , month. try_into ( ) . unwrap ( ) , day) . unwrap ( ) ,
454
- Time :: from_hms ( hours, minutes, seconds) . unwrap ( ) ,
549
+ Time :: from_hms_nano ( hours, minutes, seconds, nano ) . unwrap ( ) ,
455
550
)
456
551
}
552
+
553
+ // TODO: Alarms
554
+
555
+ /// Start listening for `event`
556
+ pub fn listen ( & mut self , exti : & mut pac:: EXTI , event : Event ) {
557
+ // Input Mapping:
558
+ // EXTI 17 = RTC Alarms
559
+ // EXTI 21 = RTC Tamper, RTC Timestamp
560
+ // EXTI 22 = RTC Wakeup Timer
561
+ self . modify ( |regs| match event {
562
+ Event :: AlarmA => {
563
+ exti. rtsr . modify ( |_, w| w. tr17 ( ) . enabled ( ) ) ;
564
+ regs. cr . modify ( |_, w| w. alraie ( ) . set_bit ( ) ) ;
565
+ }
566
+ Event :: AlarmB => {
567
+ exti. rtsr . modify ( |_, w| w. tr17 ( ) . enabled ( ) ) ;
568
+ regs. cr . modify ( |_, w| w. alrbie ( ) . set_bit ( ) ) ;
569
+ }
570
+ Event :: Wakeup => {
571
+ exti. rtsr . modify ( |_, w| w. tr22 ( ) . enabled ( ) ) ;
572
+ regs. cr . modify ( |_, w| w. wutie ( ) . set_bit ( ) ) ;
573
+ }
574
+ Event :: Timestamp => {
575
+ exti. rtsr . modify ( |_, w| w. tr21 ( ) . enabled ( ) ) ;
576
+ regs. cr . modify ( |_, w| w. tsie ( ) . set_bit ( ) ) ;
577
+ }
578
+ } ) ;
579
+ }
580
+
581
+ /// Stop listening for `event`
582
+ pub fn unlisten ( & mut self , exti : & mut pac:: EXTI , event : Event ) {
583
+ // See the note in listen() about EXTI
584
+ self . modify ( |regs| match event {
585
+ Event :: AlarmA => {
586
+ regs. cr . modify ( |_, w| w. alraie ( ) . clear_bit ( ) ) ;
587
+ exti. rtsr . modify ( |_, w| w. tr17 ( ) . disabled ( ) ) ;
588
+ }
589
+ Event :: AlarmB => {
590
+ regs. cr . modify ( |_, w| w. alrbie ( ) . clear_bit ( ) ) ;
591
+ exti. rtsr . modify ( |_, w| w. tr17 ( ) . disabled ( ) ) ;
592
+ }
593
+ Event :: Wakeup => {
594
+ regs. cr . modify ( |_, w| w. wutie ( ) . clear_bit ( ) ) ;
595
+ exti. rtsr . modify ( |_, w| w. tr22 ( ) . disabled ( ) ) ;
596
+ }
597
+ Event :: Timestamp => {
598
+ regs. cr . modify ( |_, w| w. tsie ( ) . clear_bit ( ) ) ;
599
+ exti. rtsr . modify ( |_, w| w. tr21 ( ) . disabled ( ) ) ;
600
+ }
601
+ } ) ;
602
+ }
603
+
604
+ /// Returns `true` if `event` is pending
605
+ pub fn is_pending ( & self , event : Event ) -> bool {
606
+ match event {
607
+ Event :: AlarmA => self . regs . isr . read ( ) . alraf ( ) . bit_is_set ( ) ,
608
+ Event :: AlarmB => self . regs . isr . read ( ) . alrbf ( ) . bit_is_set ( ) ,
609
+ Event :: Wakeup => self . regs . isr . read ( ) . wutf ( ) . bit_is_set ( ) ,
610
+ Event :: Timestamp => self . regs . isr . read ( ) . tsf ( ) . bit_is_set ( ) ,
611
+ }
612
+ }
613
+
614
+ /// Clears the interrupt flag for `event`
615
+ pub fn clear_interrupt ( & mut self , event : Event ) {
616
+ match event {
617
+ Event :: AlarmA => {
618
+ self . regs . isr . modify ( |_, w| w. alraf ( ) . clear_bit ( ) ) ;
619
+ }
620
+ Event :: AlarmB => {
621
+ self . regs . isr . modify ( |_, w| w. alrbf ( ) . clear_bit ( ) ) ;
622
+ }
623
+ Event :: Wakeup => {
624
+ self . regs . isr . modify ( |_, w| w. wutf ( ) . clear_bit ( ) ) ;
625
+ }
626
+ Event :: Timestamp => {
627
+ self . regs . isr . modify ( |_, w| w. tsf ( ) . clear_bit ( ) ) ;
628
+ }
629
+ }
630
+ }
457
631
}
458
632
459
633
// Two 32-bit registers (RTC_TR and RTC_DR) contain the seconds, minutes, hours (12- or 24-hour format), day (day
@@ -479,38 +653,67 @@ fn bcd2_encode(word: u32) -> Result<(u8, u8), Error> {
479
653
Ok ( ( l, r) )
480
654
}
481
655
482
- fn bcd2_decode ( fst : u8 , snd : u8 ) -> u32 {
483
- ( fst * 10 + snd) . into ( )
656
+ const fn bcd2_decode ( fst : u8 , snd : u8 ) -> u8 {
657
+ fst * 10 + snd
484
658
}
485
659
486
660
#[ inline( always) ]
487
661
fn decode_seconds ( tr : & tr:: R ) -> u8 {
488
- bcd2_decode ( tr. st ( ) . bits ( ) , tr. su ( ) . bits ( ) ) as u8
662
+ bcd2_decode ( tr. st ( ) . bits ( ) , tr. su ( ) . bits ( ) )
663
+ }
664
+ #[ inline( always) ]
665
+ fn decode_ts_seconds ( tr : & tstr:: R ) -> u8 {
666
+ bcd2_decode ( tr. st ( ) . bits ( ) , tr. su ( ) . bits ( ) )
489
667
}
490
668
491
669
#[ inline( always) ]
492
670
fn decode_minutes ( tr : & tr:: R ) -> u8 {
493
- bcd2_decode ( tr. mnt ( ) . bits ( ) , tr. mnu ( ) . bits ( ) ) as u8
671
+ bcd2_decode ( tr. mnt ( ) . bits ( ) , tr. mnu ( ) . bits ( ) )
672
+ }
673
+ #[ inline( always) ]
674
+ fn decode_ts_minutes ( tr : & tstr:: R ) -> u8 {
675
+ bcd2_decode ( tr. mnt ( ) . bits ( ) , tr. mnu ( ) . bits ( ) )
494
676
}
495
677
496
678
#[ inline( always) ]
497
679
fn decode_hours ( tr : & tr:: R ) -> u8 {
498
- bcd2_decode ( tr. ht ( ) . bits ( ) , tr. hu ( ) . bits ( ) ) as u8
680
+ bcd2_decode ( tr. ht ( ) . bits ( ) , tr. hu ( ) . bits ( ) )
681
+ }
682
+ #[ inline( always) ]
683
+ fn decode_ts_hours ( tr : & tstr:: R ) -> u8 {
684
+ bcd2_decode ( tr. ht ( ) . bits ( ) , tr. hu ( ) . bits ( ) )
499
685
}
500
686
501
687
#[ inline( always) ]
502
688
fn decode_day ( dr : & dr:: R ) -> u8 {
503
- bcd2_decode ( dr. dt ( ) . bits ( ) , dr. du ( ) . bits ( ) ) as u8
689
+ bcd2_decode ( dr. dt ( ) . bits ( ) , dr. du ( ) . bits ( ) )
690
+ }
691
+ #[ inline( always) ]
692
+ fn decode_ts_day ( dr : & tsdr:: R ) -> u8 {
693
+ bcd2_decode ( dr. dt ( ) . bits ( ) , dr. du ( ) . bits ( ) )
504
694
}
505
695
506
696
#[ inline( always) ]
507
697
fn decode_month ( dr : & dr:: R ) -> u8 {
508
698
let mt = u8:: from ( dr. mt ( ) . bit ( ) ) ;
509
- bcd2_decode ( mt, dr. mu ( ) . bits ( ) ) as u8
699
+ bcd2_decode ( mt, dr. mu ( ) . bits ( ) )
700
+ }
701
+ #[ inline( always) ]
702
+ fn decode_ts_month ( dr : & tsdr:: R ) -> u8 {
703
+ let mt = u8:: from ( dr. mt ( ) . bit ( ) ) ;
704
+ bcd2_decode ( mt, dr. mu ( ) . bits ( ) )
510
705
}
511
706
512
707
#[ inline( always) ]
513
708
fn decode_year ( dr : & dr:: R ) -> u16 {
514
- let year = bcd2_decode ( dr. yt ( ) . bits ( ) , dr. yu ( ) . bits ( ) ) + 1970 ; // 1970-01-01 is the epoch begin.
709
+ let year = ( bcd2_decode ( dr. yt ( ) . bits ( ) , dr. yu ( ) . bits ( ) ) as u32 ) + 1970 ; // 1970-01-01 is the epoch begin.
515
710
year as u16
516
711
}
712
+
713
+ const fn ss_to_nano ( ss : u16 , prediv_s : u16 ) -> u32 {
714
+ let ss = ss as u32 ;
715
+ let prediv_s = prediv_s as u32 ;
716
+ assert ! ( ss <= prediv_s) ;
717
+
718
+ ( ( ( prediv_s - ss) * 100_000 ) / ( prediv_s + 1 ) ) * 10_000
719
+ }
0 commit comments