5
\$\begingroup\$

While working on my project, I got to a point where I don't know the answer. I have a 10-bit ADC (the one incorporated in the ATMEGA328P) and it returns values up to 1023 (210 - 1).

The official documentation states that the equation to convert the values from the ADC to the corresponding voltage is:

$$ V = \frac{V_{in} \cdot ADC}{2^{10}} $$

But, if the values go up to 1023, then wouldn't it be better to replace the 210 by 210 - 1?

Thanks.

\$\endgroup\$
  • 2
    \$\begingroup\$ Doesn't matter. The poster is correct. Or, if you will, the poster is correct BECAUSE one of the 1024 ADC values is zero. \$\endgroup\$ – WhatRoughBeast Feb 16 '17 at 17:01
  • \$\begingroup\$ @FakeMoustache If 0 was divided by 1023, it would return 0, same as if it was divided by 1024. But if 1023 (the maximum achievable value) was divided by 1024, it would be different than dividing it by 1023. If the maximum value that can be returned is 1023, wouldn't it be better to be divided by 1023? \$\endgroup\$ – jparenas Feb 16 '17 at 19:15
5
\$\begingroup\$

Ignoring the harsh reality of the performance of ADCs which can be cheaply built into MCUs, in the ideal case each output count represents a possible well-defined range of input voltages.

Here is an ideal (according to Atmel's definition) 3-bit ADC.

enter image description here

There are \$2^N\$ steps. In the above example, that is 8. With an ideal unipolar ADC, an input of lower than \$\frac{V_{REF}}{2^{N+1}}\$ will give an output of 0- as you can see above, below 1/16 of the 2V reference voltage the output code will be 0.

Between \$\frac{V_{REF}}{16}\$ and \$\frac{V_{REF}}{16}+\frac{V_{REF}}{8}\$ the output count will be 1 and so on, with each step the same.

When you get up to the top of the range, a count of \$2^N-1\$ (maximum count) will represent a voltage greater than \$V_{REF}\cdot \frac {13}{16}\$.

So- the best guess (minimizing error) for a given count x (where \$ 0 \lt x \lt 2^{N-1}\$) is \$ x \frac{ V_{REF}}{2^{N}}\$, as given in the original question.


Usually MCU ADCs will saturate so ideally in the special case of x=0 you can say the input voltage is less than \$0.5 V_{REF}\cdot \frac{1}{2^N}\$ = \$V_{REF}\cdot \frac{1}{2^{N+1}}\$ and if x = \$2^{N-1}\$ then the input voltage is greater than \$V_{REF}\cdot\frac{ 2^{N+1}-3}{2^{N+1}}\$


Of course with a typical MCU of 10 bits or greater, the ADC error and noise will usually exceed 1 LSB, and Vref will usually not be accurate to 1 LSB either so it doesn't matter that much.


TL;DR

Use the original equation.

\$\endgroup\$
  • \$\begingroup\$ Hahahha that TL;DR \$\endgroup\$ – Sean87 Feb 8 at 10:30
2
\$\begingroup\$

jparenas, this is a question that comes back regularly, being a source of confusion when working with ADCs. It's closely related to the classic confusion: Full Scale Voltage (FS) versus Reference Voltage (Vref). In order to keep things simple, please consider a hypothetical 3-bit ADC (\$N\$ = 3), without the commom 0.5 LSB compensation on input (as, I think, occurs on ATmega328p) - in such case, the results obtained here does not differ so much. Three parts:

(a) See the transfer function (a) in the image below, where Va is the analog voltage and Vd is the converted digital value. FS it's just the voltage which corresponds the transition to maximum digital value (7 or \$2^N-1\$). Also, there are seven steps horizontally and seven steps vertically, where each step occurs in multiples of 1/7 FS. Let FS = 4.375 V, then each analog step is 0.625 V. Note that the sloped dashed line connecting the coordinates (0;000) to (FS;111) represents the ideal conversion that every engineer would want. So:

$$ Vd = int\left (\frac{Va}{FS}\times 7\right) $$

Here we can isolate Va to find a simple expression it:

$$ Va = \frac{Vd}{7}\times FS $$

But wait! The things are not so simple: To be more rigorous, we can see that the voltage Va actually can assume any value within a interval. Applying the definition of \$int()\$ function:

$$ \frac{Vd}{7}\times FS \leq Va < \frac{(Vd+1)}{7}\times FS$$

(b) Now see the transfer function shown in (b). Note that if there were another additional step of 1/7 FS, we could associate it with a full digital value of 8 (or \$2^N\$). Voilá! Let's call it Vref:

$$ Vref = \frac{8}{7}FS $$

Note that, for our FS = 4.375 V \$\Rightarrow\$ Vref = 5 V. See the expression \$ FS = \frac{7}{8}Vref \$. It's another way for stating that FS stays 1 LSB below Vref. Does not matter here, but for 0.5 LSB input compensated ADCs, FS would be 1.5 LSB below Vref.

(c) Finally rewrite the whole thing based only on Vref, removing that additional step. So, we get the transfer function shown in (c) - similar to the one found in datasheets, based entirelly on \$2^N\$ factor. Everyone is happy! But note there are 7 steps vertically and 8 steps horizontally. The expression for Vd is replaced to:

$$ Vd = int\left (\frac{Va}{Vref}\times 8\right) $$

Also:

$$ \frac{Vd}{8}\times Vref \leq Va < \frac{(Vd+1)}{8}\times Vref $$

ADC Transfer functions:

Dirceu Rodrigues Jr.

Thus, we can use either \$(2^N-1)\$ or \$2^N\$, since correctly associated with FS or Vref values, respectively. According the plot (c) the bad news is that we can't "measure" the Vref value (indeed, identify when the transition to this value occurs). Of course, we can overcome the problem using resistive dividers and amp. ops on ADC input to matching the value we want. But this may not worth in practice: Besides the differences being very small (for a 10-bit ADC or greater), also there are the non-idealities of the AD converter. Finally, the resistor's tolerance used could "spoil" the whole thing.

An advantage of using division by \$2^N\$ is that in simple microcontrollers (particularly 8-bit) nor having a instruction for division: This can be replaced by multiple right shifts. The difference is that the rounding for signed division is "towards zero" and for arithmetic right shift is "negative infinity". More sophisticated processors, such that ARM (other than the Cortex-M0), already incorporate instructions for division in a few cycles and single cycle multiple shifts through the native barrel shifter - with minor difference in performance.

\$\endgroup\$
1
\$\begingroup\$

You are right. The maximum digital value (1023) represents the ADC reference voltage. Therefore division by (2^(number of bits) - 1) is correct.

\$\endgroup\$
  • \$\begingroup\$ But the error is most likely more than 1 count, so trim it with a calibration constant if you really need it that accurate. \$\endgroup\$ – skvery Feb 16 '17 at 18:58
0
\$\begingroup\$

You are correct to assume both cases. Either 1023 or 1024 could be utilized in the equation since 0 is also represented. Therefore, there is 1024 different digital values to represent your analog signal where 1023 is your maximum and 0 is your minimum.

For example, if you have a peak on your analog signal of 5V, this value going through the ADC would be represented as 1023.. If 0V is your minimum, 0 would be the value coming out of your ADC. In the end, it only makes a slight difference. If you really need precise measurement and this equation is causing you issues, I would try a different microprocessor or development board since it is not that fast and 1024 bits is average for ATMEGA328p..

\$\endgroup\$
  • \$\begingroup\$ Thanks for the answer. I will stay with the ATMEGA328P as it works just fine for my project. I just wanted to clear that question out of my mind. \$\endgroup\$ – jparenas Feb 16 '17 at 19:17
0
\$\begingroup\$

Without taking away from Spehro's answer, this is how I like to think of it. Most programmers are familiar with a similar situation with pixels:

Take a theoretical monitor measuring 1000mm across with 1000 pixels. Each pixel measures 1000/1000 = 1mm. Pixels are addressed starting from zero. So the left most pixel is #0 and its size on a ruler would stretch from 0mm to 1mm. The right most pixel is #999 and its size stretches from 999mm to 1000mm.

So if you want to take #999 as 999mm you have a reading that is scaled correctly but always rounded down.

However if you decide that #999 really means "1000mm" you force a rescaling of every single pixel to 1000/999 = 1.001mm. You still have the usual 0.5 rounding error but now a scaling error too!

You may be able to tolerate this error if you don't mind that higher values are rounded up and lower values are rounded down.

Also note that integer division will also cause a rounding down to the nearest n.

And, as Spehro has said, the ADC error and noise will usually exceed 1 LSB anyway.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.