espressif / esp-idf

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

[TW#12287] ESP32 ADC accuracy #164

Open nassks opened 7 years ago

nassks commented 7 years ago

Hi,

I'm testing the ESP32's ADC on the SparkFun ESP32 Thing. Currently my measure seems very noisy, it constantly varies on the 5 first bits, and the zero value is around 90mV. Is there a way to achieve better accuracy?

My test code :

adc1_config_width(ADC_WIDTH_12Bit);
adc1_config_channel_atten(ADC1_CHANNEL_7, ADC_ATTEN_0db);

while (true) {
        vTaskDelay(300 / portTICK_PERIOD_MS);
        printf("ADC value : %x\n", adc1_get_voltage(ADC1_CHANNEL_7));
}

Thank you in advance for your help.

projectgus commented 7 years ago

The ADC has a non-linear response, and we are working on producing characterisation data which will be added to esp-idf to produce a linear output.

When you say "noisy", are you getting noisy readings on a constant voltage or is this noise caused by the non-linearity?

There's some more in this related Arduino bug: https://github.com/espressif/arduino-esp32/issues/92

projectgus commented 7 years ago

@CarlosGS : for issues, it is much better to start a new one than to post off-topic in an existing one.

For questions like this, the http://esp32.com forum may be an even better choice.

michapr commented 7 years ago

@projectgus : I think nassks means the "noise" within same values - additional I have seen that there is a "noise" between the inputs. put 1 Volt (with capacititor) on inputs CH4 ..CH7 I get such results: (using 0bd and 11db for the values)

ADC1 CH4 value: 3719 @ 0db, 1056 @ 11db
ADC1 CH5 value: 3889 @ 0db, 1052 @ 11db
ADC1 CH6 value: 3883 @ 0db, 1052 @ 11db
ADC1 CH7 value: 3891 @ 0db, 1052 @ 11db
-------
ADC1 CH4 value: 3867 @ 0db, 1056 @ 11db
ADC1 CH5 value: 3885 @ 0db, 1053 @ 11db
ADC1 CH6 value: 3887 @ 0db, 1040 @ 11db
ADC1 CH7 value: 3886 @ 0db, 1057 @ 11db
-------
ADC1 CH4 value: 3894 @ 0db, 1056 @ 11db
ADC1 CH5 value: 3855 @ 0db, 1061 @ 11db
ADC1 CH6 value: 3887 @ 0db, 1049 @ 11db
ADC1 CH7 value: 3875 @ 0db, 1053 @ 11db
-------

Difference is up to 5% - maybe it is normal?

But for 0V - I get a value "0" ... without "noise" - it is ok for me

Michael

michapr commented 7 years ago

Do not know why the crazy style came up before ;)

Code snippet for reference:

...
adc1_config_width(ADC_WIDTH_12Bit);
...
adc1_config_channel_atten(ADC1_CHANNEL_4,ADC_ATTEN_0db);
int val=adc1_get_voltage(ADC1_CHANNEL_4);
adc1_config_channel_atten(ADC1_CHANNEL_4,ADC_ATTEN_11db);
int val1=adc1_get_voltage(ADC1_CHANNEL_4);
printf("ADC1 CH4 value: %d @ 0db, %d @ 11db\n", val, val1);
....

Michael

marcmerlin commented 7 years ago

So, in case anyone finds this ADC bug, I've found another ADC issue apparently where it will return data between 0-50% input, and cap out at 4096 from 50 to 100% input, but only after I try to use RMT. Details here: https://github.com/espressif/esp-idf/issues/462

marcmerlin commented 7 years ago

So, the lastest arduino-esp32 fixes the issue I just reported when RMT is turned on, analogread values would get damaged.

FayeY commented 7 years ago

Hi nassks, is this problem solved?

igrr commented 7 years ago

@FayeY not yet, @Spritetm is working on it.

dmody commented 7 years ago

