kriswiner/MPU9250

MPU9250 magnetometer not accessible by any read

susano254 opened this issue · 4 comments

I just have got this GY-91 breakout board of MPU9255 and BMP280 I can read the accelerometer and gyro nicely

the magnetometer is being detected as 0x0C in I2C scanning but any read to any register is just some null or random values I made the bypass mode in the 0x37 register.

I have read many questions till now with similar problem with this magnetometer but non of them seems to have the problem of receiving just nothing back so do I assume the chip is faulty or Is there something I am missing.

const int MPU = 0x68; //I2C address of MPU9250
const int MAG = 0x0C; //I2C address of AK8963

void setup(){
  Serial.begin(115200);
  Wire.begin();     //init the communication object

  mpuInit();
  i2cScan();

  delay(100);

  i2cWrite(MAG, 0x0A, 0x12);
  delay(100);

  i2cRead(MAG, 0x00, 1);
  Serial.println(Wire.read());

  i2cRead(MAG, 0x0A, 1);
  Serial.println(Wire.read());

  i2cRead(MAG, 0x02, 1);
  Serial.println(Wire.read());

  i2cRead(MAG, 0x09, 1);
  Serial.println(Wire.read());
}

void i2cWrite(int addr, int regAddr, int data){
  byte error;
  Wire.beginTransmission(addr);
  Wire.write(regAddr);
  Wire.write(data);

  error = Wire.endTransmission(true);
  if(error == 0) Serial.println("Succesful Write");
  else Serial.println("Failed Write");
}

void i2cRead(int addr, int regAddr, int nBytes){
  Wire.beginTransmission(addr);
  Wire.write(regAddr);
  Wire.endTransmission(false);
  Wire.requestFrom(MPU, nBytes, true);
}

