IPDL - 13: 6LoWPAN Protocol Demonstration
Mini Project: Thread / 6LoWPAN Communication Using XIAO nRF52840
1. Project Title
Implementation of IPv6-Based Thread/6LoWPAN Communication Using Two XIAO nRF52840 Boards
2. Project Objective
The objective of this mini project is to implement a small Thread-based IPv6 wireless network using two Seeed Studio XIAO nRF52840 boards.
The project demonstrates how two low-power IEEE 802.15.4 devices can communicate using the following protocol stack:
IEEE 802.15.4 → Thread → 6LoWPAN → IPv6 → UDP → Application Data
The project specifically demonstrates:
- Setting up the XIAO nRF52840 development environment.
- Installing the Nordic nRF Connect SDK and nRF Connect for Visual Studio Code.
- Understanding and using OpenThread firmware.
- Flashing OpenThread firmware onto XIAO nRF52840 boards using the UF2 bootloader.
- Configuring one XIAO as a Thread Leader.
- Configuring a second XIAO as a Thread Child.
- Creating an Operational Dataset on the Leader.
- Transferring the Leader's dataset to the Child.
- Allowing the Child to join the Thread network.
- Obtaining IPv6 addresses from both nodes.
- Testing IPv6 connectivity using
ping. - Establishing UDP communication between the two XIAOs.
- Sending application messages over IPv6/UDP through the Thread network.
The final practical demonstrates that a small embedded device can participate in an IPv6-based low-power wireless network without using conventional Wi-Fi or Ethernet.
3. What is 6LoWPAN?
6LoWPAN stands for:
IPv6 over Low-Power Wireless Personal Area Networks.
It is a technology that allows IPv6 packets to be transported over IEEE 802.15.4 networks, which have much smaller frames and considerably lower resources than conventional Ethernet or Wi-Fi networks.
IEEE 802.15.4 provides the low-power wireless radio/link layer, while 6LoWPAN provides mechanisms needed to carry IPv6 traffic over that constrained link.

