High resolution barometer and altimeter using i2c mode

Dependents:   upverter_fitbit_clone ReadingMag_HMC5883L_work

Files at this revision

API Documentation at this revision

Comitter:
loopsva
Date:
Tue Jul 14 16:19:59 2015 +0000
Parent:
8:461f68bc94f2
Commit message:
Fixed minor bugs when using low-level I2C routines. Hi-level I2C routines ok. Also added hooks for the MS5805 (untested).

Changed in this revision

ms5611.cpp Show annotated file Show diff for this revision Revisions of this file
ms5611.h Show annotated file Show diff for this revision Revisions of this file
--- a/ms5611.cpp	Tue Apr 28 23:36:22 2015 +0000
+++ b/ms5611.cpp	Tue Jul 14 16:19:59 2015 +0000
@@ -22,6 +22,7 @@
 double S;                       // sea level barometer (mB)
 
 uint32_t C[8];                  //coefficient storage
+int MStype = 0;
 
 //--------------------------------------------------------------------------------------------------------------------------------------//
 // Constructor and destructor - default to be compatible with legacy m5611 driver
@@ -39,7 +40,8 @@
         _i2c.frequency(400000);
         _i2cWAddr = MS5611_ADDR_W;
         _i2cRAddr = MS5611_ADDR_R;
-        if(CSBpin == CSBpin_1) {
+        MStype = CSBpin;
+        if((CSBpin == CSBpin_1) || (CSBpin == MS5805)) {
             _i2cWAddr -= 2;
             _i2cRAddr -= 2;
         
@@ -112,7 +114,7 @@
 //! @return none
 //********************************************************
 
-void ms5611::m_i2c_send(char cmd) {
+int ms5611::m_i2c_send(char cmd) {
     unsigned char ret;
     ret = m_i2c_start(false);
     if(!(ret)) {
@@ -121,6 +123,7 @@
         ret = m_i2c_write(cmd);
         m_i2c_stop();
     }
+    return(ret);
 }
 
 //********************************************************
@@ -129,16 +132,29 @@
 //! @return none
 //********************************************************
 
-void ms5611::cmd_reset() {
+int ms5611::cmd_reset() {
 #if defined  MS5611i2cLOWLEVEL
-    m_i2c_send(MS5611_CMD_RESET);
+    int ret = m_i2c_send(MS5611_CMD_RESET);
+    if(!(ret)) return(ret);
 #else
     char cobuf[1];
     cobuf[0] = MS5611_CMD_RESET;
-    _i2c.write(_i2cWAddr, cobuf, 1, false);
+    int ret = _i2c.write(_i2cWAddr, cobuf, 1, false);
+    if((ret)) return(0);
 #endif
+
+#ifdef RTOS_H
+    Thread::wait(4);
+#else
     wait_ms(4);
+#endif
+
     loadCoefs();
+#if defined  MS5611i2cLOWLEVEL
+    return(ret);
+#else
+    return(1);
+#endif
 }
 
 //********************************************************
@@ -148,33 +164,47 @@
 //********************************************************
 
 unsigned long ms5611::cmd_adc(char cmd) {
-    char cobuf[3];
-    cobuf[0] = 0;
-    cobuf[1] = 0;
-    cobuf[2] = 0;
-    unsigned int ret;
+    char cobuf[3] = {0, 0, 0};
     unsigned long temp = 0;
 #if defined  MS5611i2cLOWLEVEL
-    m_i2c_send(MS5611_CMD_ADC_CONV + cmd);
+    m_i2c_start(false);
+    m_i2c_write(MS5611_CMD_ADC_CONV + cmd);
+    m_i2c_stop();
 #else
     cobuf[0] = MS5611_CMD_ADC_CONV + cmd;
     _i2c.write(_i2cWAddr, cobuf, 1, false);
 #endif
     switch (cmd & 0x0f) {
+#ifdef RTOS_H
+        case MS5611_CMD_ADC_256 : Thread::wait(1); break;
+        case MS5611_CMD_ADC_512 : Thread::wait(3); break;
+        case MS5611_CMD_ADC_1024: Thread::wait(4); break;
+        case MS5611_CMD_ADC_2048: Thread::wait(6); break;
+        case MS5611_CMD_ADC_4096: Thread::wait(10); break;
+        case MS5805_CMD_ADC_8192: Thread::wait(19); break;
+#else
         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;
+        case MS5805_CMD_ADC_8192: wait_ms(19); break;
+#endif
     }
 #if defined  MS5611i2cLOWLEVEL
-    m_i2c_send(MS5611_CMD_ADC_READ);
+    m_i2c_start(false);
+    m_i2c_write(MS5611_CMD_ADC_READ);
+    m_i2c_start(true);
+    cobuf[0] = m_i2c_readAck();
+    cobuf[1] = m_i2c_readAck();
+    cobuf[2] = m_i2c_readNak();
+    m_i2c_stop();
 #else
     cobuf[0] = MS5611_CMD_ADC_READ;
     _i2c.write(_i2cWAddr, cobuf, 1, true);
     cobuf[0] = 0;
+    _i2c.read(_i2cRAddr, cobuf, 3, false);
 #endif    
-    ret = _i2c.read(_i2cRAddr, cobuf, 3, false);
     //if(ret) printf("\n*** ms5611 ADC Read Error ");
     temp = (cobuf[0] << 16) + (cobuf[1] << 8) + cobuf[2];
     return temp;
@@ -187,19 +217,21 @@
 //********************************************************
 
 unsigned int ms5611::cmd_prom(char coef_num) {
-    char cobuf[2];
-    unsigned int ret;
+    char cobuf[2] = {0, 0};
     unsigned int rC = 0;
-    cobuf[0] = 0;
-    cobuf[1] = 0;
 #if defined  MS5611i2cLOWLEVEL
-    m_i2c_send(MS5611_CMD_PROM_RD + coef_num * 2); // send PROM READ command
+    m_i2c_start(false);
+    m_i2c_write(MS5611_CMD_PROM_RD + coef_num * 2);// send PROM READ command
+    m_i2c_start(true);
+    cobuf[0] = m_i2c_readAck();
+    cobuf[1] = m_i2c_readNak();
+    m_i2c_stop();
 #else
     cobuf[0] = MS5611_CMD_PROM_RD + coef_num * 2;
     _i2c.write(_i2cWAddr, cobuf, 1, true);
     cobuf[0] = 0;
+    _i2c.read(_i2cRAddr, cobuf, 2, false);
 #endif
-    ret = _i2c.read(_i2cRAddr, cobuf, 2, false);
     //if(ret) printf("\n*** ms5611 PROM Read Error ");
     rC = cobuf[0] * 256 + cobuf[1];
     return rC;
@@ -212,12 +244,16 @@
 //********************************************************
 
 unsigned char ms5611::crc4(unsigned int n_prom[]) {
-    unsigned int n_rem;
-    unsigned int crc_read;
-    unsigned char n_bit;
-    n_rem = 0x00;
-    crc_read = n_prom[7];
-    n_prom[7]=(0xFF00 & (n_prom[7]));
+    unsigned int n_rem = 0;
+    unsigned int crc_read = 0;
+    unsigned char n_bit = 0;
+    if(MStype == ms5611::MS5805) {
+        n_prom[0] = (n_prom[0] & 0x0FFF);
+        n_prom[7] = 0;
+    } else {
+        crc_read = n_prom[7];
+        n_prom[7]=(0xFF00 & (n_prom[7]));
+    }
     for (int cnt = 0; cnt < 16; cnt++) {
             if (cnt%2 == 1) {
                 n_rem ^= (unsigned short) ((n_prom[cnt>>1]) & 0x00FF);
@@ -232,8 +268,10 @@
                 }
             }
         }
-    n_rem= (0x000F & (n_rem >> 12));
-    n_prom[7]=crc_read;
+    n_rem= ((n_rem >> 12) & 0x000F);
+    if(!(MStype == ms5611::MS5805)) {
+        n_prom[7]=crc_read;
+    }
     return (n_rem ^ 0x0);
 }
 
@@ -295,8 +333,16 @@
 //********************************************************   
      
 void ms5611::calcPT() {
-    int32_t D2 = cmd_adc(MS5611_CMD_ADC_D2 + MS5611_CMD_ADC_4096); // read D2
-    int32_t D1 = cmd_adc(MS5611_CMD_ADC_D1 + MS5611_CMD_ADC_4096); // read D1
+    int32_t D1 = 0;
+    int32_t D2 = 0;
+    if(MStype == ms5611::MS5805) {
+        D2 = cmd_adc(MS5611_CMD_ADC_D2 + MS5805_CMD_ADC_8192); // read D2
+        D1 = cmd_adc(MS5611_CMD_ADC_D1 + MS5805_CMD_ADC_8192); // read D1
+    } else {
+        D2 = cmd_adc(MS5611_CMD_ADC_D2 + MS5611_CMD_ADC_4096); // read D2
+        D1 = cmd_adc(MS5611_CMD_ADC_D1 + MS5611_CMD_ADC_4096); // read D1
+    }
+        
     int64_t dT = D2 - ((uint64_t)C[5] << 8);
     int64_t OFF  = ((uint32_t)C[2] << 16) + ((dT * (C[4]) >> 7));     //was  OFF  = (C[2] << 17) + dT * C[4] / (1 << 6);
     int64_t SENS = ((uint32_t)C[1] << 15) + ((dT * (C[3]) >> 8));     //was  SENS = (C[1] << 16) + dT * C[3] / (1 << 7);
@@ -304,18 +350,26 @@
     int32_t TEMP = 2000 + (int64_t)dT * (int64_t)C[6] / (int64_t)(1 << 23);
 
     if(TEMP < 2000) { // if temperature lower than 20 Celsius
-        float T1 = (TEMP - 2000) * (TEMP - 2000);
-        int64_t OFF1  = (5 * T1) / 2;
-        int64_t SENS1 = (5 * T1) / 4;
-
-        if(TEMP < -1500) { // if temperature lower than -15 Celsius
-            T1 = (TEMP + 1500) * (TEMP + 1500);
-            OFF1  += 7 * T1;
-            SENS1 += 11 * T1 / 2;
-        } 
+        float T1 = 0.0;
+        int64_t OFF1, SENS1  = 0;
+        if(MStype == ms5611::MS5805) {
+            T1 = 11 * ((dT * dT) >> 35);
+            OFF1  = 31 * ((TEMP - 2000) * (TEMP - 2000)) >> 3;
+            SENS1 = 63 * ((TEMP - 2000) * (TEMP - 2000)) >> 5;
+        } else {
+            T1 = (TEMP - 2000) * (TEMP - 2000);
+            OFF1  = (5 * T1) / 2;
+            SENS1 = (5 * T1) / 4;
+    
+            if(TEMP < -1500) { // if temperature lower than -15 Celsius
+                T1 = (TEMP + 1500) * (TEMP + 1500);
+                OFF1  += 7 * T1;
+                SENS1 += 11 * T1 / 2;
+            } 
+        }
         OFF -= OFF1;
         SENS -= SENS1;
-        T = (float)TEMP / 100; 
+        T = ((double)TEMP - T1)/ 100.0; 
     }
 //    int64_t P1 = ((((int64_t)D1 * SENS) >> 21) - OFF) >> 15;   
     P = ((((int64_t)D1 * SENS ) >> 21) - OFF) / (double) (1 << 15) / 100.0;
@@ -376,7 +430,7 @@
 //********************************************************  
 
 float ms5611::getSeaLevelBaroFT(float known_alt) {
-    S = pow(pow((P * INHG), 0.190284) + 0.00001313 * known_alt , 5.2553026) * MB;
+    S = pow(pow((P * MB_INHG_DOUBLE), 0.190284) + 0.00001313 * known_alt , 5.2553026) * INHG_MB_DOUBLE;
     return((float)S);
 } 
 
@@ -389,6 +443,7 @@
 //********************************************************  
 
 float ms5611::getSeaLevelBaroM(float known_alt) {
-    S = pow(pow((P * INHG), 0.190284) + 0.00001313 * known_alt * FTMETERS , 5.2553026) * MB;
+    S = pow(pow((P * MB_INHG_DOUBLE), 0.190284) + 0.00001313 * known_alt * FEET_METERS , 5.2553026) * INHG_MB_DOUBLE;
     return((float)S);
 } 
+
--- a/ms5611.h	Tue Apr 28 23:36:22 2015 +0000
+++ b/ms5611.h	Tue Jul 14 16:19:59 2015 +0000
@@ -3,18 +3,20 @@
 
 #include "mbed.h"
 
-#if(defined(TARGET_KL25Z) )//|| defined(TARGET_K64F))
+//IMPORTANT NOTE: First attempt at also using the MS5805.  This code is untested!!
+
+//    #define MS5611i2cLOWLEVEL   1           //if the use of low-level I2C routines is needed
+//    #warning "MS5611 using low level I2C routines"
+// IMPORTANT NOTE:  On the K64F, "ack/nack", returns from single byte i2c.write(int data) are opposite 
+//                  of i2c.write(int address, const char *data, int length, bool repeated=false)    
 
-    #define MS5611i2cLOWLEVEL   1           //if the use of low-level I2C routines is needed
-    #warning "MS5611 using low level I2C routines"
-    
-#endif
-
-#define SEA_PRESS   1013.25                 //default sea level pressure level in mb
-#define KNOWNALT    327.0                   //default known altitude, 5200 Franklin Dr., 94588
-#define INHG        0.02952998751           //convert mb to in/Hg constant
-#define MB          33.8638815              //convert in/Hg to mb constant
-#define FTMETERS    0.3048                  //convert feet to meters
+#define SEA_PRESS           1013.25         //default sea level pressure level in mb
+#define KNOWNALT            327.0           //default known altitude, 5200 Franklin Dr., 94588
+#define DEGC_DEGF_FLOAT     9.0 / 5.0 + 32.0//convert degrees C to degrees F
+#define METERS_FEET         3.2808399       //convert meters to feet
+#define FEET_METERS         0.3048006       //convert feet to meters
+#define MB_INHG_DOUBLE      0.02952998751   //convert millibars to inches_of_mercury
+#define INHG_MB_DOUBLE      33.8638815767   //convert inches_of_mercury to millibars
 
 
 /** Software routines to access the Measurement Specialties' MS5611-01BA03 
@@ -46,34 +48,40 @@
  * @code
  * #include "mbed.h"
  * #include "ms5611.h" 
- *
- * //ms5611 ms(p9, p10);                        // i2c pins used
- * ms5611 ms(p9, p10, ms5611::CSBpin_0);      // NEW!! with rev 7. User can set polarity of CSB pin
- * //ms5611 ms(p9, p10, ms5611::CSBpin_1);
- *
- * Serial pc(USBTX, USBRX);                   // local terminal interface
- *
- *
+ *  
+ * #define SDA  PTE25
+ * #define SCL  PTE24
+ *  
+ * //ms5611 ms(SDA, SCL);                        // i2c pins used, legacy default constructor
+ * ms5611 ms(SDA, SCL, ms5611::CSBpin_0);      // NEW!! with rev 7. User can set polarity of CSB pin
+ * //ms5611 ms(SDA, SCL, ms5611::CSBpin_1);
+ * //ms5611 ms(SDA, SCL, ms5611::MS5805);      // NEW!! with rev 8. Allow use of MS5805 as well
+ *  
+ * Serial pc(USBTX, USBRX);                    // local terminal interface
+ *  
  * int main (void) {
- *     pc.baud(921600);                        // set up USB serial speed
- *
+ *     pc.baud(230400);                        // set up USB serial speed
+ *  
  *     // set up the ms5611
- *     pc.printf("\n\nInitializing the MS5611..\n");
- *     ms.cmd_reset();
+ *     pc.printf("\n\nInitializing the MS5611..\r\n");
+ *     int msFlag = ms.cmd_reset();
+ *     if(!(msFlag)) {
+ *        pc.printf("MS5611 I2C error!!\r\n");
+ *        return(-1);
+ *    }
  *     pc.printf("Ready\n");
- *
+ *  
  *     while(1) {
  *         double Temp = ms.calcTemp();                         //calculate press and temp, then returns current temperature in degC
  *         double Press = ms.calcPressure();                    //calculate press and temp, then returns current pressure in mb
  *         double GetPress = ms.getPressure();                  //returns current pressure in mb. Does no calculations.  Ususally done after calcTemp()
  *         double Altitude = ms.getAltitudeFT(1013.25);         //enter pressure at sea level in mb, returns altitude in feet
  *         double PressSeaLvlFT = ms.getSeaLevelBaroFT(327.2);  //enter known altitude in feet, returns sea level pressure in mb
- *         double PressSeaLvlM = ms.getAltitudeFT(99.73);       //enter known altitude in meters, returns seal level pressure in mb
- *
- *         pc.printf("Temp: %.2f degC\n", Temp);    
- *         pc.printf("Barometer: %.1f mB  %.3f in/Hg\n", Press, Press * 0.0295301);
- *         pc.printf("Alt: %.1f ft\n", Altitude);
- *         pc.printf("Sea_Lvl: %.1f ft   %.2f m\n", PressSeaLvlFT, PressSeaLvlM);
+ *  
+ *         pc.printf("Temp:       %6.2f degC   %6.2f  degF\r\n", Temp, Temp * 9.0 / 5.0 + 32.0);    
+ *         pc.printf("Barometer: %7.2f mB    %8.3f in/Hg\r\n", Press, Press * MB_INHG_DOUBLE);
+ *         pc.printf("Sea_Lvl:   %7.2f mB    %8.3f in/Hg\r\n", PressSeaLvlFT, PressSeaLvlFT * MB_INHG_DOUBLE);
+ *         pc.printf("Alt:       %7.2f m     %7.2f  ft\r\n\r\n", Altitude, Altitude * FEET_METERS);
  *         wait(2.0);
  *     }
  * }
@@ -83,19 +91,20 @@
  
 //_____ M A C R O S
 
-#define MS5611_ADDR_W 0xEE // Module address write mode (CSBpin = 0);
-#define MS5611_ADDR_R 0xEF // Module address read mode
-#define MS5611_CMD_RESET 0x1E // ADC reset command
-#define MS5611_CMD_ADC_READ 0x00 // ADC read command
-#define MS5611_CMD_ADC_CONV 0x40 // ADC conversion command
-#define MS5611_CMD_ADC_D1 0x00 // ADC D1 conversion
-#define MS5611_CMD_ADC_D2 0x10 // ADC D2 conversion
-#define MS5611_CMD_ADC_256 0x00 // ADC OSR=256
-#define MS5611_CMD_ADC_512 0x02 // ADC OSR=512
-#define MS5611_CMD_ADC_1024 0x04 // ADC OSR=1024
-#define MS5611_CMD_ADC_2048 0x06 // ADC OSR=2048
-#define MS5611_CMD_ADC_4096 0x08 // ADC OSR=4096
-#define MS5611_CMD_PROM_RD 0xA0 // Prom read command
+#define MS5611_ADDR_W 0xEE          // Module address write mode (CSBpin = 0);
+#define MS5611_ADDR_R 0xEF          // Module address read mode
+#define MS5611_CMD_RESET 0x1E       // ADC reset command
+#define MS5611_CMD_ADC_READ 0x00    // ADC read command
+#define MS5611_CMD_ADC_CONV 0x40    // ADC conversion command
+#define MS5611_CMD_ADC_D1 0x00      // ADC D1 conversion
+#define MS5611_CMD_ADC_D2 0x10      // ADC D2 conversion
+#define MS5611_CMD_ADC_256 0x00     // ADC OSR=256
+#define MS5611_CMD_ADC_512 0x02     // ADC OSR=512
+#define MS5611_CMD_ADC_1024 0x04    // ADC OSR=1024
+#define MS5611_CMD_ADC_2048 0x06    // ADC OSR=2048
+#define MS5611_CMD_ADC_4096 0x08    // ADC OSR=4096
+#define MS5805_CMD_ADC_8192 0x0A    // ADC OSR=8192
+#define MS5611_CMD_PROM_RD 0xA0     // Prom read command
 
     /** Create ms5611 controller class
      *
@@ -106,16 +115,20 @@
 
 public:
     enum CSBpolarity {
-        CSBpin_0,  //CSB pin is grounded, I2C address is 0xEE and 0xEF
-        CSBpin_1,  //CSB pin is tied to Vdd, I2C address is 0xEC and 0xED
+        CSBpin_0,   //CSB pin is grounded, I2C address is 0xEE and 0xEF
+        CSBpin_1,   //CSB pin is tied to Vdd, I2C address is 0xEC and 0xED
+        MS5805,     //MS5805 fixed at 0EC and 0xED
     };
+    
     /** Create a MS5611 object using the specified I2C object
      *   - User fixed I2C address 0xEE, CSB pin = 0
      *   - This is the default legacy constructor
      * @param sda - mbed I2C interface pin
      * @param scl - mbed I2C interface pin
+     * @return NONE
      */
     ms5611(PinName sda, PinName scl);
+    
     /** Create a MS5611 object using the specified I2C object
      *   - User defined use of the CSB pin
      *   - CSB pin = 0, user set I2C address to 0xEE
@@ -124,53 +137,56 @@
      * @param scl - mbed I2C interface pin
      * @param ms5611::CSBpin_0 - CSB pin tied to ground
      * @param ms5611::CSBpin_1 - CSB pin tied to VDD
+     * @param ms5611::MS5805   - MS5805 has only one i2c address
+     * @return NONE
      */
     ms5611(PinName sda, PinName scl, CSBpolarity CSBpin);
+    
     /** Initialize the MS5611 and set up the coefficients
-     *    First - reset the MS5611
-     *    Second - load coefficient values from the MS5611 PROM
-     *    Third  - calculate coefficient checksum
-     *  This routine only needs to be run once at boot up
-     *
+     *   - First - reset the MS5611
+     *   - Second - load coefficient values from the MS5611 PROM
+     *   - Third  - calculate coefficient checksum
+     *   - This routine only needs to be run once at boot up
      * @param NONE
+     * @return int I2C ack/nack status
      */
-    void cmd_reset();
-    /** Calculate and return compensated temperature
-     *    Returns double temperature in degC
-     *
+    int cmd_reset();
+    
+    /** Calculates compensated temperature
      * @param NONE
+     * @return double temperature in degC
      */
     double calcTemp();
-    /** Calculate and return compensated barometric pressure
-     *    Returns double pressure in millibars
-     *
+    
+    /** Calculates compensated barometric pressure
      * @param NONE
+     * @return double pressure in millibars
      */
     double calcPressure();
-    /** Return compensated barometric pressure
-     *    Returns double pressure in millibars
-     *    DOES NOT RE-CALCULATE FIRST!!!
-     *    Saves time if you calcTemp(); first
-     *
+    
+    /** Get compensated barometric pressure
+     *  - DOES NOT RE-CALCULATE FIRST!!!
+     *  - Result only valid if you calcTemp(); first
      * @param NONE
+     * @eturn double pressure in millibars
      */
     double getPressure();
-    /** Calculate and returns altitude in feet
-     *    Returns float altitude in feet
-     *
+    
+    /** Calculates altitude in feet
      * @param float known pressure (mB) at sea level
+     * @return float altitude in feet
      */
     float getAltitudeFT(float sea_pressure);
-    /** Calculate and returns sea level baro
-     *    Returns float seal level barometer in feet
-     *
+    
+    /** Calculates sea level baro
      * @param float known altitude in feet
+     * @return float sea level barometer in feet
      */
     float getSeaLevelBaroFT(float known_alt);
-    /** Calculate and returns sea level baro
-     *    Returns float seal level barometer in meters
-     *
+    
+    /** Calculates sea level baro
      * @param float known altitude in meters
+     * @return float sea level barometer in meters
      */
     float getSeaLevelBaroM(float known_alt);
     
@@ -178,11 +194,12 @@
     char _i2cWAddr;
     char _i2cRAddr;
     int m_i2c_start(bool readMode);
+    int MStype;
     void m_i2c_stop(void);
     unsigned char m_i2c_write(unsigned char data);
     unsigned char m_i2c_readAck(void);
     unsigned char m_i2c_readNak(void);
-    void m_i2c_send(char cmd);
+    int m_i2c_send(char cmd);
     void loadCoefs();
     unsigned long cmd_adc(char cmd);
     unsigned int cmd_prom(char coef_num);