cancel
Showing results for 
Search instead for 
Did you mean: 

How to configure the RTC to wake up the STM32 from Low Power modes

ST AME Support NF
ST Employee

Introduction

The STM32’s integrated RTC (Real-Time Clock) peripheral can be used to wake it up from one of the various low-power modes. It is common for battery powered applications to have a power scheme where the application will run for a short period of time and then enter a low power mode to save power and extend battery life. The RTC can be used to wake up the STM32 from a low-power mode, even in the lowest power mode like Standby.
In this article we will present the basic configuration of the RTC (Section 3.1), and two schemes of configuring the RTC peripheral of the STM32 to wake up the STM32 periodically from a low-power mode like STOP2:

  1. Using the Internal WakeUp counter to wake-up the MCU after a specified delay (Section 3.2).
  2. Using the Calendar and Alarm features of the RTC to wake-up at specified timestamps (Section 3.3).  

The basic configuration of the RTC (Section 3.1) is shared between these two implementations, but they must be configured separately.

 

1. Prerequisites:

  • Hardware:

1772.png

 

2. Theory

The RTC in the STM32 can be configured to generate EXTI interrupts, which wake-up the MCU if it is in a low-power mode. The RTC clock source for the STM32L476, the microcontroller used in this example on the Nucleo-L476RG board, can be provided by either the low-speed internal (LSI) oscillator or the low-speed external (LSE) oscillator. The Nucleo board includes a 32.768 kHz crystal connected to the LSE oscillator pins. For this exercise, the LSE oscillator is selected as the clock source for the RTC because it offers greater precision than the LSI oscillator.

Waking up after a delay with the Internal WakeUp Counter

The RTC features the Internal WakeUp Counter, which can be configured to count to a specific value while the MCU is in a low-power mode. Then, after this value is reached, the RTC generates an EXTI interrupt, waking the MCU up.

When configuring the RTC to generate interrupts with the WakeUp counter after a specified amount of time, it is necessary to calculate the counter value based on the clock provided to the RTC. The prescaler of the RTC clock is set to 16 in this example. The equations to calculate the wake-up counter settings are as follows:

  • RTC_WAKEUPCLOCK_RTCCLK_DIV = RTCCLK_Div16 = 16
  • Wakeup Time Base = (RTC_WAKEUPCLOCK_RTCCLK_DIV /(LSI))
  • Wakeup Time = Wakeup Time Base * WakeUpCounter
            = (RTC_WAKEUPCLOCK_RTCCLK_DIV /(LSI)) * WakeUpCounter
            ==> WakeUpCounter = Wakeup Time / Wakeup Time Base

 
In this example, the counter is set to trigger after 10 seconds:

  • Wakeup Time Base = 16 /(~32.768KHz )  = 0.488 ms
  • Wakeup Time = 0.488 ms  * WakeUpCounter
  • WakeUpCounter = Wakeup Time / 0.488 ms = 10s / 0.488 ms = 20491 = 0x500B

This configuration is utilized in Section 3.2.

Waking up at a timestamp using the Calendar and Alarm(s)

In some applications, it may be necessary for the microcontroller unit (MCU) to remain in a low-power mode until a specified timestamp. To achieve this, the calendar and alarm features of the real-time clock (RTC) peripheral can be used.

The calendar only needs to be configured once when powering on the MCU, and its contents are retained throughout resets as long as the MCU is powered by VDD or VBAT, where available. Note that STM32CubeMX-generated code, by default, sets the calendar to the time provided in the peripheral setup window upon every MCU reset. For proper timekeeping, a custom implementation by the application is necessary to set the internal time and date of the RTC calendar.

An alarm can be set to trigger an EXTI interrupt when the calendar's timestamp matches the one specified by the alarm. Certain fields (date, hours, seconds, etc.) can be configured to be masked when checking for this equality, meaning that the RTC will ignore them during this check.

In Section 3.3 of this article, as an example, the RTC is configured to generate an alarm on the 5th second of every minute according to its internal reference time. This is achieved by enabling masking of all the time fields except for the Seconds field.


3. Application

