ESP32-WROOM-DA Module tempi conversione ADC

buongiorno
Sono un pensionato con la decennale, perenne passione per l'informatica e la voglia di apprendere(!)
Sto sperimentando, senza un scopo preciso, le potenzialità di uno SP32.
Macchina incredibile, meravigliosa.
A seguito di alcuni problemi presentatisi ho casualmente notato dei tempi lunghi (da 45 a 80 usec) per una conversione ADC.
L'AD converter è un SAR a 12bits, una conversione dovrebbe durare 12 colpi di clock.
Domande:

  1. come si spiega tutto questo tempo in più?
  2. se è così, esiste un modo alternativo per accedere direttamente al SAR evitando tutti gli strati intermedi di software?
    Allego un'estratto dello sketch utilizzato per eseguire le misure dei tempi
    Grazie
#include  <Arduino.h>
#include <driver/adc.h>       // per usare adc1_get_raw() invece di analogRead()

#define GPIO_POT  36        // potenziometro su GPIO34 = pin3
#define GPIO_ADC1 39        // input analogico su GPIO39 = pin4

// per gli ADC
// Setta la precisione a 12 bits (0-4095) (4095 corrisponde a 3.3V)
// Setta la precisione a 8 bits  (0-255)  ( 255 corrisponde a 3.3V)
#define ADC_RESOLUTION 12


//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!
#define ADC_LEGACY                       // per utilizzare analogRead()
//!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!

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

//---Setta la precisione del convertitore ADC----
#ifdef  ADC_LEGACY
  analogReadResolution(ADC_RESOLUTION);
#else
  if (ADC_RESOLUTION==12)
  {
    adc1_config_width(ADC_WIDTH_BIT_12);
    adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_12); 			  // GPIO36 PER IL POTENZIOMETRO
    adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_12); 			  // GPIO39 PER L'OSCILLATORE
  }
  else
  {
    adc1_config_width(ADC_WIDTH_BIT_9);
    adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_6); 			  // GPIO36 PER IL POTENZIOMETRO
    adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_6); 			  // GPIO39 PER L'OSCILLATORE
  }
#endif
}

///////////////////////////////////////////////////////////////////////
void loop(void) 
{
static  uint32_t nLoop = 0;
uint16_t nValueADC = 0;
uint16_t nValuePOT = 0;

unsigned  long  nMicros = 0;
unsigned  long  nDiff = 0;

#ifdef  ADC_LEGACY
nMicros = micros();
  nValuePOT = analogRead(GPIO_POT);
nDiff = micros() - nMicros;
  nValueADC = analogRead(GPIO_ADC1);
#else
nMicros = micros();
  nValuePOT = adc1_get_raw(ADC1_CHANNEL_0);                                     // potenziometro su GPIO34
nDiff = micros() - nMicros;
  nValueADC = adc1_get_raw(ADC1_CHANNEL_3);
#endif
  if (ADC_RESOLUTION == 12)          // 12 bit (0 ... 4095)
  {
    nValuePOT = map( nValuePOT & 0xFFF, 0, 4095, 100, 2000);                    // potenziometro su GPIO34
    nValueADC = nValueADC & 0xFFF;
  }
  else                              //  8 bit (0 ... 255)
  {
    nValuePOT = map( nValuePOT & 0xFF, 0, 255, 100, 2000);                      // potenziometro su GPIO34
    nValueADC = nValueADC & 0xFF;
  }
  nLoop++;
  Serial.printf("%6d: nDiff=%4lu \n", nLoop, nDiff);
//  Serial.printf("ADC1=%4d Pot=%4d \n", nValueADC, nValuePOT);
//  Serial.printf("%6d: nDiff=%4lu \n", nLoop, nDiff);
  delay(50);
}

Ti segnalo che, nella sezione in lingua Inglese, si può scrivere solo in Inglese ... quindi, per favore, la prossima volta presta più attenzione in quale sezione metti i tuoi post; questa volta esso è stato spostato, da un moderatore della sezione di lingua Inglese, nella sezione di lingua Italiana ... la prossima volta potrebbe venire direttamente eliminato.

Grazie.

non me n'ero accorto!
scusami grazie

1 Like

Con la tua esperienza il contenuto di questo link dovrebbe sembrarti familiare:

Non ho verificato, ma ci sono buone probabilità che la analogRead() standard avvolga (wrap) questa ... ops ho guardato sempre nello stesso file:

extern uint16_t analogRead(uint8_t pin) __attribute__((weak, alias("__analogRead")));

La funzione in questione è questa:

uint16_t __analogRead(uint8_t pin) {
  int value = 0;
  adc_channel_t channel;
  adc_unit_t adc_unit;

  esp_err_t err = ESP_OK;
  err = adc_oneshot_io_to_channel(pin, &adc_unit, &channel);
  if (err != ESP_OK) {
    log_e("Pin %u is not ADC pin!", pin);
    return value;
  }

  if (perimanGetPinBus(pin, ESP32_BUS_TYPE_ADC_ONESHOT) == NULL) {
    log_d("Calling __analogInit! pin = %d", pin);
    err = __analogInit(pin, channel, adc_unit);
    if (err != ESP_OK) {
      log_e("Analog initialization failed!");
      return value;
    }
  }

  adc_oneshot_read(adc_handle[adc_unit].adc_oneshot_handle, channel, &value);
  return mapResolution(value);
}

PS: credo che la durata di conversione dipenda anche dalla frequenza di conversione, anche se non ho indagato penso che la frequenza di conversione sia configurabile.

Di più non saprei suggeriti poiché conosco questa mcu marginalmente.

Le api sono facili da navigare almeno su github, tu in locale hai tutto il sorgente, ma dove si trova lo devi scoprire da te.

Ciao.

1 Like

grazie Mauro.
Utilizzando le tue informazioni farò un pò di indagini / prove
ti faccio sapere
claudio

Di quale clock? Quasi certamente non quello dell'MCU, in genere le periferiche hanno il clock collegato ad un prescaler che divide il clock per 2/4/8/16/etc, quindi bisogna vedere cosa fa nel dettaglio l'ESP32 a tal riguardo.

Ciao, Ale.

1 Like

Infatti, a maggior ragione, è proprio questo che non mi so spiegare.
Questa MCU ha un clock di 240Mhz, sicuramente il SAR non lo utilizzerà direttamente, ma se anche fosse quello prescalato a 1Mhz, certo non giustificherebbe 60usec per la conversione.
So che è un sofisma ma ormai mi ci sono impuntato :sweat_smile:
Cercherò una qualche documentazione in rete.....
grazie

L'ESP32 ha due modalità di acquisizione ADC:
la prima, che se non sbaglio è quella che stai usando tu, è la one shot che usa il modulo RTC come fonte di timing, modulo che è molto più lento del clock principale (mi pare 150Khz).

Nella modalità continuos reading invece viene usata la modalità DMA e il tempo di acquisizione è praticamente realtime.

https://docs.espressif.com/projects/esp-idf/en/stable/esp32/api-reference/peripherals/adc_continuous.html

1 Like

grazie cotestatnt
avevo visto quella documentazione, ma non avevo capito (o non è precisato) che fosse diametralmente differente il modo di acquisizione.
Farò delle prove
Devo dire che di documentazione ce n'è tanta ma un pò "sparpagliata"
Va trovata quella giusta, nel posto giusto :love_you_gesture:

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.