BSEC Sensor Library

  • Compiling with Particle CLI like particle compile photon.
  • Using BME680 4-in-1 sensor.

I’ve been able to retrieve gas resistance values, but it’s incredibly difficult to interpret them into anything useful beyond maybe aggregating them over a long time and collecting subjective feedback… I noticed that Bosch makes a binary-only library for interpreting IAQ from this sensor: https://www.bosch-sensortec.com/bst/products/all_products/bsec How can I include this headers-only library via particle compile photon? Do I need to migrate to local toolchain for this?

Let me ping someone that might be able to help, @rickkas7 or @ParticleD are you able to assist?

1 Like

@warriorofwire,

My apologies, I have edited this post to correct my oops.
The STM32F205 is in fact part of the ARM Cortex family.

I think you will need to do a local build to have a chance of this working.

Particle Dev or Particle Build will definitely not work since they compile in the cloud.

1 Like

Hi @cyclin_al, huge fan of your work & thanks for your reply!

I’m looking at https://docs.particle.io/datasheets/photon-(wifi)/photon-datasheet/ and see STM32F205RGY6 120Mhz ARM Cortex M3 in the P0 module. Looking at my Photon on my desk, it is marked P0. I see (the 2nd row) a GCC-compiled ARM Cortex M3 distribution of the BSEC library at the 1st post url. Is this not suitable?

It is not possible to use a binary library with any of the cloud compilers (Particle Build Web IDE, Particle Dev Atom IDE, or Particle CLI).

It is possible using the to include a ARM Cortex M3 gcc library (.a) using the local gcc-arm build chain, however.

2 Likes

Thanks for the confirmation. I’ll work through getting the local build chain running.

@warriorofwire Did you manage to get it working with a local build?

I am trying the bsec_iot_example.ino example file. My folder structure is as follows:

BME680BSECTest
    inc
       bme680.c
       bme680.h
       bme680_defs.h
       bsec_datatypes.h
       bsec_interface.h
       libalgobsec.a
    src
       BME680BSECTest.cpp
       bsec_integration.c
       bsec_integration.h
       build.mk

And when I try to build using:
make clean all PLATFORM=photon APPDIR=../../BME680BSECTest

I get the following error:

/photon/system-part2 -L../../../modules/photon/system-part1 -L. -T./linker.ld -Wl,--defsym,USER_FIRMWARE_IMAGE_SIZE=0x20000 -Wl,--defsym,USER_FIRMWARE_IMAGE_LOCATION=0x80A0000 -Wl,-Map,../../BME680BSECTest/target/BME680BSECTest.map
../../../build/target/user/platform-6-m/BME680BSECTest//libuser.a(bsec_integration.o): In function `bsec_iot_init':
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:181: undefined reference to `bme680_init'
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:188: undefined reference to `bsec_init'
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:198: undefined reference to `bsec_set_configuration'
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:209: undefined reference to `bsec_set_state'
../../../build/target/user/platform-6-m/BME680BSECTest//libuser.a(bsec_integration.o): In function `bme680_bsec_update_subscription':
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:142: undefined reference to `bsec_update_subscription'
../../../build/target/user/platform-6-m/BME680BSECTest//libuser.a(bsec_integration.o): In function `bsec_iot_loop':
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:485: undefined reference to `bsec_sensor_control'
../../../build/target/user/platform-6-m/BME680BSECTest//libuser.a(bsec_integration.o): In function `bme680_bsec_trigger_measurement':
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:262: undefined reference to `bme680_set_sensor_settings'
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:265: undefined reference to `bme680_set_sensor_mode'
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:268: undefined reference to `bme680_get_profile_dur'
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:283: undefined reference to `bme680_get_sensor_mode'
../../../build/target/user/platform-6-m/BME680BSECTest//libuser.a(bsec_integration.o): In function `bme680_bsec_read_data':
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:306: undefined reference to `bme680_get_sensor_data'
../../../build/target/user/platform-6-m/BME680BSECTest//libuser.a(bsec_integration.o): In function `bme680_bsec_process_data':
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:401: undefined reference to `bsec_do_steps'
../../../build/target/user/platform-6-m/BME680BSECTest//libuser.a(bsec_integration.o): In function `bsec_iot_loop':
/home/<USER>/Documents/src/firmware/user/../../BME680BSECTest//src/bsec_integration.c:503: undefined reference to `bsec_get_state'
collect2: error: ld returned 1 exit status
../../../build/module.mk:222: recipe for target '../../BME680BSECTest/target/BME680BSECTest.elf' failed
make[1]: *** [../../BME680BSECTest/target/BME680BSECTest.elf] Error 1
make[1]: Leaving directory '/home/<USER>/Documents/src/firmware/modules/photon/user-part'
makefile:85: recipe for target '/home/<USER>/Documents/src/firmware/modules/photon/user-part/makefile' failed
make: *** [/home/<USER>/Documents/src/firmware/modules/photon/user-part/makefile] Error 2

