mirror of
https://github.com/espressif/esp-idf.git
synced 2024-10-05 20:47:46 -04:00
feat(i2s): support i2s gpio reservation
This commit is contained in:
parent
f1babb9074
commit
e4f28fcb7f
@ -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);
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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
|
||||||
}
|
}
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
@ -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);
|
||||||
|
|
||||||
|
Loading…
Reference in New Issue
Block a user