cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F405RG's RTC time drifts by +/- 6s per day (compared to UTC)

NFern.1
Associate III

External 32.786KHz crystal is connected to the terminals PC14, PC15 and 6.8pF, NPO Capacitors connected between crystal and GND.

Battery Back-up is provided.

Configured using the STM32CubeIDE (STM32CubeMX) -> Clock Configuration to use LSE (32.786KHz)

All units are synced with UTC at start-up. After running for a day some units show current time +6s while others show -6s - when compared to UTC.

Questions

1. How can we determine that the "LSE" is in use and the MCU has not failed-over to the "LSI RC"? (Assuming that there is something wrong with the PCB layout/components)

2. Assuming that the LSE is in use, since we see a fixed drift of 6s per day is there a way to compensate for this drift by configuration of the RTC?

12 REPLIES 12
S.Ma
Principal

If you can run the code on the nucleo and compare hw first. Otherwise, mcu resets, clock disable periods, configuration will have to be checked. I think Nucleo has rtc examples, check them out. I assume the external clock oscillator is precise.

The 'F4 is not capable of "falling over" to LSI. Also, LSI would result in significantly higher time difference.

Read the Fine tuning description in RTC chapter in RM.

JW

TDK
Guru

Are units always +6 or -6 or are some spot on and other in between? Could be a software issue if chip is going to sleep and incorrectly doing things on wakeup.

RTC source can be verified in RTCSEL field of RCC_BDCR.

You can verify LSI is off with LSIRDY/LSIOFF bits in RCC_CSR.

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

Hi, have a look at AN2867. STM32F4 especially "gen1" are very sensitive to quartz characteristic and npo capacitor​ values.

Be also carefull to sw issue losing fractionnal second at each boot if you use cubemx init. Don't init rtc on warm boot...​

Hi, many thanks to all for the prompt replies.

The auto-generated function MX_RTC_Init() is being called at start-up from main()

Requesting you to kindly provide some additional information or point to some links/documents to correctly handle the RTC Init.

You are right regarding some error on boot/power-cycle. Note that the RTC has battery power throughout.

2 units are configured with the exact same time and running in-sync.

Power is cycled to one of the units and it comes back on out-of-sync.

Some more details on my hardware :

Each Unit(MCU) has it's own GNSS(GPS) module.

The time of the MCUs RTCs is synced on the 1PPS pulse of GNSS(GPS) module. 

The time on the MCUs are expected to run "near" sync for atleast 1 day in-case the GPS Signal is not available.

Each of the units(MCU) turn on/off a contactor and the sync operation is easily visible and audible.

I will be comparing the RTC_CALIB outputs of the MCUs using a Scope to get a more accurate view of the time drift.

Hi,

Referring Jan's links, I replaced the auto-generated MX_RTC_INIT() with MY_RTC_INIT() --shown below -- to handle the RTC initialization on Power-ON.

A RTC Backup Register's value is checked to determine that the RTC Configuration is valid and Battery power was not lost.

This solves the issue of sub-second loss on Power Cycle. The time drift I reported is most probably due to this issue.

I have set-up some systems to run over-night so I can record time drift over 24 hours. I will update my results here tomorrow.

Thanks again for your help.

static void MY_RTC_Init(void)
{
	hrtc.Instance = RTC;
	tempBBRAMStatus = HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1);
	if (tempBBRAMStatus != 0x32F2) //if RTC & BBRAM is invalid then initialize to 01-01-2000 00:00:00
	{
		  /*Initialize RTC Only*/
		  hrtc.Init.HourFormat = RTC_HOURFORMAT_24;
		  hrtc.Init.AsynchPrediv = 127;
		  hrtc.Init.SynchPrediv = 255;
		  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();
		  }
 
		  /*Initialize RTC and set the Time and Date*/
		  RTC_TimeTypeDef sTime = {0};
		  RTC_DateTypeDef sDate = {0};
		  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();
		  }
		  HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,0x32F2); //writes data to RTC Backup register indicating RTC configuration is done
	}
	else
	{
		  HAL_PWR_EnableBkUpAccess();  //unable to figure out what is being done?
		  //__HAL_RCC_BKP_CLK_ENABLE(); // Errors so commented, seems to enable the APB1 bus clock? Not in the stm32f4xx_hal_rcc.h file
		  /*Peripheral clock enable*/
		  __HAL_RCC_RTC_ENABLE();  //Apparently trying to set RCC_BDCR(reg)->RTCEN(bit)=1
		  HAL_NVIC_SetPriority(RTC_Alarm_IRQn,0,0);
		  HAL_NVIC_EnableIRQ(RTC_Alarm_IRQn);
	}
  /*Enable the Alarm A*/
  RTC_AlarmTypeDef sAlarm = { 0 };
  sAlarm.AlarmTime.Hours = 0x0;
  sAlarm.AlarmTime.Minutes = 0x0;
  sAlarm.AlarmTime.Seconds = 0x0;
  sAlarm.AlarmTime.SubSeconds = 0x0;
  sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
  sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
  sAlarm.AlarmMask = RTC_ALARMMASK_ALL;
  sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
  sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
  sAlarm.AlarmDateWeekDay = 0x1;
  sAlarm.Alarm = RTC_ALARM_A;
  if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BCD) != HAL_OK)
  {
    Error_Handler();
  }
  /*Enable Calibrartion*/
  if (HAL_RTCEx_SetCalibrationOutPut(&hrtc, RTC_CALIBOUTPUT_1HZ) != HAL_OK)
  {
    Error_Handler();
  }
}

Hi,

After fixing the Power Cycle issue, I let the systems run for a day. I observed that the RTC was 6s ahead after 24 hours. The drift was gradual over the period.

I referred to https://community.st.com/s/question/0D50X0000A7V38M/rtc-running-fast-on-stm32l433

1 pulse => 0.0824 seconds per day.

12 pulses => 1 second per day.

72 pulses => 6 second per day.

I added an RTC Calibration parameter to my system and the following code that runs at start-up and on the parameter change

if(myRTCSmoothCal.ClkSlowdnSpdup==-1) // slow down
		HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC, RTC_SMOOTHCALIB_PLUSPULSES_RESET, myRTCSmoothCal.Pulses);
 
if(myRTCSmoothCal.ClkSlowdnSpdup==1) // speed up
		HAL_RTCEx_SetSmoothCalib(&hrtc, RTC_SMOOTHCALIB_PERIOD_32SEC, RTC_SMOOTHCALIB_PLUSPULSES_SET, (512-myRTCSmoothCal.Pulses));

The drift has now reduced to 0.5s in 24 hours.

I will run each unit for a day, note the drift and add compensation and re-run for another day to confirm.

I will use the best available crystal and capacitors for the next batch of hardware. 

Can a TCXO output be connected to the MCU's LSE OSC32 inputs? Is some additional software/register configuration required? If this is possible - then please point me to some ST documentation for TCXO connected to LSE.

Thanks a lot for the help.

Hi, tcxo may be usefull to lower frequency thermal drift.

But you MUST consider

  1. Does your system​ got thermal fluctuation,
  2. Power requirement
  3. What happen when you only have vbackup​
  4. Tcxo have also X ppm frequency error, so you MUST calculate if you can get some valuable improvement using tcxo vs cristal LSE,
  5. I never tried external oscillator​ on LSE. On HSE, it need à SW change. Please read reference manual of the used STM32...

About RTC calibration you need to Know that it MUST be re applied each cold boot (after vbackup lost)...

If you have GNSS you can also periodically verify RTC calibration​...

​​