Code Examples
DevKit2 Demo — Cellular Temperature Logger
A complete example application for the DevKit2, demonstrating its main peripherals working together: temperature sampling over I2C, persistent logging to external SPI NOR flash, LTE connectivity with power saving, and timestamped data upload over UDP.
The board definition is bundled in boards/iscatek/mbdk2, so no separate board repository needs to be fetched — pass the project's own path as BOARD_ROOT and the build finds it.
Overview
The application:
- Connects to LTE at boot and waits until UTC time has been obtained (from the modem's network time, falling back to NTP). Sampling only starts once time is known, so every reading carries a valid timestamp.
- Samples the on-board TMP1075 temperature sensor every
CONFIG_DEVKIT_DEMO_TEMP_POLL_INTERVAL_SECONDS(default 10 s) and appends each reading, with its Unix timestamp, to a queue stored in the external MX25R6435F SPI NOR flash. Queued readings survive reboots and power loss. - Uploads the queue over UDP every
CONFIG_DEVKIT_DEMO_UPLOAD_INTERVAL_MINUTES(default 60 min), or immediately when the user button is pressed. Readings are removed from the queue only after a successful send. - Runs a chase sequence across the three board LEDs throughout, as a simple visual heartbeat.
The modem stays registered on LTE the whole time; power saving comes from PSM (Power Saving Mode), which lets the modem sleep at the hardware level between transmissions.
PSM must be granted by the carrier
This is near-universal on LTE-M/NB-IoT networks, but it is not guaranteed.
Requirements
- A DevKit2 board (
mbdk2, nRF9151) with a SIM card and LTE antenna - nRF Connect SDK (tested with v3.2.2) with its toolchain installed
- A UDP server to receive the readings — see Receiving the data
Boot blocks until LTE attaches
The device waits at startup until LTE attaches and time synchronises. Without working cellular connectivity it will not begin sampling.
Building and flashing
From the repository root, in an nRF Connect SDK environment:
west build -b mbdk2/nrf9151/ns . -- -DBOARD_ROOT=$(pwd)
west flash
Set the UDP destination at build time (or in prj.conf):
west build -b mbdk2/nrf9151/ns . -- \
-DBOARD_ROOT=$(pwd) \
-DCONFIG_DEVKIT_DEMO_SERVER_ADDR=\"1.2.3.4\" \
-DCONFIG_DEVKIT_DEMO_SERVER_PORT=2469
Console output is on UART0 at 115200 baud. A successful boot looks like:
<inf> storage: 0 reading(s) pending upload from a previous session
<inf> network: Bringing up network interface
<inf> network: Waiting for network connection
<inf> network: Network connected
<inf> network: Waiting for time synchronization
<inf> network: Time synchronized, staying registered (PSM handles modem sleep)
<inf> main: Temperature: 24.375 C at 1784463893
Configuration
All options live under Devkit demo settings in menuconfig:
| Option | Default | Meaning |
|---|---|---|
DEVKIT_DEMO_SERVER_ADDR |
192.0.2.1 |
UDP server IPv4 address (must be changed) |
DEVKIT_DEMO_SERVER_PORT |
2469 |
UDP server port |
DEVKIT_DEMO_TEMP_POLL_INTERVAL_SECONDS |
10 |
Sensor sampling interval |
DEVKIT_DEMO_UPLOAD_INTERVAL_MINUTES |
60 |
Periodic upload interval |
DEVKIT_DEMO_MAX_PENDING_READINGS |
64 |
Flash queue capacity |
DEVKIT_DEMO_MAX_READINGS_PER_UPLOAD |
64 |
Cap per upload cycle |
DEVKIT_DEMO_UPLOAD_FORMAT_JSON / BINARY |
JSON | Payload format |
If the queue fills before the next upload, the oldest unsent reading is overwritten. Size the queue to cover at least one upload interval — interval / poll rate readings, plus margin for failed uploads.
Payload formats
Each upload cycle drains the queue across one or more UDP datagrams, each at most ~1 KB so it fits the nRF91 link MTU. Every datagram is self-contained and independently parseable.
JSON (default) — a JSON array, oldest reading first:
[{"temp_c":24.375,"ts_s":1784463893},{"temp_c":24.437,"ts_s":1784463903}]
Binary — back-to-back 8-byte little-endian records, no framing:
| Field | Type | Meaning |
|---|---|---|
timestamp_s |
int32_t |
Unix time, UTC, seconds |
temp_millideg |
int32_t |
Temperature, thousandths of a degree Celsius |
Receiving the data
Any UDP listener works. For a quick test with netcat:
nc -ul 2469
Storage details
Readings are held in an NVS-backed FIFO on the external flash (storage.c). The queue metadata records the firmware's queue capacity and record layout. If a build with different settings is flashed — for example after changing DEVKIT_DEMO_MAX_PENDING_READINGS — the incompatible queue is detected on boot and restarts empty, rather than returning garbage. Readings queued by a compatible build are preserved across reboots and uploaded once connectivity returns.
No on-board RTC
There is no RTC on the board. UTC is obtained from the network at boot and held as a software clock, which is why the application re-synchronises time on every boot before sampling starts.
Repository layout
| Path | Contents |
|---|---|
src/main.c |
Boot sequence and sampling loop |
src/sensor.c |
TMP1075 access (Zephyr sensor API) |
src/storage.c |
Flash-backed reading queue (NVS) |
src/network.c |
LTE connectivity and the upload cycle |
src/leds.c |
LED chase sequence |
boards/iscatek/mbdk2 |
DevKit2 board definition |
Kconfig |
Application configuration options |
Licence
Apache-2.0. See the LICENSE file included in the download.