wollewald / ADS1115_WE

An Arduino library for the 16-bit, 4 channel ADS1115 ADC. Convenient to use. All features of the ADS1115 are implemented, including alert functions.
https://wolles-elektronikkiste.de/en/ads1115-a-d-converter-with-amplifier
MIT License
79 stars 24 forks source link

sometimes no value on random channel #29

Closed s54b32julian closed 7 months ago

s54b32julian commented 10 months ago

Any idea why I get randomly 0 instead of the measured value? default SPS, single shot. A0 and A1 are pulled to high (5V) and A1,A2 are pulled to GND with 1Mohm. 1second between measurements.

0: 6.14, 1: 0.29, 2: 0.22, 3: 6.14 0: 0.00, 1: 0.29, 2: 0.00, 3: 6.14 0: 6.14, 1: 0.29, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.00, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.00, 2: 0.22, 3: 0.00 0: 0.00, 1: 0.00, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.00, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.00, 2: 0.00, 3: 6.14 0: 0.00, 1: 0.28, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.00, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.28, 2: 0.00, 3: 6.14 0: 0.00, 1: 0.28, 2: 0.22, 3: 6.14 0: 0.00, 1: 0.00, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.28, 2: 0.22, 3: 6.14 0: 0.00, 1: 0.28, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.28, 2: 0.00, 3: 6.14 0: 0.00, 1: 0.28, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.28, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.28, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.28, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.00, 2: 0.22, 3: 6.14 0: 6.14, 1: 0.28, 2: 0.22, 3: 0.00 0: 6.14, 1: 0.28, 2: 0.00, 3: 6.14

wollewald commented 10 months ago

@s54b32julian the question is not only why you get randomly 0.00 - the other question is why you get 6.14 instead of 5 V. This makes no sense because you wrote that you pulled A0 and A1 (I think you mean A3) to high (5V). 6.14 sounds like the maximum voltage (6.144). If there is really 6.14 volts at A0 and A3 and your VDD is 5 volts it would destroy the device. The maximum allowed input voltage is VDD + 0.3 volts.

Pulling up or down with 1 Mohm is not a good idea. You get into the dimension of the input impedance which is 10 Mohm for the 6.144 V range / single ended measurements (against GND). Typically one would take 10 kOhm or so or connect directly to GND.

But this still all does not explain why you get these strange results. Some questions:

s54b32julian commented 10 months ago

thanks for insane quick response (and of course for the library)! I was under impression that 6.144V is just equal Vdd==ADCin from comparator and not real 6.144V. On the PCB I only have 5V so more that 5V is not possible, ESP32 is on 3.3V rail and ADs1115 on 5V rail. I2C is level shifted 3V3<->5V.

1Mohm comes from previous design, I tested I need at least 50k to read real zero and not have floating input. But later the ADC Inputs are optional to connect, and I want to pull them to zero for not connected Inputs(external connections to the PCB). And maybe also protect inputs with 10k resistor.

to you questions:

-same GND is shared on whole PCB(also 5V rail and 3.3V share same GND) -the output above is from your single shot example

image

btw. We could also talk in german, but maybe this problem here will help others in the future with similar issues.

wollewald commented 10 months ago

Thanks - this is very helpful. The 50 kohm resistors are OK this way. I don't see anything wong in your circuit. That leads to the question what the issue is. I have just tried the single shot sketch on an ESP32 and it works fine. So, to be honest I don't know!

Have you aso tried the continuous example sketch from my library? Same issue with that?

Either it's a hardware problem on your PCB, or the ADS1115 is simply damaged or there is something very specific which does not work under your conditions with my library.

What you could do is trying the Adafruit Library for the ADS1115 / ADS1015: https://github.com/adafruit/Adafruit_ADS1X15 It's also available via the Arduino IDE library manager. I have just tried the single ended example sketch on an ESP32. It also works fine. The only thing you need to change is comment line 4 and uncomment line 3 to set the ADS1115 as target. This is done in few minutes.

s54b32julian commented 10 months ago

already tried today to change the chip. this was not the problem.

I tested the Adafruit lib, it gives me the correct 5.05V I really have. Maybe some small bug in calculation in this lib?

But I still get random Zero responses. I setup the ADS1115 on a second board without levelshifting IC and 3V3 VDD and got no more zero responses. So something is going wrong in the communication during the levelshifting...hm, I need to think more about this....

image
wollewald commented 10 months ago

I will never say that there are no bugs in my libraries, but I am very sure that the calculation of the voltages from the raw values is correct. What makes me so confident is that I have just tried it (again) like you with an ESP32, an ADS1115 and the same sketch and I get the correct values. Furthermore a lot of people use this library and if this basic feature would not work I would get bombarded with issues on GitHub and comments on my website. It's the first time I hear that.

