cancel
Showing results for 
Search instead for 
Did you mean: 

RTC resets on power-cycle despite battery

Lars Beiderbecke
Senior III

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?

8 REPLIES 8

> 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

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

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 ...)

Thanks, posted an additional question there.

Lars Beiderbecke
Senior III

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.

> 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

> 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.