Thread SensorTag

  • nRF52840 on a MS88SF2 module.
  • i²C bus scl P1.13 and sda P1.15
  • Light sensor VEMLS6030 @0x48
  • MS8607 with relative humidity @0x40, pressure and temperature @0x76
  • Reset button P0.18 and user button SW0 P1.09
  • RGB LED P0. 04 06 08

Schematics #

  • version 1.1
  • update from v1.0 added RGB LED

Manufacturing #

Board #

development #

install #

make sure there is no environment variable ZEPHYR_BASE in order to use the local zephyr version
  • create directory structure and fetch the sdk :
mkdir hsm_workspace
cd hsm_workspace
west init -m https://github.com/HomeSmartMesh/sdk-hsm-sensortag -mr main
  • fetch all dependencies from referenced repos in hsm.west.yml
west update

sdk samples #

tag_sensor_veml6030 #

west build -t guiconfig
west build -b nrf52840_sensortag -- -DCONF_FILE=prj-shell.conf
west build -b nrf52840_sensortag -- -DCONF_FILE=prj-log.conf
west flash
default config
CONFIG_GPIO=y
CONFIG_SERIAL=n

CONFIG_I2C=y
CONFIG_SENSOR=y
CONFIG_VEML6030=y

CONFIG_NEWLIB_LIBC=y
CONFIG_NEWLIB_LIBC_FLOAT_PRINTF=y
build log
-- west build: generating a build system
Including boilerplate (Zephyr base (cached)): D:/Dev/nrf52/hsm/zephyr/cmake/app/boilerplate.cmake
-- Application: D:/Dev/nrf52/hsm/hsm/samples/tag_sensor_veml6030
-- Zephyr version: 2.5.99 (D:/Dev/nrf52/hsm/zephyr)
-- Found west (found suitable version "0.10.1", minimum required is "0.7.1")
-- Board: nrf52840_sensortag
-- Cache files will be written to: D:/Dev/nrf52/hsm/zephyr/.cache
-- Found toolchain: gnuarmemb (D:/tools/gnu_arm_embedded/10 2020-q4-major)
-- Found BOARD.dts: D:/Dev/nrf52/hsm/hsm/boards/arm/nrf52840_sensortag/nrf52840_sensortag.dts

running the initial versions on ambiant light, hand cover then flash light

run log preliminary
[00:00:00.325,683] <inf> VEML6030: veml6030_init() power on
[00:00:00.326,202] <inf> VEML6030: i2c_burst_write(0x0000) success
*** Booting Zephyr OS build zephyr-v2.5.0-2187-g757cd12e6602  ***

[00:00:00.326,324] <inf> main: VEML6030 light sensor application

Found device "VEML6030", getting sensor data

[00:00:00.427,062] <inf> main: sensor: lum reading: 1255

[00:00:05.527,740] <inf> main: sensor: lum reading: 1253

[00:00:10.628,448] <inf> main: sensor: lum reading: 1242

[00:00:15.729,156] <inf> main: sensor: lum reading: 107

[00:00:20.829,864] <inf> main: sensor: lum reading: 111

[00:00:25.930,572] <inf> main: sensor: lum reading: 1304

[00:00:31.031,280] <inf> main: sensor: lum reading: 1482

[00:00:36.131,988] <inf> main: sensor: lum reading: 23082

[00:00:41.232,696] <inf> main: sensor: lum reading: 23791

[00:00:46.333,404] <inf> main: sensor: lum reading: 1257

[00:00:51.434,112] <inf> main: sensor: lum reading: 1365

[00:00:56.534,820] <inf> main: sensor: lum reading: 1354

[00:01:01.635,528] <inf> main: sensor: lum reading: 1351

[00:01:06.736,236] <inf> main: sensor: lum reading: 1349

[00:01:11.836,944] <inf> main: sensor: lum reading: 1274

running with auto mode

run log auto
[00:00:00.324,188] <inf> VEML6030: veml6030_init()
*** Booting Zephyr OS build zephyr-v2.5.0-2187-g757cd12e6602  ***

