Help migrating MPU-6050 Wire to i2c_t3

Status
Not open for further replies.

linuxgeek

Well-known member
I can see that the basic MPU-6050 example is working, but I'm trying to package it up to work more efficiently with i2c_t3. I see that there are other libraries out there that already do a lot of stuff, but they are all based on Wire, and I'm trying to keep the versatility of i2c_t3.

edit: I should add that the example is working with sensible values, but my example doesn't output sensible values.

I don't know if I'm not understanding the i2c stuff right, or if I'm doing something not right with the bitwise operators. The original example was doing 2 byte reads and doing a bitwise operation to concatenate into an int16_t.
I tried doing a single byte grab to try and replicate (which didn't work), but I'm also trying to do all 14 byte tx from the sensor and then do the bit-wise operations to store them into int16_t. Thanks for any help in identifying where I might be making a mistake.

This is the original example.

Code:
// MPU-6050 Short Example Sketch
// By Arduino User JohnChi
// August 17, 2014
// Public Domain
#include<Wire.h>
const int MPU_addr=0x68;  // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
void setup(){
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
  Serial.begin(9600);
}
void loop(){
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)    
  AcY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  Serial.print("AcX = "); Serial.print(AcX);
  Serial.print(" | AcY = "); Serial.print(AcY);
  Serial.print(" | AcZ = "); Serial.print(AcZ);
  Serial.print(" | Tmp = "); Serial.print(Tmp/340.00+36.53);  //equation for temperature in degrees C from datasheet
  Serial.print(" | GyX = "); Serial.print(GyX);
  Serial.print(" | GyY = "); Serial.print(GyY);
  Serial.print(" | GyZ = "); Serial.println(GyZ);
  delay(333);
}

Here's my attempt so far:

Code:
#include <i2c_t3.h>

#define MPU6050         2

//int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;

struct i2cConfig {
  uint32_t clock;     // I2C clock frequency
  uint8_t port;       // I2C bus number
  i2c_pins pins;      // I2C pins
  i2c_pullup pullups; // I2C pullups
  uint8_t address;    // I2C address
};

struct mpu6050Config {
  char signalName[8];
  int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;
  uint8_t sampleDivisor = 1;
  uint8_t sensorType = MPU6050;
  uint8_t ID = 0x68;
  uint8_t numSensor=1;
  i2cConfig i2c;
};

mpu6050Config mpu6050Cfg;

void setup(){
  mpu6050Cfg.i2c.address=0x68;
  mpu6050Cfg.numSensor=1;
  i2c_t3(mpu6050Cfg.i2c.port).begin(I2C_MASTER, 0x00, I2C_PINS_18_19, I2C_PULLUP_EXT, I2C_RATE_100); //t3.2
  mpu6050Init(&mpu6050Cfg);

/* Successfully migrated to mpu6050Init() I think
  Wire.begin();
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x6B);  // PWR_MGMT_1 register
  Wire.write(0);     // set to zero (wakes up the MPU-6050)
  Wire.endTransmission(true);
*/
  Serial.begin(9600);
}

void loop() {
  //sampleMPU6050Single(mpu6050Cfg.i2c.port, mpu6050Cfg.i2c.address);
  sampleMPU6050(mpu6050Cfg.i2c.port, mpu6050Cfg.i2c.address);

/*
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  AcX=Wire.read()<<8|Wire.read();  // 0x3B (ACCEL_XOUT_H) & 0x3C (ACCEL_XOUT_L)    
  AcY=Wire.read()<<8|Wire.read();  // 0x3D (ACCEL_YOUT_H) & 0x3E (ACCEL_YOUT_L)
  AcZ=Wire.read()<<8|Wire.read();  // 0x3F (ACCEL_ZOUT_H) & 0x40 (ACCEL_ZOUT_L)
  Tmp=Wire.read()<<8|Wire.read();  // 0x41 (TEMP_OUT_H) & 0x42 (TEMP_OUT_L)
  GyX=Wire.read()<<8|Wire.read();  // 0x43 (GYRO_XOUT_H) & 0x44 (GYRO_XOUT_L)
  GyY=Wire.read()<<8|Wire.read();  // 0x45 (GYRO_YOUT_H) & 0x46 (GYRO_YOUT_L)
  GyZ=Wire.read()<<8|Wire.read();  // 0x47 (GYRO_ZOUT_H) & 0x48 (GYRO_ZOUT_L)
  Serial.print("AcX = "); Serial.print(AcX);
  Serial.print(" | AcY = "); Serial.print(AcY);
  Serial.print(" | AcZ = "); Serial.print(AcZ);
  Serial.print(" | Tmp = "); Serial.print(Tmp/340.00+36.53);  //equation for temperature in degrees C from datasheet
  Serial.print(" | GyX = "); Serial.print(GyX);
  Serial.print(" | GyY = "); Serial.print(GyY);
  Serial.print(" | GyZ = "); Serial.println(GyZ);
*/  
  delay(1000);
}

void sampleMPU6050Single(uint8_t i2cPort, uint8_t i2cAddress) {
  int nVal = 7;
  int16_t vals[nVal];
  int16_t tmp;
  
  for (int i=0;i<nVal;i++) {
    tmp = readByteWire(i2cPort, i2cAddress, 0x3B) << 8 | readByteWire(i2cPort, i2cAddress, 0x3B);
    vals[nVal] = tmp;
    Serial.print("single val");
    Serial.print(i);
    Serial.print(": ");
    Serial.println(vals[i]);    
  }
}

