Skip to main content

Nordic nRF7002 Integration Guide

Overview

In this guide, we will demonstrate how to use Memfault on a system running the Nordic Semiconductor nRF7002 Wi-Fi transceiver. We will be targeting the nRF7002 development kit, which uses the nRF53840 as the application processor.

This guide consists of two main sections. The first section outlines the steps needed to connect the board to the Internet, and the second section describes how to incorporate Memfault's SDK into our application.

Setting Up Our Environment

In this section, we will demonstrate how to set up our environment for the the remainder of this guide.

We'll be using Nordic's nRF Connect SDK, which incorporates Nordic-specific components, such as support for the nRF7002 chipset, on top of Zephyr. To get started with Nordic's nRF Connect SDK, first ensure that you have a Zephyr development environment set up, including the west tool. Then, execute the following commands:

$ west init -m https://github.com/nrfconnect/sdk-nrf.git \--mr v2.4.2 zephyrmemfault
$ cd zephyrmemfault
$ west update

Then, we will have to update the Memfault SDK since the version included in the nRF Connect SDK is outdated. We can update the Memfault SDK to version 1.3.2 by executing the following commands:

$ cd modules/lib/memfault-firmware-sdk/

$ git fetch \--all \--tags

$ git checkout tags/1.3.2

While the above commands are a quick way to update the Memfault SDK, we'd like to create our own West manifest and reference the appropriate version. A personal best practice is to copy the nRF Connect SDK and make the necessary changes. An excellent reference that provides details on West and manifest files can be found here: https://docs.zephyrproject.org/latest/develop/west/index.html.

In addition to the software, we also need to configure and set up the hardware . The following image shows the nRF7002 development kit with the required connections.

First, we must connect the Wi-Fi antenna to the RF port labeled "Wi-Fi". This will ensure that we have a solid connection to our WI-Fi network. Second, we'll need to connect a cable from our development PC to the Micro-USB connector on the shorter side of the development kit. This connection will power the board, programming, and console interface. We will use the console interface to watch the debug outputs from our firmware to confirm the successful configuration.

Connecting To The Internet

Before we can incorporate the Memfault SDK into our firmware and confirm that the backend sees our device, we first need to connect our device to the Internet. Luckily, Nordic has a great example to use as our starting point. We can copy the example over to the root of our West checkout so we can make the necessary modifications:

$ cp -r nrf/samples/wifi/sta ./wifi-test

Then, we need to add our Wi-Fi credentials to the project by modifying the following lines the prj.conf file:

# Below configs need to be modified based on security
# CONFIG_STA_KEY_MGMT_NONE=y
# CONFIG_STA_KEY_MGMT_WPA2=y
# CONFIG_STA_KEY_MGMT_WPA2_256=y
# CONFIG_STA_KEY_MGMT_WPA3=y
CONFIG_STA_SAMPLE_SSID="Myssid"
CONFIG_STA_SAMPLE_PASSWORD="Mypassword"

You will need to enter the SSID and password for your Wi-Fi network for the "CONFIG_STA_SAMPLE_SSID" and "CONFIG_STA_SAMPLE_PASSWORD" configuration options, respectively. Additionally, you will need to uncomment the appropriate key management option. In my instance, with a Google Wi-Fi network, we needed to uncomment the "CONFIG_STA_KEY_MGMT_WPA2" configuration option.

After making the required changes, we can build the firmware and flash it to the device by executing the following commands:

$ west build -p always -b nrf7002dk_nrf5340_cpuapp wifi-test
$ west flash

Let's break down the first west command above. The "build" option instructs west to build the application specified in "wifi-test". The "-p always" option instructs west to start anew and reconstruct all build artifacts. The "-b nrf7002dknrf5340_cpuapp" instructs _west to use the nRF7002 development kit as our target board.

The second west command flashes our board with the binary and produces the following output:

