ADC with I2S: increasing throughput to 2 MHz

CafeNoir64
Posts: 3
Joined: Wed Oct 23, 2019 5:51 pm

ADC with I2S: increasing throughput to 2 MHz

Postby CafeNoir64 » Tue May 26, 2020 9:45 am

Hi there,

I am running high frequency ADC sampling through I2S which is loosely based on this example from the arduino-esp32 github: https://github.com/espressif/arduino-es ... eq_ADC.ino

The goal is to sample a single channel (which is excited by a pure sine wave) and compute FFT's from packets which are 512 samples long.

I have a single task running on core 1 to accomplish this, which is given below (simplified). One cycle of the while loop takes approximately 330us to complete (if the buffers are filled by DMA so the i2s_read function doesn't have to wait). So I know the maximum attainable loop frequency is approximately 3000 Hz.

Code: Select all

void FFT_compute(void *pvParameters) {
   i2sInit();  // Initialize the I2S peripheral
   size_t bytes_read;  
   uint16_t buffer[512] = {0};

   unsigned long t_start = millis();
   unsigned long fft_loop_cntr = 0;
   
   while(1){         
    fft_loop_cntr++;
    //(I2S port, destination adress, data size in bytes, bytes read counter, RTOS ticks to wait)
    i2s_read(I2S_NUM_0, &buffer, sizeof(buffer), &bytes_read, portMAX_DELAY);

    //compute FFT of sampled data   
    compute_FFT(&buffer);

    if(fft_loop_cntr % 5000 == 100){
      Serial.print("FFT loop frequency[Hz]: "); 
      Serial.println((1000*fft_loop_cntr)/(millis()-t_start));
    }   
  }
}
And the i2sInit() function is setup like this:

Code: Select all

void i2sInit()
{
  i2s_config_t i2s_config = {
  .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
  .sample_rate =  samplingFrequency,            // The format of the signal using ADC_BUILT_IN
  .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT, // is fixed at 12bit, stereo, MSB
  .channel_format = I2S_CHANNEL_FMT_ONLY_LEFT,
  .communication_format = I2S_COMM_FORMAT_I2S_MSB,
  .intr_alloc_flags = ESP_INTR_FLAG_LEVEL1,
  .dma_buf_count = 32,  //number of DMA buffers
  .dma_buf_len = 64,    //number of samples (in bytes)
  .use_apll = false,    //no Audio PLL
  .tx_desc_auto_clear = false,
  .fixed_mclk = 0
  };

  i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);
  i2s_set_adc_mode(ADC_UNIT_1, ADC_INPUT);
  SYSCON.saradc_ctrl2.sar1_inv = 1;	//SAR ADC samples are inverted by default
  SYSCON.saradc_ctrl.sar1_patt_len = 0; //Use only the first entry of the pattern table
  delay(1000); //required for stability of ADC 
  i2s_adc_enable(I2S_NUM_0);

  delay(1000); //required for stability of ADC   
  SYSCON.saradc_sar1_patt_tab[0] = 0x5C0F0F0F; //mask would be nicer, but seems to be unstable
}
The basics of this are working fine, but I am trying to increase throughput of the ADC. Currently, the maximum stable sample frequency appears to be 1.3 MHz, whereas 2 MSPS is advertised as maximum reachable. I determine this with the loop counter in my main while loop. Above 1.3-1.35 MHz sample rate the execution rate of my loop starts to drop severely instead of increase. Furthermore, the FFT is no longer accurately determining the frequency of the sinewave, indicating issues with sampling.

It should be noted that the true sample rate is already half of the configured sample rate, because the ESP samples two channels simultaneously (refered to as LEFT and RIGHT). Which is only usefull if you sample more than one source. At 1.024MHz sampling rate with 512 samples per reading, I am getting a steady state loop frequency of 992Hz, which is just below the expected (1.024/2)/512 = 1000Hz.

I have read in other threads, that the SAR ADC cannot sample continuously and needs two clock cycles to restart every 256 samples by default. This would explain my lower than expected sampling perfectly, i.e. 256/258*1000=992. Futhermore, turning restarts off with SYSCON.saradc_ctrl2.meas_num_limit = 0; (which is unadvised and indeed gives poorer data) gives me the exact 1000 Hz. (include "soc/syscon_reg" and "soc/syscon_struct.h").

So back to my main problem, what could be limiting my maximum attainable sampling rate?
  • Are the DMA or FIFO buffers limiting my throughput? Which registers can I check for this?
  • Could it be RTOS related? For instance, not enough time available to read out the buffers causing them to waste data? Personally I wouldn't expect this because the task seems to be quick enough and is the only one running.
  • Anything you can think of, help me to look in the right direction is welcome.
If any ESP32 guru's are around to help me out answering this, I would be super gratefull!
Last edited by CafeNoir64 on Wed May 27, 2020 8:17 pm, edited 1 time in total.

ESP_Sprite
Posts: 9730
Joined: Thu Nov 26, 2015 4:08 am

Re: ADC with I2S: increasing throughput to 2MSPS

Postby ESP_Sprite » Tue May 26, 2020 12:36 pm

If I recall the innards of the I2S driver correctly, the hardware will fill a buffer of `dma_buf_len` and then generate an interrupt for the I2S driver to handle that data. Given the fact that in your case, these are only 64 words, that is a great many interrupts a second... my gut feeling is that if you make that number larger (512 sounds like the logical choice, as that is your fft packet size) you should be able to get a higher sample frequency.

CafeNoir64
Posts: 3
Joined: Wed Oct 23, 2019 5:51 pm

Re: ADC with I2S: increasing throughput to 2MSPS

Postby CafeNoir64 » Tue May 26, 2020 12:51 pm

Thanks for your response. Unfortunately a buffer size of 512 or even 1024 bytes doesn't seem to make a difference. Also a larger or smaller amount of buffers seems to be ineffective. Still getting about a 100 Hz loop frequency at 1.4 MSPS. Whereas at 1.3MSPS I can achieve ~1270 Hz.

sullivan
Posts: 2
Joined: Wed Mar 16, 2022 3:52 pm

Re: ADC with I2S: increasing throughput to 2 MHz

Postby sullivan » Thu Mar 17, 2022 3:39 am

Did you managed to get the sampling freq of 2Msps? I tried the same code but my maximum sampling rate is around 125ksps. Can't get even close to 1Msps.

In addition, I don't see anyone trying to do this since there are lots of saying that ESP32 ADC only has bandwidth of 6khz. So if you are trying to get signal above that (e.g. ultrasonic or RF IF signals) it is just impossible.

sullivan
Posts: 2
Joined: Wed Mar 16, 2022 3:52 pm

Re: ADC with I2S: increasing throughput to 2 MHz

Postby sullivan » Fri Mar 18, 2022 1:14 pm

sullivan wrote:
Thu Mar 17, 2022 3:39 am
Did you managed to get the sampling freq of 2Msps? I tried the same code but my maximum sampling rate is around 125ksps. Can't get even close to 1Msps.

In addition, I don't see anyone trying to do this since there are lots of saying that ESP32 ADC only has bandwidth of 6khz. So if you are trying to get signal above that (e.g. ultrasonic or RF IF signals) it is just impossible.
I just tested it seems 6kHz bandwidth is just a legend. The real bandwidth is clearly above 50Khz.

Who is online

Users browsing this forum: No registered users and 63 guests