I2C Sensors not detected

Hi all,

I have a custom circuit board with 3 sensors (SI7021, TMP112 and MS5607) connected to the I2C bus. When I run I2C scanner on arduino uno with the sensors connected to the I2C bus (sda & scl lines have 10k resistors in series to reduce 5v to 3.3v) no devices are found.
When I repeat the test with a custom board with an atmega328 and the sesors (this time 2 BSS138 turn 5v sda and scl to 3.3v) the program freezes upon wire.endTransmission().

Any idea why this happens, how it can be solved?

Thank you in advance,
Alex

PS. the sensor board schematic is attached below as photo.

10k resistors in series for SDA and SCL :confused: Have you ever seen that before ? Is there a single person in the world that has that working ?
The SDA and SCL carry signals in both directions. Therefor I don't understand the 10k in series. They are also not in the schematic.

Two BSS138 can work as bidirectional level shifters, but that level shifter circuit needs 5V and 3.3V to operate and there should be pullup resistors on both side. I would like to see the schematic of your level shifter.

When the Wire.endTransmission() never returns, it can be that SDA or SCL is shortcut to GND, or SDA is shortcut to SCL. Perhaps a missing pullup resistor can cause it.

Solution: Buy a 3.3V Arduino board with a SAMD21 M0+ processor :smiley:
5V is so 1970's, that is almost 50 years ago.

the 10k resistors where a final resort solution to check the sensors with an uno, I understand a bi-directional level shifter is needed but i did not have one lying around. Attached is the level shifter on the atmega328's board. The jumpers are there in case the bus needed less pullup resistance (10k resistors are currently active). I did not detect any shorts between SDA-SCL-GND

That level shifter is correct. If you have four 10k pullup resistors and applied both 5V and 3.3V then it should work.
Can you connect the sensors one by one while the I2C Scanner is running ? Or are they already soldered on a board ? Do you perhaps have a I2C sensor that you know is working, just to see that the I2C Scanner can detect it.

They are soldered on the board but I removed the MS5607 in case it was creating problems (it supports SPI and I2C) so just 2 sensors remain. Unfortunately I do not have another sensor, but the sketch hangs at endTransmission so I doubt it would be much help even if I did.

What are the voltage levels of SDA and SCL while it hangs ?

3.19V each

Weird. I don't know what to do now.
You need a 3.3V Arduino board and a normal sensor. Can you remove one more sensor ? The Si7021 is the most normal one. That should work.

It is possible that the sensors are damaged by 5V, but I don't think they are.
Perhaps your board has very thin shortcut copper traces that are hard to see. Or solder splats that cause a shortcut.
Your schematic is confusing with JP5 and AD0, I don't understand that.

In the datasheet a table (page 12) shows the chip's address depending on the AD0 connection (to V+, GND, SDA, SCL). The jumpers serve the purpose to change the address. But JP5 shouldn't matter because only jp4 is shorted and jp5-6 are not.

Are you sure that if you use the level shifter, that both SDA and SCL are near 5V measured at the pins of the ATmega328P while the sketch is halted in the Wire.endTransmission() function ?
Something is definitely wrong, but I am afraid that I am out of ideas. This problem is hard to solve via internet.

If you really can not fix it, then you should start all over. Can you buy a 3.3V Arduino board and start with a breadboard like everyone else does ?

I measure 4.19V with the multimeter in the 20V range

When I run into problems like this , I usually step back and try to get one thing working. Once that is good, add another piece, then another..

BTW, the TMP112 is a really cool sensor, suitable even for medical appliances. It is highly accurate, but also very low power, so... great choice!

I suggest you simplify your problem by first wiring up only only the Uno and the TMP112 sensor.

If I understand your schematic, the 10K resistors may be the main problem. I think you are using them for level shifting, but that isn't what you need.

Instead, you should have 5K pullup resistors on the SDA and SCL lines.

I found the TMP112 datasheet, and copied the typical application diagram from it. Then I made some edits to it to suggest how to connect your Arduino. If I had a TMP112 handy, I would try it out first, but I don't. However, I have connected a few of these, though not to an UNO. It should work the same, tho.

On your pullup resistors, connect them just like in the attached drawing, to the 3.3 V output of your arduino on one side, and the respective SDA and SCL on the other side. If you have an oscilloscope, I bet it will show you the SDA or SCL voltages varying between 0V and 3.3V, which is exactly what you want.

Also, because the 3.3V output of the Uno gives you 50 ma, and the TMP112 only needs about 10 microamps , you can use the Arduino 3.3V output to run the TMP112.

This idea is all shown in the attached diagram. If you can get the TMP112 working by itself, add the other sensors one at a time.

Good luck!

elliott954:
Also, because the 3.3V output of the Uno gives you 50 ma...

Nope, 150mA.
Mistake in the datasheet.
Leo..

Wow. I hope you don't mind, but I had to look for myself, and you are right!!

The LP2985 is good for 150 ma.

That is great to know.. I learn something new every day.

Thanks!!

@elliott954 thanks a lot for your reply!! It appears strange things are happening. When I run the I2C scanner with the pullup resistors according to your shematic (10k instead of 5k), the tmp112 is found at address 0x48 (but not the SI7021 :confused: ). So I uploaded a simple sketch to read from the tmp112 and it doesn't find the sensor.

