STM32 RTCs store year as last 2 digits. They also have a primitive leap-year calculation that only checks remainder of 4.
So the year will go from 0 to 99 and then wrap (overflow). So a fixed offset of 2000 means the year will fail at 2100.
Also leap years will fail in 2100 as 2100 is seen as a leap year, when it's not.
So they have two year-2100 problems.
I have a fix for both:
- Use build year to calculate current year. Will work from build year to buildyear + 99, then it will overflow to buildyear. So the program will fail in 100 years (in 2125) instead of 75 years (2100).
- if year in RTC is 00 and date is 29 feb, then jump to march 1st. This fixes leap years until 2399 since 2100, 2200 and 2300 are not leap years. Will fail in 2400 instead of 2100.
run this before processing rtc dates:
HAL_RTC_GetTime(&hrtc, &systemTimeTemp, RTC_FORMAT_BIN);
HAL_RTC_GetDate(&hrtc, &systemDateTemp, RTC_FORMAT_BIN); // Always call GetDate after GetTime (RTC locking)
//leap year correction to allow proper leap year until 2400
if (systemDateTemp.Year == 0 && systemDateTemp.Month == 2 && systemDateTemp.Date == 29)
{
//skip leap year as year is multiple of 100, but not multiple of 400
systemDateTemp.Month = 3;
systemDateTemp.Date = 1;
__disable_irq();
SystemTime = systemTimeTemp;
SystemDate = systemDateTemp;
__enable_irq();
HAL_RTC_SetTime(&hrtc, &SystemTime, RTC_FORMAT_BIN);
HAL_RTC_SetDate(&hrtc, &SystemDate, RTC_FORMAT_BIN);
}
else
{
__disable_irq();
SystemTime = systemTimeTemp;
SystemDate = systemDateTemp;
__enable_irq();
}
(Note that this only works if the routine is run every 24 hours. So if the device is not turned on when it thinks there is a leap year (monday march 1st 2100) it won't work. You would need some algorithm to flag if it skipped the leap day that year. You could probably use some spare RTC memory for this. So if it is after march 1st and this flag has not been set, then you should add 1 day to the date and set that flag. Clear the flag if the date is before feb 29 or if it is not 2100, 2200 or 2300. An alternative algorithm would keep the date in the calendar invalid and add an offset of 1 day to a copy.)
Use this to convert RTC year to absolute year:
#define DATE_TO_YEAR(d) (d[7] == '?' ? 1900 : \
(((d[7] - '0') * 1000 ) + (d[8] - '0') * 100 + (d[9] - '0') * 10 + d[10] -'0'))
#define BUILD_YEAR DATE_TO_YEAR(__DATE__)
// allow operation beyond 2099 (up to BUILD_YEAR + 99)
uint16_t yearAbs = systemDateCopy.Year + (BUILD_YEAR/100)*100;
if (yearAbs < BUILD_YEAR)
{
yearAbs += 100;
}
If you want the program to work longer you need to periodically update the firmware to update the build date. Or you store the year in eeprom every year. RTC battery will fail before 2100. But you can always replace the battery and set the time again. It would be nice if products made now won't be automatically obsolete in 2100.
"Kudo posts if you have the same problem and kudo replies if the solution works.Click ""Accept as Solution"" if a reply solved your problem. If no solution was posted please answer with your own."