diff --git a/components/esp_hal_pmu/esp32c5/include/hal/pmu_ll.h b/components/esp_hal_pmu/esp32c5/include/hal/pmu_ll.h index 0c331f5f72..36af3b9408 100644 --- a/components/esp_hal_pmu/esp32c5/include/hal/pmu_ll.h +++ b/components/esp_hal_pmu/esp32c5/include/hal/pmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -519,6 +519,11 @@ FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_intr_status(pmu_dev_t *hw) hw->hp_ext.int_clr.reject = 1; } +FORCE_INLINE_ATTR void pmu_ll_hp_clear_lp_cpu_exc_intr_status(pmu_dev_t *hw) +{ + hw->hp_ext.int_clr.lp_cpu_exc = 1; +} + FORCE_INLINE_ATTR void pmu_ll_hp_enable_sw_intr(pmu_dev_t *hw, bool enable) { hw->hp_ext.int_ena.sw = enable; diff --git a/components/esp_hal_pmu/esp32c6/include/hal/pmu_ll.h b/components/esp_hal_pmu/esp32c6/include/hal/pmu_ll.h index 24f31334aa..3f8ee6ac87 100644 --- a/components/esp_hal_pmu/esp32c6/include/hal/pmu_ll.h +++ b/components/esp_hal_pmu/esp32c6/include/hal/pmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -519,6 +519,11 @@ FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_intr_status(pmu_dev_t *hw) hw->hp_ext.int_clr.reject = 1; } +FORCE_INLINE_ATTR void pmu_ll_hp_clear_lp_cpu_exc_intr_status(pmu_dev_t *hw) +{ + hw->hp_ext.int_clr.lp_cpu_exc = 1; +} + FORCE_INLINE_ATTR void pmu_ll_hp_enable_sw_intr(pmu_dev_t *hw, bool enable) { hw->hp_ext.int_ena.sw = enable; diff --git a/components/esp_hal_pmu/esp32p4/include/hal/pmu_ll.h b/components/esp_hal_pmu/esp32p4/include/hal/pmu_ll.h index b43ef8f40c..1822b1b63d 100644 --- a/components/esp_hal_pmu/esp32p4/include/hal/pmu_ll.h +++ b/components/esp_hal_pmu/esp32p4/include/hal/pmu_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -567,6 +567,11 @@ FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_intr_status(pmu_dev_t *hw) hw->hp_ext.int_clr.reject = 1; } +FORCE_INLINE_ATTR void pmu_ll_hp_clear_lp_cpu_exc_intr_status(pmu_dev_t *hw) +{ + hw->hp_ext.int_clr.lp_exception = 1; +} + FORCE_INLINE_ATTR uint32_t pmu_ll_hp_get_wakeup_cause(pmu_dev_t *hw) { return hw->wakeup.status0; diff --git a/components/esp_hal_pmu/esp32s31/include/hal/pmu_ll.h b/components/esp_hal_pmu/esp32s31/include/hal/pmu_ll.h index 3b1140461d..e631b3bbff 100644 --- a/components/esp_hal_pmu/esp32s31/include/hal/pmu_ll.h +++ b/components/esp_hal_pmu/esp32s31/include/hal/pmu_ll.h @@ -595,6 +595,11 @@ FORCE_INLINE_ATTR void pmu_ll_hp_clear_reject_intr_status(pmu_dev_t *hw) hw->hp_ext.int_clr.soc_sleep_reject = 1; } +FORCE_INLINE_ATTR void pmu_ll_hp_clear_lp_cpu_exc_intr_status(pmu_dev_t *hw) +{ + hw->hp_ext.int_clr.lp_cpu_exc = 1; +} + FORCE_INLINE_ATTR void pmu_ll_hp_enable_sw_intr(pmu_dev_t *hw, bool enable) { hw->hp_ext.int_ena.sw = enable; diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 4138fa6a5b..bf96a80cea 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -81,6 +81,9 @@ #endif #include "hal/temperature_sensor_hal.h" #include "hal/mspi_ll.h" +#if SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE +#include "hal/lp_aon_hal.h" +#endif #include "sdkconfig.h" #include "esp_rom_serial_output.h" @@ -1098,6 +1101,7 @@ static esp_err_t SLEEP_FN_ATTR esp_sleep_start(uint32_t sleep_flags, uint32_t cl #if CONFIG_ULP_COPROC_TYPE_LP_CORE if (s_config.wakeup_triggers & (RTC_LP_CORE_TRIG_EN | RTC_LP_CORE_TRAP_TRIG_EN)) { pmu_ll_hp_clear_sw_intr_status(&PMU); + pmu_ll_hp_clear_lp_cpu_exc_intr_status(&PMU); } #endif #endif // CONFIG_ULP_COPROC_ENABLED @@ -2533,6 +2537,15 @@ uint32_t esp_sleep_get_wakeup_causes(void) uint32_t wakeup_cause_raw = rtc_cntl_ll_get_wakeup_cause(); #endif +#if SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE + /* LP store register to read wakeup cause saved by LP core. + * Must match the register used in lp_core_utils.c */ + uint32_t lp_core_wakeup_cause_status0 = lp_aon_hal_load_wakeup_cause(); + if ((wakeup_cause_raw == 0) && (lp_core_wakeup_cause_status0 != 0)) { + wakeup_cause_raw = lp_core_wakeup_cause_status0; + } +#endif + if (wakeup_cause_raw & RTC_TIMER_TRIG_EN) { wakeup_cause |= BIT(ESP_SLEEP_WAKEUP_TIMER); } diff --git a/components/esp_rom/esp32c5/include/esp32c5/rom/rtc.h b/components/esp_rom/esp32c5/include/esp32c5/rom/rtc.h index a1cbfccc9e..be177cebdd 100644 --- a/components/esp_rom/esp32c5/include/esp32c5/rom/rtc.h +++ b/components/esp_rom/esp32c5/include/esp32c5/rom/rtc.h @@ -51,7 +51,8 @@ extern "C" { * LP_AON_STORE6_REG FAST_RTC_MEMORY_ENTRY * LP_AON_STORE7_REG FAST_RTC_MEMORY_CRC * LP_AON_STORE8_REG Store light sleep wake stub addr - * LP_AON_STORE9_REG Store the sleep mode at bit[0] (0:light sleep 1:deep sleep) + * LP_AON_STORE8_REG Store the sleep mode at bit[0] (0:light sleep 1:deep sleep) + * LP_AON_STORE9_REG LP core store wakeup cause ************************************************************************************* */ @@ -64,6 +65,7 @@ extern "C" { #define RTC_MEMORY_CRC_REG LP_AON_STORE7_REG #define RTC_SLEEP_WAKE_STUB_ADDR_REG LP_AON_STORE8_REG #define RTC_SLEEP_MODE_REG LP_AON_STORE8_REG +#define RTC_LP_CORE_STORE_WAKEUP_REG LP_AON_STORE9_REG #define RTC_DISABLE_ROM_LOG ((1 << 0) | (1 << 16)) //!< Disable logging from the ROM code. diff --git a/components/esp_rom/esp32c6/include/esp32c6/rom/rtc.h b/components/esp_rom/esp32c6/include/esp32c6/rom/rtc.h index 70a868df41..a8d34a0ece 100644 --- a/components/esp_rom/esp32c6/include/esp32c6/rom/rtc.h +++ b/components/esp_rom/esp32c6/include/esp32c6/rom/rtc.h @@ -53,6 +53,7 @@ extern "C" { * LP_AON_STORE7_REG FAST_RTC_MEMORY_CRC * LP_AON_STORE8_REG Store light sleep wake stub addr * LP_AON_STORE9_REG Store the sleep mode at bit[0] (0:light sleep 1:deep sleep) + * LP_AON_STORE9_REG LP core store wakeup cause at bit[31:2] ************************************************************************************* */ @@ -66,6 +67,7 @@ extern "C" { #define RTC_MEMORY_CRC_REG LP_AON_STORE7_REG #define RTC_SLEEP_WAKE_STUB_ADDR_REG LP_AON_STORE8_REG #define RTC_SLEEP_MODE_REG LP_AON_STORE9_REG +#define RTC_LP_CORE_STORE_WAKEUP_REG LP_AON_STORE9_REG #define RTC_DISABLE_ROM_LOG ((1 << 0) | (1 << 16)) //!< Disable logging from the ROM code. diff --git a/components/esp_rom/esp32p4/include/esp32p4/rom/rtc.h b/components/esp_rom/esp32p4/include/esp32p4/rom/rtc.h index 6eccaa9ba5..d3c39b0e1e 100644 --- a/components/esp_rom/esp32p4/include/esp32p4/rom/rtc.h +++ b/components/esp_rom/esp32p4/include/esp32p4/rom/rtc.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -53,17 +53,19 @@ extern "C" { * LP_SYS_LP_STORE8_REG sleep mode and wake stub address * LP_SYS_LP_STORE9_REG LP_UART_INIT_CTRL * LP_SYS_LP_STORE10_REG LP_ROM_LOG_CTRL + * LP_SYS_LP_STORE11_REG LP core store wakeup cause ************************************************************************************* */ -#define RTC_SLOW_CLK_CAL_REG LP_SYSTEM_REG_LP_STORE1_REG -#define RTC_BOOT_TIME_LOW_REG LP_SYSTEM_REG_LP_STORE2_REG -#define RTC_BOOT_TIME_HIGH_REG LP_SYSTEM_REG_LP_STORE3_REG -#define RTC_XTAL_FREQ_REG LP_SYSTEM_REG_LP_STORE4_REG -#define RTC_APB_FREQ_REG LP_SYSTEM_REG_LP_STORE5_REG -#define RTC_ENTRY_ADDR_REG LP_SYSTEM_REG_LP_STORE6_REG -#define RTC_RESET_CAUSE_REG LP_SYSTEM_REG_LP_STORE6_REG -#define RTC_MEMORY_CRC_REG LP_SYSTEM_REG_LP_STORE7_REG +#define RTC_SLOW_CLK_CAL_REG LP_SYSTEM_REG_LP_STORE1_REG +#define RTC_BOOT_TIME_LOW_REG LP_SYSTEM_REG_LP_STORE2_REG +#define RTC_BOOT_TIME_HIGH_REG LP_SYSTEM_REG_LP_STORE3_REG +#define RTC_XTAL_FREQ_REG LP_SYSTEM_REG_LP_STORE4_REG +#define RTC_APB_FREQ_REG LP_SYSTEM_REG_LP_STORE5_REG +#define RTC_ENTRY_ADDR_REG LP_SYSTEM_REG_LP_STORE6_REG +#define RTC_RESET_CAUSE_REG LP_SYSTEM_REG_LP_STORE6_REG +#define RTC_MEMORY_CRC_REG LP_SYSTEM_REG_LP_STORE7_REG +#define RTC_LP_CORE_STORE_WAKEUP_REG LP_SYSTEM_REG_LP_STORE11_REG #define RTC_DISABLE_ROM_LOG ((1 << 0) | (1 << 16)) //!< Disable logging from the ROM code. diff --git a/components/esp_rom/esp32s31/include/esp32s31/rom/rtc.h b/components/esp_rom/esp32s31/include/esp32s31/rom/rtc.h index b3d74f4c08..c263ded86b 100644 --- a/components/esp_rom/esp32s31/include/esp32s31/rom/rtc.h +++ b/components/esp_rom/esp32s31/include/esp32s31/rom/rtc.h @@ -46,6 +46,7 @@ extern "C" { * RTC_CNTL_STORE5_REG FAST_RTC_MEMORY_LENGTH * RTC_CNTL_STORE6_REG FAST_RTC_MEMORY_ENTRY * RTC_CNTL_STORE7_REG FAST_RTC_MEMORY_CRC + * RTC_CNTL_STORE9_REG LP core store wakeup cause ************************************************************************************* */ @@ -56,6 +57,7 @@ extern "C" { #define RTC_ENTRY_ADDR_REG LP_SYSTEM_REG_LP_STORE6_REG #define RTC_RESET_CAUSE_REG LP_SYSTEM_REG_LP_STORE6_REG #define RTC_MEMORY_CRC_REG LP_SYSTEM_REG_LP_STORE7_REG +#define RTC_LP_CORE_STORE_WAKEUP_REG LP_SYSTEM_REG_LP_STORE9_REG // light sleep /* use LP_SYS_LP_STORE8_REG to store light sleep wake stub addr and sleep mode for dualcore diff --git a/components/hal/esp32c5/include/hal/lp_aon_hal.h b/components/hal/esp32c5/include/hal/lp_aon_hal.h index 2090a64928..9854ef3b0e 100644 --- a/components/hal/esp32c5/include/hal/lp_aon_hal.h +++ b/components/hal/esp32c5/include/hal/lp_aon_hal.h @@ -15,3 +15,6 @@ #define rtc_hal_ext1_get_wakeup_pins() lp_aon_ll_ext1_get_wakeup_pins() #define lp_aon_hal_inform_wakeup_type(dslp) lp_aon_ll_inform_wakeup_type(dslp) + +#define lp_aon_hal_store_wakeup_cause(wakeup_cause) lp_aon_ll_store_wakeup_cause(wakeup_cause) +#define lp_aon_hal_load_wakeup_cause() lp_aon_ll_load_wakeup_cause() diff --git a/components/hal/esp32c5/include/hal/lp_aon_ll.h b/components/hal/esp32c5/include/hal/lp_aon_ll.h index e36779941a..f077dc59c8 100644 --- a/components/hal/esp32c5/include/hal/lp_aon_ll.h +++ b/components/hal/esp32c5/include/hal/lp_aon_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -85,6 +85,24 @@ static inline void lp_aon_ll_inform_wakeup_type(bool dslp) } } +/** + * @brief Set the wakeup cause stored by LP core + * @param wakeup_cause The wakeup cause in PMU register + */ +static inline void lp_aon_ll_store_wakeup_cause(uint32_t wakeup_cause) +{ + REG_WRITE(RTC_LP_CORE_STORE_WAKEUP_REG, wakeup_cause); +} + +/** + * @brief Get the wakeup cause stored by LP core + * @return The wakeup cause cleared before LP core sleep + */ +static inline uint32_t lp_aon_ll_load_wakeup_cause(void) +{ + return REG_READ(RTC_LP_CORE_STORE_WAKEUP_REG); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32c6/include/hal/lp_aon_hal.h b/components/hal/esp32c6/include/hal/lp_aon_hal.h index 86a8849239..d409cdbb22 100644 --- a/components/hal/esp32c6/include/hal/lp_aon_hal.h +++ b/components/hal/esp32c6/include/hal/lp_aon_hal.h @@ -13,6 +13,8 @@ extern "C" { #endif #define lp_aon_hal_inform_wakeup_type(dslp) lp_aon_ll_inform_wakeup_type(dslp) +#define lp_aon_hal_store_wakeup_cause(wakeup_cause) lp_aon_ll_store_wakeup_cause(wakeup_cause) +#define lp_aon_hal_load_wakeup_cause() lp_aon_ll_load_wakeup_cause() #ifdef __cplusplus } diff --git a/components/hal/esp32c6/include/hal/lp_aon_ll.h b/components/hal/esp32c6/include/hal/lp_aon_ll.h index 2283a0dff6..d2ce851402 100644 --- a/components/hal/esp32c6/include/hal/lp_aon_ll.h +++ b/components/hal/esp32c6/include/hal/lp_aon_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -85,6 +85,24 @@ static inline void lp_aon_ll_inform_wakeup_type(bool dslp) } } +/** + * @brief Set the wakeup cause stored by LP core + * @param wakeup_cause The wakeup cause in PMU register + */ +static inline void lp_aon_ll_store_wakeup_cause(uint32_t wakeup_cause) +{ + REG_WRITE(RTC_LP_CORE_STORE_WAKEUP_REG, (REG_READ(RTC_LP_CORE_STORE_WAKEUP_REG) & 0x1) | ((wakeup_cause << 1) & 0xFFFFFFFE)); +} + +/** + * @brief Get the wakeup cause stored by LP core + * @return The wakeup cause cleared before LP core sleep + */ +static inline uint32_t lp_aon_ll_load_wakeup_cause(void) +{ + return (REG_READ(RTC_LP_CORE_STORE_WAKEUP_REG) & 0xFFFFFFFE) >> 1; +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32p4/include/hal/lp_aon_hal.h b/components/hal/esp32p4/include/hal/lp_aon_hal.h index 31d7c57485..6152d3b952 100644 --- a/components/hal/esp32p4/include/hal/lp_aon_hal.h +++ b/components/hal/esp32p4/include/hal/lp_aon_hal.h @@ -13,6 +13,8 @@ extern "C" { #endif #define lp_aon_hal_inform_wakeup_type(dslp) lp_sys_ll_inform_wakeup_type(dslp) +#define lp_aon_hal_store_wakeup_cause(wakeup_cause) lp_sys_ll_store_wakeup_cause(wakeup_cause) +#define lp_aon_hal_load_wakeup_cause() lp_sys_ll_load_wakeup_cause() #ifdef __cplusplus } diff --git a/components/hal/esp32p4/include/hal/lp_sys_ll.h b/components/hal/esp32p4/include/hal/lp_sys_ll.h index 366edbd4d5..71d5371e9a 100644 --- a/components/hal/esp32p4/include/hal/lp_sys_ll.h +++ b/components/hal/esp32p4/include/hal/lp_sys_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -81,6 +81,25 @@ FORCE_INLINE_ATTR void lp_sys_ll_set_lp_mem_lowpower_mode(uint32_t mode) LP_SYS.lp_mem_aux_ctrl.lp_mem_lowpower_mode = mode; } #endif + +/** + * @brief Set the wakeup cause stored by LP core + * @param wakeup_cause The wakeup cause in PMU register + */ +static inline void lp_sys_ll_store_wakeup_cause(uint32_t wakeup_cause) +{ + REG_WRITE(RTC_LP_CORE_STORE_WAKEUP_REG, wakeup_cause); +} + +/** + * @brief Get the wakeup cause stored by LP core + * @return The wakeup cause cleared before LP core sleep + */ +static inline uint32_t lp_sys_ll_load_wakeup_cause(void) +{ + return REG_READ(RTC_LP_CORE_STORE_WAKEUP_REG); +} + #ifdef __cplusplus } #endif diff --git a/components/hal/esp32s31/include/hal/lp_aon_hal.h b/components/hal/esp32s31/include/hal/lp_aon_hal.h index e996c5d567..31b61e522d 100644 --- a/components/hal/esp32s31/include/hal/lp_aon_hal.h +++ b/components/hal/esp32s31/include/hal/lp_aon_hal.h @@ -13,6 +13,8 @@ extern "C" { #endif #define lp_aon_hal_inform_wakeup_type(dslp) lp_sys_ll_inform_wakeup_type(dslp) +#define lp_aon_hal_store_wakeup_cause(wakeup_cause) lp_sys_ll_store_wakeup_cause(wakeup_cause) +#define lp_aon_hal_load_wakeup_cause() lp_sys_ll_load_wakeup_cause() #ifdef __cplusplus } diff --git a/components/hal/esp32s31/include/hal/lp_sys_ll.h b/components/hal/esp32s31/include/hal/lp_sys_ll.h index bee101c9e9..3b78f818eb 100644 --- a/components/hal/esp32s31/include/hal/lp_sys_ll.h +++ b/components/hal/esp32s31/include/hal/lp_sys_ll.h @@ -65,6 +65,24 @@ static inline void lp_sys_set_regdma_link_count(int count) HAL_FORCE_MODIFY_U32_REG_FIELD(LP_SYS.backup_dma_cfg1, branch_link_length_aon, count); } +/** + * @brief Set the wakeup cause stored by LP core + * @param wakeup_cause The wakeup cause in PMU register + */ +static inline void lp_sys_ll_store_wakeup_cause(uint32_t wakeup_cause) +{ + REG_WRITE(RTC_LP_CORE_STORE_WAKEUP_REG, wakeup_cause); +} + +/** + * @brief Get the wakeup cause stored by LP core + * @return The wakeup cause cleared before LP core sleep + */ +static inline uint32_t lp_sys_ll_load_wakeup_cause(void) +{ + return REG_READ(RTC_LP_CORE_STORE_WAKEUP_REG); +} + #ifdef __cplusplus } #endif diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 06f6153eee..f32b8cb592 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -1614,3 +1614,7 @@ config SOC_LP_CORE_SUPPORT_STORE_LOAD_EXCEPTIONS config SOC_LP_CORE_SUPPORT_I2C bool default y + +config SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE + bool + default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index 3bd4e6c93a..dfb1e5755c 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -645,3 +645,4 @@ #define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM */ #define SOC_LP_CORE_SUPPORT_STORE_LOAD_EXCEPTIONS (1) /*!< LP Core will raise exceptions if accessing invalid addresses */ #define SOC_LP_CORE_SUPPORT_I2C (1) /*!< LP Core supports I2C */ +#define SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE (1) /*!< LP core requests sleep, PMU clears both HP and LP wakeup causes */ diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index c67adadfb8..b2863279a6 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1363,6 +1363,10 @@ config SOC_LP_CORE_SUPPORT_I2C bool default y +config SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE + bool + default y + config SOC_DEBUG_HAVE_OCD_STUB_BINS bool default y diff --git a/components/soc/esp32c6/include/soc/soc_caps.h b/components/soc/esp32c6/include/soc/soc_caps.h index 2ba2685ec0..2f84c538d4 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -554,6 +554,7 @@ #define SOC_LP_CORE_SINGLE_INTERRUPT_VECTOR (1) /*!< LP Core interrupts all map to a single entry in vector table */ #define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM */ #define SOC_LP_CORE_SUPPORT_I2C (1) /*!< LP Core supports I2C */ +#define SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE (1) /*!< LP core requests sleep, PMU clears both HP and LP wakeup causes */ /*------------------------------------- DEBUG CAPS -------------------------------------*/ #define SOC_DEBUG_HAVE_OCD_STUB_BINS (1) diff --git a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in index 346fb42b51..5cc4fdd166 100644 --- a/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32p4/include/soc/Kconfig.soc_caps.in @@ -1922,3 +1922,7 @@ config SOC_LP_CORE_SUPPORT_STORE_LOAD_EXCEPTIONS config SOC_LP_CORE_SUPPORT_I2C bool default y + +config SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE + bool + default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index d2eb31aad4..d90ea26e28 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -736,3 +736,4 @@ #define SOC_LP_CORE_SUPPORT_LP_ADC (1) /*!< LP ADC can be accessed from the LP-Core */ #define SOC_LP_CORE_SUPPORT_STORE_LOAD_EXCEPTIONS (1) /*!< LP Core will raise exceptions if accessing invalid addresses */ #define SOC_LP_CORE_SUPPORT_I2C (1) /*!< LP Core supports I2C */ +#define SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE (1) /*!< LP core requests sleep, PMU clears both HP and LP wakeup causes */ diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 33195205bc..3f78329b22 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -1095,6 +1095,10 @@ config SOC_LP_CORE_CONFIGURABLE_BOOT_ADDR bool default y +config SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE + bool + default y + config SOC_LP_TIMER_BIT_WIDTH_LO int default 32 diff --git a/components/soc/esp32s31/include/soc/soc_caps.h b/components/soc/esp32s31/include/soc/soc_caps.h index 596396ffdc..afd9fb845f 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -458,6 +458,7 @@ #define SOC_LP_CORE_SUPPORT_ETM (1) /*!< LP Core supports ETM wakeup */ #define SOC_LP_CORE_CONFIGURABLE_BOOT_ADDR (1) /*!< LP Core has no LP ROM; HP must write the reset_vector address (LP_RAM_BASE+0x80) to LP_SYS.lp_core_boot_addr before triggering LP wake */ //#define SOC_LP_CORE_SUPPORT_I2C (1) /*!< LP Core supports I2C */ TODO IDF-14635 +#define SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE (1) /*!< LP core requests sleep, PMU clears both HP and LP wakeup causes */ /*-------------------------- LP_TIMER CAPS ----------------------------------*/ #define SOC_LP_TIMER_BIT_WIDTH_LO 32 // Bit width of lp_timer low part diff --git a/components/ulp/lp_core/lp_core.c b/components/ulp/lp_core/lp_core.c index dafd947fe4..52bd762e38 100644 --- a/components/ulp/lp_core/lp_core.c +++ b/components/ulp/lp_core/lp_core.c @@ -30,6 +30,11 @@ extern uint8_t _rtc_ulp_memory_start[]; #endif //ESP_ROM_HAS_LP_ROM +#if SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE +#include "hal/lp_aon_hal.h" +#include "rom/rtc.h" +#endif + const static char* TAG = "ulp-lp-core"; #define WAKEUP_SOURCE_MAX_NUMBER 6 @@ -178,6 +183,19 @@ esp_err_t ulp_lp_core_load_binary(const uint8_t* program_binary, size_t program_ return ESP_OK; } +void ulp_lp_core_sleep_start(void) +{ +#if SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE + /* LP store register to save wakeup cause for HP core to query. + * Using a hardware register avoids symbol linking issues between + * the independently compiled HP and LP core binaries. + * Save PMU wakeup cause to LP store register for HP core to query */ + lp_aon_hal_store_wakeup_cause(pmu_ll_hp_get_wakeup_cause(&PMU)); +#endif + + lp_core_ll_request_sleep(); +} + void ulp_lp_core_stop(void) { if (esp_cpu_dbgr_is_attached()) { @@ -191,7 +209,7 @@ void ulp_lp_core_stop(void) } /* Disable wake-up source and put lp core to sleep */ lp_core_ll_set_wakeup_source(0); - lp_core_ll_request_sleep(); + ulp_lp_core_sleep_start(); } void ulp_lp_core_sw_intr_to_lp_trigger(void) diff --git a/components/ulp/lp_core/lp_core/lp_core_utils.c b/components/ulp/lp_core/lp_core/lp_core_utils.c index ff3fe34c7f..f1739d8e96 100644 --- a/components/ulp/lp_core/lp_core/lp_core_utils.c +++ b/components/ulp/lp_core/lp_core/lp_core_utils.c @@ -25,6 +25,10 @@ #include "esp_cpu.h" #include "ulp_lp_core_cpu_freq_shared.h" +#if SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE +#include "hal/lp_aon_hal.h" +#include "rom/rtc.h" +#endif static uint32_t lp_wakeup_cause = 0; @@ -142,9 +146,22 @@ void ulp_lp_core_lp_uart_reset_wakeup_en(void) } #endif +void ulp_lp_core_sleep_start_lp_core(void) +{ +#if SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE + /* LP store register to save wakeup cause for HP core to query. + * Using a hardware register avoids symbol linking issues between + * the independently compiled HP and LP core binaries. + * Save PMU wakeup cause to LP store register for HP core to query */ + lp_aon_hal_store_wakeup_cause(pmu_ll_hp_get_wakeup_cause(&PMU)); +#endif + + lp_core_ll_request_sleep(); +} + void ulp_lp_core_halt(void) { - lp_core_ll_request_sleep(); + ulp_lp_core_sleep_start_lp_core(); while (1); } @@ -153,7 +170,7 @@ void ulp_lp_core_stop_lp_core(void) { /* Disable wake-up source and put lp core to sleep */ lp_core_ll_set_wakeup_source(0); - lp_core_ll_request_sleep(); + ulp_lp_core_sleep_start_lp_core(); } void __attribute__((noreturn)) abort(void) diff --git a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/CMakeLists.txt b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/CMakeLists.txt index 941f808188..40a1cb0bec 100644 --- a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/CMakeLists.txt +++ b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/CMakeLists.txt @@ -59,6 +59,10 @@ if(CONFIG_SOC_LP_VAD_SUPPORTED) set(lp_core_sources_vad "lp_core/test_main_vad.c") endif() +if(CONFIG_SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE) + set(lp_core_sources_halt "lp_core/test_main_halt.c") +endif() + idf_component_register(SRCS ${app_sources} INCLUDE_DIRS "lp_core" REQUIRES ulp unity esp_timer test_utils @@ -105,3 +109,7 @@ ulp_embed_binary(lp_core_test_app_prefix1 "lp_core/test_main_prefix1.c" "${lp_c ulp_embed_binary(lp_core_test_app_prefix2 "lp_core/test_main_prefix2.c" "${lp_core_exp_dep_srcs}" PREFIX "ulp2_") ulp_embed_binary(lp_core_test_app_exception "lp_core/test_main_exception.c" "${lp_core_exp_dep_srcs}") + +if(CONFIG_SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE) + ulp_embed_binary(lp_core_test_app_halt "lp_core/test_main_halt.c" "${lp_core_exp_dep_srcs}") +endif() diff --git a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_exception.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_exception.c index fc6b14ad0a..df9177898b 100644 --- a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_exception.c +++ b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_exception.c @@ -1,10 +1,16 @@ /* - * SPDX-FileCopyrightText: 2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2025-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ +#include "ulp_lp_core_utils.h" + int main(void) { + // Wait for 1 second to ensure the HP Core enters deep sleep + ulp_lp_core_delay_us(1000000); + + // Trigger an exception to wake up the HP Core asm volatile("unimp"); } diff --git a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_halt.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_halt.c new file mode 100644 index 0000000000..12b8ebfa26 --- /dev/null +++ b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_halt.c @@ -0,0 +1,20 @@ +/* + * SPDX-FileCopyrightText: 2026 Espressif Systems (Shanghai) CO LTD + * + * SPDX-License-Identifier: Apache-2.0 + */ + +#include +#include "ulp_lp_core_utils.h" +#include "hal/lp_core_ll.h" + +int main(void) +{ + // Wait for 1 second to ensure the HP Core enters deep sleep + ulp_lp_core_delay_us(1000000); + + ulp_lp_core_wakeup_main_processor(); + /* Disable wake-up source and put lp core to sleep */ + lp_core_ll_set_wakeup_source(0); + ulp_lp_core_halt(); +} diff --git a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_shared.h b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_shared.h index d1d07d9327..bb2744406f 100644 --- a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_shared.h +++ b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_shared.h @@ -22,6 +22,7 @@ typedef enum { LP_CORE_DELAY_US_CALIBRATION_TEST, LP_CORE_DEEP_SLEEP_WAKEUP_SHORT_DELAY_TEST, LP_CORE_DEEP_SLEEP_WAKEUP_LONG_DELAY_TEST, + LP_CORE_HALT_TEST, LP_CORE_LP_UART_WRITE_TEST, LP_CORE_LP_UART_READ_TEST, LP_CORE_LP_UART_MULTI_BYTE_READ_TEST, diff --git a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core.c index 7250304a03..15ae54832a 100644 --- a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core.c +++ b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/test_lp_core.c @@ -40,6 +40,12 @@ #include "hal/lp_core_ll.h" #include "hal/rtc_io_ll.h" #include "driver/rtc_io.h" +#if SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE +#include "rom/rtc.h" +#include "esp_private/esp_pmu.h" +#include "lp_core_test_app_halt.h" +#include "hal/lp_aon_hal.h" +#endif extern const uint8_t lp_core_main_bin_start[] asm("_binary_lp_core_test_app_bin_start"); extern const uint8_t lp_core_main_bin_end[] asm("_binary_lp_core_test_app_bin_end"); @@ -64,6 +70,11 @@ extern const uint8_t lp_core_main_isr_bin_end[] asm("_binary_lp_core_test_app_ extern const uint8_t lp_core_main_exception_bin_start[] asm("_binary_lp_core_test_app_exception_bin_start"); extern const uint8_t lp_core_main_exception_bin_end[] asm("_binary_lp_core_test_app_exception_bin_end"); +#if SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE +extern const uint8_t lp_core_main_halt_bin_start[] asm("_binary_lp_core_test_app_halt_bin_start"); +extern const uint8_t lp_core_main_halt_bin_end[] asm("_binary_lp_core_test_app_halt_bin_end"); +#endif + static void load_and_start_lp_core_firmware(ulp_lp_core_cfg_t* cfg, const uint8_t* firmware_start, const uint8_t* firmware_end) { TEST_ASSERT(ulp_lp_core_load_binary(firmware_start, @@ -648,4 +659,43 @@ static void check_reset_reason_ulp_trap_wakeup(void) TEST_CASE_MULTIPLE_STAGES("LP-core exception can wakeup main cpu", "[ulp]", lp_core_prep_exception_wakeup, check_reset_reason_ulp_trap_wakeup); + +#if SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE +static void do_ulp_wakeup_with_lp_timer_deepsleep_and_halt(void) +{ + /* Load ULP firmware and start the coprocessor */ + ulp_lp_core_cfg_t cfg = { + .wakeup_source = ULP_LP_CORE_WAKEUP_SOURCE_LP_TIMER, + .lp_timer_sleep_duration_us = 1000000, // 1 second +#if ESP_ROM_HAS_LP_ROM + /* ROM Boot takes quite a bit longer, which skews the numbers of wake-ups. skip rom boot to keep the calculation simple */ + .skip_lp_rom_boot = true, +#endif + }; + + load_and_start_lp_core_firmware(&cfg, lp_core_main_halt_bin_start, lp_core_main_halt_bin_end); + + /* Setup wakeup triggers */ + TEST_ASSERT(esp_sleep_enable_ulp_wakeup() == ESP_OK); + + /* Enter Deep Sleep */ + esp_deep_sleep_start(); + + UNITY_TEST_FAIL(__LINE__, "Should not get here!"); +} + +static void check_hp_core_wakeup_cause_saved(void) +{ + uint32_t lp_core_wakeup_cause_status0 = lp_aon_hal_load_wakeup_cause(); + TEST_ASSERT_EQUAL(RTC_LP_CORE_TRIG_EN, lp_core_wakeup_cause_status0 & RTC_LP_CORE_TRIG_EN); + TEST_ASSERT_EQUAL(BIT(ESP_SLEEP_WAKEUP_ULP), esp_sleep_get_wakeup_causes() & BIT(ESP_SLEEP_WAKEUP_ULP)); + + clear_test_cmds(); +} + +TEST_CASE_MULTIPLE_STAGES("HP core wakeup causes are saved after LP core halt", "[ulp]", + do_ulp_wakeup_with_lp_timer_deepsleep_and_halt, + check_hp_core_wakeup_cause_saved); +#endif //SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE + #endif //SOC_DEEP_SLEEP_SUPPORTED