bugfix: treat too short sleep duration as sleep reject by software

This commit is contained in:
wuzhenghui 2023-05-09 14:01:29 +08:00
parent 756b5f628d
commit 5c74093300
5 changed files with 91 additions and 43 deletions

View File

@ -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); 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 * @brief Initialize PMU related power/clock/digital parameters and functions
*/ */

View File

@ -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 */ /* Start entry into sleep mode */
pmu_ll_hp_set_sleep_enable(PMU_instance()->hal->dev); 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) && while (!pmu_ll_hp_is_sleep_wakeup(PMU_instance()->hal->dev) &&
!pmu_ll_hp_is_sleep_reject(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);
} }

View File

@ -22,7 +22,9 @@
#include "esp_private/sleep_cpu.h" #include "esp_private/sleep_cpu.h"
#include "sdkconfig.h" #include "sdkconfig.h"
#if !SOC_PMU_SUPPORTED #if SOC_PMU_SUPPORTED
#include "esp_private/esp_pmu.h"
#else
#include "hal/rtc_hal.h" #include "hal/rtc_hal.h"
#endif #endif
@ -683,7 +685,7 @@ static IRAM_ATTR esp_err_t do_cpu_retention(sleep_cpu_entry_cb_t goto_sleep,
} }
#endif #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), esp_err_t IRAM_ATTR esp_sleep_cpu_retention(uint32_t (*goto_sleep)(uint32_t, uint32_t, uint32_t, bool),

View File

