I have an I2C bus with ten slaves controlled by an Arduino Nano. Periodically the system locks up; this can happen anything from a few seconds to tens of minutes after startup and does not seem to be related to any particular activity.
When the lock-up occurs, the Arduino is holding the SDA line low. Can anyone tell me what this implies? What part of the bus transaction could it have stopped in? And what can I do about it?
Thanks
Donko
When the lock-up occurs, the Arduino is holding the SDA line low.
Are you sure the Arduino is holding the signal low?
Can anyone tell me what this implies?
That the bus wiring is not correct.
What part of the bus transaction could it have stopped in?
There are several while loops in the code of the Wire library which might be endless if the bus isn't working properly.
And what can I do about it?
- Fix the bus wiring.
- Use the watchdog to reset the Arduino if a lockup happens.
- Patch the Wire library to have timeouts for every while loop. Expect the performance to degrade considerably.
With ten slave devices on the bus I guess the pull-ups are wrong. Either calculate or messure the bus capacitance and install correct pull-ups. Maybe you have to remove some.
//o// with all the information and schematics you gave you made it real easy. Try changing your 4.7K Pull Up resistors to 3.3K or a bit lower and see if that helps. Also cut the physical length of the bus by about 50% if you can.
Thanks for the replies.
Yes, I am sure the Arduino is holding the SDA line low, I disconnected everything else. I had hoped that this would be a clue to which part of the bus transaction it had got stuck in.
The bus is based on two Grove 4-port hubs wired together. The Arduino is about 100 mm of cable away from the hub and the other devices are plugged in. The shortest cable is 40 mm. The longest cable is about 450 mm to a group of four sensors wired together. Most of the devices on the bus have pull-ups. The total effective pull-up resistance is 0.95 k. Could this be too low? Data and clock rise times are 0.6 to 0.7 us and fall times are 0.2 to 0.3 us, measured at the Grove hub. Clock rate is 100 kHz.
I tried a version of the Wire library which had timeouts added but it ran like a sick sloth!
I can use the watchdog to reset the processor on lock-up but this forces me through the startup sequence which takes 5 seconds.
Sometimes the system will run for hours without failing, sometimes it fails within seconds. Not correlated with any external action, apart from a gradual loss of my hair!
The bus is based on two Grove 4-port hubs wired together. The Arduino is about 100 mm of cable away from the hub and the other devices are plugged in. The shortest cable is 40 mm. The longest cable is about 450 mm to a group of four sensors wired together.
The overall bus length should be less than 50cm, otherwise you have to lower the speed dramatically.
Most of the devices on the bus have pull-ups.
The pull-ups should exist exactly once per bus!
The total effective pull-up resistance is 0.95 k. Could this be too low?
Of course! The standard says the maximum sink current must be 3mA. Calculate yourself.
I tried a version of the Wire library which had timeouts added but it ran like a sick sloth!
As I predicted.
I can use the watchdog to reset the processor on lock-up but this forces me through the startup sequence which takes 5 seconds.
If the Wire library locks up there is a reason for it. The bus must be in an error state, so you have to initialize all devices anyway if it happened.
Sometimes the system will run for hours without failing, sometimes it fails within seconds. Not correlated with any external action, apart from a gradual loss of my hair!
In such a setup the influences may be small. Air humidity might be one factor, the actual power voltage another one. Electrical noise is good candidate too. If you don't follow the rules the result is unpredictable.
Thanks for the helpful advice. I will remove some of the pull-ups and see what happens.
I have obviously been reading the wrong specification because I thought that much lower resistance pull-ups were permissible. Can you give me a link to the correct I2C specification, please?
See the link to the pdf document at the bottom of this page: https://i2c.info/i2c-bus-specification.
For example page 47, Tabel 9, IOL is minium 3 mA for the Standard 100 kHz I2C bus.
For standard mode: Every device should at least be able to sink 3 mA.
They may sink more, but if a sensor can sink 3 mA then it is according to the I2C standard.
Therefor the pullup resistor should be choosen so the maximum sink current does not exceed 3 mA.
Tests of the pullup resistor: Gammon Forum : Electronics : Microprocessors : I2C - Two-Wire Peripheral Interface - for Arduino
Fun fact: When a pullup resistor is connected to 5V, the pullup current reduces to zero when the signal reaches 5V. It is allowed to have a current source that continuously gives 3mA. That will improve the signal a lot.
You can measure the sink current with a multimeter:
Make a sketch with Wire.begin() in the setup() function and a empty loop(). Run that sketch and measure the shortcut current from SDA to GND and from SCL to GND.
Do you have 5V and 3.3V sensors on the same I2C bus ?
Do you use a level shifter ?
When you use 3.3V sensors together with 5V sensors on a 5V Arduino board, then there is a good chance that it will go wrong.
When you use a level shifter, then a sensor has to sink both the 5V I2C bus and the 3.3V I2C bus.
When a module has a level shifter on the board, then it has often 10k on both sides of the level shifter. You have to include both resistors when calculating the sink current.
Thank you everybody for your help. I have increased the combined resistance of the pull-ups to 2 k, and that seems to have fixed the problem.