ES: PY32 Low Power Modes

The PY32F0xx provides five distinct low-power modes that significantly reduce current consumption when the microcontroller is not actively processing. This guide covers the available modes, their characteristics, and a complete example of entering sleep mode and waking via GPIO interrupt.

Low-power operation is not an afterthought in embedded design — for battery-powered IoT devices, it is the primary design constraint. A device that consumes 5 mA during active operation but enters deep sleep at 10 µA between measurements can extend battery life from days to years.

The PY32F0xx HAL provides comprehensive support for five low-power modes, each trading off between power savings and wake-up capability.


Why Low Power Modes Matter

A typical IoT sensor node spends most of its time idle — waiting for the next measurement interval, a button press, or a network event. During that idle time, the microcontroller core can be halted or most of the chip powered down.

md
Active Time vs Idle Time (typical IoT node)
--------------------------------------------
Active:  100 ms every 10 seconds  = 1% of time
Idle:    9.9 seconds every 10s    = 99% of time

If active current = 5 mA and sleep current = 10 µA:
Average current = (0.01 × 5000) + (0.99 × 10) = 50 + 9.9 = ~60 µA

Without sleep mode: 5 mA → Battery lasts 1 month (2000 mAh)
With sleep mode:    60 µA → Battery lasts ~3 years


PY32F0xx Low-Power Modes

The PY32F0xx supports five distinct low-power configurations:

ModeCorePeripheralsRegulatorWake-Up Sources
Low-Power RunRunning (low clock)ActiveLow-powerAny
SleepHaltedActiveNormalAny interrupt
Low-Power SleepHaltedActiveLow-powerAny interrupt
Stop 0OffOff (LSI/LSE only)Main onEXTI, RTC
Stop 1OffOff (LSI/LSE only)Low-powerEXTI, RTC

Mode 1: Low-Power Run Mode

Reduces the core clock frequency and switches the voltage regulator to low-power state. All peripherals remain active but at reduced performance.

Use case: Applications that must continue processing but at reduced speed to save power.

Mode 2: Sleep Mode

The Cortex-M0+ core halts. Peripherals remain active — UART can still receive data, timers continue running, and ADC can continue conversions. The voltage regulator stays in normal mode.

Wake-up: Any enabled interrupt (GPIO EXTI, UART receive, timer overflow, etc.)

c
// Enter sleep mode — wake on any interrupt
HAL_PWR_EnterSLEEPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);

Mode 3: Low-Power Sleep Mode

Like Sleep mode, but the voltage regulator switches to low-power state, further reducing current consumption.

Wake-up: Any enabled interrupt

Mode 4: Stop 0 Mode

The main clock (HSI, HSE) stops. Only LSI (low-speed internal) or LSE (low-speed external) clocks remain active, which can drive the RTC and watchdog.

The voltage regulator remains in normal mode.

Wake-up: External interrupt (EXTI), RTC alarm

c
// Enter Stop 0 mode — main regulator on
HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);

Mode 5: Stop 1 Mode

Like Stop 0, but the voltage regulator also switches to low-power mode for maximum current savings while retaining RAM content and register state.

Wake-up: External interrupt (EXTI), RTC alarm

c
// Enter Stop 1 mode — low-power regulator
HAL_PWR_EnterSTOPMode(PWR_LOWPOWERREGULATOR_ON, PWR_SLEEPENTRY_WFI);


WFI vs WFE

Two ARM instructions trigger sleep entry:

InstructionWake-Up TriggerHAL Entry
WFI (Wait For Interrupt)Any enabled interruptPWR_SLEEPENTRY_WFI
WFE (Wait For Event)Interrupt or event flagPWR_SLEEPENTRY_WFE

WFI is the most common choice — the device wakes when any configured interrupt fires.


Sleep Mode with GPIO Wake-Up: Complete Example

This example demonstrates the full flow: configure a GPIO interrupt as wake-up source, enter sleep mode, wake on button press, and toggle an LED.

cpp
#include "py32f0xx_hal.h"

// Wake-up GPIO definition
#define WAKEUP_GPIO_PIN  GPIO_PIN_0
#define WAKEUP_GPIO_PORT GPIOA
#define WAKEUP_IRQ_PRIORITY 2

// Function declarations
void SystemClock_Config(void);
void GPIO_Init_WakeUp(void);
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin);

int main(void) {
    // Initialize HAL and system clock
    HAL_Init();
    SystemClock_Config();

    // Initialize wake-up GPIO with interrupt
    GPIO_Init_WakeUp();

    // Optional: turn off LED before entering sleep
    HAL_GPIO_WritePin(GPIOC, GPIO_PIN_13, GPIO_PIN_RESET);

    // Enter Stop mode — core halts here until interrupt fires
    HAL_PWR_EnterSTOPMode(PWR_MAINREGULATOR_ON, PWR_SLEEPENTRY_WFI);

    // Execution resumes here after wake-up
    // The interrupt has already been handled by the callback below

    while (1) {
        // Main application loop after wake-up
        HAL_GPIO_TogglePin(GPIOC, GPIO_PIN_13);
        HAL_Delay(1000);
    }
}

// Configure PA0 as external interrupt for wake-up
void GPIO_Init_WakeUp(void) {
    __HAL_RCC_GPIOA_CLK_ENABLE();

    GPIO_InitTypeDef GPIO_InitStruct = {0};
    GPIO_InitStruct.Pin   = WAKEUP_GPIO_PIN;
    GPIO_InitStruct.Mode  = GPIO_MODE_IT_RISING;  // Interrupt on rising edge
    GPIO_InitStruct.Pull  = GPIO_NOPULL;
    HAL_GPIO_Init(WAKEUP_GPIO_PORT, &GPIO_InitStruct);

    // Enable EXTI interrupt in NVIC
    HAL_NVIC_SetPriority(EXTI0_1_IRQn, WAKEUP_IRQ_PRIORITY, 0);
    HAL_NVIC_EnableIRQ(EXTI0_1_IRQn);
}

// GPIO EXTI interrupt callback (called by HAL when EXTI fires)
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) {
    if (GPIO_Pin == WAKEUP_GPIO_PIN) {
        // Wake-up detected — add any immediate wake response here
    }
}

// EXTI IRQ Handler — calls the HAL driver
void EXTI0_1_IRQHandler(void) {
    HAL_GPIO_EXTI_IRQHandler(WAKEUP_GPIO_PIN);
}

// System clock configuration (implement for your specific clock needs)
void SystemClock_Config(void) {
    // Configure HSI, PLL, HCLK, PCLK as needed for your application
}


After Wake from Stop Mode

When the device wakes from Stop mode, the clock system needs to be reconfigured because the main clocks were stopped:

cpp
// After returning from HAL_PWR_EnterSTOPMode(), reconfigure clocks
void WakeUp_ClockRestore(void) {
    // Re-enable HSI or HSE and reconfigure PLL if needed
    SystemClock_Config();
}

For Sleep mode (not Stop), clock restoration is automatic — the core simply resumes where it stopped.


Low-Power Mode Selection Guide

md
Application Requirement              Recommended Mode
-----------------------              ----------------
Must keep running at lower speed?    Low-Power Run
Waiting for any interrupt?           Sleep or Low-Power Sleep
Waiting for timed event or button?   Stop 0 or Stop 1
Maximum power savings needed?        Stop 1
RTC must stay running?               Stop 0 or Stop 1 (LSE keeps RTC)


Power Consumption Reference

Typical current consumption figures for PY32F003 at 3.3V:

ModeTypical Current
Run (48 MHz)~5 mA
Sleep~1 mA
Stop 0~50 µA
Stop 1~10 µA

These figures vary with peripheral activity, temperature, and supply voltage. Always measure actual consumption in your specific circuit.


Final Thoughts

The PY32F0xx low-power mode system is well-designed for IoT and battery-powered applications. The five modes cover the full spectrum from minimal savings (Low-Power Run) to maximum savings (Stop 1), and the HAL API makes entering and exiting these modes straightforward.

The key to effective low-power design:

  • Identify how much time the device spends idle
  • Choose the deepest sleep mode that still supports the required wake-up sources
  • Minimize initialization time on wake-up to maximize time in sleep

Low-power modes are not optional for battery-powered embedded design — they are the design.