cancel
Showing results for 
Search instead for 
Did you mean: 

[bug report] STM32F1xx HAL RTC date functions are very wrong

Kazimierz Król
Associate III

Hi, sorry for the blatant title, but in this case it's justified.

The RTC functions are not just wrong. They are wrong in such a way that pretends to be good, may pass most of tests, and makes finding what's really going on a lot harder.

I am working STM32F107VC CPU, and the problematic HAL file is stm32f1xx_hal_rtc.c (firmware package version 1.8.4).

Symptom: if I set the date and time using HAL_RTC_SetTime/SetDate, and then read it back, it works fine. But when the device is powered off and on (I have a backup battery), only the time will be correct, and the date will be reset to zero.

That is because the HAL_RTC_SetDate function does not really set the date in the RTC hardware, only in the RTC_HandleTypeDef struct fields, namely DateToUpdate field. Please look into the function, and you will notice, that DateToUpdate fields are set according to the sDate parameter, then WeekDay is calculated from them, but they are never used in this function after that point. The hardware RTC counter is read, then:

  • if the hours are higher than 24, they are stripped (the date is removed), and the counter without the date is written back to the RTC counter,
  • if the hours are less than 24, the RTC counter is not updated at all.

Second problem: RTC_GetDate reads back the RTC_HandleTypeDef fields for the date instead of the hardware counter. The function actually reads the RTC counter into stime variable, but then does nothing with that variable. The comment suggests that HAL_RTC_GetTime should update the DateToUpdate field to the date read from RTC counter, and it does, but not always. The function RTC_DateUpdate is called only if the RTC counter days are higher than zero. But during normal operation the RTC counter days are rarely higher than zero, because HAL_RTC_SetDate resets them every time it is called.

But what happens if we leave the device powered off for longer than a day, so the RTC counter days will naturally become higher than zero? Here comes the biggest problem: HAL_RTC_GetTime resets the days to zero on every read - why? Why does the reading function even contains code to write RTC counter? This does not make any sense at all! HAL_RTC_GetTime contains similar core to HAL_RTC_SetDate, that will strip the days from the RTC hardware counter and write it back, effectively resetting the date on every read.

Concluding, the functions are written in the way that if your device is powered all the time, you will probably get the real date, because the functions seem to keep the date in the RTC_HandleTypeDef fields and update it accordingly. The problem will arise when your device is disconnected from power and RTC runs on the backup battery, because the RTC hardware date is never updated correctly - the functions keep resetting it on every occasion.

1 ACCEPTED SOLUTION

Accepted Solutions

Just don't use Cube/HAL.

Use the RTC in the usual epoch manner, and use the standard <time.h> functions to convert that to calendar.

JW

View solution in original post

5 REPLIES 5
ALABSTM
ST Employee

Hi @Kazimierz Król​,

Thank you for this clear and detailed report. Rather than speaking about a bug I would say limitation.

Indeed, it is indicated in the ##### WARNING: Drivers Restrictions ##### section (link) of the stm32f1xx_hal_rtc.c file that:

  • Date is saved in SRAM. Then, when MCU is in STOP or STANDBY mode, date will be lost.
  • User should implement a way to save the date.
  • An example (link) is provided inside the firmware package showing how to use the backup registers.

This is due to the way the RTC is implemented on the STM32F1xx series (no specific hardware register to keep track of the date, rather a counter incrementing each "second", from which software calculates time and date).

Regarding the way HAL_RTC_GetTime() is implemented, the purpose is to keep the RTC counter limited to 24 hours. As you mentioned, each time HAL_RTC_GetDate() is called, it calls HAL_RTC_GetTime() (link), which will:

  • strip the days from the RTC hardware counter then write it back with the remainder time value (link),
  • add the days to the days value already in RAM (link).

I hope this answers your questions and makes things clearer.

With regards,

Just don't use Cube/HAL.

Use the RTC in the usual epoch manner, and use the standard <time.h> functions to convert that to calendar.

JW

Thank you for the explanation, I must have overlooked the warning. I apologize for the critical tone of my post.

However, I don't see any reason why the date keeping couldn't be implemented. I did it myself on the STM32F107VC, and it works just fine. There are two 16-bit counters, which gives 32 bits combined, so they can keep both time and date as a Unix timestamp (possibly with a different epoch to prolong the counting life).

Could we turn this into a feature request than?

Also, using battery backup registers to keep track of the date will work only if the device is powered on at least once a day. If it's powered off for more than a day, the date will be wrong, which is unacceptable. Why the library author didn't use the built-in counter to keep track of the date along with the time? It would be the most natural and effective solution.

Thanks, already did that. The post was to let ST know about the problem.

This has historical roots, the RTC was handled in this weird way already in the SPL library back then when 'F1 were new.

JW