Using STM32 RTC backup registers

The STM32F4's RTC has 20 x 32-bit backup registers RTC_BKP_DR0 to RTC_BKP_DR19, which are maintained while in a power-off state if Vbat is supplied from a coin-cell battery or other.

There is no support in mbed's libraries for reading/writing from them, but again we can use STM HAL library calls instead.

I wrote a couple of functions as wrappers around the HAL calls:

uint32_t rtc_read_backup_reg(uint32_t BackupRegister) {
    RTC_HandleTypeDef RtcHandle;
    RtcHandle.Instance = RTC;
    return HAL_RTCEx_BKUPRead(&RtcHandle, BackupRegister);

void rtc_write_backup_reg(uint32_t BackupRegister, uint32_t data) {
    RTC_HandleTypeDef RtcHandle;
    RtcHandle.Instance = RTC;
    HAL_RTCEx_BKUPWrite(&RtcHandle, BackupRegister, data);

Currently, if you set the time using the mbed library, the backup registers are erased.To avoid this, we must use mbed-dev & edit your STM32`s rtc_api.c. Comment out

rtc_api.c rtc_init()


then your data will survive setting the clock. Issue raised.

2 comments on Using STM32 RTC backup registers:

25 Jan 2017

Hi Dave,

accessing the RTC backup registers works on a Nucleo F401RE but not on a Nucleo F103RB.

Obviously the HW is different. The data sheet for the F103 says: "The backup registers are ten 16-bit registers used to store 20 bytes ..." For the F401: "The backup registers are 32-bit registers used to store 80 bytes..." That may explain why the wrapper functions (above) don't work for the F103.

Can somebody explain what to do to access the backup registers in the F103 ??

03 Mar 2020

Hi all Already implemented RTC backup for STM32F103 in the RTCInit with those function above. Check this.

  1. include "rtc.h"
  2. define HOUR_BCKP_REG 1
  3. define MIN_BCKP_REG 2
  4. define SEC_BCKP_REG 3
  5. define WEEKDAY_BCKP_REG 4
  6. define MONTH_BCKP_REG 5
  7. define DATE_BCKP_REG 6
  8. define YEAR_BCKP_REG 7
  9. define WEEKDAY_CURR 2
  10. define MONTH_CURR 2
  11. define DATE_CURR 3
  12. define YEAR_CURR 20 RTC_HandleTypeDef hrtc; static uint8_t DayCurr=0; void rtc_write_backup_reg(uint32_t BackupRegister, uint32_t data); uint32_t rtc_read_backup_reg(uint32_t BackupRegister); RTC_DateTypeDef DateToUpdate = {0}; void MX_RTC_Init(void) { RTC_TimeTypeDef sTime={0}; volatile uint8_t weekday; volatile uint8_t month; volatile uint8_t date; volatile uint8_t year; /*Initialize RTC Only */ hrtc.Instance = RTC; hrtc.Init.AsynchPrediv = RTC_AUTO_1_SECOND; hrtc.Init.OutPut = RTC_OUTPUTSOURCE_ALARM; if (HAL_RTC_Init(&hrtc) != HAL_OK) { Error_Handler(); } /* USER CODE BEGIN Check_RTC_BKUP */ weekday = rtc_read_backup_reg (WEEKDAY_BCKP_REG); month = rtc_read_backup_reg (MONTH_BCKP_REG); date = rtc_read_backup_reg (DATE_BCKP_REG); year = rtc_read_backup_reg (YEAR_BCKP_REG); if ((weekday && month && date && year) == 0) { DateToUpdate.WeekDay = WEEKDAY_CURR; DateToUpdate.Month = MONTH_CURR; DateToUpdate.Date = DATE_CURR; DateToUpdate.Year = YEAR_CURR; rtc_write_backup_reg(WEEKDAY_BCKP_REG,DateToUpdate.WeekDay & 0x00FF); rtc_write_backup_reg(MONTH_BCKP_REG,DateToUpdate.Month & 0x00FF); rtc_write_backup_reg(DATE_BCKP_REG,DateToUpdate.Date & 0x00FF); rtc_write_backup_reg(YEAR_BCKP_REG, DateToUpdate.Year & 0x00FF); } else { DateToUpdate.WeekDay = weekday; DateToUpdate.Month = month; DateToUpdate.Date = date; DateToUpdate.Year = year; } /* USER CODE END Check_RTC_BKUP */ sTime.Hours = 0x0; sTime.Minutes = 0x0; sTime.Seconds = 0x0; if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BCD) != HAL_OK) { Error_Handler(); } if (HAL_RTC_SetDate(&hrtc, &DateToUpdate, RTC_FORMAT_BCD) != HAL_OK) { Error_Handler(); } } void rtc_write_backup_reg(uint32_t BackupRegister, uint32_t data) { hrtc.Instance = RTC; HAL_PWR_EnableBkUpAccess(); HAL_RTCEx_BKUPWrite(&hrtc, BackupRegister, data); HAL_PWR_DisableBkUpAccess(); }

uint32_t rtc_read_backup_reg(uint32_t BackupRegister) { hrtc.Instance = RTC; return HAL_RTCEx_BKUPRead(&hrtc, BackupRegister); }

Please log in to post comments.