on
2021-11-16
02:12 AM
- edited on
2024-06-04
05:09 AM
by
Laurids_PETERSE
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.
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:
To configure the wake-up timer to 10s let’s calculate the Wakeup counter that was explained above:
In the exercise below we will use the values we just calculated.
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 */
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.
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()
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
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
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
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
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
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.