[00:00:00.324,310] <inf> main: VEML6030 light sensor application
=====> light 3.614 lux
=====> light 3.582 lux
=====> light 7.142 lux
auto_measure>sample 65535 not optimal ; gain = 2.000 ; it = 800 ms
auto_measure>new params => gain = 1.000000 ; it = 800
=====> light 449.741 lux
=====> light 453.672 lux
auto_measure>sample 65535 not optimal ; gain = 1.000 ; it = 800 ms
auto_measure>new params => gain = 0.250000 ; it = 800
=====> light 1502.496 lux
=====> light 1645.315 lux
auto_measure>sample 65535 not optimal ; gain = 0.250 ; it = 800 ms
auto_measure>new params => gain = 0.125000 ; it = 800
=====> light 3081.197 lux
auto_measure>sample 65535 not optimal ; gain = 0.125 ; it = 800 ms
auto_measure>new params => gain = 0.125000 ; it = 400
=====> light 5908.954 lux
auto_measure>sample 24 not optimal ; gain = 0.125 ; it = 400 ms
auto_measure>new params => gain = 2.000000 ; it = 800
=====> light 3.031 lux
=====> light 3.010 lux
=====> light 3.136 lux
=====> light 3.794 lux
=====> light 4.478 lux
=====> light 3.139 lux
  • The previous auto mode has a disadvantage, when saturating, the best guess is still biased as it used a wrong saturated measure.
  • The following example makes a special case of a saturated measure and directly jumps to the highest mode which has the lowes integration time anyway so only 25 ms are spent, after which the sample is sure not to be saturated and either has a chance to already be in optimal mode (if it is the highest) or guqrantees that the next selected mode will be the optimal.
run log auto sat
[00:00:00.325,836] <inf> main: VEML6030 light sensor application
=====> light 70.247 lux
=====> light 67.090 lux
auto_measure>sample 65535 not optimal ; gain = 2.000 ; it = 800 ms
auto_measure>new params => gain = 0.125000 ; it = 25
auto_measure>sample 487 not optimal ; gain = 0.125 ; it = 25 ms
auto_measure>new params => gain = 0.250000 ; it = 800
=====> light 897.811 lux
=====> light 793.872 lux
auto_measure>sample 2668 not optimal ; gain = 0.250 ; it = 800 ms
auto_measure>new params => gain = 2.000000 ; it = 800
=====> light 69.358 lux
=====> light 69.289 lux
=====> light 68.566 lux
=====> light 68.465 lux

preliminary test samples #

01 dongle nrfsdk mqttsn client #

Tested firmware with MQTT-SN gateway and Mosquitto broquer
  • example based on nRFSDK for Thread and Zigbee v4.1.0 which path should be declared in an environment variable THREAD_SDK_ROOT
  • Note that, as specified in the SDK file components\toolchain\gcc\Makefile.windows the used toolchain is GNU Tools ARM Embedded/7 2018-q2-update
  • Adapted Makefile
  • As the usb dongle has only one user key KEY_0, the sequence of search_gateway, connect, publish is not cyclically executed when pressing KEY_0 multiple times.
  • zephyr with platformio environment for easy install
  • dongle led blink
  • added boards\nrf52840dongle_nrf52840.json
  • jlink is the default upload method for the nrf52840 boards

06 tag zephyr hello #

  • hello world example using the nrf52840_sensortag custom board

zephyr examples usage

west build -b nrf52840_sensortag
west flash
build log
-- west build: generating a build system
Including boilerplate (Zephyr base (cached)): D:/Projects/zephyrproject/zephyr/cmake/app/boilerplate.cmake
-- Application: D:/Dev/nrf52/nrf52_thread_sensortag/firmware/tag_zephyr_hello
-- Zephyr version: 2.5.99 (D:/Projects/zephyrproject/zephyr)
-- Found west (found suitable version "0.9.0", minimum required is "0.7.1")
-- Board: nrf52840_sensortag
-- Cache files will be written to: D:/Projects/zephyrproject/zephyr/.cache
-- Found toolchain: gnuarmemb (D:/tools/gnu_arm_embedded/9_2020-q2-update)
run log
*** Booting Zephyr OS build zephyr-v2.5.0-159-g2bfaadffb807  ***

