Skip to main content
Graduate
December 5, 2025
Solved

RTC not working on Vbat

  • December 5, 2025
  • 6 replies
  • 63 views

Hi everyone,

I am using a STM32H563RG and I need the RTC to work even if the VDD is powered off. To do that, I am plugging a battery on the VBAT pin to power the RTC and the Backup domain. But I tested it and it seems the RTC is stopped and the backup domain is cleared when VDD is powered off.

Here is my initialisation code :

/* Configure the system clock */

SystemClock_Config();

/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */


/* Initialize all configured peripherals */

MX_GPIO_Init();
MX_GPDMA1_Init();
MX_ICACHE_Init();
MX_CRC_Init();
MX_SPI1_Init();
MX_TIM3_Init();
//MX_RTC_Init();
MX_ADC1_Init();
MX_ADC2_Init();
MX_TIM2_Init();
MX_FileX_Init();
MX_IWDG_Init();
MX_TouchGFX_Init();

/* USER CODE BEGIN 2 */

LL_PWR_EnableBkUpRegulator();
LL_PWR_EnableBkUpAccess();


if(LL_RTC_BKP_GetRegister(RTC,LL_RTC_BKP_DR0) == 0x32F2){ //Read Backup register to see if it was previously written

 RTC_Datas.RTC_initialized = 1; //Set flag
 GPIO_Set(Led_orang); //Turn Orange LED On

}

else{ //If not previously written

 RTC_Datas.RTC_initialized = 0; //Clear flag
 MX_RTC_Init(); //Call RTC_Init() to initialise RTC

}

RTC_Datas.Jour = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetDay(RTC)); //Read day
RTC_Datas.Mois = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetMonth(RTC)); //Read month
RTC_Datas.Annee = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetYear(RTC)) + 2000; //Read year

RTC_Datas.Minute = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetMinute(RTC));//Read minutes
RTC_Datas.Heure = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetHour(RTC)); //Read hours

 

The value 0x32F2 is written in the BKR0 backup register by the MX_RTC_Init() function. It should stay written in it even if there is a µC reset (with VBAT at 3,3V). I check if the RTC was previously initialised by reading this backup register : if I read 0x32F2, it means it was initialised and a Orange LED is turned ON. However, after a reset (performed by the VDD being powered off then powered on right away), the Orange LED doesn't turn ON and the RTC values are reinitialised.

What I made sure of :

  • RTC is clocked on LSE
  • LSE drive capabilty is HIGH
  • TAMP secure zone is deactivated
  • VBAT stays at approx. 3V3 during reset
  • LSE still on after reset
  • BREN bit of PWR->BDCR is set (to enable backup regulator)

It seems there is no Backup domain reset happening since the RTCSEL bit field of RCC->BDCR stays at 1 after reset ( it would be equal to 0 after a bakcup domain reset).

I therefore have three questions :

1) Are the RTC values saved in the backup domain or it is two different things ?

2) Is my test method correct to prove the Backup register is cleared ?

