From 756b5f628d4296a26741703d76d0bb71e655920b Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 8 May 2023 17:38:41 +0800 Subject: [PATCH 1/4] bugfix: fix pmp retention and add pma retention --- components/esp_hw_support/sleep_cpu.c | 87 +++++++++++++++++-- components/riscv/include/riscv/csr.h | 3 + .../riscv/include/riscv/rvsleep-frames.h | 43 ++++++++- 3 files changed, 121 insertions(+), 12 deletions(-) diff --git a/components/esp_hw_support/sleep_cpu.c b/components/esp_hw_support/sleep_cpu.c index 948d5a99d2..41ed0b9b94 100644 --- a/components/esp_hw_support/sleep_cpu.c +++ b/components/esp_hw_support/sleep_cpu.c @@ -449,10 +449,7 @@ static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(voi frame->tdata1 = RV_READ_CSR(tdata1); frame->tdata2 = RV_READ_CSR(tdata2); frame->tcontrol = RV_READ_CSR(tcontrol); - frame->pmpcfg0 = RV_READ_CSR(pmpcfg0); - frame->pmpcfg1 = RV_READ_CSR(pmpcfg1); - frame->pmpcfg2 = RV_READ_CSR(pmpcfg2); - frame->pmpcfg3 = RV_READ_CSR(pmpcfg3); + frame->pmpaddr0 = RV_READ_CSR(pmpaddr0); frame->pmpaddr1 = RV_READ_CSR(pmpaddr1); frame->pmpaddr2 = RV_READ_CSR(pmpaddr2); @@ -469,6 +466,45 @@ static IRAM_ATTR RvCoreNonCriticalSleepFrame * rv_core_noncritical_regs_save(voi frame->pmpaddr13 = RV_READ_CSR(pmpaddr13); frame->pmpaddr14 = RV_READ_CSR(pmpaddr14); frame->pmpaddr15 = RV_READ_CSR(pmpaddr15); + frame->pmpcfg0 = RV_READ_CSR(pmpcfg0); + frame->pmpcfg1 = RV_READ_CSR(pmpcfg1); + frame->pmpcfg2 = RV_READ_CSR(pmpcfg2); + frame->pmpcfg3 = RV_READ_CSR(pmpcfg3); + +#if SOC_CPU_HAS_PMA + frame->pmaaddr0 = RV_READ_CSR(CSR_PMAADDR(0)); + frame->pmaaddr1 = RV_READ_CSR(CSR_PMAADDR(1)); + frame->pmaaddr2 = RV_READ_CSR(CSR_PMAADDR(2)); + frame->pmaaddr3 = RV_READ_CSR(CSR_PMAADDR(3)); + frame->pmaaddr4 = RV_READ_CSR(CSR_PMAADDR(4)); + frame->pmaaddr5 = RV_READ_CSR(CSR_PMAADDR(5)); + frame->pmaaddr6 = RV_READ_CSR(CSR_PMAADDR(6)); + frame->pmaaddr7 = RV_READ_CSR(CSR_PMAADDR(7)); + frame->pmaaddr8 = RV_READ_CSR(CSR_PMAADDR(8)); + frame->pmaaddr9 = RV_READ_CSR(CSR_PMAADDR(9)); + frame->pmaaddr10 = RV_READ_CSR(CSR_PMAADDR(10)); + frame->pmaaddr11 = RV_READ_CSR(CSR_PMAADDR(11)); + frame->pmaaddr12 = RV_READ_CSR(CSR_PMAADDR(12)); + frame->pmaaddr13 = RV_READ_CSR(CSR_PMAADDR(13)); + frame->pmaaddr14 = RV_READ_CSR(CSR_PMAADDR(14)); + frame->pmaaddr15 = RV_READ_CSR(CSR_PMAADDR(15)); + frame->pmacfg0 = RV_READ_CSR(CSR_PMACFG(0)); + frame->pmacfg1 = RV_READ_CSR(CSR_PMACFG(1)); + frame->pmacfg2 = RV_READ_CSR(CSR_PMACFG(2)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(3)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(4)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(5)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(6)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(7)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(8)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(9)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(10)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(11)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(12)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(13)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(14)); + frame->pmacfg3 = RV_READ_CSR(CSR_PMACFG(15)); +#endif // SOC_CPU_HAS_PMA frame->utvec = RV_READ_CSR(utvec); frame->ustatus = RV_READ_CSR(ustatus); @@ -498,10 +534,6 @@ static IRAM_ATTR void rv_core_noncritical_regs_restore(RvCoreNonCriticalSleepFra RV_WRITE_CSR(tdata1, frame->tdata1); RV_WRITE_CSR(tdata2, frame->tdata2); RV_WRITE_CSR(tcontrol, frame->tcontrol); - RV_WRITE_CSR(pmpcfg0, frame->pmpcfg0); - RV_WRITE_CSR(pmpcfg1, frame->pmpcfg1); - RV_WRITE_CSR(pmpcfg2, frame->pmpcfg2); - RV_WRITE_CSR(pmpcfg3, frame->pmpcfg3); RV_WRITE_CSR(pmpaddr0, frame->pmpaddr0); RV_WRITE_CSR(pmpaddr1, frame->pmpaddr1); RV_WRITE_CSR(pmpaddr2, frame->pmpaddr2); @@ -518,6 +550,45 @@ static IRAM_ATTR void rv_core_noncritical_regs_restore(RvCoreNonCriticalSleepFra RV_WRITE_CSR(pmpaddr13,frame->pmpaddr13); RV_WRITE_CSR(pmpaddr14,frame->pmpaddr14); RV_WRITE_CSR(pmpaddr15,frame->pmpaddr15); + RV_WRITE_CSR(pmpcfg0, frame->pmpcfg0); + RV_WRITE_CSR(pmpcfg1, frame->pmpcfg1); + RV_WRITE_CSR(pmpcfg2, frame->pmpcfg2); + RV_WRITE_CSR(pmpcfg3, frame->pmpcfg3); + +#if SOC_CPU_HAS_PMA + RV_WRITE_CSR(CSR_PMAADDR(0), frame->pmaaddr0); + RV_WRITE_CSR(CSR_PMAADDR(1), frame->pmaaddr1); + RV_WRITE_CSR(CSR_PMAADDR(2), frame->pmaaddr2); + RV_WRITE_CSR(CSR_PMAADDR(3), frame->pmaaddr3); + RV_WRITE_CSR(CSR_PMAADDR(4), frame->pmaaddr4); + RV_WRITE_CSR(CSR_PMAADDR(5), frame->pmaaddr5); + RV_WRITE_CSR(CSR_PMAADDR(6), frame->pmaaddr6); + RV_WRITE_CSR(CSR_PMAADDR(7), frame->pmaaddr7); + RV_WRITE_CSR(CSR_PMAADDR(8), frame->pmaaddr8); + RV_WRITE_CSR(CSR_PMAADDR(9), frame->pmaaddr9); + RV_WRITE_CSR(CSR_PMAADDR(10),frame->pmaaddr10); + RV_WRITE_CSR(CSR_PMAADDR(11),frame->pmaaddr11); + RV_WRITE_CSR(CSR_PMAADDR(12),frame->pmaaddr12); + RV_WRITE_CSR(CSR_PMAADDR(13),frame->pmaaddr13); + RV_WRITE_CSR(CSR_PMAADDR(14),frame->pmaaddr14); + RV_WRITE_CSR(CSR_PMAADDR(15),frame->pmaaddr15); + RV_WRITE_CSR(CSR_PMACFG(0), frame->pmacfg0); + RV_WRITE_CSR(CSR_PMACFG(1), frame->pmacfg1); + RV_WRITE_CSR(CSR_PMACFG(2), frame->pmacfg2); + RV_WRITE_CSR(CSR_PMACFG(3), frame->pmacfg3); + RV_WRITE_CSR(CSR_PMACFG(4), frame->pmacfg4); + RV_WRITE_CSR(CSR_PMACFG(5), frame->pmacfg5); + RV_WRITE_CSR(CSR_PMACFG(6), frame->pmacfg6); + RV_WRITE_CSR(CSR_PMACFG(7), frame->pmacfg7); + RV_WRITE_CSR(CSR_PMACFG(8), frame->pmacfg8); + RV_WRITE_CSR(CSR_PMACFG(9), frame->pmacfg9); + RV_WRITE_CSR(CSR_PMACFG(10), frame->pmacfg10); + RV_WRITE_CSR(CSR_PMACFG(11), frame->pmacfg11); + RV_WRITE_CSR(CSR_PMACFG(12), frame->pmacfg12); + RV_WRITE_CSR(CSR_PMACFG(13), frame->pmacfg13); + RV_WRITE_CSR(CSR_PMACFG(14), frame->pmacfg14); + RV_WRITE_CSR(CSR_PMACFG(15), frame->pmacfg15); +#endif //SOC_CPU_HAS_PMA RV_WRITE_CSR(utvec, frame->utvec); RV_WRITE_CSR(ustatus, frame->ustatus); diff --git a/components/riscv/include/riscv/csr.h b/components/riscv/include/riscv/csr.h index 77f33fa194..ebbda1d2fe 100644 --- a/components/riscv/include/riscv/csr.h +++ b/components/riscv/include/riscv/csr.h @@ -49,6 +49,9 @@ extern "C" { #define CSR_PMACFG0 0xBC0 #define CSR_PMAADDR0 0xBD0 +#define CSR_PMACFG(i) (CSR_PMACFG0 + (i)) +#define CSR_PMAADDR(i) (CSR_PMAADDR0 + (i)) + #define PMA_EN BIT(0) #define PMA_R BIT(4) #define PMA_W BIT(3) diff --git a/components/riscv/include/riscv/rvsleep-frames.h b/components/riscv/include/riscv/rvsleep-frames.h index 929d581c62..b4d00f9440 100644 --- a/components/riscv/include/riscv/rvsleep-frames.h +++ b/components/riscv/include/riscv/rvsleep-frames.h @@ -117,10 +117,6 @@ STRUCT_BEGIN STRUCT_FIELD (long, 4, RV_SLP_CTX_TDATA1, tdata1) STRUCT_FIELD (long, 4, RV_SLP_CTX_TDATA2, tdata2) STRUCT_FIELD (long, 4, RV_SLP_CTX_TCONTROL, tcontrol) - STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG0, pmpcfg0) - STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG1, pmpcfg1) - STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG2, pmpcfg2) - STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG3, pmpcfg3) STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR0, pmpaddr0) STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR1, pmpaddr1) STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR2, pmpaddr2) @@ -137,6 +133,45 @@ STRUCT_BEGIN STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR13, pmpaddr13) STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR14, pmpaddr14) STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPADDR15, pmpaddr15) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG0, pmpcfg0) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG1, pmpcfg1) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG2, pmpcfg2) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMPCFG3, pmpcfg3) + +#if SOC_CPU_HAS_PMA + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR0, pmaaddr0) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR1, pmaaddr1) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR2, pmaaddr2) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR3, pmaaddr3) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR4, pmaaddr4) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR5, pmaaddr5) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR6, pmaaddr6) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR7, pmaaddr7) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR8, pmaaddr8) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR9, pmaaddr9) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR10, pmaaddr10) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR11, pmaaddr11) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR12, pmaaddr12) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR13, pmaaddr13) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR14, pmaaddr14) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMAADDR15, pmaaddr15) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG0, pmacfg0) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG1, pmacfg1) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG2, pmacfg2) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG3, pmacfg3) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG4, pmacfg4) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG5, pmacfg5) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG6, pmacfg6) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG7, pmacfg7) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG8, pmacfg8) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG9, pmacfg9) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG10, pmacfg10) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG11, pmacfg11) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG12, pmacfg12) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG13, pmacfg13) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG14, pmacfg14) + STRUCT_FIELD (long, 4, RV_SLP_CTX_PMACFG15, pmacfg15) +#endif // SOC_CPU_HAS_PMA STRUCT_FIELD (long, 4, RV_SLP_CTX_UTVEC, utvec) STRUCT_FIELD (long, 4, RV_SLP_CTX_USTATUS, ustatus) From 5c740933005a1d8e865ba49abe978bd19e37c566 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Tue, 9 May 2023 14:01:29 +0800 Subject: [PATCH 2/4] bugfix: treat too short sleep duration as sleep reject by software --- .../include/esp_private/esp_pmu.h | 6 ++ .../esp_hw_support/port/esp32c6/pmu_sleep.c | 8 +- components/esp_hw_support/sleep_cpu.c | 6 +- components/esp_hw_support/sleep_modes.c | 96 +++++++++++-------- components/esp_pm/pm_impl.c | 18 +++- 5 files changed, 91 insertions(+), 43 deletions(-) diff --git a/components/esp_hw_support/include/esp_private/esp_pmu.h b/components/esp_hw_support/include/esp_private/esp_pmu.h index fe3021a830..03a85ea5a5 100644 --- a/components/esp_hw_support/include/esp_private/esp_pmu.h +++ b/components/esp_hw_support/include/esp_private/esp_pmu.h @@ -234,6 +234,12 @@ void pmu_sleep_init(const pmu_sleep_config_t *config, bool dslp); */ uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp_mem_inf_fpu, bool dslp); +/** + * @brief Finish sleep process settings and get sleep reject status + * @return return sleep reject status + */ +bool pmu_sleep_finish(void); + /** * @brief Initialize PMU related power/clock/digital parameters and functions */ diff --git a/components/esp_hw_support/port/esp32c6/pmu_sleep.c b/components/esp_hw_support/port/esp32c6/pmu_sleep.c index f990464c80..a2f28c4c52 100644 --- a/components/esp_hw_support/port/esp32c6/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c6/pmu_sleep.c @@ -278,10 +278,16 @@ uint32_t pmu_sleep_start(uint32_t wakeup_opt, uint32_t reject_opt, uint32_t lslp /* Start entry into sleep mode */ pmu_ll_hp_set_sleep_enable(PMU_instance()->hal->dev); + /* In pd_cpu lightsleep and deepsleep mode, we never get here */ while (!pmu_ll_hp_is_sleep_wakeup(PMU_instance()->hal->dev) && !pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev)) { ; } - return ESP_OK; + return pmu_sleep_finish(); +} + +bool pmu_sleep_finish(void) +{ + return pmu_ll_hp_is_sleep_reject(PMU_instance()->hal->dev); } diff --git a/components/esp_hw_support/sleep_cpu.c b/components/esp_hw_support/sleep_cpu.c index 41ed0b9b94..1bc2037d6d 100644 --- a/components/esp_hw_support/sleep_cpu.c +++ b/components/esp_hw_support/sleep_cpu.c @@ -22,7 +22,9 @@ #include "esp_private/sleep_cpu.h" #include "sdkconfig.h" -#if !SOC_PMU_SUPPORTED +#if SOC_PMU_SUPPORTED +#include "esp_private/esp_pmu.h" +#else #include "hal/rtc_hal.h" #endif @@ -683,7 +685,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep, } #endif - return ESP_OK; + return pmu_sleep_finish(); } esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool), diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 2e784e7ca6..4a71b4135d 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -124,6 +124,9 @@ #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9) #endif +// Actually costs 80us, using the fastest slow clock 150K calculation takes about 16 ticks +#define SLEEP_TIMER_ALARM_TO_SLEEP_TICKS (16) + #define LIGHT_SLEEP_TIME_OVERHEAD_US DEFAULT_HARDWARE_OUT_OVERHEAD_US #ifdef CONFIG_ESP_SYSTEM_RTC_EXT_XTAL #define DEEP_SLEEP_TIME_OVERHEAD_US (650 + 100 * 240 / CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ) @@ -224,7 +227,7 @@ static void ext0_wakeup_prepare(void); #if SOC_PM_SUPPORT_EXT1_WAKEUP static void ext1_wakeup_prepare(void); #endif -static void timer_wakeup_prepare(void); +static esp_err_t timer_wakeup_prepare(void); #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 static void touch_wakeup_prepare(void); #endif @@ -476,6 +479,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t mo // For light sleep, suspend UART output — it will resume after wakeup. // For deep sleep, wait for the contents of UART FIFO to be sent. bool deep_sleep = (mode == ESP_SLEEP_MODE_DEEP_SLEEP); + bool should_skip_sleep = false; if (deep_sleep) { flush_uarts(); @@ -585,6 +589,7 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t mo } // Enter sleep + esp_err_t result; #if SOC_PMU_SUPPORTED pmu_sleep_config_t config; pmu_sleep_init(pmu_sleep_config_default(&config, pd_flags, s_config.sleep_time_adjustment, @@ -603,7 +608,10 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t mo // Configure timer wakeup if (s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) { - timer_wakeup_prepare(); + if (timer_wakeup_prepare() != ESP_OK) { + result = ESP_ERR_SLEEP_REJECT; + should_skip_sleep = true; + } } #if CONFIG_ESP_SLEEP_SYSTIMER_STALL_WORKAROUND @@ -612,66 +620,67 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t mo } #endif - uint32_t result; - if (deep_sleep) { + if (!should_skip_sleep) { + if (deep_sleep) { #if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP - esp_sleep_isolate_digital_gpio(); + esp_sleep_isolate_digital_gpio(); #endif #if SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY - esp_set_deep_sleep_wake_stub_default_entry(); - // Enter Deep Sleep + esp_set_deep_sleep_wake_stub_default_entry(); + // Enter Deep Sleep #if SOC_PMU_SUPPORTED - result = call_rtc_sleep_start(reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep); + 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); + result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep); #endif #else #if !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP - /* If not possible stack is in RTC FAST memory, use the ROM function to calculate the CRC and save ~140 bytes IRAM */ + /* If not possible stack is in RTC FAST memory, use the ROM function to calculate the CRC and save ~140 bytes IRAM */ #if SOC_RTC_FAST_MEM_SUPPORTED - set_rtc_memory_crc(); + set_rtc_memory_crc(); #endif - result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep); + result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep); #else - /* Otherwise, need to call the dedicated soc function for this */ - result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers); + /* Otherwise, need to call the dedicated soc function for this */ + result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers); #endif #endif // SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY - } else { + } else { -/* 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 */ + /* 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 && CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND) - if(!(pd_flags & PMU_SLEEP_PD_VDDSDIO)) { - rtcio_ll_force_hold_enable(SPI_CS0_GPIO_NUM); - } + if(!(pd_flags & PMU_SLEEP_PD_VDDSDIO)) { + rtcio_ll_force_hold_enable(SPI_CS0_GPIO_NUM); + } #endif #if SOC_PM_CPU_RETENTION_BY_SW - if (pd_flags & PMU_SLEEP_PD_CPU) { - 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 { - result = call_rtc_sleep_start(reject_triggers, config.power.hp_sys.dig_power.mem_dslp, deep_sleep); - } + if (pd_flags & PMU_SLEEP_PD_CPU) { + 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 { + 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); + result = call_rtc_sleep_start(reject_triggers, config.lslp_mem_inf_fpu, deep_sleep); #endif -/* Unhold the SPI CS pin */ + /* Unhold the SPI CS pin */ #if (CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND) - if(!(pd_flags & PMU_SLEEP_PD_VDDSDIO)) { - rtcio_ll_force_hold_disable(SPI_CS0_GPIO_NUM); - } + if(!(pd_flags & PMU_SLEEP_PD_VDDSDIO)) { + rtcio_ll_force_hold_disable(SPI_CS0_GPIO_NUM); + } #endif - } + } #if CONFIG_ESP_SLEEP_SYSTIMER_STALL_WORKAROUND - if (!(pd_flags & RTC_SLEEP_PD_XTAL)) { - rtc_sleep_systimer_enable(true); - } + if (!(pd_flags & RTC_SLEEP_PD_XTAL)) { + rtc_sleep_systimer_enable(true); + } #endif + } // Restore CPU frequency #if SOC_PM_SUPPORT_PMU_MODEM_STATE @@ -1122,7 +1131,7 @@ esp_err_t esp_sleep_enable_timer_wakeup(uint64_t time_in_us) return ESP_OK; } -static void timer_wakeup_prepare(void) +static esp_err_t timer_wakeup_prepare(void) { int64_t sleep_duration = (int64_t) s_config.sleep_duration - (int64_t) s_config.sleep_time_adjustment; if (sleep_duration < 0) { @@ -1130,12 +1139,23 @@ static void timer_wakeup_prepare(void) } int64_t ticks = rtc_time_us_to_slowclk(sleep_duration, s_config.rtc_clk_cal_period); + int64_t target_wakeup_tick = s_config.rtc_ticks_at_sleep_start + ticks; #if SOC_LP_TIMER_SUPPORTED - lp_timer_hal_set_alarm_target(0, s_config.rtc_ticks_at_sleep_start + ticks); -#else - rtc_hal_set_wakeup_timer(s_config.rtc_ticks_at_sleep_start + ticks); +#if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP + // When pd_top is supported, light_sleep will flush uart, and the sleep overhead time will become an unpredictable value, + // here is the last timer wake-up validity check + if ((sleep_duration == 0) || \ + (target_wakeup_tick < lp_timer_hal_get_cycle_count() + SLEEP_TIMER_ALARM_TO_SLEEP_TICKS)) { + // Treat too short sleep duration setting as timer reject + return ESP_ERR_SLEEP_REJECT; + } #endif + lp_timer_hal_set_alarm_target(0, target_wakeup_tick); +#else + rtc_hal_set_wakeup_timer(target_wakeup_tick); +#endif + return ESP_OK; } #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 diff --git a/components/esp_pm/pm_impl.c b/components/esp_pm/pm_impl.c index 13343f48f4..9b7f6e608a 100644 --- a/components/esp_pm/pm_impl.c +++ b/components/esp_pm/pm_impl.c @@ -156,6 +156,7 @@ static const char* s_mode_names[] = { "APB_MAX", "CPU_MAX" }; +static uint32_t s_light_sleep_counts, s_light_sleep_reject_counts; #endif // WITH_PROFILING #ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT @@ -612,7 +613,13 @@ void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime ) /* Enter sleep */ ESP_PM_TRACE_ENTER(SLEEP, core_id); int64_t sleep_start = esp_timer_get_time(); - esp_light_sleep_start(); + if (esp_light_sleep_start() != ESP_OK){ +#ifdef WITH_PROFILING + s_light_sleep_reject_counts++; + } else { + s_light_sleep_counts++; +#endif + } int64_t slept_us = esp_timer_get_time() - sleep_start; ESP_PM_TRACE_EXIT(SLEEP, core_id); @@ -652,6 +659,9 @@ void esp_pm_impl_dump_stats(FILE* out) pm_time_t last_mode_change_time = s_last_mode_change_time; pm_mode_t cur_mode = s_mode; pm_time_t now = pm_get_time(); + bool light_sleep_en = s_light_sleep_en; + uint32_t light_sleep_counts = s_light_sleep_counts; + uint32_t light_sleep_reject_counts = s_light_sleep_reject_counts; portEXIT_CRITICAL_ISR(&s_switch_lock); time_in_mode[cur_mode] += now - last_mode_change_time; @@ -659,7 +669,7 @@ void esp_pm_impl_dump_stats(FILE* out) fprintf(out, "\nMode stats:\n"); fprintf(out, "%-8s %-10s %-10s %-10s\n", "Mode", "CPU_freq", "Time(us)", "Time(%)"); for (int i = 0; i < PM_MODE_COUNT; ++i) { - if (i == PM_MODE_LIGHT_SLEEP && !s_light_sleep_en) { + if (i == PM_MODE_LIGHT_SLEEP && !light_sleep_en) { /* don't display light sleep mode if it's not enabled */ continue; } @@ -670,6 +680,10 @@ void esp_pm_impl_dump_stats(FILE* out) time_in_mode[i], (int) (time_in_mode[i] * 100 / now)); } + if (light_sleep_en){ + fprintf(out, "\nSleep stats:\n"); + fprintf(out, "light_sleep_counts:%ld light_sleep_reject_counts:%ld\n", light_sleep_counts, light_sleep_reject_counts); + } } #endif // WITH_PROFILING From 388746ca31c308da31057e3a4127c0c8a56f04b7 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 8 May 2023 15:11:22 +0800 Subject: [PATCH 3/4] Kconfig: add more help info for pm related options help --- components/esp_pm/Kconfig | 8 +++++++- components/freertos/Kconfig | 3 +++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/components/esp_pm/Kconfig b/components/esp_pm/Kconfig index 246c405395..e49568f7ec 100644 --- a/components/esp_pm/Kconfig +++ b/components/esp_pm/Kconfig @@ -138,13 +138,19 @@ menu "Power Management" context of the necessary hardware for FreeRTOS to run, it will need at least 4.55 KB free heap at sleep time. Otherwise sleep will not power down the peripherals. - Note: Please use this option with caution, the current IDF does not support the retention of + Note1: Please use this option with caution, the current IDF does not support the retention of all peripherals. When the digital peripherals are powered off and a sleep and wake-up is completed, the peripherals that have not saved the running context are equivalent to performing a reset. !!! Please confirm the peripherals used in your application and their sleep retention support status before enabling this option, peripherals sleep retention driver support status is tracked in power_management.rst + Note2: When this option is enabled simultaneously with FREERTOS_USE_TICKLESS_IDLE, since the UART will + be powered down, the uart FIFO will be flushed before sleep to avoid data loss, however, this has the + potential to block the sleep process and cause the wakeup time to be skipped, which will cause the tick + of freertos to not be compensated correctly when returning from sleep and cause the system to crash. + To avoid this, you can increase FREERTOS_IDLE_TIME_BEFORE_SLEEP threshold in menuconfig. + config PM_UPDATE_CCOMPARE_HLI_WORKAROUND bool default y if PM_ENABLE && BTDM_CTRL_HLI diff --git a/components/freertos/Kconfig b/components/freertos/Kconfig index f1830ba46e..e55bb6b6a7 100644 --- a/components/freertos/Kconfig +++ b/components/freertos/Kconfig @@ -271,6 +271,9 @@ menu "FreeRTOS" # Minimal value is 2 because of a check in FreeRTOS.h (search configEXPECTED_IDLE_TIME_BEFORE_SLEEP) help FreeRTOS will enter light sleep mode if no tasks need to run for this number of ticks. + You can enable PM_PROFILING feature in esp_pm components and dump the sleep status with + esp_pm_dump_locks, if the proportion of rejected sleeps is too high, please increase + this value to improve scheduling efficiency endmenu # Kernel From 42366440713de79332e8e9aa20b72ca3a93320c4 Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Mon, 29 May 2023 14:59:22 +0800 Subject: [PATCH 4/4] feature: skip console uart flush and sleep when estimated uart flush time exceeds the sleep duration to avoid rtos tick jump failed --- components/esp_hw_support/sleep_modes.c | 60 ++++++++++++++++++------- 1 file changed, 45 insertions(+), 15 deletions(-) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 4a71b4135d..a6968fdd18 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -127,6 +127,14 @@ // Actually costs 80us, using the fastest slow clock 150K calculation takes about 16 ticks #define SLEEP_TIMER_ALARM_TO_SLEEP_TICKS (16) +#if SOC_PM_SUPPORT_TOP_PD +// IDF console uses 8 bits data mode without parity, so each char occupy 8(data)+1(start)+1(stop)=10bits +#define UART_FLUSH_US_PER_CHAR (10*1000*1000 / CONFIG_ESP_CONSOLE_UART_BAUDRATE) +#define CONCATENATE_HELPER(x, y) (x##y) +#define CONCATENATE(x, y) CONCATENATE_HELPER(x, y) +#define CONSOLE_UART_DEV (&CONCATENATE(UART, CONFIG_ESP_CONSOLE_UART_NUM)) +#endif + #define LIGHT_SLEEP_TIME_OVERHEAD_US DEFAULT_HARDWARE_OUT_OVERHEAD_US #ifdef CONFIG_ESP_SYSTEM_RTC_EXT_XTAL #define DEEP_SLEEP_TIME_OVERHEAD_US (650 + 100 * 240 / CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ) @@ -481,19 +489,6 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t mo bool deep_sleep = (mode == ESP_SLEEP_MODE_DEEP_SLEEP); bool should_skip_sleep = false; - if (deep_sleep) { - flush_uarts(); - } else { -#if SOC_PM_SUPPORT_TOP_PD - if (pd_flags & PMU_SLEEP_PD_TOP) { - flush_uarts(); - } else -#endif - { - suspend_uarts(); - } - } - #if SOC_RTC_SLOW_CLK_SUPPORT_RC_FAST_D256 //Keep the RTC8M_CLK on if RTC clock is rc_fast_d256. bool rtc_using_8md256 = (rtc_clk_slow_src_get() == SOC_RTC_SLOW_CLK_SRC_RC_FAST_D256); @@ -516,6 +511,18 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t mo rtc_clk_cpu_freq_get_config(&cpu_freq_config); rtc_clk_cpu_freq_set_xtal(); + // Deep sleep UART prepare + /* flush_uart should be as late as possible, because the later the flush, + the shorter the time overhead of entering sleep caused by blocking, + and blocking after frequency switching can also reduce the power consumption + during the active state.*/ + + /* ext/gpio deepsleep wakeup prepare will change GPIO configure, + we need to flush uart before it */ + if (deep_sleep) { + flush_uarts(); + } + #if SOC_PM_SUPPORT_EXT0_WAKEUP // Configure pins for external wakeup if (s_config.wakeup_triggers & RTC_EXT0_TRIG_EN) { @@ -614,6 +621,28 @@ static uint32_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t mo } } + // Light sleep UART prepare + if (!deep_sleep) { +#if SOC_PM_SUPPORT_TOP_PD + if (pd_flags & PMU_SLEEP_PD_TOP) { + if ((s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) && + // s_config.sleep_duration here has been compensated in timer_wakeup_prepare, + // +2 is for cover the last charactor flush time and timer alarm to sleep request time(no more than 80us) + (s_config.sleep_duration < (UART_LL_FIFO_DEF_LEN - uart_ll_get_txfifo_len(CONSOLE_UART_DEV) + 2) * UART_FLUSH_US_PER_CHAR)) { + result = ESP_ERR_SLEEP_REJECT; + should_skip_sleep = true; + } else { + /* Only flush the uart_num configured to console, the transmission integrity of + other uarts is guaranteed by the UART driver */ + esp_rom_uart_tx_wait_idle(CONFIG_ESP_CONSOLE_UART_NUM); + } + } else +#endif + { + suspend_uarts(); + } + } + #if CONFIG_ESP_SLEEP_SYSTIMER_STALL_WORKAROUND if (!(pd_flags & RTC_SLEEP_PD_XTAL)) { rtc_sleep_systimer_enable(false); @@ -1143,8 +1172,7 @@ static esp_err_t timer_wakeup_prepare(void) #if SOC_LP_TIMER_SUPPORTED #if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP - // When pd_top is supported, light_sleep will flush uart, and the sleep overhead time will become an unpredictable value, - // here is the last timer wake-up validity check + // Last timer wake-up validity check if ((sleep_duration == 0) || \ (target_wakeup_tick < lp_timer_hal_get_cycle_count() + SLEEP_TIMER_ALARM_TO_SLEEP_TICKS)) { // Treat too short sleep duration setting as timer reject @@ -1155,6 +1183,8 @@ static esp_err_t timer_wakeup_prepare(void) #else rtc_hal_set_wakeup_timer(target_wakeup_tick); #endif + + s_config.sleep_duration = sleep_duration; return ESP_OK; }