Bosch Sensortec Community

    cancel
    Showing results for 
    Search instead for 
    Did you mean: 
    SOLVED

    BSEC BME680 output value

    BSEC BME680 output value

    chakey
    New Poster

    Dear guys,

    I think I have successfully import the BSEC library and now can get the data from I2C bus. 

    Since I got the output value, but I am not sure if this is correct, so need your help to confirm.

    another question is how can I calculate the ethanol? not clear after reading the datasheet(especially Table 5).

    MCU chip is stm32g0b0ve, I use IAR IDE (version 9.20.1) to debug.

    below is the code that I modify based on the sample code.

     

     

    #include "target_config.h"
    #include "bsec_integration.h"
    #include "bsec_serialized_configurations_iaq.h"
    #include "i2c.h"
    #include "uart.h"

    /**********************************************************************************************************************/
    /* functions */
    /**********************************************************************************************************************/

    /*!
    * @brief Write operation in either I2C or SPI
    *
    * param[in] dev_addr I2C or SPI device address
    * param[in] reg_addr register address
    * param[in] reg_data_ptr pointer to the data to be written
    * param[in] data_len number of bytes to be written
    *
    * @return result of the bus communication function
    */
    int8_t bus_write(uint8_t reg_addr, uint8_t *reg_data_ptr, uint32_t data_len, void *dev_addr)
    {
    // ...
    // Please insert system specific function to write to the bus where BME680 is connected
    // ...
    uint8_t slaveaddr = *(uint8_t *) dev_addr;

    //if((I2C_MasterSend(I2C_2,slaveaddr,reg_data_ptr,data_len,I2C_MEM_MUTEX_TIMEOUT))!= HAL_OK)
    if(I2C_Reg_MasterSend(I2C_2, reg_addr, slaveaddr, reg_data_ptr ,data_len, I2C_MUTEX_TIMEOUT) != HAL_OK)
    {
    putstring("bus_write error for voc sensor.\r\n\0");
    }

    return 0;//useless return value
    }

    /*!
    * @brief Read operation in either I2C or SPI
    *
    * param[in] dev_addr I2C or SPI device address
    * param[in] reg_addr register address
    * param[out] reg_data_ptr pointer to the memory to be used to store the read data
    * param[in] data_len number of bytes to be read
    *
    * @return result of the bus communication function
    */
    int8_t bus_read(uint8_t reg_addr, uint8_t *reg_data_ptr, uint32_t data_len, void *dev_addr)
    {
    // ...
    // Please insert system specific function to read from bus where BME680 is connected
    // ...
    //uint8_t slaveaddr = (0x76 <<1);
    uint8_t slaveaddr = *(uint8_t *) dev_addr;
    int ret = I2C_Reg_MasterRead(I2C_2, reg_addr, slaveaddr, reg_data_ptr ,data_len, I2C_MUTEX_TIMEOUT);
    //int ret = I2C_MasterRead(I2C_2,slaveaddr,reg_data_ptr,data_len, I2C_MEM_MUTEX_TIMEOUT);
    if(ret != HAL_OK)
    {
    putstring("bus_read error for voc sensor.\r\n\0");
    }
    return 0;//useless return value
    }

    /*!
    * @brief System specific implementation of sleep function
    *
    * @param[in] t_us Time in microseconds
    * @param[in] intf_ptr Pointer to the interface descriptor
    *
    * @return none
    */
    void sleep_n(uint32_t t_us, void *intf_ptr)
    {
    // ...
    // Please insert system specific function sleep or delay for t_ms milliseconds
    // ...
    osDelay(t_us/1000);
    }

    /*!
    * @brief Capture the system time in microseconds
    *
    * @return system_current_time current system timestamp in microseconds
    */
    uint32_t get_timestamp_us()
    {
    uint32_t system_current_time = 0;
    // ...
    // Please insert system specific function to retrieve a timestamp (in microseconds)
    // ...
    system_current_time = xTaskGetTickCount() * 1000;
    return system_current_time;
    }

    /*!
    * @brief Handling of the ready outputs
    *
    * @param[in] timestamp time in milliseconds
    * @param[in] iaq IAQ
    * @param[in] iaq_accuracy IAQ accuracy
    * @param[in] static_iaq static IAQ
    * @param[in] temperature raw temperature
    * @param[in] humidity raw humidity
    * @param[in] temperature temperature
    * @param[in] humidity humidity
    * @param[in] pressure pressure
    * @param[in] gas raw gas
    * @param[in] gas_percentage gas percentage
    * @param[in] co2_equivalent CO2 equivalent
    * @param[in] breath_voc_equivalent breath VOC equivalent
    * @param[in] stabStatus stabilization status
    * @param[in] runInStatus run in status
    * @param[in] bsec_status value returned by the bsec_do_steps() call
    *
    * @return none
    */
    void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity,
    float pressure, float raw_temperature, float raw_humidity, float gas, float gas_percentage, bsec_library_return_t bsec_status,
    float static_iaq, float stabStatus, float runInStatus, float co2_equivalent, float breath_voc_equivalent)
    {
    // ...
    // Please insert system specific code to further process or display the BSEC outputs
    // ...
    char str[50];
    sprintf(str,"static_iaq===%f \r\n\0",breath_voc_equivalent);
    putstring(str);
    }

    /*!
    * @brief Load previous library state from non-volatile memory
    *
    * @param[in,out] state_buffer buffer to hold the loaded state string
    * @param[in] n_buffer size of the allocated state buffer
    *
    * @return number of bytes copied to state_buffer
    */
    uint32_t state_load(uint8_t *state_buffer, uint32_t n_buffer)
    {
    // ...
    // Load a previous library state from non-volatile memory, if available.
    //
    // Return zero if loading was unsuccessful or no state was available,
    // otherwise return length of loaded state string.
    // ...
    return 0;
    }

    /*!
    * @brief Save library state to non-volatile memory
    *
    * @param[in] state_buffer buffer holding the state to be stored
    * @param[in] length length of the state string to be stored
    *
    * @return none
    */
    void state_save(const uint8_t *state_buffer, uint32_t length)
    {
    // ...
    // Save the string some form of non-volatile memory, if possible.
    // ...
    }

    /*!
    * @brief Load library config from non-volatile memory
    *
    * @param[in,out] config_buffer buffer to hold the loaded state string
    * @param[in] n_buffer size of the allocated state buffer
    *
    * @return number of bytes copied to config_buffer
    */
    uint32_t config_load(uint8_t *config_buffer, uint32_t n_buffer)
    {
    // ...
    // Load a library config from non-volatile memory, if available.
    //
    // Return zero if loading was unsuccessful or no config was available,
    // otherwise return length of loaded config string.
    // ...
    memcpy(config_buffer,bsec_config_iaq,sizeof(bsec_config_iaq));
    return sizeof(bsec_config_iaq);
    }

    /*!
    * @brief Main function which configures BSEC library and then reads and processes the data from sensor based
    * on timer ticks
    *
    * @return result of the processing
    */

    int start_voc(void)
    {
    return_values_init ret;

    /* Call to the function which initializes the BSEC library
    * Switch on low-power mode and provide no temperature offset */
    ret = bsec_iot_init(BSEC_SAMPLE_RATE_CONT, 0.0f, bus_write, bus_read, sleep_n, state_load, config_load);
    if (ret.bme68x_status)
    {
    /* Could not intialize BME68x */
    return (int)ret.bme68x_status;
    }
    else if (ret.bsec_status)
    {
    /* Could not intialize BSEC library */
    return (int)ret.bsec_status;
    }

    /* Call to endless loop function which reads and processes data based on sensor settings */
    /* State is saved every 10.000 samples, which means every 10.000 * 3 secs = 500 minutes */
    bsec_iot_loop(sleep_n, get_timestamp_us, output_ready, state_save, 1);

    return 0;
    }

     

    and here is the output value in output_ready().

    chakey_0-1667280575642.png

     

    4 REPLIES 4

    BSTRobin
    Community Moderator
    Community Moderator

    Hi chakey,

    You could print output value with following reference code on STM32.
    void output_ready(int64_t timestamp, float iaq, uint8_t iaq_accuracy, float temperature, float humidity,
    float pressure, float raw_temperature, float raw_humidity, float gas, bsec_library_return_t bsec_status,
    float static_iaq, float co2_equivalent, float breath_voc_equivalent)
    {
    PDEBUG("timestamp=%lld, iaq=%f, iaq_accuracy=%d, temperature=%f, humity=%f, pressure=%f, \
    raw_temperature=%f, raw_humity=%f, gas=%f, bsec_status=%d, static_iaq=%f, co2_equivalent=%f, \
    breath_voc_equivalent=%f\r\n", timestamp, iaq, iaq_accuracy, temperature, humidity, pressure, \
    raw_temperature, raw_humidity, gas, bsec_status, static_iaq, co2_equivalent, breath_voc_equivalent);
    }

    BSEC does not output calculations of ethanol, you could refer the supported BSEC output value from integration guide.

    BSEC supported virtual sensor output signals.png
    The calibration status value iaq accuracy must reach 3 to obtain a high-precision output value.

    BSEC IAQ accuracy.png

    Hi BSTRobin

    Thanks for the update!

    Regarding to calculations of ethanol, is there any formula I can refer to calculate ethanol value?

    Regarding to calibration status value iaq accuracy, how can I configure to get a high-precision output value? or just wait some time(if yes, how long)?

    Thanks again.

    BSTRobin
    Community Moderator
    Community Moderator

    Hi chakey,

    BME680 is a metal-oxide based chemical sensor. The sensor output is created by interaction of volatile organic compounds (VOCs) with the sensitive layer of BME680. Unlike a physical sensor (e.g. pressure sensor like BMP), chemical sensors are thus influenced by a plethora of parameters and their response is very complex. On the one hand, this implies that quantification of VOCs is not possible in a random VOC mixture like the one the sensor faces in a real world environment.

    Take LP mode as an example:
    The IAQ value obtained within 8 hours is not credible, and it can be obtained after more than 8 hours.
    After 7 days, the output value of different sensors under the same environment should be within the scope of the specification, ± 15+± 15%.

    Thanks BSTRobin for the clarification!

    Icon--AD-black-48x48Icon--address-consumer-data-black-48x48Icon--appointment-black-48x48Icon--back-left-black-48x48Icon--calendar-black-48x48Icon--center-alignedIcon--Checkbox-checkIcon--clock-black-48x48Icon--close-black-48x48Icon--compare-black-48x48Icon--confirmation-black-48x48Icon--dealer-details-black-48x48Icon--delete-black-48x48Icon--delivery-black-48x48Icon--down-black-48x48Icon--download-black-48x48Ic-OverlayAlertIcon--externallink-black-48x48Icon-Filledforward-right_adjustedIcon--grid-view-black-48x48IC_gd_Check-Circle170821_Icons_Community170823_Bosch_Icons170823_Bosch_Icons170821_Icons_CommunityIC-logout170821_Icons_Community170825_Bosch_Icons170821_Icons_CommunityIC-shopping-cart2170821_Icons_CommunityIC-upIC_UserIcon--imageIcon--info-i-black-48x48Icon--left-alignedIcon--Less-minimize-black-48x48Icon-FilledIcon--List-Check-grennIcon--List-Check-blackIcon--List-Cross-blackIcon--list-view-mobile-black-48x48Icon--list-view-black-48x48Icon--More-Maximize-black-48x48Icon--my-product-black-48x48Icon--newsletter-black-48x48Icon--payment-black-48x48Icon--print-black-48x48Icon--promotion-black-48x48Icon--registration-black-48x48Icon--Reset-black-48x48Icon--right-alignedshare-circle1Icon--share-black-48x48Icon--shopping-bag-black-48x48Icon-shopping-cartIcon--start-play-black-48x48Icon--store-locator-black-48x48Ic-OverlayAlertIcon--summary-black-48x48tumblrIcon-FilledvineIc-OverlayAlertwhishlist