ESP32 ADC és DMA

ESP8266, ESP32 chipek és az ESP-xx modulok. Programozási nyelvek, trükkök, hardware tippek.
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

ESP32 ADC és DMA

Hozzászólás Szerző: csabeszq »

Egy kérdés, hogy sikerült-e már valakinek ESP32-n ADC-t mintavételezni DMA-val.
A helyzet az, hogy az én kódom mintavételez, megadom, hogy 6kHz-es mintakészletet szeretnék, mindent tök jól csinál, csak 30 kHz-en.

Legalább 1000 paramétert megváltoztattam, a végeredmény mindig ugyan az, amikor a sample rate 6000, akkor 30 kHz-en mintavételezünk. Amikor 10 kHz-et adok meg, akkor 50 kHz körül megy. Semmi nem logikus és nem értem, hogy a mintavételezésnél az 5x szorzó honnan jön.

Nem hinném, hogy a chip 800 MHz-en pörög 160 MHz helyett.

Jó lenne tényleg működő kódot látni. Az interneten sehol semmi, nincsenek példák, a chip láthatóan képes hardverből mintavételezni, csak épp nem úgy, ahogy azt az ember gondolná.

Kód: Egész kijelölése

#include <driver/i2s.h>
#include <driver/adc.h>
#include <soc/syscon_reg.h>


#define ADC_CHANNEL   ADC1_CHANNEL_0 // GPIO36
#define NUM_SAMPLES   32             // number of samples
#define DUMP_INTERVAL 5000           // dump samples at this interval 


int32_t  last_millis = -DUMP_INTERVAL;
uint32_t collected_samples = 0;
uint32_t last_sample_count = 0;


void configure_i2s() {
  i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_ADC_BUILT_IN),  // I2S receive mode with ADC
    .sample_rate = 6000,                                                          // sample rate
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,                                 // 16 bit I2S
    .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,                                 // only the right channel
    .communication_format = I2S_COMM_FORMAT_I2S,                                  // I2S format
    .intr_alloc_flags = 0,                                                        // none
    .dma_buf_count = 8,                                                           // number of DMA buffers
    .dma_buf_len = NUM_SAMPLES,                                                   // number of samples
    .use_apll = 0,                                                                // no Audio PLL
  };

  // ADC channel 0 with 11db (divide by input 3.6)
  adc1_config_channel_atten(ADC_CHANNEL, ADC_ATTEN_11db);
  // 12 bit ADC
  adc1_config_width(ADC_WIDTH_12Bit);

  // install I2S 0 driver, using event queue
  i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);

  // ADC should use ADC_CHANNEL
  i2s_set_adc_mode(ADC_UNIT_1, ADC_CHANNEL);

  // The raw ADC data is written in DMA in inverted form. This add aninversion:
  SET_PERI_REG_MASK(SYSCON_SARADC_CTRL2_REG, SYSCON_SARADC_SAR1_INV);

  // enable I2S ADC
  i2s_adc_enable(I2S_NUM_0);

  Serial.println("I2S started");
}


void setup() {
  Serial.begin(115200);
  configure_i2s();

  Serial.print("APLL        :");
  Serial.println(I2S0.clkm_conf.clka_en);
  Serial.print("CLKM_DIV_NUM:");
  Serial.println(I2S0.clkm_conf.clkm_div_num);
  Serial.print("CLKM_A      :");
  Serial.println(I2S0.clkm_conf.clkm_div_a);
  Serial.print("CLKM_B      :");
  Serial.println(I2S0.clkm_conf.clkm_div_b);
  Serial.print("RX_RATE     :");
  Serial.println(I2S0.sample_rate_conf.rx_bck_div_num );
  Serial.print("TX_RATE     :");
  Serial.println(I2S0.sample_rate_conf.tx_bck_div_num );
}

void loop() {
  uint16_t i2s_read_buff[NUM_SAMPLES];
  
  // read I2S buffer
  int num = i2s_read_bytes(I2S_NUM_0, (char*)i2s_read_buff,  NUM_SAMPLES * sizeof(uint16_t), portMAX_DELAY);

  // increase number of samples
  collected_samples += num / sizeof(uint16_t);

  // dump buffer at every second
  if( (millis() - last_millis) >= DUMP_INTERVAL )
  {
    last_millis += DUMP_INTERVAL;

    Serial.print("Collected samples:");
    Serial.println(collected_samples);
    Serial.print("Rate:");
    Serial.println(collected_samples - last_sample_count);
    last_sample_count = collected_samples;

    // print the sample buffer
    for (int i=0;i<NUM_SAMPLES;i++) {
      Serial.printf("%d, ", i2s_read_buff[i] & 0xFFF);
      if( (i & 31) == 31 )
        Serial.println();
    }
    Serial.println();
    Serial.println();
    Serial.println();
  }
}
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: ESP32 ADC és DMA

Hozzászólás Szerző: csabeszq »

Kicsit beljebb kerültem a bozótosban.
analizator.png
Az ESP32-n az I2S normál 1 bites módban is tud menni (I2S szabvány) és 16 bites LCD módban is. Amikor 1 bites módban megy, akkor bitenként tolja át DMA-val az adatokat. A speckó alapján az ADC LCD módban megy.

Kiraktam a WS/BCLK/Data jeleket. A Data-n semmi nem megy (nem 1 bites módban vagyunk), a WS (csatorna váltás jobb/ball) és a BCLK között kettes osztó van. Ebből már látszik, hogy az I2S a fenti konfiguráció alapján párhuzamos módban működik.

A logikai jelanalizátor a WS vonalon hajszál pontosan 6 kHz-es jelet mér, az van, aminek lennie kell. A BCLK pedig 12 kHz-en fut, minden tökéletes.

Már csak egy kérdés maradt: a 6 kHz mintavételezési frekvenciából hogyan lesz 30 kHz-nyi ADC adat?
:)
Nincs meg a kellő jogosultságod a hozzászóláshoz csatolt állományok megtekintéséhez.
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: ESP32 ADC és DMA

Hozzászólás Szerző: csabeszq »

Minthogy az órajelek pontosak, a kiolvasásnál, vagy az ADC-nél kell a bajnak lennie.
Egy mezei kapacitás kisülési adatai:

4095, 4095, 2755, 3327, 1941, 2303, 1343, 1625, 927, 1122, 624, 768, 402, 512, 255, 319, 127, 192, 63, 97, 6, 29, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,

Látható, hogy párban vannak az értékek, kettesével felcserélve (jobb/bal ?), a mintavételezés egyenletesnek tűnik.
Ábrán szemléltetve látható, hogy felcserélve az adatokat szép kapacitás kisülési görbét kapunk,
meresiadat.png
Hogyan lesz a 6kHz-es I2S órajelből 30 kHz egyenletes mérési adat?
Vicc.
Nincs meg a kellő jogosultságod a hozzászóláshoz csatolt állományok megtekintéséhez.
Avatar
csabeszq
Bitfaragó
Hozzászólások: 678
Csatlakozott: 2012. szeptember 5. szerda, 6:00

Re: ESP32 ADC és DMA

Hozzászólás Szerző: csabeszq »

Megvan a hiba!!!!!!!!!

Az amatőrségnek nincs határa. A 6 kHz 6000 mintát jelent másodpercenként. Minthogy 5s-enként írtam ki a minták számát, így értelemszerűen 30000 jött ki. Nincs más hátra, mint leosztani.

Egy hétvége alatt 100 méréssel és specifikáció olvasással csak sikerült rájönni, hogy honnan az az 5x szorzó. :)

A módosított, már jól működő kód itt van:

Kód: Egész kijelölése

#include <driver/i2s.h>
#include <driver/adc.h>
#include <soc/syscon_reg.h>


#define ADC_CHANNEL   ADC1_CHANNEL_0 // GPIO36
#define NUM_SAMPLES   32            // number of samples
#define DUMP_INTERVAL 5000           // dump samples at this interval 


