feat(esp_hw_support): support enable analog lowpower mode by API

Closes https://github.com/espressif/esp-idf/issues/7882
This commit is contained in:
wuzhenghui
2025-06-08 11:28:57 +08:00
parent 0fa5b07c7e
commit e55d6d8b3c
7 changed files with 56 additions and 5 deletions

View File

@@ -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;

View File

@@ -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;

View File

@@ -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

View File

@@ -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

View File

@@ -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);

View File

@@ -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) {

View File

@@ -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