Fast I2C connection

Hey,

once again I need some advice :smiley:

I'm trying to interface with a GY80 10DOF breakout. The board consists of an ADXL345 (accelerometer), a L3G4200D (gyrometer), a HMC5883L (compass) and a BMP085 (barometer), but I only need the data from the first three sensors (3 axis each).

I have written a little library, which includes functions to initialize and read out the sensors (via I2C). So far, every thing works fine, I can calculate the euler angles from the readings and the results are fine, BUT it is far to slow.
It takes around 3ms to read out all three sensors and around 863us to read only the accelerometer (calculations not included, but they only amount for fraction of this time).

I need the sensor for a very time sensitive application and 3ms won't do it. I don't know the limitation of the sensor or the I2C protocol itself, but I was hoping to get something about 500us maximum (is that realistic)? By the way, I'm using an Arduino Due.

This is basically the code I'm using:

void IMU::readBytes(int deviceAddr, int registerAddr, int numBytes, int16_t buffer[]){
	Wire.beginTransmission(deviceAddr);
	Wire.write(registerAddr | (1 << (numBytes + 1))); 
	Wire.endTransmission();
	Wire.requestFrom(deviceAddr, numBytes);

	while (Wire.available() < numBytes);
	
	for(int i = 0; i < numBytes; i++){
		buffer[i] = Wire.read();
	}
}
void IMU::getAcceleration(int16_t* ax, int16_t* ay, int16_t* az){
	int16_t buffer[6];
	readBytes(ACC_ADDRESS, ADXL345_DATAX0, 6, buffer);
	
	*ax = (buffer[1] << 8) | buffer[0];
	*ay = (buffer[3] << 8) | buffer[2];
	*az = (buffer[5] << 8) | buffer[4];
}

I think my problem comes with the while loop, which I'm using to wait until the Wire buffer reaches the desired number of bytes, but I don't know how to change it.

Also, I thought about changing the I2C speed.

A third thing that came to mind was using interrupts. I think I read something about interrupts that occur when there is new data to read (at least on the ADXL345). So I would only be reading the registers if there was new data in there...

Any help is welcome!

Josua

at what speed do you use the I2C now?

I think my problem comes with the while loop, which I'm using to wait until the Wire buffer reaches the desired number of bytes, but I don't know how to change it.

put a counter in it and see how often it loops. I expect zero time.

which means that you can remove it.

Hi Josua

Some rough arithmetic ...

To read the acceleration in your example takes (ignoring start and stop overheads):

  • 2 bytes to select the register
  • 7 bytes to read the contents

9 bytes = 72 bits. At 100 kHz, that is 720 us for data transfer time alone - in line with what you have measured.

If you could run the I2C at 400 kHz, that would come down to 180 us. Some info about 400kHz on Due here: Arduino Due I2C at 400kHz shows only 333kHz - Networking, Protocols, and Devices - Arduino Forum

Regards

Ray

Thanks for the answers!

I took a glance at the Wire library and discovered the function "setClock(uint32_t frequency)" .
So I tried using different frequencies. I started with 400khz, which shortened the duration from 3ms to 800us. Eventually I tried 800khz, 1600khz and 3200khz and the duration shrank to 250us.

However, what I do not understand is how such high frequencies are possible with the Due. The Due's datasheet states that it's TWI ports are only capable of 400kbit's

datasheets tell what will be supported reliably, you are working in a gray area where it might work for one DUE but not for the other. But if it works for you Great!