电源管理

[English]

概述

ESP-IDF 中集成的电源管理算法可以根据应用程序组件的需求,调整外围总线 (APB) 频率、CPU 频率,并使芯片进入 Light-sleep 模式,尽可能减少运行应用程序的功耗。

应用程序组件可以通过创建和获取电源管理锁来控制功耗。

例如:

  • 对于从 APB 获得时钟频率的外设,其驱动可以要求在使用该外设时,将 APB 频率设置为 80 MHz。

  • RTOS 可以要求 CPU 在有任务准备开始运行时以最高配置频率工作。

  • 一些外设可能需要中断才能启用,因此其驱动也会要求禁用 Light-sleep 模式。

因为请求较高的 APB 频率或 CPU 频率,以及禁用 Light-sleep 模式会增加功耗,请将组件使用的电源管理锁降到最少。

电源管理配置

编译时可使用 CONFIG_PM_ENABLE 选项启用电源管理功能。

启用电源管理功能将会增加中断延迟。额外延迟与多个因素有关,例如:CPU 频率、单/双核模式、是否需要进行频率切换等。CPU 频率为 240 MHz 且未启用频率调节时,最小额外延迟为 0.2 us;如果启用频率调节,且在中断入口将频率由 40 MHz 调节至 80 MHz,则最大额外延迟为 40 us。

应用程序可以通过调用 esp_pm_configure() 函数启用动态调频 (DFS) 功能和自动 Light-sleep 模式。此函数的参数为 esp_pm_config_esp32_t,定义了频率调节的相关设置。在此参数结构中,需要初始化下面三个字段:

  • max_freq_mhz:最大 CPU 频率 (MHz),即获取 ESP_PM_CPU_FREQ_MAX 锁后所使用的频率。该字段通常设置为 CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ

  • min_freq_mhz:最小 CPU 频率 (MHz),即仅获取 ESP_PM_APB_FREQ_MAX 锁后所使用的频率。该字段可设置为晶振 (XTAL) 频率值,或者 XTAL 频率值除以整数。注意,10 MHz 是生成 1 MHz 的 REF_TICK 默认时钟所需的最小频率。

  • light_sleep_enable:没有获取任何管理锁时,决定系统是否需要自动进入 Light-sleep 状态 (true/false)。

或者,如果在 menuconfig 中启用了 CONFIG_PM_DFS_INIT_AUTO 选项,最大 CPU 频率将由 CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ 设置决定,最小 CPU 频率将锁定为 XTAL 频率。

注解

  1. 自动 Light-sleep 模式基于 FreeRTOS Tickless Idle 功能,因此如果在 menuconfig 中没有启用 CONFIG_FREERTOS_USE_TICKLESS_IDLE 选项,在请求自动 Light-sleep 时,esp_pm_configure() 将会返回 ESP_ERR_NOT_SUPPORTED 错误。

  2. 在 Light-sleep 状态下,外设设有时钟门控,不会产生来自 GPIO 和内部外设的中断。Sleep Modes 文档中所提到的唤醒源可用于从 Light-sleep 状态触发唤醒。例如,EXT0 和 EXT1 唤醒源就可以通过 GPIO 唤醒芯片。

电源管理锁

应用程序可以通过获取或释放管理锁来控制电源管理算法。应用程序获取电源管理锁后,电源管理算法的操作将受到下面的限制。释放电源管理锁后,限制解除。

电源管理锁设有获取/释放计数器,如果已多次获取电源管理锁,则需要将电源管理锁释放相同次数以解除限制。

ESP32 支持下表中所述的三种电源管理锁。

电源管理锁

描述

ESP_PM_CPU_FREQ_MAX

请求使用 esp_pm_configure() 将 CPU 频率设置为最大值。ESP32 可以将该值设置为 80 MHz、160 MHz 或 240 MHz。

ESP_PM_APB_FREQ_MAX

请求将 APB 频率设置为最大值,ESP32 支持的最大频率为 80 MHz。

ESP_PM_NO_LIGHT_SLEEP

禁止自动切换至 Light-sleep 模式。

ESP32 Power Management Algorithm

The table below shows how CPU and APB frequencies will be switched if dynamic frequency scaling is enabled. You can specify the maximum CPU frequency with either esp_pm_configure() or CONFIG_ESP32_DEFAULT_CPU_FREQ_MHZ.

Max CPU Frequency Set

Lock Acquisition

CPU and APB Frequncies

240

Any of ESP_PM_CPU_FREQ_MAX
or ESP_PM_APB_FREQ_MAX acquired
CPU: 240 MHz
APB: 80 MHz

None

Min values for both frequencies set with esp_pm_configure()

160

ESP_PM_CPU_FREQ_MAX acquired

CPU: 160 MHz
APB: 80 MHz

ESP_PM_CPU_FREQ_MAX acquired, ESP_PM_APB_FREQ_MAX not acquired

CPU: 80 MHz
APB: 80 MHz

None

Min values for both frequencies set with esp_pm_configure()

80

Any of ESP_PM_CPU_FREQ_MAX
or ESP_PM_APB_FREQ_MAX acquired
CPU: 80 MHz
APB: 80 MHz

None

Min values for both frequencies set with esp_pm_configure()

If none of the locks are acquired, 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:

Light sleep duration will be chosen to wake up the chip before the nearest event (task being unblocked, or timer elapses).

动态调频和外设驱动

启用动态调频后,APB 频率可在一个 RTOS 滴答周期内多次更改。有些外设不受 APB 频率变更的影响,但有些外设可能会出现问题。例如,Timer Group 外设定时器会继续计数,但定时器计数的速度将随 APB 频率的变更而变更。

下面的外设不受 APB 频率变更的影响:

  • UART:如果 REF_TICK 用作时钟源,则 UART 不受 APB 频率变更影响。请查看 uart_config_t 中的 use_ref_tick

  • LEDC:如果 REF_TICK 用作时钟源,则 LEDC 不受 APB 频率变更影响。请查看 ledc_timer_config() 函数。

  • RMT:如果 REF_TICK 用作时钟源,则 RMT 不受 APB 频率变更影响。请查看 rmt_config_t 结构体中的 flags 成员以及 RMT_CHANNEL_FLAGS_ALWAYS_ON 宏。

目前以下外设驱动程序可感知动态调频,并在调频期间使用 ESP_PM_APB_FREQ_MAX 锁:

  • SPI master

  • I2C

  • I2S(如果 APLL 锁在使用中,I2S 则会启用 ESP_PM_NO_LIGHT_SLEEP 锁)

  • SDMMC

启用以下驱动程序时,将占用 ESP_PM_APB_FREQ_MAX 锁:

以下外设驱动程序无法感知动态调频,应用程序需自己获取/释放管理锁:

  • PCNT

  • Sigma-delta

  • Timer group

  • MCPWM

API 参考

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_get_configuration(void *config)

Get implementation-specific power management configuration.

Return

  • ESP_OK on success

  • ESP_ERR_INVALID_ARG if the pointer is null

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 control

  • arg: argument, value depends on lock_type, see esp_pm_lock_type_t

  • name: 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.

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

int max_freq_mhz

Maximum CPU frequency, in MHz

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