Pages: [1]   Go Down
Author Topic: Barometer / Altimeter MS5611  (Read 8732 times)
0 Members and 1 Guest are viewing this topic.
Japan
Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I am trying to interface an MS5611 (I bought the breakout from drotek.fr) with I2C, the datasheet is here:
http://www.meas-spec.com/downloads/MS5611-01BA01.pdf

I can read and convert the data, temperature looks accurate however the pressure is completely off, raw data is around 6450000
instead of around 9000000 necessary to calculate real atmospheric pressure around 1000 mbar.

I wrote an Arduino code and verified the math with Excel. I tried a few libraries found on the net. I tried many combination of pullups for I2C which did not make any changes, adjusted I2C speed, and tried a Mega and a Pro Mini 3.3v. Also I have 2 sensors, they give roughly the same result.

Today my BMP058 says 1003 millibar, my real altitude is 53 meter.

Anybody has experienced this with those sensors? Is there a calibration I missed?

Here is the code I am using:
Code:
// Simplest code to interface the MS5611

#include <Wire.h>

#define ADDRESS 0x77

uint32_t D1 = 0;
uint32_t D2 = 0;

int32_t dT = 0;
int32_t TEMP = 0;
int64_t OFF = 0;
int64_t SENS = 0;
int32_t P = 0;

uint16_t C[7];

void setup() {

  //Mega Arduino disable pullups
  //PORTD |= (1 << 0);
  //PORTD |= (1 << 1);
  // Disable internal pullups, 10Kohms are on the breakout
    PORTC |= (1 << 4);
    PORTC |= (1 << 5);
   
    Wire.begin();
    Serial.begin(9600);
    delay(100);
    initial(ADDRESS);
    Serial.println("temp*100 pressure*100 rawTemp rawPressure");
}

void loop()
{
    D1 = getVal(ADDRESS, 0x48); // Pressure raw
    D2 = getVal(ADDRESS, 0x58);// Temperature raw
 
    dT = (D2 - C[4] * 256);
    TEMP = 2000 + dT * C[5]/8388608;
    OFF  = C[1] * 65536LL + (dT *C[3])/128;
    SENS = C[0] * 32768LL + (C[2] * dT)/256;
    P = (D1 * SENS/2097152 - OFF)/32768;

    Serial.print(TEMP);
    Serial.print(" ");
    Serial.print(P);
    Serial.print(" ");
    Serial.print(D2); //D2 temperature
    Serial.print(" ");
    Serial.println(D1); // D1 pressure
 
    delay(100);
}

long getVal(int address, byte code)
{
    unsigned long ret = 0;
    Wire.beginTransmission(address);
    Wire.write(code);
    Wire.endTransmission();
    delay(10);
    // start read sequence
    Wire.beginTransmission(address);
    Wire.write((byte) 0x00);
    Wire.endTransmission();
    Wire.beginTransmission(address);
    Wire.requestFrom(address, (int)3);
    if(Wire.available()) {
    //    ret = ((uint32_t)Wire.read() << 16) | ((uint32_t)Wire.read() << 8) | Wire.read();
            ret = Wire.read() * 65536 + Wire.read() * 256 + Wire.read();
    }
    else {
        ret = -1;
    }
    Wire.endTransmission();
    return ret;
}

void initial(uint8_t address)
{
    Serial.println();
    Serial.println("PROM COEFFICIENTS");
   
    Wire.beginTransmission(address);
    Wire.write(0x1E); // reset
    Wire.endTransmission();
    delay(10);

    for (int i=0; i<7; i++) {
        Wire.beginTransmission(address);
        Wire.write(0xA2 + (i * 2));
        Wire.endTransmission();

        Wire.beginTransmission(address);
        Wire.requestFrom(address, (uint8_t) 6);
        delay(1);
        if(Wire.available()) {
            C[i] = Wire.read() *256 + Wire.read();
        }
        else {
            Serial.println("Error reading PROM 1"); // error reading the PROM or communicating with the device
        }
        Serial.println(C[i]);
    }
    Serial.println();
}
« Last Edit: February 26, 2012, 03:04:15 am by freto » Logged

0
Offline Offline
Shannon Member
****
Karma: 198
Posts: 11639
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Code:
    if(Wire.available()) {
    //    ret = ((uint32_t)Wire.read() << 16) | ((uint32_t)Wire.read() << 8) | Wire.read();
            ret = Wire.read() * 65536 + Wire.read() * 256 + Wire.read();
    }
    else {
        ret = -1;
    }
 
The commented out line seems better than the one you are using which isn't calculating values as long...
You could try
Code:
            ret = Wire.read() * 65536L + Wire.read() * 256L + Wire.read();
But that's not guaranteed to work for another reason:  the order of evaluation of subexpressions is not guaranteed, so that you can't be sure which byte gets used where, so you should be doing something like:
Code:
    ret = Wire.read () ;
    ret = (ret << 8) | Wire.read () ;
    ret = (ret << 8) | Wire.read () ;
Which forces the order of evaluation (and is also clearer to read, and can be converted into a loop in an obvious fashion:)
Code:
    ret = 0L ;
    for (byte i = 0 ; i < 3 ; i++)
      ret = (ret << 8) | Wire.read () ;

Also I'd be more defensive and check the value returned by available and rewrite
Code:
    if(Wire.available()) {
as
Code:
    if (Wire.available() >= 3) {
Logged

[ I won't respond to messages, use the forum please ]

Japan
Offline Offline
Newbie
*
Karma: 0
Posts: 3
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Thank you Mark for the explanation, indeed it makes the code better and safer.

I just found the solution with a microscope, in fact the sensors I bought are 5607 http://www.meas-spec.com/product/MS5607-B.aspx instead of the 5611 advertised http://www.drotek.fr/shop/fr/44-ms5611-pression-barometrique-pcb.html so the equation to derive pressure needed different coefficients.
Logged

0
Offline Offline
Shannon Member
****
Karma: 198
Posts: 11639
Arduino rocks
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I once got sent £50 worth of magnetometer breakouts when I was ordering £10 of a cheaper accelerometer chips - dutifully sent them back though.  You got a barometer at least.
Logged

[ I won't respond to messages, use the forum please ]

Offline Offline
Newbie
*
Karma: 0
Posts: 1
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

Hi,
I have made the changes suggested and it appears to give better values.

However there is some behaviour I don't understand: If you make repeated calls to get the raw temperature you get consistent values. But if you request raw temperature, then request raw pressure and then further requests to get the raw temp the temperature values are different compared to the initial reading by roughly:
912 for the 1st call after the pressure reading;
578 for the 2nd call after the pressure reading;
284 for the 3rd call after the pressure reading.
Which is perhaps roughly 4*256, 2*256, 1*256 in each case.

I have checked this behaviour with Fabio Varesano's library with the same result. (his code seems to generally return a raw temp that is different by 3*256)

The code follows and I have attached an Excel spreadsheet with results.
Any thoughts welcome.
Code:
/*
 Example code for using the MS5611 directly.

Copyright (C) 2011 Stephen Bishop

This program is free software: you can redistribute it and/or modify
it under the terms of the version 3 GNU General Public License as
published by the Free Software Foundation.

This program is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
GNU General Public License for more details.

You should have received a copy of the GNU General Public License
along with this program.  If not, see <http://www.gnu.org/licenses/>.

SDA (data line) is on analog input pin 4
SCL (clock line) is on analog input pin 5
*/


//#define DEBUG_V
#define ADDRESS 0x76 //Embedded adventures module CSB is VCC so HIGH i.e. 0x76

#include <Wire.h>

uint32_t D1 = 0;
uint32_t D2 = 0;

void setup() {
  Wire.begin();
  Serial.begin(115200);
  delay(1000);

  // Embedded adventures module CSB is VCC so HIGH
}

void loop() {
 
  Serial.print(" Direct rawtemp: "); // get raw T
  Serial.print(getVal(ADDRESS, 0x58));
  Serial.print(" Direct rawpress: "); // remove this line to test effect of pressure reading
  Serial.println(getVal(ADDRESS, 0x48)); // remove this line to test effect of pressure reading
  Serial.print(" Direct rawtemp: "); // get raw T
  Serial.print(getVal(ADDRESS, 0x58));
  Serial.print(" Direct rawtemp: "); // get raw T
  Serial.print(getVal(ADDRESS, 0x58));
  Serial.print(" Direct rawtemp: ");
  Serial.println(getVal(ADDRESS, 0x58));
}

uint32_t getVal(int address, byte code)
{
    uint32_t ret = 0;
    byte b = 0;
    Wire.beginTransmission(address);
    Wire.send(code); // changed write to send
   // Serial.print(code, BIN); // for debuging
    //Serial.print("  "); // for debuging
    Wire.endTransmission();
    delay(10);
    // start read sequence
    Wire.beginTransmission(address);
   // Wire.send((byte) 0x00);
    Wire.send(0);
    Wire.endTransmission();
    Wire.beginTransmission(address);
   // Serial.print((uint8_t) 3, BIN); // for debuging
    Wire.requestFrom((uint8_t)address, (uint8_t)3);// requestFrom MS5611
    if (Wire.available() >= 3)
        {
            ret = 0L ;
             b = 0;
     /* // for debuging
      Serial.print(b,DEC);
      Serial.print("  ");
      ret = (ret << 8) | b ;
      b = Wire.receive();
      Serial.print(b,DEC);
      Serial.print("  ");
      ret = (ret << 8) | b ;
      b = Wire.receive();
      Serial.print(b,DEC);
      Serial.print("  ");
      ret = (ret << 8) | b ;
      */
             
         for (byte i = 0 ; i < 3 ; i++)
           {
            b = Wire.receive();
           //  Serial.print(b,DEC); // for debuging
           //  Serial.print("  "); // for debuging
           ret = (ret << 8) | b ;
           }
       }
       else {
         ret = -1;
             }
       Wire.endTransmission();
    //   Serial.println(ret); // for debuging
       return ret;
}





* Directxls.xls (28.5 KB - downloaded 26 times.)
Logged

Offline Offline
Newbie
*
Karma: 0
Posts: 46
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

sorry for my intrusion...

but in the sketch   C[7]  ... what values ​​are?
Logged

Germany
Offline Offline
Jr. Member
**
Karma: 1
Posts: 70
I'm a newbie
View Profile
WWW
 Bigger Bigger  Smaller Smaller  Reset Reset

sorry for my intrusion...

but in the sketch   C[7]  ... what values ​​are?

If you are refering to sbishop61's code, it is incomplete.
Logged

Leo

Project "ALTDuino" - A homemade altimeter for model rockets.
http://www.altduino.de


Offline Offline
Newbie
*
Karma: 0
Posts: 46
View Profile
 Bigger Bigger  Smaller Smaller  Reset Reset

I solved it ... thanks

could you help me to http://arduino.cc/forum/index.php/topic,113475.0.html
Logged

Pages: [1]   Go Up
Jump to: