From 0bae7140039b0fdc64e871b88951982487d73812 Mon Sep 17 00:00:00 2001 From: James Armstrong Date: Mon, 6 Mar 2023 10:28:50 -0500 Subject: [PATCH 1/6] Added setMode function to set the esp32 uart mode Used to set the esp32 uart mode for use with RS485 Half Duplex and the auto RTS pin mode. This will set/clear the RTS pin output to control the RE/DE pin on most RS485 chips. --- cores/esp32/HardwareSerial.cpp | 10 ++++++++++ cores/esp32/HardwareSerial.h | 3 ++- cores/esp32/esp32-hal-uart.c | 11 +++++++++++ cores/esp32/esp32-hal-uart.h | 13 +++++++++++++ 4 files changed, 36 insertions(+), 1 deletion(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index e60588f931e..11e231256af 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -572,6 +572,16 @@ void HardwareSerial::setHwFlowCtrlMode(uint8_t mode, uint8_t threshold) uartSetHwFlowCtrlMode(_uart, mode, threshold); } +// Sets the uart mode in the esp32 uart for use with RS485 modes (HwFlowCtrl must be disabled and RTS pin set) +int HardwareSerial::setMode(uart_mode_t mode) +{ + if (_uart == 0) + { + return -1; + } + return uartSetMode(_uart, mode); +} + size_t HardwareSerial::setRxBufferSize(size_t new_size) { if (_uart) { diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index 6291d241778..f191bd019fc 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -164,7 +164,8 @@ class HardwareSerial: public Stream void setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin = -1, int8_t rtsPin = -1); // Enables or disables Hardware Flow Control using RTS and/or CTS pins (must use setAllPins() before) void setHwFlowCtrlMode(uint8_t mode = HW_FLOWCTRL_CTS_RTS, uint8_t threshold = 64); // 64 is half FIFO Length - + // Used to set RS485 modes such as UART_MODE_RS485_HALF_DUPLEX for Auto RTS function on ESP32 + int setMode(uint8_t mode); size_t setRxBufferSize(size_t new_size); size_t setTxBufferSize(size_t new_size); diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 7706f132d5e..95a0d18148f 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -518,6 +518,17 @@ void uart_install_putc() } } +// Routines that take care of UART mode in the HardwareSerial Class code +// used to set UART_MODE_RS485_HALF_DUPLEX auto RTS for TXD for ESP32 chips +int uartSetMode(uart_t *uart, uint8_t mode) +{ + if (uart == NULL || uart->num >= SOC_UART_NUM) + { + return -1; + } + return uart_set_mode(uart->num, mode); +} + void uartSetDebug(uart_t* uart) { if(uart == NULL || uart->num >= SOC_UART_NUM) { diff --git a/cores/esp32/esp32-hal-uart.h b/cores/esp32/esp32-hal-uart.h index 2b3268af966..3406c056e35 100644 --- a/cores/esp32/esp32-hal-uart.h +++ b/cores/esp32/esp32-hal-uart.h @@ -58,6 +58,15 @@ extern "C" { #define HW_FLOWCTRL_CTS 0x2 // use only CTS PIN for HW Flow Control #define HW_FLOWCTRL_CTS_RTS 0x3 // use both CTS and RTS PIN for HW Flow Control +// These are Hardware Uart Modes possible usage +// equivalent to UDF enum uart_mode_t from +// https://github.com/espressif/esp-idf/blob/master/components/hal/include/hal/uart_types.h#L34-L40 +#define MODE_UART 0x00 // mode: regular UART mode +#define MODE_RS485_HALF_DUPLEX 0x01 // mode: half duplex RS485 UART mode control by RTS pin +#define MODE_IRDA 0x02 // mode: IRDA UART mode +#define MODE_RS485_COLLISION_DETECT 0x03 // mode: RS485 collision detection UART mode (used for test purposes) +#define MODE_RS485_APP_CTRL 0x04 + struct uart_struct_t; typedef struct uart_struct_t uart_t; @@ -99,6 +108,10 @@ void uartDetachPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int // Enables or disables HW Flow Control function -- needs also to set CTS and/or RTS pins void uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold); +// Used to set RS485 function -- needs to disable HW Flow Control and set RTS pin to use +// RTS pin becomes RS485 half duplex RE/DE +int uartSetMode(uart_t *uart, uint8_t mode); + void uartStartDetectBaudrate(uart_t *uart); unsigned long uartDetectBaudrate(uart_t *uart); From cb7dca52127f3a4387d8aaa2fdd7f7d580259f08 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 30 Mar 2023 22:45:13 -0300 Subject: [PATCH 2/6] Add Success (bool) return in some functions --- cores/esp32/esp32-hal-uart.h | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/cores/esp32/esp32-hal-uart.h b/cores/esp32/esp32-hal-uart.h index 3406c056e35..2870c31ae61 100644 --- a/cores/esp32/esp32-hal-uart.h +++ b/cores/esp32/esp32-hal-uart.h @@ -92,8 +92,8 @@ void uartSetBaudRate(uart_t* uart, uint32_t baud_rate); uint32_t uartGetBaudRate(uart_t* uart); void uartSetRxInvert(uart_t* uart, bool invert); -void uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout); -void uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull); +bool uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout); +bool uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull); void uartSetFastReading(uart_t* uart); void uartSetDebug(uart_t* uart); @@ -106,11 +106,11 @@ bool uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t void uartDetachPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin); // Enables or disables HW Flow Control function -- needs also to set CTS and/or RTS pins -void uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold); +bool uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold); // Used to set RS485 function -- needs to disable HW Flow Control and set RTS pin to use // RTS pin becomes RS485 half duplex RE/DE -int uartSetMode(uart_t *uart, uint8_t mode); +bool uartSetMode(uart_t *uart, uint8_t mode); void uartStartDetectBaudrate(uart_t *uart); unsigned long uartDetectBaudrate(uart_t *uart); From 6b21d9f1f9455f559df9b54917f9ae8f77357f02 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 30 Mar 2023 22:55:37 -0300 Subject: [PATCH 3/6] Add Success (bool) return code to some functions --- cores/esp32/esp32-hal-uart.c | 31 ++++++++++++++++++++----------- 1 file changed, 20 insertions(+), 11 deletions(-) diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 95a0d18148f..1c9d8511658 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -160,13 +160,16 @@ bool uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t } // -void uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold) { +bool uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold) { if(uart == NULL) { - return; + return false; } // IDF will issue corresponding error message when mode or threshold are wrong and prevent crashing // IDF will check (mode > HW_FLOWCTRL_CTS_RTS || threshold >= SOC_UART_FIFO_LEN) - uart_set_hw_flow_ctrl(uart->num, (uart_hw_flowcontrol_t) mode, threshold); + UART_MUTEX_LOCK(); + bool retCode = (ESP_OK == uart_set_hw_flow_ctrl(uart->num, (uart_hw_flowcontrol_t) mode, threshold)); + UART_MUTEX_UNLOCK(); + return retCode; } @@ -247,23 +250,25 @@ void uartSetFastReading(uart_t* uart) void uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout) { if(uart == NULL) { - return; + return false; } UART_MUTEX_LOCK(); - uart_set_rx_timeout(uart->num, numSymbTimeout); + bool retCode = (ESP_OK == uart_set_rx_timeout(uart->num, numSymbTimeout)); UART_MUTEX_UNLOCK(); + return retCode; } -void uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull) +bool uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull) { if(uart == NULL) { - return; + return false; } UART_MUTEX_LOCK(); - uart_set_rx_full_threshold(uart->num, numBytesFIFOFull); + bool retCode = (ESP_OK == uart_set_rx_full_threshold(uart->num, numBytesFIFOFull)); UART_MUTEX_UNLOCK(); + return retCode; } void uartEnd(uart_t* uart) @@ -520,13 +525,17 @@ void uart_install_putc() // Routines that take care of UART mode in the HardwareSerial Class code // used to set UART_MODE_RS485_HALF_DUPLEX auto RTS for TXD for ESP32 chips -int uartSetMode(uart_t *uart, uint8_t mode) +bool uartSetMode(uart_t *uart, uint8_t mode) { if (uart == NULL || uart->num >= SOC_UART_NUM) { - return -1; + return false; } - return uart_set_mode(uart->num, mode); + + UART_MUTEX_LOCK(); + bool retCode = (ESP_OK == uart_set_mode(uart->num, mode)); + UART_MUTEX_UNLOCK(); + return retCode; } void uartSetDebug(uart_t* uart) From c18ffed0c213f68c345c406fe2a744a71b8a4735 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 30 Mar 2023 23:02:28 -0300 Subject: [PATCH 4/6] Add Success (bool) return to some functions --- cores/esp32/HardwareSerial.h | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index f191bd019fc..d6516f06f3e 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -80,13 +80,13 @@ class HardwareSerial: public Stream // Examples: Maximum for 11 bits symbol is 92 (SERIAL_8N2, SERIAL_8E1, SERIAL_8O1, etc), Maximum for 10 bits symbol is 101 (SERIAL_8N1). // For example symbols_timeout=1 defines a timeout equal to transmission time of one symbol (~11 bit) on current baudrate. // For a baudrate of 9600, SERIAL_8N1 (10 bit symbol) and symbols_timeout = 3, the timeout would be 3 / (9600 / 10) = 3.125 ms - void setRxTimeout(uint8_t symbols_timeout); + bool setRxTimeout(uint8_t symbols_timeout); // setRxFIFOFull(uint8_t fifoBytes) will set the number of bytes that will trigger UART_INTR_RXFIFO_FULL interrupt and fill up RxRingBuffer // This affects some functions such as Serial::available() and Serial.read() because, in a UART flow of receiving data, Serial internal // RxRingBuffer will be filled only after these number of bytes arrive or a RX Timeout happens. // This parameter can be set to 1 in order to receive byte by byte, but it will also consume more CPU time as the ISR will be activates often. - void setRxFIFOFull(uint8_t fifoBytes); + bool setRxFIFOFull(uint8_t fifoBytes); // onReceive will setup a callback that will be called whenever an UART interruption occurs (UART_INTR_RXFIFO_FULL or UART_INTR_RXFIFO_TOUT) // UART_INTR_RXFIFO_FULL interrupt triggers at UART_FULL_THRESH_DEFAULT bytes received (defined as 120 bytes by default in IDF) @@ -161,11 +161,11 @@ class HardwareSerial: public Stream // Negative Pin Number will keep it unmodified, thus this function can set individual pins // SetPins shall be called after Serial begin() - void setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin = -1, int8_t rtsPin = -1); + bool setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin = -1, int8_t rtsPin = -1); // Enables or disables Hardware Flow Control using RTS and/or CTS pins (must use setAllPins() before) - void setHwFlowCtrlMode(uint8_t mode = HW_FLOWCTRL_CTS_RTS, uint8_t threshold = 64); // 64 is half FIFO Length + bool setHwFlowCtrlMode(uint8_t mode = HW_FLOWCTRL_CTS_RTS, uint8_t threshold = 64); // 64 is half FIFO Length // Used to set RS485 modes such as UART_MODE_RS485_HALF_DUPLEX for Auto RTS function on ESP32 - int setMode(uint8_t mode); + bool setMode(uint8_t mode); size_t setRxBufferSize(size_t new_size); size_t setTxBufferSize(size_t new_size); From 90d7d8b65c52da64b5e05e1a77f7c51f7b1deec4 Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 30 Mar 2023 23:06:56 -0300 Subject: [PATCH 5/6] Add Success (bool) return to some functions --- cores/esp32/HardwareSerial.cpp | 30 +++++++++++++++--------------- 1 file changed, 15 insertions(+), 15 deletions(-) diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 11e231256af..7d06f65dc93 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -233,7 +233,7 @@ void HardwareSerial::onReceive(OnReceiveCb function, bool onlyOnTimeout) // A low value of FIFO Full bytes will consume more CPU time within the ISR // A high value of FIFO Full bytes will make the application wait longer to have byte available for the Stkech in a streaming scenario // Both RX FIFO Full and RX Timeout may affect when onReceive() will be called -void HardwareSerial::setRxFIFOFull(uint8_t fifoBytes) +bool HardwareSerial::setRxFIFOFull(uint8_t fifoBytes) { HSERIAL_MUTEX_LOCK(); // in case that onReceive() shall work only with RX Timeout, FIFO shall be high @@ -242,14 +242,15 @@ void HardwareSerial::setRxFIFOFull(uint8_t fifoBytes) fifoBytes = 120; log_w("OnReceive is set to Timeout only, thus FIFO Full is now 120 bytes."); } - uartSetRxFIFOFull(_uart, fifoBytes); // Set new timeout + bool retCode = uartSetRxFIFOFull(_uart, fifoBytes); // Set new timeout if (fifoBytes > 0 && fifoBytes < SOC_UART_FIFO_LEN - 1) _rxFIFOFull = fifoBytes; HSERIAL_MUTEX_UNLOCK(); + return retCode; } // timout is calculates in time to receive UART symbols at the UART baudrate. // the estimation is about 11 bits per symbol (SERIAL_8N1) -void HardwareSerial::setRxTimeout(uint8_t symbols_timeout) +bool HardwareSerial::setRxTimeout(uint8_t symbols_timeout) { HSERIAL_MUTEX_LOCK(); @@ -258,9 +259,10 @@ void HardwareSerial::setRxTimeout(uint8_t symbols_timeout) _rxTimeout = symbols_timeout; if (!symbols_timeout) _onReceiveTimeout = false; // only when RX timeout is disabled, we also must disable this flag - uartSetRxTimeout(_uart, _rxTimeout); // Set new timeout + bool retCode = uartSetRxTimeout(_uart, _rxTimeout); // Set new timeout HSERIAL_MUTEX_UNLOCK(); + return retCode; } void HardwareSerial::eventQueueReset() @@ -548,15 +550,16 @@ void HardwareSerial::setRxInvert(bool invert) } // negative Pin value will keep it unmodified -void HardwareSerial::setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) +bool HardwareSerial::setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) { if(_uart == NULL) { log_e("setPins() shall be called after begin() - nothing done\n"); - return; + return false; } - // uartSetPins() checks if pins are valid for each function and for the SoC - if (uartSetPins(_uart, rxPin, txPin, ctsPin, rtsPin)) { + // uartSetPins() checks if pins are valid for each function and for the SoC + bool retCode = uartSetPins(_uart, rxPin, txPin, ctsPin, rtsPin); + if (retCode) { _txPin = _txPin >= 0 ? txPin : _txPin; _rxPin = _rxPin >= 0 ? rxPin : _rxPin; _rtsPin = _rtsPin >= 0 ? rtsPin : _rtsPin; @@ -564,21 +567,18 @@ void HardwareSerial::setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t r } else { log_e("Error when setting Serial port Pins. Invalid Pin.\n"); } + return retCode; } // Enables or disables Hardware Flow Control using RTS and/or CTS pins (must use setAllPins() before) -void HardwareSerial::setHwFlowCtrlMode(uint8_t mode, uint8_t threshold) +bool HardwareSerial::setHwFlowCtrlMode(uint8_t mode, uint8_t threshold) { - uartSetHwFlowCtrlMode(_uart, mode, threshold); + return uartSetHwFlowCtrlMode(_uart, mode, threshold); } // Sets the uart mode in the esp32 uart for use with RS485 modes (HwFlowCtrl must be disabled and RTS pin set) -int HardwareSerial::setMode(uart_mode_t mode) +bool HardwareSerial::setMode(uint8_t mode) { - if (_uart == 0) - { - return -1; - } return uartSetMode(_uart, mode); } From 49469c95c0c4e676b6846fb7b51a103165a2054f Mon Sep 17 00:00:00 2001 From: Rodrigo Garcia Date: Thu, 30 Mar 2023 23:12:28 -0300 Subject: [PATCH 6/6] Fix uartSetRxTimeout return type --- 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 1c9d8511658..ca212577891 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -247,7 +247,7 @@ void uartSetFastReading(uart_t* uart) } -void uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout) +bool uartSetRxTimeout(uart_t* uart, uint8_t numSymbTimeout) { if(uart == NULL) { return false;