Home STM32 STM32 HAL Internal RTC in STM32: Time, Date & Alarm HAL Tutorial

Internal RTC in STM32

Learn how to configure the built‑in RTC on STM32 using HAL and CubeMX. Includes setting time, date, alarms, LCD display, VBAT backup – step‑by‑step guide. The project is available for download at the end of the post.

Internal RTC in STM32

Recommended Resources:

This tutorial uses LCD1602 connected via I2C to display the time and date. You should check out the following:

VIDEO TUTORIAL

You can check the video to see the complete explanation and working of this project.

Check out the Video Below

Introducing STM32 RTC

The RTC (Real-Time Clock) in STM32 microcontrollers is a highly configurable peripheral designed to keep track of the current time and date, even when the main system is powered down. It is especially useful in low-power applications where accurate timekeeping must be maintained with minimal energy consumption. The RTC can operate independently from the main processor using a dedicated low-speed clock (typically LSE or LSI), and it can retain its state across resets and power cycles using a backup power source such as a coin cell battery connected to the VBAT pin.

The RTC is often used in applications like data logging, alarms, time stamping, clock displays, and wake-up scheduling in low-power modes.

Key Features of STM32 RTC

  1. Time and Calendar Functions
    The RTC provides accurate tracking of time (hours, minutes, seconds) and calendar (date, month, year, day of the week) in either 24-hour or 12-hour format.
  2. Alarm Functionality
    Supports one or two independent alarms (Alarm A and Alarm B), which can trigger interrupts or wake up the device from low-power modes at a predefined time.
  3. Tamper and Timestamp Detection
    Capable of detecting external tamper events and logging timestamps, useful for applications requiring security or event tracking.
  4. Backup Domain and Battery Operation
    The RTC can run independently on a backup battery via the VBAT pin, ensuring continued timekeeping during power loss or system shutdown.

CUBEMX CONFIGURATION

Clock Configuration

Below is the image showing the clock configuration for this project.

STM32 RTC Clock Configuration

I am using the Nucleo F446RE board and it has both, LSE and HSE crystals on board. The LSE is 32.768Khz and HSE is of 8MHz. The LSE crystal is used to provide the clock to the RTC whereas the HSE will be used to clock the rest of the system.

In the RCC configuration, enable the crystal oscillator for both LSE and HSE. The image above shows how the clock is configured such that the RTC gets the 32.768KHz, while the rest of the system runs at 180MHz.

If your controller board does not have this dedicated LSE crystal of 32.768KHz, you can use the Internal RC oscillator (LSI RC) too.

RTC Configuration

Below is the image showing the RTC configuration.

STM32 RTC Configuration

Activate the Clock Source, Calendar and enable at least one of the Alarm.

In the parameter configuration, I have set the 24Hr Time format and Data format is set to binary format. You can set any random values for the time, date and alarm. We will write functions to set up the values for these parameters in the code itself.

The Asynchronous and Synchronous Predivider values are used to calculate the value of the ck_spre. The values should be chosen in a way that the ck_spre value = 1. The formula to calculate ck_spre is shown below.

RTC ck_spre Formula

The RTCCLK is at 32768, so using the PREDIV_A value of 127 and PREDEV_S value of 255 in the above formula results in the ck_spre value =1.

We have also configured the Alarm, so make sure to enable the Alarm interrupt in the NVIC Tab. We will use the LED connected to pin PA5 for the Alarm signal, so let’s set the pin PA5 as output.

RTC Alarm pin configuration

I2C Configuration

We are using the LCD1602 to display the current Time and Date. The LCD is connected using the PCF8574 I2C extender. Below is the image showing the I2C configuration.

STM32 I2C Configuration

I am using the I2C1 to connect the LCD. The I2C is configured in the standard mode with the clock speed set to 100KHz. The pins PB8 and PB9 are configured as the SCL and SDA pins.

We have already covered how to interface the LCD via I2C with STM32. You can check out the tutorial for more details.

NOTE that we will program the time to not reset with the board, but this is true as long as the board is connected to the power supply. When you disconnect the power supply, the time will reset and we can’t prevent this from happening. The only solution is to connect a 3V battery to the VBAT pin of the MCU. Doing this will keep the time running, and it does not matter if the MCU is connected to the power supply or not.

THE CODE

We are going to set the time and date in the program itself. So first let’s write a function to set the time and date

set_time