For some reason the header files in the inc folder does not seem to be linked even though it is being called in the bsec_integration.h file:

#include "bme680.h"
#include "bsec_interface.h"
#include "bsec_datatypes.h"

the build.mk file is just the boiler plate as mentioned in https://docs.particle.io/faq/particle-tools/local-build/core/#including-additional-header-directories

# Standard behavior must be included here
INCLUDE_DIRS += $(SOURCE_PATH)/$(USRSRC)  # add user sources to include path
CPPSRC += $(call target_files,$(USRSRC_SLASH),*.cpp)
CSRC += $(call target_files,$(USRSRC_SLASH),*.c)

APPSOURCES=$(call target_files,$(USRSRC_SLASH),*.cpp)
APPSOURCES+=$(call target_files,$(USRSRC_SLASH),*.c)

# Custom stuff can be added here
INCLUDE_DIRS += $(SOURCE_PATH)/inc

Is there something that I have missed?

I never did, no. I went down a rabbit hole getting local build working; (po-util now works on vanilla ubuntu server docker images) I set up a local network build server, but I had to move on to projects that had a higher priority. If you do figure out the magic way to stack the cards, please share! If I get back to this project & beat you to it I’ll post what worked.

@warriorofwire Thanks. Will keep you posted

@rickkas7 @ParticleD any chance you guys could figure out whats going wrong?

@warriorofwire I finally got it working.

  1. Regarding your local build issue. Particle has a much better tutorial here on how to set it up tool now.
  2. BSEC provides a static library that needs to be linked for the compiler to be able to use it. @tlangmo has provided step by step instruction on how to get it done.

Here is how I got it working.

  1. Get your local build up and running using Particle Workbench
  2. Clone the BME680 with IAQ output - Particle repo
  3. Add the libalgobsec.a to the the build directory /user/applications/photon-BME680/
  4. Modify makefile located in /modules/photon/user-part to add:
  • Add export MODULAR=y
export COMPILE_LTO=n
export MODULAR=y
  • Update LIB_DEPS & LDFLAGS variable to include the static library
LIB_DIRS += $(dir $(LIB_DEPS))
LIB_DEPS += $(PROJECT_ROOT)/user/applications/photon-BME680/libalgobsec.a
LDFLAGS += -Wl,--whole-archive $(PROJECT_ROOT)/hal/src/photon/lib/STM32F2xx_Peripheral_Libraries.a $(PROJECT_ROOT)/user/applications/photon-BME680/libalgobsec.a -Wl,--no-whole-archive

Compile and flash from the /modules using

  • make all PLATFORM=photon APPDIR=
  • particle flash --usb /target/.bin

(ScruffR: updated broken “local build” links to redirect to Particle Workbench)

2 Likes

For posterity, here’s my solution.