int32_t  last_millis = -DUMP_INTERVAL;
uint32_t collected_samples = 0;
uint32_t last_sample_count = 0;


void configure_i2s() {
  i2s_config_t i2s_config = {
    .mode = (i2s_mode_t)(I2S_MODE_MASTER | I2S_MODE_RX | I2S_MODE_TX | I2S_MODE_ADC_BUILT_IN),  // I2S receive mode with ADC
    .sample_rate = 6000,                                                          // sample rate
    .bits_per_sample = I2S_BITS_PER_SAMPLE_16BIT,                                 // 16 bit I2S
    .channel_format = I2S_CHANNEL_FMT_ONLY_RIGHT,                                 // only the right channel
    .communication_format = I2S_COMM_FORMAT_I2S,                                  // I2S format
    .intr_alloc_flags = 0,                                                        // none
    .dma_buf_count = 8,                                                           // number of DMA buffers
    .dma_buf_len = NUM_SAMPLES,                                                   // number of samples
    .use_apll = 0,                                                                // no Audio PLL
  };

  // ADC channel 0 with 11db (divide by input 3.6)
  adc1_config_channel_atten(ADC_CHANNEL, ADC_ATTEN_11db);
  // 12 bit ADC
  adc1_config_width(ADC_WIDTH_12Bit);

  // install I2S 0 driver, using event queue
  i2s_driver_install(I2S_NUM_0, &i2s_config, 0, NULL);

  // ADC should use ADC_CHANNEL
  i2s_set_adc_mode(ADC_UNIT_1, ADC_CHANNEL);

  // The raw ADC data is written in DMA in inverted form. This add aninversion:
  SET_PERI_REG_MASK(SYSCON_SARADC_CTRL2_REG, SYSCON_SARADC_SAR1_INV);

  // enable I2S ADC
  i2s_adc_enable(I2S_NUM_0);

  Serial.println("I2S started");
}


void setup() {
  Serial.begin(115200);
  configure_i2s();
}

void loop() {
  uint16_t i2s_read_buff[NUM_SAMPLES];
  
  // read I2S buffer
  int num = i2s_read_bytes(I2S_NUM_0, (char*)i2s_read_buff,  NUM_SAMPLES * sizeof(uint16_t), portMAX_DELAY);

  // increase number of samples
  collected_samples += num / sizeof(uint16_t);

  // dump buffer at every 5 second
  if( (millis() - last_millis) >= DUMP_INTERVAL )
  {
    last_millis += DUMP_INTERVAL;

    Serial.print("Collected samples:");
    Serial.println(collected_samples);
    Serial.print("Rate:");
    Serial.println((collected_samples - last_sample_count) * 1000 / DUMP_INTERVAL);
    last_sample_count = collected_samples;

    // print the sample buffer
    for (int i=0;i<NUM_SAMPLES;i++) {
      Serial.printf("%d, ", i2s_read_buff[i] & 0xFFF);
      if( (i & 31) == 31 )
        Serial.println();
    }
    Serial.println();
    Serial.println();
    Serial.println();
  }
}
Avatar
kapu48
Elektronbűvölő
Hozzászólások: 3375
Csatlakozott: 2008. augusztus 29. péntek, 6:00

Re: ESP32 ADC és DMA

Hozzászólás Szerző: kapu48 »

Köszi! Ez hasznos infó!
Avatar
kapu48
Elektronbűvölő
Hozzászólások: 3375
Csatlakozott: 2008. augusztus 29. péntek, 6:00

Re: ESP32 ADC és DMA

Hozzászólás Szerző: kapu48 »

Korán örültem ez nem működik az S3-ban!
írta: ESP_Sprite » 2022. március 10. csütörtök, 2:58

Az ADC DMA egy külön modul az ESP32S3-ban (már nincs integrálva az I2S-be), bár nem vagyok benne biztos, hogy jelenleg az ESP-IDF ADC-illesztőprogram támogatja-e ezt...
:(
Válasz küldése