@@ -6,9 +6,9 @@ use crate::bb;
6
6
use crate :: pac:: rtc:: { dr, tr, DR , TR } ;
7
7
use crate :: pac:: { self , rcc:: RegisterBlock , PWR , RCC , RTC } ;
8
8
use crate :: rcc:: Enable ;
9
- use core:: convert:: { TryFrom , TryInto } ;
10
9
use core:: fmt;
11
10
use core:: marker:: PhantomData ;
11
+ use fugit:: RateExtU32 ;
12
12
use time:: { Date , PrimitiveDateTime , Time , Weekday } ;
13
13
14
14
/// Invalid input error
@@ -67,8 +67,24 @@ pub struct Lse;
67
67
/// RTC clock source LSI oscillator clock (type state)
68
68
pub struct Lsi ;
69
69
70
+ pub trait FrequencySource {
71
+ fn frequency ( ) -> fugit:: Hertz < u32 > ;
72
+ }
73
+
74
+ impl FrequencySource for Lse {
75
+ fn frequency ( ) -> fugit:: Hertz < u32 > {
76
+ 32_768u32 . Hz ( )
77
+ }
78
+ }
79
+
80
+ impl FrequencySource for Lsi {
81
+ fn frequency ( ) -> fugit:: Hertz < u32 > {
82
+ 32_000u32 . Hz ( )
83
+ }
84
+ }
85
+
70
86
/// Real Time Clock peripheral
71
- pub struct Rtc < CS = Lse > {
87
+ pub struct Rtc < CS : FrequencySource = Lse > {
72
88
/// RTC Peripheral register
73
89
pub regs : RTC ,
74
90
_clock_source : PhantomData < CS > ,
@@ -239,7 +255,7 @@ impl Rtc<Lsi> {
239
255
}
240
256
}
241
257
242
- impl < CS > Rtc < CS > {
258
+ impl < CS : FrequencySource > Rtc < CS > {
243
259
fn unlock ( & mut self , rcc : & RegisterBlock , pwr : & mut PWR ) {
244
260
// Enable the backup interface
245
261
// Set APB1 - Bit 28 (PWREN)
@@ -525,28 +541,57 @@ impl<CS> Rtc<CS> {
525
541
)
526
542
}
527
543
528
- /// Configures the wakeup timer to trigger periodically every `interval` seconds
544
+ /// Configures the wakeup timer to trigger periodically every `interval` duration
529
545
///
530
546
/// # Panics
531
547
///
532
- /// Panics if interval is greater than 2¹⁷-1.
533
- pub fn enable_wakeup ( & mut self , interval : fugit:: SecsDurationU32 ) {
534
- let interval = interval. ticks ( ) ;
548
+ /// Panics if interval is greater than 2¹⁷-1 seconds.
549
+ pub fn enable_wakeup ( & mut self , interval : fugit:: MicrosDurationU64 ) {
535
550
self . modify ( false , |regs| {
536
551
regs. cr . modify ( |_, w| w. wute ( ) . clear_bit ( ) ) ;
537
552
regs. isr . modify ( |_, w| w. wutf ( ) . clear_bit ( ) ) ;
538
553
while regs. isr . read ( ) . wutwf ( ) . bit_is_clear ( ) { }
539
554
540
- if interval > 1 << 16 {
541
- regs. cr . modify ( |_, w| unsafe { w. wucksel ( ) . bits ( 0b110 ) } ) ;
542
- let interval = u16:: try_from ( interval - ( 1 << 16 ) - 1 )
543
- . expect ( "Interval was too large for wakeup timer" ) ;
555
+ use crate :: pac:: rtc:: cr:: WUCKSEL_A ;
556
+ if interval < fugit:: MicrosDurationU64 :: secs ( 32 ) {
557
+ // Use RTCCLK as the wakeup timer clock source
558
+ let frequency: fugit:: Hertz < u64 > = ( CS :: frequency ( ) / 2 ) . into ( ) ;
559
+ let freq_duration: fugit:: MicrosDurationU64 = frequency. into_duration ( ) ;
560
+ let ticks_per_interval = interval / freq_duration;
561
+
562
+ let mut prescaler = 0 ;
563
+ while ticks_per_interval >> prescaler > 1 << 16 {
564
+ prescaler += 1 ;
565
+ }
566
+
567
+ let wucksel = match prescaler {
568
+ 0 => WUCKSEL_A :: Div2 ,
569
+ 1 => WUCKSEL_A :: Div4 ,
570
+ 2 => WUCKSEL_A :: Div8 ,
571
+ 3 => WUCKSEL_A :: Div16 ,
572
+ _ => unreachable ! ( "Longer durations should use ck_spre" ) ,
573
+ } ;
574
+
575
+ let interval = u16:: try_from ( ( ticks_per_interval >> prescaler) - 1 ) . unwrap ( ) ;
576
+
577
+ regs. cr . modify ( |_, w| w. wucksel ( ) . variant ( wucksel) ) ;
544
578
regs. wutr . write ( |w| w. wut ( ) . bits ( interval) ) ;
545
579
} else {
546
- regs. cr . modify ( |_, w| unsafe { w. wucksel ( ) . bits ( 0b100 ) } ) ;
547
- let interval =
548
- u16:: try_from ( interval - 1 ) . expect ( "Interval was too large for wakeup timer" ) ;
549
- regs. wutr . write ( |w| w. wut ( ) . bits ( interval) ) ;
580
+ // Use ck_spre (1Hz) as the wakeup timer clock source
581
+ let interval = interval. to_secs ( ) ;
582
+ if interval > 1 << 16 {
583
+ regs. cr
584
+ . modify ( |_, w| w. wucksel ( ) . variant ( WUCKSEL_A :: ClockSpareWithOffset ) ) ;
585
+ let interval = u16:: try_from ( interval - ( 1 << 16 ) - 1 )
586
+ . expect ( "Interval was too large for wakeup timer" ) ;
587
+ regs. wutr . write ( |w| w. wut ( ) . bits ( interval) ) ;
588
+ } else {
589
+ regs. cr
590
+ . modify ( |_, w| w. wucksel ( ) . variant ( WUCKSEL_A :: ClockSpare ) ) ;
591
+ let interval = u16:: try_from ( interval - 1 )
592
+ . expect ( "Interval was too large for wakeup timer" ) ;
593
+ regs. wutr . write ( |w| w. wut ( ) . bits ( interval) ) ;
594
+ }
550
595
}
551
596
552
597
regs. cr . modify ( |_, w| w. wute ( ) . set_bit ( ) ) ;
0 commit comments