However, you have the problem and at least this part of the two issues is solved with the Adafruit lib. I have no explanation for this. My problem is to find a reason for this strange behavior since I can't repoduce it. I can only say what I would do if I had your setups in front of me.

You said you don't get random zeros on the second board. Does this apply for both libs? And do you still still get the 6.14 volts with my lib on the second board? And what do you get if you apply a voltage somehwhere in the middle like 1.6 volts.?

Then I would check what you get if you don't change channnels, so e.g. if you only read channel 0 and what you get if you measure in the continuous mode.

Finally, what

For the level shifter issue I had a look into the data sheet of the TXS0102DCUT. I don't see anything wrong in your circuit. A is the low voltage side, B is the high voltage side, OE is connected to VCC_A.

I would love to help more, but not sure how.

Btw, happy new year!

wollewald commented 10 months ago

And, just a gut feel, what if you add a delay(2000) at the beginning of the setup, even before Wire.begin() in the single shot example sketch?

s54b32julian commented 10 months ago

I spend today again some hours to find this out... That drives me crazy, but I really appreciate your help!

The problem with zeros must be hardware/wiring related, bc with boths libs I get zeros back. Only difference is 5.05V with Adafruit lib and 6.14 with this lib. I would look into the 6.14V thing later, when I´m sure that is not also related to the "zero problem". Also same "zero" behavior with single channel readings and also added delay to test, no change. BTW I had the same idea, because OE on levelshifter could be to early High before both rails are under their full voltage. Also played with many different i2C speeds to see if that would change something...

One idea is also that I need (different) pull-ups on 5V i2c side. The TXS0102 has internal 10k pullup on both sides. On 5V side I have no pullup and on the 3V3 side I have a additional set of pull-ups 4.7k (and also one additional i2c slave beside the Master ESP32-s3). If I feed from a second ads1115 @3V3 to the i2c on the esp32 side of the level shifter everything is fine. So it must be on the high level side or the shifter it self. But what could be wrong? Clock high level not recognized by IC and therefore zero/no response by slave? The footprints of the components are so tiny, otherwise I would probe it with my osci...

I wish you too a happy new year!

wollewald commented 10 months ago

Weird! And even more difficult to solve from distance. Let me think a bit about this. I come back if I have a good idea.

s54b32julian commented 10 months ago

Progress! Main culprit is my LC-network or the design of it. Have to dig more into that, I´m really no expert in this...

I have added C50 (sadly overlooked this was missing 1nF 0603 footprint) and that fixed 99,8% of the zero readings. Still have a couple every 100-400 readings, but maybe the Ferrit bead and capacitor combination is not well selected. I gave my best to make a stable power supply circuit on both rails, but I think the ADS1115 is VERY sensitive to high switching frequency (like from USB port, that powers currently the PCB) on the VDD pin. So maybe this interrupted the ADC IC, that the IC maybe resets or interrupts the transmission of the variable => Zero reading.

And now comes a also interesting part, with ada lib I get even after zero/false reading the correct readings again. With this lib, starting with one zero/false reading, the fault seems to transmit to every following reading. Look at the following values, it's the point where it happens. It looks a bit like all the values are bitshifted at this point, but not really per my calculation. and i also see no specific operation in this lib that do this. Maybe you know what's going on, because you know i2c bus and ads1115 way more than me.

(.......) 0: 0.36, 1: 0.13, 2: 0.19, 3: 5.04 0: 0.36, 1: 0.13, 2: 0.19, 3: 5.04 0: 0.36, 1: 0.13, 2: 0.19, 3: 5.04 0: 0.36, 1: 0.13, 2: 0.19, 3: 5.04 0: 0.36, 1: 0.13, 2: 0.19, 3: 5.04 0: 0.36, 1: 0.13, 2: 0.19, 3: 5.04 0: 0.36, 1: 0.13, 2: 0.19, 3: 5.04 0: 0.36, 1: 0.13, 2: 0.19, 3: 5.04 0: 0.36, 1: 0.13, 2: 0.19, 3: 5.04 0: 0.36, 1: 0.13, 2: 0.19, 3: 5.04 0: 0.36, 1: 0.13, 2: 0.19, 3: 5.04 0: 0.36, 1: 0.13, 2: 0.19, 3: 5.04(-> up to here all readings are stable and ok) 0: 0.36, 1: 0.13, 2: 0.19, 3: 0.00 (<-zero reading) 0: 0.98, 1: 0.38, 2: 0.54, 3: 6.14 0: 0.98, 1: 0.38, 2: 0.54, 3: 6.14 0: 0.98, 1: 0.38, 2: 0.54, 3: 6.14 0: 0.98, 1: 0.38, 2: 0.54, 3: 6.14 0: 0.98, 1: 0.38, 2: 0.54, 3: 6.14 0: 0.98, 1: 0.38, 2: 0.54, 3: 6.14 0: 0.98, 1: 0.38, 2: 0.54, 3: 6.14 0: 0.98, 1: 0.38, 2: 0.54, 3: 6.14 0: 0.98, 1: 0.38, 2: 0.54, 3: 6.14 0: 0.98, 1: 0.00, 2: 0.54, 3: 6.14 0: 0.98, 1: 0.38, 2: 0.54, 3: 6.14 (......)

