In this tutorial, we’ll discuss The STM32 Low Power Run Mode (LPR), how to enter the low power 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 Low Power Run Mode
- STM32 Enter Low Power Run Mode
- STM32 Exit Low Power Run Mode
- STM32 Low Power Run Mode Example Code Project
- Wrap Up
STM32 Low Power Run Mode
This 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
After entering this mode, the CPU has no way to check the clock frequency. This means you can “theoretically” increase it a bit more beyond the 2MHz limit. However, it’s not recommended by the datasheet nor guaranteed to work in a stable manner.
STM32 Enter Low Power Run Mode
To enter the low power mode, we must first 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.
Here is a code example for entering the STM32 low-power run 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 |
void Enter_LowPowerRunMode(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; // 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(); LowPowerRunMode_Activated = 1; } |
Note that the HAL_PWREx_EnableLowPowerRunMode() function should only be called after switching the SYSCLK down to 2MHz or less.
STM32 Exit Low Power Run 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.
This is an example code for exiting the low-power run 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 |
void Exit_LowPowerRunMode(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(); } LowPowerRunMode_Activated = 0; } |
STM32 Low Power Run Mode Example Code Project
In this example project, we’ll configure our STM32L432KC microcontroller to run at full speed (80MHz) for 3 seconds. Then it’ll automatically switch to the low power run mode to run at 2MHz.
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 clock will be observed using a global variable and the HAL_RCC_GetSysClockFreq() function.
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.
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 Low Power Run Mode 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 |
/* * LAB Name: STM32 Low Power Run Mode (LPR) 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_LowPowerRunMode(void); void Exit_LowPowerRunMode(void); uint32_t SysClk = 0; uint8_t LowPowerRunMode_Activated = 0; int main(void) { HAL_Init(); SystemClock_Config(); MX_GPIO_Init(); SysClk = HAL_RCC_GetSysClockFreq(); HAL_Delay(3000); Enter_LowPowerRunMode(); while (1) { SysClk = HAL_RCC_GetSysClockFreq(); } } void Enter_LowPowerRunMode(void) { RCC_OscInitTypeDef RCC_OscInitStruct = {0}; RCC_ClkInitTypeDef RCC_ClkInitStruct = {0}; // 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(); LowPowerRunMode_Activated = 1; } void Exit_LowPowerRunMode(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(); } LowPowerRunMode_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(LowPowerRunMode_Activated == 1) { Exit_LowPowerRunMode(); // Exit From Low Power Run Mode! } else { Enter_LowPowerRunMode(); // Re-Enter The Low Power Run Mode! } } } |
STM32 Low Power Run Mode Example Testing
To test this project, you can place two break points in the locations indicated below and keep clicking on the run button in the debug menu while monitoring the SysClk value in the live expressions window.
You can see that the system starts at full speed (80MHz), then after 3s, it goes into low-power run mode, and the SysClk becomes (2MHz). By pressing the A0 (EXTI1) push button, your system will get out of the low-power run mode back to its full-speed run mode. Further button clicks will keep the system toggling between full-speed run mode and low-power run mode.
If you’re using a different target STM32 microcontroller, or you’re willing to use different clock settings than mine. 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 run mode!
- Use the clock initialization code snippets you’ve copied so far and replace the contents of the provided example in both Enter_LowPowerRunMode() and Exit_LowPowerRunMode() 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 run 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.