3.1 Creating an STM32CubeIDE project and basic RTC configuration

  1. Open STM32CubeIDE.
  2. Create a new project with the NUCLEO-L476RG board selected as the target. 1773.png
  3. Enter a name for the project.  1774.png
  4. Initialize all peripherals with their default settings by selecting [Yes] in the following dialog: 1775.png
  5. Set the clock source of the RTC to LSE (external 32.768 KHz crystal that is on the Nucleo board) by selecting LSE for the RTC Source Mux in the Clock Configuration Tab as seen below: 1780.png
  6. In the Pinout & Configuration Tab, under Timers, select RTC and check the Activate Clock Source option to enable it:pepfof_0-1758029395643.png

     


Now the RTC is enabled and can be further configured to use one of the two aforementioned schemes for generating the wake-up interrupts. These schemes are presented below and are to be implemented separately. Section 3.2 will describe the usage of the Internal WakeUp Counter, and Section 3.3 will describe the usage of the Calendar and Alarm features of the RTC.

3.2 Wake-up after a delay

  1. Enable the Internal WakeUp feature of the RTC by selecting Internal WakeUp in the WakeUp dropdown of the RTC configuration panel.pepfof_0-1758031684245.png

     

  2. Configure the WakeUp counter. Select RTCCLK / 16 as the Wake Up Clock and then set the Wake Up Counter to 0x500B according to the calculation in Section 2 of this article.1778.png
  3. Enable the wake-up EXTI interrupt in the NVIC settings tab.
    • We will be entering STOP mode using WFI (Wait For Interrupts), so to wake up from STOP mode, we will need to enable interrupts for the RTC.
    1779.png
  4. Generate the Code by saving the MCU configuration.
  5. Add code utilizing the RTC's Internal WakeUp to the project.
    • Now that the RTC and its Internal WakeUp are configured, we are going to add some code to put the STM32 in STOP2 mode and wake-up with the RTC that we have configured.
    • STOP2 mode is one of the lowest power modes offered in the STM32L4 and that offers a fast wakeup time and preserved RAM and registers configuration. 
    • In main, execution loops on turning the LED on for 1 second, sets up the WakeUp Counter and enters STOP2 mode. Subsequently, the RTC wakes up the STM32 as soon as 10 seconds elapse.
    You may copy this snippet into your main.c file - take note of the "/* USER CODE BEGIN x */" markers and place the relevant sections in the places that these are located in your code.
    /* USER CODE BEGIN WHILE */
    while (1)
    {
    
    HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_SET);
    HAL_Delay(1000);
    HAL_GPIO_WritePin(LD2_GPIO_Port, LD2_Pin, GPIO_PIN_RESET);
    
    
    HAL_SuspendTick();
    HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0x500B, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
    
    /* Enter STOP 2 mode */
    HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
    HAL_RTCEx_DeactivateWakeUpTimer(&hrtc);
    SystemClock_Config();
    HAL_ResumeTick();
    /* USER CODE END WHILE */        
  6. Now build the code, load it and reset the board to start execution.
    • You will see the LED turn on for one second and then turn off for 10 seconds (this indicates that the STM32 is in low power mode). Then, the RTC wakes up the STM32 and the LED will be turned on again repeatedly.

