From 315d4864bb0de8ca15e4b1a5b70a315c4e3ceff8 Mon Sep 17 00:00:00 2001 From: KonstantinKondrashov Date: Sat, 7 Oct 2023 00:42:49 +0800 Subject: [PATCH] fix(esp_hw_support): Return deep sleep APIs to the original behavior Closes https://github.com/espressif/esp-idf/issues/12359 --- components/esp_hw_support/include/esp_sleep.h | 39 ++++++++++++- components/esp_hw_support/sleep_modes.c | 55 ++++++++++++++----- 2 files changed, 78 insertions(+), 16 deletions(-) diff --git a/components/esp_hw_support/include/esp_sleep.h b/components/esp_hw_support/include/esp_sleep.h index 9d8caefddc..169a3b2fbf 100644 --- a/components/esp_hw_support/include/esp_sleep.h +++ b/components/esp_hw_support/include/esp_sleep.h @@ -439,7 +439,22 @@ esp_err_t esp_sleep_pd_config(esp_sleep_pd_domain_t domain, /** * @brief Enter deep sleep with the configured wakeup options * - * This function does not return. + * @note In general, the function does not return, but if the sleep is rejected, + * then it returns from it. + * + * The reason for the rejection can be such as a short sleep time. + * + * @return + * - No return - If the sleep is not rejected. + * - ESP_ERR_SLEEP_REJECT sleep request is rejected(wakeup source set before the sleep request) + */ +esp_err_t esp_deep_sleep_try_to_start(void); + +/** + * @brief Enter deep sleep with the configured wakeup options + * + * @note The function does not do a return (no rejection). Even if wakeup source set before the sleep request + * it goes to deep sleep anyway. */ void esp_deep_sleep_start(void) __attribute__((__noreturn__)); @@ -466,10 +481,30 @@ esp_err_t esp_light_sleep_start(void); * followed by a call to esp_deep_sleep_start. * * @param time_in_us deep-sleep time, unit: microsecond + * + * @return + * - No return - If the sleep is not rejected. + * - ESP_ERR_SLEEP_REJECT sleep request is rejected(wakeup source set before the sleep request) + */ +esp_err_t esp_deep_sleep_try(uint64_t time_in_us); + +/** + * @brief Enter deep-sleep mode + * + * The device will automatically wake up after the deep-sleep time + * Upon waking up, the device calls deep sleep wake stub, and then proceeds + * to load application. + * + * Call to this function is equivalent to a call to esp_deep_sleep_enable_timer_wakeup + * followed by a call to esp_deep_sleep_start. + * + * @note The function does not do a return (no rejection).. Even if wakeup source set before the sleep request + * it goes to deep sleep anyway. + * + * @param time_in_us deep-sleep time, unit: microsecond */ void esp_deep_sleep(uint64_t time_in_us) __attribute__((__noreturn__)); - /** * @brief Register a callback to be called from the deep sleep prepare * diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 24a23d41de..f6121e12fc 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -373,6 +373,12 @@ void esp_deep_sleep(uint64_t time_in_us) esp_deep_sleep_start(); } +esp_err_t esp_deep_sleep_try(uint64_t time_in_us) +{ + esp_sleep_enable_timer_wakeup(time_in_us); + return esp_deep_sleep_try_to_start(); +} + esp_err_t esp_deep_sleep_register_hook(esp_deep_sleep_cb_t new_dslp_cb) { portENTER_CRITICAL(&spinlock_rtc_deep_sleep); @@ -549,7 +555,7 @@ inline static void IRAM_ATTR misc_modules_wake_prepare(void) 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 pd_flags, esp_sleep_mode_t mode) +static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_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. @@ -646,7 +652,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m } #endif - uint32_t reject_triggers = s_config.wakeup_triggers & RTC_SLEEP_REJECT_MASK; + uint32_t reject_triggers = allow_sleep_rejection ? (s_config.wakeup_triggers & RTC_SLEEP_REJECT_MASK) : 0; if (!deep_sleep) { /* Enable sleep reject for faster return from this function, @@ -687,7 +693,7 @@ static esp_err_t IRAM_ATTR esp_sleep_start(uint32_t pd_flags, esp_sleep_mode_t m // Configure timer wakeup if (!should_skip_sleep && (s_config.wakeup_triggers & RTC_TIMER_TRIG_EN)) { if (timer_wakeup_prepare(sleep_duration) != ESP_OK) { - should_skip_sleep = true; + should_skip_sleep = allow_sleep_rejection ? true : false; } } @@ -811,7 +817,7 @@ inline static uint32_t IRAM_ATTR call_rtc_sleep_start(uint32_t reject_triggers, #endif } -void IRAM_ATTR esp_deep_sleep_start(void) +static esp_err_t IRAM_ATTR deep_sleep_start(bool allow_sleep_rejection) { #if CONFIG_IDF_TARGET_ESP32S2 /* Due to hardware limitations, on S2 the brownout detector sometimes trigger during deep sleep @@ -872,18 +878,39 @@ void IRAM_ATTR esp_deep_sleep_start(void) #endif // Enter sleep - if (esp_sleep_start(force_pd_flags | pd_flags, ESP_SLEEP_MODE_DEEP_SLEEP) == ESP_ERR_SLEEP_REJECT) { - ESP_EARLY_LOGW(TAG, "Deep sleep request is rejected"); + esp_err_t err = ESP_OK; + if (esp_sleep_start(force_pd_flags | pd_flags, ESP_SLEEP_MODE_DEEP_SLEEP, allow_sleep_rejection) == ESP_ERR_SLEEP_REJECT) { + err = ESP_ERR_SLEEP_REJECT; +#if CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION + /* Cache Resume 2: if CONFIG_ESP_SLEEP_CACHE_SAFE_ASSERTION is enabled, cache has been suspended in esp_sleep_start */ + resume_cache(); +#endif + ESP_EARLY_LOGE(TAG, "Deep sleep request is rejected"); + } else { + // Because RTC is in a slower clock domain than the CPU, it + // can take several CPU cycles for the sleep mode to start. + while (1) { + ; + } } - - // Because RTC is in a slower clock domain than the CPU, it - // can take several CPU cycles for the sleep mode to start. - while (1) { - ; - } - // Never returns here + // Never returns here, except that the sleep is rejected. esp_ipc_isr_release_other_cpu(); portEXIT_CRITICAL(&spinlock_rtc_deep_sleep); + return err; +} + +void IRAM_ATTR esp_deep_sleep_start(void) +{ + bool allow_sleep_rejection = true; + deep_sleep_start(!allow_sleep_rejection); + // Never returns here + abort(); +} + +esp_err_t IRAM_ATTR esp_deep_sleep_try_to_start(void) +{ + bool allow_sleep_rejection = true; + return deep_sleep_start(allow_sleep_rejection); } /** @@ -901,7 +928,7 @@ static esp_err_t esp_light_sleep_inner(uint32_t pd_flags, #endif // Enter sleep - esp_err_t reject = esp_sleep_start(pd_flags, ESP_SLEEP_MODE_LIGHT_SLEEP); + esp_err_t reject = esp_sleep_start(pd_flags, ESP_SLEEP_MODE_LIGHT_SLEEP, false); #if SOC_CONFIGURABLE_VDDSDIO_SUPPORTED // If VDDSDIO regulator was controlled by RTC registers before sleep,