32F417 RTC errata sheet if reading subseconds - is this code ok?
I am referring to the bug whereby the shadowing of the date/time registers is very occassionally broken if the sync prescaler was read beforehand.
That reading order is exactly what the ST HAL functions do. See below.
HAL_RTC_GetTime reads the SSR and the time.
HAL_RTC_GetDate reads the date.
I have been doing tests and reading the RTC at 5Hz it fails once every few hours; then my code below reads the whole lot again.
int getrtc (struct tm * mytime)
{
RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef sDate = {0};
int rtcret1=0;
int rtcret2=0;
RTC_Lock();
// Implement RTC errata sheet (SSR needs reading before and after date/time and compared, until same)
uint32_t last_subsec;
volatile uint32_t errorcnt=0; // for doing a breakpoint
do
{
last_subsec = (uint32_t)(hrtc.Instance->SSR);
// Always read both, even if 1st returns an error
rtcret1 = HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN);
rtcret2 = HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN);
errorcnt++;
}
while (last_subsec != sTime.SubSeconds);
RTC_Unlock();
if ( (rtcret1!=0) || (rtcret2!=0))
return 2;
// Convert the 32F4 RTC API to the K&R standard C clock structure "tm"
// Comments in setrtc above
// No error checking - would be meaningless
mytime->tm_year = sDate.Year+100;
mytime->tm_mon = sDate.Month-1;
mytime->tm_mday = sDate.Date;
mytime->tm_wday = sDate.WeekDay; // assume the RTC maintained the day of week correctly
if (sDate.WeekDay==7) mytime->tm_wday = 0;
mytime->tm_hour = sTime.Hours;
mytime->tm_min = sTime.Minutes;
mytime->tm_sec = sTime.Seconds;
// Load subseconds into a global variable, as microseconds
// There were problems with this when using the SHIFTR method to advance the RTC...
g_SubSeconds = ((RTC_SYNC_PREDIV-sTime.SubSeconds)*1000000L)/(RTC_SYNC_PREDIV+1);
// Calculate day of year from the date, because that doesn't come from the RTC.
mytime->tm_yday = day_of_year(mytime->tm_mday, mytime->tm_mon, mytime->tm_year);
// Return -1 for daylight saving, as per K&R
mytime->tm_isdst = -1;
return 0;
}