void set_time (uint8_t hr, uint8_t min, uint8_t sec)
{
	RTC_TimeTypeDef sTime = {0};
	sTime.Hours = hr;
	sTime.Minutes = min;
	sTime.Seconds = sec;
	sTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
	sTime.StoreOperation = RTC_STOREOPERATION_RESET;
	if (HAL_RTC_SetTime(&hrtc, &sTime, RTC_FORMAT_BIN) != HAL_OK)
	{
		Error_Handler();
	}
}

I copied this code from the pre-generated function MX_RTC_Init and commented out the code inside the pre-generated function. This is to prevent the RTC from setting the same time after the MCU resets. The parameter of the function set_time will be passed to their respective places and the function HAL_RTC_SetTime will set the time to the RTC.

set_date

void set_date (uint8_t year, uint8_t month, uint8_t date, uint8_t day)  // monday = 1
{
	RTC_DateTypeDef sDate = {0};
	sDate.WeekDay = day;
	sDate.Month = month;
	sDate.Date = date;
	sDate.Year = year;
	if (HAL_RTC_SetDate(&hrtc, &sDate, RTC_FORMAT_BIN) != HAL_OK)
	{
		Error_Handler();
	}

	HAL_RTCEx_BKUPWrite(&hrtc, RTC_BKP_DR1, 0x2345);  // backup register
}

I copied this code again from the pre-generated function MX_RTC_Init and commented out the code inside the pre-generated function. This is to prevent the RTC from setting the same date after the MCU resets.The parameter of the function set_date will be passed to their respective places and the function HAL_RTC_SetDate will set the date to the RTC.

Note here that the day starts with Monday, therefore Monday = 1 and Sunday = 7.

The function HAL_RTCEx_BKUPWrite writes a random value to the backup Register RTC_BKP_DR1. The unique thing about this backup register is that it does not reset when the MCU resets, therefore the value (0x2345 in this case) will always be stored inside this Register, until we change it to some other value.

In the main function, we will read this backup Register. If it has the value we stored (0x2345), we will not update the time again. This prevents our code from writing the same time/date into the RTC every time the MCU resets.

This function HAL_RTCEx_BKUPWrite is being called in the set_date function, so you must call the set_date function in the main function. Otherwise, even the time will not be able to keep up after the reset.

Get Time & Date

Below is the function to get the time and date from the RTC.

void get_time_date(char *time, char *date)
{
  RTC_DateTypeDef gDate;
  RTC_TimeTypeDef gTime;

  /* Get the RTC current Time */
  HAL_RTC_GetTime(&hrtc, &gTime, RTC_FORMAT_BIN);
  /* Get the RTC current Date */
  HAL_RTC_GetDate(&hrtc, &gDate, RTC_FORMAT_BIN);

  /* Display time Format: hh:mm:ss */
  sprintf((char*)time,"%02d:%02d:%02d",gTime.Hours, gTime.Minutes, gTime.Seconds);

  /* Display date Format: dd-mm-yyyy */
  sprintf((char*)date,"%02d-%02d-%2d",gDate.Date, gDate.Month, 2000 + gDate.Year);
}

The parameters of this function are:

  • @time is the pointer to the character array, where the time data will be stored in the character form.
  • @date is the pointer to the character array, where the date data will be stored in the character form.

Inside this function, we will first call the functions HAL_RTC_GetTime and HAL_RTC_GetDate to get the time and date in the binary format. The respective data will be stored in the RTC time and date structures.

If you want the data in number form, you can just define these structures globally, and then utilise the time and date data. But here I want to display them on the LCD, so I need to convert them to the character format.
The function sprintf will convert these numeric data in the character format and store them in the respective arrays.

set_alarm

The following function is used to set the ALARM.

void set_alarm (uint8_t hr, uint8_t min, uint8_t sec, uint8_t date)
{
	RTC_AlarmTypeDef sAlarm = {0};
	sAlarm.AlarmTime.Hours = hr;
	sAlarm.AlarmTime.Minutes = min;
	sAlarm.AlarmTime.Seconds = sec;
	sAlarm.AlarmTime.SubSeconds = 0;
	sAlarm.AlarmTime.DayLightSaving = RTC_DAYLIGHTSAVING_NONE;
	sAlarm.AlarmTime.StoreOperation = RTC_STOREOPERATION_RESET;
	sAlarm.AlarmMask = RTC_ALARMMASK_NONE;
	sAlarm.AlarmSubSecondMask = RTC_ALARMSUBSECONDMASK_ALL;
	sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_DATE;
	sAlarm.AlarmDateWeekDay = date;
	sAlarm.Alarm = RTC_ALARM_A;
	if (HAL_RTC_SetAlarm_IT(&hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK)
	{
		Error_Handler();
	}
}

The parameters of the function are the date and time when we want the Alarm to trigger. This function is again copied from the pre-generated function MX_RTC_Init and I commented out this code inside the pre-generated function. The parameter of the function set_alarm will be passed to their respective places and the function HAL_RTC_SetAlarm will configure the Alarm in the RTC.

ALARM Event Callback

When the conditions for the Alarm in the RTC are met, an interrupt will trigger and the HAL_RTC_AlarmAEventCallback will be called. We will write our code inside this function.

void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc) 
{ 
  HAL_GPIO_WritePin (GPIOA, GPIO_PIN_5, 1); // turn on the LED 
}

