Skip to content

Commit 1052993

Browse files
committed
STM32 RTC : bypass shadow registers
- RTC_SSR for the subseconds - RTC_TR for the time - RTC_DR for the date These registers were accessed through shadow registers which are synchronized with PCLK1 (APB1 clock). They are now accessed directly in order to avoid waiting for the synchronization duration.
1 parent 61f3d8b commit 1052993

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)