From 90bf2772ac82d43a7495234f884888091dd5af9e Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Thu, 7 Mar 2024 16:59:20 +0800 Subject: [PATCH] fix(uart): Fix mismatch wakeup rising edges required with the threshold configured Closes https://github.com/espressif/esp-idf/issues/12586 --- components/esp_driver_uart/src/uart.c | 2 +- components/hal/esp32/include/hal/uart_ll.h | 10 ++++++---- components/hal/esp32c2/include/hal/uart_ll.h | 3 ++- components/hal/esp32c3/include/hal/uart_ll.h | 3 ++- components/hal/esp32c5/include/hal/uart_ll.h | 3 ++- components/hal/esp32c6/include/hal/uart_ll.h | 3 ++- components/hal/esp32h2/include/hal/uart_ll.h | 3 ++- components/hal/esp32p4/include/hal/uart_ll.h | 3 ++- components/hal/esp32s2/include/hal/uart_ll.h | 3 ++- components/hal/esp32s3/include/hal/uart_ll.h | 3 ++- docs/en/api-reference/system/sleep_modes.rst | 2 ++ docs/zh_CN/api-reference/system/sleep_modes.rst | 2 ++ examples/system/light_sleep/README.md | 6 ++++-- examples/system/light_sleep/pytest_light_sleep.py | 6 +++--- 14 files changed, 34 insertions(+), 18 deletions(-) diff --git a/components/esp_driver_uart/src/uart.c b/components/esp_driver_uart/src/uart.c index 78abcbca64..83960dcb16 100644 --- a/components/esp_driver_uart/src/uart.c +++ b/components/esp_driver_uart/src/uart.c @@ -1792,7 +1792,7 @@ esp_err_t uart_get_collision_flag(uart_port_t uart_num, bool *collision_flag) esp_err_t uart_set_wakeup_threshold(uart_port_t uart_num, int wakeup_threshold) { ESP_RETURN_ON_FALSE((uart_num < UART_NUM_MAX), ESP_ERR_INVALID_ARG, UART_TAG, "uart_num error"); - ESP_RETURN_ON_FALSE((wakeup_threshold <= UART_THRESHOLD_NUM(uart_num, UART_ACTIVE_THRESHOLD_V) && wakeup_threshold > UART_MIN_WAKEUP_THRESH), ESP_ERR_INVALID_ARG, UART_TAG, + ESP_RETURN_ON_FALSE((wakeup_threshold <= UART_THRESHOLD_NUM(uart_num, UART_ACTIVE_THRESHOLD_V) && wakeup_threshold >= UART_MIN_WAKEUP_THRESH), ESP_ERR_INVALID_ARG, UART_TAG, "wakeup_threshold out of bounds"); UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); uart_hal_set_wakeup_thrd(&(uart_context[uart_num].hal), wakeup_threshold); diff --git a/components/hal/esp32/include/hal/uart_ll.h b/components/hal/esp32/include/hal/uart_ll.h index 2988523c42..218fd52ccd 100644 --- a/components/hal/esp32/include/hal/uart_ll.h +++ b/components/hal/esp32/include/hal/uart_ll.h @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2023 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2024 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -30,7 +30,7 @@ extern "C" { // The timeout calibration factor when using ref_tick #define UART_LL_TOUT_REF_FACTOR_DEFAULT (8) -#define UART_LL_MIN_WAKEUP_THRESH (2) +#define UART_LL_MIN_WAKEUP_THRESH (3) #define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask // Define UART interrupts @@ -692,7 +692,9 @@ FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level) */ FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd) { - hw->sleep_conf.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH; + // System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+2) + // Note: On ESP32, the minimum UART wakeup threshold is 2 + 1 = 3 (UART_ACTIVE_THRESHOLD set to 0 leads to consecutive triggering wakeup) + hw->sleep_conf.active_threshold = wakeup_thrd - (UART_LL_MIN_WAKEUP_THRESH - 1); } /** @@ -834,7 +836,7 @@ FORCE_INLINE_ATTR void uart_ll_get_at_cmd_char(uart_dev_t *hw, uint8_t *cmd_char */ FORCE_INLINE_ATTR uint32_t uart_ll_get_wakeup_thrd(uart_dev_t *hw) { - return hw->sleep_conf.active_threshold + UART_LL_MIN_WAKEUP_THRESH; + return hw->sleep_conf.active_threshold + (UART_LL_MIN_WAKEUP_THRESH - 1); } /** diff --git a/components/hal/esp32c2/include/hal/uart_ll.h b/components/hal/esp32c2/include/hal/uart_ll.h index ed1d1973e5..67eda746fe 100644 --- a/components/hal/esp32c2/include/hal/uart_ll.h +++ b/components/hal/esp32c2/include/hal/uart_ll.h @@ -29,7 +29,7 @@ extern "C" { // Get UART hardware instance with giving uart num #define UART_LL_GET_HW(num) (((num) == UART_NUM_0) ? (&UART0) : (&UART1)) -#define UART_LL_MIN_WAKEUP_THRESH (2) +#define UART_LL_MIN_WAKEUP_THRESH (3) #define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask #define UART_LL_FSM_IDLE (0x0) @@ -675,6 +675,7 @@ FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level) */ FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd) { + // System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+3) hw->sleep_conf.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH; } diff --git a/components/hal/esp32c3/include/hal/uart_ll.h b/components/hal/esp32c3/include/hal/uart_ll.h index 221bee0f0c..9b83168323 100644 --- a/components/hal/esp32c3/include/hal/uart_ll.h +++ b/components/hal/esp32c3/include/hal/uart_ll.h @@ -29,7 +29,7 @@ extern "C" { // Get UART hardware instance with giving uart num #define UART_LL_GET_HW(num) (((num) == UART_NUM_0) ? (&UART0) : (&UART1)) -#define UART_LL_MIN_WAKEUP_THRESH (2) +#define UART_LL_MIN_WAKEUP_THRESH (3) #define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask #define UART_LL_FSM_IDLE (0x0) @@ -678,6 +678,7 @@ FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level) */ FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd) { + // System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+3) hw->sleep_conf.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH; } diff --git a/components/hal/esp32c5/include/hal/uart_ll.h b/components/hal/esp32c5/include/hal/uart_ll.h index 2a86663250..ea56ae3e2e 100644 --- a/components/hal/esp32c5/include/hal/uart_ll.h +++ b/components/hal/esp32c5/include/hal/uart_ll.h @@ -34,7 +34,7 @@ extern "C" { #define UART_LL_REG_FIELD_BIT_SHIFT(hw) (((hw) == &LP_UART) ? 3 : 0) -#define UART_LL_MIN_WAKEUP_THRESH (2) +#define UART_LL_MIN_WAKEUP_THRESH (3) #define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask #define UART_LL_FSM_IDLE (0x0) @@ -897,6 +897,7 @@ FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level) */ FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd) { + // System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+3) hw->sleep_conf2.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH; } diff --git a/components/hal/esp32c6/include/hal/uart_ll.h b/components/hal/esp32c6/include/hal/uart_ll.h index 77602f5e60..88759dde2e 100644 --- a/components/hal/esp32c6/include/hal/uart_ll.h +++ b/components/hal/esp32c6/include/hal/uart_ll.h @@ -33,7 +33,7 @@ extern "C" { #define UART_LL_REG_FIELD_BIT_SHIFT(hw) (((hw) == &LP_UART) ? 3 : 0) -#define UART_LL_MIN_WAKEUP_THRESH (2) +#define UART_LL_MIN_WAKEUP_THRESH (3) #define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask #define UART_LL_FSM_IDLE (0x0) @@ -867,6 +867,7 @@ FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level) */ FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd) { + // System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+3) hw->sleep_conf2.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH; } diff --git a/components/hal/esp32h2/include/hal/uart_ll.h b/components/hal/esp32h2/include/hal/uart_ll.h index f3f63de978..9e018b2bdb 100644 --- a/components/hal/esp32h2/include/hal/uart_ll.h +++ b/components/hal/esp32h2/include/hal/uart_ll.h @@ -29,7 +29,7 @@ extern "C" { // Get UART hardware instance with giving uart num #define UART_LL_GET_HW(num) (((num) == UART_NUM_0) ? (&UART0) : (&UART1)) -#define UART_LL_MIN_WAKEUP_THRESH (2) +#define UART_LL_MIN_WAKEUP_THRESH (3) #define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask #define UART_LL_FSM_IDLE (0x0) @@ -717,6 +717,7 @@ FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level) */ FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd) { + // System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+3) hw->sleep_conf2.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH; } diff --git a/components/hal/esp32p4/include/hal/uart_ll.h b/components/hal/esp32p4/include/hal/uart_ll.h index 49c5e5da98..e3f5a40d6e 100644 --- a/components/hal/esp32p4/include/hal/uart_ll.h +++ b/components/hal/esp32p4/include/hal/uart_ll.h @@ -39,7 +39,7 @@ extern "C" { #define UART_LL_REG_FIELD_BIT_SHIFT(hw) (((hw) == &LP_UART) ? 3 : 0) -#define UART_LL_MIN_WAKEUP_THRESH (2) +#define UART_LL_MIN_WAKEUP_THRESH (3) #define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask #define UART_LL_FSM_IDLE (0x0) @@ -980,6 +980,7 @@ FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level) */ FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd) { + // System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+3) hw->sleep_conf2.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH; } diff --git a/components/hal/esp32s2/include/hal/uart_ll.h b/components/hal/esp32s2/include/hal/uart_ll.h index 6f7a804abc..601cafeeee 100644 --- a/components/hal/esp32s2/include/hal/uart_ll.h +++ b/components/hal/esp32s2/include/hal/uart_ll.h @@ -28,7 +28,7 @@ extern "C" { // Get UART hardware instance with giving uart num #define UART_LL_GET_HW(num) (((num) == UART_NUM_0) ? (&UART0) : (&UART1)) -#define UART_LL_MIN_WAKEUP_THRESH (2) +#define UART_LL_MIN_WAKEUP_THRESH (3) #define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask // Define UART interrupts @@ -633,6 +633,7 @@ FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level) */ FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd) { + // System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+3) hw->sleep_conf.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH; } diff --git a/components/hal/esp32s3/include/hal/uart_ll.h b/components/hal/esp32s3/include/hal/uart_ll.h index 082cf369e5..1924c24111 100644 --- a/components/hal/esp32s3/include/hal/uart_ll.h +++ b/components/hal/esp32s3/include/hal/uart_ll.h @@ -29,7 +29,7 @@ extern "C" { // Get UART hardware instance with giving uart num #define UART_LL_GET_HW(num) (((num) == UART_NUM_0) ? (&UART0) : (((num) == UART_NUM_1) ? (&UART1) : (&UART2))) -#define UART_LL_MIN_WAKEUP_THRESH (2) +#define UART_LL_MIN_WAKEUP_THRESH (3) #define UART_LL_INTR_MASK (0x7ffff) //All interrupt mask #define UART_LL_FSM_IDLE (0x0) @@ -661,6 +661,7 @@ FORCE_INLINE_ATTR void uart_ll_set_dtr_active_level(uart_dev_t *hw, int level) */ FORCE_INLINE_ATTR void uart_ll_set_wakeup_thrd(uart_dev_t *hw, uint32_t wakeup_thrd) { + // System would wakeup when the number of positive edges of RxD signal is larger than or equal to (UART_ACTIVE_THRESHOLD+3) hw->sleep_conf.active_threshold = wakeup_thrd - UART_LL_MIN_WAKEUP_THRESH; } diff --git a/docs/en/api-reference/system/sleep_modes.rst b/docs/en/api-reference/system/sleep_modes.rst index d142ecd554..e3a4bc2b79 100644 --- a/docs/en/api-reference/system/sleep_modes.rst +++ b/docs/en/api-reference/system/sleep_modes.rst @@ -326,6 +326,8 @@ When {IDF_TARGET_NAME} receives UART input from external devices, it is often ne :cpp:func:`esp_sleep_enable_uart_wakeup` function can be used to enable this wakeup source. +After waking-up from UART, you should send some extra data through the UART port in Active mode, so that the internal wakeup indication signal can be cleared. Otherwises, the next UART wake-up would trigger with two less rising edges than the configured threshold value. + .. only:: esp32c6 or esp32h2 .. note:: diff --git a/docs/zh_CN/api-reference/system/sleep_modes.rst b/docs/zh_CN/api-reference/system/sleep_modes.rst index 511bfd17b1..ae61e1b186 100644 --- a/docs/zh_CN/api-reference/system/sleep_modes.rst +++ b/docs/zh_CN/api-reference/system/sleep_modes.rst @@ -326,6 +326,8 @@ UART 唤醒(仅适用于 Light-sleep 模式) 可调用 :cpp:func:`esp_sleep_enable_uart_wakeup` 函数来启用此唤醒源。 +使用 UART 唤醒之后,在芯片 Active 模式下需要让 UART 接受一些数据用来清零内部的唤醒指示信号。不然的话,下一次 UART 唤醒的触发将只需要比配置的阈值少两个上升沿的数量。 + .. only:: esp32c6 or esp32h2 .. note:: diff --git a/examples/system/light_sleep/README.md b/examples/system/light_sleep/README.md index 97af64fdd9..2b016833c1 100644 --- a/examples/system/light_sleep/README.md +++ b/examples/system/light_sleep/README.md @@ -11,7 +11,7 @@ The example enables the following wakeup sources: - Timer: wake up the chip in 2 seconds - EXT0: wake up the chip if a button attached to GPIO0 is pressed (i.e. if GPIO0 goes low) -- UART0: wake up the chip when the uart rx pin (default GPIO6) receive more than 3 edges. +- UART0: wake up the chip when the uart rx pin receive more than or equal to 3 rising edges. The example also prints time spent in light sleep mode to illustrate that timekeeping continues while the chip is in light sleep. @@ -60,12 +60,14 @@ For this example, the wake-up GPIO is bound to the 'BOOT' button on the board, w For this example, the wake-up UART is bound to the default console port (UART_NUM_0), we can wake-up the chip from light sleep by inputting some keys on the key board. We can see the wake-up reason is `uart` in this case. -Note #1: the UART wake-up threshould is set to 3 in this example, which means the ascii code of the input character should has at least 3 edges, for example, the ascii code of character `0` is `0011 0000` in binary, which only contains 2 edges, so the character `0` is not enough to wakeup the chip. +Note #1: the UART wake-up threshould is set to 3 in this example, which means the ascii code of the input character to wake-up the chip should has at least 3 rising edges (including the stop bit per character), for example, the ascii code of character `0` is `0011 0000` in binary, which only contains 2 rising edges, so the character `0` is not enough to wakeup the chip. Note #2: only UART0 and UART1 (if has) are supported to be configured as wake up source. And for ESP32, we have to use iomux pin for RX signal (i.e. GPIO3 for UART0 & GPIO9 for UART1), otherwise it won't success. Note #3: due to limitation of the HW, the bytes that received during light sleep is only used for waking up, and it will not be received by UART peripheral or passed to the driver. +Note #4: after waking-up from UART, you should send some extra data through the UART port, so that the internal wakeup indication signal can be cleared. Otherwises, the next UART wake-up would trigger with two less rising edges than the configured threshold value. + ### Wake-up by Touch Pad For this example, pressing any registered touch buttons can wake up the chip. diff --git a/examples/system/light_sleep/pytest_light_sleep.py b/examples/system/light_sleep/pytest_light_sleep.py index 7cbdac69d5..4ac3553b55 100644 --- a/examples/system/light_sleep/pytest_light_sleep.py +++ b/examples/system/light_sleep/pytest_light_sleep.py @@ -1,4 +1,4 @@ -# SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD +# SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD # SPDX-License-Identifier: CC0-1.0 import logging import time @@ -52,8 +52,8 @@ def test_light_sleep(dut: Dut) -> None: dut.expect_exact(ENTERING_SLEEP_STR) logging.info('Went to sleep again') - # Write 'U' to uart, 'U' in ascii is 0x55 which contains 8 edges in total - dut.write('U') + # Write 'a' to uart, 'a' in ascii is 0x61 which contains 3 rising edges in total (including the stop bit) + dut.write('a') time.sleep(1) match = dut.expect(EXIT_SLEEP_UART_REGEX) logging.info('Got third sleep period, wakeup from {}, slept for {}'.format(match.group(1), match.group(3)))