mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-29 18:27:20 +02:00
feat(uart): add pin release process to uart driver
This commit is contained in:
@ -33,6 +33,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"
|
||||
@ -105,6 +108,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 {
|
||||
@ -170,6 +177,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};
|
||||
@ -703,8 +714,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");
|
||||
@ -736,48 +802,56 @@ 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_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))) {
|
||||
if (uart_num < SOC_UART_HP_NUM) {
|
||||
gpio_func_sel(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_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)) {
|
||||
if (uart_num < SOC_UART_HP_NUM) {
|
||||
gpio_func_sel(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_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);
|
||||
@ -792,7 +866,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_func_sel(cts_io_num, PIN_FUNC_GPIO);
|
||||
gpio_set_pull_mode(cts_io_num, GPIO_PULLUP_ONLY);
|
||||
@ -1780,6 +1854,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);
|
||||
|
Reference in New Issue
Block a user