Skip to content
56 changes: 37 additions & 19 deletions cores/esp32/HardwareSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include "pins_arduino.h"
#include "HardwareSerial.h"
#include "soc/soc_caps.h"
#include "driver/uart.h"

#ifndef SOC_RX0
#if CONFIG_IDF_TARGET_ESP32
Expand Down Expand Up @@ -114,7 +115,6 @@ void serialEventRun(void)
}
#endif


HardwareSerial::HardwareSerial(int uart_nr) : _uart_nr(uart_nr), _uart(NULL), _rxBufferSize(256) {}

void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, int8_t txPin, bool invert, unsigned long timeout_ms, uint8_t rxfifo_full_thrhd)
Expand All @@ -123,28 +123,39 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
log_e("Serial number is invalid, please use numers from 0 to %u", SOC_UART_NUM - 1);
return;
}

// First Time or after end() --> set default Pins
if (!uartIsDriverInstalled(_uart)) {
switch (_uart_nr) {
case UART_NUM_0:
rxPin = rxPin < 0 ? SOC_RX0 : rxPin;
txPin = txPin < 0 ? SOC_TX0 : txPin;
break;
#if SOC_UART_NUM > 1 // may save some flash bytes...
case UART_NUM_1:
rxPin = rxPin < 0 ? RX1 : rxPin;
txPin = txPin < 0 ? TX1 : txPin;
break;
#endif
#if SOC_UART_NUM > 2 // may save some flash bytes...
case UART_NUM_2:
rxPin = rxPin < 0 ? RX2 : rxPin;
txPin = txPin < 0 ? TX2 : txPin;
break;
#endif
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

always add default: for switch statements. ESP-IDF will complain

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

done.

default:
log_e("Bad UART Number");
return;
}
}

if(_uart) {
// in this case it is a begin() over a previous begin() - maybe to change baud rate
// thus do not disable debug output
end(false);
}
if(_uart_nr == 0 && rxPin < 0 && txPin < 0) {
rxPin = SOC_RX0;
txPin = SOC_TX0;
}
#if SOC_UART_NUM > 1
if(_uart_nr == 1 && rxPin < 0 && txPin < 0) {
rxPin = RX1;
txPin = TX1;
}
#endif
#if SOC_UART_NUM > 2
if(_uart_nr == 2 && rxPin < 0 && txPin < 0) {
rxPin = RX2;
txPin = TX2;
}
#endif

// IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified.
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, invert, rxfifo_full_thrhd);
if (!baud) {
// using baud rate as zero, forces it to try to detect the current baud rate in place
Expand Down Expand Up @@ -280,9 +291,16 @@ void HardwareSerial::setRxInvert(bool invert)
uartSetRxInvert(_uart, invert);
}

void HardwareSerial::setPins(uint8_t rxPin, uint8_t txPin)
// negative Pin value will keep it unmodified
void HardwareSerial::setPins(int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin)
{
uartSetPins(_uart, rxPin, txPin, ctsPin, rtsPin);
}

// 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)
{
uartSetPins(_uart, rxPin, txPin);
uartSetHwFlowCtrlMode(_uart, mode, threshold);
}

size_t HardwareSerial::setRxBufferSize(size_t new_size) {
Expand Down
8 changes: 7 additions & 1 deletion cores/esp32/HardwareSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -107,7 +107,13 @@ class HardwareSerial: public Stream
void setDebugOutput(bool);

void setRxInvert(bool);
void setPins(uint8_t rxPin, uint8_t txPin);

// 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);
// 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

size_t setRxBufferSize(size_t new_size);

protected:
Expand Down
26 changes: 17 additions & 9 deletions cores/esp32/esp32-hal-uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -155,15 +155,27 @@ bool uartIsDriverInstalled(uart_t* uart)
return false;
}

void uartSetPins(uart_t* uart, uint8_t rxPin, uint8_t txPin)
// Valid pin UART_PIN_NO_CHANGE is defined to (-1)
// Negative Pin Number will keep it unmodified, thus this function can set individual pins
void uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin)
{
if(uart == NULL || rxPin >= SOC_GPIO_PIN_COUNT || txPin >= SOC_GPIO_PIN_COUNT) {
if(uart == NULL) {
return;
}
UART_MUTEX_LOCK();
ESP_ERROR_CHECK(uart_set_pin(uart->num, txPin, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE));
UART_MUTEX_UNLOCK();

// IDF uart_set_pin() will issue necessary Error Message and take care of all GPIO Number validation.
uart_set_pin(uart->num, txPin, rxPin, ctsPin, rtsPin);
UART_MUTEX_UNLOCK();
}

//
void uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold) {
if(uart == NULL) {
return;
}
// 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);
}


Expand All @@ -173,10 +185,6 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
return NULL;
}

if(rxPin == -1 && txPin == -1) {
return NULL;
}

uart_t* uart = &_uart_bus_array[uart_nr];

if (uart_is_driver_installed(uart_nr)) {
Expand Down
15 changes: 14 additions & 1 deletion cores/esp32/esp32-hal-uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,14 @@ extern "C" {
#define SERIAL_7O2 0x800003b
#define SERIAL_8O2 0x800003f

// These are Hardware Flow Contol possible usage
// equivalent to UDF enum uart_hw_flowcontrol_t from
// https://github.com/espressif/esp-idf/blob/master/components/hal/include/hal/uart_types.h#L75-L81
#define HW_FLOWCTRL_DISABLE 0x0 // disable HW Flow Control
#define HW_FLOWCTRL_RTS 0x1 // use only RTS PIN for HW Flow Control
#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

struct uart_struct_t;
typedef struct uart_struct_t uart_t;

Expand Down Expand Up @@ -76,7 +84,12 @@ void uartSetDebug(uart_t* uart);
int uartGetDebug();

bool uartIsDriverInstalled(uart_t* uart);
void uartSetPins(uart_t* uart, uint8_t rxPin, uint8_t txPin);

// Negative Pin Number will keep it unmodified, thus this function can set individual pins
void uartSetPins(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);

void uartStartDetectBaudrate(uart_t *uart);
unsigned long uartDetectBaudrate(uart_t *uart);
Expand Down