Merge branch 'bugfix/idf-11425' into 'master'

power management module memory (iram or flash) usage optimization

Closes IDF-11425

See merge request espressif/esp-idf!37550
This commit is contained in:
Jiang Jiang Jian
2025-04-19 11:55:45 +08:00
29 changed files with 396 additions and 216 deletions

View File

@@ -2,6 +2,7 @@ menu "ADC and ADC Calibration"
config ADC_ONESHOT_CTRL_FUNC_IN_IRAM
bool "Place ISR version ADC oneshot mode read function into IRAM"
select ESP_PERIPH_CTRL_FUNC_IN_IRAM
default n
help
Place ISR version ADC oneshot mode read function into IRAM.

View File

@@ -6,6 +6,7 @@ menu "ESP-Driver:Parallel IO Configurations"
default y
select PARLIO_OBJ_CACHE_SAFE
select GDMA_CTRL_FUNC_IN_IRAM
select ESP_PERIPH_CTRL_FUNC_IN_IRAM
help
Place Parallel IO TX ISR handler in IRAM to reduce latency caused by cache miss.

View File

@@ -23,6 +23,7 @@ menu "ESP-Driver:SPI Configurations"
bool "Place SPI master ISR function into IRAM"
default y
depends on !HEAP_PLACE_FUNCTION_INTO_FLASH
select ESP_PERIPH_CTRL_FUNC_IN_IRAM
select ESP_SPI_BUS_LOCK_ISR_FUNCS_IN_IRAM
select GDMA_CTRL_FUNC_IN_IRAM if SOC_GDMA_SUPPORTED
help
@@ -51,6 +52,7 @@ menu "ESP-Driver:SPI Configurations"
config SPI_SLAVE_ISR_IN_IRAM
bool "Place SPI slave ISR function into IRAM"
default y
select ESP_PERIPH_CTRL_FUNC_IN_IRAM
select GDMA_CTRL_FUNC_IN_IRAM if SOC_GDMA_SUPPORTED
help
Place the SPI slave ISR in to IRAM to avoid possible cache miss.

View File

@@ -70,6 +70,10 @@ menu "Hardware Settings"
# regardless of power management configuration.
config ESP_SLEEP_POWER_DOWN_FLASH
bool "Power down flash in light sleep when there is no SPIRAM or SPIRAM has independent power supply"
# TODO: PM-383
select PM_SLP_IRAM_OPT if (!IDF_TARGET_ESP32H21 && !IDF_TARGET_ESP32H4)
select ESP_PERIPH_CTRL_FUNC_IN_IRAM
select ESP_REGI2C_CTRL_FUNC_IN_IRAM
depends on !SPIRAM || ESP_LDO_RESERVE_PSRAM
depends on !(IDF_TARGET_ESP32P4 && (ESP32P4_REV_MIN_FULL < 100))
default n
@@ -219,12 +223,19 @@ menu "Hardware Settings"
endmenu
menu "Peripheral Control"
config PERIPH_CTRL_FUNC_IN_IRAM
config ESP_PERIPH_CTRL_FUNC_IN_IRAM
bool "Place peripheral control functions into IRAM"
default n
help
Place peripheral control functions (e.g. periph_module_reset) into IRAM,
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
config ESP_REGI2C_CTRL_FUNC_IN_IRAM
bool "Place regi2c control functions into IRAM"
default y
help
Place analog i2c master control functions (e.g. regi2c_ctrl_read_reg, regi2c_ctrl_write_reg) into IRAM,
so that these functions can be IRAM-safe and able to be called in the other IRAM interrupt context.
endmenu
menu "ETM Configuration"

View File

@@ -26,6 +26,12 @@
#define MHZ (1000000)
#if CONFIG_PM_SLP_IRAM_OPT
# define ESP_CLK_FN_ATTR IRAM_ATTR
#else
# define ESP_CLK_FN_ATTR
#endif
// g_ticks_us defined in ROMs for PRO and APP CPU
extern uint32_t g_ticks_per_us_pro;
@@ -48,7 +54,7 @@ _Static_assert(offsetof(retain_mem_t, checksum) == sizeof(retain_mem_t) - sizeof
#if !NON_OS_BUILD
static __attribute__((section(".rtc_timer_data_in_rtc_mem"))) retain_mem_t s_rtc_timer_retain_mem;
static uint32_t calc_checksum(void)
static ESP_CLK_FN_ATTR uint32_t calc_checksum(void)
{
uint32_t checksum = 0;
uint32_t *data = (uint32_t*) &s_rtc_timer_retain_mem;

View File

@@ -12,36 +12,61 @@ entries:
cpu: esp_cpu_clear_watchpoint (noflash)
cpu: esp_cpu_compare_and_set (noflash)
esp_memory_utils (noflash)
rtc_clk (noflash)
clk_utils (noflash)
if PM_SLP_IRAM_OPT = y:
rtc_clk (noflash)
rtc_time (noflash_text)
if SOC_CONFIGURABLE_VDDSDIO_SUPPORTED = y:
rtc_init:rtc_vddsdio_get_config (noflash)
rtc_init:rtc_vddsdio_set_config (noflash)
if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S2 = y || IDF_TARGET_ESP32S3 = y || IDF_TARGET_ESP32C2 = y || IDF_TARGET_ESP32C3 = y:
rtc_sleep (noflash_text)
rtc_time (noflash_text)
rtc_sleep:rtc_sleep_start (noflash)
if PM_SLP_IRAM_OPT = y:
rtc_sleep:rtc_sleep_get_default_config (noflash)
rtc_sleep:rtc_sleep_init (noflash)
rtc_sleep:rtc_sleep_low_init (noflash)
if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S2 = y:
rtc_sleep:rtc_sleep_pd (noflash)
if IDF_TARGET_ESP32S3 = y || IDF_TARGET_ESP32C2 = y || IDF_TARGET_ESP32C3 = y:
rtc_sleep:rtc_sleep_pu (noflash)
if SOC_PMU_SUPPORTED = y && SOC_LIGHT_SLEEP_SUPPORTED = y:
pmu_sleep (noflash)
if SPIRAM_FLASH_LOAD_TO_PSRAM = y:
pmu_init (noflash)
pmu_param (noflash)
if SOC_USB_SERIAL_JTAG_SUPPORTED = y:
if SPIRAM_FLASH_LOAD_TO_PSRAM = y:
pmu_init (noflash)
pmu_param (noflash)
elif PM_SLP_IRAM_OPT = y && IDF_TARGET_ESP32P4 != y:
pmu_param:get_act_hp_dbias (noflash)
pmu_param:get_act_lp_dbias (noflash)
if PM_SLP_IRAM_OPT = y && SOC_USB_SERIAL_JTAG_SUPPORTED = y:
sleep_console (noflash)
if SOC_USB_OTG_SUPPORTED && SOC_PM_SUPPORT_CNNT_PD = y:
if PM_SLP_IRAM_OPT = y && SOC_USB_OTG_SUPPORTED && SOC_PM_SUPPORT_CNNT_PD = y:
sleep_usb (noflash)
if IDF_TARGET_ESP32 = y || IDF_TARGET_ESP32S2 = y:
rtc_wdt (noflash_text)
if PERIPH_CTRL_FUNC_IN_IRAM = y:
periph_ctrl: periph_module_reset (noflash)
if PERIPH_CTRL_FUNC_IN_IRAM = y && ESP_WIFI_ENABLED = y:
if ESP_PERIPH_CTRL_FUNC_IN_IRAM = y:
periph_ctrl:periph_module_reset (noflash)
periph_ctrl:periph_rcc_enter (noflash)
periph_ctrl:periph_rcc_exit (noflash)
periph_ctrl:periph_rcc_acquire_enter (noflash)
periph_ctrl:periph_rcc_acquire_exit (noflash)
periph_ctrl:periph_rcc_release_enter (noflash)
periph_ctrl:periph_rcc_release_exit (noflash)
if ESP_PERIPH_CTRL_FUNC_IN_IRAM = y && ESP_WIFI_ENABLED = y:
periph_ctrl: wifi_module_enable (noflash)
periph_ctrl: wifi_module_disable (noflash)
if ESP_REGI2C_CTRL_FUNC_IN_IRAM = y:
regi2c_ctrl:regi2c_ctrl_read_reg (noflash)
regi2c_ctrl:regi2c_ctrl_read_reg_mask (noflash)
regi2c_ctrl:regi2c_ctrl_write_reg (noflash)
regi2c_ctrl:regi2c_ctrl_write_reg_mask (noflash)
regi2c_ctrl:regi2c_enter_critical (noflash)
regi2c_ctrl:regi2c_exit_critical (noflash)
if SOC_SYSTIMER_SUPPORTED = y:
systimer (noflash)
if SOC_ADC_SHARED_POWER = y:
if ADC_ONESHOT_CTRL_FUNC_IN_IRAM = y:
sar_periph_ctrl (noflash)
else:
elif PM_SLP_IRAM_OPT = y:
sar_periph_ctrl: sar_periph_ctrl_power_enable (noflash)
[mapping:soc_pm]

View File

@@ -21,35 +21,35 @@ static portMUX_TYPE periph_spinlock = portMUX_INITIALIZER_UNLOCKED;
static uint8_t ref_counts[PERIPH_MODULE_MAX] = {0};
IRAM_ATTR void periph_rcc_enter(void)
void periph_rcc_enter(void)
{
portENTER_CRITICAL_SAFE(&periph_spinlock);
}
IRAM_ATTR void periph_rcc_exit(void)
void periph_rcc_exit(void)
{
portEXIT_CRITICAL_SAFE(&periph_spinlock);
}
IRAM_ATTR uint8_t periph_rcc_acquire_enter(periph_module_t periph)
uint8_t periph_rcc_acquire_enter(periph_module_t periph)
{
periph_rcc_enter();
return ref_counts[periph];
}
IRAM_ATTR void periph_rcc_acquire_exit(periph_module_t periph, uint8_t ref_count)
void periph_rcc_acquire_exit(periph_module_t periph, uint8_t ref_count)
{
ref_counts[periph] = ++ref_count;
periph_rcc_exit();
}
IRAM_ATTR uint8_t periph_rcc_release_enter(periph_module_t periph)
uint8_t periph_rcc_release_enter(periph_module_t periph)
{
periph_rcc_enter();
return ref_counts[periph] - 1;
}
IRAM_ATTR void periph_rcc_release_exit(periph_module_t periph, uint8_t ref_count)
void periph_rcc_release_exit(periph_module_t periph, uint8_t ref_count)
{
ref_counts[periph] = ref_count;
periph_rcc_exit();

View File

@@ -65,7 +65,7 @@ typedef struct {
* Configure whether certain peripherals are powered down in deep sleep
* @param cfg power down flags as rtc_sleep_pd_config_t structure
*/
static void rtc_sleep_pd(rtc_sleep_pd_config_t cfg)
void rtc_sleep_pd(rtc_sleep_pd_config_t cfg)
{
REG_SET_FIELD(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_LSLP_MEM_FORCE_PU, ~cfg.dig_pd);
REG_SET_FIELD(RTC_CNTL_PWC_REG, RTC_CNTL_SLOWMEM_FORCE_LPU, ~cfg.rtc_pd);
@@ -345,7 +345,7 @@ uint32_t rtc_deep_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
return rtc_sleep_finish();
}
static uint32_t rtc_sleep_finish(void)
static IRAM_ATTR uint32_t rtc_sleep_finish(void)
{
/* In deep sleep mode, we never get here */
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);

View File

@@ -222,7 +222,7 @@ uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp
return rtc_sleep_finish(lslp_mem_inf_fpu);
}
static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
static IRAM_ATTR uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
{
/* In deep sleep mode, we never get here */
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);

View File

@@ -352,7 +352,7 @@ uint32_t rtc_deep_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
return rtc_sleep_finish(0);
}
static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
static IRAM_ATTR uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
{
/* In deep sleep mode, we never get here */
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);

View File

@@ -361,7 +361,7 @@ uint32_t rtc_deep_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt)
return rtc_sleep_finish(0);
}
static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
static IRAM_ATTR uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
{
/* In deep sleep mode, we never get here */
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);

View File

