Merge branch 'feat/support_esp32c5_rtc_wdt_in_sleep' into 'master'

feat(esp_hw_support): support rtc wdt during light or deep sleep

Closes PM-609, PM-654, IDFCI-5140, IDFCI-4784, IDFCI-4785, IDFCI-5139, and IDFCI-5050

See merge request espressif/esp-idf!43167
This commit is contained in:
He Binglin
2026-01-21 22:33:57 +08:00
33 changed files with 298 additions and 20 deletions

View File

@@ -20,7 +20,7 @@
/* Functions */
wdt_hal_init = 0x4fc001fc;
wdt_hal_deinit = 0x4fc00200;
wdt_hal_config_stage = 0x4fc00204;
rom_wdt_hal_config_stage = 0x4fc00204;
wdt_hal_write_protect_disable = 0x4fc00208;
wdt_hal_write_protect_enable = 0x4fc0020c;
wdt_hal_enable = 0x4fc00210;

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2022-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2022-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -113,4 +113,17 @@ void wdt_hal_deinit(wdt_hal_context_t *hal)
//Deinit HAL context
hal->mwdt_dev = NULL;
}
#if SOC_IS(ESP32P4)
extern void rom_wdt_hal_config_stage(wdt_hal_context_t *hal, wdt_stage_t stage, uint32_t timeout, wdt_stage_action_t behavior);
/* rwdt_ll_config_stage is implemented erroneously in ESP32P4 rom code, TODO: PM-654*/
void wdt_hal_config_stage(wdt_hal_context_t *hal, wdt_stage_t stage, uint32_t timeout_ticks, wdt_stage_action_t behavior)
{
if (hal->inst == WDT_RWDT && stage == WDT_STAGE0) {
timeout_ticks = timeout_ticks >> (1 + REG_GET_FIELD(EFUSE_RD_REPEAT_DATA1_REG, EFUSE_WDT_DELAY_SEL));
}
rom_wdt_hal_config_stage(hal, stage, timeout_ticks, behavior);
}
#endif // SOC_IS(ESP32P4)
#endif // ESP_ROM_WDT_INIT_PATCH

View File

@@ -272,6 +272,34 @@ menu "Hardware Settings"
to configure the value of tRES1, different types of flash require different tRES1 values, usually no
more than 35us, please refer to the datasheet of the used Flash to configure this option.
config ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP
bool "Enable rtc wdt during sleep (EXPERIMENTAL)"
depends on IDF_EXPERIMENTAL_FEATURES
depends on (SOC_LIGHT_SLEEP_SUPPORTED || SOC_DEEP_SLEEP_SUPPORTED)
default n
help
If enabled, rtc watchdog will remain active during sleep to prevent program runaway. Specifically, its
timeout will be set as the sum of the sleep duration, hardware overhead time, and RTC slow clock
compensation time.
NOTE: This feature only works when a timer wakeup is used. In the current phase, the RTC slow clock
compensation time remains zero (pending implementation). When using the RC_SLOW_CLK clock without
calibration, the maximum continuous sleep duration is typically around 5 minutes, and may vary
between chips. Therefore, avoid configuring sleep periods longer than this when enabling this option.
config ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP
bool "Enable rtc wdt during deep sleep (EXPERIMENTAL)"
depends on IDF_EXPERIMENTAL_FEATURES
depends on SOC_DEEP_SLEEP_SUPPORTED
default n
help
If enabled, rtc watchdog will remain active during deep sleep to prevent program runaway.
NOTE: This feature only works when a timer wakeup is used. In the current phase, the RTC watchdog
will not be disabled or reset after waking from deep sleep. Even though it will be reconfigured
during the bootloader phase, there remains a concern that a timeout could occur before this
reconfiguration is completed.
endmenu
menu "RTC Clock Config"

View File

@@ -47,6 +47,7 @@ typedef enum {
#define RTC_SLEEP_PD_MODEM PMU_SLEEP_PD_MODEM //!< Power down modem(include wifi, ble and 15.4)
//These flags are not power domains, but will affect some sleep parameters
#define RTC_SLEEP_USE_RTC_WDT BIT(23)
#define RTC_SLEEP_FLASH_DPD BIT(24)
#define RTC_SLEEP_LP_PERIPH_USE_RC_FAST BIT(25)
#define RTC_SLEEP_POWER_BY_VBAT BIT(26)

View File

@@ -510,6 +510,7 @@ typedef struct rtc_sleep_config_s {
uint32_t deep_slp_reject : 1; //!< enable deep sleep reject
uint32_t light_slp_reject : 1; //!< enable light sleep reject
uint32_t dbg_atten_slp : 2; //!< voltage parameter
uint32_t rtc_wdt_en : 1; //!< enable rtc wdt, in sleep mode
} rtc_sleep_config_t;
#define RTC_SLEEP_PD_DIG BIT(0) //!< Deep sleep (power down digital domain)
@@ -531,6 +532,7 @@ typedef struct rtc_sleep_config_s {
#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
#define RTC_SLEEP_XTAL_AS_RTC_FAST BIT(19)
#define RTC_SLEEP_FLASH_DPD BIT(20)
#define RTC_SLEEP_USE_RTC_WDT BIT(21)
/**
* Default initializer for rtc_sleep_config_t
*

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -15,6 +15,7 @@
#include "esp32/rom/ets_sys.h"
#include "esp32/rom/rtc.h"
#include "hal/rtc_cntl_ll.h"
#include "hal/rwdt_ll.h"
#include "esp_rom_sys.h"
#define MHZ (1000000)
@@ -122,6 +123,12 @@ void rtc_sleep_get_default_config(uint32_t sleep_flags, rtc_sleep_config_t *out_
// make sure voltage is raised when RTC 8MCLK is enabled
out_config->dbias_follow_8m = 1;
}
if (sleep_flags & RTC_SLEEP_USE_RTC_WDT) {
out_config->rtc_wdt_en = 1;
} else {
out_config->rtc_wdt_en = 0;
}
}
void rtc_sleep_init(rtc_sleep_config_t cfg)
@@ -237,6 +244,11 @@ void rtc_sleep_init(rtc_sleep_config_t cfg)
CLEAR_PERI_REG_MASK(RTC_CNTL_OPTIONS0_REG, RTC_CNTL_BIAS_SLEEP_FOLW_8M);
}
/* enable rtc wdt during sleep */
rwdt_ll_write_protect_disable(RWDT_DEV_GET());
rwdt_ll_set_pause_in_sleep_en(RWDT_DEV_GET(), !cfg.rtc_wdt_en);
rwdt_ll_write_protect_enable(RWDT_DEV_GET());
/* 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

@@ -555,6 +555,7 @@ typedef struct {
uint32_t rtc_regulator_fpu : 1; //!< keep rtc regulator powered up in sleep
uint32_t deep_slp_reject : 1; //!< enable deep sleep reject
uint32_t light_slp_reject : 1; //!< enable light sleep reject
uint32_t rtc_wdt_en : 1; //!< enable rtc wdt, in sleep mode
} rtc_sleep_config_t;
#define RTC_SLEEP_PD_DIG BIT(0) //!< Deep sleep (power down digital domain)
@@ -568,6 +569,7 @@ typedef struct {
#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
#define RTC_SLEEP_XTAL_AS_RTC_FAST BIT(19)
#define RTC_SLEEP_FLASH_DPD BIT(20)
#define RTC_SLEEP_USE_RTC_WDT BIT(21)
/**
* Default initializer for rtc_sleep_config_t

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -21,6 +21,7 @@
#include "regi2c_ctrl.h"
#include "soc/regi2c_lp_bias.h"
#include "soc/regi2c_dig_reg.h"
#include "hal/rwdt_ll.h"
static const DRAM_ATTR rtc_sleep_pu_config_t pu_cfg = RTC_SLEEP_PU_CONFIG_ALL(1);
@@ -141,6 +142,12 @@ void rtc_sleep_get_default_config(uint32_t sleep_flags, rtc_sleep_config_t *out_
out_config->bias_sleep_slp = RTC_CNTL_BIASSLP_SLEEP_DEFAULT;
out_config->pd_cur_slp = RTC_CNTL_PD_CUR_SLEEP_DEFAULT;
}
if (sleep_flags & RTC_SLEEP_USE_RTC_WDT) {
out_config->rtc_wdt_en = 1;
} else {
out_config->rtc_wdt_en = 0;
}
}
void rtc_sleep_init(rtc_sleep_config_t cfg)
@@ -182,6 +189,11 @@ void rtc_sleep_init(rtc_sleep_config_t cfg)
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_NOGATING);
}
/* enable rtc wdt during sleep */
rwdt_ll_write_protect_disable(RWDT_DEV_GET());
rwdt_ll_set_pause_in_sleep_en(RWDT_DEV_GET(), !cfg.rtc_wdt_en);
rwdt_ll_write_protect_enable(RWDT_DEV_GET());
/* enable VDDSDIO control by state machine */
REG_CLR_BIT(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_VDD_SPI_PWR_FORCE);
REG_SET_FIELD(RTC_CNTL_DIG_PWC_REG, RTC_CNTL_VDD_SPI_PD_EN, cfg.vddsdio_pd_en);

View File

@@ -595,6 +595,7 @@ typedef struct {
uint32_t rtc_regulator_fpu : 1; //!< keep rtc regulator powered up in sleep
uint32_t deep_slp_reject : 1; //!< enable deep sleep reject
uint32_t light_slp_reject : 1; //!< enable light sleep reject
uint32_t rtc_wdt_en : 1; //!< enable rtc wdt, in sleep mode
} rtc_sleep_config_t;
#define RTC_SLEEP_PD_DIG BIT(0) //!< Deep sleep (power down digital domain)
@@ -616,6 +617,7 @@ typedef struct {
#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
#define RTC_SLEEP_XTAL_AS_RTC_FAST BIT(19)
#define RTC_SLEEP_FLASH_DPD BIT(20)
#define RTC_SLEEP_USE_RTC_WDT BIT(21)
/**
* Default initializer for rtc_sleep_config_t

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -24,6 +24,7 @@
#include "soc/regi2c_dig_reg.h"
#include "soc/regi2c_lp_bias.h"
#include "hal/efuse_hal.h"
#include "hal/rwdt_ll.h"
#if SOC_SLEEP_SYSTIMER_STALL_WORKAROUND
#include "soc/systimer_reg.h"
#endif
@@ -166,6 +167,12 @@ void rtc_sleep_get_default_config(uint32_t sleep_flags, rtc_sleep_config_t *out_
out_config->bias_sleep_slp = RTC_CNTL_BIASSLP_SLEEP_DEFAULT;
out_config->pd_cur_slp = RTC_CNTL_PD_CUR_SLEEP_DEFAULT;
}
if (sleep_flags & RTC_SLEEP_USE_RTC_WDT) {
out_config->rtc_wdt_en = 1;
} else {
out_config->rtc_wdt_en = 0;
}
}
void rtc_sleep_init(rtc_sleep_config_t cfg)
@@ -233,6 +240,11 @@ void rtc_sleep_init(rtc_sleep_config_t cfg)
CLEAR_PERI_REG_MASK(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_NOGATING);
}
/* enable rtc wdt during sleep */
rwdt_ll_write_protect_disable(RWDT_DEV_GET());
rwdt_ll_set_pause_in_sleep_en(RWDT_DEV_GET(), !cfg.rtc_wdt_en);
rwdt_ll_write_protect_enable(RWDT_DEV_GET());
/* 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

@@ -316,6 +316,7 @@ static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_c
{
pmu_ll_hp_set_icg_sysclk_enable(ctx->hal->dev, HP(SLEEP), (dig->icg_func != 0));
pmu_ll_hp_set_icg_func(ctx->hal->dev, HP(SLEEP), dig->icg_func);
pmu_ll_hp_set_pause_watchdog(ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pause_wdt);
if (!dslp) {
pmu_ll_hp_set_dig_pad_slp_sel(ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel);
}

View File

@@ -330,6 +330,7 @@ typedef struct {
#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \
.syscntl = { \
.dig_pad_slp_sel = ((sleep_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
}, \
.icg_func = clk_flags \
}
@@ -337,6 +338,7 @@ typedef struct {
#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \
.syscntl = { \
.dig_pad_slp_sel = 1, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
}, \
.icg_func = 0 \
}

View File

@@ -307,6 +307,7 @@ static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_c
{
pmu_ll_hp_set_icg_sysclk_enable(ctx->hal->dev, HP(SLEEP), (dig->icg_func != 0));
pmu_ll_hp_set_icg_func(ctx->hal->dev, HP(SLEEP), dig->icg_func);
pmu_ll_hp_set_pause_watchdog(ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pause_wdt);
if (!dslp) {
pmu_ll_hp_set_dig_pad_slp_sel(ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel);
}

View File

@@ -326,6 +326,7 @@ typedef struct {
#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \
.syscntl = { \
.dig_pad_slp_sel = ((sleep_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
}, \
.icg_func = clk_flags \
}
@@ -333,6 +334,7 @@ typedef struct {
#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \
.syscntl = { \
.dig_pad_slp_sel = 1, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
}, \
.icg_func = 0 \
}

View File

@@ -293,6 +293,7 @@ static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_c
{
pmu_ll_hp_set_icg_sysclk_enable(ctx->hal->dev, HP(SLEEP), (dig->icg_func != 0));
pmu_ll_hp_set_icg_func(ctx->hal->dev, HP(SLEEP), dig->icg_func);
pmu_ll_hp_set_pause_watchdog(ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pause_wdt);
if (!dslp) {
pmu_ll_hp_set_dig_pad_slp_sel(ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel);
}

View File

@@ -326,6 +326,7 @@ typedef struct {
#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \
.syscntl = { \
.dig_pad_slp_sel = ((sleep_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
}, \
.icg_func = clk_flags \
}
@@ -333,6 +334,7 @@ typedef struct {
#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \
.syscntl = { \
.dig_pad_slp_sel = 1, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
}, \
.icg_func = 0 \
}

View File

@@ -198,6 +198,7 @@ static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_c
{
pmu_ll_hp_set_icg_sysclk_enable(ctx->hal->dev, HP(SLEEP), (dig->icg_func != 0));
pmu_ll_hp_set_icg_func(ctx->hal->dev, HP(SLEEP), dig->icg_func);
pmu_ll_hp_set_pause_watchdog(ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pause_wdt);
if (!dslp) {
pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel);
}

View File

@@ -318,6 +318,7 @@ typedef struct {
#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \
.syscntl = { \
.dig_pad_slp_sel = ((sleep_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
}, \
.icg_func = clk_flags \
}
@@ -325,6 +326,7 @@ typedef struct {
#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \
.syscntl = { \
.dig_pad_slp_sel = 1, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
}, \
.icg_func = 0 \
}

View File

@@ -211,6 +211,7 @@ static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_c
{
pmu_ll_hp_set_icg_sysclk_enable(ctx->hal->dev, HP(SLEEP), (dig->icg_func != 0));
pmu_ll_hp_set_icg_func(ctx->hal->dev, HP(SLEEP), dig->icg_func);
pmu_ll_hp_set_pause_watchdog(ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pause_wdt);
if (!dslp) {
pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel);
}

View File

@@ -351,6 +351,7 @@ typedef struct {
#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \
.syscntl = { \
.dig_pad_slp_sel = ((sleep_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
}, \
.icg_func = clk_flags \
}
@@ -358,6 +359,7 @@ typedef struct {
#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \
.syscntl = { \
.dig_pad_slp_sel = 1, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
}, \
.icg_func = 0 \
}

View File

@@ -197,6 +197,7 @@ static void pmu_sleep_power_init(pmu_context_t *ctx, const pmu_sleep_power_confi
static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_config_t *dig, bool dslp)
{
pmu_ll_hp_set_pause_watchdog(ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pause_wdt);
pmu_ll_hp_set_icg_sysclk_enable(ctx->hal->dev, HP(SLEEP), (dig->icg_func != 0));
pmu_ll_hp_set_icg_func(ctx->hal->dev, HP(SLEEP), dig->icg_func);
if (!dslp) {

View File

@@ -358,6 +358,7 @@ typedef struct {
#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \
.syscntl = { \
.dig_pad_slp_sel = ((sleep_flags) & PMU_SLEEP_PD_TOP) ? 0 : 1, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
}, \
.icg_func = clk_flags \
}
@@ -365,6 +366,7 @@ typedef struct {
#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags, clk_flags) { \
.syscntl = { \
.dig_pad_slp_sel = 1, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
}, \
.icg_func = 0 \
}

View File

@@ -267,6 +267,7 @@ static void pmu_sleep_digital_init(pmu_context_t *ctx, const pmu_sleep_digital_c
{
pmu_ll_hp_set_dig_pad_slp_sel (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pad_slp_sel);
pmu_ll_hp_set_hold_all_lp_pad (ctx->hal->dev, HP(SLEEP), dig->syscntl.lp_pad_hold_all);
pmu_ll_hp_set_pause_watchdog (ctx->hal->dev, HP(SLEEP), dig->syscntl.dig_pause_wdt);
// Lowpower workaround for LP pad holding, JTAG IOs is located on lp_pad on esp32p4, if hold its
// default state on sleep, there's a high current leakage.

View File

@@ -336,6 +336,7 @@ typedef struct {
.syscntl = { \
.dig_pad_slp_sel = 0, \
.lp_pad_hold_all = (sleep_flags & PMU_SLEEP_PD_LP_PERIPH) ? 1 : 0, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
} \
}
@@ -343,18 +344,21 @@ typedef struct {
.syscntl = { \
.dig_pad_slp_sel = 0, \
.lp_pad_hold_all = (sleep_flags & PMU_SLEEP_PD_LP_PERIPH) ? 1 : 0, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
} \
}
#else // !CONFIG_ESP32P4_SELECTS_REV_LESS_V3
#define PMU_SLEEP_DIGITAL_DSLP_CONFIG_DEFAULT(sleep_flags) { \
.syscntl = { \
.dig_pad_slp_sel = 0, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
} \
}
#define PMU_SLEEP_DIGITAL_LSLP_CONFIG_DEFAULT(sleep_flags) { \
.syscntl = { \
.dig_pad_slp_sel = 0, \
.dig_pause_wdt = ((sleep_flags) & RTC_SLEEP_USE_RTC_WDT) ? 0 : 1, \
} \
}
#endif

View File

@@ -623,6 +623,7 @@ typedef struct {
uint32_t rtc_regulator_fpu : 1; //!< keep rtc regulator powered up in sleep
uint32_t deep_slp_reject : 1; //!< enable deep sleep reject
uint32_t light_slp_reject : 1; //!< enable light sleep reject
uint32_t rtc_wdt_en : 1; //!< enable rtc wdt, in sleep mode
} rtc_sleep_config_t;
#define RTC_SLEEP_PD_DIG BIT(0) //!< Deep sleep (power down digital domain)
@@ -641,6 +642,7 @@ typedef struct {
#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
#define RTC_SLEEP_XTAL_AS_RTC_FAST BIT(19)
#define RTC_SLEEP_FLASH_DPD BIT(20)
#define RTC_SLEEP_USE_RTC_WDT BIT(20)
/**
* Default initializer for rtc_sleep_config_t

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -18,6 +18,7 @@
#include "esp32s2/rom/ets_sys.h"
#include "esp32s2/rom/rtc.h"
#include "hal/rtc_cntl_ll.h"
#include "hal/rwdt_ll.h"
/**
* Configure whether certain peripherals are powered down in deep sleep
@@ -158,6 +159,12 @@ void rtc_sleep_get_default_config(uint32_t sleep_flags, rtc_sleep_config_t *out_
out_config->bias_sleep_slp = RTC_CNTL_BIASSLP_SLEEP_DEFAULT;
out_config->pd_cur_slp = RTC_CNTL_PD_CUR_SLEEP_DEFAULT;
}
if (sleep_flags & RTC_SLEEP_USE_RTC_WDT) {
out_config->rtc_wdt_en = 1;
} else {
out_config->rtc_wdt_en = 0;
}
}
void rtc_sleep_init(rtc_sleep_config_t cfg)
@@ -237,6 +244,11 @@ void rtc_sleep_init(rtc_sleep_config_t cfg)
REG_CLR_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU);
}
/* enable rtc wdt during sleep */
rwdt_ll_write_protect_disable(RWDT_DEV_GET());
rwdt_ll_set_pause_in_sleep_en(RWDT_DEV_GET(), !cfg.rtc_wdt_en);
rwdt_ll_write_protect_enable(RWDT_DEV_GET());
/* 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

@@ -607,6 +607,7 @@ typedef struct {
uint32_t rtc_regulator_fpu : 1; //!< keep rtc regulator powered up in sleep
uint32_t deep_slp_reject : 1; //!< enable deep sleep reject
uint32_t light_slp_reject : 1; //!< enable light sleep reject
uint32_t rtc_wdt_en : 1; //!< enable rtc wdt, in sleep mode
} rtc_sleep_config_t;
#define RTC_SLEEP_PD_DIG BIT(0) //!< Deep sleep (power down digital domain)
@@ -627,6 +628,7 @@ typedef struct {
#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
#define RTC_SLEEP_XTAL_AS_RTC_FAST BIT(19)
#define RTC_SLEEP_FLASH_DPD BIT(20)
#define RTC_SLEEP_USE_RTC_WDT BIT(21)
/**
* Default initializer for rtc_sleep_config_t

View File

@@ -1,5 +1,5 @@
/*
* SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD
* SPDX-FileCopyrightText: 2015-2026 Espressif Systems (Shanghai) CO LTD
*
* SPDX-License-Identifier: Apache-2.0
*/
@@ -18,6 +18,7 @@
#include "soc/fe_reg.h"
#include "regi2c_ctrl.h"
#include "soc/regi2c_dig_reg.h"
#include "hal/rwdt_ll.h"
#define RTC_CNTL_MEM_FOLW_CPU (RTC_CNTL_SLOWMEM_FOLW_CPU | RTC_CNTL_FASTMEM_FOLW_CPU)
@@ -169,6 +170,12 @@ void rtc_sleep_get_default_config(uint32_t sleep_flags, rtc_sleep_config_t *out_
out_config->bias_sleep_slp = RTC_CNTL_BIASSLP_SLEEP_DEFAULT;
out_config->pd_cur_slp = RTC_CNTL_PD_CUR_SLEEP_DEFAULT;
}
if (sleep_flags & RTC_SLEEP_USE_RTC_WDT) {
out_config->rtc_wdt_en = 1;
} else {
out_config->rtc_wdt_en = 0;
}
}
void rtc_sleep_init(rtc_sleep_config_t cfg)
@@ -243,6 +250,11 @@ void rtc_sleep_init(rtc_sleep_config_t cfg)
REG_CLR_BIT(RTC_CNTL_CLK_CONF_REG, RTC_CNTL_CK8M_FORCE_PU);
}
/* enable rtc wdt during sleep */
rwdt_ll_write_protect_disable(RWDT_DEV_GET());
rwdt_ll_set_pause_in_sleep_en(RWDT_DEV_GET(), !cfg.rtc_wdt_en);
rwdt_ll_write_protect_enable(RWDT_DEV_GET());
/* 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

@@ -348,6 +348,10 @@ void esp_sleep_overhead_out_time_refresh(void)
static uint32_t get_power_down_flags(void);
static uint32_t get_sleep_flags(uint32_t pd_flags, bool deepsleep);
static uint32_t get_sleep_clock_icg_flags(void);
#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP
static uint32_t get_sleep_rtc_wdt_timeout(uint64_t sleep_duration);
static uint32_t calc_sleep_slow_clk_required_cycles(uint32_t timeout, uint32_t rtc_slow_clk_cal_period);
#endif
#if SOC_PM_SUPPORT_EXT0_WAKEUP
static void ext0_wakeup_prepare(void);
#endif
@@ -765,6 +769,33 @@ static SLEEP_FN_ATTR void misc_modules_wake_prepare(uint32_t sleep_flags)
#endif
}
/**
* RTC WDT prepare for using during sleep
*/
static SLEEP_FN_ATTR void sleep_rtc_wdt_prepare(bool enable)
{
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
if (enable) {
wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false);
// Use default timeout for sleep monitoring
uint32_t rtc_wdt_timeout_required_cycles = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL);
#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP
if (s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) {
uint32_t rtc_wdt_timeout = get_sleep_rtc_wdt_timeout(s_config.sleep_duration);
rtc_wdt_timeout_required_cycles = calc_sleep_slow_clk_required_cycles(rtc_wdt_timeout, s_config.rtc_clk_cal_period);
}
#endif
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, rtc_wdt_timeout_required_cycles, WDT_STAGE_ACTION_RESET_RTC);
wdt_hal_enable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
} else {
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_disable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
}
}
static SLEEP_FN_ATTR void sleep_low_power_clock_calibration(bool is_dslp)
{
// Calibrate rtc slow clock
@@ -1219,6 +1250,15 @@ static esp_err_t FORCE_IRAM_ATTR deep_sleep_start(bool allow_sleep_rejection)
// Correct the sleep time
s_config.sleep_time_adjustment = DEEP_SLEEP_TIME_OVERHEAD_US;
// Safety net: enable WDT in case exit from deep sleep fails
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
bool rtc_wdt_was_enabled = wdt_hal_is_enabled(&rtc_wdt_ctx); // If WDT was enabled in the user code, then do not change it here.
if (!rtc_wdt_was_enabled) {
sleep_rtc_wdt_prepare(true);
} else {
ESP_EARLY_LOGW(TAG, "RTC WDT is enabled and will not be reconfigured again!");
}
#if SOC_PMU_SUPPORTED
uint32_t force_pd_flags = PMU_SLEEP_PD_TOP | PMU_SLEEP_PD_VDDSDIO | PMU_SLEEP_PD_MODEM | PMU_SLEEP_PD_HP_PERIPH \
| PMU_SLEEP_PD_CPU | PMU_SLEEP_PD_MEM | PMU_SLEEP_PD_XTAL;
@@ -1265,6 +1305,10 @@ static esp_err_t FORCE_IRAM_ATTR deep_sleep_start(bool allow_sleep_rejection)
ESP_INFINITE_LOOP();
}
// Never returns here, except that the sleep is rejected.
if (!rtc_wdt_was_enabled) {
sleep_rtc_wdt_prepare(false);
}
esp_ipc_isr_stall_resume();
esp_ipc_isr_release_other_cpu();
esp_os_exit_critical(&spinlock_rtc_deep_sleep);
@@ -1536,14 +1580,11 @@ esp_err_t esp_light_sleep_start(void)
// Safety net: enable WDT in case exit from light sleep fails
wdt_hal_context_t rtc_wdt_ctx = RWDT_HAL_CONTEXT_DEFAULT();
bool wdt_was_enabled = wdt_hal_is_enabled(&rtc_wdt_ctx); // If WDT was enabled in the user code, then do not change it here.
if (!wdt_was_enabled) {
wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false);
uint32_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL);
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC);
wdt_hal_enable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
bool rtc_wdt_was_enabled = wdt_hal_is_enabled(&rtc_wdt_ctx); // If WDT was enabled in the user code, then do not change it here.
if (!rtc_wdt_was_enabled) {
sleep_rtc_wdt_prepare(true);
} else {
ESP_EARLY_LOGW(TAG, "RTC WDT is enabled and will not be reconfigured again!");
}
esp_err_t err = ESP_OK;
@@ -1615,10 +1656,8 @@ esp_err_t esp_light_sleep_start(void)
#endif
#endif
if (!wdt_was_enabled) {
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_disable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
if (!rtc_wdt_was_enabled) {
sleep_rtc_wdt_prepare(false);
}
#if CONFIG_ESP_TASK_WDT_USE_ESP_TIMER
@@ -2868,6 +2907,14 @@ static SLEEP_FN_ATTR uint32_t get_sleep_flags(uint32_t sleep_flags, bool deepsle
}
#endif
#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP
if (s_config.wakeup_triggers & RTC_TIMER_TRIG_EN) {
sleep_flags |= RTC_SLEEP_USE_RTC_WDT;
} else {
sleep_flags &= ~RTC_SLEEP_USE_RTC_WDT;
}
#endif
#if CONFIG_IDF_TARGET_ESP32P4
/* Due to esp32p4 eco0 hardware bug, if LP peripheral power domain is powerdowned in sleep, there will be a possibility of
triggering the EFUSE_CRC reset, so disable the power-down of this power domain on lightsleep for ECO0 version. */
@@ -2919,6 +2966,35 @@ static SLEEP_FN_ATTR uint32_t get_sleep_clock_icg_flags(void)
return clk_flags;
}
#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP
/* TODO: PM-609 */
/* Calculate drift cycles of rtc slow clock in long-term working scenarios. */
static SLEEP_FN_ATTR uint32_t calc_sleep_slow_clk_required_cycles(uint32_t timeout, uint32_t rtc_slow_clk_cal_period)
{
uint32_t timeout_cycles = 0;
uint32_t required_timeout_cycles = 0;
timeout_cycles = (uint32_t)rtc_time_us_to_slowclk(timeout, rtc_slow_clk_cal_period);
/* TODO: Add slow clock drift compensation */
required_timeout_cycles = timeout_cycles;
return required_timeout_cycles;
}
/* Get the timeout in microseconds for the RTC WDT sleep monitoring.
* Returns: default_timeout (1 second) + sleep_duration, all in microseconds.
*/
static SLEEP_FN_ATTR uint32_t get_sleep_rtc_wdt_timeout(uint64_t sleep_duration)
{
uint32_t default_timeout = 1000000; // 1 second in microseconds
uint32_t sleep_timeout = 0;
uint32_t rtc_wdt_timeout = 0;
sleep_timeout = (uint32_t)sleep_duration;
rtc_wdt_timeout = default_timeout + sleep_timeout;
return rtc_wdt_timeout;
}
#endif
#if CONFIG_IDF_TARGET_ESP32
/* APP core of esp32 can't access to RTC FAST MEMORY, do not define it with RTC_IRAM_ATTR */
RTC_SLOW_ATTR

