Bosch Sensortec Community

    Bsec only gives new data 4 times and then never triggers again

    Highlighted
    New Poster

    Bsec only gives new data 4 times and then never triggers again

    I have the attached code. I am attemping to run at 1hz.  I see good data several times, and then the bsec never triggers again. I am using an Stm32F767 with the normal M7 Bsec binary.

    Any ideas on what may be going on?

    This is my output:

    Up!
    5
    16000000 :: IAQ: 25.000000, IAQ Accuracy 0, Temp: 25.520000, Humidity: 35.554005
    44
    5
    1017000000 :: IAQ: 25.000000, IAQ Accuracy 0, Temp: 26.065571, Humidity: 35.213631
    45
    5
    2018000000 :: IAQ: 25.000000, IAQ Accuracy 0, Temp: 26.775574, Humidity: 33.929062
    45
    5
    3019000000 :: IAQ: 25.000000, IAQ Accuracy 0, Temp: 27.085571, Humidity: 33.259838
    45
    5
    4020000000 :: IAQ: 25.000000, IAQ Accuracy 0, Temp: 27.275574, Humidity: 32.777760
    4339
    0
    4294

     

     

    This is my code:

    #include <stm32f7xx_hal.h>
    #include "FreeRTOS.h"
    #include "task.h"
    #include <stdio.h>
    #include "bme680.h"
    #include "I2c1.h"
    #include "bsec_interface.h"
    #include "bsec_datatypes.h"
    #include "BsecDemo.h"
    #include "Ticks.h"

    static void BME680_delay(uint32_t period);
    static int8_t BME680_I2C_bus_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len);
    static int8_t BME680_I2C_bus_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len);
    static void BsecDemoTask(void* args);

    #define NUM_USED_OUTPUTS 7

    static struct bme680_dev bme680_g;

    static float bme680_temperature_offset_g = 0.0f;

    static bsec_library_return_t bme680_bsec_update_subscription(const float sample_rate)
    {
    bsec_sensor_configuration_t requested_virtual_sensors[NUM_USED_OUTPUTS];
    uint8_t n_requested_virtual_sensors = NUM_USED_OUTPUTS;
    bsec_sensor_configuration_t required_sensor_settings[BSEC_MAX_PHYSICAL_SENSOR];
    uint8_t n_required_sensor_settings = BSEC_MAX_PHYSICAL_SENSOR;

    requested_virtual_sensors[0].sensor_id = BSEC_OUTPUT_IAQ;
    requested_virtual_sensors[0].sample_rate = sample_rate;
    requested_virtual_sensors[1].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE;
    requested_virtual_sensors[1].sample_rate = sample_rate;
    requested_virtual_sensors[2].sensor_id = BSEC_OUTPUT_RAW_PRESSURE;
    requested_virtual_sensors[2].sample_rate = sample_rate;
    requested_virtual_sensors[3].sensor_id = BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY;
    requested_virtual_sensors[3].sample_rate = sample_rate;
    requested_virtual_sensors[4].sensor_id = BSEC_OUTPUT_RAW_GAS;
    requested_virtual_sensors[4].sample_rate = sample_rate;
    requested_virtual_sensors[5].sensor_id = BSEC_OUTPUT_RAW_TEMPERATURE;
    requested_virtual_sensors[5].sample_rate = sample_rate;
    requested_virtual_sensors[6].sensor_id = BSEC_OUTPUT_RAW_HUMIDITY;
    requested_virtual_sensors[6].sample_rate = sample_rate;

    // Enable/disable the requested virtual sensors
    return bsec_update_subscription(requested_virtual_sensors,
    n_requested_virtual_sensors,
    required_sensor_settings,
    &n_required_sensor_settings);
    }

    bool BsecDemo_Init(float sample_rate)
    {
    int32_t status;

    I2c1_Init();

    bme680_g.dev_id = (0x77 << 1);
    bme680_g.intf = BME680_I2C_INTF;
    bme680_g.write = BME680_I2C_bus_write;
    bme680_g.read = BME680_I2C_bus_read;
    bme680_g.delay_ms = BME680_delay;

    // Initialize BME680 API
    status = bme680_init(&bme680_g);
    if (status != BME680_OK)
    {
    printf("bme680 init fail\r\n");
    return false;
    }

    // Initialize BSEC library
    status = bsec_init();
    if (status != BSEC_OK)
    {
    printf("bsec init fail\r\n");
    return false;
    }

    // Call to the function which sets the library with subscription information
    status = bme680_bsec_update_subscription(sample_rate);
    if (status != BSEC_OK)
    {
    printf("update sub init fail %ld\r\n", status);
    return false;
    }

    xTaskCreate(BsecDemoTask, "BSECDEMO", 2048, NULL, 0, NULL);

    return true;
    }

    static void bme680_bsec_trigger_measurement(bsec_bme_settings_t *sensor_settings)
    {
    uint16_t meas_period;
    uint8_t set_required_settings;

    // Check if a forced-mode measurement should be triggered now
    if (sensor_settings->trigger_measurement)
    {
    // Set sensor configuration
    bme680_g.tph_sett.os_hum = sensor_settings->humidity_oversampling;
    bme680_g.tph_sett.os_pres = sensor_settings->pressure_oversampling;
    bme680_g.tph_sett.os_temp = sensor_settings->temperature_oversampling;
    bme680_g.gas_sett.run_gas = sensor_settings->run_gas;
    bme680_g.gas_sett.heatr_temp = sensor_settings->heater_temperature; // degree Celsius
    bme680_g.gas_sett.heatr_dur = sensor_settings->heating_duration; // milliseconds

    // Select the power mode
    // Must be set before writing the sensor configuration
    bme680_g.power_mode = BME680_FORCED_MODE;

    // Set the required sensor settings needed
    set_required_settings = BME680_OST_SEL | BME680_OSP_SEL | BME680_OSH_SEL | BME680_GAS_SENSOR_SEL;

    // Set the desired sensor configuration
    bme680_set_sensor_settings(set_required_settings, &bme680_g);

    // Set power mode as forced mode and trigger forced mode measurement
    bme680_set_sensor_mode(&bme680_g);

    // Get the total measurement duration so as to sleep or wait till the measurement is complete
    bme680_get_profile_dur(&meas_period, &bme680_g);

    // Delay till the measurement is ready. Timestamp resolution in ms
    vTaskDelay(meas_period);
    }

    // Call the API to get current operation mode of the sensor
    bme680_get_sensor_mode(&bme680_g);

    // When the measurement is completed and data is ready for reading, the sensor must be in BME680_SLEEP_MODE.
    // Read operation mode to check whether measurement is completely done and wait until the sensor is no more
    // in BME680_FORCED_MODE.
    while (bme680_g.power_mode == BME680_FORCED_MODE)
    {
    // sleep for 5 ms
    vTaskDelay(5);
    bme680_get_sensor_mode(&bme680_g);
    }
    }

    static void bme680_bsec_read_data(int64_t time_stamp_trigger, bsec_input_t *inputs, uint8_t *num_bsec_inputs, int32_t bsec_process_data)
    {
    static struct bme680_field_data data;

    // We only have to read data if the previous call the bsec_sensor_control() actually asked for it
    if (bsec_process_data)
    {
    bme680_get_sensor_data(&data, &bme680_g);

    if (data.status & BME680_NEW_DATA_MSK)
    {
    // Pressure
    if (bsec_process_data & BSEC_PROCESS_PRESSURE)
    {
    inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_PRESSURE;
    inputs[*num_bsec_inputs].signal = data.pressure;
    inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
    (*num_bsec_inputs)++;
    }

    // Temperature
    if (bsec_process_data & BSEC_PROCESS_TEMPERATURE)
    {
    inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_TEMPERATURE;
    inputs[*num_bsec_inputs].signal = data.temperature / 100.0f;
    inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
    (*num_bsec_inputs)++;

    // Also add optional heatsource input which will be subtracted from the temperature reading to
    // compensate for device-specific self-heating (supported in BSEC IAQ solution)
    inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_HEATSOURCE;
    inputs[*num_bsec_inputs].signal = bme680_temperature_offset_g;
    inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
    (*num_bsec_inputs)++;
    }

    // Humidity
    if (bsec_process_data & BSEC_PROCESS_HUMIDITY)
    {
    inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_HUMIDITY;
    inputs[*num_bsec_inputs].signal = data.humidity / 1000.0f;
    inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
    (*num_bsec_inputs)++;
    }

    // Gas
    if (bsec_process_data & BSEC_PROCESS_GAS)
    {
    // Check whether gas_valid flag is set
    if(data.status & BME680_GASM_VALID_MSK)
    {
    inputs[*num_bsec_inputs].sensor_id = BSEC_INPUT_GASRESISTOR;
    inputs[*num_bsec_inputs].signal = data.gas_resistance;
    inputs[*num_bsec_inputs].time_stamp = time_stamp_trigger;
    (*num_bsec_inputs)++;
    }
    }
    }
    }
    }

    static void bme680_bsec_process_data(bsec_input_t *bsec_inputs, uint8_t num_bsec_inputs)
    {
    bsec_output_t bsec_outputs[BSEC_NUMBER_OUTPUTS];
    uint8_t num_bsec_outputs = 0;
    uint8_t index = 0;
    int64_t timestamp = 0;
    float iaq = 0.0f;
    uint8_t iaq_accuracy = 0;
    float temp = 0.0f;
    float raw_temp = 0.0f;
    float raw_pressure = 0.0f;
    float humidity = 0.0f;
    float raw_humidity = 0.0f;
    float raw_gas = 0.0f;

    // Check if something should be processed by BSEC
    if (num_bsec_inputs > 0)
    {
    // Set number of outputs to the size of the allocated buffer
    // BSEC_NUMBER_OUTPUTS to be defined
    num_bsec_outputs = BSEC_NUMBER_OUTPUTS;

    // Do Bsec
    bsec_do_steps(bsec_inputs, num_bsec_inputs, bsec_outputs, &num_bsec_outputs);

    // Iterate through the outputs and extract the relevant ones.
    for (index = 0; index < num_bsec_outputs; index++)
    {
    switch (bsec_outputs[index].sensor_id)
    {
    case BSEC_OUTPUT_IAQ:
    iaq = bsec_outputs[index].signal;
    iaq_accuracy = bsec_outputs[index].accuracy;
    break;
    case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_TEMPERATURE:
    temp = bsec_outputs[index].signal;
    break;
    case BSEC_OUTPUT_RAW_PRESSURE:
    raw_pressure = bsec_outputs[index].signal;
    break;
    case BSEC_OUTPUT_SENSOR_HEAT_COMPENSATED_HUMIDITY:
    humidity = bsec_outputs[index].signal;
    break;
    case BSEC_OUTPUT_RAW_GAS:
    raw_gas = bsec_outputs[index].signal;
    break;
    case BSEC_OUTPUT_RAW_TEMPERATURE:
    raw_temp = bsec_outputs[index].signal;
    break;
    case BSEC_OUTPUT_RAW_HUMIDITY:
    raw_humidity = bsec_outputs[index].signal;
    break;
    default:
    continue;
    }

    // Assume that all the returned timestamps are the same
    timestamp = bsec_outputs[index].time_stamp;
    }

    printf("%lli :: IAQ: %f, IAQ Accuracy %d, Temp: %f, Humidity: %f\r\n",
    timestamp,
    iaq,
    iaq_accuracy,
    temp,
    humidity);
    }
    }

    static void BsecDemoTask(void* args)
    {
    int64_t time_stamp = 0;
    bsec_input_t bsec_inputs[BSEC_MAX_PHYSICAL_SENSOR];
    uint8_t num_bsec_inputs = 0;
    bsec_bme_settings_t sensor_settings;
    int64_t time_stamp_interval_ms = 0;

    while (true)
    {
    // get the timestamp in nanoseconds before calling bsec_sensor_control()
    time_stamp = Ticks_Now() * 1000 * 1000;

    // Retrieve sensor settings to be used in this time instant by calling bsec_sensor_control
    bsec_sensor_control(time_stamp, &sensor_settings);

    // Trigger a measurement if necessary
    bme680_bsec_trigger_measurement(&sensor_settings);

    // Read data from last measurement
    num_bsec_inputs = 0;
    bme680_bsec_read_data(time_stamp, bsec_inputs, &num_bsec_inputs, sensor_settings.process_data);
    printf("%d\r\n", num_bsec_inputs);

    // Time to invoke BSEC to perform the actual processing
    bme680_bsec_process_data(bsec_inputs, num_bsec_inputs);

    // Compute how long we can sleep until we need to call bsec_sensor_control() next
    // Time_stamp is converted from microseconds to nanoseconds first and then the difference to milliseconds
    time_stamp_interval_ms = (sensor_settings.next_call - Ticks_Now() * 1000 * 1000) / 1000000;
    printf("%lld\r\n", time_stamp_interval_ms);
    if (time_stamp_interval_ms > 0)
    {
    vTaskDelay(time_stamp_interval_ms);
    }
    }
    }

    static int8_t BME680_I2C_bus_write(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len)
    {
    if (!I2c1_Write(dev_id, reg_addr, data, len))
    {
    return -1;
    }

    return 0;
    }

    static int8_t BME680_I2C_bus_read(uint8_t dev_id, uint8_t reg_addr, uint8_t *data, uint16_t len)
    {
    if (!I2c1_Read(dev_id, reg_addr, data, len))
    {
    return -1;
    }

    return 0;
    }

    static void BME680_delay(uint32_t period)
    {
    // Inline delay
    // Don't let the scheduler take it!
    HAL_Delay(period);
    }

     

    8 REPLIES 8
    Highlighted
    Community Moderator

    Re: Bsec only gives new data 4 times and then never triggers again

    Valid sampling rates are found in bsec_datatypes.h, and can be either BSEC_SAMPLE_RATE_LP (for 3s sampling period) or BSEC_SAMPLE_RATE_ULP (for 5min sampling period). Please try to use BSEC_SAMPLE_RATE_LP in your project and let us know if the issue persists.

    Highlighted
    New Poster

    Re: Bsec only gives new data 4 times and then never triggers again

    Hi,

    Unfortunatly, this does not fix the issue. The updates do some in at the lower frequency, but after a smaller number of them, the bsec goes into the same mode of failure seen here where it does not trigger and gives long timeouts. It seems like this might be time related perhaps, where the bsec will only work for a certain amount of time once it is started?

    Any additional ideas? I'm trying to fast track a demo of this for a production application so I'd really like to get this running quickly.

    Highlighted
    Community Moderator

    Re: Bsec only gives new data 4 times and then never triggers again

    This is not a typical BSEC behavior, it should run over time without problems. Did you try running other process than BSEC in your task (e.g. raw BME680 data, or even a blinky) to see if the issue comes from BSEC's integration or other system/tasks mismatch? Is it possible that you have not allocated sufficient stack to BSEC's task (or other tasks)? Did you check if any BSEC function is returning some error/warning messages (e.g. bsec_sensor_control(), bsec_do_steps(), etc.)? Can you track that BSEC is called with accurate timings, or if something else in the system is causing BSEC to be called after unexpected delays?

    Highlighted
    New Poster

    Re: Bsec only gives new data 4 times and then never triggers again

    Turns out I am getting an error: BSEC_W_SC_CALL_TIMING_VIOLATION.

    So there must be a timing issue somewhere.... everything for the bsec is in nanoseconds, and my ticks are in mS...  So will look for issues in my conversion unless you see one.

    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