3.3 Wake-up at a specific timestamp

  1. Enable the Calendar and Alarm features in the RTC configuration panel:
    • Check the Activate Calendar option.
    • For one of the available alarms (Alarm A in this instance), select Internal Alarm from the appropriate dropdown.
    Note that the Calendar Time and Date are not modified in this example and are set to their default value of Jan 1. of the 0th year. As we will be configuring the alarm to trigger every minute with masking, this does not make a difference in our application. In real-world applications, these fields need to be modified by user code for proper time-keeping.Screenshot 2025-09-16 112405.png
  2. Configure Alarm A in the Parameter Settings tab:
    • Set the Seconds field to 5.
    • Enable masking for all fields of the Alarm except for Seconds.Screenshot 2025-09-16 112517.png
    With this configuration, the timestamp will match the one specified by Alarm A every time the RTC's calendar has the value of "5" in the Seconds field, meaning that it will trigger on the 5th second of every elapsed minute.
    With proper time-keeping implemented by the user application, this setup can be modified and the masking removed to generate the EXTI interrupt at an arbitrary timestamp.
  3. Enable the alarm EXTI interrupt in the NVIC settings tab.
    • We will be entering STOP mode using WFI (Wait For Interrupts), so to wake up from STOP mode, we will need to enable interrupts for the RTC.
    pepfof_0-1758032384714.png
  4. Generate the Code by saving the MCU configuration.
  5. Add code utilizing the RTC's Calendar and Alarms to the project.
    • Now that the RTC and its Calendar and Alarm A are configured, we are going to add some code to toggle the state of the Green LED available on the Nucleo, and then enter STOP2 mode. Note that the Alarm configuration code is generated automatically by STM32CubeMX in the MX_RTC_Init() function, so no code accessing the RTC is required in the main loop.
    • Every time the LED changes state indicates that the MCU has exited STOP2 mode, toggled it, and entered STOP2 mode once more. With the previous alarm configuration, this will happen on the 5th second, and then every minute on, from the reset of the MCU.
    • Note again that STM32CubeMX generates the code in such a way that the Calendar has its time and date set to the same value on every reset of the MCU. This means that time-keeping will not persist across resets in this example, but can be easily amended in your real-world application.
    You may copy this snippet into your main.c file - take note of the "/* USER CODE BEGIN x */" markers and place the relevant sections in the places that these are located in your code.
    /* USER CODE BEGIN WHILE */
    while (1)
    {
    /* Toggle LED */
    HAL_GPIO_TogglePin(LD2_GPIO_Port, LD2_Pin);
    
    HAL_SuspendTick();
    /* Enter STOP 2 mode */
    HAL_PWREx_EnterSTOP2Mode(PWR_STOPENTRY_WFI);
    SystemClock_Config();
    HAL_ResumeTick();
    /* USER CODE END WHILE */
  6. Now build the code, load it and reset the board to start execution.
    • You will see the LED turn on for 5 seconds and then toggle every minute, meaning that the alarm is getting triggered repeatedly.

 

4. Related Links

Comments
TKusc.1
Associate II

Thanks, nice article. ICNR, the calculation of the WakeUpCounter results exactly in 0x5000 (20480 dec) time. It is easier (for me) to calculate as follows:

The XTAL 'counts' 32768 per second. We divide by 16 i.e. 2048 oszillations (counts) per second. 10 sec: Multiplied with 10 is 20480 or 0x5000.

Strooom
Senior

This is a useful article. But, when implementing this on my design, it does not work 100% :

If other code (in the main loop while(1)) uses critical sections (to achieve thread safety from ISR), the MCU does not stay asleep, but wakes up immediately..

If you have no other code disabling/enabling interrupts, then the MCU goes into sleep without problems.

See this question : STM32WLE immediately exist Stop2 when using UTILS_ENTER_CRITICAL_SECTION()

Strooom
Senior

Hi, the above problem was due to a certain function disabling the interrupts, and then the WFI does not stop the MCU.

After correcting this, the above example works perfect. Thank you

Dodo
Associate II

Hi Laura,

Nice example does it also apply to the stm32wle5J?

And is it possible to use a time based wakeup and a external interrupt wakeup as well?

Thanks for your time.

Greetings Dom

Dodo
Associate II

Ok I tried it out of the blue and it generates an error. It says:

09:29:23 **** Incremental Build of configuration Debug for project Seeed-LoRa-E5 ****
make -j16 all 
arm-none-eabi-gcc "../Core/Src/main.c" -mcpu=cortex-m4 -std=gnu11 -g3 -DDEBUG -DCORE_CM4 -DUSE_HAL_DRIVER -DSTM32WLE5xx -c -I../Core/Inc -I"C:/Users/Dominik/Downloads/Seeed-LoRa-E5-master/Drivers/BSP/STM32WLxx_Nucleo" -I../Drivers/STM32WLxx_HAL_Driver/Inc -I../Drivers/STM32WLxx_HAL_Driver/Inc/Legacy -I../Drivers/CMSIS/Device/ST/STM32WLxx/Include -I../Drivers/CMSIS/Include -I../LoRaWAN/App -I../LoRaWAN/Target -I../Utilities/trace/adv_trace -I../Utilities/misc -I../Utilities/sequencer -I../Utilities/timer -I../Utilities/lpm/tiny_lpm -I../Middlewares/Third_Party/LoRaWAN/LmHandler/Packages -I../Middlewares/Third_Party/SubGHz_Phy -I../Middlewares/Third_Party/SubGHz_Phy/stm32_radio_driver -I../Middlewares/Third_Party/LoRaWAN/Crypto -I../Middlewares/Third_Party/LoRaWAN/Mac/Region -I../Middlewares/Third_Party/LoRaWAN/Mac -I../Middlewares/Third_Party/LoRaWAN/LmHandler -I../Middlewares/Third_Party/LoRaWAN/Utilities -O0 -ffunction-sections -fdata-sections -Wall -fstack-usage -fcyclomatic-complexity -MMD -MP -MF"Core/Src/main.d" -MT"Core/Src/main.o" --specs=nano.specs -mfloat-abi=soft -mthumb -o "Core/Src/main.o"
../Core/Src/main.c: In function 'main':
../Core/Src/main.c:106:34: error: 'hrtc' undeclared (first use in this function)
  106 |     HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0x500B, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
      |                                  ^~~~
../Core/Src/main.c:106:34: note: each undeclared identifier is reported only once for each function it appears in
../Core/Src/main.c:106:5: error: too few arguments to function 'HAL_RTCEx_SetWakeUpTimer_IT'
  106 |     HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0x500B, RTC_WAKEUPCLOCK_RTCCLK_DIV16);
      |     ^~~~~~~~~~~~~~~~~~~~~~~~~~~
