STM32-Power management (to achieve low power consumption)

Table of Contents

Power management

Power-on reset (POR) and power-down reset (PDR)

Configure PVD monitoring function

WFI and WFE commands

Enter stop mode

Enter standby mode

Experimental link 1: PWR_PVD monitoring

Experimental operation

PVD configuration

Test session

Experimental session 2: PWR sleep mode

Experimental operation

Test session

Experimental session 3: PWR standby mode

Experimental operation

Test session

Experimental phenomena

Experimental session 4: PWR stop mode

Experimental operation

Test session


Power Management

The STM32 HAL library provides complete functions and commands for power management.

Working mode (high power consumption -> low power consumption): running, sleep, stop, standby.

If the backup domain power supply is normal, the RTC in the backup domain can run normally, and the data in the registers in the backup domain will be saved and will not be affected by the power consumption mode.

Low power mode:

Sleep mode: The core is stopped, peripherals are still running, and the power consumption is the highest.

Stop mode: All clocks are stopped and the power consumption is low, typically about 20uA.

Standby mode: The 1.8V core power supply is turned off, and the power consumption is the lowest, typically about 2uA.

Stop mode is commonly used in general development because power consumption is low and any interrupt or event can wake it up. Standby mode can only be woken up by specific events or pins, and the real-time performance is not as good as stop mode.

Power-on reset (POR) and power-down reset (PDR)

When it is detected that the voltage of VDD is lower than the thresholds VPOR and VPDR, the STM32 chip will automatically remain in the reset state without external circuit assistance to prevent serious consequences caused by forced operation due to insufficient voltage.

When the voltage is initially lower than VPOR (about 1.92V), STM32 remains in the power-on reset state (POR, Power On Reset). When the VDD voltage continues to rise above VPOR, the chip begins to operate normally.

When the chip starts to operate normally, when it detects that the VDD voltage drops below the VPDR threshold (about 1.88V), it will enter the power-down reset state (PDR, Power Down Reset).

Configure PVD monitoring function

PVD can monitor the voltage of VDD. When it is lower than the threshold, a PVD interrupt can be generated to allow the system to perform emergency processing. This threshold can be directly configured to a certain threshold level using the library function PWR_PVDLevelConfig.

WFI and WFE commands

When entering various low-power modes, you need to call WFI or WFE commands, which are essentially kernel instructions. These instructions are encapsulated into functions in the library file core_cm3.h or cmsis_armcc.h.

/* Wait for interrupt. It is a kind of pause execution instruction that pauses until any interrupt is generated and wakes up */
#define __WFI __wfi

/* Wait for events. It is a kind of pause execution instruction, which is paused until any event occurs and is awakened */
#define __WFE __wfe

These two instructions can enter the low-power mode after being called. They need to be called using __WFI(); and __WFE(); (because __wfi and __wfe are built-in functions of the compiler, and the corresponding functions are called internally. assembly instructions).

For details, please check the “Cortex-CM3/CM4 Authoritative Guide”.

Enter stop mode

Directly calling the WFI and WFE instructions can enter sleep mode, and entering stop mode requires setting some register bits before calling the instructions. The STM32 HAL library encapsulates this part of the operation into HAL_PWR_EnterSTOPMode().

Parameter 1: If the voltage regulator is running normally, that is, the power supply does not enter low power consumption, there is basically no delay in waking up. On the contrary, there is a little delay.

Parameter 2: When WFI enters, it needs to wake up by interrupt, and when WFE enters, it needs to wake up by event. You can also choose both together.

After waking up from the shutdown mode, HSI is automatically selected as the system clock (8MHz) to run.Generally, it needs to be reconfigured. Just call the system clock configuration function directly.

After waking up from the shutdown mode, the Flash program starts executing from an interrupt or event.

/**
  * @brief Enter stop mode
  * @note In stop mode all I/O will remain in the state before stopping.
  * @note When exiting stop mode using an interrupt or wake-up event, the HSI RC oscillator is selected as the system clock.
  * @note When the regulator is operating in low power mode, there is an additional startup delay when waking up from stop mode.
  * By keeping the internal voltage regulator open in stop mode, start-up time is reduced but consumption is higher.
  * @param Regulator: Specifies the regulator status in stop mode.
  * @arg PWR_MAINREGULATOR_ON: The voltage regulator is operating normally
  * @arg PWR_LOWPOWERREGULATOR_ON: Regulator low power operation
  * @param STOPEntry: Specifies whether to use the WFI or WFE instruction to enter stop mode.
  * @arg PWR_STOPENTRY_WFI: Use the WFI command to enter stop mode
  * @arg PWR_STOPENTRY_WFE: Use the WFE instruction to enter stop mode
  * @retval None
  */