Just leaving my two cents on this... I was hoping to use an inexpensive Voltage Reference IC (LM4040C30ILP) to help increase the accuracy of measured values. I too found the ADC to be non linear and have included my data below for anyone interested. voltage, ADC 2 2222 3 3730 1 1033 1.5 1629 0 0 0.5 422 2.5 2840 2.8 3300 3.1 3980 3.007 3750

image

dmody commented 7 years ago

took another crack at this, and assuming the ADC readings are related to the 3.3V regulator voltage (mine is at 3.275 V on a developer board). Here's what I found. image

negativekelvin commented 7 years ago

@dmody interesting, have you tried to fit curves to the upper range and lower range separately?

imotion-software commented 7 years ago

In the future, are you planning to include linearization of adc1_get_voltage or it will be in charge to the user to correct non linear behavior?

Just to know, because if we implement linearization on user app and then adc1_get_voltage will change behavior we'll have to remove all those parts.

dmody commented 7 years ago

I did not consider doing that. Sounds like a decent idea. I wonder which would be faster to execute. Sounds like a fun experiment to see.

I think the bigger problem I'm having is the noise. I haven't put my scope on the unit to see if the noise is real or not, but my approach to filtering was to do a for loop acquiring 100 samples, and to do a moving average of 10 samples. Ie For I= 1 to 100 Daq = (analog input value + daq*9)/10

Would love to hear other people's thoughts on this.

On Sun, May 7, 2017 at 7:08 PM negativekelvin notifications@github.com wrote:

@dmody https://github.com/dmody interesting, have you tried to fit curves to the upper range and lower range separately?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/espressif/esp-idf/issues/164#issuecomment-299742244, or mute the thread https://github.com/notifications/unsubscribe-auth/ARtFwIoqc_VQwfuKdMKY0gdDNeBqlh1eks5r3k70gaJpZM4LNbPn .

markterrill commented 7 years ago

really interested in this

0xAl3xH commented 7 years ago

Are we going to fix this soon? I feel like many applications depend on this feature. Is there a workaround at least?

Spritetm commented 7 years ago

Yes, we are. It took us some time to build an automated testing rig to accurately and reliably grab the characteristics of a representative sample of ESP32s; that has rendered the first curves this week and we're working on converting these into some linearization code.

0xAl3xH commented 7 years ago

@Spritetm any updates on this? Perhaps a timeline to when this might be fixed? Thanks!

MaxSNi commented 6 years ago

@Spritetm @igrr I would love to hear an update on this - or if there is an effective workaround?

dmody commented 6 years ago

@MaxSNi The best workaround for me was to write a little function that returns the voltage based on the DAQ value using the formula I presented above. I can post the function if you like.

MaxSNi commented 6 years ago

@dmody I would love to see your function. I made a quick function from my own excel trend equation and while it does work better, its pretty crude...

dmody commented 6 years ago

@MaxSNi //*** Analog to Digital Conversion Function **** float A2D(float SenVal) { if(SenVal<1) return(0); else if (SenVal>4094) return(99); else return(-0.000000000023926 pow(SenVal,3) + 0.000000094746 pow(SenVal,2) + 0.00074539 * SenVal + 0.14925);

}

imotion-software commented 6 years ago

Is there any update on this issue? It sounds me really crazy that on an IoT chip there's no way to have a good ADC reading.

markterrill commented 6 years ago

Probably time to look at other options. i realised a few months ago its simply not going to be ready anytime this calendar year for production use

jan-bozelie commented 6 years ago

we have a simmulair problem , i can live with a correction factor but we discoverd in testing 10 esp32 samples , the difference between samples can be >10 to 20% , making a calibration nessesery for each esp , making it unusable for serios work

imotion-software commented 6 years ago

Hi @jan-bozelie. I'm aware there should be huge differences betweens samples due to the internal reference voltage regulator, but at the moment ADCs suffer of two distinct issues:

I think we should split ADC issue in two steps. Once we have corrected the non linearities, the EOS issue could be easily faced using an external voltage reference or a calibration procedure.

This problem has been totally ignored by Espressif, and I think ADCs are really important for an IoT application.

@igrr ... can we have an official response from Espressif about the fact ADC issue can or cannot be solved? At the moment we have a peripheral which is absolutely useless.

