Merge pull request #7365 from jeromecoutant/PR_RTC_SHADOW

STM32 RTC : bypass shadow registers
pull/7498/head
Cruz Monrreal 2018-07-11 21:29:02 -05:00 committed by GitHub
commit e1df16e843
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
2 changed files with 108 additions and 83 deletions

View File

@ -33,6 +33,14 @@
#include "rtc_api_hal.h"
#include "mbed_mktime.h"
#include "mbed_error.h"
#include "mbed_critical.h"
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
volatile uint32_t LP_continuous_time = 0;
volatile uint32_t LP_last_RTC_time = 0;
#endif
static int RTC_inited = 0;
static RTC_HandleTypeDef RtcHandle;
@ -41,18 +49,15 @@ void rtc_init(void)
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_PeriphCLKInitTypeDef PeriphClkInitStruct = {0};
if (RTC_inited) {
return;
}
RTC_inited = 1;
// Enable access to Backup domain
__HAL_RCC_PWR_CLK_ENABLE();
HAL_PWR_EnableBkUpAccess();
#if DEVICE_LPTICKER
if ((rtc_isenabled()) && ((RTC->PRER & RTC_PRER_PREDIV_S) == PREDIV_S_VALUE)) {
#else /* DEVICE_LPTICKER */
if (rtc_isenabled()) {
#endif /* DEVICE_LPTICKER */
return;
}
#if MBED_CONF_TARGET_LSE_AVAILABLE
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; // Mandatory, otherwise the PLL is reconfigured!
@ -114,48 +119,20 @@ void rtc_init(void)
error("RTC initialization failed");
}
rtc_synchronize(); // Wait for RSF
if (!rtc_isenabled()) {
rtc_write(0);
#if !(TARGET_STM32F1) && !(TARGET_STM32F2)
/* STM32F1 : there are no shadow registers */
/* STM32F2 : shadow registers can not be bypassed */
if (HAL_RTCEx_EnableBypassShadow(&RtcHandle) != HAL_OK) {
error("EnableBypassShadow error");
}
#endif /* TARGET_STM32F1 || TARGET_STM32F2 */
}
void rtc_free(void)
{
// Disable access to Backup domain
HAL_PWR_DisableBkUpAccess();
/* RTC clock can not be reset */
}
/*
ST RTC_DateTypeDef structure
WeekDay 1=monday, 2=tuesday, ..., 7=sunday
Month 0x1=january, 0x2=february, ..., 0x12=december
Date day of the month 1-31
Year year 0-99
ST RTC_TimeTypeDef structure
Hours 0-12 if the RTC_HourFormat_12 is selected during init
0-23 if the RTC_HourFormat_24 is selected during init
Minutes 0-59
Seconds 0-59
TimeFormat RTC_HOURFORMAT12_AM/RTC_HOURFORMAT12_PM
SubSeconds time unit range between [0-1] Second with [1 Sec / SecondFraction +1] granularity
SecondFraction range or granularity of Sub Second register content corresponding to Synchronous pre-scaler factor value (PREDIV_S)
DayLightSaving RTC_DAYLIGHTSAVING_SUB1H/RTC_DAYLIGHTSAVING_ADD1H/RTC_DAYLIGHTSAVING_NONE
StoreOperation RTC_STOREOPERATION_RESET/RTC_STOREOPERATION_SET
struct tm
tm_sec seconds after the minute 0-61
tm_min minutes after the hour 0-59
tm_hour hours since midnight 0-23
tm_mday day of the month 1-31
tm_mon months since January 0-11
tm_year years since 1900
tm_wday days since Sunday 0-6
tm_yday days since January 1 0-365
tm_isdst Daylight Saving Time flag
*/
/*
Information about STM32F0, STM32F2, STM32F3, STM32F4, STM32F7, STM32L0, STM32L1, STM32L4:
@ -172,7 +149,7 @@ Information about STM32F1:
For date, there is no specific register, only a software structure.
It is then not a problem to not use shifts.
*/
#if TARGET_STM32F1
time_t rtc_read(void)
{
RTC_DateTypeDef dateStruct = {0};
@ -186,7 +163,6 @@ time_t rtc_read(void)
HAL_RTC_GetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN);
#if TARGET_STM32F1
/* date information is null before first write procedure */
/* set 01/01/1970 as default values */
if (dateStruct.Year == 0) {
@ -194,7 +170,6 @@ time_t rtc_read(void)
dateStruct.Month = 1 ;
dateStruct.Date = 1 ;
}
#endif
// Setup a tm structure based on the RTC
/* tm_wday information is ignored by _rtc_maketime */
@ -215,11 +190,57 @@ time_t rtc_read(void)
return t;
}
#else /* TARGET_STM32F1 */
time_t rtc_read(void)
{
struct tm timeinfo;
/* Since the shadow registers are bypassed we have to read the time twice and compare them until both times are the same */
uint32_t Read_time = RTC->TR & RTC_TR_RESERVED_MASK;
uint32_t Read_date = RTC->DR & RTC_DR_RESERVED_MASK;
while ((Read_time != (RTC->TR & RTC_TR_RESERVED_MASK)) || (Read_date != (RTC->DR & RTC_DR_RESERVED_MASK))) {
Read_time = RTC->TR & RTC_TR_RESERVED_MASK;
Read_date = RTC->DR & RTC_DR_RESERVED_MASK;
}
/* Setup a tm structure based on the RTC
struct tm :
tm_sec seconds after the minute 0-61
tm_min minutes after the hour 0-59
tm_hour hours since midnight 0-23
tm_mday day of the month 1-31
tm_mon months since January 0-11
tm_year years since 1900
tm_yday information is ignored by _rtc_maketime
tm_wday information is ignored by _rtc_maketime
tm_isdst information is ignored by _rtc_maketime
*/
timeinfo.tm_mday = RTC_Bcd2ToByte((uint8_t)(Read_date & (RTC_DR_DT | RTC_DR_DU)));
timeinfo.tm_mon = RTC_Bcd2ToByte((uint8_t)((Read_date & (RTC_DR_MT | RTC_DR_MU)) >> 8)) - 1;
timeinfo.tm_year = RTC_Bcd2ToByte((uint8_t)((Read_date & (RTC_DR_YT | RTC_DR_YU)) >> 16)) + 68;
timeinfo.tm_hour = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_HT | RTC_TR_HU)) >> 16));
timeinfo.tm_min = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_MNT | RTC_TR_MNU)) >> 8));
timeinfo.tm_sec = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_ST | RTC_TR_SU)) >> 0));
// Convert to timestamp
time_t t;
if (_rtc_maketime(&timeinfo, &t, RTC_4_YEAR_LEAP_YEAR_SUPPORT) == false) {
return 0;
}
return t;
}
#endif /* TARGET_STM32F1 */
void rtc_write(time_t t)
{
RTC_DateTypeDef dateStruct = {0};
RTC_TimeTypeDef timeStruct = {0};
core_util_critical_section_enter();
RtcHandle.Instance = RTC;
// Convert the time into a tm
@ -247,6 +268,17 @@ void rtc_write(time_t t)
timeStruct.StoreOperation = RTC_STOREOPERATION_RESET;
#endif /* TARGET_STM32F1 */
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
/* Need to update LP_continuous_time value before new RTC time */
uint32_t current_lp_time = rtc_read_lp();
/* LP_last_RTC_time value is updated with the new RTC time */
LP_last_RTC_time = timeStruct.Seconds + timeStruct.Minutes * 60 + timeStruct.Hours * 60 * 60;
/* Save current SSR */
uint32_t Read_SubSeconds = (uint32_t)(RTC->SSR);
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
// Change the RTC current date/time
if (HAL_RTC_SetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN) != HAL_OK) {
error("HAL_RTC_SetDate error\n");
@ -254,24 +286,24 @@ void rtc_write(time_t t)
if (HAL_RTC_SetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN) != HAL_OK) {
error("HAL_RTC_SetTime error\n");
}
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
while (Read_SubSeconds != (RTC->SSR)) {
}
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */
core_util_critical_section_exit();
}
int rtc_isenabled(void)
{
#if !(TARGET_STM32F1)
return (((RTC->ISR & RTC_ISR_INITS) == RTC_ISR_INITS) && ((RTC->ISR & RTC_ISR_RSF) == RTC_ISR_RSF));
return ((RTC->ISR & RTC_ISR_INITS) == RTC_ISR_INITS);
#else /* TARGET_STM32F1 */
return ((RTC->CRL & RTC_CRL_RSF) == RTC_CRL_RSF);
#endif /* TARGET_STM32F1 */
}
void rtc_synchronize(void)
{
RtcHandle.Instance = RTC;
if (HAL_RTC_WaitForSynchro(&RtcHandle) != HAL_OK) {
error("rtc_synchronize error\n");
}
}
#if DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM
@ -279,8 +311,6 @@ static void RTC_IRQHandler(void);
static void (*irq_handler)(void);
volatile uint8_t lp_Fired = 0;
volatile uint32_t LP_continuous_time = 0;
volatile uint32_t LP_last_RTC_time = 0;
static void RTC_IRQHandler(void)
{
@ -311,31 +341,34 @@ static void RTC_IRQHandler(void)
uint32_t rtc_read_lp(void)
{
RTC_TimeTypeDef timeStruct = {0};
RTC_DateTypeDef dateStruct = {0};
struct tm timeinfo;
RtcHandle.Instance = RTC;
HAL_RTC_GetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN);
/* Since the shadow registers are bypassed we have to read the time twice and compare them until both times are the same */
/* We don't have to read date as we bypass shadow registers */
uint32_t Read_SecondFraction = (uint32_t)(RTC->PRER & RTC_PRER_PREDIV_S);
uint32_t Read_time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
uint32_t Read_SubSeconds = (uint32_t)(RTC->SSR);
/* Reading RTC current time locks the values in calendar shadow registers until Current date is read
to ensure consistency between the time and date values */
HAL_RTC_GetDate(&RtcHandle, &dateStruct, RTC_FORMAT_BIN);
if (timeStruct.SubSeconds > timeStruct.SecondFraction) {
/* SS can be larger than PREDIV_S only after a shift operation. In that case, the correct
time/date is one second less than as indicated by RTC_TR/RTC_DR. */
timeStruct.Seconds -= 1;
while ((Read_time != (RTC->TR & RTC_TR_RESERVED_MASK)) || (Read_SubSeconds != (RTC->SSR))) {
Read_time = (uint32_t)(RTC->TR & RTC_TR_RESERVED_MASK);
Read_SubSeconds = (uint32_t)(RTC->SSR);
}
uint32_t RTC_time_s = timeStruct.Seconds + timeStruct.Minutes * 60 + timeStruct.Hours * 60 * 60; // Max 0x0001-517F => * 8191 + 8191 = 0x2A2E-AE80
timeinfo.tm_hour = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_HT | RTC_TR_HU)) >> 16));
timeinfo.tm_min = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_MNT | RTC_TR_MNU)) >> 8));
timeinfo.tm_sec = RTC_Bcd2ToByte((uint8_t)((Read_time & (RTC_TR_ST | RTC_TR_SU)) >> 0));
uint32_t RTC_time_s = timeinfo.tm_sec + timeinfo.tm_min * 60 + timeinfo.tm_hour * 60 * 60; // Max 0x0001-517F => * 8191 + 8191 = 0x2A2E-AE80
if (LP_last_RTC_time <= RTC_time_s) {
LP_continuous_time += (RTC_time_s - LP_last_RTC_time);
} else {
/* Add 24h */
LP_continuous_time += (24 * 60 * 60 + RTC_time_s - LP_last_RTC_time);
}
LP_last_RTC_time = RTC_time_s;
return LP_continuous_time * PREDIV_S_VALUE + timeStruct.SecondFraction - timeStruct.SubSeconds;
return LP_continuous_time * PREDIV_S_VALUE + Read_SecondFraction - Read_SubSeconds;
}
void rtc_set_wake_up_timer(timestamp_t timestamp)
@ -377,7 +410,11 @@ void rtc_fire_interrupt(void)
void rtc_deactivate_wake_up_timer(void)
{
RtcHandle.Instance = RTC;
HAL_RTCEx_DeactivateWakeUpTimer(&RtcHandle);
__HAL_RTC_WRITEPROTECTION_DISABLE(&RtcHandle);
__HAL_RTC_WAKEUPTIMER_DISABLE(&RtcHandle);
__HAL_RTC_WAKEUPTIMER_DISABLE_IT(&RtcHandle, RTC_IT_WUT);
__HAL_RTC_WRITEPROTECTION_ENABLE(&RtcHandle);
NVIC_DisableIRQ(RTC_WKUP_IRQn);
}
#endif /* DEVICE_LPTICKER && !MBED_CONF_TARGET_LPTICKER_LPTIM */

View File

@ -35,7 +35,6 @@
#include "mbed_critical.h"
#include "mbed_error.h"
extern void rtc_synchronize(void);
extern void save_timer_ctx(void);
extern void restore_timer_ctx(void);
@ -203,17 +202,6 @@ void hal_deepsleep(void)
restore_timer_ctx();
#if DEVICE_RTC
/* Wait for RTC RSF bit synchro if RTC is configured */
#if (TARGET_STM32F2) || (TARGET_STM32F4) || (TARGET_STM32F7)
if (READ_BIT(RCC->BDCR, RCC_BDCR_RTCSEL)) {
#else /* (TARGET_STM32F2) || (TARGET_STM32F4) || (TARGET_STM32F7) */
if (__HAL_RCC_GET_RTC_SOURCE()) {
#endif /* (TARGET_STM32F2) || (TARGET_STM32F4) || (TARGET_STM32F7) */
rtc_synchronize();
}
#endif
// Enable IRQs
core_util_critical_section_exit();
}