fix(esp_hw_support): Return deep sleep APIs to the original behavior

Closes https://github.com/espressif/esp-idf/issues/12359
This commit is contained in:
KonstantinKondrashov
2023-10-07 00:42:49 +08:00
parent ee6ea577e2
commit 315d4864bb
2 changed files with 78 additions and 16 deletions

View File

@ -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 * @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__)); 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. * followed by a call to esp_deep_sleep_start.
* *
* @param time_in_us deep-sleep time, unit: microsecond * @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__)); void esp_deep_sleep(uint64_t time_in_us) __attribute__((__noreturn__));
/** /**
* @brief Register a callback to be called from the deep sleep prepare * @brief Register a callback to be called from the deep sleep prepare
* *

View File

@ -373,6 +373,12 @@ void esp_deep_sleep(uint64_t time_in_us)
esp_deep_sleep_start(); 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) esp_err_t esp_deep_sleep_register_hook(esp_deep_sleep_cb_t new_dslp_cb)
{ {
portENTER_CRITICAL(&spinlock_rtc_deep_sleep); 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); 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. // 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. // 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 #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) { if (!deep_sleep) {
/* Enable sleep reject for faster return from this function, /* 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 // Configure timer wakeup
if (!should_skip_sleep && (s_config.wakeup_triggers & RTC_TIMER_TRIG_EN)) { if (!should_skip_sleep && (s_config.wakeup_triggers & RTC_TIMER_TRIG_EN)) {
if (timer_wakeup_prepare(sleep_duration) != ESP_OK) { 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 #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 #if CONFIG_IDF_TARGET_ESP32S2
/* Due to hardware limitations, on S2 the brownout detector sometimes trigger during deep sleep /* 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 #endif
// Enter sleep // Enter sleep
if (esp_sleep_start(force_pd_flags | pd_flags, ESP_SLEEP_MODE_DEEP_SLEEP) == ESP_ERR_SLEEP_REJECT) { esp_err_t err = ESP_OK;
ESP_EARLY_LOGW(TAG, "Deep sleep request is rejected"); 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) {
;
}
} }
// Never returns here, except that the sleep is rejected.
// 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
esp_ipc_isr_release_other_cpu(); esp_ipc_isr_release_other_cpu();
portEXIT_CRITICAL(&spinlock_rtc_deep_sleep); 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 #endif
// Enter sleep // 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 SOC_CONFIGURABLE_VDDSDIO_SUPPORTED
// If VDDSDIO regulator was controlled by RTC registers before sleep, // If VDDSDIO regulator was controlled by RTC registers before sleep,