Building and Provisioning a Hubble Beacon on the Silicon Labs EFR32xG26

The Hubble Network delivers device data to the cloud through more than 100 million terrestrial gateways that pick up standard Bluetooth LE advertisements and forward them to the Hubble backend. Instead of requiring a cellular modem or a proprietary radio, Hubble works with many types of existing silicon, like the Silicon Labs EFR32xG26.

The xG26 Dev Kit is built around the EFR32MG26B510F3200IM68, a 32-bit Arm Cortex-M33 with an FPU, 3200 kB of on-chip flash, and 512 kB of RAM. Unlike boards that hand Bluetooth off to a separate co-processor, the EFR32MG26 runs its 2.4 GHz radio on the same core as your application, so there is no second firmware image to flash.

In this guide, you will learn how to turn an xG26 Dev Kit (xG26-DK2608A) into a working Hubble beacon with Zephyr RTOS, and how to move its encryption key out of the compiled firmware and into the board’s flash-backed storage, so the same firmware build works for every device you provision afterward. We will follow a similar process to our previous tutorial, though this tutorial includes steps specific to the EFR32xG26.

Initial Setup

Before you can run Hubble firmware on your EFR32xG26 board, you need to install the core toolchain, set up a Zephyr workspace, and register your device with the Hubble Network.

Install Core Toolchain

You need to install the following tools on your PC in order to develop Zephyr firmware for your dev board:

  • Python 3.10 or newer: Runs the build scripts
  • CMake: Configures the Zephyr build
  • Ninja: Compiles and links the Zephyr firmware
  • West: Zephyr’s command-line build manager
    • Install it with pip install west
  • Zephyr SDK: Contains the cross-compiler that turns your code into runnable firmware on your EFR32xG26
    • Download the latest Zephyr SDK bundle for your PC from the Zephyr SDK releases page, extract it somewhere permanent, such as ~/zephyr-sdk, then run ./setup.sh on macOS or Linux, or setup.cmd on Windows, from inside that folder

Install Flashing Tools

After you finish installing your core toolchain, install the following tools on your PC to help you load firmware onto the dev board itself:

  • J-Link Software Pack: Allows your PC to properly recognize and communicate with your dev board
  • Simplicity Studio: Not needed for the build itself, but recommended for updating the on-board J-Link firmware, which is worth doing before you use a new kit for the first time
  • Simplicity Commander (optional): An alternative flashing path, available in Zephyr as the silabs_commander runner if you would rather not use J-Link

Set Up Your Zephyr Workspace

Your Zephyr workspace is a folder on your PC where the entire EFR32xG26 firmware will live. It consists of Zephyr itself, the board support files, and the Hubble SDK, in a format that West recognizes to correctly build your firmware.

Follow the steps below to properly set up your Zephyr workspace for Hubble development:

  1. Initialize the workspace by running west init -m https://github.com/HubbleNetwork/hubble-device-sdk ~/hubble-workspace
    • This command fetches a manifest describing all the resources your workspace needs
    • It will automatically create a workspace named hubble-workspace. Change the last argument of the command if you want to name your workspace differently or place it in another location on your PC.
  2. Add resources to your workspace by running west update from inside the workspace folder
    • This command downloads Zephyr, the Silicon Labs hardware abstraction layer, and the Hubble SDK
  3. Fetch the Bluetooth controller binary by running west blobs fetch hal_silabs
    • Important because the EFR32xG26’s radio depends on a pre-compiled controller library from Silicon Labs, which Zephyr’s silabs,bt-hci-efr32 driver calls into
    • This library is linked into your application at build time rather than flashed separately, so there is no second programming step here
  4. Install the remaining Python dependencies by running pip install -r ~/hubble-workspace/zephyr/scripts/requirements.txt

Register Your Device With Hubble

Every Hubble device needs a unique AES-256 key in order to authenticate and connect to the Hubble Network. The steps below will guide you to quickly obtain a key for your EFR32xG26 board.

  1. Log in to your Hubble developer account at dash.hubble.com
    • If you do not already have an account, you can create a new one using the same link
  2. Select Add a Device at the top right corner of the dashboard, then select I just need a Device Key
Hubble dashboard Add a Device dialog with the I just need a Device Key option selected
  1. Enter a device name, such as dev_board, and leave the remaining fields at their default values. Select Register device to proceed
Hubble dashboard device registration form with a device name entered
  1. Save the Device Key shown
Hubble dashboard displaying the generated Device Key for the new device

Part 1: Turn Your EFR32xG26 Dev Kit Into a Hubble Beacon

