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 ns-cmsis-nn meeting the version guard in aot_common.h
(at least 7.35.0 for this release). Changing module.type changes build files,
platform headers and hooks, so regenerate for the environment you use.
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 | Integration files | Recipe |
|---|---|---|
| Zephyr | Module manifest and Kconfig | Build the walkthrough application |
| neuralSPOT | Make fragment | Add to a neuralSPOT application |
| CMake | CMake target | Add to a CMake project |
| NSX | Module manifest and CMake target | Use an NSX workspace |
| CMSIS-Pack | Pack description and optional archive | Package for a pack-aware tool |
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 Versions.
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/ # Kernel library checkoutmkdir -p app/src app/modulescp -R /path/to/ns-cmsis-nn app/modules/ns-cmsis-nnReplace /path/to/ns-cmsis-nn with your pinned kernel-library checkout. Record
its revision. 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.
neuralSPOT
Section titled “neuralSPOT”For an existing neuralSPOT application, regenerate into a separate directory:
helia-aot convert --path kws.yaml --module.type neuralspot --module.path ./out-neuralspotCopy out-neuralspot/kws_ref and ns-cmsis-nn into the application’s modules
directory, then add both to its makefile:
modules += modules/ns-cmsis-nnmodules += modules/kws_refThe generated module.mk uses neuralSPOT’s make-library helper. Call
aot_test_case_init and, only after it succeeds, aot_test_case_run from the
application after its board and logging initialization. Check both statuses.
Generated logging uses ns_lp_printf, so use the application’s configured
console. Build with the neuralSPOT project’s normal make target; its startup,
linker script and programming procedure remain part of that project.
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 the kernel library 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; the latter requires nsx::cmsis_nn and
exports nsx::kws_ref.
Set an optional attributes header before adding the generated directory:
add_subdirectory(modules/nsx-cmsis-nn)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 kernel-library switches described
in Precision.
CMSIS-Pack
Section titled “CMSIS-Pack”helia-aot convert --path kws.yaml --module.type cmsis_pack --module.path ./Ambiq.kws_ref.0.23.0.packThe .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.