[00:00:00.337,707] <inf> main: Hello from Sensor Tag
[00:00:01.337,768] <inf> main: loop: 0
[00:00:02.337,860] <inf> main: loop: 1
[00:00:03.338,012] <inf> main: loop: 2
[00:00:04.338,104] <inf> main: loop: 3
[00:00:05.338,256] <inf> main: loop: 4
[00:00:06.338,348] <inf> main: loop: 5
[00:00:07.338,500] <inf> main: loop: 6
[00:00:08.338,562] <inf> main: loop: 7
[00:00:09.338,653] <inf> main: loop: 8
[00:00:10.338,745] <inf> main: loop: 9
[00:00:11.338,836] <inf> main: loop: 10
[00:00:12.338,928] <inf> main: loop: 11
[00:00:13.339,019] <inf> main: loop: 12
[00:00:14.339,111] <inf> main: loop: 13
[00:00:15.339,202] <inf> main: loop: 14
[00:00:16.339,294] <inf> main: loop: 15
[00:00:17.339,385] <inf> main: loop: 16
[00:00:18.339,477] <inf> main: loop: 17

07 tag zephyr button #

  • introducing user button interrupt
build log
-- west build: generating a build system
Including boilerplate (Zephyr base): D:/Projects/zephyrproject/zephyr/cmake/app/boilerplate.cmake
-- Application: D:/Dev/nrf52/nrf52_thread_sensortag/firmware/07_tag_zephyr_button
-- Zephyr version: 2.5.99 (D:/Projects/zephyrproject/zephyr)
-- Found Python3: C:/Users/User/AppData/Local/Programs/Python/Python39/python.exe (found suitable exact version "3.9.0") found components: Interpreter
-- Found west (found suitable version "0.9.0", minimum required is "0.7.1")
-- Board: nrf52840_sensortag
-- Cache files will be written to: D:/Projects/zephyrproject/zephyr/.cache
-- Found toolchain: gnuarmemb (D:/tools/gnu_arm_embedded/9_2020-q2-update)
-- Found BOARD.dts: D:/Dev/nrf52/nrf52_thread_sensortag/firmware/boards/arm/nrf52840_sensortag/nrf52840_sensortag.dts
run log

rtt log

