STM32 gotchas
198. RTC at midnight does not roll over, but goes to 24:00:00 and counts up

Observations in this article refer to RTCv2, although it's quite likely they apply also to RTCv3 in calendar mode.

If the RTC is set to 12-hour (AM/PM) mode (by setting RTC_CR.FMT = 1), and then the hour field in RTC_TR is set to a value above 12, the clock will run up to 23:59:59, but then upon the next second it will turn to 24:00:00 (rather than roll over to 00:00:00). The date is not incremented at this moment, either.

After that, RTC will continue to clock up to 39:59:59, and only after that it rolls over to 00:00:00. Date is incremented after that "late" rollover, too. After that, the RTC keeps running up to 12:59:59 PM, when it rolls over to 01:00:00 AM, as is normal in the 12-clock mode1.

Of course, one would not set RTC to 12-hour mode and then set time to above 12 hours, so how could this happen?

One mechanism, how RTC_CR.FMT can get inadvertently set is through using uninitialized structs in calling Cube/HAL functions which write into RTC_CR. Another mechanism is the possible corruption of RTC registers due to VBAT brownout.

By the way, other RTC calendar fields behave similarly in that if they are inadvertently set beyond their normal range, they continue to be incremented until they roll over "naturally" due to number of bits. For example, after setting seconds to 61 they keep counting up to 79 after which the seconds "naturally" roll over to 00 2. Such incorrectly set calendar field can again occur due to incompletely set initialization structs when using Cube/HAL functions.

Note, that Cube/HAL functions, which read the calendar date/time, don't guarantee that the structs used will have all their fields filled in; so reading date/time into an uninitialized struct, modifying it, and writing it back may also result in writing unexpected values into some of the time/date register fields.


1. As an example, one of the many related threads reporting such behaviour here.

2. Don't forget, that the calendar fields don't count in binary, but in binary-coded-decimal (BCD). So, for this seconds example, the 4-bit wide RTC_TR.SU field counts from 0 to 9, and the 3-bit wide RTC_TR.ST field counts from 6 to 7 (normally, it would count from 0 to 5).
There's another, less obvious consequence of the RTC calendar fields being BCD - if such incorrectly set BCD field is used in a calculation which converts BCD to binary and adds the fields up to an "epoch"-style value, depending on how exactly that conversion is performed, the results may be wildly off with little clue to the underlying problem.