mbed library sources. Supersedes mbed-src.

Dependents:   Nucleo_Hello_Encoder BLE_iBeaconScan AM1805_DEMO DISCO-F429ZI_ExportTemplate1 ... more

Revision:
187:0387e8f68319
Parent:
186:707f6e361f3e
Child:
188:bcfe06ba3d64
--- a/targets/TARGET_STM/rtc_api.c	Fri Jun 22 16:45:37 2018 +0100
+++ b/targets/TARGET_STM/rtc_api.c	Thu Sep 06 13:40:20 2018 +0100
@@ -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 @@
     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 @@
         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 @@
 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 @@
     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 @@
         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 @@
     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
@@ -229,8 +250,8 @@
     }
 
     // Fill RTC structures
-    if (timeinfo.tm_wday == 0) {
-        dateStruct.WeekDay    = 7;
+    if (timeinfo.tm_wday == 0) { /* Sunday specific case */
+        dateStruct.WeekDay    = RTC_WEEKDAY_SUNDAY;
     } else {
         dateStruct.WeekDay    = timeinfo.tm_wday;
     }
@@ -247,6 +268,17 @@
     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 */
+    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 @@
     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,16 +311,14 @@
 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)
 {
     /*  Update HAL state */
     RtcHandle.Instance = RTC;
-    if(__HAL_RTC_WAKEUPTIMER_GET_IT(&RtcHandle, RTC_IT_WUT)) {
+    if (__HAL_RTC_WAKEUPTIMER_GET_IT(&RtcHandle, RTC_IT_WUT)) {
         /* Get the status of the Interrupt */
-        if((uint32_t)(RTC->CR & RTC_IT_WUT) != (uint32_t)RESET) {
+        if ((uint32_t)(RTC->CR & RTC_IT_WUT) != (uint32_t)RESET) {
             /* Clear the WAKEUPTIMER interrupt pending bit */
             __HAL_RTC_WAKEUPTIMER_CLEAR_FLAG(&RtcHandle, RTC_FLAG_WUTF);
 
@@ -311,31 +341,34 @@
 
 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);
+    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);
+    }
 
-    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;
-    }
-    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_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 */