I2S_0 and I2S_1 clocks drift out of sync

SiliconFields
Posts: 3
Joined: Wed Aug 18, 2021 7:42 am

I2S_0 and I2S_1 clocks drift out of sync

Postby SiliconFields » Mon Oct 04, 2021 8:34 am

In our project, we have two I2S peripherals;
  • An internal ADC on driver I2S_0.
  • An external DAC on I2S_1
We use DMA and an interrupt routine to read the ADC at 44.1KHz via I2S. We use DMA and an interrupt routine to write to the DAC at 44.1KHz via I2S. It is a simple DSP setup; an analog signal is sampled, processed by the ESP32, and set out via an external DAC.

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*/);	 
Is this clock drift a known bug in the I2S internal ADC driver? Or are we missing something obvious?

Thank you in advance for any help you can provide!

nateimig
Posts: 1
Joined: Sun Dec 20, 2015 9:41 am

Re: I2S_0 and I2S_1 clocks drift out of sync

Postby nateimig » Fri Nov 03, 2023 8:46 pm

I'm currently experiencing the same thing honestly. Currently comparing the calculated timestamp (from the data bytes written & sample rate) vs. the timestamp (from current uptime & start uptime). Then plotting the recorded difference between them over an hour I'm seeing a average leading lag that accrues linearly up to around 100ms. This is setting the sample rate to 44100Hz and the use_apll=1 for "accurate clock timing". Was wondering if this was temperature driven clock drift. I mean the deviation for that is like 1.2 sample rate different (44098.8) between the ideal 44100 sample rate.

Looking at it with a scope on the bit clock with persistence on triggering on edge you can see the smearing of neighboring clock edges...

Who is online

Users browsing this forum: No registered users and 51 guests