From 979c7f99a3978c3cfa4c7b91265028f4b5862ac4 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 5 Feb 2025 16:06:33 +0800 Subject: [PATCH 1/7] 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 cf674ab328..2ae1945593 100644 --- a/components/vfs/vfs_uart.c +++ b/components/vfs/vfs_uart.c @@ -879,7 +879,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 2b6ddf64f5d396cf9de3e8302499d628315f7dee Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Thu, 6 Mar 2025 18:47:41 +0800 Subject: [PATCH 2/7] 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 | 8 ++++++-- components/hal/include/hal/uart_types.h | 3 ++- 2 files changed, 8 insertions(+), 3 deletions(-) diff --git a/components/driver/uart/include/driver/uart.h b/components/driver/uart/include/driver/uart.h index 502012d53d..7063594bac 100644 --- a/components/driver/uart/include/driver/uart.h +++ b/components/driver/uart/include/driver/uart.h @@ -208,7 +208,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. @@ -220,7 +222,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 diff --git a/components/hal/include/hal/uart_types.h b/components/hal/include/hal/uart_types.h index 6062d4355a..fdf877c528 100644 --- a/components/hal/include/hal/uart_types.h +++ b/components/hal/include/hal/uart_types.h @@ -118,7 +118,8 @@ typedef struct { * @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*/ From f39c15c80b250cdd2d35ae9929d321c6a069150b Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Thu, 13 Mar 2025 19:10:21 +0800 Subject: [PATCH 3/7] 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 dce4996f42..62a8a43bf1 100644 --- a/components/esp_hw_support/sleep_modes.c +++ b/components/esp_hw_support/sleep_modes.c @@ -532,13 +532,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_NUM; ++i) { -#ifdef CONFIG_IDF_TARGET_ESP32 - esp_rom_uart_tx_wait_idle(i); -#else if (periph_ll_periph_enabled(PERIPH_UART0_MODULE + i)) { esp_rom_uart_tx_wait_idle(i); } -#endif } } @@ -551,11 +547,9 @@ static IRAM_ATTR void suspend_uarts(void) { s_suspended_uarts_bmap = 0; for (int i = 0; i < SOC_UART_NUM; ++i) { -#ifndef CONFIG_IDF_TARGET_ESP32 if (!periph_ll_periph_enabled(PERIPH_UART0_MODULE + i)) { continue; } -#endif uart_ll_force_xoff(i); s_suspended_uarts_bmap |= BIT(i); #if SOC_UART_SUPPORT_FSM_TX_WAIT_SEND From a3db2491a61dd56f4e4031f1d41a2360fd9fe226 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Thu, 3 Apr 2025 22:16:28 +0800 Subject: [PATCH 4/7] 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 9dbebf99459d1ed2bab830c40682b4e021009dab Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Mon, 19 May 2025 22:18:24 +0800 Subject: [PATCH 5/7] 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 a99eac40db6fc8880f4a2dbc76f003faad28fd59 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 23 Apr 2025 15:28:41 +0800 Subject: [PATCH 6/7] feat(uart): add pin release process to uart driver --- components/driver/uart/uart.c | 79 +++++++++++++++++++++++++++-------- 1 file changed, 62 insertions(+), 17 deletions(-) diff --git a/components/driver/uart/uart.c b/components/driver/uart/uart.c index 27d56b3658..08c2d16804 100644 --- a/components/driver/uart/uart.c +++ b/components/driver/uart/uart.c @@ -86,10 +86,14 @@ static const char *UART_TAG = "uart"; // Check actual UART mode set #define UART_IS_MODE_SET(uart_number, mode) ((p_uart_obj[uart_number]->uart_mode == mode)) -#define UART_CONTEX_INIT_DEF(uart_num) {\ - .hal.dev = UART_LL_GET_HW(uart_num),\ - INIT_CRIT_SECTION_LOCK_IN_STRUCT(spinlock)\ - .hw_enabled = false,\ +#define UART_CONTEX_INIT_DEF(uart_num) { \ + .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 { @@ -162,6 +166,10 @@ typedef struct { uart_hal_context_t hal; /*!< UART hal context*/ DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(spinlock) bool hw_enabled; + 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}; @@ -614,8 +622,33 @@ 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 (uart_context[uart_num].rx_io_num >= 0) { + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false); + } + + if (uart_context[uart_num].rts_io_num >= 0) { + gpio_ll_output_disable(&GPIO, uart_context[uart_num].rts_io_num); + } + + if (uart_context[uart_num].cts_io_num >= 0) { + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, UART_PERIPH_SIGNAL(uart_num, SOC_UART_CTS_PIN_IDX), false); + } + + 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"); @@ -625,31 +658,40 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r ESP_RETURN_ON_FALSE((rts_io_num < 0 || (GPIO_IS_VALID_OUTPUT_GPIO(rts_io_num))), ESP_FAIL, UART_TAG, "rts_io_num error"); ESP_RETURN_ON_FALSE((cts_io_num < 0 || (GPIO_IS_VALID_GPIO(cts_io_num))), ESP_FAIL, UART_TAG, "cts_io_num error"); + // 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))) { - 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 (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)) { + 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 (rx_io_num >= 0 && (tx_rx_same_io || !uart_try_set_iomux_pin(uart_num, rx_io_num, SOC_UART_RX_PIN_IDX))) { - 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 (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)) { + 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 (rts_io_num >= 0 && !uart_try_set_iomux_pin(uart_num, rts_io_num, SOC_UART_RTS_PIN_IDX)) { + 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))) { 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); // output enable is set inside esp_rom_gpio_connect_out_signal func after the signal is connected } - 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))) { 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); gpio_set_direction(cts_io_num, GPIO_MODE_INPUT); @@ -1638,6 +1680,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 3057ddeaeb5e34416c9d06830f8f7fd2bff70a98 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 23 Apr 2025 16:13:09 +0800 Subject: [PATCH 7/7] 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 08c2d16804..e6a14cb060 100644 --- a/components/driver/uart/uart.c +++ b/components/driver/uart/uart.c @@ -629,10 +629,16 @@ static void uart_release_pin(uart_port_t uart_num) } if (uart_context[uart_num].tx_io_num >= 0) { gpio_ll_output_disable(&GPIO, uart_context[uart_num].tx_io_num); +#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 } if (uart_context[uart_num].rx_io_num >= 0) { esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false); +#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 } if (uart_context[uart_num].rts_io_num >= 0) { @@ -668,6 +674,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)) { 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); @@ -678,6 +690,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)) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rx_io_num], PIN_FUNC_GPIO); gpio_ll_input_enable(&GPIO, rx_io_num);