---
title: "Walkthrough: Nordic nRF54L15 Boards over Bluetooth LE"
description: "Walkthrough: Nordic nRF54L15 Boards over Bluetooth LE"
---

[Skip to content](https://portal.sandgrain.eu/knowledge-base/what-question-is-your-article-answeringwalkthrough-nordic-nrf54l15-boards-over-bluetooth-le#main-content)

English

Show submenu for translations

![SandGrain\_Logo\_RGB\_white-bijgesneden (1)](https://portal.sandgrain.eu/hs-fs/hubfs/SandGrain_Logo_RGB_white-bijgesneden%20(1).png?width=427&height=83&name=SandGrain_Logo_RGB_white-bijgesneden%20(1).png)

Open main navigation

Close main navigation

- English
  
  Show submenu for translations
- [Contact us](https://portal.sandgrain.eu/login)

[Contact us](https://portal.sandgrain.eu/login?hsLang=en)

 How can we help you?

- There are no suggestions because the search field is empty.

1. [Knowledge Base](https://portal.sandgrain.eu/knowledge-base?hsLang=en)
2. [SDK](https://portal.sandgrain.eu/knowledge-base/sdk?hsLang=en)
3. [SandGrain SDK](https://portal.sandgrain.eu/knowledge-base/sdk?hsLang=en#sandgrain-sdk)

October 6, 2026

# Walkthrough: Nordic nRF54L15 Boards over Bluetooth LE

**Who this is for:** Developers running the Bluetooth LE variant of the SDK, where the device SDK runs on real Nordic nRF54L15 boards instead of a USB Token on a PC.

**What you'll accomplish:** Set up and run the full demonstration: one or more Nordic boards authenticate to the cloud over Bluetooth LE, through a Raspberry Pi gateway, against the TrustBridge stack on a laptop.

**This variant uses different git branch from the rest of the SDK.**  [`release/v3.6.1`](https://github.com/SandGrain-CyberRock/SandGrain-TrustBridgeSDK/tree/release/v3.6.1)

Don't mix these with the [`release/v3.6.0`](https://github.com/SandGrain-CyberRock/SandGrain-TrustBridgeSDK/tree/release/v3.6.0) instructions in the other walkthroughs.

### How this topology works

Three things talk to each other:

- One or more **Nordic nRF54L15 boards** are the devices being authenticated. Each board carries a SandGrain SGT1001 security chip.
- One **Raspberry Pi** acts as the **gateway**: a small computer that talks to the boards wirelessly and forwards their messages to the cloud.
- One **laptop or PC** runs the **TrustBridge stack** locally inside Docker.

The boards talk to the gateway over **Bluetooth Low Energy (BLE)** (the same low-power wireless used by fitness trackers and smart sensors). The gateway talks to the laptop over the normal network (Wi-Fi or Ethernet).

```
Board 1 (nRF54L15)                                Laptop / PC  ┌─────────────────┐   Bluetooth   ┌──────────────┐  Network    ┌─────────────────┐              ┌──────────────┐          ┌──────────────┐  │ SandGrain device│◀───────────▶ │ Raspberry Pi │◀────────▶│ TrustBridge  │    │ + security chip │              │ gateway      │          │ (Docker)     │    └─────────────────┘              │ one wireless │          └──────────────┘  Board 2 (nRF54L15)                 │ channel per  │   ┌─────────────────┐   Bluetooth   │ board        │   │ SandGrain device│◀───────────▶  └──────────────┘   └─────────────────┘ 
```

Each board proves to the cloud that it is genuine, and the cloud proves to the board that it is genuine. This two-way check is **mutual authentication**. Several boards can run it at the same time through one gateway.

### What you need

- One or more **Nordic nRF54L15-DK** boards, each fitted with its SGB chip, plus a USB cable per board.
- A **Raspberry Pi** (with built-in Bluetooth) for the gateway, running Raspberry Pi OS with network access.
- A **laptop or PC** with Docker installed, on the same network as the Pi.
- A Windows, Linux, or macOS PC for programming the boards (can be the same laptop). Only needed if a board doesn't already have the SandGrain software on it.
- The **SandGrain SDK** (as a zip file, or from the project's GitHub repository).

### Three ideas to know first

Reading this before you start makes everything else clearer.

- **Advertising.** A board announces itself over Bluetooth under the name `SandGrain-Dev`, like a name tag it broadcasts. The gateway continuously looks (**scans**) for name tags starting with `SandGrain-Dev` and connects to each board it finds.
- **Channels.** The gateway serves one board per **channel** (think of a channel as one reserved seat). It's built for a fixed number of seats (2 by default). See *Serving more boards* below to change that.
- **TID, the device identity.** Every SGB chip has a unique identity number, the **TID** (a 64-character code starting with `8000...`). The cloud only accepts devices whose TID has been registered (**enrolled**) beforehand. Every board must be enrolled once.

### Step 1 - Laptop: start the TrustBridge Docker stack

The stack (frontend, backend, cloud, and Mosquitto broker) runs on the laptop inside Docker. From the `TrustBridge-BE` folder, on the `release/v3.6.1` branch:

```
git checkout release/v3.6.1cd TrustBridge/TrustBridge-BE./start-all.ps1        # Windows ./start-all.sh         # Linux/macOS docker compose ps 
```

`docker compose ps` should list the services as running. This brings up:

- the **message broker** on port **1883** (the post office that passes messages between the gateway and the cloud)
- the **TrustBridge application** (backend on port **3000**, plus the web page you open in a browser)

> **![Terminal listing the TrustBridge Docker services with status "running".](https://portal.sandgrain.eu/hs-fs/hubfs/image48-png.png?width=670&height=52&name=image48-png.png)**`docker compose ps` output showing the TrustBridge services running.

### Find the laptop's network address

The Pi needs to reach the laptop. On the laptop, run `ipconfig` (Windows) and note the IPv4 address (something like `192.168.12.10`). This guide calls it `<LAPTOP_IP>`. Wherever you see `<LAPTOP_IP>`, type that address.

If the gateway later can't reach the laptop, allow ports **1883** and **3000** through the laptop's firewall.

### Enroll every board

Each board must be registered in TrustBridge before it can authenticate:

1. **Read the board's TID.** Connect to the board with a serial terminal (see *Step 4 - Talk to a board*) and choose menu option `0`. The board runs a self-test and prints its TID, the 64-character code starting with `8000...`.
2. **Enroll that TID** in the TrustBridge web page.
3. **Repeat for every board.** Two boards means two enrollments, each with its own TID.

### Step 2 - Raspberry Pi: set up the gateway

Copy the SandGrain SDK onto the Pi and check out the `multi-ble-gateway` branch.

**Don't copy the folder directly from a Windows PC to the Pi** - Windows line endings break the build. Either clone from GitHub directly on the Pi, or on Windows create a clean archive with `git archive --format=tar.gz -o sdk.tar.gz multi-ble-gateway` and extract that on the Pi.

### One-time setup

```
git checkout release/v3.6.1 cd SandGrain-SDK/PoC_SDK_v3/poc_sdk_gateway ./scripts/pi_ble_gateway_setup.sh --broker <LAPTOP_IP>
```

The script installs everything the gateway needs, builds the gateway program (`test_gw`), grants it permission to use Bluetooth, and writes a settings file. It takes a few minutes on the first run.

> **![Raspberry Pi terminal showing the BLE gateway setup script running to completion.](https://portal.sandgrain.eu/hs-fs/hubfs/image49-png.png?width=670&height=361&name=image49-png.png)**Output of `pi_ble_gateway_setup.sh` installing dependencies and building the gateway.

### Check the settings file

Confirm it points at the laptop:

```
cat app/.env.ble.gateway 
```

You should see:

```
MQTT_BROKER=<LAPTOP_IP> MQTT_PORT=1883 MQTT_USER=sandgrain MQTT_PASS=admin BE_URL=http://<LAPTOP_IP>:3000/api 
```

The username and password must match the message broker's credentials on the laptop. To edit the file:

```
nano app/.env.ble.gateway 
```

Save with `Ctrl + X`, then `Y`, then `Enter`. Verify again with `cat app/.env.ble.gateway`.

> **![nano editor showing the gateway MQTT and backend settings.](https://portal.sandgrain.eu/hs-fs/hubfs/image52-png.png?width=670&height=373&name=image52-png.png)**Editing `.env.ble.gateway` in nano.

> **![terminal showing the corrected .env.ble.gateway contents.](https://portal.sandgrain.eu/hs-fs/hubfs/image51-png.png?width=670&height=131&name=image51-png.png)**`cat` output confirming the saved settings.

---

### Step 3 - Run the gateway

```
cd PoC_SDK_v3/poc_sdk_gateway/app ./run_ble_gateway.sh 
```

Before any board is set up, expect this message:

```
[COMM_BLE] no unbound 'SandGrain-Dev*' peripheral found in scan (2 channel(s) waiting) 
```

That's normal until a board is running.

### What a good start looks like

Once boards are up, the gateway connects to the laptop, then starts scanning:

```
scanning for BLE peripherals 'SandGrain-Dev*' 
```

For every powered board it finds, it prints a short sequence ending in:

```
[ch0] ... link ready 
```

One `link ready` line per board. The channel numbers `[ch0]`, `[ch1]`, ... tell the boards apart in the log.

> **![Raspberry Pi terminal showing the BLE gateway scanning and reporting a board link as ready.](https://portal.sandgrain.eu/hs-fs/hubfs/image54-png.png?width=670&height=369&name=image54-png.png)**Gateway log showing `link ready` for a connected board.

### Serving more boards

The gateway is built for 2 boards unless told otherwise. To serve three, rebuild it once on the Pi with the channel count set to 3:

```
cd PoC_SDK_v3/poc_sdk_gateway/app make clean && make GW_BLE=1 GW_BLE_DEVICES=3 sudo setcap 'cap_net_raw,cap_net_admin+eip' ./test_gw 
```

The last line re-grants the freshly built program its Bluetooth permission.

#### Good to know:

- If fewer boards are switched on than the gateway has channels, the spare channels simply keep scanning. That's harmless.
- Every board you add must also be enrolled in TrustBridge (see *Enroll every board* above).

### Step 4 - Nordic boards: program and operate

Each board runs the SandGrain device SDK. If your boards were delivered already programmed, skip to *Talk to a board* below.

### One-time: install the build tools (Windows / Linux / macOS)

Programming a board (**flashing**) needs Nordic's free development tools. Two ways to install them, both ending with the same result:

#### **Option A - through VS Code (recommended):**

1. Install Visual Studio Code from `https://code.visualstudio.com`.
2. In VS Code, open the Extensions panel (`Ctrl + Shift + X`) and install the **nRF Connect for VS Code Extension Pack**.
3. Open the nRF Connect panel in the sidebar, choose **Install Toolchain**, then **Manage SDKs**, and install SDK version **v3.3.0**.

> **![VS Code nRF Connect panel installing the toolchain and SDK version 3.3.0.](https://portal.sandgrain.eu/hs-fs/hubfs/image55-png.png?width=440&height=410&name=image55-png.png)**
> 
> nRF Connect toolchain and SDK v3.3.0 install in VS Code.

#### **Option B - through nRF Connect for Desktop:**

1. Install **nRF Connect for Desktop** from `https://www.nordicsemi.com/Products/Development-tools/nRF-Connect-for-Desktop`.
2. Open its **Toolchain Manager** and install SDK version **v3.3.0**.

Finally, install the **SEGGER J-Link** drivers from `https://www.segger.com/downloads/jlink/` (choose the "J-Link Software and Documentation Pack"). These let the PC program the board and talk to it over USB. On Linux or macOS, pick the matching J-Link package from the same page.

**Linux only:** install Nordic's USB permission rules from `https://github.com/NordicSemiconductor/nrf-udev` so the board can be programmed without administrator rights.

### Build and flash a board

Connect the board to the PC by USB.

#### **Windows (PowerShell), in the `sandgrain-sdk` folder:**

```
git checkout nrf54l15-ble-device git branch cd PoC_SDK_v3\poc_sdk_device_nrf .\flash_device.ps1 
```

> **![PowerShell output building the Nordic firmware and flashing the nRF54L15 board.](https://portal.sandgrain.eu/hs-fs/hubfs/image56-png.png?width=670&height=308&name=image56-png.png)![PowerShell output building the Nordic firmware and flashing the nRF54L15 board.](https://portal.sandgrain.eu/hs-fs/hubfs/image57-png.png?width=670&height=364&name=image57-png.png)![PowerShell output building the Nordic firmware and flashing the nRF54L15 board.](https://portal.sandgrain.eu/hs-fs/hubfs/image58-png.png?width=670&height=361&name=image58-png.png)**`flash_device.ps1` finding the tools, building, and programming the board.

The script finds the installed tools by itself, builds the software, and programs the board. When it finishes, the board restarts and is ready. Add `-Monitor` to open a serial terminal right away. If more than one board is connected, add `-Snr <serial-number>` to pick which one (the serial number is on the board's J-Link label).

#### **Linux or macOS,** use the shell script instead (same folder, same behavior):

```
git checkout nrf54l15-ble-device cd PoC_SDK_v3/poc_sdk_device_nrf chmod +x flash_device.sh    # first time only ./flash_device.sh 
```

Its options use two dashes: `--monitor` opens the serial monitor after flashing, `--no-flash` builds only, and `--snr <serial-number>` picks a board when more than one is connected.

The very first run on a machine may pause to download a small Nordic flashing component (the `nrfutil device` command). This needs an internet connection and happens only once.

### Talk to a board (the serial terminal)

The board is operated through a **serial terminal**, a text window on the PC connected over the board's USB cable. Settings: the board's COM port at speed **115200**.

Use a terminal program that can *send* keystrokes, not just display output. For example PuTTY, Visual Studio's Serial Monitor, or:

```
python -m serial.tools.miniterm COM3 115200 
```

Your COM port number may differ (Windows Device Manager lists it under "Ports"). On Linux the board appears as `/dev/ttyACM0` (or similar); on macOS as `/dev/tty.usbmodem...`. Use that name in the same command. The board exposes two serial ports - if the menu doesn't appear on the first, try the other. Running `./flash_device.sh --monitor` finds the port by itself.

When the board starts, it prints a welcome banner, its self-test result including the TID, and then a menu. The two options you need:

- `0` - self-test; prints the board's TID (used once, for enrollment)
- `1` - runs the mutual authentication

If pressing a key does nothing, the terminal program is display-only. Switch to one of the programs named above.

> **![serial terminal displaying the Nordic board's self-test, TID, and option menu.](https://portal.sandgrain.eu/hs-fs/hubfs/image59-png.png?width=670&height=247&name=image59-png.png)**Board serial terminal showing the welcome banner, TID, and menu.

### Running several boards

Several boards work with no software changes:

- All boards may keep the same broadcast name `SandGrain-Dev`. The gateway tells them apart by their unique Bluetooth hardware addresses, so identical names don't clash (the only downside is cosmetic: the log shows the same name on every channel).
- Each board must be enrolled in TrustBridge with its own TID.
- The gateway must be built with at least as many channels as boards.
- Power the boards on in any order; the gateway keeps scanning and picks up each one as it appears.

### Step 5 - Run the demonstration

Assuming the one-time setup is done:

1. **Laptop:** start the cloud (Step 1) if it isn't running. All board TIDs enrolled.
2. **Boards:** plug in / power on every board. They start broadcasting immediately.
3. **Raspberry Pi:** start the gateway (Step 3). Watch it print one `link ready` per board.
4. **Each board:** in its serial terminal, press `1` to start the mutual authentication. You can trigger all boards at once; the gateway handles them side by side.

#### **What success looks like:**

- **Gateway log:** interleaved lines per channel (`[CH0]`, `[CH1]`, ...) walking through the authentication steps, each ending in `AUTH_OK`.
- **Each board's terminal:** `MUTUAL AUTH OK`.
- **TrustBridge web page:** a successful authentication shown for each device.

The start order isn't strict. A board powered on late is found by the gateway's next scan; a gateway started before the boards simply waits.

> **![gateway terminal showing per-channel authentication steps completing.](https://portal.sandgrain.eu/hs-fs/hubfs/image60-png.png?width=670&height=356&name=image60-png.png)**Gateway log showing the authentication steps ending in `AUTH_OK`.

> **![serial terminal showing a successful mutual authentication on the board.](https://portal.sandgrain.eu/hs-fs/hubfs/image61-png.png?width=670&height=248&name=image61-png.png)**Board terminal showing `MUTUAL AUTH OK`.

### Mutual authentication flow with TrustBridge

With devices registered on TrustBridge, they can be claimed and a full mutual authentication flow started.

> **![TrustBridge web page enrolling a new device called nrfBLE.](https://portal.sandgrain.eu/hs-fs/hubfs/image62-png.png?width=670&height=279&name=image62-png.png)**Registering a new device named `nrfBLE` in TrustBridge.

> **![Raspberry Pi terminal with the BLE gateway active.](https://portal.sandgrain.eu/hs-fs/hubfs/image63-png.png?width=670&height=354&name=image63-png.png)**The gateway running.

> **![serial monitor connected to the running board.](https://portal.sandgrain.eu/hs-fs/hubfs/image64-png.png?width=670&height=249&name=image64-png.png)**The device monitored through the serial monitor.

Enter `1` in the input box at the bottom of the serial monitor and press Enter to start the mutual authentication flow.

> **![serial monitor input box with the value 1 entered.](https://portal.sandgrain.eu/hs-fs/hubfs/image65-png.png?width=670&height=249&name=image65-png.png)**Entering `1` in the serial monitor to start the flow.

> **![serial monitor showing Mutual Authentication OK.](https://portal.sandgrain.eu/hs-fs/hubfs/image66-png.png?width=670&height=360&name=image66-png.png)**`Mutual Authentication OK` at the end of the serial output.

> **![TrustBridge web page showing a successful authentication for the device.](https://portal.sandgrain.eu/hs-fs/hubfs/image67-png.png?width=670&height=359&name=image67-png.png)**The same result verified on TrustBridge.

### Restarts and recovery

The system cleans up after itself:

- A board can be unplugged or restarted at any time. The gateway first tries to reconnect directly; if the board stays away, it forgets it and re-finds it by scanning as soon as it's back.
- The gateway can be stopped (Ctrl-C) and restarted at any time. It re-finds all boards on its own.
- No fixed order is required after any restart.

### Troubleshooting

| Problem | What to check |
| --- | --- |
| The gateway never finds a board | Is the board powered? On the Pi, run `rfkill unblock bluetooth` (the system can switch Bluetooth off) and restart the gateway. |
| The gateway reports a Bluetooth permission error | Start it with `./run_ble_gateway.sh` (this uses the version with permissions granted), or run `sudo -E ./test_gw`. |
| The gateway cannot reach the laptop | Wrong `<LAPTOP_IP>` in the settings file, or the laptop firewall is blocking ports 1883/3000. |
| Authentication fails at the cloud | That board's TID isn't enrolled in TrustBridge, or the username/password in the gateway settings file doesn't match the message broker. |
| All boards connect but only one authenticates | Nothing is wrong. Authentication starts on each board only when you press `1` on that board. |
| Pressing `1` on the board does nothing | The terminal program is display-only. Use PuTTY or miniterm (see *Talk to a board*). |
| The board can't be flashed, "COM port busy" | Close the serial terminal window before flashing, then reopen it afterward. |
| A board authenticated before but fails after being moved/re-powered | Wait a few seconds; the gateway reconnects on its own. If the log shows it "gave up", it re-finds the board on the next scan automatically. |

### Quick reference

| Item | Value |
| --- | --- |
| Board broadcast name | `SandGrain-Dev` |
| Serial terminal speed | 115200 |
| Board menu: print TID | option `0` |
| Board menu: run authentication | option `1` |
| Message broker port (laptop) | 1883 |
| TrustBridge backend port (laptop) | 3000 |
| Gateway settings file (Pi) | `PoC_SDK_v3/poc_sdk_gateway/app/.env.ble.gateway` |
| Gateway start command (Pi) | `./run_ble_gateway.sh` |
| Gateway channel count | build option `GW_BLE_DEVICES=<n>` (default 2) |
| Software branches | laptop: `trustbridge-0.4`, Pi gateway: `multi-ble-gateway`, board: `nrf54l15-ble-device` |

 

- [User Documentation](https://portal.sandgrain.eu/knowledge-base/user-documentation?hsLang=en#main-content)

    - [Quick Starter Guide](https://portal.sandgrain.eu/knowledge-base/user-documentation?hsLang=en#quick-starter-guide)
    - [User Manual](https://portal.sandgrain.eu/knowledge-base/user-documentation?hsLang=en#user-manual)
    - [Whitepaper](https://portal.sandgrain.eu/knowledge-base/user-documentation?hsLang=en#whitepaper)
    - [Token Leaflet](https://portal.sandgrain.eu/knowledge-base/user-documentation?hsLang=en#token-leaflet)
    - [Claim Token Procedure](https://portal.sandgrain.eu/knowledge-base/user-documentation?hsLang=en#claim-token-procedure)
    - [Daisy Chain](https://portal.sandgrain.eu/knowledge-base/user-documentation?hsLang=en#daisy-chain)
    - [Release Note](https://portal.sandgrain.eu/knowledge-base/user-documentation?hsLang=en#release-note)
    - [Naming Convention](https://portal.sandgrain.eu/knowledge-base/user-documentation?hsLang=en#naming-convention)
    - [SandGrain SDK](https://portal.sandgrain.eu/knowledge-base/user-documentation?hsLang=en#sandgrain-sdk)
    - [TrustBridge](https://portal.sandgrain.eu/knowledge-base/user-documentation?hsLang=en#trustbridge)
- [API Documentation](https://portal.sandgrain.eu/knowledge-base/api-documentation?hsLang=en#main-content)

    - [Device API Integration](https://portal.sandgrain.eu/knowledge-base/api-documentation?hsLang=en#device-api-integration)
    - [Daisy Chain and Attestation](https://portal.sandgrain.eu/knowledge-base/api-documentation?hsLang=en#daisy-chain-and-attestation)
- [SDK](https://portal.sandgrain.eu/knowledge-base/sdk?hsLang=en#main-content)

    - [Core Functions](https://portal.sandgrain.eu/knowledge-base/sdk?hsLang=en#core-functions)
    - [SandGrain SDK](https://portal.sandgrain.eu/knowledge-base/sdk?hsLang=en#sandgrain-sdk)

[![SandGrain\_Logo\_RGB\_white-bijgesneden (1)-1](https://portal.sandgrain.eu/hs-fs/hubfs/SandGrain_Logo_RGB_white-bijgesneden%20(1)-1.png?width=427&height=83&name=SandGrain_Logo_RGB_white-bijgesneden%20(1)-1.png "SandGrain_Logo_RGB_white-bijgesneden (1)-1")](https://portal.sandgrain.eu/?hsLang=en)

<https://www.facebook.com/> <https://www.twitter.com/> <https://www.instagram.com/> <https://podcasts.apple.com/> [mailto:email@email.com](mailto:email@email.com)

Copyright © 2026, sandgrain.eu