Using BSEC 2 library for bme688 with Thingy53

I'm developing a custom project for thingy53. 

I'm trying to use the bsec2 library to use the bme688 in Thingy53, but there's no reference example anywhere.

With the library provided by bosch, the libalgobsec.a and bsec_interface.h and bsec_datatypes.h files, I succeed to compile together.

But I don't know how to program them including config files.

I find the example with bme680 which is integrated in Thingy91, the asset tracker.

However, that was meaningless because the bsec library version is different (bme680 -> bsec v1.4x / bme688 -> bsec v2.0x) and because of different version, the structure of library is also different.

I think the Thingy53's edge-impulse example uses bme688. But also, unlike Thiny52, Thingy53's source code is not distributed.

So, is there example that adopts bme688's bsec lib. v2.0x for the custom project?

If not, How could I integrate bsec v2.0x library to my custom project?

Here's my CMakeList.txt. I built my project based on Nordic_LBS example from NCS v2.0.0 (zephyr) with Thingy53.

#
# Copyright (c) 2018 Nordic Semiconductor
#
# SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
#
cmake_minimum_required(VERSION 3.20.0)

set(PM_STATIC_YML_FILE
  ${CMAKE_CURRENT_SOURCE_DIR}/boards/pm_static_${BOARD}.yml
  )

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(THINGY53_AMG88XX_BLE_APP)

# NORDIC SDK APP START
target_sources(app PRIVATE src/main.c)

# Preinitialization related to Thingy:53 DFU
target_sources_ifdef(CONFIG_BOARD_THINGY53_NRF5340_CPUAPP app PRIVATE
  boards/thingy53.c
)
target_sources_ifdef(CONFIG_BOARD_THINGY53_NRF5340_CPUAPP_NS app PRIVATE
  boards/thingy53.c
)


# NORDIC SDK APP END
zephyr_library_include_directories(.)
zephyr_library_include_directories({ZEPHYR_BASE}/drivers/sensor/amg88xx)

# zephyr_library_sources(amg88xx.c)
# zephyr_library_sources_ifdef(CONFIG_AMG88XX_TRIGGER amg88xx_trigger.c)


#External library config
# The external static library that we are linking with does not know
# how to build for this platform so we export all the flags used in
# this zephyr build to the external build system.
#
# Other external build systems may be self-contained enough that they
# do not need any build information from zephyr. Or they may be
# incompatible with certain zephyr options and need them to be
# filtered out.
zephyr_get_include_directories_for_lang_as_string(       C includes)
zephyr_get_system_include_directories_for_lang_as_string(C system_includes)
zephyr_get_compile_definitions_for_lang_as_string(       C definitions)
zephyr_get_compile_options_for_lang_as_string(           C options)

set(external_project_cflags
  "${includes} ${definitions} ${options} ${system_includes}"
  )

include(ExternalProject)

# Add an external project to be able download and build the third
# party library. In this case downloading is not necessary as it has
# been committed to the repository.
set(lib_gt2_src_dir   ${CMAKE_CURRENT_SOURCE_DIR}/lib_gt2)
set(lib_gt2_build_dir ${CMAKE_CURRENT_BINARY_DIR}/lib_gt2)

set(LIB_GT2_LIB_DIR     ${lib_gt2_build_dir}/lib)
set(LIB_GT2_SOURCE_DIR  ${lib_gt2_build_dir}/src)
set(LIB_GT2_INCLUDE_DIR ${lib_gt2_src_dir}/include)