6LoWPAN is particularly useful for:
- IoT devices
- Sensor networks
- Smart-home devices
- Industrial sensing
- Battery-powered nodes
- Mesh networks
4. What is Thread?
Thread is a low-power, IPv6-based mesh networking protocol designed for IoT devices. Thread uses IEEE 802.15.4 at the wireless link layer and provides an IPv6-based networking architecture. In this project, Thread provides the network layer between the two XIAO boards.
Thread therefore makes it possible for the XIAO boards to communicate using IPv6 addresses while the actual wireless transmission takes place through the nRF52840's IEEE 802.15.4 radio.
5. What is a XIAO nRF52840?
The Seeed Studio XIAO nRF52840 is a very small development board based on Nordic Semiconductor's nRF52840 microcontroller.
The nRF52840 contains a 64 MHz ARM Cortex-M4F processor and supports wireless technologies including Bluetooth Low Energy and IEEE 802.15.4. The XIAO board provides USB connectivity, GPIO, analog interfaces and other peripherals in a very small form factor.
The XIAO nRF52840 is particularly suitable for this project because the nRF52840 provides the IEEE 802.15.4 radio required for Thread.
Important hardware features include:
- Nordic nRF52840 MCU
- ARM Cortex-M4F processor
- 64 MHz operation
- IEEE 802.15.4 capability
- Bluetooth 5 capability
- USB Type-C
- GPIO
- ADC
- SPI
- I²C
- UART
- NFC
- On-board antenna
- USB bootloader
The XIAO nRF52840 Sense additionally includes sensors such as an IMU and microphone.
For this project, the important feature is not the sensors. The important feature is the nRF52840's IEEE 802.15.4 capability.
6. Hardware Required
Hardware
- 2 × Seeed Studio XIAO nRF52840 or XIAO nRF52840 Sense
- 2 × USB Type-C data cables
- Windows PC
- Internet connection
Optional:
- Sensors
- LEDs
- Breadboard
- Jumper wires
The basic Thread/6LoWPAN experiment does not require any external sensor.
7. Software Required
Install the following:
- Visual Studio Code
- nRF Connect for Visual Studio Code
- nRF Connect SDK
- nRF Connect SDK Toolchain
- Required Nordic utilities/drivers
- USB drivers as required by the development environment
Nordic currently recommends using Visual Studio Code together with nRF Connect for VS Code for nRF Connect SDK development. The nRF Connect extension provides the development environment for building, flashing and monitoring nRF Connect SDK applications.
8. Setting Up Nordic Development Environment in Visual Studio Code
Step 1 — Install Visual Studio Code
Download and install the latest supported version of Visual Studio Code.
After installation, launch Visual Studio Code.
Step 2 — Install nRF Connect for VS Code
Open:
Visual Studio Code → Extensions
Search for:
nRF Connect for VS Code
Install the main Nordic extension.
The current nRF Connect for VS Code installation also provides the associated extensions used for:
- nRF Connect development
- DeviceTree
- Kconfig
- nRF Terminal
Nordic documents these as the extension set used together with nRF Connect for VS Code.
After installation, restart Visual Studio Code if requested.
9. Install the nRF Connect SDK
Open the nRF Connect for VS Code extension from the VS Code Activity Bar.
On a new installation, the Welcome View provides an:
Install SDK
option.
Click:
Install SDK
Nordic's current installation process can install the SDK and matching toolchain together.
Step 10 — Select the SDK
The installer will ask for the download region.
Select the appropriate region.
Then select:
nRF Connect SDK
You will see available stable versions.
For a teaching/lab project, use a stable SDK release rather than an experimental or development branch.
Nordic recommends working with a specific stable SDK release unless you have a reason to use another revision.
11. Install the Toolchain
The SDK installation can install the corresponding toolchain.
The toolchain contains the development components required to build applications for the nRF Connect SDK.
The installation may take several minutes.
Wait until VS Code reports that the installation has completed successfully.
Nordic's current documentation describes the SDK and toolchain as separate components but recommends installing them together for a first-time setup.
12. Verify the Nordic Installation
Open the nRF Connect extension in VS Code.
The installed SDK should appear in the SDK/toolchain management section.
You should be able to see the installed SDK version and associated toolchain.
If the installation is successful, the development environment is ready.
13. Understanding the OpenThread Firmware
For this project, the XIAO boards need firmware containing an OpenThread CLI.
The firmware provides commands such as:
dataset
ifconfig
thread
state
ipaddr
ping
udp
These commands allow you to configure and control the Thread network directly from the serial terminal.
The OpenThread CLI provides commands for creating and managing Operational Datasets, starting Thread, checking node state and performing UDP communication.
14. Important Concept — Leader and Child Are Not Two Different Firmware Programs
This is very important for the mini project.
You do not need:
- one special "Leader firmware"
- one special "Child firmware"
Instead, the same OpenThread-capable firmware can be used on both XIAO boards.
The role is determined by the Thread network configuration and the state of the device.
For this project:
XIAO #1 = configured to create the Thread network
→ becomes Leader
XIAO #2 = given the Leader's Operational Dataset
→ joins the existing network
→ becomes Child
Therefore, the firmware is installed first, and the Leader/Child role is established afterward using OpenThread CLI commands.
15. Flashing OpenThread Firmware to the XIAO
The XIAO nRF52840 uses a UF2-compatible bootloader. Zephyr's current XIAO documentation describes entering UF2 bootloader mode by double-tapping the reset button and copying the generated .uf2 file to the board's USB mass-storage device.
For this mini project, you can use a pre-built OpenThread UF2 firmware if you already have the firmware file used in your previous setup.
The file will normally have:
.uf2
extension.
16. Connect the First XIAO
Connect the first XIAO to the computer using a USB Type-C data cable.
Allow Windows to detect the board.
17. Enter UF2 Bootloader Mode
Locate the small RESET button on the XIAO.
Quickly press the reset button twice.
The board should enter bootloader mode.
A USB mass-storage drive should appear in Windows.
The exact drive name can depend on the bootloader/firmware, but the XIAO's UF2 bootloader exposes a removable drive for firmware copying.
18. Copy the OpenThread UF2 Firmware
Open the bootloader drive.
Copy the OpenThread firmware:
your_openthread_firmware.uf2
into the bootloader drive.
Do not open or modify the UF2 file.
Simply copy it to the board.
The board will automatically reset after the firmware has been written.
19. Verify the Firmware
After flashing, Windows should detect the XIAO again as a USB serial device.
Open:
VS Code → Serial Monitor
Select the XIAO's COM port.
In your previous setup, the boards appeared as:
COM26
COM27
Your COM numbers may be different.
Set the baud rate to:
115200
The OpenThread CLI should now be available.
20. Flash the Second XIAO
Disconnect the first XIAO if necessary.
Connect the second XIAO.
Again:
- Connect USB.
- Double-click RESET.
- Wait for the UF2 drive.
- Copy the same OpenThread
.uf2firmware. - Allow the board to reboot.
- Open its serial port.
- Set baud rate to
115200.
At this point both boards should have the same OpenThread-capable firmware.
21. Enable Serial Monitor in VS Code
After flashing the OpenThread firmware, open Visual Studio Code.
Open the nRF Connect for VS Code extension and select nRF Terminal from the VS Code Activity Bar.
Click the + button to create a new serial terminal.
Select the COM port corresponding to the XIAO board.
For example:
COM26
Set the baud rate to:
115200
Press Enter.
The OpenThread CLI should now appear in the terminal.
For the second XIAO, open another terminal and select its corresponding COM port, for example:
COM27
Use:
115200
You can now enter OpenThread commands directly in the terminal, such as:
state
or:
ipaddr
XIAO nRF52840 — Thread + 6LoWPAN + UDP : Now Communication Time
Assume:
XIAO #1 = LEADER
XIAO #2 = CHILD
Leader COM26
Child COM27
UDP Port = 12345
Your actual COM ports can of course change.
1. LEADER — complete command sequence
Start with the Leader XIAO.
Step 1 — Clear old dataset
dataset clear
Expected:
Done
Step 2 — Create a NEW Thread network
dataset init new
Expected:
Done
This generates a new random Thread Operational Dataset containing things such as:
- Channel
- PAN ID
- Extended PAN ID
- Network Key
- Network Name
- Mesh-local prefix
- PSKc
OpenThread documents dataset init new specifically for creating a new dataset.
Step 3 — Display the dataset
Immediately do:
dataset
You should get something similar to:
Active Timestamp: 1
Channel: 21
Channel Mask: 0x07fff800
Ext PAN ID: xxxxxxxxxxxxxxxx
Mesh Local Prefix: fdxx:xxxx:xxxx:xxxx::/64
Network Key: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Network Name: OpenThread-xxxx
PAN ID: 0xxxxxxx
PSKc: xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx
Security Policy: 0, onrcb
Done
Important: keep this information.
Step 4 — Commit the dataset
dataset commit active
Expected:
Done
This writes the Operational Dataset as the Active Operational Dataset.
Step 5 — Bring up IPv6
ifconfig up
Expected:
Done
Step 6 — Start Thread
thread start
Expected:
Done
Now check:
state
Initially it may show:
detached
Then after a short time the Leader should become:
leader
You can repeatedly use:
state
The normal target is:
leader
2. Get the Leader's complete dataset
This is the most important command for creating the Child.
On the Leader:
dataset active -x
You will get a long hexadecimal string, for example:
0e080000000000010000000300001035060004001fffe00208xxxxxxxxxxxxxxxx...
Copy the entire line.
OpenThread specifically supports dataset active -x for obtaining a hex-encoded Active Operational Dataset that can then be applied to another device with dataset set active.
3. Check Leader IPv6 addresses
Run:
ipaddr
You may see something like:
fdxx:xxxx:xxxx:xxxx:0:ff:fe00:xxxx
fdxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
fe80:....
For our UDP test, we'll normally use the Thread mesh-local IPv6 address, beginning with:
fd...
For example:
fd00:abcd:1234:5678:xxxx:xxxx:xxxx:xxxx
Don't use the fe80:: address for this simple test.
4. Test that Leader is working
You can check:
thread state
or simply:
state
You can also check:
ipaddr
And:
netdata show
For a simple two-node experiment, the important result is:
state
leader
5. CHILD — complete command sequence
Now move to the second XIAO.
First clear whatever old network information it has.
dataset clear
Then:
ifconfig down
Then:
thread stop
If the board wasn't running Thread, that's okay.
6. Give the Child the Leader's dataset
This is where your previous procedure needs to be slightly changed.
DO NOT do this on the Child:
dataset init new
because that creates a new network.
Instead, take the hexadecimal string obtained from:
dataset active -x
on the Leader.
Then on the Child:
dataset set active YOUR_LEADER_DATASET_HEX
For example:
dataset set active 0e080000000000010000000300001035060004001fffe00208xxxxxxxxxxxxxxxx...
Expected:
Done
This is the documented way of putting the same Active Operational Dataset onto a new device.
7. Start the Child's Thread interface
On Child:
ifconfig up
Then:
thread start
Expected:
Done
Wait a few seconds.
Then:
state
Expected:
child
You might briefly see:
detached
before:
child
That is normal during attachment.
8. Check Child IPv6 addresses
On Child:
ipaddr
You should get something like:
fdxx:xxxx:xxxx:xxxx:0:ff:fe00:xxxx
fdxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx:xxxx
fe80:....
Again, note the fd... address.
For example:
fd00:abcd:1234:5678:1111:2222:3333:4444
We'll call that:
CHILD_IP
9. Verify Leader ↔ Child connectivity
Now go back to the Leader.
Take the Child's fd... address.
Run:
ping CHILD_IP
For example:
ping fd00:abcd:1234:5678:1111:2222:3333:4444
Expected:
16 bytes from fd00:abcd:1234:5678:1111:2222:3333:4444:
icmp_seq=1 hlim=64 time=10ms
1 packets transmitted, 1 packets received.
Packet loss = 0.0%.
That proves: Leader communicates with the Child through IPv6 over the Thread/6LoWPAN network.

