I2C Communication Problem.

Hi,

I’m trying to connect two Arduino Uno by I2C with very simple sketch and I’m having problems.

The wires are like this: https://encrypted-tbn0.gstatic.com/images?q=tbn:ANd9GcRHLCpH3FR1mSkSJpZm7Nqk_Sgl_x6bNO_0_7zIAAH_J48JQ4Qp

With 4k7 resistors (I tried 2k2, 1k, 100k…)

And de sketches are:

Master:

#include <Wire.h> 


void setup () 
{
  Serial.begin(115200); 
  Wire.begin();   
} 


void loop()
{
	if(getData(0x02) == 0)
	{
	  count++;
	  Serial.println("\tOk");
	}
	else
	{
	  countErr++;
	  Serial.println("\tWrong!");
	}
}  

int getData(int sensorID)
{
  int i = 0;
  Wire.requestFrom(sensorID, 5, true);
 
  while(Wire.available())
  {
    char c = Wire.read();
    Serial.print(c, DEC);
    i++;
  }

  if(i == 5) // he leido 5, salgo con Ok
  {
    return 0;
  }
  return 1;
}

Slave:

Wire.begin(0x02);
Wire.onRequest(requestData);

void requestData()
{
	digitalWrite(13, HIGH);
	delay(100);
	digitalWrite(13, LOW);

	static bool change = false;

	if (change)
	{
		Wire.write("12345", 5);
	}
	else
	{
		Wire.write("54321", 5);
	}
	change = !change;	
}

The output is:

12345 Ok
 ÿÿÿÿ Ok
 ÿÿÿÿ Ok
54321 Ok
12345 Ok
 ÿÿÿÿ Ok
12345 Ok
 ÿÿÿÿ Ok
12345 Ok
54321 Ok
12345 Ok
 ÿÿÿÿ Ok
12345 Ok

And in DEC:

0-1-1-1-1	Ok
4950515253	Ok
5352515049	Ok
4950515253	Ok
0-1-1-1-1	Ok
5352515049	Ok
4950515253	Ok
0-1-1-1-1	Ok
4950515253	Ok
5352515049	Ok
0-1-1-1-1	Ok
4950515253	Ok
5352515049	Ok
4950515253	Ok
5352515049	Ok
4950515253	Ok
5352515049	Ok
4950515253	Ok
5352515049	Ok
0-1-1-1-1	Ok
4950515253	Ok

Is this a expected behaviour? Is the 0-1-1-1-1 an error in I2C that I must to discard?

Counting the error in a sample period of 10s, I had a 10% error, I think that is a high error rate.

Googling a read that the length of the cables are very important, the I2C bus that I have is no longer than 5-8cm.

Thaks you

Your requestData() function is called from an interrupt. Keep it as short and as fast a possible. You may not use the delay() function. And for example you may also not use any Serial function in such an interrupt handler. Remove the delay() from the requestData() function..

You could blink the led for example with : digitalWrite ( 13, change ? HIGH : LOW );

Did you know that you can start the Arduino IDE twice ? You can select an Arduino serial port in each of them, so you can develop both sketches at the same time side by side. You can also open the serial monitor for each Arduino at the same time.

Hi,

I tried to put just the Wire.write as you suggested.

void requestData()
{
    Wire.write("67890", 5);
}

And still getting errors. Maybe less, arround 7%.

Peter_n: You could blink the led for example with : digitalWrite ( 13, change ? HIGH : LOW );

Doing this I cannt appreciate the blink of LED, its blink very fast.

Peter_n: Did you know that you can start the Arduino IDE twice ? You can select an Arduino serial port in each of them, so you can develop both sketches at the same time side by side. You can also open the serial monitor for each Arduino at the same time.

Yes, I know. However I use to code in visual studio and pure C++, without "setup" and "loop". But the test I was doing was in Arduino Sketches.

Can I do something to improve the I2C bus? I want to connect 3 arduinos.

Thank you.

Could you add a delay at the end of the loop() in the Master. You request now data very often, probably filling the Serial output buffer. Baudrate 115200 is 10kbytes per second, that should be no problem, but I'm not sure. For example : delay(100);

If that doesn't help, can you provide two complete test sketches to test with two Arduino Unos ?

Hi Peter_n,

Sorry for delay. I’m making a IMU with one Arduino Pro Mini. For now just have an accelerometer, gyro and magnetometer.

I’m trying to send the YPR (yaw pitch roll) via I2C to other Arduino Pro Mini.

Slave Code:

#include <Arduino.h>
#include <HardwareSerial.h>
#include <Wire\Wire.h>
#include "ADXL345.h"
#include "ITG3205.h"
#include "HMC5883L.h"
#include "wiring.h"

#define ANGLE(x,y) (degrees(atan2(x,y))
#define I2C_PACKET_SIZE sizeof(imuData)

void requestData();
void getSensorData();
void getYawPitchRoll();
void getComplementaryFilter();

ADXL345 accel;
ITG3205 gyro;
HMC5883L magn;

//Loop Times
long samplePeriod = 20;
long lastSamplePeriod = 0;
long lastSampleTime = 0;

// Complementary filter
float ALPHA = 0.2;
float GYRO_GAIN = 1;
float ACCEL_GAIN = 1;
int step = 0;

typedef struct imuData
{
 float yaw;
 float pitch;
 float roll;
};

typedef union i2cPacket
{
 imuData imuValues;
 byte byteArray[sizeof(imuData)];
};

i2cPacket imu;

int main()
{
 init();

 pinMode(13, OUTPUT);
 
 //THREE BLINKS
 digitalWrite(13, HIGH);
 delay(100);
 digitalWrite(13, LOW);
 delay(100);
 digitalWrite(13, HIGH);
 delay(100);
 digitalWrite(13, LOW);
 delay(100);
 digitalWrite(13, HIGH);
 delay(100);
 digitalWrite(13, LOW);

 //Join to I2C bus as Slave
 Wire.begin(0x02);
 Wire.onRequest(requestData);

 //Serial.begin(115200);
 //Serial.println("Ready");

 //ACCEL
 accel.initAccel();
 accel.calibration();
 accel.printOffsets();

 //GYRO
 gyro.init();
 gyro.calibration();
 //gyro.printOffsets();

 //MAGN
 magn.init();
 //magn.calibration();
 //magn.printOffsets();


 for (;;)
 {
 lastSamplePeriod = micros() - lastSampleTime;

 //YPR
 getYawPitchRoll();
 

 //Serial.print(imu.imuValues.yaw);
 //Serial.print("\t");
 //Serial.print(imu.imuValues.pitch);
 //Serial.print("\t");
 //Serial.print(imu.imuValues.roll);
 //Serial.println("\t");


 lastSampleTime = micros();
 }

 return 0;
}

void getYawPitchRoll()
{
 getSensorData();

 getComplementaryFilter();
}

void getSensorData()
{
 // Get values of each sensor in different loop 
 switch (step)
 {
 case 0:
 //ACCEL
 accel.getAngleData();
 step++;
 break;
 case 1:
 //GYRO 
 gyro.getDSData();
 step++;
 break;
 case 2:
 //MAGN
 magn.getClearRawData();
 step = 0;
 break;
 default:
 break;
 }
}

void getComplementaryFilter()
{ 
 imu.imuValues.yaw = ALPHA * (imu.imuValues.yaw + (gyro.dsData[0] * GYRO_GAIN) * ((float)(micros() - lastSampleTime) / 1000000)) + (1.0f - ALPHA) * (accel.angleData[0] * ACCEL_GAIN);
 imu.imuValues.pitch = ALPHA * (imu.imuValues.pitch + (gyro.dsData[1] * GYRO_GAIN) * ((float)(micros() - lastSampleTime) / 1000000)) + (1.0f - ALPHA) * (accel.angleData[1] * ACCEL_GAIN);
 imu.imuValues.roll = 0;
}

void requestData()
{
 Wire.write(imu.byteArray, I2C_PACKET_SIZE);
}

If I uncomment the Serial, I get this values:

Ready
0.25 -0.21 0.00 
0.30 -0.26 0.00 
0.31 -0.26 0.00 
0.31 -0.09 0.00 
0.31 -0.05 0.00 
0.31 -0.05 0.00 
0.31 -0.04 0.00 
...

So, the Yaw, Pitch, Roll is ok.

Now, the Master part (in pure Arduino code):

#include <Wire.h> 

typedef struct imuData
{
 float yaw;
 float pitch;
 float roll;
};

typedef union i2cPacket
{
 imuData imuValues;
 byte byteArray[sizeof(imuData)];
};

i2cPacket imu;

void setup () 
{
  Serial.begin(115200); 
  Wire.begin();   
} 

void loop()
{
  if(getData(0x02))
  {
    //Serial.println("\tOk");
    Serial.println(imu.imuValues.yaw);
  }
  else
  {
    Serial.println("\tWrong!");
  }

  delay(300);
}  

bool getData(int sensorID)
{
  int i = 0;

  Wire.beginTransmission(sensorID);
  Wire.requestFrom(sensorID, 12);
 
  while(Wire.available())
  {
    imu.byteArray[i] = Wire.read();
    i++;
  }
  Wire.endTransmission();
  return (i == 12);
}

The output is:

0.00
0.00
0.00
nan
-15.45
-13.77
-13.02
-13.93
-12.37
nan
-11.42
-9.92
-11.81
-13.34
-14.36
nan
-16.70
nan
nan
-18.63
-16.68
-16.52
nan
-13.54
-12.92
-13.51
-12.94
-13.20
-12.48
-13.24
-13.13
nan
nan
nan
-10.08
-11.00
 Wrong!
-20.36
...

I assume that the nan is when I receive the 0, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1, -1

And the values are not the same from IMU.

PD: I tried a very simple example of I2C between Arduinos and it works fine.
Maybe the problem is that the accel+gyro+magn (GY-85) is connected in the same I2C bus, but it has different address and only Arduino “IMU” query it.

Well,

It seems that was a wiring problem. Now seems to work well (ignoring the errors that occurred) but at some point it has a small break and values remain frozen, or the entery program frozens.

Any idea?