Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
29 commits
Select commit Hold shift + click to select a range
7db47ca
feat(uart): Add function to invert hardware UART Tx line
asund Jun 3, 2025
948c485
Merge branch 'master' into uart_tx_invert
asund Jun 4, 2025
119082f
feat(uart): Refactor UART signal inversion handling
SuGlider Nov 3, 2025
268f282
feat(uart): Add UART signal inversion functions
SuGlider Nov 3, 2025
474edd3
feat(uart): Refactor UART signal inversion handling
SuGlider Nov 3, 2025
4e94855
feat(uart): Change setRxInvert and setTxInvert to return bool
SuGlider Nov 3, 2025
2e3ae48
feat(uart) : Refactor serial inversion methods to return bool
SuGlider Nov 3, 2025
af3ec5b
feat(uart): adds commentatries
SuGlider Nov 3, 2025
84da944
feat(uart): add commentaties
SuGlider Nov 3, 2025
ce6e5be
Merge branch 'master' into uart_tx_invert
SuGlider Nov 3, 2025
c2f54ac
feat(uart): Refactor uartPinSignalInversion for mutex locking
SuGlider Nov 3, 2025
3781bef
Refactor UART inversion functions to use new method
SuGlider Nov 3, 2025
9634116
fix(uart): missing uart struct usage
SuGlider Nov 3, 2025
84f3796
fix(uart): missing function return value
SuGlider Nov 3, 2025
5753a02
feat(uart): add commentaties
SuGlider Nov 4, 2025
9541212
Merge branch 'master' into uart_tx_invert
SuGlider Nov 4, 2025
06b2dfa
fix(uart): inverting rx instead of tx
SuGlider Nov 4, 2025
c409993
feat(uart): logging for UART signal inversion
SuGlider Nov 4, 2025
c74f4e9
feat(uart): standard verbose log message
SuGlider Nov 4, 2025
ffe7769
feat(uart): add not inverted verbose log message
SuGlider Nov 4, 2025
6718c90
fix(uart): misspeling comment
SuGlider Nov 4, 2025
600e134
fix(uart): fixes bad code formating
SuGlider Nov 4, 2025
1acfa42
fix(uart): fixes misspeling
SuGlider Nov 4, 2025
949b366
fix(uart): fixes bad code formating
SuGlider Nov 4, 2025
f85e5f2
fix(uart): fixes bad code formating
SuGlider Nov 4, 2025
bfad07c
fix(uart): fixes bad code formating
SuGlider Nov 4, 2025
3992555
fix(uart): fixes extra spaces
SuGlider Nov 4, 2025
3f6abf9
fix(uart): extra spacing
SuGlider Nov 4, 2025
e6e09ce
feat(uart): Improve logging for UART signal inversion
SuGlider Nov 4, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
16 changes: 14 additions & 2 deletions cores/esp32/HardwareSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -572,8 +572,20 @@ HardwareSerial::operator bool() const {
return uartIsDriverInstalled(_uart);
}

