Jens Schneider / BME280
Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers BME280.cpp Source File

BME280.cpp

00001 /*****************************************************************************
00002  *                                                                           *
00003  * BOSCH BME208 Temperature Pressure Humidity Sensor Driver / I2C            *
00004  *                                                                           *
00005  * (c) 2015 Jens Schneider                                                   *
00006  * mailto:jens.schneider@kaust.edu.sa                                        *
00007  * Visual Computing Center (VCC)                                             *
00008  * King Abdullah University of Science and Technology (KAUST)                *
00009  * 4700 Thuwal, Kingdom of Saudi Arabia                                      *
00010  *                                                                           *
00011  * PERMISSION GRANTED TO USE IN NON-COMMERCIAL AND EDUCATIONAL PROJECTS      *
00012  * NO RESPONSIBILITY ASSUMED FOR DAMAGE OR LOSS OF ANY HARDWARE OR SOFTWARE  *
00013  *                                                                           *
00014  * version 0.1                                                               *
00015  * last change 07.Nov.2015                                                   *
00016  *                                                                           *
00017  *****************************************************************************/
00018 #include"BME280.h"
00019 
00020 const uint8_t BME280::REG_HUM_LSB           = 0xFE;
00021 const uint8_t BME280::REG_HUM_MSB           = 0xFD;
00022 const uint8_t BME280::REG_TEMP_XLSB         = 0xFC;
00023 const uint8_t BME280::REG_TEMP_LSB          = 0xFB;
00024 const uint8_t BME280::REG_TEMP_MSB          = 0xFA;
00025 const uint8_t BME280::REG_PRESS_XLSB        = 0xF9;
00026 const uint8_t BME280::REG_PRESS_LSB         = 0xF8;
00027 const uint8_t BME280::REG_PRESS_MSB         = 0xF7;
00028 
00029 const uint8_t BME280::REG_CONFIG            = 0xF5;
00030 const uint8_t BME280::REG_CTRL_MEAS         = 0xF4;
00031 const uint8_t BME280::REG_STATUS            = 0xF3;
00032 const uint8_t BME280::REG_CTRL_HUM          = 0xF2;
00033 const uint8_t BME280::REG_CALIB26_41_BASE   = 0xE1;
00034 const uint8_t BME280::REG_RESET             = 0xE0;
00035 const uint8_t BME280::REG_ID                = 0xD0;
00036 const uint8_t BME280::REG_CALIB00_25_BASE   = 0x88;
00037 
00038 const uint8_t BME280::VAL_CALIB26_41_SIZE   = 0x10;
00039 const uint8_t BME280::VAL_CALIB00_25_SIZE   = 0x1A;
00040 const uint8_t BME280::VAL_CHIP_ID           = 0x60;
00041 const uint8_t BME280::VAL_RESET             = 0xB6;
00042 
00043 const uint8_t BME280::STATUS_IDLE           = 0x00;
00044 const uint8_t BME280::STATUS_MEASURING      = 0x08;
00045 const uint8_t BME280::STATUS_UPDATING       = 0x01;
00046 const uint8_t BME280::STATUS_ERROR          = 0xFF;
00047 
00048 const std::string BME280::m_name = std::string("Bosch BME280");
00049 
00050 BME280::BME280(void) : m_pI2C(NULL), m_address(0x00), m_fine_temp(0x1F3E6), m_mode(MODE_SLEEP),m_bOk(false) {
00051     // initialized m_fine_temp to 25C
00052 }
00053 
00054 BME280::~BME280(void) {
00055     done();
00056 }
00057 
00058 bool BME280::init(I2C& i2c, uint8_t address) {
00059     m_bOk = false;
00060     m_pI2C = &i2c;
00061     m_address = address<<1;
00062     m_fine_temp = 0x1F3E6;
00063     if (!reset()) return false;    
00064     if (read_chip_id()!=0x60) return false;    
00065     if (!read_calibration()) return false;    
00066     m_bOk = true;
00067     return true;
00068 }
00069 
00070 const bool& BME280::is_ok(void) const {
00071     return m_bOk;
00072 }
00073 
00074 bool BME280::done(void) {
00075     stop();
00076     m_pI2C = NULL;
00077     m_address = 0x00;
00078     m_mode = MODE_SLEEP;
00079     return true;
00080 }
00081 
00082 
00083 bool BME280::start( BME280::sampling_t hum, 
00084                     BME280::sampling_t temp, 
00085                     BME280::sampling_t press,
00086                     BME280::standby_t standby,
00087                     BME280::filter_t filter,
00088                     BME280::mode_t mode) {
00089     // 1. Reset
00090     if (!reset()) return false;
00091     
00092     // 2. Write CONFIG
00093     uint8_t val_cfg = uint8_t(standby)<<5;
00094     val_cfg|=uint8_t(filter)<<2;
00095     if (!write8(REG_CONFIG,val_cfg)) return false;    
00096     
00097     // 3. Write CTRL_HUM
00098     if (!write8(REG_CTRL_HUM,uint8_t(hum))) return false;
00099 
00100     // 4. Write CTRL_MEAS
00101     uint8_t val_meas = uint8_t(temp)<<5;
00102     val_meas |= uint8_t(press)<<2;
00103     val_meas |= uint8_t(mode);
00104     if (!write8(REG_CTRL_MEAS,val_meas)) return false;
00105     
00106     m_mode = mode;
00107     m_bOk  = true;
00108     
00109     return true;
00110 }
00111 
00112 bool BME280::stop(void) {
00113     return reset();
00114 }
00115 
00116 bool BME280::get(float& temperature, float& pressure, float& humidity) {
00117     int32_t T;
00118     uint32_t P, H;
00119     if (!get(T,P,H)) return false;
00120     temperature = float(T)*0.01f;           // in degree C
00121     pressure    = 0.01f*(float(P)/256.0f);  // in hPa / mbar
00122     humidity    = float(H)/1024.0f;         // in %
00123     return true;
00124 }
00125 
00126 bool BME280::get(int32_t& temperature, uint32_t& pressure, uint32_t& humidity) {
00127     if (m_mode!=MODE_AUTO) {
00128         // Trigger forced conversion by updating CTRL_MEAS register
00129         uint8_t val = 0x00;
00130         if (!read8(REG_CTRL_MEAS,val)) return false;
00131         val = (val&0xFC)|uint8_t(MODE_FORCED);
00132         if (!write8(REG_CTRL_MEAS,val)) return false;
00133         // Wait for measurement to finish
00134         do {
00135             val = read_status();
00136             if ((val&STATUS_MEASURING)!=0) wait_ms(1);
00137         }  while(val&STATUS_MEASURING);
00138     }
00139     int32_t rawT, rawP, rawH;
00140     if (!raw_data(rawT,rawP,rawH)) return false;
00141     temperature = compensate_T(rawT);
00142     pressure = compensate_P(rawP);
00143     humidity = compensate_H(rawH);
00144     return true;
00145 }
00146 
00147 const std::string& BME280::name(void) const {
00148     return m_name;
00149 }
00150 
00151 bool BME280::raw_data(int32_t& rawT, int32_t& rawP, int32_t& rawH) {
00152     if (m_pI2C==NULL) return false;
00153     uint8_t data[8];
00154     if (!burst_read(data,8,REG_PRESS_MSB)) {
00155         rawT = rawP = rawH = 0;
00156         return false;
00157     }
00158     rawP = (int32_t(data[0])<<12)|(int32_t(data[1])<<4)|(int32_t(data[2])>>4);
00159     rawT = (int32_t(data[3])<<12)|(int32_t(data[4])<<4)|(int32_t(data[5])>>4);
00160     rawH = (int32_t(data[6])<<8)|int32_t(data[7]);
00161     return true;
00162 }
00163         
00164 
00165 int16_t BME280::conv_s16(const uint8_t* data, int lo, int hi) const {
00166     return int16_t(uint16_t(data[lo])|(uint16_t(data[hi])<<8));
00167 }
00168 
00169 uint16_t BME280::conv_u16(const uint8_t* data, int lo, int hi) const {
00170     return uint16_t(data[lo])|(uint16_t(data[hi])<<8);
00171 }
00172 
00173 bool BME280::read_calibration(void) {
00174     if (m_pI2C==NULL) return false;
00175     return read_calibration_lo() && read_calibration_hi();
00176 }
00177 
00178 bool BME280::read_calibration_lo(void) {
00179     if (m_pI2C==NULL) return false;
00180     uint8_t data[VAL_CALIB00_25_SIZE];
00181     if (!burst_read(data,VAL_CALIB00_25_SIZE,REG_CALIB00_25_BASE)) return false;
00182     m_calib.dig_T1 = conv_u16(data,0,1);    // 0x88:89
00183     m_calib.dig_T2 = conv_s16(data,2,3);    // 0x8A:8B
00184     m_calib.dig_T3 = conv_s16(data,4,5);    // 0x8C:8D
00185     m_calib.dig_P1 = conv_u16(data,6,7);    // 0x8E:8F
00186     m_calib.dig_P2 = conv_s16(data,8,9);    // 0x90:91
00187     m_calib.dig_P3 = conv_s16(data,10,11);  // 0x92:93
00188     m_calib.dig_P4 = conv_s16(data,12,13);  // 0x94:95
00189     m_calib.dig_P5 = conv_s16(data,14,15);  // 0x96:97
00190     m_calib.dig_P6 = conv_s16(data,16,17);  // 0x98:99
00191     m_calib.dig_P7 = conv_s16(data,18,19);  // 0x9A:9B
00192     m_calib.dig_P8 = conv_s16(data,20,21);  // 0x9C:9D
00193     m_calib.dig_P9 = conv_s16(data,22,23);  // 0x9E:9F
00194                                             // 0xA0
00195     m_calib.dig_H1 = data[25];              // 0xA1
00196     return true;
00197 }
00198 
00199 bool BME280::read_calibration_hi(void) {
00200     if (m_pI2C==NULL) return false;
00201     uint8_t data[VAL_CALIB26_41_SIZE];
00202     if (!burst_read(data,VAL_CALIB26_41_SIZE,REG_CALIB26_41_BASE)) return false;
00203     m_calib.dig_H2 = conv_s16(data,0,1);                                            // 0xE1:E2
00204     m_calib.dig_H3 = data[2];                                                       // 0xE3
00205     m_calib.dig_H4 = int16_t((uint16_t(data[3])<<8)|uint16_t((data[4]&0xF)<<4))>>4; // 0xE4:E5[3:0]
00206     m_calib.dig_H5 = int16_t((uint16_t(data[5])<<8)|uint16_t((data[4]&0xF0))>>4);   // 0xE5[7:4]:E6
00207     m_calib.dig_H6 = int8_t(data[6]);                                               // 0xE7
00208     return true;
00209 }
00210 
00211 int32_t BME280::compensate_T(int32_t raw_T) {
00212     int32_t var1, var2, T;
00213     var1 = ((((raw_T>>3) - ((int32_t)m_calib.dig_T1<<1))) * ((int32_t)m_calib.dig_T2)) >> 11;    
00214     var2 = (((((raw_T>>4) - ((int32_t)m_calib.dig_T1)) * ((raw_T>>4) - ((int32_t)m_calib.dig_T1))) >> 12) * ((int32_t)m_calib.dig_T3)) >> 14;
00215     m_fine_temp = var1 + var2;
00216     T = (m_fine_temp * 5 + 128) >> 8;
00217     return T;
00218 }
00219 
00220 uint32_t BME280::compensate_P(int32_t raw_P) {
00221     int64_t var1, var2, p;
00222     var1 = ((int64_t)m_fine_temp) - 128000;
00223     var2 = var1 * var1 * (int64_t)m_calib.dig_P6;
00224     var2 = var2 + ((var1*(int64_t)m_calib.dig_P5)<<17);
00225     var2 = var2 + (((int64_t)m_calib.dig_P4)<<35);
00226     var1 = ((var1 * var1 * (int64_t)m_calib.dig_P3)>>8) + ((var1 * (int64_t)m_calib.dig_P2)<<12);
00227     var1 = (((((int64_t)1)<<47)+var1))*((int64_t)m_calib.dig_P1)>>33;
00228     if (var1 == 0) return false; // avoid division by zero
00229     p = 1048576-raw_P;
00230     p = (((p<<31)-var2)*3125)/var1;
00231     var1 = (((int64_t)m_calib.dig_P9) * (p>>13) * (p>>13)) >> 25;
00232     var2 = (((int64_t)m_calib.dig_P8) * p) >> 19;
00233     p = ((p + var1 + var2) >> 8) + (((int64_t)m_calib.dig_P7)<<4);
00234     return (uint32_t)p;
00235 }
00236 
00237 uint32_t BME280::compensate_H(int32_t raw_H) {
00238     int32_t v_x1_u32r;
00239     v_x1_u32r = (m_fine_temp - ((int32_t)76800));
00240     v_x1_u32r = (((((raw_H << 14) - (((int32_t)m_calib.dig_H4) << 20) - (((int32_t)m_calib.dig_H5) * v_x1_u32r)) +
00241                 ((int32_t)16384)) >> 15) * (((((((v_x1_u32r * ((int32_t)m_calib.dig_H6)) >> 10) * (((v_x1_u32r * 
00242                 ((int32_t)m_calib.dig_H3)) >> 11) + ((int32_t)32768))) >> 10) + ((int32_t)2097152)) *
00243                 ((int32_t)m_calib.dig_H2) + 8192) >> 14));
00244     v_x1_u32r = (v_x1_u32r - (((((v_x1_u32r >> 15) * (v_x1_u32r >> 15)) >> 7) * ((int32_t)m_calib.dig_H1)) >> 4));
00245     v_x1_u32r = (v_x1_u32r < 0 ? 0 : v_x1_u32r);
00246     v_x1_u32r = (v_x1_u32r > 419430400 ? 419430400 : v_x1_u32r);
00247     return (uint32_t)(v_x1_u32r>>12);
00248 }
00249 
00250 // ======================================== LOW LEVEL API ========================================
00251 bool BME280::reset(void) {
00252     m_bOk = false;
00253     if (write8(REG_RESET,VAL_RESET)) {
00254         wait_ms(2);
00255         m_mode = MODE_SLEEP;
00256         return true;
00257     }
00258     return false;
00259 }
00260 
00261 uint8_t BME280::read_chip_id(void) {
00262     uint8_t result;
00263     if (read8(REG_ID,result)) return result;
00264     else return 0x00;
00265 }
00266 
00267 uint8_t BME280::read_status(void) {
00268     uint8_t result;
00269     if (read8(REG_STATUS,result)) return result&0x9;
00270     else return STATUS_ERROR;
00271 }
00272 
00273 bool BME280::read8(uint8_t reg, uint8_t& val) {
00274     if (m_pI2C==NULL) return false;
00275     uint8_t ok = 0x00;
00276     val = 0x00;
00277     m_pI2C->start();
00278         ok = (ok<<1)|m_pI2C->write(m_address);
00279         ok = (ok<<1)|m_pI2C->write(reg);
00280         m_pI2C->start();
00281         ok = (ok<<1)|m_pI2C->write(m_address|1);
00282         val = m_pI2C->read(0);
00283     m_pI2C->stop();
00284     return ok==0x7;
00285 }
00286 
00287 bool BME280::write8(uint8_t reg, uint8_t val) {
00288     if (m_pI2C==NULL) return false;
00289     uint8_t ok = 0x00;
00290     m_pI2C->start();
00291         ok = (ok<<1)|m_pI2C->write(m_address);
00292         ok = (ok<<1)|m_pI2C->write(reg);
00293         ok = (ok<<1)|m_pI2C->write(val);
00294     m_pI2C->stop();
00295     return ok==0x7;
00296 }
00297 
00298 const BME280::calib_t& BME280::calib(void) const {
00299     return m_calib;
00300 }
00301 
00302 bool BME280::burst_read(uint8_t* data, uint8_t nBytes, uint8_t reg) {
00303     if (m_pI2C==NULL) return false;
00304     if (nBytes==0) return false;
00305     if (data==NULL) return false;
00306     uint8_t ok = 0x00;
00307     m_pI2C->start();
00308         ok = (ok<<1)|m_pI2C->write(m_address);
00309         ok = (ok<<1)|m_pI2C->write(reg);
00310         m_pI2C->start();
00311         ok = (ok<<1)|m_pI2C->write(m_address|1);
00312         for (int i=0; i<nBytes-1; i++) data[i] = m_pI2C->read(1);
00313         data[nBytes-1] = m_pI2C->read(0);
00314     m_pI2C->stop();
00315     if (ok!=0x7) {
00316         memset(data,0,nBytes);
00317         return false;
00318     }
00319     return true;
00320 }