From 46ff88717ca78f5a39b72fa2bc3a2b96a84fc8da Mon Sep 17 00:00:00 2001 From: hebinglin Date: Fri, 5 Jun 2026 20:01:15 +0800 Subject: [PATCH] fix(ulp): fix lp uart keep wakeup triggered --- .../esp32c5/include/soc/Kconfig.soc_caps.in | 4 +++ components/soc/esp32c5/include/soc/soc_caps.h | 1 + .../esp32c6/include/soc/Kconfig.soc_caps.in | 4 +++ components/soc/esp32c6/include/soc/soc_caps.h | 1 + .../esp32p4/include/soc/Kconfig.soc_caps.in | 4 +++ components/soc/esp32p4/include/soc/soc_caps.h | 1 + .../esp32s31/include/soc/Kconfig.soc_caps.in | 4 +++ .../soc/esp32s31/include/soc/soc_caps.h | 1 + .../ulp/lp_core/lp_core/lp_core_utils.c | 26 ++++++++++++------- .../include/ulp_lp_core_lp_uart_shared.h | 9 ++++--- .../main/lp_core/test_main_uart_wakeup.c | 10 +++---- docs/en/api-reference/system/sleep_modes.rst | 6 +++-- .../api-reference/system/sleep_modes.rst | 6 +++-- .../main/lp_core/main.c | 9 +++---- 14 files changed, 57 insertions(+), 29 deletions(-) diff --git a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in index 91063efa613..3440d12e43a 100644 --- a/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c5/include/soc/Kconfig.soc_caps.in @@ -1606,3 +1606,7 @@ config SOC_LP_CORE_SUPPORT_I2C config SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE bool default y + +config SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED + bool + default y diff --git a/components/soc/esp32c5/include/soc/soc_caps.h b/components/soc/esp32c5/include/soc/soc_caps.h index ae82fe8a1e2..c90fb873eff 100644 --- a/components/soc/esp32c5/include/soc/soc_caps.h +++ b/components/soc/esp32c5/include/soc/soc_caps.h @@ -639,3 +639,4 @@ #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 */ +#define SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED (1) /*!< LP UART wakeup source is kept triggered */ diff --git a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in index 36a8f2f068e..976f556501f 100644 --- a/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32c6/include/soc/Kconfig.soc_caps.in @@ -1343,6 +1343,10 @@ config SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE bool default y +config SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED + 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 88f51d69f1a..09bec1f163f 100644 --- a/components/soc/esp32c6/include/soc/soc_caps.h +++ b/components/soc/esp32c6/include/soc/soc_caps.h @@ -544,6 +544,7 @@ #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 */ +#define SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED (1) /*!< LP UART wakeup source is kept triggered */ /*------------------------------------- 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 a49d6378765..8e1f7041273 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_I2C config SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE bool default y + +config SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED + bool + default y diff --git a/components/soc/esp32p4/include/soc/soc_caps.h b/components/soc/esp32p4/include/soc/soc_caps.h index 5eade623e78..121bbe74711 100644 --- a/components/soc/esp32p4/include/soc/soc_caps.h +++ b/components/soc/esp32p4/include/soc/soc_caps.h @@ -735,3 +735,4 @@ #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 */ +#define SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED (1) /*!< LP UART wakeup source is kept triggered */ diff --git a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in index 4aed35e6376..d0e9bdf51b4 100644 --- a/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in +++ b/components/soc/esp32s31/include/soc/Kconfig.soc_caps.in @@ -1547,6 +1547,10 @@ config SOC_LP_CORE_HAS_PMP bool default y +config SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED + 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 eb9ae8eaa7f..91b7a0f98a1 100644 --- a/components/soc/esp32s31/include/soc/soc_caps.h +++ b/components/soc/esp32s31/include/soc/soc_caps.h @@ -576,6 +576,7 @@ #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 */ #define SOC_LP_CORE_HAS_PMP (1) /*!< LP Core RISC-V has 16 PMP entries (128-byte granularity, RISC-V v1.10) */ +#define SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED (1) /*!< LP UART wakeup source is kept triggered */ /*-------------------------- 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/lp_core_utils.c b/components/ulp/lp_core/lp_core/lp_core_utils.c index 2ba6464aeec..dc987c272cb 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,8 @@ #include "esp_cpu.h" #include "ulp_lp_core_cpu_freq_shared.h" +#include "ulp_lp_core_lp_uart_shared.h" +#include "ulp_lp_core_uart.h" #if SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE #include "hal/lp_aon_hal.h" #include "rom/rtc.h" @@ -32,6 +34,14 @@ static uint32_t lp_wakeup_cause = 0; +#if SOC_ULP_LP_UART_SUPPORTED +void ulp_lp_core_lp_uart_reset_wakeup_en(void) +{ + lp_core_ll_enable_lp_uart_wakeup(false); + lp_core_ll_enable_lp_uart_wakeup(true); +} +#endif + void ulp_lp_core_update_wakeup_cause(void) { lp_wakeup_cause = 0; @@ -46,6 +56,13 @@ void ulp_lp_core_update_wakeup_cause(void) && (uart_ll_get_intraw_mask(&LP_UART) & LP_UART_WAKEUP_INT_RAW)) { lp_wakeup_cause |= LP_CORE_LL_WAKEUP_SOURCE_LP_UART; uart_ll_clr_intsts_mask(&LP_UART, LP_UART_WAKEUP_INT_CLR); +#if SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED + // In these chips, the LP UART wakeup source is kept triggered, so we need to + // reset the wakeup register and flush the UART buffer manually after waking up. + lp_core_uart_tx_flush(LP_UART_NUM_0); + lp_core_uart_clear_buf(); + ulp_lp_core_lp_uart_reset_wakeup_en(); +#endif } #endif @@ -141,15 +158,6 @@ void ulp_lp_core_delay_cycles(uint32_t cycles) } } -#if SOC_ULP_LP_UART_SUPPORTED - -void ulp_lp_core_lp_uart_reset_wakeup_en(void) -{ - lp_core_ll_enable_lp_uart_wakeup(false); - lp_core_ll_enable_lp_uart_wakeup(true); -} -#endif - void ulp_lp_core_sleep_start_lp_core(void) { #if SOC_LP_CORE_HW_AUTO_CLRWAKEUPCAUSE diff --git a/components/ulp/lp_core/shared/include/ulp_lp_core_lp_uart_shared.h b/components/ulp/lp_core/shared/include/ulp_lp_core_lp_uart_shared.h index 63ff39d0f7d..c51bf35ae8b 100644 --- a/components/ulp/lp_core/shared/include/ulp_lp_core_lp_uart_shared.h +++ b/components/ulp/lp_core/shared/include/ulp_lp_core_lp_uart_shared.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -19,9 +19,10 @@ extern "C" { * * @note This function configures the LP UART wakeup mode. Ensure that the UART has already been initialized * with the lp_core_uart_init() call. - * Once the LP Core wakes up due to the LP UART, the wakeup feature is disabled. - * To re-enable the wakeup from the LP UART, you must call - * ulp_lp_core_lp_uart_reset_wakeup_en() again before the LP core goes to sleep. + * Once the LP Core wakes up due to the LP UART, the wakeup will be kept triggered in the chips with + * SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED. You need to call ulp_lp_core_lp_uart_reset_wakeup_en() + * to reset the wakeup signal and the UART buffer manually after waking up, which is done in ulp + * startup phase. * Also be aware of limitations in different modes mentioned in the uart_wakeup_cfg_t struct. * * diff --git a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_uart_wakeup.c b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_uart_wakeup.c index 54e2f691881..aecb478f326 100644 --- a/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_uart_wakeup.c +++ b/components/ulp/test_apps/lp_core/lp_core_basic_tests/main/lp_core/test_main_uart_wakeup.c @@ -1,19 +1,17 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "ulp_lp_core_utils.h" #include "ulp_lp_core_print.h" -#include "ulp_lp_core_lp_uart_shared.h" -#include "lp_core_uart.h" #include "ulp_lp_core_uart.h" int main(void) { lp_core_printf("Hello world\r\n"); - ulp_lp_core_delay_us(5000); - lp_core_uart_clear_buf(); - ulp_lp_core_lp_uart_reset_wakeup_en(); + lp_core_uart_tx_flush(LP_UART_NUM_0); + + return 0; } diff --git a/docs/en/api-reference/system/sleep_modes.rst b/docs/en/api-reference/system/sleep_modes.rst index 65b57286c60..e7f50c1ce46 100644 --- a/docs/en/api-reference/system/sleep_modes.rst +++ b/docs/en/api-reference/system/sleep_modes.rst @@ -454,9 +454,11 @@ The UART wakeup supports the following modes: #. Initialize the LP UART (call :cpp:func:`lp_core_uart_init`). #. Configure the LP_UART wakeup mode using the :cpp:func:`lp_core_uart_wakeup_setup` function with a :cpp:type:`uart_wakeup_cfg_t` structure, using the same configuration method as HP UART. - .. note:: + .. only:: SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED - Once the LP core wakes up due to LP_UART, you must call :cpp:func:`ulp_lp_core_lp_uart_reset_wakeup_en` or reset the LP UART module to clear the wakeup signal before the LP core goes to sleep, otherwise, it will be repeated wakeup. + .. note:: + + On chips with ``SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED``, the LP UART wakeup signal remains triggered after a wakeup event. The LP core startup flow (:cpp:func:`ulp_lp_core_update_wakeup_cause`) automatically calls :cpp:func:`ulp_lp_core_lp_uart_reset_wakeup_en` and :cpp:func:`lp_core_uart_clear_buf` to clear this state. If the standard startup flow is not used, you must handle this manually; otherwise, repeated wakeups will occur. For example code on LP_UART wakeup, refer to :example:`system/ulp/lp_core/lp_uart/lp_uart_char_seq_wakeup`. diff --git a/docs/zh_CN/api-reference/system/sleep_modes.rst b/docs/zh_CN/api-reference/system/sleep_modes.rst index d0d06ec4c62..8a2ffd80620 100644 --- a/docs/zh_CN/api-reference/system/sleep_modes.rst +++ b/docs/zh_CN/api-reference/system/sleep_modes.rst @@ -454,9 +454,11 @@ UART 唤醒支持以下模式: #. 初始化 LP UART(调用 :cpp:func:`lp_core_uart_init`)。 #. 使用 :cpp:func:`lp_core_uart_wakeup_setup` 函数配置 LP_UART 的唤醒模式,参数使用 :cpp:type:`uart_wakeup_cfg_t` 结构体,配置方式与 HP UART 相同。 - .. note:: + .. only:: SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED - 当 LP 核因 LP_UART 唤醒后,必须在 LP 核进入睡眠前调用 :cpp:func:`ulp_lp_core_lp_uart_reset_wakeup_en` 函数或是复位整个 LP UART 模块以清除唤醒信号,否则会被重复唤醒。 + .. note:: + + 在支持 ``SOC_LP_CORE_LP_UART_WAKEUP_KEEP_TRIGGERED`` 的芯片上,LP UART 唤醒后唤醒信号会保持触发状态。LP 核启动流程(:cpp:func:`ulp_lp_core_update_wakeup_cause`)会自动调用 :cpp:func:`ulp_lp_core_lp_uart_reset_wakeup_en` 和 :cpp:func:`lp_core_uart_clear_buf` 清除该状态。若未走标准启动流程,则需手动处理,否则会被重复唤醒。 有关 LP_UART 唤醒的示例代码,请参考 :example:`system/ulp/lp_core/lp_uart/lp_uart_char_seq_wakeup`。 diff --git a/examples/system/ulp/lp_core/lp_uart/lp_uart_char_seq_wakeup/main/lp_core/main.c b/examples/system/ulp/lp_core/lp_uart/lp_uart_char_seq_wakeup/main/lp_core/main.c index 0bc04ec231b..237842c54c1 100644 --- a/examples/system/ulp/lp_core/lp_uart/lp_uart_char_seq_wakeup/main/lp_core/main.c +++ b/examples/system/ulp/lp_core/lp_uart/lp_uart_char_seq_wakeup/main/lp_core/main.c @@ -1,20 +1,17 @@ /* - * SPDX-FileCopyrightText: 2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2024-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ #include "ulp_lp_core_utils.h" #include "ulp_lp_core_print.h" -#include "ulp_lp_core_lp_uart_shared.h" +#include "ulp_lp_core_uart.h" int main (void) { lp_core_printf("Hello world\r\n"); + lp_core_uart_tx_flush(LP_UART_NUM_0); - // If you want to make it possible to wake up from UART after sleep, - // you have to reset the wakeup register and the UART buffer manually. - // ulp_lp_core_lp_uart_reset_wakeup_en(); - // lp_core_uart_clear_buf(); return 0; }