cancel
Showing results for 
Search instead for 
Did you mean: 

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

ST AME Support NF
ST Employee

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

1. Introduction


The STM32’s integrated RTC (Real-Time Clock) peripheral can be used to periodically wake it up from one of the various Low Power modes. It is very 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 see how to configure the RTC peripheral of the STM32 to wake up the STM32 periodically from a low power mode like STOP2 mode which is one of the lowest power modes of the STM3L4.

2. Pre-requisite

 
  • Hardware:
    • Mini USB cable to power and program the board
    • Nucleo-L476
1772.png
  • Software
    • STM32CubeIDE
 

3. Theory


The RTC in the STM32 can be configured as a wakeup source and used to wake up the microcontroller from low power modes like STOP. . Let’s say we want to wake up every 10 seconds from the STOP mode, the RTC can easily be set up to do that. The RTC clock source for the STM32L476, the microcontroller used in this example on the Nucleo-L476 board, can be provided by either the LSI (Low Speed Internal) or LSE (Low Speed External) oscillator. The Nucleo board includes a 32.768 KHz crystal connected to the LSE oscillator pins. For this exercise, the LSE oscillator will be selected as the clock source for the RTC as it offers more precision than the LSI oscillator.
We are going to calculate the WakeUp Counter of the RTC so that it wakes up the STM32 every 10 seconds. Let’s set the prescaler of the RTC clock to 16 as an example. Here are the equations to calculate the WakeUp Counter settings:
 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
 
 To configure the wake-up timer to 10s let’s calculate the Wakeup counter that was explained above:
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

In the exercise below we will use the values we just calculated.


4. Steps

  1. Open STM32CubeIDE  
  2. Create a new project using the NUCLEO-L476 board

1773.png
 
  1. Enter a name for the project. 
  • For this article I will call my project “RTCWakeUP”
1774.png
 
  1. Initialize all peripherals with their default settings:
  • To do this please click on Yes below:
1775.png
  1. Select RTC
  • In the “Pinout & Configuration” Tab, under Timers, select RTC:
1776.png
  1. Activate the clock source and enable the Internal WakeUp
  • First click on “Activate Clock Source” to enable the clock to the RTCperipheral.
  • For WakeUp, select “Internal WakeUp” as opposed to outputting the WakeUp signal to a pin. This Internal WakeUp will be responsible for waking up the STM32 from low power mode after the programmed period of time set in the RTC.
1777.png
  1. Configure RTC
  • We will use the values we calculated earlier in this article. Select Wake Up Clock to be RTCCLK /16 and then set the Wake Up Counter to 0x500B.
1778.png
 
  1. Enable RTC global interrupts
  • 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
  1. Set the clock source of the RTC to LSE (external 32.768 KHz crystal that is on the Nucleo board):
  • In the Clock Configuration Tab select LSE for the RTC source Mux as seen below:
1780.png
 
  1. Generate Code
  • Save the project and that will generate the code.
  1. Adding code
  • Now we are going to add some code to put the STM32 in a low power mode: STOP 2 mode and wakeup 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, entering STOP 2 mode and then the RTC waking up the STM32 after 10 seconds. When the RTC wakes up the device, execution goes to the RTC ISR to clear some RTC fags and then goes back to main to continue code execution.

 
  /* 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 */
 
  1. 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 off for 10 seconds (STM32 in low power mode) and then RTC wakes up the STM32 and the LED will be turned on again and this will be continuously repeated.
 

5. Links


STM32L496 - Datasheet
STM32L47xxx, STM32L48xxx, STM32L49xxx and STM32L4Axxx advanced Arm®-based 32-bit MCUs - Reference manual
STM32CubeIDE - Integrated Development Environment for STM32 - STMicroelectronics
NUCLEO-L476RG - STM32 Nucleo-64 development board with STM32L476RG MCU, supports Arduino and ST morpho connectivity - STMicroelectronics
Comments
TKusc.1
Associate

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
Associate III

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
Associate III

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
Associate III

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

Version history
Last update:
‎2021-11-16 02:12 AM
Updated by: