- An internal ADC on driver I2S_0.
- An external DAC on I2S_1
Problem: The sampling rates diverge a small amount between the external DAC and internal ADC. Even though i2s_clk_get reports both ADC and DAC are set to precisely 44.1KHz, the ADC buffer fills up slower than the DAC, by just a few milliseconds. The result is that the ADC buffer runs out and there is periodically no new data to send to the DAC.
Expected behavior: Sampling rates should not diverge between external DAC and internal ADC.
Things we tried: We tried CLK_APLL, and PLL_D2_CLK, different sampling rates (multiples of 256, 128, etc.), bigger DMA buffers, smaller DMA buffers, more DMA buffers, fewer DMA buffers, different cores, different core speeds, RTOS tick changes, different interrupt priorities, latest version of IDF, older version of IDF, different I2S configs (channels, formats, etc.).
Nothing works to get rid of the small drift.
Config;
Code: Select all
i2s_config_t i2s_config_dac =
{
.mode = I2S_MODE_MASTER | I2S_MODE_TX, // Only TX
.sample_rate = SAMPLE_RATE,
.bits_per_sample = 16,
.channel_format = I2S_CHANNEL_FMT_RIGHT_LEFT, //2-channels
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
.dma_buf_count = DMA_BUFFER_COUNT,
.dma_buf_len = 256,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1
};
i2s_pin_config_t pin_config_dac =
{
.bck_io_num = I2S_BCK_IO,
.ws_io_num = I2S_WS_IO,
.data_out_num = I2S_DO_IO,
.data_in_num = I2S_DI_IO //Not used
};
i2s_driver_install(1 /*I2S Driver 1 used for DAC*/, &i2s_config_dac, 1, &i2s_event_queue_DAC);
i2s_set_pin(1 /*I2S Driver 1 used for DAC*/, &pin_config_dac);
// create a task to catch TX completion events on core 1
xret = xTaskCreatePinnedToCore(I2Sout /*function*/, "I2Sout" /*name of task*/, 4096 /*stack size*/, NULL /*task input parameter*/, 1 /*priority*/, &I2StaskHandleDAC /*task handle*/, 1 /*core*/);
// I2S ADC
i2s_config_t i2s_config_adc = {
.mode = I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN,
.sample_rate = SAMPLE_RATE,
.bits_per_sample = 16,
.communication_format = I2S_COMM_FORMAT_STAND_MSB,
.channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,
.dma_buf_count = DMA_BUFFER_COUNT,
.dma_buf_len = 256,
.use_apll = false,
.intr_alloc_flags = ESP_INTR_FLAG_LEVEL1 //Interrupt level 1
};
// install/start i2s driver and create event queue
i2s_driver_install(0 /*I2S Driver 0 used for ADC*/, &i2s_config_adc, 1, &i2s_event_queue_ADC);
// GPIO32/ADC1-CH4
i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_4);
// enable ADC
i2s_adc_enable(0 /*I2S Driver 0 used for ADC*/,);
// create a task to catch RX completion events on core 1
xret = xTaskCreatePinnedToCore(I2SIn /*function*/, "I2SIn" /*name of task*/, 4096 /*stack size*/, NULL /*task input parameter*/, 1 /*priority*/, &I2StaskHandleADC /*task handle*/, 1 /*core*/);
Thank you in advance for any help you can provide!