void HardwareSerial::setRxInvert(bool invert) {
uartSetRxInvert(_uart, invert);
bool HardwareSerial::setRxInvert(bool invert) {
return uartSetRxInvert(_uart, invert);
}

bool HardwareSerial::setTxInvert(bool invert) {
return uartSetTxInvert(_uart, invert);
}

bool HardwareSerial::setCtsInvert(bool invert) {
return uartSetCtsInvert(_uart, invert);
}

bool HardwareSerial::setRtsInvert(bool invert) {
return uartSetRtsInvert(_uart, invert);
}

// negative Pin value will keep it unmodified
Expand Down
7 changes: 6 additions & 1 deletion cores/esp32/HardwareSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -356,7 +356,12 @@ class HardwareSerial : public Stream {

void setDebugOutput(bool);

void setRxInvert(bool);
// functions used to enable or disable UART pins signal inversion
// returns the requested operation success status
bool setRxInvert(bool);
bool setTxInvert(bool);
bool setCtsInvert(bool);
bool setRtsInvert(bool);

// Negative Pin Number will keep it unmodified, thus this function can set individual pins
// setPins() can be called after or before begin()
Expand Down
103 changes: 72 additions & 31 deletions cores/esp32/esp32-hal-uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ struct uart_struct_t {
bool _inverted; // UART inverted signal
uint8_t _rxfifo_full_thrhd; // UART RX FIFO full threshold
int8_t _uart_clock_source; // UART Clock Source that should be used if user defines an specific one with setClockSource()
uint32_t inv_mask; // UART inverse mask used to maintain related pin state
};

#if CONFIG_DISABLE_HAL_LOCKS
Expand All @@ -68,21 +69,21 @@ struct uart_struct_t {
#define UART_MUTEX_UNLOCK()

static uart_t _uart_bus_array[] = {
{0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
{0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
#if SOC_UART_NUM > 1
{1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
{1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
#endif
#if SOC_UART_NUM > 2
{2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
{2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
#endif
#if SOC_UART_NUM > 3
{3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
{3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
#endif
#if SOC_UART_NUM > 4
{4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
{4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
#endif
#if SOC_UART_NUM > 5
{5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
{5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
#endif
};

Expand All @@ -97,21 +98,21 @@ static uart_t _uart_bus_array[] = {
xSemaphoreGive(uart->lock)

static uart_t _uart_bus_array[] = {
{NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
{NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
#if SOC_UART_NUM > 1
{NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
{NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
#endif
#if SOC_UART_NUM > 2
{NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
{NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
#endif
#if SOC_UART_NUM > 3
{NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
{NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
#endif
#if SOC_UART_NUM > 4
{NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
{NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
#endif
#if SOC_UART_NUM > 5
{NULL, 5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
{NULL, 5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
#endif
};

Expand Down Expand Up @@ -873,10 +874,20 @@ uart_t *uartBegin(
if (retCode) {
if (inverted) {
// invert signal for both Rx and Tx
retCode &= ESP_OK == uart_set_line_inverse(uart_nr, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV);
uint32_t _inv_mask = uart->inv_mask;
_inv_mask |= UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV;
retCode &= ESP_OK == uart_set_line_inverse(uart_nr, _inv_mask);
if (retCode) {
uart->inv_mask = _inv_mask;
log_v("UART%d: RX and TX signals are set to be inverted.", uart_nr);
}
} else {
// disable invert signal for both Rx and Tx
retCode &= ESP_OK == uart_set_line_inverse(uart_nr, UART_SIGNAL_INV_DISABLE);
if (retCode) {
uart->inv_mask = UART_SIGNAL_INV_DISABLE;
log_v("UART%d: RX and TX signals are set not inverted.", uart_nr);
}
}
}
// if all fine, set internal parameters
Expand Down Expand Up @@ -978,28 +989,58 @@ void uartEnd(uint8_t uart_num) {
UART_MUTEX_UNLOCK();
}

void uartSetRxInvert(uart_t *uart, bool invert) {
// Helper generic function that takes a uart_signal_inv_t mask to be properly applied to the designated uart pin
// invMask can be UART_SIGNAL_RXD_INV, UART_SIGNAL_TXD_INV, UART_SIGNAL_RTS_INV, UART_SIGNAL_CTS_INV
// returns the operation success status
bool uartPinSignalInversion(uart_t *uart, uint32_t invMask, bool inverted) {
if (uart == NULL) {
return;
return false;
}
#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5
// POTENTIAL ISSUE :: original code only set/reset rxd_inv bit
// IDF or LL set/reset the whole inv_mask!
// if (invert)
// ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV));
// else
// ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE));
log_e("uartSetRxInvert is not supported in ESP32C6, ESP32H2 and ESP32P4");
#else
// this implementation is better over IDF API because it only affects RXD
// this is supported in ESP32, ESP32-S2 and ESP32-C3
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
if (invert) {
hw->conf0.rxd_inv = 1;
UART_MUTEX_LOCK();
uint32_t _inv_mask = uart->inv_mask;
if (inverted) {
_inv_mask |= invMask;
} else {
hw->conf0.rxd_inv = 0;
_inv_mask &= ~invMask;
}
#endif
bool retCode = ESP_OK == uart_set_line_inverse(uart->num, _inv_mask);
if (retCode) {
uart->inv_mask = _inv_mask;
}
UART_MUTEX_UNLOCK();
return retCode;
}

bool uartSetRxInvert(uart_t *uart, bool invert) {
if (uartPinSignalInversion(uart, UART_SIGNAL_RXD_INV, invert)) {
log_v("UART%d: RX signal inversion %s", uart->num, invert ? "enabled" : "disabled");
return true;
}
return false;
}

bool uartSetTxInvert(uart_t *uart, bool invert) {
if (uartPinSignalInversion(uart, UART_SIGNAL_TXD_INV, invert)) {
log_v("UART%d: TX signal inversion %s", uart->num, invert ? "enabled" : "disabled");
return true;
}
return false;
}

bool uartSetCtsInvert(uart_t *uart, bool invert) {
if (uartPinSignalInversion(uart, UART_SIGNAL_CTS_INV, invert)) {
log_v("UART%d: CTS signal inversion %s", uart->num, invert ? "enabled" : "disabled");
return true;
}
return false;
}

bool uartSetRtsInvert(uart_t *uart, bool invert) {
if (uartPinSignalInversion(uart, UART_SIGNAL_RTS_INV, invert)) {
log_v("UART%d: RTS signal inversion %s", uart->num, invert ? "enabled" : "disabled");
return true;
}
return false;
}

uint32_t uartAvailable(uart_t *uart) {
Expand Down
10 changes: 9 additions & 1 deletion cores/esp32/esp32-hal-uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -61,7 +61,15 @@ void uartFlushTxOnly(uart_t *uart, bool txOnly);
bool uartSetBaudRate(uart_t *uart, uint32_t baud_rate);
uint32_t uartGetBaudRate(uart_t *uart);

void uartSetRxInvert(uart_t *uart, bool invert);
// Helper generic function that takes a uart_signal_inv_t mask to be properly applied to the designated uart pin
// invMask can be UART_SIGNAL_RXD_INV, UART_SIGNAL_TXD_INV, UART_SIGNAL_RTS_INV, UART_SIGNAL_CTS_INV
// returns the operation success status
bool uartPinSignalInversion(uart_t *uart, uint32_t invMask, bool inverted);
// functions used to individually enable or disable UART pins inversion
bool uartSetRxInvert(uart_t *uart, bool invert);
bool uartSetTxInvert(uart_t *uart, bool invert);
bool uartSetCtsInvert(uart_t *uart, bool invert);
bool uartSetRtsInvert(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);
Expand Down
8 changes: 8 additions & 0 deletions tests/validation/uart/uart.ino
Original file line number Diff line number Diff line change
Expand Up @@ -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");
}

Expand Down Expand Up @@ -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");
}

Expand Down
Loading