Edit: and when I do adc.init(); after a "zero reading", I get: 0: 0.32, 1: 0.11, 2: 0.22, 3: 5.04 0: 0.32, 1: 0.11, 2: 0.22, 3: 5.05 0: 0.32, 1: 0.11, 2: 0.22, 3: 5.05 0: 0.32, 1: 0.11, 2: 0.22, 3: 5.05 0: 0.00, 1: 0.11, 2: 0.21, 3: 2.05 0: 0.30, 1: 0.11, 2: 0.21, 3: 2.05 0: 0.30, 1: 0.11, 2: 0.21, 3: 2.05 0: 0.30, 1: 0.11, 2: 0.21, 3: 2.05

wollewald commented 10 months ago

I have a theory: for which reason ever, maybe a voltage supply issue, the ADS1115 resets at a certain point. The default voltage range of the ADS1115 after a reset is +/-2.048 V. Both the Adafruit lib and my lib change the default to +/- 6.144 V.
So, after an unplanned reset my lib still "thinks" the range is +/- 6.144 V, but in fact the gain for the 2.048 V range is applied. The effect is that the internal calculation is wrong and you will get results that are three times higher, but everything beyond 2.048 V is cut (but calculated to 6.144), because you can't exceed the maximum raw value (2^15).

I can reproduce this behavior when I remove the ADS1115 module from the breadboard while the single shot sketch is running and then put it back.

It would be helpful for me if you could run the following sketch which outputs the raw values and ranges (the range that the ADS1115 applies for calculations).

#include<ADS1115_WE.h> 
#include<Wire.h>
#define I2C_ADDRESS 0x48

ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);

void setup() {
  delay(100);
  Wire.begin();
  Serial.begin(9600);
  if(!adc.init()){
    Serial.println("ADS1115 not connected!");
  }
  adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change parameter to change range
}

void loop() {
  float voltage = 0.0;

  Serial.print("0: ");
  voltage = readChannel(ADS1115_COMP_0_GND);
  Serial.print(voltage,3);
  uint16_t raw = adc.getRawResult();
  Serial.print(",  0,RAW: ");
  Serial.print(raw, BIN);

  Serial.print(",   1: ");
  voltage = readChannel(ADS1115_COMP_1_GND);
  Serial.print(voltage,3);
  raw = adc.getRawResult();
  Serial.print(",  1,RAW: ");
  Serial.println(raw, BIN);

  Serial.print("2: ");
  voltage = readChannel(ADS1115_COMP_2_GND);
  Serial.print(voltage,3);
  raw = adc.getRawResult();
  Serial.print(",  2,RAW: ");
  Serial.print(raw, BIN);

  Serial.print(",   3: ");
  voltage = readChannel(ADS1115_COMP_3_GND);
  Serial.print(voltage,3);
  raw = adc.getRawResult();
  Serial.print(",  3,RAW: ");
  Serial.print(raw, BIN);

  Serial.print("  Range: ");
  Serial.println(adc.getVoltageRange_mV());
  Serial.println("----------");

  delay(1000);
}

float readChannel(ADS1115_MUX channel) {
  float voltage = 0.0;
  adc.setCompareChannels(channel);
  adc.startSingleMeasurement();
  while(adc.isBusy()){}
  voltage = adc.getResult_V(); 
  return voltage;
}

The next question is why the Adafruit lib does not have the range issue. And I also have an explanation for this. When starting a conversion, the Adafruit lib does not only write the responsible bit for the conversion into theconfig register, it also writes the range, data rate, etc. as you can see here: https://github.com/adafruit/Adafruit_ADS1X15/blob/c7ae837c7f595656d7be43e21cdf950f103f62e4/Adafruit_ADS1X15.cpp#L328C7-L328C7 Since this is safer I am going to apply the same. With every issue I also learn!