@@ -284,7 +284,7 @@ __attribute__((weak)) uint32_t rtc_sleep_start(uint32_t wakeup_opt, uint32_t rej
return rtc_sleep_finish(lslp_mem_inf_fpu);
}
static uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
static IRAM_ATTR uint32_t rtc_sleep_finish(uint32_t lslp_mem_inf_fpu)
{
/* In deep sleep mode, we never get here */
uint32_t reject = REG_GET_FIELD(RTC_CNTL_INT_RAW_REG, RTC_CNTL_SLP_REJECT_INT_RAW);

View File

@@ -18,7 +18,7 @@ static portMUX_TYPE mux = portMUX_INITIALIZER_UNLOCKED;
static DRAM_ATTR __attribute__((unused)) const char *TAG = "REGI2C";
uint8_t IRAM_ATTR regi2c_ctrl_read_reg(uint8_t block, uint8_t host_id, uint8_t reg_add)
uint8_t regi2c_ctrl_read_reg(uint8_t block, uint8_t host_id, uint8_t reg_add)
{
REGI2C_CLOCK_ENABLE();
portENTER_CRITICAL_SAFE(&mux);
@@ -28,7 +28,7 @@ uint8_t IRAM_ATTR regi2c_ctrl_read_reg(uint8_t block, uint8_t host_id, uint8_t r
return value;
}
uint8_t IRAM_ATTR regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb)
uint8_t regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb)
{
REGI2C_CLOCK_ENABLE();
portENTER_CRITICAL_SAFE(&mux);
@@ -38,7 +38,7 @@ uint8_t IRAM_ATTR regi2c_ctrl_read_reg_mask(uint8_t block, uint8_t host_id, uint
return value;
}
void IRAM_ATTR regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data)
void regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t data)
{
REGI2C_CLOCK_ENABLE();
portENTER_CRITICAL_SAFE(&mux);
@@ -47,7 +47,7 @@ void IRAM_ATTR regi2c_ctrl_write_reg(uint8_t block, uint8_t host_id, uint8_t reg
REGI2C_CLOCK_DISABLE();
}
void IRAM_ATTR regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data)
void regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_t reg_add, uint8_t msb, uint8_t lsb, uint8_t data)
{
REGI2C_CLOCK_ENABLE();
portENTER_CRITICAL_SAFE(&mux);
@@ -56,12 +56,12 @@ void IRAM_ATTR regi2c_ctrl_write_reg_mask(uint8_t block, uint8_t host_id, uint8_
REGI2C_CLOCK_DISABLE();
}
void IRAM_ATTR regi2c_enter_critical(void)
void regi2c_enter_critical(void)
{
portENTER_CRITICAL_SAFE(&mux);
}
void IRAM_ATTR regi2c_exit_critical(void)
void regi2c_exit_critical(void)
{
portEXIT_CRITICAL_SAFE(&mux);
}

View File

@@ -33,6 +33,12 @@ static const char *TAG_TSENS = "temperature_sensor";
#define TSENS_RCC_ATOMIC()
#endif
#if CONFIG_PM_SLP_IRAM_OPT
# define SAR_PERIPH_CTRL_COMMON_FN_ATTR IRAM_ATTR
#else
# define SAR_PERIPH_CTRL_COMMON_FN_ATTR
#endif
static int s_record_min = INT_NOT_USED;
static int s_record_max = INT_NOT_USED;
static int s_temperature_sensor_power_cnt;
@@ -79,7 +85,7 @@ void temperature_sensor_power_release(void)
portEXIT_CRITICAL(&rtc_spinlock);
}
static int temperature_sensor_get_raw_value(void)
static SAR_PERIPH_CTRL_COMMON_FN_ATTR int temperature_sensor_get_raw_value(void)
{
int raw_value = temperature_sensor_ll_get_raw_value();
return (TEMPERATURE_SENSOR_LL_ADC_FACTOR * raw_value - TEMPERATURE_SENSOR_LL_DAC_FACTOR * temperature_sensor_attributes[s_tsens_idx].offset - TEMPERATURE_SENSOR_LL_OFFSET_FACTOR);

View File

@@ -7,3 +7,5 @@ CONFIG_FOUR_UNIVERSAL_MAC_ADDRESS CONFIG_ESP32_UNIVERSAL_M
CONFIG_ESP_SYSTEM_PD_FLASH CONFIG_ESP_SLEEP_POWER_DOWN_FLASH
CONFIG_ESP_SYSTEM_BROWNOUT_INTR CONFIG_ESP_BROWNOUT_USE_INTR
CONFIG_PERIPH_CTRL_FUNC_IN_IRAM CONFIG_ESP_PERIPH_CTRL_FUNC_IN_IRAM

View File

@@ -14,6 +14,7 @@
#include "esp_log.h"
#include "esp_memory_utils.h"
#include "soc/soc_caps.h"
#include "soc/uart_pins.h"
#include "sdkconfig.h"
@@ -151,6 +152,23 @@ IRAM_ATTR void esp_sleep_isolate_digital_gpio(void)
/* isolate digital IO that is not held(keep the configuration of digital IOs held by users) */
for (gpio_num_t gpio_num = GPIO_NUM_0; gpio_num < GPIO_NUM_MAX; gpio_num++) {
if (GPIO_IS_VALID_DIGITAL_IO_PAD(gpio_num) && !gpio_hal_is_digital_io_hold(&gpio_hal, gpio_num)) {
bool is_mspi_io_pad = false;
esp_mspi_io_t mspi_ios[] = { ESP_MSPI_IO_CS0, ESP_MSPI_IO_CLK, ESP_MSPI_IO_Q, ESP_MSPI_IO_D, ESP_MSPI_IO_HD, ESP_MSPI_IO_WP };
for (int i = 0; i < sizeof(mspi_ios) / sizeof(mspi_ios[0]); i++) {
if (esp_mspi_get_io(mspi_ios[i]) == gpio_num) {
is_mspi_io_pad = true;
break;
}
}
// Ignore MSPI and default Console UART io pads, When the CPU executes
// the following instructions to configure the MSPI IO PAD, access on
// the MSPI signal lines (as CPU instruction execution and MSPI access
// operations are asynchronous) may cause the SoC to hang.
if (is_mspi_io_pad || gpio_num == U0RXD_GPIO_NUM || gpio_num == U0TXD_GPIO_NUM) {
continue;
}
/* disable I/O */
gpio_hal_input_disable(&gpio_hal, gpio_num);
gpio_hal_output_disable(&gpio_hal, gpio_num);

View File

@@ -77,7 +77,7 @@ esp_err_t esp_unregister_mac_bb_pd_callback(mac_bb_power_down_cb_t cb)
return ESP_ERR_INVALID_STATE;
}
void IRAM_ATTR mac_bb_power_down_cb_execute(void)
void mac_bb_power_down_cb_execute(void)
{
for (int i = 0; i < MAC_BB_POWER_DOWN_CB_NO; i++) {
if (s_mac_bb_power_down_cb[i]) {
@@ -118,7 +118,7 @@ esp_err_t esp_unregister_mac_bb_pu_callback(mac_bb_power_up_cb_t cb)
return ESP_ERR_INVALID_STATE;
}
void IRAM_ATTR mac_bb_power_up_cb_execute(void)
void mac_bb_power_up_cb_execute(void)
{
for (int i = 0; i < MAC_BB_POWER_UP_CB_NO; i++) {
if (s_mac_bb_power_up_cb[i]) {
@@ -221,7 +221,7 @@ bool modem_domain_pd_allowed(void)
#endif
}
uint32_t IRAM_ATTR sleep_modem_reject_triggers(void)
uint32_t sleep_modem_reject_triggers(void)
{
uint32_t reject_triggers = 0;
#if SOC_PM_SUPPORT_PMU_MODEM_STATE

View File

@@ -162,6 +162,12 @@
#elif CONFIG_IDF_TARGET_ESP32C2
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (118)
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9)
# if !CONFIG_PM_SLP_IRAM_OPT
#undef DEFAULT_SLEEP_OUT_OVERHEAD_US
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (2779)
#undef DEFAULT_HARDWARE_OUT_OVERHEAD_US
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (157)
# endif
#elif CONFIG_IDF_TARGET_ESP32C6
#define DEFAULT_SLEEP_OUT_OVERHEAD_US (318)
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (56)
@@ -216,6 +222,12 @@
#define CHECK_SOURCE(source, value, mask) ((s_config.wakeup_triggers & mask) && \
(source == value))
#if CONFIG_PM_SLP_IRAM_OPT
# define SLEEP_FN_ATTR IRAM_ATTR
#else
# define SLEEP_FN_ATTR
#endif
#define MAX_DSLP_HOOKS 3
static esp_deep_sleep_cb_t s_dslp_cb[MAX_DSLP_HOOKS] = {0};
@@ -525,7 +537,7 @@ static uint32_t s_stopped_tgwdt_bmap = 0;
#endif
// Must be called from critical sections.
static void IRAM_ATTR suspend_timers(uint32_t sleep_flags) {
static SLEEP_FN_ATTR void suspend_timers(uint32_t sleep_flags) {
if (!(sleep_flags & RTC_SLEEP_PD_XTAL)) {
#if SOC_SLEEP_TGWDT_STOP_WORKAROUND
/* If timegroup implemented task watchdog or interrupt watchdog is running, we have to stop it. */
@@ -547,7 +559,7 @@ static void IRAM_ATTR suspend_timers(uint32_t sleep_flags) {
}
// Must be called from critical sections.
static void IRAM_ATTR resume_timers(uint32_t sleep_flags) {
static SLEEP_FN_ATTR void resume_timers(uint32_t sleep_flags) {
if (!(sleep_flags & RTC_SLEEP_PD_XTAL)) {
#if SOC_SLEEP_SYSTIMER_STALL_WORKAROUND
for (uint32_t counter_id = 0; counter_id < SOC_SYSTIMER_COUNTER_NUM; ++counter_id) {
@@ -567,7 +579,7 @@ static void IRAM_ATTR resume_timers(uint32_t sleep_flags) {
}
// [refactor-todo] provide target logic for body of uart functions below
static void IRAM_ATTR flush_uarts(void)
static SLEEP_FN_ATTR void flush_uarts(void)
{
for (int i = 0; i < SOC_UART_HP_NUM; ++i) {
if (uart_ll_is_enabled(i)) {
@@ -582,7 +594,7 @@ static uint32_t s_suspended_uarts_bmap = 0;
* Suspend enabled uarts and return suspended uarts bit map.
* Must be called from critical sections.
*/
FORCE_INLINE_ATTR void suspend_uarts(void)
static SLEEP_FN_ATTR void suspend_uarts(void)
{
s_suspended_uarts_bmap = 0;
for (int i = 0; i < SOC_UART_HP_NUM; ++i) {
@@ -603,7 +615,7 @@ FORCE_INLINE_ATTR void suspend_uarts(void)
}
// Must be called from critical sections
FORCE_INLINE_ATTR void resume_uarts(void)
static SLEEP_FN_ATTR void resume_uarts(void)
{
for (int i = 0; i < SOC_UART_HP_NUM; ++i) {
if (s_suspended_uarts_bmap & 0x1) {
@@ -629,7 +641,7 @@ FORCE_INLINE_ATTR void resume_uarts(void)
completion time has exceeded the wakeup time, we should abandon the flush, skip the sleep and
return ESP_ERR_SLEEP_REJECT.
*/
FORCE_INLINE_ATTR bool light_sleep_uart_prepare(uint32_t sleep_flags, int64_t sleep_duration)
static SLEEP_FN_ATTR bool light_sleep_uart_prepare(uint32_t sleep_flags, int64_t sleep_duration)
{
bool should_skip_sleep = false;
#if !SOC_PM_SUPPORT_TOP_PD || !CONFIG_ESP_CONSOLE_UART
@@ -662,7 +674,7 @@ FORCE_INLINE_ATTR bool light_sleep_uart_prepare(uint32_t sleep_flags, int64_t sl
/**
* These save-restore workaround should be moved to lower layer
*/
FORCE_INLINE_ATTR void misc_modules_sleep_prepare(uint32_t sleep_flags, bool deep_sleep)
static SLEEP_FN_ATTR void misc_modules_sleep_prepare(uint32_t sleep_flags, bool deep_sleep)
{
if (deep_sleep){
for (int n = 0; n < MAX_DSLP_HOOKS; n++) {
@@ -716,7 +728,7 @@ FORCE_INLINE_ATTR void misc_modules_sleep_prepare(uint32_t sleep_flags, bool dee
/**
* These save-restore workaround should be moved to lower layer
*/
FORCE_INLINE_ATTR void misc_modules_wake_prepare(uint32_t sleep_flags)
static SLEEP_FN_ATTR void misc_modules_wake_prepare(uint32_t sleep_flags)
{
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
if (sleep_flags & PMU_SLEEP_PD_TOP) {
@@ -760,7 +772,7 @@ FORCE_INLINE_ATTR void misc_modules_wake_prepare(uint32_t sleep_flags)
#endif
}
static IRAM_ATTR void sleep_low_power_clock_calibration(bool is_dslp)
static SLEEP_FN_ATTR void sleep_low_power_clock_calibration(bool is_dslp)
{
// Calibrate rtc slow clock
#ifdef CONFIG_ESP_SYSTEM_RTC_EXT_XTAL
@@ -800,7 +812,133 @@ static IRAM_ATTR void sleep_low_power_clock_calibration(bool is_dslp)
inline static uint32_t call_rtc_sleep_start(uint32_t reject_triggers, uint32_t lslp_mem_inf_fpu, bool dslp);
static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t clk_flags, esp_sleep_mode_t mode, bool allow_sleep_rejection)
#if SOC_PMU_SUPPORTED
static esp_err_t IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint32_t reject_triggers, bool deep_sleep, pmu_sleep_config_t *config)
#else
static esp_err_t IRAM_ATTR esp_sleep_start_safe(uint32_t sleep_flags, uint32_t reject_triggers, bool deep_sleep, rtc_sleep_config_t *config)
#endif
{
esp_err_t result = ESP_OK;
#if CONFIG_ESP_SLEEP_DEBUG
if (s_sleep_ctx != NULL) {
s_sleep_ctx->wakeup_triggers = s_config.wakeup_triggers;
}
#endif
if (deep_sleep) {
#if SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP && !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP
esp_sleep_isolate_digital_gpio();
#endif
#if ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB && SOC_DEEP_SLEEP_SUPPORTED
#if SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
esp_set_deep_sleep_wake_stub_default_entry();
#elif !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP && SOC_RTC_FAST_MEM_SUPPORTED
/* If not possible stack is in RTC FAST memory, use the ROM function to calculate the CRC and save ~140 bytes IRAM */
set_rtc_memory_crc();
#endif // SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
#endif
#if SOC_DCDC_SUPPORTED
uint64_t ldo_increased_us = rtc_time_slowclk_to_us(rtc_time_get() - s_config.rtc_ticks_at_ldo_prepare, s_config.rtc_clk_cal_period);
if (ldo_increased_us < LDO_POWER_TAKEOVER_PREPARATION_TIME_US) {
esp_rom_delay_us(LDO_POWER_TAKEOVER_PREPARATION_TIME_US - ldo_increased_us);
}
pmu_sleep_shutdown_dcdc();
#endif
// Enter Deep Sleep
#if!ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB || SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY || !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
#if SOC_PMU_SUPPORTED
result = call_rtc_sleep_start(reject_triggers, config->power.hp_sys.dig_power.mem_dslp, deep_sleep);
#else
result = call_rtc_sleep_start(reject_triggers, config->lslp_mem_inf_fpu, deep_sleep);
#endif
#else
/* Otherwise, need to call the dedicated soc function for this */
result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers);
#endif
} else {
suspend_timers(sleep_flags);
/* Cache Suspend 1: will wait cache idle in cache suspend */
suspend_cache();
/* On esp32c6, only the lp_aon pad hold function can only hold the GPIO state in the active mode.
In order to avoid the leakage of the SPI cs pin, hold it here */
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) {
#if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
/* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */
#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359
gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS0);
#endif
#endif
#if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
/* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */
gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS1);
#endif
}
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
if (sleep_flags & PMU_SLEEP_PD_TOP) {
esp_sleep_mmu_retention(true);
}
#endif
#if SOC_DCDC_SUPPORTED && !CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON
uint64_t ldo_increased_us = rtc_time_slowclk_to_us(rtc_time_get() - s_config.rtc_ticks_at_ldo_prepare, s_config.rtc_clk_cal_period);
if (ldo_increased_us < LDO_POWER_TAKEOVER_PREPARATION_TIME_US) {
esp_rom_delay_us(LDO_POWER_TAKEOVER_PREPARATION_TIME_US - ldo_increased_us);
}
pmu_sleep_shutdown_dcdc();
#endif
#if SOC_PMU_SUPPORTED
#if SOC_PM_CPU_RETENTION_BY_SW && ESP_SLEEP_POWER_DOWN_CPU
esp_sleep_execute_event_callbacks(SLEEP_EVENT_HW_GOTO_SLEEP, (void *)0);
if (sleep_flags & (PMU_SLEEP_PD_CPU | PMU_SLEEP_PD_TOP)) {
result = esp_sleep_cpu_retention(pmu_sleep_start, s_config.wakeup_triggers, reject_triggers, config->power.hp_sys.dig_power.mem_dslp, deep_sleep);
} else
#endif
{
#if !CONFIG_FREERTOS_UNICORE && ESP_SLEEP_POWER_DOWN_CPU && SOC_PM_CPU_RETENTION_BY_SW
// Skip smp retention if CPU power domain power-down is not allowed
esp_sleep_cpu_skip_retention();
#endif
result = call_rtc_sleep_start(reject_triggers, config->power.hp_sys.dig_power.mem_dslp, deep_sleep);
}
esp_sleep_execute_event_callbacks(SLEEP_EVENT_HW_EXIT_SLEEP, (void *)0);
#else
result = call_rtc_sleep_start(reject_triggers, config->lslp_mem_inf_fpu, deep_sleep);
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
if (sleep_flags & PMU_SLEEP_PD_TOP) {
esp_sleep_mmu_retention(false);
}
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
/* Unhold the SPI CS pin */
if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) {
#if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359
gpio_ll_hold_dis(&GPIO, MSPI_IOMUX_PIN_NUM_CS0);
#endif
#endif
#if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
gpio_ll_hold_dis(&GPIO, MSPI_IOMUX_PIN_NUM_CS1);
#endif
}
#endif
/* Cache Resume 1: Resume cache for continue running*/
resume_cache();
resume_timers(sleep_flags);
}
return result;
}
static esp_err_t SLEEP_FN_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t clk_flags, esp_sleep_mode_t mode, bool allow_sleep_rejection)
{
// Stop UART output so that output is not lost due to APB frequency change.
// For light sleep, suspend UART output — it will resume after wakeup.
@@ -980,123 +1118,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t clk_fl
esp_sleep_cpu_skip_retention();
#endif
} else {
#if CONFIG_ESP_SLEEP_DEBUG
if (s_sleep_ctx != NULL) {
s_sleep_ctx->wakeup_triggers = s_config.wakeup_triggers;
}
#endif
if (deep_sleep) {
#if SOC_GPIO_SUPPORT_HOLD_IO_IN_DSLP && !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP
esp_sleep_isolate_digital_gpio();
#endif
#if ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB && SOC_DEEP_SLEEP_SUPPORTED
#if SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
esp_set_deep_sleep_wake_stub_default_entry();
#elif !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP && SOC_RTC_FAST_MEM_SUPPORTED
/* If not possible stack is in RTC FAST memory, use the ROM function to calculate the CRC and save ~140 bytes IRAM */
set_rtc_memory_crc();
#endif // SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
#endif
#if SOC_DCDC_SUPPORTED
uint64_t ldo_increased_us = rtc_time_slowclk_to_us(rtc_time_get() - s_config.rtc_ticks_at_ldo_prepare, s_config.rtc_clk_cal_period);
if (ldo_increased_us < LDO_POWER_TAKEOVER_PREPARATION_TIME_US) {
esp_rom_delay_us(LDO_POWER_TAKEOVER_PREPARATION_TIME_US - ldo_increased_us);
}
pmu_sleep_shutdown_dcdc();
#endif
// Enter Deep Sleep
#if!ESP_ROM_SUPPORT_DEEP_SLEEP_WAKEUP_STUB || SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY || !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP
#if SOC_PMU_SUPPORTED
result = call_rtc_sleep_start(reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep);
#else
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep);
#endif
#else
/* Otherwise, need to call the dedicated soc function for this */
result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers);
#endif
} else {
suspend_timers(sleep_flags);
/* Cache Suspend 1: will wait cache idle in cache suspend */
suspend_cache();
/* On esp32c6, only the lp_aon pad hold function can only hold the GPIO state in the active mode.
In order to avoid the leakage of the SPI cs pin, hold it here */
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) {
#if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
/* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */
#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359
gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS0);
#endif
#endif
#if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
/* Cache suspend also means SPI bus IDLE, then we can hold SPI CS pin safely */
gpio_ll_hold_en(&GPIO, MSPI_IOMUX_PIN_NUM_CS1);
#endif
}
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
if (sleep_flags & PMU_SLEEP_PD_TOP) {
esp_sleep_mmu_retention(true);
}
#endif
#if SOC_DCDC_SUPPORTED && !CONFIG_ESP_SLEEP_KEEP_DCDC_ALWAYS_ON
uint64_t ldo_increased_us = rtc_time_slowclk_to_us(rtc_time_get() - s_config.rtc_ticks_at_ldo_prepare, s_config.rtc_clk_cal_period);
if (ldo_increased_us < LDO_POWER_TAKEOVER_PREPARATION_TIME_US) {
esp_rom_delay_us(LDO_POWER_TAKEOVER_PREPARATION_TIME_US - ldo_increased_us);
}
pmu_sleep_shutdown_dcdc();
#endif
#if SOC_PMU_SUPPORTED
#if SOC_PM_CPU_RETENTION_BY_SW && ESP_SLEEP_POWER_DOWN_CPU
esp_sleep_execute_event_callbacks(SLEEP_EVENT_HW_GOTO_SLEEP, (void *)0);
if (sleep_flags & (PMU_SLEEP_PD_CPU | PMU_SLEEP_PD_TOP)) {
result = esp_sleep_cpu_retention(pmu_sleep_start, s_config.wakeup_triggers, reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep);
} else
#endif
{
#if !CONFIG_FREERTOS_UNICORE && ESP_SLEEP_POWER_DOWN_CPU && SOC_PM_CPU_RETENTION_BY_SW
// Skip smp retention if CPU power domain power-down is not allowed
esp_sleep_cpu_skip_retention();
#endif
result = call_rtc_sleep_start(reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep);
}
esp_sleep_execute_event_callbacks(SLEEP_EVENT_HW_EXIT_SLEEP, (void *)0);
#else
result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep);
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD
if (sleep_flags & PMU_SLEEP_PD_TOP) {
esp_sleep_mmu_retention(false);
}
#endif
#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
/* Unhold the SPI CS pin */
if(!(sleep_flags & RTC_SLEEP_PD_VDDSDIO) && (sleep_flags & PMU_SLEEP_PD_TOP)) {
#if CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND
#if !CONFIG_IDF_TARGET_ESP32H2 // ESP32H2 TODO IDF-7359
gpio_ll_hold_dis(&GPIO, MSPI_IOMUX_PIN_NUM_CS0);
#endif
#endif
#if CONFIG_ESP_SLEEP_PSRAM_LEAKAGE_WORKAROUND && CONFIG_SPIRAM
gpio_ll_hold_dis(&GPIO, MSPI_IOMUX_PIN_NUM_CS1);
#endif
}
#endif
/* Cache Resume 1: Resume cache for continue running*/
resume_cache();
resume_timers(sleep_flags);
}
result = esp_sleep_start_safe(sleep_flags, reject_triggers, deep_sleep, &config);
}
#if CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION
if (sleep_flags & RTC_SLEEP_PD_VDDSDIO) {
@@ -1119,6 +1141,21 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t clk_fl
if (!deep_sleep) {
if (result == ESP_OK) {
#if !CONFIG_PM_SLP_IRAM_OPT && !CONFIG_IDF_TARGET_ESP32
#if CONFIG_SPIRAM
# if CONFIG_IDF_TARGET_ESP32P4
cache_ll_writeback_all(CACHE_LL_LEVEL_ALL, CACHE_TYPE_DATA, CACHE_LL_ID_ALL);
# else
Cache_WriteBack_All();
# endif
#endif
/* When the IRAM optimization for the sleep flow is disabled, all
* cache contents are forcibly invalidated before exiting the sleep
* flow. This ensures that the code execution time of sleep exit
* flow remains consistent, allowing the use of ccount to
* dynamically calculate the sleep adjustment time. */
cache_ll_invalidate_all(CACHE_LL_LEVEL_ALL, CACHE_TYPE_ALL, CACHE_LL_ID_ALL);
#endif
s_config.ccount_ticks_record = esp_cpu_get_cycle_count();
#if SOC_PM_RETENTION_SW_TRIGGER_REGDMA
if (sleep_flags & PMU_SLEEP_PD_TOP) {
@@ -1254,9 +1291,9 @@ esp_err_t IRAM_ATTR esp_deep_sleep_try_to_start(void)
* Placed into IRAM as flash may need some time to be powered on.
*/
static esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, uint32_t clk_flags,
uint32_t flash_enable_time_us) IRAM_ATTR __attribute__((noinline));
uint32_t flash_enable_time_us) __attribute__((noinline));
static esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, uint32_t clk_flags,
static SLEEP_FN_ATTR esp_err_t esp_light_sleep_inner(uint32_t sleep_flags, uint32_t clk_flags,
uint32_t flash_enable_time_us)
{
#if SOC_CONFIGURABLE_VDDSDIO_SUPPORTED
@@ -1687,7 +1724,7 @@ esp_err_t esp_sleep_enable_vad_wakeup(void)
}
#endif
static esp_err_t timer_wakeup_prepare(int64_t sleep_duration)
static SLEEP_FN_ATTR esp_err_t timer_wakeup_prepare(int64_t sleep_duration)
{
if (sleep_duration < 0) {
sleep_duration = 0;
@@ -2325,7 +2362,7 @@ FORCE_INLINE_ATTR bool top_domain_pd_allowed(void) {
}
#endif
static uint32_t get_power_down_flags(void)
static SLEEP_FN_ATTR uint32_t get_power_down_flags(void)
{
// Where needed, convert AUTO options to ON. Later interpret AUTO as OFF.
@@ -2502,7 +2539,7 @@ static uint32_t get_power_down_flags(void)
return pd_flags;
}
static uint32_t get_sleep_flags(uint32_t sleep_flags, bool deepsleep)
static SLEEP_FN_ATTR uint32_t get_sleep_flags(uint32_t sleep_flags, bool deepsleep)
{
// Override user-configured FOSC power modes.
if (s_sleep_sub_mode_ref_cnt[ESP_SLEEP_RTC_USE_RC_FAST_MODE]) {
@@ -2554,7 +2591,7 @@ static uint32_t get_sleep_flags(uint32_t sleep_flags, bool deepsleep)
return sleep_flags;
}
static uint32_t get_sleep_clock_icg_flags(void)
static SLEEP_FN_ATTR uint32_t get_sleep_clock_icg_flags(void)
{
uint32_t clk_flags = 0;

View File

@@ -10,6 +10,7 @@ menu "ESP-Driver:LCD Controller Configurations"
config LCD_RGB_ISR_IRAM_SAFE
bool "RGB LCD ISR IRAM-Safe"
select GDMA_ISR_HANDLER_IN_IRAM # bounce buffer mode relies on GDMA EOF interrupt
select ESP_PERIPH_CTRL_FUNC_IN_IRAM
default n
help
Ensure the LCD interrupt is IRAM-Safe by allowing the interrupt handler to be

View File

@@ -1,4 +1,14 @@
menu "Power Management"
config PM_SLEEP_FUNC_IN_IRAM
bool "Place Power Management module functions in IRAM" if IDF_TARGET_ESP32C2
default y
select PM_SLP_IRAM_OPT if SOC_LIGHT_SLEEP_SUPPORTED
select PM_RTOS_IDLE_OPT if FREERTOS_USE_TICKLESS_IDLE
select ESP_PERIPH_CTRL_FUNC_IN_IRAM
select ESP_REGI2C_CTRL_FUNC_IN_IRAM
config PM_ENABLE
bool "Support for power management"
# SMP FreeRTOS currently does not support power management IDF-4997
@@ -49,7 +59,8 @@ menu "Power Management"
config PM_SLP_IRAM_OPT
bool "Put lightsleep related codes in internal RAM"
depends on SOC_LIGHT_SLEEP_SUPPORTED && ESP_TIMER_IN_IRAM
depends on SOC_LIGHT_SLEEP_SUPPORTED
select ESP_TIMER_IN_IRAM
help
If enabled, about 2.1KB of lightsleep related source code would be in IRAM and chip would sleep
longer for 310us at 160MHz CPU frequency most each time.

View File

@@ -7,44 +7,45 @@ entries:
if PM_SLP_IRAM_OPT = y:
pm_impl:esp_pm_impl_get_cpu_freq (noflash)
if FREERTOS_USE_TICKLESS_IDLE = y:
pm_impl:vApplicationSleep (noflash)
[mapping:esp_hw_support_pm]
archive: libesp_hw_support.a
entries:
if PM_SLP_IRAM_OPT = y:
sleep_modes:esp_light_sleep_start (noflash)
sleep_modes:esp_sleep_enable_timer_wakeup (noflash)
sleep_modes:timer_wakeup_prepare (noflash)
sleep_modes:get_power_down_flags (noflash)
sleep_modes:get_sleep_flags (noflash)
sleep_modes:get_sleep_clock_icg_flags (noflash)
if SOC_LIGHT_SLEEP_SUPPORTED = y:
sleep_modes:esp_light_sleep_start (noflash)
sleep_modes:esp_sleep_enable_timer_wakeup (noflash)
sleep_modem:modem_domain_pd_allowed (noflash)
sleep_modem:periph_inform_out_light_sleep_overhead (noflash)
sleep_modem:sleep_modem_reject_triggers (noflash)
if ESP_PHY_MAC_BB_PD = y:
sleep_modem:mac_bb_power_down_cb_execute (noflash)
sleep_modem:mac_bb_power_up_cb_execute (noflash)
if GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL = y:
sleep_gpio:gpio_sleep_mode_config_apply (noflash)
if SOC_PM_SUPPORT_TOP_PD = y:
sleep_clock:clock_domain_pd_allowed (noflash)
sleep_system_peripheral:peripheral_domain_pd_allowed (noflash)
if SOC_PM_CPU_RETENTION_BY_RTCCNTL = y && (PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP = y || SOC_PM_SUPPORT_TAGMEM_PD = y):
sleep_cpu:sleep_enable_cpu_retention (noflash)
if PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP = y || (SOC_CPU_IN_TOP_DOMAIN = y && PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP = y):
sleep_cpu:cpu_domain_pd_allowed (noflash)
if SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD = y && PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP = y:
sleep_mmu:mmu_domain_pd_allowed (noflash)
esp_clk:esp_clk_slowclk_cal_set (noflash)
esp_clk:esp_clk_slowclk_cal_get (noflash)
esp_clk:esp_rtc_get_time_us (noflash)
esp_clk:esp_clk_private_lock (noflash)
esp_clk:esp_clk_private_unlock (noflash)
if SOC_RTC_MEM_SUPPORTED = y:
esp_clk:calc_checksum (noflash)
if SOC_SYSTIMER_SUPPORTED = y:
systimer (noflash)
if GPIO_ESP32_SUPPORT_SWITCH_SLP_PULL = y:
sleep_gpio:gpio_sleep_mode_config_apply (noflash)
if SOC_PM_CPU_RETENTION_BY_RTCCNTL = y && (PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP = y || SOC_PM_SUPPORT_TAGMEM_PD = y):
sleep_cpu:sleep_enable_cpu_retention (noflash)
if PM_POWER_DOWN_CPU_IN_LIGHT_SLEEP = y || (SOC_CPU_IN_TOP_DOMAIN = y && PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP = y):
sleep_cpu:cpu_domain_pd_allowed (noflash)
if SOC_PM_SUPPORT_TOP_PD = y:
sleep_clock:clock_domain_pd_allowed (noflash)
sleep_system_peripheral:peripheral_domain_pd_allowed (noflash)
if SOC_PM_MMU_TABLE_RETENTION_WHEN_TOP_PD = y && PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP = y:
sleep_mmu:mmu_domain_pd_allowed (noflash)
sleep_modem:modem_domain_pd_allowed (noflash)
sleep_modem:periph_inform_out_light_sleep_overhead (noflash)
sar_periph_ctrl:sar_periph_ctrl_power_disable (noflash)
if IDF_TARGET_ESP32H21 != y && IDF_TARGET_ESP32H4 != y:
sar_periph_ctrl:sar_periph_ctrl_power_disable (noflash)
if SOC_TEMP_SENSOR_SUPPORTED = y:
sar_periph_ctrl_common:temperature_sensor_power_acquire (noflash)
sar_periph_ctrl_common:temperature_sensor_power_release (noflash)
sar_periph_ctrl_common:temperature_sensor_get_raw_value (noflash)
sar_periph_ctrl_common:temp_sensor_get_raw_value (noflash)
regi2c_ctrl:regi2c_saradc_enable (noflash)
regi2c_ctrl:regi2c_saradc_disable (noflash)
@@ -57,17 +58,6 @@ archive: libesp_system.a
entries:
if PM_RTOS_IDLE_OPT = y:
freertos_hooks:esp_vApplicationIdleHook (noflash)
if PM_SLP_IRAM_OPT = y:
task_wdt:idle_hook_cb (noflash)
task_wdt:task_wdt_timer_feed (noflash)
task_wdt:find_entry_and_check_all_reset (noflash)
task_wdt:find_entry_from_task_handle_and_check_all_reset (noflash)
task_wdt:esp_task_wdt_reset (noflash)
task_wdt:esp_task_wdt_reset_user (noflash)
if ESP_TASK_WDT_USE_ESP_TIMER = y:
task_wdt_impl_esp_timer:esp_task_wdt_impl_timer_feed (noflash)
else:
task_wdt_impl_timergroup:esp_task_wdt_impl_timer_feed (noflash)
[mapping:esp_timer_pm]
archive: libesp_timer.a

View File

@@ -803,7 +803,7 @@ static inline void IRAM_ATTR other_core_should_skip_light_sleep(int core_id)
#endif
}
void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
void vApplicationSleep( TickType_t xExpectedIdleTime )
{
portENTER_CRITICAL(&s_switch_lock);
int core_id = xPortGetCoreID();

View File

@@ -36,6 +36,12 @@
#define BACKTRACE_MSG "backtrace"
#endif
#if CONFIG_PM_RTOS_IDLE_OPT
# define TASK_WDT_FN_ATTR IRAM_ATTR
#else
# define TASK_WDT_FN_ATTR
#endif
/* We will use this function in order to simulate an `abort()` occurring in
* a different context than the one it's called from. */
extern void xt_unhandled_exception(void *frame);
@@ -96,7 +102,7 @@ static char core_user_names[CONFIG_FREERTOS_NUMBER_OF_CORES][CORE_USER_NAME_LEN]
* @brief Reset the timer and reset flags of each entry
* When entering this function, the spinlock has already been taken, no need to take it back.
*/
static void task_wdt_timer_feed(void)
static TASK_WDT_FN_ATTR void task_wdt_timer_feed(void)
{
esp_task_wdt_impl_timer_feed(p_twdt_obj->impl_ctx);
@@ -114,7 +120,7 @@ static void task_wdt_timer_feed(void)
* @param[out] all_reset Whether all entries have been reset
* @return Whether the user entry exists
*/
static bool find_entry_and_check_all_reset(twdt_entry_t *user_entry, bool *all_reset)
static TASK_WDT_FN_ATTR bool find_entry_and_check_all_reset(twdt_entry_t *user_entry, bool *all_reset)
{
bool found_user_entry = false;
bool found_non_reset = false;
@@ -139,7 +145,7 @@ static bool find_entry_and_check_all_reset(twdt_entry_t *user_entry, bool *all_r
* @param[out] all_reset Whether all entries have been reset
* @return Task entry, or NULL if not found
*/
static twdt_entry_t *find_entry_from_task_handle_and_check_all_reset(TaskHandle_t handle, bool *all_reset)
static TASK_WDT_FN_ATTR twdt_entry_t *find_entry_from_task_handle_and_check_all_reset(TaskHandle_t handle, bool *all_reset)
{
twdt_entry_t *target = NULL;
bool found_non_reset = false;
@@ -448,7 +454,7 @@ static void task_wdt_timeout_handling(int cores_fail, bool panic)
*
* @return Whether the idle tasks should continue idling
*/
static bool idle_hook_cb(void)
static TASK_WDT_FN_ATTR bool idle_hook_cb(void)
{
#if CONFIG_FREERTOS_SMP
esp_task_wdt_reset_user(core_user_handles[xPortGetCoreID()]);
@@ -687,7 +693,7 @@ esp_err_t esp_task_wdt_add_user(const char *user_name, esp_task_wdt_user_handle_
return ret;
}
esp_err_t esp_task_wdt_reset(void)
esp_err_t TASK_WDT_FN_ATTR esp_task_wdt_reset(void)
{
ESP_RETURN_ON_FALSE(p_twdt_obj != NULL, ESP_ERR_INVALID_STATE, TAG, "TWDT was never initialized");
esp_err_t ret;
@@ -711,7 +717,7 @@ err:
return ret;
}
esp_err_t esp_task_wdt_reset_user(esp_task_wdt_user_handle_t user_handle)
esp_err_t TASK_WDT_FN_ATTR esp_task_wdt_reset_user(esp_task_wdt_user_handle_t user_handle)
{
ESP_RETURN_ON_FALSE(user_handle != NULL, ESP_ERR_INVALID_ARG, TAG, "Invalid arguments");
ESP_RETURN_ON_FALSE(p_twdt_obj != NULL, ESP_ERR_INVALID_STATE, TAG, "TWDT was never initialized");

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -17,6 +17,12 @@
#include "esp_timer.h"
#include "esp_private/esp_task_wdt_impl.h"
#if CONFIG_PM_SLP_IRAM_OPT
# define TASK_WDT_FN_ATTR IRAM_ATTR
#else
# define TASK_WDT_FN_ATTR
#endif
/**
* Context for the software implementation of the Task WatchDog Timer.
* This will be passed as a parameter to public functions below. */
@@ -50,7 +56,7 @@ esp_err_t esp_task_wdt_impl_timer_allocate(const esp_task_wdt_config_t *config,
esp_err_t ret = esp_timer_create(&timer_args, &ctx->sw_timer);
ESP_GOTO_ON_FALSE((ret == ESP_OK), ret, reterr, TAG, "could not start periodic timer");
/* Configure it as a periodic timer, so that we check the Tasks everytime it is triggered.
/* Configure it as a periodic timer, so that we check the Tasks every time it is triggered.
* No need to start the timer here, it will be started later with `esp_task_wdt_impl_timer_restart` */
ctx->period_ms = config->timeout_ms;
@@ -89,7 +95,7 @@ void esp_task_wdt_impl_timer_free(twdt_ctx_t obj)
}
}
esp_err_t esp_task_wdt_impl_timer_feed(twdt_ctx_t obj)
esp_err_t TASK_WDT_FN_ATTR esp_task_wdt_impl_timer_feed(twdt_ctx_t obj)
{
esp_err_t ret = ESP_OK;
const twdt_ctx_soft_t* ctx = (twdt_ctx_soft_t*) obj;

View File

@@ -32,6 +32,12 @@
#define TWDT_TIMER_GROUP 0
#define TWDT_INTR_SOURCE SYS_TG0_WDT_INTR_SOURCE
#if CONFIG_PM_SLP_IRAM_OPT
# define TASK_WDT_FN_ATTR IRAM_ATTR
#else
# define TASK_WDT_FN_ATTR
#endif
/**
* Context for the software implementation of the Task WatchDog Timer.
* This will be passed as a parameter to public functions below. */
@@ -177,7 +183,7 @@ void esp_task_wdt_impl_timer_free(twdt_ctx_t obj)
}
}
esp_err_t esp_task_wdt_impl_timer_feed(twdt_ctx_t obj)
esp_err_t TASK_WDT_FN_ATTR esp_task_wdt_impl_timer_feed(twdt_ctx_t obj)
{
esp_err_t ret = ESP_OK;
twdt_ctx_hard_t* ctx = (twdt_ctx_hard_t*) obj;

View File

@@ -343,7 +343,8 @@ menu "Wi-Fi"
config ESP_WIFI_SLP_IRAM_OPT
bool "WiFi SLP IRAM speed optimization"
select PM_SLP_DEFAULT_PARAMS_OPT
select PERIPH_CTRL_FUNC_IN_IRAM
select PM_SLEEP_FUNC_IN_IRAM
select ESP_PERIPH_CTRL_FUNC_IN_IRAM
default y if SOC_WIFI_HE_SUPPORT
help
Select this option to place called Wi-Fi library TBTT process and receive beacon functions in IRAM.

View File

@@ -285,6 +285,28 @@ This section introduces the recommended configuration and configuration steps fo
Due to the shared power pins between flash and PSRAM, cutting power to PSRAM would result in data loss. Therefore, to ensure light sleep does not disrupt program execution, enabling this option requires that the system does not utilize PSRAM.
.. only:: esp32c2
- To reduce the on-chip RAM usage of the Power Management module (:ref:CONFIG_PM_SLEEP_FUNC_IN_IRAM), the options in the table below are used to control whether individual components of the Power Management module enable or disable on-chip RAM optimization when :ref:CONFIG_PM_SLEEP_FUNC_IN_IRAM is disabled.
.. list-table::
:header-rows: 1
:widths: 30 60
* - Configuration Name
- Configuration Description
* - :ref:`CONFIG_PM_SLP_IRAM_OPT`
- When this option is enabled, the software flow for entering and exiting light/deep sleep is linked to on-chip RAM, which shortens the sleep transition time but consumes more on-chip RAM resources. When this option is disabled, the light/deep sleep software flow is compiled into flash memory instead, resulting in longer sleep transition time but saving on-chip RAM resources.
* - :ref:`CONFIG_PM_RTOS_IDLE_OPT`
- In auto light sleep mode, when this option is enabled, the FreeRTOS system tick, IDLE task hook functions, and the FreeRTOS tickless idle software context are linked to on-chip RAM. Otherwise, they will be linked to flash memory.
* - :ref:`CONFIG_ESP_PERIPH_CTRL_FUNC_IN_IRAM`
- When this option is enabled, the software implementation related to peripheral clock and reset control will be linked to on-chip RAM. Otherwise, it will be linked to flash memory.
* - :ref:`CONFIG_ESP_REGI2C_CTRL_FUNC_IN_IRAM`
- When this option is enabled, the software implementation related to Analog I2C read/write access will be linked to on-chip RAM. Otherwise, it will be linked to flash memory.
Configuration Steps:

View File

@@ -285,6 +285,28 @@ Light-sleep 模式配置
由于 flash 和 PSRAM 共用供电管脚PSRAM 关闭供电将会导致数据丢失,因此,为保证 light sleep 不破坏程序运行状态,启用该选项的前提是系统没有使用 PSRAM。
.. only:: esp32c2
- 减少 Power Managemet 模块片内 RAM 内存资源使用量 (:ref:`CONFIG_PM_SLEEP_FUNC_IN_IRAM`),当 :ref:`CONFIG_PM_SLEEP_FUNC_IN_IRAM` 禁止时,下面表格中选项分别用于控制 Power Management 模块各部分组件启用或禁止片内 RAM 优化
.. list-table::
:header-rows: 1
:widths: 60 30
* - 配置项
- 描述
* - :ref:`CONFIG_PM_SLP_IRAM_OPT`
- 使能该选项后执行 light / deep sleep 软件流程上下文被链接到片内 RAM 空间,这意味着系统进出睡眠时间变短,消耗更多的片内 RAM 资源禁止该选项light / deep sleep 软件流程上下文将被编译到 Flash 空间,这意味着系统进出睡眠时间变长,但会节约片内 RAM 资源。
* - :ref:`CONFIG_PM_RTOS_IDLE_OPT`
- auto light sleep 模式下使能该选项后FreeRTOS 系统滴答IDLE 任务回调函数及 FreeRTOS Tickless idle 软件上下文被链接到片内 RAM 空间,反之将被链接到 Flash 空间。
* - :ref:`CONFIG_ESP_PERIPH_CTRL_FUNC_IN_IRAM`
- 使能该选项后外设时钟及复位控制相关的软件实现将被链接到片内 RAM 空间,反之将被链接到 Flash 空间。
* - :ref:`CONFIG_ESP_REGI2C_CTRL_FUNC_IN_IRAM`
- 使能该选项后 Analog I2C 读写访问相关的软件实现将被链接到片内 RAM 空间,反之被链接到 Flash 空间。
配置方法:

View File

@@ -19,3 +19,9 @@ CONFIG_SPI_FLASH_PLACE_FUNCTIONS_IN_IRAM=n
CONFIG_ESP_INTR_IN_IRAM=n
CONFIG_LOG_IN_IRAM=n
CONFIG_ESP_ROM_PRINT_IN_IRAM=n
# Low power related options
CONFIG_PM_SLEEP_FUNC_IN_IRAM=n
CONFIG_PM_SLP_IRAM_OPT=n
CONFIG_PM_RTOS_IDLE_OPT=n
CONFIG_ESP_PERIPH_CTRL_FUNC_IN_IRAM=n
CONFIG_ESP_REGI2C_CTRL_FUNC_IN_IRAM=n