From 9a246bcbf117301f4244cbb0a444abefed8d861b Mon Sep 17 00:00:00 2001 From: wuzhenghui Date: Sun, 8 Oct 2023 16:48:00 +0800 Subject: [PATCH] feat: support dump last time sleep context --- components/esp_hw_support/Kconfig | 6 ++ .../include/esp_private/esp_sleep_internal.h | 19 ++++- components/esp_hw_support/sleep_modes.c | 70 +++++++++++++++---- 3 files changed, 80 insertions(+), 15 deletions(-) diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index 5aa11dc938..62ce1951dd 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -172,6 +172,12 @@ menu "Hardware Settings" For chips after esp32, the delay will be executed only in light sleep flow, the delay controlled by the EFUSE_FLASH_TPUW in ROM will be executed in deepsleep wake up flow.) + config ESP_SLEEP_DEBUG + bool "esp sleep debug" + default n + help + Enable esp sleep debug. + config ESP_SLEEP_GPIO_ENABLE_INTERNAL_RESISTORS bool "Allow to enable internal pull-up/downs for the Deep-Sleep wakeup IOs" default y diff --git a/components/esp_hw_support/include/esp_private/esp_sleep_internal.h b/components/esp_hw_support/include/esp_private/esp_sleep_internal.h index 56a6b5fde1..83bbcc2509 100644 --- a/components/esp_hw_support/include/esp_private/esp_sleep_internal.h +++ b/components/esp_hw_support/include/esp_private/esp_sleep_internal.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -13,6 +13,23 @@ extern "C" { #endif +#if CONFIG_ESP_SLEEP_DEBUG +typedef struct { + uint32_t lightsleep_cnt; + uint64_t sleep_in_rtc_time_stamp; + uint64_t sleep_out_rtc_time_stamp; + uint32_t wakeup_triggers; + uint32_t sleep_flags; + esp_err_t sleep_request_result; +} esp_sleep_context_t; + +/** + * @brief Set the context pointer of last sleep request + * @param sleep_ctx Structure where the context of the sleep information needs to be recorded in + */ +void esp_sleep_set_sleep_context(esp_sleep_context_t *sleep_ctx); +#endif + /** * @brief Enables the use of ADC and temperature sensor in monitor (ULP) mode * diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index b6f30498b8..543c438c20 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -83,7 +83,6 @@ #include "esp32c2/rom/rtc.h" #elif CONFIG_IDF_TARGET_ESP32C6 #include "esp32c6/rom/rtc.h" -#include "hal/lp_timer_hal.h" #include "hal/gpio_ll.h" #elif CONFIG_IDF_TARGET_ESP32H2 #include "esp32h2/rom/rtc.h" @@ -196,8 +195,10 @@ typedef struct { uint32_t ext0_trigger_level : 1; uint32_t ext0_rtc_gpio_num : 5; #endif +#if SOC_GPIO_SUPPORT_DEEPSLEEP_WAKEUP uint32_t gpio_wakeup_mask : 8; // 8 is the maximum RTCIO number in all chips that support GPIO wakeup uint32_t gpio_trigger_mode : 8; +#endif uint32_t sleep_time_adjustment; uint32_t ccount_ticks_record; uint32_t sleep_time_overhead_out; @@ -207,6 +208,17 @@ typedef struct { } sleep_config_t; +#if CONFIG_ESP_SLEEP_DEBUG +static esp_sleep_context_t *s_sleep_ctx = NULL; + +void esp_sleep_set_sleep_context(esp_sleep_context_t *sleep_ctx) +{ + s_sleep_ctx = sleep_ctx; +} +#endif + +static uint32_t s_lightsleep_cnt = 0; + _Static_assert(22 >= SOC_RTCIO_PIN_COUNT, "Chip has more RTCIOs than 22, should increase ext1_rtc_gpio_mask field size"); static sleep_config_t s_config = { @@ -715,11 +727,18 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m if (periph_using_8m) { sleep_flags |= RTC_SLEEP_DIG_USE_8M; } + +#if CONFIG_ESP_SLEEP_DEBUG + if (s_sleep_ctx != NULL) { + s_sleep_ctx->sleep_flags = sleep_flags; + } +#endif + // 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, + pmu_sleep_init(pmu_sleep_config_default(&config, sleep_flags, s_config.sleep_time_adjustment, s_config.rtc_clk_cal_period, s_config.fast_clk_cal_period, deep_sleep), deep_sleep); #else @@ -749,6 +768,11 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m if (should_skip_sleep) { result = ESP_ERR_SLEEP_REJECT; } 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_SINGLE_IO_IN_DSLP esp_sleep_isolate_digital_gpio(); @@ -792,8 +816,9 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m esp_sleep_execute_event_callbacks(SLEEP_EVENT_HW_GOTO_SLEEP, (void *)0); 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 { + } else #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); @@ -1063,15 +1088,18 @@ esp_err_t esp_light_sleep_start(void) */ esp_clk_private_lock(); -#if SOC_LP_TIMER_SUPPORTED - s_config.rtc_ticks_at_sleep_start = lp_timer_hal_get_cycle_count(); -#else s_config.rtc_ticks_at_sleep_start = rtc_time_get(); -#endif uint32_t ccount_at_sleep_start = esp_cpu_get_cycle_count(); esp_sleep_execute_event_callbacks(SLEEP_EVENT_HW_TIME_START, (void *)0); uint64_t high_res_time_at_start = esp_timer_get_time(); uint32_t sleep_time_overhead_in = (ccount_at_sleep_start - s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL); + +#if CONFIG_ESP_SLEEP_DEBUG + if (s_sleep_ctx != NULL) { + s_sleep_ctx->sleep_in_rtc_time_stamp = s_config.rtc_ticks_at_sleep_start; + } +#endif + esp_ipc_isr_stall_other_cpu(); // Decide which power domains can be powered down @@ -1164,6 +1192,13 @@ esp_err_t esp_light_sleep_start(void) // reset light sleep wakeup flag before a new light sleep s_light_sleep_wakeup = false; + s_lightsleep_cnt++; +#if CONFIG_ESP_SLEEP_DEBUG + if (s_sleep_ctx != NULL) { + s_sleep_ctx->lightsleep_cnt = s_lightsleep_cnt; + } +#endif + // if rtc timer wakeup source is enabled, need to compare final sleep duration and min sleep duration to avoid late wakeup if ((s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) && (final_sleep_duration_us <= min_sleep_duration_us)) { err = ESP_ERR_SLEEP_TOO_SHORT_SLEEP_DURATION; @@ -1176,13 +1211,15 @@ esp_err_t esp_light_sleep_start(void) s_light_sleep_wakeup = (err == ESP_OK); // System timer has been stopped for the duration of the sleep, correct for that. -#if SOC_LP_TIMER_SUPPORTED - uint64_t rtc_ticks_at_end = lp_timer_hal_get_cycle_count(); -#else uint64_t rtc_ticks_at_end = rtc_time_get(); -#endif uint64_t rtc_time_diff = rtc_time_slowclk_to_us(rtc_ticks_at_end - s_config.rtc_ticks_at_sleep_start, s_config.rtc_clk_cal_period); +#if CONFIG_ESP_SLEEP_DEBUG + if (s_sleep_ctx != NULL) { + s_sleep_ctx->sleep_out_rtc_time_stamp = rtc_ticks_at_end; + } +#endif + /** * If sleep duration is too small(less than 1 rtc_slow_clk cycle), rtc_time_diff will be zero. * In this case, just ignore the time compensation and keep esp_timer monotonic. @@ -1211,6 +1248,12 @@ esp_err_t esp_light_sleep_start(void) esp_sleep_execute_event_callbacks(SLEEP_EVENT_SW_EXIT_SLEEP, (void *)0); s_config.sleep_time_overhead_out = (esp_cpu_get_cycle_count() - s_config.ccount_ticks_record) / (esp_clk_cpu_freq() / 1000000ULL); + +#if CONFIG_ESP_SLEEP_DEBUG + if (s_sleep_ctx != NULL) { + s_sleep_ctx->sleep_request_result = err; + } +#endif return err; } @@ -1307,7 +1350,7 @@ static esp_err_t timer_wakeup_prepare(int64_t sleep_duration) #if CONFIG_PM_POWER_DOWN_PERIPHERAL_IN_LIGHT_SLEEP // 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)) { + (target_wakeup_tick < rtc_time_get() + SLEEP_TIMER_ALARM_TO_SLEEP_TICKS)) { // Treat too short sleep duration setting as timer reject return ESP_ERR_SLEEP_REJECT; } @@ -1850,7 +1893,6 @@ static uint32_t get_power_down_flags(void) } #endif - #ifdef CONFIG_IDF_TARGET_ESP32 s_config.domain[ESP_PD_DOMAIN_XTAL].pd_option = ESP_PD_OPTION_OFF; #endif