diff --git a/targets/TARGET_STM/lp_ticker.c b/targets/TARGET_STM/lp_ticker.c index 3404994aa7..7b12b34736 100644 --- a/targets/TARGET_STM/lp_ticker.c +++ b/targets/TARGET_STM/lp_ticker.c @@ -292,15 +292,8 @@ void lp_ticker_init(void) uint32_t lp_ticker_read(void) { - uint32_t usecs = 0; - time_t time = 0; - - do { - time = rtc_read(); - usecs = rtc_read_subseconds(); - } while (time != rtc_read()); - - return (time * 1000000) + usecs; + uint32_t usecs = rtc_read_us(); + return usecs; } void lp_ticker_set_interrupt(timestamp_t timestamp) diff --git a/targets/TARGET_STM/rtc_api.c b/targets/TARGET_STM/rtc_api.c index 9e91753c86..50e273c5ba 100644 --- a/targets/TARGET_STM/rtc_api.c +++ b/targets/TARGET_STM/rtc_api.c @@ -36,8 +36,12 @@ static RTC_HandleTypeDef RtcHandle; #if DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM + +#define GET_TICK_PERIOD(VALUE) (2048 * 1000000 / VALUE) /* 1s / SynchPrediv value * 2^11 (value to get the maximum precision value with no u32 overflow) */ + static void (*irq_handler)(void); static void RTC_IRQHandler(void); +static uint32_t lp_TickPeriod_us = GET_TICK_PERIOD(4095); /* default SynchPrediv value = 4095 */ #endif /* DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM */ void rtc_init(void) @@ -123,6 +127,10 @@ void rtc_init(void) RtcHandle.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN; #endif /* TARGET_STM32F1 */ +#if DEVICE_LOWPOWERTIMER && !MBED_CONF_TARGET_LOWPOWERTIMER_LPTIM + lp_TickPeriod_us = GET_TICK_PERIOD(RtcHandle.Init.SynchPrediv); +#endif + if (HAL_RTC_Init(&RtcHandle) != HAL_OK) { error("RTC initialization failed"); } @@ -306,9 +314,27 @@ static void RTC_IRQHandler(void) } } -uint32_t rtc_read_subseconds(void) +uint32_t rtc_read_us(void) { - return 1000000.f * ((double)((RTC->PRER & RTC_PRER_PREDIV_S) - RTC->SSR) / ((RTC->PRER & RTC_PRER_PREDIV_S) + 1)); + RTC_TimeTypeDef timeStruct = {0}; + RTC_DateTypeDef dateStruct = {0}; + + RtcHandle.Instance = RTC; + HAL_RTC_GetTime(&RtcHandle, &timeStruct, RTC_FORMAT_BIN); + + /* 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; + } + uint32_t RTCTime = timeStruct.Seconds + timeStruct.Minutes * 60 + timeStruct.Hours * 60 * 60; + uint32_t Time_us = ((timeStruct.SecondFraction - timeStruct.SubSeconds) * lp_TickPeriod_us) >> 11; + + return (RTCTime * 1000000) + Time_us ; } void rtc_set_wake_up_timer(uint32_t delta) diff --git a/targets/TARGET_STM/rtc_api_hal.h b/targets/TARGET_STM/rtc_api_hal.h index 5013b3bbeb..ff1722a0e8 100644 --- a/targets/TARGET_STM/rtc_api_hal.h +++ b/targets/TARGET_STM/rtc_api_hal.h @@ -51,11 +51,11 @@ extern "C" { #define RTC_CLOCK LSI_VALUE #endif -/** Read the subsecond register. +/** Read RTC time with subsecond precision. * - * @return The remaining time as microseconds (0-999999) + * @return Time is microsecond */ -uint32_t rtc_read_subseconds(void); +uint32_t rtc_read_us(void); /** Program a wake up timer event in delta microseconds. *