Skip to main content

STM32CubeIDE Integration Guide

The following guide will walk you through step-by-step how to integrate and test the Memfault SDK for a STM32 device using STM32CubeIDE.

1. Create a Project

Create a Project and get a Project Key

Go to app.memfault.com and from the "Select A Project" dropdown, click on "Create Project" to setup your first project. Choose a name that reflects your product, such as "smart-sink-dev".

Once you've created your project, you'll be automatically taken to an page that includes your project key. Copy the key and follow the rest of this guide.

2. Set up the SDK

The following steps will be walking through adding Memfault to a standard STM32CubeIDE example project. For reference, this project is located at ~/STM32CubeIDE/workspace_1.16.1/Virtual_COM_Port with the following directory structure:

.
├── .git
├── .gitignore
├── .mxproject
├── Binary
├── Drivers
├── Inc
├── Middlewares
├── README.md
├── STM32CubeIDE
├── Src
├── Virtual_COM_Port.ioc
└── readme.html

Add Memfault SDK as a Submodule

Add SDK as a submodule at top level of project (i.e. project folder within the workspace):

cd $PROJECT_ROOT  # e.g. ~/STM32CubeIDE/workspace_1.16.1/Virtual_COM_Port
git submodule add https://github.com/memfault/memfault-firmware-sdk.git memfault-firmware-sdk
git add . # stage the addition of the submodule

Your directory structure should now look like:

.
├── .git
├── .gitignore
├── .gitmodules # <-- new
├── .mxproject
├── Binary
├── Drivers
├── Inc
├── Middlewares
├── README.md
├── STM32CubeIDE
├── Src
├── Virtual_COM_Port.ioc
├── memfault-firmware-sdk # <-- new
└── readme.html

Note that because the SDK is intentionally not nested into the STM32CubeIDE folder, Memfault sources will not get picked up by the build by default. In the next step, we will add these sources to the STM32CubeIDE build system.

Next, use the Memfault Eclipse project patcher script to link Memfault includes and sources into the project using these arguments:

  • --memfault-sdk-dir: The directory memfault-firmware-sdk was copied to
  • --project-dir: The directory with the Eclipse .project to update
cd $PROJECT_ROOT # e.g. ~/STM32CubeIDE/workspace_1.16.1/Virtual_COM_Port
python3 memfault-firmware-sdk/scripts/eclipse_patch.py \
--memfault-sdk-dir memfault-firmware-sdk \
--project-dir STM32CubeIDE
Writing result to ~/STM32CubeIDE/workspace_1.16.1/Virtual_COM_Port/STM32CubeIDE/.project
Writing result to ~/STM32CubeIDE/workspace_1.16.1/Virtual_COM_Port/STM32CubeIDE/.cproject
Hurray, .project & .cproject have been successfully patched! Be sure to 'Refresh' project to synchronize changes!

As noted in the message, run a Refresh on the project to ensure STMCubeIDE picks up the changes. Your directory structure in STM32CubeIDE will now look like:

Create Platform-Specific Files

Create a folder to hold your platform-specific files and copy templates:

cd $PROJECT_ROOT
mkdir STM32CubeIDE/memfault_port
cp memfault-firmware-sdk/ports/templates/* $PROJECT_ROOT/STM32CubeIDE/memfault_port

Link the RAM-backed coredump implementation in $PROJECT_ROOT/memfault-firmware-sdk/ports/panics/src/memfault_platform_ram_backed_coredump.c into $PROJECT_ROOT/STM32CubeIDE/memfault_port/. Dragging and dropping from the file system is easiest. Select the Link to files option after dropping the file into the memfault_port folder:

Add this new memfault_port folder to the project include paths under Properties > C/C++ Build > Settings > Tool Settings > MCU GCC Compiler > Include Paths. Be sure this setting is applied to "All configurations".

Add the required macro option in memfault_platform_config.h:

memfault_platform_config.h
#define MEMFAULT_USE_GNU_BUILD_ID 1

Right after the .text section in your linker file, add the _start_gnu_build_id_start. For this sample project, we edit STM32L476RGTX_FLASH.ld:

.note.gnu.build-id :
{
__start_gnu_build_id_start = .;
KEEP(*(.note.gnu.build-id))
} > FLASH
info

Be sure to update FLASH to match the name of the section .text is placed in!

Remove Conflicting Exception Headers

Memfault provides exception handlers to capture crashes properly. STM32 provides these handlers by default, and a linker error such as the following will be emitted when left in:

~/STM32CubeIDE/workspace_1.16.1/Virtual_COM_Port/memfault-firmware-sdk/components/panics/src/memfault_fault_handling_arm.c:433: multiple definition of `NMI_Handler'; ./Application/User/stm32l4xx_it.o:~/STM32CubeIDE/workspace_1.16.1/Virtual_COM_Port/Src/stm32l4xx_it.c:89: first defined here

Remove the handler definitions for the following handlers provided by STM32 to allow Memfault's to be used. For this sample project, they are in stm32l4xx_it.c:

  • NMI_Handler()
  • HardFault_Handler()
  • MemManage_Handler()
  • BusFault_Handler()
  • UsageFault_Handler()

Boot Memfault & Enable Basic Platform Logging

  1. Add the Memfault platform boot function to your main() function. For example:

    main.c
    /* Private includes ----------------------------------------------------------*/

    /* USER CODE BEGIN Includes */

    #include "memfault/components.h"

    /* USER CODE END Includes */

    // ...

    int main(void)
    {
    // ...

    /* USER CODE BEGIN 2 */

    memfault_platform_boot();

    /* USER CODE END 2 */

    // ...
    };
  2. Memfault prints a few log messages when this function is called. Add a simple definition to the memfault_platform_log_config.h file to push these prints to the console. For example:

    memfault_platform_log_config.h
    #include "stdio.h"

    #define _LOG_IMPL(lvl, fmt, ...) \
    do { \
    printf(fmt "\r\n", ## __VA_ARGS__ ); \
    } while (0)

    #define MEMFAULT_LOG_DEBUG(fmt, ...) _LOG_IMPL(kMemfaultPlatformLogLevel_Debug, fmt, ## __VA_ARGS__)
    #define MEMFAULT_LOG_INFO(fmt, ...) _LOG_IMPL(kMemfaultPlatformLogLevel_Info, fmt, ## __VA_ARGS__)
    #define MEMFAULT_LOG_WARN(fmt, ...) _LOG_IMPL(kMemfaultPlatformLogLevel_Warning, fmt, ## __VA_ARGS__)
    #define MEMFAULT_LOG_ERROR(fmt, ...) _LOG_IMPL(kMemfaultPlatformLogLevel_Error, fmt, ## __VA_ARGS__)

    #define MEMFAULT_LOG_RAW(fmt, ...) _LOG_IMPL(kMemfaultPlatformLogLevel_Debug, fmt "\n", ## __VA_ARGS__)
  3. Then, tell Memfault to pick up these sources by adding the following define in your memfault_platform_config.h:

    memfault_platform_config.h
    #define MEMFAULT_PLATFORM_HAS_LOG_CONFIG 1

✅ Build Check

Build and flash to ensure the source was included correctly. The following should appear on boot!

GNU Build ID: <build id>
S/N: DEMOSERIAL
SW type: app-fw
SW version: 1.0.0
HW version: dvt1
Memfault Initialized!

3. Add STM32 Reboot Tracking

For the STM F4, F7, H7, L4, and WB part families, ports are available for recovering reset reason information by reading the "Reset and Clock Control" (RCC)'s "control & status register" (CSR).

  1. Add memfault-firmware-sdk/ports/stm32cube/l4/rcc_reboot_tracking.c as a Linked File under memfault_components via the drag and drop method described earlier.
  2. Remove definition for memfault_reboot_reason_get() in memfault_platform_port.c

✅ Build Check

Rebuild to ensure the new reboot tracking was adding correctly. A new print should appear on boot:

GNU Build ID: <build id>
S/N: DEMOSERIAL
SW type: app-fw
SW version: 1.0.0
HW version: dvt1
Reset Reason, RCC_CSR=0x1c000600
Reset Causes:
Software
Memfault Initialized!

4. (If applicable) Integrate FreeRTOS Port

  1. Execute the eclipse patcher to include FreeRTOS port sources:

    python3 memfault-firmware-sdk/scripts/eclipse_patch.py \
    --memfault-sdk-dir memfault-firmware-sdk \
    --project-dir STM32CubeIDE \
    --target-port freertos
  2. Add link to the FreeRTOS port heartbeat config folder memfault-firmware-sdk/ports/freertos/config inside memfault_includes/ports. Drag and drop this config folder and select Link to files and folders:

    The memfault_includes folder should now look like:

  3. Add an include path to memfault_includes/ports/config folder in project settings. Be sure to apply this setting to "All configurations".

  4. Add #include "memfault_metrics_heartbeat_freertos_config.def" to your memfault_port/memfault_metrics_heartbeat_config.def

  5. Remove definition for memfault_platform_metrics_timer_boot() in memfault_platform_port.c. This is implemented by the FreeRTOS port in the SDK.

  6. Remove definition for vApplicationStackOverflowHook() — the Memfault FreeRTOS port provides a definition for this as well.

  7. Add the Memfault FreeRTOS port initialization function to your memfault_platform_boot():

    memfault_platform_port.c
    #include "memfault/components.h"
    #include "memfault/ports/freertos.h"

    int memfault_platform_boot(void) {

    memfault_build_info_dump();
    memfault_device_info_dump();

    // Boot FreeRTOS port
    memfault_freertos_port_boot();

    memfault_platform_reboot_tracking_boot();

    // ...

    return 0
    }
  8. By default, Memfault uses FreeRTOS semaphores for locking, therefore the FreeRTOS scheduler must be initialized before memfault_platform_boot() is called. Adjust the location of memfault_platform_boot() if needed.

✅ Build Check

Rebuild and reflash to ensure the new FreeRTOS source was added properly!

Testing Things Out

For testing the integration, Memfault recommends enabling Memfault's demo CLI on the target device.

Once enabled, you can try collecting a crash as a first step:

mflt> test_assert

The device will crash and reset. Once the CLI is back up, check that a coredump is available:

mflt> get_core
MFLT: [INFO] Has coredump with size: 20224

Dump the captured data to the console:

mflt> export

Copy the logs from the console, navigate to the "Integration Hub / Chunks Debug" view for your project, and paste the logs:

Testing Data Uploaded to Memfault

Now it's time to see data decoded in the Memfault platform. To do that, we first need to upload the generated symbol file (for STM32CubeIDE projects, it's usually $PROJECT_ROOT/STM32CubeIDE/Debug/<your project name>.elf or $PROJECT_ROOT/STM32CubeIDE/Release/<your project name>.elf).

Upload Symbol File

At this point, you should be able to generate test events and crashes and push the data to the Memfault UI.

You can confirm the error traces and crashes have arrived successfully by navigating to the "Issues" page- there should be a new issue with the "Symbols Missing" label:

Clicking into the Issue will show the trace and a message that the symbol file is missing. It can be uploaded by clicking the button highlighted below:

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

note

The Issue created when the symbol file is missing can now be set to resolved. It's good practice to always upload a symbol file before devices send any data.

Symbol files can also be uploaded from the Software → Symbol Files tab (follow this deep link to be brought to the symbol file upload point in the UI):

In addition to supporting decoding trace/coredump data, symbol files are also required for decoding Metrics.

tip

You can programmatically upload symbol files with the Memfault CLI tool.

Symbol files should be uploaded to Memfault before devices send any data, to ensure all device data can be decoded.

Next Steps

For more information on logging, OTA, reboot reasons, and other pieces of Memfault, explore the Core Subsystems Guides!