In order to get raw data from the Gyroscope (ITG3200), the following sequence of calls are made:
void ITG3200::readmem(uint8_t _addr, uint8_t _nbytes, uint8_t __buff[]) {
Wire.beginTransmission(_dev_address); // start transmission to device
Wire.write(_addr); // sends register address to read from
Wire.endTransmission(); // end transmission
Wire.beginTransmission(_dev_address); // start transmission to device
//crashes on next line
Wire.requestFrom(_dev_address, _nbytes);// send data n-bytes read
uint8_t i = 0;
while (Wire.available()) {
__buff[i] = Wire.read(); // receive DATA
i++;
}
Wire.endTransmission(); // end transmission
}
It will run for a while (I'm calling this code in a loop every 100ms), but then it will freeze up on the call to requestFrom after a while and not return. I've tracked the problem down to inside the following function: uint8_t twi_readFrom(uint8_t address, uint8_t* data, uint8_t length, uint8_t sendStop) (which is in the twi.c file in /libraries/Wire/utility/twi.c).
Has anyone had this problem before with the ITG3200? I suspect I have a timing problem (not calling this code fast enough or too fast), but have not been able to fix it. Why does this just seem to hang sometimes? Any help is appreciated.
I have read before that beginTransmission does not need to be called before requestFrom, and I have tried running this code with the beginTransmission removed, but I have the same problem.
A few functions of the I2C Wire library are "blocking".
They have no timeout, and the sketch will stop if they don't receive data from the I2C device.
The beginTransmission() and endTransmission() should not be around the requestFrom().
This is the normal way to read:
// Set the register address by writing a byte.
// The return value of the endTransmission
// can be used to detect if the device is available.
// The endTransmission() handles the I2C session,
// using the data in the buffer.
Wire.beginTransmission(...);
Wire.write(...);
Wire.endTransmission();
// Read data in a new I2C session.
// The requestFrom() is a complete I2C session,
// with start and stop conditions.
// The I2C device returns the data starting from the register address,
// that was set before.
// The requestFrom() places the read data in a buffer.
// The available() and read() operate on the buffer.
Wire.requestFrom(...);
while (Wire.available()) {
... = Wire.read();
}
I've tried commenting out the beginTransmission and endTransmission lines, to no avail. The accelerometer which never freezes uses the following in its code (I've disabled those lines too):
void ADXL345::readFrom(byte address, int num, byte _buff[]) {
Wire.beginTransmission(_dev_address); // start transmission to device
Wire.write(address); // sends address to read from
Wire.endTransmission(); // end transmission
Wire.beginTransmission(_dev_address); // start transmission to device
Wire.requestFrom(_dev_address, num); // request 6 bytes from device
int i = 0;
while(Wire.available()) // device may send less than requested (abnormal)
{
_buff[i] = Wire.read(); // receive a byte
i++;
}
if(i != num){
status = ADXL345_ERROR;
error_code = ADXL345_READ_ERROR;
}
Wire.endTransmission(); // end transmission
}
The code hands inside requestFrom(). Some research I've done since posting this tells me that in particular the ITG3200 gyroscope has this problem with the I2C library. There are two busy-spin loops inside twi.c that wait for the bus to have a 'ready' status, and if this status is never reached, the loops never terminate and the application hangs.
I've tried putting a timeout in these loops and calling twi_init() to attempt to reset the Wire interface, also to no avail (the application just hangs next time through the loop).
I'm tempted to blame the ITG3200, since other devices (magnetometer, accel, different gyros) people are using do not have this issue nearly as often if at all.
Someone on another forum mentioned it might have to do with noise on the bus. The more noise, the less likely the Wire library will terminate.
in ITG3200.cpp help improve stability (I had it crash once since commenting these lines out though), but seems to run much longer. I may put a 50 or 100ms delay between my queries to see if this helps...