void i2cScan(){
  byte error, address;
  int nDevices = 0;

  for(address = 1; address < 127; address++ ) {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) {
      Serial.print("Unknown error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
}

void mpuInit(){
  //reset the mpu
  i2cWrite(MPU, 0x6B, 0x00);

  //enable the bypass multiplexer
  i2cWrite(MPU, 0x37, 0x02);
}

You need to read all of the mag data registers in succession in one operation including the status register. The latter is required for proper operation of the AK8963C.

I am not trying to read any Data registers yet just the ID register ( register 0 ) whose value should be fixed to ox48 and the CNTL1 register after writing a continous mode (MODE[3:0] = 2 or 6 ) to it
Both return either zeros or some random values but the i2c library reports no transmission errors which is why I suspected the chip to be faulty

I used this library to test it and it worked fine, so I knew the module wasn't the problem , traced the library code tried to tinker the mpuInit function I had with the setup one in the library nothing worked

finally for some reason using the read_byte function in the library it read successfully, So I noticed I had a typo in the address in i2cRead function definition silly me :(...
but anyway it works fine now, thanks a lot for ur fast response!!

here's the trimmed arduino code that works for me that just read the 9 axis raw values for any future visitors it's also worth noting for any newbie with this sensor like me that u need to read the ST2 register after reading the 6 measurement registers or else the measurement values will not be updated

void setup(){
  mpuInit();
  Serial.print("I2C bypass mode: ");
  Serial.println(read_byte(MPU, 55));
  Serial.print("I2C master mode: ");
  Serial.println(read_byte(MPU, 106));

  i2cScan();

  Serial.println(read_byte(MAG, 0x00));
  Serial.println(read_byte(MAG, 0x09));
  Serial.println(read_byte(MAG, 0x02));
  Serial.println(read_byte(MAG, 0x0A));
  
  //continous mode 2 and 16 bit resolution
  write_byte(MAG, 0x0A, 0x16);
  Serial.println(read_byte(MAG, 0x0A));

} 

void loop(){
  readAcc();
  readGyro();
  readMagneto();

  //finally print the values collected
  printData();
}

void write_byte(uint8_t address, uint8_t subAddress, uint8_t data) {
  Wire.beginTransmission(address);    // Initialize the Tx buffer
  Wire.write(subAddress);             // Put slave register address in Tx buffer
  Wire.write(data);                   // Put data in Tx buffer
  error = Wire.endTransmission();  // Send the Tx buffer
  if (error){
    Serial.println("Failed");
    Serial.println(error);
  }
}

uint8_t read_byte(uint8_t address, uint8_t subAddress){
  uint8_t data = 0;                         // `data` will store the register data
  Wire.beginTransmission(address);         // Initialize the Tx buffer
  Wire.write(subAddress);                  // Put slave register address in Tx buffer
  error = Wire.endTransmission(false);  // Send the Tx buffer, but send a restart to keep connection alive
  if (error){
    Serial.println("Failed");
    Serial.println(error);
  }
  Wire.requestFrom(address, (size_t)1);       // Read one byte from slave register address
  if (Wire.available()) data = Wire.read();  // Fill Rx buffer with result
  return data;                                 // Return data read from slave register
}

void read_bytes(uint8_t address, uint8_t subAddress, size_t nBytes){
  uint8_t data = 0;                         // `data` will store the register data
  Wire.beginTransmission(address);         // Initialize the Tx buffer
  Wire.write(subAddress);                  // Put slave register address in Tx buffer
  error = Wire.endTransmission(false);  // Send the Tx buffer, but send a restart to keep connection alive
  if (error){
    Serial.println("Failed");
    Serial.println(error);
  }
  Wire.requestFrom(address, nBytes);       // Read one byte from slave register address
}


void i2cScan(){
  byte error, address;
  int nDevices = 0;

  for(address = 1; address < 127; address++ ) {
    // The i2c_scanner uses the return value of
    // the Write.endTransmisstion to see if
    // a device did acknowledge to the address.
    Wire.beginTransmission(address);
    error = Wire.endTransmission();

    if (error == 0) {
      Serial.print("I2C device found at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.print(address,HEX);
      Serial.println("  !");

      nDevices++;
    }
    else if (error==4) {
      Serial.print("Unknown error at address 0x");
      if (address<16) 
        Serial.print("0");
      Serial.println(address,HEX);
    }    
  }
  if (nDevices == 0)
    Serial.println("No I2C devices found\n");
  else
    Serial.println("done\n");
}

void mpuInit(){
  //reset the mpu
  write_byte(MPU, 0x6B, 0x80);
  delay(100);

  write_byte(MPU, 0x6B, 0x00);
  delay(100);

  write_byte(MPU, 0x6B, 0x01);
  delay(200);

  //enable the bypass multiplexer
  write_byte(MPU, 0x37, 0x02);
  delay(100);
}


void readAcc(){
  int16_t tempax, tempay, tempaz;
  //first read accelerometer data
  read_bytes(MPU, 0x3B, 6);

  //accelerometer raw data
  tempax = ( (Wire.read() << 8) | Wire.read() ); 
  tempay = ( (Wire.read() << 8) | Wire.read() ); 
  tempaz = ( (Wire.read() << 8) | Wire.read() ); 

  ax = tempax / ACC_FACTOR;
  ay = tempay / ACC_FACTOR;
  az = tempaz / ACC_FACTOR;

  ax -= accErrorX;
  ay -= accErrorY;
  az -= accErrorZ;
}


void readGyro(){
  int16_t tempgx, tempgy, tempgz;
  
  //second read gyro
  read_bytes(MPU, 0x43, 6);

  //gyro raw data
  tempgx = ( (Wire.read() << 8) | Wire.read() ); 
  tempgy = ( (Wire.read() << 8) | Wire.read() );
  tempgz = ( (Wire.read() << 8) | Wire.read() );

  gx =  tempgx / GYRO_FACTOR;
  gy =  tempgy / GYRO_FACTOR;
  gz =  tempgz / GYRO_FACTOR;


  gx -= gyroErrorx;
  gy -= gyroErrorY;
  gz -= gyroErrorZ;
}

void readMagneto(){
  int16_t tempmx, tempmy, tempmz;
  uint8_t st1, st2;
  

  st1 = read_byte(MAG, 0x02);
  if(!(st1 & 1)){
    Serial.print("Data not ready, st1 = ");
    Serial.println(st1);
  }
  //read magnetometer measurements
  Wire.beginTransmission(MAG);
  Wire.write(0x03);
  Wire.endTransmission(false);
  Wire.requestFrom(MAG, 6, true);

  //myro raw data
  tempmx = ( Wire.read() | (Wire.read() << 8) ); 
  tempmy = ( Wire.read() | (Wire.read() << 8) );
  tempmz = ( Wire.read() | (Wire.read() << 8) );
  st2 = read_byte(MAG, 0x09);
  Serial.println(st2);

  mx =  tempmx / MAGNETO_FACTOR;
  my =  tempmy / MAGNETO_FACTOR;
  mz =  tempmz / MAGNETO_FACTOR;

  mx -= magnetoErrorX;
  my -= magnetoErrorY;
  mz -= magnetoErrorZ;
}