From f3ac90d8deb9b9eeaf7f023186921d2a3c9f1773 Mon Sep 17 00:00:00 2001 From: Andrew Sund Date: Mon, 2 Jun 2025 17:47:28 -0700 Subject: [PATCH] feat(HardwareSerial): Add function to invert Hardware UART's Tx line alongside existing Rx functionality Simply clone existing Rx functionality for Tx. The goal here is to allow granular control over both lines but avoid overloading HardwareSerial::begin() to change the boolean 'invert' parameter to a bitmask type. --- cores/esp32/HardwareSerial.cpp | 4 ++++ cores/esp32/HardwareSerial.h | 1 + cores/esp32/esp32-hal-uart.c | 24 ++++++++++++++++++++++++ cores/esp32/esp32-hal-uart.h | 1 + tests/validation/uart/uart.ino | 8 ++++++++ 5 files changed, 38 insertions(+) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 6d762da21fb..42acdb742b7 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -578,6 +578,10 @@ void HardwareSerial::setRxInvert(bool invert) { uartSetRxInvert(_uart, invert); } +void HardwareSerial::setTxInvert(bool invert) { + uartSetTxInvert(_uart, invert); +} + // negative Pin value will keep it unmodified // can be called after or before begin() bool HardwareSerial::setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) { diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index e974f112701..c6dc917706d 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -349,6 +349,7 @@ class HardwareSerial : public Stream { void setDebugOutput(bool); void setRxInvert(bool); + void setTxInvert(bool); // Negative Pin Number will keep it unmodified, thus this function can set individual pins // setPins() can be called after or before begin() diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 5311aff4f37..745fbace533 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -847,6 +847,30 @@ void uartSetRxInvert(uart_t *uart, bool invert) { #endif } +void uartSetTxInvert(uart_t *uart, bool invert) { + if (uart == NULL) { + return; + } +#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 + // POTENTIAL ISSUE :: original code only set/reset txd_inv bit + // IDF or LL set/reset the whole inv_mask! + // if (invert) + // ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_TXD_INV)); + // else + // ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE)); + log_e("uartSetTxInvert is not supported in ESP32C6, ESP32H2 and ESP32P4"); +#else + // this implementation is better over IDF API because it only affects TXD + // this is supported in ESP32, ESP32-S2 and ESP32-C3 + uart_dev_t *hw = UART_LL_GET_HW(uart->num); + if (invert) { + hw->conf0.txd_inv = 1; + } else { + hw->conf0.txd_inv = 0; + } +#endif +} + uint32_t uartAvailable(uart_t *uart) { if (uart == NULL) { diff --git a/cores/esp32/esp32-hal-uart.h b/cores/esp32/esp32-hal-uart.h index 41b005aa151..4f23ab629f5 100644 --- a/cores/esp32/esp32-hal-uart.h +++ b/cores/esp32/esp32-hal-uart.h @@ -62,6 +62,7 @@ bool uartSetBaudRate(uart_t *uart, uint32_t baud_rate); uint32_t uartGetBaudRate(uart_t *uart); void uartSetRxInvert(uart_t *uart, bool invert); +void uartSetTxInvert(uart_t *uart, bool invert); bool uartSetRxTimeout(uart_t *uart, uint8_t numSymbTimeout); bool uartSetRxFIFOFull(uart_t *uart, uint8_t numBytesFIFOFull); void uartSetFastReading(uart_t *uart); diff --git a/tests/validation/uart/uart.ino b/tests/validation/uart/uart.ino index 794fc9affc2..18da797659b 100644 --- a/tests/validation/uart/uart.ino +++ b/tests/validation/uart/uart.ino @@ -276,6 +276,10 @@ void enabled_uart_calls_test(void) { Serial1.setRxInvert(true); Serial1.setRxInvert(false); + log_d("Checking if Serial 1 TX can be inverted while running"); + Serial1.setTxInvert(true); + Serial1.setTxInvert(false); + Serial.println("Enabled UART calls test successful"); } @@ -351,6 +355,10 @@ void disabled_uart_calls_test(void) { Serial1.setRxInvert(true); Serial1.setRxInvert(false); + log_d("Checking if Serial 1 TX can be inverted when stopped"); + Serial1.setTxInvert(true); + Serial1.setTxInvert(false); + Serial.println("Disabled UART calls test successful"); }