Skip to main content
Peter Mather
Associate III
April 18, 2019
Solved

RTC losing fractions of second on uP reset - how to solve?

  • April 18, 2019
  • 9 replies
  • 3719 views

My code initialises the RTC using the standard CubeMX code but before setting the clock it tests for a valid year > 2018. This works perfectly and the time and date are preserved through resets of the uP.

However, it appear that either the reset or the call to HAL_RTC_Init zeroes the fractions of a second stored in the RTC registers. This can be proven by repeated resetting the processor each time withing a second which causes time to stand still.

Is there a solution to this so that the fractions of a second are preserved through resets and power cycles?

Thanks

static void MX_RTC_Init(void)
{
 
 /* USER CODE BEGIN RTC_Init 0 */
	int up=RTC_SMOOTHCALIB_PLUSPULSES_RESET;
	int calibrate= -Option.RTC_Calibrate;
 /* USER CODE END RTC_Init 0 */
 
 RTC_TimeTypeDef sTime;
 RTC_DateTypeDef sDate;
 
 /* USER CODE BEGIN RTC_Init 1 */
 
 /* USER CODE END RTC_Init 1 */
 /** Initialize RTC Only 
 */
 hrtc.Instance = RTC;
 hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
 hrtc.Init.AsynchPrediv = 7;
 hrtc.Init.SynchPrediv = 4095;
 hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
 hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
 hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
 if (HAL_RTC_Init(&hrtc) != HAL_OK)
 {
 Error_Handler();
 }
 
 /* USER CODE BEGIN Check_RTC_BKUP */
 if (HAL_RTC_GetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
 {
	 Error_Handler();
 }
 
 if (HAL_RTC_GetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
 {
	 Error_Handler();
 }
 RtcGetTime();
 if(sDate.Year<18){
 
 /* USER CODE END Check_RTC_BKUP */
 
 /** Initialize RTC and set the Time and Date 
 */
 sTime.Hours = 0x0;
 sTime.Minutes = 0x0;
 sTime.Seconds = 0x0;
 sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
 sTime.StoreOperation = RTC_STOREOPERATION_RESET;
 if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK)
 {
 Error_Handler();
 }
 sDate.WeekDay = RTC_WEEKDAY_MONDAY;
 sDate.Month = RTC_MONTH_JANUARY;
 sDate.Date = 0x1;
 sDate.Year = 0x0;
 
 if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BCD) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN RTC_Init 2 */
 }
 if(Option.RTC_Calibrate>0){
	 up=RTC_SMOOTHCALIB_PLUSPULSES_SET;
	 calibrate=512-Option.RTC_Calibrate;
 }
 HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC, up, calibrate);
 
 /* USER CODE END RTC_Init 2 */
 
}

This topic has been closed for replies.
Best answer by Peter Mather

Thanks that and one of the cube example programs gave the clue. Key is the statement that restores the RTC structure.

 RTC_TimeTypeDef sTime;
 RTC_DateTypeDef sDate;
 
 /* USER CODE BEGIN RTC_Init 1 */
 /* USER CODE END RTC_Init 1 */
 /** Initialize RTC Only 
 */
 hrtc.Instance = RTC;
 hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
 hrtc.Init.AsynchPrediv = 7;
 hrtc.Init.SynchPrediv = 4095;
 hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
 hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
 hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
 __HAL_RTC_RESET_HANDLE_STATE(&hrtc);
 if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)){
	 MMPrintString("Full Init\r\n");
	 if (HAL_RTC_Init(&hrtc) != HAL_OK)
	 {
		 Error_Handler();
	 }
}

9 replies

waclawek.jan
Super User
April 18, 2019

I don't Cube but IMO you are not supposed to do

  HAL_RTC_Init(&hrtc);

every time you reset the mcu

https://community.st.com/s/question/0D50X00009XkgBWSAZ/stm32-rtc-loses-one-second-after-each-reset

JW

Peter Mather
Peter MatherAuthorBest answer
Associate III
April 18, 2019

