Skip to content

I2C Issues with MPU9250 Breakout Boards. #937

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
mjs513 opened this issue Dec 21, 2017 · 4 comments
Closed

I2C Issues with MPU9250 Breakout Boards. #937

mjs513 opened this issue Dec 21, 2017 · 4 comments

Comments

@mjs513
Copy link

mjs513 commented Dec 21, 2017

Hardware:

Board: ?Onehorse ESP32 Dev Board?
Core Installation/update date: ?12/18/14?
IDE name: ?Arduino IDE 1.8.5?
Flash Frequency: ?80Mhz?
Upload Speed: ?921600?

Description:

I2C reads of MPU9250 are failing. Issue was identified when running a full up sketch for the 9250 and was failing on reading the whoiam register. Even if this is removed it is failing to successfully read any data. It was however identifying the correct addresses when doing a i2scan. This was tested on two different MPU9250 breakout boards. A test sketch was then implemented to do a i2c bus scan and read the who am I register for the correct value.

For the MS5637 pressure sensor, BME280 pressure sensor and the BNO055 it worked no issue. However it failed for the MPU9250.

I installed a early version of the ESP32 Core from about 02/20/17 and it successfully ran the test sketch, i.e., it read the MPU9250 fine - no issues. The 9250 should not be a special case for the ESP32 as it is not for any other boards that I have tested it on - uno, mega, due, teensy 3.2 and 3.5. Especially since it was working before. The new implementation of I2C seems to have broken something.

Sketch:

#include "Wire.h"   

#define MPU9250_ADDRESS 0x68  // Device address when ADO = 0
#define WHO_AM_I_MPU9250 0x75 // Should return 0x71

#define BNO055_ADDRESS 0x28   //  Device address of BNO055 when ADO = 0
#define BNO055_CHIP_ID          0x00    // should be 0xA0              
#define BNO055_ACC_ID           0x01    // should be 0xFB              
#define BNO055_MAG_ID           0x02    // should be 0x32              
#define BNO055_GYRO_ID          0x03    // should be 0x0F

void setup() 
{
  Serial.begin(115200);
  delay(4000);

  Wire.begin(21,22,400000); //(SDA, SCL) (21,22) are default on ESP32, 400 kHz I2C clock
  delay(1000);

  // Set up the interrupt pin, its set as active high, push-pull
  pinMode(5, OUTPUT);
  digitalWrite(5, LOW);

  I2Cscan();// look for I2C devices on the bus
  delay(1000);

  // Read the WHO_AM_I register, this is a good test of communication
  Serial.println("MPU9250 9-axis motion sensor...");
  uint8_t c = readByte(MPU9250_ADDRESS, WHO_AM_I_MPU9250);  // Read WHO_AM_I register for MPU-9250
  Serial.print("MPU9250 "); Serial.print("I AM "); Serial.print(c, HEX); Serial.print(" I should be "); Serial.println(0x71, HEX);
  // Read the WHO_AM_I register of the magnetometer, this is a good test of communication
/*
  // Read the WHO_AM_I register, this is a good test of communication
  Serial.println("BNO055 9-axis motion sensor...");
  byte c = readByte(BNO055_ADDRESS, BNO055_CHIP_ID);  // Read WHO_AM_I register for BNO055
  Serial.print("BNO055 Address = 0x"); Serial.println(BNO055_ADDRESS, HEX);
  Serial.print("BNO055 WHO_AM_I = 0x"); Serial.println(BNO055_CHIP_ID, HEX);
  Serial.print("BNO055 "); Serial.print("I AM "); Serial.print(c, HEX); Serial.println(" I should be 0xA0");
  delay(1000);
  // Read the WHO_AM_I register of the accelerometer, this is a good test of communication
  byte d = readByte(BNO055_ADDRESS, BNO055_ACC_ID);  // Read WHO_AM_I register for accelerometer
  Serial.print("BNO055 ACC "); Serial.print("I AM "); Serial.print(d, HEX); Serial.println(" I should be 0xFB"); 
  delay(1000);
  // Read the WHO_AM_I register of the magnetometer, this is a good test of communication
  byte e = readByte(BNO055_ADDRESS, BNO055_MAG_ID);  // Read WHO_AM_I register for magnetometer
  Serial.print("BNO055 MAG "); Serial.print("I AM "); Serial.print(e, HEX); Serial.println(" I should be 0x32");
  delay(1000);
  // Read the WHO_AM_I register of the gyroscope, this is a good test of communication
  byte f = readByte(BNO055_ADDRESS, BNO055_GYRO_ID);  // Read WHO_AM_I register for LIS3MDL
  Serial.print("BNO055 GYRO "); Serial.print("I AM "); Serial.print(f, HEX); Serial.println(" I should be 0x0F");
*/
}

