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
35 REPLIES 35

I'm using an STM32L151 and have the same problem, after every reset I lose about 1 second.

Thus the check on the INITS flag isn't perfect as it relies on the YEAR being set.

extract from manual

Bit 4 INITS: Initialization status flag This bit is set by hardware when the calendar year field is different from 0 (power-on reset value state). 0: Calendar has not been initialized 1: Calendar has been initialized

But finally I know a work around, set the year.

Also after applying the above fix I found that calling HAL_RTCEx_SetCoarseCalib( &hrtc, RTC_CALIBSIGN_NEGATIVE, value ) at reset also lost time, best to only call it when an adjustment is made.

As I only use time, the workaround was to set the year to 22, now in 78 years time for 1 year the device will lose time 😁

 > Thus the check on the INITS flag isn't perfect as it relies on the YEAR being set.

Indeed.

I personally check RCC_BDCR.RTCEN.

JW

const uint32_t rBDCR = RCC_BDCR_RTCEN | _VAL2FLD(RCC_BDCR_RTCSEL, 1) | RCC_BDCR_LSEON;
 
if ((RCC->BDCR & (RCC_BDCR_RTCEN | RCC_BDCR_RTCSEL | RCC_BDCR_LSEDRV | RCC_BDCR_LSEBYP | RCC_BDCR_LSEON)) != rBDCR) {
	RCC->BDCR = RCC_BDCR_BDRST;
	RCC->BDCR = rBDCR;
}

I'm doing it like this. The bonus is that if something got wrong with any of those bits, they (and the whole backup domain) will be reconfigured on the next boot.

> As I only use time, the workaround was to set the year to 22

Setting a year to 1 seems like the best choice.

Nice.

Btw. _VAL2FLD() macro was added to CMSIS in v4.20, somewhen in 2015, quite late to the dance.

Roughly in the same timeframe (for STM32, with the advent of Cube) the ***_Pos and ***_Msk macros - upon which the _VAL2FLD() macro depends - appeared in the CMSIS-mandated device headers. This just shows how woefully inexperienced both ARM and STM32 crew were.

JW