void HAL_PWR_EnterSTOPMode(uint32_t Regulator, uint8_t STOPEntry)
{
    /* Check parameters */
    assert_param(IS_PWR_REGULATOR(Regulator));
    assert_param(IS_PWR_STOP_ENTRY(STOPEntry));

    /* Clear the PDDS bit in the PWR register to specify that the CPU enters stop mode when it enters deep sleep */
    CLEAR_BIT(PWR->CR, PWR_CR_PDDS);

    /* According to the voltage stabilization parameter value, select the voltage stabilization mode by setting the LPDS bit in the PWR register */
    MODIFY_REG(PWR->CR, PWR_CR_LPDS, Regulator);

    /* Set the SLEEPDEEP bit of the kernel system control register */
    SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));

    /* Select stop mode to enter */
    if (STOPEntry == PWR_STOPENTRY_WFI)
    {
        /* Request to wait for interrupt */
        __WFI();
    }
    else
    {
        /* Request waiting event */
        __SEV();
        PWR_OverloadWfe(); /* Redefine WFE locally */
        PWR_OverloadWfe(); /* Redefine WFE locally */
    }

    /* The following program is executed when re-awakening and clears the SLEEPDEEP bit of the kernel system control register */
    CLEAR_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));
}

After entering stop mode, all I/O of STM32 remain in the state before stopping.

How to achieve lower power consumption in stop mode?

Release all pin IO ports and configure them to analog input status. (Note: Do not lock the IO port before configuration, almost zero consumption, but you need to reconfigure the IO port after waking up)

HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_STOPENTRY_WFI);

The correctly configured power consumption at this time is around 10uA.

When the I/O port is configured as an analog input:

The output buffer is disabled;

Schmitt trigger inputs are disabled, resulting in zero consumption on each analog I/O pin. The Schmitt trigger trigger output value is forced to 0;

Strong pull-up and pull-down resistors are disabled;

The value is 0 when reading the input data register.

Enter standby mode

The STM32 HAL library encapsulates this part of the operation into HAL_PWR_EnterSTANDBYMode().

/**
  * @brief Enter standby mode
  * @note In standby mode, all I/O pins are high impedance except in the following cases::
  * - reset pin (still valid)
  * - TAMPER pin if configured for tamper or calibration out.
  * - WKUP pin (PA0) (if WKUP wake-up function is enabled).
  * @retval None
  */
void HAL_PWR_EnterSTANDBYMode(void)
{
    /* Select standby mode */
    SET_BIT(PWR->CR, PWR_CR_PDDS);

    /* Set the SLEEPDEEP bit of the kernel system control register */
    SET_BIT(SCB->SCR, ((uint32_t)SCB_SCR_SLEEPDEEP_Msk));

    /* Only when the storage operation is completed can the standby mode be entered. Use the following statement to ensure that the storage operation is completed */
#if defined (__CC_ARM)
    __force_stores();
#endif
    /* Request to wait for interrupt */
    __WFI();
}

Standby mode can also be entered using the WFE command, which can be modified if necessary.

After entering standby mode, except for the I/O enabled for wake-up, all other I/Os enter a high-impedance state. After waking up from standby mode, if you want to avoid resetting the STM32 chip, the program will restart from the beginning.

Experimental session 1: PWR_PVD monitoring

Experimental operation

Use an external adjustable power supply, adjust it to a 5V output, and connect it to the 5V and GND pins of the development board to power the board;

Reset the development board and the LED will be green when the voltage is normal;

Adjust the voltage of the adjustable power supply downward. When it drops to about 4V, the LED will be red. (The PVD monitoring voltage controlled in the program is about 2.8V. When 5V drops to 4V, the VDD power supply connected to the STM32 will drop below 2.8V, causing a PVD event, and the red light will be turned on during the interrupt).

Note: Unplug all other power cords (including downloader and USB cable). It cannot be much higher than 5V, which may cause the development board to burn out.

PVD configuration

