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;
}