00> *** Booting Zephyr OS build zephyr-v2.5.0-159-g2bfaadffb807  ***
00> 
00> [00:00:00.334,259] <inf> main: Hello from Sensor Tag Button example
00> [00:00:00.334,289] <inf> main: Set up button at GPIO_1 pin 9
00> 
00> [00:00:01.334,350] <inf> main: loop: 0
00> [00:00:02.334,442] <inf> main: loop: 1
00> [00:00:03.334,533] <inf> main: loop: 2
00> [00:00:04.334,625] <inf> main: loop: 3
00> [00:00:05.334,716] <inf> main: loop: 4
00> [00:00:06.334,808] <inf> main: loop: 5
00> [00:00:07.334,899] <inf> main: loop: 6
00> [00:00:08.334,991] <inf> main: loop: 7
00> [00:00:09.335,083] <inf> main: loop: 8
00> [00:00:10.335,174] <inf> main: loop: 9
00> [00:00:11.335,266] <inf> main: loop: 10
00> [00:00:12.335,357] <inf> main: loop: 11
00> [00:00:13.335,449] <inf> main: loop: 12
00> [00:00:14.335,540] <inf> main: loop: 13
00> [00:00:15.335,632] <inf> main: loop: 14
00> [00:00:16.335,723] <inf> main: loop: 15
00> [00:00:17.335,815] <inf> main: loop: 16
00> [00:00:18.335,906] <inf> main: loop: 17
00> [00:00:19.335,998] <inf> main: loop: 18
00> [00:00:20.336,090] <inf> main: loop: 19
00> [00:00:21.336,181] <inf> main: loop: 20
00> [00:00:22.336,273] <inf> main: loop: 21
00> [00:00:23.336,364] <inf> main: loop: 22
00> [00:00:24.336,456] <inf> main: loop: 23
00> [00:00:25.336,547] <inf> main: loop: 24
00> [00:00:26.336,639] <inf> main: loop: 25
00> [00:00:27.336,730] <inf> main: loop: 26
00> [00:00:28.336,822] <inf> main: loop: 27
00> [00:00:29.336,914] <inf> main: loop: 28
00> [00:00:30.337,005] <inf> main: loop: 29
00> [00:00:31.337,097] <inf> main: loop: 30
00> [00:00:32.337,188] <inf> main: loop: 31
00> [00:00:32.920,257] <inf> main: Button pressed at 1078731
00> 
00> [00:00:33.282,348] <inf> main: Button pressed at 1090596
00> 
00> [00:00:33.337,249] <inf> main: loop: 32
00> [00:00:34.337,310] <inf> main: loop: 33
00> [00:00:35.337,402] <inf> main: loop: 34
00> [00:00:36.337,493] <inf> main: loop: 35
00> [00:00:37.337,585] <inf> main: loop: 36
00> [00:00:38.337,677] <inf> main: loop: 37
00> [00:00:39.337,768] <inf> main: loop: 38
00> [00:00:40.337,860] <inf> main: loop: 39
00> [00:00:41.337,951] <inf> main: loop: 40
00> [00:00:42.338,043] <inf> main: loop: 41
00> [00:00:43.338,134] <inf> main: loop: 42
00> [00:00:44.338,226] <inf> main: loop: 43
00> [00:00:45.338,317] <inf> main: loop: 44
00> *** Booting Zephyr OS build zephyr-v2.5.0-159-g2bfaadffb807  ***
00> 
00> [00:00:00.250,396] <inf> main: Hello from Sensor Tag Button example
00> [00:00:00.250,396] <inf> main: Set up button at GPIO_1 pin 9
00> 
00> [00:00:01.250,457] <inf> main: loop: 0
00> [00:00:02.250,549] <inf> main: loop: 1
00> [00:00:03.250,640] <inf> main: loop: 2
00> [00:00:04.250,732] <inf> main: loop: 3
00> [00:00:05.250,823] <inf> main: loop: 4
00> [00:00:05.709,991] <inf> main: Button pressed at 187105
00> 
00> [00:00:06.250,915] <inf> main: loop: 5
00> [00:00:07.250,976] <inf> main: loop: 6
00> [00:00:08.251,068] <inf> main: loop: 7
00> [00:00:09.251,159] <inf> main: loop: 8
00> [00:00:10.251,251] <inf> main: loop: 9
00> [00:00:11.251,342] <inf> main: loop: 10
00> [00:00:12.251,434] <inf> main: loop: 11
00> [00:00:13.251,525] <inf> main: loop: 12
00> [00:00:14.251,617] <inf> main: loop: 13
00> [00:00:15.251,708] <inf> main: loop: 14
00> [00:00:16.251,800] <inf> main: loop: 15
00> [00:00:17.251,892] <inf> main: loop: 16
00> [00:00:18.251,983] <inf> main: loop: 17
00> [00:00:19.252,075] <inf> main: loop: 18
00> [00:00:20.252,166] <inf> main: loop: 19
00> [00:00:21.252,258] <inf> main: loop: 20
00> [00:00:22.252,349] <inf> main: loop: 21

08 tag zephyr thread #

Simplest example with thread stack running

  • thread stack added through config only
  • menuconfig only runs on linux or wsl with the command west build -t menuconfig
  • the generated config is under build/zephyr/.config
  • Note that once the openthread config is persisted in non-volatile memory, changing the config would have no effect as the stored config has precedence over code
  • the persisted config can be deleted with ot factoryreset
  • Note that up to Zephyr version zephyr-v2.5.0-159-g2bfaadffb807 the compilation throws an error

Environment variables

  • GNUARMEMB_TOOLCHAIN_PATH = D:\tools\gnu_arm_embedded\9_2020-q2-update
  • ZEPHYR_BASE = D:\Projects\zp\zephyrproject\zephyr
  • ZEPHYR_TOOLCHAIN_VARIANT = gnuarmemb

usage

west build -b nrf52840_sensortag -- -DCONF_FILE=prj-shell.conf
west build -b nrf52840_sensortag -- -DCONF_FILE=prj-log.conf
west flash
default config
#
# Thread Network configuration
#
CONFIG_OPENTHREAD_PANID=43981
CONFIG_OPENTHREAD_CHANNEL=13
CONFIG_OPENTHREAD_NETWORK_NAME="ot_zephyr"
CONFIG_OPENTHREAD_XPANID="de:ad:00:be:ef:00:ca:fe"
CONFIG_OPENTHREAD_MASTERKEY=""
CONFIG_OPENTHREAD_FTD=y
# CONFIG_OPENTHREAD_MTD is not set
CONFIG_OPENTHREAD_MAX_CHILDREN=32
CONFIG_OPENTHREAD_MAX_IP_ADDR_PER_CHILD=6
CONFIG_OPENTHREAD_CONFIG_PLATFORM_INFO="Zephyr"
CONFIG_OPENTHREAD_RADIO_LINK_IEEE_802_15_4_ENABLE=y
# CONFIG_OPENTHREAD_RADIO_LINK_TREL_ENABLE is not set
CONFIG_OPENTHREAD_CSL_SAMPLE_WINDOW=30
CONFIG_OPENTHREAD_CSL_RECEIVE_TIME_AHEAD=3
# CONFIG_OPENTHREAD_SRP_CLIENT is not set
# CONFIG_OPENTHREAD_SRP_SERVER is not set
# end of Thread Network configuration
project shell config
CONFIG_NETWORKING=y
CONFIG_NET_L2_OPENTHREAD=y

CONFIG_OPENTHREAD_CHANNEL=13
CONFIG_OPENTHREAD_PANID=47825

# Disable certain parts of Zephyr IPv6 stack
CONFIG_NET_IPV6_NBR_CACHE=n
CONFIG_NET_IPV6_MLD=n

# Kernel options
CONFIG_MAIN_STACK_SIZE=2048
CONFIG_INIT_STACKS=y

#pios
CONFIG_GPIO=y
CONFIG_SERIAL=n

# Logging
CONFIG_LOG=n
CONFIG_LOG_BACKEND_RTT=n
CONFIG_LOG_BACKEND_UART=n
CONFIG_BOOT_BANNER=y
CONFIG_USE_SEGGER_RTT=y

CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=n
CONFIG_RTT_CONSOLE=y

# shell
CONFIG_SHELL=y
CONFIG_SHELL_BACKEND_RTT=y
CONFIG_SHELL_BACKEND_SERIAL=n
build log
-- west build: generating a build system
Including boilerplate (Zephyr base): D:/Projects/zp/zephyrproject/zephyr/cmake/app/boilerplate.cmake
-- Application: D:/Dev/nrf52/nrf52_thread_sensortag/firmware/08_tag_zephyr_thread
-- Zephyr version: 2.5.99 (D:/Projects/zp/zephyrproject/zephyr)
-- Found Python3: C:/Users/User/AppData/Local/Programs/Python/Python39/python.exe (found suitable exact version "3.9.0") found components: Interpreter
-- Found west (found suitable version "0.10.1", minimum required is "0.7.1")
-- Board: nrf52840_sensortag
-- Cache files will be written to: D:/Projects/zp/zephyrproject/zephyr/.cache
-- Found toolchain: gnuarmemb (D:/tools/gnu_arm_embedded/10 2020-q4-major)
-- Found BOARD.dts: D:/Dev/nrf52/nrf52_thread_sensortag/firmware/boards/arm/nrf52840_sensortag/nrf52840_sensortag.dts
run log
rtt:~$ *** Booting Zephyr OS build zephyr-v2.5.0-2187-g757cd12e6602  ***
ot state
leader

Done

rtt:~$ ot ipaddr
fdde:ad00:beef:0:0:ff:fe00:fc00

fdde:ad00:beef:0:0:ff:fe00:1800