void loop() {
  // put your main code here, to run repeatedly:

}

// simple function to scan for I2C devices on the bus
void I2Cscan() 
{
    // scan for i2c devices
  byte error, address;
  int nDevices;

  Serial.println("Scanning...");

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

  uint8_t readByte(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
  Wire.endTransmission(false);             // Send the Tx buffer, but send a restart to keep connection alive
  Wire.requestFrom(address, 1);  // Read two bytes from slave register address on MPU9250 
  data = Wire.read();                      // Fill Rx buffer with result
  return data;                             // Return data read from slave register
}

Debug Messages:

MPU9250 9-axis motion sensor...
[W][esp32-hal-i2c.c:235] i2cWrite(): Ack Error! Addr: 68
[W][esp32-hal-i2c.c:334] i2cRead(): Ack Error! Addr: 68, index 0
MPU9250 I AM FF I should be 71
@mjs513
Copy link
Author

mjs513 commented Dec 22, 2017

I started to do some debugging to determine where and when the issue with failing to correctly read the mpu9250 occurred. The approach I took was to download the latest git (12/22 0400hrs) and replace the esp32-hal-i2c.h, esp32-hal-i2c.cpp, wire.h and wire.cpp with the versions I had from about march 2017 (it already had the i2c stability fix in by @me-no-dev). After incorporating the dport i2c changes it compiled and recognized the 9250 no problem.

When I incorporated Add initial handling for long I2C reads dated 10/21 it failed to recognize the 9250 whoiam register. It did still recognize that there was a valid device on the bus.

Maybe this will help in identifying where the issue lies.

@mjs513
Copy link
Author

mjs513 commented Dec 25, 2017

Ok. Did some more debugging over the last couple of days as time permitted and finally just figured out that it is the same issue that resolved by @me-no-dev in issue 90.. Once I put the two byte solution in place it worked. Here is the code snippet that I used instead of what was originally posted:

  uint8_t readByte(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
  Wire.endTransmission(false);             // Send the Tx buffer, but send a restart to keep connection alive
  Wire.requestFrom(address, (uint8_t) 2);  // Read two bytes from slave register address on MPU9250 
  data = Wire.read();
  Wire.read();                             // Fill Rx buffer with result
  return data;                             // Return data read from slave register
}

What changed in i2c long read functions that would have caused I can not tell you. But this is now special case for the MPU9250. Again, not an issue with any other board that I have tried. Think that's about all I can do.

@mjs513
Copy link
Author

mjs513 commented Dec 25, 2017

I just tried stickbreakers fork with changes to i2c/wire files and it worked without the 2 byte read trick. The only issue seems to be speed. I did a test of a 7state Kalman filter with the MPU9250 and did a timing test with the old working version of i2c and the updates occurred every 836us. With stickbreakers changes it is about 915us. This compares to a Teensy 35 (120Mhz) which performs the update at 736us.

Once stickbreakers i2c changes occur I guess this issue can be closed - once it is tested of course.

Thanks
Mike

@copercini
Copy link
Contributor

The I2C core was changed to @stickbreaker code officially after 13dcfe5 (thanks @stickbreaker), Let's close issues with old code and if have problems with the new code, open new issues =)

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants