Skip to content

Commit 9d84c78

Browse files
SuGliderCopilotpre-commit-ci-lite[bot]
authored
feat(uart): fixes pin attach for any IDF 5.x (#11499)
* feat(uart): fixes pin attach for any IDF 5.x * fix(uart): commentary typo error Co-authored-by: Copilot <[email protected]> * fix(uart): commentary typo error Co-authored-by: Copilot <[email protected]> * fix(uart): commentary typo error Co-authored-by: Copilot <[email protected]> * fix(uart): commentary style fix * ci(pre-commit): Apply automatic fixes --------- Co-authored-by: Copilot <[email protected]> Co-authored-by: pre-commit-ci-lite[bot] <117423508+pre-commit-ci-lite[bot]@users.noreply.github.com>
1 parent 01e4d5d commit 9d84c78

File tree

1 file changed

+126
-5
lines changed

1 file changed

+126
-5
lines changed

cores/esp32/esp32-hal-uart.c

Lines changed: 126 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -295,6 +295,125 @@ static bool _uartDetachBus_RTS(void *busptr) {
295295
return _uartDetachPins(bus->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, bus->_rtsPin);
296296
}
297297

298+
static bool _uartTrySetIomuxPin(uart_port_t uart_num, int io_num, uint32_t idx) {
299+
// Store a pointer to the default pin, to optimize access to its fields.
300+
const uart_periph_sig_t *upin = &uart_periph_signal[uart_num].pins[idx];
301+
302+
// In theory, if default_gpio is -1, iomux_func should also be -1, but let's be safe and test both.
303+
if (upin->iomux_func == -1 || upin->default_gpio == -1 || upin->default_gpio != io_num) {
304+
return false;
305+
}
306+
307+
// Assign the correct function to the GPIO.
308+
assert(upin->iomux_func != -1);
309+
if (uart_num < SOC_UART_HP_NUM) {
310+
gpio_iomux_out(io_num, upin->iomux_func, false);
311+
// If the pin is input, we also have to redirect the signal, in order to bypass the GPIO matrix.
312+
if (upin->input) {
313+
gpio_iomux_in(io_num, upin->signal);
314+
}
315+
}
316+
#if (SOC_UART_LP_NUM >= 1) && (SOC_RTCIO_PIN_COUNT >= 1)
317+
else {
318+
if (upin->input) {
319+
rtc_gpio_set_direction(io_num, RTC_GPIO_MODE_INPUT_ONLY);
320+
} else {
321+
rtc_gpio_set_direction(io_num, RTC_GPIO_MODE_OUTPUT_ONLY);
322+
}
323+
rtc_gpio_init(io_num);
324+
rtc_gpio_iomux_func_sel(io_num, upin->iomux_func);
325+
}
326+
#endif
327+
return true;
328+
}
329+
330+
static esp_err_t _uartInternalSetPin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num) {
331+
// Since an IO cannot route peripheral signals via IOMUX and GPIO matrix at the same time,
332+
// if tx and rx share the same IO, both signals need to be routed to IOs through GPIO matrix
333+
bool tx_rx_same_io = (tx_io_num == rx_io_num);
334+
335+
// In the following statements, if the io_num is negative, no need to configure anything.
336+
if (tx_io_num >= 0) {
337+
#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND || CONFIG_PM_SLP_DISABLE_GPIO
338+
// In such case, IOs are going to switch to sleep configuration (isolate) when entering sleep for power saving reason
339+
// But TX IO in isolate state could write garbled data to the other end
340+
// Therefore, we should disable the switch of the TX pin to sleep configuration
341+
gpio_sleep_sel_dis(tx_io_num);
342+
#endif
343+
if (tx_rx_same_io || !_uartTrySetIomuxPin(uart_num, tx_io_num, SOC_UART_TX_PIN_IDX)) {
344+
if (uart_num < SOC_UART_HP_NUM) {
345+
gpio_func_sel(tx_io_num, PIN_FUNC_GPIO);
346+
esp_rom_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0);
347+
// output enable is set inside esp_rom_gpio_connect_out_signal func after the signal is connected
348+
// (output enabled too early may cause unnecessary level change at the pad)
349+
}
350+
#if SOC_LP_GPIO_MATRIX_SUPPORTED
351+
else {
352+
rtc_gpio_init(tx_io_num); // set as a LP_GPIO pin
353+
lp_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0);
354+
// output enable is set inside lp_gpio_connect_out_signal func after the signal is connected
355+
}
356+
#endif
357+
}
358+
}
359+
360+
if (rx_io_num >= 0) {
361+
#if CONFIG_ESP_SLEEP_GPIO_RESET_WORKAROUND || CONFIG_PM_SLP_DISABLE_GPIO
362+
// In such case, IOs are going to switch to sleep configuration (isolate) when entering sleep for power saving reason
363+
// But RX IO in isolate state could receive garbled data into FIFO, which is not desired
364+
// Therefore, we should disable the switch of the RX pin to sleep configuration
365+
gpio_sleep_sel_dis(rx_io_num);
366+
#endif
367+
if (tx_rx_same_io || !_uartTrySetIomuxPin(uart_num, rx_io_num, SOC_UART_RX_PIN_IDX)) {
368+
if (uart_num < SOC_UART_HP_NUM) {
369+
gpio_input_enable(rx_io_num);
370+
esp_rom_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0);
371+
}
372+
#if SOC_LP_GPIO_MATRIX_SUPPORTED
373+
else {
374+
rtc_gpio_mode_t mode = (tx_rx_same_io ? RTC_GPIO_MODE_INPUT_OUTPUT : RTC_GPIO_MODE_INPUT_ONLY);
375+
rtc_gpio_set_direction(rx_io_num, mode);
376+
if (!tx_rx_same_io) { // set the same pin again as a LP_GPIO will overwrite connected out_signal, not desired, so skip
377+
rtc_gpio_init(rx_io_num); // set as a LP_GPIO pin
378+
}
379+
lp_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0);
380+
}
381+
#endif
382+
}
383+
}
384+
385+
if (rts_io_num >= 0 && !_uartTrySetIomuxPin(uart_num, rts_io_num, SOC_UART_RTS_PIN_IDX)) {
386+
if (uart_num < SOC_UART_HP_NUM) {
387+
gpio_func_sel(rts_io_num, PIN_FUNC_GPIO);
388+
esp_rom_gpio_connect_out_signal(rts_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RTS_PIN_IDX), 0, 0);
389+
// output enable is set inside esp_rom_gpio_connect_out_signal func after the signal is connected
390+
}
391+
#if SOC_LP_GPIO_MATRIX_SUPPORTED
392+
else {
393+
rtc_gpio_init(rts_io_num); // set as a LP_GPIO pin
394+
lp_gpio_connect_out_signal(rts_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RTS_PIN_IDX), 0, 0);
395+
// output enable is set inside lp_gpio_connect_out_signal func after the signal is connected
396+
}
397+
#endif
398+
}
399+
400+
if (cts_io_num >= 0 && !_uartTrySetIomuxPin(uart_num, cts_io_num, SOC_UART_CTS_PIN_IDX)) {
401+
if (uart_num < SOC_UART_HP_NUM) {
402+
gpio_pullup_en(cts_io_num);
403+
gpio_input_enable(cts_io_num);
404+
esp_rom_gpio_connect_in_signal(cts_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_CTS_PIN_IDX), 0);
405+
}
406+
#if SOC_LP_GPIO_MATRIX_SUPPORTED
407+
else {
408+
rtc_gpio_set_direction(cts_io_num, RTC_GPIO_MODE_INPUT_ONLY);
409+
rtc_gpio_init(cts_io_num); // set as a LP_GPIO pin
410+
lp_gpio_connect_in_signal(cts_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_CTS_PIN_IDX), 0);
411+
}
412+
#endif
413+
}
414+
return ESP_OK;
415+
}
416+
298417
// Attach function for UART
299418
// connects the IO Pad, set Paripheral Manager and internal UART structure data
300419
static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t ctsPin, int8_t rtsPin) {
@@ -307,7 +426,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
307426
//log_v("attaching UART%d pins: prev,new RX(%d,%d) TX(%d,%d) CTS(%d,%d) RTS(%d,%d)", uart_num,
308427
// uart->_rxPin, rxPin, uart->_txPin, txPin, uart->_ctsPin, ctsPin, uart->_rtsPin, rtsPin); vTaskDelay(10);
309428

310-
// IDF uart_set_pin() checks if the pin is used within LP UART and if it is a valid RTC IO pin
429+
// IDF _uartInternalSetPin() checks if the pin is used within LP UART and if it is a valid RTC IO pin
311430
// No need for Arduino Layer to check it again
312431
bool retCode = true;
313432
if (rxPin >= 0) {
@@ -316,7 +435,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
316435
perimanClearPinBus(rxPin);
317436
}
318437
// connect RX Pad
319-
bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
438+
bool ret = ESP_OK == _uartInternalSetPin(uart->num, UART_PIN_NO_CHANGE, rxPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
320439
#if SOC_UART_LP_NUM >= 1
321440
if (ret && uart_num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
322441
ret &= lp_uart_config_io(uart->num, rxPin, RTC_GPIO_MODE_INPUT_ONLY, SOC_UART_RX_PIN_IDX);
@@ -339,7 +458,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
339458
perimanClearPinBus(txPin);
340459
}
341460
// connect TX Pad
342-
bool ret = ESP_OK == uart_set_pin(uart->num, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
461+
bool ret = ESP_OK == _uartInternalSetPin(uart->num, txPin, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE);
343462
#if SOC_UART_LP_NUM >= 1
344463
if (ret && uart_num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
345464
ret &= lp_uart_config_io(uart->num, txPin, RTC_GPIO_MODE_OUTPUT_ONLY, SOC_UART_TX_PIN_IDX);
@@ -362,7 +481,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
362481
perimanClearPinBus(ctsPin);
363482
}
364483
// connect CTS Pad
365-
bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, ctsPin);
484+
bool ret = ESP_OK == _uartInternalSetPin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, ctsPin);
366485
#if SOC_UART_LP_NUM >= 1
367486
if (ret && uart_num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
368487
ret &= lp_uart_config_io(uart->num, ctsPin, RTC_GPIO_MODE_INPUT_ONLY, SOC_UART_CTS_PIN_IDX);
@@ -385,7 +504,7 @@ static bool _uartAttachPins(uint8_t uart_num, int8_t rxPin, int8_t txPin, int8_t
385504
perimanClearPinBus(rtsPin);
386505
}
387506
// connect RTS Pad
388-
bool ret = ESP_OK == uart_set_pin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin, UART_PIN_NO_CHANGE);
507+
bool ret = ESP_OK == _uartInternalSetPin(uart->num, UART_PIN_NO_CHANGE, UART_PIN_NO_CHANGE, rtsPin, UART_PIN_NO_CHANGE);
389508
#if SOC_UART_LP_NUM >= 1
390509
if (ret && uart_num >= SOC_UART_HP_NUM) { // it is a LP UART NUM
391510
ret &= lp_uart_config_io(uart->num, rtsPin, RTC_GPIO_MODE_OUTPUT_ONLY, SOC_UART_RTS_PIN_IDX);
@@ -1398,11 +1517,13 @@ void uart_internal_loopback(uint8_t uartNum, int8_t rxPin) {
13981517
log_e("UART%d is not supported for loopback or RX pin %d is invalid.", uartNum, rxPin);
13991518
return;
14001519
}
1520+
#if 0 // leave this code here for future reference and need
14011521
// forces rxPin to use GPIO Matrix and setup the pin to receive UART TX Signal - IDF 5.4.1 Change with uart_release_pin()
14021522
gpio_func_sel((gpio_num_t)rxPin, PIN_FUNC_GPIO);
14031523
gpio_pullup_en((gpio_num_t)rxPin);
14041524
gpio_input_enable((gpio_num_t)rxPin);
14051525
esp_rom_gpio_connect_in_signal(rxPin, uart_periph_signal[uartNum].pins[SOC_UART_RX_PIN_IDX].signal, false);
1526+
#endif
14061527
esp_rom_gpio_connect_out_signal(rxPin, uart_periph_signal[uartNum].pins[SOC_UART_TX_PIN_IDX].signal, false, false);
14071528
}
14081529

0 commit comments

Comments
 (0)