In file included from ../Drivers/STM32WLxx_HAL_Driver/Inc/stm32wlxx_hal_rtc.h:738,
                 from ../Core/Inc/stm32wlxx_hal_conf.h:281,
                 from ../Drivers/STM32WLxx_HAL_Driver/Inc/stm32wlxx_hal.h:29,
                 from ../Core/Inc/main.h:30,
                 from ../Core/Src/main.c:20:
../Drivers/STM32WLxx_HAL_Driver/Inc/stm32wlxx_hal_rtc_ex.h:1141:19: note: declared here
 1141 | HAL_StatusTypeDef HAL_RTCEx_SetWakeUpTimer_IT(RTC_HandleTypeDef *hrtc, uint32_t WakeUpCounter, uint32_t WakeUpClock, uint32_t WakeUpAutoClr);
      |                   ^~~~~~~~~~~~~~~~~~~~~~~~~~~
make: *** [Core/Src/subdir.mk:76: Core/Src/main.o] Error 1
"make -j16 all" terminated with exit code 2. Build might be incomplete.
 
09:29:23 Build Failed. 3 errors, 0 warnings. (took 486ms)
 

I´m not sure it is undeclared?

Greetings Dom

Strooom
Senior

hrtc is a 'handle' to the RTC object. It is declared in main.c

if you want to use it in other source code files, you have to add

extern RTC_HandleTypeDef hrtc;

and for the RTC_HandleTypeDef to be a known type, you have to include eg. main.h

Dodo
Associate II

Hmm I added the code like so:

/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "gpio.h"
 
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
    extern RTC_HandleTypeDef hrtc;
/* USER CODE END Includes */

After that there is an error about too few arguments within the call:

HAL_RTCEx_SetWakeUpTimer_IT(&hrtc, 0x500B, RTC_WAKEUPCLOCK_RTCCLK_DIV16);

Which I do understand because when following the expression via (Ctrl- right click) I do see that there should be:

HAL_StatusTypeDef HAL_RTCEx_SetWakeUpTimer_IT(RTC_HandleTypeDef *hrtc, uint32_t WakeUpCounter, uint32_t WakeUpClock, uint32_t WakeUpAutoClr)

four I guess. But it is not autogenerated be Cube MX?

Regards Dom

pradeepwagre
Associate III

What I need to do if I want to wake up the mcu at specific time.For example if 24hrs format for RTC is configured.I want mcu to wake up at 6am and 12pm.Do some job and again go to sleep.

Version history
Last update:
‎2025-11-28 7:42 AM
Updated by: