Skip to main content

ARM GCC Getting Started Guide

This tutorial will go over integrating the panics component of the Memfault Firmware SDK into a system that is using the GNU ARM Embedded Toolchain (GCC) compiler.

Clone Memfault SDK

Using a Git client, clone the memfault-firmware-sdk repository from:

$ git clone https://github.com/memfault/memfault-firmware-sdk.git

Add Memfault SDK to Build System

For Make or CMake based projects, the Memfault SDK has a helper file which can be included by the build system to pick up the necessary dependencies.

For example, the Make integration looks like this:

MEMFAULT_COMPONENTS := core util panics
MEMFAULT_SDK_ROOT = $(YOUR_PROJECT_ROOT_DIR)/memfault-firmware-sdk
include $(MEMFAULT_SDK_ROOT)/makefiles/MemfaultWorker.mk
# [...]
YOUR_SRC_FILES += $(MEMFAULT_COMPONENTS_SRCS)
YOUR_INC_PATHS += $(MEMFAULT_COMPONENTS_INC_FOLDERS)

Manually Adding Sources

If you are using another build system, sources can also be added to the projects source list manually:

Details
  • add $MEMFAULT_FIRMWARE_SDK/components/[panics, core, util]/include to the include paths provided as -I arguments to gcc
  • pick up the source files located at $MEMFAULT_FIRMWARE_SDK/components/[panics, core, util]/src.

The exact list you need for this tutorial can be found here

MEMFAULT_SDK_ROOT = $(ROOT_DIR)/memfault-firmware-sdk
MEMFAULT_CORE_SRC_DIR = $(MEMFAULT_SDK_ROOT)/components/core/src
MEMFAULT_PANICS_SRC_DIR = $(MEMFAULT_SDK_ROOT)/components/panics/src
MEMFAULT_UTIL_SRC_DIR = $(MEMFAULT_SDK_ROOT)/components/util/src

YOUR_SRC_FILES += \
$(MEMFAULT_CORE_SRC_DIR)/arch_arm_cortex_m.c \
$(MEMFAULT_CORE_SRC_DIR)/memfault_data_packetizer.c \
$(MEMFAULT_CORE_SRC_DIR)/memfault_event_storage.c \
$(MEMFAULT_CORE_SRC_DIR)/memfault_log.c \
$(MEMFAULT_CORE_SRC_DIR)/memfault_serializer_helper.c \
$(MEMFAULT_CORE_SRC_DIR)/memfault_trace_event.c \
$(MEMFAULT_PANICS_SRC_DIR)/memfault_coredump.c \
$(MEMFAULT_PANICS_SRC_DIR)/memfault_coredump_regions_armv7.c \
$(MEMFAULT_PANICS_SRC_DIR)/memfault_fault_handling_arm.c \
$(MEMFAULT_PANICS_SRC_DIR)/memfault_ram_reboot_info_tracking.c \
$(MEMFAULT_PANICS_SRC_DIR)/memfault_reboot_tracking_serializer.c \
$(MEMFAULT_UTIL_SRC_DIR)/memfault_chunk_transport.c \
$(MEMFAULT_UTIL_SRC_DIR)/memfault_circular_buffer.c \
$(MEMFAULT_UTIL_SRC_DIR)/memfault_crc16_ccitt.c \
$(MEMFAULT_UTIL_SRC_DIR)/memfault_minimal_cbor.c \
$(MEMFAULT_UTIL_SRC_DIR)/memfault_varint.c \

YOUR_INC_PATHS += \
$(MEMFAULT_SDK_ROOT)/components/core/include \
$(MEMFAULT_SDK_ROOT)/components/panics/include \
$(MEMFAULT_SDK_ROOT)/components/util/include

Implement platform specific storage region for crash data

We typically recommend starting with the RAM based Coredump port. By default this will only save the top of the stack at the time of crash but it lets you quickly get the system up and running and get a feel for how things work. To do this:

  1. Add $(MEMFAULT_SDK_ROOT)/ports/panics/src/memfault_platform_ram_backed_coredump.c to the build

  2. Mark the section being used to hold the coredump as a NOLOAD region in your linker script so it remains uninitialized when the device reboots

    /* your linker script (.ld file) */
    .noinit (NOLOAD): { KEEP(*(*.mflt_coredump)) } > RAM

Coredump data can also be stored to any other backing storage (eMMC, external NOR flash, internal flash, etc) by implementing the required dependencies instead of using memfault_platform_ram_backed_coredump.c.

Implement other platform dependencies

In order to save coredumps, you will need to fill in the functions in the block below

#include "memfault/panics/assert.h"
#include "memfault/core/platform/core.h"
#include "memfault/core/platform/debug_log.h"
#include "memfault/core/platform/device_info.h"

void memfault_platform_log(eMemfaultPlatformLogLevel level, const char *fmt, ...) {
// Hook up logging implementation
}

void memfault_platform_get_device_info(sMemfaultDeviceInfo *info) {
// platform specific version information
*info = (sMemfaultDeviceInfo) {
.device_serial = "DEMOSERIAL",
.software_type = "nrf-main",
.software_version = "1.0.0",
.hardware_version = "nrf-proto",
};
}

void memfault_platform_reboot(void) {
// Last function called before memfault after a crash
// expect the platform to reboot the system
__asm("bkpt 1");
while (1) { }
}

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, all data is published via the same "chunk" REST endpoint and the firmware 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()) { }
}
Server-side rate limiting will apply to the device you're using to work on the integration process. Once you can see the device on the Memfault Web App, consider enabling Server-Side Developer Mode for it on the Memfault Web App to temporarily bypass these limits.