2
\$\begingroup\$

On a custom board I have an ADC which measures -5V to +5V. And outputs in Hex via SPI like this:

0x8000 to 0x0000 = most negative to 0
0x0000 to 0x7FFF = 0 to most positive

I just started studiyng ADCs so I am not sure what is going on. I beleive I have negative full scale of -5V and positive full scale of +5V.

Questions:

  • What this numbering system is based on? Is it two's complement?
  • Why there is no 0xFFFF value?
  • How can I convert these numbers to a real voltage?
\$\endgroup\$

closed as unclear what you're asking by pipe, Marcus Müller, Sparky256, mkeith, Bimpelrekkie Feb 12 at 9:28

Please clarify your specific problem or add additional details to highlight exactly what you need. As it's currently written, it’s hard to tell exactly what you're asking. See the How to Ask page for help clarifying this question. If this question can be reworded to fit the rules in the help center, please edit the question.

  • 9
    \$\begingroup\$ That's up to the ADC datasheet to define. You don't mention the ADC type, which would be integral to this question... \$\endgroup\$ – Marcus Müller Feb 8 at 12:03
  • \$\begingroup\$ are you sure your ranges are correct? \$\endgroup\$ – Colin Feb 8 at 12:27
  • 3
    \$\begingroup\$ There is a 0xFFFF value. That's -1. \$\endgroup\$ – brhans Feb 8 at 12:42
  • 1
    \$\begingroup\$ VTC until the specific ADC is mentioned, otherwise we can only guess. @MarcusMüller You should probably also VTC if you really think the information is integral to the question. \$\endgroup\$ – pipe Feb 8 at 16:14
  • \$\begingroup\$ Basically, that is impossible. The two ranges overlap almost completely. Just as one example, 0x7FFF is inside the range 0x8000 to 0x0000. So is it negative or positive? It is not two's complement (or any other numbering system) and it is not possible to convert it to a real voltage because almost every number will fall into both positive range and negative range. Given the time that has passed, with no additional comments from OP, I agree that this question should be closed. \$\endgroup\$ – mkeith Feb 12 at 5:57
8
\$\begingroup\$

It looks like you have a 16-bit, 2's-complement ADC with a range of \$-5V \le V_{IN} < 5V\$. If that's the case, then the digital values can be interpreted as signed integers from -32768 to +32767. The measured voltage is

\$ V_{IN} = \frac{DigitalValue}{32768} \times 5\$

\$\endgroup\$
4
\$\begingroup\$

I'll just add to @Eliot's answer that in reality if you have floating point math available (and choose to use it) you should convert DigitalValue to floating point before dividing.

If you only have integer math available you can multiply by five (you need more than 16 bits, obviously) and then throw away the least-significant 2 bits (or round) and place the radix point right of the 4th bit. For example 0x7FFF FFFF -> 0x27FF FFFF FB -> 0x4.FFF FFFF (one LSB less than 5.0000).

\$\endgroup\$
  • \$\begingroup\$ Wow this is a cool trick...but luckily stm32 arm core can handle floating points no problem...I guess your trick is good for 8bit micros? \$\endgroup\$ – DEKKER Feb 12 at 2:37
4
\$\begingroup\$

If you count most negative to 0 using integers, you count ..., -4, -3, -2, -1, 0 If you count most negative to 0 using hexadecimals, you count (in your case) 0x8000, 0x8001 ..., 0xFFFE, 0xFFFF, 0

So, there is the 0xFFFF.

Now, your scale is 0X8000 to 0x7FFF, so, in decimal -32768 to 32767, the full scale is 65636 (-32768 +-32767 + 1). The scale represents -5V to +5V, full scale 10V. The conversion is:

Vmeasured = SPI_OUPUT_in_HEX / 65536 * 10V

P.S. I guess using 65536 or 65535 for dividing is a matter of taste; it hardly influences the accuracy. Using 65535 may be preferable/nessecary in old tiny microprocessors.

\$\endgroup\$
  • \$\begingroup\$ So how do you get -5 out of your formula when the digital value is 0x8000? I think you are assuming an input range of 0 to 10V rather than -5V to +5V. \$\endgroup\$ – Elliot Alderson Feb 8 at 13:50
  • 2
    \$\begingroup\$ How would 65535 be necessary? 65536 doesn't need a divide instruction at all, it's just a right-shift by 16 places (in integral or fixed-point math) or ldexp(x, -16) on floating-point. \$\endgroup\$ – Ben Voigt Feb 8 at 14:58
  • \$\begingroup\$ You're right, my reason was that 65536 is easier to shift. I made a typo. \$\endgroup\$ – Huisman Feb 8 at 15:56
  • \$\begingroup\$ @Elliot The question says 0x8000 = most negative number... so in the context of the question it is -32768 \$\endgroup\$ – Huisman Feb 8 at 15:57
  • \$\begingroup\$ So you should use a signed, integer value rather than the HEXVALUE in your equation? I think that part is confusing. \$\endgroup\$ – Elliot Alderson Feb 8 at 15:59
3
\$\begingroup\$

Recommended thing would be to grab datasheet for your ADC chip and see in chapter named "Data Format". In this chapter it will be explained how the numeric values (data) from the ADC is represented.

It seems that your digital representation is something named 2's complement. Here is the wiki link.

From values you have provided I assume it is 16-bit ADC. So, max value 0x7FFF is your +Vref (positive reference voltage) and 0x8000 is -Vref (negative reference voltage). 0xFFFF in 2's complementary equals to -1.

Example:
Let's say your positive reference voltage is 2.5V, and negative reference voltage is -2.5V, then when you see obtained value of ADC equal 0x7FFF it means you have 2.5V on the ADC input. To calculate other positive values you take Vref and divide it by numbers of bits value (0x7FFF equals to dec 32767), so if your ADC gives you 0x0001 is equivalent of

1 * (2.5[V]/32767) = 0.0000763[V]  

BTW, this smallest step your ADC is capable to measure is called ADC resolution

Let's have about half range of positive ADC, so now your ADC gives you a number of 0x4000. This is 16384 dec, so calculation here is:

true_voltage_value = 16384 * (2.5[V]/32767) = 1.250099[V]

For negative numbers: if your ADC value is bigger or equal to 0x7FFF then your action may be: negative_measured_value = measured_value - (0xFFFF + 1)
So, when ADC provides you value of 0xFFFF it goes:

negative_measured_value = 0xFFFF -  (0xFFFF +1) = -1  
true_volt_value = -1 * (2.5[V]/32767) = -0.000076V

Huisman answers it as well.

Note: The values calculated here are theoretical, and how precise your measurement is depend from stability and accuracy of reference voltage(s).

\$\endgroup\$
  • 1
    \$\begingroup\$ If you are doing the math on a 16 bit integer your formula for negative_measured_value just returns measured_value. \$\endgroup\$ – Elliot Alderson Feb 8 at 13:53

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