33
33
#include "rtc_api_hal.h"
34
34
#include "mbed_mktime.h"
35
35
#include "mbed_error.h"
36
+ #include "mbed_critical.h"
37
+
38
+ #if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
39
+ volatile uint32_t LP_continuous_time = 0 ;
40
+ volatile uint32_t LP_last_RTC_time = 0 ;
41
+ #endif
42
+
43
+ static int RTC_inited = 0 ;
36
44
37
45
static RTC_HandleTypeDef RtcHandle ;
38
46
@@ -41,18 +49,15 @@ void rtc_init(void)
41
49
RCC_OscInitTypeDef RCC_OscInitStruct = {0 };
42
50
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0 };
43
51
52
+ if (RTC_inited ) {
53
+ return ;
54
+ }
55
+ RTC_inited = 1 ;
56
+
44
57
// Enable access to Backup domain
45
58
__HAL_RCC_PWR_CLK_ENABLE ();
46
59
HAL_PWR_EnableBkUpAccess ();
47
60
48
- #if DEVICE_LPTICKER
49
- if ((rtc_isenabled ()) && ((RTC -> PRER & RTC_PRER_PREDIV_S ) == PREDIV_S_VALUE )) {
50
- #else /* DEVICE_LPTICKER */
51
- if (rtc_isenabled ()) {
52
- #endif /* DEVICE_LPTICKER */
53
- return ;
54
- }
55
-
56
61
#if MBED_CONF_TARGET_LSE_AVAILABLE
57
62
RCC_OscInitStruct .OscillatorType = RCC_OSCILLATORTYPE_LSE ;
58
63
RCC_OscInitStruct .PLL .PLLState = RCC_PLL_NONE ; // Mandatory, otherwise the PLL is reconfigured!
@@ -114,48 +119,20 @@ void rtc_init(void)
114
119
error ("RTC initialization failed" );
115
120
}
116
121
117
- rtc_synchronize (); // Wait for RSF
118
-
119
- if (!rtc_isenabled ()) {
120
- rtc_write (0 );
122
+ #if !(TARGET_STM32F1 ) && !(TARGET_STM32F2 )
123
+ /* STM32F1 : there are no shadow registers */
124
+ /* STM32F2 : shadow registers can not be bypassed */
125
+ if (HAL_RTCEx_EnableBypassShadow (& RtcHandle ) != HAL_OK ) {
126
+ error ("EnableBypassShadow error" );
121
127
}
128
+ #endif /* TARGET_STM32F1 || TARGET_STM32F2 */
122
129
}
123
130
124
131
void rtc_free (void )
125
132
{
126
- // Disable access to Backup domain
127
- HAL_PWR_DisableBkUpAccess ();
133
+ /* RTC clock can not be reset */
128
134
}
129
135
130
- /*
131
- ST RTC_DateTypeDef structure
132
- WeekDay 1=monday, 2=tuesday, ..., 7=sunday
133
- Month 0x1=january, 0x2=february, ..., 0x12=december
134
- Date day of the month 1-31
135
- Year year 0-99
136
-
137
- ST RTC_TimeTypeDef structure
138
- Hours 0-12 if the RTC_HourFormat_12 is selected during init
139
- 0-23 if the RTC_HourFormat_24 is selected during init
140
- Minutes 0-59
141
- Seconds 0-59
142
- TimeFormat RTC_HOURFORMAT12_AM/RTC_HOURFORMAT12_PM
143
- SubSeconds time unit range between [0-1] Second with [1 Sec / SecondFraction +1] granularity
144
- SecondFraction range or granularity of Sub Second register content corresponding to Synchronous pre-scaler factor value (PREDIV_S)
145
- DayLightSaving RTC_DAYLIGHTSAVING_SUB1H/RTC_DAYLIGHTSAVING_ADD1H/RTC_DAYLIGHTSAVING_NONE
146
- StoreOperation RTC_STOREOPERATION_RESET/RTC_STOREOPERATION_SET
147
-
148
- struct tm
149
- tm_sec seconds after the minute 0-61
150
- tm_min minutes after the hour 0-59
151
- tm_hour hours since midnight 0-23
152
- tm_mday day of the month 1-31
153
- tm_mon months since January 0-11
154
- tm_year years since 1900
155
- tm_wday days since Sunday 0-6
156
- tm_yday days since January 1 0-365
157
- tm_isdst Daylight Saving Time flag
158
- */
159
136
160
137
/*
161
138
Information about STM32F0, STM32F2, STM32F3, STM32F4, STM32F7, STM32L0, STM32L1, STM32L4:
@@ -172,7 +149,7 @@ Information about STM32F1:
172
149
For date, there is no specific register, only a software structure.
173
150
It is then not a problem to not use shifts.
174
151
*/
175
-
152
+ #if TARGET_STM32F1
176
153
time_t rtc_read (void )
177
154
{
178
155
RTC_DateTypeDef dateStruct = {0 };
@@ -186,15 +163,13 @@ time_t rtc_read(void)
186
163
HAL_RTC_GetTime (& RtcHandle , & timeStruct , RTC_FORMAT_BIN );
187
164
HAL_RTC_GetDate (& RtcHandle , & dateStruct , RTC_FORMAT_BIN );
188
165
189
- #if TARGET_STM32F1
190
166
/* date information is null before first write procedure */
191
167
/* set 01/01/1970 as default values */
192
168
if (dateStruct .Year == 0 ) {
193
169
dateStruct .Year = 2 ;
194
170
dateStruct .Month = 1 ;
195
171
dateStruct .Date = 1 ;
196
172
}
197
- #endif
198
173
199
174
// Setup a tm structure based on the RTC
200
175
/* tm_wday information is ignored by _rtc_maketime */
@@ -215,11 +190,57 @@ time_t rtc_read(void)
215
190
return t ;
216
191
}
217
192
193
+ #else /* TARGET_STM32F1 */
194
+
195
+ time_t rtc_read (void )
196
+ {
197
+ struct tm timeinfo ;
198
+
199
+ /* Since the shadow registers are bypassed we have to read the time twice and compare them until both times are the same */
200
+ uint32_t Read_time = RTC -> TR & RTC_TR_RESERVED_MASK ;
201
+ uint32_t Read_date = RTC -> DR & RTC_DR_RESERVED_MASK ;
202
+
203
+ while ((Read_time != (RTC -> TR & RTC_TR_RESERVED_MASK )) || (Read_date != (RTC -> DR & RTC_DR_RESERVED_MASK ))) {
204
+ Read_time = RTC -> TR & RTC_TR_RESERVED_MASK ;
205
+ Read_date = RTC -> DR & RTC_DR_RESERVED_MASK ;
206
+ }
207
+
208
+ /* Setup a tm structure based on the RTC
209
+ struct tm :
210
+ tm_sec seconds after the minute 0-61
211
+ tm_min minutes after the hour 0-59
212
+ tm_hour hours since midnight 0-23
213
+ tm_mday day of the month 1-31
214
+ tm_mon months since January 0-11
215
+ tm_year years since 1900
216
+ tm_yday information is ignored by _rtc_maketime
217
+ tm_wday information is ignored by _rtc_maketime
218
+ tm_isdst information is ignored by _rtc_maketime
219
+ */
220
+ timeinfo .tm_mday = RTC_Bcd2ToByte ((uint8_t )(Read_date & (RTC_DR_DT | RTC_DR_DU )));
221
+ timeinfo .tm_mon = RTC_Bcd2ToByte ((uint8_t )((Read_date & (RTC_DR_MT | RTC_DR_MU )) >> 8 )) - 1 ;
222
+ timeinfo .tm_year = RTC_Bcd2ToByte ((uint8_t )((Read_date & (RTC_DR_YT | RTC_DR_YU )) >> 16 )) + 68 ;
223
+ timeinfo .tm_hour = RTC_Bcd2ToByte ((uint8_t )((Read_time & (RTC_TR_HT | RTC_TR_HU )) >> 16 ));
224
+ timeinfo .tm_min = RTC_Bcd2ToByte ((uint8_t )((Read_time & (RTC_TR_MNT | RTC_TR_MNU )) >> 8 ));
225
+ timeinfo .tm_sec = RTC_Bcd2ToByte ((uint8_t )((Read_time & (RTC_TR_ST | RTC_TR_SU )) >> 0 ));
226
+
227
+ // Convert to timestamp
228
+ time_t t ;
229
+ if (_rtc_maketime (& timeinfo , & t , RTC_4_YEAR_LEAP_YEAR_SUPPORT ) == false) {
230
+ return 0 ;
231
+ }
232
+
233
+ return t ;
234
+ }
235
+
236
+ #endif /* TARGET_STM32F1 */
237
+
218
238
void rtc_write (time_t t )
219
239
{
220
240
RTC_DateTypeDef dateStruct = {0 };
221
241
RTC_TimeTypeDef timeStruct = {0 };
222
242
243
+ core_util_critical_section_enter ();
223
244
RtcHandle .Instance = RTC ;
224
245
225
246
// Convert the time into a tm
@@ -247,40 +268,49 @@ void rtc_write(time_t t)
247
268
timeStruct .StoreOperation = RTC_STOREOPERATION_RESET ;
248
269
#endif /* TARGET_STM32F1 */
249
270
271
+ #if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
272
+ /* Need to update LP_continuous_time value before new RTC time */
273
+ uint32_t current_lp_time = rtc_read_lp ();
274
+
275
+ /* LP_last_RTC_time value is updated with the new RTC time */
276
+ LP_last_RTC_time = timeStruct .Seconds + timeStruct .Minutes * 60 + timeStruct .Hours * 60 * 60 ;
277
+
278
+ /* Save current SSR */
279
+ uint32_t Read_SubSeconds = (uint32_t )(RTC -> SSR );
280
+ #endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
281
+
250
282
// Change the RTC current date/time
251
283
if (HAL_RTC_SetDate (& RtcHandle , & dateStruct , RTC_FORMAT_BIN ) != HAL_OK ) {
252
284
error ("HAL_RTC_SetDate error\n" );
253
285
}
254
286
if (HAL_RTC_SetTime (& RtcHandle , & timeStruct , RTC_FORMAT_BIN ) != HAL_OK ) {
255
287
error ("HAL_RTC_SetTime error\n" );
256
288
}
289
+
290
+ #if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
291
+ while (Read_SubSeconds != (RTC -> SSR )) {
292
+ }
293
+ #endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
294
+
295
+ core_util_critical_section_exit ();
257
296
}
258
297
259
298
int rtc_isenabled (void )
260
299
{
261
300
#if !(TARGET_STM32F1 )
262
- return ((( RTC -> ISR & RTC_ISR_INITS ) == RTC_ISR_INITS ) && (( RTC -> ISR & RTC_ISR_RSF ) == RTC_ISR_RSF ) );
301
+ return ((RTC -> ISR & RTC_ISR_INITS ) == RTC_ISR_INITS );
263
302
#else /* TARGET_STM32F1 */
264
303
return ((RTC -> CRL & RTC_CRL_RSF ) == RTC_CRL_RSF );
265
304
#endif /* TARGET_STM32F1 */
266
305
}
267
306
268
- void rtc_synchronize (void )
269
- {
270
- RtcHandle .Instance = RTC ;
271
- if (HAL_RTC_WaitForSynchro (& RtcHandle ) != HAL_OK ) {
272
- error ("rtc_synchronize error\n" );
273
- }
274
- }
275
307
276
308
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
277
309
278
310
static void RTC_IRQHandler (void );
279
311
static void (* irq_handler )(void );
280
312
281
313
volatile uint8_t lp_Fired = 0 ;
282
- volatile uint32_t LP_continuous_time = 0 ;
283
- volatile uint32_t LP_last_RTC_time = 0 ;
284
314
285
315
static void RTC_IRQHandler (void )
286
316
{
@@ -311,31 +341,34 @@ static void RTC_IRQHandler(void)
311
341
312
342
uint32_t rtc_read_lp (void )
313
343
{
314
- RTC_TimeTypeDef timeStruct = {0 };
315
- RTC_DateTypeDef dateStruct = {0 };
316
-
317
- RtcHandle .Instance = RTC ;
318
- HAL_RTC_GetTime (& RtcHandle , & timeStruct , RTC_FORMAT_BIN );
344
+ struct tm timeinfo ;
319
345
320
- /* Reading RTC current time locks the values in calendar shadow registers until Current date is read
321
- to ensure consistency between the time and date values */
322
- HAL_RTC_GetDate (& RtcHandle , & dateStruct , RTC_FORMAT_BIN );
346
+ /* Since the shadow registers are bypassed we have to read the time twice and compare them until both times are the same */
347
+ /* We don't have to read date as we bypass shadow registers */
348
+ uint32_t Read_SecondFraction = (uint32_t )(RTC -> PRER & RTC_PRER_PREDIV_S );
349
+ uint32_t Read_time = (uint32_t )(RTC -> TR & RTC_TR_RESERVED_MASK );
350
+ uint32_t Read_SubSeconds = (uint32_t )(RTC -> SSR );
323
351
324
- if (timeStruct .SubSeconds > timeStruct .SecondFraction ) {
325
- /* SS can be larger than PREDIV_S only after a shift operation. In that case, the correct
326
- time/date is one second less than as indicated by RTC_TR/RTC_DR. */
327
- timeStruct .Seconds -= 1 ;
352
+ while ((Read_time != (RTC -> TR & RTC_TR_RESERVED_MASK )) || (Read_SubSeconds != (RTC -> SSR ))) {
353
+ Read_time = (uint32_t )(RTC -> TR & RTC_TR_RESERVED_MASK );
354
+ Read_SubSeconds = (uint32_t )(RTC -> SSR );
328
355
}
329
- uint32_t RTC_time_s = timeStruct .Seconds + timeStruct .Minutes * 60 + timeStruct .Hours * 60 * 60 ; // Max 0x0001-517F => * 8191 + 8191 = 0x2A2E-AE80
356
+
357
+ timeinfo .tm_hour = RTC_Bcd2ToByte ((uint8_t )((Read_time & (RTC_TR_HT | RTC_TR_HU )) >> 16 ));
358
+ timeinfo .tm_min = RTC_Bcd2ToByte ((uint8_t )((Read_time & (RTC_TR_MNT | RTC_TR_MNU )) >> 8 ));
359
+ timeinfo .tm_sec = RTC_Bcd2ToByte ((uint8_t )((Read_time & (RTC_TR_ST | RTC_TR_SU )) >> 0 ));
360
+
361
+ uint32_t RTC_time_s = timeinfo .tm_sec + timeinfo .tm_min * 60 + timeinfo .tm_hour * 60 * 60 ; // Max 0x0001-517F => * 8191 + 8191 = 0x2A2E-AE80
330
362
331
363
if (LP_last_RTC_time <= RTC_time_s ) {
332
364
LP_continuous_time += (RTC_time_s - LP_last_RTC_time );
333
365
} else {
366
+ /* Add 24h */
334
367
LP_continuous_time += (24 * 60 * 60 + RTC_time_s - LP_last_RTC_time );
335
368
}
336
369
LP_last_RTC_time = RTC_time_s ;
337
370
338
- return LP_continuous_time * PREDIV_S_VALUE + timeStruct . SecondFraction - timeStruct . SubSeconds ;
371
+ return LP_continuous_time * PREDIV_S_VALUE + Read_SecondFraction - Read_SubSeconds ;
339
372
}
340
373
341
374
void rtc_set_wake_up_timer (timestamp_t timestamp )
@@ -377,7 +410,11 @@ void rtc_fire_interrupt(void)
377
410
void rtc_deactivate_wake_up_timer (void )
378
411
{
379
412
RtcHandle .Instance = RTC ;
380
- HAL_RTCEx_DeactivateWakeUpTimer (& RtcHandle );
413
+ __HAL_RTC_WRITEPROTECTION_DISABLE (& RtcHandle );
414
+ __HAL_RTC_WAKEUPTIMER_DISABLE (& RtcHandle );
415
+ __HAL_RTC_WAKEUPTIMER_DISABLE_IT (& RtcHandle , RTC_IT_WUT );
416
+ __HAL_RTC_WRITEPROTECTION_ENABLE (& RtcHandle );
417
+ NVIC_DisableIRQ (RTC_WKUP_IRQn );
381
418
}
382
419
383
420
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
0 commit comments