Skip to content

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:

  1. 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.
  2. 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.
  3. 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.
  4. 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.