I2C hangs with sunfounder linefollower

I build a small robot with several devices on the I2C bus.

Everything worked fine until i added the life follower.

Info on the line follower is here:
http://wiki.sunfounder.cc/index.php?title=Line_Follower_Module

I first suspected my code (and pull-ups) but it seems to be specific to the device:
I can make the line-follower work fine on its own, if there is nothing else on the i2c bus

So i tried the "standard" i2cscanner with 2 devices, it reports the addresses of both a few times but then it hangs
It works fine as long as the module is alone on the bus.

When I check the I2C signals i can see the SDA remains low after it hits the line follower ACK (see attached)

The line follower has build-on pull-ups of 1K (i measured it and seems right, 1k seems already low so i doubt it will get better by going even lower and the signals seem reasonably rectangular, usually an indication that pull-up is ok)

it works again once or twice when i hit the reset on the line follower. I can make it work by adding a watchdog that sends a reset to the module when the Arduino hangs, but it's not an ideal solution.

I've build quite a few Arduino projects with i2c displays and other sensors without problems, this one stumps me and it's interesting that it does work on its own.

1k :o That value is too low.

Are all your I2C modules compatible with a 5V I2C bus ?

According to the I2C standard, the sink current (to pull SDA or SCL low) is maximum 3mA. Each device is allowed to sink more, but each device should at least be able to sink 3mA. Some manufacturers make chips that can barely sink 3mA.

Can you check all the pullup resistors on all modules ?
Calculated the combined pullup. 5V / 3mA = 1666 ohm, the combined pullup should not be lower.

To check you calculation, you can measure the sink current with a multimeter.
Make a sketch with "Wire.begin()" in setup() and a empty loop(). Run that sketch. Measure the shortcut current from SDA to GND and the shortcut current from SCL to GND.

After you have posted a message with a picture on this forum, you can copy the link to the photo. Then you can modify your post and add that picture with the picture button:

Well the line follower comes with the 1k pull-ups, i would have to solder them off to try with higher values.
I did not add more pull-ups, the other I2C is a OLED display that i have used in several other projects. In some other projects i usually start with 4k7 pull up (i've noticed many modules seem to work even without a pull-up but then the signals become a lot more sinusoidal

The weird thing with this module is that it works on its own but as soon as you add another i2c module it hangs the i2c bus. As you can see in the scope, the moment the SDA should go high, it does go up a little bit but it does not flip high.

As far as i know they are all 5v (they all do work independently on 5v). When i use the OLED stand-alone i use 4k7 pull-ups but here i mostly use it to test the line follower module which already has 1k pull-ups, no easy way to raise the pullup without soldering

According to the wiki web site for the module (Uses the MCU STM8S105C4 as the controller,):

Wiring Test board ---- Arduino UNO

VCC ----- 5V
GND ----- GND
SCL ----- A5
SDA ----- A4

Also if i send a "reset" to the module it works again (once or twice). When i do that i can actually reliably use the other i2c modules as long as i don't address this one. it's not a one-off on this module either as i have 2 of them and they both have this problem.

Current during wire.begin / idle loop:
SDA/GND: 5mA
SCL/GND: 9.8mA (i measured a few times it's mostly stable but i also measure 13mA a little while later)

I really don't care about when it hangs and how and what SDA is doing and if a reset helps ::slight_smile:
Your pullup is beyond anything reasonable. That is your major problem at the moment, so you have to fix that first.

Is a OLED connected to the I2C bus ? Only the Adafruit module is compatible with a 5V I2C bus. Other OLED displays are not, even if the seller claims they are. The OLED displays are known to cause problems on the I2C bus for others. With a lot of I2C devices, perhaps you can give the OLED its own (software) I2C bus.

You must bring the sink current for SDA and SCL below 3mA. I don't understand why they are not the same and why SCL changes. With too much pullup the 5mA is as expected, I can understand that. But the 9.8 or 13mA for SCL is very weird.

ok some new info

when use the example sketch for the line follower, i am able to combine it with showing something on the OLED (in fact i show one of the data-pieces i get from the line follower).

So weird: it all works with some code but e.g. the line follower hangs with the i2c scanner (And some of my own code as well)

Could it be a programming side problem?
Below code is basically a merge of copy/paste of the line follower example with the SSD1306 example.

THIS WORKS!

But, the i2cscanner hangs, and my own much more complex code as well in a similar way.
My code works with several i2c sensors and it also works with just the line-follower but as soon as i merge using both it hangs just like the i2cscanner.

#include "SSD1306Ascii.h"
#include "SSD1306AsciiAvrI2c.h"

#include <Wire.h>
#define uchar unsigned char
uchar t;
//void send_data(short a1,short b1,short c1,short d1,short e1,short f1);
uchar data[16];

// 0X3C+SA0 - 0x3C or 0x3D
#define I2C_ADDRESS 0x3C
// Define proper RST_PIN if required.
#define RST_PIN -1
SSD1306AsciiAvrI2c oled;

void setup()
{
Wire.begin(); // join i2c bus (address optional for master)
Serial.begin(115200); // start serial for output
Serial.println("TEST");
t = 0;

oled.begin(&Adafruit128x64, I2C_ADDRESS);
oled.setFont(Adafruit5x7);
oled.clear();
oled.println("init!");

}
void loop()
{
Wire.requestFrom(9, 16); // request 16 bytes from slave device #9
while (Wire.available()) // slave may send less than requested
{
data[t] = Wire.read(); // receive a byte as character
if (t < 15)
t++;
else
t = 0;
}

oled.clear();
oled.println(data[0]);

Serial.print("data[0]:");
Serial.println(data[0]);
Serial.print("data[2]:");
Serial.println(data[2]);
Serial.print("data[4]:");
Serial.println(data[4]);
Serial.print("data[6]:");
Serial.println(data[6]);
Serial.print("data[8]:");
Serial.println(data[8]);
Serial.print("data[10]:");
Serial.println(data[10]);
Serial.print("data[12]:");
Serial.println(data[12]);
Serial.print("data[14]:");
Serial.println(data[14]);
delay(500);
}

ok removed the 1k's from the board
using the build in pullups, i believe they are 10k

SDA/GND: 1.8mA
SCL/GND: 3mA

Result: after reset it works twice then hangs again

Added 4k7 pull-ups
Same result, i2c scanner works twice then hangs after finding 0x09

SDA/GND: around 1.7mA
SCL/GND 3mA (it's not static 3mA it moves from around 3.4mA to 2.8mA)

Scanning...
I2C device found at address 0x09 !
I2C device found at address 0x3C !
done

Scanning...
...hangs...

yes the OLED is also connected to the I2c (it's the point that both do work independently, and they even both work together as long as i use the requestFrom on the line follower module as in their example. The OLED works fine in tandem with a few other I2C items (a 23017 and 2 i2c modules to read rotary encoders). My problems started when i added the line follower and since it even hangs with the i2cscanner i does not seem to be my code.

The pulses seem quite rectangular but at some point SDA goes low and does not come back up, a reset of the module makes it work once or twice again.

If i skip address 0x09 (line follower array) in the i2cscanner then the 0x3c (OLED) keeps responding fine all the time

the logic analyzer shows a hang in the i2cscanner the 2nd screenshot is using code where requestFrom works (and i can show the data on tthe OLED on the same i2c bus so both work fine in that scenario).

To be clear both programs use the same hardware setup (module on 0x09 and OLED on 0x3C.

For some reason i can't attach the 2nd screenshot (get message it's not a safe attachment, tried it as png and also 'save as' jpg)

it shows the read which after addressing the 0x09 does successfully read data from that device...

missing screenshot for previous post... working read

The raised ground level could indicate a shortcut.

There is one more test that you can do: add a delay(1) in the for-loop of the I2C scanner. That gives the linefollower some time after each I2C address is put on the bus.

The linefollower uses a STM8S105C4 processor. That means it does the I2C for a part in software. I think it might be buggy. You could add delay(1) after each I2C transaction with the linefollower, so the STM8S105C4 has some time to breathe.

The example for the linefollower uses only a Wire.requestFrom().
The I2C scanner checks for an acknowledge when the I2C is put on the bus with Wire.beginTransmission() and Wire.endTransmission(). It is possible that the linefollower does not behave like a normal I2C device and only works properly with Wire.requestFrom().
It is also possible that the software for the linefollower was developed while it was the only device on the bus. You could give the linefollower also its own I2C bus with software I2C.

When the I2C Scanner causes a problem and Wire.requestFrom() not, that is good enough for me. Then they forgot to put that in the processor.

Do you have the Adafruit OLED module ? That one is better. Any other OLED is a 3.3V device with a 3.3V I2C bus.
The OLED might have been working, but perhaps it was already weakening the I2C bus. Keep in mind that the OLED might disturb the I2C bus for others. That is what they do.

The fluctation of the sink current of SCL is something I have never seen before. It is as if the linefollower is trying to become Master on the bus :confused: If the linefollower is causing that, then I would never use it.

This is important information:

PhiMu:
If i skip address 0x09 (line follower array) in the i2cscanner then the 0x3c (OLED) keeps responding fine all the time

My guess: The linefollower does something weird and the combination with the OLED makes it worse. Since the linefollower uses a processor, it might need extra delays and a Wire.beginTransmission()/Wire.endTransmission() should be avoided.
When you don't have a Adafruit OLED, then add a level shifter for the OLED and perhaps give it its own I2C bus. Can you buy an other linefollower ?

That's all I can say about it. It is a nasty problem.

Thanks for the insights, i was also thinking maybe it is because the line-follower has its own MCU and maybe not pure
sorry for not responding sooner, too many other things going on. I will try your suggestions with respect of putting delays or even a separate bus.