This article explores STM32 Stop Mode, which enables low power consumption in embedded systems. By utilizing this feature, STM32 microcontrollers can significantly reduce energy usage during idle periods while ensuring quick wake-up capabilities.
Things used in this project
Software apps and online services
1-Â STMicroelectronics STM32CubeMX
2-Â STMicroelectronics STM32CubeIDE
3-Â Proteus 8
Power Management in STM32: Utilizing Stop Mode for Enhanced Power Efficiency
Effective power management is vital for designing efficient and sustainable electronic devices. In STM32 microcontrollers, Stop Mode significantly reduces power consumption, extending battery life and optimizing overall energy use.
This guide explains how to enter and exit Stop Mode using the HAL library, details various methods for doing so, and provides practical tips for integrating Stop Mode into your STM32 projects.
Understanding Stop Mode in STM32 :
Stop Mode offers a deeper power-saving state than Sleep Mode. By combining Cortex-M3 deep sleep functionality with peripheral clock gating, it drastically lowers power consumption while retaining SRAM and register contents. During Stop Mode, all clocks in the 1.8 V domain stop, and the PLL, HSI, and HSE RC oscillators turn off. However, I/O pins maintain their state as in Run mode, ensuring responsiveness to external signals.
Entering Stop Mode :
To activate Stop Mode, use the HAL_PWR_EnterSTOPMode function from the HAL library. This function allows you to configure the voltage regulator and specify the entry method:
Voltage Regulator Configuration:
- Main Regulator ON: Keeps the main voltage regulator on.
- Low Power Regulator ON: Switches the voltage regulator to a low-power mode, further reducing power consumption.
Entry Methods:
- WFI (Wait For Interrupt): The microcontroller enters Stop Mode and remains there until an interrupt occurs. This method is straightforward and useful when you expect to wake up the microcontroller based on interrupts.
- WFE (Wait For Event): The microcontroller enters Stop Mode and waits for an event to occur. This method is suitable when the microcontroller needs to wake up in response to specific events without explicitly configuring interrupts.
Stop Mode Entry Mechanisms
- Sleep-Now: The microcontroller enters Stop Mode immediately after executing the WFI or WFE instruction if the SLEEPONEXIT bit is cleared in the Cortex-M3 System Control register. This mechanism is useful when you want the microcontroller to enter Stop Mode as soon as possible.
- Sleep-on-Exit: The microcontroller enters Stop Mode automatically when it finishes executing the current lowest priority Interrupt Service Routine (ISR) if the SLEEPONEXIT bit is set. This is beneficial when you want the microcontroller to enter Stop Mode after handling an interrupt without needing additional instructions.
NOTE :
- Stop Mode requires setting the SLEEPDEEP bit and using the WFI or WFE instruction, with additional configuration in the power control register.
- Sleep Mode can be entered automatically using the SLEEPONEXIT bit after handling an ISR, but this is not the same as Stop Mode.
Additional Considerations for Entering Stop Mode
- Voltage Regulator Configuration: Configure the LPDS bit in the Power Control register (PWR_CR) to put the internal voltage regulator in low-power mode.
- Ongoing Operations: Stop Mode entry is delayed if Flash memory programming or APB domain access is ongoing.
- Peripheral Power Consumption: Ensure that peripherals like ADC or DAC are disabled to avoid power consumption during Stop Mode.
Exiting Stop Mode :
The mechanism for exiting Stop Mode depends on how it was entered:
- WFI Entry Mode: The microcontroller exits Stop Mode when an interrupt from any EXTI line (internal or external) configured in Interrupt mode is acknowledged by the Nested Vectored Interrupt Controller (NVIC). This means that any configured peripheral interrupt can wake the microcontroller from Stop Mode and resume normal operation.
- WFE Entry Mode: The microcontroller exits Stop Mode when a wake-up event occurs. This event can be generated in two main ways:
- Peripheral Interrupts: An interrupt from a peripheral configured to wake up the microcontroller. The SEVONPEND bit in the Cortex-M3 System Control register must be enabled to wake the microcontroller on any pending events.
- EXTI Lines: External or internal EXTI lines configured in event mode can also wake up the microcontroller. This method leverages event lines to trigger wake-up without needing to clear the interrupt pending bits.
Wake-Up Considerations:
- System Clock: Upon exiting Stop Mode, the HSI RC oscillator is selected as the system clock.
- Wake-Up Latency: If the voltage regulator operates in low-power mode, an additional startup delay is incurred when waking up from Stop Mode. By keeping the internal regulator ON during Stop Mode, the consumption is higher, although the startup time is reduced.
Practical Tips for Using Stop Mode
- Optimize Wake-Up Sources: Configure only essential wake-up sources to minimize wake-up latency and power consumption.
- Efficient Clock Configuration: Ensure that the system clock configuration is optimized for minimal power consumption upon wake-up.
- Balancing Power and Performance: Choose the appropriate voltage regulator mode (main or low-power) based on the required wake-up time and power savings.
- Peripheral Management: Disable power-consuming peripherals such as ADC or DAC before entering Stop Mode to maximize power savings.
In this project, we will configure the STM32 microcontroller to enter Stop Mode and wake up via the RTC alarm. We will utilize the HAL_PWR_EnterSTOPMode function to enable Stop Mode and configure the RTC to trigger an alarm after a set period. Upon waking, the system will reinitialize necessary peripherals and perform an ADC measurement. This approach will help conserve power during idle periods while maintaining the microcontroller’s capability to perform periodic tasks, optimizing both power management and system responsiveness.
STM32CubeMX Configuration:
- Open CubeMX & Create New Project Choose The Target MCUÂ STM32F103C6Â & Double-Click Its Name
- In Tab System Core Set Low Speed Clock LSE : Crystal/Ceramic Resonator
- Go To The Clock Configuration & Set The System Clock To 32MHz
Configuration for the TIMERÂ Mode:
- In Tab Timers RTC Mode and Configuration ‘ (Activate Clock Srouce && select RTC Output on Temper pin)
-  In Paramater Settings General (Enable Auto Predivider Calclation && Set Asynchronous Previde value to automatic && set Output to Alarm pulse signal on the TAMPER pin)
- In NVIC Settings Enable RTC alam interrupt through EXTI line 17Â
Configuration for the GPIO Mode:
- Configure The GPIO Pins PB1 as Output Pin
- Configure The GPIO Pins PB2 as Output Pin
Configuration for the UART Mode:
- Enable USART1 Module (Asynchronous Mode)
- Set the USART1 communication parameters (baud rate =Â 115200, parity=NON, stop bits =1, and word length =Â 8bits)
Configuration for the HAL Settings:
- Set all Free pins as Analogs (to optimize the power consumption )
- Generate The Initialization Code & Open The Project In CubeIDE
STM32CubeIDE Configuration:
- Write The Application Layer Code
- main.c
/* USER CODE END Header */ /* Includes ------------------------------------------------------------------*/ #include "main.h" /* Private includes ----------------------------------------------------------*/ /* USER CODE BEGIN Includes */ #include<stdio.h> #include<string.h> /* USER CODE END Includes */ /* Private variables ---------------------------------------------------------*/ ADC_HandleTypeDef hadc1; RTC_HandleTypeDef hrtc; UART_HandleTypeDef huart1; /* USER CODE BEGIN PV */ /* USER CODE END PV */ /* Private function prototypes -----------------------------------------------*/ void SystemClock_Config(void); static void MX_GPIO_Init(void); static void MX_USART1_UART_Init(void); static void MX_RTC_Init(void); static void MX_ADC1_Init(void); /* USER CODE BEGIN PFP */ static void performADCMeasurement(void); static void sendUARTMessage(char *message); static void reconfigureRTCAlarm(RTC_HandleTypeDef *hrtc, uint32_t secondsToAdd); /* USER CODE END PFP */ /* Private user code ---------------------------------------------------------*/ /* USER CODE BEGIN 0 */ void HAL_RTC_AlarmAEventCallback(RTC_HandleTypeDef *hrtc) { sendUARTMessage(" RTC Alarm Triggered: LED ON\r\n"); // Reinitialize peripherals after waking up MX_ADC1_Init(); // Reinitialize ADC // Perform ADC measurement and transmit the result over UART performADCMeasurement(); // Reconfigure the alarm to trigger after 20 seconds reconfigureRTCAlarm(hrtc, 20); } void Enter_Stop_Mode(void) { HAL_GPIO_WritePin(GPIOB, GPIO_PIN_2,0); HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1,1); sendUARTMessage("0-Entering Stop Mode\r\n"); // Disable ADC power-consuming peripherals before entering Stop Mode to maximize power savings HAL_ADC_DeInit(&hadc1); // Suspend SysTick interrupt to prevent it from waking up the MCU HAL_SuspendTick(); // Enter Stop Mode with low power regulator on HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI); // Resume SysTick interrupt and reconfigure system clock after waking up HAL_ResumeTick(); SystemClock_Config(); sendUARTMessage("1-Woke up from Stop Mode\r\n"); sendUARTMessage("2-System Clock Reconfigured\r\n"); sendUARTMessage("-------------------------------\r\n"); // Toggle an LED HAL_GPIO_WritePin(GPIOB, GPIO_PIN_1,0); for (int i = 0; i < 20; i++) { HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_2); HAL_Delay(100); } HAL_Delay(500); } void sendUARTMessage(char *message) { HAL_UART_Transmit(&huart1, (uint8_t*)message, strlen(message), HAL_MAX_DELAY); } void performADCMeasurement(void) { // Start ADC conversion HAL_ADC_Start(&hadc1); // Wait for ADC conversion to complete if (HAL_ADC_PollForConversion(&hadc1, HAL_MAX_DELAY) == HAL_OK) { // Get the ADC value uint32_t adcValue = HAL_ADC_GetValue(&hadc1); // Convert the ADC value to a string and send it over UART char adcMsg[50]; snprintf(adcMsg, sizeof(adcMsg), " ADC Value: %lu\r\n", adcValue); sendUARTMessage(" **********************************\n\r"); sendUARTMessage(adcMsg); sendUARTMessage(" **********************************\n\r"); } // Stop ADC conversion HAL_ADC_Stop(&hadc1); } void reconfigureRTCAlarm(RTC_HandleTypeDef *hrtc, uint32_t secondsToAdd) { RTC_TimeTypeDef time = {0}; RTC_DateTypeDef date = {0}; HAL_RTC_GetTime(hrtc, &time, RTC_FORMAT_BIN); HAL_RTC_GetDate(hrtc, &date, RTC_FORMAT_BIN); time.Seconds += secondsToAdd; if (time.Seconds >= 60) { time.Minutes++; time.Seconds -= 60; } if (time.Minutes >= 60) { time.Hours++; time.Minutes -= 60; } if (time.Hours >= 24) { time.Hours = 0; } RTC_AlarmTypeDef sAlarm = {0}; sAlarm.Alarm = RTC_ALARM_A; sAlarm.AlarmTime.Hours = time.Hours; sAlarm.AlarmTime.Minutes = time.Minutes; sAlarm.AlarmTime.Seconds = time.Seconds; if (HAL_RTC_SetAlarm_IT(hrtc, &sAlarm, RTC_FORMAT_BIN) != HAL_OK) { sendUARTMessage("Error: Setting RTC Alarm Failed\r\n"); Error_Handler(); } sendUARTMessage(" RTC Alarm Reconfigured\r\n"); } /* USER CODE END 0 */ /** * @brief The application entry point. * @retval int */ int main(void) { /* Reset of all peripherals, Initializes the Flash interface and the Systick. */ HAL_Init(); /* Configure the system clock */ SystemClock_Config(); /* Initialize all configured peripherals */ MX_GPIO_Init(); MX_USART1_UART_Init(); MX_RTC_Init(); MX_ADC1_Init(); /* USER CODE BEGIN WHILE */ while (1) { /* USER CODE END WHILE */ /* USER CODE BEGIN 3 */ Enter_Stop_Mode(); } /* USER CODE END 3 */ }
Proteus Configuration :
- Open Proteus & Create New Project and click next
- Click on Pick Device
- Search for STM32F103C6 & LED-RED & LED-GREEN , POT
- Click on Virtual Instruments Mode then choose Terminal
- Click on Terminal Mode then choose (DEFAULT & POWER &GROUND)
- finally make the circuit below and start the simulation
That’s all!
If you have any questions or suggestions don’t hesitate to leave a comment below