From 8555a9b3c3b9eb85c44401da8fb0b35e96c41552 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Mon, 19 Jan 2026 20:04:35 +0800 Subject: [PATCH 1/8] feat(esp_hw_support): support rtc wdt during light sleep --- components/esp_hw_support/Kconfig | 16 ++++++++++++++ .../include/esp_private/esp_pmu.h | 1 + .../port/esp32/include/soc/rtc.h | 2 ++ .../esp_hw_support/port/esp32/rtc_sleep.c | 14 +++++++++++- .../port/esp32c2/include/soc/rtc.h | 2 ++ .../esp_hw_support/port/esp32c2/rtc_sleep.c | 14 +++++++++++- .../port/esp32c3/include/soc/rtc.h | 2 ++ .../esp_hw_support/port/esp32c3/rtc_sleep.c | 14 +++++++++++- .../esp_hw_support/port/esp32c5/pmu_sleep.c | 1 + .../port/esp32c5/private_include/pmu_param.h | 2 ++ .../esp_hw_support/port/esp32c6/pmu_sleep.c | 1 + .../port/esp32c6/private_include/pmu_param.h | 2 ++ .../esp_hw_support/port/esp32c61/pmu_sleep.c | 1 + .../port/esp32c61/private_include/pmu_param.h | 2 ++ .../esp_hw_support/port/esp32h2/pmu_sleep.c | 1 + .../port/esp32h2/private_include/pmu_param.h | 2 ++ .../esp_hw_support/port/esp32h21/pmu_sleep.c | 1 + .../port/esp32h21/private_include/pmu_param.h | 2 ++ .../esp_hw_support/port/esp32h4/pmu_sleep.c | 1 + .../port/esp32h4/private_include/pmu_param.h | 2 ++ .../esp_hw_support/port/esp32p4/pmu_sleep.c | 1 + .../port/esp32p4/private_include/pmu_param.h | 4 ++++ .../port/esp32s2/include/soc/rtc.h | 2 ++ .../esp_hw_support/port/esp32s2/rtc_sleep.c | 14 +++++++++++- .../port/esp32s3/include/soc/rtc.h | 2 ++ .../esp_hw_support/port/esp32s3/rtc_sleep.c | 14 +++++++++++- components/esp_hw_support/sleep_modes.c | 22 +++++++++++++++++-- 27 files changed, 135 insertions(+), 7 deletions(-) diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index 9df98590087..cdc2ab7c0f0 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -272,6 +272,22 @@ 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 + 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: In the current phase, the RTC slow clock compensation time remains zero (pending implementation). + When using the RC_SLOW_CLK 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. + + endmenu menu "RTC Clock Config" diff --git a/components/esp_hw_support/include/esp_private/esp_pmu.h b/components/esp_hw_support/include/esp_private/esp_pmu.h index edddcbac3c1..550d139b9a7 100644 --- a/components/esp_hw_support/include/esp_private/esp_pmu.h +++ b/components/esp_hw_support/include/esp_private/esp_pmu.h @@ -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) 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 214ee3de5f6..ee13f754a04 100644 --- a/components/esp_hw_support/port/esp32/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32/include/soc/rtc.h @@ -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 * diff --git a/components/esp_hw_support/port/esp32/rtc_sleep.c b/components/esp_hw_support/port/esp32/rtc_sleep.c index 45648d6588e..15a64c0a748 100644 --- a/components/esp_hw_support/port/esp32/rtc_sleep.c +++ b/components/esp_hw_support/port/esp32/rtc_sleep.c @@ -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); diff --git a/components/esp_hw_support/port/esp32c2/include/soc/rtc.h b/components/esp_hw_support/port/esp32c2/include/soc/rtc.h index 443625bdbe8..0cae435c2b1 100644 --- a/components/esp_hw_support/port/esp32c2/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32c2/include/soc/rtc.h @@ -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 diff --git a/components/esp_hw_support/port/esp32c2/rtc_sleep.c b/components/esp_hw_support/port/esp32c2/rtc_sleep.c index 17d1ac06a8e..0d423129dbc 100644 --- a/components/esp_hw_support/port/esp32c2/rtc_sleep.c +++ b/components/esp_hw_support/port/esp32c2/rtc_sleep.c @@ -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); diff --git a/components/esp_hw_support/port/esp32c3/include/soc/rtc.h b/components/esp_hw_support/port/esp32c3/include/soc/rtc.h index bd25c529060..a46e40716c7 100644 --- a/components/esp_hw_support/port/esp32c3/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32c3/include/soc/rtc.h @@ -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 diff --git a/components/esp_hw_support/port/esp32c3/rtc_sleep.c b/components/esp_hw_support/port/esp32c3/rtc_sleep.c index 9962cd5c9c9..8fc212dd2aa 100644 --- a/components/esp_hw_support/port/esp32c3/rtc_sleep.c +++ b/components/esp_hw_support/port/esp32c3/rtc_sleep.c @@ -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); diff --git a/components/esp_hw_support/port/esp32c5/pmu_sleep.c b/components/esp_hw_support/port/esp32c5/pmu_sleep.c index d2bdfc37391..fc44516207b 100644 --- a/components/esp_hw_support/port/esp32c5/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c5/pmu_sleep.c @@ -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); } diff --git a/components/esp_hw_support/port/esp32c5/private_include/pmu_param.h b/components/esp_hw_support/port/esp32c5/private_include/pmu_param.h index 3c7d1bee14d..0806c163258 100644 --- a/components/esp_hw_support/port/esp32c5/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32c5/private_include/pmu_param.h @@ -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 \ } diff --git a/components/esp_hw_support/port/esp32c6/pmu_sleep.c b/components/esp_hw_support/port/esp32c6/pmu_sleep.c index eba9feafcea..1050c3ec134 100644 --- a/components/esp_hw_support/port/esp32c6/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c6/pmu_sleep.c @@ -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); } diff --git a/components/esp_hw_support/port/esp32c6/private_include/pmu_param.h b/components/esp_hw_support/port/esp32c6/private_include/pmu_param.h index 523ffb42dbd..06b7679e86d 100644 --- a/components/esp_hw_support/port/esp32c6/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32c6/private_include/pmu_param.h @@ -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 \ } diff --git a/components/esp_hw_support/port/esp32c61/pmu_sleep.c b/components/esp_hw_support/port/esp32c61/pmu_sleep.c index c265b5bfd23..71ca1fe98be 100644 --- a/components/esp_hw_support/port/esp32c61/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32c61/pmu_sleep.c @@ -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); } diff --git a/components/esp_hw_support/port/esp32c61/private_include/pmu_param.h b/components/esp_hw_support/port/esp32c61/private_include/pmu_param.h index 335f0a9a3ff..8d4f77c9990 100644 --- a/components/esp_hw_support/port/esp32c61/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32c61/private_include/pmu_param.h @@ -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 \ } diff --git a/components/esp_hw_support/port/esp32h2/pmu_sleep.c b/components/esp_hw_support/port/esp32h2/pmu_sleep.c index de4a8f434a2..ef62ce4594a 100644 --- a/components/esp_hw_support/port/esp32h2/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32h2/pmu_sleep.c @@ -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); } diff --git a/components/esp_hw_support/port/esp32h2/private_include/pmu_param.h b/components/esp_hw_support/port/esp32h2/private_include/pmu_param.h index 4d3679faab0..da7f3c2a636 100644 --- a/components/esp_hw_support/port/esp32h2/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32h2/private_include/pmu_param.h @@ -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 \ } diff --git a/components/esp_hw_support/port/esp32h21/pmu_sleep.c b/components/esp_hw_support/port/esp32h21/pmu_sleep.c index 52aa8f8ab0a..11b40baa4ee 100644 --- a/components/esp_hw_support/port/esp32h21/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32h21/pmu_sleep.c @@ -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); } diff --git a/components/esp_hw_support/port/esp32h21/private_include/pmu_param.h b/components/esp_hw_support/port/esp32h21/private_include/pmu_param.h index 288c7682a14..3d379d303a6 100644 --- a/components/esp_hw_support/port/esp32h21/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32h21/private_include/pmu_param.h @@ -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 \ } diff --git a/components/esp_hw_support/port/esp32h4/pmu_sleep.c b/components/esp_hw_support/port/esp32h4/pmu_sleep.c index 90305982c7c..505138d7d67 100644 --- a/components/esp_hw_support/port/esp32h4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32h4/pmu_sleep.c @@ -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) { diff --git a/components/esp_hw_support/port/esp32h4/private_include/pmu_param.h b/components/esp_hw_support/port/esp32h4/private_include/pmu_param.h index c9ec40c3978..144af0a46a8 100644 --- a/components/esp_hw_support/port/esp32h4/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32h4/private_include/pmu_param.h @@ -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 \ } diff --git a/components/esp_hw_support/port/esp32p4/pmu_sleep.c b/components/esp_hw_support/port/esp32p4/pmu_sleep.c index ffa19f9e654..19c724814c0 100644 --- a/components/esp_hw_support/port/esp32p4/pmu_sleep.c +++ b/components/esp_hw_support/port/esp32p4/pmu_sleep.c @@ -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. diff --git a/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h b/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h index 41dc4c48873..675d7c1921b 100644 --- a/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h +++ b/components/esp_hw_support/port/esp32p4/private_include/pmu_param.h @@ -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 diff --git a/components/esp_hw_support/port/esp32s2/include/soc/rtc.h b/components/esp_hw_support/port/esp32s2/include/soc/rtc.h index 8c74e62ab57..7bd0ffece3e 100644 --- a/components/esp_hw_support/port/esp32s2/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32s2/include/soc/rtc.h @@ -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 diff --git a/components/esp_hw_support/port/esp32s2/rtc_sleep.c b/components/esp_hw_support/port/esp32s2/rtc_sleep.c index a07908c19f5..dc3eb6aa6e5 100644 --- a/components/esp_hw_support/port/esp32s2/rtc_sleep.c +++ b/components/esp_hw_support/port/esp32s2/rtc_sleep.c @@ -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); diff --git a/components/esp_hw_support/port/esp32s3/include/soc/rtc.h b/components/esp_hw_support/port/esp32s3/include/soc/rtc.h index 99646a1ba3f..481ad6ebab8 100644 --- a/components/esp_hw_support/port/esp32s3/include/soc/rtc.h +++ b/components/esp_hw_support/port/esp32s3/include/soc/rtc.h @@ -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 diff --git a/components/esp_hw_support/port/esp32s3/rtc_sleep.c b/components/esp_hw_support/port/esp32s3/rtc_sleep.c index dd53fef9984..5c416320038 100644 --- a/components/esp_hw_support/port/esp32s3/rtc_sleep.c +++ b/components/esp_hw_support/port/esp32s3/rtc_sleep.c @@ -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); diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 5c8bd0c95a8..a32aa2c95f3 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -348,6 +348,7 @@ 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); +static uint32_t get_slow_clk_zero_drift_compensate(uint32_t sleep_duration); #if SOC_PM_SUPPORT_EXT0_WAKEUP static void ext0_wakeup_prepare(void); #endif @@ -1539,9 +1540,15 @@ esp_err_t esp_light_sleep_start(void) 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); + uint64_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); +#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP + uint64_t sleep_timout_ticks = rtc_time_us_to_slowclk(s_config.sleep_duration, s_config.rtc_clk_cal_period); +#else + uint64_t sleep_timout_ticks = 0; +#endif + uint64_t slow_clk_comp_ticks = get_slow_clk_zero_drift_compensate(sleep_timout_ticks + stage_timeout_ticks); 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_config_stage(&rtc_wdt_ctx, WDT_STAGE0, (uint32_t)(stage_timeout_ticks + sleep_timout_ticks + slow_clk_comp_ticks), WDT_STAGE_ACTION_RESET_RTC); wdt_hal_enable(&rtc_wdt_ctx); wdt_hal_write_protect_enable(&rtc_wdt_ctx); } @@ -2868,6 +2875,10 @@ 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 + 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 +2930,13 @@ static SLEEP_FN_ATTR uint32_t get_sleep_clock_icg_flags(void) return clk_flags; } +/* Compensate zero drift of rtc slow clock in long-term working scenarios */ +static uint32_t get_slow_clk_zero_drift_compensate(uint32_t sleep_duration) +{ + (void) sleep_duration; + return 0; +} + #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 From c02944f8b886a670fabfcbcf5cd6563182afb13b Mon Sep 17 00:00:00 2001 From: hebinglin Date: Fri, 7 Nov 2025 15:42:12 +0800 Subject: [PATCH 2/8] feat(esp_hw_support): support rtc wdt during deep sleep --- components/esp_hw_support/Kconfig | 13 ++++++++++- components/esp_hw_support/sleep_modes.c | 29 +++++++++++++++++++++++++ 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index cdc2ab7c0f0..2fe584267fe 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -275,7 +275,7 @@ menu "Hardware Settings" 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 + 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 @@ -288,6 +288,17 @@ menu "Hardware Settings" 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: 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" diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index a32aa2c95f3..79569a6e2d9 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -1220,6 +1220,26 @@ 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; +#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP + // Safety net: enable WDT in case exit from deep 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); + uint64_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); +#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP + uint64_t sleep_timout_ticks = rtc_time_us_to_slowclk(s_config.sleep_duration, s_config.rtc_clk_cal_period); +#else + uint64_t sleep_timout_ticks = 0; +#endif + uint64_t slow_clk_comp_ticks = get_slow_clk_zero_drift_compensate(sleep_timout_ticks + stage_timeout_ticks); + wdt_hal_write_protect_disable(&rtc_wdt_ctx); + wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, (uint32_t)(stage_timeout_ticks + sleep_timout_ticks + slow_clk_comp_ticks), WDT_STAGE_ACTION_RESET_RTC); + wdt_hal_enable(&rtc_wdt_ctx); + wdt_hal_write_protect_enable(&rtc_wdt_ctx); + } +#endif + #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,7 +1285,16 @@ static esp_err_t FORCE_IRAM_ATTR deep_sleep_start(bool allow_sleep_rejection) // can take several CPU cycles for the sleep mode to start. ESP_INFINITE_LOOP(); } + // Never returns here, except that the sleep is rejected. +#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP + 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); + } +#endif + esp_ipc_isr_stall_resume(); esp_ipc_isr_release_other_cpu(); esp_os_exit_critical(&spinlock_rtc_deep_sleep); From b763ce797416b6a8ce6d786915d29e2de50cd351 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Tue, 11 Nov 2025 10:45:37 +0800 Subject: [PATCH 3/8] change(esp_hw_support): add sleep_rtc_wdt_prepare api for rtc wdt enable or disable --- components/esp_hw_support/Kconfig | 15 ++-- components/esp_hw_support/sleep_modes.c | 106 ++++++++++++++---------- 2 files changed, 72 insertions(+), 49 deletions(-) diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index 2fe584267fe..58cb43a38c8 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -282,10 +282,10 @@ menu "Hardware Settings" timeout will be set as the sum of the sleep duration, hardware overhead time, and RTC slow clock compensation time. - NOTE: In the current phase, the RTC slow clock compensation time remains zero (pending implementation). - When using the RC_SLOW_CLK 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. + 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 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 @@ -296,9 +296,10 @@ menu "Hardware Settings" help If enabled, rtc watchdog will remain active during deep sleep to prevent program runaway. - NOTE: 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. + 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" diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 79569a6e2d9..9dbd886ff9c 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -348,7 +348,8 @@ 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); -static uint32_t get_slow_clk_zero_drift_compensate(uint32_t sleep_duration); +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); #if SOC_PM_SUPPORT_EXT0_WAKEUP static void ext0_wakeup_prepare(void); #endif @@ -766,6 +767,28 @@ 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 = get_sleep_rtc_wdt_timeout(s_config.sleep_duration); + uint32_t rtc_wdt_timeout_required_cycles = calc_sleep_slow_clk_required_cycles(rtc_wdt_timeout, s_config.rtc_clk_cal_period); + 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 @@ -1223,20 +1246,11 @@ static esp_err_t FORCE_IRAM_ATTR deep_sleep_start(bool allow_sleep_rejection) #if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP // Safety net: enable WDT in case exit from deep 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); - uint64_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); -#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP - uint64_t sleep_timout_ticks = rtc_time_us_to_slowclk(s_config.sleep_duration, s_config.rtc_clk_cal_period); -#else - uint64_t sleep_timout_ticks = 0; -#endif - uint64_t slow_clk_comp_ticks = get_slow_clk_zero_drift_compensate(sleep_timout_ticks + stage_timeout_ticks); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, (uint32_t)(stage_timeout_ticks + sleep_timout_ticks + slow_clk_comp_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!"); } #endif @@ -1285,13 +1299,10 @@ static esp_err_t FORCE_IRAM_ATTR deep_sleep_start(bool allow_sleep_rejection) // can take several CPU cycles for the sleep mode to start. ESP_INFINITE_LOOP(); } - // Never returns here, except that the sleep is rejected. #if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP - 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); } #endif @@ -1566,20 +1577,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); - uint64_t stage_timeout_ticks = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); -#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP - uint64_t sleep_timout_ticks = rtc_time_us_to_slowclk(s_config.sleep_duration, s_config.rtc_clk_cal_period); -#else - uint64_t sleep_timout_ticks = 0; -#endif - uint64_t slow_clk_comp_ticks = get_slow_clk_zero_drift_compensate(sleep_timout_ticks + stage_timeout_ticks); - wdt_hal_write_protect_disable(&rtc_wdt_ctx); - wdt_hal_config_stage(&rtc_wdt_ctx, WDT_STAGE0, (uint32_t)(stage_timeout_ticks + sleep_timout_ticks + slow_clk_comp_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; @@ -1651,10 +1653,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 @@ -2959,11 +2959,33 @@ static SLEEP_FN_ATTR uint32_t get_sleep_clock_icg_flags(void) return clk_flags; } -/* Compensate zero drift of rtc slow clock in long-term working scenarios */ -static uint32_t get_slow_clk_zero_drift_compensate(uint32_t sleep_duration) +/* 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) { - (void) sleep_duration; - return 0; + 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; + +#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP || CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP + sleep_timeout = (uint32_t)sleep_duration; +#endif + rtc_wdt_timeout = default_timeout + sleep_timeout; + + return rtc_wdt_timeout; } #if CONFIG_IDF_TARGET_ESP32 From 6fa4a504f9d19f2c7e9cb8a7f5e9d04538326f56 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Wed, 31 Dec 2025 17:22:05 +0800 Subject: [PATCH 4/8] feat(esp_hw_support): add rtc wdt runnning during sleep test case --- .../main/test_rtc_wdt.c | 63 +++++++++++++++++++ .../pytest_esp_hw_support.py | 1 + .../sdkconfig.ci.rwdt_monitor | 4 ++ 3 files changed, 68 insertions(+) create mode 100644 components/esp_hw_support/test_apps/esp_hw_support_unity_tests/sdkconfig.ci.rwdt_monitor diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_rtc_wdt.c b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_rtc_wdt.c index 29340c724e8..b7ed1066cc8 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_rtc_wdt.c +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_rtc_wdt.c @@ -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_DEEP_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_DEEP_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 diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/pytest_esp_hw_support.py b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/pytest_esp_hw_support.py index e33083f6c8e..76a2e37382e 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/pytest_esp_hw_support.py +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/pytest_esp_hw_support.py @@ -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'], ) diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/sdkconfig.ci.rwdt_monitor b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/sdkconfig.ci.rwdt_monitor new file mode 100644 index 00000000000..38d3c2840db --- /dev/null +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/sdkconfig.ci.rwdt_monitor @@ -0,0 +1,4 @@ +# enable RTC WDT during sleep period +CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP=y +CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP=y +CONFIG_IDF_EXPERIMENTAL_FEATURES=y From 2554f1265cbd48a9f39080d45a8c31488276216d Mon Sep 17 00:00:00 2001 From: hebinglin Date: Mon, 5 Jan 2026 15:50:57 +0800 Subject: [PATCH 5/8] fix(esp_hal_wdt): replace the erroneous RWDT timeout config in ROM with the code in ram --- components/esp_hal_wdt/esp32p4/rom.wdt.ld | 2 +- components/esp_hal_wdt/include/hal/wdt_hal.h | 2 +- components/esp_hal_wdt/rom_patch.c | 15 ++++++++++++++- 3 files changed, 16 insertions(+), 3 deletions(-) diff --git a/components/esp_hal_wdt/esp32p4/rom.wdt.ld b/components/esp_hal_wdt/esp32p4/rom.wdt.ld index 6b872fa581e..ed3bfd3d81e 100644 --- a/components/esp_hal_wdt/esp32p4/rom.wdt.ld +++ b/components/esp_hal_wdt/esp32p4/rom.wdt.ld @@ -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; diff --git a/components/esp_hal_wdt/include/hal/wdt_hal.h b/components/esp_hal_wdt/include/hal/wdt_hal.h index eb6a8aa382a..da9c9f5d09a 100644 --- a/components/esp_hal_wdt/include/hal/wdt_hal.h +++ b/components/esp_hal_wdt/include/hal/wdt_hal.h @@ -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 */ diff --git a/components/esp_hal_wdt/rom_patch.c b/components/esp_hal_wdt/rom_patch.c index 4f31da8c4a7..659ffa97967 100644 --- a/components/esp_hal_wdt/rom_patch.c +++ b/components/esp_hal_wdt/rom_patch.c @@ -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 From b683d47ab6944a3f8dd2f0d30f90f5a8d4322c04 Mon Sep 17 00:00:00 2001 From: hebinglin Date: Thu, 8 Jan 2026 12:27:25 +0800 Subject: [PATCH 6/8] change(esp_hw_support): reduce the ram size for rwdt monitoring during sleep --- components/esp_hw_support/sleep_modes.c | 10 ++++++++-- 1 file changed, 8 insertions(+), 2 deletions(-) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 9dbd886ff9c..5673b25fe88 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -348,8 +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 || CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_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 @@ -776,8 +778,12 @@ static SLEEP_FN_ATTR void sleep_rtc_wdt_prepare(bool enable) if (enable) { wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); // Use default timeout for sleep monitoring +#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP || CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP uint32_t rtc_wdt_timeout = get_sleep_rtc_wdt_timeout(s_config.sleep_duration); uint32_t rtc_wdt_timeout_required_cycles = calc_sleep_slow_clk_required_cycles(rtc_wdt_timeout, s_config.rtc_clk_cal_period); +#else + uint32_t rtc_wdt_timeout_required_cycles = (uint32_t)(1000ULL * rtc_clk_slow_freq_get_hz() / 1000ULL); +#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); @@ -2959,6 +2965,7 @@ static SLEEP_FN_ATTR uint32_t get_sleep_clock_icg_flags(void) return clk_flags; } +#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP || CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_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) @@ -2980,13 +2987,12 @@ static SLEEP_FN_ATTR uint32_t get_sleep_rtc_wdt_timeout(uint64_t sleep_duration) uint32_t sleep_timeout = 0; uint32_t rtc_wdt_timeout = 0; -#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP || CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP sleep_timeout = (uint32_t)sleep_duration; -#endif 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 */ From 267a02faa165174efb1213ffe6e21277d35c7cef Mon Sep 17 00:00:00 2001 From: hebinglin Date: Fri, 9 Jan 2026 17:29:54 +0800 Subject: [PATCH 7/8] change(esp_hw_support): add timer wakeup check when use rtc wdt during sleep --- components/esp_hw_support/sleep_modes.c | 15 ++++++++++----- 1 file changed, 10 insertions(+), 5 deletions(-) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 5673b25fe88..cd3f88be50c 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -778,11 +778,12 @@ static SLEEP_FN_ATTR void sleep_rtc_wdt_prepare(bool enable) if (enable) { wdt_hal_init(&rtc_wdt_ctx, WDT_RWDT, 0, false); // Use default timeout for sleep monitoring -#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP || CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP - uint32_t rtc_wdt_timeout = get_sleep_rtc_wdt_timeout(s_config.sleep_duration); - uint32_t rtc_wdt_timeout_required_cycles = calc_sleep_slow_clk_required_cycles(rtc_wdt_timeout, s_config.rtc_clk_cal_period); -#else 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 || CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_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); @@ -2911,7 +2912,11 @@ 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 - sleep_flags |= RTC_SLEEP_USE_RTC_WDT; + 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 From 847a31fc6ca12d1933ff85467a534ba756cdf6fa Mon Sep 17 00:00:00 2001 From: hebinglin Date: Thu, 15 Jan 2026 17:54:11 +0800 Subject: [PATCH 8/8] change(esp_hw_support): enable rwdt monitoring deep sleep software adjustment period by default --- components/esp_hw_support/Kconfig | 2 +- components/esp_hw_support/sleep_modes.c | 10 +++------- .../esp_hw_support_unity_tests/main/test_rtc_wdt.c | 4 ++-- .../sdkconfig.ci.rwdt_monitor | 1 - 4 files changed, 6 insertions(+), 11 deletions(-) diff --git a/components/esp_hw_support/Kconfig b/components/esp_hw_support/Kconfig index 58cb43a38c8..50ab6162efc 100644 --- a/components/esp_hw_support/Kconfig +++ b/components/esp_hw_support/Kconfig @@ -283,7 +283,7 @@ menu "Hardware Settings" 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 without + 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. diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index cd3f88be50c..6f2c2fc1394 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -348,7 +348,7 @@ 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 || CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP +#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 @@ -779,7 +779,7 @@ static SLEEP_FN_ATTR void sleep_rtc_wdt_prepare(bool 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 || CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP +#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); @@ -1250,7 +1250,6 @@ 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; -#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP // 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. @@ -1259,7 +1258,6 @@ static esp_err_t FORCE_IRAM_ATTR deep_sleep_start(bool allow_sleep_rejection) } else { ESP_EARLY_LOGW(TAG, "RTC WDT is enabled and will not be reconfigured again!"); } -#endif #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 \ @@ -1307,11 +1305,9 @@ 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 CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP if (!rtc_wdt_was_enabled) { sleep_rtc_wdt_prepare(false); } -#endif esp_ipc_isr_stall_resume(); esp_ipc_isr_release_other_cpu(); @@ -2970,7 +2966,7 @@ static SLEEP_FN_ATTR uint32_t get_sleep_clock_icg_flags(void) return clk_flags; } -#if CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP || CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP +#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) diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_rtc_wdt.c b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_rtc_wdt.c index b7ed1066cc8..c7bfdde3233 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_rtc_wdt.c +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/main/test_rtc_wdt.c @@ -202,7 +202,7 @@ static void rtc_wdt_light_sleep_prepare_timeout(void) } #endif -#if SOC_DEEP_SLEEP_SUPPORTED && CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP +#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) { @@ -266,7 +266,7 @@ TEST_CASE_MULTIPLE_STAGES( ) #endif -#if SOC_DEEP_SLEEP_SUPPORTED && CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP +#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]", diff --git a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/sdkconfig.ci.rwdt_monitor b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/sdkconfig.ci.rwdt_monitor index 38d3c2840db..74dc69c3331 100644 --- a/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/sdkconfig.ci.rwdt_monitor +++ b/components/esp_hw_support/test_apps/esp_hw_support_unity_tests/sdkconfig.ci.rwdt_monitor @@ -1,4 +1,3 @@ # enable RTC WDT during sleep period CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_SLEEP=y -CONFIG_ESP_SLEEP_ENABLE_RTC_WDT_IN_DEEP_SLEEP=y CONFIG_IDF_EXPERIMENTAL_FEATURES=y