mirror of
https://github.com/espressif/esp-idf.git
synced 2025-07-30 18:57:19 +02:00
feat(uart): add pin release process to uart driver
This commit is contained in:
@ -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
|
* SPDX-License-Identifier: Apache-2.0
|
||||||
*/
|
*/
|
||||||
@ -32,6 +32,9 @@
|
|||||||
#include "driver/rtc_io.h"
|
#include "driver/rtc_io.h"
|
||||||
#include "soc/rtc_io_channel.h"
|
#include "soc/rtc_io_channel.h"
|
||||||
#include "driver/lp_io.h"
|
#include "driver/lp_io.h"
|
||||||
|
#if SOC_LP_GPIO_MATRIX_SUPPORTED
|
||||||
|
#include "soc/lp_gpio_pins.h"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#if I2C_USE_RETENTION_LINK
|
#if I2C_USE_RETENTION_LINK
|
||||||
#include "esp_private/sleep_retention.h"
|
#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->sda_num), TAG, "deinit rtc gpio failed");
|
||||||
ESP_RETURN_ON_ERROR(rtc_gpio_deinit(handle->scl_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
|
#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(LP_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].sda_in_sig, 0);
|
||||||
#endif
|
#endif
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
|
@ -36,6 +36,9 @@
|
|||||||
#include "driver/rtc_io.h"
|
#include "driver/rtc_io.h"
|
||||||
#include "hal/rtc_io_ll.h"
|
#include "hal/rtc_io_ll.h"
|
||||||
#include "driver/lp_io.h"
|
#include "driver/lp_io.h"
|
||||||
|
#if SOC_LP_GPIO_MATRIX_SUPPORTED
|
||||||
|
#include "soc/lp_gpio_pins.h"
|
||||||
|
#endif
|
||||||
#endif
|
#endif
|
||||||
#include "clk_ctrl_os.h"
|
#include "clk_ctrl_os.h"
|
||||||
#include "esp_pm.h"
|
#include "esp_pm.h"
|
||||||
@ -109,6 +112,11 @@ static const char *UART_TAG = "uart";
|
|||||||
.hal.dev = UART_LL_GET_HW(uart_num), \
|
.hal.dev = UART_LL_GET_HW(uart_num), \
|
||||||
INIT_CRIT_SECTION_LOCK_IN_STRUCT(spinlock) \
|
INIT_CRIT_SECTION_LOCK_IN_STRUCT(spinlock) \
|
||||||
.hw_enabled = false, \
|
.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 {
|
typedef struct {
|
||||||
@ -170,6 +178,11 @@ typedef struct {
|
|||||||
uart_hal_context_t hal; /*!< UART hal context*/
|
uart_hal_context_t hal; /*!< UART hal context*/
|
||||||
DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(spinlock)
|
DECLARE_CRIT_SECTION_LOCK_IN_STRUCT(spinlock)
|
||||||
bool hw_enabled;
|
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;
|
} uart_context_t;
|
||||||
|
|
||||||
static uart_obj_t *p_uart_obj[UART_NUM_MAX] = {0};
|
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;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
//internal signal can be output to multiple GPIO pads
|
static void uart_release_pin(uart_port_t uart_num)
|
||||||
//only one GPIO pad can connect with input signal
|
{
|
||||||
|
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_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");
|
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
|
#endif
|
||||||
|
|
||||||
|
// First, release previously configured IOs if there is
|
||||||
|
uart_release_pin(uart_num);
|
||||||
|
|
||||||
// Potential IO reserved mask
|
// Potential IO reserved mask
|
||||||
uint64_t io_reserve_mask = 0;
|
uint64_t io_reserve_mask = 0;
|
||||||
io_reserve_mask |= (tx_io_num > 0 ? BIT64(tx_io_num) : 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);
|
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. */
|
/* 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 (tx_io_num >= 0) {
|
||||||
if (uart_num < SOC_UART_HP_NUM) {
|
uart_context[uart_num].tx_io_num = tx_io_num;
|
||||||
gpio_func_sel(tx_io_num, PIN_FUNC_GPIO);
|
if (tx_rx_same_io || !uart_try_set_iomux_pin(uart_num, tx_io_num, SOC_UART_TX_PIN_IDX)) {
|
||||||
esp_rom_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0);
|
if (uart_num < SOC_UART_HP_NUM) {
|
||||||
// output enable is set inside esp_rom_gpio_connect_out_signal func after the signal is connected
|
gpio_func_sel(tx_io_num, PIN_FUNC_GPIO);
|
||||||
// (output enabled too early may cause unnecessary level change at the pad)
|
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
|
||||||
#if SOC_LP_GPIO_MATRIX_SUPPORTED
|
// (output enabled too early may cause unnecessary level change at the pad)
|
||||||
else {
|
}
|
||||||
rtc_gpio_init(tx_io_num); // set as a LP_GPIO pin
|
#if SOC_LP_GPIO_MATRIX_SUPPORTED
|
||||||
lp_gpio_connect_out_signal(tx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_TX_PIN_IDX), 0, 0);
|
else {
|
||||||
// output enable is set inside lp_gpio_connect_out_signal func after the signal is connected
|
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);
|
||||||
#endif
|
// output enable is set inside lp_gpio_connect_out_signal func after the signal is connected
|
||||||
}
|
|
||||||
|
|
||||||
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
|
|
||||||
}
|
}
|
||||||
|
|
||||||
lp_gpio_connect_in_signal(rx_io_num, UART_PERIPH_SIGNAL(uart_num, SOC_UART_RX_PIN_IDX), 0);
|
|
||||||
}
|
|
||||||
#endif
|
#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) {
|
if (uart_num < SOC_UART_HP_NUM) {
|
||||||
gpio_func_sel(rts_io_num, PIN_FUNC_GPIO);
|
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);
|
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
|
#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
|
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) {
|
if (uart_num < SOC_UART_HP_NUM) {
|
||||||
gpio_pullup_en(cts_io_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
|
// 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 old_busy_mask = esp_gpio_reserve(io_reserve_mask);
|
||||||
uint64_t conflict_mask = old_busy_mask & io_reserve_mask;
|
uint64_t conflict_mask = old_busy_mask & io_reserve_mask;
|
||||||
while (conflict_mask > 0) {
|
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");
|
ESP_LOGI(UART_TAG, "ALREADY NULL");
|
||||||
return ESP_OK;
|
return ESP_OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
uart_release_pin(uart_num);
|
||||||
|
|
||||||
esp_intr_free(p_uart_obj[uart_num]->intr_handle);
|
esp_intr_free(p_uart_obj[uart_num]->intr_handle);
|
||||||
uart_disable_rx_intr(uart_num);
|
uart_disable_rx_intr(uart_num);
|
||||||
uart_disable_tx_intr(uart_num);
|
uart_disable_tx_intr(uart_num);
|
||||||
|
Reference in New Issue
Block a user