From 6ebe14cb4924c3690ea09437e49df28a9c8d1896 Mon Sep 17 00:00:00 2001 From: SuGlider Date: Sun, 30 Nov 2025 14:37:21 -0300 Subject: [PATCH 01/19] fix(uart): terminates uart driver whenever rx and tx are detached --- cores/esp32/HardwareSerial.cpp | 3 --- cores/esp32/esp32-hal-uart.c | 11 +++++++++++ 2 files changed, 11 insertions(+), 3 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 5c0ed3e50f7..20611924a48 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -483,9 +483,6 @@ void HardwareSerial::end() { // including any tasks or debug message channel (log_x()) - but not for IDF log messages! _onReceiveCB = NULL; _onReceiveErrorCB = NULL; - if (uartGetDebug() == _uart_nr) { - uartSetDebug(0); - } _rxFIFOFull = 0; uartEnd(_uart_nr); // fully detach all pins and delete the UART driver _destroyEventTask(); // when IDF uart driver is deleted, _eventTask must finish too diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 8eb6bc1c645..07b04431480 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -284,6 +284,10 @@ static bool _uartDetachBus_RX(void *busptr) { // sanity check - it should never happen assert(busptr && "_uartDetachBus_RX bus NULL pointer."); uart_t *bus = (uart_t *)busptr; + if (bus->_txPin < 0) { // both rx and tx pins are detached, terminate the uart driver + uartEnd(bus->num); + return true; + } return _uartDetachPins(bus->num, bus->_rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } @@ -291,6 +295,10 @@ static bool _uartDetachBus_TX(void *busptr) { // sanity check - it should never happen assert(busptr && "_uartDetachBus_TX bus NULL pointer."); uart_t *bus = (uart_t *)busptr; + if (bus->_rxPin < 0) { // both rx and tx pins are detached, terminate the uart driver + uartEnd(bus->num); + return true; + } return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, bus->_txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } @@ -986,6 +994,9 @@ void uartEnd(uint8_t uart_num) { if (uart_is_driver_installed(uart_num)) { uart_driver_delete(uart_num); } + if (uartGetDebug() == uart_num) { + uartSetDebug(0); + } UART_MUTEX_UNLOCK(); } From 5f25e443dda07cf26a609b1db7cc3fd229a7ecae Mon Sep 17 00:00:00 2001 From: SuGlider Date: Sun, 30 Nov 2025 15:08:26 -0300 Subject: [PATCH 02/19] fix(uart): detaching pin check points --- cores/esp32/chip-debug-report.cpp | 2 +- cores/esp32/esp32-hal-uart.c | 36 +++++++++++++++++++++++++++---- 2 files changed, 33 insertions(+), 5 deletions(-) diff --git a/cores/esp32/chip-debug-report.cpp b/cores/esp32/chip-debug-report.cpp index f4f29a1e005..414dd108a63 100644 --- a/cores/esp32/chip-debug-report.cpp +++ b/cores/esp32/chip-debug-report.cpp @@ -291,7 +291,7 @@ static void printPerimanInfo(void) { void printBeforeSetupInfo(void) { #if ARDUINO_USB_CDC_ON_BOOT - Serial.begin(0); + Serial.begin(); Serial.setDebugOutput(true); uint8_t t = 0; while (!Serial && (t++ < 200)) { diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 07b04431480..b8b7e21e33b 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -282,8 +282,15 @@ static bool _uartDetachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t // Peripheral Manager detach callback for each specific UART PIN static bool _uartDetachBus_RX(void *busptr) { // sanity check - it should never happen - assert(busptr && "_uartDetachBus_RX bus NULL pointer."); + if (busptr == NULL) { + log_e("_uartDetachBus_RX: busptr is NULL"); + return false; + } uart_t *bus = (uart_t *)busptr; + if (bus->_rxPin < 0) { + log_d("_uartDetachBus_RX: RX pin already detached for UART%d", bus->num); + return true; + } if (bus->_txPin < 0) { // both rx and tx pins are detached, terminate the uart driver uartEnd(bus->num); return true; @@ -293,8 +300,15 @@ static bool _uartDetachBus_RX(void *busptr) { static bool _uartDetachBus_TX(void *busptr) { // sanity check - it should never happen - assert(busptr && "_uartDetachBus_TX bus NULL pointer."); + if (busptr == NULL) { + log_e("_uartDetachBus_TX: busptr is NULL"); + return false; + } uart_t *bus = (uart_t *)busptr; + if (bus->_txPin < 0) { + log_d("_uartDetachBus_TX: TX pin already detached for UART%d", bus->num); + return true; + } if (bus->_rxPin < 0) { // both rx and tx pins are detached, terminate the uart driver uartEnd(bus->num); return true; @@ -304,15 +318,29 @@ static bool _uartDetachBus_TX(void *busptr) { static bool _uartDetachBus_CTS(void *busptr) { // sanity check - it should never happen - assert(busptr && "_uartDetachBus_CTS bus NULL pointer."); + if (busptr == NULL) { + log_e("_uartDetachBus_CTS: busptr is NULL"); + return false; + } uart_t *bus = (uart_t *)busptr; + if (bus->_ctsPin < 0) { + log_d("_uartDetachBus_CTS: CTS pin already detached for UART%d", bus->num); + return true; + } return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, bus->_ctsPin, UART_PIN_NO_CHANGE); } static bool _uartDetachBus_RTS(void *busptr) { // sanity check - it should never happen - assert(busptr && "_uartDetachBus_RTS bus NULL pointer."); + if (busptr == NULL) { + log_e("_uartDetachBus_RTS: busptr is NULL"); + return false; + } uart_t *bus = (uart_t *)busptr; + if (bus->_rtsPin < 0) { + log_d("_uartDetachBus_RTS: RTS pin already detached for UART%d", bus->num); + return true; + } return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, bus->_rtsPin); } From 85d92e931c7567a88eaffa823da4e527d073b540 Mon Sep 17 00:00:00 2001 From: SuGlider Date: Sun, 30 Nov 2025 15:26:05 -0300 Subject: [PATCH 03/19] fix(uart): extended lod messages --- cores/esp32/esp32-hal-uart.c | 2 ++ 1 file changed, 2 insertions(+) diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index b8b7e21e33b..d9766180ec4 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -292,6 +292,7 @@ static bool _uartDetachBus_RX(void *busptr) { return true; } if (bus->_txPin < 0) { // both rx and tx pins are detached, terminate the uart driver + log_d("_uartDetachBus_RX: both RX and TX pins detached for UART%d, terminating driver", bus->num); uartEnd(bus->num); return true; } @@ -310,6 +311,7 @@ static bool _uartDetachBus_TX(void *busptr) { return true; } if (bus->_rxPin < 0) { // both rx and tx pins are detached, terminate the uart driver + log_d("_uartDetachBus_TX: both RX and TX pins detached for UART%d, terminating driver", bus->num); uartEnd(bus->num); return true; } From f41795c486e23d97f948b35d64c84dc78940e328 Mon Sep 17 00:00:00 2001 From: SuGlider Date: Mon, 1 Dec 2025 19:24:50 -0300 Subject: [PATCH 04/19] fix(uart): fixes setPins to keep driver working --- cores/esp32/esp32-hal-uart.c | 25 +++++++++++++++++++++++++ 1 file changed, 25 insertions(+) diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index d9766180ec4..48eed7b6d8d 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -667,6 +667,16 @@ bool uartSetPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, in //log_v("setting UART%d pins: prev->new RX(%d->%d) TX(%d->%d) CTS(%d->%d) RTS(%d->%d)", uart_num, // uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); + // mute bus detaching callbacks to avoid terminating the UART driver when both RX and TX pins are detached + peripheral_bus_deinit_cb_t rxDeinit = perimanGetBusDeinit(ESP32_BUS_TYPE_UART_RX); + peripheral_bus_deinit_cb_t txDeinit = perimanGetBusDeinit(ESP32_BUS_TYPE_UART_TX); + peripheral_bus_deinit_cb_t ctsDeinit = perimanGetBusDeinit(ESP32_BUS_TYPE_UART_CTS); + peripheral_bus_deinit_cb_t rtsDeinit = perimanGetBusDeinit(ESP32_BUS_TYPE_UART_RTS); + perimanClearBusDeinit(ESP32_BUS_TYPE_UART_RX); + perimanClearBusDeinit(ESP32_BUS_TYPE_UART_TX); + perimanClearBusDeinit(ESP32_BUS_TYPE_UART_CTS); + perimanClearBusDeinit(ESP32_BUS_TYPE_UART_RTS); + // First step: detaches all previous UART pins bool rxPinChanged = rxPin >= 0 && rxPin != uart->_rxPin; if (rxPinChanged) { @@ -698,6 +708,21 @@ bool uartSetPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, in if (rtsPinChanged) { retCode &= _uartAttachPins(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin); } + + // restore bus detaching callbacks + if (rxDeinit != NULL) { + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_RX, rxDeinit); + } + if (txDeinit != NULL) { + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_TX, txDeinit); + } + if (ctsDeinit != NULL) { + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_CTS, ctsDeinit); + } + if (rtsDeinit != NULL) { + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_RTS, rtsDeinit); + } + UART_MUTEX_UNLOCK(); if (!retCode) { From febad6d04a08eabda4fc6daee4f9eeeab6c87397 Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Mon, 1 Dec 2025 21:09:01 -0300 Subject: [PATCH 05/19] fix(uart): peripheral manager CI test adjusting Updated UART test configurations to handle I2C interactions correctly by detaching TX pin and restarting the UART driver when both RX and TX are detached. --- tests/validation/uart/uart.ino | 28 ++++++++++++++++++++++++++-- 1 file changed, 26 insertions(+), 2 deletions(-) diff --git a/tests/validation/uart/uart.ino b/tests/validation/uart/uart.ino index 18da797659b..0df383317a4 100644 --- a/tests/validation/uart/uart.ino +++ b/tests/validation/uart/uart.ino @@ -450,7 +450,9 @@ void periman_test(void) { for (auto *ref : uart_test_configs) { UARTTestConfig &config = *ref; - Wire.begin(config.default_rx_pin, config.default_tx_pin); + // when both RX and TX are detached the UART driver is stopped, + // therefore, it may change just one the UART pins for testing + Wire.begin(config.default_rx_pin, -1); config.recv_msg = ""; log_d("Trying to send message using UART%d with I2C enabled", config.uart_num); @@ -459,7 +461,30 @@ void periman_test(void) { log_d("Disabling I2C and re-enabling UART%d", config.uart_num); + // when just chenging one UART pin, the driver will continue to work + // and it is possible to just change back the UART pins config.serial.setPins(config.default_rx_pin, config.default_tx_pin); + + uart_internal_loopback(config.uart_num, config.default_rx_pin); + + log_d("Trying to send message using UART%d with I2C disabled", config.uart_num); + config.transmit_and_check_msg("while I2C is disabled"); + + + // when both RX and TX are detached the UART driver is stopped, + // Therefore, it needs to be restarted + Wire.begin(config.default_rx_pin, config.default_tx_pin); + config.recv_msg = ""; + + log_d("Trying to send message using UART%d with I2C enabled", config.uart_num); + config.transmit_and_check_msg("while used by I2C", false); + TEST_ASSERT_EQUAL_STRING("", config.recv_msg.c_str()); + + log_d("Disabling I2C and re-enabling UART%d", config.uart_num); + + // when both RX and TX are detached the UART driver is stopped, therefore, starting the driver again is necessary + config.serial.begin(115200, SERIAL_8N1, config.default_rx_pin, config.default_tx_pin); + uart_internal_loopback(config.uart_num, config.default_rx_pin); log_d("Trying to send message using UART%d with I2C disabled", config.uart_num); @@ -468,7 +493,6 @@ void periman_test(void) { Serial.println("Peripheral manager test successful"); } - // This test checks if messages can be transmitted and received correctly after changing the CPU frequency void change_cpu_frequency_test(void) { uint32_t old_freq = getCpuFrequencyMhz(); From c329742bd43f35a6861744a031c1da210d03b5dd Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Tue, 2 Dec 2025 15:41:11 -0300 Subject: [PATCH 06/19] fix(uart): Refactor UART test to detach only one pin Updated UART test configuration to detach only one pin instead of both, ensuring the UART driver continues to function. Removed redundant code related to UART driver restart when both pins are detached. --- tests/validation/uart/uart.ino | 30 ++++-------------------------- 1 file changed, 4 insertions(+), 26 deletions(-) diff --git a/tests/validation/uart/uart.ino b/tests/validation/uart/uart.ino index 0df383317a4..6a3c26c8cec 100644 --- a/tests/validation/uart/uart.ino +++ b/tests/validation/uart/uart.ino @@ -450,9 +450,9 @@ void periman_test(void) { for (auto *ref : uart_test_configs) { UARTTestConfig &config = *ref; - // when both RX and TX are detached the UART driver is stopped, - // therefore, it may change just one the UART pins for testing - Wire.begin(config.default_rx_pin, -1); + // detaching both pins will result in stoping the UART driver + // Only detach one of the pins + Wire.begin(config.default_rx_pin, /*config.default_tx_pin*/ -1); config.recv_msg = ""; log_d("Trying to send message using UART%d with I2C enabled", config.uart_num); @@ -461,30 +461,7 @@ void periman_test(void) { log_d("Disabling I2C and re-enabling UART%d", config.uart_num); - // when just chenging one UART pin, the driver will continue to work - // and it is possible to just change back the UART pins config.serial.setPins(config.default_rx_pin, config.default_tx_pin); - - uart_internal_loopback(config.uart_num, config.default_rx_pin); - - log_d("Trying to send message using UART%d with I2C disabled", config.uart_num); - config.transmit_and_check_msg("while I2C is disabled"); - - - // when both RX and TX are detached the UART driver is stopped, - // Therefore, it needs to be restarted - Wire.begin(config.default_rx_pin, config.default_tx_pin); - config.recv_msg = ""; - - log_d("Trying to send message using UART%d with I2C enabled", config.uart_num); - config.transmit_and_check_msg("while used by I2C", false); - TEST_ASSERT_EQUAL_STRING("", config.recv_msg.c_str()); - - log_d("Disabling I2C and re-enabling UART%d", config.uart_num); - - // when both RX and TX are detached the UART driver is stopped, therefore, starting the driver again is necessary - config.serial.begin(115200, SERIAL_8N1, config.default_rx_pin, config.default_tx_pin); - uart_internal_loopback(config.uart_num, config.default_rx_pin); log_d("Trying to send message using UART%d with I2C disabled", config.uart_num); @@ -493,6 +470,7 @@ void periman_test(void) { Serial.println("Peripheral manager test successful"); } + // This test checks if messages can be transmitted and received correctly after changing the CPU frequency void change_cpu_frequency_test(void) { uint32_t old_freq = getCpuFrequencyMhz(); From e681a944216d5747c40239ce6db21ec088d9ceb2 Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Tue, 2 Dec 2025 17:55:57 -0300 Subject: [PATCH 07/19] fix(uart_test): do not detach both UART pins Updated UART test configuration to detach TX pin while keeping RX pin active. Adjusted assertions to reflect the new pin settings. --- tests/validation/uart/uart.ino | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/tests/validation/uart/uart.ino b/tests/validation/uart/uart.ino index 6a3c26c8cec..341c7adc0ef 100644 --- a/tests/validation/uart/uart.ino +++ b/tests/validation/uart/uart.ino @@ -377,9 +377,11 @@ void change_pins_test(void) { UARTTestConfig &config = *uart_test_configs[0]; // pinMode will force enabling the internal pullup resistor (IDF 5.3.2 Change) pinMode(NEW_RX1, INPUT_PULLUP); - config.serial.setPins(NEW_RX1, NEW_TX1); + // Detaching both pins will result in stoping the UART driver + // Only detach one of the pins + config.serial.setPins(NEW_RX1, /*NEW_TX1*/ -1); TEST_ASSERT_EQUAL(NEW_RX1, uart_get_RxPin(config.uart_num)); - TEST_ASSERT_EQUAL(NEW_TX1, uart_get_TxPin(config.uart_num)); + //TEST_ASSERT_EQUAL(NEW_TX1, uart_get_TxPin(config.uart_num)); uart_internal_loopback(config.uart_num, NEW_RX1); config.transmit_and_check_msg("using new pins"); @@ -387,9 +389,11 @@ void change_pins_test(void) { for (int i = 0; i < TEST_UART_NUM; i++) { UARTTestConfig &config = *uart_test_configs[i]; UARTTestConfig &next_uart = *uart_test_configs[(i + 1) % TEST_UART_NUM]; - config.serial.setPins(next_uart.default_rx_pin, next_uart.default_tx_pin); + // Detaching both pins will result in stoping the UART driver + // Only detach one of the pins + config.serial.setPins(next_uart.default_rx_pin, /*next_uart.default_tx_pin*/ -1); TEST_ASSERT_EQUAL(uart_get_RxPin(config.uart_num), next_uart.default_rx_pin); - TEST_ASSERT_EQUAL(uart_get_TxPin(config.uart_num), next_uart.default_tx_pin); + //TEST_ASSERT_EQUAL(uart_get_TxPin(config.uart_num), next_uart.default_tx_pin); uart_internal_loopback(config.uart_num, next_uart.default_rx_pin); config.transmit_and_check_msg("using new pins"); @@ -398,7 +402,6 @@ void change_pins_test(void) { Serial.println("Change pins test successful"); } - // This test checks if the auto baudrate detection works on ESP32 and ESP32-S2 #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 void auto_baudrate_test(void) { @@ -450,7 +453,7 @@ void periman_test(void) { for (auto *ref : uart_test_configs) { UARTTestConfig &config = *ref; - // detaching both pins will result in stoping the UART driver + // Detaching both pins will result in stoping the UART driver // Only detach one of the pins Wire.begin(config.default_rx_pin, /*config.default_tx_pin*/ -1); config.recv_msg = ""; From 3663af976ee489996c3999414f1324f8ce9f8c4f Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Tue, 2 Dec 2025 17:57:31 -0300 Subject: [PATCH 08/19] fix(uart_test): formatting --- tests/validation/uart/uart.ino | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/validation/uart/uart.ino b/tests/validation/uart/uart.ino index 341c7adc0ef..28b81a51d32 100644 --- a/tests/validation/uart/uart.ino +++ b/tests/validation/uart/uart.ino @@ -402,6 +402,7 @@ void change_pins_test(void) { Serial.println("Change pins test successful"); } + // This test checks if the auto baudrate detection works on ESP32 and ESP32-S2 #if CONFIG_IDF_TARGET_ESP32 || CONFIG_IDF_TARGET_ESP32S2 void auto_baudrate_test(void) { From 520cd35d81564ab6fe1648841d09058dd73b5f5b Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Tue, 2 Dec 2025 18:26:39 -0300 Subject: [PATCH 09/19] fix(uart_doc): Document RX and TX pin detachment behavior Added note about driver behavior when RX and TX pins are detached. --- docs/en/api/serial.rst | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/docs/en/api/serial.rst b/docs/en/api/serial.rst index 69f9969196d..280d20216b1 100644 --- a/docs/en/api/serial.rst +++ b/docs/en/api/serial.rst @@ -23,6 +23,10 @@ with additional features for advanced use cases. * **Event callbacks**: Receive and error event callbacks * **Configurable buffers**: Adjustable RX and TX buffer sizes +.. note:: + In case that both pins RX and TX are detached from UART, the driver will be stopped. + Detaching may occur when, for instance, starting another peripheral using RX and TX pins, such as Wire.begin(RX0, TX0). + UART Availability ----------------- From 6f720750224b84a45879a18058234c0653c9f37d Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Tue, 2 Dec 2025 19:27:14 -0300 Subject: [PATCH 10/19] fix(uart): code formatting Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- cores/esp32/esp32-hal-uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 48eed7b6d8d..b916102410e 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -292,7 +292,7 @@ static bool _uartDetachBus_RX(void *busptr) { return true; } if (bus->_txPin < 0) { // both rx and tx pins are detached, terminate the uart driver - log_d("_uartDetachBus_RX: both RX and TX pins detached for UART%d, terminating driver", bus->num); + log_d("_uartDetachBus_RX: both RX and TX pins detached for UART%d, terminating driver", bus->num); uartEnd(bus->num); return true; } From 7d3c42189993fb23b2d2a16d617144f6c82c9c13 Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Tue, 2 Dec 2025 19:27:25 -0300 Subject: [PATCH 11/19] fix(uart): code formatting Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- cores/esp32/esp32-hal-uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index b916102410e..75b41fe6e80 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -294,7 +294,7 @@ static bool _uartDetachBus_RX(void *busptr) { if (bus->_txPin < 0) { // both rx and tx pins are detached, terminate the uart driver log_d("_uartDetachBus_RX: both RX and TX pins detached for UART%d, terminating driver", bus->num); uartEnd(bus->num); - return true; + return true; } return _uartDetachPins(bus->num, bus->_rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } From 8d2557a2a8d370a26104ed4f0b53da8d1038d1d3 Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Tue, 2 Dec 2025 19:27:42 -0300 Subject: [PATCH 12/19] fix(uart): code formatting Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- cores/esp32/esp32-hal-uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 75b41fe6e80..b27bb46c826 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -309,7 +309,7 @@ static bool _uartDetachBus_TX(void *busptr) { if (bus->_txPin < 0) { log_d("_uartDetachBus_TX: TX pin already detached for UART%d", bus->num); return true; - } + } if (bus->_rxPin < 0) { // both rx and tx pins are detached, terminate the uart driver log_d("_uartDetachBus_TX: both RX and TX pins detached for UART%d, terminating driver", bus->num); uartEnd(bus->num); From 6f614a06379302d2ff87b85e24ddf7701e71ec76 Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Tue, 2 Dec 2025 19:28:13 -0300 Subject: [PATCH 13/19] fix(uart): code formatting Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- cores/esp32/esp32-hal-uart.c | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index b27bb46c826..0c5e63de044 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -313,7 +313,7 @@ static bool _uartDetachBus_TX(void *busptr) { if (bus->_rxPin < 0) { // both rx and tx pins are detached, terminate the uart driver log_d("_uartDetachBus_TX: both RX and TX pins detached for UART%d, terminating driver", bus->num); uartEnd(bus->num); - return true; + return true; } return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, bus->_txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } From 66c43f73d4335c35c2418e2ee920294906b61aeb Mon Sep 17 00:00:00 2001 From: SuGlider Date: Tue, 2 Dec 2025 23:19:57 -0300 Subject: [PATCH 14/19] feat(uart): C wrapper to end related Serial object --- cores/esp32/HardwareSerial.cpp | 25 +++++++++++++++++++++++++ cores/esp32/esp32-hal-uart.c | 7 +++++-- 2 files changed, 30 insertions(+), 2 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 20611924a48..f24385e6402 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -61,6 +61,31 @@ HardwareSerial Serial5(5); extern void HWCDCSerialEvent(void) __attribute__((weak)); #endif +// C-callable helper used by HAL when pins are detached and the high-level +// HardwareSerial instance must be finalized. +extern "C" void hal_uart_notify_pins_detached(int uart_num) { + log_d("hal_uart_notify_pins_detached: Notifying HardwareSerial for UART%d", uart_num); + switch (uart_num) { + case UART_NUM_0: Serial0.end(); break; +#if SOC_UART_NUM > 1 + case UART_NUM_1: Serial1.end(); break; +#endif +#if SOC_UART_NUM > 2 + case UART_NUM_2: Serial2.end(); break; +#endif +#if SOC_UART_NUM > 3 + case UART_NUM_3: Serial3.end(); break; +#endif +#if SOC_UART_NUM > 4 + case UART_NUM_4: Serial4.end(); break; +#endif +#if SOC_UART_NUM > 5 + case UART_NUM_4: Serial5.end(); break; +#endif + default: break; + } +} + #if USB_SERIAL_IS_DEFINED == 1 // Native USB CDC Event // Used by Hardware Serial for USB CDC events extern void USBSerialEvent(void) __attribute__((weak)); diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 0c5e63de044..722d6d36a20 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -42,6 +42,9 @@ static int s_uart_debug_nr = 0; // UART number for debug output #define REF_TICK_BAUDRATE_LIMIT 250000 // this is maximum UART badrate using REF_TICK as clock +/* C prototype for the notifier implemented in HardwareSerial.cpp */ +extern void hal_uart_notify_pins_detached(int uart_num); + struct uart_struct_t { #if !CONFIG_DISABLE_HAL_LOCKS @@ -293,7 +296,7 @@ static bool _uartDetachBus_RX(void *busptr) { } if (bus->_txPin < 0) { // both rx and tx pins are detached, terminate the uart driver log_d("_uartDetachBus_RX: both RX and TX pins detached for UART%d, terminating driver", bus->num); - uartEnd(bus->num); + hal_uart_notify_pins_detached(bus->num); return true; } return _uartDetachPins(bus->num, bus->_rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); @@ -312,7 +315,7 @@ static bool _uartDetachBus_TX(void *busptr) { } if (bus->_rxPin < 0) { // both rx and tx pins are detached, terminate the uart driver log_d("_uartDetachBus_TX: both RX and TX pins detached for UART%d, terminating driver", bus->num); - uartEnd(bus->num); + hal_uart_notify_pins_detached(bus->num); return true; } return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, bus->_txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); From 0a87a50ae3d2e15540ef80d7c293eaea321baff1 Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Tue, 2 Dec 2025 23:27:07 -0300 Subject: [PATCH 15/19] fix(uart): fixes bad case value Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> --- cores/esp32/HardwareSerial.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index f24385e6402..4c81f69ec7e 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -80,7 +80,7 @@ extern "C" void hal_uart_notify_pins_detached(int uart_num) { case UART_NUM_4: Serial4.end(); break; #endif #if SOC_UART_NUM > 5 - case UART_NUM_4: Serial5.end(); break; + case UART_NUM_5: Serial5.end(); break; #endif default: break; } From f2a23ccba57b6797201ecb845381e8c917da081b Mon Sep 17 00:00:00 2001 From: SuGlider Date: Tue, 2 Dec 2025 23:36:35 -0300 Subject: [PATCH 16/19] fix(uart): C wrapper to end related Serial object --- cores/esp32/HardwareSerial.cpp | 16 +++++++++------- 1 file changed, 9 insertions(+), 7 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 4c81f69ec7e..8a02c1b65cf 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -66,23 +66,25 @@ extern void HWCDCSerialEvent(void) __attribute__((weak)); extern "C" void hal_uart_notify_pins_detached(int uart_num) { log_d("hal_uart_notify_pins_detached: Notifying HardwareSerial for UART%d", uart_num); switch (uart_num) { - case UART_NUM_0: Serial0.end(); break; + case 0: Serial0.end(); break; #if SOC_UART_NUM > 1 - case UART_NUM_1: Serial1.end(); break; + case 1: Serial1.end(); break; #endif #if SOC_UART_NUM > 2 - case UART_NUM_2: Serial2.end(); break; + case 2: Serial2.end(); break; #endif #if SOC_UART_NUM > 3 - case UART_NUM_3: Serial3.end(); break; + case 3: Serial3.end(); break; #endif #if SOC_UART_NUM > 4 - case UART_NUM_4: Serial4.end(); break; + case 4: Serial4.end(); break; #endif #if SOC_UART_NUM > 5 - case UART_NUM_5: Serial5.end(); break; + case 5: Serial5.end(); break; #endif - default: break; + default: + log_e("hal_uart_notify_pins_detached: UART%d not handled!", uart_num); + break; } } From 2024abe6ef9facf2740945412e6271b98a8396d3 Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Wed, 3 Dec 2025 09:25:37 -0300 Subject: [PATCH 17/19] fix(docs): adding comma --- docs/en/api/serial.rst | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/docs/en/api/serial.rst b/docs/en/api/serial.rst index 280d20216b1..86ddd26a891 100644 --- a/docs/en/api/serial.rst +++ b/docs/en/api/serial.rst @@ -24,7 +24,7 @@ with additional features for advanced use cases. * **Configurable buffers**: Adjustable RX and TX buffer sizes .. note:: - In case that both pins RX and TX are detached from UART, the driver will be stopped. + In case that both pins, RX and TX are detached from UART, the driver will be stopped. Detaching may occur when, for instance, starting another peripheral using RX and TX pins, such as Wire.begin(RX0, TX0). UART Availability From 1e9077585a718d8af92f35ceb261bc8b600b520e Mon Sep 17 00:00:00 2001 From: "pre-commit-ci-lite[bot]" <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com> Date: Wed, 3 Dec 2025 12:53:54 +0000 Subject: [PATCH 18/19] ci(pre-commit): Apply automatic fixes --- cores/esp32/HardwareSerial.cpp | 4 +--- cores/esp32/esp32-hal-uart.c | 4 ++-- 2 files changed, 3 insertions(+), 5 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 8a02c1b65cf..7d4e4888e47 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -82,9 +82,7 @@ extern "C" void hal_uart_notify_pins_detached(int uart_num) { #if SOC_UART_NUM > 5 case 5: Serial5.end(); break; #endif - default: - log_e("hal_uart_notify_pins_detached: UART%d not handled!", uart_num); - break; + default: log_e("hal_uart_notify_pins_detached: UART%d not handled!", uart_num); break; } } diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 722d6d36a20..4b80108fb0e 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -294,7 +294,7 @@ static bool _uartDetachBus_RX(void *busptr) { log_d("_uartDetachBus_RX: RX pin already detached for UART%d", bus->num); return true; } - if (bus->_txPin < 0) { // both rx and tx pins are detached, terminate the uart driver + if (bus->_txPin < 0) { // both rx and tx pins are detached, terminate the uart driver log_d("_uartDetachBus_RX: both RX and TX pins detached for UART%d, terminating driver", bus->num); hal_uart_notify_pins_detached(bus->num); return true; @@ -313,7 +313,7 @@ static bool _uartDetachBus_TX(void *busptr) { log_d("_uartDetachBus_TX: TX pin already detached for UART%d", bus->num); return true; } - if (bus->_rxPin < 0) { // both rx and tx pins are detached, terminate the uart driver + if (bus->_rxPin < 0) { // both rx and tx pins are detached, terminate the uart driver log_d("_uartDetachBus_TX: both RX and TX pins detached for UART%d, terminating driver", bus->num); hal_uart_notify_pins_detached(bus->num); return true; From fec4a8228772b3268390267ef04c389c2c84af92 Mon Sep 17 00:00:00 2001 From: Sugar Glider Date: Wed, 3 Dec 2025 14:37:58 -0300 Subject: [PATCH 19/19] fix(uart_ci): typo in UART driver comment --- tests/validation/uart/uart.ino | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/tests/validation/uart/uart.ino b/tests/validation/uart/uart.ino index 28b81a51d32..ee83c334e19 100644 --- a/tests/validation/uart/uart.ino +++ b/tests/validation/uart/uart.ino @@ -377,7 +377,7 @@ void change_pins_test(void) { UARTTestConfig &config = *uart_test_configs[0]; // pinMode will force enabling the internal pullup resistor (IDF 5.3.2 Change) pinMode(NEW_RX1, INPUT_PULLUP); - // Detaching both pins will result in stoping the UART driver + // Detaching both pins will result in stopping the UART driver // Only detach one of the pins config.serial.setPins(NEW_RX1, /*NEW_TX1*/ -1); TEST_ASSERT_EQUAL(NEW_RX1, uart_get_RxPin(config.uart_num)); @@ -389,7 +389,7 @@ void change_pins_test(void) { for (int i = 0; i < TEST_UART_NUM; i++) { UARTTestConfig &config = *uart_test_configs[i]; UARTTestConfig &next_uart = *uart_test_configs[(i + 1) % TEST_UART_NUM]; - // Detaching both pins will result in stoping the UART driver + // Detaching both pins will result in stopping the UART driver // Only detach one of the pins config.serial.setPins(next_uart.default_rx_pin, /*next_uart.default_tx_pin*/ -1); TEST_ASSERT_EQUAL(uart_get_RxPin(config.uart_num), next_uart.default_rx_pin); @@ -454,7 +454,7 @@ void periman_test(void) { for (auto *ref : uart_test_configs) { UARTTestConfig &config = *ref; - // Detaching both pins will result in stoping the UART driver + // Detaching both pins will result in stopping the UART driver // Only detach one of the pins Wire.begin(config.default_rx_pin, /*config.default_tx_pin*/ -1); config.recv_msg = "";