cancel
Showing results for 
Search instead for 
Did you mean: 

STM32H753 and RTC return wrong day

Pilous Droip
Senior

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();

}

 

 

 

 

 

8 REPLIES 8
AScha.3
Chief III

First, you should re-order the reading , read this from HAL lib:

>

@note You must call HAL_RTC_GetDate() after HAL_RTC_GetTime() to unlock the values

in the higher-order calendar shadow registers to ensure consistency between the time and date values.

<

So read xx_time , xx_date

 

	/* Read time and date registers in BCD format */

	rtc_time = LL_RTC_TIME_Get(RTC);
        rtc_date = LL_RTC_DATE_Get(RTC);
	rtc_time2 = LL_RTC_TIME_Get(RTC);
        rtc_date2 = LL_RTC_DATE_Get(RTC);

 

If you feel a post has answered your question, please click "Accept as Solution".

Hi AScha.3

since i am not using HAL so I copied these functions and used my internal function.

 

void BSP_RTC_GetDateTime(BSP_RTC_Time_t *data)
{
        // always clear
    memset((void*) data, 0, sizeof(BSP_RTC_Time_t));

    MP_BSP_GetRTCmutex();

    uint32_t tmpreg;

    // [DATE]

    uint32_t rtc_dr_reserved_mask = (RTC_DR_YT | RTC_DR_YU | RTC_DR_WDU | RTC_DR_MT | RTC_DR_MU | RTC_DR_DT | RTC_DR_DU);

    /* Get the DR register */
    tmpreg = (uint32_t) (RTC->DR & rtc_dr_reserved_mask);

    /* Fill the structure fields with the read parameters */
    data->year = (uint8_t) ((tmpreg & (RTC_DR_YT | RTC_DR_YU)) >> RTC_DR_YU_Pos);
    data->month = (uint8_t) ((tmpreg & (RTC_DR_MT | RTC_DR_MU)) >> RTC_DR_MU_Pos);
    data->day = (uint8_t) ((tmpreg & (RTC_DR_DT | RTC_DR_DU)) >> RTC_DR_DU_Pos);
    data->day_in_week = (uint8_t) ((tmpreg & (RTC_DR_WDU)) >> RTC_DR_WDU_Pos);

    uint8_t tmp;
    /* Convert the date structure parameters to Binary format */
    tmp = ((data->year & 0xF0U) >> 4U) * 10U;
    data->year = (tmp + (data->year & 0x0FU));

    tmp = ((data->month & 0xF0U) >> 4U) * 10U;
    data->month = (tmp + (data->month & 0x0FU));

    tmp = ((data->day & 0xF0U) >> 4U) * 10U;
    data->day = (tmp + (data->day & 0x0FU));

    // [TIME]

    uint32_t rtc_tr_reserved_mask = (RTC_TR_PM | RTC_TR_HT | RTC_TR_HU | RTC_TR_MNT | RTC_TR_MNU | RTC_TR_ST | RTC_TR_SU);

    /* Get subseconds structure field from the corresponding register*/
    data->subseconds = (uint32_t) (RTC->SSR);

    uint32_t SecondFraction = (uint32_t)(RTC->PRER & RTC_PRER_PREDIV_S);

    /* Get the TR register */
    tmpreg = (uint32_t) (RTC->TR & rtc_tr_reserved_mask);

    /* Fill the structure fields with the read parameters */
    data->hours = (uint8_t) ((tmpreg & (RTC_TR_HT | RTC_TR_HU)) >> RTC_TR_HU_Pos);
    data->minutes = (uint8_t) ((tmpreg & (RTC_TR_MNT | RTC_TR_MNU)) >> RTC_TR_MNU_Pos);
    data->seconds = (uint8_t) ((tmpreg & (RTC_TR_ST | RTC_TR_SU)) >> RTC_TR_SU_Pos);

    tmp = ((data->hours & 0xF0U) >> 4U) * 10U;
    data->hours = (tmp + (data->hours & 0x0FU));

    tmp = ((data->minutes & 0xF0U) >> 4U) * 10U;
    data->minutes = (tmp + (data->minutes & 0x0FU));

    tmp = ((data->seconds & 0xF0U) >> 4U) * 10U;
    data->seconds = (tmp + (data->seconds & 0x0FU));

    MP_BSP_GiveRTCmutex();
}

 

 

