Is it possible to restart the i2c-bus in software with Wire.h?

Hi,

I'm reading a smart battery voltage (ebike battery) with

#include "Wire.h"
#define bl03_address 0x0b

int data_low = 0;
int data_high = 0;

void setup()
{
 Wire.begin(); // wake up I2C bus
 Serial.begin(115200);
 
}

void getvoltage()
{
 Wire.beginTransmission(bl03_address); 
 Wire.write(0x09); 
 Wire.endTransmission(false);
 Wire.requestFrom(bl03_address, 2);
 data_low  = Wire.read();
 data_high = Wire.read();
  
 double tempDataVoltage = (data_high*256) + data_low;
  
 double voltage = tempDataVoltage/3*10;
 Serial.print(voltage,0);
 Serial.print(",");
}

void loop()
{

getvoltage();
delay(500);

Serial.println("");
}

After a while it hangs itself up. Why? The battery is a slave device on the i2c bus and the arduino acts as a master. But there is the second master, the bike controller, who sends also requests to the battery.

So if it hangs, pressing the hardware reset on the arduino helps to reinitialize the bus. But is there a possibility to do that in the code, like a IF TIMEOUT FOR X SECONDS, RESTART BUS ?

Thats the sniffing data, I got from my buspirate:

[0x16+0x0D+[0x17+0x48+0x00-]  
[0x16+0x09+[0x17+0x48+0x30-]  my arduino
[0x16+0x0F+[0x17+0x74+0x14-]
[0x16+0x0F+[0x17+0x74+0x14-]
[0x16+0x16+[0x17+0xC0+0x00-]
[0x16+0x16+[0x17+0xC0+0x00-]
[0x16+0x09+[0x17+0x48+0x30-]  my arduino
[0x16+0x0D+[0x17+0x48+0x00-]
[0x16+0x0D+[0x17+0x48+0x00-]
[0x16+0x09+[0x17+0x48+0x30-]   my arduino
[0x16+0x0F+[0x17+0x74+0x14-]
[0x16+0x0F+[0x17+0x74+0x14-]
[0x16+0x16+[0x17+0xC0+0x00-]
[0x16+0x16+[0x17+0xC0+0x00-]
[0x16+0x09+[0x17+0x48+0x30-]   my arduino
[0x16+0x0D+[0x17+0x48+0x00-]
[0x16+0x0D+[0x17+0x48+0x00-]
[0x16+0x09+[0x17+0x40+0x10+0x01-]   my arduino
[0x16+0x09+[0x17+0x48+0x30-]    my arduino
[0x16+0x0F+[0x17+0x74+0x14-]
[0x16+0x0F+[0x17+0x74+0x14-]
[0x16+0x09+[0x17+0x48+0x30-]  my arduino
[0x16+0x16+[0x17+0xC0+0x00-]
[0x16+0x16+[0x17+0xC0+0x00-]
[0x16+0x09+[0x17+0x40+0x63+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x
00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x00+0x
00+0x00+0x00+0x00+0x00+0x00+0x00+      Hangs up

So it seems the arduino is doing arbitration, i think, and waits for his chance to join the bus.

Help in this case would be great.

toonlumberjack

The Wire library is "blocking". There are a few situations that makes it to wait forever. For example if the SDA and SCL accidently connect to each other.

You should avoid the situation that two Masters can claim the bus. You need one Master. The Master could retrieve the data from one Slave and send it to another Slave.

Restarting the Wire library is not possible in the sketch itself.

You can use the WatchDog and let the WatchDog reset the Arduino.

I run into a library bug when the Slave is an Arduino. You didn't mention if the bike controller or the battery are Arduinos.

Oh sorry I missed that point:

bike controller is built in version (I have no access to the pcb without destroying the display)
battery is a 36 V 13 Ah Lion secondary battery with bms (which supports data to the master on the bus who ask after the values)

Watchdog could be a option....have to try

You need one Master.

Yeah, would be nice if it is so. I have two options so: Looking fo a software solution .... didn't end well until now. Looking for a hardware solution. NXP formerly Philips something invents the i2c bus. They have developed different ICs for I2C. One is PCA9541. It's a "2to1 I2CBus Master Selector". I have already ordered it.

But still looking for software solutions.

Has anyone tried the dsscircuits.com is for sale | HugeDomains ?

There is this function:

Function:         I2c.timeOut(timeOut) - Allows the user to program a time out limit to prevent

                        and recover from I2C bus lockups.  I2C bus lockups have a tendency to freeze

                        a program which typically requires a power cycle to restart your progrm. This

                        allows the user to define a time out in which the I2C will release itself and reinitialize

                        and continue on with the next function.  Setting the value to zero will disable the function.

                        On a side note, be careful with setting too low a value because some devices support clock

                        stretching which can increase the time before an acknowledgement is sent which could be

                        misconstrued as a lockup.

                        If a lock up occurs the returned parameters from Read and/or Writes will contain a 1.

Parameters:    (uint16_t)timeOut: 1 - 65535 milliseconds. (ie 1000 = 1 second time out), 0 - disabled (default)

Return:             none

I'll try this one the next hours.

So further advice is appreciated.

toonlumberjack

That library implements a repeated start, but that is now also in the Arduino library.
The timeout is a good idea.

I have posted a few bugs/requests at Github for the Arduino Wire library:

But so far nothing is happening.

The hardware of the Arduino has some kind of collision detect if two Masters want the bus, but I don't know if that is implemented in the Arduino library.

You are breaking into an existing I2C bus, I think that it will always cause some kind of trouble, even with a master-selector ic.
Some microcontrollers (not the one used in the Arduino) are capable of sniffing the I2C bus.

That library implements a repeated start, but that is now also in the Arduino library.
The timeout is a good idea.

Think so too.

You are breaking into an existing I2C bus, I think that it will always cause some kind of trouble, even with a master-selector ic.

We'll see... Hope there won't be so much trouble.

Hi toonlumberjack

Did you solve the problem.... as I have exact same problem.
My Master is hanging even though I have a watchdog on both the Master and the Slave :frowning:

But the watchdog on the master can't kick in when the I2C is hanging. Big problem!

Br Tim