Merge branch 'bugfix/check_i2s_intr_alloc_failure_v5.3' into 'release/v5.3'

fix(i2s): check gdma callback register state and add missed port2 on p4 (v5.3)

See merge request espressif/esp-idf!31426
This commit is contained in:
Michael (XIAO Xufeng)
2024-06-12 02:21:20 +08:00
4 changed files with 51 additions and 9 deletions

View File

@ -348,14 +348,22 @@ static esp_err_t i2s_dma_intr_init(i2s_port_t i2s_num, int intr_flag)
gdma_trigger_t trig = {.periph = GDMA_TRIG_PERIPH_I2S};
switch (i2s_num) {
#if SOC_I2S_NUM > 2
case I2S_NUM_2:
trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S2;
break;
#endif
#if SOC_I2S_NUM > 1
case I2S_NUM_1:
trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S1;
break;
#endif
default:
case I2S_NUM_0:
trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S0;
break;
default:
ESP_LOGE(TAG, "Unsupported I2S port number");
return ESP_ERR_NOT_SUPPORTED;
}
/* Set GDMA config */

View File

@ -696,6 +696,7 @@ static void IRAM_ATTR i2s_dma_tx_callback(void *arg)
*/
esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag)
{
esp_err_t ret = ESP_OK;
i2s_port_t port_id = handle->controller->id;
ESP_RETURN_ON_FALSE((port_id >= 0) && (port_id < SOC_I2S_NUM), ESP_ERR_INVALID_ARG, TAG, "invalid handle");
#if SOC_GDMA_SUPPORTED
@ -703,14 +704,22 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag)
gdma_trigger_t trig = {.periph = GDMA_TRIG_PERIPH_I2S};
switch (port_id) {
#if SOC_I2S_NUM > 2
case I2S_NUM_2:
trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S2;
break;
#endif
#if SOC_I2S_NUM > 1
case I2S_NUM_1:
trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S1;
break;
#endif
default:
case I2S_NUM_0:
trig.instance_id = SOC_GDMA_TRIG_PERIPH_I2S0;
break;
default:
ESP_LOGE(TAG, "Unsupported I2S port number");
return ESP_ERR_NOT_SUPPORTED;
}
/* Set GDMA config */
@ -719,18 +728,18 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag)
dma_cfg.direction = GDMA_CHANNEL_DIRECTION_TX;
/* Register a new GDMA tx channel */
ESP_RETURN_ON_ERROR(gdma_new_channel(&dma_cfg, &handle->dma.dma_chan), TAG, "Register tx dma channel error");
ESP_RETURN_ON_ERROR(gdma_connect(handle->dma.dma_chan, trig), TAG, "Connect tx dma channel error");
ESP_GOTO_ON_ERROR(gdma_connect(handle->dma.dma_chan, trig), err1, TAG, "Connect tx dma channel error");
gdma_tx_event_callbacks_t cb = {.on_trans_eof = i2s_dma_tx_callback};
/* Set callback function for GDMA, the interrupt is triggered by GDMA, then the GDMA ISR will call the callback function */
gdma_register_tx_event_callbacks(handle->dma.dma_chan, &cb, handle);
ESP_GOTO_ON_ERROR(gdma_register_tx_event_callbacks(handle->dma.dma_chan, &cb, handle), err2, TAG, "Register tx callback failed");
} else {
dma_cfg.direction = GDMA_CHANNEL_DIRECTION_RX;
/* Register a new GDMA rx channel */
ESP_RETURN_ON_ERROR(gdma_new_channel(&dma_cfg, &handle->dma.dma_chan), TAG, "Register rx dma channel error");
ESP_RETURN_ON_ERROR(gdma_connect(handle->dma.dma_chan, trig), TAG, "Connect rx dma channel error");
ESP_GOTO_ON_ERROR(gdma_connect(handle->dma.dma_chan, trig), err1, TAG, "Connect rx dma channel error");
gdma_rx_event_callbacks_t cb = {.on_recv_eof = i2s_dma_rx_callback};
/* Set callback function for GDMA, the interrupt is triggered by GDMA, then the GDMA ISR will call the callback function */
gdma_register_rx_event_callbacks(handle->dma.dma_chan, &cb, handle);
ESP_GOTO_ON_ERROR(gdma_register_rx_event_callbacks(handle->dma.dma_chan, &cb, handle), err2, TAG, "Register rx callback failed");
}
#else
intr_flag |= handle->intr_prio_flags;
@ -747,7 +756,15 @@ esp_err_t i2s_init_dma_intr(i2s_chan_handle_t handle, int intr_flag)
/* Start DMA */
i2s_ll_enable_dma(handle->controller->hal.dev, true);
#endif // SOC_GDMA_SUPPORTED
return ESP_OK;
return ret;
#if SOC_GDMA_SUPPORTED
err2:
gdma_disconnect(handle->dma.dma_chan);
err1:
gdma_del_channel(handle->dma.dma_chan);
handle->dma.dma_chan = NULL;
return ret;
#endif
}
static uint64_t s_i2s_get_pair_chan_gpio_mask(i2s_chan_handle_t handle)

