End-to-end guide for the 91m1_ppp host application on nRF54L15 or nRF54LM20B. Complete these steps in order to wire up the hardware, build and flash firmware, and connect the device to nRF Cloud over CoAP.
The application connects to nRF Cloud over CoAP/DTLS from the host MCU (nRF54L15 or nRF54LM20B). Cellular data goes through the nRF91M1 Serial Modem via PPP; credentials are stored on the host using the TLS credentials shell and TF-M Protected Storage. Until onboarding is complete, nrf_cloud_coap_connect() will fail even if credentials are installed locally.
-
Wire up the development boards — Connect the host DK (nRF54L15 or nRF54LM20B) to the nRF9151 DK (Serial Modem). Configure both DKs in the Board Configurator and flash Serial Modem firmware with PPP and CMUX enabled on the nRF9151. Use the
serial_modem_*_nrf9151dk_nrf91m1.zipfrom your SMHA release bundle, or download the newest matching archive from ncs-serial-modem releases. See Hardware setup for wiring, pin assignments, and how to flash the Serial Modem image. -
Build and flash 91m1_ppp on the host DK
All
westcommands must run inside the nRF Connect SDK toolchain environment. Launch it first (see Initialize the workspace):nrfutil sdk-manager toolchain launch --ncs-version v3.4.0 --shell
nRF54L15 DK:
cd applications/91m1_ppp west build -b nrf54l15dk/nrf54l15/cpuapp/ns -p west flash --recovernRF54LM20B DK:
cd applications/91m1_ppp west build -b nrf54lm20dk/nrf54lm20b/cpuapp/ns -p west flash --recoverFor Wi-Fi location with the nRF7002-EB2 shield, see Hardware setup — Wi-Fi location.
-
Verify the host application boots — Open a serial terminal on the host console port (see Hardware setup for which VCOM to use on your board). Confirm the application starts and note the Device ID from the boot log:
<inf> nrf_cloud_info: Device ID: E4361AD8FD3E4554This 16-character hex ID comes from the host SoC HW ID (
CONFIG_NRF_CLOUD_CLIENT_ID_SRC_HW_ID). Use it for credential generation and portal onboarding — it is not the nRF91 modem UUID. The cloud module logs it again when connecting:<inf> cloud: nRF Cloud client ID: E4361AD8FD3E4554 -
Install nRF Cloud Utils (one-time setup on your host machine)
pip3 install nrfcloud-utils
See the nRF Cloud Utils repository for details.
-
Create a self-signed CA certificate (one-time; reuse the same CA for all devices)
create_ca_cert -c US -f self_
Replace
USwith your two-letter country code. This produces three files (serial number varies):self_<serial>_ca.pem— CA certificateself_<serial>_prv.pem— CA private keyself_<serial>_pub.pem— CA public key
Keep the CA private key secure.
-
Install device credentials on the host — Run
device_credentials_installerfrom the directory containing your CA files, pointing at the host console serial port and the device ID from step 3:device_credentials_installer \ --ca self_<serial>_ca.pem \ --ca-key self_<serial>_prv.pem \ --id-str <device_id> \ -s -d --verify --coap --local-cert --cmd-type tls_cred_shell \ --port /dev/cu.usbmodem*
Where:
<device_id>is the 16-character hex ID from the boot log (for exampleE4361AD8FD3E4554).--coapinstalls the CoAP server root CA in addition to the AWS root CA chain.--local-certgenerates the device certificate and private key on the host (required because the TLS credentials shell does not support CSR generation).--cmd-type tls_cred_shellsendscredshell commands over the host UART.-ssaves generated PEM files (<device_id>_crt.pem,<device_id>_prv.pem, etc.) in the current directory.-ddeletes any existing credentials in sec tag 16842753 before installing new ones.--verifyconfirms credentials were written correctly.--portselects the host console serial port (adjust for your OS; omit if auto-detection works). On nRF54LM20B, use VCOM0 (primary port) for both plain and nRF7002-EB2 builds.
On success you should see:
Saving nRF Cloud device onboarding CSV file onboard.csv... Onboarding CSV file saved, row count: 1Delete the device private key PEM from your host after installation if you used
--local-cert. The default nRF Cloud security tag is 16842753 (CONFIG_NRF_CLOUD_SEC_TAG). -
Onboard the device to your nRF Cloud account — Register the device public key using the CSV generated in the previous step:
nrf_cloud_onboard --api-key <your_api_key> --csv onboard.csv
Use an API key from your nRF Cloud user account.
-
Verify the nRF Cloud connection — After onboarding:
-
Ensure the cellular link is up — wait for
Network connectedin the log (PPP over the Serial Modem). -
The cloud module retries automatically every 10 seconds if credentials or valid time are missing.
-
On success, logs show:
<inf> cloud: nRF Cloud client ID: E4361AD8FD3E4554 <inf> main: Cloud connected <inf> main: Cloud message sent -
On first connect, the application sends a demo JSON message and polls for FOTA updates. While cloud stays connected, this cloud synchronization repeats every 30 seconds (see Application behavior).
Credentials persist across reboot when
CONFIG_TLS_CREDENTIALS_BACKEND_PROTECTED_STORAGEis enabled. -
The host application runs on nRF54L15 and uses the nRF91M1 Serial Modem for cellular data over PPP. Modules communicate over zbus and coordinate with SMF state machines. After network and cloud are up, the main module periodically sends a demo device message and requests a FOTA poll.
See Application behavior for the full startup sequence, cloud synchronization, and Memfault integration, and Architecture for the module design and state machines.
CoAP authentication uses a JWT signed with the installed private key. Only the CA certificate and private key are required at runtime; the device certificate is used for portal onboarding.
| Symptom | Action |
|---|---|
Missing required nRF Cloud credentials |
Re-run device_credentials_installer with --coap --cmd-type tls_cred_shell |
nrf_cloud_coap_connect auth failure |
Confirm the device is onboarded in the portal with the correct device ID |
| Wrong device in portal | Use the host Device ID from boot log, not the modem %DEVICEUUID |
| JWT / time errors | After Network connected, run net dns query time.google.com. Ping to an IP does not prove DNS works. If logs show getaddrinfo entries overflow, ensure CONFIG_DNS_RESOLVER_AI_MAX_ENTRIES=4 is set. If SNTP fails with Not enough connection contexts, increase CONFIG_NET_MAX_CONN (IPv4-only builds default to 4, which is too low once DNS + modem + SNTP + CoAP are active) |
nrf_cloud_coap_connect error -111 |
Host-native CoAP needs DTLS sockets (CONFIG_NET_SOCKETS_SOCKOPT_TLS, CONFIG_NET_SOCKETS_ENABLE_DTLS). If enabling DTLS causes RAM overflowed, lower CONFIG_MBEDTLS_SSL_IN/OUT_CONTENT_LEN to 1024 (defaults are 16 KB each) and disable IPv6. Then run net dns query coap.nrfcloud.com after PPP is up |
Failed to parse certificate err -0x2180 |
Shell-provisioned credentials are PEM. Enable CONFIG_MBEDTLS_PEM_PARSE_C=y (see nrf/samples/wifi/nrf_cloud/prj.conf). Reinstall credentials if a prior install truncated them |
Failed to parse certificate err -0xffffffff |
mbedTLS returned 1: one cert in the CA chain or device cert failed to parse. Enable CONFIG_MBEDTLS_RSA_C, CONFIG_MBEDTLS_ECP_C, and CONFIG_PSA_WANT_ALG_ECDH (see nrf/samples/wifi/nrf_cloud/prj.conf) |
RAM overflowed with cloud enabled |
Trim TLS buffers (MBEDTLS_SSL_IN/OUT_CONTENT_LEN=1024), disable CONFIG_NET_IPV6, and reduce NET_PKT/BUF counts before dropping DTLS |
FOTA download Failed to create socket, errno 12 while cloud is connected |
The CoAP cloud session and the FOTA CoAP downloader each need a DTLS context. Ensure CONFIG_NET_SOCKETS_TLS_MAX_CONTEXTS is at least 2 and increase CONFIG_MBEDTLS_HEAP_SIZE if needed (see 93m1_ppp/prj.conf) |
| Boot loop (~6 s) | Usually a hard fault from stack overflow. Increase CONFIG_APP_CLOUD_THREAD_STACK_SIZE (default 10240) if cloud connect faults; keep CONFIG_MODEM_DEDICATED_WORKQUEUE=y. To capture the fault, temporarily set CONFIG_RESET_ON_FATAL_ERROR=n and check for fatal_error: Resetting system or stack traces |
device_credentials_installer cannot connect |
Confirm the shell prompt (uart:~$) is visible on the selected serial port |
| Serial Modem console silent after its boot banners | Expected: Serial Modem suspends its log UART after init. Run modem at "AT#XLOG=1" to resume it (see below) |
CONFIG_MODEM_AT_SHELL exposes the modem's AT interface over the host shell using the CMUX user pipe, for Serial Modem commands that have no host-side equivalent:
uart:~$ modem at "AT#XLOG=1"
OKThis is how you get Serial Modem logs during operation. The modem prints its bootloader and application banners over VCOM1 at 1000000 baud and then suspends the log backend and the UART, so the console stays silent until AT#XLOG=1 resumes it. Note that the pipe only exists once the modem has attached, CMUX runtime power save closes it again when idle (the command then answers modem is not ready, so retry), and any host reboot resets the modem and turns logging back off.
The application includes Memfault for remote crash reporting and device health metrics. The SDK uploads data periodically in the background (CONFIG_MEMFAULT_PERIODIC_UPLOAD) over the nRF Cloud CoAP session.
See Memfault remote debugging for how to open the Memfault dashboard from nRF Cloud, upload zephyr.elf, and verify data collection.
| Guide | Description |
|---|---|
| Application behavior | Startup sequence, cloud sync, FOTA, and Memfault at runtime |
| Architecture | Module design, zbus message passing, and SMF state machines |
| Hardware setup | Host + Serial Modem wiring (nRF54L15, nRF54LM20B, optional nRF7002-EB2 for Wi-Fi location), board configurator, Serial Modem firmware |
| Memfault remote debugging | Open Memfault from nRF Cloud, upload symbol files, view coredumps |
Module documentation:
- Main module — business logic, cloud synchronization, FOTA coordination
- Network module — PPP link to the Serial Modem
- Cloud module — nRF Cloud CoAP session, device messages, shadow
- FOTA module — firmware updates of the host application
- Location module — Wi-Fi based positioning (location overlay)