I have multiple particle projects I build on a regular basis. So I went ahead and make a .sh to remember how to link in the BSEC lib whenever I build this thing. I also use gcc 7 and have a bunch of minor firmware fixes to make it work. Gcc 8 is almost there, but I need to find some time again to play with it. Gotta have those lambda capture initialization expressions!

My take on your steps:

  1. Same.
  2. Just download the newest BSEC from bosch at the OP url and copy the /API and /algo/bin/Normal_version/gcc/Cortex_M3 folders into folders project’s /lib folder, like /lib/BME680_driver and lib/BSEC_1472.
    Location is actually unimportant, but for your sanity, you should organize your stuff.
  3. Already copied in the gcc/Cortex_M3 folder, no-op.
  4. I guess you need to make MODULAR=y, but I don’t know why it wouldn’t just always be y?

Here’s how to structure your folders for this solution

.
├── CMakeLists.txt // because I develop with CLion
├── lib
│   ├── BME680_driver
│   └── BSEC_1472
├── project.properties // just names the project and maybe makes the particle make work
└── src
    ├── build.mk
    ├── main_loop_file.cpp
    ├── other_project_subdirectories
    └── for_good_organization

Your build.mk needs to be just right or stuff doesn’t work. Here’s the first bit of mine, in case it helps you. These makefiles are a pain in the glutes to get figured out.

# From https://docs.particle.io/faq/particle-tools/local-build/photon/#including-additional-header-directories
# Standard behavior must be included here (So says particle)
INCLUDE_DIRS += $(SOURCE_PATH)/$(USRSRC)  # add user sources to include path
CPPSRC += $(call target_files,$(USRSRC_SLASH),*.cpp)
CSRC += $(call target_files,$(USRSRC_SLASH),*.c)

APPSOURCES=$(call target_files,$(USRSRC_SLASH),*.cpp)
APPSOURCES+=$(call target_files,$(USRSRC_SLASH),*.c)

# Project-specific stuff goes after the Particle boilerplate above.

$(info ************ Variables)
$(info ************** PROJECT_ROOT: ${PROJECT_ROOT})
$(info ************** SOURCE_PATH: ${SOURCE_PATH})
$(info ************** USRSRC: ${USRSRC})


########## Libraries

$(info ************)
$(info ************ Libraries)

$(info ************)
$(info ************ Bosch BME 680 driver)
bme680_dir = $(SOURCE_PATH)lib/BME680_driver/
$(info ************** include dir:  $(bme680_dir))
INCLUDE_DIRS += $(bme680_dir)
CPPSRC += $(call target_files,$(bme680_dir),*.cpp)
APPSOURCES += $(call target_files,$(bme680_dir),*.cpp)
$(info ************)

$(info ************)
$(info ************ BSEC version 1.4.7.2, 20190122)
bsec_lib = ${SOURCE_PATH}lib/BSEC_1472/libalgobsec.a
bsec_dir = ${SOURCE_PATH}lib/BSEC_1472/
$(info ************** include dir:  $(bsec_dir))
$(info ************** algo library: $(bsec_lib))
INCLUDE_DIRS += $(bsec_dir)
LIB_DEPS += $(bsec_lib)
$(info ************)

Then you just need a way to invoke the build. Here’s my script:

#!/bin/zsh
set -e

pushd ~/firmware/main
LDFLAGS="-Wl,--whole-archive /home/username/code/photon/project_base_dir/lib/BSEC_1472/libalgobsec.a -Wl,--no-whole-archive" \
        make PLATFORM=photon v=1 GCC_ARM_PATH="/home/username/arm-gcc-7/bin/"  APPDIR=/home/username/code/photon/project_base_dir 

The variable expansion in build.mk is really important. Some stuff ends up copied to one place, while some other stuff is sourced from your source dir while particle’s make runs. This should get you pretty close, and does not rely on particle library semantics. po-util is still a good first stop, but I needed more control and getting a build.mk recipe that works is about as much control as I can get.