Skip to content
This repository has been archived by the owner on Jan 11, 2024. It is now read-only.

I2C error #117

Closed
malas opened this issue Dec 5, 2014 · 17 comments
Closed

I2C error #117

malas opened this issue Dec 5, 2014 · 17 comments

Comments

@malas
Copy link

malas commented Dec 5, 2014

Hello, i am having an issue using PI4J I2CDevice.write
the error occurs randomly - after several commands are executed successfully, after several hundred commands executed successfully.

code causing error is:

writeBuffer[0] = (byte)2;
writeBuffer[1] = pin.getPinNumber();
writeBuffer[2] = (byte)Math.round(power*2.55);
device.write(writeBuffer, 0, writeBuffer.length);

the error:

java.io.IOException: Error writing to /dev/i2c-1 at address 0x4. Got -20001.
at com.pi4j.io.i2c.impl.I2CDeviceImpl.write(I2CDeviceImpl.java:100)

code runs in a raspberryPi model B using PI4J 1.0-SANPSHOT as a Master, the Slave device is Arduino Mini

any thoughts on this?

@tinue
Copy link

tinue commented Dec 6, 2014

Sorry for jumping in, but I have the exact same problem. Hopefully an additional scenario helps to pin down this problem.
The part that fails randomly (about 2 out of 10 write() fail) is here:

try {
  device.write((byte) 0x01);
  //System.out.print("Pass " + (i+1) + ": 0x01; ");
  Thread.sleep(500);
  device.write((byte) 0x00);
  //System.out.println("Pass " + (i+1) + ": 0x00");
  Thread.sleep(500);
} catch (IOException e) {
  System.out.println("Can't write a byte: " + e);
}

When I uncomment the commented lines I get no errors, so it seems to be a subtle timing issue.

@PoJD
Copy link
Contributor

PoJD commented Dec 6, 2014

I frankly doubt this is an issue in PI4j. I face also some random issue
with a humidity sensor. But that is really fault of the device rather than
the library. Can you try the same device via a different board? (I.e. not
raspberry). If you face the same random failures there (I believe so), then
you know it is this device's fault...
Dne 6. 12. 2014 21:27 "tinue" notifications@github.com napsal(a):

Sorry for jumping in, but I have the exact same problem. Hopefully an
additional scenario helps to pin down this problem.
The part that fails randomly (about 2 out of 10 write() fail) is here:

try {
device.write((byte) 0x01);
//System.out.print("Pass " + (i+1) + ": 0x01; ");
Thread.sleep(500);
device.write((byte) 0x00);
//System.out.println("Pass " + (i+1) + ": 0x00");
Thread.sleep(500);
} catch (IOException e) {
System.out.println("Can't write a byte: " + e);
}

When I uncomment the commented lines I get no errors, so it seems to be a
subtle timing issue.


Reply to this email directly or view it on GitHub
#117 (comment).

@malas
Copy link
Author

malas commented Dec 6, 2014

i know for sure that the sensors sometimes return faulty or no data, but that is not a reason for I2C to freeze.

@PoJD
Copy link
Contributor

PoJD commented Dec 6, 2014

Well if I2C returns error code (beginning of this thread), then this would
match the sensor at fault... What freeze do you mean?
Dne 6. 12. 2014 21:36 "Laurynas Mališauskas" notifications@github.com
napsal(a):

i know for sure that the sensors sometimes return faulty or no data, but
that is not a reason for I2C to freeze.


Reply to this email directly or view it on GitHub
#117 (comment).

@malas
Copy link
Author

malas commented Dec 6, 2014

RPi is connect via I2C to Arduino and Arduino is connected to a sensor. Arduino is responsible for I2C responses, not the sensor. If the sensor returns faulty data upon request from RPi Arduino returns no data too (maybe it should always return some data even in case of errors with sensors?).

