ADS1115 (A/D converter) Problem

zorgloub

Member
Hello to the Community
I am experiencing the wonderful, complete and cheap Analog/Digital Converter ADS1115-16bits-4channels-i2c.
However, I have a strange problem that I can't explain.
I have configured the register for normal reading on input AIN0 and between GND and I am measuring a voltage of 3.3V.
The Full Scale PGA is correctly configured to 4.096v.
The data returned are perfectly correct when I measure the 3.3v.
But when this input is set to GND, the MSB saturates to FF and the LSB also approaches an almost as high value.
While these two bytes should be very close to zero, or even equal to zero!
Nothing changes if I put a pull-down resistance on the input.
Do you have an explanation for solving this false measure, which is certainly a problem for me?

The code and diagram are in the attached pdf.

Thank you in advance.
 

Attachments

hippy

Technical Support
Staff member
But when this input is set to GND, the MSB saturates to FF and the LSB also approaches an almost as high value.
I would guess the ADC allows negative readings and what you are seeing is a two's complement result where a small negative value is also what a large unsigned value would look like, eg -

$FFFF = -1
$FFFE = -2
$FFFD = -3
etc

You could either consider anything with bit15 set ($8000) to be 'zero' or could do a more complicated adjustment as "voltage = (adc + K) / N".

