Skip to main content
coppercrimp
Associate III
May 23, 2017
Solved

STM32 RTC loses one second after each reset

  • May 23, 2017
  • 16 replies
  • 16233 views
Posted on May 23, 2017 at 07:46

I have a custom board based on the STM32F407 device. The board is running well except for one nagging detail: the RTC loses one second each time I power the board on/off

My device uses a low frequency external crystal and a backup coincell battery. The crystal is the CM7V-T1A 32.768kHz from Micro Crystal and it runs fine and keeps accurate time from either the coincell or main battery power. But again, the RTC looses approximately 1 second every time the board is powered on from the main external batteries. If the user powers the board on and off ten times (while keeping the backup coincell connected of course), then approximately 10 seconds of time is lost on the RTC.

I see many postings on this forum of people reporting loss of time when coming out of sleep modes. However my problem happens irregardless of whether the processor ever enters sleep mode. I do check the Wakeup Flag and the Standby Flag on power up though. Below is the first lines of code from my main() function:

int main(void)

{

HAL_Init();

/* Configure the system clock */

SystemClock_Config_HighSpeed();

/* Initialize all configured peripherals */

MX_GPIO_Init();

CheckFlashDefaults();

MX_DMA_Init();

MX_I2C1_Init();

MX_SDIO_SD_Init();

StatusLED_ConfigI2C(&hi2c1);

if(__HAL_PWR_GET_FLAG(PWR_FLAG_WU) != RESET)

{

      __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

}

/* Check the status of standby flag SB*/

if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) == RESET)

{

      RTC_Init();

}

else

{

      /*Resuming from standby routine */

      __HAL_PWR_CLEAR_FLAG(PWR_FLAG_SB);

}

And here is the code that initializes the RTC:

void RTC_Init(void)

{

   RTC_TimeTypeDef sTime;

   RTC_DateTypeDef sDate;

   /**Initialize RTC and set the Time and Date

   */

   hrtc.Instance = RTC;

   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;

   HAL_RTC_Init(&hrtc);

   /* Read the Back Up Register 0 Data */

   if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0) != 0x32F2)

   {

      /* Configure RTC Calendar */

      sTime.Hours = 4;

      sTime.Minutes = 0;

      sTime.Seconds = 0;

      sTime.SubSeconds = 0;

      sTime.TimeFormat = RTC_HOURFORMAT12_AM;

      sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;

      sTime.StoreOperation = RTC_STOREOPERATION_RESET;

      HAL_RTC_SetTime(&hrtc, &sTime, FORMAT_BCD);

      sDate.WeekDay = RTC_WEEKDAY_MONDAY;

      sDate.Month = RTC_MONTH_JANUARY;

      sDate.Date = 1;

      sDate.Year = 0;

      HAL_RTC_SetDate(&hrtc, &sDate, FORMAT_BCD);

      /*♯♯-3- Writes a data in a RTC Backup data Register0 ♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯♯*/

      HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,0x32F2);

   }

}

#stm32f4 #rtc
This topic has been closed for replies.
Best answer by MSine

I solved this problem in the following way:

0690X000006DkvIQAS.png

16 replies

coppercrimp
Associate III
May 25, 2017
Posted on May 25, 2017 at 17:19

Anyone out there have a suggestion on how to fix this?

Thanks,

Rob

waclawek.jan
Super User
May 25, 2017
Posted on May 25, 2017 at 17:28

Exactly 1 second missing? Even if you power it down for say 10 seconds?

[EDIT}

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

  HAL_RTC_Init(&hrtc);

every time you reset the mcu

JW

coppercrimp
Associate III
May 25, 2017
Posted on May 25, 2017 at 17:32

It's not exactly one second but it's close. Probably more like 800ms

It doesnt matter how long the board is powered down (as long as the backup battery is connected). The problem only seems to be effected by the number of times the power is cycled or the processor is reset

Tuttle.Darrell
Associate II
May 25, 2017
Posted on May 25, 2017 at 17:55

I don't HAL or Cube either, but I think you may want to look at the flag check prior to calling HAL_RTC_Init()

You have:

if (__HAL_PWR_GET_FLAG(PWR_FLAG_SB) == RESET)

I use SPL and I believe the correct check using SPL is:

if(RTC_GetFlagStatus(RTC_FLAG_INITS)==RESET)

I'm thinking the HAL equivalent is probably very similar.

I believe initialization freezes the clock, so it shouldn't be performed every reset.

coppercrimp
Associate III
May 25, 2017
Posted on May 25, 2017 at 18:13

Hi Tut,

Yes I considered that the initialization might freeze the clock, so I tried calling 

RTC_Init() multiple times consecutively on startup to see if this increased the number of missing seconds. It did not. The problem might have more to do with the section of code that configures the pins and the 32kHz external crystal. Here's my code for that:

void SystemClock_Config_HighSpeed(void)

{

   RCC_OscInitTypeDef RCC_OscInitStruct;

   RCC_ClkInitTypeDef RCC_ClkInitStruct;

   RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;

   __HAL_RCC_PWR_CLK_ENABLE();

   __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);

   RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE|RCC_OSCILLATORTYPE_LSE;

   RCC_OscInitStruct.HSEState = RCC_HSE_ON;

   RCC_OscInitStruct.LSEState = RCC_LSE_ON;

   RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;

   RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;

   RCC_OscInitStruct.PLL.PLLM = 8;

   RCC_OscInitStruct.PLL.PLLN = 336;

   RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;

   RCC_OscInitStruct.PLL.PLLQ = 7;

   if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)

   {

      Error_Handler();

   }  

   RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK

   |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;

   RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;

   RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;

   RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;

   RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;

   if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)

   {

      Error_Handler();

   }

   PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_I2S|RCC_PERIPHCLK_RTC;

   PeriphClkInitStruct.PLLI2S.PLLI2SN = 192;

   PeriphClkInitStruct.PLLI2S.PLLI2SR = 2;

   PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;

   if (HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct) != HAL_OK)

   {

      Error_Handler();

   }

   HAL_RCC_MCOConfig(RCC_MCO1, RCC_MCO1SOURCE_HSE, RCC_MCODIV_4);

   HAL_SYSTICK_Config(HAL_RCC_GetHCLKFreq()/1000);

   HAL_SYSTICK_CLKSourceConfig(SYSTICK_CLKSOURCE_HCLK);

   /* SysTick_IRQn interrupt configuration */

   HAL_NVIC_SetPriority(SysTick_IRQn, 0, 0);

}

This code is called each time the board is powered up. Would changing this fix the problem?

Tuttle.Darrell
Associate II
May 25, 2017
Posted on May 25, 2017 at 18:27

I really don't have time to go through your code. There are a number of things I do after checking the RTC_FLAG_INITS flag (there are a few function calls to my own code mixed in here, but you should get the idea). Note the clock configuration which I believe you were asking about:

EDIT ... Added top line to enable the power controller interface clock prior to test for RTC initialization (sorry I missed seeing that line in my code).

RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE); // Enable the Power Controller interface clock
if(RTC_GetFlagStatus(RTC_FLAG_INITS)==RESET) // Initialization freezes clock so only perform this if new vbat/vdd power-up
 {
 PWR_BackupAccessCmd(ENABLE); // Enable access to RTC domain
 
 RCC_LSEConfig(RCC_LSE_ON); // Turns on the external 768khz oscillator (if not already on)
 while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) {}; // Wait until LSE is ready
 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // Selects the external 768khz oscillator (LSE) for the RTC
 RCC_RTCCLKCmd(ENABLE); // Enable the RTC Clock
 
 RTC_StructInit(&RTC_InitStruct); // Set RTC_InitStruct to default values
 RTC_InitStruct.RTC_HourFormat = RTC_HOUR_FORMAT;
 RTC_Init(&RTC_InitStruct);
 
 #if defined(USE_EEPROM)
 // Get rtc_calib_val from EEPROM
 eeprom_bytes = 2;
 if(sEE_ReadBuffer((uint8_t*)&rtc_calib_val,EEPROM_RTC_CAL_OFFSET,(uint32_t*)&eeprom_bytes)==sEE_FAIL)
 {
 rtc_calib_val = RTC_CALIB_VAL; // Set to default value defined in mydefs.h if EEPROM read fails
 }
 else while(eeprom_bytes) {}; // Wait for DMA to complete reading into buffer
 #else
 rtc_calib_val = RTC_CALIB_VAL; // Set to default value defined in mydefs.h if EEPROM read fails
 #endif
 Board_set_rtc_calib_val(rtc_calib_val);
 PWR_BackupAccessCmd(DISABLE); // Disable access to RTC domain (must re-enable to set time and date or access internal backup RAM)
 } // end if(RTC_GetFlagStatus(RTC_FLAG_INITS)==RESET)
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

waclawek.jan
Super User
May 25, 2017
Posted on May 25, 2017 at 19:24


