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