By "I2C freeze" i mean that RPi sends I2C commands without any exceptions, but there is no data returned at all and the Arduino is no longer responding to any of commands (even if they don't return any data).

@tinue
Copy link

tinue commented Dec 7, 2014

Also in my case, there is no sensor involved on the I2C bus. The Raspberry Pi is the I2C master, and the Arduino (Rainbowduino v3 in my case) is the slave. As I have written, I can prevent the issue by just adding a few "System.out.println()" into the Java code.

Since I am sending only two bytes per second, and reading them immediately on the Rainbowduino, I don't think the slave is the only problem. It must be something in the collaboration between Rainbowduino and Raspberry Pi that is causing the issue.

It may be something in PI4j, but it may just as well be something in the Raspberry Pi I2C driver, or even something in the hardware. However, I don't know where to start looking, and how.

@JanJansen47
Copy link

See the attachment. I had random i2c bus issues. Sometimes it took days between bus errors. Since I use bus extenders I never ever got them anymore.
Jan Jansen
Sagittalaan 22 5632al
+31688806529
On 7 Dec 2014 07:01, tinue notifications@github.com wrote:Also in my case, there is no sensor involved on the I2C bus. The Raspberry Pi is the I2C master, and the Arduino (Rainbowduino v3 in my case) is the slave. As I have written, I can prevent the issue by just adding a few "System.out.println()" into the Java code.

Since I am sending only two bytes per second, and reading them immediately on the Rainbowduino, I don't think the slave is the only problem. It must be something in the collaboration between Rainbowduino and Raspberry Pi that is causing the issue.

It may be something in PI4j, but it may just as well be something in the Raspberry Pi I2C driver, or even something in the hardware. However, I don't know where to start looking, and how.

—Reply to this email directly or view it on GitHub.

@malas
Copy link
Author

malas commented Dec 7, 2014

@JanJansen47 i do not see any attachments in your reply, could you give an URL to the resource?

@tinue
Copy link

tinue commented Dec 7, 2014

I have to agree that PI4j is in the clear. The implementation of e.g. write() is very simple. Basically the native device is opened, and a byte is written. If the number of bytes written is not equal to the number that should have been written, then (numWritten - 20'000) is returned.
So obviously "-1" is returned, which gives the "-20001" return code.

PI4j could implement stuff like transparent retries etc., which would facilitate things, but the actual reason for the error is outside of PI4j.

I also tried to play with the I2C bus speed, from 1000 up to 110000, but without significant change.

@malas
Copy link
Author

malas commented Dec 7, 2014

@tinue could you explain in more detail the error -20001 return code, maybe then i would be able to debug further.

@tinue
Copy link

tinue commented Dec 7, 2014

I just checked in the source code, and it looks really simple:

response = write(fd, buf, 1);
  if (response != 1) {
    return response - 20000;

So apparently the write call returns -1, instead of the expected 1, so (-1 - 20000) is returned to Java, i.e. -20001.

To learn more, I think one would now have to check the device driver for I2C, which has write() implemented.

Update: In your case -20001 is strange, though. The code looks like this:

response = write(fd, buf, size);
  if (response != size) {
    return response - 20000;
  }

So unless you are writing exactly one byte, you should get a different number.

Update to the update: Obviously you also get "-1" in your call, so -20001 still is the expected return.

@JanJansen47
Copy link

Jan Jansen
Sagittalaan 22 5632al
+31688806529
On 7 Dec 2014 08:09, Laurynas Mališauskas notifications@github.com wrote:@JanJansen47 i do not see any attachments in your reply, could you give an URL to the resource?

—Reply to this email directly or view it on GitHub.

@JanJansen47
Copy link

Had random i2c errors with my pi. Turned out to be a hardware issue. I used an NXP solution. Never ever got errors anymore. Maybe you have the same issues. I used a scope to check the protocol. Remember it is always tricky to connect devices with separate supplies.
Jan Jansen
Sagittalaan 22 5632al
+31688806529
On 7 Dec 2014 08:22, tinue notifications@github.com wrote:I just checked in the source code, and it looks really simple:

response = write(fd, buf, 1);
if (response != 1) {
return response - 20000;

So apparently the write call returns -1, instead of the expected 1, so (-1 - 20000) is returned to Java, i.e. -20001.

—Reply to this email directly or view it on GitHub.

@tinue
Copy link

tinue commented Dec 7, 2014

There seems to be a known issue: raspberrypi/linux#254

I am not sure if this applies to my case, because so far I only send data from the Pi to the Arduino. But maybe the "ack" from Arduino to Pi is what gets lost.

If I understand everything correctly (and I am far from being sure), then I would have to change my code on the Arduino side. Right now I am doing everything in the interrupt handling routine of the I2C interrupt. It looks like I should not do this, and instead just set e.g. a flag that tells the main loop() what to do. This way the interrupt finishes much faster, and there is no risk that the next interrupt gets lost.

But again, I am far from being sure that this would solve the issue.

Edit: Changing the Arduino code does not fix anything.

@tinue
Copy link

tinue commented Dec 7, 2014

Just to confirm: I have the same problems when I use Python. It looks different, of course (Errno 5 Input/output error), but I think it has the same underlying cause.
So IMO the discussion should continue somewhere else (I2C driver, perhaps?)

@malas
Copy link
Author

malas commented Dec 7, 2014

my devices are connected from the same power supply., so this should not be the case.

so far from all the comments i think i should try to lower the I2C speed and hope for the best.

@tinue
Copy link

tinue commented Dec 7, 2014

With the default speed of 100'000 I get an error in about 1 in 10. With 75'000 it's maybe 1 in 100. So in the end it's a combination of measures:

  • Reduce the bus speed
  • On the Arduino, handle the interrupt really fast (or even avoid handling the interrupt, and do everything in the loop() method)
  • Implement a retry mechanism
    • Send single bytes only. This is simple on the sender side, but requires buffering on the receiver.
    • On the sender, retry if there is an exception
    • Unfortunately, the byte may have been lost, or the ack. So if there is an exception, sometimes the byte has been received by the Arduino, and sometimes not. This requires an idempotent handler on the Arduino side, which can be rather complex if all one can send is single bytes. One could e.g. make sure that the highest bit of the message flips between two messages. So if two bytes are received that have the highest bit identical, then the second one must be thrown away.

Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.
Labels
None yet
Projects
None yet
Development

No branches or pull requests

5 participants