10. Now configure UDP
This is where your screenshot becomes particularly useful.
Let's make:
Leader = UDP SERVER
Child = UDP CLIENT
Port = 12345
11. LEADER — UDP server
On the Leader:
udp open
Expected:
Done
Then:
udp bind :: 12345
Expected:
Done
This means:
IPv6 address = ::
UDP port = 12345
The :: means the unspecified IPv6 address, allowing the socket to accept traffic on the available IPv6 addresses. This is the standard OpenThread CLI UDP procedure.
You now have: LEADER UDP socket- port 12345
12. CHILD — UDP client
On Child:
udp open
Expected:
Done
You don't actually have to bind the Child for a simple send test.
Now take the Leader's IPv6 address.
For example:
fd00:abcd:1234:5678:aaaa:bbbb:cccc:dddd
Then:
udp send fd00:abcd:1234:5678:aaaa:bbbb:cccc:dddd 12345 Hello_Leader
Expected:
Done
OpenThread's official UDP example follows exactly this pattern: udp open, optionally udp bind, then udp send <IPv6> <port> <message>.
13. What should happen?
On the Leader, you should see something similar to:
Received UDP message
depending on the particular OpenThread CLI build.
Conceptually:
THREAD NETWORK
┌─────────────────────────┐
XIAO #2 XIAO #1
CHILD LEADER
│ │
│ │
│ IPv6 / UDP │
│──────────────────────>│
│ │
│ "Hello_Leader" │
│ │
COM27 COM26
UDP destination port: 12345
14. Reverse direction — Leader → Child
If you want the Leader to send a message back to the Child, bind the Child.
On Child:
udp bind :: 12345
Then on Leader:
udp send CHILD_IP 12345 Hello_Child
For example:
udp send fd00:abcd:1234:5678:1111:2222:3333:4444 12345 Hello_Child
Now you have bidirectional UDP:


15. The complete cheat sheet
LEADER
Run these in this order:
dataset clear
dataset init new
dataset
dataset commit active
ifconfig up
thread start
state
ipaddr
dataset active -x
Then test the Child:
ping CHILD_IP
Then UDP server:
udp open
udp bind :: 12345
CHILD
Use the Leader's dataset:
dataset clear
ifconfig down
thread stop
Then:
dataset set active LEADER_DATASET_HEX
Then:
ifconfig up
thread start
Check:
state
ipaddr
Expected:
child
Then UDP:
udp open
Send to Leader:
udp send LEADER_IP 12345 Hello_Leader
16. Full two-way UDP setup
LEADER
dataset clear
dataset init new
dataset
dataset commit active
ifconfig up
thread start
state
ipaddr
dataset active -x
Copy the dataset.
Then:
udp open
udp bind :: 12345
CHILD
dataset clear
ifconfig down
thread stop
dataset set active LEADER_DATASET_HEX
ifconfig up
thread start
state
ipaddr
udp open
Then:
udp send LEADER_IP 12345 Hello_Leader
For reverse communication, on Child:
udp bind :: 12345
Then on Leader:
udp send CHILD_IP 12345 Hello_Child

17. Useful diagnostic commands
| Purpose | Command |
|---|---|
| Show current Thread state | state
|
| Show IPv6 addresses | ipaddr
|
| Show current dataset | dataset
|
| Get dataset as hex | dataset active -x
|
| Create new network | dataset init new
|
| Clear dataset | dataset clear
|
| Commit dataset | dataset commit active
|
| Bring IPv6 up | ifconfig up
|
| Bring IPv6 down | ifconfig down
|
| Start Thread | thread start
|
| Stop Thread | thread stop
|
| Show Thread neighbors | neighbor table
|
| Show Thread network data | netdata show
|
| Test IPv6 connectivity | ping <IPv6>
|
| Open UDP socket | udp open
|
| Bind UDP socket | udp bind :: 12345
|
| Send UDP | udp send <IPv6> 12345 <message>
|
| Close UDP | udp close
|
| UDP help | udp help
|
| Thread help | thread help
|
| Dataset help | dataset help
|
The current OpenThread CLI reference lists these dataset and UDP operations, including dataset clear, dataset commit active, dataset init, udp open, udp bind, udp send, and udp close.