Go Down

Topic: I2C hang (Read 1 time) previous topic - next topic

SamBrownADK



I have 2 Uno R3 boards talking back and forth to each other via I2C (simple messages). All is well. No problems. When I pull power on either board (to simulate a fault in the wire, dead battery, failed board, etc) the other board hangs at the wire.endTransmission() point. This is the exact spot it hangs. I can;t even get a return code: just freezes. If I power up the "broken" board and chatter returns to normal like nothing happened.

I have tried many solutions I have read about here (including WSWireLib.h which Uno R3 does not like for some reason) and still can not get past this problem. I am a beginner and do not have an IT background. Any suggestion in the right direction is appreciated.  All the threads I have read suggest there is a new / updated lib to deal with this exact problem but nothing seems to replace wire.h properly.

chucktodd

I have 2 Uno R3 boards talking back and forth to each other via I2C (simple messages). All is well. No problems. When I pull power on either board (to simulate a fault in the wire, dead battery, failed board, etc) the other board hangs at the wire.endTransmission() point. This is the exact spot it hangs. I can;t even get a return code: just freezes. If I power up the "broken" board and chatter returns to normal like nothing happened.
You need to understand the electrical interface of the I2C bus.

On the I2C bus, there is one set of pullup resistors supplying power for the bus. To send data over the bus the connected devices (both master and slave) pull these signals to GND.  So normally the Bus(SDA,SCL) are at VCC.

Now most digital electronic device have input protection circuits on each pin.  One of the simplest methods of protecting an input from overvoltage is to connect a diode from the input pin to VCC.  The purpose of this diode is to route any voltage on the input pin that exeeds Vcc to VCC.

When you 'pull the power' on one of your devices, this means than any voltage on any pin of those devices that are now greater than the device's VCC are shorted to that device's VCC circuit.

The effect is to Ground the I2C bus.  This causes the Wire.h library to think the bus is inuse.  It will wait fore ever for the bus to become ready.

I modified Wire.h to handle this timeout problem, but my library is now out of date I think it is compatible with Arduino 1.6.5.  

To handle your power fail issue, you will have to add hardware.  You will have to create a circuit that will isolate any device that fails from the I2C bus.

I use PCA9545A I2C bus switches.  This switch allows me to break my I2C network in 4 controllable branches. When I get a timeout failure on the I2C bus, I reset the PCA9545, this isolates each branch of my I2C net.  Then I individually try each branch until the network 'hangs' again. When I have identified the failing branch I just isolate that single branch.

So, my solution requires a modified version of Wire.h, and some hardware.

Chuck.
Currently built mega http server, Now converting it to ESP32.

SamBrownADK

chucktodd:  Thank you. I am going to look into the PCA9545A.  Thank you for explaining to me what the darn thing is and what the issues are... :-)

chucktodd

#3
Mar 06, 2017, 04:57 am Last Edit: Mar 06, 2017, 04:59 am by chucktodd
chucktodd:  Thank you. I am going to look into the PCA9545A.  Thank you for explaining to me what the darn thing is and what the issues are... :-)
You can find my modified version of the Wire library on github my userid is StickBreaker.

It is not compatible/test with the 1.8.x Arduino environment, but all of my changes are commented. Look for 'chuck' in the comments.  You could compare my changes with the current Wire library and make appropriate changes.

Chuck.
Currently built mega http server, Now converting it to ESP32.

SamBrownADK

chucktodd: Thank you again!  I am not sure what to comment or modify in your files but I will try my best. I am new to programming and Arduino so still kinda flying blind... but having fun doing it :-)   Thank you very much for helping me again, sometimes all the "stuff" I need to know is a bit overwhelming.

SamBrownADK

One more question: with the comments I rem in / out make it compatable with the current Arduino environment (1.8x)?

chucktodd

One more question: with the comments I rem in / out make it compatable with the current Arduino environment (1.8x)?
No, my modified version of the Wire library won't run if you comment out my changes,  My changes replace function in the Wire library.

I just meant that you could see what I changed and why. 

My modified version address a couple of issues:
  • Adds timeouts to the bus synchronization loops.
  • Changes Wire.write(int) to actually send two bytes instead of just one.
  • Changes how onRequest() functions.
    The Original version only allow ONE Wire.write() inside the callback. (1.8.x fixed this)
    My version allows multiple Wire.write() to build up a response.
    And my version allows random number of bytes in the responses.  The callback can be written such that is only returns one byte at a time.  As long a the master is requesting bytes it can send them.  This makes my version act differently then the stock version, so my version is not directly compatible.
  • my version adds a lastError() function to return a useful error code, instead of just 'failed'.


For your situation, I think you should start with the Current Ardunino enviroment. Read through the Wire.h library code and add timeouts to the synchronization loops.  With those timeouts added, you have to add tests for those timeout fails in your code, and decide how you will recover.

It is going to take some effort on your part to add fail recovery.  The Arduino environment is designed to be simple and easy to use, not robust and durable.  Your recover from power failure scenario was never envisioned.

Chuck.
Currently built mega http server, Now converting it to ESP32.

SamBrownADK

OK. thank you again.  Well, I have a lotta learning to do but it will be fun :-)  Thank you Chuck!

hobbyist1863

Hello! I too experienced the problem of my code hanging up when one of my slave Arduinos lost power but I was able to create a workaround to this problem while still using the default Wire library.

My original project included having one master Arduino request data from a number of slaves connected together in a chain (SDA and SCL feed into A4 pins and A5 pins on slave and connect to next slave through the SDA and SCL pins).

By using an Arduino relay shield I was able to bypass the slave that lost power and detect this loss with a (!Wire.available()) function after data had been requested for the specified slave address.

I have attached a basic circuit diagram depicting my solution. The numbers on the wire terminals for each respective relay denote the state of each pin with 1=Normally Closed, 2= Common, and 3= Normally Open. By programming each slave to keep the relays high at all times it ensures that the master can talk to each slave when powered and when power is lost the SDA and SCL lines simply bypass the unpowered slave ensuring your program doesn't hang up.

This solution has been working great for me and I hope it does the same for you!

paynterf

Hi,

I too have had problems with I2C bus reliability.  I ran across unaie's modified version of twi.c and twi.h that added timeouts to all of the blocking 'while()' loops, and this seems to have solved the problem (or at least my problem!).  Unaie's original twi.c/h wasn't compatible with the later 'repeated starts' versions of twi.c/h, so I had to do a little work to merge the two.

See my post(s) at

http://fpaynter.com/2018/08/integrating-time-memory-and-heading-capability-part-v/

for details

Frank

Go Up