And my debug log:

 

BSP_RTC_Time_t RTCtimeLog;
BSP_RTC_GetDateTime(&RTCtimeLog);
DbgPrint("RTC time label         : %d.%d.20%02d %02d:%02d:%02d", RTCtimeLog.day, RTCtimeLog.month, RTCtimeLog.year, RTCtimeLog.hours, RTCtimeLog.minutes, RTCtimeLog.seconds);

 

 

logs...

  1. [99563][D][TIME--T] RTC time label : 25.3.2024 06:24:25
  2. [95683][D][TIME--T] RTC time label : 24.3.2024 06:24:18

And you see I have 2 different days. And more often than not I get the wrong data.

Hi,

but still you not obey the sequence, how to read rtc.

Just try only using this:

 

	/* Read time and date registers in BCD format */

   rtc_time = LL_RTC_TIME_Get(RTC);
   rtc_date = LL_RTC_DATE_Get(RTC);

 

I am also not using HAL for this, also not LL , i read registers direct. :)

(and never had a problem with the rtc.)

If you feel a post has answered your question, please click "Accept as Solution".

I am sorry. It was my fault. I tried your solution but the problem is still the same.

rtc_time = LL_RTC_TIME_Get(RTC);
rtc_date = LL_RTC_DATE_Get(RTC);

And I tried my solution and the problem is still here.

void BSP_RTC_GetDateTime(BSP_RTC_Time_t *data)
{
        // always clear
    memset((void*) data, 0, sizeof(BSP_RTC_Time_t));

    MP_BSP_GetRTCmutex();

    uint32_t tmpreg;
	
	// [TIME]

    uint32_t rtc_tr_reserved_mask = (RTC_TR_PM | RTC_TR_HT | RTC_TR_HU | RTC_TR_MNT | RTC_TR_MNU | RTC_TR_ST | RTC_TR_SU);

    /* Get subseconds structure field from the corresponding register*/
    data->subseconds = (uint32_t) (RTC->SSR);

    uint32_t SecondFraction = (uint32_t)(RTC->PRER & RTC_PRER_PREDIV_S);

    /* Get the TR register */
    tmpreg = (uint32_t) (RTC->TR & rtc_tr_reserved_mask);

    /* Fill the structure fields with the read parameters */
    data->hours = (uint8_t) ((tmpreg & (RTC_TR_HT | RTC_TR_HU)) >> RTC_TR_HU_Pos);
    data->minutes = (uint8_t) ((tmpreg & (RTC_TR_MNT | RTC_TR_MNU)) >> RTC_TR_MNU_Pos);
    data->seconds = (uint8_t) ((tmpreg & (RTC_TR_ST | RTC_TR_SU)) >> RTC_TR_SU_Pos);

    tmp = ((data->hours & 0xF0U) >> 4U) * 10U;
    data->hours = (tmp + (data->hours & 0x0FU));

    tmp = ((data->minutes & 0xF0U) >> 4U) * 10U;
    data->minutes = (tmp + (data->minutes & 0x0FU));

    tmp = ((data->seconds & 0xF0U) >> 4U) * 10U;
    data->seconds = (tmp + (data->seconds & 0x0FU));

    // [DATE]

    uint32_t rtc_dr_reserved_mask = (RTC_DR_YT | RTC_DR_YU | RTC_DR_WDU | RTC_DR_MT | RTC_DR_MU | RTC_DR_DT | RTC_DR_DU);

    /* Get the DR register */
    tmpreg = (uint32_t) (RTC->DR & rtc_dr_reserved_mask);

    /* Fill the structure fields with the read parameters */
    data->year = (uint8_t) ((tmpreg & (RTC_DR_YT | RTC_DR_YU)) >> RTC_DR_YU_Pos);
    data->month = (uint8_t) ((tmpreg & (RTC_DR_MT | RTC_DR_MU)) >> RTC_DR_MU_Pos);
    data->day = (uint8_t) ((tmpreg & (RTC_DR_DT | RTC_DR_DU)) >> RTC_DR_DU_Pos);
    data->day_in_week = (uint8_t) ((tmpreg & (RTC_DR_WDU)) >> RTC_DR_WDU_Pos);

    uint8_t tmp;
    /* Convert the date structure parameters to Binary format */
    tmp = ((data->year & 0xF0U) >> 4U) * 10U;
    data->year = (tmp + (data->year & 0x0FU));

    tmp = ((data->month & 0xF0U) >> 4U) * 10U;
    data->month = (tmp + (data->month & 0x0FU));

    tmp = ((data->day & 0xF0U) >> 4U) * 10U;
    data->day = (tmp + (data->day & 0x0FU));

    MP_BSP_GiveRTCmutex();
}

