nRF Connect SDK Integration

In this guide we will walk through the steps for integrating the Memfault Firmware SDK into a project using the nRF Connect SDK. The integration has been tested against the v1.3.0 nRF Connect SDK release.

Upon completion of the integration, the following subcomponents will be added to your system!

Integration Steps

⚠️ This tutorial assumes you have a working nRF Connect SDK Environment and are able to flash a board supported by the SDK (i.e nRF91, nRF53, nRF52, etc)

Add memfault-firmware-sdk to nrf/west.yml

You will first need to add the memfault-firmware-sdk to your projects manifest. By default, for the nRF Connect SDK this is located at nrf/west.yml:

diff --git a/west.yml b/west.yml
index 17071f47..84bb97f0 100644
--- a/west.yml
+++ b/west.yml
@@ -112,6 +114,10 @@ manifest:
repo-path: mbedtls
revision: mbedtls-2.16.6
remote: armmbed
+ - name: memfault-firmware-sdk
+ url: https://github.com/memfault/memfault-firmware-sdk
+ path: modules/memfault-firmware-sdk
+ revision: master

You will then need to run west update to clone the memfault-firmware-sdk:

$ west update
# ...
=== updating memfault-firmware-sdk (modules/memfault-firmware-sdk):
--- memfault-firmware-sdk: initializing
Initialized empty Git repository in modules/memfault-firmware-sdk/.git/
--- memfault-firmware-sdk: fetching, need revision master

Apply Zephyr Patch to Enable Coredump Collection

The memfault-firmware-sdk relies on a small patch to the Zephyr fault handling infrastructure so full stacktraces and local variable state can be recovered when an exception takes place. You can add it to your system by appling the patch included in the SDK:

$ cd ${PATH_TO_ZEPHYR_REPO}/zephyr
# Apply & Commit Patch
$ git am ../modules/memfault-firmware-sdk/ports/nrf-connect-sdk/zephyr/01-v1.3.0-full-esf.patch

Add Memfault to Project's CMakeLists.txt

Add the following before the find_package(...) line in your project's CMakeLists.txt

list(APPEND ZEPHYR_EXTRA_MODULES $ENV{ZEPHYR_BASE}/../modules/memfault-firmware-sdk/ports/nrf-connect-sdk)
# Note: A line like "find_package(Zephyr HINTS $ENV{ZEPHYR_BASE})" should be below

Implement Platform Dependency

In order to save traces, you will need to implement a dependency function that tells memfault version information

#include "memfault/core/platform/device_info.h"
void memfault_platform_get_device_info(sMemfaultDeviceInfo *info) {
// platform specific version information
*info = (sMemfaultDeviceInfo) {
.device_serial = "your-device-serial",
.software_type = "sw-name-fill-me-in",
.software_version = "1.0.0-dev1",
.hardware_version = "hw-name-fill-me-in",
};
}

Create trace reasons definition file

The trace event module within the SDK makes it easy to track errors in a way that requires less storage than full coredump traces and also allows the system to keep running after capturing the event. The program counter, return address and a custom "reason" are saved.

The list of custom reasons is defined in a separate file that you need to create.

The file must be named memfault_trace_reason_user_config.def and placed in a directory included in your project.

$ cd $YOUR_PROJECT_ROOT
$ mkdir config
$ touch config/memfault_trace_reason_user_config.def

And then in your project's CMakeLists.txt add:

zephyr_include_directories(config)

To start, we recommend adding a couple reasons for error paths in your codebase (such as peripheral bus read/write failures, transport errors and unexpected timeouts).

Here is what the memfault_trace_reason_user_config.def file should look like:

// your_project/config/memfault_trace_reason_user_config.def
MEMFAULT_TRACE_REASON_DEFINE(your_custom_error_reason_1)
MEMFAULT_TRACE_REASON_DEFINE(your_custom_error_reason_2)
// ...

Generate Some Trace Events

Next, we'll need to use the MEMFAULT_TRACE_EVENT macro to capture a trace event when an error occurs.

Note that it is perfectly fine to use the same reason in different places. Because the program counter and return address are captured in the trace event, you will be able to see the two topmost frames (function name, source file and line) in Memfault's Issue UI and distinguish between the two.

The nRF Connect SDK port also exposes a mflt trace CLI command which can be used to generate events for test purposes:

uart:~$ mflt trace
<dbg> <mflt>: Trace Event Generated!

You can also start to add trace events for error paths you are interested in tracking:

#include "memfault/core/trace_event.h"
// [ ...]
void ble_le_process_ll_pkt(...) {
// ...
if (invalid_msg_id) {
MEMFAULT_TRACE_EVENT(bt_invalid_msg_id);
// ...
}
// ..
}

Create a Project and Get Project API Key

Go to https://app.memfault.com/ and from the "Select A Project" dropdown, click on "Create Project" to setup your first project such as "smart-sink-dev".

Then navigate to "Settings" -> "General", where you can find the "Project API Key" which will be used to communicate with Memfault's web services.

Publish data to the Memfault cloud

Extensive details about how data from the Memfault SDK makes it to the cloud can be found here. In short, the Memfault SDK packetizes data into "chunks" that must be pushed to the Memfault cloud via the chunk REST endpoint.

A typical integration looks like this:

#include "memfault/core/data_packetizer.h"
// [...]
bool try_send_memfault_data(void) {
// buffer to copy chunk data into
uint8_t buf[USER_CHUNK_SIZE];
size_t buf_len = sizeof(buf);
bool data_available = memfault_packetizer_get_chunk(buf, &buf_len);
if (!data_available ) {
return false; // no more data to send
}
// send payload collected to chunks endpoint
user_transport_send_chunk_data(buf, buf_len);
return true;
}
void send_memfault_data(void) {
// [... user specific logic deciding when & how much data to send
while (try_send_memfault_data()) { }
}

Test Tip

Data can also also be dumped out over the CLI using the mflt export_data CLI command.

uart:~$ mflt export_data
<inf> <mflt>: MC:SFQCpwIBAwEHalRFU1RTRVJJQUwKbXRlc3Qtc29mdHdhcmUJajEuMC4wLXRlcw==:
<inf> <mflt>: MC:gCx0Bm10ZXN0LWhhcmR3YXJlBKEBoXJjaHVua190ZXN0X3N1Y2Nlc3MBMeQ=:

The CLI output can then be saved to a file and the "chunk" data can be posted to the Memfault Cloud using the Memfault CLI tool:

$ memfault --project-key ${YOUR_PROJECT_API_KEY} post-chunk --encoding sdk_data_export cli-output.txt
Found 2 Chunks. Sending Data ...
Success

Upload Symbol File

At this point you should be able to generate a test trace event and push it to the Memfault UI. You can confirm the issue has arrived succesfully by navigating to the "Issues" page. Follow the link pointed to below and upload a symbol file.

After this step you will see the trace in the list of issues!

💡 You can programatically upload symbol files with the Memfault CLI tool.

Troubleshooting Data Transfer

If you run into any issues with your data transfer implementation, we have tools to help!