Merge branch 'feat/support_lp_debug_probe' into 'master'

feat(esp_hw_support): support esp32p4 VDD_BAT sleep mode main power control by LP_Probe

Closes IDF-15413

See merge request espressif/esp-idf!46509
This commit is contained in:
Jiang Jiang Jian
2026-05-08 17:23:15 +08:00
20 changed files with 399 additions and 9025 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-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -16,6 +16,10 @@
#include "soc/soc_caps.h"
#include "soc/debug_probe_periph.h"
#include "soc/io_mux_reg.h"
#if SOC_DEBUG_PROBE_NUM_UNIT >= 2 && SOC_LP_GPIO_MATRIX_SUPPORTED
#include "driver/rtc_io.h"
#include "driver/lp_io.h"
#endif
#include "hal/debug_probe_ll.h"
#include "esp_private/debug_probe.h"
#include "esp_private/gpio.h"
@@ -28,9 +32,10 @@ typedef struct debug_probe_unit_t debug_probe_unit_t;
typedef struct debug_probe_channel_t debug_probe_channel_t;
struct debug_probe_unit_t {
int unit_id; // unit id
debug_probe_unit_id_t unit_id; // unit id
debug_probe_channel_t *channels[DEBUG_PROBE_LL_CHANNELS_PER_UNIT]; // channels installed in this unit
uint64_t pin_bit_mask; // bit-mask of the GPIOs used by this unit
uint32_t probe_out_inv_mask; // bit i set = invert i-th probe signal
};
struct debug_probe_channel_t {
@@ -45,9 +50,31 @@ typedef struct debug_probe_platform_t {
static debug_probe_platform_t s_platform; // singleton platform
static esp_err_t connect_probe_out_to_pin(debug_probe_unit_id_t unit_id, int pin, unsigned sig_idx, bool out_inv)
{
if (unit_id == DEBUG_PROBE_UNIT_HP) {
esp_err_t ret = gpio_func_sel((gpio_num_t)pin, PIN_FUNC_GPIO);
if (ret != ESP_OK) {
return ret;
}
esp_rom_gpio_connect_out_signal(pin, debug_probe_periph_signals.units[0].out_sig[sig_idx], out_inv, false);
return ESP_OK;
}
#if SOC_DEBUG_PROBE_NUM_UNIT >= 2
if (!rtc_gpio_is_valid_gpio((gpio_num_t)pin)) {
return ESP_ERR_INVALID_ARG;
}
esp_err_t ret = rtc_gpio_init((gpio_num_t)pin);
return (ret == ESP_OK) ? lp_gpio_connect_out_signal((gpio_num_t)pin,
debug_probe_periph_signals.units[1].out_sig[sig_idx], out_inv, false) : ret;
#else
return ESP_ERR_NOT_SUPPORTED;
#endif
}
static esp_err_t debug_probe_unit_destroy(debug_probe_unit_t *unit)
{
int unit_id = unit->unit_id;
debug_probe_unit_id_t unit_id = unit->unit_id;
// remove the unit from the platform
_lock_acquire(&s_platform.mutex);
@@ -57,6 +84,13 @@ static esp_err_t debug_probe_unit_destroy(debug_probe_unit_t *unit)
// disable the probe output
debug_probe_ll_enable_unit(unit_id, false);
esp_gpio_revoke(unit->pin_bit_mask);
#if SOC_DEBUG_PROBE_NUM_UNIT >= 2
if (unit_id == DEBUG_PROBE_UNIT_LP) {
for (uint64_t m = unit->pin_bit_mask; m; m &= m - 1) {
rtc_gpio_deinit((gpio_num_t)(__builtin_ffsll(m) - 1));
}
}
#endif
// free the memory
free(unit);
return ESP_OK;
@@ -65,21 +99,20 @@ static esp_err_t debug_probe_unit_destroy(debug_probe_unit_t *unit)
esp_err_t debug_probe_new_unit(const debug_probe_unit_config_t *config, debug_probe_unit_handle_t *out_handle)
{
debug_probe_unit_t *unit = NULL;
int unit_id = -1;
ESP_RETURN_ON_FALSE(config && out_handle, ESP_ERR_INVALID_ARG, TAG, "invalid args");
debug_probe_unit_id_t unit_id = config->unit_id;
ESP_RETURN_ON_FALSE(config && out_handle && unit_id < SOC_DEBUG_PROBE_NUM_UNIT, ESP_ERR_INVALID_ARG, TAG, "invalid args");
// search for a free unit slot
/* Check the requested unit slot is free (unit_id from config->unit_id) */
_lock_acquire(&s_platform.mutex);
for (int i = 0; i < SOC_DEBUG_PROBE_NUM_UNIT; i++) {
if (s_platform.units[i] == NULL) {
unit_id = i;
unit = calloc(1, sizeof(debug_probe_unit_t));
s_platform.units[i] = unit;
break;
}
if (s_platform.units[unit_id] != NULL) {
_lock_release(&s_platform.mutex);
ESP_RETURN_ON_FALSE(false, ESP_ERR_NOT_FOUND, TAG, "unit slot in use");
}
unit = calloc(1, sizeof(debug_probe_unit_t));
if (unit) {
s_platform.units[unit_id] = unit;
}
_lock_release(&s_platform.mutex);
ESP_RETURN_ON_FALSE(unit_id >= 0, ESP_ERR_NOT_FOUND, TAG, "no free unit slot");
ESP_RETURN_ON_FALSE(unit, ESP_ERR_NO_MEM, TAG, "no mem for unit");
unit->unit_id = unit_id;
@@ -97,21 +130,32 @@ esp_err_t debug_probe_new_unit(const debug_probe_unit_config_t *config, debug_pr
}
// connect the probe output signals to the GPIOs
esp_err_t ret = ESP_OK;
for (int i = 0; i < SOC_DEBUG_PROBE_MAX_OUTPUT_WIDTH; i++) {
if (config->probe_out_gpio_nums[i] >= 0) {
gpio_func_sel(config->probe_out_gpio_nums[i], PIN_FUNC_GPIO);
esp_rom_gpio_connect_out_signal(config->probe_out_gpio_nums[i],
debug_probe_periph_signals.units[unit_id].out_sig[i],
false, false);
int pin = config->probe_out_gpio_nums[i];
if (pin >= 0) {
bool out_inv = !!(config->probe_out_inv_mask & BIT(i));
ret = connect_probe_out_to_pin(unit_id, pin, (unsigned)i, out_inv);
if (ret != ESP_OK) {
ESP_LOGE(TAG, "Probe out pin %d failed: %s", pin, esp_err_to_name(ret));
break;
}
}
}
if (ret != ESP_OK) {
unit->pin_bit_mask = pin_bit_mask;
(void)debug_probe_unit_destroy(unit);
return ret;
}
unit->pin_bit_mask = pin_bit_mask;
unit->probe_out_inv_mask = config->probe_out_inv_mask;
// enable the probe unit
debug_probe_ll_enable_unit(unit_id, true);
*out_handle = unit;
return ESP_OK;
return ret;
}
esp_err_t debug_probe_del_unit(debug_probe_unit_handle_t unit)
@@ -134,7 +178,7 @@ esp_err_t debug_probe_del_unit(debug_probe_unit_handle_t unit)
static esp_err_t debug_probe_channel_destroy(debug_probe_channel_t *chan)
{
debug_probe_unit_t *unit = chan->unit;
int unit_id = unit->unit_id;
debug_probe_unit_id_t unit_id = unit->unit_id;
int chan_id = chan->chan_id;
// remove the channel from the unit
@@ -154,7 +198,7 @@ esp_err_t debug_probe_new_channel(debug_probe_unit_handle_t unit, const debug_pr
debug_probe_channel_t *chan = NULL;
int chan_id = -1;
ESP_RETURN_ON_FALSE(unit && config && out_handle, ESP_ERR_INVALID_ARG, TAG, "invalid args");
int unit_id = unit->unit_id;
debug_probe_unit_id_t unit_id = unit->unit_id;
// search for a free channel slot
_lock_acquire(&s_platform.mutex);
@@ -173,7 +217,10 @@ esp_err_t debug_probe_new_channel(debug_probe_unit_handle_t unit, const debug_pr
chan->unit = unit;
// one channel can only monitor one target module
debug_probe_ll_channel_set_target_module(unit_id, chan_id, config->target_module);
uint8_t target_module = (unit_id == DEBUG_PROBE_UNIT_HP)
? (uint8_t)config->target_module.hp_target
: (uint8_t)config->target_module.lp_target;
debug_probe_ll_channel_set_target_module(unit_id, chan_id, target_module);
debug_probe_ll_enable_channel(unit_id, chan_id, true);
*out_handle = chan;
@@ -189,9 +236,10 @@ esp_err_t debug_probe_del_channel(debug_probe_channel_handle_t chan)
esp_err_t debug_probe_chan_add_signal_by_byte(debug_probe_channel_handle_t chan, uint8_t byte_idx, uint8_t sig_group)
{
ESP_RETURN_ON_FALSE(chan, ESP_ERR_INVALID_ARG, TAG, "invalid args");
ESP_RETURN_ON_FALSE(byte_idx < 4, ESP_ERR_INVALID_ARG, TAG, "byte_idx out of range");
ESP_RETURN_ON_FALSE(sig_group < 16, ESP_ERR_INVALID_ARG, TAG, "sig_group out of range");
debug_probe_unit_t *unit = chan->unit;
ESP_RETURN_ON_FALSE(byte_idx < ((unit->unit_id == DEBUG_PROBE_UNIT_LP) ? 2 : 4),
ESP_ERR_INVALID_ARG, TAG, "byte_idx out of range");
ESP_RETURN_ON_FALSE(sig_group < 16, ESP_ERR_INVALID_ARG, TAG, "sig_group out of range");
debug_probe_ll_channel_add_signal_group(unit->unit_id, chan->chan_id, byte_idx, sig_group);
return ESP_OK;
}
@@ -199,18 +247,25 @@ esp_err_t debug_probe_chan_add_signal_by_byte(debug_probe_channel_handle_t chan,
esp_err_t debug_probe_unit_merge16(debug_probe_unit_handle_t unit, debug_probe_channel_handle_t chan0, debug_probe_split_u16_t split_of_chan0,
debug_probe_channel_handle_t chan1, debug_probe_split_u16_t split_of_chan1)
{
ESP_RETURN_ON_FALSE(unit && chan0 && chan1, ESP_ERR_INVALID_ARG, TAG, "invalid args");
ESP_RETURN_ON_FALSE(chan0->unit == unit && chan1->unit == unit, ESP_ERR_INVALID_ARG, TAG, "chan not belong to unit");
int unit_id = unit->unit_id;
ESP_RETURN_ON_FALSE(unit && chan0, ESP_ERR_INVALID_ARG, TAG, "invalid args");
ESP_RETURN_ON_FALSE(chan0->unit == unit, ESP_ERR_INVALID_ARG, TAG, "chan0 not belong to unit");
if (chan1 != NULL) {
ESP_RETURN_ON_FALSE(chan1->unit == unit, ESP_ERR_INVALID_ARG, TAG, "chan1 not belong to unit");
}
debug_probe_unit_id_t unit_id = unit->unit_id;
debug_probe_ll_set_lower16_output(unit_id, chan0->chan_id, split_of_chan0);
debug_probe_ll_set_upper16_output(unit_id, chan1->chan_id, split_of_chan1);
if (chan1 != NULL) {
debug_probe_ll_set_upper16_output(unit_id, chan1->chan_id, split_of_chan1);
}
return ESP_OK;
}
esp_err_t debug_probe_unit_read(debug_probe_unit_handle_t unit, uint32_t *value)
{
ESP_RETURN_ON_FALSE(unit && value, ESP_ERR_INVALID_ARG, TAG, "invalid args");
int unit_id = unit->unit_id;
*value = debug_probe_ll_read_output(unit_id);
debug_probe_unit_id_t unit_id = unit->unit_id;
uint32_t raw = debug_probe_ll_read_output(unit_id);
*value = raw ^ unit->probe_out_inv_mask;
return ESP_OK;
}
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -30,7 +30,9 @@ typedef struct debug_probe_channel_t *debug_probe_channel_handle_t;
* @brief Configuration for a debug probe unit
*/
typedef struct {
gpio_num_t probe_out_gpio_nums[DEBUG_PROBE_MAX_OUTPUT_WIDTH]; ///< GPIO numbers for probe output
debug_probe_unit_id_t unit_id; ///< DEBUG_PROBE_UNIT_HP or DEBUG_PROBE_UNIT_LP
gpio_num_t probe_out_gpio_nums[DEBUG_PROBE_MAX_OUTPUT_WIDTH]; ///< GPIO numbers for probe output
uint32_t probe_out_inv_mask; ///< Bit mask: bit i set = invert output for i-th probe signal (default 0 = no inversion)
} debug_probe_unit_config_t;
/**
@@ -60,9 +62,13 @@ esp_err_t debug_probe_del_unit(debug_probe_unit_handle_t unit);
/**
* @brief Configuration for a debug probe channel
* @note Use hp_target for HP unit, lp_target for LP unit
*/
typedef struct {
debug_probe_target_t target_module; ///< Target module of the debug probe channel
union {
debug_probe_target_t hp_target; ///< Target when unit is HP
debug_probe_target_lp_t lp_target; ///< Target when unit is LP
} target_module;
} debug_probe_channel_config_t;
/**
@@ -103,7 +109,7 @@ esp_err_t debug_probe_del_channel(debug_probe_channel_handle_t chan);
* @note You can save up to 32 signals in a channel, but in the end, only the part of them (e.g. upper or lower 16 signals) can be output to the GPIO pads.
*
* @param[in] chan Handle of the debug probe channel
* @param[in] byte_idx Byte index of the signals, ranges from 0 to 3
* @param[in] byte_idx Byte index (HP: 0-3, LP: 0-1)
* @param[in] sig_group Signal group of the signal, ranges from 0 to 15
* @return
* - ESP_OK on success
@@ -128,8 +134,8 @@ esp_err_t debug_probe_chan_add_signal_by_byte(debug_probe_channel_handle_t chan,
* @param[in] unit Handle of the debug probe unit
* @param[in] chan0 Handle of the debug probe channel 0, whose output will be merged to the lower 16 signals of the unit output
* @param[in] split_of_chan0 Part of the channel 0 output to be merged
* @param[in] chan1 Handle of the debug probe channel 1, whose output will be merged to the upper 16 signals of the unit output
* @param[in] split_of_chan1 Part of the channel 1 output to be merged
* @param[in] chan1 Handle of the debug probe channel 1 for upper 16 bits; can be NULL to ignore upper16
* @param[in] split_of_chan1 Part of the channel 1 output (ignored when chan1 is NULL)
* @return
* - ESP_OK on success
* - ESP_ERR_INVALID_ARG if the parameters are invalid
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -20,11 +20,15 @@ extern "C" {
#endif
#if SOC_DEBUG_PROBE_SUPPORTED
#define DEBUG_PROBE_MAX_OUTPUT_WIDTH SOC_DEBUG_PROBE_MAX_OUTPUT_WIDTH
#define DEBUG_PROBE_MAX_OUTPUT_WIDTH SOC_DEBUG_PROBE_MAX_OUTPUT_WIDTH
#define DEBUG_PROBE_GPIO_NUMS_NONE { [0 ... (SOC_DEBUG_PROBE_MAX_OUTPUT_WIDTH - 1)] = -1 }
typedef soc_debug_probe_target_t debug_probe_target_t;
typedef soc_debug_probe_target_lp_t debug_probe_target_lp_t;
#else
#define DEBUG_PROBE_MAX_OUTPUT_WIDTH 16
#define DEBUG_PROBE_MAX_OUTPUT_WIDTH 16
#define DEBUG_PROBE_GPIO_NUMS_NONE { [0 ... 15] = -1 }
typedef int debug_probe_target_t;
typedef int debug_probe_target_lp_t;
#endif
#ifdef __cplusplus
@@ -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
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -15,21 +15,29 @@
TEST_CASE("debug probe install & uninstall", "[debug_probe]")
{
debug_probe_unit_config_t unit_config = {
.probe_out_gpio_nums = {0},
};
debug_probe_unit_handle_t probe_units[SOC_DEBUG_PROBE_NUM_UNIT] = {0};
printf("install debug probe exhaustively\r\n");
for (int i = 0; i < SOC_DEBUG_PROBE_NUM_UNIT; i++) {
debug_probe_unit_config_t unit_config = {
.unit_id = (debug_probe_unit_id_t)i,
.probe_out_gpio_nums = {0},
};
TEST_ESP_OK(debug_probe_new_unit(&unit_config, &probe_units[i]));
}
debug_probe_unit_config_t unit_config = {
.unit_id = DEBUG_PROBE_UNIT_HP,
.probe_out_gpio_nums = {0},
};
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, debug_probe_new_unit(&unit_config, &probe_units[0]));
debug_probe_channel_config_t chan_config = {
.target_module = 1,
};
debug_probe_channel_handle_t probe_chans[SOC_DEBUG_PROBE_NUM_UNIT][DEBUG_PROBE_LL_CHANNELS_PER_UNIT] = {0};
for (int i = 0; i < SOC_DEBUG_PROBE_NUM_UNIT; i++) {
debug_probe_channel_config_t chan_config = {0};
if (i == 0) {
chan_config.target_module.hp_target = DEBUG_PROBE_TARGET_AXI_GDMA;
} else {
chan_config.target_module.lp_target = DEBUG_PROBE_TARGET_LP_PMU;
}
for (int j = 0; j < DEBUG_PROBE_LL_CHANNELS_PER_UNIT; j++) {
TEST_ESP_OK(debug_probe_new_channel(probe_units[i], &chan_config, &probe_chans[i][j]));
}
@@ -47,10 +55,8 @@ TEST_CASE("debug probe install & uninstall", "[debug_probe]")
TEST_CASE("debug probe read", "[debug_probe]")
{
debug_probe_unit_config_t unit_config = {
.probe_out_gpio_nums = {
-1, -1, -1, -1, -1, -1, -1, -1,
-1, -1, -1, -1, -1, -1, -1, -1,
}
.unit_id = DEBUG_PROBE_UNIT_HP,
.probe_out_gpio_nums = DEBUG_PROBE_GPIO_NUMS_NONE,
};
debug_probe_unit_handle_t probe_unit = NULL;
TEST_ESP_OK(debug_probe_new_unit(&unit_config, &probe_unit));
@@ -58,9 +64,8 @@ TEST_CASE("debug probe read", "[debug_probe]")
// allocate two channels from the unit, each channel monitor different target module
debug_probe_channel_handle_t probe_chans[2] = {0};
for (int i = 0; i < 2; i++) {
debug_probe_channel_config_t chan_config = {
.target_module = i + 1,
};
debug_probe_channel_config_t chan_config = {0};
chan_config.target_module.hp_target = (debug_probe_target_t)(i + 1);
TEST_ESP_OK(debug_probe_new_channel(probe_unit, &chan_config, &probe_chans[i]));
// group15[7:0] contains the debug target module ID
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -10,8 +10,8 @@
#include <stdbool.h>
#include "hal/misc.h"
#include "hal/assert.h"
#include "soc/debug_probe_targets.h"
#include "soc/hp_system_struct.h"
#include "soc/lp_system_struct.h"
#include "hal/debug_probe_types.h"
/**
@@ -29,39 +29,58 @@ extern "C" {
/**
* @brief Enable the debug probe module
*
* @param unit_id unit identifier, see debug_probe_unit_id_t
* @param en true: enable, false: disable
*/
static inline void debug_probe_ll_enable_unit(int unit_id, bool en)
static inline void debug_probe_ll_enable_unit(debug_probe_unit_id_t unit_id, bool en)
{
HP_SYSTEM.probea_ctrl.reg_probe_global_en = en;
if (unit_id == DEBUG_PROBE_UNIT_HP) {
HP_SYSTEM.probea_ctrl.reg_probe_global_en = en;
} else {
LP_SYS.lp_probea_ctrl.probe_global_en = en;
}
}
/**
* @brief Enable a specific channel in the debug probe unit
*
* @param unit_id unit identifier, see debug_probe_unit_id_t
* @param channel channel number (only support 0 and 1)
* @param en true: enable, false: disable
*/
static inline void debug_probe_ll_enable_channel(int unit_id, int channel, bool en)
static inline void debug_probe_ll_enable_channel(debug_probe_unit_id_t unit_id, int channel, bool en)
{
// channel 0 is always enabled
if (channel == 1) {
HP_SYSTEM.probeb_ctrl.reg_probe_b_en = en;
if (unit_id == DEBUG_PROBE_UNIT_HP) {
HP_SYSTEM.probeb_ctrl.reg_probe_b_en = en;
} else {
LP_SYS.lp_probeb_ctrl.probe_b_en = en;
}
}
}
/**
* @brief Set the target module for a probe channel
*
* @param unit_id unit identifier, see debug_probe_unit_id_t
* @param channel channel number (only support 0 and 1)
* @param target_module target module, see soc_debug_probe_target_t
* @param target_module HP: soc_debug_probe_target_t, LP: soc_debug_probe_target_lp_t
*/
static inline void debug_probe_ll_channel_set_target_module(int unit_id, uint8_t channel, soc_debug_probe_target_t target_module)
static inline void debug_probe_ll_channel_set_target_module(debug_probe_unit_id_t unit_id, uint8_t channel, uint8_t target_module)
{
if (channel == 0) {
HP_SYSTEM.probea_ctrl.reg_probe_a_top_sel = target_module;
if (unit_id == DEBUG_PROBE_UNIT_HP) {
HP_SYSTEM.probea_ctrl.reg_probe_a_top_sel = target_module;
} else {
LP_SYS.lp_probea_ctrl.probe_a_top_sel = target_module;
}
} else {
HP_SYSTEM.probeb_ctrl.reg_probe_b_top_sel = target_module;
if (unit_id == DEBUG_PROBE_UNIT_HP) {
HP_SYSTEM.probeb_ctrl.reg_probe_b_top_sel = target_module;
} else {
LP_SYS.lp_probeb_ctrl.probe_b_top_sel = target_module;
}
}
}
@@ -74,14 +93,24 @@ static inline void debug_probe_ll_channel_set_target_module(int unit_id, uint8_t
* @param sig_byte_idx signal byte index (0-3)
* @param sig_group signal group (0-15)
*/
static inline void debug_probe_ll_channel_add_signal_group(int unit_id, uint8_t channel, uint8_t sig_byte_idx, uint8_t sig_group)
static inline void debug_probe_ll_channel_add_signal_group(debug_probe_unit_id_t unit_id, uint8_t channel, uint8_t sig_byte_idx, uint8_t sig_group)
{
if (channel == 0) {
HP_SYSTEM.probea_ctrl.reg_probe_a_mod_sel &= ~(0xf << (sig_byte_idx * 4));
HP_SYSTEM.probea_ctrl.reg_probe_a_mod_sel |= (sig_group << (sig_byte_idx * 4));
if (unit_id == DEBUG_PROBE_UNIT_HP) {
if (channel == 0) {
HP_SYSTEM.probea_ctrl.reg_probe_a_mod_sel &= ~(0xf << (sig_byte_idx * 4));
HP_SYSTEM.probea_ctrl.reg_probe_a_mod_sel |= (sig_group << (sig_byte_idx * 4));
} else {
HP_SYSTEM.probeb_ctrl.reg_probe_b_mod_sel &= ~(0xf << (sig_byte_idx * 4));
HP_SYSTEM.probeb_ctrl.reg_probe_b_mod_sel |= (sig_group << (sig_byte_idx * 4));
}
} else {
HP_SYSTEM.probeb_ctrl.reg_probe_b_mod_sel &= ~(0xf << (sig_byte_idx * 4));
HP_SYSTEM.probeb_ctrl.reg_probe_b_mod_sel |= (sig_group << (sig_byte_idx * 4));
if (channel == 0) {
LP_SYS.lp_probea_ctrl.probe_a_mod_sel &= ~(0xf << (sig_byte_idx * 4));
LP_SYS.lp_probea_ctrl.probe_a_mod_sel |= (sig_group << (sig_byte_idx * 4));
} else {
LP_SYS.lp_probeb_ctrl.probe_b_mod_sel &= ~(0xf << (sig_byte_idx * 4));
LP_SYS.lp_probeb_ctrl.probe_b_mod_sel |= (sig_group << (sig_byte_idx * 4));
}
}
}
@@ -90,18 +119,27 @@ static inline void debug_probe_ll_channel_add_signal_group(int unit_id, uint8_t
*
* @param part where does the probe_top_out[15:0] come from
*/
static inline void debug_probe_ll_set_lower16_output(int unit_id, int channel, debug_probe_split_u16_t part)
static inline void debug_probe_ll_set_lower16_output(debug_probe_unit_id_t unit_id, int channel, debug_probe_split_u16_t part)
{
HP_SYSTEM.probea_ctrl.reg_probe_l_sel = channel * 2 + DEBUG_PROBE_LL_PART_TO_REG_VAL(part);
uint8_t val = (uint8_t)(channel * 2 + DEBUG_PROBE_LL_PART_TO_REG_VAL(part));
if (unit_id == DEBUG_PROBE_UNIT_HP) {
HP_SYSTEM.probea_ctrl.reg_probe_l_sel = val;
} else {
LP_SYS.lp_probea_ctrl.probe_l_sel = val;
}
}
/**
* @brief Set the upper 16 bits of the probe output
*
* @param part where does the probe_top_out[31:16] come from
* @note No-op for LP unit: only 16 bits are routed to LP GPIO, so upper 16 selection has no effect.
*/
static inline void debug_probe_ll_set_upper16_output(int unit_id, int channel, debug_probe_split_u16_t part)
static inline void debug_probe_ll_set_upper16_output(debug_probe_unit_id_t unit_id, int channel, debug_probe_split_u16_t part)
{
if (unit_id != DEBUG_PROBE_UNIT_HP) {
return; /* LP has only 16 bits to GPIO; probe_top_out[31:16] is not routed */
}
HP_SYSTEM.probea_ctrl.reg_probe_h_sel = channel * 2 + DEBUG_PROBE_LL_PART_TO_REG_VAL(part);
}
@@ -112,9 +150,13 @@ static inline void debug_probe_ll_set_upper16_output(int unit_id, int channel,
*
* @return the value that currently being probed
*/
static inline uint32_t debug_probe_ll_read_output(int unit_id)
static inline uint32_t debug_probe_ll_read_output(debug_probe_unit_id_t unit_id)
{
return HP_SYSTEM.probe_out.reg_probe_top_out;
if (unit_id == DEBUG_PROBE_UNIT_HP) {
return HP_SYSTEM.probe_out.reg_probe_top_out;
} else {
return LP_SYS.lp_probe_out.probe_top_out;
}
}
#ifdef __cplusplus
+10 -1
View File
@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -10,6 +10,15 @@
extern "C" {
#endif
/**
* @brief Debug probe unit identifier (HP vs LP)
*/
typedef enum {
DEBUG_PROBE_UNIT_HP = 0,
DEBUG_PROBE_UNIT_LP = 1,
} debug_probe_unit_id_t;
/**
* @brief The 32bit debug probe output can be split into two 16bit parts
*/
+22 -1
View File
@@ -1,10 +1,11 @@
/*
* SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0 OR MIT
*/
#include "soc/gpio_sig_map.h"
#include "soc/lp_gpio_sig_map.h"
#include "soc/debug_probe_periph.h"
const debug_probe_signal_conn_t debug_probe_periph_signals = {
@@ -28,6 +29,26 @@ const debug_probe_signal_conn_t debug_probe_periph_signals = {
[14] = HP_PROBE_TOP_OUT14_IDX,
[15] = HP_PROBE_TOP_OUT15_IDX,
}
},
[1] = {
.out_sig = {
[0] = LP_PROBE_TOP_OUT0_IDX,
[1] = LP_PROBE_TOP_OUT1_IDX,
[2] = LP_PROBE_TOP_OUT2_IDX,
[3] = LP_PROBE_TOP_OUT3_IDX,
[4] = LP_PROBE_TOP_OUT4_IDX,
[5] = LP_PROBE_TOP_OUT5_IDX,
[6] = LP_PROBE_TOP_OUT6_IDX,
[7] = LP_PROBE_TOP_OUT7_IDX,
[8] = LP_PROBE_TOP_OUT8_IDX,
[9] = LP_PROBE_TOP_OUT9_IDX,
[10] = LP_PROBE_TOP_OUT10_IDX,
[11] = LP_PROBE_TOP_OUT11_IDX,
[12] = LP_PROBE_TOP_OUT12_IDX,
[13] = LP_PROBE_TOP_OUT13_IDX,
[14] = LP_PROBE_TOP_OUT14_IDX,
[15] = LP_PROBE_TOP_OUT15_IDX,
}
}
}
};
@@ -745,7 +745,7 @@ config SOC_CLOCKOUT_SUPPORT_CHANNEL_DIVIDER
config SOC_DEBUG_PROBE_NUM_UNIT
int
default 1
default 2
config SOC_DEBUG_PROBE_MAX_OUTPUT_WIDTH
int
@@ -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
@@ -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 OR MIT
*/
@@ -49,6 +49,23 @@ typedef enum {
DEBUG_PROBE_TARGET_PVT = 30, // PVT
} soc_debug_probe_target_t;
/**
* @brief LP probe target module (probe_a_top_sel 0..10)
*/
typedef enum {
DEBUG_PROBE_TARGET_LP_PMU = 0, // LP PMU
DEBUG_PROBE_TARGET_LP_TCM_RAM = 1, // LP TCM RAM
DEBUG_PROBE_TARGET_LP_TCM_ROM = 2, // LP TCM ROM
DEBUG_PROBE_TARGET_LP_CORE = 3, // LP Core
DEBUG_PROBE_TARGET_LP_ADC = 4, // LP ADC
DEBUG_PROBE_TARGET_LP_SPI = 5, // LP SPI
DEBUG_PROBE_TARGET_LP_TOUCH = 6, // LP Touch
DEBUG_PROBE_TARGET_LP_ANA_PERI = 7, // LP Analog Peripherals
DEBUG_PROBE_TARGET_LP_AON_CLKRST = 8, // LP AON Clock/Reset
DEBUG_PROBE_TARGET_LP_SYS_MISC = 9, // LP System Misc
DEBUG_PROBE_TARGET_LP_SYS_PROBE_IN = 10, // LP System Probe In
} soc_debug_probe_target_lp_t;
#ifdef __cplusplus
}
#endif
@@ -285,7 +285,7 @@
#define SOC_GPIO_CLOCKOUT_CHANNEL_NUM (2)
#define SOC_CLOCKOUT_SUPPORT_CHANNEL_DIVIDER (1)
#define SOC_DEBUG_PROBE_NUM_UNIT (1U) // Number of debug probe units
#define SOC_DEBUG_PROBE_NUM_UNIT (2U) // Unit 0: HP probe, Unit 1: LP probe
#define SOC_DEBUG_PROBE_MAX_OUTPUT_WIDTH (16) // Maximum width of the debug probe output in each unit
/*-------------------------- RTCIO CAPS --------------------------------------*/
@@ -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