Go Down

Topic: Issues with I2C - data returned is weird... (Read 910 times) previous topic - next topic

CyberBill

I'm trying to get my arduino up and running with a 3-axis magnetometer (HMC5883L) and 3-axis accelerometer (MMA8452) over I2C.  When I connect up the magnetometer I get mostly decent data - but the "IDENTIFIER" registers don't return the right data, and it seems like the actual data returned from the magnetometer may be bad.  The values seem strange, but it is definitely responding to movement, but if I rotate about the Z axis, the Z value changes - which shouldn't happen.  The accelerometer is just completely out of whack.  If I print out the entire register set, the status register has 0xFF, rather than 0x00, and then all the other registers are 0xEC, 0xE6, 0x05, 0x00 - repeating.  It makes no sense.  I can re-read the same register and get totally different results each time.  Now - the particularly strange part is that if I have my loop read the 6 bytes of accelerometer data and print out the X,Y,Z values - the Y value is completely correct... But the others are whack.  And if I read them individually, they're all bad. (usually returning 0 or 0x0F)

Anyway - I am not sure what to do next to debug this.  I know data is going out and coming back in, but the data returned is just inconsistent.  I am using a logic level converter to switch between 5v and 3.3v, and I am using 4.7k pullups.  I've tried changing the pullups, I've tried putting pullups on the 5v side, I've tried removing one I2C device and using the other, etc.  Any tips would be much appreciated!!  Here are some code snippets:

Code: [Select]
// I2C Addresses:
#define COMPASS 0x1E       //0011110b, I2C 7bit address of HMC5883L 3-Axis Magnetometer
#define ACCELEROMETER 0x1D //0011101b, I2C 7bit address of MMA8452Q 3-Axis Accelerometer

bool I2CReadRegisters( byte address, byte reg, byte bytes )
{
  // Select the register
  Wire.beginTransmission(address);
  Wire.write(reg);
  if( Wire.endTransmission() != 0 )
  {
    Serial.print("I2CReadRegisters( Address=0x");
    Serial.print(address, HEX);
    Serial.print(", Register=0x");
    Serial.print(reg, HEX);
    Serial.print(", NumBytes=");
    Serial.print(bytes, DEC);
    Serial.println(") - failed at endTransmission");
    return false;
  }
  /* Request 'bytes' byte*/
  Wire.requestFrom(address,bytes);
  while( Wire.available() < bytes );
  return true;
}

bool I2CWriteRegister( byte address, byte reg, byte value )
{
  Wire.beginTransmission(address);
  Wire.write(reg);
  Wire.write(value);
  if( Wire.endTransmission() != 0 )
  {
    Serial.print("I2CWriteRegister( Address=0x");
    Serial.print(address, HEX);
    Serial.print(", Register=0x");
    Serial.print(reg, HEX);
    Serial.print(", Value=");
    Serial.print(value, HEX);
    Serial.println(") - failed at endTransmission");
    return false;
  }
  return true;
}

inline void ReadAccelerometer()
{
  // Only request the accelerometer data every 1500ms
  static unsigned long s_lastUpdateTime = 0;
  unsigned long now = millis();
  int delta = now - s_lastUpdateTime;
  if( s_lastUpdateTime != 0 && delta < 1500 )
  {
    return;
  }
  s_lastUpdateTime = now;
 
  Serial.print("Accelerometer: ");
 
  // Request 6 bytes, starting at register 0x01
  if( I2CReadRegisters(ACCELEROMETER, 0x01, 6) )
  {
    static char axis[] = {'x','y','z'};
    for(int i=0; i<3; ++i)
    {
      char value = Wire.read();
      Wire.read(); // Throw 2nd byte away.
      Serial.print(" ");
      Serial.print(axis[i]);
      Serial.print("=");
      Serial.print(value, DEC);
    }
    Serial.println("");
  }
 
  I2CReadRegisters(ACCELEROMETER, 0x01, 1);
  char value = Wire.read();
  Serial.print(" X=");
  Serial.print(value, DEC);
 
  I2CReadRegisters(ACCELEROMETER, 0x03, 1);
  value = Wire.read();
  Serial.print(" Y=");
  Serial.print(value, DEC);
 
  I2CReadRegisters(ACCELEROMETER, 0x05, 1);
  value = Wire.read();
  Serial.print(" Z=");
  Serial.println(value, DEC);
}

inline void ReadCompass()
{
  // Only request the compass every 500ms
  static unsigned long s_lastUpdateTime = 0;
  unsigned long now = millis();
  int delta = now - s_lastUpdateTime;
  if( s_lastUpdateTime != 0 && delta < 500 )
  {
    return;
  }
  s_lastUpdateTime = now;
 
  // Request 6 bytes, starting at register 0x03
  I2CReadRegisters(COMPASS, 0x03, 6);
 
  // Read the data
  Serial.print("Compass: X=");
  int value = Wire.read()<<8;
  value |= Wire.read();
  Serial.print(value);
 
  Serial.print(" Y=");
  value = Wire.read()<<8;
  value |= Wire.read();
  Serial.print(value);
 
  Serial.print(" Z=");
  value = Wire.read()<<8;
  value |= Wire.read();
  Serial.println(value);
}


And some sample output when I've got it only reading the accelerometer:
Code: [Select]

Accelerometer:  x=-1 y=-28 z=0
X=0 Y=0 Z=15
Accelerometer:  x=-1 y=-28 z=0
X=15 Y=15 Z=15
Accelerometer:  x=-1 y=-28 z=9
X=0 Y=0 Z=0
Accelerometer:  x=-1 y=-28 z=0
X=0 Y=15 Z=15
Accelerometer:  x=-1 y=-28 z=0
X=14 Y=14 Z=14
Accelerometer:  x=-1 y=-28 z=0
X=0 Y=15 Z=15
Accelerometer:  x=-1 y=-28 z=0
X=0 Y=15 Z=15
Accelerometer:  x=-1 y=-28 z=0
X=15 Y=15 Z=15
Accelerometer:  x=-1 y=-28 z=0
X=0 Y=0 Z=15

^-- Note that the y=-28 is correct, but the others are not.

CyberBill

So, about 5 minutes after I posted this I found the problem. :)

Code: [Select]
bool I2CReadRegisters( byte address, byte reg, byte bytes )
{
  // Select the register
  Wire.beginTransmission(address);
  Wire.write(reg);
  if( Wire.endTransmission() != 0 )     <-- ISSUE IS RIGHT HERE!!!!
  {
    Serial.print("I2CReadRegisters( Address=0x");
    Serial.print(address, HEX);
    Serial.print(", Register=0x");
    Serial.print(reg, HEX);
    Serial.print(", NumBytes=");
    Serial.print(bytes, DEC);
    Serial.println(") - failed at endTransmission");
    return false;
  }
  /* Request 'bytes' byte*/
  Wire.requestFrom(address,bytes);
  while( Wire.available() < bytes );
  return true;
}


The line:   if( Wire.endTransmission() != 0 )   The problem is that Wire.endTransmission takes an optional parameter ("stop") that defaults to true.  I guess some I2C devices will work fine either way, and some will not work the way it's written.  The fix is to pass in "false":

if( Wire.endTransmission(false) != 0 )

After that - everything works. :)

Fransie


copil

Hey,
Can you kindly tell me what exactly is the output of this sensor??? what i am getting is like x=55, y=87, z=92. what are these readings radians or Gauss???? My application is to find magnetic field strength.
Can you help me on this???

Go Up