Question
STM32H753 and RTC return wrong day
In my project I want to use RTC on STM32H753 chip. And when reading the date, I get the wrong data in the position of days. And I can't fix this problem. When I debug, the registers are set successfully. :face_with_rolling_eyes:
Init function:
void BSP__RTC_InitAndRead(void)
{
FLAG GoReadRTC;
// defaults
memset((void*) &BSP_RTC_Time, 0, sizeof(BSP_RTC_Time_t));
// note. RTC clock enable is in H7_BSP_MCUCLK
// assume RTC has a valid timestamp in it
GoReadRTC = TRUE;
// HSE?
if (FALSE == HSE_FAILURE_status)
{
// yes, HSE is ready
// check clock source
if (LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_HSE)
{
// we will reset the RTC
GoReadRTC = FALSE;
// Set by software to select the clock source for the RTC. These bits can be written only one time
// (except in case of failure detection on LSE). These bits must be written before LSECSSON is
// enabled. The BDRST bit can be used to reset them, then it can be written one time again.
// LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_HSE); -> see few lines lower
};
// (re-)enable it again
LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_HSE); // re-enable...
LL_RCC_SetRTC_HSEPrescaler(LL_RCC_RTC_HSE_DIV_25); // always repeat the HSE prescaler configuration
} else
{
if (LL_RCC_GetRTCClockSource() != LL_RCC_RTC_CLKSOURCE_LSI)
{
// full configuration
GoReadRTC = FALSE;
}
LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSI); // re-enable...
}
// After a system reset, the application can read the INITS flag in the RTC_ISR register to
// check if the calendar has been initialized or not. If this flag equals 0, the calendar has not
// been initialized since the year field is set at its Backup domain reset default value (0x00).
// 1: if not active INITS
// rtc is not config
// 2: if active RCC_CSR bit PORRSTF
// Start up RTC
if ( (0 == LL_RTC_IsActiveFlag_INITS(RTC)) ||
(resetReason & RCC_RSR_PORRSTF)
)
{
GoReadRTC = FALSE;
}
//
if (GoReadRTC)
{
// always to be sure
EnableBKPdomain();
// Enable RTC Clock
LL_RCC_EnableRTC();
// To read the calendar after initialization,
// the software must first check that the RSF flag is set in the RTC_ISR register.
// -> always done while reading from RTC -> OK
// info
BSP_RTC_was_running = TRUE;
// set info
BSP_RTC_Status = TRUE;
// set info: HW is ready
BSP_RTCready = TRUE;
// application can now read RTC contents any time it wants
} else
{
// info
BSP_RTC_was_running = FALSE;
// set info
BSP_RTC_Status = FALSE;
// INIT REQUIRED
LL_RTC_InitTypeDef RTC_InitStruct = {0};
LL_RTC_TimeTypeDef RTC_TimeStruct = {0};
LL_RTC_DateTypeDef RTC_DateStruct = {0};
// A software reset, triggered by setting BDRST bit in the RCC Backup Domain Control
// Register (RCC_BDCR). All RTC registers and the RCC_BDCR register are reset to
// their default values. When a Backup domain reset occurs, the RTC is stopped and all
// the RTC registers are set to their reset values.
// *** The backup RAM is not affected. ***
LL_RCC_ForceBackupDomainReset();
LL_RCC_ReleaseBackupDomainReset();
// because of BKP Domain reset -> we have to re-enable the access to the BKP Domain
// (previously enabled in SystemClock_Config)
EnableBKPdomain();
if (FALSE == HSE_FAILURE_status) {
LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_HSE);
LL_RCC_SetRTC_HSEPrescaler(LL_RCC_RTC_HSE_DIV_25);
} else {
LL_RCC_SetRTCClockSource(LL_RCC_RTC_CLKSOURCE_LSI);
}
// deinit
LL_RCC_EnableRTC(); // musi se zavolat pred deinitem !
LL_RTC_DeInit(RTC);
// RTC CLOCK
LL_RTC_StructInit(&RTC_InitStruct);
RTC_InitStruct.HourFormat = LL_RTC_HOURFORMAT_24HOUR;
if (FALSE == HSE_FAILURE_status)
{
// HSE / 25 => 1 MHz
RTC_InitStruct.AsynchPrescaler = 125 - 1; // ck_apre = 8000
RTC_InitStruct.SynchPrescaler = 8000 - 1; // (1MHz / 125) - 1 = 7999 // ck_spre = 1 Hz
} else
{
// LSI -> approx 32kHz
RTC_InitStruct.AsynchPrescaler = 0x1F; // 31+1
RTC_InitStruct.SynchPrescaler = 0x3E8; // 999+1
}
LL_RTC_Init(RTC, &RTC_InitStruct);
// Enable RTC Clock
LL_RCC_EnableRTC();
// Initialize RTC and set the Time and Date
LL_RTC_TIME_StructInit(&RTC_TimeStruct);
RTC_TimeStruct.Hours = 0x0;
RTC_TimeStruct.Minutes = 0x0;
RTC_TimeStruct.Seconds = 0x0;
LL_RTC_TIME_Init(RTC, LL_RTC_FORMAT_BIN, &RTC_TimeStruct);
LL_RTC_DATE_StructInit(&RTC_DateStruct);
RTC_DateStruct.WeekDay = LL_RTC_WEEKDAY_MONDAY;
RTC_DateStruct.Month = LL_RTC_MONTH_JANUARY;
RTC_DateStruct.Day = 0x1;
RTC_DateStruct.Year = 22; // 0..99
LL_RTC_DATE_Init(RTC, LL_RTC_FORMAT_BIN, &RTC_DateStruct);
// set info: HW is ready
BSP_RTCready = TRUE;
}
// disable ALARM
if (BSP_RTCready)
{
LL_RTC_DisableWriteProtection(RTC);
LL_RTC_ClearFlag_ALRA(RTC);
LL_RTC_DisableIT_ALRA(RTC);
LL_RTC_ALMA_Disable(RTC);
LL_RTC_EnableWriteProtection(RTC);
}
if (BSP_RTCready)
{
// start - make sure to fill the GlobalTime once, right now
BSP_gt_last_msec = BSP_GetTick() + 1024;
BSP_RTCtime_Is_Requested(TRUE);
}
}
And my reading function
void BSP_RTC_GetDateTime(BSP_RTC_Time_t *data)
{
uint32_t rtc_date, rtc_time;
uint32_t rtc_date2, rtc_time2;
uint32_t TimeOut;
//
if (FALSE == IsPtrValid((void *)data))
{
return;
}
// always clear
memset((void *)data, 0, sizeof(BSP_RTC_Time_t));
// RTC initialized ?
if (FALSE == BSP_RTCready)
{
return;
}
//
MP_BSP_GetRTCmutex();
// RSF must be cleared by software after the first calendar read, and
// then the software must wait until RSF is set before reading again the RTC_SSR, RTC_TR
// and RTC_DR registers.
LL_RTC_ClearFlag_RS(RTC);
TimeOut = 0x00FFFFFF;
while (0 == LL_RTC_IsActiveFlag_RS(RTC))
{
if (0 == TimeOut) break; // pokud to dojede na timeout, je spatne inicializovany clock pro RTC !
TimeOut--;
}
// The software must read all the registers twice, and then
// compare the results to confirm that the data is coherent and correct.
/* Read time and date registers in BCD format */
rtc_time = LL_RTC_TIME_Get(RTC);
rtc_time2 = LL_RTC_TIME_Get(RTC);
if (rtc_time != rtc_time2)
{
rtc_time = LL_RTC_TIME_Get(RTC);
}
rtc_date = LL_RTC_DATE_Get(RTC);
rtc_date2 = LL_RTC_DATE_Get(RTC);
if (rtc_date != rtc_date2)
{
rtc_date = LL_RTC_DATE_Get(RTC);
}
//
LL_RTC_ClearFlag_RS(RTC);
//
MP_BSP_GiveRTCmutex();
//
memset((void*)data, 0, sizeof(BSP_RTC_Time_t));
//
data->year = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_YEAR(rtc_date));
data->month = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_MONTH(rtc_date));
data->day = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_DAY(rtc_date));
//
data->hours = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_HOUR(rtc_time));
data->minutes = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_MINUTE(rtc_time));
data->seconds = __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_SECOND(rtc_time));
}
and for setting rtc is here c code
void BSP_RTC_SetDateTime(const BSP_RTC_Time_t *data)
{
LL_RTC_TimeTypeDef RTC_TimeStruct;
LL_RTC_DateTypeDef RTC_DateStruct;
// RTC initialized ? or invalid ARG ?
if ((FALSE == BSP_RTCready)||(FALSE == IsPtrValid((void *)data)))
{
return;
}
// go
//
MP_BSP_GetRTCmutex();
// write in BIN format
LL_RTC_TIME_StructInit(&RTC_TimeStruct);
RTC_TimeStruct.TimeFormat = LL_RTC_TIME_FORMAT_AM_OR_24;
RTC_TimeStruct.Hours = data->hours;
RTC_TimeStruct.Minutes = data->minutes;
RTC_TimeStruct.Seconds = data->seconds;
// write in BIN format
LL_RTC_DATE_StructInit(&RTC_DateStruct);
RTC_DateStruct.Day = data->day;
RTC_DateStruct.Month = data->month;
RTC_DateStruct.Year = data->year;
RTC_DateStruct.WeekDay = data->day_in_week;
// write in BIN format
if (LL_RTC_DATE_Init(RTC, LL_RTC_FORMAT_BIN, &RTC_DateStruct) != 0) {
errprint(">> Write date failed");
}
if (LL_RTC_TIME_Init(RTC, LL_RTC_FORMAT_BIN, &RTC_TimeStruct) != 0) {
errprint(">> Write time failed");
}
// we got new time -> RTC is valid
BSP_RTC_Status = TRUE;
//
MP_BSP_GiveRTCmutex();
}
