Skip to content

Commit a8c74c4

Browse files
asundSuGliderCopilotpre-commit-ci-lite[bot]
authored
feat(uart): Add function to invert hardware UART Tx line (#11428)
* feat(uart): Add function to invert hardware UART Tx line Simply clone existing Rx functionality for Tx. Allow granular control over both lines. Avoid overloading HardwareSerial::begin() to change the bool invert parameter to a bitmask type. Add an untested implementation for ESP32C6, ESP32H2, ESP32P4 that references the different register naming on those chips. * feat(uart): Refactor UART signal inversion handling Refactor UART inversion functions to use a helper for signal inversion. Update UART bus array structure to include inversion mask. * feat(uart): Add UART signal inversion functions Added functions for UART signal inversion and updated existing function signatures. * feat(uart): Refactor UART signal inversion handling * feat(uart): Change setRxInvert and setTxInvert to return bool * feat(uart) : Refactor serial inversion methods to return bool Changed setRxInvert, setTxInvert to return bool. Added setCtsInvert and setRtsInvert methods. * feat(uart): adds commentatries Added functions for UART pins signal inversion. * feat(uart): add commentaties * feat(uart): Refactor uartPinSignalInversion for mutex locking * Refactor UART inversion functions to use new method * fix(uart): missing uart struct usage * fix(uart): missing function return value * feat(uart): add commentaties * fix(uart): inverting rx instead of tx * feat(uart): logging for UART signal inversion Added logging for signal inversion in UART functions. * feat(uart): standard verbose log message * feat(uart): add not inverted verbose log message * fix(uart): misspeling comment Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix(uart): fixes bad code formating Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix(uart): fixes misspeling Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix(uart): fixes bad code formating Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix(uart): fixes bad code formating Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix(uart): fixes bad code formating Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix(uart): fixes extra spaces Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * fix(uart): extra spacing Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> * feat(uart): Improve logging for UART signal inversion * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: Sugar Glider <rodrigo.garcia@espressif.com> Co-authored-by: Copilot <175728472+Copilot@users.noreply.github.com> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parent e3ce2ec commit a8c74c4

File tree

5 files changed

+109
-35
lines changed

5 files changed

+109
-35
lines changed

cores/esp32/HardwareSerial.cpp

Lines changed: 14 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -572,8 +572,20 @@ HardwareSerial::operator bool() const {
572572
return uartIsDriverInstalled(_uart);
573573
}
574574

575-
void HardwareSerial::setRxInvert(bool invert) {
576-
uartSetRxInvert(_uart, invert);
575+
bool HardwareSerial::setRxInvert(bool invert) {
576+
return uartSetRxInvert(_uart, invert);
577+
}
578+
579+
bool HardwareSerial::setTxInvert(bool invert) {
580+
return uartSetTxInvert(_uart, invert);
581+
}
582+
583+
bool HardwareSerial::setCtsInvert(bool invert) {
584+
return uartSetCtsInvert(_uart, invert);
585+
}
586+
587+
bool HardwareSerial::setRtsInvert(bool invert) {
588+
return uartSetRtsInvert(_uart, invert);
577589
}
578590

579591
// negative Pin value will keep it unmodified

cores/esp32/HardwareSerial.h

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -356,7 +356,12 @@ class HardwareSerial : public Stream {
356356

357357
void setDebugOutput(bool);
358358

359-
void setRxInvert(bool);
359+
// functions used to enable or disable UART pins signal inversion
360+
// returns the requested operation success status
361+
bool setRxInvert(bool);
362+
bool setTxInvert(bool);
363+
bool setCtsInvert(bool);
364+
bool setRtsInvert(bool);
360365

361366
// Negative Pin Number will keep it unmodified, thus this function can set individual pins
362367
// setPins() can be called after or before begin()

cores/esp32/esp32-hal-uart.c

Lines changed: 72 additions & 31 deletions
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ struct uart_struct_t {
6060
bool _inverted; // UART inverted signal
6161
uint8_t _rxfifo_full_thrhd; // UART RX FIFO full threshold
6262
int8_t _uart_clock_source; // UART Clock Source that should be used if user defines an specific one with setClockSource()
63+
uint32_t inv_mask; // UART inverse mask used to maintain related pin state
6364
};
6465

6566
#if CONFIG_DISABLE_HAL_LOCKS
@@ -68,21 +69,21 @@ struct uart_struct_t {
6869
#define UART_MUTEX_UNLOCK()
6970

7071
static uart_t _uart_bus_array[] = {
71-
{0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
72+
{0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
7273
#if SOC_UART_NUM > 1
73-
{1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
74+
{1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
7475
#endif
7576
#if SOC_UART_NUM > 2
76-
{2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
77+
{2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
7778
#endif
7879
#if SOC_UART_NUM > 3
79-
{3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
80+
{3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
8081
#endif
8182
#if SOC_UART_NUM > 4
82-
{4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
83+
{4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
8384
#endif
8485
#if SOC_UART_NUM > 5
85-
{5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
86+
{5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
8687
#endif
8788
};
8889

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

99100
static uart_t _uart_bus_array[] = {
100-
{NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
101+
{NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
101102
#if SOC_UART_NUM > 1
102-
{NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
103+
{NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
103104
#endif
104105
#if SOC_UART_NUM > 2
105-
{NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
106+
{NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
106107
#endif
107108
#if SOC_UART_NUM > 3
108-
{NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
109+
{NULL, 3, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
109110
#endif
110111
#if SOC_UART_NUM > 4
111-
{NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
112+
{NULL, 4, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
112113
#endif
113114
#if SOC_UART_NUM > 5
114-
{NULL, 5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1},
115+
{NULL, 5, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0, -1, 0},
115116
#endif
116117
};
117118

@@ -873,10 +874,20 @@ uart_t *uartBegin(
873874
if (retCode) {
874875
if (inverted) {
875876
// invert signal for both Rx and Tx
876-
retCode &= ESP_OK == uart_set_line_inverse(uart_nr, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV);
877+
uint32_t _inv_mask = uart->inv_mask;
878+
_inv_mask |= UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV;
879+
retCode &= ESP_OK == uart_set_line_inverse(uart_nr, _inv_mask);
880+
if (retCode) {
881+
uart->inv_mask = _inv_mask;
882+
log_v("UART%d: RX and TX signals are set to be inverted.", uart_nr);
883+
}
877884
} else {
878885
// disable invert signal for both Rx and Tx
879886
retCode &= ESP_OK == uart_set_line_inverse(uart_nr, UART_SIGNAL_INV_DISABLE);
887+
if (retCode) {
888+
uart->inv_mask = UART_SIGNAL_INV_DISABLE;
889+
log_v("UART%d: RX and TX signals are set not inverted.", uart_nr);
890+
}
880891
}
881892
}
882893
// if all fine, set internal parameters
@@ -978,28 +989,58 @@ void uartEnd(uint8_t uart_num) {
978989
UART_MUTEX_UNLOCK();
979990
}
980991

981-
void uartSetRxInvert(uart_t *uart, bool invert) {
992+
// Helper generic function that takes a uart_signal_inv_t mask to be properly applied to the designated uart pin
993+
// invMask can be UART_SIGNAL_RXD_INV, UART_SIGNAL_TXD_INV, UART_SIGNAL_RTS_INV, UART_SIGNAL_CTS_INV
994+
// returns the operation success status
995+
bool uartPinSignalInversion(uart_t *uart, uint32_t invMask, bool inverted) {
982996
if (uart == NULL) {
983-
return;
997+
return false;
984998
}
985-
#if CONFIG_IDF_TARGET_ESP32C6 || CONFIG_IDF_TARGET_ESP32H2 || CONFIG_IDF_TARGET_ESP32P4 || CONFIG_IDF_TARGET_ESP32C5
986-
// POTENTIAL ISSUE :: original code only set/reset rxd_inv bit
987-
// IDF or LL set/reset the whole inv_mask!
988-
// if (invert)
989-
// ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_RXD_INV));
990-
// else
991-
// ESP_ERROR_CHECK(uart_set_line_inverse(uart->num, UART_SIGNAL_INV_DISABLE));
992-
log_e("uartSetRxInvert is not supported in ESP32C6, ESP32H2 and ESP32P4");
993-
#else
994-
// this implementation is better over IDF API because it only affects RXD
995-
// this is supported in ESP32, ESP32-S2 and ESP32-C3
996-
uart_dev_t *hw = UART_LL_GET_HW(uart->num);
997-
if (invert) {
998-
hw->conf0.rxd_inv = 1;
999+
UART_MUTEX_LOCK();
1000+
uint32_t _inv_mask = uart->inv_mask;
1001+
if (inverted) {
1002+
_inv_mask |= invMask;
9991003
} else {
1000-
hw->conf0.rxd_inv = 0;
1004+
_inv_mask &= ~invMask;
10011005
}
1002-
#endif
1006+
bool retCode = ESP_OK == uart_set_line_inverse(uart->num, _inv_mask);
1007+
if (retCode) {
1008+
uart->inv_mask = _inv_mask;
1009+
}
1010+
UART_MUTEX_UNLOCK();
1011+
return retCode;
1012+
}
1013+
1014+
bool uartSetRxInvert(uart_t *uart, bool invert) {
1015+
if (uartPinSignalInversion(uart, UART_SIGNAL_RXD_INV, invert)) {
1016+
log_v("UART%d: RX signal inversion %s", uart->num, invert ? "enabled" : "disabled");
1017+
return true;
1018+
}
1019+
return false;
1020+
}
1021+
1022+
bool uartSetTxInvert(uart_t *uart, bool invert) {
1023+
if (uartPinSignalInversion(uart, UART_SIGNAL_TXD_INV, invert)) {
1024+
log_v("UART%d: TX signal inversion %s", uart->num, invert ? "enabled" : "disabled");
1025+
return true;
1026+
}
1027+
return false;
1028+
}
1029+
1030+
bool uartSetCtsInvert(uart_t *uart, bool invert) {
1031+
if (uartPinSignalInversion(uart, UART_SIGNAL_CTS_INV, invert)) {
1032+
log_v("UART%d: CTS signal inversion %s", uart->num, invert ? "enabled" : "disabled");
1033+
return true;
1034+
}
1035+
return false;
1036+
}
1037+
1038+
bool uartSetRtsInvert(uart_t *uart, bool invert) {
1039+
if (uartPinSignalInversion(uart, UART_SIGNAL_RTS_INV, invert)) {
1040+
log_v("UART%d: RTS signal inversion %s", uart->num, invert ? "enabled" : "disabled");
1041+
return true;
1042+
}
1043+
return false;
10031044
}
10041045

10051046
uint32_t uartAvailable(uart_t *uart) {

cores/esp32/esp32-hal-uart.h

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,7 +61,15 @@ void uartFlushTxOnly(uart_t *uart, bool txOnly);
6161
bool uartSetBaudRate(uart_t *uart, uint32_t baud_rate);
6262
uint32_t uartGetBaudRate(uart_t *uart);
6363

64-
void uartSetRxInvert(uart_t *uart, bool invert);
64+
// Helper generic function that takes a uart_signal_inv_t mask to be properly applied to the designated uart pin
65+
// invMask can be UART_SIGNAL_RXD_INV, UART_SIGNAL_TXD_INV, UART_SIGNAL_RTS_INV, UART_SIGNAL_CTS_INV
66+
// returns the operation success status
67+
bool uartPinSignalInversion(uart_t *uart, uint32_t invMask, bool inverted);
68+
// functions used to individually enable or disable UART pins inversion
69+
bool uartSetRxInvert(uart_t *uart, bool invert);
70+
bool uartSetTxInvert(uart_t *uart, bool invert);
71+
bool uartSetCtsInvert(uart_t *uart, bool invert);
72+
bool uartSetRtsInvert(uart_t *uart, bool invert);
6573
bool uartSetRxTimeout(uart_t *uart, uint8_t numSymbTimeout);
6674
bool uartSetRxFIFOFull(uart_t *uart, uint8_t numBytesFIFOFull);
6775
void uartSetFastReading(uart_t *uart);

tests/validation/uart/uart.ino

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -276,6 +276,10 @@ void enabled_uart_calls_test(void) {
276276
Serial1.setRxInvert(true);
277277
Serial1.setRxInvert(false);
278278

279+
log_d("Checking if Serial 1 TX can be inverted while running");
280+
Serial1.setTxInvert(true);
281+
Serial1.setTxInvert(false);
282+
279283
Serial.println("Enabled UART calls test successful");
280284
}
281285

@@ -351,6 +355,10 @@ void disabled_uart_calls_test(void) {
351355
Serial1.setRxInvert(true);
352356
Serial1.setRxInvert(false);
353357

358+
log_d("Checking if Serial 1 TX can be inverted when stopped");
359+
Serial1.setTxInvert(true);
360+
Serial1.setTxInvert(false);
361+
354362
Serial.println("Disabled UART calls test successful");
355363
}
356364

0 commit comments

Comments
 (0)