Application collecting data from two I2C breakout boards freezes

Hello,

Thanks for taking the time to lend a hand!

I’m trying to collect data from two different I2C boards on an Electron with up-to-date firmware. I have an MPU6050 on Wire (D0=SDA & D1=SCL), and an BMP085 on Wire1 (C4=SDA & C5=SCL). Independently, each works fine. However, when I combine the code for each it gets hung up in a while loop at line 147 that’s looking at whether Wire1/BMP085 is available or not.

Here:

int readIntRegister(unsigned char r)
{
  unsigned char msb, lsb;
  Wire1.beginTransmission(I2C_ADDRESS);
  Wire1.write(r);  
  Wire1.endTransmission();

  Wire1.requestFrom(I2C_ADDRESS, 2); 
  while(!Wire1.available()); // LINE 147 WHERE THE CODE HANGS
  msb = Wire1.read();
  while(!Wire1.available());
  lsb = Wire1.read();
  return (((int)msb<<8) | ((int)lsb));
}   

This code is called in setup(), after the code that sets up Wire/MPU6050 is executed. My I2C addresses are correct at 0x68 for the MPU6050, and 0x77 for the BMP085. No clue what’s going on here, so any hints would be greatly appreciated. The complete body of code is below.

const int MPU_addr=0x68;  // I2C address of the MPU-6050
int16_t AcX,AcY,AcZ,Tmp,GyX,GyY,GyZ;

// From the datasheet the BMP module address LSB distinguishes
// between read (1) and write (0) operations, corresponding to 
// address 0xEF (read) and 0xEE (write).
// shift the address 1 bit right (0xEF or 0xEE), the Wire library only needs the 7
// most significant bits for the address 0xEF >> 1 = 0x77
// 0xEE >> 1 = 0x77
int I2C_ADDRESS = 0x77;  // sensor address

// oversampling setting, 0 = ultra low power, 1 = standard, 2 = high, 3 = ultra high resolution
const unsigned char oversampling_setting = 3; //oversampling for measurement
const unsigned char pressure_conversiontime[4] = { 
  5, 8, 14, 26 };  // delays for oversampling settings 0, 1, 2 and 3   

// sensor registers from the BOSCH BMP085 datasheet
int ac1;
int ac2; 
int ac3; 
unsigned int ac4;
unsigned int ac5;
unsigned int ac6;
int b1; 
int b2;
int mb;
int mc;
int md;

// variables to keep the values
int temperature = 0;
long pressure = 0;

// read temperature and pressure from sensor
void readSensor() {
  int  ut= readUT();
  long up = readUP();
  long x1, x2, x3, b3, b5, b6, p;
  unsigned long b4, b7;

  //calculate true temperature
  x1 = ((long)ut - ac6) * ac5 >> 15;
  x2 = ((long) mc << 11) / (x1 + md);
  b5 = x1 + x2;
  temperature = (b5 + 8) >> 4;

  //calculate true pressure
  b6 = b5 - 4000;
  x1 = (b2 * (b6 * b6 >> 12)) >> 11; 
  x2 = ac2 * b6 >> 11;
  x3 = x1 + x2;
  b3 = (((int32_t) ac1 * 4 + x3)<<oversampling_setting + 2) >> 2;
  x1 = ac3 * b6 >> 13;
  x2 = (b1 * (b6 * b6 >> 12)) >> 16;
  x3 = ((x1 + x2) + 2) >> 2;
  b4 = (ac4 * (uint32_t) (x3 + 32768)) >> 15;
  b7 = ((uint32_t) up - b3) * (50000 >> oversampling_setting);
  p = b7 < 0x80000000 ? (b7 * 2) / b4 : (b7 / b4) * 2;

  x1 = (p >> 8) * (p >> 8);
  x1 = (x1 * 3038) >> 16;
  x2 = (-7357 * p) >> 16;
  pressure = p + ((x1 + x2 + 3791) >> 4);
}

// read uncompensated temperature value
unsigned int readUT() {
  writeRegister(0xf4,0x2e);
  delay(5); // the datasheet suggests 4.5 ms
  return readIntRegister(0xf6);
}

// read uncompensated pressure value
long readUP() {
  writeRegister(0xf4,0x34+(oversampling_setting<<6));
  delay(pressure_conversiontime[oversampling_setting]);

  unsigned char msb, lsb, xlsb;
  Wire1.beginTransmission(I2C_ADDRESS);
  Wire1.write(0xf6);  // register to read
  Wire1.endTransmission();

  Wire1.requestFrom(I2C_ADDRESS, 3); // request three bytes
  while(!Wire1.available()); // wait until data available
  msb = Wire1.read();
  while(!Wire1.available()); // wait until data available
  lsb |= Wire1.read();
  while(!Wire1.available()); // wait until data available
  xlsb |= Wire1.read();
  return (((long)msb<<16) | ((long)lsb<<8) | ((long)xlsb)) >>(8-oversampling_setting);
}

