Hey all,
I'm banging my head against the wall with this one. I'm using a GY-521 breakout board for the MPU6050 to communicate 3 axis gyroscope values to a Mega 2560 along 1 meter of CAT6E cable with the I2C protocol. The SDA and SCL lines are each twisted with ground to reduce coupling between the two. The I2C bus is isolated (and level shifted to 3.3V) between the Mega and the sensor by a Texas Instruments TCA9517 bus buffer on a PCB I spun up for this purpose.
My issue is that when I set up the MPU6050 on a breadboard with an Adafruit bidirectional logic level converter, I can read sensor values just fine. When I go through the CAT6E and my PCB, the sensor does not communicate and I end up reading all zeros. The Mega is being supplied with 5V, the GY-521 is being supplied with 3.3V (the onboard LDO regulator will produce 3.3V from as low as ~2.1V input), and the TCA9517 utilizes both voltages. I2C level on the Arduino side is 5V and logic level on the sensor side is 3.3V. The sketch I am using is Jeff Rowberg's MPU6050_raw example, attached at the end of this post.
My first thought was an improper pinout between the Mega, my PCB, and the MPU6050, but I rung everything out with a multimeter and all is well. The CAT6 wiring from the MPU6050 matches that of other sensors I have gotten to work with this setup (DS3231, SSD1307, MCP9808, MAX30102), and my power supplies are stable. My second thought was improperly sized pullup resistors on the I2C bus, since any length of cabling is going to increase bus capacitance. I replaced the pullup resistors on both the 5V high side and 3.3V low side with values to set the sink current between 2 and 3 mA. This is within datasheet limits for all of the devices, under the I2C spec limit of 3 mA, and much stronger than the <1mA current the original values offered. Still no results from the sensor.
I got the I2C bus on a scope, and I'm pretty confused by what I'm seeing. My rising edges look good, so whether or not the pullup values were a problem before, they aren't now. The clock line looks great with or without the MPU6050 present on the bus. The data line looks great ("SDA_Open.jpg") without the MPU6050 on the bus. However, when the sensor is added to the bus ("SDA1.jpg" and "SDA2.jpg"), it seems to me that the sensor is attempting to communicate but is holding the line at .3V rather than releasing it to 3.3V. I replaced the TCA9517 thinking I may have damaged it, and tried a second MPU6050 with the same results. Other sensors that I have wired in this manner communicate without issue on this same bus. If anybody has suggestions, I would very much appreciate them. I've attached the part of the PCB schematic that relates to this comms line, a schematic for the GY-521, and some cellphone captures (sorry, didn't have a flash drive on me). Has anybody seen this before?
Jeff Rowberg's code:
// I2C device class (I2Cdev) demonstration Arduino sketch for MPU6050 class
// 10/7/2011 by Jeff Rowberg <jeff@rowberg.net>
// Updates should (hopefully) always be available at https://github.com/jrowberg/i2cdevlib
//
// Changelog:
// 2013-05-08 - added multiple output formats
// - added seamless Fastwire support
// 2011-10-07 - initial release
/* ============================================
I2Cdev device library code is placed under the MIT license
Copyright (c) 2011 Jeff Rowberg
===============================================
*/
// I2Cdev and MPU6050 must be installed as libraries, or else the .cpp/.h files
// for both classes must be in the include path of your project
#include "I2Cdev.h"
#include "MPU6050.h"
// Arduino Wire library is required if I2Cdev I2CDEV_ARDUINO_WIRE implementation
// is used in I2Cdev.h
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
#include "Wire.h"
#endif
MPU6050 accelgyro;
//MPU6050 accelgyro(0x69); // <-- use for AD0 high
int16_t ax, ay, az;
int16_t gx, gy, gz;
#define LED_PIN 13
bool blinkState = false;
void setup() {
// join I2C bus (I2Cdev library doesn't do this automatically)
#if I2CDEV_IMPLEMENTATION == I2CDEV_ARDUINO_WIRE
Wire.begin();
#elif I2CDEV_IMPLEMENTATION == I2CDEV_BUILTIN_FASTWIRE
Fastwire::setup(400, true);
#endif
Serial.begin(38400);
// initialize device
Serial.println("Initializing I2C devices...");
accelgyro.initialize();
// verify connection
Serial.println("Testing device connections...");
Serial.println(accelgyro.testConnection() ? "MPU6050 connection successful" : "MPU6050 connection failed");
// use the code below to change accel/gyro offset values
/*
Serial.println("Updating internal sensor offsets...");
// -76 -2359 1688 0 0 0
Serial.print(accelgyro.getXAccelOffset()); Serial.print("\t"); // -76
Serial.print(accelgyro.getYAccelOffset()); Serial.print("\t"); // -2359
Serial.print(accelgyro.getZAccelOffset()); Serial.print("\t"); // 1688
Serial.print(accelgyro.getXGyroOffset()); Serial.print("\t"); // 0
Serial.print(accelgyro.getYGyroOffset()); Serial.print("\t"); // 0
Serial.print(accelgyro.getZGyroOffset()); Serial.print("\t"); // 0
Serial.print("\n");
accelgyro.setXGyroOffset(220);
accelgyro.setYGyroOffset(76);
accelgyro.setZGyroOffset(-85);
Serial.print(accelgyro.getXAccelOffset()); Serial.print("\t"); // -76
Serial.print(accelgyro.getYAccelOffset()); Serial.print("\t"); // -2359
Serial.print(accelgyro.getZAccelOffset()); Serial.print("\t"); // 1688
Serial.print(accelgyro.getXGyroOffset()); Serial.print("\t"); // 0
Serial.print(accelgyro.getYGyroOffset()); Serial.print("\t"); // 0
Serial.print(accelgyro.getZGyroOffset()); Serial.print("\t"); // 0
Serial.print("\n");
*/
// configure Arduino LED pin for output
pinMode(LED_PIN, OUTPUT);
}
void loop() {
// read raw accel/gyro measurements from device
accelgyro.getMotion6(&ax, &ay, &az, &gx, &gy, &gz);
// these methods (and a few others) are also available
//accelgyro.getAcceleration(&ax, &ay, &az);
//accelgyro.getRotation(&gx, &gy, &gz);
#ifdef OUTPUT_READABLE_ACCELGYRO
// display tab-separated accel/gyro x/y/z values
Serial.print("a/g:\t");
Serial.print(ax); Serial.print("\t");
Serial.print(ay); Serial.print("\t");
Serial.print(az); Serial.print("\t");
Serial.print(gx); Serial.print("\t");
Serial.print(gy); Serial.print("\t");
Serial.println(gz);
#endif
#ifdef OUTPUT_BINARY_ACCELGYRO
Serial.write((uint8_t)(ax >> 8)); Serial.write((uint8_t)(ax & 0xFF));
Serial.write((uint8_t)(ay >> 8)); Serial.write((uint8_t)(ay & 0xFF));
Serial.write((uint8_t)(az >> 8)); Serial.write((uint8_t)(az & 0xFF));
Serial.write((uint8_t)(gx >> 8)); Serial.write((uint8_t)(gx & 0xFF));
Serial.write((uint8_t)(gy >> 8)); Serial.write((uint8_t)(gy & 0xFF));
Serial.write((uint8_t)(gz >> 8)); Serial.write((uint8_t)(gz & 0xFF));
#endif
// blink LED to indicate activity
blinkState = !blinkState;
digitalWrite(LED_PIN, blinkState);
}
MPU6050_Comms.zip (1.58 MB)