Sampling multiple channels via ADC DMA

hdejong
Posts: 1
Joined: Sun Jan 03, 2021 1:17 pm

Sampling multiple channels via ADC DMA

Postby hdejong » Sun Jan 03, 2021 1:28 pm

I have a problem using the pattern table in SARADC_SAR1_PATT_TAB1_REG. Whatever I specify as a pattern, the ESP32 only samples the channel that I have set in the i2s_set_adc_mode function. Does anyone have a working example on how to scan multiple channels with the DIG SAR ADC controller?


Sample code:

Code: Select all

void adc_handler(void* parameter) {
    #define adc_tag "ADC_Task"
    esp_log_level_set(adc_tag, ESP_LOG_DEBUG);
    ESP_LOGI(adc_tag, "Starting the adc handler task.");

    static i2s_config_t i2s_config = {
      .mode                 = (i2s_mode_t) (I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),
      .sample_rate          = adc_sample_rate,
      .bits_per_sample      = I2S_BITS_PER_SAMPLE_16BIT,
      .channel_format       = I2S_CHANNEL_FMT_ONLY_LEFT,
      .communication_format = I2S_COMM_FORMAT_I2S_MSB,
      .intr_alloc_flags     = ESP_INTR_FLAG_LEVEL1,
      .dma_buf_count        = 2,
      .dma_buf_len          = adc_dma_buf_len,
      .use_apll             = true
    };

    static adc_i2s_pattern_t adc_i2c_pattern[] = {
      { {.atten = ADC_ATTEN_DB_0, .bits = ADC_WIDTH_12Bit, .channel = ADC1_CHANNEL_0 } },
      { {.atten = ADC_ATTEN_DB_0, .bits = ADC_WIDTH_12Bit, .channel = ADC1_CHANNEL_3 } },
      { {.atten = ADC_ATTEN_DB_0, .bits = ADC_WIDTH_12Bit, .channel = ADC1_CHANNEL_4 } },
      { {.atten = ADC_ATTEN_DB_0, .bits = ADC_WIDTH_12Bit, .channel = ADC1_CHANNEL_6 } }
    };

    // install and start i2s driver
    i2s_driver_install(i2s_num, &i2s_config, 2, &i2s_event_queue);
    i2s_set_adc_mode(ADC_UNIT_1, ADC1_CHANNEL_MAX);

    // config adc atten and width
    ESP_LOGD(adc_tag, "adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_0db);\n");
    adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_0db);
    adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_0db);
    adc1_config_channel_atten(ADC1_CHANNEL_4, ADC_ATTEN_0db);
    adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_0db);
    ESP_LOGD(adc_tag, "adc1_config_width(ADC_WIDTH_12Bit);\n");
    adc1_config_width(ADC_WIDTH_12Bit);
 
    // Scan multiple channels.
    ESP_LOGD(adc_tag, "SET_PERI_REG_BITS(0x%08x, 0x%02x, 3, 0x%02x);\n", SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_SAR1_PATT_LEN, SYSCON_SARADC_SAR1_PATT_LEN_S);
    SET_PERI_REG_BITS(SYSCON_SARADC_CTRL_REG, SYSCON_SARADC_SAR1_PATT_LEN, 3, SYSCON_SARADC_SAR1_PATT_LEN_S);

    // This 32 bit register has 4 bytes for the first set of channels to scan.
    // Each byte consists of:
    // [7:4] Channel
    // [3:2] Bit Width; 3=12bit, 2=11bit, 1=10bit, 0=9bit
    // [1:0] Attenuation; 3=11dB, 2=6dB, 1=2.5dB, 0=0dB
    ESP_LOGD(adc_tag, "WRITE_PERI_REG(0x%08x, 0x%02x, 0x%02x, 0x%02x, 0x%02x);\n",SYSCON_SARADC_SAR1_PATT_TAB1_REG,adc_i2c_pattern[0].val,adc_i2c_pattern[1].val,adc_i2c_pattern[2].val,adc_i2c_pattern[3].val);
    WRITE_PERI_REG(SYSCON_SARADC_SAR1_PATT_TAB1_REG, adc_i2c_pattern);

    // The raw ADC data is written to DMA in inverted form. Invert back.
    ESP_LOGD(adc_tag, "SET_PERI_REG_MASK(0x%08x, 0x%08x);\n", SYSCON_SARADC_CTRL2_REG, SYSCON_SARADC_SAR1_INV);
    SET_PERI_REG_MASK(SYSCON_SARADC_CTRL2_REG, SYSCON_SARADC_SAR1_INV);

    // Delay for 5 seconds to allow the ADC to start-up
    delay(5000);
    ESP_LOGD(adc_tag, "i2s_adc_enable(0x%02x);\n", i2s_num);
    i2s_adc_enable(i2s_num);

    int i2s_read_len = adc_dma_buf_len * sizeof(uint16_t);
    struct i2s_buffer_t {
      unsigned int timestamp;
      uint16_t     buffer[adc_dma_buf_len];
    } i2s_buffer;
   
    while (1)
    {
      system_event_t event;
      size_t bytes_read;
      // vTaskDelayUntil(&xLastWakeTime, xDelay);
      if (xQueueReceive(i2s_event_queue, &event, portMAX_DELAY) == pdPASS) {
        if (event.event_id == 2) {
          i2s_buffer.timestamp = esp_timer_get_time();
          i2s_read(i2s_num, (char*) i2s_buffer.buffer, i2s_read_len, &bytes_read, portMAX_DELAY);
          if (socket_adc_connected) {
            if (digitalRead(boot) == LOW) ESP_LOGD(adc_tag, "Socket Connected,     Timestamp : %i, [%04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x]", i2s_buffer.timestamp, i2s_buffer.buffer[0], i2s_buffer.buffer[1], i2s_buffer.buffer[2], i2s_buffer.buffer[3], i2s_buffer.buffer[4], i2s_buffer.buffer[5], i2s_buffer.buffer[6], i2s_buffer.buffer[7]);
            unsigned int temp = i2s_buffer.timestamp;
            ws_adc.binaryAll((uint8_t *)&temp, sizeof(temp));
          } else {
            if (digitalRead(boot) == LOW) ESP_LOGD(adc_tag, "Socket Not Connected, Timestamp : %i, [%04x, %04x, %04x, %04x, %04x, %04x, %04x, %04x]", i2s_buffer.timestamp, i2s_buffer.buffer[0], i2s_buffer.buffer[1], i2s_buffer.buffer[2], i2s_buffer.buffer[3], i2s_buffer.buffer[4], i2s_buffer.buffer[5], i2s_buffer.buffer[6], i2s_buffer.buffer[7]);
          }
        }
      }
    }
    vTaskDelete(NULL);
}

pilotjiri
Posts: 1
Joined: Tue Oct 26, 2021 8:54 am

Re: Sampling multiple channels via ADC DMA

Postby pilotjiri » Tue Oct 26, 2021 9:05 am

Hi, did you get this working? I want to sample just 2 ADC channels (5 and 6) with DMA (real time clock) on at least 8kHz sampling frequency, and process buffers (filtering, FFT and more) on lower frequency, but I can only get one channel working (I2S0) and other is filled with 0s.

Is there some sample code, I could not find any working example, how to configure multiple ADC channes with DMA.

Can you please point me to right direction?

AntonioTesta
Posts: 7
Joined: Wed Jun 21, 2023 11:47 am

Re: Sampling multiple channels via ADC DMA

Postby AntonioTesta » Mon Sep 18, 2023 11:14 am

Did you both hdejong and pilotjiri have success reading two simultaneous channels using i2s and DMA on ESP32 ??? I have this problem since many years ago and so far there is no solution. I would suggest to someone from Espressif enter into this issue...

Who is online

Users browsing this forum: No registered users and 40 guests