2021-04-27 03:55 AM
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?
2021-04-27 04:10 AM
> 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
2021-04-27 04:31 AM
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.
2021-04-27 05:26 AM
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 ...)
2021-04-27 07:00 AM
2021-04-27 07:23 AM
Thanks, posted an additional question there.
2021-04-29 09:17 AM
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.
2021-04-29 09:29 AM
> 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
2021-04-29 09:47 AM
> 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.