1
1
//! Real-time clock.
2
2
3
3
use crate :: { pac, rcc:: lsi_hz} ;
4
-
5
4
use chrono:: { Datelike , NaiveDate , NaiveDateTime , NaiveTime , Timelike } ;
6
-
7
- use pac:: rcc:: {
8
- bdcr:: RTCSEL_A ,
9
- csr:: LSIPRE_A :: { DIV1 , DIV128 } ,
5
+ use pac:: {
6
+ rcc:: {
7
+ bdcr:: RTCSEL_A ,
8
+ csr:: LSIPRE_A :: { DIV1 , DIV128 } ,
9
+ } ,
10
+ rtc:: cr:: WUCKSEL_A ,
10
11
} ;
11
12
12
13
/// RTC clock selection
@@ -22,6 +23,29 @@ pub enum Clk {
22
23
Hse = RTCSEL_A :: HSE32 as u8 ,
23
24
}
24
25
26
+ /// Status (interrupt) masks.
27
+ ///
28
+ /// Used for [`Rtc::clear_status`].
29
+ pub mod stat {
30
+ /// SSR underflow flag
31
+ pub const SSRU : u32 = 1 << 6 ;
32
+ /// Internal timestamp flag
33
+ pub const ITS : u32 = 1 << 5 ;
34
+ /// Timestamp overflow flag
35
+ pub const TSOV : u32 = 1 << 4 ;
36
+ /// Timestamp flag
37
+ pub const TS : u32 = 1 << 3 ;
38
+ /// Wakeup timer flag
39
+ pub const WUT : u32 = 1 << 2 ;
40
+ /// Alarm B flag
41
+ pub const ALRB : u32 = 1 << 1 ;
42
+ /// Alarm A flag
43
+ pub const ALRA : u32 = 1 << 0 ;
44
+
45
+ /// All status flags.
46
+ pub const ALL : u32 = SSRU | ITS | TSOV | TS | WUT | ALRB | ALRA ;
47
+ }
48
+
25
49
/// Real-time clock driver.
26
50
#[ derive( Debug ) ]
27
51
pub struct Rtc {
@@ -183,6 +207,29 @@ impl Rtc {
183
207
}
184
208
}
185
209
210
+ /// Read the RTC status (interrupt) register.
211
+ #[ inline]
212
+ pub fn status ( ) -> pac:: rtc:: sr:: R {
213
+ // saftey: atomic read with no side-effects
214
+ unsafe { ( * pac:: RTC :: ptr ( ) ) . sr . read ( ) }
215
+ }
216
+
217
+ /// Read the RTC masked status (interrupt) register.
218
+ #[ inline]
219
+ pub fn masked_status ( ) -> pac:: rtc:: misr:: R {
220
+ // saftey: atomic read with no side-effects
221
+ unsafe { ( * pac:: RTC :: ptr ( ) ) . misr . read ( ) }
222
+ }
223
+
224
+ /// Clear status (interrupt) flags.
225
+ ///
226
+ /// Status flag masks can be found in [`stat`].
227
+ #[ inline]
228
+ pub fn clear_status ( mask : u32 ) {
229
+ // safety: mask is masked with valid register fields
230
+ unsafe { ( * pac:: RTC :: ptr ( ) ) . scr . write ( |w| w. bits ( mask & stat:: ALL ) ) }
231
+ }
232
+
186
233
// configure prescaler for a 1Hz clock
187
234
//
188
235
// RM0453 Rev 2 page 996:
@@ -409,6 +456,64 @@ impl Rtc {
409
456
}
410
457
}
411
458
459
+ /// Setup the periodic wakeup timer for `sec + 1` seconds.
460
+ ///
461
+ /// `sec` can only go up to 2<sup>17</sup> (36 hours), values greater than
462
+ /// this will be set to the maximum.
463
+ ///
464
+ /// # Example
465
+ ///
466
+ /// Setup the wakeup timer to go off in 1 hour, without interrupts.
467
+ ///
468
+ /// ```no_run
469
+ /// # use stm32wl_hal::{pac, rtc};
470
+ /// # let mut dp: pac::Peripherals = pac::Peripherals::take().unwrap();
471
+ /// # let mut rtc = rtc::Rtc::new(dp.RTC, rtc::Clk::Lse, &mut dp.PWR, &mut dp.RCC);
472
+ /// rtc.setup_wakeup_timer(3599, false);
473
+ /// ```
474
+ pub fn setup_wakeup_timer ( & mut self , sec : u32 , irq_en : bool ) {
475
+ // The following sequence is required to configure or change the wakeup
476
+ // timer auto-reload value (WUT[15:0] in RTC_WUTR):
477
+
478
+ // 1. Clear WUTE in RTC_CR to disable the wakeup timer.
479
+ self . rtc . cr . modify ( |_, w| w. wute ( ) . clear_bit ( ) ) ;
480
+ // 2. Poll WUTWF until it is set in RTC_ICSR to make sure the access to
481
+ // wakeup auto-reload counter and to WUCKSEL[2:0] bits is allowed.
482
+ // This step must be skipped in calendar initialization mode.
483
+ // If WUCKSEL[2] = 0:
484
+ // WUTWF is set around 1 ck_wut + 1 RTCCLK cycles after WUTE bit is cleared.
485
+ // If WUCKSEL[2] = 1:
486
+ // WUTWF is set up to 1 ck_apre + 1 RTCCLK cycles after WUTE bit is cleared.
487
+ while self . rtc . icsr . read ( ) . wutwf ( ) . bit_is_clear ( ) { }
488
+ // 3. Program the wakeup auto-reload value WUT[15:0], WUTOCLR[15:0]
489
+ // and the wakeup clock selection (WUCKSEL[2:0] bits in RTC_CR).
490
+ // Set WUTE in RTC_CR to enable the timer again.
491
+ // The wakeup timer restarts down-counting.
492
+ // If WUCKSEL[2] = 0:
493
+ // WUTWF is cleared around 1 ck_wut + 1 RTCCLK cycles after WUTE bit is set.
494
+ // If WUCKSEL[2] = 1:
495
+ // WUTWF is cleared up to 1 ck_apre + 1 RTCCLK cycles after WUTE bit is set.
496
+ let ( wucksel, sec) : ( WUCKSEL_A , u16 ) = match u16:: try_from ( sec) {
497
+ Ok ( sec) => ( WUCKSEL_A :: CLOCKSPARE , sec) ,
498
+ Err ( _) => (
499
+ WUCKSEL_A :: CLOCKSPAREWITHOFFSET ,
500
+ u16:: try_from ( sec - ( 1 << 16 ) - 1 ) . unwrap_or ( u16:: MAX ) ,
501
+ ) ,
502
+ } ;
503
+
504
+ self . rtc
505
+ . cr
506
+ . modify ( |_, w| w. wucksel ( ) . variant ( wucksel) . wutie ( ) . bit ( irq_en) ) ;
507
+ self . rtc . wutr . write ( |w| w. wut ( ) . bits ( sec) . wutoclr ( ) . bits ( 0 ) ) ;
508
+ self . rtc . cr . modify ( |_, w| w. wute ( ) . set_bit ( ) ) ;
509
+ }
510
+
511
+ /// Disable the wakeup timer.
512
+ #[ inline]
513
+ pub fn disable_wakeup_timer ( & mut self ) {
514
+ self . rtc . cr . modify ( |_, w| w. wute ( ) . clear_bit ( ) ) ;
515
+ }
516
+
412
517
/// Disable the RTC write protection.
413
518
#[ inline]
414
519
pub fn disable_write_protect ( & mut self ) {
0 commit comments