Inside this function we will set the pin PA5, which is connected to the LED on board. So the LED will turn on indicating the Alarm.

The main function

int main ()
{
  ....
  lcd_init();
  if (HAL_RTCEx_BKUPRead(&hrtc, RTC_BKP_DR1) != 0x2345)
  {
    set_time(15, 54, 00);
    set_date(24, 8, 11, 7);
  }
  set_alarm(15, 55, 0, 11);

Inside the main function we will first initialise the LCD. Then we will read the RTC backup Register. If it has the value we stored (0x2345), we will not update the time again. This prevents our code from writing the same time/date into the RTC every time the MCU resets.

But if the value stored in the Backup Register is not equal to 0x2345, that would mean that this is the first time the code is running and hence we need to set the time and date in the RTC. Here I am setting the current time and date. Also set the alarm by calling the set_alarm function.

We will read the time in the while loop as shown below.

  while (1)
  {
    get_time_date(timeData, dateData);
    lcd_put_cur(0,0);
    lcd_send_string(timeData);
    lcd_put_cur(1,0);
    lcd_send_string(dateData);
    HAL_Delay(500);
  }
}

Here we will first read time and date data. The data is stored in the arrays, timeData and dateData, in the character form. We will print these arrays on the LCD.

RESULT

Below is the gif showing the result of the above code.

STM32 RTC Working

As you can see above, the time is updating every second on the LCD. Also note that as soon as the alarm is triggered, the LED on board tuns ON. This indicates that the Alarm was triggered successfully.

PROJECT DOWNLOAD

Info

You can help with the development by DONATING Below.
To download the project, click the DOWNLOAD button.

You May Also Like

Subscribe
Notify of

18 Comments
Newest
Oldest Most Voted
Inline Feedbacks
View all comments
Maryam
2 years ago

Hello, thank you so much.
I have a problem. May you help me please?
In my project,I don’t use RTC, so the pins of microcontroller for RTC oscillator are not connected.
When the power is connected to my stm32 board, the code isn’t run until I touch the location of RTC Oscillator (32kHz crystal and 2.7pF capacitors).After this, the code is run correctly.

Thank’s for your guidance

Thamanoon Kedwiriyakarn
2 years ago

Hello, thank you very much for your tuterial.

hmmm
3 years ago

No matter how you slice it, 0x18 will never equal the year 2018.

Ghani
4 years ago

hi, how can I Download the code?

didi
4 years ago

sAlarm.AlarmDateWeekDaySel = RTC_ALARMDATEWEEKDAYSEL_WEEKDAY;
hi any idea how to set the alarm register if you wantalarm monday to friday.
sAlarm.AlarmDateWeekDay = 1;//Monday

sss
4 years ago

hi, i did simlar project. It works well but except; after soft reset, ı can get correct time but date resets itself. Do you have any suggestion.?
thnx

SkyAndy
4 years ago
A declaration of the sAlarm variable is missing in the description

add follow Line

void set_alarm(void) {
   RTC_AlarmTypeDef sAlarm;

sadeq
5 years ago

hi
I need a library to drive 16*2 LCD (not i2c version) in CUBE IDE (using HAL) for stm32f103.
can you help me about this?
thank you

Fernando
Reply to  sadeq
3 years ago

I have it a good one!

john bahtia
5 years ago

there is something wrong with my code. i try to run it but the pc doesnt register the time on the stm32

5 years ago

I want to use STM32 microcontroller to implement a real time clock. The problem is when the controller has no power, how can I keep the real time clock still going?

sss
Reply to  Anthony Cheng
4 years ago

use cr2032 battery

olga
6 years ago

Hi
I tried the code but in my screen I can see 00:00:00 01-01-2000

kaushla
Reply to  olga
3 years ago

so you have to set date and time in RTC_init function

keyboard_arrow_up