I2C interfering with interupts

There seems to be interference between interrupts I am using and I2C. I have found a way round this but I do not understand how it works.

I have a homemade robot that was working but I have not used for about 2 years.
It does not work now.

It has an Raspberry Pi deciding where it wants to go and an Arduino Uno actually doing the operation of motors etc.

That Arduino is attached to:

  • two motor controllers by I2C. The problem does not seem to affect these.
  • another Arduino running homemade wheel encoders by I2C using Master reader/Slave writer mode
  • 3 channel Radio Control allowing the thing to be steered when it gets lost. These are connected to 3
    pins that have interrupts using the PinChangeInt library.(the problems also occur using the EnableInterrupt library)

The raspberry Pi is currently not connected

As I said all this used to work fine but I am about to integrate another sensor (Lidar) so I tried to get it
to work as it was before proceeding.

The RC and the motor controllers work happily but as soon as I try to read the wheel encoder Arduino
the program freezes.

The RC works fine by itself with the motor controllers and the wheel encoders work by themselves while the RC is not being used, so I can only think that the interrupt routines and the I2C are in some way interfering with each other. I only write to the motor controllers.

The function that reads the encoder is a straight copy of the example in the library

void getTicks( long *rightTicks, long *leftTicks)
{
	byte right1, right2,right3,right4, left1, left2, left3, left4;

	
	Wire.requestFrom(2, 8);    // request 6 bytes from slave device #2

	
	while (Wire.available() < 8);               // Wait for bytes to become available
	right1 = Wire.read();
	right2 = Wire.read();
	right3 = Wire.read();
	right4 = Wire.read();
	left1  = Wire.read();
	left2  = Wire.read();
	left3  = Wire.read();
	left4  = Wire.read();
	
	*rightTicks = (((long)right4) << 24) + (((long)right3) << 16) + (((long)right2) << 8) + ((long)right1);
	*leftTicks  = (((long)left4)  << 24) + (((long)left3)  << 16) + (((long)left2)  << 8) + ((long)left1);
	
}

It occurrrred to me that if it somehow missed seeing 8 bytes it could wait for ever so I changed the code to have a time out as follows:

void getTicks( long *rightTicks, long *leftTicks)
  {
    byte right1, right2,right3,right4, left1, left2, left3, left4;
  
    
    long dTime = 0;
    long strt =  micros();
    while(dTime < 5000)
    {        
        Wire.requestFrom(ENCODERS, 8,true);    // request 8 bytes from slave device #2 
      
        if (Wire.available() == 8) break;               // Wait for bytes to become available
        dTime = micros()-strt;
        
    }
    Serial.println(dTime);
    if( dTime <5000)
    {
        right1 = Wire.read();
        right2 = Wire.read();
        right3 = Wire.read();
        right4 = Wire.read();
        left1  = Wire.read();
        left2  = Wire.read();
        left3  = Wire.read();
        left4  = Wire.read();
        *rightTicks = (((long)right4) << 24) + (((long)right3) << 16) + (((long)right2) << 8) + ((long)right1);
        *leftTicks  = (((long)left4)  << 24) + (((long)left3)  << 16) + (((long)left2)  << 8) + ((long)left1);
    }
    else
    {
      // remove any bytes
      while(Wire.available())
      {
        Wire.read();
      }
      }
      // just set to anything at the moment
       *rightTicks = 123;
       *leftTicks  = 123;
    }
    
       
  }

This works BUT the line " Serial.println(dTime); " put in to see what was happening always prints zero. In other words there is never a time out and it never gets to the line " dTime = micros()-strt; ".

So putting in this bit of code seems to have stopped the supposed interference.

Can anybody explain what is happening?

Thanks

Alan

Post the complete program so we can see everything in context.

If it used to work properly and now it does not something must have changed in the meantime.

If the device has not been used for a long time maybe there is a poor connection somewhere due to corrosion or due to accidental disturbance.

Have you re-uploaded the program and inadvertantly uploaded the wrong version - or perhaps used a different version of the Arduino IDE?

...R

After a Wire.requestFrom() there is no need to wait. Remove every timing/delay/wait after Wire.requestFrom().

A Wire.requestFrom() is a complete I2C transmission, with start and stop, everything.
When the Wire.requestFrom() returns, the I2C transmission has finished and the data is waiting in a receive buffer inside the Wire library.

The Wire.available() gives the number of available bytes that are waiting in the buffer (the receive buffer inside the Wire library).

There is no need to read the unread data with Wire.read().
The I2C bus uses packets, it is not a stream of data. When data of a I2C transmission is not used, it simply disappeares.

If something is wrong on the I2C bus, and nothing is received, then you can check the return value of Wire.requestFrom() or use the Wire.available().

Sometimes a I2C chip is not ready, because it is busy with something. Only a few chips have that and that should be in the datasheet. In that case the Wire.requestFrom() can be called over and over again until the I2C chip is finally ready to reply to the I2C bus.

Thank you for the replies. I have used a different version of the IDE and I am aware that the Wire library has changed during the last 2 years which could be the cause.

I have now found that using the WSWire library solves the problem without the changes I made, so the hang up is probably within the Wire library.

I still do not understand how the changes I made could get it to work .

Alan

I don't know the WSWire. This one ? GitHub - steamfire/WSWireLib: Arduino Wire Library modified to add timeouts to the freeze-prone TWI while() loops
If you need a Wire library with timeouts, then the I2C hardware bus has a serious problem. Do you use a cable or the wrong pullup resistors ? I think you better fix the I2C hardware bus.

That doesn't mean that I agree with the Arduino Wire library halting a sketch when there is something wrong with the hardware I2C bus. An embedded system should never be blocking by an external event of course. It is a big shame that the Arduino Wire library could halt a sketch.

Why don't you fix the things I mentioned and show the new sketch ?

Koepel:
I don't know the WSWire. This one ? GitHub - steamfire/WSWireLib: Arduino Wire Library modified to add timeouts to the freeze-prone TWI while() loops
If you need a Wire library with timeouts, then the I2C hardware bus has a serious problem. Do you use a cable or the wrong pullup resistors ? I think you better fix the I2C hardware bus.

That doesn't mean that I agree with the Arduino Wire library halting a sketch when there is something wrong with the hardware I2C bus. An embedded system should never be blocking by an external event of course. It is a big shame that the Arduino Wire library could halt a sketch.

Why don't you fix the things I mentioned and show the new sketch ?

The Hanging failure of WIRE.h is well known. In twi.c there are multiple:

while(TWI_READY != twi_state){continue;}
// and
while(TWI_MRX == twi_state){continue;}
// and
while(TWCR & _BV(TWSTO)){continue;}

If the bus is hung, Either through hardware malfunction or software glitch, TWI will lockup the sketch.

It was decided that error handling would be too complex for Arduino Users. So, if there is a bus error. the sketch hangs. There is no support for recovery.

Chuck.