I2C scanner finds it, but simple data reader doesn't. So I merge the two and what I found is that if "scan" all adresses for connected devices, then the sensor works and prints out the room temperature fine. If I narrow down the address range (from 1..127 to something else, say 60..127), the sensor is found but prints zeros.

This is highly irregular and unstable behavior, any idea what is going on?

Also, the scanner should find the SI7021 at address 0x40, but it doesn't...

The "level shifter" image is odd:


it would be OK if the resistors are connected to 3.3V instead of an apparently open jumper. Then you don't need that many resistors, a single pull-up per line is enough. 4k7 or 3k3 are good starting values. Too little resistance (too many resistors) may also cause problems with sensors not being able to pull low the line.

You also need pull-ups (4k7 or 10k) on the 5V side.

Easiest is of course the ready-made level shifter boards that are readily available on the market.

After that indeed best to start with just one sensor, make that work. Go from there. I also don't see any other obvious problems (just to make sure: you did solder all the headers in the sensors, didn't you?)

@alex_poupakis, the unstable behavior is something you should focus on.

Can you make a photo of it ?

I hope you don't put the I2C bus in a flat ribbon cable, that won't work. The I2C bus is a "bus", but it can not go through long cables. Perhaps your Uno is a clone without decoupling capacitors. Perhaps there is a grounding problem. Perhaps there is a voltage problem.

I consider the I2C bus good, when one in a million (or less) I2C transactions fails.

@wvmarle I have soldered the jumpers with the 10k pullup resistors, so the bus (on both 5v and 3.3v) sees 10k pull-ups. The jumpers are there to give options about the resistance (10k, 4.7k, 1.8k) but only one on each voltage side is soldered.
I soldered the 2x3 header.

@Koepel, flat ribbon cable, no. Header with wires, yes. But it's 13cm long and the total length from sensors to uno is about 25cm. The Uno is an original one.

Attached is a screenshot of the serial monitor. The left output is for 1..127 address range while the right output is for 60..127.

The following code is the I2C scanner with a method for reading and printing TMP112 data.

#include <Wire.h>
 
 
void setup()
{
  Wire.begin();
 
  Serial.begin(9600);
  while (!Serial);             // Leonardo: wait for serial monitor
  Serial.println("\nI2C Scanner");
}
 
 
void loop()
{
  byte error, address;
  int nDevices;
 
  Serial.println("Scanning...");
 
  nDevices = 0;
  for(address = 1; address < 127; address++ ){
    Wire.beginTransmission(address);
    error = Wire.endTransmission();
    
    if (error == 0)
    {
      Serial.print("I2C device found at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");
 
      nDevices++;
    }
    else if (error==4)
    {
      Serial.print("Unknown error at address 0x");
      if (address<16)
        Serial.print("0");
      Serial.println(address,HEX);
    }


    if (address == 72 && error == 0){
      Serial.println("tmp112");
      getTemp102();
    }
    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
 
  delay(500);
}


void getTemp102(){
  byte TMP102_I2C_ADDRESS = 0x48;
  byte firstbyte, secondbyte;
  int val;
  float convertedtemp;
  float correctedtemp;
  
  Wire.beginTransmission(TMP102_I2C_ADDRESS);
  Wire.write(0x00);
  Wire.endTransmission();
  Wire.requestFrom(TMP102_I2C_ADDRESS, 2);
  Wire.endTransmission();
 
 
  firstbyte      = (Wire.read());
  secondbyte     = (Wire.read());
  val = ((firstbyte) << 4);  
  val |= (secondbyte >> 4);    

  convertedtemp = val*0.0625;
  correctedtemp = convertedtemp - 5;
   
 
  Serial.print("firstbyte is ");
  Serial.print("\t");
  Serial.println(firstbyte, BIN);
  Serial.print("secondbyte is ");
  Serial.print("\t");
  Serial.println(secondbyte, BIN);
  Serial.print("Concatenated byte is ");
  Serial.print("\t");
  Serial.println(val, BIN);
  Serial.print("Converted temp is ");
  Serial.print("\t");
  Serial.println(val*0.0625);
  Serial.print("Corrected temp is ");
  Serial.print("\t");
  Serial.println(correctedtemp);
  Serial.println();
}

Remove the Wire.endTransmission() after the Wire.requestFrom().
That is a common mistake: Common-mistakes#2.
Maybe the TMP112 is one of the few sensors that gets confused with the extra bus activity or the Wire library does something with the received data.

Output you better copy/paste into the forum using code tags, just like you posted your code. Easier and more readable.

This output at a glance looks good; I see your sensor is detected and produces a reasonable looking output - most of the time. So I would say the sensor and code are both good. So what's left is the connection betwe

I notice you get lots of zero values returned. My best guess is a problem with the pull-up resistors and/or the level shifters: somehow the bus remains low, so either something is actively pulling it low all the time (shouldn't happen), or the resistors do not pull up the line properly. The latter is the most likely. A stronger pull-up may also be the solution. I2C over ribbon cables is indeed not recommended, keep the SCL and SDA lines on opposite sides of the GND and Vcc lines to minimise interference.

Do you have access to a scope? If so try and have a look at the actual signals on the wire.