feat(i2s): support i2s gpio reservation

This commit is contained in:
laokaiyao 2024-04-02 14:57:00 +08:00
parent f1babb9074
commit e4f28fcb7f
5 changed files with 121 additions and 47 deletions

View File

@ -283,6 +283,7 @@ static esp_err_t i2s_register_channel(i2s_controller_t *i2s_obj, i2s_dir_t dir,
new_chan->dma.curr_desc = NULL; new_chan->dma.curr_desc = NULL;
new_chan->start = NULL; new_chan->start = NULL;
new_chan->stop = NULL; new_chan->stop = NULL;
new_chan->reserve_gpio_mask = 0;
if (dir == I2S_DIR_TX) { if (dir == I2S_DIR_TX) {
if (i2s_obj->tx_chan) { if (i2s_obj->tx_chan) {
@ -749,7 +750,42 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag)
return ESP_OK; return ESP_OK;
} }
void i2s_gpio_check_and_set(int gpio, uint32_t signal_idx, bool is_input, bool is_invert) static uint64_t s_i2s_get_pair_chan_gpio_mask(i2s_chan_handle_t handle)
{
if (handle->dir == I2S_DIR_TX) {
return handle->controller->rx_chan ? handle->controller->rx_chan->reserve_gpio_mask : 0;
}
return handle->controller->tx_chan ? handle->controller->tx_chan->reserve_gpio_mask : 0;
}
void i2s_output_gpio_reserve(i2s_chan_handle_t handle, int gpio_num)
{
bool used_by_pair_chan = false;
/* If the gpio is used by the pair channel do not show warning for this case */
if (handle->controller->full_duplex) {
used_by_pair_chan = !!(s_i2s_get_pair_chan_gpio_mask(handle) & BIT64(gpio_num));
}
/* reserve the GPIO output path, because we don't expect another peripheral to signal to the same GPIO */
if (!used_by_pair_chan && (esp_gpio_reserve(BIT64(gpio_num)) & BIT64(gpio_num))) {
ESP_LOGW(TAG, "GPIO %d is not usable, maybe conflict with others", gpio_num);
}
handle->reserve_gpio_mask |= BIT64(gpio_num);
}
void i2s_output_gpio_revoke(i2s_chan_handle_t handle, uint64_t gpio_mask)
{
uint64_t revoke_mask = gpio_mask;
/* If the gpio is used by the pair channel do not show warning for this case */
if (handle->controller->full_duplex) {
uint64_t pair_chan_gpio_mask = s_i2s_get_pair_chan_gpio_mask(handle);
/* Only revoke the gpio which is not used by the pair channel */
revoke_mask = (pair_chan_gpio_mask ^ gpio_mask) & gpio_mask;
}
esp_gpio_revoke(revoke_mask);
handle->reserve_gpio_mask &= ~gpio_mask;
}
void i2s_gpio_check_and_set(i2s_chan_handle_t handle, int gpio, uint32_t signal_idx, bool is_input, bool is_invert)
{ {
/* Ignore the pin if pin = I2S_GPIO_UNUSED */ /* Ignore the pin if pin = I2S_GPIO_UNUSED */
if (gpio != (int)I2S_GPIO_UNUSED) { if (gpio != (int)I2S_GPIO_UNUSED) {
@ -759,15 +795,17 @@ void i2s_gpio_check_and_set(int gpio, uint32_t signal_idx, bool is_input, bool i
gpio_set_direction(gpio, GPIO_MODE_INPUT); gpio_set_direction(gpio, GPIO_MODE_INPUT);
esp_rom_gpio_connect_in_signal(gpio, signal_idx, is_invert); esp_rom_gpio_connect_in_signal(gpio, signal_idx, is_invert);
} else { } else {
i2s_output_gpio_reserve(handle, gpio);
gpio_set_direction(gpio, GPIO_MODE_OUTPUT); gpio_set_direction(gpio, GPIO_MODE_OUTPUT);
esp_rom_gpio_connect_out_signal(gpio, signal_idx, is_invert, 0); esp_rom_gpio_connect_out_signal(gpio, signal_idx, is_invert, 0);
} }
} }
} }
void i2s_gpio_loopback_set(int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx) void i2s_gpio_loopback_set(i2s_chan_handle_t handle, int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx)
{ {
if (gpio != (int)I2S_GPIO_UNUSED) { if (gpio != (int)I2S_GPIO_UNUSED) {
i2s_output_gpio_reserve(handle, gpio);
gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO); gpio_hal_iomux_func_sel(GPIO_PIN_MUX_REG[gpio], PIN_FUNC_GPIO);
gpio_set_direction(gpio, GPIO_MODE_INPUT_OUTPUT); gpio_set_direction(gpio, GPIO_MODE_INPUT_OUTPUT);
esp_rom_gpio_connect_out_signal(gpio, out_sig_idx, 0, 0); esp_rom_gpio_connect_out_signal(gpio, out_sig_idx, 0, 0);
@ -775,7 +813,7 @@ void i2s_gpio_loopback_set(int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx)
} }
} }
esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_src, bool is_invert) esp_err_t i2s_check_set_mclk(i2s_chan_handle_t handle, i2s_port_t id, int gpio_num, i2s_clock_src_t clk_src, bool is_invert)
{ {
if (gpio_num == (int)I2S_GPIO_UNUSED) { if (gpio_num == (int)I2S_GPIO_UNUSED) {
return ESP_OK; return ESP_OK;
@ -784,6 +822,7 @@ esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_sr
bool is_i2s0 = id == I2S_NUM_0; bool is_i2s0 = id == I2S_NUM_0;
bool is_apll = clk_src == I2S_CLK_SRC_APLL; bool is_apll = clk_src == I2S_CLK_SRC_APLL;
if (g_i2s.controller[id]->mclk_out_hdl == NULL) { if (g_i2s.controller[id]->mclk_out_hdl == NULL) {
i2s_output_gpio_reserve(handle, gpio_num);
soc_clkout_sig_id_t clkout_sig = is_apll ? CLKOUT_SIG_APLL : (is_i2s0 ? CLKOUT_SIG_I2S0 : CLKOUT_SIG_I2S1); soc_clkout_sig_id_t clkout_sig = is_apll ? CLKOUT_SIG_APLL : (is_i2s0 ? CLKOUT_SIG_I2S0 : CLKOUT_SIG_I2S1);
ESP_RETURN_ON_ERROR(esp_clock_output_start(clkout_sig, gpio_num, &(g_i2s.controller[id]->mclk_out_hdl)), TAG, "mclk configure failed"); ESP_RETURN_ON_ERROR(esp_clock_output_start(clkout_sig, gpio_num, &(g_i2s.controller[id]->mclk_out_hdl)), TAG, "mclk configure failed");
} }
@ -791,11 +830,11 @@ esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_sr
ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "mck_io_num invalid"); ESP_RETURN_ON_FALSE(GPIO_IS_VALID_GPIO(gpio_num), ESP_ERR_INVALID_ARG, TAG, "mck_io_num invalid");
#if SOC_I2S_HW_VERSION_2 #if SOC_I2S_HW_VERSION_2
if (clk_src == I2S_CLK_SRC_EXTERNAL) { if (clk_src == I2S_CLK_SRC_EXTERNAL) {
i2s_gpio_check_and_set(gpio_num, i2s_periph_signal[id].mck_in_sig, true, is_invert); i2s_gpio_check_and_set(handle, gpio_num, i2s_periph_signal[id].mck_in_sig, true, is_invert);
} else } else
#endif // SOC_I2S_HW_VERSION_2 #endif // SOC_I2S_HW_VERSION_2
{ {
i2s_gpio_check_and_set(gpio_num, i2s_periph_signal[id].mck_out_sig, false, is_invert); i2s_gpio_check_and_set(handle, gpio_num, i2s_periph_signal[id].mck_out_sig, false, is_invert);
} }
#endif // CONFIG_IDF_TARGET_ESP32 #endif // CONFIG_IDF_TARGET_ESP32
ESP_LOGD(TAG, "MCLK is pinned to GPIO%d on I2S%d", gpio_num, id); ESP_LOGD(TAG, "MCLK is pinned to GPIO%d on I2S%d", gpio_num, id);
@ -930,6 +969,9 @@ esp_err_t i2s_del_channel(i2s_chan_handle_t handle)
esp_pm_lock_delete(handle->pm_lock); esp_pm_lock_delete(handle->pm_lock);
} }
#endif #endif
if (handle->reserve_gpio_mask) {
i2s_output_gpio_revoke(handle, handle->reserve_gpio_mask);
}
if (handle->mode_info) { if (handle->mode_info) {
free(handle->mode_info); free(handle->mode_info);
} }

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -132,23 +132,23 @@ static esp_err_t i2s_pdm_tx_set_gpio(i2s_chan_handle_t handle, const i2s_pdm_tx_
ESP_ERR_INVALID_ARG, TAG, "dout gpio is invalid"); ESP_ERR_INVALID_ARG, TAG, "dout gpio is invalid");
i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)handle->mode_info; i2s_pdm_tx_config_t *pdm_tx_cfg = (i2s_pdm_tx_config_t *)handle->mode_info;
/* Set data output GPIO */ /* Set data output GPIO */
i2s_gpio_check_and_set(gpio_cfg->dout, i2s_periph_signal[id].data_out_sig, false, false); i2s_gpio_check_and_set(handle, gpio_cfg->dout, i2s_periph_signal[id].data_out_sig, false, false);
#if SOC_I2S_PDM_MAX_TX_LINES > 1 #if SOC_I2S_PDM_MAX_TX_LINES > 1
if (pdm_tx_cfg->slot_cfg.line_mode == I2S_PDM_TX_TWO_LINE_DAC) { if (pdm_tx_cfg->slot_cfg.line_mode == I2S_PDM_TX_TWO_LINE_DAC) {
i2s_gpio_check_and_set(gpio_cfg->dout2, i2s_periph_signal[id].data_out_sigs[1], false, false); i2s_gpio_check_and_set(handle, gpio_cfg->dout2, i2s_periph_signal[id].data_out_sigs[1], false, false);
} }
#endif #endif
if (handle->role == I2S_ROLE_SLAVE) { if (handle->role == I2S_ROLE_SLAVE) {
/* For "tx + slave" mode, select TX signal index for ws and bck */ /* For "tx + slave" mode, select TX signal index for ws and bck */
if (!handle->controller->full_duplex) { if (!handle->controller->full_duplex) {
i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].s_tx_ws_sig, true, gpio_cfg->invert_flags.clk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->clk, i2s_periph_signal[id].s_tx_ws_sig, true, gpio_cfg->invert_flags.clk_inv);
/* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */ /* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */
} else { } else {
i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].s_rx_ws_sig, true, gpio_cfg->invert_flags.clk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->clk, i2s_periph_signal[id].s_rx_ws_sig, true, gpio_cfg->invert_flags.clk_inv);
} }
} else { } else {
i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].m_tx_ws_sig, false, gpio_cfg->invert_flags.clk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->clk, i2s_periph_signal[id].m_tx_ws_sig, false, gpio_cfg->invert_flags.clk_inv);
} }
#if SOC_I2S_HW_VERSION_2 #if SOC_I2S_HW_VERSION_2
I2S_CLOCK_SRC_ATOMIC() { I2S_CLOCK_SRC_ATOMIC() {
@ -311,6 +311,9 @@ esp_err_t i2s_channel_reconfig_pdm_tx_gpio(i2s_chan_handle_t handle, const i2s_p
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode"); ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio"); ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio");
if (handle->reserve_gpio_mask) {
i2s_output_gpio_revoke(handle, handle->reserve_gpio_mask);
}
ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed"); ESP_GOTO_ON_ERROR(i2s_pdm_tx_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
xSemaphoreGive(handle->mutex); xSemaphoreGive(handle->mutex);
@ -422,21 +425,21 @@ static esp_err_t i2s_pdm_rx_set_gpio(i2s_chan_handle_t handle, const i2s_pdm_rx_
#if SOC_I2S_PDM_MAX_RX_LINES > 1 #if SOC_I2S_PDM_MAX_RX_LINES > 1
for (int i = 0; i < SOC_I2S_PDM_MAX_RX_LINES; i++) { for (int i = 0; i < SOC_I2S_PDM_MAX_RX_LINES; i++) {
if (pdm_rx_cfg->slot_cfg.slot_mask & (0x03 << (i * 2))) { if (pdm_rx_cfg->slot_cfg.slot_mask & (0x03 << (i * 2))) {
i2s_gpio_check_and_set(gpio_cfg->dins[i], i2s_periph_signal[id].data_in_sigs[i], true, false); i2s_gpio_check_and_set(handle, gpio_cfg->dins[i], i2s_periph_signal[id].data_in_sigs[i], true, false);
} }
} }
#else #else
i2s_gpio_check_and_set(gpio_cfg->din, i2s_periph_signal[id].data_in_sig, true, false); i2s_gpio_check_and_set(handle, gpio_cfg->din, i2s_periph_signal[id].data_in_sig, true, false);
#endif #endif
if (handle->role == I2S_ROLE_SLAVE) { if (handle->role == I2S_ROLE_SLAVE) {
/* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */ /* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */
i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].s_rx_ws_sig, true, gpio_cfg->invert_flags.clk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->clk, i2s_periph_signal[id].s_rx_ws_sig, true, gpio_cfg->invert_flags.clk_inv);
} else { } else {
if (!handle->controller->full_duplex) { if (!handle->controller->full_duplex) {
i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].m_rx_ws_sig, false, gpio_cfg->invert_flags.clk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->clk, i2s_periph_signal[id].m_rx_ws_sig, false, gpio_cfg->invert_flags.clk_inv);
} else { } else {
i2s_gpio_check_and_set(gpio_cfg->clk, i2s_periph_signal[id].m_tx_ws_sig, false, gpio_cfg->invert_flags.clk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->clk, i2s_periph_signal[id].m_tx_ws_sig, false, gpio_cfg->invert_flags.clk_inv);
} }
} }
#if SOC_I2S_HW_VERSION_2 #if SOC_I2S_HW_VERSION_2
@ -595,6 +598,9 @@ esp_err_t i2s_channel_reconfig_pdm_rx_gpio(i2s_chan_handle_t handle, const i2s_p
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode"); ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_PDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio"); ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio");
if (handle->reserve_gpio_mask) {
i2s_output_gpio_revoke(handle, handle->reserve_gpio_mask);
}
ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed"); ESP_GOTO_ON_ERROR(i2s_pdm_rx_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
xSemaphoreGive(handle->mutex); xSemaphoreGive(handle->mutex);

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -20,6 +20,7 @@
#include "esp_private/gdma.h" #include "esp_private/gdma.h"
#endif #endif
#include "esp_private/periph_ctrl.h" #include "esp_private/periph_ctrl.h"
#include "esp_private/esp_gpio_reserve.h"
#include "esp_pm.h" #include "esp_pm.h"
#include "esp_err.h" #include "esp_err.h"
#include "sdkconfig.h" #include "sdkconfig.h"
@ -146,6 +147,7 @@ struct i2s_channel_obj_t {
esp_pm_lock_handle_t pm_lock; /*!< Power management lock, to avoid apb clock frequency changes while i2s is working */ esp_pm_lock_handle_t pm_lock; /*!< Power management lock, to avoid apb clock frequency changes while i2s is working */
#endif #endif
QueueHandle_t msg_queue; /*!< Message queue handler, used for transporting data between interrupt and read/write task */ QueueHandle_t msg_queue; /*!< Message queue handler, used for transporting data between interrupt and read/write task */
uint64_t reserve_gpio_mask; /*!< The gpio mask that has been reserved by I2S */
i2s_event_callbacks_internal_t callbacks; /*!< Callback functions */ i2s_event_callbacks_internal_t callbacks; /*!< Callback functions */
void *user_data; /*!< User data for callback functions */ void *user_data; /*!< User data for callback functions */
void (*start)(i2s_chan_handle_t); /*!< start tx/rx channel */ void (*start)(i2s_chan_handle_t); /*!< start tx/rx channel */
@ -224,16 +226,18 @@ uint32_t i2s_get_source_clk_freq(i2s_clock_src_t clk_src, uint32_t mclk_freq_hz)
/** /**
* @brief Check gpio validity and attach to corresponding signal * @brief Check gpio validity and attach to corresponding signal
* *
* @param handle I2S channel handle
* @param gpio GPIO number * @param gpio GPIO number
* @param signal_idx Signal index * @param signal_idx Signal index
* @param is_input Is input gpio * @param is_input Is input gpio
* @param is_invert Is invert gpio * @param is_invert Is invert gpio
*/ */
void i2s_gpio_check_and_set(int gpio, uint32_t signal_idx, bool is_input, bool is_invert); void i2s_gpio_check_and_set(i2s_chan_handle_t handle, int gpio, uint32_t signal_idx, bool is_input, bool is_invert);
/** /**
* @brief Check gpio validity and output mclk signal * @brief Check gpio validity and output mclk signal
* *
* @param handle I2S channel handle
* @param id I2S port id * @param id I2S port id
* @param gpio_num GPIO number * @param gpio_num GPIO number
* @param clk_src The clock source of this I2S port * @param clk_src The clock source of this I2S port
@ -242,16 +246,33 @@ void i2s_gpio_check_and_set(int gpio, uint32_t signal_idx, bool is_input, bool i
* - ESP_OK Set mclk output gpio success * - ESP_OK Set mclk output gpio success
* - ESP_ERR_INVALID_ARG Invalid GPIO number * - ESP_ERR_INVALID_ARG Invalid GPIO number
*/ */
esp_err_t i2s_check_set_mclk(i2s_port_t id, int gpio_num, i2s_clock_src_t clk_src, bool is_invert); esp_err_t i2s_check_set_mclk(i2s_chan_handle_t handle, i2s_port_t id, int gpio_num, i2s_clock_src_t clk_src, bool is_invert);
/** /**
* @brief Attach data out signal and data in signal to a same gpio * @brief Attach data out signal and data in signal to a same gpio
* *
* @param handle I2S channel handle
* @param gpio GPIO number * @param gpio GPIO number
* @param out_sig_idx Data out signal index * @param out_sig_idx Data out signal index
* @param in_sig_idx Data in signal index * @param in_sig_idx Data in signal index
*/ */
void i2s_gpio_loopback_set(int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx); void i2s_gpio_loopback_set(i2s_chan_handle_t handle, int gpio, uint32_t out_sig_idx, uint32_t in_sig_idx);
/**
* @brief Reserve the GPIO that configured as I2S output signal
*
* @param handle I2S channel handle
* @param gpio_num The output gpio number to be reserved
*/
void i2s_output_gpio_reserve(i2s_chan_handle_t handle, int gpio_num);
/**
* @brief Revoke the GPIO that configured as I2S output signal
*
* @param handle I2S channel handle
* @param gpio_mask The output gpio mask to be revoked
*/
void i2s_output_gpio_revoke(i2s_chan_handle_t handle, uint64_t gpio_mask);
#ifdef __cplusplus #ifdef __cplusplus
} }

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -145,20 +145,19 @@ static esp_err_t i2s_std_set_gpio(i2s_chan_handle_t handle, const i2s_std_gpio_c
ESP_RETURN_ON_FALSE((gpio_cfg->ws == -1 || GPIO_IS_VALID_GPIO(gpio_cfg->ws)), ESP_RETURN_ON_FALSE((gpio_cfg->ws == -1 || GPIO_IS_VALID_GPIO(gpio_cfg->ws)),
ESP_ERR_INVALID_ARG, TAG, "ws invalid"); ESP_ERR_INVALID_ARG, TAG, "ws invalid");
i2s_std_config_t *std_cfg = (i2s_std_config_t *)(handle->mode_info); i2s_std_config_t *std_cfg = (i2s_std_config_t *)(handle->mode_info);
/* Loopback if dout = din */ /* Loopback if dout = din */
if (gpio_cfg->dout != -1 && gpio_cfg->dout == gpio_cfg->din) { if (gpio_cfg->dout != -1 && gpio_cfg->dout == gpio_cfg->din) {
i2s_gpio_loopback_set(gpio_cfg->dout, i2s_periph_signal[id].data_out_sig, i2s_periph_signal[id].data_in_sig); i2s_gpio_loopback_set(handle, gpio_cfg->dout, i2s_periph_signal[id].data_out_sig, i2s_periph_signal[id].data_in_sig);
} else if (handle->dir == I2S_DIR_TX) { } else if (handle->dir == I2S_DIR_TX) {
/* Set data output GPIO */ /* Set data output GPIO */
i2s_gpio_check_and_set(gpio_cfg->dout, i2s_periph_signal[id].data_out_sig, false, false); i2s_gpio_check_and_set(handle, gpio_cfg->dout, i2s_periph_signal[id].data_out_sig, false, false);
} else { } else {
/* Set data input GPIO */ /* Set data input GPIO */
i2s_gpio_check_and_set(gpio_cfg->din, i2s_periph_signal[id].data_in_sig, true, false); i2s_gpio_check_and_set(handle, gpio_cfg->din, i2s_periph_signal[id].data_in_sig, true, false);
} }
/* Set mclk pin */ /* Set mclk pin */
ESP_RETURN_ON_ERROR(i2s_check_set_mclk(id, gpio_cfg->mclk, std_cfg->clk_cfg.clk_src, gpio_cfg->invert_flags.mclk_inv), TAG, "mclk config failed"); ESP_RETURN_ON_ERROR(i2s_check_set_mclk(handle, id, gpio_cfg->mclk, std_cfg->clk_cfg.clk_src, gpio_cfg->invert_flags.mclk_inv), TAG, "mclk config failed");
if (handle->role == I2S_ROLE_SLAVE) { if (handle->role == I2S_ROLE_SLAVE) {
/* For "tx + slave" mode, select TX signal index for ws and bck */ /* For "tx + slave" mode, select TX signal index for ws and bck */
@ -168,12 +167,12 @@ static esp_err_t i2s_std_set_gpio(i2s_chan_handle_t handle, const i2s_std_gpio_c
i2s_ll_mclk_bind_to_tx_clk(handle->controller->hal.dev); i2s_ll_mclk_bind_to_tx_clk(handle->controller->hal.dev);
} }
#endif #endif
i2s_gpio_check_and_set(gpio_cfg->ws, i2s_periph_signal[id].s_tx_ws_sig, true, gpio_cfg->invert_flags.ws_inv); i2s_gpio_check_and_set(handle, gpio_cfg->ws, i2s_periph_signal[id].s_tx_ws_sig, true, gpio_cfg->invert_flags.ws_inv);
i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].s_tx_bck_sig, true, gpio_cfg->invert_flags.bclk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->bclk, i2s_periph_signal[id].s_tx_bck_sig, true, gpio_cfg->invert_flags.bclk_inv);
/* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */ /* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */
} else { } else {
i2s_gpio_check_and_set(gpio_cfg->ws, i2s_periph_signal[id].s_rx_ws_sig, true, gpio_cfg->invert_flags.ws_inv); i2s_gpio_check_and_set(handle, gpio_cfg->ws, i2s_periph_signal[id].s_rx_ws_sig, true, gpio_cfg->invert_flags.ws_inv);
i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].s_rx_bck_sig, true, gpio_cfg->invert_flags.bclk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->bclk, i2s_periph_signal[id].s_rx_bck_sig, true, gpio_cfg->invert_flags.bclk_inv);
} }
} else { } else {
/* For "rx + master" mode, select RX signal index for ws and bck */ /* For "rx + master" mode, select RX signal index for ws and bck */
@ -183,12 +182,12 @@ static esp_err_t i2s_std_set_gpio(i2s_chan_handle_t handle, const i2s_std_gpio_c
i2s_ll_mclk_bind_to_rx_clk(handle->controller->hal.dev); i2s_ll_mclk_bind_to_rx_clk(handle->controller->hal.dev);
} }
#endif #endif
i2s_gpio_check_and_set(gpio_cfg->ws, i2s_periph_signal[id].m_rx_ws_sig, false, gpio_cfg->invert_flags.ws_inv); i2s_gpio_check_and_set(handle, gpio_cfg->ws, i2s_periph_signal[id].m_rx_ws_sig, false, gpio_cfg->invert_flags.ws_inv);
i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].m_rx_bck_sig, false, gpio_cfg->invert_flags.bclk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->bclk, i2s_periph_signal[id].m_rx_bck_sig, false, gpio_cfg->invert_flags.bclk_inv);
/* For "tx + rx + master" or "tx + master" mode, select TX signal index for ws and bck */ /* For "tx + rx + master" or "tx + master" mode, select TX signal index for ws and bck */
} else { } else {
i2s_gpio_check_and_set(gpio_cfg->ws, i2s_periph_signal[id].m_tx_ws_sig, false, gpio_cfg->invert_flags.ws_inv); i2s_gpio_check_and_set(handle, gpio_cfg->ws, i2s_periph_signal[id].m_tx_ws_sig, false, gpio_cfg->invert_flags.ws_inv);
i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].m_tx_bck_sig, false, gpio_cfg->invert_flags.bclk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->bclk, i2s_periph_signal[id].m_tx_bck_sig, false, gpio_cfg->invert_flags.bclk_inv);
} }
} }
/* Update the mode info: gpio configuration */ /* Update the mode info: gpio configuration */
@ -349,6 +348,9 @@ esp_err_t i2s_channel_reconfig_std_gpio(i2s_chan_handle_t handle, const i2s_std_
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_STD, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode"); ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_STD, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio"); ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio");
if (handle->reserve_gpio_mask) {
i2s_output_gpio_revoke(handle, handle->reserve_gpio_mask);
}
ESP_GOTO_ON_ERROR(i2s_std_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed"); ESP_GOTO_ON_ERROR(i2s_std_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
xSemaphoreGive(handle->mutex); xSemaphoreGive(handle->mutex);

View File

@ -1,5 +1,5 @@
/* /*
* SPDX-FileCopyrightText: 2022-2023 Espressif Systems (Shanghai) CO LTD * SPDX-FileCopyrightText: 2022-2024 Espressif Systems (Shanghai) CO LTD
* *
* SPDX-License-Identifier: Apache-2.0 * SPDX-License-Identifier: Apache-2.0
*/ */
@ -153,17 +153,17 @@ static esp_err_t i2s_tdm_set_gpio(i2s_chan_handle_t handle, const i2s_tdm_gpio_c
/* Loopback if dout = din */ /* Loopback if dout = din */
if (gpio_cfg->dout != -1 && if (gpio_cfg->dout != -1 &&
gpio_cfg->dout == gpio_cfg->din) { gpio_cfg->dout == gpio_cfg->din) {
i2s_gpio_loopback_set(gpio_cfg->dout, i2s_periph_signal[id].data_out_sig, i2s_periph_signal[id].data_in_sig); i2s_gpio_loopback_set(handle, gpio_cfg->dout, i2s_periph_signal[id].data_out_sig, i2s_periph_signal[id].data_in_sig);
} else if (handle->dir == I2S_DIR_TX) { } else if (handle->dir == I2S_DIR_TX) {
/* Set data output GPIO */ /* Set data output GPIO */
i2s_gpio_check_and_set(gpio_cfg->dout, i2s_periph_signal[id].data_out_sig, false, false); i2s_gpio_check_and_set(handle, gpio_cfg->dout, i2s_periph_signal[id].data_out_sig, false, false);
} else { } else {
/* Set data input GPIO */ /* Set data input GPIO */
i2s_gpio_check_and_set(gpio_cfg->din, i2s_periph_signal[id].data_in_sig, true, false); i2s_gpio_check_and_set(handle, gpio_cfg->din, i2s_periph_signal[id].data_in_sig, true, false);
} }
/* Set mclk pin */ /* Set mclk pin */
ESP_RETURN_ON_ERROR(i2s_check_set_mclk(id, gpio_cfg->mclk, tdm_cfg->clk_cfg.clk_src, gpio_cfg->invert_flags.mclk_inv), TAG, "mclk config failed"); ESP_RETURN_ON_ERROR(i2s_check_set_mclk(handle, id, gpio_cfg->mclk, tdm_cfg->clk_cfg.clk_src, gpio_cfg->invert_flags.mclk_inv), TAG, "mclk config failed");
if (handle->role == I2S_ROLE_SLAVE) { if (handle->role == I2S_ROLE_SLAVE) {
/* For "tx + slave" mode, select TX signal index for ws and bck */ /* For "tx + slave" mode, select TX signal index for ws and bck */
@ -173,12 +173,12 @@ static esp_err_t i2s_tdm_set_gpio(i2s_chan_handle_t handle, const i2s_tdm_gpio_c
i2s_ll_mclk_bind_to_tx_clk(handle->controller->hal.dev); i2s_ll_mclk_bind_to_tx_clk(handle->controller->hal.dev);
} }
#endif #endif
i2s_gpio_check_and_set(gpio_cfg->ws, i2s_periph_signal[id].s_tx_ws_sig, true, gpio_cfg->invert_flags.ws_inv); i2s_gpio_check_and_set(handle, gpio_cfg->ws, i2s_periph_signal[id].s_tx_ws_sig, true, gpio_cfg->invert_flags.ws_inv);
i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].s_tx_bck_sig, true, gpio_cfg->invert_flags.bclk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->bclk, i2s_periph_signal[id].s_tx_bck_sig, true, gpio_cfg->invert_flags.bclk_inv);
/* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */ /* For "tx + rx + slave" or "rx + slave" mode, select RX signal index for ws and bck */
} else { } else {
i2s_gpio_check_and_set(gpio_cfg->ws, i2s_periph_signal[id].s_rx_ws_sig, true, gpio_cfg->invert_flags.ws_inv); i2s_gpio_check_and_set(handle, gpio_cfg->ws, i2s_periph_signal[id].s_rx_ws_sig, true, gpio_cfg->invert_flags.ws_inv);
i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].s_rx_bck_sig, true, gpio_cfg->invert_flags.bclk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->bclk, i2s_periph_signal[id].s_rx_bck_sig, true, gpio_cfg->invert_flags.bclk_inv);
} }
} else { } else {
/* For "rx + master" mode, select RX signal index for ws and bck */ /* For "rx + master" mode, select RX signal index for ws and bck */
@ -188,12 +188,12 @@ static esp_err_t i2s_tdm_set_gpio(i2s_chan_handle_t handle, const i2s_tdm_gpio_c
i2s_ll_mclk_bind_to_rx_clk(handle->controller->hal.dev); i2s_ll_mclk_bind_to_rx_clk(handle->controller->hal.dev);
} }
#endif #endif
i2s_gpio_check_and_set(gpio_cfg->ws, i2s_periph_signal[id].m_rx_ws_sig, false, gpio_cfg->invert_flags.ws_inv); i2s_gpio_check_and_set(handle, gpio_cfg->ws, i2s_periph_signal[id].m_rx_ws_sig, false, gpio_cfg->invert_flags.ws_inv);
i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].m_rx_bck_sig, false, gpio_cfg->invert_flags.bclk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->bclk, i2s_periph_signal[id].m_rx_bck_sig, false, gpio_cfg->invert_flags.bclk_inv);
/* For "tx + rx + master" or "tx + master" mode, select TX signal index for ws and bck */ /* For "tx + rx + master" or "tx + master" mode, select TX signal index for ws and bck */
} else { } else {
i2s_gpio_check_and_set(gpio_cfg->ws, i2s_periph_signal[id].m_tx_ws_sig, false, gpio_cfg->invert_flags.ws_inv); i2s_gpio_check_and_set(handle, gpio_cfg->ws, i2s_periph_signal[id].m_tx_ws_sig, false, gpio_cfg->invert_flags.ws_inv);
i2s_gpio_check_and_set(gpio_cfg->bclk, i2s_periph_signal[id].m_tx_bck_sig, false, gpio_cfg->invert_flags.bclk_inv); i2s_gpio_check_and_set(handle, gpio_cfg->bclk, i2s_periph_signal[id].m_tx_bck_sig, false, gpio_cfg->invert_flags.bclk_inv);
} }
} }
/* Update the mode info: gpio configuration */ /* Update the mode info: gpio configuration */
@ -357,6 +357,9 @@ esp_err_t i2s_channel_reconfig_tdm_gpio(i2s_chan_handle_t handle, const i2s_tdm_
ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_TDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode"); ESP_GOTO_ON_FALSE(handle->mode == I2S_COMM_MODE_TDM, ESP_ERR_INVALID_ARG, err, TAG, "This handle is not working in standard mode");
ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio"); ESP_GOTO_ON_FALSE(handle->state == I2S_CHAN_STATE_READY, ESP_ERR_INVALID_STATE, err, TAG, "Invalid state, I2S should be disabled before reconfiguring the gpio");
if (handle->reserve_gpio_mask) {
i2s_output_gpio_revoke(handle, handle->reserve_gpio_mask);
}
ESP_GOTO_ON_ERROR(i2s_tdm_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed"); ESP_GOTO_ON_ERROR(i2s_tdm_set_gpio(handle, gpio_cfg), err, TAG, "set i2s standard slot failed");
xSemaphoreGive(handle->mutex); xSemaphoreGive(handle->mutex);