Skip to main content
Lars Beiderbecke
Senior III
April 27, 2021
Question

RTC resets on power-cycle despite battery

  • April 27, 2021
  • 8 replies
  • 3417 views

I've connected a CR2032 battery to the V_BAT pin on my custom STM32F746 board. Right now, the battery is connected directly without a Schottky diode. When I power the board off and on again, though, the RTC is reset to zero values.

According to the reference:

To allow the RTC to operate even when the main digital supply (VDD) is turned off, the VBAT pin powers the following blocks:

• The RTC

• The LSE oscillator

• The backup SRAM when the low-power backup regulator is enabled

Because of this list (and I'm using the LSE), I figured that I don't have to muck around with shadow registers manually.

Could it be that the standard MX_RTC_Init(); function generated by CubeMX also resets the RTC time and date? If so, how would I fix that?

This topic has been closed for replies.

8 replies

waclawek.jan
Super User
April 27, 2021

> Could it be that the standard MX_RTC_Init(); function generated by CubeMX also resets the RTC time and date?

Maybe. What's in it?

> If so, how would I fix that?

Don't use it.

JW

Lars Beiderbecke
Senior III
April 27, 2021

Well, it's basically this:

 if(hrtc->State == HAL_RTC_STATE_RESET)
 {
 /* Allocate lock resource and initialize it */
 hrtc->Lock = HAL_UNLOCKED;
 
 /* Initialize RTC MSP */
 HAL_RTC_MspInit(hrtc);
 }
 
 /* Set RTC state */
 hrtc->State = HAL_RTC_STATE_BUSY;
 
 /* Disable the write protection for RTC registers */
 __HAL_RTC_WRITEPROTECTION_DISABLE(hrtc);
 
 /* Set Initialization mode */
 if(RTC_EnterInitMode(hrtc) != HAL_OK)
 {
 /* Enable the write protection for RTC registers */
 __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
 
 /* Set RTC state */
 hrtc->State = HAL_RTC_STATE_ERROR;
 
 return HAL_ERROR;
 }
 else
 {
 /* Clear RTC_CR FMT, OSEL and POL Bits */
 hrtc->Instance->CR &= ((uint32_t)~(RTC_CR_FMT | RTC_CR_OSEL | RTC_CR_POL));
 /* Set RTC_CR register */
 hrtc->Instance->CR |= (uint32_t)(hrtc->Init.HourFormat | hrtc->Init.OutPut | hrtc->Init.OutPutPolarity);
 
 /* Configure the RTC PRER */
 hrtc->Instance->PRER = (uint32_t)(hrtc->Init.SynchPrediv);
 hrtc->Instance->PRER |= (uint32_t)(hrtc->Init.AsynchPrediv << 16);
 
 /* Exit Initialization mode */
 hrtc->Instance->ISR &= (uint32_t)~RTC_ISR_INIT;
 
 hrtc->Instance->OR &= (uint32_t)~RTC_OR_ALARMTYPE;
 hrtc->Instance->OR |= (uint32_t)(hrtc->Init.OutPutType);
 
 /* Enable the write protection for RTC registers */
 __HAL_RTC_WRITEPROTECTION_ENABLE(hrtc);
 
 /* Set RTC state */
 hrtc->State = HAL_RTC_STATE_READY;
 
 return HAL_OK;
 }

I'd guess that HAL_RTC_MspInit(hrtc); needs to be called at least once, but maybe RTC_EnterInitMode() shouldn't? But it seems it's called everytime.

typedef enum
{
 HAL_RTC_STATE_RESET = 0x00U, /*!< RTC not yet initialized or disabled */
 HAL_RTC_STATE_READY = 0x01U, /*!< RTC initialized and ready for use */
 HAL_RTC_STATE_BUSY = 0x02U, /*!< RTC process is ongoing */
 HAL_RTC_STATE_TIMEOUT = 0x03U, /*!< RTC timeout state */
 HAL_RTC_STATE_ERROR = 0x04U /*!< RTC error state */
} HAL_RTCStateTypeDef;

You'd think that hrtc->State = HAL_RTC_STATE_BUSY survives power off, but maybe it doesn't? The init code looks like it does handle power downs with batteries.

Lars Beiderbecke
Senior III
April 27, 2021

Alright, I ended up editing MX_RTC_Init():

void MX_RTC_Init(void)
{
 
 /** Initialize RTC Only
 */
 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;
 
// if (HAL_RTC_Init(&hrtc) != HAL_OK)
// {
// Error_Handler();
// }
 
 hrtc.Lock = HAL_UNLOCKED;
 HAL_RTC_MspInit(&hrtc);
}

Not sure if that HAL_UNLOCKED is necessary, but it was in the HAL_RTC_Init() function. And now it works! (Strange, through, that CubeMX wouldn't handle this ...)

Lars Beiderbecke
Senior III
April 27, 2021

Thanks, posted an additional question there.

Lars Beiderbecke
Senior III
April 29, 2021

Wait, I don't relate to the linked post. My issue is RTC reset on power cycle, but NOT on soft reset. Also, my MX_RTC_Init() definitely doesn't contain code to reset the RTC. As shown above, the only function called is HAL_RTC_Init (which calls RTC_EnterInitMode()), whose implementation merely sets some registers and state.

HAL_StatusTypeDef RTC_EnterInitMode(RTC_HandleTypeDef* hrtc)
{
 uint32_t tickstart = 0;
 
 /* Check if the Initialization mode is set */
 if((hrtc->Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
 {
 /* Set the Initialization mode */
 hrtc->Instance->ISR = (uint32_t)RTC_INIT_MASK;
 
 /* Get tick */
 tickstart = HAL_GetTick();
 
 /* Wait till RTC is in INIT state and if Time out is reached exit */
 while((hrtc->Instance->ISR & RTC_ISR_INITF) == (uint32_t)RESET)
 {
 if((HAL_GetTick() - tickstart ) > RTC_TIMEOUT_VALUE)
 {
 return HAL_TIMEOUT;
 }
 }
 }
 
 return HAL_OK;
}

Still, commenting out this function solved my reset problems on power cycle. How does this actually work? MX_RTC_Init() sets all bits in ISR to one, and waits until the INITF flag is set. But where does the actual RTC reset happen?

Again, you'd want a reset if the battery is missing, and not if it is there.

waclawek.jan
Super User
April 29, 2021

> My issue is RTC reset on power cycle

How do you know? What are exactly the symptoms? How do you set up the date/time registers, and how do you check them after the reset, exactly?

Calling HAL_RTC_Init () unconditionally is a long-existing known flaw, as entering the INIT mode clears the subsecond counter; search here for "in average half second lost upon each reset".

JW

Lars Beiderbecke
Senior III
April 29, 2021

> How do you know? What are exactly the symptoms? How do you set up the date/time registers, and how do you check them after the reset, exactly?

Since I'm using HAL, I don't mess with registers myself. When I power my board, the RTC starts ticking with all values zero. Now that I think about it, I don't really know what happens during soft reset, simply because my board doesn't allow that. So I can only power cycle.

Since that part of my user program is not working, I currently don't set the date and time. The RTC just begins ticking at all zero values.

If I power cycle, the RTC values are back to zero. If I connect a CR2032 to V_bat and power cycle, the RTC values are still back to zero. If I comment out the call to HAL_RTC_Init(&hrtc) in MX_RTC_Init() and power cycle with battery connected, the RTC returns non-zero values, around the correct elapsed time.

So, to summarize, for me not just the sub-second counter is cleared, but all counters.