3) What could clear the Backup register and the RTC values reset ?

    This topic has been closed for replies.
    Best answer by Karakala

    Ok I solved my issue. At reset, we must set RTCAPBEN in RCC->APB3ENR to enable the backup domain clock, and enable the IRQ on RTC (not saved in the Backup domain apparently).I also added a small delay after reading the backup register and before reading the saved RTC values because the date I read wasn't always correct. I suspect a startup latency of the backup regulator. 

    Here is my code :

     /* Configure the system clock */
     SystemClock_Config();
    
     /* USER CODE BEGIN SysInit */
     LL_EXTI_DisableIT_0_31(LL_EXTI_LINE_0);					//Désactivation des interruption sur KEY_SELECT
     LL_EXTI_DisableIT_0_31(LL_EXTI_LINE_10);					//Désactivation des interruptions sur PSE
     LL_EXTI_DisableFallingTrig_0_31(LL_EXTI_LINE_13);			//Disable IRQ on T_com
     /* USER CODE END SysInit */
    
     /* Initialize all configured peripherals */
     MX_GPIO_Init();
     MX_GPDMA1_Init();
     MX_ICACHE_Init();
     MX_CRC_Init();
     MX_SPI1_Init();
     MX_TIM3_Init();
     //MX_RTC_Init();
     MX_ADC1_Init();
     MX_ADC2_Init();
     MX_TIM2_Init();
     MX_FileX_Init();
     MX_IWDG_Init();
     MX_TouchGFX_Init();
     /* USER CODE BEGIN 2 */
    	LL_PWR_EnableBkUpRegulator();
    	LL_APB3_GRP1_EnableClock(LL_APB3_GRP1_PERIPH_RTCAPB);			//Enable Backup domain clock
    	LL_PWR_EnableBkUpAccess();
    
    	if(LL_RTC_BKP_GetRegister(RTC,LL_RTC_BKP_DR0) == 0x32F2){			//Read Backup register to see if it was previously written
    		NVIC_SetPriority(RTC_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
    		NVIC_EnableIRQ(RTC_IRQn);										//Enable RTC IRQ
    		HAL_Delay(20);													//Small delay before reading RTC values
    	}
    	else{																//If not previously written
    		MX_RTC_Init();												//Call RTC_Init() to initialise RTC
    	}
    
    	RTC_Datas.Jour = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetDay(RTC));			//Récuperation du jour
    	RTC_Datas.Mois = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetMonth(RTC));		//Récuperation du mois
    	RTC_Datas.Annee = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetYear(RTC)) + 2000;//Récuperation de l'année
    
    	RTC_Datas.Minute = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetMinute(RTC));//Récuperation de la minute
    	RTC_Datas.Heure = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetHour(RTC));	//Récuperation de l'heure

     

    6 replies

    Super User
    December 5, 2025

    Welcome to the forum.

    Please see: How to write your question to maximize your chances to find a solution for best results.

    In particular, please give details of your hardware.

    KarakalaAuthor
    Graduate
    December 10, 2025

    Hi again,

    Here is my connection diagram :

    Karakala_0-1765375132570.png

    Vbat is around 3,5V normally. It is not charged by the µC but by a dedicated circuit. I also deactivated the measure on Vbat since the measuring error is about 10%.

     

    Technical Moderator
    December 12, 2025

    hello @Karakala 
    If you review the diagram in the datasheet, you will find out that the backup domain contains RTC and other peripherals.

    Gyessine_0-1765554079681.png

    Honestly, this is not a commonly known issue because The RTC is supposed to be functional in VBAT mode and in all low-power modes when it is clocked by the LSE. however, can you verify the selected LSE driving capability option is compatible with your gain margin? you can use AN2867 to calculate it.
    You can refer to this thread also.
    Hope that helps as a start
    Gyessine

     

    KarakalaAuthor
    Graduate
    December 15, 2025

    Hi @Gyessine 

    Thanks for answering me. I calculated it with my quartz parametters (ESR = 50kR typ/70kR max, C0 = 1,7pF and CL = 12,5pF), I makes gmcrit = 1,71µA/V. It means that only the High Drive Capabilty has a higher value (2,7µA/V) according to the STM32H563 datasheet. My gain margin would be inferior to 5 ?

    But yet it works since my RTC is running correctly when it is powered. This could explain that it is not saved ?

     

    Super User
    December 13, 2025

    Does the problem happen only upon power off/on, or also when using a NRST reset?

    Read out and check/compare-to-pre-reset-state/post content of RTC, TAMPER and RCC_BDCR registers. Do you have enabled RCC_APB3ENR.RTCAPBEN?

    JW

    KarakalaAuthor
    Graduate
    December 15, 2025

    Hi @waclawek.jan 

    Thanks for your answer.

    It didn't work also using a NRST reset. But at reset I didn't enabled RCC_APB3ENR.RTCAPBEN, I thought it was supposed to be saved at reset. Now it's enabled before reading the backup register, and the RTC is saved using a NRST reset, but not using a power off reset. However the value 0x32F2 is saved in the backup register BKPDR0 in both reset case. I checked again if there was no voltage drop on Vbat and if the quartz still runs at power off, no issue there. 

     

    That's not finished yet, but that's an advance !

    Here is my updated code :

     /* Configure the system clock */
     SystemClock_Config();
    
     /* USER CODE BEGIN SysInit */
     LL_EXTI_DisableIT_0_31(LL_EXTI_LINE_0);					//Désactivation des interruption sur KEY_SELECT
     LL_EXTI_DisableIT_0_31(LL_EXTI_LINE_10);					//Désactivation des interruptions sur PSE
     LL_EXTI_DisableFallingTrig_0_31(LL_EXTI_LINE_13);			//Disable IRQ on T_com
     /* USER CODE END SysInit */
    
     /* Initialize all configured peripherals */
     MX_GPIO_Init();
     MX_GPDMA1_Init();
     MX_ICACHE_Init();
     MX_CRC_Init();
     MX_SPI1_Init();
     MX_TIM3_Init();
     //MX_RTC_Init();
     MX_ADC1_Init();
     MX_ADC2_Init();
     MX_TIM2_Init();
     MX_FileX_Init();
     MX_IWDG_Init();
     MX_TouchGFX_Init();
     /* USER CODE BEGIN 2 */
     LL_PWR_EnableBkUpRegulator();
     LL_APB3_GRP1_EnableClock(LL_APB3_GRP1_PERIPH_RTCAPB);
     LL_PWR_EnableBkUpAccess();
    
     if(LL_RTC_BKP_GetRegister(RTC,LL_RTC_BKP_DR0) == 0x32F2){			//Read Backup register to see if it was previously written
    	 RTC_Datas.RTC_initialized = 1;								//Set flag
    	 LL_RCC_EnableRTC();
    	 GPIO_Set(Led_orang);											//Turn Orange LED On
     }
     else{																//If not previously written
    	 RTC_Datas.RTC_initialized = 0;								//Clear flag
    	 MX_RTC_Init();												//Call RTC_Init() to initialise RTC
     }
    
    
    	RTC_Datas.Jour = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetDay(RTC));			//Récuperation du jour
    	RTC_Datas.Mois = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetMonth(RTC));		//Récuperation du mois
    	RTC_Datas.Annee = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetYear(RTC)) + 2000;//Récuperation de l'année
    
    	RTC_Datas.Minute = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetMinute(RTC));//Récuperation de la minute
    	RTC_Datas.Heure = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetHour(RTC));	//Récuperation de l'heure

     

    Super User
    December 15, 2025

    Read out and check/compare-to-pre-reset-state/post content of RTC, TAMPER and RCC_BDCR registers,

    JW

    KarakalaAuthorAnswer
    Graduate
    December 15, 2025

    Ok I solved my issue. At reset, we must set RTCAPBEN in RCC->APB3ENR to enable the backup domain clock, and enable the IRQ on RTC (not saved in the Backup domain apparently).I also added a small delay after reading the backup register and before reading the saved RTC values because the date I read wasn't always correct. I suspect a startup latency of the backup regulator. 

    Here is my code :

     /* Configure the system clock */
     SystemClock_Config();
    
     /* USER CODE BEGIN SysInit */
     LL_EXTI_DisableIT_0_31(LL_EXTI_LINE_0);					//Désactivation des interruption sur KEY_SELECT
     LL_EXTI_DisableIT_0_31(LL_EXTI_LINE_10);					//Désactivation des interruptions sur PSE
     LL_EXTI_DisableFallingTrig_0_31(LL_EXTI_LINE_13);			//Disable IRQ on T_com
     /* USER CODE END SysInit */
    
     /* Initialize all configured peripherals */
     MX_GPIO_Init();
     MX_GPDMA1_Init();
     MX_ICACHE_Init();
     MX_CRC_Init();
     MX_SPI1_Init();
     MX_TIM3_Init();
     //MX_RTC_Init();
     MX_ADC1_Init();
     MX_ADC2_Init();
     MX_TIM2_Init();
     MX_FileX_Init();
     MX_IWDG_Init();
     MX_TouchGFX_Init();
     /* USER CODE BEGIN 2 */
    	LL_PWR_EnableBkUpRegulator();
    	LL_APB3_GRP1_EnableClock(LL_APB3_GRP1_PERIPH_RTCAPB);			//Enable Backup domain clock
    	LL_PWR_EnableBkUpAccess();
    
    	if(LL_RTC_BKP_GetRegister(RTC,LL_RTC_BKP_DR0) == 0x32F2){			//Read Backup register to see if it was previously written
    		NVIC_SetPriority(RTC_IRQn, NVIC_EncodePriority(NVIC_GetPriorityGrouping(),0, 0));
    		NVIC_EnableIRQ(RTC_IRQn);										//Enable RTC IRQ
    		HAL_Delay(20);													//Small delay before reading RTC values
    	}
    	else{																//If not previously written
    		MX_RTC_Init();												//Call RTC_Init() to initialise RTC
    	}
    
    	RTC_Datas.Jour = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetDay(RTC));			//Récuperation du jour
    	RTC_Datas.Mois = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetMonth(RTC));		//Récuperation du mois
    	RTC_Datas.Annee = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_DATE_GetYear(RTC)) + 2000;//Récuperation de l'année
    
    	RTC_Datas.Minute = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetMinute(RTC));//Récuperation de la minute
    	RTC_Datas.Heure = __LL_RTC_CONVERT_BCD2BIN(LL_RTC_TIME_GetHour(RTC));	//Récuperation de l'heure

     

    Super User
    December 15, 2025

    I also added a small delay after reading the backup register and before reading the saved RTC values because the date I read wasn't always correct.

    If you don't have RTC_CR.BYPSHAD set (and I suspect you don't, as that's the default), you have to wait until RTC_ICSR.RSF is set before reading the RTC time and date, see Reading the calendar subchapter in RTC chapter in RM.

    JW

    KarakalaAuthor
    Graduate
    December 15, 2025

    Yep that was it, thanks !