Reading Pressure sensor data from BMP390 sensor over I2C

I have created a library and facing an issue with measuring the right pressure values from Bosch's BMP390 sensor over I2C.

I can measure accurate temperature values but not pressure. Here is the code snippet for the sensor. The function measurePress() measures the pressure value. The values are very high during the reading.

I could not find what the issue is.

double BMP390::measurePress()
{
  double pressure;
  
  struct coffvals vals;
  struct pars par;
  double t_lin;

  t_lin = measureTemp();

  double partial_data1, partial_data2, partial_data3, partial_data4, partial_out1, partial_out2;
  
  byte coffs[16];

  readi2cbytes(NVM_PAR_P1, 16, coffs);

  vals.p1 = ((coffs[1]<<8) | coffs[0]);
  vals.p2 = ((coffs[3]<<8) | coffs[2]);
  vals.p3 =  coffs[4];
  
  vals.p4 = coffs[5];
  vals.p5 = ((coffs[7]<<8) | coffs[6]);
  vals.p6 = ((coffs[9]<<8) | coffs[8]);
  
  vals.p7 = coffs[10];
  vals.p8 = coffs[11];
  vals.p9 = ((coffs[13]<<8) | coffs[12]);
  vals.p10 = coffs[14];
  vals.p11 = coffs[15];

  par.par_p1 = (double)(vals.p1/128.0);
  par.par_p2 = (double)(vals.p2/32768.0);
  par.par_p3 = (double)(vals.p3/4294967296.0);
  par.par_p4 = (double)(vals.p4/137438953472.0);
  par.par_p5 = (double)(vals.p5 * 8.0);
  par.par_p6 = (double)(vals.p6/64.0);
  par.par_p7 = (double)(vals.p7/256.0);
  par.par_p8 = (double)(vals.p8/32768.0);
  par.par_p9 = (double)(vals.p9/281474976700000.0);
  par.par_p10 = (double)(vals.p10/281474976700000.0);
  par.par_p11 = (double)(vals.p11/36893488150000000000.0);

  partial_data1 = (double)(par.par_p6 * t_lin);
  partial_data2 = (double)(par.par_p7 * t_lin * t_lin);
  partial_data3 = (double)(par.par_p8 * t_lin * t_lin * t_lin);

  partial_out1 = (double)(par.par_p5 + partial_data1 + partial_data2 + partial_data3);
  
  partial_data1 = (double)(par.par_p2 * t_lin);
  partial_data2 = (double)(par.par_p3 * t_lin * t_lin);
  partial_data3 = (double)(par.par_p4 * t_lin * t_lin * t_lin);

  uint32_t upres;
  byte ttvals[5];
  readi2cbytes(DATA_0, 6, ttvals);

  upres = (ttvals[2]<<16 | ttvals[1]<<8 | ttvals[0]);

  partial_out2 = (double)upres * (par.par_p1 + partial_data1 + partial_data2 + partial_data3);

  partial_data1 = (double)upres * (double)upres;
  partial_data2 = (double)(par.par_p9 + (par.par_p10 * t_lin));
  
  partial_data3 = (double)(partial_data1 * partial_data2);
  partial_data4 = (double)(partial_data3 + ((double) (upres) * (double)(upres)*(double)(upres))*par.par_p11);

  pressure = partial_out1 + partial_out2 + partial_data4;

  return pressure;
}
struct coffvals
{
  uint16_t t1;
  uint16_t t2;
  int8_t   t3;
  
  int16_t p1;
  int16_t p2;
  int8_t   p3;
  
  int8_t   p4;
  uint16_t p5;
  uint16_t p6;
  
  int8_t   p7;
  int8_t   p8;
  int16_t  p9;
  int8_t   p10;
  int8_t   p11;  
};

struct pars
{ 
  double par_t1;
  double par_t2;
  double par_t3;

  double par_p1;
  double par_p2;
  double par_p3;
  double par_p4;
  double par_p5;
  double par_p6;
  double par_p7;
  double par_p8;
  double par_p9;
  double par_p10;
  double par_p11;
 
};

bst-bmp390-ds002.pdf (1.8 MB)

You may compare your Library structure with the attached file.
Adafruit_BMP3XX-master.zip (63.9 KB)

Hi, So far everything seems correct. I have seen a couple of libraries online that do this the same way as I do. Hence, I am wondering.

There is an error in the above code. I found it.
As per the datasheet.

par.par_p1 = (double)(vals.p1/128.0);
par.par_p2 = (double)(vals.p2/32768.0);

Should be

par.par_p1 = (double)((vals.p1 - 16384.0) / 1048576.0);
par.par_p2 = (double)((vals.p2 - 16384.0)/ 536870912.0);

Thanks for support.

3 Likes

Where is this function "readi2cbytes()" ?

When I search online for functions with that name, they are all bad.

Hi, That's I have created, you wont find it online. It is just to read bytes on i2c bus.

void BMP390::readi2cbytes(uint8_t reg, int count, uint8_t temp[]) 
{
  Wire.beginTransmission(BMP_ADDRESS);
  Wire.write(reg);
  Wire.endTransmission();
  Wire.requestFrom(BMP_ADDRESS, count);

  for(int i=0; i<count; i++){
    temp[i] = Wire.read();    
    }
}

It's good :smiley:

1 Like

Why not like below to read actual number of data bytes that have arrived from Slave?

byte m = Wire.requestFrom(BMP_ADDRESS, count);
for(int i=0; i<m; i++)
{
    temp[i] = Wire.read();    
}

Both are same though. In your suggestion. It would use one more variable byte m. In mine it won't.!!

If the I2C bus is bad and the Wire.requestFrom() returns zero, then the buffer is not filled with rubbish data. Using the return value of Wire.requestFrom() is therefor better.

How it can be? Say, you have requested for 30 bytes. The comm line is broken after the arrival of 25 bytes. Your timeout mechanism has saved your system from being locked in an infinite loop. In this case m and count are not the same.

Right, good suggestion. In my case though, I will know that the data is rubbish means i2c is bad. instead, I would not know that fast that old data is coming. :grin:
But a good suggestion, when I have a use case, where I expect some value, and I know what approximately it should be. I will use that.
There are many things though I can work on to improve the code.

Right now, while measuring pressure and temperature, if all of a sudden some garbage come's in, I know that i2c is bad...

If you really want to help and improve my code. you are welcome to review my library for sensor MPU6050. I would love to hear back.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.