diff --git a/components/driver/uart/uart.c b/components/driver/uart/uart.c index 27f78cf923..af85adb65e 100644 --- a/components/driver/uart/uart.c +++ b/components/driver/uart/uart.c @@ -33,6 +33,9 @@ #include "esp_clk_tree.h" #include "sdkconfig.h" #include "esp_rom_gpio.h" +#if SOC_LP_GPIO_MATRIX_SUPPORTED +#include "soc/lp_gpio_pins.h" +#endif #include "clk_ctrl_os.h" #include "esp_pm.h" #include "esp_private/sleep_retention.h" @@ -104,6 +107,10 @@ static const char *UART_TAG = "uart"; .hal.dev = UART_LL_GET_HW(uart_num), \ INIT_CRIT_SECTION_LOCK_IN_STRUCT(spinlock) \ .hw_enabled = false, \ + .tx_io_num = -1, \ + .rx_io_num = -1, \ + .rts_io_num = -1, \ + .cts_io_num = -1, \ } typedef struct { @@ -169,6 +176,10 @@ typedef struct { bool retention_link_inited; /*!< Mark whether the retention link is inited */ bool retention_link_created; /*!< Mark whether the retention link is created */ #endif + int tx_io_num; + int rx_io_num; + int rts_io_num; + int cts_io_num; } uart_context_t; static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0}; @@ -706,8 +717,63 @@ static bool uart_try_set_iomux_pin(uart_port_t uart_num, int io_num, uint32_t id return true; } -//internal signal can be output to multiple GPIO pads -//only one GPIO pad can connect with input signal +static void uart_release_pin(uart_port_t uart_num) +{ + if (uart_num >= UART_NUM_MAX) { + return; + } + if (uart_context[uart_num].tx_io_num >= 0) { + gpio_ll_output_disable(&GPIO, uart_context[uart_num].tx_io_num); +#if (SOC_UART_LP_NUM >= 1) + if (!(uart_num < SOC_UART_HP_NUM)) { + rtc_gpio_deinit(uart_context[uart_num].tx_io_num); + } +#endif + } + + if (uart_context[uart_num].rx_io_num >= 0) { + if (uart_num < SOC_UART_HP_NUM) { + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ONE_INPUT, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false); + } +#if (SOC_UART_LP_NUM >= 1) + else { +#if SOC_LP_GPIO_MATRIX_SUPPORTED + lp_gpio_connect_in_signal(LP_GPIO_MATRIX_CONST_ONE_INPUT, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), false); +#endif + rtc_gpio_deinit(uart_context[uart_num].rx_io_num); + } +#endif + } + + if (uart_context[uart_num].rts_io_num >= 0) { + gpio_ll_output_disable(&GPIO, uart_context[uart_num].rts_io_num); +#if (SOC_UART_LP_NUM >= 1) + if (!(uart_num < SOC_UART_HP_NUM)) { + rtc_gpio_deinit(uart_context[uart_num].rts_io_num); + } +#endif + } + + if (uart_context[uart_num].cts_io_num >= 0) { + if (uart_num < SOC_UART_HP_NUM) { + esp_rom_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, UART_PERIPH_SIGNAL(uart_num, SOC_UART_CTS_PIN_IDX), false); + } +#if (SOC_UART_LP_NUM >= 1) + else { +#if SOC_LP_GPIO_MATRIX_SUPPORTED + lp_gpio_connect_in_signal(LP_GPIO_MATRIX_CONST_ZERO_INPUT, UART_PERIPH_SIGNAL(uart_num, SOC_UART_CTS_PIN_IDX), false); +#endif + rtc_gpio_deinit(uart_context[uart_num].cts_io_num); + } +#endif + } + + uart_context[uart_num].tx_io_num = -1; + uart_context[uart_num].rx_io_num = -1; + uart_context[uart_num].rts_io_num = -1; + uart_context[uart_num].cts_io_num = -1; +} + esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int rts_io_num, int cts_io_num) { ESP_RETURN_ON_FALSE((uart_num >= 0), ESP_FAIL, UART_TAG, "uart_num error"); @@ -739,48 +805,57 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r } #endif + // First, release previously configured IOs if there is + uart_release_pin(uart_num); + // Since an IO cannot route peripheral signals via IOMUX and GPIO matrix at the same time, // if tx and rx share the same IO, both signals need to be route to IOs through GPIO matrix bool tx_rx_same_io = (tx_io_num == rx_io_num); /* In the following statements, if the io_num is negative, no need to configure anything. */ - if (tx_io_num >= 0 && (tx_rx_same_io || !uart_try_set_iomux_pin(uart_num, tx_io_num, SOC_UART_TX_PIN_IDX))) { - if (uart_num < SOC_UART_HP_NUM) { - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[tx_io_num], PIN_FUNC_GPIO); - esp_rom_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0); - // output enable is set inside esp_rom_gpio_connect_out_signal func after the signal is connected - // (output enabled too early may cause unnecessary level change at the pad) - } -#if SOC_LP_GPIO_MATRIX_SUPPORTED - else { - rtc_gpio_init(tx_io_num); // set as a LP_GPIO pin - - lp_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0); - // output enable is set inside lp_gpio_connect_out_signal func after the signal is connected - } -#endif - } - - if (rx_io_num >= 0 && (tx_rx_same_io || !uart_try_set_iomux_pin(uart_num, rx_io_num, SOC_UART_RX_PIN_IDX))) { - if (uart_num < SOC_UART_HP_NUM) { - gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rx_io_num], PIN_FUNC_GPIO); - gpio_ll_input_enable(&GPIO, rx_io_num); - esp_rom_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0); - } -#if SOC_LP_GPIO_MATRIX_SUPPORTED - else { - rtc_gpio_mode_t mode = (tx_rx_same_io ? RTC_GPIO_MODE_INPUT_OUTPUT : RTC_GPIO_MODE_INPUT_ONLY); - rtc_gpio_set_direction(rx_io_num, mode); - if (!tx_rx_same_io) { // set the same pin again as a LP_GPIO will overwrite connected out_signal, not desired, so skip - rtc_gpio_init(rx_io_num); // set as a LP_GPIO pin + if (tx_io_num >= 0) { + uart_context[uart_num].tx_io_num = tx_io_num; + if (tx_rx_same_io || !uart_try_set_iomux_pin(uart_num, tx_io_num, SOC_UART_TX_PIN_IDX)) { + if (uart_num < SOC_UART_HP_NUM) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[tx_io_num], PIN_FUNC_GPIO); + esp_rom_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0); + // output enable is set inside esp_rom_gpio_connect_out_signal func after the signal is connected + // (output enabled too early may cause unnecessary level change at the pad) } +#if SOC_LP_GPIO_MATRIX_SUPPORTED + else { + rtc_gpio_init(tx_io_num); // set as a LP_GPIO pin - lp_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0); - } + lp_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0); + // output enable is set inside lp_gpio_connect_out_signal func after the signal is connected + } #endif + } } - if (rts_io_num >= 0 && !uart_try_set_iomux_pin(uart_num, rts_io_num, SOC_UART_RTS_PIN_IDX)) { + if (rx_io_num >= 0) { + uart_context[uart_num].rx_io_num = rx_io_num; + if (tx_rx_same_io || !uart_try_set_iomux_pin(uart_num, rx_io_num, SOC_UART_RX_PIN_IDX)) { + if (uart_num < SOC_UART_HP_NUM) { + gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rx_io_num], PIN_FUNC_GPIO); + gpio_ll_input_enable(&GPIO, rx_io_num); + esp_rom_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0); + } +#if SOC_LP_GPIO_MATRIX_SUPPORTED + else { + rtc_gpio_mode_t mode = (tx_rx_same_io ? RTC_GPIO_MODE_INPUT_OUTPUT : RTC_GPIO_MODE_INPUT_ONLY); + rtc_gpio_set_direction(rx_io_num, mode); + if (!tx_rx_same_io) { // set the same pin again as a LP_GPIO will overwrite connected out_signal, not desired, so skip + rtc_gpio_init(rx_io_num); // set as a LP_GPIO pin + } + + lp_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0); + } +#endif + } + } + + if (rts_io_num >= 0 && (uart_context[uart_num].rts_io_num = rts_io_num, !uart_try_set_iomux_pin(uart_num, rts_io_num, SOC_UART_RTS_PIN_IDX))) { if (uart_num < SOC_UART_HP_NUM) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[rts_io_num], PIN_FUNC_GPIO); esp_rom_gpio_connect_out_signal(rts_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RTS_PIN_IDX), 0, 0); @@ -795,7 +870,7 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r #endif } - if (cts_io_num >= 0 && !uart_try_set_iomux_pin(uart_num, cts_io_num, SOC_UART_CTS_PIN_IDX)) { + if (cts_io_num >= 0 && (uart_context[uart_num].cts_io_num = cts_io_num, !uart_try_set_iomux_pin(uart_num, cts_io_num, SOC_UART_CTS_PIN_IDX))) { if (uart_num < SOC_UART_HP_NUM) { gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[cts_io_num], PIN_FUNC_GPIO); gpio_set_pull_mode(cts_io_num, GPIO_PULLUP_ONLY); @@ -1785,6 +1860,9 @@ esp_err_t uart_driver_delete(uart_port_t uart_num) ESP_LOGI(UART_TAG, "ALREADY NULL"); return ESP_OK; } + + uart_release_pin(uart_num); + esp_intr_free(p_uart_obj[uart_num]->intr_handle); uart_disable_rx_intr(uart_num); uart_disable_tx_intr(uart_num);