警告

This document is not updated for ESP32H2 yet, so some of the content may not be correct.

This warning was automatically inserted due to the source file being in the add_warnings_pages list.

电源管理

[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_t 定义了频率调节的相关设置。在此参数结构中,需要初始化以下三个字段:

  • max_freq_mhz:最大 CPU 频率 (MHz),即获取 ESP_PM_CPU_FREQ_MAX 锁后所使用的频率。该字段通常设置为 CONFIG_ESP_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_ESP_DEFAULT_CPU_FREQ_MHZ 设置决定,最小 CPU 频率将锁定为 XTAL 频率。

备注

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

备注

Light-sleep 状态下,外设设有时钟门控,不会产生来自 GPIO 和内部外设的中断。睡眠模式 文档中所提到的唤醒源可用于从 Light-sleep 状态触发唤醒。

例如,EXT0 和 EXT1 唤醒源可以通过 GPIO 唤醒芯片。

电源管理锁

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

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

ESP32-H2 支持下表中三种电源管理锁。

电源管理锁

描述

ESP_PM_CPU_FREQ_MAX

请求使用 esp_pm_configure() 将 CPU 频率设置为最大值。ESP32-H2 可以将该值设置为 Not updated yet。

ESP_PM_APB_FREQ_MAX

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

ESP_PM_NO_LIGHT_SLEEP

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

ESP32-H2 电源管理算法

下表列出了启用动态调频时如何切换 CPU 频率和 APB 频率。您可以使用 esp_pm_configure() 或者 CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ 指定 CPU 最大频率。

CPU 最高频率

电源管理锁获取情况

APB 频率和 CPU 频率

96

获取 ESP_PM_CPU_FREQ_MAX

CPU: 96 MHz
APB: 32 Mhz
获取 ESP_PM_APB_FREQ_MAX,
未获得 ESP_PM_CPU_FREQ_MAX
CPU: 32 MHz
APB: 32 Mhz

使用 esp_pm_configure() 为二者设置最小值

64

获取 ESP_PM_CPU_FREQ_MAX

CPU: 64 MHz
APB: 32 Mhz
获取 ESP_PM_APB_FREQ_MAX,
未获得 ESP_PM_CPU_FREQ_MAX
CPU: 32 MHz
APB: 32 Mhz

使用 esp_pm_configure() 为二者设置最小值

48

获取 ESP_PM_CPU_FREQ_MAX

CPU: 48 MHz
APB: 32 Mhz
获取 ESP_PM_APB_FREQ_MAX,
未获得 ESP_PM_CPU_FREQ_MAX
CPU: 32 MHz
APB: 32 Mhz

使用 esp_pm_configure() 为二者设置最小值

如果没有获取任何管理锁,调用 esp_pm_configure() 将启动 Light-sleep 模式。 Light-sleep 模式持续时间由以下因素决定:

  • 处于阻塞状态的 FreeRTOS 任务数(有限超时)

  • 高分辨率定时器 API 注册的计数器数量

您也可以设置 Light-sleep 模式在最近事件(任务解除阻塞,或计时器超时)之前持续多久才唤醒芯片。

为了跳过不必要的唤醒,可以将 skip_unhandled_events 选项设置为 true 来初始化 esp_timer。带有此标志的定时器不会唤醒系统,有助于减少功耗。

动态调频和外设驱动

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

时钟频率不受 APB 频率影响的外设时钟源通常有 REF_TICK, XTAL, RC_FAST (i.e. RTC_8M)。因此,为了保证外设在 DFS 期间的所有行为一致,建议在上述时钟中选择其一作为外设的时钟源。如果想要了解更多详情可以浏览每个外设 ”API 参考 > 外设 API“ 页面的 “电源管理” 章节。

目前以下外设驱动程序可感知动态调频,并在调频期间使用 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 驱动

Light-sleep 外设下电

ESP32-H2 支持在 Light-sleep 时掉电外设的电源域.

如果在 menuconfig 中启用了 CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP,在初始化外设时,驱动会将外设工作的寄存器上下文注册到休眠备份链表中, 在进入休眠前,REG_DMA 外设会读取休眠备份链表中的配置,根据链表中的配置将外设的寄存器上下文备份至内存,REG_DMA 也会在唤醒时将上下文从内存恢复到外设寄存中。

目前 IDF 支持以下外设的 Light-sleep 上下文备份: - INT_MTX - TEE/APM - IO_MUX / GPIO - UART0 - TIMG0 - SPI0/1 - SYSTIMER

以下外设尚未支持: - ETM - TIMG1 - ASSIST_DEBUG - Trace - Crypto: AES/ECC/HMAC/RSA/SHA/DS/XTA_AES/ECDSA - SPI2 - I2C - I2S - PCNT - USB-Serial-JTAG - TWAI - LEDC - MCPWM - RMT - SARADC - SDIO - PARL_IO - UART1

对于未支持 Light-sleep 上下文备份的外设,若启用了电源管理功能,应在外设工作时持有 ESP_PM_NO_LIGHT_SLEEP 锁以避免进入休眠导致外设工作上下文丢失。

备注

当外设电源域在睡眠期间断电时,IO_MUX 和 GPIO 模块都处于下电状态,这意味着芯片引脚的状态不会受这些模块控制。要在休眠期间保持 IO 的状态,需要在配置 GPIO 状态前后调用 gpio_hold_dis()gpio_hold_en()。此操作可确保 IO 配置被锁存,防止 IO 在睡眠期间浮空。

API 参考

Header File

Functions

esp_err_t esp_pm_configure(const void *config)

Set implementation-specific power management configuration.

参数

config -- pointer to implementation-specific configuration structure (e.g. esp_pm_config_esp32)

返回

  • 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

esp_err_t esp_pm_get_configuration(void *config)

Get implementation-specific power management configuration.

参数

config -- pointer to implementation-specific configuration structure (e.g. esp_pm_config_esp32)

返回

  • ESP_OK on success

  • ESP_ERR_INVALID_ARG if the pointer is null

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.

参数
  • 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_handle -- [out] 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_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

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.

参数

handle -- handle obtained from esp_pm_lock_create function

返回

  • 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

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.

参数

handle -- handle obtained from esp_pm_lock_create function

返回

  • 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

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.

参数

handle -- handle obtained from esp_pm_lock_create function

返回

  • 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

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.

参数

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.

返回

  • ESP_OK on success

  • ESP_ERR_NOT_SUPPORTED if CONFIG_PM_ENABLE is not enabled in sdkconfig

Structures

struct esp_pm_config_t

Power management config.

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

Type Definitions

typedef esp_pm_config_t esp_pm_config_esp32_t

backward compatibility newer chips no longer require this typedef

typedef esp_pm_config_t esp_pm_config_esp32s2_t
typedef esp_pm_config_t esp_pm_config_esp32s3_t
typedef esp_pm_config_t esp_pm_config_esp32c3_t
typedef esp_pm_config_t esp_pm_config_esp32c2_t
typedef esp_pm_config_t esp_pm_config_esp32c6_t
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:

enumerator 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.

enumerator 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.

enumerator ESP_PM_NO_LIGHT_SLEEP

Prevent the system from going into light sleep. Argument is unused and should be set to 0.