The data I write to the RTC I write to the console and they are 100% correct.

Hmmm...i do it this way:

 

	uint32_t rTR = RTC->TR;		// read time register first !
	uint32_t rDR = RTC->DR;		// read date register

 

 Try : put this in your 

BSP_RTC_GetDateTime

(simply direct, not with pointer and memset ..etc. )

If you feel a post has answered your question, please click "Accept as Solution".

I modif function to direct console print and read from registers.

void BSP_RTC_GetDateTime(BSP_RTC_Time_t *data)
{
	uint32_t rtc_date, rtc_time;
	uint32_t TimeOut;

	// always clear
	memset((void *)data, 0, sizeof(BSP_RTC_Time_t));
	
	//
	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; 
		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 = RTC->TR;
	rtc_date = RTC->DR;

	//
	LL_RTC_ClearFlag_RS(RTC);
	//
	MP_BSP_GiveRTCmutex();
	
	debugprint("%d.%d.20%02d %d:%d:%d", __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_DAY(rtc_date)),
	        __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_MONTH(rtc_date)),
	        __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_YEAR(rtc_date)),
	        __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_HOUR(rtc_time)),
	        __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_MINUTE(rtc_time)),
	        __LL_RTC_CONVERT_BCD2BIN(__LL_RTC_GET_SECOND(rtc_time)));

}

 

And output. Today is missing. :beaming_face_with_smiling_eyes:

  1. 24.3.2024 15:10:28
    24.3.2024 15:10:29
    24.3.2024 15:10:30
    24.3.2024 15:10:31
    24.3.2024 15:10:32
    24.3.2024 15:10:33
    24.3.2024 15:10:34
    24.3.2024 15:10:36
    24.3.2024 15:10:37
    24.3.2024 15:10:38

A: you have a time machine !

B: you should set date to 25.

:)

(But seem no "wrong" values there, reading is constant.)

If you feel a post has answered your question, please click "Accept as Solution".

So, if I understand it correctly, you're not able to set the RTC date/time if you run the code; but you are able to set it if single-stepping, correct?

This might indicate timing issues. You are performing lots of steps some of which I am not convinced they are needed, others are hidden behind LL calls I am not going to decipher. Assuming you've already set up LSE to run, you need to (I don't use H7 so some steps may be different in details):

1. enable RTC APB access in RCC (if given STM32 has this feature)

2. enable backup-domain access by setting PWR_CR1.DBP; this assumes PWR has already enabled clock in RCC

3. enable RTC write access by "unlocking" it, see RTC_WPR

4. place RTC into the INIT state, see RTC_ISR.INIT/INITF

5. set RTC_TR and RTC_DR

6. clear the readback status bit, RTC_ISR.RSF

7. exit INIT state by clearing RTC_ISR.INIT

8. wait until RSF gets set, then you can read RTC_TR/RTC_DR (in this order, as @AScha.3 said above)

There might be short delays needed between some of these steps.  My guess is between 1. and anything else, but it may be elsewhere. Try inserting short delays at strategic points and observe, if the RTC write is successful.

JW