@@ -20,6 +20,11 @@ pub struct RtcClkLse;
20
20
/// RTC clock source LSI oscillator clock (type state)
21
21
pub struct RtcClkLsi ;
22
22
23
+ pub enum RestoredOrNewRtc < CS > {
24
+ Restored ( Rtc < CS > ) ,
25
+ New ( Rtc < CS > ) ,
26
+ }
27
+
23
28
/**
24
29
Real time clock
25
30
@@ -44,14 +49,19 @@ pub struct Rtc<CS = RtcClkLse> {
44
49
45
50
impl Rtc < RtcClkLse > {
46
51
/**
47
- Initialises the RTC. The `BackupDomain` struct is created by
48
- `Rcc.bkp.constrain()`.
52
+ Initialises the RTC with low-speed external crystal source (lse).
53
+ The `BackupDomain` struct is created by `Rcc.bkp.constrain()`.
49
54
50
55
The frequency is set to 1 Hz.
51
56
52
57
Since the RTC is part of the backup domain, The RTC counter is not reset by normal resets or
53
58
power cycles where (VBAT) still has power. Use [set_time](#method.set_time) if you want to
54
59
reset the counter.
60
+
61
+ In case application is running of a battery on VBAT,
62
+ this method will reset the RTC every time, leading to lost time,
63
+ you may want to use
64
+ [`restore_or_new`](Rtc::<RtcClkLse>::restore_or_new) instead.
55
65
*/
56
66
pub fn new ( regs : RTC , bkp : & mut BackupDomain ) -> Self {
57
67
let mut result = Rtc {
@@ -72,6 +82,37 @@ impl Rtc<RtcClkLse> {
72
82
result
73
83
}
74
84
85
+ /// Tries to obtain currently running RTC to prevent a reset in case it was running from VBAT.
86
+ /// If the RTC is not running, or is not LSE, it will be reinitialized.
87
+ ///
88
+ /// # Examples
89
+ /// ```
90
+ /// let rtc = match Rtc::restore_or_new(p.RTC, &mut backup_domain) {
91
+ /// Restored(rtc) => rtc, // The rtc is restored from previous configuration. You may verify the frequency you want if needed.
92
+ /// New(rtc) => { // The rtc was just initialized, the clock source selected, frequency is 1.Hz()
93
+ /// // Initialize rtc with desired parameters
94
+ /// rtc.select_frequency(2u16.Hz()); // Set the frequency to 2 Hz. This will stay same after reset
95
+ /// rtc
96
+ /// }
97
+ /// };
98
+ /// ```
99
+ pub fn restore_or_new ( regs : RTC , bkp : & mut BackupDomain ) -> RestoredOrNewRtc < RtcClkLse > {
100
+ if !Self :: is_enabled ( ) {
101
+ RestoredOrNewRtc :: New ( Rtc :: new ( regs, bkp) )
102
+ } else {
103
+ RestoredOrNewRtc :: Restored ( Rtc {
104
+ regs,
105
+ _clock_source : PhantomData ,
106
+ } )
107
+ }
108
+ }
109
+
110
+ /// Returns whether the RTC is currently enabled and LSE is selected.
111
+ fn is_enabled ( ) -> bool {
112
+ let rcc = unsafe { & * RCC :: ptr ( ) } ;
113
+ rcc. bdcr . read ( ) . rtcen ( ) . bit ( ) && rcc. bdcr . read ( ) . rtcsel ( ) . is_lse ( )
114
+ }
115
+
75
116
/// Enables the RTC device with the lse as the clock
76
117
fn enable_rtc ( _bkp : & mut BackupDomain ) {
77
118
// NOTE: Safe RCC access because we are only accessing bdcr
@@ -93,6 +134,21 @@ impl Rtc<RtcClkLse> {
93
134
}
94
135
95
136
impl Rtc < RtcClkLsi > {
137
+ /**
138
+ Initialises the RTC with low-speed internal oscillator source (lsi).
139
+ The `BackupDomain` struct is created by `Rcc.bkp.constrain()`.
140
+
141
+ The frequency is set to 1 Hz.
142
+
143
+ Since the RTC is part of the backup domain, The RTC counter is not reset by normal resets or
144
+ power cycles where (VBAT) still has power. Use [set_time](#method.set_time) if you want to
145
+ reset the counter.
146
+
147
+ In case application is running of a battery on VBAT,
148
+ this method will reset the RTC every time, leading to lost time,
149
+ you may want to use
150
+ [`restore_or_new_lsi`](Rtc::<RtcClkLsi>::restore_or_new_lsi) instead.
151
+ */
96
152
pub fn new_lsi ( regs : RTC , bkp : & mut BackupDomain ) -> Self {
97
153
let mut result = Rtc {
98
154
regs,
@@ -112,6 +168,25 @@ impl Rtc<RtcClkLsi> {
112
168
result
113
169
}
114
170
171
+ /// Tries to obtain currently running RTC to prevent reset in case it was running from VBAT.
172
+ /// If the RTC is not running, or is not LSI, it will be reinitialized.
173
+ pub fn restore_or_new_lsi ( regs : RTC , bkp : & mut BackupDomain ) -> RestoredOrNewRtc < RtcClkLsi > {
174
+ if !Rtc :: < RtcClkLsi > :: is_enabled ( ) {
175
+ RestoredOrNewRtc :: New ( Rtc :: new_lsi ( regs, bkp) )
176
+ } else {
177
+ RestoredOrNewRtc :: Restored ( Rtc {
178
+ regs,
179
+ _clock_source : PhantomData ,
180
+ } )
181
+ }
182
+ }
183
+
184
+ /// Returns whether the RTC is currently enabled and LSI is selected.
185
+ fn is_enabled ( ) -> bool {
186
+ let rcc = unsafe { & * RCC :: ptr ( ) } ;
187
+ rcc. bdcr . read ( ) . rtcen ( ) . bit ( ) && rcc. bdcr . read ( ) . rtcsel ( ) . is_lsi ( )
188
+ }
189
+
115
190
/// Enables the RTC device with the lsi as the clock
116
191
fn enable_rtc ( _bkp : & mut BackupDomain ) {
117
192
// NOTE: Safe RCC access because we are only accessing bdcr
@@ -136,6 +211,22 @@ impl Rtc<RtcClkLsi> {
136
211
}
137
212
138
213
impl Rtc < RtcClkHseDiv128 > {
214
+ /**
215
+ Initialises the RTC with high-speed external oscillator source (hse)
216
+ divided by 128.
217
+ The `BackupDomain` struct is created by `Rcc.bkp.constrain()`.
218
+
219
+ The frequency is set to 1 Hz.
220
+
221
+ Since the RTC is part of the backup domain, The RTC counter is not reset by normal resets or
222
+ power cycles where (VBAT) still has power. Use [set_time](#method.set_time) if you want to
223
+ reset the counter.
224
+
225
+ In case application is running of a battery on VBAT,
226
+ this method will reset the RTC every time, leading to lost time,
227
+ you may want to use
228
+ [`restore_or_new_hse`](Rtc::<RtcClkHseDiv128>::restore_or_new_hse) instead.
229
+ */
139
230
pub fn new_hse ( regs : RTC , bkp : & mut BackupDomain , hse : Hertz ) -> Self {
140
231
let mut result = Rtc {
141
232
regs,
@@ -155,6 +246,28 @@ impl Rtc<RtcClkHseDiv128> {
155
246
result
156
247
}
157
248
249
+ /// Tries to obtain currently running RTC to prevent reset in case it was running from VBAT.
250
+ /// If the RTC is not running, or is not HSE, it will be reinitialized.
251
+ pub fn restore_or_new_hse (
252
+ regs : RTC ,
253
+ bkp : & mut BackupDomain ,
254
+ hse : Hertz ,
255
+ ) -> RestoredOrNewRtc < RtcClkHseDiv128 > {
256
+ if !Self :: is_enabled ( ) {
257
+ RestoredOrNewRtc :: New ( Rtc :: new_hse ( regs, bkp, hse) )
258
+ } else {
259
+ RestoredOrNewRtc :: Restored ( Rtc {
260
+ regs,
261
+ _clock_source : PhantomData ,
262
+ } )
263
+ }
264
+ }
265
+
266
+ fn is_enabled ( ) -> bool {
267
+ let rcc = unsafe { & * RCC :: ptr ( ) } ;
268
+ rcc. bdcr . read ( ) . rtcen ( ) . bit ( ) && rcc. bdcr . read ( ) . rtcsel ( ) . is_hse ( )
269
+ }
270
+
158
271
/// Enables the RTC device with the lsi as the clock
159
272
fn enable_rtc ( _bkp : & mut BackupDomain ) {
160
273
// NOTE: Safe RCC access because we are only accessing bdcr
0 commit comments