While I was working lately on a project to build a joystick using salvaged parts from an old RC transmitter https://github.com/fryktoria/arduino_Gaming_Controller which is utilizing the Analog to Digital Converter (ADC) of an Arduino, I once again stumbled upon the age old question:
“To find the voltage that produced a value of A as a reading on the ADC converter, the correct formula isA * Vref/1023
orA * Vref/1024
?”.
Discussion forums hosted several opinions, some purely theoretical, others practical and of course some totally misleading. During the past years, I have not encountered any forum that provided a conclusive response on this question. So, I wanted to check what our Artificial Intelligence friends have to say about that.
As expected, AI machines are trained by the information they find online. One was in favor of 1024, explaining that this is the correct value, because it is consistent to the theory of the operation of Analog to Digital Converters. It also considered 1024 as the value that provides the highest precision, making this approach more applicable to operations that require high accuracy. Yet, asking the machine why some people are in favor of 1023, it took an neutral position, stating that the results do not differ so much and that although 1024 is “dictated” by some obscure mathematical theory, 1023 provides more “practical” results, whatever that means.
Another AI engine was absolutely and without any doubt in favor of 1023. After I insisted that 1024 would be a better option, it explained that the difference is subtle and provided a more detailed explanation. This same engine is so indoctrinated with 1023, that even after I asked it to summarize this very same article, it still insisted that this article considers 1023 as correct!!!
So, if our fellow colleagues of the future would like to be informed on our final verdict, would they consider that it is just a matter of personal opinion? At the time that scientists are arguing on quantum mechanics, how can we leave such a trivial issue without a clear and precise answer?
Before I proceed to the verdict, let me explain that the argumentation started when people realized that the 10-bit analog to digital converter of the ATMega328 microprocessor of the Arduino Uno provided values from 0 to 1023, and therefore they considered that 0 should be the value produced by the minimum input voltage, i.e. 0 Volt and 1023 should be the value produced by the highest value of the reference voltage, usually 5V or 1V.
Several schools of thought crossed their swords:
Only a few people tried to shed real light to the problem but their voice was lost in the noise. Professional experts may have decided to stay out of this, since in a discussion forum, an expert's vote has the same gravity as all of the others. So, will the AI engines of the future have every right to consider us stupid for not reaching a conclusion?
Considering that the question is:
“What is the voltage that is input to an analog port of ATMega328 which produces a digital value of A?”
There is only one correct response:
“The voltage isA * Vref/1024
plus or minus 2 LSB and provided that there are no external or internal noise sources that would alter the reading”.
Therefore, if the ADC reading is 512 and Vref is +5V, the voltage producing the reading is 512*5/1024 = 2.5 V plus or minus 2 * 5/1024=0.01V, assuming that there is no noise.
The most appropriate reference for this is paragraph 24.7 of the ATMega328 specification document, page 252. For those who may not have access to electronic design books or even do not wish to spend a lot of time in reading ADC theory, paragraph 24.6.3 may give a small insight to ADC accuracy.
On top of 24.7 that has been referenced in a few forums, one should not ignore the ADC features in paragraph 24.1, where it is stated that:
“the Absolute Accuracy of the 10-bit ADC is +- 2LSB”
Finally, at the end of paragraph 24.7, it is stated that:
“0x000 represents analog ground, and 0x3FF represents the selected reference voltage minus one LSB”
0x3FF is decimal 1023, so the very designers of the ADC inform us that the maximum digital value produced by the ADC is not expected to reach the reference voltage. Considering also that the +- 2 LSB accuracy, there is a whole range of voltages that may produce 1023. This proves that the very concept of considering 1023 as equal to the reference voltage is invalid.
It is strange that lots of people, as well as their trained AIs have the wrong belief that the maximum ADC value should be equal to the voltage reference. Consider for example the most simple ADC with one bit. This is actually a comparator circuit. Assume that the threshold has been set to half of the reference voltage, such as 2.5 V for a Vref of 5 V. To keep things simple, assume also that there is no hysteresis over the threshold voltage. In that case, digital 0 is the output of the ADC for every voltage between 0 V and 2.5 V. Digital 1 would be the ADC output for every voltage higher than 2.5 V. How is it possible that somebody would even think that 1 should be exactly 5V? A 10-bit ADC such as the one of ATMega328 implements multiple such comparison thresholds and the voltage range between two successive thresholds is of course much, much smaller (ADC implementations use various methods to make the conversion but this is irrelevant at the moment). But the concept is exactly the same: 1023 is the output of the ADC, when the input voltage falls within the range of voltages, higher than the highest comparison threshold and up to the maximum voltage that the analog port input can sustain.
Because 1023 would be the correct response to a different question. That question would be:
“How do I map the readings 0 to 1023 of the analog to digital converter to a value between 0V and Vref?”
I would also like to add:
“… considering that I am aware of the consequences of my decision to do this mapping.”
This would be a totally valid question to someone who is building for example a digital display to somehow present the input voltage. For most projects where the designer has already selected an ATMega328 as the appropriate and adequate analog to digital converter, a precision of 0.02 Volts and a resolution of two decimal digits may suffice. It is always the responsibility of the designer to estimate the maximum allowed error.
Therefore, the question for which 1023 is the correct answer, has to do with the mapping of parameters between the input and the output and not to absolute voltage level. The mapping of the analog to digital converter output does not actually preserve the units of input to the output. The output might as well be floors of a building or the number of coconuts stored one on top of each other, after having being carried by a European swallow (forever cursed by Monty Python, to think about the average air velocity of laden swallows, every time a reference to coconuts is made). Actually, the symbol V
is simply printed next to the display presenting the voltage, so the actual value of the voltage is disassociated from whatever appears on the display.
A most common application would be to convert 0-1023 to percentages from 0% to 100%. After this conversion, you can manipulate the values any way you like. But, please, do not refer to abolute input voltages, unless you accompany your data with the proper documentation and validation.
As a proof of thought, consider the map
function of the Arduino ecosystem.
long map(long x, long in_min, long in_max, long out_min, long out_max) { return (x - in_min) * (out_max - out_min) / (in_max - in_min) + out_min; }
Supposing that we wish to apply the map
function to map a value x between 0 - 1023 to a value between 0 and 5, the calculation would be:
(x - 0)(5-0) /(1023 - 0) + 0 = x * 5 / 1023
This shows where 1023 comes from. And also shows that there is no need to explicitly set a dimension, such as a voltage unit (V) after the 5. Might as well be a (C) for coconut, for those who considered the coconut analogy just a joke!
Arguments regarding comparison of accuracy between the two methods are meaningless, when you try to compare different things. Would it be logical to say that 1 Kg is 999 grams, because the difference is very small? Or, would it be logical to say that we make a personal choice to select 1000 grams because it provides more accurate results to the calculations compared to 999 grams? Absolutely not. This is not a matter of personal opinion. It is a waste of brain power to discuss about accuracy and precision, when the approach is faulty by inception.
Yes, of course there are cases where we take decisions to exclude parameters that have a small incluence on our calculations. You will not be crazy to include the Special Theory of Relativity when you design a tachometer for your kid's bicycle. We only take shortcuts when we understand the controlling mechanisms, regardless if it is a device or a business process. The whole point of the simplification is to make things easier to implement, having defined the acceptable error that this simplification will cause.
Induced errors should always be taken into account. I am certain that most people complaining about getting “bad” readings from an ADC, which I mentioned as “haters” above, are experiencing problems with unstable power supplies, missing accurate voltage references, bad decoupling, crosstalk, stray inductance and capacitance, as well as several other causes of error lurking in the implementation of an electronic circuit. The ATMega328 manual itself provides several information on how to disable internal MCU functions in order to minimize the noise that would alter the readings of the ADC. Also, there is currently online a lot of both scientific and practical/experimental documentation on the design of the cabling and PCB traces. Building a circuit that faces the hardness of the real world goes way beyond writing some lines of code and consider that the circuit will behave exactly as a well-mannered and predictable software.
It always depends on what exactly you want to do. If for example, your intention is to present your data to your user as a slider that goes from 0% to 100%, then it is a mapping problem and the proper value to use is 1023 and not 1024. But if you care about absolute values, why use 1023 when you know that the correct value is 1024? It is true that the difference between the results obtained using 1023 or 1024 is quite small. Actually, the practical thinkers would be happy to know that the value obtained using 1023 falls within the 1 LSB range between two successive ADC readings, so that actual difference is lower than the +-2 LSB absolute accuracy that the ADC provides. Yet, the small difference is not an excuse to knowingly do something wrong.
In conclusion, you need to analyze your problem and most important, to define your acceptable margins of error. If your display presents a value that is not stable at the second decimal point, this does not mean that your ADC is crap. It is your responsibility to inform the users on what exactly they are observing.
Going back to the Arduino map
function, every unit of x is approximately 5 mV. The +- 2 LSB error means that the difference between the “real” input voltage to the output is +- 10 mV (+-0.01 V), or a range of 20 mV, without even taking into account other sources of error and noise. You cannot fool yourself or the users of your device to think that, although they see in a resolution of 2 decimal digits, the value is 100% accurate.
I would also like to point out that there are other mapping functions that you can use in your application. If you do not care about going to the extremes of 0% and 100% of the scale, you may consider the A * Vref/1024 + 1/2 LSB
. This function creates a better fit of the ADC stepped curve to a linear input from 0 to Vref.
I believe that it has been proven beyond doubt at the discussion above, that you get correct answers only if you ask the right questions. Whenever I face an unsolvable problem, I remember what my teachers have been telling me:
“If you cannot find the solution to a problem, read again the description of the problem”
If you obtain a better understanding of the nature of the problem and even re-phrase it in a way that the new expression exposes the parameters that govern the dynamics of the problem, you will have many more chances to solve it.
Same with AI. I purposely did not present here the questions I submitted to the AI engines and their exact answers, since the phrasing of the question produced a totally different result. It seems that AI behaves exactly as the discussion forums they have been trained with. It is a great tool. Let us train it by providing correct data.