Pages: [1]   Go Down
Author Topic: FreeIMU ITG3200 Wire.requestFrom freezing up occassionally  (Read 556 times)
0 Members and 1 Guest are viewing this topic.
Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I'm using a 6DOF IMU: https://www.sparkfun.com/products/10121 and the FreeIMU implementation for this IMU (code at http://www.varesano.net/projects/hardware/FreeIMU).

In order to get raw data from the Gyroscope (ITG3200), the following sequence of calls are made:

Code:
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.

I can provide more details if necessary. Thanks.
Logged

Offline Offline
Edison Member
*
Karma: 57
Posts: 2078
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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:
Code:
// 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();
}

You could use this, http://www.i2cdevlib.com/
« Last Edit: April 02, 2013, 02:53:22 am by Erdin » Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

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):

Code:
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.
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've also switched out the I2C dev library and the ITG3200 library with the one mentioned in your post, and I have the same problem (keeps freezing).
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 16
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I've found https://code.google.com/p/itg-3200driver/issues/detail?id=2 to be useful for others having this problem.

In particular, it seems that commenting out the following lines:

Code:
  setITGReady(_ITGReady);
  setRawDataReady(_INTRawDataReady); 

from inside

Code:
void ITG3200::init(unsigned int address, byte _SRateDiv, byte _Range, byte _filterBW, byte _ClockSrc, bool _ITGReady, bool _INTRawDataReady) {
  _dev_address = address;
  setSampleRateDiv(_SRateDiv);
  setFSRange(_Range);
  setFilterBW(_filterBW);
  setClockSource(_ClockSrc);
  //setITGReady(_ITGReady);
  //setRawDataReady(_INTRawDataReady); 
  delay(GYROSTART_UP_DELAY);  // startup
}

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...
Logged

Pages: [1]   Go Up
Jump to: