ADC Linear Gain/Offset Correction

In my last post I explored the errors of unprocessed ADC data. In this post, I will show what happens if you add some simple gain + offset correction.

Arduino INL

Gain error is caused by DNL. The ideal code width is 1, but lets say that there is a predictable DNL error of +.1 LSB- that means that for every code (and there could be a lot of codes!), the measured value strays from the ideal value by +.1 LSB. At the end of the range, the difference will be +.1LSB * number of codes. This (in the example) is equal to INL. Take a look at the INL of the arduino above- the average code width is 1.08, so the INL increases by .08 LSBs/code. Therefore the INL looks like a straight line when plotted against LSB.

Corrected INL plot for Arduino

If we just assume each LSB is a little bigger, we will get a much lower INL. This will cause us to loose a little voltage resolution (.08 LSBs), but we will end up with a MUCH lower INL. This is the same data, but with gain correction. INL was reduced from 85 LSBs to about 6 LSBs.

However, the INL can still be improved- at low voltages, the most ADCs dont work very well. This causes a large DNL at the first code, as seen here in the corrected plot. This is where the line shoots straight up from 0 to about 6 at the first ADC code.

Arduino uno adc near code 0. orange line is the end of adc code 0

On a plot of DAC input-ADC output, it looks like the above – basically code 0 has a huge width. We can null this out by just adding a small offset to all the data. That means code 0 will still be wrong, but the rest of the codes will be right. because only the first code is messed up, we can usually ignore this error because we it only exists for a single code (code 0).

MUCH better

Here is the DNL for the fully corrected ADC- the max DNL across the whole ADC is closer to .8 now, except at code 0, which is off by about 6LSBs. This is equivalent to saying we cant measure less than 6 LSBs, but that if we make these corrections we will have an accuracy that is about .00084 mV (with 100x oversampling). That is pretty darn good.

What about the other ADCs?

How much can the other ADCs be improved? The ADS already has a pretty perfect gain and very little offset, so I skipped trying to fix it. Note the new LSB size and standard deviation are different than the previous values – to avoid the influence of the extremes of the ADCs, I only used the middle 90% of the ADC range to calculate the average LSB size.

ADC NAMELost Range
(millivolts)
New LSB size
(LSBs)
Compensated INL
(LSB)
INL Improvement
(LSB)
Compensated INL
(Volts)
ADS101501.160.00008
ESP (COMP)1971.00±.7123.8*129.2.006
ATMEGA328P61.08±.070.8683.62.0009
SAMD21231.01±.5011.263.85.002
*this is actually much worse

Surprisingly, the ESP and the SAMD are much closer in this comparison. SAMD still wins out, but at least the ESP32 has recovered slightly from having a three-digit INL. The one caveat here is that my calculation of code widths does not account for missing codes, which produce -1 DNL each. This data is correct if the missing codes on the ESP (of which there are 15) need to be ignored for this to be valid.

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out /  Change )

Twitter picture

You are commenting using your Twitter account. Log Out /  Change )

Facebook photo

You are commenting using your Facebook account. Log Out /  Change )

Connecting to %s