Troubleshooting Odd Readings with MS5611 Sensor via I2C Protocol

Hello everyone,

I hope this message finds you well.

Over the last couple of days, I've been working on writing code to make use of the MS5611 sensor via the I2C protocol. However, I've been encountering some odd readings for the pressure. As for the temperature, it seems alright, although I've noticed that the value decreases rapidly when I touch the sensor.

Here's the code I've written so far:

#include "Particle.h"
#include "Wire.h"

#define MS5611_ADDR 0x77 // I2C address of the MS5611

// MS5611 commands
#define MS5611_CMD_RESET        0x1E
#define MS5611_CMD_CONV_D1_256  0x40
#define MS5611_CMD_CONV_D2_256  0x50
#define MS5611_CMD_ADC_READ     0x00

// Calibration coefficients
uint16_t C1, C2, C3, C4, C5, C6;

void setup() {
    Wire.begin();
    Serial.begin(9600);
    delay(1000); // Wait for sensor to power up
    
    resetSensor();
    if (!readCalibrationCoefficients()) {
        Serial.println("Failed to read calibration coefficients! Check connections.");
        while (true); // Hang here if calibration fails
    }
}

void loop() {
    float pressure, temperature;
    if (readPressureAndTemperature(pressure, temperature)) {
        Particle.publish("Pressure: ", String(pressure));
        Particle.publish("Temperature: ", String(temperature));
        Serial.print("Pressure: ");
        Serial.print(pressure, 2);
         Serial.println(" mbar");
         Serial.print("temp: ");
        Serial.print(temperature, 2);
         Serial.println(" C");
    } else {
        Serial.println("Failed to read pressure and temperature! Retrying...");
        delay(1000); // delay before retrying
    }
    
    delay(1000); // delay between readings
}

void resetSensor() {
    Wire.beginTransmission(MS5611_ADDR);
    Wire.write(MS5611_CMD_RESET);
    Wire.endTransmission();
    delay(3); // reset takes 2.8ms
}

bool readCalibrationCoefficients() {
    // Read C1 coefficient
    Wire.beginTransmission(MS5611_ADDR);
    Wire.write(0xA2); // address of first coefficient
    Wire.endTransmission();
    
    Wire.requestFrom(MS5611_ADDR, 2);
    C1 = (Wire.read() << 8) | Wire.read();
    
    // Read C2 coefficient
    Wire.beginTransmission(MS5611_ADDR);
    Wire.write(0xA4); // address of second coefficient
    Wire.endTransmission();
    
    Wire.requestFrom(MS5611_ADDR, 2);
    C2 = (Wire.read() << 8) | Wire.read();
    
    // Read C3 coefficient
    Wire.beginTransmission(MS5611_ADDR);
    Wire.write(0xA6); // address of third coefficient
    Wire.endTransmission();
    
    Wire.requestFrom(MS5611_ADDR, 2);
    C3 = (Wire.read() << 8) | Wire.read();
    
    // Read C4 coefficient
    Wire.beginTransmission(MS5611_ADDR);
    Wire.write(0xA8); // address of fourth coefficient
    Wire.endTransmission();
    
    Wire.requestFrom(MS5611_ADDR, 2);
    C4 = (Wire.read() << 8) | Wire.read();
    
    // Read C5 coefficient
    Wire.beginTransmission(MS5611_ADDR);
    Wire.write(0xAA); // address of fifth coefficient
    Wire.endTransmission();
    
    Wire.requestFrom(MS5611_ADDR, 2);
    C5 = (Wire.read() << 8) | Wire.read();
    
    // Read C6 coefficient
    Wire.beginTransmission(MS5611_ADDR);
    Wire.write(0xAC); // address of sixth coefficient
    Wire.endTransmission();
    
    Wire.requestFrom(MS5611_ADDR, 2);
    C6 = (Wire.read() << 8) | Wire.read();
    
    // Check if all coefficients are non-zero
    if (C1 == 0 || C2 == 0 || C3 == 0 || C4 == 0 || C5 == 0 || C6 == 0) {
        return false; // Calibration failed
    }
    
    return true; // Calibration successful
}

bool readPressureAndTemperature(float& pressure, float& temperature) {
    // Start pressure conversion
    Wire.beginTransmission(MS5611_ADDR);
    Wire.write(MS5611_CMD_CONV_D1_256);
    Wire.endTransmission();
    delay(10); // conversion time for 256 oversampling is 0.9ms
    
    // Read pressure ADC
    Wire.beginTransmission(MS5611_ADDR);
    Wire.write(MS5611_CMD_ADC_READ);
    Wire.endTransmission();
    
    Wire.requestFrom(MS5611_ADDR, 3);
    uint32_t pressureADC = 0;
    pressureADC |= (Wire.read() << 16);
    pressureADC |= (Wire.read() << 8);
    pressureADC |= Wire.read();
    
    // Start temperature conversion
    Wire.beginTransmission(MS5611_ADDR);
    Wire.write(MS5611_CMD_CONV_D2_256);
    Wire.endTransmission();
    delay(10); // conversion time for 256 oversampling is 0.9ms
    
    // Read temperature ADC
    Wire.beginTransmission(MS5611_ADDR);
    Wire.write(MS5611_CMD_ADC_READ);
    Wire.endTransmission();
    
    Wire.requestFrom(MS5611_ADDR, 3);
    uint32_t temperatureADC = 0;
    temperatureADC |= (Wire.read() << 16);
    temperatureADC |= (Wire.read() << 8);
    temperatureADC |= Wire.read();
    
    // Check if any of the ADC readings are zero
    if (pressureADC == 0 || temperatureADC == 0) {
        return false; // Sensor reading error
    }
    
    // Calculate temperature
    int32_t dT = temperatureADC - C5 * (1 << 8);
    temperature = 2000 + ((dT * C6) / (1 << 23));
    temperature /= 100.0; // Convert to degrees Celsius
    
    // Calculate temperature compensated pressure
    int64_t off = C2 * (1 << 16) + (C4 * dT) / (1 << 7);
    int64_t sens = C1 * (1 << 15) + (C3 * dT) / (1 << 8);
    int32_t pressureComp = (pressureADC * sens / (1 << 21) - off) / (1 << 15);
    pressure = pressureComp / 100.0; // Convert to mbar
    
    return true; // Readings successful
}

Here are the results observed when viewing the serial monitor on Arduino or the Particle dashboard:

And here are the results obtained when utilizing an Arduino Uno with a library:

image

I would greatly appreciate any guidance or suggestions on how to effectively implement I2C communication for this setup. If anyone has experience with similar projects or has insights into alternative approaches, your input would be invaluable.

Thank you in advance for your assistance.
Best regards,
Nayel

Nothing sticks out to me in the code, but I would start by comparing the values of pressureADC, temperatureADC, dT, off, and sens between the Arduino and the Particle device. It could be something strange with I2C byte order or integer promotion that you're not expecting.

1 Like

Hi @jettonj,

Thanks for the suggestion! I'll compare those values and let you know what I find. Your help is much appreciated!

Regards,
Nayel

Hi @jettonj,

So for now what I did is to see if I had the same message between the sensor and MCU on both platform :

Here is analyse, we begin with the adress of the sensor wich is in our case 0x77 :

And now we have the biffy message :

(This is the overall message between the sensor and the particle)



image

This is the MS5611_CMD_CONV_D1_256 for the conversion


And now for the arduino side :


So now the difference is that we begin with reset command and we send after the command A0 wich is the PROM Read , in contrary to my code, Then we have the usual sequence of coefficient and after with have this :

Wich is the MS5611_CMD_CONV_D1_256 command.

but without any value that return.

Then we have another value that's read from the adc with the conversion that goes with it :

And finally the last frame :

Wich is another read from the adc with the conversion that goes with it.

Now I don't know what to do, do you a suggestion?

Best regards,
Nayel

The I2C plots are a great start! What scope do you use? They look nice.
I think next you may want to simply print out the all of the variables you have to the terminal. I think you're asking for all of the data correctly but I would compare exactly what the coefficients for between Arduino/Particle, as they should be the same if they're stored in ROM right? Just make sure everything except the readings themselves align.

Hi @jettonj,

Thanks for your reply, I'm utilizing the logic analyzer, which I believe is from Cmsis Keil, alongside the Pulseview Software.

image

Here is the link to the one I have : Cmsis Keil
You can have it for 3 euros If you're new to aliexpress

Here is a link to a better brand called WEAct Studio : We act studio

image

You can also have it for 3 euros If you're new to aliexpress

Here is all the variable for the particle side :
image

Regarding the Arduino, I can't find a way to access the coefficients. However, as you can observe in the first picture, I've mostly corrected the issue, particularly concerning pressure (which reads as 1000mbar in Lyon). However, regarding temperature, I'm unsure why, but when I touch the sensor, it drops to 18 degrees. Additionally, even when I'm not touching it, there's a 5-degree difference between the Arduino and the Particle.For the altitude, let's say I don't know how to do it :sweat_smile:

When I look at the values returned from the MS5611 between the Arduino and the Particle device, they're very similar. So I believe the issue lies either in the math or how you're storing the coefficients.

image

Also note that in your last screenshot the coefficients don't line up with their values shown over I2C. You're expecting 0xB5FC for C1 but you only pick up 0x009C, so maybe the Wire buffer has two byte in it already when you first try to store C1? Maybe print out Wire.available() right before that to check. If there's something already there just try discarding them with Wire.flush(). Or maybe your C7 was a typo and you had the correct values for C1->C7 but you should double check.

Hello @jettonj,

Thank you for your suggestion, I will definitly give it a try.

I'm currently working on understanding the steps you explained thoroughly.

Best regards,
Nayel