If you have ever made a small connected project—such as flashing an LED on an ESP32 or sending sensor data to an online dashboard—you have already seen how exciting connected hardware can be.
But Wi-Fi is only one piece of the picture. It relies on local networks, passwords, and limited coverage.
Cellular IoT opens a much bigger world.
It enables a tracker to stay connected far from home networks. It keeps systems like parcel lockers online in busy urban areas. It allows devices in different places, even different countries, to exchange data without depending on nearby Wi-Fi.
This tutorial is an entry point into that larger system.
Instead of building a device that only works on your local network, you will create a small connected node that reaches into the cellular infrastructure around it. It will search for a network, connect to a mobile tower, and gain access to the internet.
When that connection is finally established, the LED will turn on.
Step 1 — Preparing the HardwareBefore the software does anything, the hardware needs one essential thing first: a network identity.
What comes in the boxInside the Nordic nRF9151 DK package, you will find the development board and two SIM cards—one from Onomondo and another from a Conexa.
There is also a sticker included.
If you just unboxed your nRF9151 DK, you probably noticed that Nordic includes two SIM cards: one from Onomondo and one from Wireless Logic. Nordic describes both as bundled starter SIMs with preloaded data, but they are not meant to represent exactly the same setup experience.
At first glance, it is easy to assume that any SIM should behave the same way: insert it, power up the board, and expect it to connect. In practice, cellular IoT depends heavily on how the network profile is configured. The APN determines how a device reaches a data network, and different providers may use different APN models and access policies.
Onomondo SIMOnomondo says its SIMs are delivered activated, recommends the APN onomondo, and promotes a single-APN approach for IoT deployments. That makes it a good fit for a beginner “first connection” exercise where the goal is to get online quickly and verify that the modem, SIM, and network path are working.
If you want to work with the Onomondo card instead, I already covered that flow in a separate tutorial, available here
Conexa SIMThe Wireless Logic card belongs to a different ecosystem. Wireless Logic positions Conexa as an enterprise IoT network and ties SIM management to tools such as SIMPro and DevicePro. Their documentation also states that the correct APN details are required for the device to authenticate and start a data session, and those details are provided through the order information or SIMPro.
Conexa SIM is better explained as a separate path, because its exact setup can depend on the provisioned APN and network service profile. Wireless Logic also distinguishes between private and public APN setups, and in standard private APN deployments devices are commonly assigned private static IP addresses.
The goal in this guide is to bring up the board with the Conexa SIM and walk through the setup that fits the Wireless Logic ecosystem. Wireless Logic positions Conexa alongside tools such as SIMPro and DevicePro, which are part of its device and connectivity management stack.
Step 2 — Insert Conexa SIM into the nRF9151Carefully pop the nano-SIM out of its plastic holder.
Insert the Conexa nano-SIM into the slot on the board.
Connect the board via USB, and flip the power switch.
Conexa SIM card is using the (VF-NL) IMSI, which means that it does not support NB-IoT coverage; only LTE-M connectivity is available.
Check Coverage Link Currently, the only verified network launch for VF-NL in Poland (my case) is with the Orange network. Because of this, there is no specific steering profile applied to this SIM card, so it will automatically connect to the best available network in the area at any given time.
Note: Safari is not supported by SimPro dashboard, so please switch to Chrome or Firefox to ensure the portal functions correctly.
Flip the plastic holder card over and scan the QR code to be redirected to the registration page, where you can claim your free data.
After registering your SIM, you will receive 12 months of access to the Conexa network and the SIMPro connectivity management platform. You will also get an additional 45MB of data on top of the initial 5MB included with your SIM.
And yeah, once you submit the registration form, it might take a little while to process, so just heads up.
Make sure they actually allocated your data, because at first, support activated my SIM but didn't include any traffic, so it couldn't connect.
Cellular IoT is not Arduino-style simplicity. It’s closer to real embedded systems used in production.
That’s why we use:
- nRF Connect SDK
- Zephyr RTOS
- Visual Studio Code
Install nRF Connect for Desktop.
nRF Connect for Desktop serves as the centralized cross-platform gateway for Nordic Semiconductor’s specialized development tools. While the actual coding and compilation occur within VS Code, this desktop suite provides a graphical "app-store" interface for hardware-specific utilities that operate independently of the IDE.
By installing this hub, the developer gains access to a modular suite of applications designed for real-time hardware diagnostics and optimization:
- Cellular Monitor: A high-level diagnostic tool used for real-time modem tracing and AT command evaluation, replacing the legacy LTE Link Monitor.
- Programmer: A visual interface for inspecting memory layouts and flashing compiled
.hexbinaries directly to the SoC. - Power Profiler: An essential utility for analyzing current consumption when used with the Power Profiler Kit (PPK2), critical for low-power Zephyr applications.
- Bluetooth Low Energy: A comprehensive tool for scanning, advertising, and testing GATT services on BLE-enabled devices.
The installation of nRF Connect for Desktop completes the environment by bridging the gap between the Firmware (Zephyr/NCS) and the Physical Hardware, providing the visibility needed to debug cellular connectivity and power efficiency that a standard text editor cannot provide.
Open Toolchain Manager and install Quick Start.
During installation, you will be prompted to name your board. In the third step, you will need to choose which firmware to upload; select AT commands.
The programming process will now begin.
The system will then verify your board.
Then, Quick Start will remind you of the default SIM variants included in the box.
Then you can evaluate AT commands by opening Cellular Monitor.Then, you can evaluate AT commands by opening Cellular Monitor.
Explore the learning resources to find out more.
Now you need to install the SDK. Since I am developing using the VS Code IDE, I will choose Option 1.
Open VS Code with extension.
After the extension, SDK, and toolchain have been successfully installed.
You will then have the correct build configuration within VS Code.
Congratulations! You have successfully finished setting up your development environment.
Now that everything is installed, let's open Cellular Monitor.
Debugging and APN connection via Cellular MonitorSince you have the environment ready, this is where you'll start interacting directly with the hardware.
To get a real-time look at how your device is interacting with the towers, open the Cellular Monitor app. This is the most powerful tool for troubleshooting connection issues or verifying roaming status.
Connect to the device detected by the system by clicking its name in the top-left corner.
Click start to trace.
Then, you will be able to see the tracing process in real-time.
For more detailed debugging install Programmer, Cellular Monitor, Power Profiler if needed.
When you use Nordic’s Cellular Monitor, the dashboard can be a bit deceiving. A green checkmark next to "LTE CONNECTION" on the left side does not mean you are connected to the internet!
With Conexa, you'll encounter situations like this because you have to manually provide the APN and password.
Open serial terminal
You are now communicating directly with the modem.
Enter the APN provided in the Conexa email.
AT+CGDCONT=0,"IP","eapn1.net"Check the result; it should return 'OK'.
Now, enter your username and password, then press Enter.
AT+CGAUTH=0,1,"NordicSe","NordicSe"similar, must return OK.
Now, close the serial terminal.
Check the PDN tab at the top right to verify that your APN is registered.
To prove you actually bypassed the cell tower's "bouncer" and got an IP address, you need to look at the LTE Network panel in the center of the screen.
Here are the 3 fields you must check to confirm a true connection:
EPS Network Registration Status (The Magic Number)
This is the most important number on your screen.
- Status 2:Searching / Attaching. If you are stuck on 2, the tower sees you, but it is actively deciding whether to let you in (or silently dropping you).
- Status 3:Registration Denied. The tower explicitly rejected your SIM card.
- Status 5 (or 1):Registered Roaming (or Home).This is the goal! In the Onomondo screenshot, you can see it says 5. This means the network authenticated the SIM, accepted the APN, and gave the device a seat at the table.
Essentially, the Zephyr RTOS is already installed as part of the nRF Connect SDK (NCS) setup, so there is no need to install it separately—unless you plan to develop applications independently of the Nordic ecosystem.
In my case on macOS, Zephyr was installed at:
/opt/nordic/ncs/v3.2.4/zephyrNow you’re ready to create something real.
Step 6 — Building Your First nRF9151 Application Using Zephyr RTOS and ConexaOpen VS Code, navigate to the nRF Connect Extension, and click Create a New Application.
Open VS Code and navigate to the nRF Connect extension. Click Create a new application, where you can choose to copy from an existing sample or browse the nRF Connect SDK Add-on index for external repositories.
While I highly recommend exploring the various samples available in the SDK to understand the breadth of the Zephyr RTOS and Nordic SDK, we will focus specifically on the blank application for now.
Detailed walkthroughs of other samples will be covered in a separate tutorial.
Name your application as you wish and press 'Enter' to finalize the project structure.
You will be prompted to scan for kits; click 'Search'
Once complete, you will be provided with a project template containing all the necessary files for development.
You are using a Wireless Logic (Conexa-LD) SIM card. Unlike standard IoT SIMs that auto-configure, this specific SIM requires a private APN, a Username, and a Password to attach to the network. If the modem doesn't provide these credentials during the handshake, the cell tower will reject the connection.
Once you have completed registration in Step 3, Wireless Logic will email you an Excel-attachment containing your APN details, you will need to insert them into your main.c code
Open the prj.conf file in your project, and paste these lines:
# Enable the LTE Link Controller
CONFIG_LTE_LINK_CONTROL=y
# Force LTE-M Only (Optional: use LTE_M_NBIOT if you want both)
CONFIG_LTE_NETWORK_MODE_LTE_M=yNow for the code. This is the absolute simplest way to connect to a cell tower in Zephyr.
Open src/main.c, delete the default code, and paste this exact program. It is heavily commented so you know exactly what is happening:
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <modem/nrf_modem_lib.h>
#include <modem/lte_lc.h>
#include <stdio.h>
// Grab LED 0 from the Devicetree
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
int main(void)
{
printf("\nStarting Conexa Enterprise Cellular Demo!\n");
// 1. Setup the LED pin
if (device_is_ready(led.port)) {
gpio_pin_configure_dt(&led, GPIO_OUTPUT_INACTIVE);
}
// 2. Initialize the Modem
printf("Initializing modem...\n");
if (nrf_modem_lib_init() != 0) {
printf("Failed to initialize modem!\n");
return -1;
}
// 3. THE DIFFERENCE: Inject the Enterprise Credentials
printf("Injecting eapn1.net APN and passwords...\n");
// Clear the Forbidden Blacklist in case of previous rejections
nrf_modem_at_printf("AT%%CLEARFPLMN");
// Set APN to eapn1.net on Context 0
nrf_modem_at_printf("AT+CGDCONT=0,\"IP\",\"eapn1.net\"");
// Set Authentication to PAP (1), User: NordicSe, Pass: NordicSe
nrf_modem_at_printf("AT+CGAUTH=0,1,\"NordicSe\",\"NordicSe\"");
// 4. Connect to the LTE Network
printf("Connecting to network. This may take a minute...\n");
// Note: This is a "blocking" function. The code pauses here until the network attaches!
int err = lte_lc_connect();
if (err) {
printf("Failed to connect! Error: %d\n", err);
return -1;
}
// 5. Success! Turn on the LED to prove we are online.
printf("\nCONNECTED! Turning on LED 1.\n");
gpio_pin_set_dt(&led, 1);
// Keep the main thread alive
while (1) {
k_sleep(K_SECONDS(1));
}
}Click on the nRF Connect icon in the Activity Bar. In the Applications panel at the bottom, locate your project and click '+ Add build configuration' to define your hardware targets.
In the Build Configuration menu, ensure that the SDK and Toolchain are both set to the nRF Connect versions you installed.
Then, set the Board target specifically to nrf9151dk/nrf9151/ns to match your hardware.
Scroll to the bottom of the Build Configuration panel and click 'Build Configuration'.
The terminal will open automatically, allowing you to monitor the progress as it compiles your project.
When the build successfully finishes—as it should for nRF Connect SDK v3.2.4 —you will receive a notification in the status bar, and your binary image will be ready to flash to the hardware.
You are now ready to flash the board. Navigate to the Actions tab in the nRF Connect sidebar and click 'Flash' to load the compiled image onto your nRF9151.
The flashing process will now begin using West, Zephyr’s meta-tool. You can monitor the progress in the terminal as it erases, programs, and verifies the binary on your nRF9151.
Navigate to the Connected Devices tab in the nRF Connect sidebar. Here, you will see your nRF9151 DK listed, confirming that the toolchain has a solid connection to your hardware.
Click the name of your nRF9151 DK to expand the dropdown list and view the available serial ports and hardware details.
Click the name of your nRF9151 DK to expand the dropdown list. This will reveal the available serial ports VCOM and specific hardware details, allowing you to interface directly with the board.
- VCOM0: Usually the Application Port. This is where your Zephyr
printkmessages (like "Connecting to Onomondo...") will appear. - VCOM1: Usually the Modem/AT Port. If you want to manually ask the modem
AT+CEREG?to see your registration status, this is the port you'd use.
Locate VCOM0 in the dropdown list and click the 'Plug' (Fork) icon next to it. This will open the Serial Terminal at the bottom of your screen, where you can monitor the application logs in real-time.
Once the port is open, you will receive real-time logs in the terminal. This allows you to monitor the device's boot sequence, modem initialization, and the live connection status as it attaches to the Onomondo network.
If the terminal is blank or you missed the initial startup messages, press the physical RESET button on your nRF9151 DK to refresh the output and view the full boot sequence from the beginning.
Once the device successfully connects to the LTE-M Onomondo network, you will see a confirmation message in the terminal, and LED 1 on the board will light up to indicate an active connection.
Okay, so where’s the blink? The LED will blink while searching for a signal and switch to a stable, solid light once successfully connected to the network.
Edit main.c code:
#include <zephyr/kernel.h>
#include <zephyr/drivers/gpio.h>
#include <modem/nrf_modem_lib.h>
#include <modem/lte_lc.h>
#include <stdio.h>
// 1. Setup LED and our "Blink" worker
static const struct gpio_dt_spec led = GPIO_DT_SPEC_GET(DT_ALIAS(led0), gpios);
static struct k_work_delayable blink_work;
// Worker ONLY handles blinking. It runs every 500ms until told to stop.
static void blink_handler(struct k_work *work)
{
gpio_pin_toggle_dt(&led);
k_work_reschedule(&blink_work, K_MSEC(500));
}
// 2. Network Event Handler
static void lte_handler(const struct lte_lc_evt *const evt)
{
if (evt->type == LTE_LC_EVT_NW_REG_STATUS) {
bool connected = (evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_HOME ||
evt->nw_reg_status == LTE_LC_NW_REG_REGISTERED_ROAMING);
if (connected) {
printf("\nCONNECTED! Turning LED 1 solid.\n");
// Stop the blinking task, and turn the LED ON
k_work_cancel_delayable(&blink_work);
gpio_pin_set_dt(&led, 1);
} else {
printf("\nSearching for network...\n");
// Start (or restart) the blinking task
k_work_reschedule(&blink_work, K_NO_WAIT);
}
}
}
// 3. Main Application
int main(void)
{
printf("Starting Enterprise Smart Cellular Blink!\n");
// Initialize LED and Worker
if (!device_is_ready(led.port)) return -1;
gpio_pin_configure_dt(&led, GPIO_OUTPUT_INACTIVE);
k_work_init_delayable(&blink_work, blink_handler);
// Turn on Modem
if (nrf_modem_lib_init() != 0) {
printf("Modem init failed!\n");
return -1;
}
// --- THE ENTERPRISE DIFFERENCE ---
printf("Injecting Conexa APN credentials via AT commands...\n");
// 1. Wipe the FPLMN blacklist (Crucial for global roaming SIMs)
nrf_modem_at_printf("AT%%CLEARFPLMN");
// 2. Inject the APN (eapn1.net)
nrf_modem_at_printf("AT+CGDCONT=0,\"IP\",\"eapn1.net\"");
// 3. Inject the PAP Password (User: NordicSe, Pass: NordicSe)
nrf_modem_at_printf("AT+CGAUTH=0,1,\"NordicSe\",\"NordicSe\"");
// ---------------------------------
// Connect in the background (triggers lte_handler on changes)
printf("Connecting asynchronously. Let the blinking begin!\n");
lte_lc_connect_async(lte_handler);
// Put the main thread to sleep forever. The background worker handles the rest!
k_sleep(K_FOREVER);
return 0;
}What is next?Follow this separate tutorial to try the same setup with an Onomondo SIM:
https://www.hackster.io/maxxlife/iot-blink-with-nrf9151-zephyr-and-onomondo-sim-3368ac


_UoqlmTWtmc.png?auto=compress%2Cformat&w=48&h=48&fit=fill&bg=ffffff)




Comments