Skip to content

Zephyr Integration

Zephyr + HeliaAOT + NS-CMSIS-NN (Customer Integration Guide)

This guide assumes you are working in a west workspace created by west init, and that the workspace contains: - zephyr/ (Zephyr repo) - modules/ (external Zephyr modules) - app/ (your application source)

Below is the expected workspace layout; details on how to create each part follow later in this guide.

<ws>/
├── zephyr/
│   ├── west.yml                 # NOTE: in this environment, west.yml lives inside zephyr/
│   └── ...                      # Zephyr source tree
├── modules/
│   ├── ns-cmsis-nn/             # NS-CMSIS-NN Zephyr module (checked out or copied)
│   └── helia_aot_nn/            # HeliaAOT generated Zephyr module (checked out or copied)
└── app/
    └── helia_aot_app/
        ├── CMakeLists.txt
        ├── prj.conf
        ├── VERSION              # optional
        └── src/
            └── main.c

It also assumes known-good versions: - Zephyr: 4.3 - Zephyr SDK: zephyr-sdk-0.17.4


1) Install prerequisites (quick expectations)

  • Install Zephyr and Python dependencies per Zephyr Getting Started.
  • Install Zephyr SDK per Zephyr Getting Started.

(Exact host dependency install steps are intentionally omitted here to avoid duplicating upstream Zephyr documentation.)

For official guidance, see:


2) Create or enter a west workspace

  • Create or enter an existing west workspace (west init / west update).
  • Confirm zephyr/ exists at the workspace root.
  • Run west update after editing zephyr/west.yml.

3) Generate the HeliaAOT Zephyr module

Run HeliaAOT convert on your model:

helia-aot convert \
    --model.path model.tflite \
    --module.path ./out \
    --module.name helia_aot_nn \
    --module.type zephyr

Expected output layout

This command produces:

out/helia_aot_nn/
├── includes-api/
├── src/
├── zephyr/
│   ├── CMakeLists.txt
│   ├── Kconfig
│   └── module.yml
├── LICENSE
└── README.md

Place the module into the workspace

Copy (or move) the generated module into modules/:

cp -r ./out/helia_aot_nn <ws>/modules/helia_aot_nn

4) Add NS-CMSIS-NN to the workspace

You have two supported integration styles: west-managed (recommended for reproducibility) or app-local (useful for quick experiments). Pick one and stay consistent. HeliaAOT-generated models rely on CMSIS-NN kernels provided by ns-cmsis-nn (rather than Tensorflow), which must be available at build time.

Add NS-CMSIS-NN as a project entry in zephyr/west.yml (in this environment, the manifest is under zephyr/).

Example snippet:

remotes:
  - name: ambiqai
    url-base: git@github.com:AmbiqAI

projects:
  - name: ns-cmsis-nn
    remote: ambiqai
    repo-path: ns-cmsis-nn
    path: modules/ns-cmsis-nn
    revision: main

Notes: - If an ambiqai remote already exists, reuse it or rename this one to avoid collisions. - Prefer pinning revision to a tag or commit SHA instead of main for reproducibility.

Then from <ws>:

west update

This produces:

<ws>/modules/ns-cmsis-nn
cp -r <path-to-ns-cmsis-nn> <ws>/modules/ns-cmsis-nn

5) Choose how Zephyr discovers modules: west vs ZEPHYR_EXTRA_MODULES

Zephyr can discover modules in two common ways:

If modules are included as projects: in the manifest, they’re fetched/pinned by west. This is ideal when you want:

  • reproducible builds
  • clean CI
  • a single place to pin known-good revisions

Note: HeliaAOT modules are generated artifacts, so they typically are not fetched from a remote by west. For HeliaAOT-generated modules, follow step 5B (use ZEPHYR_EXTRA_MODULES).

If you want your app to explicitly point to module paths (including locally copied/generated modules), you can set:

  • ZEPHYR_EXTRA_MODULES in your app CMakeLists.txt

This is convenient for:

  • app-local “bring your own module” development
  • quickly switching between module variants without editing a manifest

Tradeoff: more manual path management; reproducibility depends on your own process.


6) Create the application

<ws>/app/helia_aot_app/CMakeLists.txt

Below is a pragmatic pattern that works whether modules are west-fetched or copied locally into <ws>/modules.

cmake_minimum_required(VERSION 3.20.0)

# If you are NOT relying on west/module discovery, explicitly list module paths here.
# If modules are already discovered via west manifest, you can remove this block.
list(APPEND ZEPHYR_EXTRA_MODULES
  ${CMAKE_CURRENT_SOURCE_DIR}/../../modules/ns-cmsis-nn
  ${CMAKE_CURRENT_SOURCE_DIR}/../../modules/helia_aot_nn
)
# IMPORTANT: must appear before find_package(Zephyr)

find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})
project(helia_aot_app)

target_sources(app PRIVATE src/main.c)

<ws>/app/helia_aot_app/prj.conf

This file is necessarily board/model dependent. Keep it minimal and add only what you need.

... # Existing configurations

# Enable FPU support
CONFIG_FPU=y
# If multiple threads/ISRs may use MVE/FP:
# CONFIG_FPU_SHARING=y

# Enable printing via UART
CONFIG_PRINTK=y
CONFIG_CONSOLE=y
CONFIG_UART_CONSOLE=y

# Enable NS-CMSIS-NN
CONFIG_NS_CMSIS_NN=y
# Enable all kernels
CONFIG_NS_CMSIS_NN_ALL=y
# -OR- selectively add kernels
# CONFIG_NS_CMSIS_NN_ACTIVATION=y
# CONFIG_NS_CMSIS_NN_BASICMATH=y
# CONFIG_NS_CMSIS_NN_CONCATENATION=y
# CONFIG_NS_CMSIS_NN_CONVOLUTION=y
# CONFIG_NS_CMSIS_NN_FULLYCONNECTED=y
# CONFIG_NS_CMSIS_NN_LSTM=y
# CONFIG_NS_CMSIS_NN_NNSUPPORT=y
# CONFIG_NS_CMSIS_NN_PAD=y
# CONFIG_NS_CMSIS_NN_POOLING=y
# CONFIG_NS_CMSIS_NN_QUANTIZATION=y
# CONFIG_NS_CMSIS_NN_RESHAPE=y
# CONFIG_NS_CMSIS_NN_SOFTMAX=y
# CONFIG_NS_CMSIS_NN_STRIDED_SLICE=y
# CONFIG_NS_CMSIS_NN_SVD=y
# CONFIG_NS_CMSIS_NN_TRANSPOSE=y

# Enable HELIA_AOT_NN module
CONFIG_HELIA_AOT_NN=y
# ^ Notice we use uppercase with hyphens replaced by underscores

<ws>/app/helia_aot_app/src/main.c

Use the generated API from includes-api/ (made available through the module build).

#include "aot_model.h"
#include "aot_common.h"
#include <zephyr/sys/printk.h>

static aot_model_context_t aot_model_ctx;

int main(void)
{
    int32_t status = aot_model_init(&aot_model_ctx);
    if (status != 0) {
        printk("aot_model_init failed: %ld\n", (long)status);
        return 0;
    }

    // TODO: Fill inputs
    // Example conceptually:
    // memcpy(aot_model_ctx.inputs[0].data, my_input, aot_model_ctx.inputs[0].nbytes);

    status = aot_model_run(&aot_model_ctx);
    if (status != 0) {
        printk("aot_model_run failed: %ld\n", (long)status);
        return 0;
    }

    // TODO: Read outputs

    printk("HeliaAOT inference complete\n");
    while(1);
}

7) Build

west build -p always -b <board> -s <ws>/app/helia_aot_app -d <ws>/out/build

Example:

west build -p always -b apollo510_evb -s <ws>/app/helia_aot_app -d <ws>/out/build

8) Flash

west flash --build-dir out/build
Note: To view application output, ensure console support is enabled in prj.conf, then connect to the board's console using a serial terminal. For example, on macOS:

screen /dev/tty.usbmodemXXXX 115200

9) Common integration checkpoints

  • Confirm both modules are physically present:

  • <ws>/modules/ns-cmsis-nn

  • <ws>/modules/helia_aot_nn
  • Confirm HeliaAOT module metadata exists:

  • <ws>/modules/helia_aot_nn/zephyr/module.yml

  • If the module is not discovered:

  • ensure ZEPHYR_EXTRA_MODULES paths are correct or

  • ensure the module is included/discoverable via west/module mechanism