Esp32 analogRead very slow

AnalogRead took 100 microseconds to give a result in Arduino. But the hardware is much fast. Anyone knows a better implementation for reading the ADcs?

I'm not familiar with the ESP32.

Which hardware? Are you refering to the clockspeed of the processor or the actual ADC hardware? What does the datasheet say about the ADC.

How do you know?

Please show your code.

let’s see the code and the output

I'd like to see the code, please, of an analog reading taking 100us and the code used to measure the time of the ADC reading.

One could strip off using the Arduino core code and use the ESP32's API to read the A:D and strip off some computing time.


#include <driver/adc.h>


void setup()
{
  adc1_config_width(ADC_WIDTH_12Bit);
  adc1_config_channel_atten(ADC1_CHANNEL_6, ADC_ATTEN_DB_11);// using GPIO 34 wind direction
  adc1_config_channel_atten(ADC1_CHANNEL_3, ADC_ATTEN_DB_11);// using GPIO 39 current
  adc1_config_channel_atten(ADC1_CHANNEL_0, ADC_ATTEN_DB_11);// using GPIO 36 battery volts
}

void fReadBattery( void * parameter )
{
  const float r1 = 50500.0f; // R1 in ohm, 50K
  const float r2 = 10000.0f; // R2 in ohm, 10k potentiometer
  const TickType_t xFrequency = 1000; //delay for mS
  float    adcValue = 0.0f;
  float    Vbatt = 0.0f;
  int      printCount = 0;
  float    vRefScale = (3.3f / 4096.0f) * ((r1 + r2) / r2);
  uint64_t TimePastKalman  = esp_timer_get_time(); // used by the Kalman filter UpdateProcessNoise, time since last kalman calculation
  SimpleKalmanFilter KF_ADC_b( 1.0f, 1.0f, .01f );
  TickType_t xLastWakeTime = xTaskGetTickCount();
  for (;;)
  {
    adc1_get_raw(ADC1_CHANNEL_0); //read and discard
    adcValue = float( adc1_get_raw(ADC1_CHANNEL_0) ); //take a raw ADC reading
    KF_ADC_b.setProcessNoise( (esp_timer_get_time() - TimePastKalman) / 1000000.0f ); //get time, in microsecods, since last readings
    adcValue = KF_ADC_b.updateEstimate( adcValue ); // apply simple Kalman filter
    Vbatt = adcValue * vRefScale;
    xSemaphoreTake( sema_CalculatedVoltage, portMAX_DELAY );
    CalculatedVoltage = Vbatt;
    xSemaphoreGive( sema_CalculatedVoltage );
    
      printCount++;
      if ( printCount == 3 )
      {
      //log_i( "Vbatt %f", Vbatt );
      printCount = 0;
      }
    
    TimePastKalman = esp_timer_get_time(); // time of update complete
    xLastWakeTime = xTaskGetTickCount();
    vTaskDelayUntil( &xLastWakeTime, xFrequency );
    //log_i( "fReadBattery %d",  uxTaskGetStackHighWaterMark( NULL ) );
  }
  vTaskDelete( NULL );
}
////





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

1 Like

I have set a pin, then use analogRead, then make the pin low. An oscilloscope attached to the pin shows about 100 us.

Thanks Idahowalker! I am tired because complexity of such code. My goal is to sample 4 channels at 10k samples/second. Maybe I must switch to another board or platform.

May be with the ADC DMA feature (continuous mode)?

see the discussion here ESP32 ADC DMA generates samples way too fast? (IDFGH-7285) · Issue #8874 · espressif/esp-idf · GitHub

an interesting video on the DMA process

Show your code?

1 Like

ok:

// this file: interrupt_analog_test.ino
// This code is for testing analogRead delay
// Compiled using Arduino IDE
// ESP32-WROOM-DA Module
// Board is ESP WROOM 32 made by www.diymore.cc
// Does nothing more than fire a periodic timer
// interrupt every 200 microseconds and an analogRead
// inside the ISR: PinTEST is high before read,
// then is low. An oscilloscope in PinTEST allows measure time.
// Library installed: ESP32TimerInterrupt by Khoi Hoang version 2.2
// in Boards Manager: ESP32 by Espressif systems version 2.0.4

#define PinTEST 27

hw_timer_t *timer_for_test = NULL;

IRAM_ATTR int value_discard;

void IRAM_ATTR onTimer_Alarm_ISR(){

digitalWrite(PinTEST, HIGH);
value_discard = analogRead(34); //read analog value in
//pin 34 and assign to an integer
digitalWrite(PinTEST, LOW);
}

void setup() {

pinMode(PinTEST, OUTPUT);

timer_for_test = timerBegin(0, 80, true);// use hardware timer nro. 0,
// prescaler=80, rising edge
timerAttachInterrupt(timer_for_test, &onTimer_Alarm_ISR, true); // associate ISR with pointer
timerAlarmWrite(timer_for_test, 200, true); // makes hardware timer nro. 0 works in Alarm mode,
//alarm set every 200 counts , automatic reload the timer for endless working
timerAlarmEnable(timer_for_test); // Just Enable

}

void loop() {
// do nothing, only the timer interrupt routine fires every 200 microseconds
}
// end of file

More precise measuring gives me 80 microseconds for each analogRead(). Still slow for me.

I think you can find some of stuff you are looking for here: Analog to Digital Converter - ESP32-S2 - — ESP-IDF Programming Guide v4.2.3 documentation

Yeah, tradeoff between ADC precision and measuring times. I haven't tried myself for ESP32 though, only Arduino Uno by manipulating its ADC status registers.

If I were tried this for ESP32, I can give you definite answer for this.

This might be of interest.

1 Like

This may be the best that can be achieved with the ESP32 ADC:

What is your application?

The solution of Ivan Voras was to reimplement the analogRead funtion. But he do not use Arduino, he use IDF. In Arduino IDE this solution do not compile.

again -

Is an experimental sampling of biological signals. This ends sampling 4 analog channels for 3 or 4 seconds and then send data over WiFi. I really appreciate a simple example of using ESP32's DMA analog sampling in Arduino IDE but all that i have found is for IDF and too complex.

Thanks dlloyd. Espressif has deleted file rtc_module.c . Of course, they do not use Arduino IDE, only IDF or whatever. The only thing that i have learn is that " The implementation of adc1_get_raw is quite complex and does a lot of hardware initialization/locking around adc_convert() ." [quote from Patrick, 2018/08/28]
adc1_get_raw works in Arduino IDE and has a conversion time of 42 microseconds. Setting adc_set_clk_div() do not work in Arduino IDE.

What are the characteristics of the signals you need to sample? I'm not aware of biological signals with a large bandwidth.

You may wish to consider using external ADC's such as
https://eu.mouser.com/datasheet/2/256/MAX153-364778.pdf

Thanks John!! Yes, i am thinking about using external ADC. But maybe a SPI or I2C chip because MAX153 uses almost all IOs in ESP32. I feel the ESP32 has all hardware i need but the lack of a good analogRead implementation in Arduino is a shame.

What about a Raspberry Pi (if they are in stock somewhere) with a USB analog capture device.