View File

@ -22,6 +22,9 @@ typedef enum {
I2S_NUM_0 = 0, /*!< I2S controller port 0 */
#if SOC_I2S_NUM > 1
I2S_NUM_1 = 1, /*!< I2S controller port 1 */
#endif
#if SOC_I2S_NUM > 2
I2S_NUM_2 = 2, /*!< I2S controller port 2 */
#endif
I2S_NUM_AUTO, /*!< Select whichever port is available */
} i2s_port_t;

View File

@ -190,7 +190,21 @@ TEST_CASE("I2S_basic_channel_allocation_reconfig_deleting_test", "[i2s]")
TEST_ESP_OK(i2s_channel_enable(tx_handle));
TEST_ESP_OK(i2s_channel_disable(tx_handle));
TEST_ESP_OK(i2s_del_channel(tx_handle));
TEST_ASSERT(i2s_channel_get_info(tx_handle, &chan_info) == ESP_ERR_NOT_FOUND);
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, i2s_channel_get_info(tx_handle, &chan_info));
/* Exhaust test */
std_cfg.gpio_cfg.mclk = -1;
i2s_chan_handle_t tx_ex[SOC_I2S_NUM] = {};
for (int i = 0; i < SOC_I2S_NUM; i++) {
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_ex[i], NULL));
TEST_ESP_OK(i2s_channel_init_std_mode(tx_ex[i], &std_cfg));
TEST_ESP_OK(i2s_channel_enable(tx_ex[i]));
}
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, i2s_new_channel(&chan_cfg, &tx_handle, NULL));
for (int i = 0; i < SOC_I2S_NUM; i++) {
TEST_ESP_OK(i2s_channel_disable(tx_ex[i]));
TEST_ESP_OK(i2s_del_channel(tx_ex[i]));
}
/* Duplex channel basic test */
chan_cfg.id = I2S_NUM_0; // Specify port id to I2S port 0
@ -208,7 +222,7 @@ TEST_CASE("I2S_basic_channel_allocation_reconfig_deleting_test", "[i2s]")
/* Hold the occupation */
TEST_ESP_OK(i2s_platform_acquire_occupation(I2S_NUM_0, "test_i2s"));
TEST_ASSERT(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle) == ESP_ERR_NOT_FOUND);
TEST_ESP_ERR(ESP_ERR_NOT_FOUND, i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
TEST_ESP_OK(i2s_platform_release_occupation(I2S_NUM_0));
TEST_ESP_OK(i2s_new_channel(&chan_cfg, &tx_handle, &rx_handle));
TEST_ESP_OK(i2s_del_channel(tx_handle));