igrr commented 6 years ago

The official response has been already given by @Spritetm above (well, that is as official as you will get). We are working on both parts of the issue (nonlinearities and different v_ref):

V_REF compensation works pretty well, the errors which remain are due to run-time variation of V_REF. If you add an external reference voltage source and connect it to one of the ADC pins, you can apply correction at runtime, compensating even for temperature changes.

Linearization works best for low attenuation settings (0 and 1), as for these settings the transfer curve is closest to being linear. At attenuation setting 3 things get a bit more messy and hard to correct for, so we advise using lowest attenuation if possible. You will still not get rail-to-rail performance, but the result may be sufficient for a non-precision application.

(1): currently I can not give you any indication what that date might be.

imotion-software commented 6 years ago

Hi @igrr, really thank you for your feedback!

We have 10 samples of a custom board with an external 1.2V voltage reference (TI LM4041A12) and operational amplifier to filter input signals and adapt impedance. They have an output range of 0.15V to 1.8V (in order to avoid start end end of scale).

We tried to implement many of the linearization tables found (they are all different!) and also used an heavy software filter on the external voltage reference pad to correct dynamic fluctuations caused by the internal voltage reference instability and work always with the correct end of scale.

I tried this approach on 10 different boards, and with all of them we have acquisition errors close to the 5-10% (which is useless for an ADC).

In my opinion, the non-linear characteristic is something different chip by chip, it's not only a matter of the internal voltage reference. And if this true, there's absolutely no way to compensate it.

imotion-software commented 6 years ago

@Spritetm did you try to plot non-linear characteristic on different ESP32 chips?

Few users tried to plot it and they all get different results. I personally tried on few samples and always get something different...

jan-bozelie commented 6 years ago

No we have as utility a pilot development for in the medium gas distribution grid ( ongoing)

1 natural gas presure sensor 0-300mBar gauge --> 5V suply 0-3.3V output per home ( the sensor is max 0.5% error and is ok)

  And also not sensitive for 0.5V voltage variations in the supply

There is no noticeble noice on the suply voltage during this experiments

The ESP board has a stabelizer 5V tot 3.3V feeded with a usb adapter / or laptop usb port

We did make 10 samples ahead of a pilot of 5000pc

For each 10 sensors we did make a voltage measurement readung compared to a voltage calibrator , with oversampling and avagaging

From these measurements we did make a correction curve, reducing 10%relative eror to 1% we can live with that

Than we checked the other , assuming the correction curve is aplicapable for all esp

But no --> worst case error between 10 ESP32 samples is 20% , what would inplement we would have to calibrate each sensor seperate

What would take at lease 20min labour , and not afordable

Conclusion , we have to look for an other solution , or a fix

One experiment we planed = ( put more analog inputs in parallel of the same ESP32 )

