Deploy on Arm Cortex-M
On this page
- What you’ll do
- Prerequisites
- Step 1: Get the target-support package
- Step 2: Build and flash the example
- Step 3: Compile your model
- Step 4: Generate the CMSIS-NN deployment core
- Step 5: Embed the plan
- Step 6: Swap in your model and rebuild
- Step 7: Flash and read the output
- Step 8: Check the output against the host
- Adapting to other boards
- Troubleshooting
- Next steps
This guide takes an INT8 model onto an Arm Cortex-M microcontroller with the
CMSIS-NN kernels, from an ONNX file to an inference running on the board and
printing its output over serial. It uses the
tigris-cortex-m target-support
package, which supplies the board bring-up and the cmsis-nn build that the
runtime’s kernel adapter links against.
The primary board here is the NUCLEO-H753ZI (Cortex-M7). The Adapting to other boards section covers the NUCLEO-F446RE and the Raspberry Pi Pico 2 (RP2350).
What you’ll do
- Build and flash the package’s ready-made example, to confirm your toolchain and board work end to end.
- Compile your own model, generate a CMSIS-NN deployment core, embed it, and build firmware for it.
- Read the on-device output and check it against the host.
Prerequisites
- Python 3.10+ with
tigris-mlinstalled (pip install tigris-ml) - The Arm GNU toolchain (
arm-none-eabi-gcc) and CMake 3.20+ - A NUCLEO-H753ZI board and a way to flash it (ST-LINK via
st-flash, the STM32CubeProgrammer CLI, or OpenOCD) - A serial terminal (for example
screen,minicom, ortio) for the ST-LINK virtual COM port
The package fetches its remaining dependencies — the TiGrIS runtime, CMSIS-NN, CMSIS-Core, and the STM32 CMSIS-Device pack — by pinned commit at configure time, so an internet connection is needed for the first build.
Step 1: Get the target-support package
git clone https://github.com/raws-labs/tigris-cortex-m.git
cd tigris-cortex-mIt ships a pre-generated example under examples/ds_cnn/ (a DS-CNN keyword
spotter compiled for a 64 KiB budget), so you can build a known-good firmware
before touching your own model.
Step 2: Build and flash the example
cmake -B build -DTIGRIS_BOARD=nucleo_h753zi
cmake --build buildThis produces build/tigris_firmware.bin. Flash it to the start of flash:
st-flash write build/tigris_firmware.bin 0x08000000Open the ST-LINK virtual COM port at 115200 baud. The firmware runs one inference on a fixed input and prints the INT8 output vector and the cycle count. On the H753 at 480 MHz, DS-CNN runs in roughly 11 ms; exact numbers are compiler and toolchain results and may shift between releases.
If this works, your toolchain, board, and flashing setup are good, and the rest of the guide only swaps in a different model.
Step 3: Compile your model
Produce a binary plan sized to the board’s SRAM:
tigris compile model.onnx -m 128K -o model.tgrsThe -m budget is the fast (SRAM) pool. It must fit the board’s usable SRAM,
because the CMSIS-NN fast arena is provisioned at the budget, not at the
(smaller) activation peak. The H753 has ample SRAM; on a smaller part, lower the
budget until the plan fits. See the compile
reference for the full flag set and Operator and Backend
Support for what the
CMSIS-NN backend accelerates.
Step 4: Generate the CMSIS-NN deployment core
tigris codegen model.tgrs --backend cmsis-nn --format core \
--output tigris_codegen_core.c --header tigris_codegen_core.h--format core emits a self-contained deployment core — it loads the embedded
plan, prepares the CMSIS-NN backend, and runs the schedule — rather than a full
example application. The board firmware calls into it. See
codegen for the other formats
and backends.
Step 5: Embed the plan
The .tgrs plan is data, not code, so convert it to a C array the firmware can
carry in flash:
python tools/bin2c.py model.tgrs model_blob.c --symbol g_tigris_planStep 6: Swap in your model and rebuild
Replace the three files in examples/ds_cnn/ with the ones you just generated —
tigris_codegen_core.c, tigris_codegen_core.h, and model_blob.c — then
rebuild, sizing the arenas to your plan and board:
cmake -B build -DTIGRIS_BOARD=nucleo_h753zi \
-DTIGRIS_APP_FAST_ARENA_BYTES=131072
cmake --build buildSet -DTIGRIS_APP_FAST_ARENA_BYTES to at least your plan’s -m budget, and
-DTIGRIS_APP_SLOW_ARENA_BYTES if the plan uses a slow pool. If the linker
reports the .bss section overflowing SRAM, the arenas are larger than the
board holds — lower the budget and the arena together.
Step 7: Flash and read the output
st-flash write build/tigris_firmware.bin 0x08000000Read the serial port again: the firmware prints your model’s INT8 output vector and its cycle count.
Step 8: Check the output against the host
The runtime is designed to produce the same INT8 output on the device as on the
host for the same plan and input. To confirm your deployment, run the same model
and input through the host — for example the reference backend, or ONNX
Runtime on the original float model — and compare the INT8 vectors. They should
match exactly; a mismatch usually means the input fed on-device differs from the
one you compared against.
Adapting to other boards
- NUCLEO-F446RE (Cortex-M4F, 128 KiB SRAM): build with
-DTIGRIS_BOARD=nucleo_f446re. The smaller SRAM is the binding constraint — keep the-mbudget and the fast arena within 128 KiB. - Raspberry Pi Pico 2 / RP2350 (Cortex-M33): a separate pico-sdk build
producing a
.uf2. See the package’s README for thePICO_SDK_PATHinvocation and flashing.
To bring up a board the package doesn’t cover, implement include/tigris_hal.h
for it (clock, a UART for printf, a cycle counter) and add a board file; the
package README’s “Porting a board” section walks through it.
Troubleshooting
.bssoverflows SRAM at link time — the arenas exceed the board’s SRAM. Lower the plan’s-mbudget and-DTIGRIS_APP_FAST_ARENA_BYTEStogether.Unknown boardat configure time — pass a supported-DTIGRIS_BOARDvalue (nucleo_f446re,nucleo_h753zi, or the pico2 project).- First configure fails to fetch dependencies — the pinned sources are
fetched over the network; for an offline build, point each at a local mirror
with
-DFETCHCONTENT_SOURCE_DIR_<NAME>=<path>(see the package README).
Next steps
compileandcodegen— the full CLI reference.- The
tigris-cortex-mpackage — board files, the example, and porting notes.