diff --git a/cores/esp32/HardwareSerial.cpp b/cores/esp32/HardwareSerial.cpp index 33014f13a66..258aa489d6a 100644 --- a/cores/esp32/HardwareSerial.cpp +++ b/cores/esp32/HardwareSerial.cpp @@ -148,7 +148,7 @@ void serialEventRun(void) #define HSERIAL_MUTEX_UNLOCK() #endif -HardwareSerial::HardwareSerial(int uart_nr) : +HardwareSerial::HardwareSerial(uint8_t uart_nr) : _uart_nr(uart_nr), _uart(NULL), _rxBufferSize(256), @@ -172,6 +172,12 @@ _eventTask(NULL) } } #endif + // sets UART0 (default console) RX/TX pins as already configured in boot + if (uart_nr == 0) { + setPins(SOC_RX0, SOC_TX0); + } + // set deinit function in the Peripheral Manager + uart_init_PeriMan(); } HardwareSerial::~HardwareSerial() @@ -341,8 +347,8 @@ void HardwareSerial::_uartEventTask(void *args) 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) { - if(0 > _uart_nr || _uart_nr >= SOC_UART_NUM) { - log_e("Serial number is invalid, please use numers from 0 to %u", SOC_UART_NUM - 1); + if(_uart_nr >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use a number from 0 to %u", SOC_UART_NUM - 1); return; } @@ -356,26 +362,32 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in HSERIAL_MUTEX_LOCK(); // First Time or after end() --> set default Pins if (!uartIsDriverInstalled(_uart)) { + // get previously used RX/TX pins, if any. + int8_t _rxPin = uart_get_RxPin(_uart_nr); + int8_t _txPin = uart_get_TxPin(_uart_nr); switch (_uart_nr) { case UART_NUM_0: if (rxPin < 0 && txPin < 0) { - rxPin = SOC_RX0; - txPin = SOC_TX0; + // do not change RX0/TX0 if it has already been set before + 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: if (rxPin < 0 && txPin < 0) { - rxPin = RX1; - txPin = TX1; + // do not change RX1/TX1 if it has already been set before + 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: if (rxPin < 0 && txPin < 0) { - rxPin = RX2; - txPin = TX2; + // do not change RX2/TX2 if it has already been set before + rxPin = _rxPin < 0 ? RX2 : _rxPin; + txPin = _txPin < 0 ? TX2 : _txPin; } break; #endif @@ -389,6 +401,7 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in } // IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified. + // it will detach previous UART attached pins _uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd); if (!baud) { // using baud rate as zero, forces it to try to detect the current baud rate in place @@ -451,13 +464,13 @@ void HardwareSerial::end(bool fullyTerminate) uartSetDebug(0); } _rxFIFOFull = 0; - uartEnd(_uart); // fully detach all pins and delete the UART driver + uartEnd(_uart_nr); // fully detach all pins and delete the UART driver } else { // do not invalidate callbacks, detach pins, invalidate DBG output uart_driver_delete(_uart_nr); } - uartEnd(_uart); + uartEnd(_uart_nr); _uart = 0; _destroyEventTask(); } @@ -539,8 +552,8 @@ size_t HardwareSerial::write(const uint8_t *buffer, size_t size) uartWriteBuf(_uart, buffer, size); return size; } -uint32_t HardwareSerial::baudRate() +uint32_t HardwareSerial::baudRate() { return uartGetBaudRate(_uart); } @@ -555,19 +568,11 @@ void HardwareSerial::setRxInvert(bool 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) { - if(_uart == NULL) { - log_e("setPins() shall be called after begin() - nothing done\n"); - return false; - } - - // uartSetPins() checks if pins are valid for each function and for the SoC - if (uartSetPins(_uart, rxPin, txPin, ctsPin, rtsPin)) { - return true; - } else { - return false; - } + // uartSetPins() checks if pins are valid and, if necessary, detaches the previous ones + return uartSetPins(_uart_nr, rxPin, txPin, ctsPin, rtsPin); } // Enables or disables Hardware Flow Control using RTS and/or CTS pins (must use setAllPins() before) diff --git a/cores/esp32/HardwareSerial.h b/cores/esp32/HardwareSerial.h index 358264375e6..3e8261d370d 100644 --- a/cores/esp32/HardwareSerial.h +++ b/cores/esp32/HardwareSerial.h @@ -71,7 +71,7 @@ typedef std::function OnReceiveErrorCb; class HardwareSerial: public Stream { public: - HardwareSerial(int uart_nr); + HardwareSerial(uint8_t uart_nr); ~HardwareSerial(); // setRxTimeout sets the timeout after which onReceive callback will be called (after receiving data, it waits for this time of UART rx inactivity to call the callback fnc) @@ -106,6 +106,11 @@ class HardwareSerial: public Stream // eventQueueReset clears all events in the queue (the events that trigger onReceive and onReceiveError) - maybe usefull in some use cases void eventQueueReset(); + // When pins are changed, it will detach the previous ones + // if pin is negative, it won't be set/changed and will be kept as is + // timeout_ms is used in baudrate detection (ESP32, ESP32S2 only) + // invert will invert RX/TX polarity + // rxfifo_full_thrhd if the UART Flow Control Threshold in the UART FIFO (max 127) void begin(unsigned long baud, uint32_t config=SERIAL_8N1, int8_t rxPin=-1, int8_t txPin=-1, bool invert=false, unsigned long timeout_ms = 20000UL, uint8_t rxfifo_full_thrhd = 112); void end(bool fullyTerminate = true); void updateBaudRate(unsigned long baud); @@ -160,7 +165,8 @@ class HardwareSerial: public Stream void setRxInvert(bool); // Negative Pin Number will keep it unmodified, thus this function can set individual pins - // SetPins shall be called after Serial begin() + // setPins() can be called after or before begin() + // When pins are changed, it will detach the previous ones 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) bool setHwFlowCtrlMode(uint8_t mode = HW_FLOWCTRL_CTS_RTS, uint8_t threshold = 64); // 64 is half FIFO Length @@ -170,7 +176,7 @@ class HardwareSerial: public Stream size_t setTxBufferSize(size_t new_size); protected: - int _uart_nr; + uint8_t _uart_nr; uart_t* _uart; size_t _rxBufferSize; size_t _txBufferSize; diff --git a/cores/esp32/chip-debug-report.cpp b/cores/esp32/chip-debug-report.cpp index fa9b9564b78..a8821b9695c 100644 --- a/cores/esp32/chip-debug-report.cpp +++ b/cores/esp32/chip-debug-report.cpp @@ -253,7 +253,10 @@ static void printPerimanInfo(void){ chip_report_printf(" %17u : ", i); switch(type){ case ESP32_BUS_TYPE_GPIO: chip_report_printf("GPIO\n"); break; - case ESP32_BUS_TYPE_UART: chip_report_printf("UART\n"); break; + case ESP32_BUS_TYPE_UART_RX: chip_report_printf("UART_RX\n"); break; + case ESP32_BUS_TYPE_UART_TX: chip_report_printf("UART_TX\n"); break; + case ESP32_BUS_TYPE_UART_CTS: chip_report_printf("UART_CTS\n"); break; + case ESP32_BUS_TYPE_UART_RTS: chip_report_printf("UART_RTS\n"); break; #if SOC_SDM_SUPPORTED case ESP32_BUS_TYPE_SIGMADELTA: chip_report_printf("SIGMADELTA\n"); break; #endif diff --git a/cores/esp32/esp32-hal-periman.h b/cores/esp32/esp32-hal-periman.h index 72827eeff93..94e80986698 100644 --- a/cores/esp32/esp32-hal-periman.h +++ b/cores/esp32/esp32-hal-periman.h @@ -17,7 +17,10 @@ extern "C" typedef enum { ESP32_BUS_TYPE_INIT, // IO has not been attached to a bus yet ESP32_BUS_TYPE_GPIO, // IO is used as GPIO - ESP32_BUS_TYPE_UART, // IO is used as UART pin + ESP32_BUS_TYPE_UART_RX, // IO is used as UART RX pin + ESP32_BUS_TYPE_UART_TX, // IO is used as UART TX pin + ESP32_BUS_TYPE_UART_CTS, // IO is used as UART CTS pin + ESP32_BUS_TYPE_UART_RTS, // IO is used as UART RTS pin #if SOC_SDM_SUPPORTED ESP32_BUS_TYPE_SIGMADELTA, // IO is used as SigmeDelta output #endif diff --git a/cores/esp32/esp32-hal-uart.c b/cores/esp32/esp32-hal-uart.c index 149c8c40dcd..7817d7463b0 100644 --- a/cores/esp32/esp32-hal-uart.c +++ b/cores/esp32/esp32-hal-uart.c @@ -65,8 +65,8 @@ static uart_t _uart_bus_array[] = { #else -#define UART_MUTEX_LOCK() do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS) -#define UART_MUTEX_UNLOCK() xSemaphoreGive(uart->lock) +#define UART_MUTEX_LOCK() if(uart->lock != NULL) do {} while (xSemaphoreTake(uart->lock, portMAX_DELAY) != pdPASS) +#define UART_MUTEX_UNLOCK() if(uart->lock != NULL) xSemaphoreGive(uart->lock) static uart_t _uart_bus_array[] = { {NULL, 0, false, 0, NULL, -1, -1, -1, -1}, @@ -80,35 +80,178 @@ static uart_t _uart_bus_array[] = { #endif -// IDF UART has no detach function. As consequence, after ending a UART, the previous pins continue -// to work as RX/TX. It can be verified by changing the UART pins and writing to the UART. Output can -// be seen in the previous pins and new pins as well. -// Valid pin UART_PIN_NO_CHANGE is defined to (-1) // Negative Pin Number will keep it unmodified, thus this function can detach individual pins -static void _uartDetachPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) +// This function will also unset the pins in the Peripheral Manager and set the pin to -1 after detaching +static bool _uartDetachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) { - if(uart == NULL) { - return; + if(uart_num >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + return false; } - if (txPin >= 0) { + // get UART information + uart_t* uart = &_uart_bus_array[uart_num]; + bool retCode = true; + //log_v("detaching UART%d pins: prev,pin RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num, + // uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); + + // detaches pins and sets Peripheral Manager and UART information + if (rxPin >= 0 && uart->_rxPin == rxPin && perimanGetPinBusType(rxPin) == ESP32_BUS_TYPE_UART_RX) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rxPin], PIN_FUNC_GPIO); + esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_LOW, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false); + uart->_rxPin = -1; // -1 means unassigned/detached + if (!perimanSetPinBus(rxPin, ESP32_BUS_TYPE_INIT, NULL)) { + retCode = false; + log_e("UART%d failed to detach RX pin %d", uart_num, rxPin); + } + } + if (txPin >= 0 && uart->_txPin == txPin && perimanGetPinBusType(txPin) == ESP32_BUS_TYPE_UART_TX) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[txPin], PIN_FUNC_GPIO); esp_rom_gpio_connect_out_signal(txPin, SIG_GPIO_OUT_IDX, false, false); + uart->_txPin = -1; // -1 means unassigned/detached + if (!perimanSetPinBus(txPin, ESP32_BUS_TYPE_INIT, NULL)) { + retCode = false; + log_e("UART%d failed to detach TX pin %d", uart_num, txPin); + } } - - if (rxPin >= 0) { - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rxPin], PIN_FUNC_GPIO); - esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_LOW, UART_PERIPH_SIGNAL(uart->num, SOC_UART_RX_PIN_IDX), false); + if (ctsPin >= 0 && uart->_ctsPin == ctsPin && perimanGetPinBusType(ctsPin) == ESP32_BUS_TYPE_UART_CTS) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[ctsPin], PIN_FUNC_GPIO); + esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_LOW, UART_PERIPH_SIGNAL(uart_num, SOC_UART_CTS_PIN_IDX), false); + uart->_ctsPin = -1; // -1 means unassigned/detached + if (!perimanSetPinBus(ctsPin, ESP32_BUS_TYPE_INIT, NULL)) { + retCode = false; + log_e("UART%d failed to detach CTS pin %d", uart_num, ctsPin); + } } - - if (rtsPin >= 0) { + if (rtsPin >= 0 && uart->_rtsPin == rtsPin && perimanGetPinBusType(rtsPin) == ESP32_BUS_TYPE_UART_RTS) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rtsPin], PIN_FUNC_GPIO); esp_rom_gpio_connect_out_signal(rtsPin, SIG_GPIO_OUT_IDX, false, false); + uart->_rtsPin = -1; // -1 means unassigned/detached + if (!perimanSetPinBus(rtsPin, ESP32_BUS_TYPE_INIT, NULL)) { + retCode = false; + log_e("UART%d failed to detach RTS pin %d", uart_num, rtsPin); + } } + return retCode; +} +// Peripheral Manager detach callback for each specific UART PIN +static bool _uartDetachBus_RX(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_uartDetachBus_RX bus NULL pointer."); + uart_t* bus = (uart_t*) busptr; + return _uartDetachPins(bus->num, bus->_rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); +} + +static bool _uartDetachBus_TX(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_uartDetachBus_TX bus NULL pointer."); + uart_t* bus = (uart_t*) busptr; + return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, bus->_txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); +} + + +static bool _uartDetachBus_CTS(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_uartDetachBus_CTS bus NULL pointer."); + uart_t* bus = (uart_t*) busptr; + return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, bus->_ctsPin, UART_PIN_NO_CHANGE); +} + +static bool _uartDetachBus_RTS(void *busptr) +{ + // sanity check - it should never happen + assert(busptr && "_uartDetachBus_RTS bus NULL pointer."); + uart_t* bus = (uart_t*) busptr; + return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, bus->_rtsPin); +} + +// Attach function for UART +// connects the IO Pad, set Paripheral Manager and internal UART structure data +static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) +{ + if(uart_num >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); + return false; + } + // get UART information + uart_t* uart = &_uart_bus_array[uart_num]; + //log_v("attaching UART%d pins: prev,new RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num, + // uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); + + + bool retCode = true; + if (rxPin >= 0) { + // connect RX Pad + bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + if (ret) { + ret &= perimanSetPinBus(rxPin, ESP32_BUS_TYPE_UART_RX, (void *)uart); + if (ret) uart->_rxPin = rxPin; + } + if (!ret) { + log_e("UART%d failed to attach RX pin %d", uart_num, rxPin); + } + retCode &= ret; + } + if (txPin >= 0) { + // connect TX Pad + bool ret = ESP_OK == uart_set_pin(uart->num, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + if (ret) { + ret &= perimanSetPinBus(txPin, ESP32_BUS_TYPE_UART_TX, (void *)uart); + if (ret) uart->_txPin = txPin; + } + if (!ret) { + log_e("UART%d failed to attach TX pin %d", uart_num, txPin); + } + retCode &= ret; + } if (ctsPin >= 0) { - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[ctsPin], PIN_FUNC_GPIO); - esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_LOW, UART_PERIPH_SIGNAL(uart->num, SOC_UART_CTS_PIN_IDX), false); + // connect CTS Pad + bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, ctsPin); + if (ret) { + ret &= perimanSetPinBus(ctsPin, ESP32_BUS_TYPE_UART_CTS, (void *)uart); + if (ret) uart->_ctsPin = ctsPin; + } + if (!ret) { + log_e("UART%d failed to attach CTS pin %d", uart_num, ctsPin); + } + retCode &= ret; } + if (rtsPin >= 0) { + // connect RTS Pad + bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin, UART_PIN_NO_CHANGE); + if (ret) { + ret &= perimanSetPinBus(rtsPin, ESP32_BUS_TYPE_UART_RTS, (void *)uart); + if (ret) uart->_rtsPin = rtsPin; + } + if (!ret) { + log_e("UART%d failed to attach RTS pin %d", uart_num, rtsPin); + } + retCode &= ret; + } + return retCode; +} + +// just helper functions +int8_t uart_get_RxPin(uint8_t uart_num) +{ + return _uart_bus_array[uart_num]._rxPin; +} + +int8_t uart_get_TxPin(uint8_t uart_num) +{ + return _uart_bus_array[uart_num]._txPin; +} + +void uart_init_PeriMan(void) +{ + // set Peripheral Manager deInit Callback for each UART pin + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_RX, _uartDetachBus_RX); + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_TX, _uartDetachBus_TX); + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_CTS, _uartDetachBus_CTS); + perimanSetBusDeinit(ESP32_BUS_TYPE_UART_RTS, _uartDetachBus_RTS); } // Routines that take care of UART events will be in the HardwareSerial Class code @@ -135,99 +278,59 @@ bool uartIsDriverInstalled(uart_t* uart) return false; } -// Peripheral Manager detach callback -static bool _uartDetachBus(void *busptr) -{ - // sanity check - it should never happen - assert(busptr && "_uartDetachBus bus NULL pointer."); - - bool retCode = true; - uart_t* bus = (uart_t*) busptr; - - if (bus->_rxPin > 0 && perimanGetPinBusType(bus->_rxPin) == ESP32_BUS_TYPE_UART) { - int8_t oldPinNum = bus->_rxPin; - _uartDetachPins(bus, bus->_rxPin, -1, -1, -1); - bus->_rxPin = -1; - retCode &= perimanSetPinBus(oldPinNum, ESP32_BUS_TYPE_INIT, NULL); - } - if (retCode && bus->_txPin > 0 && perimanGetPinBusType(bus->_txPin) == ESP32_BUS_TYPE_UART) { - int8_t oldPinNum = bus->_txPin; - _uartDetachPins(bus, -1, bus->_txPin, -1, -1); - bus->_txPin = -1; - retCode &= perimanSetPinBus(oldPinNum, ESP32_BUS_TYPE_INIT, NULL); - } - if (retCode && bus->_ctsPin > 0 && perimanGetPinBusType(bus->_ctsPin) == ESP32_BUS_TYPE_UART) { - int8_t oldPinNum = bus->_ctsPin; - _uartDetachPins(bus, -1, -1, bus->_ctsPin, -1); - bus->_ctsPin = -1; - retCode &= perimanSetPinBus(oldPinNum, ESP32_BUS_TYPE_INIT, NULL); - } - if (retCode && bus->_rtsPin > 0 && perimanGetPinBusType(bus->_rtsPin) == ESP32_BUS_TYPE_UART) { - int8_t oldPinNum = bus->_rtsPin; - _uartDetachPins(bus, -1, -1, -1, bus->_rtsPin); - bus->_rtsPin = -1; - retCode &= perimanSetPinBus(oldPinNum, ESP32_BUS_TYPE_INIT, NULL); - } - if(retCode && uart_is_driver_installed(bus->num)) { - retCode &= ESP_OK == uart_driver_delete(bus->num); - } - - return retCode; -} - -// Valid pin UART_PIN_NO_CHANGE is defined to (-1) // Negative Pin Number will keep it unmodified, thus this function can set individual pins -bool uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) +// When pins are changed, it will detach the previous one +bool uartSetPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) { - if(uart == NULL) { + if(uart_num >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); return false; } + // get UART information + uart_t* uart = &_uart_bus_array[uart_num]; bool retCode = true; UART_MUTEX_LOCK(); - if (rxPin > 0) { - // detachs previous UART pin - if (uart->_rxPin > 0 && rxPin != uart->_rxPin) _uartDetachPins(uart, uart->_rxPin, -1, -1, -1); - //assign the new one - retCode &= perimanSetPinBus(rxPin, ESP32_BUS_TYPE_UART, (void *)uart); - if (retCode) { - uart->_rxPin = rxPin; - } + + //log_v("setting UART%d pins: prev->new RX(%d->%d) TX(%d->%d) CTS(%d->%d) RTS(%d->%d)", uart_num, + // uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10); + + // First step: detachs all previous UART pins + bool rxPinChanged = rxPin >= 0 && rxPin != uart->_rxPin; + if (rxPinChanged) { + retCode &= _uartDetachPins(uart_num, uart->_rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } - if (retCode && txPin > 0) { - // detachs previous UART pin - if (uart->_txPin > 0 && txPin != uart->_txPin) _uartDetachPins(uart, -1, uart->_txPin, -1, -1); - //assign the new one - retCode &= perimanSetPinBus(txPin, ESP32_BUS_TYPE_UART, (void *)uart); - if (retCode) { - uart->_txPin = txPin; - } + bool txPinChanged = txPin >= 0 && txPin != uart->_txPin; + if (txPinChanged) { + retCode &= _uartDetachPins(uart_num, UART_PIN_NO_CHANGE, uart->_txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); } - if (retCode && ctsPin > 0) { - // detachs previous UART pin - if (uart->_ctsPin > 0 && ctsPin != uart->_ctsPin) _uartDetachPins(uart, -1, -1, uart->_ctsPin, -1); - //assign the new one - retCode &= perimanSetPinBus(ctsPin, ESP32_BUS_TYPE_UART, (void *)uart); - if (retCode) { - uart->_ctsPin = ctsPin; - } + bool ctsPinChanged = ctsPin >= 0 && ctsPin != uart->_ctsPin; + if (ctsPinChanged) { + retCode &= _uartDetachPins(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, uart->_ctsPin, UART_PIN_NO_CHANGE); } - if (retCode && rtsPin > 0) { - // detachs previous UART pin - if (uart->_rtsPin > 0 && rtsPin != uart->_rtsPin) _uartDetachPins(uart, -1, -1, -1, uart->_rtsPin); - //assign the new one - retCode &= perimanSetPinBus(rtsPin, ESP32_BUS_TYPE_UART, (void *)uart); - if (retCode) { - uart->_rtsPin = rtsPin; - } + bool rtsPinChanged = rtsPin >= 0 && rtsPin != uart->_rtsPin; + if (rtsPinChanged) { + retCode &= _uartDetachPins(uart_num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, uart->_rtsPin); } - // IDF uart_set_pin() will issue necessary Error Message and take care of all GPIO Number validation. - if (retCode) retCode &= ESP_OK == uart_set_pin(uart->num, txPin, rxPin, rtsPin, ctsPin); + // Second step: attach all UART new pins + if (rxPinChanged) { + retCode &= _uartAttachPins(uart_num, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + } + if (txPinChanged) { + retCode &= _uartAttachPins(uart_num, UART_PIN_NO_CHANGE, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + } + if (ctsPinChanged) { + retCode &= _uartAttachPins(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, ctsPin, UART_PIN_NO_CHANGE); + } + if (rtsPinChanged) { + retCode &= _uartAttachPins(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin); + } UART_MUTEX_UNLOCK(); - // if it fails at any point ... detachs UART - if (!retCode) _uartDetachBus((void *) uart); + if (!retCode) { + log_e("UART%d set pins failed."); + } return retCode; } @@ -251,11 +354,8 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx } uart_t* uart = &_uart_bus_array[uart_nr]; - // set Peripheral Manager deInit Callback - perimanSetBusDeinit(ESP32_BUS_TYPE_UART, _uartDetachBus); - if (uart_is_driver_installed(uart_nr)) { - _uartDetachBus((void *) uart); + uartEnd(uart_nr); } #if !CONFIG_DISABLE_HAL_LOCKS @@ -288,12 +388,12 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx } UART_MUTEX_UNLOCK(); - - if (retCode) retCode &= uartSetPins(uart, rxPin, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); + // uartSetPins detaches previous pins if new ones are used over a previous begin() + if (retCode) retCode &= uartSetPins(uart_nr, rxPin, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE); if (retCode) uartFlush(uart); else { - _uartDetachBus((void *) uart); + uartEnd(uart_nr); uart = NULL; log_e("UART%d initialization error.", uart->num); } @@ -348,14 +448,20 @@ bool uartSetRxFIFOFull(uart_t* uart, uint8_t numBytesFIFOFull) } -void uartEnd(uart_t* uart) +void uartEnd(uint8_t uart_num) { - if(uart == NULL) { + if(uart_num >= SOC_UART_NUM) { + log_e("Serial number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1); return; } + // get UART information + uart_t* uart = &_uart_bus_array[uart_num]; UART_MUTEX_LOCK(); - _uartDetachBus((void *) uart); + _uartDetachPins(uart_num, uart->_rxPin, uart->_txPin, uart->_ctsPin, uart->_rtsPin); + if(uart_is_driver_installed(uart_num)) { + uart_driver_delete(uart_num); + } UART_MUTEX_UNLOCK(); } diff --git a/cores/esp32/esp32-hal-uart.h b/cores/esp32/esp32-hal-uart.h index a1531d6042d..c904a248f4c 100644 --- a/cores/esp32/esp32-hal-uart.h +++ b/cores/esp32/esp32-hal-uart.h @@ -103,7 +103,7 @@ struct uart_struct_t; typedef struct uart_struct_t uart_t; uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rxPin, int8_t txPin, uint16_t rx_buffer_size, uint16_t tx_buffer_size, bool inverted, uint8_t rxfifo_full_thrhd); -void uartEnd(uart_t* uart); +void uartEnd(uint8_t uart_num); // This is used to retrieve the Event Queue pointer from a UART IDF Driver in order to allow user to deal with its events void uartGetEventQueue(uart_t* uart, QueueHandle_t *q); @@ -133,8 +133,16 @@ int uartGetDebug(); bool uartIsDriverInstalled(uart_t* uart); -// Negative Pin Number will keep it unmodified, thus this function can set/reset individual pins -bool uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin); +// Negative Pin Number will keep it unmodified, thus this function can set individual pins +// When pins are changed, it will detach the previous ones +// Can be called before or after begin() +bool uartSetPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin); + +// helper functions +int8_t uart_get_RxPin(uint8_t uart_num); +int8_t uart_get_TxPin(uint8_t uart_num); +void uart_init_PeriMan(void); + // Enables or disables HW Flow Control function -- needs also to set CTS and/or RTS pins bool uartSetHwFlowCtrlMode(uart_t *uart, uint8_t mode, uint8_t threshold);