Firmware integration
Build the out/kws_ref module from the previous step into a small application.
The main path below uses Zephyr on Apollo510 EVB and calls the generated test
case. You can finish the build without connecting a board.
Every format needs heliaCORE, Ambiq’s kernel library, which is released as the
ns-cmsis-nn package. Each module needs ns-cmsis-nn at or above the version it
records: the guard in aot_common.h, also written as
generator.cmsis_nn_required in aot_plan.json. The repository-wide minimum
is on Version requirements, and operators can raise it, so read
the module’s own value. Get ns-cmsis-nn from its
releases; upstream Arm
CMSIS-NN is not supported. Changing module.type changes build files,
platform headers and hooks, so regenerate for the environment you use.
CMake and NSX check the provider’s readable version header during configuration. An older version fails with the required and detected versions. This early check recognizes decimal version literals, including parenthesized literals; it does not evaluate C preprocessor expressions. If the header or version cannot be resolved, the generated common-header check remains the compatibility guard.
Choose your build environment
Section titled “Choose your build environment”Follow Zephyr to complete this walkthrough, or use the recipe matching your
existing firmware project. Each recipe starts from the same saved kws.yaml.
| Environment | Status | Integration files | Recipe |
|---|---|---|---|
| Zephyr | Supported | Module manifest and Kconfig | Build the walkthrough application |
| CMake | Supported | CMake target | Add to a CMake project |
| NSX | Supported | Module manifest and CMake target | Use an NSX workspace |
| CMSIS-Pack | Evaluation | Pack description and optional archive | Package for a pack-aware tool |
For Zephyr, CMake and NSX, the file layout and C interface of the output are
covered by the compatibility promise;
how far each one is built and run by the repository’s CI is on
Toolchains and build environments.
CMSIS-Pack output is for evaluation until the packs it writes pass full
packchk validation, and is not covered by the promise.
Zephyr
Section titled “Zephyr”Start with a working west workspace and Zephyr SDK supporting apollo510_evb.
The repository’s Zephyr compile test pins Zephyr v4.3.0, west 1.5.0 and SDK
0.17.4 with the arm-zephyr-eabi toolchain. Its workspace includes cmsis_6,
hal_ambiq and cmsis-dsp. The current kernel dependency used by that test is
listed on Version requirements.
If Zephyr is new to you, complete its environment setup and build an Apollo510 Hello World application first. The application below assumes that SDK/toolchain setup is already working; it supplies all the additional application files for this model.
From the kws-first directory used for conversion, create:
kws-first/├── out/kws_ref/ # Already generated└── app/ ├── CMakeLists.txt ├── prj.conf ├── src/main.c └── modules/ns-cmsis-nn/ # heliaCORE checkoutmkdir -p app/src app/modulesgit clone --depth 1 --branch vX.Y.Z https://github.com/AmbiqAI/ns-cmsis-nn.git app/modules/ns-cmsis-nnReplace vX.Y.Z with the version in aot_common.h or a newer release tag, and
record it. Register it and the generated module before Zephyr configures
the application:
cmake_minimum_required(VERSION 3.20.0)
list(APPEND ZEPHYR_EXTRA_MODULES ${CMAKE_CURRENT_SOURCE_DIR}/modules/ns-cmsis-nn ${CMAKE_CURRENT_SOURCE_DIR}/../out/kws_ref)find_package(Zephyr REQUIRED HINTS $ENV{ZEPHYR_BASE})project(kws_first)target_sources(app PRIVATE src/main.c)Enable the generated module, kernels and serial logging:
CONFIG_FPU=yCONFIG_NS_CMSIS_NN=yCONFIG_NS_CMSIS_NN_ALL=yCONFIG_KWS_REF=yCONFIG_PRINTK=yCONFIG_CONSOLE=yCONFIG_UART_CONSOLE=yCONFIG_KWS_REF comes from module.name, uppercased with hyphens changed to
underscores. CONFIG_NS_CMSIS_NN_ALL includes all kernel families; the generated
README lists individual family switches for later build-size tuning.
Save this complete entry point:
#include <zephyr/kernel.h>#include <zephyr/sys/printk.h>#include "aot_test_case.h"
int main(void){ printk("KWS golden check: starting\n"); int32_t status = aot_test_case_init(); printk("KWS init status=%ld\n", (long)status); if (status != 0) { return (int)status; }
status = aot_test_case_run(); printk("KWS test status=%ld\n", (long)status); return (int)status;}The test owns its context, copies golden.npz input data from generated constant
arrays, runs the model and compares the output. It does not read files from the
board. Zephyr’s CONFIG_PRINTK also enables logging from the generated module;
without it, those comparison messages are discarded.
Using your Zephyr environment, build from kws-first:
west build -p always -b apollo510_evb -s app -d build/kws_refCheck for build/kws_ref/zephyr/zephyr.elf. Inspect the build’s linker map when
confirming memory placement: Apollo510 Zephyr hooks distinguish DTCM data from
ITCM, and the rest of your firmware also consumes memory. A successful link
establishes the build contract, not numerical correctness.
The repository’s Zephyr job compiles and links a small add_scalar_s8 model
with verification disabled against a real Zephyr/CMSIS 6 tree. That exercises
the integration mechanism; it is not a recorded KWS execution or a board test.
Continue to On-device validation to
program and observe this application.
For a firmware project that already supplies the cross-toolchain, startup and linker script:
helia-aot convert --path kws.yaml --module.type cmake --module.path ./out-cmakeIn the parent project, add heliaCORE before the generated module:
add_subdirectory(modules/ns-cmsis-nn)add_subdirectory(/absolute/path/to/out-cmake/kws_ref ${CMAKE_BINARY_DIR}/kws_ref)target_link_libraries(app PRIVATE kws_ref)The generated static library exposes includes-api, requests c_std_99, links
m for GCC/Clang and links ns::cmsis-nn if that target already exists. Without
it, the consumer must supply equivalent compatible kernel linkage. Merely
configuring this library does not create a complete firmware executable.
CMake output defaults AOT_PRINTF and placement hooks to no-ops. Supply logging
and section definitions to all generated translation units, for example
through a compiler-preincluded application header configured on the module
target. A macro defined only in main.c does not affect separately compiled
aot_test_case.c. Confirm actual placement in the linker map.
helia-aot convert --path kws.yaml --module.type nsx --module.path ./out-nsxThis emits CMakeLists.txt and nsx-module.yaml. Use them inside a neuralSPOT-X
project whose board layer defines NSX_BOARD_FLAGS_TARGET. Add the NSX kernel
module before the generated module. It is nsx-cmsis-nn, which ships in the
ns-cmsis-nn repository’s nsx/ directory, so a workspace that vendors
ns-cmsis-nn at modules/ns-cmsis-nn adds modules/ns-cmsis-nn/nsx; make sure
that checkout is at least the module’s required version. NSX cannot declare a
dependency version yet
(AmbiqAI/neuralspotx#284),
so the generated nsx-module.yaml states that version as a comment on its
nsx-cmsis-nn entry. The generated CMakeLists.txt enforces it at configure
time when it can read the version from arm_nn_types.h in the kernel target’s
include directories; otherwise the #error in <prefix>_common.h enforces it
at compile time. The generated module requires nsx::cmsis_nn and exports
nsx::kws_ref.
Set an optional attributes header before adding the generated directory:
add_subdirectory(modules/ns-cmsis-nn/nsx)set(KWS_REF_ATTRIBUTES_HEADER "${CMAKE_CURRENT_SOURCE_DIR}/my_attributes.h")add_subdirectory(/absolute/path/to/out-nsx/kws_ref ${CMAKE_BINARY_DIR}/kws_ref)target_link_libraries(app PRIVATE nsx::kws_ref)The header is force-preincluded into generated sources. Use it to define the
application’s placement and AOT_PRINTF hooks, which otherwise default to
no-ops. Float models additionally need the heliaCORE build switches described
in Precision.
CMSIS-Pack
Section titled “CMSIS-Pack”CMSIS-Pack output is for evaluation; see the end of this section for what is and is not checked.
helia-aot convert --path kws.yaml --module.type cmsis_pack --module.path ./Ambiq.kws_ref.<version>.packReplace <version> with the heliaAOT version (helia-aot version); the pack
declares that version as its release, so the file name then matches the pack.
The .pack contains a .pdsc at its root, C sources and public headers. Its
core condition follows the selected platform’s CPU, and its dependency names
the required Ambiq.NS-CMSIS-NN component/version. A directory output leaves an
unpacked tree; .zip is a plain archive, not an installable pack.
Install the pack and its kernel dependency through your pack-aware build tool,
select its Machine Learning / AOT Model component, and supply the same
checked application calls and logging/placement hooks. One generated pack
targets one platform configuration.
The converter does not invoke packchk itself. Repository tests run it with XSD
validation disabled and allow specified unresolved-dependency warnings; they do
not compile a consuming pack project. Validate your installed dependency set
and build in the actual consumer tool.