@ -124,6 +124,9 @@
#define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9) #define DEFAULT_HARDWARE_OUT_OVERHEAD_US (9)
#endif #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 #define LIGHT_SLEEP_TIME_OVERHEAD_US DEFAULT_HARDWARE_OUT_OVERHEAD_US
#ifdef CONFIG_ESP_SYSTEM_RTC_EXT_XTAL #ifdef CONFIG_ESP_SYSTEM_RTC_EXT_XTAL
#define DEEP_SLEEP_TIME_OVERHEAD_US (650 + 100 * 240 / CONFIG_ESP_DEFAULT_CPU_FREQ_MHZ) #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 #if SOC_PM_SUPPORT_EXT1_WAKEUP
static void ext1_wakeup_prepare(void); static void ext1_wakeup_prepare(void);
#endif #endif
static void timer_wakeup_prepare(void); static esp_err_t timer_wakeup_prepare(void);
#if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3
static void touch_wakeup_prepare(void); static void touch_wakeup_prepare(void);
#endif #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 light sleep, suspend UART output — it will resume after wakeup.
// For deep sleep, wait for the contents of UART FIFO to be sent. // For deep sleep, wait for the contents of UART FIFO to be sent.
bool deep_sleep = (mode == ESP_SLEEP_MODE_DEEP_SLEEP); bool deep_sleep = (mode == ESP_SLEEP_MODE_DEEP_SLEEP);
bool should_skip_sleep = false;
if (deep_sleep) { if (deep_sleep) {
flush_uarts(); 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 // Enter sleep
esp_err_t result;
#if SOC_PMU_SUPPORTED #if SOC_PMU_SUPPORTED
pmu_sleep_config_t config; pmu_sleep_config_t config;
pmu_sleep_init(pmu_sleep_config_default(&config, pd_flags, s_config.sleep_time_adjustment, 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 // Configure timer wakeup
if (s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) { 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 #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 #endif
uint32_t result; if (!should_skip_sleep) {
if (deep_sleep) { if (deep_sleep) {
#if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP #if !SOC_GPIO_SUPPORT_HOLD_SINGLE_IO_IN_DSLP
esp_sleep_isolate_digital_gpio(); esp_sleep_isolate_digital_gpio();
#endif #endif
#if SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY #if SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY
esp_set_deep_sleep_wake_stub_default_entry(); esp_set_deep_sleep_wake_stub_default_entry();
// Enter Deep Sleep // Enter Deep Sleep
#if SOC_PMU_SUPPORTED #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 #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 #endif
#else #else
#if !CONFIG_ESP_SYSTEM_ALLOW_RTC_FAST_MEM_AS_HEAP #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 #if SOC_RTC_FAST_MEM_SUPPORTED
set_rtc_memory_crc(); set_rtc_memory_crc();
#endif #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 #else
/* Otherwise, need to call the dedicated soc function for this */ /* Otherwise, need to call the dedicated soc function for this */
result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers); result = rtc_deep_sleep_start(s_config.wakeup_triggers, reject_triggers);
#endif #endif
#endif // SOC_PM_SUPPORT_DEEPSLEEP_CHECK_STUB_ONLY #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. /* 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 */ 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 (CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND)
if(!(pd_flags & PMU_SLEEP_PD_VDDSDIO)) { if(!(pd_flags & PMU_SLEEP_PD_VDDSDIO)) {
rtcio_ll_force_hold_enable(SPI_CS0_GPIO_NUM); rtcio_ll_force_hold_enable(SPI_CS0_GPIO_NUM);
} }
#endif #endif
#if SOC_PM_CPU_RETENTION_BY_SW #if SOC_PM_CPU_RETENTION_BY_SW
if (pd_flags & PMU_SLEEP_PD_CPU) { 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); 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 { } else {
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 #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 #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 (CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP && CONFIG_ESP_SLEEP_FLASH_LEAKAGE_WORKAROUND)
if(!(pd_flags & PMU_SLEEP_PD_VDDSDIO)) { if(!(pd_flags & PMU_SLEEP_PD_VDDSDIO)) {
rtcio_ll_force_hold_disable(SPI_CS0_GPIO_NUM); rtcio_ll_force_hold_disable(SPI_CS0_GPIO_NUM);
} }
#endif #endif
} }
#if CONFIG_ESP_SLEEP_SYSTIMER_STALL_WORKAROUND #if CONFIG_ESP_SLEEP_SYSTIMER_STALL_WORKAROUND
if (!(pd_flags & RTC_SLEEP_PD_XTAL)) { if (!(pd_flags & RTC_SLEEP_PD_XTAL)) {
rtc_sleep_systimer_enable(true); rtc_sleep_systimer_enable(true);
} }
#endif #endif
}
// Restore CPU frequency // Restore CPU frequency
#if SOC_PM_SUPPORT_PMU_MODEM_STATE #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; 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; int64_t sleep_duration = (int64_t) s_config.sleep_duration - (int64_t) s_config.sleep_time_adjustment;
if (sleep_duration < 0) { 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 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 #if SOC_LP_TIMER_SUPPORTED
lp_timer_hal_set_alarm_target(0, s_config.rtc_ticks_at_sleep_start + ticks); #if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP
#else // When pd_top is supported, light_sleep will flush uart, and the sleep overhead time will become an unpredictable value,
rtc_hal_set_wakeup_timer(s_config.rtc_ticks_at_sleep_start + ticks); // 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 #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 #if CONFIG_IDF_TARGET_ESP32S2 || CONFIG_IDF_TARGET_ESP32S3

View File

@ -156,6 +156,7 @@ static const char* s_mode_names[] = {
"APB_MAX", "APB_MAX",
"CPU_MAX" "CPU_MAX"
}; };
static uint32_t s_light_sleep_counts, s_light_sleep_reject_counts;
#endif // WITH_PROFILING #endif // WITH_PROFILING
#ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT #ifdef CONFIG_FREERTOS_SYSTICK_USES_CCOUNT
@ -612,7 +613,13 @@ void IRAM_ATTR vApplicationSleep( TickType_t xExpectedIdleTime )
/* Enter sleep */ /* Enter sleep */
ESP_PM_TRACE_ENTER(SLEEP, core_id); ESP_PM_TRACE_ENTER(SLEEP, core_id);
int64_t sleep_start = esp_timer_get_time(); 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; int64_t slept_us = esp_timer_get_time() - sleep_start;
ESP_PM_TRACE_EXIT(SLEEP, core_id); 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_time_t last_mode_change_time = s_last_mode_change_time;
pm_mode_t cur_mode = s_mode; pm_mode_t cur_mode = s_mode;
pm_time_t now = pm_get_time(); 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); portEXIT_CRITICAL_ISR(&s_switch_lock);
time_in_mode[cur_mode] += now - last_mode_change_time; 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, "\nMode stats:\n");
fprintf(out, "%-8s %-10s %-10s %-10s\n", "Mode", "CPU_freq", "Time(us)", "Time(%)"); fprintf(out, "%-8s %-10s %-10s %-10s\n", "Mode", "CPU_freq", "Time(us)", "Time(%)");
for (int i = 0; i < PM_MODE_COUNT; ++i) { 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 */ /* don't display light sleep mode if it's not enabled */
continue; continue;
} }
@ -670,6 +680,10 @@ void esp_pm_impl_dump_stats(FILE* out)
time_in_mode[i], time_in_mode[i],
(int) (time_in_mode[i] * 100 / now)); (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 #endif // WITH_PROFILING