View File

@@ -17,6 +17,7 @@
#include "esp_system.h"
#include "esp_intr_alloc.h"
#include "esp_private/rtc_ctrl.h"
#include "esp_private/esp_sleep_internal.h"
/* As the RTC slow clock used by RWDT is derived using RC oscillator by default,
* the timing accuracy is not very precise, and may vary from chip to chip.
@@ -178,6 +179,50 @@ static void rtc_wdt_setup_then_reset_RTC(void)
}
}
#if SOC_LIGHT_SLEEP_SUPPORTED && CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP
/* MULTI test case for light sleep prepare timeout then RTC WDT resets RTC */
static void rtc_wdt_light_sleep_prepare_timeout(void)
{
uint32_t stage_timeout_ticks = (uint32_t)(1000 * rtc_clk_slow_freq_get_hz() / 1000ULL); /* 1000ms for interrupt */
esp_sleep_enable_timer_wakeup(3000000);
/* Setup RTC WDT */
// Here enable RTC_WDT then the setup in sleep flow will be skipped
wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, true);
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC);
wdt_hal_enable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
TEST_ASSERT_TRUE(wdt_hal_is_enabled(&rtc_wdt_ctx));
printf("RTC WDT setup stage-0 RESET (1000ms)\n");
esp_light_sleep_start();
/* Wait for RTC WDT to reset the main system and RTC */
esp_restart();
}
#endif
#if SOC_DEEP_SLEEP_SUPPORTED && CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP
/* MULTI test case for deep sleep prepare timeout then RTC WDT resets RTC */
static void rtc_wdt_deep_sleep_prepare_timeout(void)
{
uint32_t stage_timeout_ticks = (uint32_t)(1000 * rtc_clk_slow_freq_get_hz() / 1000ULL); /* 1000ms for interrupt */
esp_sleep_enable_timer_wakeup(3000000);
/* Setup RTC WDT */
// Here enable RTC_WDT then the setup in sleep flow will be skipped
wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, true);
wdt_hal_write_protect_disable(&rtc_wdt_ctx);
wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, stage_timeout_ticks, WDT_STAGE_ACTION_RESET_RTC);
wdt_hal_enable(&rtc_wdt_ctx);
wdt_hal_write_protect_enable(&rtc_wdt_ctx);
TEST_ASSERT_TRUE(wdt_hal_is_enabled(&rtc_wdt_ctx));
printf("RTC WDT setup stage-0 RESET (1000ms)\n");
esp_deep_sleep_start();
}
#endif
static void rtc_wdt_verify_SYSTEM_reset(void)
{
printf("Confirming if reset reason matches 0x9 (main system reset)\n");
@@ -211,3 +256,21 @@ TEST_CASE_MULTIPLE_STAGES(
rtc_wdt_setup_then_reset_RTC,
rtc_wdt_verify_RTC_reset
)
#if SOC_LIGHT_SLEEP_SUPPORTED && CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP
TEST_CASE_MULTIPLE_STAGES(
"Light sleep prepare timeout then RTC WDT resets RTC",
"[rtc_wdt][lightsleep][reset]",
rtc_wdt_light_sleep_prepare_timeout,
rtc_wdt_verify_RTC_reset
)
#endif
#if SOC_DEEP_SLEEP_SUPPORTED && CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP
TEST_CASE_MULTIPLE_STAGES(
"Deep sleep prepare timeout then RTC WDT resets RTC",
"[rtc_wdt][deepsleep][reset]",
rtc_wdt_deep_sleep_prepare_timeout,
rtc_wdt_verify_RTC_reset
)
#endif

View File

@@ -13,6 +13,7 @@ from pytest_embedded_idf.utils import soc_filtered_targets
('single_core_esp32', 'esp32'),
*(('default', target) for target in soc_filtered_targets('IDF_TARGET not in ["esp32c5"]')),
*(('release', target) for target in soc_filtered_targets('IDF_TARGET not in ["esp32c5"]')),
*(('rwdt_monitor', target) for target in soc_filtered_targets('IDF_TARGET not in ["esp32c5"]')),
],
indirect=['config', 'target'],
)

View File

@@ -0,0 +1,3 @@
# enable RTC WDT during sleep period
CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP=y
CONFIG_IDF_EXPERIMENTAL_FEATURES=y