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.
Dependents: MERGE Sensor_iAQ_sgp30_bme_si7051 POCBreath_V2_smd_commercial
BME680.cpp
00001 /** 00002 * @brief BME680.cpp 00003 * @details Low power gas, pressure, temperature & humidity sensor. 00004 * Function file. 00005 * 00006 * 00007 * @return N/A 00008 * 00009 * @author Manuel Caballero 00010 * @date 21/July/2018 00011 * @version 21/July/2018 The ORIGIN 00012 * @pre This is just a port from Bosh driver to mBed ( c++ ) 00013 * @warning N/A 00014 * @pre This code belongs to Nimbus Centre ( http://www.nimbus.cit.ie ). 00015 */ 00016 /**\mainpage 00017 * Copyright (C) 2017 - 2018 Bosch Sensortec GmbH 00018 * 00019 * Redistribution and use in source and binary forms, with or without 00020 * modification, are permitted provided that the following conditions are met: 00021 * 00022 * Redistributions of source code must retain the above copyright 00023 * notice, this list of conditions and the following disclaimer. 00024 * 00025 * Redistributions in binary form must reproduce the above copyright 00026 * notice, this list of conditions and the following disclaimer in the 00027 * documentation and/or other materials provided with the distribution. 00028 * 00029 * Neither the name of the copyright holder nor the names of the 00030 * contributors may be used to endorse or promote products derived from 00031 * this software without specific prior written permission. 00032 * 00033 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND 00034 * CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 00035 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED 00036 * WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE 00037 * DISCLAIMED. IN NO EVENT SHALL COPYRIGHT HOLDER 00038 * OR CONTRIBUTORS BE LIABLE FOR ANY 00039 * DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, 00040 * OR CONSEQUENTIAL DAMAGES(INCLUDING, BUT NOT LIMITED TO, 00041 * PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; 00042 * LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 00043 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, 00044 * WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 00045 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN 00046 * ANY WAY OUT OF THE USE OF THIS 00047 * SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE 00048 * 00049 * The information provided is believed to be accurate and reliable. 00050 * The copyright holder assumes no responsibility 00051 * for the consequences of use 00052 * of such information nor for any infringement of patents or 00053 * other rights of third parties which may result from its use. 00054 * No license is granted by implication or otherwise under any patent or 00055 * patent rights of the copyright holder. 00056 * 00057 * File bme680.c 00058 * @date 19 Jun 2018 00059 * @version 3.5.9 00060 * 00061 */ 00062 00063 /*! @file bme680.c 00064 @brief Sensor driver for BME680 sensor */ 00065 #include "BME680.h" 00066 00067 BME680::BME680 ( PinName sda, PinName scl, uint32_t freq ) 00068 : _i2c ( sda, scl ) 00069 { 00070 _i2c.frequency ( freq ); 00071 } 00072 00073 00074 BME680::~BME680() 00075 { 00076 } 00077 00078 00079 /****************** Global Function Definitions *******************************/ 00080 /*! 00081 *@brief This API is the entry point. 00082 *It reads the chip-id and calibration data from the sensor. 00083 */ 00084 int8_t BME680::bme680_init(struct bme680_dev *dev) 00085 { 00086 int8_t rslt; 00087 00088 /* Check for null pointer in the device structure*/ 00089 rslt = null_ptr_check(dev); 00090 if (rslt == BME680_OK) { 00091 /* Soft reset to restore it to default values*/ 00092 rslt = bme680_soft_reset(dev); 00093 if (rslt == BME680_OK) { 00094 rslt = bme680_get_regs(BME680_CHIP_ID_ADDR, &dev->chip_id , 1, dev); 00095 if (rslt == BME680_OK) { 00096 if (dev->chip_id == BME680_CHIP_ID) { 00097 /* Get the Calibration data */ 00098 rslt = get_calib_data(dev); 00099 } else { 00100 rslt = BME680_E_DEV_NOT_FOUND; 00101 } 00102 } 00103 } 00104 } 00105 00106 return rslt; 00107 } 00108 00109 /*! 00110 * @brief This API reads the data from the given register address of the sensor. 00111 */ 00112 int8_t BME680::bme680_get_regs(uint8_t reg_addr, uint8_t *reg_data, uint16_t len, struct bme680_dev *dev) 00113 { 00114 int8_t rslt; 00115 00116 /* Check for null pointer in the device structure*/ 00117 rslt = null_ptr_check(dev); 00118 if (rslt == BME680_OK) { 00119 if (dev->intf == BME680_SPI_INTF ) { 00120 /* Set the memory page */ 00121 rslt = set_mem_page(reg_addr, dev); 00122 if (rslt == BME680_OK) 00123 reg_addr = reg_addr | BME680_SPI_RD_MSK; 00124 } 00125 dev->com_rslt = dev->read (dev->dev_id , reg_addr, reg_data, len); 00126 if (dev->com_rslt != 0) 00127 rslt = BME680_E_COM_FAIL; 00128 } 00129 00130 return rslt; 00131 } 00132 00133 /*! 00134 * @brief This API writes the given data to the register address 00135 * of the sensor. 00136 */ 00137 int8_t BME680::bme680_set_regs(const uint8_t *reg_addr, const uint8_t *reg_data, uint8_t len, struct bme680_dev *dev) 00138 { 00139 int8_t rslt; 00140 /* Length of the temporary buffer is 2*(length of register)*/ 00141 uint8_t tmp_buff[BME680_TMP_BUFFER_LENGTH] = { 0 }; 00142 uint16_t index; 00143 00144 /* Check for null pointer in the device structure*/ 00145 rslt = null_ptr_check(dev); 00146 if (rslt == BME680_OK) { 00147 if ((len > 0) && (len < BME680_TMP_BUFFER_LENGTH / 2)) { 00148 /* Interleave the 2 arrays */ 00149 for (index = 0; index < len; index++) { 00150 if (dev->intf == BME680_SPI_INTF ) { 00151 /* Set the memory page */ 00152 rslt = set_mem_page(reg_addr[index], dev); 00153 tmp_buff[(2 * index)] = reg_addr[index] & BME680_SPI_WR_MSK; 00154 } else { 00155 tmp_buff[(2 * index)] = reg_addr[index]; 00156 } 00157 tmp_buff[(2 * index) + 1] = reg_data[index]; 00158 } 00159 /* Write the interleaved array */ 00160 if (rslt == BME680_OK) { 00161 dev->com_rslt = dev->write (dev->dev_id , tmp_buff[0], &tmp_buff[1], (2 * len) - 1); 00162 if (dev->com_rslt != 0) 00163 rslt = BME680_E_COM_FAIL; 00164 } 00165 } else { 00166 rslt = BME680_E_INVALID_LENGTH; 00167 } 00168 } 00169 00170 return rslt; 00171 } 00172 00173 /*! 00174 * @brief This API performs the soft reset of the sensor. 00175 */ 00176 int8_t BME680::bme680_soft_reset(struct bme680_dev *dev) 00177 { 00178 int8_t rslt; 00179 uint8_t reg_addr = BME680_SOFT_RESET_ADDR; 00180 /* 0xb6 is the soft reset command */ 00181 uint8_t soft_rst_cmd = BME680_SOFT_RESET_CMD; 00182 00183 /* Check for null pointer in the device structure*/ 00184 rslt = null_ptr_check(dev); 00185 if (rslt == BME680_OK) { 00186 if (dev->intf == BME680_SPI_INTF ) 00187 rslt = get_mem_page(dev); 00188 00189 /* Reset the device */ 00190 if (rslt == BME680_OK) { 00191 rslt = bme680_set_regs(®_addr, &soft_rst_cmd, 1, dev); 00192 /* Wait for 5ms */ 00193 dev->delay_ms (BME680_RESET_PERIOD); 00194 00195 if (rslt == BME680_OK) { 00196 /* After reset get the memory page */ 00197 if (dev->intf == BME680_SPI_INTF ) 00198 rslt = get_mem_page(dev); 00199 } 00200 } 00201 } 00202 00203 return rslt; 00204 } 00205 00206 /*! 00207 * @brief This API is used to set the oversampling, filter and T,P,H, gas selection 00208 * settings in the sensor. 00209 */ 00210 int8_t BME680::bme680_set_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev) 00211 { 00212 int8_t rslt; 00213 uint8_t reg_addr; 00214 uint8_t data = 0; 00215 uint8_t count = 0; 00216 uint8_t reg_array[BME680_REG_BUFFER_LENGTH] = { 0 }; 00217 uint8_t data_array[BME680_REG_BUFFER_LENGTH] = { 0 }; 00218 uint8_t intended_power_mode = dev->power_mode ; /* Save intended power mode */ 00219 00220 /* Check for null pointer in the device structure*/ 00221 rslt = null_ptr_check(dev); 00222 if (rslt == BME680_OK) { 00223 if (desired_settings & BME680_GAS_MEAS_SEL) 00224 rslt = set_gas_config(dev); 00225 00226 dev->power_mode = BME680_SLEEP_MODE; 00227 if (rslt == BME680_OK) 00228 rslt = bme680_set_sensor_mode(dev); 00229 00230 /* Selecting the filter */ 00231 if (desired_settings & BME680_FILTER_SEL) { 00232 rslt = boundary_check(&dev->tph_sett .filter , BME680_FILTER_SIZE_0, BME680_FILTER_SIZE_127, dev); 00233 reg_addr = BME680_CONF_ODR_FILT_ADDR; 00234 00235 if (rslt == BME680_OK) 00236 rslt = bme680_get_regs(reg_addr, &data, 1, dev); 00237 00238 if (desired_settings & BME680_FILTER_SEL) 00239 data = BME680_SET_BITS(data, BME680_FILTER, dev->tph_sett .filter ); 00240 00241 reg_array[count] = reg_addr; /* Append configuration */ 00242 data_array[count] = data; 00243 count++; 00244 } 00245 00246 /* Selecting heater control for the sensor */ 00247 if (desired_settings & BME680_HCNTRL_SEL) { 00248 rslt = boundary_check(&dev->gas_sett .heatr_ctrl , BME680_ENABLE_HEATER, 00249 BME680_DISABLE_HEATER, dev); 00250 reg_addr = BME680_CONF_HEAT_CTRL_ADDR; 00251 00252 if (rslt == BME680_OK) 00253 rslt = bme680_get_regs(reg_addr, &data, 1, dev); 00254 data = BME680_SET_BITS_POS_0(data, BME680_HCTRL, dev->gas_sett .heatr_ctrl ); 00255 00256 reg_array[count] = reg_addr; /* Append configuration */ 00257 data_array[count] = data; 00258 count++; 00259 } 00260 00261 /* Selecting heater T,P oversampling for the sensor */ 00262 if (desired_settings & (BME680_OST_SEL | BME680_OSP_SEL)) { 00263 rslt = boundary_check(&dev->tph_sett .os_temp , BME680_OS_NONE, BME680_OS_16X, dev); 00264 reg_addr = BME680_CONF_T_P_MODE_ADDR; 00265 00266 if (rslt == BME680_OK) 00267 rslt = bme680_get_regs(reg_addr, &data, 1, dev); 00268 00269 if (desired_settings & BME680_OST_SEL) 00270 data = BME680_SET_BITS(data, BME680_OST, dev->tph_sett .os_temp ); 00271 00272 if (desired_settings & BME680_OSP_SEL) 00273 data = BME680_SET_BITS(data, BME680_OSP, dev->tph_sett .os_pres ); 00274 00275 reg_array[count] = reg_addr; 00276 data_array[count] = data; 00277 count++; 00278 } 00279 00280 /* Selecting humidity oversampling for the sensor */ 00281 if (desired_settings & BME680_OSH_SEL) { 00282 rslt = boundary_check(&dev->tph_sett .os_hum , BME680_OS_NONE, BME680_OS_16X, dev); 00283 reg_addr = BME680_CONF_OS_H_ADDR; 00284 00285 if (rslt == BME680_OK) 00286 rslt = bme680_get_regs(reg_addr, &data, 1, dev); 00287 data = BME680_SET_BITS_POS_0(data, BME680_OSH, dev->tph_sett .os_hum ); 00288 00289 reg_array[count] = reg_addr; /* Append configuration */ 00290 data_array[count] = data; 00291 count++; 00292 } 00293 00294 /* Selecting the runGas and NB conversion settings for the sensor */ 00295 if (desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)) { 00296 rslt = boundary_check(&dev->gas_sett .run_gas , BME680_RUN_GAS_DISABLE, 00297 BME680_RUN_GAS_ENABLE, dev); 00298 if (rslt == BME680_OK) { 00299 /* Validate boundary conditions */ 00300 rslt = boundary_check(&dev->gas_sett .nb_conv , BME680_NBCONV_MIN, 00301 BME680_NBCONV_MAX, dev); 00302 } 00303 00304 reg_addr = BME680_CONF_ODR_RUN_GAS_NBC_ADDR; 00305 00306 if (rslt == BME680_OK) 00307 rslt = bme680_get_regs(reg_addr, &data, 1, dev); 00308 00309 if (desired_settings & BME680_RUN_GAS_SEL) 00310 data = BME680_SET_BITS(data, BME680_RUN_GAS, dev->gas_sett .run_gas ); 00311 00312 if (desired_settings & BME680_NBCONV_SEL) 00313 data = BME680_SET_BITS_POS_0(data, BME680_NBCONV, dev->gas_sett .nb_conv ); 00314 00315 reg_array[count] = reg_addr; /* Append configuration */ 00316 data_array[count] = data; 00317 count++; 00318 } 00319 00320 if (rslt == BME680_OK) 00321 rslt = bme680_set_regs(reg_array, data_array, count, dev); 00322 00323 /* Restore previous intended power mode */ 00324 dev->power_mode = intended_power_mode; 00325 } 00326 00327 return rslt; 00328 } 00329 00330 /*! 00331 * @brief This API is used to get the oversampling, filter and T,P,H, gas selection 00332 * settings in the sensor. 00333 */ 00334 int8_t BME680::bme680_get_sensor_settings(uint16_t desired_settings, struct bme680_dev *dev) 00335 { 00336 int8_t rslt; 00337 /* starting address of the register array for burst read*/ 00338 uint8_t reg_addr = BME680_CONF_HEAT_CTRL_ADDR; 00339 uint8_t data_array[BME680_REG_BUFFER_LENGTH] = { 0 }; 00340 00341 /* Check for null pointer in the device structure*/ 00342 rslt = null_ptr_check(dev); 00343 if (rslt == BME680_OK) { 00344 rslt = bme680_get_regs(reg_addr, data_array, BME680_REG_BUFFER_LENGTH, dev); 00345 00346 if (rslt == BME680_OK) { 00347 if (desired_settings & BME680_GAS_MEAS_SEL) 00348 rslt = get_gas_config(dev); 00349 00350 /* get the T,P,H ,Filter,ODR settings here */ 00351 if (desired_settings & BME680_FILTER_SEL) 00352 dev->tph_sett .filter = BME680_GET_BITS(data_array[BME680_REG_FILTER_INDEX], 00353 BME680_FILTER); 00354 00355 if (desired_settings & (BME680_OST_SEL | BME680_OSP_SEL)) { 00356 dev->tph_sett .os_temp = BME680_GET_BITS(data_array[BME680_REG_TEMP_INDEX], BME680_OST); 00357 dev->tph_sett .os_pres = BME680_GET_BITS(data_array[BME680_REG_PRES_INDEX], BME680_OSP); 00358 } 00359 00360 if (desired_settings & BME680_OSH_SEL) 00361 dev->tph_sett .os_hum = BME680_GET_BITS_POS_0(data_array[BME680_REG_HUM_INDEX], 00362 BME680_OSH); 00363 00364 /* get the gas related settings */ 00365 if (desired_settings & BME680_HCNTRL_SEL) 00366 dev->gas_sett .heatr_ctrl = BME680_GET_BITS_POS_0(data_array[BME680_REG_HCTRL_INDEX], 00367 BME680_HCTRL); 00368 00369 if (desired_settings & (BME680_RUN_GAS_SEL | BME680_NBCONV_SEL)) { 00370 dev->gas_sett .nb_conv = BME680_GET_BITS_POS_0(data_array[BME680_REG_NBCONV_INDEX], 00371 BME680_NBCONV); 00372 dev->gas_sett .run_gas = BME680_GET_BITS(data_array[BME680_REG_RUN_GAS_INDEX], 00373 BME680_RUN_GAS); 00374 } 00375 } 00376 } else { 00377 rslt = BME680_E_NULL_PTR; 00378 } 00379 00380 return rslt; 00381 } 00382 00383 /*! 00384 * @brief This API is used to set the power mode of the sensor. 00385 */ 00386 int8_t BME680::bme680_set_sensor_mode(struct bme680_dev *dev) 00387 { 00388 int8_t rslt; 00389 uint8_t tmp_pow_mode; 00390 uint8_t pow_mode = 0; 00391 uint8_t reg_addr = BME680_CONF_T_P_MODE_ADDR; 00392 00393 /* Check for null pointer in the device structure*/ 00394 rslt = null_ptr_check(dev); 00395 if (rslt == BME680_OK) { 00396 /* Call repeatedly until in sleep */ 00397 do { 00398 rslt = bme680_get_regs(BME680_CONF_T_P_MODE_ADDR, &tmp_pow_mode, 1, dev); 00399 if (rslt == BME680_OK) { 00400 /* Put to sleep before changing mode */ 00401 pow_mode = (tmp_pow_mode & BME680_MODE_MSK); 00402 00403 if (pow_mode != BME680_SLEEP_MODE) { 00404 tmp_pow_mode = tmp_pow_mode & (~BME680_MODE_MSK); /* Set to sleep */ 00405 rslt = bme680_set_regs(®_addr, &tmp_pow_mode, 1, dev); 00406 dev->delay_ms (BME680_POLL_PERIOD_MS); 00407 } 00408 } 00409 } while (pow_mode != BME680_SLEEP_MODE); 00410 00411 /* Already in sleep */ 00412 if (dev->power_mode != BME680_SLEEP_MODE) { 00413 tmp_pow_mode = (tmp_pow_mode & ~BME680_MODE_MSK) | (dev->power_mode & BME680_MODE_MSK); 00414 if (rslt == BME680_OK) 00415 rslt = bme680_set_regs(®_addr, &tmp_pow_mode, 1, dev); 00416 } 00417 } 00418 00419 return rslt; 00420 } 00421 00422 /*! 00423 * @brief This API is used to get the power mode of the sensor. 00424 */ 00425 int8_t BME680::bme680_get_sensor_mode(struct bme680_dev *dev) 00426 { 00427 int8_t rslt; 00428 uint8_t mode; 00429 00430 /* Check for null pointer in the device structure*/ 00431 rslt = null_ptr_check(dev); 00432 if (rslt == BME680_OK) { 00433 rslt = bme680_get_regs(BME680_CONF_T_P_MODE_ADDR, &mode, 1, dev); 00434 /* Masking the other register bit info*/ 00435 dev->power_mode = mode & BME680_MODE_MSK; 00436 } 00437 00438 return rslt; 00439 } 00440 00441 /*! 00442 * @brief This API is used to set the profile duration of the sensor. 00443 */ 00444 void BME680::bme680_set_profile_dur(uint16_t duration, struct bme680_dev *dev) 00445 { 00446 uint32_t tph_dur; /* Calculate in us */ 00447 uint32_t meas_cycles; 00448 uint8_t os_to_meas_cycles[6] = {0, 1, 2, 4, 8, 16}; 00449 00450 meas_cycles = os_to_meas_cycles[dev->tph_sett .os_temp ]; 00451 meas_cycles += os_to_meas_cycles[dev->tph_sett .os_pres ]; 00452 meas_cycles += os_to_meas_cycles[dev->tph_sett .os_hum ]; 00453 00454 /* TPH measurement duration */ 00455 tph_dur = meas_cycles * UINT32_C(1963); 00456 tph_dur += UINT32_C(477 * 4); /* TPH switching duration */ 00457 tph_dur += UINT32_C(477 * 5); /* Gas measurement duration */ 00458 tph_dur += UINT32_C(500); /* Get it to the closest whole number.*/ 00459 tph_dur /= UINT32_C(1000); /* Convert to ms */ 00460 00461 tph_dur += UINT32_C(1); /* Wake up duration of 1ms */ 00462 /* The remaining time should be used for heating */ 00463 dev->gas_sett .heatr_dur = duration - (uint16_t) tph_dur; 00464 } 00465 00466 /*! 00467 * @brief This API is used to get the profile duration of the sensor. 00468 */ 00469 void BME680::bme680_get_profile_dur(uint16_t *duration, const struct bme680_dev *dev) 00470 { 00471 uint32_t tph_dur; /* Calculate in us */ 00472 uint32_t meas_cycles; 00473 uint8_t os_to_meas_cycles[6] = {0, 1, 2, 4, 8, 16}; 00474 00475 meas_cycles = os_to_meas_cycles[dev->tph_sett .os_temp ]; 00476 meas_cycles += os_to_meas_cycles[dev->tph_sett .os_pres ]; 00477 meas_cycles += os_to_meas_cycles[dev->tph_sett .os_hum ]; 00478 00479 /* TPH measurement duration */ 00480 tph_dur = meas_cycles * UINT32_C(1963); 00481 tph_dur += UINT32_C(477 * 4); /* TPH switching duration */ 00482 tph_dur += UINT32_C(477 * 5); /* Gas measurement duration */ 00483 tph_dur += UINT32_C(500); /* Get it to the closest whole number.*/ 00484 tph_dur /= UINT32_C(1000); /* Convert to ms */ 00485 00486 tph_dur += UINT32_C(1); /* Wake up duration of 1ms */ 00487 00488 *duration = (uint16_t) tph_dur; 00489 00490 /* Get the gas duration only when the run gas is enabled */ 00491 if (dev->gas_sett .run_gas ) { 00492 /* The remaining time should be used for heating */ 00493 *duration += dev->gas_sett .heatr_dur ; 00494 } 00495 } 00496 00497 /*! 00498 * @brief This API reads the pressure, temperature and humidity and gas data 00499 * from the sensor, compensates the data and store it in the bme680_data 00500 * structure instance passed by the user. 00501 */ 00502 int8_t BME680::bme680_get_sensor_data(struct bme680_field_data *data, struct bme680_dev *dev) 00503 { 00504 int8_t rslt; 00505 00506 /* Check for null pointer in the device structure*/ 00507 rslt = null_ptr_check(dev); 00508 if (rslt == BME680_OK) { 00509 /* Reading the sensor data in forced mode only */ 00510 rslt = read_field_data(data, dev); 00511 if (rslt == BME680_OK) { 00512 if (data->status & BME680_NEW_DATA_MSK) 00513 dev->new_fields = 1; 00514 else 00515 dev->new_fields = 0; 00516 } 00517 } 00518 00519 return rslt; 00520 } 00521 00522 /*! 00523 * @brief This internal API is used to read the calibrated data from the sensor. 00524 */ 00525 int8_t BME680::get_calib_data(struct bme680_dev *dev) 00526 { 00527 int8_t rslt; 00528 uint8_t coeff_array[BME680_COEFF_SIZE] = { 0 }; 00529 uint8_t temp_var = 0; /* Temporary variable */ 00530 00531 /* Check for null pointer in the device structure*/ 00532 rslt = null_ptr_check(dev); 00533 if (rslt == BME680_OK) { 00534 rslt = bme680_get_regs(BME680_COEFF_ADDR1, coeff_array, BME680_COEFF_ADDR1_LEN, dev); 00535 /* Append the second half in the same array */ 00536 if (rslt == BME680_OK) 00537 rslt = bme680_get_regs(BME680_COEFF_ADDR2, &coeff_array[BME680_COEFF_ADDR1_LEN] 00538 , BME680_COEFF_ADDR2_LEN, dev); 00539 00540 /* Temperature related coefficients */ 00541 dev->calib .par_t1 = (uint16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_T1_MSB_REG], 00542 coeff_array[BME680_T1_LSB_REG])); 00543 dev->calib .par_t2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_T2_MSB_REG], 00544 coeff_array[BME680_T2_LSB_REG])); 00545 dev->calib .par_t3 = (int8_t) (coeff_array[BME680_T3_REG]); 00546 00547 /* Pressure related coefficients */ 00548 dev->calib .par_p1 = (uint16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P1_MSB_REG], 00549 coeff_array[BME680_P1_LSB_REG])); 00550 dev->calib .par_p2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P2_MSB_REG], 00551 coeff_array[BME680_P2_LSB_REG])); 00552 dev->calib .par_p3 = (int8_t) coeff_array[BME680_P3_REG]; 00553 dev->calib .par_p4 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P4_MSB_REG], 00554 coeff_array[BME680_P4_LSB_REG])); 00555 dev->calib .par_p5 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P5_MSB_REG], 00556 coeff_array[BME680_P5_LSB_REG])); 00557 dev->calib .par_p6 = (int8_t) (coeff_array[BME680_P6_REG]); 00558 dev->calib .par_p7 = (int8_t) (coeff_array[BME680_P7_REG]); 00559 dev->calib .par_p8 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P8_MSB_REG], 00560 coeff_array[BME680_P8_LSB_REG])); 00561 dev->calib .par_p9 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_P9_MSB_REG], 00562 coeff_array[BME680_P9_LSB_REG])); 00563 dev->calib .par_p10 = (uint8_t) (coeff_array[BME680_P10_REG]); 00564 00565 /* Humidity related coefficients */ 00566 dev->calib .par_h1 = (uint16_t) (((uint16_t) coeff_array[BME680_H1_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) 00567 | (coeff_array[BME680_H1_LSB_REG] & BME680_BIT_H1_DATA_MSK)); 00568 dev->calib .par_h2 = (uint16_t) (((uint16_t) coeff_array[BME680_H2_MSB_REG] << BME680_HUM_REG_SHIFT_VAL) 00569 | ((coeff_array[BME680_H2_LSB_REG]) >> BME680_HUM_REG_SHIFT_VAL)); 00570 dev->calib .par_h3 = (int8_t) coeff_array[BME680_H3_REG]; 00571 dev->calib .par_h4 = (int8_t) coeff_array[BME680_H4_REG]; 00572 dev->calib .par_h5 = (int8_t) coeff_array[BME680_H5_REG]; 00573 dev->calib .par_h6 = (uint8_t) coeff_array[BME680_H6_REG]; 00574 dev->calib .par_h7 = (int8_t) coeff_array[BME680_H7_REG]; 00575 00576 /* Gas heater related coefficients */ 00577 dev->calib .par_gh1 = (int8_t) coeff_array[BME680_GH1_REG]; 00578 dev->calib .par_gh2 = (int16_t) (BME680_CONCAT_BYTES(coeff_array[BME680_GH2_MSB_REG], 00579 coeff_array[BME680_GH2_LSB_REG])); 00580 dev->calib .par_gh3 = (int8_t) coeff_array[BME680_GH3_REG]; 00581 00582 /* Other coefficients */ 00583 if (rslt == BME680_OK) { 00584 rslt = bme680_get_regs(BME680_ADDR_RES_HEAT_RANGE_ADDR, &temp_var, 1, dev); 00585 00586 dev->calib .res_heat_range = ((temp_var & BME680_RHRANGE_MSK) / 16); 00587 if (rslt == BME680_OK) { 00588 rslt = bme680_get_regs(BME680_ADDR_RES_HEAT_VAL_ADDR, &temp_var, 1, dev); 00589 00590 dev->calib .res_heat_val = (int8_t) temp_var; 00591 if (rslt == BME680_OK) 00592 rslt = bme680_get_regs(BME680_ADDR_RANGE_SW_ERR_ADDR, &temp_var, 1, dev); 00593 } 00594 } 00595 dev->calib .range_sw_err = ((int8_t) temp_var & (int8_t) BME680_RSERROR_MSK) / 16; 00596 } 00597 00598 return rslt; 00599 } 00600 00601 /*! 00602 * @brief This internal API is used to set the gas configuration of the sensor. 00603 */ 00604 int8_t BME680::set_gas_config(struct bme680_dev *dev) 00605 { 00606 int8_t rslt; 00607 00608 /* Check for null pointer in the device structure*/ 00609 rslt = null_ptr_check(dev); 00610 if (rslt == BME680_OK) { 00611 00612 uint8_t reg_addr[2] = {0}; 00613 uint8_t reg_data[2] = {0}; 00614 00615 if (dev->power_mode == BME680_FORCED_MODE) { 00616 reg_addr[0] = BME680_RES_HEAT0_ADDR; 00617 reg_data[0] = calc_heater_res(dev->gas_sett .heatr_temp , dev); 00618 reg_addr[1] = BME680_GAS_WAIT0_ADDR; 00619 reg_data[1] = calc_heater_dur(dev->gas_sett .heatr_dur ); 00620 dev->gas_sett .nb_conv = 0; 00621 } else { 00622 rslt = BME680_W_DEFINE_PWR_MODE; 00623 } 00624 if (rslt == BME680_OK) 00625 rslt = bme680_set_regs(reg_addr, reg_data, 2, dev); 00626 } 00627 00628 return rslt; 00629 } 00630 00631 /*! 00632 * @brief This internal API is used to get the gas configuration of the sensor. 00633 * @note heatr_temp and heatr_dur values are currently register data 00634 * and not the actual values set 00635 */ 00636 int8_t BME680::get_gas_config(struct bme680_dev *dev) 00637 { 00638 int8_t rslt; 00639 /* starting address of the register array for burst read*/ 00640 uint8_t reg_addr1 = BME680_ADDR_SENS_CONF_START; 00641 uint8_t reg_addr2 = BME680_ADDR_GAS_CONF_START; 00642 uint8_t reg_data = 0; 00643 00644 /* Check for null pointer in the device structure*/ 00645 rslt = null_ptr_check(dev); 00646 if (rslt == BME680_OK) { 00647 if (BME680_SPI_INTF == dev->intf ) { 00648 /* Memory page switch the SPI address*/ 00649 rslt = set_mem_page(reg_addr1, dev); 00650 } 00651 00652 if (rslt == BME680_OK) { 00653 rslt = bme680_get_regs(reg_addr1, ®_data, 1, dev); 00654 if (rslt == BME680_OK) { 00655 dev->gas_sett .heatr_temp = reg_data; 00656 rslt = bme680_get_regs(reg_addr2, ®_data, 1, dev); 00657 if (rslt == BME680_OK) { 00658 /* Heating duration register value */ 00659 dev->gas_sett .heatr_dur = reg_data; 00660 } 00661 } 00662 } 00663 } 00664 00665 return rslt; 00666 } 00667 00668 #ifndef BME680_FLOAT_POINT_COMPENSATION 00669 00670 /*! 00671 * @brief This internal API is used to calculate the temperature value. 00672 */ 00673 int16_t BME680::calc_temperature(uint32_t temp_adc, struct bme680_dev *dev) 00674 { 00675 int64_t var1; 00676 int64_t var2; 00677 int64_t var3; 00678 int16_t calc_temp; 00679 00680 var1 = ((int32_t) temp_adc >> 3) - ((int32_t) dev->calib .par_t1 << 1); 00681 var2 = (var1 * (int32_t) dev->calib .par_t2 ) >> 11; 00682 var3 = ((var1 >> 1) * (var1 >> 1)) >> 12; 00683 var3 = ((var3) * ((int32_t) dev->calib .par_t3 << 4)) >> 14; 00684 dev->calib .t_fine = (int32_t) (var2 + var3); 00685 calc_temp = (int16_t) (((dev->calib .t_fine * 5) + 128) >> 8); 00686 00687 return calc_temp; 00688 } 00689 00690 /*! 00691 * @brief This internal API is used to calculate the pressure value. 00692 */ 00693 uint32_t BME680::calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev) 00694 { 00695 int32_t var1; 00696 int32_t var2; 00697 int32_t var3; 00698 int32_t pressure_comp; 00699 00700 var1 = (((int32_t)dev->calib .t_fine ) >> 1) - 64000; 00701 var2 = ((((var1 >> 2) * (var1 >> 2)) >> 11) * 00702 (int32_t)dev->calib .par_p6 ) >> 2; 00703 var2 = var2 + ((var1 * (int32_t)dev->calib .par_p5 ) << 1); 00704 var2 = (var2 >> 2) + ((int32_t)dev->calib .par_p4 << 16); 00705 var1 = (((((var1 >> 2) * (var1 >> 2)) >> 13) * 00706 ((int32_t)dev->calib .par_p3 << 5)) >> 3) + 00707 (((int32_t)dev->calib .par_p2 * var1) >> 1); 00708 var1 = var1 >> 18; 00709 var1 = ((32768 + var1) * (int32_t)dev->calib .par_p1 ) >> 15; 00710 pressure_comp = 1048576 - pres_adc; 00711 pressure_comp = (int32_t)((pressure_comp - (var2 >> 12)) * ((uint32_t)3125)); 00712 if (pressure_comp >= BME680_MAX_OVERFLOW_VAL) 00713 pressure_comp = ((pressure_comp / var1) << 1); 00714 else 00715 pressure_comp = ((pressure_comp << 1) / var1); 00716 var1 = ((int32_t)dev->calib .par_p9 * (int32_t)(((pressure_comp >> 3) * 00717 (pressure_comp >> 3)) >> 13)) >> 12; 00718 var2 = ((int32_t)(pressure_comp >> 2) * 00719 (int32_t)dev->calib .par_p8 ) >> 13; 00720 var3 = ((int32_t)(pressure_comp >> 8) * (int32_t)(pressure_comp >> 8) * 00721 (int32_t)(pressure_comp >> 8) * 00722 (int32_t)dev->calib .par_p10 ) >> 17; 00723 00724 pressure_comp = (int32_t)(pressure_comp) + ((var1 + var2 + var3 + 00725 ((int32_t)dev->calib .par_p7 << 7)) >> 4); 00726 00727 return (uint32_t)pressure_comp; 00728 00729 } 00730 00731 /*! 00732 * @brief This internal API is used to calculate the humidity value. 00733 */ 00734 uint32_t BME680::calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev) 00735 { 00736 int32_t var1; 00737 int32_t var2; 00738 int32_t var3; 00739 int32_t var4; 00740 int32_t var5; 00741 int32_t var6; 00742 int32_t temp_scaled; 00743 int32_t calc_hum; 00744 00745 temp_scaled = (((int32_t) dev->calib .t_fine * 5) + 128) >> 8; 00746 var1 = (int32_t) (hum_adc - ((int32_t) ((int32_t) dev->calib .par_h1 * 16))) 00747 - (((temp_scaled * (int32_t) dev->calib .par_h3 ) / ((int32_t) 100)) >> 1); 00748 var2 = ((int32_t) dev->calib .par_h2 00749 * (((temp_scaled * (int32_t) dev->calib .par_h4 ) / ((int32_t) 100)) 00750 + (((temp_scaled * ((temp_scaled * (int32_t) dev->calib .par_h5 ) / ((int32_t) 100))) >> 6) 00751 / ((int32_t) 100)) + (int32_t) (1 << 14))) >> 10; 00752 var3 = var1 * var2; 00753 var4 = (int32_t) dev->calib .par_h6 << 7; 00754 var4 = ((var4) + ((temp_scaled * (int32_t) dev->calib .par_h7 ) / ((int32_t) 100))) >> 4; 00755 var5 = ((var3 >> 14) * (var3 >> 14)) >> 10; 00756 var6 = (var4 * var5) >> 1; 00757 calc_hum = (((var3 + var6) >> 10) * ((int32_t) 1000)) >> 12; 00758 00759 if (calc_hum > 100000) /* Cap at 100%rH */ 00760 calc_hum = 100000; 00761 else if (calc_hum < 0) 00762 calc_hum = 0; 00763 00764 return (uint32_t) calc_hum; 00765 } 00766 00767 /*! 00768 * @brief This internal API is used to calculate the Gas Resistance value. 00769 */ 00770 uint32_t BME680::calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, const struct bme680_dev *dev) 00771 { 00772 int64_t var1; 00773 uint64_t var2; 00774 int64_t var3; 00775 uint32_t calc_gas_res; 00776 /**Look up table 1 for the possible gas range values */ 00777 uint32_t lookupTable1[16] = { UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2147483647), 00778 UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2130303777), 00779 UINT32_C(2147483647), UINT32_C(2147483647), UINT32_C(2143188679), UINT32_C(2136746228), 00780 UINT32_C(2147483647), UINT32_C(2126008810), UINT32_C(2147483647), UINT32_C(2147483647) 00781 }; 00782 /**Look up table 2 for the possible gas range values */ 00783 uint32_t lookupTable2[16] = { UINT32_C(4096000000), UINT32_C(2048000000), UINT32_C(1024000000), UINT32_C(512000000), 00784 UINT32_C(255744255), UINT32_C(127110228), UINT32_C(64000000), UINT32_C(32258064), UINT32_C(16016016), 00785 UINT32_C(8000000), UINT32_C(4000000), UINT32_C(2000000), UINT32_C(1000000), UINT32_C(500000), 00786 UINT32_C(250000), UINT32_C(125000) 00787 }; 00788 00789 var1 = (int64_t) ((1340 + (5 * (int64_t) dev->calib .range_sw_err )) * 00790 ((int64_t) lookupTable1[gas_range])) >> 16; 00791 var2 = (((int64_t) ((int64_t) gas_res_adc << 15) - (int64_t) (16777216)) + var1); 00792 var3 = (((int64_t) lookupTable2[gas_range] * (int64_t) var1) >> 9); 00793 calc_gas_res = (uint32_t) ((var3 + ((int64_t) var2 >> 1)) / (int64_t) var2); 00794 00795 return calc_gas_res; 00796 } 00797 00798 /*! 00799 * @brief This internal API is used to calculate the Heat Resistance value. 00800 */ 00801 uint8_t BME680::calc_heater_res(uint16_t temp, const struct bme680_dev *dev) 00802 { 00803 uint8_t heatr_res; 00804 int32_t var1; 00805 int32_t var2; 00806 int32_t var3; 00807 int32_t var4; 00808 int32_t var5; 00809 int32_t heatr_res_x100; 00810 00811 if (temp > 400) /* Cap temperature */ 00812 temp = 400; 00813 00814 var1 = (((int32_t) dev->amb_temp * dev->calib .par_gh3 ) / 1000) * 256; 00815 var2 = (dev->calib .par_gh1 + 784) * (((((dev->calib .par_gh2 + 154009) * temp * 5) / 100) + 3276800) / 10); 00816 var3 = var1 + (var2 / 2); 00817 var4 = (var3 / (dev->calib .res_heat_range + 4)); 00818 var5 = (131 * dev->calib .res_heat_val ) + 65536; 00819 heatr_res_x100 = (int32_t) (((var4 / var5) - 250) * 34); 00820 heatr_res = (uint8_t) ((heatr_res_x100 + 50) / 100); 00821 00822 return heatr_res; 00823 } 00824 00825 #else 00826 00827 00828 /*! 00829 * @brief This internal API is used to calculate the 00830 * temperature value in float format 00831 */ 00832 float BME680::calc_temperature(uint32_t temp_adc, struct bme680_dev *dev) 00833 { 00834 float var1 = 0; 00835 float var2 = 0; 00836 float calc_temp = 0; 00837 00838 /* calculate var1 data */ 00839 var1 = ((((float)temp_adc / 16384.0f) - ((float)dev->calib .par_t1 / 1024.0f)) 00840 * ((float)dev->calib .par_t2 )); 00841 00842 /* calculate var2 data */ 00843 var2 = (((((float)temp_adc / 131072.0f) - ((float)dev->calib .par_t1 / 8192.0f)) * 00844 (((float)temp_adc / 131072.0f) - ((float)dev->calib .par_t1 / 8192.0f))) * 00845 ((float)dev->calib .par_t3 * 16.0f)); 00846 00847 /* t_fine value*/ 00848 dev->calib .t_fine = (var1 + var2); 00849 00850 /* compensated temperature data*/ 00851 calc_temp = ((dev->calib .t_fine ) / 5120.0f); 00852 00853 return calc_temp; 00854 } 00855 00856 /*! 00857 * @brief This internal API is used to calculate the 00858 * pressure value in float format 00859 */ 00860 float BME680::calc_pressure(uint32_t pres_adc, const struct bme680_dev *dev) 00861 { 00862 float var1 = 0; 00863 float var2 = 0; 00864 float var3 = 0; 00865 float calc_pres = 0; 00866 00867 var1 = (((float)dev->calib .t_fine / 2.0f) - 64000.0f); 00868 var2 = var1 * var1 * (((float)dev->calib .par_p6 ) / (131072.0f)); 00869 var2 = var2 + (var1 * ((float)dev->calib .par_p5 ) * 2.0f); 00870 var2 = (var2 / 4.0f) + (((float)dev->calib .par_p4 ) * 65536.0f); 00871 var1 = (((((float)dev->calib .par_p3 * var1 * var1) / 16384.0f) 00872 + ((float)dev->calib .par_p2 * var1)) / 524288.0f); 00873 var1 = ((1.0f + (var1 / 32768.0f)) * ((float)dev->calib .par_p1 )); 00874 calc_pres = (1048576.0f - ((float)pres_adc)); 00875 00876 /* Avoid exception caused by division by zero */ 00877 if ((int)var1 != 0) { 00878 calc_pres = (((calc_pres - (var2 / 4096.0f)) * 6250.0f) / var1); 00879 var1 = (((float)dev->calib .par_p9 ) * calc_pres * calc_pres) / 2147483648.0f; 00880 var2 = calc_pres * (((float)dev->calib .par_p8 ) / 32768.0f); 00881 var3 = ((calc_pres / 256.0f) * (calc_pres / 256.0f) * (calc_pres / 256.0f) 00882 * (dev->calib .par_p10 / 131072.0f)); 00883 calc_pres = (calc_pres + (var1 + var2 + var3 + ((float)dev->calib .par_p7 * 128.0f)) / 16.0f); 00884 } else { 00885 calc_pres = 0; 00886 } 00887 00888 return calc_pres; 00889 } 00890 00891 /*! 00892 * @brief This internal API is used to calculate the 00893 * humidity value in float format 00894 */ 00895 float BME680::calc_humidity(uint16_t hum_adc, const struct bme680_dev *dev) 00896 { 00897 float calc_hum = 0; 00898 float var1 = 0; 00899 float var2 = 0; 00900 float var3 = 0; 00901 float var4 = 0; 00902 float temp_comp; 00903 00904 /* compensated temperature data*/ 00905 temp_comp = ((dev->calib .t_fine ) / 5120.0f); 00906 00907 var1 = (float)((float)hum_adc) - (((float)dev->calib .par_h1 * 16.0f) + (((float)dev->calib .par_h3 / 2.0f) 00908 * temp_comp)); 00909 00910 var2 = var1 * ((float)(((float) dev->calib.par_h2 / 262144.0f) * (1.0f + (((float)dev->calib.par_h4 / 16384.0f) 00911 * temp_comp) + (((float)dev->calib.par_h5 / 1048576.0f) * temp_comp * temp_comp)))); 00912 00913 var3 = (float) dev->calib.par_h6 / 16384.0f; 00914 00915 var4 = (float) dev->calib.par_h7 / 2097152.0f; 00916 00917 calc_hum = var2 + ((var3 + (var4 * temp_comp)) * var2 * var2); 00918 00919 if (calc_hum > 100.0f) 00920 calc_hum = 100.0f; 00921 else if (calc_hum < 0.0f) 00922 calc_hum = 0.0f; 00923 00924 return calc_hum; 00925 } 00926 00927 /*! 00928 * @brief This internal API is used to calculate the 00929 * gas resistance value in float format 00930 */ 00931 float BME680::calc_gas_resistance(uint16_t gas_res_adc, uint8_t gas_range, const struct bme680_dev *dev) 00932 { 00933 float calc_gas_res; 00934 float var1 = 0; 00935 float var2 = 0; 00936 float var3 = 0; 00937 00938 const float lookup_k1_range[16] = { 00939 0.0, 0.0, 0.0, 0.0, 0.0, -1.0, 0.0, -0.8, 00940 0.0, 0.0, -0.2, -0.5, 0.0, -1.0, 0.0, 0.0 00941 }; 00942 const float lookup_k2_range[16] = { 00943 0.0, 0.0, 0.0, 0.0, 0.1, 0.7, 0.0, -0.8, 00944 -0.1, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0, 0.0 00945 }; 00946 00947 var1 = (1340.0f + (5.0f * dev->calib.range_sw_err)); 00948 var2 = (var1) * (1.0f + lookup_k1_range[gas_range]/100.0f); 00949 var3 = 1.0f + (lookup_k2_range[gas_range]/100.0f); 00950 00951 calc_gas_res = 1.0f / (float)(var3 * (0.000000125f) * (float)(1 << gas_range) * (((((float)gas_res_adc) 00952 - 512.0f)/var2) + 1.0f)); 00953 00954 return calc_gas_res; 00955 } 00956 00957 /*! 00958 * @brief This internal API is used to calculate the 00959 * heater resistance value in float format 00960 */ 00961 float BME680::calc_heater_res(uint16_t temp, const struct bme680_dev *dev) 00962 { 00963 float var1 = 0; 00964 float var2 = 0; 00965 float var3 = 0; 00966 float var4 = 0; 00967 float var5 = 0; 00968 float res_heat = 0; 00969 00970 if (temp > 400) /* Cap temperature */ 00971 temp = 400; 00972 00973 var1 = (((float)dev->calib .par_gh1 / (16.0f)) + 49.0f); 00974 var2 = ((((float)dev->calib .par_gh2 / (32768.0f)) * (0.0005f)) + 0.00235f); 00975 var3 = ((float)dev->calib .par_gh3 / (1024.0f)); 00976 var4 = (var1 * (1.0f + (var2 * (float)temp))); 00977 var5 = (var4 + (var3 * (float)dev->amb_temp )); 00978 res_heat = (uint8_t)(3.4f * ((var5 * (4 / (4 + (float)dev->calib .res_heat_range )) * 00979 (1/(1 + ((float) dev->calib .res_heat_val * 0.002f)))) - 25)); 00980 00981 return res_heat; 00982 } 00983 00984 #endif 00985 00986 /*! 00987 * @brief This internal API is used to calculate the Heat duration value. 00988 */ 00989 uint8_t BME680::calc_heater_dur(uint16_t dur) 00990 { 00991 uint8_t factor = 0; 00992 uint8_t durval; 00993 00994 if (dur >= 0xfc0) { 00995 durval = 0xff; /* Max duration*/ 00996 } else { 00997 while (dur > 0x3F) { 00998 dur = dur / 4; 00999 factor += 1; 01000 } 01001 durval = (uint8_t) (dur + (factor * 64)); 01002 } 01003 01004 return durval; 01005 } 01006 01007 /*! 01008 * @brief This internal API is used to calculate the field data of sensor. 01009 */ 01010 int8_t BME680::read_field_data(struct bme680_field_data *data, struct bme680_dev *dev) 01011 { 01012 int8_t rslt; 01013 uint8_t buff[BME680_FIELD_LENGTH] = { 0 }; 01014 uint8_t gas_range; 01015 uint32_t adc_temp; 01016 uint32_t adc_pres; 01017 uint16_t adc_hum; 01018 uint16_t adc_gas_res; 01019 uint8_t tries = 10; 01020 01021 /* Check for null pointer in the device structure*/ 01022 rslt = null_ptr_check(dev); 01023 do { 01024 if (rslt == BME680_OK) { 01025 rslt = bme680_get_regs(((uint8_t) (BME680_FIELD0_ADDR)), buff, (uint16_t) BME680_FIELD_LENGTH, 01026 dev); 01027 01028 data->status = buff[0] & BME680_NEW_DATA_MSK; 01029 data->gas_index = buff[0] & BME680_GAS_INDEX_MSK; 01030 data->meas_index = buff[1]; 01031 01032 /* read the raw data from the sensor */ 01033 adc_pres = (uint32_t) (((uint32_t) buff[2] * 4096) | ((uint32_t) buff[3] * 16) 01034 | ((uint32_t) buff[4] / 16)); 01035 adc_temp = (uint32_t) (((uint32_t) buff[5] * 4096) | ((uint32_t) buff[6] * 16) 01036 | ((uint32_t) buff[7] / 16)); 01037 adc_hum = (uint16_t) (((uint32_t) buff[8] * 256) | (uint32_t) buff[9]); 01038 adc_gas_res = (uint16_t) ((uint32_t) buff[13] * 4 | (((uint32_t) buff[14]) / 64)); 01039 gas_range = buff[14] & BME680_GAS_RANGE_MSK; 01040 01041 data->status |= buff[14] & BME680_GASM_VALID_MSK; 01042 data->status |= buff[14] & BME680_HEAT_STAB_MSK; 01043 01044 if (data->status & BME680_NEW_DATA_MSK) { 01045 data->temperature = calc_temperature(adc_temp, dev); 01046 data->pressure = calc_pressure(adc_pres, dev); 01047 data->humidity = calc_humidity(adc_hum, dev); 01048 data->gas_resistance = calc_gas_resistance(adc_gas_res, gas_range, dev); 01049 break; 01050 } 01051 /* Delay to poll the data */ 01052 dev->delay_ms (BME680_POLL_PERIOD_MS); 01053 } 01054 tries--; 01055 } while (tries); 01056 01057 if (!tries) 01058 rslt = BME680_W_NO_NEW_DATA; 01059 01060 return rslt; 01061 } 01062 01063 /*! 01064 * @brief This internal API is used to set the memory page based on register address. 01065 */ 01066 int8_t BME680::set_mem_page(uint8_t reg_addr, struct bme680_dev *dev) 01067 { 01068 int8_t rslt; 01069 uint8_t reg; 01070 uint8_t mem_page; 01071 01072 /* Check for null pointers in the device structure*/ 01073 rslt = null_ptr_check(dev); 01074 if (rslt == BME680_OK) { 01075 if (reg_addr > 0x7f) 01076 mem_page = BME680_MEM_PAGE1; 01077 else 01078 mem_page = BME680_MEM_PAGE0; 01079 01080 if (mem_page != dev->mem_page ) { 01081 dev->mem_page = mem_page; 01082 01083 dev->com_rslt = dev->read (dev->dev_id , BME680_MEM_PAGE_ADDR | BME680_SPI_RD_MSK, ®, 1); 01084 if (dev->com_rslt != 0) 01085 rslt = BME680_E_COM_FAIL; 01086 01087 if (rslt == BME680_OK) { 01088 reg = reg & (~BME680_MEM_PAGE_MSK); 01089 reg = reg | (dev->mem_page & BME680_MEM_PAGE_MSK); 01090 01091 dev->com_rslt = dev->write (dev->dev_id , BME680_MEM_PAGE_ADDR & BME680_SPI_WR_MSK, 01092 ®, 1); 01093 if (dev->com_rslt != 0) 01094 rslt = BME680_E_COM_FAIL; 01095 } 01096 } 01097 } 01098 01099 return rslt; 01100 } 01101 01102 /*! 01103 * @brief This internal API is used to get the memory page based on register address. 01104 */ 01105 int8_t BME680::get_mem_page(struct bme680_dev *dev) 01106 { 01107 int8_t rslt; 01108 uint8_t reg; 01109 01110 /* Check for null pointer in the device structure*/ 01111 rslt = null_ptr_check(dev); 01112 if (rslt == BME680_OK) { 01113 dev->com_rslt = dev->read (dev->dev_id , BME680_MEM_PAGE_ADDR | BME680_SPI_RD_MSK, ®, 1); 01114 if (dev->com_rslt != 0) 01115 rslt = BME680_E_COM_FAIL; 01116 else 01117 dev->mem_page = reg & BME680_MEM_PAGE_MSK; 01118 } 01119 01120 return rslt; 01121 } 01122 01123 /*! 01124 * @brief This internal API is used to validate the boundary 01125 * conditions. 01126 */ 01127 int8_t BME680::boundary_check(uint8_t *value, uint8_t min, uint8_t max, struct bme680_dev *dev) 01128 { 01129 int8_t rslt = BME680_OK; 01130 01131 if (value != NULL) { 01132 /* Check if value is below minimum value */ 01133 if (*value < min) { 01134 /* Auto correct the invalid value to minimum value */ 01135 *value = min; 01136 dev->info_msg |= BME680_I_MIN_CORRECTION; 01137 } 01138 /* Check if value is above maximum value */ 01139 if (*value > max) { 01140 /* Auto correct the invalid value to maximum value */ 01141 *value = max; 01142 dev->info_msg |= BME680_I_MAX_CORRECTION; 01143 } 01144 } else { 01145 rslt = BME680_E_NULL_PTR; 01146 } 01147 01148 return rslt; 01149 } 01150 01151 /*! 01152 * @brief This internal API is used to validate the device structure pointer for 01153 * null conditions. 01154 */ 01155 int8_t BME680::null_ptr_check(const struct bme680_dev *dev) 01156 { 01157 int8_t rslt; 01158 01159 if ((dev == NULL) || (dev->read == NULL) || (dev->write == NULL) || (dev->delay_ms == NULL)) { 01160 /* Device structure pointer is not valid */ 01161 rslt = BME680_E_NULL_PTR; 01162 } else { 01163 /* Device structure is fine */ 01164 rslt = BME680_OK; 01165 } 01166 01167 return rslt; 01168 }
Generated on Wed Jul 13 2022 22:21:17 by
1.7.2