Skip to content

Commit 5fed183

Browse files
committed
UART: fixes begin()
1 parent e4d6a8a commit 5fed183

File tree

3 files changed

+172
-47
lines changed

3 files changed

+172
-47
lines changed

cores/esp32/HardwareSerial.cpp

Lines changed: 24 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -114,7 +114,7 @@ _eventTask(NULL)
114114

115115
HardwareSerial::~HardwareSerial()
116116
{
117-
end(true); // explicit Full UART termination
117+
end(); // explicit Full UART termination
118118
#if !CONFIG_DISABLE_HAL_LOCKS
119119
if(_lock != NULL){
120120
vSemaphoreDelete(_lock);
@@ -329,16 +329,20 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
329329
// map logical pins to GPIO numbers
330330
rxPin = digitalPinToGPIONumber(rxPin);
331331
txPin = digitalPinToGPIONumber(txPin);
332+
// IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified.
333+
// it will detach previous UART attached pins
332334

333-
if(_uart) {
334-
// in this case it is a begin() over a previous begin() - maybe to change baud rate
335-
// thus do not disable debug output
336-
end(false); // disables IDF UART driver and UART event Task + sets _uart to NULL
335+
// indicates that uartbegin() has to initilize a new IDF driver
336+
if (_testUartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd)) {
337+
_destroyEventTask(); // when IDF uart driver must be restarted, _eventTask must finish too
337338
}
338339

339-
// IDF UART driver keeps Pin setting on restarting. Negative Pin number will keep it unmodified.
340-
// it will detach previous UART attached pins
341340
_uart = uartBegin(_uart_nr, baud ? baud : 9600, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd);
341+
if (_uart == NULL) {
342+
log_e("UART driver failed to start. Please check the logs.");
343+
HSERIAL_MUTEX_UNLOCK();
344+
return;
345+
}
342346
if (!baud) {
343347
// using baud rate as zero, forces it to try to detect the current baud rate in place
344348
uartStartDetectBaudrate(_uart);
@@ -348,11 +352,14 @@ void HardwareSerial::begin(unsigned long baud, uint32_t config, int8_t rxPin, in
348352
yield();
349353
}
350354

351-
end(false); // disables IDF UART driver and UART event Task + sets _uart to NULL
352-
353355
if(detectedBaudRate) {
354356
delay(100); // Give some time...
355357
_uart = uartBegin(_uart_nr, detectedBaudRate, config, rxPin, txPin, _rxBufferSize, _txBufferSize, invert, rxfifo_full_thrhd);
358+
if (_uart == NULL) {
359+
log_e("UART driver failed to start. Please check the logs.");
360+
HSERIAL_MUTEX_UNLOCK();
361+
return;
362+
}
356363
} else {
357364
log_e("Could not detect baudrate. Serial data at the port must be present within the timeout for detection to be possible");
358365
_uart = NULL;
@@ -389,22 +396,17 @@ void HardwareSerial::updateBaudRate(unsigned long baud)
389396
uartSetBaudRate(_uart, baud);
390397
}
391398

392-
void HardwareSerial::end(bool fullyTerminate)
399+
void HardwareSerial::end()
393400
{
394401
// default Serial.end() will completely disable HardwareSerial,
395402
// including any tasks or debug message channel (log_x()) - but not for IDF log messages!
396-
if(fullyTerminate) {
397-
_onReceiveCB = NULL;
398-
_onReceiveErrorCB = NULL;
399-
if (uartGetDebug() == _uart_nr) {
400-
uartSetDebug(0);
401-
}
402-
_rxFIFOFull = 0;
403-
uartEnd(_uart_nr); // fully detach all pins and delete the UART driver
404-
} else {
405-
// do not invalidate callbacks, detach pins, invalidate DBG output
406-
uart_driver_delete(_uart_nr);
403+
_onReceiveCB = NULL;
404+
_onReceiveErrorCB = NULL;
405+
if (uartGetDebug() == _uart_nr) {
406+
uartSetDebug(0);
407407
}
408+
_rxFIFOFull = 0;
409+
uartEnd(_uart_nr); // fully detach all pins and delete the UART driver
408410
_destroyEventTask(); // when IDF uart driver is deleted, _eventTask must finish too
409411
_uart = NULL;
410412
}
@@ -564,3 +566,4 @@ size_t HardwareSerial::setTxBufferSize(size_t new_size) {
564566
_txBufferSize = new_size;
565567
return _txBufferSize;
566568
}
569+

cores/esp32/esp32-hal-uart.c

Lines changed: 147 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@
1414

1515
#include "esp32-hal-uart.h"
1616

17+
#define SOC_UART_SUPPORTED 1
1718
#if SOC_UART_SUPPORTED
1819
#include "esp32-hal.h"
1920
#include "esp32-hal-periman.h"
@@ -33,19 +34,25 @@
3334
#include "hal/gpio_hal.h"
3435
#include "esp_rom_gpio.h"
3536

36-
static int s_uart_debug_nr = 0;
37+
static int s_uart_debug_nr = 0; // UART number for debug output
3738

3839
struct uart_struct_t {
3940

4041
#if !CONFIG_DISABLE_HAL_LOCKS
41-
SemaphoreHandle_t lock;
42+
SemaphoreHandle_t lock; // UART lock
4243
#endif
4344

44-
uint8_t num;
45-
bool has_peek;
46-
uint8_t peek_byte;
47-
QueueHandle_t uart_event_queue; // export it by some uartGetEventQueue() function
48-
int8_t _rxPin, _txPin, _ctsPin, _rtsPin; // UART GPIOs
45+
uint8_t num; // UART number for IDF driver API
46+
bool has_peek; // flag to indicate that there is a peek byte pending to be read
47+
uint8_t peek_byte; // peek byte that has been read but not consumed
48+
QueueHandle_t uart_event_queue; // export it by some uartGetEventQueue() function
49+
// configuration data:: Arduino API tipical data
50+
int8_t _rxPin, _txPin, _ctsPin, _rtsPin; // UART GPIOs
51+
uint32_t _baudrate, _config; // UART baudrate and config
52+
// UART ESP32 specific data
53+
uint16_t _rx_buffer_size, _tx_buffer_size; // UART RX and TX buffer sizes
54+
bool _inverted; // UART inverted signal
55+
uint8_t _rxfifo_full_thrhd; // UART RX FIFO full threshold
4956
};
5057

5158
#if CONFIG_DISABLE_HAL_LOCKS
@@ -54,12 +61,12 @@ struct uart_struct_t {
5461
#define UART_MUTEX_UNLOCK()
5562

5663
static uart_t _uart_bus_array[] = {
57-
{0, false, 0, NULL, -1, -1, -1, -1},
64+
{0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
5865
#if SOC_UART_NUM > 1
59-
{1, false, 0, NULL, -1, -1, -1, -1},
66+
{1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
6067
#endif
6168
#if SOC_UART_NUM > 2
62-
{2, false, 0, NULL, -1, -1, -1, -1},
69+
{2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
6370
#endif
6471
};
6572

@@ -69,12 +76,12 @@ static uart_t _uart_bus_array[] = {
6976
#define UART_MUTEX_UNLOCK() if(uart->lock != NULL) xSemaphoreGive(uart->lock)
7077

7178
static uart_t _uart_bus_array[] = {
72-
{NULL, 0, false, 0, NULL, -1, -1, -1, -1},
79+
{NULL, 0, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
7380
#if SOC_UART_NUM > 1
74-
{NULL, 1, false, 0, NULL, -1, -1, -1, -1},
81+
{NULL, 1, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
7582
#endif
7683
#if SOC_UART_NUM > 2
77-
{NULL, 2, false, 0, NULL, -1, -1, -1, -1},
84+
{NULL, 2, false, 0, NULL, -1, -1, -1, -1, 0, 0, 0, 0, false, 0},
7885
#endif
7986
};
8087

@@ -97,7 +104,12 @@ static bool _uartDetachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
97104
// detaches pins and sets Peripheral Manager and UART information
98105
if (rxPin >= 0 && uart->_rxPin == rxPin && perimanGetPinBusType(rxPin) == ESP32_BUS_TYPE_UART_RX) {
99106
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rxPin], PIN_FUNC_GPIO);
100-
esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_LOW, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false);
107+
// avoids cause BREAK in the UART line
108+
if (uart->_inverted) {
109+
esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_LOW, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false);
110+
} else {
111+
esp_rom_gpio_connect_in_signal(GPIO_FUNC_IN_HIGH, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false);
112+
}
101113
uart->_rxPin = -1; // -1 means unassigned/detached
102114
if (!perimanClearPinBus(rxPin)) {
103115
retCode = false;
@@ -355,28 +367,121 @@ bool uartSetHwFlowCtrlMode(uart_t *uart, uart_hw_flowcontrol_t mode, uint8_t thr
355367
return retCode;
356368
}
357369

358-
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)
370+
// This helper function will return true if a new IDF UART driver needs to be restarted and false if the current one can continue its execution
371+
bool _testUartBegin(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)
359372
{
360373
if(uart_nr >= SOC_UART_NUM) {
361-
return NULL;
374+
return false; // no new driver has to be installed
362375
}
363376
uart_t* uart = &_uart_bus_array[uart_nr];
364-
377+
// verify if is necessary to restart the UART driver
365378
if (uart_is_driver_installed(uart_nr)) {
366-
uartEnd(uart_nr);
379+
// some parameters can't be changed unless we end the UART driver
380+
if ( uart->_rx_buffer_size != rx_buffer_size || uart->_tx_buffer_size != tx_buffer_size || uart->_inverted != inverted || uart->_rxfifo_full_thrhd != rxfifo_full_thrhd) {
381+
return true; // the current IDF UART driver must be terminated and a new driver shall be installed
382+
} else {
383+
return false; // The current IDF UART driver can continue its execution
384+
}
385+
} else {
386+
return true; // no IDF UART driver is running and a new driver shall be installed
367387
}
388+
}
389+
390+
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)
391+
{
392+
if(uart_nr >= SOC_UART_NUM) {
393+
log_e("UART number is invalid, please use number from 0 to %u", SOC_UART_NUM - 1);
394+
return NULL; // no new driver was installed
395+
}
396+
uart_t* uart = &_uart_bus_array[uart_nr];
397+
log_v("UART%d baud(%ld) Mode(%x) rxPin(%d) txPin(%d)", uart_nr, baudrate, config, rxPin, txPin);
368398

369399
#if !CONFIG_DISABLE_HAL_LOCKS
370400
if(uart->lock == NULL) {
371401
uart->lock = xSemaphoreCreateMutex();
372402
if(uart->lock == NULL) {
373403
log_e("HAL LOCK error.");
374-
return NULL;
404+
return NULL; // no new driver was installed
375405
}
376406
}
377407
#endif
378-
UART_MUTEX_LOCK();
379408

409+
if (uart_is_driver_installed(uart_nr)) {
410+
log_v("UART%d Driver already installed.", uart_nr);
411+
// some parameters can't be changed unless we end the UART driver
412+
if ( uart->_rx_buffer_size != rx_buffer_size || uart->_tx_buffer_size != tx_buffer_size || uart->_inverted != inverted || uart->_rxfifo_full_thrhd != rxfifo_full_thrhd) {
413+
log_v("UART%d changing buffer sizes or inverted signal or rxfifo_full_thrhd. IDF driver will be restarted", uart_nr);
414+
uartEnd(uart_nr);
415+
} else {
416+
bool retCode = true;
417+
UART_MUTEX_LOCK();
418+
//User may just want to change some parameters, such as baudrate, data length, parity, stop bits or pins
419+
if (uart->_baudrate != baudrate) {
420+
if (ESP_OK != uart_set_baudrate(uart_nr, baudrate)) {
421+
log_e("UART%d changing baudrate failed.", uart_nr);
422+
retCode = false;
423+
} else {
424+
log_v("UART%d changed baudrate to %d", uart_nr, baudrate);
425+
uart->_baudrate = baudrate;
426+
}
427+
}
428+
uart_word_length_t data_bits = (config & 0xc) >> 2;
429+
uart_parity_t parity = config & 0x3;
430+
uart_stop_bits_t stop_bits = (config & 0x30) >> 4;
431+
if (retCode && (uart->_config & 0xc) >> 2 != data_bits) {
432+
if (ESP_OK != uart_set_word_length(uart_nr, data_bits)) {
433+
log_e("UART%d changing data length failed.", uart_nr);
434+
retCode = false;
435+
} else {
436+
log_v("UART%d changed data length to %d", uart_nr, data_bits + 5);
437+
}
438+
}
439+
if (retCode && (uart->_config & 0x3) != parity) {
440+
if (ESP_OK != uart_set_parity(uart_nr, parity)) {
441+
log_e("UART%d changing parity failed.", uart_nr);
442+
retCode = false;
443+
} else {
444+
log_v("UART%d changed parity to %s", uart_nr, parity == 0 ? "NONE" : parity == 2 ? "EVEN" : "ODD");
445+
}
446+
}
447+
if (retCode && (uart->_config & 0xc30) >> 4 != stop_bits) {
448+
if (ESP_OK != uart_set_stop_bits(uart_nr, stop_bits)) {
449+
log_e("UART%d changing stop bits failed.", uart_nr);
450+
retCode = false;
451+
} else {
452+
log_v("UART%d changed stop bits to %d", uart_nr, stop_bits == 3 ? 2 : 1);
453+
}
454+
}
455+
if (retCode) uart->_config = config;
456+
if (retCode && rxPin > 0 && uart->_rxPin != rxPin) {
457+
retCode &= _uartDetachPins(uart_nr, uart->_rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
458+
retCode &= _uartAttachPins(uart_nr, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
459+
if (!retCode) {
460+
log_e("UART%d changing RX pin failed.", uart_nr);
461+
} else {
462+
log_v("UART%d changed RX pin to %d", uart_nr, rxPin);
463+
}
464+
}
465+
if (retCode && txPin > 0 && uart->_txPin != txPin) {
466+
retCode &= _uartDetachPins(uart_nr, UART_PIN_NO_CHANGE, uart->_txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
467+
retCode &= _uartAttachPins(uart_nr, UART_PIN_NO_CHANGE, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
468+
if (!retCode) {
469+
log_e("UART%d changing TX pin failed.", uart_nr);
470+
} else {
471+
log_v("UART%d changed TX pin to %d", uart_nr, txPin);
472+
}
473+
}
474+
UART_MUTEX_UNLOCK();
475+
if (retCode) {
476+
// UART driver was already working, just return the uart_t structure, syaing that no new driver was installed
477+
return uart;
478+
}
479+
// if we reach this point, it means that we need to restart the UART driver
480+
uartEnd(uart_nr);
481+
}
482+
} else {
483+
log_v("UART%d not installed. Starting installation", uart_nr);
484+
}
380485
uart_config_t uart_config;
381486
uart_config.data_bits = (config & 0xc) >> 2;
382487
uart_config.parity = (config & 0x3);
@@ -386,7 +491,10 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
386491
uart_config.baud_rate = baudrate;
387492
// CLK_APB for ESP32|S2|S3|C3 -- CLK_PLL_F40M for C2 -- CLK_PLL_F48M for H2 -- CLK_PLL_F80M for C6
388493
uart_config.source_clk = UART_SCLK_DEFAULT;
494+
495+
UART_MUTEX_LOCK();
389496
bool retCode = ESP_OK == uart_driver_install(uart_nr, rx_buffer_size, tx_buffer_size, 20, &(uart->uart_event_queue), 0);
497+
390498
if (retCode) retCode &= ESP_OK == uart_param_config(uart_nr, &uart_config);
391499

392500
// Is it right or the idea is to swap rx and tx pins?
@@ -395,19 +503,31 @@ uart_t* uartBegin(uint8_t uart_nr, uint32_t baudrate, uint32_t config, int8_t rx
395503
retCode &= ESP_OK == uart_set_line_inverse(uart_nr, UART_SIGNAL_TXD_INV | UART_SIGNAL_RXD_INV);
396504
}
397505

506+
if (retCode) {
507+
uart->_baudrate = baudrate;
508+
uart->_config = config;
509+
uart->_inverted = inverted;
510+
uart->_rxfifo_full_thrhd = rxfifo_full_thrhd;
511+
uart->_rx_buffer_size = rx_buffer_size;
512+
uart->_tx_buffer_size = tx_buffer_size;
513+
uart->_ctsPin = -1;
514+
uart->_rtsPin = -1;
515+
uart->has_peek = false;
516+
uart->peek_byte = 0;
517+
}
398518
UART_MUTEX_UNLOCK();
519+
399520
// uartSetPins detaches previous pins if new ones are used over a previous begin()
400521
if (retCode) retCode &= uartSetPins(uart_nr, rxPin, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
401-
402-
if (retCode) uartFlush(uart);
403-
else {
522+
if (!retCode) {
404523
uartEnd(uart_nr);
405524
uart = NULL;
406525
log_e("UART%d initialization error.", uart->num);
526+
} else {
527+
uartFlush(uart);
528+
log_v("UART%d initialization done.", uart->num);
407529
}
408-
409-
log_v("UART%d baud(%ld) Mode(%x) rxPin(%d) txPin(%d)", uart_nr, baudrate, config, rxPin, txPin);
410-
return uart;
530+
return uart; // a new driver was installed
411531
}
412532

413533
// This function code is under testing - for now just keep it here
@@ -1025,3 +1145,4 @@ int uart_send_msg_with_break(uint8_t uartNum, uint8_t *msg, size_t msgSize)
10251145
}
10261146

10271147
#endif /* SOC_UART_SUPPORTED */
1148+

cores/esp32/esp32-hal-uart.h

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,7 @@ extern "C" {
3232
struct uart_struct_t;
3333
typedef struct uart_struct_t uart_t;
3434

35+
bool _testUartBegin(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);
3536
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);
3637
void uartEnd(uint8_t uart_num);
3738

0 commit comments

Comments
 (0)