I2C Slave blocks after some time when using wire library

Hi there,
I run into trouble when using the arduino wire library for communication between an Arduino Uno (master) and an Arduino pro mini board (slave).
I transmit 28 bytes of data two each 500 ms. It runs good for a period of time, but after lets say 2-3 minutes the slave blocks.

I already tried with or without external pullup restistors (4.7 K) -> still slaves blocks after a few minutes
I already tried without Arduinos connected to PC -> still slaves blocks after a few minutes
I already tried to increase the buffer size in twi.h and wire.h to 64 bytes -> still slaves blocks after a few minutes.

Now I am running out of ideas...

Here is the master code executed each 500 ms in main loop:

Wire.beginTransmission(4); // transmit to device #4
for (index = 0; index < 28; index++)
Wire.write (dataPtr[index]);
Wire.endTransmission(); // stop transmitting
}

Here is the slave code executed in receiveEvent function:

while (Wire.available() > 0) {
c = Wire.read();
if (index < sizeof (Data_t)) {
dataPtr[index] = c;
recvCRC+=dataPtr[index];
index++;
}
}

When I restart the slave by pressing the reset button communication goes on...

I am running the arduino (master) on only 5.1 volt. But this seems not to be a problem for other functionality.
I am running SoftwareSerial on the slave also - can this interfere with the wire library?

What can be the problem? Please help :slight_smile:

Thanks in advance...

Hi guys,

I continue testing.

More background information:

On the slave (pro mini) which freezes I used also:

  • HardwareSerial with 115200 for trace outputs
  • SoftwareSerial with 19200 for communicating with another device.

I tried first to comment out the communication with the SoftwareSerial which had no effect.

BUT when I take the trace outputs to hardware serial out including the Serial.Beging (115200) statement I was now able to run stable for 15 minutes, which was never reached before...

Is it possible that the hardware serial interferes with the wire library?

You might get some help if you post your entire sketch from the slave.

I will take a guess that you are using the String data type somewhere in your code. That always causes a crash in my sketches.

Hi Tim,

I have to cleanup the sketch a little before I post it completely :stuck_out_tongue:

But of course the trace outputs to serial contain strings: Here is what I used for example:

Serial.print ("I2C Messages: "); Serial.print (countI2C);
Serial.print (" I2C Time Max: "); Serial.print (maxI2C);

You mean this could be the reason for a crash? That would be horrable?!?

Not string as in character array, String as in Object.

Like maybe this?

String recvCRC;

Ahhh okay...

But I don't use this...

Oli_Berlin:
Ahhh okay...

But I don't use this...

Then what is this?

      recvCRC+=dataPtr[index];

This is a CRC computation. recvCRC ist defined as uint8_t...

Here is the slave code executed in receiveEvent function:

while (Wire.available() > 0) {
c = Wire.read();
if (index < sizeof (Data_t)) {
dataPtr[index] = c;
recvCRC+=dataPtr[index];
index++;
}
}

Are all variables used here declared as volatile? I hope you don't do any Serial.print() in the receiveEvent() function. As Tim already wrote, show us the complete code because the problem may be in a completely other place than you might expect it.

After several tests I am quit sure that it was the communication with the hardware serial which lead to the menationed problems...
Now I don't have any blockings at all.

Maybe it is because Hardware Serial has conflicts with Software Serial which is also running on the mini pro...

If somebody knows why this could interfere with the wire lib please tell...

pylon:

Here is the slave code executed in receiveEvent function:

while (Wire.available() > 0) {
c = Wire.read();
if (index < sizeof (Data_t)) {
dataPtr[index] = c;
recvCRC+=dataPtr[index];
index++;
}
}

Are all variables used here declared as volatile? I hope you don't do any Serial.print() in the receiveEvent() function. As Tim already wrote, show us the complete code because the problem may be in a completely other place than you might expect it.

Unfortunately i did and I did not set the variables to valatile...

Here is the code, please comment...

#include <arduino.h>
#include <SoftwareSerial.h>
#include <Wire.h>

// #define TRACES

uint32_t countI2C = 0;
uint32_t now, start;
uint32_t maxI2C=0, lastI2C, millisStart;
uint8_t recvCRC, bytesRead;
uint8_t statusLED;
Data_t data;

#ifdef TRACES
uint32_t traceMillis=0;
#endif

void setup() {

#ifdef TRACES
// Hardware serial setup
Serial.begin (115200);
#endif

// Init status LED
pinMode(STATUS_LED_PIN, OUTPUT);
statusLED = 0;

// I2C Setup
Wire.begin(4); // join i2c bus with address #4
Wire.onReceive(receiveEvent); // register event
recvCRC = 0;
bytesRead=0;
millisStart = millis();
}

void loop() {

// Check is something has been arrived on I2C Bus
if (bytesRead > 0) {
bytesRead = 0;
countI2C++;
if (lastI2C > maxI2C)
maxI2C = lastI2C;

// Toggle status LED
if (0 == statusLED) {
statusLED = 1;
digitalWrite(STATUS_LED_PIN, HIGH);
} else {
statusLED = 0;
digitalWrite(STATUS_LED_PIN, LOW);
}
}

#ifdef TRACES
if (millis() - traceMillis > 1000) {
traceMillis = millis();
Serial.print ("I2C Messages: "); Serial.print (countI2C);
Serial.print (" I2C Time Max: "); Serial.print (maxI2C);
Serial.print (" I2C Time: "); Serial.print (lastI2C);
}
#endif
}

// function that executes whenever data is received from master
// this function is registered as an event, see setup()
void receiveEvent(int howMany)
{
char *dataPtr = (char *) &data;
byte c;
uint8_t index=0;
uint32_t startT, endT;

#ifdef TRACES
Serial.print ("Receive: "); Serial.println (howMany);
#endif
index = 0;
recvCRC = 0;
startT = micros();
while (Wire.available() > 0) {
c = Wire.read();
if (index < sizeof (Data_t)) {
dataPtr[index] = c;
recvCRC+=dataPtr[index];
index++;
}
}
lastI2C = micros() - startT;
bytesRead = index;
#ifdef TRACES
Serial.print ("Index: "); Serial.print (index);
Serial.print (" Time"); Serial.println (lastI2C);
#endif
}

What happens if I use Serial.print() inside the receiveEvent function?

Oli_Berlin:
What happens if I use Serial.print() inside the receiveEvent function?

You might get a dead-lock as you're experiencing. The problem is that Serial.print() just writes into a buffer that needs to emptied by an interrupt that fills the hardware register with the next byte when the previous one is completely transferred. The problem is that inside an interrupt handler (receiveEvent() is called in interrupt context) interrupts are disabled. If you make a print() and the buffer is full, the code just waits (the interrupt should make some space again) but it will never get better because no interrupt is executed.
BTW: micros() also will not always work as you might expect for the same reason.

You should declare all global variables used in the interrupt handler as "volatile", p.e.

volatile uint8_t recvCRC;

What happens in your code, when the array you are putting the received characters into, gets full ?