cancel
Showing results for 
Search instead for 
Did you mean: 

STM32 RTC loses one second after each reset

coppercrimp
Associate III
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
1 ACCEPTED SOLUTION

Accepted Solutions
MSine
Associate

I solved this problem in the following way:

0690X000006DkvIQAS.png

View solution in original post

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

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

Thanks,

Rob

Tuttle.Darrell
Associate II
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
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?

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

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

Posted on May 25, 2017 at 17:53

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

  HAL_RTC_Init(&hrtc);

every time you reset the mcu

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)
�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

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

Posted on May 25, 2017 at 20:47

Thanks Tut! I'll give your code a try and see what happens