In this tutorial, we’ll discuss The STM32 Deep Sleep (Low Power Sleep) Mode, how to enter the low power sleep mode, and how to exit from it with some code examples and a full test project. Without further ado, let’s get right into it!
Table of Contents
- STM32 Deep Sleep (Low Power Sleep) Mode
- STM32 Enter Deep Sleep (Low Power Sleep) Mode
- STM32 Exit Deep Sleep (Low Power Sleep) Mode
- STM32 Deep Sleep (Low Power Sleep) Example Code Project
- Wrap Up
STM32 Deep Sleep (Low Power Sleep) Mode
The STM32 Low Power Sleep Mode (Deep Sleep) is entered from the Low Power Run Mode. It’s a combination of Low Power Run (LPR) Mode and Sleep Mode to achieve even less current consumption than both modes. According to the following state diagram that shows all the possible transitions for STM32 low-power modes, we first need to go from “Run Mode” to “Low Power Run Mode”, then we go into “Low Power Sleep (Deep Sleep) Mode”.
1) Go to Low Power Run Mode
Low Power Run mode is achieved by reducing the system clock frequency (SYSCLK) below 2 MHz. The code is executed from the SRAM or the flash memory. The regulator is in low-power mode to minimize its operating current.
For the STM32L432KC target microcontroller, in Low-Power Run Mode, the current consumption is:
- At 2MHz: 211µA
- At 100kHz: 30µA
2) Go to Low Power Sleep (Deep Sleep) Mode
This mode is entered from the Low-power run mode. Only the CPU clock is stopped. When wake-up is triggered by an event or an interrupt, the system reverts to the Low-power run mode.
Unlike Sleep mode, in Low-power sleep mode (Deep Sleep): the main regulator is OFF and the low-power regulator is ON.
For the STM32L432KC target microcontroller, in Low-Power Sleep (Deep Sleep) Mode, the current consumption is:
- At 2MHz: 72µA
- At 100kHz: 23µA
Unlike the STM32 sleep mode, while the target MCU is in the deep sleep (low-power sleep) mode, it’s not possible to start a debugging session. Due to the fact that the CPU core is no longer clocked during low-power mode, so debugging features are disabled.
STM32 Enter Deep Sleep (Low Power Sleep) Mode
To enter the low-power sleep (deep sleep) mode, we must first go into low-power run (LPR) mode. Then we can move into low-power sleep (deep sleep) mode.
#1
To go from Run mode to Low Power Run Mode, set the SYSCLK to 2MHz or less.
This can be done by selecting another clock source than the HSI/PLL which is typically way above this limit. The MSI clock source may be a good candidate for this purpose.
#2
Then, we can move from the low-power run mode to the low-power sleep (deep sleep) mode using the HAL_PWR_EnterSLEEPMode() function.
Here is a code example for entering the STM32 Deep Sleep (Low Power Sleep) Mode:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
void Enter_LowPowerSleepMode(void) // Enter DeepSleep Mode { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; //---[ Go To Low Power Run Mode ]--- // Step1: Switch To The LowFreq. MSI Clock (2MHz) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = 0; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_5; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI; // <--- Use MSI Instead of HSI-PLL RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { Error_Handler(); } // Step2: Enable Low Power Run Mode HAL_PWREx_EnableLowPowerRunMode(); //---[ Go To Low Power Sleep Mode ]--- DeepSleepMode_Activated = 1; HAL_SuspendTick(); HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI); } |
Note that the HAL_PWREx_EnableLowPowerRunMode() function should only be called after switching the SYSCLK down to 2MHz or less.
You need to Stop The SysTick Timer as it will wake up the CPU every 1ms through its interrupt signal. And don’t forget to resume its operation upon waking up to make sure any systick-dependent software components will continue to operate normally.
STM32 Exit Deep Sleep (Low Power Sleep) Mode
To exit from the low-power run mode, we can use any signal we want since the microcontroller is essentially running but at a much lower speed. EXTI pin interrupts are available, timer interrupts, or whatever your system needs.
#1
Upon receiving an interrupt signal, the CPU automatically wakes up from the low-power sleep (deep sleep) mode and gets back into the low-power run (LPR) mode. Therefore, we need to re-enable the Systick timer using the HAL_ResumeTick() function after waking up from sleep.
#2
To completely reverse the effect of going into deep sleep mode, we still need to get out of the low power run (LPR) mode back to the normal run mode at full speed (i.e. 80MHz, or whatever). To do this, we need to switch the clock source back from the low-frequency MSI to the HSI-PLL (@ 80MHz, or whatever your original system’s clock was).
This is an example code for exiting the low-power sleep (deep sleep) mode upon receiving an EXTI interrupt on the GPIO1 line.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 |
void Exit_LowPowerSleepMode(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; // Step1: Disable Low Power Run Mode HAL_PWREx_DisableLowPowerRunMode(); // Step2: Switch Back To The HSI-PLL Clock (80MHz) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 1; RCC_OscInitStruct.PLL.PLLN = 10; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // <--- Switch Back To The HSI-PLL RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { Error_Handler(); } // Step3: Resume SysTick HAL_ResumeTick(); DeepSleepMode_Activated = 0; } |
STM32 Deep Sleep (Low Power Sleep) Example Code Project
In this example project, we’ll configure our STM32L432KC microcontroller to run at full speed (80MHz) for 1 second. Then it’ll automatically switch to the low-power sleep (deep sleep) mode.
Upon receiving an EXTI interrupt on the GPIO1 pin from a push button, the system will switch back to the original full-speed run operation (80MHz). And it’ll keep toggling between both modes each time the interrupt button is pressed.
The system operation will be observed using a GPIO output pin (PB3) going to an LED that keeps toggling inside the main while(1) loop. It’s better to use a power profiler that can measure the board’s current consumption.
Step #1
Open STM32CubeMX, create a new project, and select the target microcontroller. For me, it’s (STM32L432KC)
Step #2
Configure a GPIO pin in EXTI input pull-down mode (button). I’ll use A1 pin (EXTI1), you can choose any EXTI-capable pin.
Enable The EXTI interrupt from the NVIC configuration tab.
Configure a GPIO output pin (PB3) that goes to an LED which indicates whether the CPU is running or sleeping currently.
Step #3
Go to the Clock configuration page and select the internal HSI+PLL as a clock source to give you the maximum SysClk of 80MHz (in my case). This is the base full-speed run mode.
When I want to switch to the low-power run mode, I’ll need to use a 2MHz clock source. For that purpose, I’ll use the internal MSI clock source. As indicated in the screenshot below. There are two paths for the clock that feeds my SysClk with 80MHz or 2MHz.
Step #4
Name & Generate The Project Initialization Code For CubeIDE or The IDE You’re Using.
STM32 Deep Sleep (Low Power Sleep) Example Code
Here is The Application Code For This LAB (main.c)
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 |
/* * LAB Name: STM32 Low Power Sleep Mode (DeepSleep) Test Project * Author: Khaled Magdy * For More Info Visit: www.DeepBlueMbedded.com */ #include "main.h" void SystemClock_Config(void); static void MX_GPIO_Init(void); void Enter_LowPowerSleepMode(void); void Exit_LowPowerSleepMode(void); uint8_t DeepSleepMode_Activated = 0; uint8_t EnterDeepSleepFlag = 0; int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); HAL_Delay(1000); Enter_LowPowerSleepMode(); while (1) { if(EnterDeepSleepFlag) { // Re-Enter Sleep Mode! EnterDeepSleepFlag = 0; Enter_LowPowerSleepMode(); } HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_3); HAL_Delay(100); } } void Enter_LowPowerSleepMode(void) // Enter DeepSleep Mode { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; //---[ Go To Low Power Run Mode ]--- // Step1: Switch To The LowFreq. MSI Clock (2MHz) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_MSI; RCC_OscInitStruct.MSIState = RCC_MSI_ON; RCC_OscInitStruct.MSICalibrationValue = 0; RCC_OscInitStruct.MSIClockRange = RCC_MSIRANGE_5; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_MSI; // <--- Use MSI Instead of HSI-PLL RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { Error_Handler(); } // Step2: Enable Low Power Run Mode HAL_PWREx_EnableLowPowerRunMode(); //---[ Go To Low Power Sleep Mode ]--- DeepSleepMode_Activated = 1; HAL_SuspendTick(); HAL_PWR_EnterSLEEPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI); } void Exit_LowPowerSleepMode(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; // Step1: Disable Low Power Run Mode HAL_PWREx_DisableLowPowerRunMode(); // Step2: Switch Back To The HSI-PLL Clock (80MHz) RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSI; RCC_OscInitStruct.HSIState = RCC_HSI_ON; RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT; RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON; RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSI; RCC_OscInitStruct.PLL.PLLM = 1; RCC_OscInitStruct.PLL.PLLN = 10; RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV7; RCC_OscInitStruct.PLL.PLLQ = RCC_PLLQ_DIV2; RCC_OscInitStruct.PLL.PLLR = RCC_PLLR_DIV2; if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK) { Error_Handler(); } RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2; RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK; // <--- Switch Back To The HSI-PLL RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1; RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1; RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1; if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_4) != HAL_OK) { Error_Handler(); } // Step3: Resume SysTick HAL_ResumeTick(); DeepSleepMode_Activated = 0; } void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) { if(GPIO_Pin == GPIO_PIN_1) // If The INT Source Is EXTI Line1 (A1 Pin) { if(DeepSleepMode_Activated == 1) { // CPU Has Exited From Low Power Sleep Mode To Low Power Run Mode Exit_LowPowerSleepMode(); } else { // Re-Enter Deep Sleep Mode! EnterDeepSleepFlag = 1; } } } |
STM32 Deep Sleep (Low Power Sleep) Mode Example Testing
To test this project, you’d better use a power profiler kit that can measure extremely low currents (in µA or even nA range). Development boards are not ideal for such application testing because they typically have onboard sensors, LEDs, and a bunch of extra passive/active electronics that draw a significant amount of current compared to the MCU under test.
If you’re using a different target STM32 microcontroller, or you’re willing to use different clock settings than mine (STM32L432KC @ 80MHz). Let’s say you’d like to run at 48MHz in full-speed mode and 100kHz in low-power run mode. Then you can do the following:
- Configure your clock in CubeMX to the desired full speed (i.e. 48MHz, 100MHz, 280MHz, or whatever)
- Generate the code
- Copy the contents of the SystemClock_Config() function
- Go back to CubeMX and select the desired low-frequency source (i.e. MSI 100kHz, 1MHz, or whatever value below 2MHz)
- Generate the code
- Copy the contents of the SystemClock_Config() function again
- Now you’ve got the clock configuration code for both cases of going into and out of the low-power sleep mode!
- Use the clock initialization code snippets you’ve copied so far and replace the contents of the provided example in both Enter_LowPowerSleepMode() and Exit_LowPowerSleepMode() functions.
Required Parts For STM32 Examples
All the example Code/LABs/Projects in this STM32 Series of Tutorials are done using the Dev boards & Electronic Parts Below:
QTY. | Component Name | Amazon.com | AliExpress | eBay |
1 | STM32-F103 BluePill Board (ARM Cortex-M3 @ 72MHz) | Amazon | AliExpress | eBay |
1 | Nucleo-L432KC (ARM Cortex-M4 @ 80MHz) | Amazon | AliExpress | eBay |
1 | ST-Link V2 Debugger | Amazon | AliExpress | eBay |
2 | BreadBoard | Amazon | AliExpress | eBay |
1 | LEDs Kit | Amazon & Amazon | AliExpress | eBay |
1 | Resistors Kit | Amazon & Amazon | AliExpress | eBay |
1 | Capacitors Kit | Amazon & Amazon | AliExpress & AliExpress | eBay & eBay |
1 | Jumper Wires Pack | Amazon & Amazon | AliExpress & AliExpress | eBay & eBay |
1 | Push Buttons | Amazon & Amazon | AliExpress | eBay |
1 | Potentiometers | Amazon | AliExpress | eBay |
1 | Micro USB Cable | Amazon | AliExpress | eBay |
★ Check The Links Below For The Full Course Kit List & LAB Test Equipment Required For Debugging ★
Download Attachments
You can download all attachment files for this Article/Tutorial (project files, schematics, code, etc..) using the link below. Please consider supporting our work through the various support options listed in the link down below. Every small donation helps to keep this website up and running and ultimately supports the whole community.
Wrap Up
In conclusion, we’ve explored the STM32 low-power sleep (Deep Sleep) mode, what it does to reduce the current consumption, and what are the current consumption numbers expected from this mode using the (STM32L432KC) target microcontroller.
You can build on top of the provided example code project and integrate it into your system. You can also check the rest of the tutorials in this series to learn more about other low-power modes in STM32 microcontrollers.