Once you have completed the initial setup, the sample Zephyr application in the Hubble SDK handles most of the remaining work to turn your EFR32xG26 into a Hubble beacon. Generate your key, build the firmware, flash it, and confirm the board is broadcasting.

Generate Your Encryption Key

The Hubble SDK includes an embed_key_time.py script that generates an encryption key from the device key you got from the Hubble device registration.

To use the script, first navigate to the Hubble beacon sample application in your workspace ~/hubble-workspace/modules/lib/hubblenetwork-sdk/samples/zephyr/ble-beacon. Then, save your device key in a plain text file named master.key in that directory. In the same folder, run the following command:

python ../../../tools/embed_key_time.py -b master.key -o ./src

In /src, you’ll see key.c, which is the encryption key your EFR32xG26 will use to connect to the Hubble Network.

Build and Flash the Firmware

With key.c in place, you can build your firmware. From your workspace, run the command:

west build -p -b xg26_dk2608a modules/lib/hubblenetwork-sdk/samples/zephyr/ble-beacon

The -p flag forces a clean build, and -b xg26_dk2608a tells the toolchain to build firmware for your xG26 Dev Kit. Once your firmware is built, connect the kit over USB and flash it with the command:

west flash

west flash programs the board through the on-board J-Link. Two things to check if the flash doesn’t succeed:

  • Make sure the J-Link tools are installed and on your PATH. If west reports that it can’t find the J-Link executable, install the J-Link Software Pack and add its install folder to your PATH.
  • Make sure the kit’s debugger firmware is current. If your PC doesn’t recognize the kit, or flashing stalls partway through, open Simplicity Studio and update the on-board J-Link firmware. You can also fall back to Simplicity Commander with west flash -r silabs_commander.

Because the Bluetooth controller library was linked into the image you just programmed, the radio is ready and the board can begin advertising as soon as the application boots.

Verify the Beacon Works

After you flash Hubble firmware onto your board for the first time, it’s important to confirm your Hubble beacon is actually broadcasting. Connect a serial terminal to your board, and check for log output showing the Hubble SDK initialized and started advertising. Also, open your Hubble dashboard and check the logs of your device’s activity.

Hubble dashboard showing activity logs for the EFR32xG26 device

Part 2: Store Your Hubble Encryption Key in NVS

Now that you have a working Hubble beacon, it’s time to move your encryption key out of the firmware and into the board’s flash-backed storage. The problem with keeping the key in the firmware is that if you are managing a fleet of identical Hubble devices, you need a separate firmware image for each device. If the key is stored on each device outside of the firmware image, you can maintain one image for many devices without worry.

Moving the key out of the firmware image takes two changes. First, the firmware needs to read the key from flash-backed storage instead of a compiled-in array, which means enabling Zephyr’s NVS support and adding a settings handler that loads the key at boot. Second, once that updated firmware is running, write the actual key into flash over the same serial connection used to verify the beacon, since the board only accepts that write after the new firmware is in place.

Find the Right Flash Region for the Key

First, you need to find the right region of flash memory for your encryption key. The EFR32MG26 boots from its 3200 kB of on-chip flash, and Zephyr’s board definition already splits that flash into partitions. Alongside the mcuboot region and the two 1560 kB application image slots, the board reserves a 32 KiB partition labeled storage at flash offset 0x318000. Zephyr’s NVS and Settings subsystems look for a partition with that exact label by default, so the xG26 Dev Kit needs no devicetree overlay to use them. Because this region sits above both application image slots, rebuilding or reflashing your firmware never touches it, and a key written there survives every future build.

Note: The xG26 Dev Kit also carries a Macronix MX25R6435F 64 Mbit SPI-NOR flash chip, but the default storage partition — and therefore your key — lives on the EFR32MG26’s internal flash. Therefore, the internal flash is the easiest one to use for this tutorial.

Enable Flash Storage in Your Build

Next, enable Zephyr’s flash storage subsystems. Add the following to prj.conf in your ble-beacon sample:

CONFIG_FLASH=y
CONFIG_FLASH_MAP=y
CONFIG_NVS=y
CONFIG_SETTINGS=y
CONFIG_SETTINGS_NVS=y
CONFIG_SHELL=y
CONFIG_SETTINGS_SHELL=y

That last option, CONFIG_SETTINGS_SHELL, adds a settings command to the serial shell, giving you a way to write the key into flash without touching your build at all. It’s also worth adding CONFIG_LOG=y (and CONFIG_LOG_BACKEND_UART=y) so the beacon’s status messages appear in your serial terminal.

Update Your Firmware

Now, it’s time to update the application code itself in main.c. Start by removing the #include "key.c" line, since the key no longer needs to compile into your application. Register a settings handler instead, one that copies the stored key into a runtime buffer whenever Zephyr loads settings at startup:

#include <zephyr/settings/settings.h>

static uint8_t stored_key[CONFIG_HUBBLE_KEY_SIZE];
static bool key_loaded;

// Called by settings_load() for any stored entry named "hubble/key"
static int hubble_key_settings_set(const char *name, size_t len,
                                    settings_read_cb read_cb, void *cb_arg)
{
	if (len != sizeof(stored_key)) {
		return -EINVAL;
	}
	// read_cb copies the stored bytes into stored_key
	if (read_cb(cb_arg, stored_key, sizeof(stored_key)) < 0) {
		return -EIO;
	}
	key_loaded = true;
	return 0;
}

// Registers the handler above for the "hubble/key" settings entry
SETTINGS_STATIC_HANDLER_DEFINE(hubble_key, "hubble/key", NULL,
				hubble_key_settings_set, NULL, NULL);

In main(), call settings_subsys_init() and settings_load() before your existing call to hubble_init(), then pass stored_key in place of master_key. Your updated code should look like the following:

int main(void)
{
	int err = 0;
	size_t out_len;

	LOG_DBG("Hubble Network BLE Beacon started");

	/* Synchrounosly initialize the Bluetooth subsystem. */
	err = bt_enable(NULL);
	if (err != 0) {
		LOG_ERR("Bluetooth init failed (err %d)", err);
		return err;
	}

#ifdef CONFIG_HUBBLE_BEACON_SAMPLE_USE_CTS
	err = hubble_ble_time_sync();
	if (err != 0) {
		LOG_ERR("Could not get unix_time time synced !");
		goto end;
	}
#endif /* CONFIG_HUBBLE_BEACON_SAMPLE_USE_CTS */

	// Load saved encryption key from NVS
	settings_subsys_init();
	// Triggers hubble_key_settings_set() if a key is stored
	settings_load();
	if (!key_loaded) {
		// No key found in flash, so nothing has been provisioned yet
		LOG_ERR("No Hubble key found in NVM; halting.");
		goto end;
	}

	// stored_key replaces the old master_key
	err = hubble_init(unix_time, stored_key);
	if (err != 0) {
		LOG_ERR("Failed to initialize Hubble BLE Network");
		goto end;
	}

Rebuild and reflash with the same west build and west flash commands from before. On this first boot, no key exists in flash yet, so your beacon should stay silent (and, with logging enabled, print No Hubble key found in NVM; halting.).

Write the Key into NVS

Once you’ve flashed the updated firmware, you need to write the actual encryption key into your board’s flash storage over the serial shell.

The settings shell stores values as raw bytes in hexadecimal unless you tell it otherwise, but your Hubble device key is Base64-encoded, so you need to convert it to hex first. You can use the following command in Windows Powershell to get the hex version of the encryption key:

[System.BitConverter]::ToString([Convert]::FromBase64String("YOUR_BASE64_DEVICE_KEY")).Replace("-","").ToLower()

The result should be 64 hex characters for an AES-256 key (32 bytes). Then, in your serial terminal, write the hex key:

settings write hubble/key <your-hex-key>

Confirm it was written correctly with the command:

settings read hubble/key

This last command should print an exact copy of your encryption key in hex. Below is an example of the output you should see:

Serial shell output showing settings write and settings read confirming the stored hubble/key value in hex

Confirm the Key Actually Persists

Writing the key once isn’t proof that it survives long term, so it’s important to confirm that next. Reset the board without reprovisioning it, and the device should show up on your Hubble dashboard again within a minute. That confirms the key survives a power cycle, but it doesn’t yet prove it lives outside the firmware image. For that, rebuild and reflash the application from scratch, then reset the board once more, still without running settings write again. If the device still transmits data to the Hubble Network, the key survived a complete firmware rewrite, confirming it lives in the separate storage partition instead of the image you just replaced.

Hubble dashboard confirming the EFR32xG26 still transmits data after a full firmware rewrite

Provision More Than One Board

Once a single xG26 Dev Kit holds its key in flash, the same firmware image works for every board you build afterward. You no longer need a unique compiled binary per device, and updating the beacon application no longer risks touching device-specific data. Hubble describes several patterns for provisioning devices at scale, and the approach you learned here can easily be applied to the field. Flash one firmware image everywhere, then write each board’s own key over serial, or through your own provisioning fixture, as the last step before shipping your device fleet.


Ready to connect your devices anywhere on Earth? Get started with Hubble Network for free →