Van: imotion-software [mailto:notifications@github.com] Verzonden: dinsdag 22 augustus 2017 13:53 Aan: espressif/esp-idf esp-idf@noreply.github.com CC: jan-bozelie jan@bozelie.com; Mention mention@noreply.github.com Onderwerp: Re: [espressif/esp-idf] [TW#12287] ESP32 ADC accuracy (#164)

@Spritetm https://github.com/spritetm did you try to plot non-linear characteristic on different ESP32 chips?

Few users tried to plot it and they all get different results. I personally tried on few samples and always get something different...

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/espressif/esp-idf/issues/164#issuecomment-324003352 , or mute the thread https://github.com/notifications/unsubscribe-auth/AdBrfwkasXeWB1AM092yUDkt9DIz518Cks5sasEvgaJpZM4LNbPn . https://github.com/notifications/beacon/AdBrf07IBwKQbKUCYoXl0WmIRHGEFMX4ks5sasEvgaJpZM4LNbPn.gif

jan-bozelie commented 6 years ago

I can confirm that is is chip to chip different from our 10 samples

In my aplication , (one sensor one esp32), i could live with an havy correction algoritm

I cant live with labour time and cost , for calibrating each analog input & each esp seperatly

Is there a bad sample ranproduction range ??

Van: imotion-software [mailto:notifications@github.com] Verzonden: dinsdag 22 augustus 2017 13:51 Aan: espressif/esp-idf esp-idf@noreply.github.com CC: jan-bozelie jan@bozelie.com; Mention mention@noreply.github.com Onderwerp: Re: [espressif/esp-idf] [TW#12287] ESP32 ADC accuracy (#164)

Hi @igrr https://github.com/igrr , really thank you for your feedback!

We have 10 samples of a custom board with an external 1.2V voltage reference (TI LM4041A12) and operational amplifier to filter input signals and adapt impedance. They have an output range of 0.15V to 1.8V (in order to avoid start end end of scale).

We tried to implement many of the linearization tables found (they are all different!) and also used an heavy software filter on the external voltage reference pad to correct dynamic fluctuations caused by the internal voltage reference instability and work always with the correct end of scale.

I tried this approach on 10 different boards, and with all of them we have acquisition errors close to the 5-10% (which is useless for an ADC).

In my opinion, the non-linear characteristic is something different chip by chip, it's not only a matter of the internal voltage reference. And if this true, there's absolutely no way to compensate it.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/espressif/esp-idf/issues/164#issuecomment-324002843 , or mute the thread https://github.com/notifications/unsubscribe-auth/AdBrf7BUz9ceTEpFCbc8SlpLlfbWp4WHks5sasCYgaJpZM4LNbPn . https://github.com/notifications/beacon/AdBrfyvs8QiQJywI5olP6KUU632b_-7fks5sasCYgaJpZM4LNbPn.gif

Spritetm commented 6 years ago

http://i.imgur.com/mTkip9V.png This is a set of a few boards. (We have more, but this is data I have right here). As you can see, the reference voltage of all ESP32s is slightly different (hence the steepness of the curve differs from esp to esp) and the start and ends of each curve as well as the entire attn=3 curve is non-linear, but apart from the reference voltage, the ESPs do not really have that different-looking curves.

imotion-software commented 6 years ago

Hi @Spritetm ! Is it possibile to have raw excel data of the graph you posted with those 8 devices?

vseven commented 6 years ago

Here is some testing I did tonight using freshly pulled code from repo and built firmware. 12-bit and atten at -11db (defaults). I do not know enough to change the atten or width...I can hack away at Arduino sketches but I don't know if I can change it from there and I'm not sure where to change it in the source before I build the firmware. If anyone can tell me I'll try the -6db setting instead of the default -11db and see if it's better:

6e0f1c1a78a49e90bd66b9abd2f8f91518157c7e_1_690x414

ESP32-Voltage-vs-ADC-Reading.txt

imotion-software commented 6 years ago

Hi @vseven,

if you want to change attenuation, there's a specific function "adc1_config_channel_atten". For width, you can change it calling "adc1_config_width".

I think -6dB should have a more linear characteristic, but probably reducing width will simply reduce noise but not non-linearities.

If you make a test at -6dB, please share result because I'm interested too.

vseven commented 6 years ago

Ive tried those commands in my Arduino sketch, multiple times, and just get a compile error. I must not have the syntax correct nor can i find it anywhere. I made a post on ESP32.com's forums asking but no reply yet. Once i change it i will retest and post.

vseven commented 6 years ago

Clarification: I have tried "analogReadResolution" and "analogSetAttenuation" from Arduino and it fails to compile. I guess I can try changing the static set values in the code and recompile the firmware? Only place I have found this would be in adc.h and platform.h and I would just hack it, changing the enum for 11db to equal 2 instead of 3 but that doesn't sound like a great idea.

EDIT: Figured it out...had to put the statements in my Setup().

androidcho commented 6 years ago

Does this bug get fixed?

vseven commented 6 years ago

No but i did a lot of work on getting better results that might help you: https://esp32.com/viewtopic.php?f=19&t=2881

negativekelvin commented 6 years ago

https://esp-idf.readthedocs.io/en/latest/api-reference/peripherals/adc.html#adc-calibration

rojer commented 6 years ago

ok, so basically vref needs to be routed to gpio, measured and recorded in the particular device so it can apply the right correction values. this is unfortunate. i assume this will be fixed in the future revisions of the chip?

in the mean time, i have an application where i only need to measure value of one thermistor. i wonder if i can use vref to gpio routing to avoid the extra calibration step. say, i have a circuit like this:

IO25 (Vref) ---,
               |
               RT
               |
IO34 ----------*
               |
               RB
               |
              ---
               -
               .

RT is the thermistor, RB is a bias resistor, value TBD. will using Vref like this allow me to get accurate reading of drop across RT on IO34 without calibration? using attenuation of 0, naturally.

DrBomb commented 6 years ago

How would we "burn" the Vref into the fuses? I'd like to make the test for every ESP32, store the value and not worrying about measuring it again.

negativekelvin commented 6 years ago

@rojer they say chips will ship with factory cal burned to efuse at some unspecified time in the future or possibly by special order.

rojer commented 6 years ago

@negativekelvin that makes sense.

@DrBomb i know you're a mOS user, so this may be handy - mos utility can operate on eFuses:

$ mos -X esp32-efuse-get
...
$ mos -X esp32-efuse-set
Error: one or more ops required. op is 'fuse=value', 'fuse=@file' or 'fuse.{WD|RD}=1'

i guess you could use (part of) the user_key field for this.

rojer commented 6 years ago

FWIW, here are my results from 10 devices i had lying around, calculated error % before calibration and after. 12 bits, 11 db atten. columns are: id, measured voltage on input: raw reading => voltage @ vref 1100 (error %); measured vref => voltage @ vref (error %).

00, 1.648: 1953 => 1.697 (3.0%); vref 1.070 => 1.657 (0.5%)
04, 1.669: 1886 => 1.642 (1.6%); vref 1.100 => 1.642 (1.6%)
05, 1.650: 1835 => 1.600 (3.1%); vref 1.130 => 1.639 (0.7%)
06, 1.653: 1856 => 1.618 (2.2%); vref 1.122 => 1.648 (0.3%)
AC, 1.651: 1819 => 1.586 (4.1%); vref 1.132 => 1.628 (1.4%)
03, 1.643: 1776 => 1.552 (5.8%); vref 1.143 => 1.608 (2.2%)
tt, 1.635: 1778 => 1.556 (5.1%); vref 1.129 => 1.595 (2.5%)
SL, 1.658: 1839 => 1.604 (3.4%); vref 1.119 => 1.629 (1.2%)
5C, 1.640: 1819 => 1.587 (3.3%); vref 1.129 => 1.625 (0.9%)
9C, 1.654: 1891 => 1.646 (0.5%); vref 1.105 => 1.652 (0.1%)

so, calibration gets the errors down, but doesn't quite eliminate them.

also, i found that reading ADC disables vref output to the pin, which is unfortunate.

negativekelvin commented 6 years ago

Are you averaging multiple samples?

jan-bozelie commented 6 years ago

Yes we did and it improved the noice error , as we could expect

Van: negativekelvin [mailto:notifications@github.com] Verzonden: zaterdag 30 september 2017 09:22 Aan: espressif/esp-idf esp-idf@noreply.github.com CC: jan-bozelie jan@bozelie.com; Mention mention@noreply.github.com Onderwerp: Re: [espressif/esp-idf] [TW#12287] ESP32 ADC accuracy (#164)

Are you averaging multiple samples?

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/espressif/esp-idf/issues/164#issuecomment-333290111 , or mute the thread https://github.com/notifications/unsubscribe-auth/AdBrf7zTC-cTKnUmmpiwW-jCk_qbKrEZks5snewNgaJpZM4LNbPn . https://github.com/notifications/beacon/AdBrf5Hmjj5auK5I-dNJKTJB8nnL_Bx1ks5snewNgaJpZM4LNbPn.gif

jan-bozelie commented 6 years ago

Thanks , for the info --> informative

however, calibrating each io is killing each business case

I did buy pressure sensors with 0.25% accuracy , adding than 2.5% is a lot

Van: Deomid Ryabkov [mailto:notifications@github.com] Verzonden: vrijdag 29 september 2017 23:34 Aan: espressif/esp-idf esp-idf@noreply.github.com CC: jan-bozelie jan@bozelie.com; Mention mention@noreply.github.com Onderwerp: Re: [espressif/esp-idf] [TW#12287] ESP32 ADC accuracy (#164)

FWIW, here are my results from 10 devices i had lying around, calculated error % before calibration and after. columns are: id, measured voltage on input: raw reading => voltage @ vref 1100 (error %); measured vref => voltage @ vref (error %).

00, 1.648: 1953 => 1.697 (3.0%); vref 1.070 => 1.657 (0.5%) 04, 1.669: 1886 => 1.642 (1.6%); vref 1.100 => 1.642 (1.6%) 05, 1.650: 1835 => 1.600 (3.1%); vref 1.130 => 1.639 (0.7%) 06, 1.653: 1856 => 1.618 (2.2%); vref 1.122 => 1.648 (0.3%) AC, 1.651: 1819 => 1.586 (4.1%); vref 1.132 => 1.628 (1.4%) 03, 1.643: 1776 => 1.552 (5.8%); vref 1.143 => 1.608 (2.2%) tt, 1.635: 1778 => 1.556 (5.1%); vref 1.129 => 1.595 (2.5%) SL, 1.658: 1839 => 1.604 (3.4%); vref 1.119 => 1.629 (1.2%) 5C, 1.640: 1819 => 1.587 (3.3%); vref 1.129 => 1.625 (0.9%) 9C, 1.654: 1891 => 1.646 (0.5%); vref 1.105 => 1.652 (0.1%)

so, calibration gets the errors down, but doesn't quite eliminate them.

also, i found that reading ADC disables vref output to the pin, which is unfortunate.

— You are receiving this because you were mentioned. Reply to this email directly, view it on GitHub https://github.com/espressif/esp-idf/issues/164#issuecomment-333244540 , or mute the thread https://github.com/notifications/unsubscribe-auth/AdBrf3Rxzrq8sTqrvyQKnSoxqQgmv8etks5snWJZgaJpZM4LNbPn . https://github.com/notifications/beacon/AdBrf4j0b-sqdV7HFJ6Pi_c8XKsNcrGOks5snWJZgaJpZM4LNbPn.gif

rojer commented 6 years ago

Are you averaging multiple samples?

i was not. i'd take a reading every second, print it out, and then use one of these lines to compute.

[Sep 29 22:25:36.037] timer_cb             Tick 1890 1645 (vref 1100) 1651 (vref 1105)
[Sep 29 22:25:37.037] timer_cb             Tock 1887 1643 (vref 1100) 1649 (vref 1105)
[Sep 29 22:25:38.037] timer_cb             Tick 1886 1642 (vref 1100) 1648 (vref 1105)
[Sep 29 22:25:39.037] timer_cb             Tock 1891 1646 (vref 1100) 1652 (vref 1105)
[Sep 29 22:25:40.037] timer_cb             Tick 1894 1649 (vref 1100) 1655 (vref 1105)
[Sep 29 22:25:41.037] timer_cb             Tock 1888 1644 (vref 1100) 1650 (vref 1105)

calibrating each io is killing each business case

exactly my thinking. it's imperative that Espressif starts doing it at some point, or we can forget about ADC for all but the most trivial applications.

androidcho commented 6 years ago

So we won't get linearization data integrated into ESP-IDF? Very bad if that's the case..

projectgus commented 6 years ago

So we won't get linearization data integrated into ESP-IDF? Very bad if that's the case..

Linearization of ADC readings is integrated into ESP-IDF now via the esp_adc_cal API. The part which is still pending is being able to calibrate the chip's internal Vref (a fixed voltage offset applied to the linearized value) from a value shipped in the ESP32 from the factory.

Right now the options are:

Future revisions of the ESP32 will have VRef measured as part of the in-factory test, with the value stored in efuse.