Sample I2S audio in an ISR
Posted: Fri Mar 29, 2019 9:09 pm
Hello,
Sampling I2S audio from an ics43434 is trivial enough polling away using i2S_read to a buffer w/in a while loop. However, I am surprised to see that I have been unsuccessful sampling i2s audio using an ISR. Furthermore, I see no examples of doing this on the internet! To be clear, I mean setting up a I2S(1 or 0) as Master to receive on various GPIO pins then scheduling and ISR (eg: w/ esp_intr_alloc) and finally -- DOING THE i2s_read IN THE ISR!
I've cobbled together some code that looks like it should work, but I hit some stubborn points using esp_intr_alloc. I humbly post the following for your consideration:
So what happens? Output>
No free interrupt found with the specified flags
Okay, so what interrupt should I be using? I have also tried or'ing in ESP_INTR_FLAG_SHARED
Thx,
QC
*I am using the esp32_win32_msys2_environment_and_toolchain-20170918 on Windows (mingw32).
Sampling I2S audio from an ics43434 is trivial enough polling away using i2S_read to a buffer w/in a while loop. However, I am surprised to see that I have been unsuccessful sampling i2s audio using an ISR. Furthermore, I see no examples of doing this on the internet! To be clear, I mean setting up a I2S(1 or 0) as Master to receive on various GPIO pins then scheduling and ISR (eg: w/ esp_intr_alloc) and finally -- DOING THE i2s_read IN THE ISR!
I've cobbled together some code that looks like it should work, but I hit some stubborn points using esp_intr_alloc. I humbly post the following for your consideration:
Code: Select all
#define LOG_LOCAL_LEVEL ESP_LOG_VERBOSE
#include "ics43434.h"
#include "buffer.h"
#include "esp_err.h"
#include "esp_log.h"
#include "driver/i2s.h"
#include <errno.h>
/** ISR **/
static void IRAM_ATTR dmaInt(void* arg) {
uint32_t numBytesRead = 0;
//this is an isr, there should be a i2s_event ready for us, so DON'T WAIT!
if (i2s_read(I2S_NUM_1, Buffer::getCurrent(), DMA_SIZE,
&numBytesRead, 0) == ESP_OK) {
if (numBytesRead == DMA_SIZE) Buffer::advance();
};
//PS: OH BY THE WAY... how do we qualify that we are interrupted for a read??? can we cast "arg"?
}
//anonymous
namespace {
intr_handle_t i2s_interrupt;
static const char *TAG = "ics4343.cpp";
/* RX: I2S_NUM_1 */
#define I2S_CLOCK GPIO_NUM_25
#define I2S_WS GPIO_NUM_26
#define I2S_DIN GPIO_NUM_22
//incase the issue has something to do with DACs I tried other pins too eg:
//#define I2S_CLOCK GPIO_NUM_18
//#define I2S_WS GPIO_NUM_19
//#define I2S_DIN GPIO_NUM_23
//the results were the same
i2s_config_t i2s_config_rx;
i2s_pin_config_t pin_config_rx = { bck_io_num: I2S_CLOCK, ws_io_num: I2S_WS,
data_out_num : I2S_PIN_NO_CHANGE, data_in_num: GPIO_NUM_22 };
void setupInterrupt() {
esp_err_t err = esp_intr_alloc(ETS_I2S1_INTR_SOURCE,
ESP_INTR_FLAG_INTRDISABLED | ESP_INTR_FLAG_LEVEL1 | ESP_INTR_FLAG_IRAM,
&dmaInt,
NULL, &i2s_interrupt);
if (err != ESP_OK)
ESP_LOGE(TAG, "Error esp_intr_alloc %s", esp_err_to_name(err));
}
}
bool Ics43434::setup() {
//stuff the configuration
i2s_config_rx.mode = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_RX);
i2s_config_rx.sample_rate = AUDIO_SAMPLE_RATE;
i2s_config_rx.bits_per_sample = I2S_BITS_PER_SAMPLE_24BIT;
i2s_config_rx.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT; // 2-channels
i2s_config_rx.communication_format =
(i2s_comm_format_t) (I2S_COMM_FORMAT_I2S | I2S_COMM_FORMAT_I2S_LSB);
i2s_config_rx.intr_alloc_flags = (ESP_INTR_FLAG_LEVEL1
| ESP_INTR_FLAG_SHARED); // Interrupt level 1
i2s_config_rx.dma_buf_count = 2; // number of DMA buffers, 128 max.
i2s_config_rx.dma_buf_len = AUDIO_SAMPLES_PER_DMA; // pretty sure .. this is # of elements, not sizeof
i2s_config_rx.use_apll = false; // use APLL as main I2S clock ... less accurate :(
i2s_config_rx.fixed_mclk = false; // not using MCLK output
//mic stuff
ESP_LOGV(TAG, "Using I2S peripheral");
i2s_driver_install(I2S_NUM_1, &i2s_config_rx, 0, NULL);
if (GPIO_IS_VALID_GPIO(I2S_WS)&&GPIO_IS_VALID_GPIO(I2S_CLOCK)
&& GPIO_IS_VALID_GPIO(I2S_DIN)) {
ESP_LOGI(TAG, "gpio pins look valid");
i2s_set_pin(I2S_NUM_1, &pin_config_rx);
i2s_zero_dma_buffer(I2S_NUM_1);
} else ESP_LOGE(TAG, "gpio pins aren't valid");
setupInterrupt();
return true;
}
bool Ics43434::startRecording() {
bool rv = true;
//enable the interrupt and away we go
esp_err_t err = esp_intr_enable(i2s_interrupt);
if (err != ESP_OK)
ESP_LOGE(TAG, "error in esp_intr_enable: %s", esp_err_to_name(err));
return rv;
}
bool Ics43434::stopRecording() {
esp_intr_disable(i2s_interrupt);
return true;
}
According to the docs ESP_ERR_NOT_FOUND above means:V (281) ics4343.cpp: Using I2S peripheral
I (291) ics4343.cpp: gpio pins look valid
E (291) ics4343.cpp: Error esp_intr_alloc ESP_ERR_NOT_FOUND
I (301) main.cpp: : call startRecording
E (301) ics4343.cpp: error in esp_intr_enable: ESP_ERR_INVALID_ARG
No free interrupt found with the specified flags
Okay, so what interrupt should I be using? I have also tried or'ing in ESP_INTR_FLAG_SHARED
Thx,
QC
*I am using the esp32_win32_msys2_environment_and_toolchain-20170918 on Windows (mingw32).