I2s microphone sample rate seems halft as big as it's supposed to
Posted: Sat Feb 25, 2023 7:51 pm
I'm using an INMP441 i2s microphone (datasheet) and using the esp-dsp library and esp-idf 5.0.1 to create an fft series. I'm sampling at 10 240 Hz but I can't see any signals higher than about 2500 Hz, and the plot of the fft shows an alias around 2500 Hz as well. Is there some error in my i2s setup? Is using the microphone as mono making the sample rate half as big? The word select clock is supposed to be the same as the sample rate for non-PDM mode.
I played a tone of 2000 Hz and dumped the data to serial, then ran an fft in matlab. The mirroring around fs/2 is expected but not four lines, and anything above 2500 Hz disappears.. My i2s setup:
Reading is done in a task that notifies a different task to copy the data, I've tried swapping the data as suggested by the i2s rx documentation but I saw no difference:
I played a tone of 2000 Hz and dumped the data to serial, then ran an fft in matlab. The mirroring around fs/2 is expected but not four lines, and anything above 2500 Hz disappears.. My i2s setup:
Code: Select all
void init_i2s(size_t sample_rate) {
i2s_chan_config_t rx_chan_cfg = I2S_CHANNEL_DEFAULT_CONFIG(I2S_NUM_AUTO, I2S_ROLE_MASTER);
ESP_ERROR_CHECK(i2s_new_channel(&rx_chan_cfg, NULL, &rx_chan));
i2s_std_config_t rx_std_cfg = {
.clk_cfg = I2S_STD_CLK_DEFAULT_CONFIG(sample_rate),
.slot_cfg = I2S_STD_PHILIPS_SLOT_DEFAULT_CONFIG(I2S_DATA_BIT_WIDTH_16BIT, I2S_SLOT_MODE_MONO),
.gpio_cfg =
{
.mclk = I2S_GPIO_UNUSED,
.bclk = SCK_PIN,
.ws = WS_PIN,
.dout = I2S_GPIO_UNUSED,
.din = SD_PIN,
.invert_flags =
{
.mclk_inv = false,
.bclk_inv = false,
.ws_inv = false,
},
},
};
ESP_ERROR_CHECK(i2s_channel_init_std_mode(rx_chan, &rx_std_cfg));
ESP_ERROR_CHECK(i2s_channel_enable(rx_chan));
}
Code: Select all
static int16_t* read_buffer;
static size_t read_bytes = 0;
void sampler_run_task(void* param) {
extern TaskHandle_t sample_buffer_task_handle;
read_buffer = (int16_t*)calloc(samp->overlap, sizeof(int16_t));
size_t buf_size = 1024;
while (true) {
ESP_ERROR_CHECK(i2s_channel_read(rx_chan, read_buffer, buf_size, &read_bytes, 1000));
if (read_bytes > 0) {
xTaskNotifyGive(sample_buffer_task_handle); // copy samples to buffer
}
}
free(read_buffer);
vTaskDelete(NULL);
}
void copy_sample_buffer_task(void* param) {
extern TaskHandle_t fft_task_handle;
while (true) {
ulTaskNotifyTake(pdTRUE, portMAX_DELAY); // wait to be notified
sampler_buffer_add(sample_buffer, read_buffer, read_bytes / sizeof(int16_t));
xTaskNotifyGive(fft_task_handle); // run fft
}
}
void sampler_buffer_add(int16* buffer, int16_t* batch, size_t length) {
// samples are in wrong order, swap every other
// https://docs.espressif.com/projects/esp-idf/en/latest/esp32/api-reference/peripherals/i2s.html#std-rx-mode
// for (size_t i = 0; i < length; i += 2) {
// buffer[i + 0] = bswap16(batch[i + 1]);
// buffer[i + 1] = bswap16(batch[i]);
// }
for (size_t i = 0; i < length; i += 1) {
// swap bytes to little endian
buffer[i] = bswap16(batch[i]);
}
}