Skip to content

Fixes UART pin detach on Serial.end() #7402

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Nov 2, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
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
22 changes: 19 additions & 3 deletions cores/esp32/HardwareSerial.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -145,6 +145,10 @@ _eventTask(NULL)
#if !CONFIG_DISABLE_HAL_LOCKS
,_lock(NULL)
#endif
,_rxPin(-1)
,_txPin(-1)
,_ctsPin(-1)
,_rtsPin(-1)
{
#if !CONFIG_DISABLE_HAL_LOCKS
if(_lock == NULL){
Expand Down Expand Up @@ -384,7 +388,8 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in

// Set UART RX timeout
uartSetRxTimeout(_uart, _rxTimeout);

_rxPin = rxPin;
_txPin = txPin;
HSERIAL_MUTEX_UNLOCK();
}

Expand All @@ -403,6 +408,8 @@ void HardwareSerial::end(bool fullyTerminate)
if (uartGetDebug() == _uart_nr) {
uartSetDebug(0);
}
uartDetachPins(_uart, _rxPin, _txPin, _ctsPin, _rtsPin);
_rxPin = _txPin = _ctsPin = _rtsPin = -1;
}
delay(10);
uartEnd(_uart);
Expand Down Expand Up @@ -507,10 +514,19 @@ void HardwareSerial::setRxInvert(bool invert)
void 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");
log_e("setPins() shall be called after begin() - nothing done\n");
return;
}
uartSetPins(_uart, rxPin, txPin, ctsPin, rtsPin);

// uartSetPins() checks if pins are valid for each function and for the SoC
if (uartSetPins(_uart, rxPin, txPin, ctsPin, rtsPin)) {
_txPin = _txPin >= 0 ? txPin : _txPin;
_rxPin = _rxPin >= 0 ? rxPin : _rxPin;
_rtsPin = _rtsPin >= 0 ? rtsPin : _rtsPin;
_ctsPin = _ctsPin >= 0 ? ctsPin : _ctsPin;
} else {
log_e("Error when setting Serial port Pins. Invalid Pin.\n");
}
}

// Enables or disables Hardware Flow Control using RTS and/or CTS pins (must use setAllPins() before)
Expand Down
1 change: 1 addition & 0 deletions cores/esp32/HardwareSerial.h
Original file line number Diff line number Diff line change
Expand Up @@ -176,6 +176,7 @@ class HardwareSerial: public Stream
#if !CONFIG_DISABLE_HAL_LOCKS
SemaphoreHandle_t _lock;
#endif
int8_t _rxPin, _txPin, _ctsPin, _rtsPin;

void _createEventTask(void *args);
void _destroyEventTask(void);
Expand Down
44 changes: 41 additions & 3 deletions cores/esp32/esp32-hal-uart.c
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,9 @@
#include "soc/soc_caps.h"
#include "soc/uart_struct.h"

#include "hal/gpio_hal.h"
#include "esp_rom_gpio.h"

static int s_uart_debug_nr = 0;

struct uart_struct_t {
Expand Down Expand Up @@ -69,6 +72,40 @@ 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
void uartDetachPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin)
{
if(uart == NULL) {
return;
}

UART_MUTEX_LOCK();
if (txPin >= 0) {
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);
}

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 (rtsPin >= 0) {
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);
}

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);
}
UART_MUTEX_UNLOCK();
}

// solves issue https://github.com/espressif/arduino-esp32/issues/6032
// baudrate must be multiplied when CPU Frequency is lower than APB 80MHz
uint32_t _get_effective_baudrate(uint32_t baudrate)
Expand Down Expand Up @@ -108,15 +145,16 @@ bool uartIsDriverInstalled(uart_t* uart)

// 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)
bool uartSetPins(uart_t* uart, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin)
{
if(uart == NULL) {
return;
return false;
}
UART_MUTEX_LOCK();
// IDF uart_set_pin() will issue necessary Error Message and take care of all GPIO Number validation.
uart_set_pin(uart->num, txPin, rxPin, rtsPin, ctsPin);
bool retCode = uart_set_pin(uart->num, txPin, rxPin, rtsPin, ctsPin) == ESP_OK;
UART_MUTEX_UNLOCK();
return retCode;
}

//
Expand Down
5 changes: 3 additions & 2 deletions cores/esp32/esp32-hal-uart.h
Original file line number Diff line number Diff line change
Expand Up @@ -91,8 +91,9 @@ int uartGetDebug();

bool uartIsDriverInstalled(uart_t* uart);

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