Skip to content

Commit e1df16e

Browse files
author
Cruz Monrreal
authored
Merge pull request #7365 from jeromecoutant/PR_RTC_SHADOW
STM32 RTC : bypass shadow registers
2 parents 19c6f3b + 1052993 commit e1df16e

File tree

2 files changed

+108
-83
lines changed

2 files changed

+108
-83
lines changed

targets/TARGET_STM/rtc_api.c

Lines changed: 108 additions & 71 deletions
Original file line numberDiff line numberDiff line change
@@ -33,6 +33,14 @@
3333
#include "rtc_api_hal.h"
3434
#include "mbed_mktime.h"
3535
#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;
3644

3745
static RTC_HandleTypeDef RtcHandle;
3846

@@ -41,18 +49,15 @@ void rtc_init(void)
4149
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
4250
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
4351

52+
if (RTC_inited) {
53+
return;
54+
}
55+
RTC_inited = 1;
56+
4457
// Enable access to Backup domain
4558
__HAL_RCC_PWR_CLK_ENABLE();
4659
HAL_PWR_EnableBkUpAccess();
4760

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-
5661
#if MBED_CONF_TARGET_LSE_AVAILABLE
5762
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
5863
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
@@ -114,48 +119,20 @@ void rtc_init(void)
114119
error("RTC initialization failed");
115120
}
116121

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");
121127
}
128+
#endif /* TARGET_STM32F1 || TARGET_STM32F2 */
122129
}
123130

124131
void rtc_free(void)
125132
{
126-
// Disable access to Backup domain
127-
HAL_PWR_DisableBkUpAccess();
133+
/* RTC clock can not be reset */
128134
}
129135

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-
*/
159136

160137
/*
161138
Information about STM32F0, STM32F2, STM32F3, STM32F4, STM32F7, STM32L0, STM32L1, STM32L4:
@@ -172,7 +149,7 @@ Information about STM32F1:
172149
For date, there is no specific register, only a software structure.
173150
It is then not a problem to not use shifts.
174151
*/
175-
152+
#if TARGET_STM32F1
176153
time_t rtc_read(void)
177154
{
178155
RTC_DateTypeDef dateStruct = {0};
@@ -186,15 +163,13 @@ time_t rtc_read(void)
186163
HAL_RTC_GetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN);
187164
HAL_RTC_GetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN);
188165

189-
#if TARGET_STM32F1
190166
/* date information is null before first write procedure */
191167
/* set 01/01/1970 as default values */
192168
if (dateStruct.Year == 0) {
193169
dateStruct.Year = 2 ;
194170
dateStruct.Month = 1 ;
195171
dateStruct.Date = 1 ;
196172
}
197-
#endif
198173

199174
// Setup a tm structure based on the RTC
200175
/* tm_wday information is ignored by _rtc_maketime */
@@ -215,11 +190,57 @@ time_t rtc_read(void)
215190
return t;
216191
}
217192

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+
218238
void rtc_write(time_t t)
219239
{
220240
RTC_DateTypeDef dateStruct = {0};
221241
RTC_TimeTypeDef timeStruct = {0};
222242

243+
core_util_critical_section_enter();
223244
RtcHandle.Instance = RTC;
224245

225246
// Convert the time into a tm
@@ -247,40 +268,49 @@ void rtc_write(time_t t)
247268
timeStruct.StoreOperation = RTC_STOREOPERATION_RESET;
248269
#endif /* TARGET_STM32F1 */
249270

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+
250282
// Change the RTC current date/time
251283
if (HAL_RTC_SetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN) != HAL_OK) {
252284
error("HAL_RTC_SetDate error\n");
253285
}
254286
if (HAL_RTC_SetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN) != HAL_OK) {
255287
error("HAL_RTC_SetTime error\n");
256288
}
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();
257296
}
258297

259298
int rtc_isenabled(void)
260299
{
261300
#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);
263302
#else /* TARGET_STM32F1 */
264303
return ((RTC->CRL & RTC_CRL_RSF) == RTC_CRL_RSF);
265304
#endif /* TARGET_STM32F1 */
266305
}
267306

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-
}
275307

276308
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
277309

278310
static void RTC_IRQHandler(void);
279311
static void (*irq_handler)(void);
280312

281313
volatile uint8_t lp_Fired = 0;
282-
volatile uint32_t LP_continuous_time = 0;
283-
volatile uint32_t LP_last_RTC_time = 0;
284314

285315
static void RTC_IRQHandler(void)
286316
{
@@ -311,31 +341,34 @@ static void RTC_IRQHandler(void)
311341

312342
uint32_t rtc_read_lp(void)
313343
{
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;
319345

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);
323351

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);
328355
}
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
330362

331363
if (LP_last_RTC_time <= RTC_time_s) {
332364
LP_continuous_time += (RTC_time_s - LP_last_RTC_time);
333365
} else {
366+
/* Add 24h */
334367
LP_continuous_time += (24 * 60 * 60 + RTC_time_s - LP_last_RTC_time);
335368
}
336369
LP_last_RTC_time = RTC_time_s;
337370

338-
return LP_continuous_time * PREDIV_S_VALUE + timeStruct.SecondFraction - timeStruct.SubSeconds;
371+
return LP_continuous_time * PREDIV_S_VALUE + Read_SecondFraction - Read_SubSeconds;
339372
}
340373

341374
void rtc_set_wake_up_timer(timestamp_t timestamp)
@@ -377,7 +410,11 @@ void rtc_fire_interrupt(void)
377410
void rtc_deactivate_wake_up_timer(void)
378411
{
379412
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);
381418
}
382419

383420
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */

targets/TARGET_STM/sleep.c

Lines changed: 0 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -35,7 +35,6 @@
3535
#include "mbed_critical.h"
3636
#include "mbed_error.h"
3737

38-
extern void rtc_synchronize(void);
3938
extern void save_timer_ctx(void);
4039
extern void restore_timer_ctx(void);
4140

@@ -203,17 +202,6 @@ void hal_deepsleep(void)
203202

204203
restore_timer_ctx();
205204

206-
#if DEVICE_RTC
207-
/* Wait for RTC RSF bit synchro if RTC is configured */
208-
#if (TARGET_STM32F2) || (TARGET_STM32F4) || (TARGET_STM32F7)
209-
if (READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL)) {
210-
#else /* (TARGET_STM32F2) || (TARGET_STM32F4) || (TARGET_STM32F7) */
211-
if (__HAL_RCC_GET_RTC_SOURCE()) {
212-
#endif /* (TARGET_STM32F2) || (TARGET_STM32F4) || (TARGET_STM32F7) */
213-
rtc_synchronize();
214-
}
215-
#endif
216-
217205
// Enable IRQs
218206
core_util_critical_section_exit();
219207
}

0 commit comments

Comments
 (0)