UAVRO / ms5611

Dependents:   Q2_Stabi

Fork of ms5611 by Kevin Braun

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ms5611.cpp Source File

ms5611.cpp

00001 //!
00002 //! @file an520_I2C.c,v
00003 //!
00004 //! Copyright (c) 2009 MEAS Switzerland
00005 //!
00006 //!
00007 //!
00008 //! @brief This C code is for starter reference only. It is written for the
00009 //! MEAS Switzerland MS56xx pressure sensor modules and Atmel Atmega644p
00010 //! microcontroller.
00011 //!
00012 //! @version 1.0 $Id: an520_I2C.c,v 1.0
00013 //!
00014 //! @todo
00015 
00016 #include "mbed.h"
00017 #include "ms5611.h"
00018 
00019 double P;                       // compensated pressure value (mB)
00020 double T;                       // compensated temperature value (degC)
00021 double A;                       // altitude (ft)
00022 double S;                       // sea level barometer (mB)
00023 
00024 uint32_t C[8];                  //coefficient storage
00025 
00026 //--------------------------------------------------------------------------------------------------------------------------------------//
00027 // Constructor and destructor - default to be compatible with legacy m5611 driver
00028 
00029 ms5611::ms5611(PinName sda, PinName scl)  : _i2c(sda, scl) {
00030         _i2c.frequency(400000);
00031         _i2cWAddr = MS5611_ADDR_W;
00032         _i2cRAddr = MS5611_ADDR_R;
00033         step = 1;
00034 }
00035 
00036 //--------------------------------------------------------------------------------------------------------------------------------------//
00037 // Constructor and destructor - new, to allow for user to select i2c address based on CSB pin
00038 
00039 ms5611::ms5611(PinName sda, PinName scl, CSBpolarity CSBpin)  : _i2c(sda, scl) {
00040         _i2c.frequency(400000);
00041         _i2cWAddr = MS5611_ADDR_W;
00042         _i2cRAddr = MS5611_ADDR_R;
00043         if(CSBpin == CSBpin_1) {
00044             _i2cWAddr -= 2;
00045             _i2cRAddr -= 2;
00046         
00047         }
00048         step = 1;
00049 }
00050 
00051 //********************************************************
00052 //! @brief send I2C start condition and the address byte
00053 //!
00054 //! @return 0
00055 //********************************************************
00056 
00057 int32_t ms5611::m_i2c_start(bool readMode) {
00058     int32_t twst;
00059     _i2c.start();
00060     if(readMode == true) {
00061         twst = m_i2c_write(_i2cRAddr);
00062     } else {
00063         twst = m_i2c_write(_i2cWAddr);
00064     }
00065     return(twst);
00066 }
00067 
00068 //********************************************************
00069 //! @brief send I2C stop condition
00070 //!
00071 //! @return none
00072 //********************************************************
00073 
00074 void ms5611::m_i2c_stop() {
00075     _i2c.stop();
00076 }
00077 
00078 //********************************************************
00079 //! @brief send I2C stop condition
00080 //!
00081 //! @return remote ack status
00082 //********************************************************
00083 
00084 uint8_t ms5611::m_i2c_write(uint8_t data) {
00085     uint8_t twst = _i2c.write(data);
00086     return(twst);
00087 }
00088 
00089 //********************************************************
00090 //! @brief read I2C byte with acknowledgment
00091 //!
00092 //! @return read byte
00093 //********************************************************
00094 
00095 uint8_t ms5611::m_i2c_readAck() {
00096     uint8_t twst = _i2c.read(1);
00097     return(twst);
00098 }
00099 
00100 //********************************************************
00101 //! @brief read I2C byte without acknowledgment
00102 //!
00103 //! @return read byte
00104 //********************************************************
00105 
00106 uint8_t ms5611::m_i2c_readNak() {
00107     uint8_t twst = _i2c.read(0);
00108     return(twst);
00109 }
00110 
00111 //********************************************************
00112 //! @brief send command using I2C hardware interface
00113 //!
00114 //! @return none
00115 //********************************************************
00116 
00117 void ms5611::m_i2c_send(uint8_t cmd) {
00118     uint8_t ret;
00119     ret = m_i2c_start(false);
00120     if(!(ret)) {
00121         m_i2c_stop();
00122     } else {
00123         ret = m_i2c_write(cmd);
00124         m_i2c_stop();
00125     }
00126 }
00127 
00128 //********************************************************
00129 //! @brief send reset sequence
00130 //!
00131 //! @return none
00132 //********************************************************
00133 
00134 void ms5611::cmd_reset() {
00135 #if defined  MS5611i2cLOWLEVEL
00136     m_i2c_send(MS5611_CMD_RESET);
00137 #else
00138     cobuf[0] = MS5611_CMD_RESET;
00139     _i2c.write(_i2cWAddr, cobuf, 1, false);
00140 #endif
00141     wait_ms(4);
00142     loadCoefs();
00143 }
00144 
00145 //********************************************************
00146 //! @brief preform adc conversion
00147 //!
00148 //! @return 24bit result
00149 //********************************************************
00150 
00151 uint64_t ms5611::cmd_adc(uint8_t cmd) {
00152     uint64_t temp = 0;
00153     if( step & 0b101 ){ // or 0b1 either 0b100
00154 #if defined  MS5611i2cLOWLEVEL
00155         m_i2c_send(MS5611_CMD_ADC_CONV + cmd);
00156 #else
00157         cobuf[0] = 0;
00158         cobuf[1] = 0;
00159         cobuf[2] = 0;
00160         cobuf[0] = MS5611_CMD_ADC_CONV + cmd;
00161         _i2c.write(_i2cWAddr, cobuf, 1, false);
00162 #endif
00163         /*
00164         switch (cmd & 0x0f) {
00165             case MS5611_CMD_ADC_256 : wait_us(900); break;
00166             case MS5611_CMD_ADC_512 : wait_ms(3); break;
00167             case MS5611_CMD_ADC_1024: wait_ms(4); break;
00168             case MS5611_CMD_ADC_2048: wait_ms(6); break;
00169             case MS5611_CMD_ADC_4096: wait_ms(10); break;
00170         }
00171         */
00172         step = step<<1; // will be 0b10 or 0b1000    
00173         return 0;
00174     }
00175     else if( step & 0b1010 ){ // or 0b10 either 0b1000
00176 #if defined  MS5611i2cLOWLEVEL
00177         m_i2c_send(MS5611_CMD_ADC_READ);
00178         m_i2c_start(true);
00179         temp = m_i2c_readAck();
00180         temp = (temp << 8) | m_i2c_readAck();
00181         temp = (temp << 8) | m_i2c_readNak();
00182         m_i2c_stop();
00183 #else
00184         cobuf[0] = MS5611_CMD_ADC_READ;
00185         _i2c.write(_i2cWAddr, cobuf, 1, true);
00186         cobuf[0] = 0;
00187         _i2c.read(_i2cRAddr, cobuf, 3, false);
00188         temp = (cobuf[0] << 16) | (cobuf[1] << 8) | cobuf[2];
00189 #endif
00190         step = step<<1; // will be 0b100 or 0b10000    
00191         return temp;
00192     }
00193     return 0;
00194 }
00195 
00196 //********************************************************
00197 //! @brief Read calibration coefficients
00198 //!
00199 //! @return coefficient
00200 //********************************************************
00201 
00202 uint32_t ms5611::cmd_prom(uint8_t coef_num) {
00203     uint32_t rC = 0;
00204 #if defined  MS5611i2cLOWLEVEL
00205     m_i2c_send(MS5611_CMD_PROM_RD + coef_num * 2); // send PROM READ command
00206     m_i2c_start(true);
00207     rC = m_i2c_readAck();
00208     rC = (rC << 8) | m_i2c_readNak();
00209     m_i2c_stop();
00210 #else
00211     cobuf[0] = 0;
00212     cobuf[1] = 0;
00213     cobuf[0] = MS5611_CMD_PROM_RD + coef_num * 2;
00214     _i2c.write(_i2cWAddr, cobuf, 1, true);
00215     cobuf[0] = 0;
00216     _i2c.read(_i2cRAddr, cobuf, 2, false);
00217     rC = (cobuf[0] << 8) | cobuf[1];
00218 #endif
00219     return rC;
00220 }
00221 
00222 //********************************************************
00223 //! @brief calculate the CRC code
00224 //!
00225 //! @return crc code
00226 //********************************************************
00227 
00228 uint8_t ms5611::crc4(uint32_t n_prom[]) {
00229     uint32_t n_rem;
00230     uint32_t crc_read;
00231     uint8_t n_bit;
00232     n_rem = 0x00;
00233     crc_read = n_prom[7];
00234     n_prom[7]=(0xFF00 & (n_prom[7]));
00235     for (int cnt = 0; cnt < 16; cnt++) {
00236             if (cnt%2 == 1) {
00237                 n_rem ^= (uint16_t) ((n_prom[cnt>>1]) & 0x00FF);
00238             } else {
00239                 n_rem ^= (uint16_t) (n_prom[cnt>>1]>>8);
00240             }
00241             for (n_bit = 8; n_bit > 0; n_bit--) {
00242                 if (n_rem & (0x8000)) {
00243                     n_rem = (n_rem << 1) ^ 0x3000;
00244                 } else {
00245                     n_rem = (n_rem << 1);
00246                 }
00247             }
00248         }
00249     n_rem= (0x000F & (n_rem >> 12));
00250     n_prom[7]=crc_read;
00251     return (n_rem ^ 0x0);
00252 }
00253 
00254 /*
00255 The CRC code is calculated and written in factory with the LSB byte in the prom n_prom[7] set to 0x00 (see
00256 Coefficient table below). It is thus important to clear those bytes from the calculation buffer before proceeding
00257 with the CRC calculation itself:
00258 n_prom[7]=(0xFF00 & (n_prom[7])); //CRC byte is replaced by 0
00259 As a simple test of the CRC code, the following coefficient table could be used:
00260 uint32_t nprom[] = {0x3132,0x3334,0x3536,0x3738,0x3940,0x4142,0x4344,0x4500};
00261 the resulting calculated CRC should be 0xB.
00262 
00263 DB  15  14  13  12  11  10  9   8   7   6   5   4   3   2   1   0 
00264 Addr
00265 0               16 bit reserved for manufacturer
00266 1               Coefficient 1 (16 bit unsigned)
00267 2               Coefficient 2 (16 bit unsigned)
00268 3               Coefficient 3 (16 bit unsigned)
00269 4               Coefficient 4 (16 bit unsigned)
00270 5               Coefficient 5 (16 bit unsigned)
00271 6               Coefficient 6 (16 bit unsigned)
00272 7                                   0   0   0   0     CRC(0x0)
00273 */    
00274 /*   
00275     //Returns 0x0b as per AP520_004 
00276     C[0] = 0x3132;
00277     C[1] = 0x3334;
00278     C[2] = 0x3536;
00279     C[3] = 0x3738;
00280     C[4] = 0x3940;
00281     C[5] = 0x4142;
00282     C[6] = 0x4344;
00283     C[7] = 0x4546;
00284     n_crc = ms.crc4(C); // calculate the CRC
00285     pc.printf("testing CRC: 0x%x\n", n_crc);
00286 */
00287 
00288 //********************************************************
00289 //! @brief load all calibration coefficients
00290 //!
00291 //! @return none
00292 //********************************************************
00293 
00294 void ms5611::loadCoefs() {
00295     for (int i = 0; i < 8; i++){ 
00296         wait_ms(50);
00297         C[i] = cmd_prom(i);
00298     }
00299     uint8_t n_crc = crc4(C);
00300 }
00301 
00302 //********************************************************
00303 //! @brief calculate temperature and pressure
00304 //!
00305 //! @return none
00306 //********************************************************   
00307      
00308 uint8_t ms5611::calcPT() {
00309     if( step & 0b11 ){ // or 0b1 either 0b10
00310         D2 = cmd_adc(MS5611_CMD_ADC_D2 + MS5611_CMD_ADC_2048); // read D2
00311     }
00312     if( step & 0b1100 ){ // or 0b10 either 0b100 
00313         D1 = cmd_adc(MS5611_CMD_ADC_D1 + MS5611_CMD_ADC_2048); // read D1
00314     }
00315     if( step & 0b10000 ){
00316         int64_t dT = D2 - ((uint64_t)C[5] << 8);
00317         int64_t OFF  = ((uint32_t)C[2] << 16) + ((dT * (C[4]) >> 7));     //was  OFF  = (C[2] << 17) + dT * C[4] / (1 << 6);
00318         int64_t SENS = ((uint32_t)C[1] << 15) + ((dT * (C[3]) >> 8));     //was  SENS = (C[1] << 16) + dT * C[3] / (1 << 7);
00319         int32_t TEMP = 2000 + (int64_t)dT * (int64_t)C[6] / (int64_t)(1 << 23);
00320         T = (double) TEMP / 100.0;
00321 
00322         if(TEMP < 2000) { // if temperature lower than +20 Celsius
00323             int64_t T1 = ((int64_t)TEMP - 2000) * ((int64_t)TEMP - 2000);
00324             int64_t OFF1  = (5 * T1) >> 1;
00325             int64_t SENS1 = (5 * T1) >> 2;
00326 
00327             if(TEMP < -1500) { // if temperature lower than -15 Celsius
00328                 T1 = ((int64_t)TEMP + 1500) * ((int64_t)TEMP + 1500);
00329                 OFF1  +=  7 * T1;
00330                 SENS1 += 11 * T1 >> 1;
00331             } 
00332             OFF -= OFF1;
00333             SENS -= SENS1;
00334         }
00335         P = (double)(((((int64_t)D1 * SENS ) >> 21) - OFF) / (double) (1 << 15)) / 100.0;
00336         step = 1;
00337         return 1;
00338     }
00339     return 0;
00340 }
00341 
00342 //********************************************************
00343 //! @brief calculate temperature
00344 //!
00345 //! @return double temperature degC
00346 //********************************************************  
00347 
00348 double ms5611::calcTemp() {
00349     calcPT();
00350     return(T);
00351 } 
00352 
00353 //********************************************************
00354 //! @brief calculate pressure
00355 //!
00356 //! @return double barometric pressure millibar
00357 //********************************************************  
00358 
00359 double ms5611::calcPressure() {
00360     calcPT();
00361     return(P);
00362 } 
00363 
00364 //********************************************************
00365 //! @brief get pressure, no calculation
00366 //!
00367 //! @return double barometric pressure millibar
00368 //********************************************************  
00369 
00370 double ms5611::getPressure() {
00371     //calcPT();
00372     return(P);
00373 } 
00374 
00375 float ms5611::getAltitude() {
00376     A = (1 - pow(P/(double)1013.250, 0.190295)) * 44330.0;
00377     //A = (1 - (pow((P / (double)sea_pressure), 0.190284))) * 145366.45;
00378     return((float)A);
00379 } 
00380 
00381 //********************************************************
00382 //! @brief get altitude from known sea level barometer, 
00383 //! @      no pre-pressure calculation
00384 //!
00385 //! @enter float sea level barometer
00386 //! @return float altitude in feet
00387 //********************************************************  
00388 
00389 float ms5611::getAltitudeFT(float sea_pressure) {
00390     A = (1 - (pow((P / (double)sea_pressure), 0.190284))) * 145366.45;
00391     return((float)A);
00392 } 
00393 
00394 //********************************************************
00395 //! @brief get sea level pressure from known altitude(ft), 
00396 //! @      no pre-pressure calculation
00397 //!
00398 //! @enter float known altitude in feet
00399 //! @return float seal level barometer in mb
00400 //********************************************************  
00401 
00402 float ms5611::getSeaLevelBaroFT(float known_alt) {
00403     S = pow(pow((P * INHG), 0.190284) + 0.00001313 * known_alt , 5.2553026) * MB;
00404     return((float)S);
00405 } 
00406 
00407 //********************************************************
00408 //! @brief get sea level pressure from known altitude(m), 
00409 //! @      no pre-pressure calculation
00410 //!
00411 //! @enter float known altitude in meters
00412 //! @return float seal level barometer in mb
00413 //********************************************************  
00414 
00415 float ms5611::getSeaLevelBaroM(float known_alt) {
00416     S = pow(pow((P * INHG), 0.190284) + 0.00001313 * known_alt * FTMETERS , 5.2553026) * MB;
00417     return((float)S);
00418 }