I would start with this and see what that shows -
Code:
Hi2cin (MSBy,LSBy)
If MSBy < $80 Then
  Gosub Convert
  Sertxd ("---> MSB = ",#b8," LSB = ",#b9," MilliVolts = ",#W0,cr,lf)
Else
  b1 = MSBy
  b0 = LSBy
  w0 = -w0
  MSBy = b1
  LSBy = b0
  Gosub Convert
  Sertxd ("---> MSB = ",#b8," LSB = ",#b9," MilliVolts = -",#W0,cr,lf)
End If
There is likely some mileage in putting MSBy after LSBy, eg MSBy=b9, LSBy=b8 and then you can take advantage that the 16-bit value is automatically created in w4, which seems to be Vin. That would help simplify the Convert routine and the above code; the five lines between ELSE and GOSUB Convert can then become a simple "Vin = -Vin".
 
Last edited:

zorgloub

Member
Hello Hippy,
Interesting lead.
But there seems to be a controversy, concerning this circuit, about the possibility of reading negative values.
I have read that applying a negative voltage to these inputs can destroy the circuit.
Unless it's only possible in differential measurements?
In any case, the converter is configured here as a direct measurement between GND.
And if we neglect the value "8" displayed, there would still be a measurement of more than 1.88 volts while the input is at GND!?
 

hippy

Technical Support
Staff member
But there seems to be a controversy, concerning this circuit, about the possibility of reading negative values.
I have read that applying a negative voltage to these inputs can destroy the circuit.
Unless it's only possible in differential measurements?
I am not familiar with the ADS1115 chip so don't know what its capabilities are. Negative voltages may well destroy the chip, but that doesn't preclude the chip from reporting what it perceives to be negative values.

It does seem odd that the 'connected to 0V' result varies so much. single digit negatives would be expected, just 'noise', but a whole quarter volt is surprising. Are you sure the input is connected to 0V and not floating ?

I just noticed that I am printing the MSBy and LSBy values after negation so that isn't that useful. This is a better refactoring of your code, untested of course, some comments missing but the code is complete -
Code:
Symbol reserveW0 = w0  ; b1:b0

Symbol Vin       = w1  ; b3:b2

Symbol adc       = w2  ; b5:b4
Symbol adc.lsb   = b4
Symbol adc.msb   = b5

Symbol cfg       = w3  ; b7:b6
Symbol cfg.lsb   = b6
Symbol cfg.msb   = b7

Symbol temp_wd   = w4  ; b9:b8

Symbol Coef      = b10

Hi2csetup i2cmaster, %10010000, i2cfast_8, i2cbyte 'ADDR_pin Grounded

' Calculation Coef
'----------------------
Coef = 8 ' 4,096v_FS PGA=001
'Coef = 16 ' 2,048v_FS PGA=010 (Default)
'Coef = 32 ' 1,024v_FS PGA=011
'Coef = 64 ' 0,512v_FS PGA=100
'Coef = 128 ' 0,256v_FS PGA=101/110/111

Sertxd ("-----------------------------------------",cr,lf)
Sertxd (" START Programme",cr,lf)
Sertxd ("-----------------------------------------",cr,lf)
Pause 500
' Configuration of the CONFIG Register
'-------------------------------------------
Hi2cout (%00000001,%11010010,%10000011)'Write to Reg.CONFIG, MSB, LSB
'PGA = bits[11:9] =001 --> (4,096V Full Scale) Coef W1=8
'MUX = bits[14:12]=101 --> (AINP = AIN1 and AINN = GND)
'MODE = bit[8]=0 --> (Continuous)
Gosub Read_CFG 'Read Reg.CONFIG (Facultative)

Main:
DO
  Hi2cout (%00000000) 'Pointer to Reg.Conversion
  Pause 500
  Hi2cin (adc.msb,adc.lsb)'Read MSB,LSB
  Sertxd ("---> MSB = ",#adc.msb," LSB = ",#adc.lsb," MilliVolts = ")
  If adc.msb < $80 Then
    Gosub Convert
    SerTxd( #Vin,cr,lf)
  Else
    adc = -adc
    Gosub Convert
    Sertxd ("-",#Vin,cr,lf)
  End If
LOOP

Convert:
  Vin = adc / Coef
  Return

Read_CFG:
  Hi2cin (cfg.msb,cfg.lsb) ' Read Register CONFIG (Only bits[14:0]!?)
  Pause 500
  Sertxd (" cfg.msb = ",#cfg.msb," cfg.lsb = ",#cfg.lsb,cr,lf,cr,lf)
  b0 = cfg.msb
  SerTxd( "cfg.msb = %", #bit7,"-", #bit6, #bit5, #bit4,"-", #bit3, #bit2, #bit1,"-", #bit0," " )
  b0 = cfg.lsb
  SerTxd( "cfg.lsb = %", #bit7, #bit6, #bit5,"-", #bit4,"-", #bit3,"-", #bit2,"-", #bit1, #bit0, CR, LF )
  Sertxd (" MUX PGA MODE DR",cr,lf)
  Sertxd ("-----------------------------------------------------------",cr,lf)
  Pause 2000
  Return
The main changes are to take advantage that two 'b' variables form a 'w' variable and not to use any 'b' variables in the SERTXD, except for b0, b1 and bitX which can be tolerated.
 

hippy

Technical Support
Staff member
But there seems to be a controversy, concerning this circuit, about the possibility of reading negative values.
I have read that applying a negative voltage to these inputs can destroy the circuit.
Unless it's only possible in differential measurements?
The answer to that appears to be that the chip will not tolerate negative voltages.

However it does allow two positive voltages in differential mode where the upper voltage being less than the lower voltage will deliver a negative voltage difference. That is +4V and +2V will report +2V difference, while +2V and +4V would report -2V difference.

The chip internally is always differential, just that in single-ended mode its lower voltage is internally connected to 0V and the input becomes the upper voltage, so a negative voltage can be reported when the chip's lower voltage input appears to be higher than the voltage being input. That would usually be a result of noise in the circuit.
 

zorgloub

Member
Thank you Hippy for devoting your precious time to my problem!
Your last routine is much improved.
is it normal, however, to read a (very small) negative value when Vin is connected to ground.
Shouldn't the answer be zero?
Attached, print-screen of the console.
 

Attachments

AllyCat

Senior Member
Hi,
I have read that applying a negative voltage to these inputs can destroy the circuit.
Nearly all integrated circuits hare internal "ElectroStatic protection Diodes" connected from every input pin to the internal supply and ground rails. So if a "large" negative or positive voltage is applied, without any current-limiting resistance, then there is a risk that the chip will be damaged or even destroyed. However, the forward voltage of most silicon diodes is around 0.5 volt, so a "small" voltage outside the rails may not do any damage (but a series resistance of at least a few k Ohms would be wise).

Some ADCs (e.g. as in the PICaxes) will just "stop" (at zero output) with input voltages below zero. However, it's difficult to design analogue circuits with inputs which work with high accuracy right down to zero volts (i.e. "rail to rail" designs) so one solution is to "sit up" (offset) the input voltage, for example with a resistive bias/divider or an Op-Amp with slightly less than unity gain. The internal circuit then needs to numerically subtract the offset voltage, but if the calibration is not perfect then a negative voltage might be reported. There is also the possibility that if any significant current is flowing in the Earth rail to the ADC, then the "Earth" (reference) voltage is actually higher than "zero" volts (i.e. even Earth rail conductors can have some resistance)..

Cheers, Alan.
 
Last edited:

hippy

Technical Support
Staff member
s it normal, however, to read a (very small) negative value when Vin is connected to ground.
Shouldn't the answer be zero?
The answer should be zero but it's quite common and normal for there to be some noise ( internally or externally ) which causes the voltage to be just above or below zero. Many ADC's won't show a negative voltage, will clamp it at zero, but this particular chip does.

The more resolution an ADC has, the more likely one will see that noise. It's equivalent to winding an audio amplifier's volume up and hearing more hiss.

What you are seeing is therefore as expected, perfectly normal.
 

zorgloub

Member
Well, thank you very much!
Your answers are particularly quick and very complete.
Thank you for responding to my requests.
This forum is really very responsive, informative and helpful.
Have a good day, everyone.
Sincerely.
 

Attachments

zorgloub

Member
Hi Hippy,
I would like a little more information, which is certainly elementary!
What happens to the bits of the ADC byte when you say "ADC = -ADC"?
I don't understand the logical equation that modifies these bits in this case.
Thank you again.
 

Attachments

hippy

Technical Support
Staff member
Two's complement numbers are relative to zero, added to or subtracted from -
Code:
00000000 + 2 = 00000010
00000000 + 1 = 00000001
00000000 + 0 = 00000000
00000000 - 1 = 11111111
00000000 - 2 = 11111110
Two's complement does a negation by inverting the bits then adding one -
Code:
-1       = 11111111
Inverted = 00000000
Add 1    = 00000001 => 1

-2       = 11111110
Inverted = 00000001
Add 1    = 00000010 => 2
That woks in both directions -
Code:
1        = 00000001
Inverted = 11111110
Add 1    = 11111111 => -1

2        = 00000010
Inverted = 11111101
Add 1    = 11111110 => -2
That "ADC = -ADC" can also be "ADC = 0 - ADC" or "ADC = ADC ^ $FFFF + 1".
 
Last edited:

zorgloub

Member
Thank you hippy for this clear and precise information.
I have just seen a practical and intuitive way: If you have to quickly transform a number into its complement of two, a good way is to keep all the numbers from the right to the first 1 (included) and then reverse all the following ones.
 

Attachments

AllyCat

Senior Member
Hi,

No I don't think so*. Firstly "Invert" or "Negate" is a better term than "Reverse" which generally implies : Left <--> Right (e.g. 0001 --> 1000 ).

Remember that 0 = minus 0 , so does your method achieve that (i.e. Twos Complement of 0 = 0) ? The "Invert all bits and add 1" does do this, e.g. 0000 inverted = 1111 ; 1111 + 0001 = 0000 .

*EDIT: Hmm, perhaps your method does work. But it's much easier for a computer (program) to do : "NOT variable + 1" than to work through each bit in turn from Right to Left.

Cheers, Alan.
 
Last edited:

hippy

Technical Support
Staff member
I have just seen a practical and intuitive way: If you have to quickly transform a number into its complement of two, a good way is to keep all the numbers from the right to the first 1 (included) and then reverse all the following ones.
I doubt that works for all possible numbers.

Besides "invert and add one" is quick enough and will almost always be faster than determining which is the first bit set.

And, on top of that, one doesn't have to do anything, PICAXE Basic provides for negation simply by placing a minus in front of the number, as in "ADC = -ADC", no need to mess about doing anything else.
 
Top