if(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
# https://www.gnu.org/software/make/manual/html_node/MAKE-Variable.html
set(submake "$(MAKE)")
else() # Obviously no MAKEFLAGS. Let's hope a "make" can be found somewhere.
set(submake "make")
endif()

ExternalProject_Add(
  lib_gt2_grideye_project                 # Name for custom target
  PREFIX     ${lib_gt2_build_dir} # Root dir for entire project
  SOURCE_DIR ${lib_gt2_src_dir}
  BINARY_DIR ${lib_gt2_src_dir} # This particular build system is invoked from the root
  CONFIGURE_COMMAND ""    # Skip configuring the project, e.g. with autoconf
  BUILD_COMMAND
  ${submake}
  PREFIX=${lib_gt2_build_dir}
  CC=${CMAKE_C_COMPILER}
  AR=${CMAKE_AR}
  CFLAGS=${external_project_cflags}
  INSTALL_COMMAND ""      # This particular build system has no install command
  BUILD_BYPRODUCTS ${LIB_GT2_LIB_DIR}/lib_gt2.a
  BUILD_BYPRODUCTS ${LIB_GT2_SOURCE_DIR}/libalgobsec.a
  DEPENDS zephyr_interface
  )

# Create a wrapper CMake library that our app can link with
add_library(lib_gt2_grideye STATIC IMPORTED GLOBAL)
add_dependencies(
  lib_gt2_grideye
  lib_gt2_grideye_project
  )
set_target_properties(lib_gt2_grideye PROPERTIES IMPORTED_LOCATION              ${LIB_GT2_LIB_DIR}/lib_gt2.a)
# set_target_properties(lib_gt2_grideye PROPERTIES IMPORTED_LOCATION              ${LIB_GT2_SOURCE_DIR}/libalgobsec.a)
set_target_properties(lib_gt2_grideye PROPERTIES INTERFACE_INCLUDE_DIRECTORIES  ${LIB_GT2_INCLUDE_DIR})

# BSEC static library configuration
add_library(lib_bsec STATIC IMPORTED GLOBAL)
# add_dependencies(lib_bsec)
set_target_properties(lib_bsec PROPERTIES IMPORTED_LOCATION                     ${LIB_GT2_SOURCE_DIR}/libalgobsec.a)
set_target_properties(lib_bsec PROPERTIES INTERFACE_INCLUDE_DIRECTORIES         ${LIB_GT2_INCLUDE_DIR})

target_link_libraries(app PUBLIC lib_gt2_grideye)

Parents Reply Children
  • Hi Hieu, Thanks for your interest.

    Becuase, without the BSEC v2.0 library,  Bosch only provides the gas sensor's raw resistance value. 

    I appreciate that you found the BME68x-Sensor-API and Bosch-BSEC2-Library, but the first one (Sensor-API) is already integrated into the zephyr project. 

    --> zephyr/drivers/sensor/bme680 at main · zephyrproject-rtos/zephyr (github.com)

    And the second one (Bosch-BSEC2-Libary) is not a good solution because it is an Arduino-based library and it comments that cortex m33 (Thingy53's nrf5340) is not supported. The BSEC2 Library, which I downloaded from Bosch's official homepage, comments that m33 and m33F are supported.

    I need the processed air quality index and eCO2 values which are calculated from gas resistance by the static library.

    I want to know why the bosch publishes the library just like this way...

  • Hi Kang,

    rtlab_hmk said:

    I appreciate that you found the BME68x-Sensor-API and Bosch-BSEC2-Library, but the first one (Sensor-API) is already integrated into the zephyr project. 

    --> zephyr/drivers/sensor/bme680 at main · zephyrproject-rtos/zephyr (github.com)

    I looked at it and it looks fairly similar but not entirely similar to BME68x-Sensor-API. Are you sure?

    In any cases, the bme680 module in zephyr, which you link, does have all these four values you are looking for. Is there a reason you don't want to use it?

    rtlab_hmkang said:
    temperature, humidity, air pressure and, "Gas resistance"

    // https://github.com/nrfconnect/sdk-zephyr/blob/86893246053c50d34618f09ec6722cae8ba19472/drivers/sensor/bme680/bme680.h#L202
    // zephyr/drivers/sensor/bme680/bme680.h Line 201
    struct bme680_data {
    
    	...
    
    	/* Calculated sensor values. */
    	int32_t calc_temp;
    	uint32_t calc_press;
    	uint32_t calc_humidity;
    	uint32_t calc_gas_resistance;
    
    	...
    
    };

    Having discovered that, I looked back at the example I initially sent to you, and I think you could try this:

    int result = sensor_channel_get(sBme688SensorDev, SENSOR_CHAN_GAS_RES, &sTemperature);


    You obviously have been looking at these BME sensor libraries for way longer than I did, so this is just me trying to support by double checking.

    Whether you want to have further discussion, or you got things under control and would like me off your back, please just let me know Slight smile

    Best regards,

    Hieu

  • Hi, Hieu

    Bosch said the BSEC v2.0 library is a pre-compiled library that extracts meaningful gas quality values (Air Quality Index, eCO2, TVOC, etc.). The APIs we discussed provide only the gas sensors' raw electric resistance value which is not a human-friendly value to analyze.

    I'm trying to integrate the BSEC v2.0 library into my zephyr-based project.

    I'm not sure how long it takes, but if it is done, I'll reply to this discussion surely.

  • Hi Kang,

    Ah, I see fully why you want that .a BSEC library now.

    The sample External Library shows you how you can add an external library.
    In this sample, they use a pair of .c and .h but it is possible to change it to support .a and .h. I tested it.

    What I did to test adding a precompiled .a static library file was:

    • Build the sample once to get the .a file
    • In the mylib source, delete the .c file, put .a file in
    • In the project CMakeLists.txt, remove line 8 to 60
    • In the project CMakeLists.txt, change the set_target_properties() command to point to your .a and include folders.
    • Here is my final CMakeLists.txt for reference
      # SPDX-License-Identifier: Apache-2.0
      
      cmake_minimum_required(VERSION 3.20.0)
      find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
      project(external_lib)
      
      target_sources(app PRIVATE src/main.c)
      
      add_library(mylib_lib STATIC IMPORTED GLOBAL)
      add_dependencies(
        mylib_lib
        mylib_project
        )
      set_target_properties(mylib_lib PROPERTIES IMPORTED_LOCATION             ${CMAKE_CURRENT_SOURCE_DIR}/mylib/lib/libmylib.a)
      set_target_properties(mylib_lib PROPERTIES INTERFACE_INCLUDE_DIRECTORIES ${CMAKE_CURRENT_SOURCE_DIR}/mylib/include)
      
      target_link_libraries(app PUBLIC mylib_lib)
      

    I am not very proficient in CMake though, so my solution might be hacky and not fully proper. But I made sure it worked.

    Finally, a thing to note: If you are using Windows, the VS Code Extension and command line west build cannot build the above sample successfully. You can launch a Bash from the Toolchain Manager and call west build from there instead.

    Hope this helps.

    Best regards,

    Hieu

  • Hi Hieu,

    Finally, I found what I missed, and I want you to know how I solved the problem.

    My very first "CMakeLists.txt" includes ExternalProjectAdd() cmake command.

    This cmake command can add external static library with *.c and *.h files coded by the user. But, this command needs to know the *.c and *.h file's directory which includes Makefile of the source and header file. Here is the Makefile of its directory.

    PREFIX ?= .
    OBJ_DIR ?= $(PREFIX)/obj
    LIB_DIR ?= $(PREFIX)/lib
    
    all:
    	mkdir -p $(OBJ_DIR) $(LIB_DIR)
    	$(CC) -c $(CFLAGS) -MD -Iinclude src/gt2_grideye.c -o $(OBJ_DIR)/gt2_grideye.o
    	# $(CC) -c $(CFLAGS) -MD -Iinclude src/gt2_environment.c -o $(OBJ_DIR)/gt2_environment.o ./include/libalgobsec.a 
    	$(CC) $(CFLAGS) -MD -Iinclude src/gt2_environment.c -o $(OBJ_DIR)/gt2_environment.o 
    	$(CC) -c $(CFLAGS) -MD -Iinclude src/gt2_ble_service.c -o $(OBJ_DIR)/gt2_ble_service.o
    	$(AR) -rcs $(LIB_DIR)/lib_gt2.a $(OBJ_DIR)/*.o
    	
    clean:
    	rm -rf $(OBJ_DIR) $(LIB_DIR)

    This Makefile makes a static library named "lib_gt2.a". I succeed to link "lib_gt2.a" to my main project and it worked properly. The "gt2_environment.c" uses bsec library, I need to let the gt2_environment.c know where the static library is. However, when I tried to link "libalgobsec.a" with this makefile, by adding "./include/libalgobsec.a -lm" to end of the "~~gt2_environment.o" line, Makefile and the gcc complier only said that they can't find bsec libraries.

    Like this, the Makefile does not find zephyr and nrf-sdk specific headers. Because the zephyr based project is managed by "cmake", specific directories' specific makefile isn't good to link external library.

    So, I restructured my project's code tree, and I finally could compile the project.

    Here is my new CMakeLists.txt and my new directory structure.

    #
    # Copyright (c) 2018 Nordic Semiconductor
    #
    # SPDX-License-Identifier: LicenseRef-Nordic-5-Clause
    #
    cmake_minimum_required(VERSION 3.20.0)
    
    set(PM_STATIC_YML_FILE
      ${CMAKE_CURRENT_SOURCE_DIR}/boards/pm_static_${BOARD}.yml
      )
    
    find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
    project(THINGY53_AMG88XX_BLE_APP)
    
    # NORDIC SDK APP START
    target_sources(app PRIVATE src/main.c)
    
    # Preinitialization related to Thingy:53 DFU
    target_sources_ifdef(CONFIG_BOARD_THINGY53_NRF5340_CPUAPP app PRIVATE
      boards/thingy53.c
    )
    target_sources_ifdef(CONFIG_BOARD_THINGY53_NRF5340_CPUAPP_NS app PRIVATE
      boards/thingy53.c
    )
    
    
    # NORDIC SDK APP END
    zephyr_library_include_directories(.)
    zephyr_library_include_directories({ZEPHYR_BASE}/drivers/sensor/amg88xx)
    
    # zephyr_library_sources(amg88xx.c)
    # zephyr_library_sources_ifdef(CONFIG_AMG88XX_TRIGGER amg88xx_trigger.c)
    
    
    #External library config
    # The external static library that we are linking with does not know
    # how to build for this platform so we export all the flags used in
    # this zephyr build to the external build system.
    #
    # Other external build systems may be self-contained enough that they
    # do not need any build information from zephyr. Or they may be
    # incompatible with certain zephyr options and need them to be
    # filtered out.
    zephyr_get_include_directories_for_lang_as_string(       C includes)
    zephyr_get_system_include_directories_for_lang_as_string(C system_includes)
    zephyr_get_compile_definitions_for_lang_as_string(       C definitions)
    zephyr_get_compile_options_for_lang_as_string(           C options)
    
    set(external_project_cflags
      "${includes} ${definitions} ${options} ${system_includes}"
      )
    
    # Add an external project to be able download and build the third
    # party library. In this case downloading is not necessary as it has
    # been committed to the repository.
    if(CMAKE_GENERATOR STREQUAL "Unix Makefiles")
    # https://www.gnu.org/software/make/manual/html_node/MAKE-Variable.html
    set(submake "$(MAKE)")
    else() # Obviously no MAKEFLAGS. Let's hope a "make" can be found somewhere.
    set(submake "make")
    endif()
    
    
    # ADD custom source and header files
    target_include_directories(app PRIVATE src/adld_include)
    target_sources(app PRIVATE src/adld_src/gt2_environment.c)
    target_sources(app PRIVATE src/adld_src/gt2_ble_service.c)
    target_sources(app PRIVATE src/adld_src/gt2_grideye.c)
    
    # BSEC static library configuration
    
    zephyr_library_import(lib_bsec ${CMAKE_CURRENT_SOURCE_DIR}/lib_bsec/src/libalgobsec.a)
    target_include_directories(app PUBLIC ${CMAKE_CURRENT_SOURCE_DIR}/lib_bsec/include)
    target_link_libraries(lib_bsec INTERFACE kernel)
    target_link_libraries(app PRIVATE lib_bsec)
    
    # add_library(lib_bsec STATIC IMPORTED GLOBAL)
    # set_target_properties(lib_bsec PROPERTIES IMPORTED_LOCATION                     ${CMAKE_CURRENT_SOURCE_DIR}/lib_bsec/src/libalgobsec.a)
    # set_target_properties(lib_bsec PROPERTIES INTERFACE_INCLUDE_DIRECTORIES         ${CMAKE_CURRENT_SOURCE_DIR}/lib_bsec/include)
    # target_link_libraries(app PUBLIC lib_bsec)
    

    I located custom *.c and *.h files to the "src" directory where the "main.c" is located. And edited the CMakeLists.txt to let it know where the custom files are by using "target_include_directories" and "target_sources".

    I hope this issues is useful to someone who want's to include external libraries and custom source and header files at one time.

    Best regards. 

    Kang. H.M.

    ps. I succeed to compile, flash and debug, the device logs that the thread with the bsec library had stack overflow. Now, I have to figure out where the stack overflow comes from Slight smile

Related