void sampleMPU6050(uint8_t i2cPort, uint8_t i2cAddress) {
  int nVal = 7;
  uint8_t bytes[nVal*2];
  int16_t vals[nVal];

  readBytesWire(i2cPort, i2cAddress, 0X3B, (nVal*2), &bytes[0]);
  
  for (int i = 0; i < nVal; i += 2) {
//    vals[i/2] = bytes[i] + (bytes[i+1] << 8);
    vals[i/2] = bytes[i] | (int16_t)bytes[i+1] << 8;
  }

    Serial.print("mpu6050 vals: ");
  for (int i=0;i<nVal;i++) {
    Serial.print(i);
    Serial.print("=");
    Serial.print(vals[i]);
    Serial.print(" | ");
  }
  Serial.println();
}

void mpu6050Init(struct mpu6050Config *cfg) {
      writeByteWire(cfg->i2c.port, cfg->i2c.address, 0x6B, 0);
}

/**
* write data to sensor
*/
void writeByteWire(uint8_t port, uint8_t address, uint8_t subAddress, uint8_t data) {
  i2c_t3(port).beginTransmission(address);  // Initialize the Tx buffer
  i2c_t3(port).write(subAddress);           // Put slave register address in Tx buffer
  i2c_t3(port).write(data);                 // Put data in Tx buffer
  i2c_t3(port).endTransmission();           // Send the Tx buffer
}

/**
* read a byte of data from sensor
*/
uint8_t readByteWire(uint8_t port, uint8_t address, uint8_t subAddress) {
  uint8_t data; // `data` will store the register data   
  i2c_t3(port).beginTransmission(address);         // Initialize the Tx buffer
  i2c_t3(port).write(subAddress);                  // Put slave register address in Tx buffer
  i2c_t3(port).endTransmission(I2C_NOSTOP);        // Send the Tx buffer, but send a restart to keep connection alive
//  Wire.endTransmission(false);             // Send the Tx buffer, but send a restart to keep connection alive
//  Wire.requestFrom(address, 1);  // Read one byte from slave register address 
  i2c_t3(port).requestFrom(address, (size_t) 1);   // Read one byte from slave register address 
  data = i2c_t3(port).read();                      // Fill Rx buffer with result
  return data;                                     // Return data read from slave register
}

/*
* read a chunk of data from sensor
*/
void readBytesWire(uint8_t i2cPort, uint8_t address, uint8_t subAddress, uint8_t count, uint8_t * dest) {  
  i2c_t3(i2cPort).beginTransmission(address);   // Initialize the Tx buffer
  i2c_t3(i2cPort).write(subAddress);            // Put slave register address in Tx buffer
  i2c_t3(i2cPort).endTransmission(I2C_NOSTOP);  // Send the Tx buffer, but send a restart to keep connection alive
//  Wire.endTransmission(false);       // Send the Tx buffer, but send a restart to keep connection alive
  uint8_t i = 0;
//        Wire.requestFrom(address, count);  // Read bytes from slave register address 
        i2c_t3(i2cPort).requestFrom(address, (size_t) count);  // Read bytes from slave register address 
  while (i2c_t3(i2cPort).available()) {
        dest[i++] = i2c_t3(i2cPort).read(); }         // Put read results in the Rx buffer
}
 
Last edited:
Still don't have it working, but I think I somehow left the i2c port # undefined, and that's probably the problem that I was preventing me from figuring it out.
 
This looks like a coding error in posted attempt::
Code:
vals[nVal] = tmp;  // nVal should be 'i'

Not sure I see the value in the rewrite? AFAIK The initial code asks for a single long 14 byte transaction. The alternate code makes 14 single bytes requests? That is i2c extra overhead?

I'm not sure how the device operates but the 14 byte single transfer is likely a single sample time - when making repeated requests over time it is possible the dataset returned comes from different samples because of the time involved? That looks like interrupting the device 28 times? 14 times to specify address and 14 times to read a byte?

Just typing in the browser here but can this work?
Code:
  Wire.beginTransmission(MPU_addr);
  Wire.write(0x3B);  // starting with register 0x3B (ACCEL_XOUT_H)
  Wire.endTransmission(false);
  Wire.requestFrom(MPU_addr,14,true);  // request a total of 14 registers
  
  for (int i=0;i<nVal;i++) {
    tmp = Wire.read()<<8|Wire.read();
    vals[i] = tmp;
  }
  for (int i=0;i<nVal;i++) {
    Serial.print(i);
    Serial.print(": ");
    Serial.println(vals[i]);    
  }
 
Last edited:
Thanks, I have it working as expected now.

I think both methods are doing 14 separate calls, if I understand it correctly.

This is I think the same.

Code:
 i2c_t3(i2cPort).requestFrom(address, (size_t) count);  // Read bytes from slave register address 
  while (i2c_t3(i2cPort).available()) {
        dest[i++] = i2c_t3(i2cPort).read();
  }

I also tried to emulate the original more closely for testing.

I still have to learn if it's actually possible to get the 14 bytes in one call. But mostly I was rewriting it, so that I can easily configure different sensors to use different i2c ports and addresses.
 
Status
Not open for further replies.
Back
Top