High resolution barometer and altimeter using i2c mode

Dependents:   Q2_Stabi

Fork of ms5611 by Kevin Braun

Revision:
0:f97f410d4a21
Child:
2:05804ed70748
--- /dev/null	Thu Jan 01 00:00:00 1970 +0000
+++ b/ms5611.cpp	Tue May 07 18:44:06 2013 +0000
@@ -0,0 +1,300 @@
+//!
+//! @file an520_I2C.c,v
+//!
+//! Copyright (c) 2009 MEAS Switzerland
+//!
+//!
+//!
+//! @brief This C code is for starter reference only. It is written for the
+//! MEAS Switzerland MS56xx pressure sensor modules and Atmel Atmega644p
+//! microcontroller.
+//!
+//! @version 1.0 $Id: an520_I2C.c,v 1.0
+//!
+//! @todo
+
+#include "mbed.h"
+#include "ms5611.h"
+
+//--------------------------------------------------------------------------------------------------------------------------------------//
+// Constructor and destructor
+
+ms5611::ms5611(PinName sda, PinName scl)  : _i2c(sda, scl) {
+
+}
+
+//********************************************************
+//! @brief send I2C start condition and the address byte
+//!
+//! @return 0
+//********************************************************
+
+int ms5611::m_i2c_start(bool readMode) {
+    int twst;
+    _i2c.start();
+    if(readMode == true) {
+        twst = m_i2c_write(MS5611_ADDR_R);
+    } else {
+        twst = m_i2c_write(MS5611_ADDR_W);
+    }
+    return(twst);
+}
+
+//********************************************************
+//! @brief send I2C stop condition
+//!
+//! @return none
+//********************************************************
+
+void ms5611::m_i2c_stop(void) {
+    _i2c.stop();
+}
+
+//********************************************************
+//! @brief send I2C stop condition
+//!
+//! @return remote ack status
+//********************************************************
+
+unsigned char ms5611::m_i2c_write(unsigned char data) {
+    int twst = _i2c.write(data);
+    return(twst);
+}
+
+//********************************************************
+//! @brief read I2C byte with acknowledgment
+//!
+//! @return read byte
+//********************************************************
+
+unsigned char ms5611::m_i2c_readAck(void) {
+    int twst = _i2c.read(1);
+    return(twst);
+}
+
+//********************************************************
+//! @brief read I2C byte without acknowledgment
+//!
+//! @return read byte
+//********************************************************
+
+unsigned char ms5611::m_i2c_readNak(void) {
+    int twst = _i2c.read(0);
+    return(twst);
+}
+
+//********************************************************
+//! @brief send command using I2C hardware interface
+//!
+//! @return none
+//********************************************************
+
+void ms5611::m_i2c_send(char cmd) {
+    unsigned char ret;
+    ret = m_i2c_start(false); // set device address and write mode
+    if(!(ret)) {//failed to issue start condition, possibly no device found */
+        m_i2c_stop();
+    } else {// issuing start condition ok, device accessible
+        ret = m_i2c_write(cmd);
+        m_i2c_stop();
+    }
+}
+
+//********************************************************
+//! @brief send reset sequence
+//!
+//! @return none
+//********************************************************
+
+void ms5611::cmd_reset() {
+    m_i2c_send(MS5611_CMD_RESET); // send reset sequence
+    wait_ms(4); // wait for the reset sequence timing
+    loadCoefs();
+}
+
+//********************************************************
+//! @brief preform adc conversion
+//!
+//! @return 24bit result
+//********************************************************
+
+unsigned long ms5611::cmd_adc(char cmd) {
+    char cobuf[3];
+    cobuf[0] = 0;
+    cobuf[1] = 0;
+    cobuf[2] = 0;
+    unsigned int ret;
+    unsigned long temp = 0;
+    m_i2c_send(MS5611_CMD_ADC_CONV + cmd); // send conversion command
+    switch (cmd & 0x0f) { // wait necessary conversion time
+        case MS5611_CMD_ADC_256 : wait_us(900); break;
+        case MS5611_CMD_ADC_512 : wait_ms(3); break;
+        case MS5611_CMD_ADC_1024: wait_ms(4); break;
+        case MS5611_CMD_ADC_2048: wait_ms(6); break;
+        case MS5611_CMD_ADC_4096: wait_ms(10); break;
+    }
+    m_i2c_send(MS5611_CMD_ADC_READ);
+    
+    ret = _i2c.read(MS5611_ADDR_R, cobuf, 3, false);
+    if(ret) printf("\n*** ms5611 ADC Read Error ");
+    temp = (cobuf[0] << 16) + (cobuf[1] << 8) + cobuf[2];
+    return temp;
+}
+
+//********************************************************
+//! @brief Read calibration coefficients
+//!
+//! @return coefficient
+//********************************************************
+
+unsigned int ms5611::cmd_prom(char coef_num) {
+    char cobuf[2];
+    unsigned int ret;
+    unsigned int rC = 0;
+    cobuf[0] = 0;
+    cobuf[1] = 0;
+    m_i2c_send(MS5611_CMD_PROM_RD + coef_num * 2); // send PROM READ command
+    ret = _i2c.read(MS5611_ADDR_R, cobuf, 2, false);
+    if(ret) printf("\n*** ms5611 PROM Read Error ");
+    rC = cobuf[0] * 256 + cobuf[1];
+    return rC;
+}
+
+//********************************************************
+//! @brief calculate the CRC code
+//!
+//! @return crc code
+//********************************************************
+
+unsigned char ms5611::crc4(unsigned int n_prom[]) {
+    //int cnt; // simple counter
+    unsigned int n_rem; // crc reminder
+    unsigned int crc_read; // original value of the crc
+    unsigned char n_bit;
+    n_rem = 0x00;
+    crc_read = n_prom[7]; //save read CRC
+    n_prom[7]=(0xFF00 & (n_prom[7])); //CRC byte is replaced by 0
+    for (int cnt = 0; cnt < 16; cnt++) {// operation is performed on bytes  // choose LSB or MSB
+            if (cnt%2 == 1) {
+                n_rem ^= (unsigned short) ((n_prom[cnt>>1]) & 0x00FF);
+            } else {
+                n_rem ^= (unsigned short) (n_prom[cnt>>1]>>8);
+            }
+            for (n_bit = 8; n_bit > 0; n_bit--) {
+                if (n_rem & (0x8000)) {
+                    n_rem = (n_rem << 1) ^ 0x3000;
+                } else {
+                    n_rem = (n_rem << 1);
+                }
+            }
+        }
+    n_rem= (0x000F & (n_rem >> 12)); // final 4-bit reminder is CRC code
+//    printf("n_rem: %x  crc_read: %x  n_prom[7]: %x\n", n_rem, crc_read, n_prom[7]);
+    
+    n_prom[7]=crc_read; // restore the crc_read to its original place
+    return (n_rem ^ 0x0);
+/*
+The CRC code is calculated and written in factory with the LSB byte in the prom n_prom[7] set to 0x00 (see
+Coefficient table below). It is thus important to clear those bytes from the calculation buffer before proceeding
+with the CRC calculation itself:
+n_prom[7]=(0xFF00 & (n_prom[7])); //CRC byte is replaced by 0
+As a simple test of the CRC code, the following coefficient table could be used:
+unsigned int nprom[] = {0x3132,0x3334,0x3536,0x3738,0x3940,0x4142,0x4344,0x4500};
+the resulting calculated CRC should be 0xB.
+
+DB  15  14  13  12  11  10  9   8   7   6   5   4   3   2   1   0 
+Addr
+0               16 bit reserved for manufacturer
+1               Coefficient 1 (16 bit unsigned)
+2               Coefficient 2 (16 bit unsigned)
+3               Coefficient 3 (16 bit unsigned)
+4               Coefficient 4 (16 bit unsigned)
+5               Coefficient 5 (16 bit unsigned)
+6               Coefficient 6 (16 bit unsigned)
+7                                   0   0   0   0     CRC(0x0)
+*/    
+/*   
+    //Returns 0x0b as per AP520_004 
+    PTbuffer[0] = 0x3132;
+    PTbuffer[1] = 0x3334;
+    PTbuffer[2] = 0x3536;
+    PTbuffer[3] = 0x3738;
+    PTbuffer[4] = 0x3940;
+    PTbuffer[5] = 0x4142;
+    PTbuffer[6] = 0x4344;
+    PTbuffer[7] = 0x4546;
+    n_crc = ms.crc4(C); // calculate the CRC
+    pc.printf("testing CRC: 0x%x\n", n_crc);
+*/
+       
+}
+//********************************************************
+//! @brief load all calibration coefficients
+//!
+//! @return none
+//********************************************************
+
+unsigned int PTbuffer[8];       // calibration coefficients
+
+void ms5611::loadCoefs() {
+   // printf("Getting coefficients...   ");
+    for (int i = 0; i < 8; i++){ 
+        wait_ms(50);
+        PTbuffer[i] = cmd_prom(i); // read coefficients
+       // printf("0x%04x ", PTbuffer[i]);
+    }
+   // printf("\nCalculate CRC4: ");
+    unsigned char n_crc = crc4(PTbuffer); // calculate the CRC
+   // printf(" 0x%02x\n", n_crc);
+}
+
+double P;                       // compensated pressure value
+double T;                       // compensated temperature value
+
+//********************************************************
+//! @brief calculate temperature and pressure
+//!
+//! @return none
+//********************************************************   
+     
+void ms5611::calcPT() {
+    unsigned long D2 = cmd_adc(MS5611_CMD_ADC_D2 + MS5611_CMD_ADC_4096); // read D2
+    unsigned long D1 = cmd_adc(MS5611_CMD_ADC_D1 + MS5611_CMD_ADC_4096); // read D1
+    // calculate 1st order pressure and temperature (MS5607 1st order algorithm)
+
+    double dT = D2 - (PTbuffer[5] << 8);
+    //change OFF and SENS scaling factor for ms5611
+    double OFF  = (PTbuffer[2] << 16) + dT * PTbuffer[4] / (1 << 6);     //was  OFF  = (PTbuffer[2] << 17) + dT * PTbuffer[4] / (1 << 6);
+    double SENS = (PTbuffer[1] << 15) + dT * PTbuffer[3] / (1 << 7);     //was  SENS = (PTbuffer[1] << 16) + dT * PTbuffer[3] / (1 << 7);
+    T = (2000 + (dT * PTbuffer[6]) / (1 << 23)) / 100;
+    P = (((D1*SENS) / (1 << 21) - OFF) / (1 << 15)) / 100;
+        
+//        dT = D2 - PTbuffer[5] * pow(2,8);
+//        OFF  = PTbuffer[2] * pow(2,17) + dT * PTbuffer[4] / pow(2,6);
+//        SENS = PTbuffer[1] * pow(2,16) + dT * PTbuffer[3] / pow(2,7);
+//        T = (2000 + (dT * PTbuffer[6]) / pow(2,23)) / 100;
+//        P = (((D1*SENS) / pow(2,21) - OFF) / pow(2,15)) / 100;
+        // place to use P, T, put them on LCD, send them trough RS232 interface...
+}
+
+//********************************************************
+//! @brief calculate temperature
+//!
+//! @return double temperature degC
+//********************************************************  
+
+double ms5611::calcTemp() {
+    calcPT();
+    return(T);
+} 
+
+//********************************************************
+//! @brief calculate prssure
+//!
+//! @return double barometric pressure millibar
+//********************************************************  
+
+double ms5611::calcPressure() {
+    calcPT();
+    return(P);
+} 
\ No newline at end of file