Important changes to repositories hosted on mbed.com
Mbed hosted mercurial repositories are deprecated and are due to be permanently deleted in July 2026.
To keep a copy of this software download the repository Zip archive or clone locally using Mercurial.
It is also possible to export all your personal repositories from the account settings page.
Fork of ms5611 by
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 }
Generated on Sun Jul 17 2022 09:44:22 by