if(RTC_GetFlagStatus(RTC_FLAG_INITS)==RESET) { // Initialization freezes clock so only perform this if new vbat/vdd power-up
 PWR_BackupAccessCmd(ENABLE); // Enable access to RTC domain
 RCC_LSEConfig(RCC_LSE_ON); // Turns on the external 768khz oscillator (if not already on)
 while(RCC_GetFlagStatus(RCC_FLAG_LSERDY) == RESET) {}; // Wait until LSE is ready
 RCC_RTCCLKConfig(RCC_RTCCLKSource_LSE); // Selects the external 768khz oscillator (LSE) for the RTC
 RCC_RTCCLKCmd(ENABLE); // Enable the RTC Clock
 RTC_StructInit(&RTC_InitStruct); // Set RTC_InitStruct to default values
 RTC_InitStruct.RTC_HourFormat = RTC_HOUR_FORMAT;
 RTC_Init(&RTC_InitStruct);
#if defined(USE_EEPROM)
// Get rtc_calib_val from EEPROM
 eeprom_bytes = 2;
 if(sEE_ReadBuffer((uint8_t*)&rtc_calib_val,EEPROM_RTC_CAL_OFFSET,(uint32_t*)&eeprom_bytes)==sEE_FAIL) {
 rtc_calib_val = RTC_CALIB_VAL; // Set to default value defined in mydefs.h if EEPROM read fails
 } else while(eeprom_bytes) {}; // Wait for DMA to complete reading into buffer
#else
 rtc_calib_val = RTC_CALIB_VAL; // Set to default value defined in mydefs.h if EEPROM read fails
#endif
 Board_set_rtc_calib_val(rtc_calib_val);

 PWR_BackupAccessCmd(DISABLE); // Disable access to RTC domain (must re-enable to set time and date or access internal backup RAM)
} // end if(RTC_GetFlagStatus(RTC_FLAG_INITS)==RESET)�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

... -> More -> Syntax Highlighter

May

Will impose moderation.

JW

Siddharth Singh
Visitor II
May 27, 2017
Posted on May 27, 2017 at 15:07

I have the exact same problem. I am using STM32F103, CubeMX and an external LSE 32.768 KHz crystal with VBat source as a CR2032 Lithium cell. The clock is keeping accurate time while either on power or on backup coin cell. However, I lose around 500 - 600 ms every time the micro is powered up or if I reset the micro using the reset button.

If I hit reset button 100 times, I lose close to a minute.

I do not suspect the crystal as I have taken measurements using an oscilloscope and also I have enabled output on RTC pin and the timing measures perfectly.

It has something to do with the initialization and I have not been able to figure that out so far!

waclawek.jan
Super User
May 28, 2017
Posted on May 28, 2017 at 16:26

If the RTC is already running, you need no initialization at all.

JW

AVI-crak
Senior
December 6, 2017
Posted on December 06, 2017 at 15:08

Checking, performing a new initialization of the clock in case of an error:

if (! ((RCC->BDCR & RCC_BDCR_LSERDY) /// hour quartz worked before

&&(((RCC->BDCR) & RCC_BDCR_RTCSEL ) == RCC_BDCR_RTCSEL_0) /// switch on external clock quartz

&&((RCC->BDCR) & RCC_BDCR_RTCEN)) )/// the clock is already working

{

//Your code for starting the clock and calendar

}

coppercrimp
Associate III
May 30, 2017
Posted on May 30, 2017 at 20:32

Ok, so I'm back to trying to get my RTC problem corrected. I appreciate the help I've gotten so far. I'm pursuing Tut's suggestion of checking RTC_FLAG_INITS flag before configuring the RTC external clock. Tut uses the code:

if(RTC_GetFlagStatus(RTC_FLAG_INITS)==RESET) {

This appears to be from the Standard Peripheral Libraries. Since I'm fairly new to the STM32 I've gotten started with the HAL libraries. I'm having trouble finding an equivalent function in the HAL libraries to RTC_GetFlagStatus() function. Does anyone know the function to use? Again, I need to check the RTC_FLAG_INITS flag using the HAL libraries.

Also if anyone can point me to an example project or documentation showing properconfiguring the RTC clock that would be a huge help! All the documentation I've seen so far seems to skip this crucial bit of initialization code

Thanks again,

Rob

waclawek.jan
Super User
May 31, 2017
Posted on May 31, 2017 at 00:01

Rob,

I need to check the RTC_FLAG_INITS flag using the HAL libraries.

I don't understand you. You've used a Cube example code, to find out it's faulty, and still insist in using Cube?

The INITS flag is in RTC_ISR register. Read the RTC chapter of RM0090, especially RTC initialization and configuration  mainly its final note mentioning the INITS flag; and see the description of RTC_ISR.INITS in the registers description subchapter.

Now do you still insist on using a 'library' to check a single read-only bit?

Btw., I went through the 'library' files, and there's nothing specifically intended to check INITS. You could use something like

__HAL_RTC_ALARM_GET_FLAG(your_rtc_instance, RTC_FLAG_INITS)

(no guarantee, as you've might have found out I despice using libraries) but the comment (thus doxygen-autovomited 'documentation') says that the second parameter is to be one of

STM32F411xE HAL User Manual: RTC Exported Macros

  • RTC_FLAG_ALRAF
  • RTC_FLAG_ALRBF
  • RTC_FLAG_ALRAWF
  • RTC_FLAG_ALRBWF

so it's up to you.

JW

PS. Oh, and checking INITS is not the only way how to check whether RTC has been already started... although maybe the easiest one.

coppercrimp
Associate III
May 30, 2017
Posted on May 31, 2017 at 01:45

After some trial and error I came up with a solution that seems to work. The key piece Iseemed to be missing was this:

You SHOULD configure the peripheral clock for the RTC every time the themicrocontroller resets. I.e. the following code:

RCC_PeriphCLKInitTypeDef PeriphClkInitStruct;
PeriphClkInitStruct.PeriphClockSelection = RCC_PERIPHCLK_RTC;
 PeriphClkInitStruct.RTCClockSelection = RCC_RTCCLKSOURCE_LSE;
 HAL_RCCEx_PeriphCLKConfig(&PeriphClkInitStruct);�?�?�?�?

The aboveconfiguration doesn't seem to save after a power on reset in the backup domain

You SHOULD NOT need to reconfigure the 32kHz oscillator after each reset. I.e. the following code:

RCC_OscInitTypeDef RCC_OscInitStruct; 
 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE; 
 RCC_OscInitStruct.LSEState = RCC_LSE_ON;
 HAL_RCC_OscConfig(&RCC_OscInitStruct);�?�?�?�?

In the end I settled on the following RTC_INIT() function, which seems to work in my testing so far:

void RTC_Init(void)
{ 
 RTC_HandleTypeDef hrtc;
 hrtc.Instance = RTC;
 
 /* Read the Back Up Register 0 Data */
 if(HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR0) != 0x32F2) 
 {
 //Only execute this code if the RTC has not previously been configured
 //**INITIALIZE 32kHz CLOCK*********************************
 RCC_OscInitTypeDef RCC_OscInitStruct; 
 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_LSE; 
 RCC_OscInitStruct.LSEState = RCC_LSE_ON;
 HAL_RCC_OscConfig(&RCC_OscInitStruct);
 //**END INITIALIZE 32kHz CLOCK************************************************ 
 
 /* Initialize RTC and set the Time and Date */
 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;
 HAL_RTC_Init(&hrtc); 
 
 RTC_TimeTypeDef sTime;
 RTC_DateTypeDef sDate; 
 
 /* Configure RTC Calendar */
 sTime.Hours = 0;
 sTime.Minutes = 0;
 sTime.Seconds = 0;
 sTime.SubSeconds = 0;
 sTime.TimeFormat = RTC_HOURFORMAT12_AM;
 sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
 sTime.StoreOperation = RTC_STOREOPERATION_RESET;
 HAL_RTC_SetTime(&hrtc, &sTime, FORMAT_BCD);
 sDate.WeekDay = RTC_WEEKDAY_MONDAY;
 sDate.Month = RTC_MONTH_JANUARY;
 sDate.Date = 1;
 sDate.Year = 1;
 HAL_RTC_SetDate(&hrtc, &sDate, FORMAT_BCD);
 /*##-3- Writes a data in a RTC Backup data Register0 #####################*/
 HAL_RTCEx_BKUPWrite(&hrtc,RTC_BKP_DR0,0x32F2); 
 } 
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

Siddharth Singh
Visitor II
May 31, 2017
Posted on May 31, 2017 at 18:32

Thanks Rob, this did the trick 

:)

 

:)

coppercrimp
Associate III
December 5, 2017
Posted on December 05, 2017 at 20:57

Just wanted to point out that there still doesn't seem to be any workable code examples for configuring the RTC with the HAL libraries. Seems funny that such a basic feature is still missing

-Rob

john doe
Senior III
December 6, 2017
Posted on December 06, 2017 at 01:40

What is unworkable about the existing examples?  And which chip family do you mean?  The newer chips have much better RTC capabilities.

coppercrimp
Associate III
December 6, 2017
Posted on December 06, 2017 at 02:43

There is a bug in the HAL code where the RTC loses a second every time the processor is reset or powered on. The chip I'm using is the STM32F407 but I believe the problem is in the code and not the microcontroller

ST Technical Moderator
March 16, 2018
Posted on March 16, 2018 at 15:44

Hello All,

I confirm this issue for HAL RTC and highlighted internally to developer team for fix.

Sorry for such inconvenience.

Best Regards,

Imen

In order to give better visibility on the answered topics, please click on 'Best answer' on the reply which solved your issue or answered your question. Thanks
MSine
MSineBest answer
Visitor II
February 21, 2019

I solved this problem in the following way:

0690X000006DkvIQAS.png