Oxford CWM Team / MS5637

Fork of MS5637 by chris stevens

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers ms5637.cpp Source File

ms5637.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 "ms5637.h"
00018 //Serial pc2(USBTX, USBRX);
00019 
00020 double P;                       // compensated pressure value (mB)
00021 double T;                       // compensated temperature value (degC)
00022 double A;                       // altitude (ft)
00023 double S;                       // sea level barometer (mB)
00024 
00025 uint32_t C[8];                  //coefficient storage
00026 
00027 //--------------------------------------------------------------------------------------------------------------------------------------//
00028 // Constructor and destructor
00029 
00030 ms5637::ms5637(PinName sda, PinName scl)  : _i2c(sda, scl) {
00031         _i2c.frequency(400000);
00032 }
00033 
00034 //********************************************************
00035 //! @brief send I2C start condition and the address byte
00036 //!
00037 //! @return 0
00038 //********************************************************
00039 
00040 int ms5637::m_i2c_start(bool readMode) {
00041     int twst;
00042     _i2c.start();
00043     if(readMode == true) {
00044         twst = m_i2c_write(MS5637_ADDR_R);
00045     } else {
00046         twst = m_i2c_write(MS5637_ADDR_W);
00047     }
00048     return(twst);
00049 }
00050 
00051 //********************************************************
00052 //! @brief send I2C stop condition
00053 //!
00054 //! @return none
00055 //********************************************************
00056 
00057 void ms5637::m_i2c_stop(void) {
00058     _i2c.stop();
00059 }
00060 
00061 //********************************************************
00062 //! @brief send I2C stop condition
00063 //!
00064 //! @return remote ack status
00065 //********************************************************
00066 
00067 unsigned char ms5637::m_i2c_write(unsigned char data) {
00068     int twst = _i2c.write(data);
00069     return(twst);
00070 }
00071 
00072 //********************************************************
00073 //! @brief read I2C byte with acknowledgment
00074 //!
00075 //! @return read byte
00076 //********************************************************
00077 
00078 unsigned char ms5637::m_i2c_readAck(void) {
00079     int twst = _i2c.read(1);
00080     return(twst);
00081 }
00082 
00083 //********************************************************
00084 //! @brief read I2C byte without acknowledgment
00085 //!
00086 //! @return read byte
00087 //********************************************************
00088 
00089 unsigned char ms5637::m_i2c_readNak(void) {
00090     int twst = _i2c.read(0);
00091     return(twst);
00092 }
00093 
00094 //********************************************************
00095 //! @brief send command using I2C hardware interface
00096 //!
00097 //! @return none
00098 //********************************************************
00099 
00100 void ms5637::m_i2c_send(char cmd) {
00101     unsigned char ret;
00102     ret = m_i2c_start(false);
00103     if(!(ret)) {
00104         m_i2c_stop();
00105     } else {
00106         ret = m_i2c_write(cmd);
00107         m_i2c_stop();
00108     }
00109 }
00110 
00111 //********************************************************
00112 //! @brief send reset sequence
00113 //!
00114 //! @return none
00115 //********************************************************
00116 
00117 void ms5637::cmd_reset() {
00118     m_i2c_send(MS5637_CMD_RESET);
00119     wait_ms(4);
00120     loadCoefs();
00121 }
00122 
00123 //********************************************************
00124 //! @brief preform adc conversion
00125 //!
00126 //! @return 24bit result
00127 //********************************************************
00128 
00129 unsigned long ms5637::cmd_adc(char cmd) {
00130     char cobuf[3];
00131     cobuf[0] = 0;
00132     cobuf[1] = 0;
00133     cobuf[2] = 0;
00134     unsigned int ret;
00135     unsigned long temp = 0;
00136     m_i2c_send(MS5637_CMD_ADC_CONV + cmd);
00137     switch (cmd & 0x0f) {
00138         case MS5637_CMD_ADC_256 : wait_us(900); break;
00139         case MS5637_CMD_ADC_512 : wait_ms(3); break;
00140         case MS5637_CMD_ADC_1024: wait_ms(4); break;
00141         case MS5637_CMD_ADC_2048: wait_ms(6); break;
00142         case MS5637_CMD_ADC_4096: wait_ms(10); break;
00143     }
00144     m_i2c_send(MS5637_CMD_ADC_READ);
00145     
00146     ret = _i2c.read(MS5637_ADDR_R, cobuf, 3, false);
00147     if(ret) printf("\n*** ms5637 ADC Read Error ");
00148     temp = (cobuf[0] << 16) + (cobuf[1] << 8) + cobuf[2];
00149     return temp;
00150 }
00151 
00152 //********************************************************
00153 //! @brief Read calibration coefficients
00154 //!
00155 //! @return coefficient
00156 //********************************************************
00157 
00158 unsigned int ms5637::cmd_prom(char coef_num) {
00159     char cobuf[2];
00160     unsigned int ret;
00161     unsigned int rC = 0;
00162     cobuf[0] = 0;
00163     cobuf[1] = 0;
00164     m_i2c_send(MS5637_CMD_PROM_RD + coef_num * 2); // send PROM READ command
00165     ret = _i2c.read(MS5637_ADDR_R, cobuf, 2, false);
00166     if(ret) printf("\n*** ms5637 PROM Read Error ");
00167     rC = cobuf[0] * 256 + cobuf[1];
00168     return rC;
00169 }
00170 
00171 //********************************************************
00172 //! @brief calculate the CRC code
00173 //!
00174 //! @return crc code
00175 //********************************************************
00176 
00177 unsigned char ms5637::crc4(unsigned int n_prom[]) {
00178     unsigned int n_rem;
00179     unsigned int crc_read;
00180     unsigned char n_bit;
00181     n_rem = 0x00;
00182     crc_read = n_prom[7];
00183     n_prom[7]=(0xFF00 & (n_prom[7]));
00184     for (int cnt = 0; cnt < 16; cnt++) {
00185             if (cnt%2 == 1) {
00186                 n_rem ^= (unsigned short) ((n_prom[cnt>>1]) & 0x00FF);
00187             } else {
00188                 n_rem ^= (unsigned short) (n_prom[cnt>>1]>>8);
00189             }
00190             for (n_bit = 8; n_bit > 0; n_bit--) {
00191                 if (n_rem & (0x8000)) {
00192                     n_rem = (n_rem << 1) ^ 0x3000;
00193                 } else {
00194                     n_rem = (n_rem << 1);
00195                 }
00196             }
00197         }
00198     n_rem= (0x000F & (n_rem >> 12));
00199     n_prom[7]=crc_read;
00200     return (n_rem ^ 0x0);
00201 }
00202 
00203 /*
00204 The CRC code is calculated and written in factory with the LSB byte in the prom n_prom[7] set to 0x00 (see
00205 Coefficient table below). It is thus important to clear those bytes from the calculation buffer before proceeding
00206 with the CRC calculation itself:
00207 n_prom[7]=(0xFF00 & (n_prom[7])); //CRC byte is replaced by 0
00208 As a simple test of the CRC code, the following coefficient table could be used:
00209 unsigned int nprom[] = {0x3132,0x3334,0x3536,0x3738,0x3940,0x4142,0x4344,0x4500};
00210 the resulting calculated CRC should be 0xB.
00211 
00212 DB  15  14  13  12  11  10  9   8   7   6   5   4   3   2   1   0 
00213 Addr
00214 0               16 bit reserved for manufacturer
00215 1               Coefficient 1 (16 bit unsigned)
00216 2               Coefficient 2 (16 bit unsigned)
00217 3               Coefficient 3 (16 bit unsigned)
00218 4               Coefficient 4 (16 bit unsigned)
00219 5               Coefficient 5 (16 bit unsigned)
00220 6               Coefficient 6 (16 bit unsigned)
00221 7                                   0   0   0   0     CRC(0x0)
00222 */    
00223 /*   
00224     //Returns 0x0b as per AP520_004 
00225     C[0] = 0x3132;
00226     C[1] = 0x3334;
00227     C[2] = 0x3536;
00228     C[3] = 0x3738;
00229     C[4] = 0x3940;
00230     C[5] = 0x4142;
00231     C[6] = 0x4344;
00232     C[7] = 0x4546;
00233     n_crc = ms.crc4(C); // calculate the CRC
00234     pc.printf("testing CRC: 0x%x\n", n_crc);
00235 */
00236 
00237 //********************************************************
00238 //! @brief load all calibration coefficients
00239 //!
00240 //! @return none
00241 //********************************************************
00242 
00243 void ms5637::loadCoefs() {
00244     for (int i = 0; i < 8; i++){ 
00245         wait_ms(50);
00246         C[i] = cmd_prom(i);
00247     }
00248     unsigned char n_crc = crc4(C);
00249 }
00250 
00251 //********************************************************
00252 //! @brief calculate temperature and pressure
00253 //!
00254 //! @return none
00255 //********************************************************   
00256      
00257 void ms5637::calcPT() {
00258     int32_t D2 = cmd_adc(MS5637_CMD_ADC_D2 + MS5637_CMD_ADC_4096); // read D2
00259     int32_t D1 = cmd_adc(MS5637_CMD_ADC_D1 + MS5637_CMD_ADC_4096); // read D1
00260 
00261     float dT = (float)D2 - ((float)C[5] * 256.0);
00262     float TEMP = 2000.0 + (dT*(float)C[6])/8388608.0;
00263     
00264     float OFF  = ((float)C[2] * 131072.0 + (dT * (float)C[4])/64.0);
00265     float SENS = ((float)C[1] * 65536.0)+ ((dT * ((float)C[3]) /128.0));
00266     
00267     // Commented out serial pc2 at start of code so you can check raw values
00268     //pc2.printf("D1: %d\r\nD2: %d\r\nC1: %d\r\nC2: %d\r\nC3: %d\r\nC4: %d\r\nC5: %d\r\nC6: %d\r\n", D1, D2, C[1], C[2], C[3], C[4], C[5], C[6]);
00269     //pc2.printf("OFF: %f\r\nSENS: %f\r\n",OFF, SENS);
00270 
00271 if(TEMP < 2000) { // if temperature lower than 20 Celsius
00272         float T1 = (TEMP - 2000.0) * (TEMP - 2000.0);
00273         float OFF1  = (61.0 * T1) / 16.0;
00274         float SENS1 = (29.0 * T1) / 16.0;
00275  
00276         if(TEMP < -1500) { // if temperature lower than -15 Celsius
00277             T1 = (TEMP + 1500.0) * (TEMP + 1500.0);
00278             OFF1  += 17.0 * T1;
00279             SENS1 += 9.0 * T1 ;
00280         } 
00281         OFF -= OFF1;
00282         SENS -= SENS1;
00283     }
00284         T = TEMP / 100.0;
00285         P = ((D1*(SENS / 2097152.0)-OFF)/32768.0)/100.0;
00286 }
00287 
00288 //********************************************************
00289 //! @brief calculate temperature
00290 //!
00291 //! @return double temperature degC
00292 //********************************************************  
00293 
00294 double ms5637::calcTemp() {
00295     calcPT();
00296     return(T);
00297 } 
00298 
00299 //********************************************************
00300 //! @brief calculate pressure
00301 //!
00302 //! @return double barometric pressure millibar
00303 //********************************************************  
00304 
00305 double ms5637::calcPressure() {
00306     calcPT();
00307     return(P);
00308 } 
00309 
00310 //********************************************************
00311 //! @brief get pressure, no calculation
00312 //!
00313 //! @return double barometric pressure millibar
00314 //********************************************************  
00315 
00316 double ms5637::getPressure() {
00317     calcPT();
00318     return(P);
00319 } 
00320 
00321 //********************************************************
00322 //! @brief get altitude from known sea level barometer, 
00323 //! @      no pre-pressure calculation
00324 //!
00325 //! @enter float sea level barometer
00326 //! @return float altitude in feet
00327 //********************************************************  
00328 
00329 float ms5637::getAltitudeFT(float sea_pressure) {
00330     A = (1 - (pow((P / (double)sea_pressure), 0.190284))) * 145366.45;
00331     return((float)A);
00332 } 
00333 
00334 //********************************************************
00335 //! @brief get sea level pressure from known altitude(ft), 
00336 //! @      no pre-pressure calculation
00337 //!
00338 //! @enter float known altitude in feet
00339 //! @return float seal level barometer in mb
00340 //********************************************************  
00341 
00342 float ms5637::getSeaLevelBaroFT(float known_alt) {
00343     S = pow(pow((P * INHG), 0.190284) + 0.00001313 * known_alt , 5.2553026) * MB;
00344     return((float)S);
00345 } 
00346 
00347 //********************************************************
00348 //! @brief get sea level pressure from known altitude(m), 
00349 //! @      no pre-pressure calculation
00350 //!
00351 //! @enter float known altitude in meters
00352 //! @return float seal level barometer in mb
00353 //********************************************************  
00354 
00355 float ms5637::getSeaLevelBaroM(float known_alt) {
00356     S = pow(pow((P * INHG), 0.190284) + 0.00001313 * known_alt * FTMETERS , 5.2553026) * MB;
00357     return((float)S);
00358 }