Power Management¶
Overview¶
Power management algorithm included in ESP-IDF can adjust APB frequency, CPU frequency, and put the chip into light sleep mode to run the application at smallest possible power consumption, given the requirements of application components.
Application components can express their requirements by creating and acquiring power management locks.
For instance, a driver for a peripheral clocked from APB can request the APB frequency to be set to 80 MHz, for the duration while the peripheral is used. Another example is that the RTOS will request the CPU to run at the highest configured frequency while there are tasks ready to run. Yet another example is a peripheral driver which needs interrupts to be enabled. Such driver can request light sleep to be disabled.
Naturally, requesting higher APB or CPU frequency or disabling light sleep causes higher current consumption. Components should try to limit usage of power management locks to the shortest amount of time possible.
Configuration¶
Power management can be enabled at compile time, using CONFIG_PM_ENABLE option.
Enabling power management features comes at the cost of increased interrupt latency. Extra latency depends on a number of factors, among which are CPU frequency, single/dual core mode, whether frequency switch needs to be performed or not. Minimal extra latency is 0.2us (when CPU frequency is 240MHz, and frequency scaling is not enabled), maximum extra latency is 40us (when frequency scaling is enabled, and a switch from 40MHz to 80MHz is performed on interrupt entry).
Dynamic frequency scaling (DFS) and automatic light sleep can be enabled in the application by calling esp_pm_configure()
function. Its argument is a structure defining frequency scaling settings, cpp:class:esp_pm_config_esp32_t. In this structure, 3 fields need to be initialized:
max_freq_mhz
- Maximal CPU frequency, in MHZ (i.e. frequency used whenESP_PM_CPU_FREQ_MAX
lock is taken). This will usually be set to CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ.min_freq_mhz
— Minimal CPU frequency, in MHz (i.e. frequency used when onlyESP_PM_APB_FREQ_MAX
locks are taken). This can be set to XTAL frequency, or XTAL frequency divided by integer. Note that 10MHz is the lowest frequency at which the default REF_TICK clock of 1MHz can be generated.light_sleep_enable
— Whether system should automatically enter light sleep when no locks are taken (true
/false
).
Note
Automatic light sleep is based on FreeRTOS Tickless Idle functionality. esp_pm_configure()
will return an ESP_ERR_NOT_SUPPORTED error if CONFIG_FREERTOS_USE_TICKLESS_IDLE option is not enabled in menuconfig, but automatic light sleep is requested.
Note
In light sleep, peripherals are clock gated, and interrupts (from GPIOs and internal peripherals) will not be generated. Wakeup source described in Sleep Modes documentation can be used to wake from light sleep state. For example, EXT0 and EXT1 wakeup source can be used to wake up from a GPIO.
Alternatively, CONFIG_PM_DFS_INIT_AUTO option can be enabled in menuconfig. If enabled, maximal CPU frequency is determined by CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ setting, and minimal CPU frequency is set to the XTAL frequency.
Power Management Locks¶
As mentioned in the overview, applications can acquire/release locks to control the power management algorithm. When application takes a lock, power management algorithm operation is restricted in a way described below, for each lock. When the lock is released, such restriction is removed.
Different parts of the application can take the same lock. In this case, the lock must be released the same number of times as it was acquired, in order for power managment algorithm to resume.
In ESP32, three types of locks are supported:
ESP_PM_CPU_FREQ_MAX
Requests CPU frequency to be at the maximal value set via
esp_pm_configure()
. For ESP32, this value can be set to 80, 160, or 240MHz.ESP_PM_APB_FREQ_MAX
Requests APB frequency to be at the maximal supported value. For ESP32, this is 80 MHz.
ESP_PM_NO_LIGHT_SLEEP
Prevents automatic light sleep from being used.
Power Management Algorithm for the ESP32¶
When dynamic frequency scaling is enabled, CPU frequency will be switched as follows:
If maximal CPU frequency (set using
esp_pm_configure()
or CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ) is 240 MHz:When
ESP_PM_CPU_FREQ_MAX
orESP_PM_APB_FREQ_MAX
locks are acquired, CPU frequency will be 240 MHz, and APB frequency will be 80 MHz.Otherwise, frequency will be switched to the minimal value set using
esp_pm_configure()
.
If maximal CPU frequency is 160 MHz:
When
ESP_PM_CPU_FREQ_MAX
is acquired, CPU frequency is set to 160 MHz, and APB frequency to 80 MHz.When
ESP_PM_CPU_FREQ_MAX
is not acquired, butESP_PM_APB_FREQ_MAX
is, CPU and APB frequencies are set to 80 MHz.Otherwise, frequency will be switched to the minimal value set using
esp_pm_configure()
.
If maximal CPU frequency is 80 MHz:
When
ESP_PM_CPU_FREQ_MAX
orESP_PM_APB_FREQ_MAX
locks are acquired, CPU and APB frequencies will be 80 MHz.Otherwise, frequency will be switched to the minimal value set using
esp_pm_configure()
.
When none of the locks are aquired, and light sleep is enabled in a call to
esp_pm_configure()
, the system will go into light sleep mode. The duration of light sleep will be determined by:FreeRTOS tasks blocked with finite timeouts
Timers registered with High resolution timer APIs
Light sleep will duration will be chosen to wake up before the nearest event (task being unblocked, or timer elapses).
Dynamic Frequency Scaling and Peripheral Drivers¶
When DFS is enabled, APB frequency can be changed several times within a single RTOS tick. Some peripherals can work normally even when APB frequency changes; some can not.
The following peripherals can work even when APB frequency is changing:
UART: if REF_TICK is used as clock source (see use_ref_tick member of uart_config_t).
LEDC: if REF_TICK is used as clock source (see
ledc_timer_config()
function).RMT: if REF_TICK is used as clock source. Currently the driver does not support REF_TICK, but it can be enabled by clearing
RMT_REF_ALWAYS_ON_CHx
bit for the respective channel.
Currently, the following peripheral drivers are aware of DFS and will use ESP_PM_APB_FREQ_MAX
lock for the duration of the transaction:
SPI master
I2C
I2S (If APLL clock is used then it will use
ESP_PM_NO_LIGHT_SLEEP
lock)SDMMC
The following drivers will hold ESP_PM_APB_FREQ_MAX
lock while the driver is enabled:
SPI slave — between calls to
spi_slave_initialize()
andspi_slave_free()
.Ethernet — between calls to
esp_eth_enable()
andesp_eth_disable()
.WiFi — between calls to
esp_wifi_start()
andesp_wifi_stop()
. If modem sleep is enabled, lock will be released for thte periods of time when radio is disabled.Bluetooth — between calls to
esp_bt_controller_enable()
andesp_bt_controller_disable()
.CAN - between calls to
can_driver_install()
andcan_driver_uninstall()
The following peripheral drivers are not aware of DFS yet. Applications need to acquire/release locks when necessary:
MCPWM
PCNT
Sigma-delta
Timer group
API Reference¶
Header File¶
Functions¶
-
esp_err_t
esp_pm_configure
(const void *config)¶ Set implementation-specific power management configuration.
- Return
ESP_OK on success
ESP_ERR_INVALID_ARG if the configuration values are not correct
ESP_ERR_NOT_SUPPORTED if certain combination of values is not supported, or if CONFIG_PM_ENABLE is not enabled in sdkconfig
- Parameters
config
: pointer to implementation-specific configuration structure (e.g. esp_pm_config_esp32)
-
esp_err_t
esp_pm_lock_create
(esp_pm_lock_type_t lock_type, int arg, const char *name, esp_pm_lock_handle_t *out_handle)¶ Initialize a lock handle for certain power management parameter.
When lock is created, initially it is not taken. Call esp_pm_lock_acquire to take the lock.
This function must not be called from an ISR.
- Return
ESP_OK on success
ESP_ERR_NO_MEM if the lock structure can not be allocated
ESP_ERR_INVALID_ARG if out_handle is NULL or type argument is not valid
ESP_ERR_NOT_SUPPORTED if CONFIG_PM_ENABLE is not enabled in sdkconfig
- Parameters
lock_type
: Power management constraint which the lock should controlarg
: argument, value depends on lock_type, see esp_pm_lock_type_tname
: arbitrary string identifying the lock (e.g. “wifi” or “spi”). Used by the esp_pm_dump_locks function to list existing locks. May be set to NULL. If not set to NULL, must point to a string which is valid for the lifetime of the lock.[out] out_handle
: handle returned from this function. Use this handle when calling esp_pm_lock_delete, esp_pm_lock_acquire, esp_pm_lock_release. Must not be NULL.
-
esp_err_t
esp_pm_lock_acquire
(esp_pm_lock_handle_t handle)¶ Take a power management lock.
Once the lock is taken, power management algorithm will not switch to the mode specified in a call to esp_pm_lock_create, or any of the lower power modes (higher numeric values of ‘mode’).
The lock is recursive, in the sense that if esp_pm_lock_acquire is called a number of times, esp_pm_lock_release has to be called the same number of times in order to release the lock.
This function may be called from an ISR.
This function is not thread-safe w.r.t. calls to other esp_pm_lock_* functions for the same handle.
- Return
ESP_OK on success
ESP_ERR_INVALID_ARG if the handle is invalid
ESP_ERR_NOT_SUPPORTED if CONFIG_PM_ENABLE is not enabled in sdkconfig
- Parameters
handle
: handle obtained from esp_pm_lock_create function
-
esp_err_t
esp_pm_lock_release
(esp_pm_lock_handle_t handle)¶ Release the lock taken using esp_pm_lock_acquire.
Call to this functions removes power management restrictions placed when taking the lock.
Locks are recursive, so if esp_pm_lock_acquire is called a number of times, esp_pm_lock_release has to be called the same number of times in order to actually release the lock.
This function may be called from an ISR.
This function is not thread-safe w.r.t. calls to other esp_pm_lock_* functions for the same handle.
- Return
ESP_OK on success
ESP_ERR_INVALID_ARG if the handle is invalid
ESP_ERR_INVALID_STATE if lock is not acquired
ESP_ERR_NOT_SUPPORTED if CONFIG_PM_ENABLE is not enabled in sdkconfig
- Parameters
handle
: handle obtained from esp_pm_lock_create function
-
esp_err_t
esp_pm_lock_delete
(esp_pm_lock_handle_t handle)¶ Delete a lock created using esp_pm_lock.
The lock must be released before calling this function.
This function must not be called from an ISR.
- Return
ESP_OK on success
ESP_ERR_INVALID_ARG if the handle argument is NULL
ESP_ERR_INVALID_STATE if the lock is still acquired
ESP_ERR_NOT_SUPPORTED if CONFIG_PM_ENABLE is not enabled in sdkconfig
- Parameters
handle
: handle obtained from esp_pm_lock_create function
-
esp_err_t
esp_pm_dump_locks
(FILE *stream)¶ Dump the list of all locks to stderr
This function dumps debugging information about locks created using esp_pm_lock_create to an output stream.
This function must not be called from an ISR. If esp_pm_lock_acquire/release are called while this function is running, inconsistent results may be reported.
- Return
ESP_OK on success
ESP_ERR_NOT_SUPPORTED if CONFIG_PM_ENABLE is not enabled in sdkconfig
- Parameters
stream
: stream to print information to; use stdout or stderr to print to the console; use fmemopen/open_memstream to print to a string buffer.
Type Definitions¶
-
typedef struct esp_pm_lock *
esp_pm_lock_handle_t
¶ Opaque handle to the power management lock.
Enumerations¶
-
enum
esp_pm_lock_type_t
¶ Power management constraints.
Values:
-
ESP_PM_CPU_FREQ_MAX
¶ Require CPU frequency to be at the maximum value set via esp_pm_configure. Argument is unused and should be set to 0.
-
ESP_PM_APB_FREQ_MAX
¶ Require APB frequency to be at the maximum value supported by the chip. Argument is unused and should be set to 0.
-
ESP_PM_NO_LIGHT_SLEEP
¶ Prevent the system from going into light sleep. Argument is unused and should be set to 0.
-
Header File¶
Structures¶
-
struct
esp_pm_config_esp32_t
¶ Power management config for ESP32.
Pass a pointer to this structure as an argument to esp_pm_configure function.
Public Members
-
rtc_cpu_freq_t
max_cpu_freq
¶ Maximum CPU frequency to use. Deprecated, use max_freq_mhz instead.
-
int
max_freq_mhz
¶ Maximum CPU frequency, in MHz
-
rtc_cpu_freq_t
min_cpu_freq
¶ Minimum CPU frequency to use when no frequency locks are taken. Deprecated, use min_freq_mhz instead.
-
int
min_freq_mhz
¶ Minimum CPU frequency to use when no locks are taken, in MHz
-
bool
light_sleep_enable
¶ Enter light sleep when no locks are taken
-
rtc_cpu_freq_t