From 60f5828a4a790d4481aaf7c69eac72e3af1079fe Mon Sep 17 00:00:00 2001 From: Song Ruo Jing Date: Wed, 23 Apr 2025 15:28:41 +0800 Subject: [PATCH] feat(uart): add pin release process to uart driver --- components/esp_driver_i2c/i2c_common.c | 9 +- components/esp_driver_uart/src/uart.c | 154 +++++++++++++++++++------ 2 files changed, 125 insertions(+), 38 deletions(-) diff --git a/components/esp_driver_i2c/i2c_common.c b/components/esp_driver_i2c/i2c_common.c index 73126c95ae..12a452d550 100644 --- a/components/esp_driver_i2c/i2c_common.c +++ b/components/esp_driver_i2c/i2c_common.c @@ -1,5 +1,5 @@ /* - * SPDX-FileCopyrightText: 2023-2024 Espressif Systems (Shanghai) CO LTD + * SPDX-FileCopyrightText: 2023-2025 Espressif Systems (Shanghai) CO LTD * * SPDX-License-Identifier: Apache-2.0 */ @@ -32,6 +32,9 @@ #include "driver/rtc_io.h" #include "soc/rtc_io_channel.h" #include "driver/lp_io.h" +#if SOC_LP_GPIO_MATRIX_SUPPORTED +#include "soc/lp_gpio_pins.h" +#endif #endif #if I2C_USE_RETENTION_LINK #include "esp_private/sleep_retention.h" @@ -427,8 +430,8 @@ esp_err_t i2c_common_deinit_pins(i2c_bus_handle_t handle) ESP_RETURN_ON_ERROR(rtc_gpio_deinit(handle->sda_num), TAG, "deinit rtc gpio failed"); ESP_RETURN_ON_ERROR(rtc_gpio_deinit(handle->scl_num), TAG, "deinit rtc gpio failed"); #if SOC_LP_GPIO_MATRIX_SUPPORTED - lp_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, i2c_periph_signal[port_id].scl_in_sig, 0); - lp_gpio_connect_in_signal(GPIO_MATRIX_CONST_ZERO_INPUT, i2c_periph_signal[port_id].sda_in_sig, 0); + lp_gpio_connect_in_signal(LP_GPIO_MATRIX_CONST_ZERO_INPUT, i2c_periph_signal[port_id].scl_in_sig, 0); + lp_gpio_connect_in_signal(LP_GPIO_MATRIX_CONST_ZERO_INPUT, i2c_periph_signal[port_id].sda_in_sig, 0); #endif } #endif diff --git a/components/esp_driver_uart/src/uart.c b/components/esp_driver_uart/src/uart.c index 166fb502a5..a30a0b9c22 100644 --- a/components/esp_driver_uart/src/uart.c +++ b/components/esp_driver_uart/src/uart.c @@ -36,6 +36,9 @@ #include "driver/rtc_io.h" #include "hal/rtc_io_ll.h" #include "driver/lp_io.h" +#if SOC_LP_GPIO_MATRIX_SUPPORTED +#include "soc/lp_gpio_pins.h" +#endif #endif #include "clk_ctrl_os.h" #include "esp_pm.h" @@ -109,6 +112,11 @@ 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, \ + .io_reserved_mask = 0, \ } typedef struct { @@ -170,6 +178,11 @@ typedef struct { uart_hal_context_t hal; /*!< UART hal context*/ DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(spinlock) bool hw_enabled; + int tx_io_num; + int rx_io_num; + int rts_io_num; + int cts_io_num; + uint64_t io_reserved_mask; } uart_context_t; static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0}; @@ -707,8 +720,66 @@ 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_output_disable(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_output_disable(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 + } + + esp_gpio_revoke(uart_context[uart_num].io_reserved_mask); + + 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; + uart_context[uart_num].io_reserved_mask = 0; +} + 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"); @@ -740,6 +811,9 @@ 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); + // Potential IO reserved mask uint64_t io_reserve_mask = 0; io_reserve_mask |= (tx_io_num > 0 ? BIT64(tx_io_num) : 0); @@ -752,42 +826,48 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r 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_func_sel(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))) { - io_reserve_mask &= ~BIT64(rx_io_num); // input IO via GPIO matrix does not need to be reserved - if (uart_num < SOC_UART_HP_NUM) { - gpio_input_enable(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_func_sel(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 } - - 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_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)) { + io_reserve_mask &= ~BIT64(rx_io_num); // input IO via GPIO matrix does not need to be reserved + if (uart_num < SOC_UART_HP_NUM) { + gpio_input_enable(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_func_sel(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); @@ -802,7 +882,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))) { io_reserve_mask &= ~BIT64(cts_io_num); // input IO via GPIO matrix does not need to be reserved if (uart_num < SOC_UART_HP_NUM) { gpio_pullup_en(cts_io_num); @@ -819,6 +899,7 @@ esp_err_t uart_set_pin(uart_port_t uart_num, int tx_io_num, int rx_io_num, int r } // IO reserve + uart_context[uart_num].io_reserved_mask = io_reserve_mask; uint64_t old_busy_mask = esp_gpio_reserve(io_reserve_mask); uint64_t conflict_mask = old_busy_mask & io_reserve_mask; while (conflict_mask > 0) { @@ -1801,6 +1882,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);