From a59daff749208ff3f0b3275fa918bb0aaac469b0 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Thu, 2 Jul 2026 17:14:02 +0800 Subject: [PATCH 1/5] fix(uart): fix uart sw flow ctrl XOFF char write to wrong reg on ESP32C6 Add software flow control test case Introduced in e6ef4d1791f851c9f6390edb2c3c3ef0d99cbc64 Closes https://github.com/espressif/esp-idf/issues/18779 --- .../esp_driver_uart/include/driver/uart.h | 8 +- .../test_apps/uart/main/test_uart.c | 209 ++++++++++++++++++ .../test_apps/uart/pytest_uart.py | 57 ++++- .../esp32c6/include/hal/uart_ll.h | 2 +- .../soc/esp32c6/register/soc/uart_struct.h | 4 +- 5 files changed, 267 insertions(+), 13 deletions(-) diff --git a/components/esp_driver_uart/include/driver/uart.h b/components/esp_driver_uart/include/driver/uart.h index 7aabb006bbf..68e55c78b3b 100644 --- a/components/esp_driver_uart/include/driver/uart.h +++ b/components/esp_driver_uart/include/driver/uart.h @@ -283,10 +283,12 @@ esp_err_t uart_set_hw_flow_ctrl(uart_port_t uart_num, uart_hw_flowcontrol_t flow /** * @brief Set software flow control. * + * The XON and XOFF characters are '0x11' and '0x13' respectively. + * * @param uart_num UART port number, the max port number is (UART_NUM_MAX -1) - * @param enable switch on or off - * @param rx_thresh_xon low water mark - * @param rx_thresh_xoff high water mark + * @param enable Enable or disable software flow control feature + * @param rx_thresh_xon Low RX FIFO water mark for TX to send XON character + * @param rx_thresh_xoff High RX FIFO water mark for TX to send XOFF character * * @return * - ESP_OK Success diff --git a/components/esp_driver_uart/test_apps/uart/main/test_uart.c b/components/esp_driver_uart/test_apps/uart/main/test_uart.c index b6a270edea0..709a82823ae 100644 --- a/components/esp_driver_uart/test_apps/uart/main/test_uart.c +++ b/components/esp_driver_uart/test_apps/uart/main/test_uart.c @@ -26,6 +26,7 @@ #include "soc/clk_tree_defs.h" #include "test_common.h" #include "esp_attr.h" +#include "esp_timer.h" #define BUF_SIZE (100) #define UART_BAUD_11520 (11520) @@ -645,6 +646,214 @@ TEST_CASE("uart in one-wire mode", "[uart]") TEST_ESP_OK(uart_driver_delete(uart_num)); } +// XON/XOFF software flow control characters (must match the ones the driver programs into the hardware) +#define TEST_UART_XON_CHAR (0x11) +#define TEST_UART_XOFF_CHAR (0x13) + +// A small, fixed amount of payload written to the UART to probe whether the transmitter is draining it. +// Kept well within the smallest HW TX FIFO (the LP UART has only 16 bytes) so the write always fits and, since +// the FIFO is empty at every call site, uart_write_bytes() never blocks waiting for FIFO space. +#define TEST_UART_TX_PROBE_BYTES (8) + +// The probe window: a running transmitter drains TEST_UART_TX_PROBE_BYTES in well under 1 ms at any reasonable +// baud rate, so 100 ms is plenty to tell "draining" (tx goes idle) from "paused" (tx never goes idle). +#define TEST_UART_TX_PROBE_WINDOW_MS (100) + +// Queue a fixed chunk of payload through the driver's TX path (installed with no TX ring buffer, so the bytes +// go straight to the HW TX FIFO). The payload byte must differ from XON/XOFF; its value is irrelevant to the +// local TX flow control decision. +static void test_uart_write_txfifo_probe(uart_port_t uart_num) +{ + uint8_t payload[TEST_UART_TX_PROBE_BYTES]; + memset(payload, 0x55, sizeof(payload)); + uart_write_bytes(uart_num, payload, sizeof(payload)); +} + +// Return true once TX has stopped draining (i.e. an XOFF was received and the transmitter paused). +// Each iteration queues a small probe into the (empty) FIFO and waits for the transmitter to go idle: if it +// cannot finish within the probe window the transmitter is paused. Otherwise it drained the probe (running), +// leaving the FIFO empty again for the next iteration. +static bool test_uart_wait_tx_paused(uart_port_t uart_num, int timeout_ms) +{ + int64_t deadline = esp_timer_get_time() + (int64_t)timeout_ms * 1000; + while (esp_timer_get_time() < deadline) { + test_uart_write_txfifo_probe(uart_num); + if (uart_wait_tx_done(uart_num, pdMS_TO_TICKS(TEST_UART_TX_PROBE_WINDOW_MS)) == ESP_ERR_TIMEOUT) { + return true; // probe could not drain -> paused + } + } + return false; +} + +// Return true once TX starts draining again (i.e. an XON was received and the transmitter resumed). +// The probe bytes queued by the pause step are still sitting in the FIFO (nothing drains while paused), so we +// just wait for the transmitter to finally go idle, which only happens once it resumes and shifts them out. +static bool test_uart_wait_tx_resumed(uart_port_t uart_num, int timeout_ms) +{ + int64_t deadline = esp_timer_get_time() + (int64_t)timeout_ms * 1000; + while (esp_timer_get_time() < deadline) { + if (uart_wait_tx_done(uart_num, pdMS_TO_TICKS(TEST_UART_TX_PROBE_WINDOW_MS)) == ESP_OK) { + return true; // FIFO drained -> resumed + } + } + return false; +} + +// Wait until the RX FIFO has accumulated more than the XOFF threshold (so an XOFF should have been sent). +static bool test_uart_wait_rxfifo_filled(uart_dev_t *hw, uint32_t xoff_thresh, int timeout_ms) +{ + int64_t deadline = esp_timer_get_time() + (int64_t)timeout_ms * 1000; + while (esp_timer_get_time() < deadline) { + if (uart_ll_get_rxfifo_len(hw) > xoff_thresh) { + return true; + } + vTaskDelay(pdMS_TO_TICKS(5)); + } + return false; +} + +// Drain the whole HW RX FIFO directly (the driver's RX interrupts are disabled), dropping the level below the +// XON threshold so the hardware sends an XON. +static void test_uart_drain_rxfifo(uart_dev_t *hw) +{ + uint8_t buf[64]; + uint32_t len; + while ((len = uart_ll_get_rxfifo_len(hw)) > 0) { + if (len > sizeof(buf)) { + len = sizeof(buf); + } + uart_ll_read_rxfifo(hw, buf, len); + } +} + +/* + * This test verifies both directions of the UART hardware software-flow-control (XON/XOFF) feature: + * 1. Receiving flow control: once the UART receives an XOFF character it must stop transmitting, and resume + * once it receives an XON character. + * 2. Sending flow control: once the RX FIFO fills past the XOFF threshold the UART must transmit an XOFF + * character, and once it is drained below the XON threshold it must transmit an XON character. + * + * For the HP UART port, the test taps the UART RX onto the console UART RX pad so the host (pytest) can inject + * XON/XOFF (direction 1) over the very same serial connection it already uses to talk to the console, without + * extra wiring. For direction 2, the console TX pad is temporarily re-routed to the UART TX signal so the host + * can observe the XON/XOFF characters the UART sends. The console UART RX pad is a regular (HP) GPIO though, + * while the LP UART can only use LP-capable (RTC) GPIOs, so it cannot borrow the console pads. Hence for the LP + * UART port the test keeps the LP UART on its normal pins and a manual tester is expected to physically wire + * the console/UART0 RX and TX lines to them. (CI only exercises HP UART.) + * + * The UART TX shifts data out at the configured baud rate regardless of where it is routed, so direction 1 is + * observed on the DUT by watching the HW TX FIFO drain. + */ +TEST_CASE("uart software flow control (XON/XOFF)", "[uart_flow_ctrl]") +{ + uart_port_param_t port_param = {}; + TEST_ASSERT(port_select(&port_param)); + uart_port_t uart_num = port_param.port_num; + uart_dev_t *hw = UART_LL_GET_HW(uart_num); + const bool is_hp_uart = (uart_num < SOC_UART_HP_NUM); + + printf("Note that if you are in any terminal program, likely the XON/XOFF will be trapped by the shell. Run 'stty -ixon -ixoff' to let the keys pass through your terminal application!\n"); + + int rx_pin, tx_pin; + if (is_hp_uart) { + // HP UART: tap the UART RX onto the console UART RX pad so the host can inject XON/XOFF over the console. + // The TX is left unrouted for now; it is hijacked onto the console TX pad later for the sending direction. + rx_pin = uart_periph_signal[CONFIG_CONSOLE_UART_NUM].pins[SOC_UART_PERIPH_SIGNAL_RX].default_gpio; + TEST_ASSERT(rx_pin >= 0); + tx_pin = UART_PIN_NO_CHANGE; + } else { + // LP UART: keep both pins on their normal IOs; a manual tester wires the console/UART0 lines to them. + printf("LP UART needs manual wiring of console UART lines to the UART pins (TX-to-RX, RX-to-TX)\n"); + rx_pin = port_param.rx_pin_num; + tx_pin = port_param.tx_pin_num; + } + + uart_config_t uart_config = { + .baud_rate = 115200, + .data_bits = UART_DATA_8_BITS, + .parity = UART_PARITY_DISABLE, + .stop_bits = UART_STOP_BITS_1, + .flow_ctrl = UART_HW_FLOWCTRL_DISABLE, + .source_clk = port_param.default_src_clk, + }; + // No TX ring buffer: the direct FIFO writes below go straight to the HW TX FIFO, so monitoring the FIFO + // level reflects the real transmitter state. + TEST_ESP_OK(uart_driver_install(uart_num, BUF_SIZE * 2, 0, 0, NULL, 0)); + TEST_ESP_OK(uart_param_config(uart_num, &uart_config)); + TEST_ESP_OK(uart_set_pin(uart_num, tx_pin, rx_pin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE)); + + // RX FIFO thresholds and fill size that drive the *sending* direction (part 2). They must fit the HW FIFO, + // which is much smaller on the LP UART (16 bytes) than on the HP UART (128 bytes). + // - xoff_thresh: when the RX FIFO rises above this, the hardware sends XOFF + // - xon_thresh: when the RX FIFO drops below this, the hardware sends XON + // - fill_bytes: amount the host sends, chosen > xoff_thresh and <= HW FIFO length (so no overflow) + int xon_thresh, xoff_thresh, fill_bytes; + if (is_hp_uart) { + xon_thresh = 10; + xoff_thresh = 40; + fill_bytes = 64; + } else { + xon_thresh = 2; + xoff_thresh = 8; + fill_bytes = 12; + } + + // Enable software flow control with the thresholds above. + TEST_ESP_OK(uart_set_sw_flow_ctrl(uart_num, true, xon_thresh, xoff_thresh)); + + // ---- Part 1: receiving XON/XOFF pauses / resumes the transmitter ---- + printf("\n"); + printf("Send %#04x (XOFF - Ctrl+S) to stop UART transmission\n", TEST_UART_XOFF_CHAR); + bool paused = test_uart_wait_tx_paused(uart_num, 20000); + TEST_ASSERT_MESSAGE(paused, "UART transmitter did not pause after receiving XOFF"); + printf("UART transmission stopped\n"); + + printf("Send %#04x (XON - Ctrl+Q) to start UART transmission\n", TEST_UART_XON_CHAR); + bool resumed = test_uart_wait_tx_resumed(uart_num, 20000); + TEST_ASSERT_MESSAGE(resumed, "UART transmitter did not resume after receiving XON"); + printf("UART transmission resumed\n"); + + // Part 1 left the transmitter idle (uart_wait_tx_done returned OK); reset the TX FIFO anyway to guarantee a + // clean slate before observing the auto XON/XOFF. + uart_ll_txfifo_rst(hw); + + // ---- Part 2: filling / draining the RX FIFO makes the UART send XOFF / XON ---- + // Disable the driver's RX interrupts so the RX FIFO is not auto-drained; we drain it explicitly below. This + // guarantees the XOFF is sent (FIFO stays above the XOFF threshold) before we drop it below the XON threshold. + TEST_ESP_OK(uart_disable_rx_intr(uart_num)); + uart_ll_rxfifo_rst(hw); + + printf("\n"); + printf("Send %d bytes to fill RX FIFO\n", fill_bytes); + fflush(stdout); + + const int console_tx_pin = uart_periph_signal[CONFIG_CONSOLE_UART_NUM].pins[SOC_UART_PERIPH_SIGNAL_TX].default_gpio; + const int console_tx_signal = uart_periph_signal[CONFIG_CONSOLE_UART_NUM].pins[SOC_UART_PERIPH_SIGNAL_TX].signal; + const int uart_tx_signal = uart_periph_signal[uart_num].pins[SOC_UART_PERIPH_SIGNAL_TX].signal; + + if (is_hp_uart) { + // Make sure the prompt is fully sent, then hijack the console TX pad so the host reads the UART's TX. + uart_wait_tx_idle_polling(CONFIG_CONSOLE_UART_NUM); + gpio_func_sel(console_tx_pin, PIN_FUNC_GPIO); + esp_rom_gpio_connect_out_signal(console_tx_pin, uart_tx_signal, false, false); + } + + bool filled = test_uart_wait_rxfifo_filled(hw, xoff_thresh, 20000); // by now an XOFF should have been sent + test_uart_drain_rxfifo(hw); // dropping below XON threshold sends XON + uart_wait_tx_idle_polling(uart_num); // let the XON finish transmitting + vTaskDelay(pdMS_TO_TICKS(10)); + + if (is_hp_uart) { + // Restore the console TX pad so the unity test result can be reported over the console again. + esp_rom_gpio_connect_out_signal(console_tx_pin, console_tx_signal, false, false); + } + TEST_ASSERT_MESSAGE(filled, "RX FIFO was not filled past the XOFF threshold by the host"); + printf("Please manually read the TX signal to confirm that it actually sent XOFF and XON characters\n"); + + TEST_ESP_OK(uart_set_sw_flow_ctrl(uart_num, false, 0, 0)); + TEST_ESP_OK(uart_driver_delete(uart_num)); +} + static void uart_console_write_task(void *arg) { while (1) { diff --git a/components/esp_driver_uart/test_apps/uart/pytest_uart.py b/components/esp_driver_uart/test_apps/uart/pytest_uart.py index eda9df15400..00ea0eaf7ff 100644 --- a/components/esp_driver_uart/test_apps/uart/pytest_uart.py +++ b/components/esp_driver_uart/test_apps/uart/pytest_uart.py @@ -19,6 +19,38 @@ input_argv = { } +def _run_uart_flow_ctrl_case(dut, case) -> None: # type: ignore + # Only the HP UART port is exercised in CI: its RX/TX borrow the console UART RX/TX pads, so the + # host can inject and observe the XON (0x11) / XOFF (0x13) characters over the console connection + # without extra wiring. The LP UART port cannot borrow the console pads (LP-only GPIOs) and would + # need UART0 to be physically wired to the LP UART pins, so it is left for manual testing only. + dut.serial.hard_reset() + dut._get_ready() + dut.confirm_write(case.index, expect_str=f'Running {case.name}...') + + dut.expect("select to test 'uart' or 'lp_uart' port", timeout=10) + dut.write('uart') + + # Drive the HP UART software-flow-control case (both directions) after the 'uart' port has been selected. + # Part 1: the DUT reacts to XON/XOFF that we inject over the console connection. + dut.expect_exact('Send 0x13 (XOFF - Ctrl+S) to stop UART transmission', timeout=10) + dut.write(b'\x13') + dut.expect_exact('UART transmission stopped', timeout=25) + + dut.expect_exact('Send 0x11 (XON - Ctrl+Q) to start UART transmission', timeout=10) + dut.write(b'\x11') + dut.expect_exact('UART transmission resumed', timeout=25) + + # Part 2: the DUT auto-sends XOFF/XON when its RX FIFO fills/drains. It temporarily borrows the console TX + # pad, so we read the raw XOFF (0x13) then XON (0x11) bytes back over the console connection. + dut.expect_exact('Send 64 bytes to fill RX FIFO', timeout=10) + dut.write(b'A' * 64) + dut.expect(b'\x13') # XOFF + dut.expect(b'\x11') # XON + + dut.expect_unity_test_output() + + @pytest.mark.temp_skip_ci(targets=['esp32s3'], reason='skip due to duplication with test_uart_single_dev_psram') @pytest.mark.generic @pytest.mark.parametrize( @@ -43,6 +75,10 @@ def test_uart_single_dev(case_tester) -> None: # type: ignore # multi-dev cases, skip on generic runner continue + if 'uart_flow_ctrl' in case.groups: + _run_uart_flow_ctrl_case(dut, case) + continue + if 'hp-uart-only' not in case.groups: for uart_port in uart_ports: dut.serial.hard_reset() @@ -70,14 +106,21 @@ def test_uart_single_dev(case_tester) -> None: # type: ignore def test_uart_single_dev_psram(case_tester) -> None: # type: ignore dut = case_tester.first_dut for case in case_tester.test_menu: - if 'wakeup' not in case.groups: - dut.serial.hard_reset() - dut._get_ready() - dut.confirm_write(case.index, expect_str=f'Running {case.name}...') + if 'wakeup' in case.groups: + # multi-dev cases, skip on generic runner + continue - dut.expect("select to test 'uart' or 'lp_uart' port", timeout=10) - dut.write('uart') - dut.expect_unity_test_output() + if 'uart_flow_ctrl' in case.groups: + _run_uart_flow_ctrl_case(dut, case) + continue + + dut.serial.hard_reset() + dut._get_ready() + dut.confirm_write(case.index, expect_str=f'Running {case.name}...') + + dut.expect("select to test 'uart' or 'lp_uart' port", timeout=10) + dut.write('uart') + dut.expect_unity_test_output() # ESP32 only supports uart wakeup if signal routes through IOMUX diff --git a/components/esp_hal_uart/esp32c6/include/hal/uart_ll.h b/components/esp_hal_uart/esp32c6/include/hal/uart_ll.h index 3112f95f704..dc9b0fb992d 100644 --- a/components/esp_hal_uart/esp32c6/include/hal/uart_ll.h +++ b/components/esp_hal_uart/esp32c6/include/hal/uart_ll.h @@ -979,7 +979,7 @@ FORCE_INLINE_ATTR void uart_ll_set_sw_flow_ctrl(uart_dev_t *hw, uart_sw_flowctrl HAL_FORCE_MODIFY_U32_REG_FIELD(hw->swfc_conf1, xon_threshold, (flow_ctrl->xon_thrd) << UART_LL_REG_FIELD_BIT_SHIFT(hw)); HAL_FORCE_MODIFY_U32_REG_FIELD(hw->swfc_conf1, xoff_threshold, (flow_ctrl->xoff_thrd) << UART_LL_REG_FIELD_BIT_SHIFT(hw)); HAL_FORCE_MODIFY_U32_REG_FIELD(hw->swfc_conf0_sync, xon_character, flow_ctrl->xon_char); - HAL_FORCE_MODIFY_U32_REG_FIELD(hw->swfc_conf0_sync, xon_character, flow_ctrl->xoff_char); + HAL_FORCE_MODIFY_U32_REG_FIELD(hw->swfc_conf0_sync, xoff_character, flow_ctrl->xoff_char); } else { hw->swfc_conf0_sync.sw_flow_con_en = 0; hw->swfc_conf0_sync.xonoff_del = 0; diff --git a/components/soc/esp32c6/register/soc/uart_struct.h b/components/soc/esp32c6/register/soc/uart_struct.h index 2ac955176b0..2a4f289441d 100644 --- a/components/soc/esp32c6/register/soc/uart_struct.h +++ b/components/soc/esp32c6/register/soc/uart_struct.h @@ -741,10 +741,10 @@ typedef union { * This register stores the Xon flow control char. */ uint32_t xon_character:8; - /** xoff_threshold : R/W; bitpos: [15:8]; default: 19; + /** xoff_character : R/W; bitpos: [15:8]; default: 19; * This register stores the Xoff flow control char. */ - uint32_t xoff_threshold:8; + uint32_t xoff_character:8; /** xon_xoff_still_send : R/W; bitpos: [16]; default: 0; * In software flow control mode, UART Tx is disabled once UART Rx receives XOFF. In * this status, UART Tx can not transmit XOFF even the received data number is larger From 5a796df200e4e666ac3bb5d99af1142330fc06c1 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Mon, 6 Jul 2026 20:53:28 +0800 Subject: [PATCH 2/5] ci(uart): enable test for esp32h4 --- components/esp_driver_uart/test_apps/uart/pytest_uart.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/components/esp_driver_uart/test_apps/uart/pytest_uart.py b/components/esp_driver_uart/test_apps/uart/pytest_uart.py index 00ea0eaf7ff..7d31a72b279 100644 --- a/components/esp_driver_uart/test_apps/uart/pytest_uart.py +++ b/components/esp_driver_uart/test_apps/uart/pytest_uart.py @@ -15,6 +15,7 @@ input_argv = { 'esp32p4': ['uart', 'lp_uart'], 'esp32c5': ['uart', 'lp_uart'], 'esp32c61': ['uart'], + 'esp32h4': ['uart'], 'esp32s31': ['uart', 'lp_uart'], } @@ -62,7 +63,6 @@ def _run_uart_flow_ctrl_case(dut, case) -> None: # type: ignore indirect=True, ) @idf_parametrize('target', ['supported_targets'], indirect=['target']) -@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='cannot pass') # TODO: IDF-15619 def test_uart_single_dev(case_tester) -> None: # type: ignore dut = case_tester.first_dut chip_type = dut.app.target @@ -102,7 +102,6 @@ def test_uart_single_dev(case_tester) -> None: # type: ignore indirect=True, ) @idf_parametrize('target', ['esp32s3'], indirect=['target']) -@pytest.mark.temp_skip_ci(targets=['esp32h4'], reason='cannot pass') # TODO: IDF-15619 def test_uart_single_dev_psram(case_tester) -> None: # type: ignore dut = case_tester.first_dut for case in case_tester.test_menu: From 339d8b568dca51e66cd0ab5bea0d36e0d25de148 Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 1 Jul 2026 15:25:37 +0800 Subject: [PATCH 3/5] feat(uart): add collision detection test cases for RS485 Related https://github.com/espressif/esp-idf/issues/16101 --- .../test_apps/.build-test-rules.yml | 2 +- .../test_apps/rs485/main/test_rs485.c | 223 +++++++++++++++--- .../test_apps/rs485/pytest_rs485.py | 2 +- .../test_apps/rs485/sdkconfig.defaults.esp32 | 4 + .../test_apps/uart/main/test_uart.c | 16 +- 5 files changed, 202 insertions(+), 45 deletions(-) create mode 100644 components/esp_driver_uart/test_apps/rs485/sdkconfig.defaults.esp32 diff --git a/components/esp_driver_uart/test_apps/.build-test-rules.yml b/components/esp_driver_uart/test_apps/.build-test-rules.yml index 835eacb6696..dbaba151cfc 100644 --- a/components/esp_driver_uart/test_apps/.build-test-rules.yml +++ b/components/esp_driver_uart/test_apps/.build-test-rules.yml @@ -4,7 +4,7 @@ components/esp_driver_uart/test_apps/rs485: disable: - if: SOC_UART_SUPPORTED != 1 disable_test: - - if: IDF_TARGET not in ["esp32", "esp32h2"] + - if: IDF_TARGET not in ["esp32", "esp32h2", "esp32s3"] temporary: true reason: lack of runners depends_components: diff --git a/components/esp_driver_uart/test_apps/rs485/main/test_rs485.c b/components/esp_driver_uart/test_apps/rs485/main/test_rs485.c index 67ff1f3ac2f..e8b8677e962 100644 --- a/components/esp_driver_uart/test_apps/rs485/main/test_rs485.c +++ b/components/esp_driver_uart/test_apps/rs485/main/test_rs485.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2021-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2021-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -14,20 +14,22 @@ #include "esp_random.h" // for uint32_t esp_random() #include "sdkconfig.h" -#define UART_NUM1 (UART_NUM_1) +#define UART_NUM (UART_NUM_1 - CONFIG_CONSOLE_UART_NUM) #define UART_BAUD_RATE (115200 * 10) #define BUF_SIZE (512) #if CONFIG_IDF_TARGET_ESP32 -#define UART1_RX_PIN (22) -#define UART1_TX_PIN (23) -// For RS485 Half-Duplex Mode manages DE/~RE -#define RS485_DE_PIN (18) // For ESP32, let's use RTS signal to control DE/~RE pin -#elif CONFIG_IDF_TARGET_ESP32H2 -#define UART1_RX_PIN (4) -#define UART1_TX_PIN (5) -// For RS485 Half-Duplex Mode manages DE/~RE -#define RS485_DE_PIN (12) // For ESP32H2, let's use DTR signal to control DE/~RE pin +#define UART_RX_PIN (22) +#define UART_TX_PIN (23) +#define RS485_DE_PIN (18) // uses RTS or DTR signal to control DE/~RE pin +#elif CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32S3 +#define UART_RX_PIN (4) +#define UART_TX_PIN (5) +#define RS485_DE_PIN (12) // uses RTS or DTR signal to control DE/~RE pin +#else // for build success only (no runner) +#define UART_RX_PIN (0) +#define UART_TX_PIN (0) +#define RS485_DE_PIN (0) #endif // Number of packets to be send during test @@ -158,7 +160,7 @@ static uint16_t buffer_fill_random(uint8_t *buffer, size_t length) return crc; } -static void rs485_init(void) +static void rs485_init(uart_mode_t mode) { uart_config_t uart_config = { .baud_rate = UART_BAUD_RATE, @@ -170,19 +172,21 @@ static void rs485_init(void) .source_clk = UART_SCLK_DEFAULT, }; ESP_LOGI(TAG, "RS485 port initialization..."); - TEST_ESP_OK(uart_wait_tx_idle_polling(UART_NUM1)); - // Configure UART1 parameters - TEST_ESP_OK(uart_param_config(UART_NUM1, &uart_config)); - // Set UART1 pins -#if CONFIG_IDF_TARGET_ESP32 - TEST_ESP_OK(uart_set_pin(UART_NUM1, UART1_TX_PIN, UART1_RX_PIN, RS485_DE_PIN, UART_PIN_NO_CHANGE)); -#elif CONFIG_IDF_TARGET_ESP32H2 - TEST_ESP_OK(uart_set_pin(UART_NUM1, UART1_TX_PIN, UART1_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, RS485_DE_PIN, UART_PIN_NO_CHANGE)); -#endif + TEST_ESP_OK(uart_wait_tx_idle_polling(UART_NUM)); + // Configure UART port parameters + TEST_ESP_OK(uart_param_config(UART_NUM, &uart_config)); + // Set UART pins + if (mode == UART_MODE_RS485_HALF_DUPLEX) { // RTS toggle by software, DTR toggle by hardware in this mode + TEST_ESP_OK(uart_set_pin(UART_NUM, UART_TX_PIN, UART_RX_PIN, RS485_DE_PIN, UART_PIN_NO_CHANGE)); + } else if (mode == UART_MODE_RS485_COLLISION_DETECT) { // no RTS toggle in this mode + TEST_ESP_OK(uart_set_pin(UART_NUM, UART_TX_PIN, UART_RX_PIN, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, RS485_DE_PIN, UART_PIN_NO_CHANGE)); + } else { + TEST_ASSERT(false); + } // Install UART driver (we don't need an event queue here) - TEST_ESP_OK(uart_driver_install(UART_NUM1, BUF_SIZE * 2, 0, 0, NULL, 0)); - // Setup rs485 half duplex mode - TEST_ESP_OK(uart_set_mode(UART_NUM1, UART_MODE_RS485_HALF_DUPLEX)); + TEST_ESP_OK(uart_driver_install(UART_NUM, BUF_SIZE * 2, 0, 0, NULL, 0)); + // Setup the requested rs485 mode + TEST_ESP_OK(uart_set_mode(UART_NUM, mode)); } static esp_err_t print_packet_data(const char *str, uint8_t *buffer, uint16_t buffer_size) @@ -209,7 +213,7 @@ static esp_err_t print_packet_data(const char *str, uint8_t *buffer, uint16_t bu // Slave test case for multi device static void rs485_slave(void) { - rs485_init(); + rs485_init(UART_MODE_RS485_HALF_DUPLEX); uint8_t* slave_data = (uint8_t*) malloc(BUF_SIZE); uint16_t err_count = 0, good_count = 0; unity_send_signal("Slave_ready"); @@ -217,15 +221,15 @@ static void rs485_slave(void) ESP_LOGI(TAG, "Start receive loop."); for (int pack_count = 0; pack_count < PACKETS_NUMBER; pack_count++) { //Read slave_data from UART - int len = uart_read_bytes(UART_NUM1, slave_data, BUF_SIZE, PACKET_READ_TICS); + int len = uart_read_bytes(UART_NUM, slave_data, BUF_SIZE, PACKET_READ_TICS); //Write slave_data back to UART if (len > 2) { esp_err_t status = print_packet_data("Received ", slave_data, len); // If received packet is correct then send it back if (status == ESP_OK) { - uart_write_bytes(UART_NUM1, (char*)slave_data, len); - uart_wait_tx_idle_polling(UART_NUM1); + uart_write_bytes(UART_NUM, (char*)slave_data, len); + uart_wait_tx_idle_polling(UART_NUM); good_count++; } else { printf("Incorrect packet received.\r\n"); @@ -238,9 +242,9 @@ static void rs485_slave(void) } ESP_LOGI(TAG, "Test completed. Received packets = %d, errors = %d", good_count, err_count); // Wait for packet to be sent - uart_wait_tx_done(UART_NUM1, PACKET_READ_TICS); + uart_wait_tx_done(UART_NUM, PACKET_READ_TICS); free(slave_data); - uart_driver_delete(UART_NUM1); + uart_driver_delete(UART_NUM); TEST_CHECK_PROC_FAIL(err_count, TEST_ALLOW_PROC_FAIL); } @@ -250,7 +254,7 @@ static void rs485_slave(void) static void rs485_master(void) { uint16_t err_count = 0, good_count = 0; - rs485_init(); + rs485_init(UART_MODE_RS485_HALF_DUPLEX); uint8_t* master_buffer = (uint8_t*) malloc(BUF_SIZE); uint8_t* slave_buffer = (uint8_t*) malloc(BUF_SIZE); // The master test case should be synchronized with slave @@ -263,10 +267,10 @@ static void rs485_master(void) // Print created packet for debugging esp_err_t status = print_packet_data("Send ", master_buffer, BUF_SIZE); TEST_ASSERT(status == ESP_OK); - uart_write_bytes(UART_NUM1, (char*)master_buffer, BUF_SIZE); - uart_wait_tx_idle_polling(UART_NUM1); + uart_write_bytes(UART_NUM, (char*)master_buffer, BUF_SIZE); + uart_wait_tx_idle_polling(UART_NUM); // Read translated packet from slave - int len = uart_read_bytes(UART_NUM1, slave_buffer, BUF_SIZE, PACKET_READ_TICS); + int len = uart_read_bytes(UART_NUM, slave_buffer, BUF_SIZE, PACKET_READ_TICS); // Check if the received packet is too short if (len > 2) { // Print received packet and check checksum @@ -283,11 +287,11 @@ static void rs485_master(void) err_count++; } } - uart_wait_tx_done(UART_NUM1, PACKET_READ_TICS); + uart_wait_tx_done(UART_NUM, PACKET_READ_TICS); // Free the buffer and delete driver at the end free(master_buffer); free(slave_buffer); - uart_driver_delete(UART_NUM1); + uart_driver_delete(UART_NUM); ESP_LOGI(TAG, "Test completed. Received packets = %d, errors = %d", good_count, err_count); TEST_CHECK_PROC_FAIL(err_count, TEST_ALLOW_PROC_FAIL); } @@ -298,3 +302,150 @@ static void rs485_master(void) * RS485 bus driver hardware to be connected to boards. */ TEST_CASE_MULTIPLE_DEVICES("RS485 half duplex uart multiple devices test.", "[RS485]", rs485_master, rs485_slave); + +// The device under check: in UART_MODE_RS485_COLLISION_DETECT mode the receiver +// stays enabled during transmission, so the device should be able to read back +// from the bus the same data it has just sent. Under UART_MODE_RS485_COLLISION_DETECT +// mode, RTS signal will not be asserted during transmission, instead, uses hardware +// DTR signal to drive DE pin. And ~RE pin is grounded for continuous reception. +static void rs485_recv_while_send(uart_mode_t mode) +{ + rs485_init(mode); + uint8_t *tx_buffer = (uint8_t *) malloc(BUF_SIZE); + uint8_t *rx_buffer = (uint8_t *) malloc(BUF_SIZE); + TEST_ASSERT_NOT_NULL(tx_buffer); + TEST_ASSERT_NOT_NULL(rx_buffer); + + uint16_t err_count = 0; + // The device under check reads back its own transmission from the bus, so it must receive every byte on every round (no tolerance here) + // The exchange is repeated PACKETS_NUMBER times, kept in sync with the peer by a signal each round + for (int i = 0; i < PACKETS_NUMBER; i++) { + // Wait until the peer is ready and listening (it must not drive the bus) + unity_wait_for_signal("Peer_ready"); + + buffer_fill_random(tx_buffer, BUF_SIZE); + TEST_ESP_OK(uart_flush_input(UART_NUM)); + int written = uart_write_bytes(UART_NUM, (const char *) tx_buffer, BUF_SIZE); + TEST_ASSERT_EQUAL_INT(BUF_SIZE, written); + TEST_ESP_OK(uart_wait_tx_done(UART_NUM, PACKET_READ_TICS)); + + // The data sent on the bus is received back while sending + int read_len = uart_read_bytes(UART_NUM, rx_buffer, BUF_SIZE, PACKET_READ_TICS); + bool ok = (read_len == BUF_SIZE) && (memcmp(tx_buffer, rx_buffer, BUF_SIZE) == 0); + ESP_LOGI(TAG, "Packet %d: sent %d bytes, received %d bytes back while sending (%s)", + i, written, read_len, ok ? "match" : "mismatch"); + if (!ok) { + err_count++; + } + + // Signal the peer that this round is over so it can resynchronize + unity_send_signal("Round_done"); + } + // No missing bytes are allowed on the device that reads back its own data + TEST_ASSERT_EQUAL_INT(0, err_count); + + free(tx_buffer); + free(rx_buffer); + uart_driver_delete(UART_NUM); +} + +// The peer device: it only listens (never drives the bus) so that the device +// under check can verify it receives its own transmitted data. The peer also +// receives the same packet from the bus and verifies its integrity (CRC). +static void rs485_quiet_peer(uart_mode_t mode) +{ + rs485_init(mode); + uint8_t *rx_buffer = (uint8_t *) malloc(BUF_SIZE); + TEST_ASSERT_NOT_NULL(rx_buffer); + + uint16_t err_count = 0; + // Mirror the sender: run PACKETS_NUMBER rounds and tolerate a small percentage of failures in case a few bytes are dropped on the bus + for (int i = 0; i < PACKETS_NUMBER; i++) { + // Discard any residual/partial data from a previous round before announcing readiness for a fresh packet + TEST_ESP_OK(uart_flush_input(UART_NUM)); + unity_send_signal("Peer_ready"); + + // The peer receives the packet sent on the bus and verifies it + int read_len = uart_read_bytes(UART_NUM, rx_buffer, BUF_SIZE, PACKET_READ_TICS); + ESP_LOGI(TAG, "Packet %d: peer received %d bytes", i, read_len); + if (read_len != BUF_SIZE || print_packet_data("Peer received ", rx_buffer, read_len) != ESP_OK) { + err_count++; + } + + // Wait for the sender to finish this round before flushing/reading again + unity_wait_for_signal("Round_done"); + } + TEST_CHECK_PROC_FAIL(err_count, TEST_ALLOW_PROC_FAIL); + + free(rx_buffer); + uart_driver_delete(UART_NUM); +} + +static void rs485_recv_while_send_coll_det(void) +{ + rs485_recv_while_send(UART_MODE_RS485_COLLISION_DETECT); +} + +static void rs485_quiet_peer_coll_det(void) +{ + rs485_quiet_peer(UART_MODE_RS485_COLLISION_DETECT); +} + +/* + * This multi devices test case verifies that in UART_MODE_RS485_COLLISION_DETECT + * mode the device receives back the data it sends out on the bus. It requires + * RS485 bus driver hardware (with the receiver kept enabled) connected to the + * boards. Only one device drives the bus. +*/ +TEST_CASE_MULTIPLE_DEVICES("RS485 collision detect mode can receive while sending", "[RS485]", rs485_recv_while_send_coll_det, rs485_quiet_peer_coll_det); + +// Both devices transmit (different data) at the same time to force a bus +// collision. In UART_MODE_RS485_COLLISION_DETECT mode the received data then +// differs from the transmitted data, which raises the collision flag. +static void rs485_collision_dev(uart_mode_t mode, const char *self_ready, const char *peer_ready) +{ + rs485_init(mode); + uint8_t *tx_buffer = (uint8_t *) malloc(BUF_SIZE); + TEST_ASSERT_NOT_NULL(tx_buffer); + buffer_fill_random(tx_buffer, BUF_SIZE); + + // Barrier: make sure both devices start transmitting at roughly the same time + unity_send_signal(self_ready); + unity_wait_for_signal(peer_ready); + + bool collision_flag = false; + // Both devices drive the bus simultaneously with different data, so the data + // received back differs from the transmitted data and the collision flag gets + // raised. Keep transmitting for the whole loop (do not stop on the first + // detection): if a device stopped early, its peer would then transmit alone + // and might never observe a collision. + for (int i = 0; i < PACKETS_NUMBER; i++) { + bool flag = false; + uart_write_bytes(UART_NUM, (const char *) tx_buffer, BUF_SIZE); + uart_wait_tx_done(UART_NUM, PACKET_READ_TICS); + TEST_ESP_OK(uart_get_collision_flag(UART_NUM, &flag)); + collision_flag |= flag; + } + ESP_LOGI(TAG, "Collision detected: %s", collision_flag ? "yes" : "no"); + TEST_ASSERT_TRUE(collision_flag); + + free(tx_buffer); + uart_driver_delete(UART_NUM); +} + +static void rs485_collision_master_coll_det(void) +{ + rs485_collision_dev(UART_MODE_RS485_COLLISION_DETECT, "Coll_master_ready", "Coll_slave_ready"); +} + +static void rs485_collision_slave_coll_det(void) +{ + rs485_collision_dev(UART_MODE_RS485_COLLISION_DETECT, "Coll_slave_ready", "Coll_master_ready"); +} + +/* + * This multi devices test case verifies the collision detection of the + * UART_MODE_RS485_COLLISION_DETECT mode. Both devices transmit at the same time, + * causing a bus collision that must be detected by the UART hardware. +*/ +TEST_CASE_MULTIPLE_DEVICES("RS485 collision detect mode can detect collision", "[RS485]", rs485_collision_master_coll_det, rs485_collision_slave_coll_det); diff --git a/components/esp_driver_uart/test_apps/rs485/pytest_rs485.py b/components/esp_driver_uart/test_apps/rs485/pytest_rs485.py index 7bbebecd2d9..a9491555691 100644 --- a/components/esp_driver_uart/test_apps/rs485/pytest_rs485.py +++ b/components/esp_driver_uart/test_apps/rs485/pytest_rs485.py @@ -15,6 +15,6 @@ from pytest_embedded_idf.utils import idf_parametrize ], indirect=True, ) -@idf_parametrize('target', ['esp32', 'esp32h2'], indirect=['target']) +@idf_parametrize('target', ['esp32', 'esp32h2', 'esp32s3'], indirect=['target']) def test_rs485_multi_dev(case_tester) -> None: # type: ignore case_tester.run_all_multi_dev_cases(reset=True) diff --git a/components/esp_driver_uart/test_apps/rs485/sdkconfig.defaults.esp32 b/components/esp_driver_uart/test_apps/rs485/sdkconfig.defaults.esp32 new file mode 100644 index 00000000000..2ed44984b09 --- /dev/null +++ b/components/esp_driver_uart/test_apps/rs485/sdkconfig.defaults.esp32 @@ -0,0 +1,4 @@ +# For ESP32, only UART0 port has DTR/DSR signal +# In order to run the rs485 test cases fully, use UART1 as the console uart, so that UART0 can be the test port +CONFIG_ESP_CONSOLE_UART_CUSTOM=y +CONFIG_ESP_CONSOLE_UART_CUSTOM_NUM_1=y diff --git a/components/esp_driver_uart/test_apps/uart/main/test_uart.c b/components/esp_driver_uart/test_apps/uart/main/test_uart.c index 709a82823ae..43bd7afa366 100644 --- a/components/esp_driver_uart/test_apps/uart/main/test_uart.c +++ b/components/esp_driver_uart/test_apps/uart/main/test_uart.c @@ -27,6 +27,7 @@ #include "test_common.h" #include "esp_attr.h" #include "esp_timer.h" +#include "sdkconfig.h" #define BUF_SIZE (100) #define UART_BAUD_11520 (11520) @@ -868,7 +869,8 @@ TEST_CASE("uart auto baud rate detection", "[uart]") TEST_ASSERT(port_select(&port_param)); // This is indeed a standalone feature, no need to specify the uart port, call port_select() to be compatible with pytest // And this test case no need to be tested twice on HP/LP uart ports both exist targets (also, LP UART does not support auto baud rate detection functionality) - if (port_param.port_num < SOC_UART_HP_NUM) { + uart_port_t uart_num = port_param.port_num; + if (uart_num < SOC_UART_HP_NUM) { TaskHandle_t console_write_task = NULL; xTaskCreate(uart_console_write_task, "uart_console_write_task", 2048, NULL, 5, &console_write_task); vTaskDelay(20); @@ -883,9 +885,9 @@ TEST_CASE("uart auto baud rate detection", "[uart]") uart_bitrate_res_t res = {}; uart_get_baudrate(CONFIG_CONSOLE_UART_NUM, &actual_baudrate); - TEST_ESP_OK(uart_detect_bitrate_start(UART_NUM_1, &conf)); // acquire a new uart port + TEST_ESP_OK(uart_detect_bitrate_start(uart_num, &conf)); // acquire a new uart port vTaskDelay(pdMS_TO_TICKS(500)); - TEST_ESP_OK(uart_detect_bitrate_stop(UART_NUM_1, false, &res)); // no releasing + TEST_ESP_OK(uart_detect_bitrate_stop(uart_num, false, &res)); // no releasing detected_baudrate = res.clk_freq_hz * 2 / res.pos_period; // assume the wave has a slow falling slew rate TEST_ASSERT_INT32_WITHIN(actual_baudrate * 0.03, actual_baudrate, detected_baudrate); // allow 3% error @@ -893,9 +895,9 @@ TEST_CASE("uart auto baud rate detection", "[uart]") uart_set_baudrate(CONFIG_CONSOLE_UART_NUM, 38400); uart_get_baudrate(CONFIG_CONSOLE_UART_NUM, &actual_baudrate); - TEST_ESP_OK(uart_detect_bitrate_start(UART_NUM_1, NULL)); // use the previously acquired uart port + TEST_ESP_OK(uart_detect_bitrate_start(uart_num, NULL)); // use the previously acquired uart port vTaskDelay(pdMS_TO_TICKS(500)); - TEST_ESP_OK(uart_detect_bitrate_stop(UART_NUM_1, true, &res)); // release the uart port + TEST_ESP_OK(uart_detect_bitrate_stop(uart_num, true, &res)); // release the uart port detected_baudrate = res.clk_freq_hz * 2 / res.pos_period; TEST_ASSERT_INT32_WITHIN(actual_baudrate * 0.03, actual_baudrate, detected_baudrate); @@ -903,9 +905,9 @@ TEST_CASE("uart auto baud rate detection", "[uart]") uart_set_baudrate(CONFIG_CONSOLE_UART_NUM, CONFIG_CONSOLE_UART_BAUDRATE); uart_get_baudrate(CONFIG_CONSOLE_UART_NUM, &actual_baudrate); - TEST_ESP_OK(uart_detect_bitrate_start(UART_NUM_1, &conf)); // acquire a new uart port again + TEST_ESP_OK(uart_detect_bitrate_start(uart_num, &conf)); // acquire a new uart port again vTaskDelay(pdMS_TO_TICKS(500)); - TEST_ESP_OK(uart_detect_bitrate_stop(UART_NUM_1, true, &res)); // release it + TEST_ESP_OK(uart_detect_bitrate_stop(uart_num, true, &res)); // release it detected_baudrate = res.clk_freq_hz * 2 / res.pos_period; TEST_ASSERT_INT32_WITHIN(actual_baudrate * 0.03, actual_baudrate, detected_baudrate); From d5a3169ee5be9d795ab436c8b9b67d36bef0de0d Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Fri, 3 Jul 2026 15:41:59 +0800 Subject: [PATCH 4/5] fix(stdio): add console input ability when selects ESP_CONSOLE_UART_CUSTOM_NUM_1 --- components/bootloader_support/src/bootloader_console.c | 7 ++++--- .../esp_stdio/test_apps/stdio/sdkconfig.ci.custom_uart | 1 + components/esp_system/port/cpu_start.c | 3 +++ 3 files changed, 8 insertions(+), 3 deletions(-) diff --git a/components/bootloader_support/src/bootloader_console.c b/components/bootloader_support/src/bootloader_console.c index 291dee0afba..fb56ca94da0 100644 --- a/components/bootloader_support/src/bootloader_console.c +++ b/components/bootloader_support/src/bootloader_console.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2020-2025 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2020-2026 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -63,8 +63,9 @@ void bootloader_console_init(void) const int uart_tx_gpio = (CONFIG_ESP_CONSOLE_UART_TX_GPIO >= 0) ? CONFIG_ESP_CONSOLE_UART_TX_GPIO : U0TXD_GPIO_NUM; const int uart_rx_gpio = (CONFIG_ESP_CONSOLE_UART_RX_GPIO >= 0) ? CONFIG_ESP_CONSOLE_UART_RX_GPIO : U0RXD_GPIO_NUM; - // Switch to the new UART (this just changes UART number used for esp_rom_printf in ROM code). - esp_rom_output_set_as_console(uart_num); + // Switch to the new UART + esp_rom_output_set_as_console(uart_num); // changes UART number used for esp_rom_printf in ROM code + esp_rom_output_switch_buffer(uart_num); // If console is attached to UART1 or if non-default pins are used, // need to reconfigure pins using GPIO matrix diff --git a/components/esp_stdio/test_apps/stdio/sdkconfig.ci.custom_uart b/components/esp_stdio/test_apps/stdio/sdkconfig.ci.custom_uart index 80ed1761ac2..56ee759e76b 100644 --- a/components/esp_stdio/test_apps/stdio/sdkconfig.ci.custom_uart +++ b/components/esp_stdio/test_apps/stdio/sdkconfig.ci.custom_uart @@ -1 +1,2 @@ CONFIG_ESP_CONSOLE_UART_CUSTOM=y +CONFIG_ESP_CONSOLE_UART_CUSTOM_NUM_1=y diff --git a/components/esp_system/port/cpu_start.c b/components/esp_system/port/cpu_start.c index f3abf008924..408b39e1483 100644 --- a/components/esp_system/port/cpu_start.c +++ b/components/esp_system/port/cpu_start.c @@ -264,6 +264,9 @@ void ESP_SYSTEM_IRAM_ATTR call_start_cpu1(void) #elif !CONFIG_ESP_CONSOLE_USB_CDC esp_rom_install_uart_printf(); esp_rom_output_set_as_console(CONFIG_ESP_CONSOLE_ROM_SERIAL_PORT_NUM); +#if CONFIG_ESP_CONSOLE_UART_CUSTOM + esp_rom_output_switch_buffer(CONFIG_ESP_CONSOLE_UART_NUM); +#endif #endif cpu_utility_ll_enable_debug(1); From 5910abe5eff352bbc1840f51da61bb12b61bfd35 Mon Sep 17 00:00:00 2001 From: Abanoub Salah Date: Sun, 31 May 2026 09:17:39 +0300 Subject: [PATCH 5/5] uart: fix threshold configuration loss when interrupts are disabled --- components/esp_driver_uart/src/uart.c | 8 ++------ 1 file changed, 2 insertions(+), 6 deletions(-) diff --git a/components/esp_driver_uart/src/uart.c b/components/esp_driver_uart/src/uart.c index f10546a2375..13f367c02bb 100644 --- a/components/esp_driver_uart/src/uart.c +++ b/components/esp_driver_uart/src/uart.c @@ -2219,9 +2219,7 @@ esp_err_t uart_set_rx_full_threshold(uart_port_t uart_num, int threshold) return ESP_ERR_INVALID_STATE; } UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); - if (uart_hal_get_intr_ena_status(&(uart_context[uart_num].hal)) & UART_INTR_RXFIFO_FULL) { - uart_hal_set_rxfifo_full_thr(&(uart_context[uart_num].hal), threshold); - } + uart_hal_set_rxfifo_full_thr(&(uart_context[uart_num].hal), threshold); UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; } @@ -2236,9 +2234,7 @@ esp_err_t uart_set_tx_empty_threshold(uart_port_t uart_num, int threshold) return ESP_ERR_INVALID_STATE; } UART_ENTER_CRITICAL(&(uart_context[uart_num].spinlock)); - if (uart_hal_get_intr_ena_status(&(uart_context[uart_num].hal)) & UART_INTR_TXFIFO_EMPTY) { - uart_hal_set_txfifo_empty_thr(&(uart_context[uart_num].hal), threshold); - } + uart_hal_set_txfifo_empty_thr(&(uart_context[uart_num].hal), threshold); UART_EXIT_CRITICAL(&(uart_context[uart_num].spinlock)); return ESP_OK; }