espressif / esp-idf

Espressif IoT Development Framework. Official development framework for Espressif SoCs.
Apache License 2.0
13.38k stars 7.22k forks source link

Not real time update from adc_digi_read_bytes (IDFGH-6755) #8383

Open eos1d3 opened 2 years ago

eos1d3 commented 2 years ago

Environment

Problem Description

The ADC readings on console are not updated immediately. It can take up to 60 seconds to see new value.

//Detailed problem description goes here. It seems each call to adc_digi_read_bytes, it returns a lot of old ADC values and current ADC values are not read immediately. By connecting one ADC pin to GND and start the board, first reading are all 0. Then connect 3.3V to the same ADC pin, the console is still showing 0 reading for up to 60 seconds.

Expected Behavior

Change of ADC voltage will see real time update reading in console.

Actual Behavior

Huge delay to see ADC value changes (depends on ADC settings below):

#define TIMES              256
vTaskDelay(1);             // at line 161 in the example

The above needs 5 seconds delay to see new value.

#define TIMES              16
vTaskDelay(100);           // at line 161 in the example, change to 1 second delay

The above needs 60+ seconds delay to see new value.

Steps to reproduce

1. Copy ADC DMA Example: https://github.com/espressif/esp-idf/blob/master/examples/peripherals/adc/dma_read/main/adc_dma_example_main.c
2. For easy debugging, use only ADC1 as shown in the code below:

#define ADC_CONV_MODE       ADC_CONV_SINGLE_UNIT_1 
#define ADC_OUTPUT_TYPE     ADC_DIGI_OUTPUT_FORMAT_TYPE1  

. . . 

static adc_channel_t channel[2] = {ADC1_CHANNEL_2, ADC1_CHANNEL_3};
eos1d3 commented 2 years ago

The concept of saving old and outdated ADC values in ringbuffer is likely wrong. Old ADC values are actually useless and must be ignored. Each time a call to get the ADC values must all be the current values.

For example, if ADC is used for over-current detection, the response time is too slow and all values are actually irrelevant any more.

I use a lot ST 8-bit and 32-bit MCU and never see this kind of ringbuffer implementation. For continuous ADC reading, ST DMA will just update current values to an integer array, from first channel to last channel and then restart repeatedly. Old values are overwritten in the array. So the array always contain real time values.

With STM32 MCU, it has hardware oversampling so that the ADC will continuously scan selected channels in 2x, to 256x times. And it will divide the sum of each channel by number of oversampling with hardware. Optionally the ADC can be programmed to right shift the sum of each channel automatically from 1 to 8 bits, so the width of ADC bits adjust from 12 bits to 16 bits.

ESP does not have hardware oversampling, but I think it is better to do similar way by by using interrupt.

In the ADC DMA example, I used 2 ADC channels, adc_digi_read_bytes returns 128 values. This consumes a lot of memory with the structure of each element. With ST approach, it is just an array of two integer!