From 87325fa964f2fe02e1be91e39c0115f9ebd77d33 Mon Sep 17 00:00:00 2001 From: Omar Chebib Date: Wed, 24 Feb 2021 10:53:24 +0800 Subject: [PATCH] esp_system: add VDD_SDIO power domain configuration for light sleep VDD_SDIO power domain can now be configured for light sleep by the application. It is now possible to keep the power domain ON during light sleep, keeping the GPIOs connected to it powered. The power domain will, by default be: - Kept ON if CONFIG_ESP_SYSTEM_PD_FLASH is not set - Turned OFF if not set The application can still force it to be ON by calling `esp_sleep_pd_config(ESP_PD_DOMAIN_VDDSDIO, ESP_PD_OPTION_ON);` --- components/esp_system/include/esp_sleep.h | 1 + components/esp_system/sleep_modes.c | 81 +++++++++++++++-------- 2 files changed, 56 insertions(+), 26 deletions(-) diff --git a/components/esp_system/include/esp_sleep.h b/components/esp_system/include/esp_sleep.h index 68360a76e2..3899ab3da3 100644 --- a/components/esp_system/include/esp_sleep.h +++ b/components/esp_system/include/esp_sleep.h @@ -50,6 +50,7 @@ typedef enum { ESP_PD_DOMAIN_RTC_FAST_MEM, //!< RTC fast memory ESP_PD_DOMAIN_XTAL, //!< XTAL oscillator ESP_PD_DOMAIN_CPU, //!< CPU core + ESP_PD_DOMAIN_VDDSDIO, //!< VDD_SDIO ESP_PD_DOMAIN_MAX //!< Number of domains } esp_sleep_pd_domain_t; diff --git a/components/esp_system/sleep_modes.c b/components/esp_system/sleep_modes.c index 4dae2dd1a3..5310b8c5eb 100644 --- a/components/esp_system/sleep_modes.c +++ b/components/esp_system/sleep_modes.c @@ -151,7 +151,7 @@ typedef struct { } sleep_config_t; static sleep_config_t s_config = { - .pd_options = { ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO }, + .pd_options = { ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO, ESP_PD_OPTION_AUTO }, .ccount_ticks_record = 0, .sleep_time_overhead_out = DEFAULT_SLEEP_OUT_OVERHEAD_US, .wakeup_triggers = 0 @@ -724,35 +724,43 @@ esp_err_t esp_light_sleep_start(void) // If it needs to be powered down, adjust sleep time. const uint32_t flash_enable_time_us = VDD_SDIO_POWERUP_TO_FLASH_READ_US + DEEP_SLEEP_WAKEUP_DELAY; -#if CONFIG_ESP_SYSTEM_PD_FLASH - /* - * When SPIRAM is disabled in menuconfig, the minimum sleep time of the - * system needs to meet the sum below: - * 1. Wait time for the flash power-on after waking up; - * 2. The execution time of codes between RTC Timer get start time - * with hardware starts to switch state to sleep; - * 3. The hardware state switching time of the rtc state machine during - * sleep and wake-up. This process requires 6 cycles to complete. - * The specific hardware state switching process and the cycles - * consumed are rtc_cpu_run_stall(1), cut_pll_rtl(2), cut_8m(1), - * min_protect(2); - * 4. All the adjustment time which is s_config.sleep_time_adjustment below. + /** + * If VDD_SDIO power domain is requested to be turned off, bit `RTC_SLEEP_PD_VDDSDIO` + * will be set in `pd_flags`. */ - const uint32_t vddsdio_pd_sleep_duration = MAX(FLASH_PD_MIN_SLEEP_TIME_US, - flash_enable_time_us + LIGHT_SLEEP_MIN_TIME_US + s_config.sleep_time_adjustment - + rtc_time_slowclk_to_us(RTC_MODULE_SLEEP_PREPARE_CYCLES, s_config.rtc_clk_cal_period)); + if ((pd_flags & RTC_SLEEP_PD_VDDSDIO) != 0) { + /* + * When VDD_SDIO power domain has to be turned off, the minimum sleep time of the + * system needs to meet the sum below: + * 1. Wait time for the flash power-on after waking up; + * 2. The execution time of codes between RTC Timer get start time + * with hardware starts to switch state to sleep; + * 3. The hardware state switching time of the rtc state machine during + * sleep and wake-up. This process requires 6 cycles to complete. + * The specific hardware state switching process and the cycles + * consumed are rtc_cpu_run_stall(1), cut_pll_rtl(2), cut_8m(1), + * min_protect(2); + * 4. All the adjustment time which is s_config.sleep_time_adjustment below. + */ + const uint32_t vddsdio_pd_sleep_duration = MAX(FLASH_PD_MIN_SLEEP_TIME_US, + flash_enable_time_us + LIGHT_SLEEP_MIN_TIME_US + s_config.sleep_time_adjustment + + rtc_time_slowclk_to_us(RTC_MODULE_SLEEP_PREPARE_CYCLES, s_config.rtc_clk_cal_period)); - if (s_config.sleep_duration > vddsdio_pd_sleep_duration) { - pd_flags |= RTC_SLEEP_PD_VDDSDIO; - if (s_config.sleep_time_overhead_out < flash_enable_time_us) { - s_config.sleep_time_adjustment += flash_enable_time_us; - } - } else { - if (s_config.sleep_time_overhead_out > flash_enable_time_us) { - s_config.sleep_time_adjustment -= flash_enable_time_us; + if (s_config.sleep_duration > vddsdio_pd_sleep_duration) { + if (s_config.sleep_time_overhead_out < flash_enable_time_us) { + s_config.sleep_time_adjustment += flash_enable_time_us; + } + } else { + /** + * Minimum sleep time is not enough, then keep the VDD_SDIO power + * domain on. + */ + pd_flags &= ~RTC_SLEEP_PD_VDDSDIO; + if (s_config.sleep_time_overhead_out > flash_enable_time_us) { + s_config.sleep_time_adjustment -= flash_enable_time_us; + } } } -#endif //CONFIG_ESP_SYSTEM_PD_FLASH periph_inform_out_light_sleep_overhead(s_config.sleep_time_adjustment - sleep_time_overhead_in); @@ -1330,6 +1338,27 @@ static uint32_t get_power_down_flags(void) pd_flags |= RTC_SLEEP_PD_XTAL; #endif + /** + * VDD_SDIO power domain shall be kept on during the light sleep + * when CONFIG_ESP_SYSTEM_PD_FLASH is not set and off when it is set. + * The application can still force the power domain to remain on by calling + * `esp_sleep_pd_config` before getting into light sleep mode. + * + * In deep sleep mode, the power domain will be turned off, regardless the + * value of this field. + */ + if (s_config.pd_options[ESP_PD_DOMAIN_VDDSDIO] == ESP_PD_OPTION_AUTO) { +#ifdef CONFIG_ESP_SYSTEM_PD_FLASH + s_config.pd_options[ESP_PD_DOMAIN_VDDSDIO] = ESP_PD_OPTION_OFF; +#else + s_config.pd_options[ESP_PD_DOMAIN_VDDSDIO] = ESP_PD_OPTION_ON; +#endif + } + + if (s_config.pd_options[ESP_PD_DOMAIN_VDDSDIO] != ESP_PD_OPTION_ON) { + pd_flags |= RTC_SLEEP_PD_VDDSDIO; + } + #if ((defined CONFIG_ESP32_RTC_CLK_SRC_EXT_CRYS) && (defined CONFIG_ESP32_RTC_EXT_CRYST_ADDIT_CURRENT)) if ((s_config.wakeup_triggers & (RTC_TOUCH_TRIG_EN | RTC_ULP_TRIG_EN)) == 0) { // If enabled EXT1 only and enable the additional current by touch, should be keep RTC_PERIPH power on.