void PVD_Config(void)
{
PWR_PVDTypeDef sConfigPVD;
\t
/*Enable PWR clock */
__HAL_RCC_PWR_CLK_ENABLE();
\t
/* Configure PVD interrupt */
HAL_NVIC_SetPriority(PVD_IRQn, 0,0);
HAL_NVIC_EnableIRQ(PVD_IRQn);

/* Configure PVD level 6 (the threshold of PVD detection voltage is 2.8V, and a PVD interrupt is generated when the VDD voltage is lower than 2.8V.
Specific data can be obtained by consulting the data manual) The specific level is configured according to your actual application requirements*/
sConfigPVD.PVDLevel = PWR_PVDLEVEL_6;
sConfigPVD.Mode = PWR_PVD_MODE_IT_RISING_FALLING;
HAL_PWR_ConfigPVD( & amp;sConfigPVD);
\t
/* Enable PVD output */
HAL_PWR_EnablePVD();
}

Test session

void PVD_IRQHandler(void)
{
HAL_PWR_PVD_IRQHandler();
}

void HAL_PWR_PVDCallback(void)
{
LED red light
}

void test(void)
{
initialization
LED green light

// Configure PVD. When the voltage is too low, it will enter the interrupt service function and turn on the red light.
PVD_Config();
\t
while(1)
{}
}

Experimental session 2: PWR sleep mode

Experimental operation

LED: green light for normal operation, red light for sleep state, and blue light for just waking up.

KEY: key1 and key2 are configured in IO interrupt mode.

After running for a period of time, it automatically enters sleep time and wakes up by pressing the key (key1 or key2).

In the sleep state, the DAP downloader cannot download the program to STM32. You can wake it up and then download it or press the reset button to put the chip in reset state and release the reset button after downloading.

Test session

int main(void)
{
initialization

    while (1)
    {
        LED green light
        HAL_Delay(2000);

        LED red light
        HAL_SuspendTick(); //Suspend the tick clock to prevent waking up through the tick clock interrupt
        //Enter sleep mode
        HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);
\t\t
        //Wait for interrupt to wake up K1 or K2 key interrupt
\t\t
        LED blue light
        HAL_ResumeTick(); //After waking up, resume the tick clock
        HAL_Delay(2000);
\t\t
        //Continue executing the while loop
    }
}

Experimental session 3: PWR standby mode

Experimental operation

LED: Green light indicates that this reset is power-on or pin reset, red light indicates standby status, and blue light indicates that it has just been awakened.

KEY: key2 is configured in input mode.

Long press the KEY2 button to enter standby mode. In standby mode, press KEY1 button to wake up. The system will be reset after waking up. The source of reset can be determined by detecting the PWR_CSR:WUF flag.

In standby mode, the DAP downloader cannot download programs for STM32, and can be downloaded again after waking up.

Note: Since the WKUP pin (PA0) must use a rising edge to wake up the system in standby mode, the hardware design is to connect the PA0 pin to KEY1, and when KEY1 is pressed, a rising edge will be generated on the PA0 pin, thereby realizing the wake-up function. .

Test session

/**
  * @brief is used to detect whether the key is pressed for a long time
  * @param None
  * @retval 1: The button was pressed for a long time 0: The button was not pressed for a long time
  */
static uint8_t KEY2_LongPress(void)
{
    uint8_t downCnt = 0; //Record the number of times pressed
    uint8_t upCnt = 0; //Record the number of times released
\t
    while (1) //Infinite loop, ended by return
    {
        HAL_Delay(20); //Delay for a while and then detect

        if (HAL_GPIO_ReadPin(KEY2_GPIO_PORT, KEY2_PIN) == SET) //Key press detected
        {
            downCnt + + ; //Record the number of times pressed
            upCnt = 0; //Clear key release records

            if (downCnt >= 100) //The press time is enough
            {
                return 1; //Detect that the button has been pressed for a long time
            }
        }
        else
        {
            upCnt + + ; //Record the number of releases

            if (upCnt > 5) //Release detected more than 5 times continuously
            {
                return 0; //The pressing time is too short and it is not a long press operation.
            }
        }
    }
}

int main(void)
{
initialization

    /* Enable the clock of the power management unit. The clock must be enabled to enter standby mode */
__HAL_RCC_PWR_CLK_ENABLE();

    //Detect reset source
    if (__HAL_PWR_GET_FLAG(PWR_FLAG_WU) == SET)
    { // Standby mode before reset
        __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);
        LED blue light
    }
    else
    {
//Normal operation before reset
        LED green light
    }

    while (1)
    {
        // Long press the K2 button to enter standby mode
        if (KEY2_LongPress())
        {
            LED red light
            HAL_Delay(1000);

            /*Clear WU status bit*/
            __HAL_PWR_CLEAR_FLAG(PWR_FLAG_WU);

            /* Enable the wake-up function of the WKUP pin and enable PA0*/
            HAL_PWR_EnableWakeUpPin(0x00000100U);

            //Pause the tick clock to prevent wake-up by tick clock interrupt
            HAL_SuspendTick();
\t\t\t
            /* Enter standby mode */
            HAL_PWR_EnterSTANDBYMode();
        }
    }
}

