feat(esp_hw_support): support main power control during VBAT powered deep sleep

This commit is contained in:
wuzhenghui
2026-05-08 14:24:35 +08:00
parent 5c2e3b768e
commit 799669c7a4
9 changed files with 117 additions and 8945 deletions
@@ -634,12 +634,36 @@ FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_digital_power_down_wait_cycle(pmu_dev_t
FORCE_INLINE_ATTR void pmu_ll_lp_set_analog_wait_target_cycle(pmu_dev_t *hw, uint32_t slow_clk_cycle)
{
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
HAL_ASSERT(slow_clk_cycle <= 1020);
uint32_t target = 0, expand = 0;
if (slow_clk_cycle <= 255) {
target = slow_clk_cycle;
expand = 0;
} else if (slow_clk_cycle <= 510) {
expand = 1;
target = (slow_clk_cycle + 1) >> 1;
} else if (slow_clk_cycle <= 1020) {
expand = 2;
target = (slow_clk_cycle + 3) >> 2;
}
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target, target);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target_expand, expand);
#else
HAL_ASSERT(slow_clk_cycle <= 255);
HAL_FORCE_MODIFY_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target, slow_clk_cycle);
#endif
}
FORCE_INLINE_ATTR uint32_t pmu_ll_lp_get_analog_wait_target_cycle(pmu_dev_t *hw)
{
#if HAL_CONFIG(CHIP_SUPPORT_MIN_REV) >= 300
uint32_t target = HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target);
uint32_t expand = HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target_expand);
return target << expand;
#else
return HAL_FORCE_READ_U32_REG_FIELD(hw->wakeup.cntl5, lp_ana_wait_target);
#endif
}
FORCE_INLINE_ATTR void pmu_ll_set_xtal_stable_wait_cycle(pmu_dev_t *hw, uint32_t cycle)
@@ -28,6 +28,8 @@ typedef enum {
#define VBAT_LL_CHARGER_MASK (BIT(27)|BIT(28))
#define VBAT_LL_DETECT_MASK (BIT(30))
#define VBAT_LL_LP_SLEEP_PROBE_ID (9)
#ifdef __cplusplus
extern "C" {
#endif
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -237,7 +237,7 @@ typedef struct {
typedef struct {
uint16_t digital_power_supply_wait_cycle;
uint8_t min_slp_slow_clk_cycle;
uint8_t analog_wait_target_cycle;
uint16_t analog_wait_target_cycle;
uint8_t digital_power_down_wait_cycle;
uint8_t digital_power_up_wait_cycle;
} pmu_lp_param_t;
@@ -526,11 +526,21 @@ typedef struct pmu_sleep_machine_constant {
// DCDC startup, which saves more power compared to waiting in the Active state.
#define PMU_HP_ANA_WAIT_TIME_PU_TOP_US (PMU_HP_ANA_WAIT_TIME_PD_TOP_US + PMU_REGDMA_S2A_WORK_TIME_US) // 945
#ifndef MAX
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#endif
#if CONFIG_ESP_VBAT_CONTROL_MAIN_POWER_IN_DSLP
#define PMU_LP_ANA_WAIT_TIME_US MAX(154, CONFIG_ESP_VBAT_MAIN_POWER_WAKEUP_ADVANCE_US)
#else
#define PMU_LP_ANA_WAIT_TIME_US 154
#endif
#define PMU_SLEEP_MC_DEFAULT() { \
.lp = { \
.min_slp_time_us = 450, \
.wakeup_wait_cycle = 4, \
.analog_wait_time_us = 154, \
.analog_wait_time_us = PMU_LP_ANA_WAIT_TIME_US, \
.xtal_wait_stable_time_us = 250, \
.clk_switch_cycle = 1, \
.clk_power_on_wait_cycle = 1, \
@@ -200,6 +200,48 @@ menu "Power Supplier"
help
The resistor value of charger circuit.
config ESP_VBAT_CONTROL_MAIN_POWER_IN_DSLP
bool "Control main power (ESP_3V3) enable via GPIO when VBAT powers deep sleep"
default n
depends on ESP_VBAT_INIT_AUTO && SOC_MAIN_POWER_CONTROL_SUPPORTED
help
When enabled, after the chip enters deep sleep and switches to VDD_BAT (VBAT)
power, ESP_VBAT_MAIN_POWER_CTRL_PIN is used to disable the main power (ESP_3V3)
enable. The main power is re-enabled in advance before wakeup.
config ESP_VBAT_MAIN_POWER_CTRL_PIN
int "GPIO for main power (ESP_3V3) enable"
default 2
range 0 3 if !RTC_CLK_SRC_EXT_CRYS
range 2 3 if RTC_CLK_SRC_EXT_CRYS
depends on ESP_VBAT_CONTROL_MAIN_POWER_IN_DSLP
help
RTC GPIO used to enable/disable the main power rail (ESP_3V3) when VBAT is active.
config ESP_VBAT_MAIN_POWER_CTRL_PIN_INV
bool "Invert main power control pin output (Output high to enable power by default)"
default n
depends on ESP_VBAT_CONTROL_MAIN_POWER_IN_DSLP
help
When enabled, the ESP_VBAT_MAIN_POWER_CTRL_PIN logic for the main power control
pin is inverted. (n: output high to enable power; y = output low to enable power).
config ESP_VBAT_MAIN_POWER_WAKEUP_ADVANCE_US
int "Main power enable advance time before wakeup (us)"
default 1000
range 0 1500 if !RTC_CLK_SRC_EXT_CRYS && ESP32P4_SELECTS_REV_LESS_V3
range 0 7500 if RTC_CLK_SRC_EXT_CRYS && ESP32P4_SELECTS_REV_LESS_V3
range 0 6000 if !RTC_CLK_SRC_EXT_CRYS && !ESP32P4_SELECTS_REV_LESS_V3
range 0 30000 if RTC_CLK_SRC_EXT_CRYS && !ESP32P4_SELECTS_REV_LESS_V3
depends on ESP_VBAT_CONTROL_MAIN_POWER_IN_DSLP
help
Advance time in microseconds to assert main power (ESP_3V3) enable before the
chip starts the wakeup sequence and switches to main voltage supply. The delay
allows the external main power rail to reach target voltage before chip exits
deep sleep. Set this value to be greater than or equal to your main power
supply's startup/settling time (from enable assertion to stable output voltage).
If too small, the main rail may not be ready when the chip wakes, which can
cause brownout or unstable boot.
endmenu
endmenu
+30 -2
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -15,6 +15,7 @@
#include "hal/vbat_hal.h"
#include "freertos/FreeRTOS.h"
#include "sdkconfig.h"
#include "esp_private/debug_probe.h"
#include "esp_private/esp_sleep_internal.h"
#include "esp_private/startup_internal.h"
#include "esp_private/rtc_ctrl.h"
@@ -46,6 +47,10 @@
#define VBAT_CHARGER_HYSTERESIS_THRESHOLD_HIGH (VBAT_CHARGER_HYSTERESIS_THRESHOLD_LOW + (VBAT_CHARGER_FILTER_TIME_US * SOC_CLK_RC_FAST_FREQ_APPROX) / MHZ)
#endif
#if CONFIG_ESP_VBAT_CONTROL_MAIN_POWER_IN_DSLP
#define ESP_3V3_CTRL_PIN CONFIG_ESP_VBAT_MAIN_POWER_CTRL_PIN
#endif
#if CONFIG_ESP_VBAT_USE_RECHARGEABLE_BATTERY
#if (VBAT_CHARGER_RESISTOR_VALUE < 1000 || VBAT_CHARGER_RESISTOR_VALUE > 4500 || VBAT_CHARGER_RESISTOR_VALUE % 500 != 0)
#error "vbat charger resistor (ESP_VBAT_CHARGER_CIRCUIT_RESISTOR_VAL) must be between 1000 and 4500 ohms and must be a multiple of 500."
@@ -54,7 +59,7 @@
#if (VBAT_BROWNOUT_DET_LVL >= VBAT_CHARGE_DET_LVL_LOW)
#error "vbat charger low threshold is equal or lower than vbat brownout threshold, please put vbat brownout threshold lower than vbat charger low threshold"
#endif
#endif
#endif // CONFIG_ESP_VBAT_INIT_AUTO
ESP_LOG_ATTR_TAG(TAG, "VBAT");
#endif
@@ -171,6 +176,29 @@ esp_err_t esp_vbat_init(void)
esp_sleep_sub_mode_force_disable(ESP_SLEEP_VBAT_POWER_DEEPSLEEP_MODE);
esp_sleep_sub_mode_config(ESP_SLEEP_VBAT_POWER_DEEPSLEEP_MODE, true);
esp_sleep_enable_vbat_under_volt_wakeup();
#if CONFIG_ESP_VBAT_CONTROL_MAIN_POWER_IN_DSLP
if (esp_reset_reason() != ESP_RST_DEEPSLEEP) {
debug_probe_unit_handle_t lp_probe_hdl;
debug_probe_unit_config_t unit_config = {
.unit_id = DEBUG_PROBE_UNIT_LP,
.probe_out_gpio_nums = DEBUG_PROBE_GPIO_NUMS_NONE,
};
debug_probe_channel_config_t chan_config = {0};
debug_probe_channel_handle_t lp_probe_channel_hdl;
chan_config.target_module.lp_target = DEBUG_PROBE_TARGET_LP_PMU;
unit_config.probe_out_gpio_nums[VBAT_LL_LP_SLEEP_PROBE_ID] = ESP_3V3_CTRL_PIN;
#if !CONFIG_ESP_VBAT_MAIN_POWER_CTRL_PIN_INV
unit_config.probe_out_inv_mask |= BIT(VBAT_LL_LP_SLEEP_PROBE_ID);
#endif
ESP_ERROR_CHECK(debug_probe_new_unit(&unit_config, &lp_probe_hdl));
ESP_ERROR_CHECK(debug_probe_new_channel(lp_probe_hdl, &chan_config, &lp_probe_channel_hdl));
ESP_ERROR_CHECK(debug_probe_chan_add_signal_by_byte(lp_probe_channel_hdl, 1, DEBUG_PROBE_TARGET_LP_PMU));
ESP_ERROR_CHECK(debug_probe_unit_merge16(lp_probe_hdl, lp_probe_channel_hdl, DEBUG_PROBE_SPLIT_UPPER16, NULL, 0));
}
// The LP Probe & LP IOMUX pathways depend on the LP_PERIPH power domain.
esp_sleep_pd_config(ESP_PD_DOMAIN_RTC_PERIPH, ESP_PD_OPTION_ON);
#endif
return ESP_OK;
}
#endif
@@ -1811,6 +1811,10 @@ config SOC_PM_RETENTION_MODULE_NUM
int
default 64
config SOC_MAIN_POWER_CONTROL_SUPPORTED
bool
default y
config SOC_CLK_RC_FAST_SUPPORT_CALIBRATION
bool
default y
@@ -686,6 +686,8 @@
#define SOC_PM_RETENTION_MODULE_NUM (64)
#define SOC_MAIN_POWER_CONTROL_SUPPORTED (1) /*!<Supports outputting an enable signal to control the power-on and power-off of the main power supply when powered by VBAT.*/
/*-------------------------- CLOCK SUBSYSTEM CAPS ----------------------------------------*/
#define SOC_CLK_RC_FAST_SUPPORT_CALIBRATION (1)
File diff suppressed because it is too large Load Diff
File diff suppressed because it is too large Load Diff