Thanks that and one of the cube example programs gave the clue. Key is the statement that restores the RTC structure.

 RTC_TimeTypeDef sTime;
 RTC_DateTypeDef sDate;
 
 /* USER CODE BEGIN RTC_Init 1 */
 /* USER CODE END RTC_Init 1 */
 /** Initialize RTC Only 
 */
 hrtc.Instance = RTC;
 hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
 hrtc.Init.AsynchPrediv = 7;
 hrtc.Init.SynchPrediv = 4095;
 hrtc.Init.OutPut = RTC_OUTPUT_DISABLE;
 hrtc.Init.OutPutPolarity = RTC_OUTPUT_POLARITY_HIGH;
 hrtc.Init.OutPutType = RTC_OUTPUT_TYPE_OPENDRAIN;
 __HAL_RTC_RESET_HANDLE_STATE(&hrtc);
 if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)){
	 MMPrintString("Full Init\r\n");
	 if (HAL_RTC_Init(&hrtc) != HAL_OK)
	 {
		 Error_Handler();
	 }
}

Ingmar
Associate II
October 27, 2022

@Community member​ : Thanks a lot! These two lines

__HAL_RTC_RESET_HANDLE_STATE(&hrtc);
 
 if (__HAL_RCC_GET_FLAG(RCC_FLAG_PORRST)){

were not included in the code I was using, obviously taken from some older reference example.

Thus, HAL_RTC_Init() was called on every startup.

Edit: Works only after reset, but not after power down... :(

waclawek.jan
Super User
October 27, 2022
Ingmar
Associate II
October 27, 2022

Yep, I just found this (kind of official ST) answer which implements that solution:

HAL_RTC_Init() looses time · Issue #24 · STMicroelectronics/STM32CubeH7 (github.com)

Seems to work in my code. Thanks a lot, confirms it somehow.

Piranha
Principal III
October 27, 2022

Better test the RCC_BDCR configuration, especially the RTCEN bit.

Ingmar
Associate II
October 27, 2022
Piranha
Principal III
October 27, 2022

Jan and I gave you a better solution than the incompetent HAL/Cube developers.

LLeva.1
Associate II
January 8, 2023

not everyone is very smart to understand "Better test the RCC_BDCR configuration, especially the RTCEN bit." or "It may be a better idea to use RCC_BDCR.RTCEN as basis for this test" without working example. At least I do not know how implement it. :(

Piranha
Principal III
January 8, 2023

To develop software one must be capable of... developing software. How surprising! One have to know at least the generic software design principles, C programming language and have the basic level of hardware understanding. Those are the prerequisites for these tasks! The same as you cannot go to university and ask the professors to teach you the basic arithmetic.

And, by the way, in the first link Jan posted, there is a post from me with an example code exactly for this issue...

waclawek.jan
Super User
January 8, 2023
if ((RCC->BDCR & RCC_BDCR_RTCEN) == 0) {
 // start LSE and initialize RTC here
}

JW

LLeva.1
Associate II
January 9, 2023

Thanks for your help. As CubeMX loves to destroy the code, somehow I was confused, that it is not working... here is CubeMX ":friendly" variant:

RTC_TimeTypeDef sTime = {0};
RTC_DateTypeDef DateToUpdate = {0};
 /* USER CODE BEGIN RTC_Init 1 */
 hrtc.Instance = RTC;
 hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
 hrtc.Init.OutPut = RTC_OUTPUTSOURCE_ALARM;
	if ((RCC->BDCR & RCC_BDCR_RTCEN) == 0) {
 /* USER CODE END RTC_Init 1 */
 /** Initialize RTC Only
 */
 hrtc.Instance = RTC;
 hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND;
 hrtc.Init.OutPut = RTC_OUTPUTSOURCE_ALARM;
 if (HAL_RTC_Init(&hrtc) != HAL_OK)
 {
 Error_Handler();
 }
 /* USER CODE BEGIN Check_RTC_BKUP */
 } else
 /* RTC int */
 {
 HAL_NVIC_SetPriority(RTC_IRQn,15,0);
 HAL_NVIC_EnableIRQ(RTC_IRQn);
 }
	if(HAL_RTCEx_BKUPRead(&hrtc,RTC_BKP_DR1)!= 0x5051)
	{
 /* USER CODE END Check_RTC_BKUP */
...

I had to enable RTC interrupts manually. Also, some code is duplicated - just only to keep it from deleted by Cube.