From 6b1bfc96cb317496c338b211b0b8ffc7eaacf043 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 5 Feb 2025 16:06:33 +0800 Subject: [PATCH 1/9] fix(uart): fixed coverity ininitialized scalar variable in uart_tcgetattr --- components/vfs/vfs_uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/components/vfs/vfs_uart.c b/components/vfs/vfs_uart.c index a882042088..8fbe1f97d6 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -875,7 +875,7 @@ static int uart_tcgetattr(int fd, struct termios *p) } { - uint32_t baudrate; + uint32_t baudrate = 0; if (uart_get_baudrate(fd, &baudrate) != ESP_OK) { errno = EINVAL; return -1; From 8b0d4a17e61b6c76a5a4a27b88aa3e4268b87389 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Thu, 6 Mar 2025 18:47:41 +0800 Subject: [PATCH 2/9] docs(uart): improve set/get baud rate API docs Closes https://github.com/espressif/esp-idf/issues/15449 --- components/driver/uart/include/driver/uart.h | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) diff --git a/components/driver/uart/include/driver/uart.h b/components/driver/uart/include/driver/uart.h index e78a1c48b2..bf1b2bd2c5 100644 --- a/components/driver/uart/include/driver/uart.h +++ b/components/driver/uart/include/driver/uart.h @@ -37,7 +37,8 @@ extern "C" { * @brief UART configuration parameters for uart_param_config function */ typedef struct { - int baud_rate; /*!< UART baud rate*/ + int baud_rate; /*!< UART baud rate + Note that the actual baud rate set could have a slight deviation from the user-configured value due to rounding error*/ uart_word_length_t data_bits; /*!< UART byte size*/ uart_parity_t parity; /*!< UART parity mode*/ uart_stop_bits_t stop_bits; /*!< UART stop bits*/ @@ -228,7 +229,9 @@ esp_err_t uart_get_parity(uart_port_t uart_num, uart_parity_t* parity_mode); esp_err_t uart_get_sclk_freq(uart_sclk_t sclk, uint32_t* out_freq_hz); /** - * @brief Set UART baud rate. + * @brief Set desired UART baud rate. + * + * Note that the actual baud rate set could have a slight deviation from the user-configured value due to rounding error. * * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param baudrate UART baud rate. @@ -240,7 +243,9 @@ esp_err_t uart_get_sclk_freq(uart_sclk_t sclk, uint32_t* out_freq_hz); esp_err_t uart_set_baudrate(uart_port_t uart_num, uint32_t baudrate); /** - * @brief Get the UART baud rate configuration. + * @brief Get the actual UART baud rate. + * + * It returns the real UART rate set in the hardware. It could have a slight deviation from the user-configured baud rate. * * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1). * @param baudrate Pointer to accept value of UART baud rate From cb75dc37356f378732b91e9451556fdf171b4ed1 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Thu, 13 Mar 2025 19:10:21 +0800 Subject: [PATCH 3/9] fix(sleep): uart suspend/flush should also check if port is enabled on esp32 --- components/esp_hw_support/sleep_modes.c | 6 ------ 1 file changed, 6 deletions(-) diff --git a/components/esp_hw_support/sleep_modes.c b/components/esp_hw_support/sleep_modes.c index 4eb0bb5566..e2955a85b6 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -531,13 +531,9 @@ static void IRAM_ATTR resume_timers(uint32_t pd_flags) { static void IRAM_ATTR flush_uarts(void) { for (int i = 0; i < SOC_UART_HP_NUM; ++i) { -#ifdef CONFIG_IDF_TARGET_ESP32 - esp_rom_uart_tx_wait_idle(i); -#else if (uart_ll_is_enabled(i)) { esp_rom_uart_tx_wait_idle(i); } -#endif } } @@ -551,11 +547,9 @@ FORCE_INLINE_ATTR void suspend_uarts(void) { s_suspended_uarts_bmap = 0; for (int i = 0; i < SOC_UART_HP_NUM; ++i) { -#ifndef CONFIG_IDF_TARGET_ESP32 if (!uart_ll_is_enabled(i)) { continue; } -#endif uart_ll_force_xoff(i); s_suspended_uarts_bmap |= BIT(i); #if SOC_UART_SUPPORT_FSM_TX_WAIT_SEND From e182cfac59b11ae009a9eaa722762e8e05c35965 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 19 Mar 2025 22:00:09 +0800 Subject: [PATCH 4/9] fix(uart): correct C3/S3 module enable porcedure to avoid undesired line noise --- components/hal/esp32c3/include/hal/uart_ll.h | 2 ++ components/hal/esp32s3/include/hal/uart_ll.h | 3 +++ 2 files changed, 5 insertions(+) diff --git a/components/hal/esp32c3/include/hal/uart_ll.h b/components/hal/esp32c3/include/hal/uart_ll.h index dc833a1e04..7b85f6414b 100644 --- a/components/hal/esp32c3/include/hal/uart_ll.h +++ b/components/hal/esp32c3/include/hal/uart_ll.h @@ -107,12 +107,14 @@ static inline void uart_ll_reset_register(uart_port_t uart_num) // ESP32C3 requires a workaround: enable core reset before enabling uart module clock to prevent uart output garbage value switch (uart_num) { case 0: + SYSTEM.perip_rst_en0.reg_uart_rst = 0; UART0.clk_conf.rst_core = 1; SYSTEM.perip_rst_en0.reg_uart_rst = 1; SYSTEM.perip_rst_en0.reg_uart_rst = 0; UART0.clk_conf.rst_core = 0; break; case 1: + SYSTEM.perip_rst_en0.reg_uart1_rst = 0; UART1.clk_conf.rst_core = 1; SYSTEM.perip_rst_en0.reg_uart1_rst = 1; SYSTEM.perip_rst_en0.reg_uart1_rst = 0; diff --git a/components/hal/esp32s3/include/hal/uart_ll.h b/components/hal/esp32s3/include/hal/uart_ll.h index d74b0e7e27..1666cecabd 100644 --- a/components/hal/esp32s3/include/hal/uart_ll.h +++ b/components/hal/esp32s3/include/hal/uart_ll.h @@ -112,18 +112,21 @@ static inline void uart_ll_reset_register(uart_port_t uart_num) // ESP32S3 requires a workaround: enable core reset before enabling uart module clock to prevent uart output garbage value switch (uart_num) { case 0: + SYSTEM.perip_rst_en0.uart_rst = 0; UART0.clk_conf.rst_core = 1; SYSTEM.perip_rst_en0.uart_rst = 1; SYSTEM.perip_rst_en0.uart_rst = 0; UART0.clk_conf.rst_core = 0; break; case 1: + SYSTEM.perip_rst_en0.uart1_rst = 0; UART1.clk_conf.rst_core = 1; SYSTEM.perip_rst_en0.uart1_rst = 1; SYSTEM.perip_rst_en0.uart1_rst = 0; UART1.clk_conf.rst_core = 0; break; case 2: + SYSTEM.perip_rst_en1.uart2_rst = 0; UART2.clk_conf.rst_core = 1; SYSTEM.perip_rst_en1.uart2_rst = 1; SYSTEM.perip_rst_en1.uart2_rst = 0; From 4b7f3ca2107723df757ab0121e2dcd49b8089c23 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Thu, 3 Apr 2025 22:16:28 +0800 Subject: [PATCH 5/9] fix(uart): fix nmea0183 example wrong knots to m/s unit conversion Closes https://github.com/espressif/esp-idf/issues/15695 --- .../peripherals/uart/nmea0183_parser/main/nmea_parser.c | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/examples/peripherals/uart/nmea0183_parser/main/nmea_parser.c b/examples/peripherals/uart/nmea0183_parser/main/nmea_parser.c index 0dbd6ab9d9..3502dca847 100644 --- a/examples/peripherals/uart/nmea0183_parser/main/nmea_parser.c +++ b/examples/peripherals/uart/nmea0183_parser/main/nmea_parser.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2015-2022 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2015-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -264,7 +264,7 @@ static void parse_rmc(esp_gps_t *esp_gps) } break; case 7: /* Process ground speed in unit m/s */ - esp_gps->parent.speed = strtof(esp_gps->item_str, NULL) * 1.852; + esp_gps->parent.speed = strtof(esp_gps->item_str, NULL) * 0.514444; break; case 8: /* Process true course over ground */ esp_gps->parent.cog = strtof(esp_gps->item_str, NULL); @@ -338,7 +338,7 @@ static void parse_vtg(esp_gps_t *esp_gps) esp_gps->parent.variation = strtof(esp_gps->item_str, NULL); break; case 5:/* Process ground speed in unit m/s */ - esp_gps->parent.speed = strtof(esp_gps->item_str, NULL) * 1.852;//knots to m/s + esp_gps->parent.speed = strtof(esp_gps->item_str, NULL) * 0.514444;//knots to m/s break; case 7:/* Process ground speed in unit m/s */ esp_gps->parent.speed = strtof(esp_gps->item_str, NULL) / 3.6;//km/h to m/s @@ -702,7 +702,7 @@ nmea_parser_handle_t nmea_parser_init(const nmea_parser_config_t *config) .task_name = NULL }; if (esp_event_loop_create(&loop_args, &esp_gps->event_loop_hdl) != ESP_OK) { - ESP_LOGE(GPS_TAG, "create event loop faild"); + ESP_LOGE(GPS_TAG, "create event loop failed"); goto err_eloop; } /* Create NMEA Parser task */ From 296e4e9104325316b6ea71bc607632c25ac6e288 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Mon, 19 May 2025 22:18:24 +0800 Subject: [PATCH 6/9] fix(dedic_gpio): fix calloc to heap_caps_calloc --- components/driver/gpio/dedic_gpio.c | 7 ++++--- 1 file changed, 4 insertions(+), 3 deletions(-) diff --git a/components/driver/gpio/dedic_gpio.c b/components/driver/gpio/dedic_gpio.c index b6ddc8e6d1..069382f703 100644 --- a/components/driver/gpio/dedic_gpio.c +++ b/components/driver/gpio/dedic_gpio.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2021 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -31,6 +31,7 @@ #include "hal/dedic_gpio_ll.h" #endif +#define DEDIC_GPIO_MEM_ALLOC_CAPS MALLOC_CAP_DEFAULT static const char *TAG = "dedic_gpio"; @@ -74,7 +75,7 @@ static esp_err_t dedic_gpio_build_platform(int core_id) // prevent building platform concurrently _lock_acquire(&s_platform_mutexlock[core_id]); if (!s_platform[core_id]) { - s_platform[core_id] = calloc(1, sizeof(dedic_gpio_platform_t)); + s_platform[core_id] = (dedic_gpio_platform_t *)heap_caps_calloc(1, sizeof(dedic_gpio_platform_t), DEDIC_GPIO_MEM_ALLOC_CAPS); if (s_platform[core_id]) { // initialize platfrom members s_platform[core_id]->spinlock = (portMUX_TYPE)portMUX_INITIALIZER_UNLOCKED; @@ -205,7 +206,7 @@ esp_err_t dedic_gpio_new_bundle(const dedic_gpio_bundle_config_t *config, dedic_ ESP_GOTO_ON_ERROR(dedic_gpio_build_platform(core_id), err, TAG, "build platform %d failed", core_id); size_t bundle_size = sizeof(dedic_gpio_bundle_t) + config->array_size * sizeof(config->gpio_array[0]); - bundle = calloc(1, bundle_size); + bundle = (dedic_gpio_bundle_t *)heap_caps_calloc(1, bundle_size, DEDIC_GPIO_MEM_ALLOC_CAPS); ESP_GOTO_ON_FALSE(bundle, ESP_ERR_NO_MEM, err, TAG, "no mem for bundle"); // for performance reasons, we only search for continuous channels From 76c20fdb103842f5ebcdfbfa0401982bd481d65c Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Tue, 15 Apr 2025 15:10:17 +0800 Subject: [PATCH 7/9] fix(gpio): add some detailed error log for gpio_pullup_en and gpio_pulldown_en --- components/driver/gpio/gpio.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/components/driver/gpio/gpio.c b/components/driver/gpio/gpio.c index b12d9cdf99..04065df8d8 100644 --- a/components/driver/gpio/gpio.c +++ b/components/driver/gpio/gpio.c @@ -77,7 +77,7 @@ static gpio_context_t gpio_context = { esp_err_t gpio_pullup_en(gpio_num_t gpio_num) { - GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO number error (input-only pad has no internal PU)", ESP_ERR_INVALID_ARG); if (!rtc_gpio_is_valid_gpio(gpio_num) || SOC_GPIO_SUPPORT_RTC_INDEPENDENT) { portENTER_CRITICAL(&gpio_context.gpio_spinlock); @@ -115,7 +115,7 @@ esp_err_t gpio_pullup_dis(gpio_num_t gpio_num) esp_err_t gpio_pulldown_en(gpio_num_t gpio_num) { - GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO number error", ESP_ERR_INVALID_ARG); + GPIO_CHECK(GPIO_IS_VALID_OUTPUT_GPIO(gpio_num), "GPIO number error (input-only pad has no internal PD)", ESP_ERR_INVALID_ARG); if (!rtc_gpio_is_valid_gpio(gpio_num) || SOC_GPIO_SUPPORT_RTC_INDEPENDENT) { portENTER_CRITICAL(&gpio_context.gpio_spinlock); From bd275c1da3f9a6143e0b51c97841a8f8f9ad3a4a Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 23 Apr 2025 15:28:41 +0800 Subject: [PATCH 8/9] feat(uart): add pin release process to uart driver --- components/driver/uart/uart.c | 148 ++++++++++++++++++++++++++-------- 1 file changed, 113 insertions(+), 35 deletions(-) diff --git a/components/driver/uart/uart.c b/components/driver/uart/uart.c index 27f78cf923..af85adb65e 100644 --- a/components/driver/uart/uart.c +++ b/components/driver/uart/uart.c @@ -33,6 +33,9 @@ #include "esp_clk_tree.h" #include "sdkconfig.h" #include "esp_rom_gpio.h" +#if SOC_LP_GPIO_MATRIX_SUPPORTED +#include "soc/lp_gpio_pins.h" +#endif #include "clk_ctrl_os.h" #include "esp_pm.h" #include "esp_private/sleep_retention.h" @@ -104,6 +107,10 @@ static const char *UART_TAG = "uart"; .hal.dev = UART_LL_GET_HW(uart_num), \ INIT_CRIT_SECTION_LOCK_IN_STRUCT(spinlock) \ .hw_enabled = false, \ + .tx_io_num = -1, \ + .rx_io_num = -1, \ + .rts_io_num = -1, \ + .cts_io_num = -1, \ } typedef struct { @@ -169,6 +176,10 @@ typedef struct { bool retention_link_inited; /*!< Mark whether the retention link is inited */ bool retention_link_created; /*!< Mark whether the retention link is created */ #endif + int tx_io_num; + int rx_io_num; + int rts_io_num; + int cts_io_num; } uart_context_t; static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0}; @@ -706,8 +717,63 @@ static bool uart_try_set_iomux_pin(uart_port_t uart_num, int io_num, uint32_t id return true; } -//internal signal can be output to multiple GPIO pads -//only one GPIO pad can connect with input signal +static void uart_release_pin(uart_port_t uart_num) +{ + if (uart_num >= UART_NUM_MAX) { + return; + } + if (uart_context[uart_num].tx_io_num >= 0) { + gpio_ll_output_disable(&GPIO, uart_context[uart_num].tx_io_num); +#if (SOC_UART_LP_NUM >= 1) + if (!(uart_num < SOC_UART_HP_NUM)) { + rtc_gpio_deinit(uart_context[uart_num].tx_io_num); + } +#endif + } + + if (uart_context[uart_num].rx_io_num >= 0) { + if (uart_num < SOC_UART_HP_NUM) { + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false); + } +#if (SOC_UART_LP_NUM >= 1) + else { +#if SOC_LP_GPIO_MATRIX_SUPPORTED + lp_gpio_connect_in_signal(LP_GPIO_MATRIX_CONST_ONE_INPUT, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false); +#endif + rtc_gpio_deinit(uart_context[uart_num].rx_io_num); + } +#endif + } + + if (uart_context[uart_num].rts_io_num >= 0) { + gpio_ll_output_disable(&GPIO, uart_context[uart_num].rts_io_num); +#if (SOC_UART_LP_NUM >= 1) + if (!(uart_num < SOC_UART_HP_NUM)) { + rtc_gpio_deinit(uart_context[uart_num].rts_io_num); + } +#endif + } + + if (uart_context[uart_num].cts_io_num >= 0) { + if (uart_num < SOC_UART_HP_NUM) { + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, UART_PERIPH_SIGNAL(uart_num, SOC_UART_CTS_PIN_IDX), false); + } +#if (SOC_UART_LP_NUM >= 1) + else { +#if SOC_LP_GPIO_MATRIX_SUPPORTED + lp_gpio_connect_in_signal(LP_GPIO_MATRIX_CONST_ZERO_INPUT, UART_PERIPH_SIGNAL(uart_num, SOC_UART_CTS_PIN_IDX), false); +#endif + rtc_gpio_deinit(uart_context[uart_num].cts_io_num); + } +#endif + } + + uart_context[uart_num].tx_io_num = -1; + uart_context[uart_num].rx_io_num = -1; + uart_context[uart_num].rts_io_num = -1; + uart_context[uart_num].cts_io_num = -1; +} + esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num) { ESP_RETURN_ON_FALSE((uart_num >= 0), ESP_FAIL, UART_TAG, "uart_num error"); @@ -739,48 +805,57 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r } #endif + // First, release previously configured IOs if there is + uart_release_pin(uart_num); + // Since an IO cannot route peripheral signals via IOMUX and GPIO matrix at the same time, // if tx and rx share the same IO, both signals need to be route to IOs through GPIO matrix bool tx_rx_same_io = (tx_io_num == rx_io_num); /* In the following statements, if the io_num is negative, no need to configure anything. */ - if (tx_io_num >= 0 && (tx_rx_same_io || !uart_try_set_iomux_pin(uart_num, tx_io_num, SOC_UART_TX_PIN_IDX))) { - if (uart_num < SOC_UART_HP_NUM) { - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[tx_io_num], PIN_FUNC_GPIO); - esp_rom_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0); - // output enable is set inside esp_rom_gpio_connect_out_signal func after the signal is connected - // (output enabled too early may cause unnecessary level change at the pad) - } -#if SOC_LP_GPIO_MATRIX_SUPPORTED - else { - rtc_gpio_init(tx_io_num); // set as a LP_GPIO pin - - lp_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0); - // output enable is set inside lp_gpio_connect_out_signal func after the signal is connected - } -#endif - } - - if (rx_io_num >= 0 && (tx_rx_same_io || !uart_try_set_iomux_pin(uart_num, rx_io_num, SOC_UART_RX_PIN_IDX))) { - if (uart_num < SOC_UART_HP_NUM) { - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rx_io_num], PIN_FUNC_GPIO); - gpio_ll_input_enable(&GPIO, rx_io_num); - esp_rom_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0); - } -#if SOC_LP_GPIO_MATRIX_SUPPORTED - else { - rtc_gpio_mode_t mode = (tx_rx_same_io ? RTC_GPIO_MODE_INPUT_OUTPUT : RTC_GPIO_MODE_INPUT_ONLY); - rtc_gpio_set_direction(rx_io_num, mode); - if (!tx_rx_same_io) { // set the same pin again as a LP_GPIO will overwrite connected out_signal, not desired, so skip - rtc_gpio_init(rx_io_num); // set as a LP_GPIO pin + if (tx_io_num >= 0) { + uart_context[uart_num].tx_io_num = tx_io_num; + if (tx_rx_same_io || !uart_try_set_iomux_pin(uart_num, tx_io_num, SOC_UART_TX_PIN_IDX)) { + if (uart_num < SOC_UART_HP_NUM) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[tx_io_num], PIN_FUNC_GPIO); + esp_rom_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0); + // output enable is set inside esp_rom_gpio_connect_out_signal func after the signal is connected + // (output enabled too early may cause unnecessary level change at the pad) } +#if SOC_LP_GPIO_MATRIX_SUPPORTED + else { + rtc_gpio_init(tx_io_num); // set as a LP_GPIO pin - lp_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0); - } + lp_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0); + // output enable is set inside lp_gpio_connect_out_signal func after the signal is connected + } #endif + } } - if (rts_io_num >= 0 && !uart_try_set_iomux_pin(uart_num, rts_io_num, SOC_UART_RTS_PIN_IDX)) { + if (rx_io_num >= 0) { + uart_context[uart_num].rx_io_num = rx_io_num; + if (tx_rx_same_io || !uart_try_set_iomux_pin(uart_num, rx_io_num, SOC_UART_RX_PIN_IDX)) { + if (uart_num < SOC_UART_HP_NUM) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rx_io_num], PIN_FUNC_GPIO); + gpio_ll_input_enable(&GPIO, rx_io_num); + esp_rom_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0); + } +#if SOC_LP_GPIO_MATRIX_SUPPORTED + else { + rtc_gpio_mode_t mode = (tx_rx_same_io ? RTC_GPIO_MODE_INPUT_OUTPUT : RTC_GPIO_MODE_INPUT_ONLY); + rtc_gpio_set_direction(rx_io_num, mode); + if (!tx_rx_same_io) { // set the same pin again as a LP_GPIO will overwrite connected out_signal, not desired, so skip + rtc_gpio_init(rx_io_num); // set as a LP_GPIO pin + } + + lp_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0); + } +#endif + } + } + + if (rts_io_num >= 0 && (uart_context[uart_num].rts_io_num = rts_io_num, !uart_try_set_iomux_pin(uart_num, rts_io_num, SOC_UART_RTS_PIN_IDX))) { if (uart_num < SOC_UART_HP_NUM) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rts_io_num], PIN_FUNC_GPIO); esp_rom_gpio_connect_out_signal(rts_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RTS_PIN_IDX), 0, 0); @@ -795,7 +870,7 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r #endif } - if (cts_io_num >= 0 && !uart_try_set_iomux_pin(uart_num, cts_io_num, SOC_UART_CTS_PIN_IDX)) { + if (cts_io_num >= 0 && (uart_context[uart_num].cts_io_num = cts_io_num, !uart_try_set_iomux_pin(uart_num, cts_io_num, SOC_UART_CTS_PIN_IDX))) { if (uart_num < SOC_UART_HP_NUM) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[cts_io_num], PIN_FUNC_GPIO); gpio_set_pull_mode(cts_io_num, GPIO_PULLUP_ONLY); @@ -1785,6 +1860,9 @@ esp_err_t uart_driver_delete(uart_port_t uart_num) ESP_LOGI(UART_TAG, "ALREADY NULL"); return ESP_OK; } + + uart_release_pin(uart_num); + esp_intr_free(p_uart_obj[uart_num]->intr_handle); uart_disable_rx_intr(uart_num); uart_disable_tx_intr(uart_num); From d35327153779d9bc302756cc49de04717eeb5025 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 23 Apr 2025 16:13:09 +0800 Subject: [PATCH 9/9] fix(uart): eliminate garbled data on UART TX/RX line in sleep --- components/driver/uart/uart.c | 18 ++++++++++++++++++ 1 file changed, 18 insertions(+) diff --git a/components/driver/uart/uart.c b/components/driver/uart/uart.c index af85adb65e..1839720acd 100644 --- a/components/driver/uart/uart.c +++ b/components/driver/uart/uart.c @@ -728,6 +728,9 @@ static void uart_release_pin(uart_port_t uart_num) if (!(uart_num < SOC_UART_HP_NUM)) { rtc_gpio_deinit(uart_context[uart_num].tx_io_num); } +#endif +#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND || CONFIG_PM_SLP_DISABLE_GPIO + gpio_sleep_sel_en(uart_context[uart_num].tx_io_num); // re-enable the switch to the sleep configuration to save power consumption #endif } @@ -742,6 +745,9 @@ static void uart_release_pin(uart_port_t uart_num) #endif rtc_gpio_deinit(uart_context[uart_num].rx_io_num); } +#endif +#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND || CONFIG_PM_SLP_DISABLE_GPIO + gpio_sleep_sel_en(uart_context[uart_num].rx_io_num); // re-enable the switch to the sleep configuration to save power consumption #endif } @@ -815,6 +821,12 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r /* In the following statements, if the io_num is negative, no need to configure anything. */ if (tx_io_num >= 0) { uart_context[uart_num].tx_io_num = tx_io_num; +#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND || CONFIG_PM_SLP_DISABLE_GPIO + // In such case, IOs are going to switch to sleep configuration (isolate) when entering sleep for power saving reason + // But TX IO in isolate state could write garbled data to the other end + // Therefore, we should disable the switch of the TX pin to sleep configuration + gpio_sleep_sel_dis(tx_io_num); +#endif if (tx_rx_same_io || !uart_try_set_iomux_pin(uart_num, tx_io_num, SOC_UART_TX_PIN_IDX)) { if (uart_num < SOC_UART_HP_NUM) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[tx_io_num], PIN_FUNC_GPIO); @@ -835,6 +847,12 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r if (rx_io_num >= 0) { uart_context[uart_num].rx_io_num = rx_io_num; +#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND || CONFIG_PM_SLP_DISABLE_GPIO + // In such case, IOs are going to switch to sleep configuration (isolate) when entering sleep for power saving reason + // But RX IO in isolate state could receive garbled data into FIFO, which is not desired + // Therefore, we should disable the switch of the RX pin to sleep configuration + gpio_sleep_sel_dis(rx_io_num); +#endif if (tx_rx_same_io || !uart_try_set_iomux_pin(uart_num, rx_io_num, SOC_UART_RX_PIN_IDX)) { if (uart_num < SOC_UART_HP_NUM) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rx_io_num], PIN_FUNC_GPIO);