I would say this makes all sense. If it's true, then problem is at least limited to the resets. So maybe you could check with your oscilloscope the voltage directly at the VCC pin of your ADS1115.

s54b32julian commented 10 months ago

I would say your are absolutely right and also for me now everything makes sense! Very happy to learn more and more this way.

I also probed the supply voltage at the chip, and my LC circuit on VDD/VSS mostly working. Except when I write a Serial message (over built in USB interface) I got a huge sweep every time. This is not nice, I can workaround this in software and dealing with the reset of the adc1115, but maybe better solving this with some additional caps.

Here is the part of the output, where it resets it self. 0: 0.452, 0,RAW: 100101101100, 1: 0.193, 1,RAW: 10000000110 2: 0.526, 2,RAW: 101011110100, 3: 5.026, 3,RAW: 110100010110011 Range: 6144

0: 0.452, 0,RAW: 100101101100, 1: 0.193, 1,RAW: 10000000101 2: 0.525, 2,RAW: 101011101111, 3: 5.026, 3,RAW: 110100010110110 Range: 6144

0: 0.452, 0,RAW: 100101101100, 1: 0.193, 1,RAW: 10000000100 2: 0.522, 2,RAW: 101011100010, 3: 5.024, 3,RAW: 110100010101101 Range: 6144

0: 0.453, 0,RAW: 100101110000, 1: 0.000, 1,RAW: 0 2: 1.465, 2,RAW: 1111010000011, 3: 6.144, 3,RAW: 111111111111111 Range: 6144

0: 1.261, 0,RAW: 1101001000100, 1: 0.552, 1,RAW: 101110000001 2: 1.462, 2,RAW: 1111001110100, 3: 6.144, 3,RAW: 111111111111111 Range: 6144

0: 1.264, 0,RAW: 1101001010101, 1: 0.553, 1,RAW: 101110000011 2: 1.461, 2,RAW: 1111001110001, 3: 6.144, 3,RAW: 111111111111111 Range: 6144

wollewald commented 10 months ago

That's what I expected, great.

I would also recommend to add some caps. Agree not nice to do that at a late stage after you thought your design is completed.

I am interested to hear from you when you have solved everything. Good luck!

wollewald commented 7 months ago

Since I haven't heard any news I am now closing this issue.

s54b32julian commented 5 months ago

I like to add for completeness if someone has similar issues...the whole problem is based on the power supply. The ADS1115 ist EXTREMELY sensitiv to input voltage with spikes/ripple.

Also after removing the 2 inductors from vdd/vss I got far more stable readings. Also picking a suitable voltage supply without any noise, spikes etc is a PITA.

wollewald commented 5 months ago

Hi @s54b32julian, thanks for sharing your expereience. It would be helpful if you could share more details:

Since I was interested in this, I tried a bit myself. I supplied the ADS1115 via an LM2596-ADJ module. The input voltage was 9V, output voltage was ~4,8 V. In order to produce a "nice" ripple of > 100 mV I have attached an additional load:

Screenshot 2024-06-01 152901

As a stable voltage to be measured I took a Li-Battery.

The sketch I have applied was:

#include<ADS1115_WE.h> 
#include<Wire.h>
#define I2C_ADDRESS 0x48

ADS1115_WE adc = ADS1115_WE(I2C_ADDRESS);

void setup() {
  Wire.begin();
  Serial.begin(9600);
  if(!adc.init()){
    Serial.println("ADS1115 not connected!");
  }
  adc.setVoltageRange_mV(ADS1115_RANGE_6144); //comment line/change parameter to change range
  adc.setCompareChannels(ADS1115_COMP_0_GND); //comment line/change parameter to change channel
  adc.setMeasureMode(ADS1115_CONTINUOUS); //comment line/change parameter to change mode
}

void loop() {
  float voltage = 0.0;
  Serial.print("Voltage [mV]: ");
  voltage = adc.getResult_mV();
  Serial.println(voltage, 2);
  delay(1000);
}

This was the result:

Screenshot 2024-06-01 151650

The resolution of the ADS1115 at +/- 6.144 volts is 0.1875 mV. So the noise was just 1 bit.

Then I thought maybe my ripple was too fast (frequency 57.5 kHz) to have an impact. Therefore, I have done another test. This time, I have used an adjustable voltage supply for my ADS1115. I have varied the voltage between 4 and 5 volts and again the measured voltage (again the Li battery) has not changed by more than two bits.

So, I can't see a visible impact on the output voltage when the input voltage has ripples or when I vary the level of the input voltage.

I have added the option to open discussions. Maybe this is a better place because other people might not look into a closed issue with different title. If you chose this way the I will copy my comment also there.