fdde:ad00:beef:0:e004:6a1d:8704:d57f

fe80:0:0:0:38a9:1cd0:752:f538

Done

09 tag zephyr i2c #

  • using i2c_0 device from dts
  • direct transactions with sensors using i2c_reg_read_byte()
config
CONFIG_GPIO=y
CONFIG_SERIAL=n

CONFIG_I2C=y

# Logging
CONFIG_LOG=y
CONFIG_LOG_BACKEND_RTT=y
CONFIG_LOG_BACKEND_UART=n
CONFIG_BOOT_BANNER=y
CONFIG_USE_SEGGER_RTT=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=n
CONFIG_RTT_CONSOLE=y
build log
-- west build: generating a build system
Including boilerplate (Zephyr base): D:/Projects/zp/zephyrproject/zephyr/cmake/app/boilerplate.cmake
-- Application: D:/Dev/nrf52/nrf52_thread_sensortag/firmware/09_tag_zephyr_i2c
-- Zephyr version: 2.5.99 (D:/Projects/zp/zephyrproject/zephyr)
-- Found Python3: C:/Users/User/AppData/Local/Programs/Python/Python39/python.exe (found suitable exact version "3.9.0") found components: Interpreter
-- Found west (found suitable version "0.10.1", minimum required is "0.7.1")
-- Board: nrf52840_sensortag
-- Cache files will be written to: D:/Projects/zp/zephyrproject/zephyr/.cache
-- Found toolchain: gnuarmemb (D:/tools/gnu_arm_embedded/10 2020-q4-major)
-- Found BOARD.dts: D:/Dev/nrf52/nrf52_thread_sensortag/firmware/boards/arm/nrf52840_sensortag/nrf52840_sensortag.dts

...

[146/146] Linking C executable zephyr\zephyr.elf
Memory region         Used Size  Region Size  %age Used
           FLASH:       27168 B         1 MB      2.59%
            SRAM:        7936 B       256 KB      3.03%
        IDT_LIST:          0 GB         2 KB      0.00%
run log
*** Booting Zephyr OS build zephyr-v2.5.0-2187-g757cd12e6602  ***

[00:00:00.327,209] <inf> main: Hello from Sensor Tag I2C example
[00:00:00.327,728] <inf> main: VEML6030 @48 reg[0] 'ALS_CONF' = 1
[00:00:00.328,247] <inf> main: MS8607 @40 'Relative Humidity RH' reg[0xE7] 'user register' = 2
[00:00:00.328,765] <inf> main: MS8607 @76 'Pressure and Temperature' reg[0] 'ADC Read' => 0

flashing #

  • SWD pogo pins adapter
  • Pogo Pin P75-E2 Dia 1.3mm Length 16.5mm

Produced versions #

  • v 1.1 15.04.2021
  • v 1.0 10.02.2021

FAQ - Discussion #

  • If you need support, want to ask a question or suggest a different answer, you can join the discussion on the discord server
Does this Thread SensorTag support MQTT ?
At the moment, a firmware is in preparation that support MQTT-SN which needs an MQTT-SN gateway to connect it to an MQTT broquer. Mode details in the MQTT Sensors Node
Is it possible to save energy by collecting many sensor samples over time and sending them together?

Yes, sure, the use cases could be slpit as follows :

  • For short term buffering, it’s possible to use the RAM retention feature, you pay as you go fine granular (per 4 kB block: 30nA)
  • For long term buffering, we’re no longer on the sensors network use case and rather on the logger tag use case, there you can use the Flash, 1 MB is huge. In my use case, I don’t use buffering in order to allow live update of measures on the user’s apps, but combining like a level trigger to immediately send values on big changes with buffering and sending all the values cyclically could be quite smart, you will need a QoS through to ensure your data is really sent after a while, which will also consume RF transactions, I opted for sending every single value on an RF packet which is also used as an alive signal to know when the sensor is dead or out of reach, so no problem if once a packet is lost in a while, but practically, as I use a flood mesh, most measures arrive more than once to the server. I think after all, such things should be configurable by the end users’s app, and should not be hardcoded