void  getCalibrationData() {
  Serial.println("Reading Calibration Data");
  ac1 = readIntRegister(0xAA);
  Serial.print("AC1: ");
  Serial.println(ac1,DEC);
  ac2 = readIntRegister(0xAC);
  Serial.print("AC2: ");
  Serial.println(ac2,DEC);
  ac3 = readIntRegister(0xAE);
  Serial.print("AC3: ");
  Serial.println(ac3,DEC);
  ac4 = readIntRegister(0xB0);
  Serial.print("AC4: ");
  Serial.println(ac4,DEC);
  ac5 = readIntRegister(0xB2);
  Serial.print("AC5: ");
  Serial.println(ac5,DEC);
  ac6 = readIntRegister(0xB4);
  Serial.print("AC6: ");
  Serial.println(ac6,DEC);
  b1 = readIntRegister(0xB6);
  Serial.print("B1: ");
  Serial.println(b1,DEC);
  b2 = readIntRegister(0xB8);
  Serial.print("B2: ");
  Serial.println(b1,DEC);
  mb = readIntRegister(0xBA);
  Serial.print("MB: ");
  Serial.println(mb,DEC);
  mc = readIntRegister(0xBC);
  Serial.print("MC: ");
  Serial.println(mc,DEC);
  md = readIntRegister(0xBE);
  Serial.print("MD: ");
  Serial.println(md,DEC);
}

void writeRegister(unsigned char r, unsigned char v)
{
  Wire1.beginTransmission(I2C_ADDRESS);
  Wire1.write(r);
  Wire1.write(v);
  Wire1.endTransmission();
}

// read a 16 bit register
int readIntRegister(unsigned char r)
{
  unsigned char msb, lsb;
  Wire1.beginTransmission(I2C_ADDRESS);
  Wire1.write(r);  // register to read
  Wire1.endTransmission();

  Wire1.requestFrom(I2C_ADDRESS, 2); // request two bytes
  while(!Wire1.available()); // wait until data available
  msb = Wire1.read();
  while(!Wire1.available()); // wait until data available
  lsb = Wire1.read();
  return (((int)msb<<8) | ((int)lsb));
}


void setup()
{  
  Serial.begin(9600);  
  
  Wire.setSpeed(100000);
  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

  Wire1.setSpeed(100000);
  Wire1.begin();
  getCalibrationData();
}

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);
    
  readSensor();
  Serial.print("Temperature: ");
  Serial.print(temperature,DEC);
  Serial.print(" Pressure: ");
  Serial.println(pressure,DEC);

  delay(333);
}

Shouldn’t the while be while (Wirex.Avaliable) - you seem to have !Wirex.available)

Early on Sunday morning and brain only operating at 10% so I could be totally wrong!

Stan

I guess this line should wait while there is no data available and only procede when data has arrived (as the comment states).

But in case of blocking I2C you might want to do while(!Wire.available()) Particle.process(); to stay connected.

Does an added delay(2); before line 142 change anything?

Hi Stan,

As ScruffR mentions below, the while(!Wire1.available()) is meant to pause the application until the BMP085 is ready, but for some reason it’s getting hung up there. In other words, when code for both BOB’s is running, the BMP085 never becomes available.

@ScruffR, I’ll try both of your suggestions and reply to your comment with the results.

Hi ScruffR,

Yup, the while statement is meant to do as you said. For reasons yet unknown though, Wire1/BMP085 never becomes available.

Unfortunately delay(2) and Particle.process() had no effect on the results.

How if you swap the boards between the two I2C interfaces or even attach both to the same?

Swapping the boards is something I tried early on and it didn’t change anything for me. I’ve currently got them both on the same interface (D0 & D1), which actually got me past the while loop in readIntRegister() only to get stuck on the same issue in readUP() when it’s called in loop(){} from readSensor().

EDIT: Never mind! I totally missed removing the “1” from a Wire1.requestFrom() call in readUP(). Putting both boards on the same interface was the fix here.

That being said, it seems to me that there’s a firmware bug when it comes to using Wire with Wire1…unless that is not the purpose of differentiating between the two.

Thanks for the help!

Darn, you got it to work! I was having the exact same problem with a Digole display unit. I could write to it just fine via I2C but when I tried to read, the exact same while(!Wire.available()) would hang. I was never able to get to the root of the problem and the best I could get on my logic analyzer was the returned bytes from the diplay were NAK’ed by the system firmware. I am going to repeat my tests with the latest 0.6 release to see if I have any luck.

Realise that is the intent now - needed more coffee before original reply!

Regardless, as @ScruffR mentioned, a particle.process in the while loop would be a good thing!

Stan

I can sympathize. :wink:

And I’ve dropped Particle.process(); in there for good measure. Thanks!