I2S Input DMA setup

dawime
Posts: 6
Joined: Sat Aug 13, 2022 7:35 pm

I2S Input DMA setup

Postby dawime » Sun Mar 19, 2023 10:41 pm

Hello - I am trying to interface a mems I2C microphone to I2S0 - I have verified that the device is clocking and outputing data - The idea is to setup DMA buffers, to trigger an interrupt when DMA is complete, from the DMA ISR signal a task that will read out the last buffer, process it and notify other consumers for that data.

My problem seems to be that the DMA ISR is not getting set. I checked that the semaphores are setup properly, but I can't quite figure it out. Here is the code:

Code: mic.c Select all



static int16_t dma_buf[DMA_BUF_COUNT][DMA_BUF_LEN];
static int buf_ptr = 0;
SemaphoreHandle_t i2s_dma_sem;
static intr_handle_t i2s_isr_ret_handle;

void IRAM_ATTR i2s_isr_handler(void *arg)
{
BaseType_t xHigherPriorityTaskWoken = pdFALSE;

xSemaphoreGiveFromISR(i2s_dma_sem, &xHigherPriorityTaskWoken);
if (xHigherPriorityTaskWoken) {
portYIELD_FROM_ISR();
}
}


void mic_task(void *arg)
{
size_t bytesRead;
color_t sample_colors[6] = { red, green, blue, yellow, purple, silver };
printf("mic_task enabled\n\r");
while (1)
{
if (xSemaphoreTake(i2s_dma_sem, portMAX_DELAY) == pdTRUE) {
// Process the data in dma_buf[buf_ptr]
// ...
i2s_read(I2S_NUM, (void *)&dma_buf[buf_ptr], DMA_BUF_LEN * sizeof(int16_t), &bytesRead, 0);
buf_ptr = (buf_ptr + 1) % DMA_BUF_COUNT;
printf("Read %d bytes",bytesRead);

// Signal the main application that new data is available
// ...
}
}
}

void mic_init()
{
i2s_config_t i2s_config = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX,
.sample_rate = 44100,
.bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,
.channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
.communication_format = I2S_COMM_FORMAT_I2S_MSB,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
.dma_buf_count = DMA_BUF_COUNT,
.dma_buf_len = DMA_BUF_LEN,
.use_apll = false,
.tx_desc_auto_clear = false,
.fixed_mclk = 0,


};
i2s_driver_install(I2S_NUM, &i2s_config, 0, NULL);
i2s_set_clk(I2S_NUM, 44100, I2S_BITS_PER_SAMPLE_16BIT, I2S_CHANNEL_MONO);
i2s_pin_config_t pin_config = {
.mck_io_num = I2S_PIN_NO_CHANGE,
.bck_io_num = 3,
.ws_io_num = I2S_PIN_NO_CHANGE,
.data_out_num = I2S_PIN_NO_CHANGE,
.data_in_num = 8
};
i2s_set_pin(I2S_NUM, &pin_config);
i2s_zero_dma_buffer(I2S_NUM);

i2s_dma_sem = xSemaphoreCreateBinary();
esp_err_t err =esp_intr_alloc(ETS_I2S0_INTR_SOURCE, ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM, i2s_isr_handler, NULL, &i2s_isr_ret_handle);
if (err != ESP_OK)
ESP_LOGE(TAG, "Error esp_intr_alloc %s", esp_err_to_name(err));


err = esp_intr_enable(i2s_isr_ret_handle);
ESP_LOGI(TAG, "INTERRUPT Enable: %d ", err);
xTaskCreate(mic_task, "mic_task", 4096, NULL, 5, NULL);

}
Any ideas why i2s_isr_handler does not get called? Both esp_intr_alloc() and esp_intr_enable() return ESP_OK.

Thank you

Sprite
Espressif staff
Espressif staff
Posts: 10593
Joined: Thu Nov 26, 2015 4:08 am

Re: I2S Input DMA setup

Postby Sprite » Mon Mar 20, 2023 12:38 am

You cannot use both the driver as well as install your own ISR, and in your particular case, you don't need to. i2s_read() already suspends the calling task until the i2s peripheral has data available (that's why the driver needs the interrupt, it uses that to unblock the task calling i2s_read).

dawime
Posts: 6
Joined: Sat Aug 13, 2022 7:35 pm

Re: I2S Input DMA setup

Postby dawime » Mon Mar 20, 2023 2:36 pm

Thank you - I couldn't locate any documentation on it, but it makes sense. If the read will be blocking already, then I can forgo my interrupt and just running it on my thread directly.

Who is online

Users browsing this forum: Bing [Bot], PetalBot, YisouSpider and 7 guests