Stable I2S callback??
Posted: Tue Jan 07, 2025 5:57 pm
I'm trying to setup a callback mechanism for I2S where I play f.i. 128 samples @48000 Hz sample rate (i.e. ~2666 us per callback). I also use the "on_sent" callback to take a timestamp (with esp_timer_get_time), and then I've written out stats once each second.
But the result is quite disheartening:
Basic code is:
Any ideas on what goes wrong? I would suspect that the ISR callback function would be called quite close to when the DMA transmit is completed...?
But the result is quite disheartening:
Code: Select all
I (5332) i2s_cb: Min interval (us): 0
I (5332) i2s_cb: Max interval (us): 4610
I (5332) i2s_cb: Avg interval (us): 2451
I (6282) i2s_cb: Min interval (us): 0
I (6282) i2s_cb: Max interval (us): 4609
I (6282) i2s_cb: Avg interval (us): 2464
I (7222) i2s_cb: Min interval (us): 0
I (7222) i2s_cb: Max interval (us): 4609
I (7222) i2s_cb: Avg interval (us): 2464
I (8172) i2s_cb: Min interval (us): 0
I (8172) i2s_cb: Max interval (us): 4610
I (8172) i2s_cb: Avg interval (us): 2451
Code: Select all
static bool IRAM_ATTR sent_callback(i2s_chan_handle_t handle,
i2s_event_data_t* event,
void* user_ctx)
{
int64_t* p_ts = (int64_t*)(user_ctx);
*p_ts = (s_config.timestamp_fn)(); // This points to the esp_timer_get_time function...
return false;
}
static void i2s_pdm_tx_task(void* args)
{
const int buf_size_bytes =
s_config.buffer_size * (s_config.stereo ? 2 : 1) * sizeof(int16_t);
int16_t* w_buf = (int16_t*)calloc(1, buf_size_bytes);
assert(w_buf);
i2s_chan_handle_t tx_chan =
i2s_init_pdm_tx(s_config.sample_rate, s_config.stereo);
size_t w_bytes = 0;
int64_t timestamp;
int n = 0;
i2s_event_callbacks_t callbacks = {NULL};
callbacks.on_sent = sent_callback;
ESP_ERROR_CHECK(
i2s_channel_register_event_callback(tx_chan, &callbacks, ×tamp));
// Preload first data
(s_config.i2s_callback_fn)(
s_config.args, timestamp, w_buf, s_config.buffer_size);
ESP_ERROR_CHECK(
i2s_channel_preload_data(tx_chan, w_buf, buf_size_bytes, &w_bytes));
ESP_ERROR_CHECK(i2s_channel_enable(tx_chan));
while (1) {
// Call the audio callback function
(s_config.i2s_callback_fn)(
s_config.args, timestamp, w_buf, s_config.buffer_size);
// Write buffer to I2S DMA
if (i2s_channel_write(tx_chan, w_buf, buf_size_bytes, &w_bytes, 1000) !=
ESP_OK ||
w_bytes != buf_size_bytes) {
ESP_LOGE(TAG, "Write Task: i2s write failed");
break;
}
}
free(w_buf);
vTaskDelete(NULL);
}