$ west flash
-- west flash: rebuilding
ninja: no work to do.
-- west flash: using runner nrfjprog
Using board 1050727914
-- runners.nrfjprog: Flashing file: /home/mab/memfault/nrf7002/zephyrmemfault-working/build/zephyr/zephyr.hex
[ #################### ] 14.876s | Erase file - Done erasing
[ #################### ] 3.342s | Program file - Done programming
[ #################### ] 3.418s | Verify file - Done verifying
Applying pin reset.
-- runners.nrfjprog: Board with serial number 1050727914 flashed successfully.

If we open a serial connection to the console interface, we should see the following output when it successfully connects to our Wi-Fi network and gets an IP address:

[00:00:07.210,723] <inf> sta: ==================
[00:00:07.210,723] <inf> sta: State: AUTHENTICATING
[00:00:07.268,218] <inf> wifi_nrf: wifi_nrf_wpa_supp_associate: Association request sent successfully

[00:00:07.333,648] <inf> sta: Connected
[00:00:07.373,748] <inf> net_dhcpv4: Received: 10.10.2.100
[00:00:07.373,870] <inf> net_config: IPv4 address: 10.10.2.100
[00:00:07.373,870] <inf> net_config: Lease time: 86400 seconds
[00:00:07.373,901] <inf> net_config: Subnet: 255.255.255.0
[00:00:07.373,962] <inf> net_config: Router: 10.10.2.1
[00:00:07.375,701] <inf> sta: DHCP IP address: 10.10.2.100
[00:00:07.518,157] <inf> sta: ==================
[00:00:07.518,188] <inf> sta: State: COMPLETED
[00:00:07.518,218] <inf> sta: Interface Mode: STATION
[00:00:07.518,249] <inf> sta: Link Mode: WIFI 4 (802.11n/HT)
[00:00:07.518,249] <inf> sta: SSID: mab
[00:00:07.518,280] <inf> sta: BSSID: 9C:4F:5F:24:10:61
[00:00:07.518,310] <inf> sta: Band: 2.4GHz
[00:00:07.518,310] <inf> sta: Channel: 6
[00:00:07.518,341] <inf> sta: Security: WPA2-PSK
[00:00:07.518,371] <inf> sta: MFP: Optional
[00:00:07.518,371] <inf> sta: RSSI: -26

And we're now connected to the Internet!

Incorporating Memfault's SDK

The next step is to incorporate Memfault's SDK into our application. First, we need to modify the "prj.conf" file and add the following configuration options:

# Needed to enable the Memfault SDK
CONFIG_MEMFAULT=y

# Must be set to the Memfault Project Key, which can be retrieved from the web
# interface: https://app.memfault.com/organizations/-/projects/-/settings
CONFIG_MEMFAULT_NCS_PROJECT_KEY="<fill in>"

# Enables periodic uploads of data over the web interface
CONFIG_MEMFAULT_HTTP_PERIODIC_UPLOAD=y

# Enables the Memfault SDK to capture Zephyr logs
CONFIG_MEMFAULT_LOGGING_ENABLE=y

# Configures the Memfault SDK logging level to be debugging, which is the
# highest level
CONFIG_MEMFAULT_LOG_LEVEL_DBG=y

# Enables support for Memfault's HTTP API, used for uploading data and
# performing OTA requests directly to Memfault's server
CONFIG_MEMFAULT_HTTP_ENABLE=y

# Leverages Zephyr's infrastructure for storing root certificates
CONFIG_MEMFAULT_ROOT_CERT_STORAGE_TLS_CREDENTIAL_STORAGE=y

# Provide the required TLS certificates on initialization
CONFIG_MEMFAULT_NCS_PROVISION_CERTIFICATES=y

# Enables support for DNS (which is needed to resolve Memfault's named URLs)
CONFIG_DNS_RESOLVER=y

# Enables support for additional file descriptors, which are necessary for
# socket communications
CONFIG_POSIX_MAX_FDS=9

# Enables support for the mbedTLS cryptography library, which is needed to
# establish a secure connection with the Memfault backend
CONFIG_MBEDTLS=y

# Instructs the mbedTLS library to use the global heap. If unset, an
# mbedTLS-specific heap must be provided
CONFIG_MBEDTLS_ENABLE_HEAP=y

# Increases the amount of heap used by the mbedTLS library to 120,000 bytes.
# This number is likely larger than required, and can be tuned down if needed.
CONFIG_MBEDLTS_HEAP_SIZE=120000

# Enables RSA support for the TLS handshake with the Memfault backend
CONFIG_MBEDTLSA_RSA_C=y

# Enables support for RFC 6066 SNI in TLS, required by Memfault
CONFIG_MBEDTLS_SSL_SERVER_NAME_INDICATION=y

# Needs to be increased from 16 to 64, which helps with throughput and
# reliability when sending coredumps to Memfault
CONFIG_NET_TX_BUF_TX_COUNT=64

# Needs to be increased to 1, which enables queuing of TX data, instead of
# being pushed directly to the driver
CONFIG_NET_TC_TX_COUNT=1

We also need to modify the C source file since we need to send data to the Memfault backend, and the example only connects to a Wi-Fi network and retrieves an IP address. First, let's add a function that will trigger sending data to the Memfault backend. We can do that with the following lines:

static void send_memfault_data(void)
{
LOG_INF("Sending data to Memfault");

/* Check if there is any data available to be sent. */
if (!memfault_packetizer_data_available()) {
LOG_DBG("No data to send");
return;
}

/* Upload any stored data to Memfault */
memfault_zephyr_port_post_data();
}

The example only has notifications during Wi-Fi connection events. Instead, we need to add support for notifications when we've received an IP address since establishing a connection doesn't mean that we are connected to the Internet. We first, we need to create a static variable of type "net_mgmt_event_callback" at the top of the file:

// Callback for IP related events
static struct net_mgmt_event_callback net_mgmt_ipv4_callback;

We then need to add a function that will be called on IP related events:

static void prv_ipv4_mgmt_event_handler(struct net_mgmt_event_callback *cb, uint32_t event,
struct net_if *iface)
{
switch (event) {
case NET_EVENT_IPV4_ADDR_ADD:
LOG_INF("IPv4 address acquired");
context.connected = true;
break;
case NET_EVENT_IPV4_ADDR_DEL:
LOG_INF("IPv4 address lost");
// network_disconnected();
break;
default:
LOG_DBG("Unknown event: 0x%08X", event);
break;
}
}

When we have received an IP address, we are setting the "connected" flag of the "context" global variable to true, which will be used to trigger the transmission of data to the Memfault backend.

We must then register this function with the Zephyr network management infrastructure, which we can do in main. The following lines show how we can do this:

int main(void)
{
...
net_mgmt_init_event_callback(&net_shell_mgmt_cb, net_mgmt_event_handler,
NET_EVENT_IPV4_DHCP_BOUND);

net_mgmt_add_event_callback(&net_shell_mgmt_cb);

// initialize and register the IPv4 event callback
net_mgmt_init_event_callback(&net_mgmt_ipv4_callback, prv_ipv4_mgmt_event_handler,
NET_EVENT_IPV4_ADDR_ADD | NET_EVENT_IPV4_ADDR_DEL);
net_mgmt_add_event_callback(&net_mgmt_ipv4_callback);
...
}

Finally, we can use the "context.connected" flag in the main event loop to trigger transmission of the relevant data to the Memfault backend. We can accomplish this with the following lines of code, with the modifications in bold:

while (1) {
wifi_connect();
...
if (context.connected) {
// k_sleep(K_FOREVER);
send_memfault_data();
} else if (!context.connect_result) {
LOG_ERR("Connection Timed Out");
}
}

If we build and flash the firmware to the device, and look at the console output, we can see that the device has successfully sent data to the Memfault backend and the backend has responded successfully:

[01:56:34.941,864] <inf> sta: Sending data to Memfault
[01:56:35.578,918] <dbg> mflt: memfault_platform_log: Response Complete: Parse Status 0 HTTP Status 202!
[01:56:35.578,948] <dbg> mflt: memfault_platform_log: Body: Accepted
[01:56:35.579,010] <dbg> mflt: memfault_platform_log: No more data to send

Summary

In this guide, we demonstrated how to incorporate Memfault's SDK to work with the nRF7002 Wi-Fi transceiver chip, with Zephyr running on the accompanying nRF53840 application processor. We started with a Wi-Fi sample provided by Nordic and identified the necessary modifications to allow the device to connect the Wi-Fi network. Once we confirmed a connection to the Wi-Fi network, we identified additional modifications to incorporate the Memfault SDK. Finally, we tested our modifications and confirmed that the backend successfully received data and that the device appeared in the backend.

Memfault has an excellent example that can be used to exercise more of Memfault's features. The example is located at https://github.com/nrfconnect/sdk-nrf/tree/main/samples/debug/memfault. The example can be executed on the nRF7002 development kit and provides a comprehensive Memfault CLI to generate and upload coredumps and device metrics.