Experimental Phenomenon

Turn on and run normally with green light. Long press the KEY2 button, the red light will appear, and after 1 second, it will enter the standby mode and the LED will turn off. Press the KEY1 button to exit the standby mode and automatically reset, showing a blue light. Press the reset button and run the green light again.

Experimental session 4: PWR stop mode

Experimental operation

LED: Green light is running normally, red light is in stop state, and blue light has just been awakened.

KEY: key1 and key2 are configured in IO interrupt mode.

After running for a period of time, it automatically enters the stop time and wakes up by pressing the key (key1 or key2).

In standby mode, the DAP downloader cannot download programs for STM32, and can be downloaded again after waking up.

Note: Since the WKUP pin (PA0) must use a rising edge to wake up the system in standby mode, the hardware design is to connect the PA0 pin to KEY1, and when KEY1 is pressed, a rising edge will be generated on the PA0 pin, thereby realizing the wake-up function. .

Test session

/**
  * @brief Configure the system clock after waking up from stop mode: enable HSE, PLL and select PLL as the system clock source.

  * @param None
  * @retval None
  */
static void SYSCLKConfig_STOP(void)
{
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
uint32_t pFLatency = 0;

/* Enable power control clock */
__HAL_RCC_PWR_CLK_ENABLE();

/* Get the oscillator configuration based on the internal RCC register */
HAL_RCC_GetOscConfig( & amp;RCC_OscInitStruct);

/* Reconfigure system clock after waking up from stop mode: enable HSE and PLL */
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
if (HAL_RCC_OscConfig( & amp;RCC_OscInitStruct) != HAL_OK)
{
while(1) { ; }
}

/* Get the clock configuration based on the internal RCC register */
HAL_RCC_GetClockConfig( & amp;RCC_ClkInitStruct, & amp;pFLatency);

/* Select PLL as the system clock source, and configure the HCLK, PCLK1 and PCLK2 clock division coefficients */
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_SYSCLK;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
if (HAL_RCC_ClockConfig( & amp;RCC_ClkInitStruct, pFLatency) != HAL_OK)
{
while(1) { ; }
}
}

int main(void)
{
uint32_t SYSCLK_Frequency = 0;
uint32_t HCLK_Frequency = 0;
uint32_t PCLK1_Frequency = 0;
uint32_t PCLK2_Frequency = 0;
uint32_t SYSCLK_Source = 0;
\t
initialization

while(1)
{
LED green light
HAL_Delay(2000);

//Enter stop mode, turn on red light, press KEY1 or KEY2 button to wake up
LED_RED;
HAL_SuspendTick(); //Suspend the tick clock to prevent waking up through the tick clock interrupt
/* Enter stop mode, set the voltage regulator to low power mode, and wait for interrupt wake-up */
HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_STOPENTRY_WFI);
\t\t
// Wait for interrupt to wake up K1 or K2 key interrupt
\t\t
// Awakened, blue light indicates
LED blue light
SystemCoreClockUpdate(); //Update the SystemCoreClock variable according to the value of the clock register
//Get the clock status after waking up
SYSCLK_Frequency = HAL_RCC_GetSysClockFreq();
HCLK_Frequency = HAL_RCC_GetHCLKFreq();
PCLK1_Frequency = HAL_RCC_GetPCLK1Freq();
PCLK2_Frequency = HAL_RCC_GetPCLK2Freq();
SYSCLK_Source = __HAL_RCC_GET_SYSCLK_SOURCE();
\t\t 
/* Configure system clock after waking up from stop mode: enable HSE, PLL*/
/* Select PLL as system clock source (HSE and PLL are disabled in stop mode)*/
SYSCLKConfig_STOP();
\t\t
HAL_ResumeTick(); //After waking up, resume the tick clock
//Get the reconfigured clock status
SYSCLK_Frequency = HAL_RCC_GetSysClockFreq();
HCLK_Frequency = HAL_RCC_GetHCLKFreq();
PCLK1_Frequency = HAL_RCC_GetPCLK1Freq();
PCLK2_Frequency = HAL_RCC_GetPCLK2Freq();
SYSCLK_Source = __HAL_RCC_GET_SYSCLK_SOURCE();
\t\t
HAL_Delay(2000);

//Continue executing the while loop
}
}