Bosch Sensortec Community

    Showing results for 
    Search instead for 
    Did you mean: 

    BME680: Gas sensor heater unstable

    BME680: Gas sensor heater unstable


    Dear members,  I am evaluating the BME680 for smoldering fire detection in a dirty environment, which means that I am looking for a way to discriminate easily and heavily oxidizable gas species. For that purpose, I have forked from Bosch's BME680 driver to make use of the sensor's ability to configure and query 10 different heater configurations (temperature and duration). You can find the modified code here: 

    I use all possible ten heater configurations; each step has a duration of 50 ms. That is more then the 20-30 ms which, according to the documentation, are required to achieve a stable heater temperature. The temperatures are 400°C down to 130°C in decrements of 30 K.

    Here comes my problem: Normally, that configuration works fine. I have tested it with a BME680 on a Joy-It breakout board connected directly to a Raspi 3 via I²C at 3.3 V, and it runs flawlessly for days. I have recorded a communication cycle with an oscilloscope; see Scope_regular.png

    In my lab setup driven by a Odroid C2, however, there are three of those BME680 boards connected to the I²C via a TCA9548A multiplexer and P82B96 line buffers with a supply voltage of 3.6 V. They may run equally flawlessly for up to a day, but after some (possibly shorter) time any one of them can get into an error state in which it is unable to achieve a stable heater temperature. Once it occurs, that always affects all ten temperature steps, whereas that sensor's other measurements (ambient temperature, pressure, humidity) continue to work fine. I have captured a communication cycle in the error state as well; see Scope_long.png

    How to stabilize the heater? Do I have to use longer cycles? It does not seem to depend on ambient temperature, as it usually happens at room temperature.

    The sensor is initialized like this:


    			dev_id = BME680_I2C_ADDR_PRIMARY;
    			intf = BME680_I2C_INTF;
    			/* amb_temp can be set to 25 prior to configuring the gas sensor
    			 * or by performing a few temperature readings without operating the gas sensor.
    			amb_temp = 25;
    			if (bme680_init() != BME680_OK) {
    				throw new std::domain_error("Could not initialize BME680.");
    			/* Set the temperature, pressure and humidity settings */
    			tph_sett.os_hum = BME680_OS_2X;
    			tph_sett.os_pres = BME680_OS_4X;
    			tph_sett.os_temp = BME680_OS_8X;
    			tph_sett.filter = BME680_FILTER_SIZE_3;
    			/* Set the remaining gas sensor settings and link the heating profile */
    			gas_sett.run_gas = BME680_ENABLE_GAS_MEAS;
    			gas_sett.nb_conv = 0;
    			/* Select the power mode */
    			/* Must be set before writing the sensor configuration */
    			power_mode = BME680_FORCED_MODE;
    			/* Set the required sensor settings needed */
    			uint8_t const set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_FILTER_SEL | BME680_GAS_SENSOR_SEL;
    			/* Set the desired sensor configuration */
    			if (bme680_set_sensor_settings(set_required_settings) != BME680_OK) {
    				throw new std::domain_error("Could not configure BME680.");
    			/* Set the power mode */
    			if (bme680_set_sensor_mode() != BME680_OK) {
    				throw new std::domain_error("Could not set BME680's power mode.");


    Here is the code that is run in a loop to query the sensor:


    for (size_t i{0}; i < gasResistance.size(); ++i) {
    				if (_measurementEnd) {
    					struct bme680_field_data data;
    					if (bme680_get_sensor_data(&data) == BME680_OK) {
    						averageTemperature += celsius_t{data.temperature / 100.0f};
    						averagePressure += hectopascal_t{data.pressure / 100.0f};
    						averageHumidity += data.humidity / 1000.0f;
    						/* Avoid using measurements from an unstable heating setup */
    						if (dayta.status & BME680_GASM_VALID_MSK) {
    							/* Select the next gas sensor heater profile. */
    							this->gas_sett.nb_conv = overflowingNext<uint8_t, BME680_HEATER_SET_COUNT-1>(data.gas_index);
    							if (bme680_set_sensor_settings(BME680_NBCONV_SEL) != BME680_OK) {
    								ErrorObservable::notifyObservers("Next heater profile could not be selected."s);
    						} else {
                            // This is the error that keeps occurring:
    							ErrorObservable::notifyObservers("Measurement from unstable heating setup rejected."s);
    					} else {
    						ErrorObservable::notifyObservers("Data could not be acquired from device."s);
    				} else {
    					ErrorObservable::notifyObservers("Measurement had not been started."s);
    				/* Trigger the next measurement if you would like to read data out continuously */
    				if (power_mode == BME680_FORCED_MODE) {
    					if (bme680_set_sensor_mode() == BME680_OK) {
    						auto const measurementStart(std::chrono::steady_clock::now());
    						/* Calculate the total measurement duration (which takes time). */
    						uint16_t meas_period;
    						_measurementEnd = measurementStart + std::chrono::milliseconds{meas_period};
    					} else {
    						ErrorObservable::notifyObservers("Could not set sensor mode after measurement."s);



    16 REPLIES 16

    Community Moderator
    Community Moderator

    I saw some strange pattern in Scope_long.png as following, if it is SDA line,  then the output looks strange.  and it is not found in standard image. 

    Can you try to remove other sensors on your board of Odroid C2, then try again to see if issue will become better or worse.  



    Hi Vincent, thank you for the quick response. That is well observed, but easily explained: The buffer P82B96 uses a low level of 0.8V (instead of 0V) in one direction of transmission in order to allow for clock streching without latching the bus. You cannot see it in the other case because there is no such buffer used there.

    With a bus voltage of U=3.6V and an upper limit for the low level of 0.3*U=1.08V, that is within the I²C spec. I checked BME680's spec and found in table 21 that it needs the low level below 0.2*U, which would be 0.72V and seems indeed too low in the given case. The BME680 itself, however, is beyond a level shifter on the Joy-it board, which allows up to 5V supply voltage, so I expect the bus level to be shifted accordingly. It might still be that temperature drift comes into play here after a while if the low level is very close to the limit in the first place.

    It is currently working correctly, and I measured again: Scope_Odroid_regular. It looks just the same as in the error case, except for more data being transmitted.

    Here is also a close up of communication start: Scope_Odroid_error_close.

    Anyway, I do not really believe that this is the problem because the other measurements (temperature, pressure, humidity) can be queried no problem.

    Community Moderator
    Community Moderator

    In your new error log,  i didn't see ACK for that I2C command.  it is not get ACK from bus or just because you zoom out so ACK is not in the range?  

    Let's assume the I2C is not the root cause of this issue first.  

    You mentioned the same code runs well on Raspi 3 with only one sensor but not able to run on Odroid C2 with 3 BME680 sensors, right?  

    If it is the case,  you can just disconnect another two BME680 on your Odroid C2 platform, and also just run one sensor,  is it still have same issue or not?  

    Also i want to understand your error,  is it the following error you got? 

    Measurement from unstable heating setup rejected


    It is because following value is 0, right?   what is dayta.status?  

    dayta.status & BME680_GASM_VALID_MSK


    It is one complete communication cycle, yes. If I zoom out to 2ms/div, the start of the next communication cycle appears on the scope, but no additional ACK between them.

    Vincent, can you clarify which ACK exactly you are missing? The latest screenshot Scope_Odroid_regular is for the working case on Odroid, and I think it looks the same as the working case on Raspi, Scope_regular.

    You are right about the error message I get. "dayta" equals "data" and is an instance of bme680_field_data from Bosch's driver. Sorry for the additional 'y', that's a typo.

    The first two I²C messages are caused by this line in the driver:


    int8_t bme680_dev::read_field_data(struct bme680_field_data *data) 
    rslt = bme680_get_regs(((uint8_t) (BME680_FIELD0_ADDR)), buff, (uint16_t) BME680_FIELD_LENGTH);


    I'll see if I can reproduce the error with only one sensor on the Odroid, but it may take hours until it shows up.