diff --git a/components/esp_adc/adc_oneshot.c b/components/esp_adc/adc_oneshot.c index cd85a76281..e0118f06a4 100644 --- a/components/esp_adc/adc_oneshot.c +++ b/components/esp_adc/adc_oneshot.c @@ -163,6 +163,10 @@ esp_err_t adc_oneshot_new_unit(const adc_oneshot_unit_init_cfg_t *init_config, a esp_sleep_sub_mode_config(ESP_SLEEP_USE_ADC_TSEN_MONITOR_MODE, true); #endif } +#if CONFIG_IDF_TARGET_ESP32 + // SAR will be used in monitor state, forcibly disable analog lowpower mode to keep system functionality. + esp_sleep_sub_mode_force_disable(ESP_SLEEP_ANALOG_LOW_POWER_MODE); +#endif ESP_LOGD(TAG, "new adc unit%"PRId32" is created", unit->unit_id); *ret_unit = unit; 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 dc2d2f87fe..d66b739d8e 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 @@ -40,6 +40,9 @@ typedef enum { ESP_SLEEP_DIG_USE_XTAL_MODE, //!< The mode requested by digital peripherals to keep XTAL clock on during sleep (both HP_SLEEP and LP_SLEEP mode). (!!! Only valid for lightsleep, will override the XTAL domain config by esp_sleep_pd_config) ESP_SLEEP_LP_USE_XTAL_MODE, //!< The mode requested by lp peripherals to keep XTAL clock on during sleep. Only valid for lightsleep. ESP_SLEEP_VBAT_POWER_DEEPSLEEP_MODE, //!< The mode to switch power supply to VBAT during deep sleep. +#if CONFIG_IDF_TARGET_ESP32 + ESP_SLEEP_ANALOG_LOW_POWER_MODE, //!< If analog-related peripherals(ADC, TSENS, TOUCH) is not used in monitor mode, analog low power mode can be enabled to reduce power consumption (~300uA) in monitor state. +#endif ESP_SLEEP_MODE_MAX, } esp_sleep_sub_mode_t; diff --git a/components/esp_hw_support/include/esp_sleep.h b/components/esp_hw_support/include/esp_sleep.h index a0e40763fc..02e7b22ac5 100644 --- a/components/esp_hw_support/include/esp_sleep.h +++ b/components/esp_hw_support/include/esp_sleep.h @@ -755,6 +755,16 @@ void esp_default_wake_deep_sleep(void); */ void esp_deep_sleep_disable_rom_logging(void); +#if CONFIG_IDF_TARGET_ESP32 +/** + * @brief If analog-related peripherals(ADC, TOUCH) is not used in monitor mode, analog low power mode + * can be enabled by this API to reduce power consumption in monitor state. + * + * @param enable Enable or disable lowpower analog mode + */ +void esp_sleep_enable_lowpower_analog_mode(bool enable); +#endif + #if ESP_SLEEP_POWER_DOWN_CPU #if SOC_PM_CPU_RETENTION_BY_RTCCNTL diff --git a/components/esp_hw_support/port/esp32/include/soc/rtc.h b/components/esp_hw_support/port/esp32/include/soc/rtc.h index aafa9f65e0..d3a453e4d6 100644 --- a/components/esp_hw_support/port/esp32/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32/include/soc/rtc.h @@ -508,6 +508,7 @@ typedef struct rtc_sleep_config_s { uint32_t dig_dbias_slp : 3; //!< set bias for digital domain, in sleep mode uint32_t rtc_dbias_wak : 3; //!< set bias for RTC domain, in active mode uint32_t rtc_dbias_slp : 3; //!< set bias for RTC domain, in sleep mode + uint32_t dbias_follow_8m : 1; //!< raise voltage if RTC 8MCLK is enabled uint32_t lslp_meminf_pd : 1; //!< remove all peripheral force power up flags uint32_t vddsdio_pd_en : 1; //!< power down VDDSDIO regulator uint32_t xtal_fpu : 1; //!< keep main XTAL powered up in sleep @@ -527,6 +528,9 @@ typedef struct rtc_sleep_config_s { #define RTC_SLEEP_PD_INT_8M BIT(8) //!< Power down Internal 8M oscillator //These flags are not power domains, but will affect some sleep parameters +#if CONFIG_IDF_TARGET_ESP32 +#define RTC_SLEEP_WITH_LOWPOWER_ANALOG BIT(15) //!< Setting analog low power mode in esp32 monitor state, in which analog-related peripherals(ADC, TOUCH) is not used. +#endif #define RTC_SLEEP_DIG_USE_8M BIT(16) #define RTC_SLEEP_USE_ADC_TESEN_MONITOR BIT(17) #define RTC_SLEEP_NO_ULTRA_LOW BIT(18) //!< Avoid using ultra low power in deep sleep, in which RTCIO cannot be used as input, and RTCMEM can't work under high temperature diff --git a/components/esp_hw_support/port/esp32/rtc_sleep.c b/components/esp_hw_support/port/esp32/rtc_sleep.c index 1e51ac04ac..28abed9ae5 100644 --- a/components/esp_hw_support/port/esp32/rtc_sleep.c +++ b/components/esp_hw_support/port/esp32/rtc_sleep.c @@ -116,6 +116,13 @@ void rtc_sleep_get_default_config(uint32_t sleep_flags, rtc_sleep_config_t *out_ out_config->rtc_dbias_slp = !((sleep_flags) & RTC_SLEEP_PD_INT_8M) ? RTC_CNTL_DBIAS_1V10 : RTC_CNTL_DBIAS_0V90; out_config->dbg_atten_slp = RTC_CNTL_DBG_ATTEN_NODROP; } + + if (sleep_flags & RTC_SLEEP_WITH_LOWPOWER_ANALOG) { + out_config->dbias_follow_8m = 0; + } else { + // make sure voltage is raised when RTC 8MCLK is enabled + out_config->dbias_follow_8m = 1; + } } void rtc_sleep_init(rtc_sleep_config_t cfg) @@ -221,6 +228,16 @@ void rtc_sleep_init(rtc_sleep_config_t cfg) REG_CLR_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU); } + if (cfg.dbias_follow_8m) { + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_CORE_FOLW_8M); + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FOLW_8M); + SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_SLEEP_FOLW_8M); + } else { + CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_CORE_FOLW_8M); + CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FOLW_8M); + CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_SLEEP_FOLW_8M); + } + /* enable VDDSDIO control by state machine */ REG_CLR_BIT(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_FORCE); REG_SET_FIELD(RTC_CNTL_SDIO_CONF_REG, RTC_CNTL_SDIO_PD_EN, cfg.vddsdio_pd_en); diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 35fa4292de..635f98f9f9 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -2390,6 +2390,9 @@ int32_t* esp_sleep_sub_mode_dump_config(FILE *stream) { [ESP_SLEEP_DIG_USE_XTAL_MODE] = "ESP_SLEEP_DIG_USE_XTAL_MODE", [ESP_SLEEP_LP_USE_XTAL_MODE] = "ESP_SLEEP_LP_USE_XTAL_MODE", [ESP_SLEEP_VBAT_POWER_DEEPSLEEP_MODE] = "ESP_SLEEP_VBAT_POWER_DEEPSLEEP_MODE", +#if CONFIG_IDF_TARGET_ESP32 + [ESP_SLEEP_ANALOG_LOW_POWER_MODE] = "ESP_SLEEP_ANALOG_LOW_POWER_MODE", +#endif }[mode], s_sleep_sub_mode_ref_cnt[mode] ? "ENABLED" : "DISABLED", s_sleep_sub_mode_ref_cnt[mode]); @@ -2669,6 +2672,12 @@ static SLEEP_FN_ATTR uint32_t get_sleep_flags(uint32_t sleep_flags, bool deepsle } #endif +#if CONFIG_IDF_TARGET_ESP32 + if (s_sleep_sub_mode_ref_cnt[ESP_SLEEP_ANALOG_LOW_POWER_MODE]) { + sleep_flags |= RTC_SLEEP_WITH_LOWPOWER_ANALOG; + } +#endif + #ifdef CONFIG_ESP_SLEEP_RTC_BUS_ISO_WORKAROUND if (!deepsleep) { sleep_flags &= ~RTC_SLEEP_PD_RTC_PERIPH; @@ -2732,6 +2741,13 @@ esp_deep_sleep_disable_rom_logging(void) rtc_suppress_rom_log(); } +#if CONFIG_IDF_TARGET_ESP32 +void esp_sleep_enable_lowpower_analog_mode(bool enable) +{ + esp_sleep_sub_mode_config(ESP_SLEEP_ANALOG_LOW_POWER_MODE, enable); +} +#endif + __attribute__((deprecated("Please use esp_sleep_sub_mode_config instead"))) void esp_sleep_periph_use_8m(bool use_or_not) { if (use_or_not) { diff --git a/components/ulp/ulp_fsm/ulp.c b/components/ulp/ulp_fsm/ulp.c index e03751b0eb..b7e96b1899 100644 --- a/components/ulp/ulp_fsm/ulp.c +++ b/components/ulp/ulp_fsm/ulp.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2010-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2010-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -74,10 +74,7 @@ esp_err_t ulp_run(uint32_t entry_point) CLEAR_PERI_REG_MASK(SENS_SAR_START_FORCE_REG, SENS_ULP_CP_FORCE_START_TOP_M); // set time until wakeup is allowed to the smallest possible REG_SET_FIELD(RTC_CNTL_TIMER5_REG, RTC_CNTL_MIN_SLP_VAL, RTC_CNTL_MIN_SLP_VAL_MIN); - // make sure voltage is raised when RTC 8MCLK is enabled - SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_I2C_FOLW_8M); - SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_CORE_FOLW_8M); - SET_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_SLEEP_FOLW_8M); + // enable ULP timer SET_PERI_REG_MASK(RTC_CNTL_STATE0_REG, RTC_CNTL_ULP_CP_SLP_TIMER_EN); #else