Skip to content

Commit fb4f8a1

Browse files
committed
NXP backend: Building MCUXpresso example
1 parent d8d40a8 commit fb4f8a1

8 files changed

Lines changed: 452 additions & 0 deletions

File tree

.github/workflows/pull.yml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1718,3 +1718,22 @@ jobs:
17181718
echo "Neutron backend library not found!"
17191719
exit 1
17201720
fi
1721+
1722+
nxp-mcuxpresso-test:
1723+
name: nxp-mcuxpresso-test
1724+
uses: pytorch/test-infra/.github/workflows/linux_job_v2.yml@main
1725+
permissions:
1726+
id-token: write
1727+
contents: read
1728+
with:
1729+
runner: linux.2xlarge
1730+
docker-image: ci-image:executorch-ubuntu-22.04-arm-sdk
1731+
submodules: 'recursive'
1732+
ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }}
1733+
timeout: 180
1734+
script: |
1735+
# The generic Linux job chooses to use base env, not the one setup by the image
1736+
CONDA_ENV=$(conda env list --json | jq -r ".envs | .[-1]")
1737+
conda activate "${CONDA_ENV}"
1738+
1739+
./examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/test_build_from_scratch.sh
Lines changed: 140 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,140 @@
1+
# Using the MCUXpresso Example
2+
3+
This example demonstrates how to build and run the ExecuTorch CIFARNet application for the NXP RT700 platform using the MCUXpresso SDK and the GNU Arm Embedded Toolchain. Before building the project, make sure that all required dependencies are installed and that the necessary environment variables are configured correctly.
4+
5+
> **Tip:** The `test_build_from_scratch.sh` script automates all the steps described in this guide, including downloading the ARM GNU toolchain, preparing the model, and downloading the MCUXpresso SDK using the `west` tool. If you prefer a fully automated setup, you can run it directly instead of following the manual steps below.
6+
7+
All scripts described in this guide are located in the following directory of the ExecuTorch repository:
8+
9+
```text
10+
examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/
11+
```
12+
13+
## 1. Install the Arm GNU Toolchain
14+
15+
First, download the Arm GCC cross-compilation toolchain that is supported by the RT700 platform:
16+
17+
```text
18+
https://developer.arm.com/-/media/Files/downloads/gnu/15.2.rel1/binrel/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi.tar.xz
19+
```
20+
21+
After extracting the archive, create an environment variable called `ARMGCC_DIR` that points to the root directory of the toolchain installation. The build scripts use this variable to locate the compiler, linker, and other required tools.
22+
23+
Example on Linux:
24+
25+
```bash
26+
export ARMGCC_DIR=/path/to/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi
27+
```
28+
29+
To verify the installation, you can run:
30+
31+
```bash
32+
$ARMGCC_DIR/bin/arm-none-eabi-gcc --version
33+
```
34+
35+
The command should print the installed compiler version.
36+
37+
## 2. Download the MCUXpresso SDK
38+
39+
Next, download MCUXpresso SDK version **26.06** for the RT700 device family:
40+
41+
```text
42+
https://mcuxpresso.nxp.com/builder?hw=MIMXRT700-EVK
43+
```
44+
45+
When generating the SDK package, make sure that you select:
46+
47+
- **Target Board:** MIMXRT700-EVK
48+
- **Layout:** ARM GCC / MCUXpresso for VS Code
49+
50+
After extracting the SDK package, configure the `SdkRootDirPath` environment variable to point to the SDK root directory.
51+
52+
Example on Linux:
53+
54+
```bash
55+
export SdkRootDirPath=/path/to/SDK_26_06
56+
```
57+
58+
The build system relies on this variable to locate board support packages, middleware components, startup code, linker scripts, and device-specific libraries.
59+
60+
## 3. Prepare the Model Header File
61+
62+
Before building the application, a compiled model must be provided as a C header file named `model_pte.h` and placed in the project directory alongside the build script. Run the provided helper script to generate it:
63+
64+
```bash
65+
./prepare_model.sh
66+
```
67+
68+
The script performs the following steps:
69+
70+
1. Installs ExecuTorch and its Python dependencies.
71+
2. Installs the `eiq-neutron-sdk` Python package in the version that has been tested with the current ExecuTorch release.
72+
3. Compiles the CIFARNet model using the NXP ExecuTorch ahead-of-time (AoT) pipeline and produces a `.pte` model file.
73+
4. Converts the `.pte` file into the `model_pte.h` C header, with the correct memory-section attributes for the RT700 target.
74+
75+
> **Important:** The MCUXpresso SDK package includes a pre-built CIFARNet model and a set of Neutron libraries, but this build flow deliberately does **not** use either of them. Instead, `prepare_model.sh` installs the `eiq-neutron-sdk` version that was tested with the current ExecuTorch release, compiles the model from scratch, and the linker later picks up the matching Neutron libraries from that same installation. This keeps the ExecuTorch AoT compiler, the model bytecode, the Neutron driver, the Neutron firmware, and the ExecuTorch runtime all in sync.
76+
77+
Once the script finishes, verify that `model_pte.h` was created in the project directory before proceeding to the build step.
78+
79+
## 4. Build the Application
80+
81+
Once the environment variables have been configured and `model_pte.h` is present in the project directory, set the `NEUTRON_LIB_DIR` variable to the directory that contains the Neutron static libraries shipped with the eiq-neutron-sdk:
82+
83+
```bash
84+
export NEUTRON_LIB_DIR=/path/to/eiq_neutron_sdk/libs
85+
```
86+
87+
The build script expects the following libraries to exist in that directory:
88+
89+
- `libNeutronDriver.a`
90+
- `libNeutronFirmware.a`
91+
92+
Then build the project by executing the provided script:
93+
94+
```bash
95+
./build_example.sh
96+
```
97+
98+
The script validates all required inputs, configures CMake, compiles the source code, links the application, and generates the executable image:
99+
100+
```text
101+
flash_release/executorch_cifarnet.elf
102+
```
103+
104+
If the build completes successfully, the ELF file will be available and ready for programming onto the target board.
105+
106+
## 5. Flash the Application
107+
108+
The generated application can be programmed onto the RT700 device using SEGGER J-Link tools.
109+
110+
### Linux
111+
112+
```bash
113+
echo "loadfile flash_release/executorch_cifarnet.elf" | \
114+
/opt/SEGGER/JLink_V796k/JLinkExe \
115+
-IF SWD \
116+
-speed auto \
117+
-Device MIMXRT798S_M33_0
118+
```
119+
120+
Before flashing, ensure that:
121+
122+
- The board is powered on.
123+
- The JLink debugger probe is flashed on device, if not see [documentation](https://mcuxpresso.nxp.com/mcuxsdk/26.06.00/html/boards/RT/mimxrt700evk/gettingStartedXplorer/topics/program_lpc-link2_with_segger_j-link.html) how to flash it.
124+
- The J-Link debugger is connected to the target.
125+
- The SWD interface is available and correctly wired.
126+
- No other debugging application is currently using the J-Link connection.
127+
128+
The programming process typically takes only a few seconds. Once the image has been loaded successfully, the application can be started directly from flash memory.
129+
130+
## 6. Running the Example
131+
132+
After the firmware is programmed, reset the board and open a serial terminal connected to the device's debug UART interface. The application will initialize the hardware, load the embedded CIFARNet model, and begin performing image inference.
133+
134+
During execution, inference results and diagnostic messages are printed to the terminal. The included demonstration image contains a cat, and the model is expected to classify the image accordingly.
135+
136+
A successful run produces output similar to the following:
137+
138+
![example](terminal.png "Example")
139+
140+
This example serves as a basic validation that the ExecuTorch runtime, model integration, SDK configuration, and hardware platform are all functioning correctly. It can also be used as a starting point for evaluating custom neural network models and experimenting with on-device machine learning workloads on the RT700 platform.

docs/source/backends/nxp/nxp-overview.md

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,11 @@ For more finegrained tutorial, visit [this manual page](https://mcuxpresso.nxp.c
5252
For guideline how to update the eIQ Neutron Runtime on MCUXpresso SDK, follow the instructions from the eIQ Neutron SDK package `docs/NeutronSDKUserGuide.md` available
5353
here https://www.nxp.com/design/design-center/software/eiq-ai-development-environment/eiq-toolkit-for-end-to-end-model-development-and-deployment:EIQ-TOOLKIT.
5454

55+
## Using the MCUXpresso Example
56+
57+
[This page](nxp-mcuxpresso-example.md) demonstrates how to build and run the ExecuTorch CIFARNet example from MCUXpresso SDK.
58+
59+
5560
## Reference
5661

5762
**→{doc}`nxp-partitioner` — Partitioner options.**
44.2 KB
Loading
Lines changed: 151 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,151 @@
1+
# Copyright 2026 NXP
2+
#
3+
# This source code is licensed under the BSD-style license found in the
4+
# LICENSE file in the root directory of this source tree.
5+
6+
cmake_minimum_required(VERSION 3.10.0)
7+
8+
# THE VERSION NUMBER
9+
set(MCUXPRESSO_CMAKE_FORMAT_MAJOR_VERSION 2)
10+
set(MCUXPRESSO_CMAKE_FORMAT_MINOR_VERSION 0)
11+
12+
set(CMAKE_EXECUTABLE_LIBRARY_PREFIX)
13+
set(CMAKE_EXECUTABLE_LIBRARY_SUFFIX)
14+
15+
# CURRENT DIRECTORY
16+
set(ProjDirPath ${CMAKE_CURRENT_SOURCE_DIR})
17+
18+
set(EXECUTABLE_OUTPUT_PATH ${ProjDirPath}/${CMAKE_BUILD_TYPE})
19+
set(LIBRARY_OUTPUT_PATH ${ProjDirPath}/${CMAKE_BUILD_TYPE})
20+
21+
# Skip link step during compiler check (bare-metal cross-compilation).
22+
set(CMAKE_TRY_COMPILE_TARGET_TYPE STATIC_LIBRARY)
23+
24+
project(executorch_cifarnet)
25+
26+
enable_language(ASM)
27+
28+
set(MCUX_BUILD_TYPES flash_debug flash_release)
29+
30+
set(MCUX_SDK_PROJECT_NAME executorch_cifarnet.elf)
31+
32+
set(EXECUTORCH_ROOT_DIR ${CMAKE_CURRENT_SOURCE_DIR}/../../../../..)
33+
34+
# CPU and FPU flags required for Cortex-M33 with single-precision FPU.
35+
set(CPU_FLAGS "-mcpu=cortex-m33 -mthumb -mfloat-abi=hard -mfpu=fpv5-sp-d16")
36+
set(CPU_DEFINES
37+
"-DCPU_MIMXRT798SGFOA_cm33_core0 -DCPU_MIMXRT798SGFOB_cm33_core0 \
38+
-DMIMXRT798S_cm33_core0_SERIES -DMCUXPRESSO_SDK \
39+
-D__STARTUP_INITIALIZE_NONCACHEDATA -D__STARTUP_CLEAR_BSS \
40+
-DDSP_IMAGE_COPY_TO_RAM=1 -DBOOT_HEADER_ENABLE=1 \
41+
-DEIQ_EXAMPLE_HSRUN_CLOCK -DMCUX_META_BUILD \
42+
-DPRINTF_ADVANCED_ENABLE=1 -DPRINTF_FLOAT_ENABLE=1 -DNO_HEAP_USAGE=1 \
43+
-DSDK_DEBUGCONSOLE=1 -DSDK_I2C_BASED_COMPONENT_USED=1"
44+
)
45+
set(CMAKE_C_FLAGS
46+
"${CMAKE_C_FLAGS} ${CPU_FLAGS} ${CPU_DEFINES} -fno-common -ffunction-sections -fdata-sections -fno-builtin -mapcs -std=gnu99"
47+
)
48+
set(CMAKE_CXX_FLAGS
49+
"${CMAKE_CXX_FLAGS} ${CPU_FLAGS} ${CPU_DEFINES} -fno-common -ffunction-sections -fdata-sections -fno-builtin -mapcs -fno-rtti -fno-exceptions"
50+
)
51+
set(CMAKE_ASM_FLAGS "${CMAKE_ASM_FLAGS} ${CPU_FLAGS} ${CPU_DEFINES}")
52+
set(CMAKE_EXE_LINKER_FLAGS
53+
"${CMAKE_EXE_LINKER_FLAGS} ${CPU_FLAGS} -fno-common -ffunction-sections -fdata-sections -fno-builtin -mapcs -Wl,--gc-sections -Wl,-static -specs=nano.specs -specs=nosys.specs -T\"${SdkRootDirPath}/examples/_boards/mimxrt700evk/eiq_examples/executorch_cifarnet/cm33_core0/gcc/MIMXRT798Sxxxx_cm33_core0_flash.ld\" -static"
54+
)
55+
56+
add_executable(
57+
${MCUX_SDK_PROJECT_NAME}
58+
${SdkRootDirPath}/examples/_boards/mimxrt700evk/flash_config/flash_config.c
59+
${SdkRootDirPath}/examples/_boards/mimxrt700evk/eiq_examples/executorch_cifarnet/cm33_core0/hardware_init.c
60+
${SdkRootDirPath}/examples/_boards/mimxrt700evk/eiq_examples/executorch_cifarnet/cm33_core0/pin_mux.c
61+
${SdkRootDirPath}/examples/_boards/mimxrt700evk/board.c
62+
${SdkRootDirPath}/examples/_boards/mimxrt700evk/pmic_support.c
63+
${SdkRootDirPath}/examples/_boards/mimxrt700evk/common/clock/cm33_core0/clock_config.c
64+
${SdkRootDirPath}/examples/eiq_examples/executorch_cifarnet/main.cpp
65+
${SdkRootDirPath}/examples/eiq_examples/executorch_cifarnet/RegisterKernels.cpp
66+
${SdkRootDirPath}/examples/eiq_examples/common/timer.c
67+
${SdkRootDirPath}/devices/RT/RT700/MIMXRT798S/startup_MIMXRT798S_cm33_core0.c
68+
${EXECUTORCH_ROOT_DIR}/backends/nxp/runtime/NeutronBackend.cpp
69+
${SdkRootDirPath}/middleware/tfm/tf-m/platform/ext/common/syscalls_stub.c
70+
# Device-level drivers (clock, power, reset, system init).
71+
${SdkRootDirPath}/devices/RT/RT700/MIMXRT798S/drivers/fsl_clock.c
72+
${SdkRootDirPath}/devices/RT/RT700/MIMXRT798S/drivers/fsl_power.c
73+
${SdkRootDirPath}/devices/RT/RT700/MIMXRT798S/drivers/fsl_reset.c
74+
${SdkRootDirPath}/devices/RT/RT700/MIMXRT798S/system_MIMXRT798S_cm33_core0.c
75+
# Common ARM driver (provides SDK_DelayAtLeastUs).
76+
${SdkRootDirPath}/drivers/common/fsl_common_arm.c
77+
# Peripheral drivers.
78+
${SdkRootDirPath}/drivers/cache/xcache/fsl_cache.c
79+
${SdkRootDirPath}/drivers/lpflexcomm/fsl_lpflexcomm.c
80+
${SdkRootDirPath}/drivers/lpflexcomm/lpi2c/fsl_lpi2c.c
81+
${SdkRootDirPath}/drivers/lpflexcomm/lpuart/fsl_lpuart.c
82+
${SdkRootDirPath}/drivers/gpio/fsl_gpio.c
83+
${SdkRootDirPath}/drivers/glikey/fsl_glikey.c
84+
# UART HAL adapter (provides HAL_UartInit etc.).
85+
${SdkRootDirPath}/components/uart/fsl_adapter_lpuart.c
86+
# PMIC driver.
87+
${SdkRootDirPath}/components/pmic/pca9422/fsl_pca9422.c
88+
# Debug console (provides DbgConsole_Init/Printf).
89+
${SdkRootDirPath}/components/debug_console_lite/fsl_debug_console.c
90+
)
91+
92+
target_include_directories(
93+
${MCUX_SDK_PROJECT_NAME}
94+
PRIVATE
95+
${CMAKE_CURRENT_SOURCE_DIR}
96+
${SdkRootDirPath}/arch/arm/CMSIS/Core/Include
97+
${SdkRootDirPath}/devices/RT/RT700/MIMXRT798S
98+
${SdkRootDirPath}/devices/RT/RT700/MIMXRT798S/cm33_core0
99+
${SdkRootDirPath}/devices/RT/RT700/MIMXRT798S/drivers
100+
${SdkRootDirPath}/devices/RT/RT700/periph
101+
${SdkRootDirPath}/drivers/common
102+
${SdkRootDirPath}/components/pmic/pca9422
103+
${SdkRootDirPath}/components/uart
104+
${SdkRootDirPath}/components/debug_console_lite
105+
${SdkRootDirPath}/examples/_boards/mimxrt700evk
106+
${SdkRootDirPath}/examples/_boards/mimxrt700evk/flash_config
107+
${SdkRootDirPath}/examples/_boards/mimxrt700evk/eiq_examples/executorch_cifarnet/cm33_core0
108+
${SdkRootDirPath}/examples/_boards/mimxrt700evk/common/clock/cm33_core0
109+
${SdkRootDirPath}/examples/eiq_examples/executorch_cifarnet
110+
${SdkRootDirPath}/examples/eiq_examples/common
111+
${SdkRootDirPath}/boards/mimxrt700evk/eiq_examples/executorch_cifarnet/cm33_core0
112+
${SdkRootDirPath}/examples/_boards/mimxrt700evk/eiq_examples/executorch_cifarnet/npu
113+
${SdkRootDirPath}/drivers/cache/xcache
114+
${SdkRootDirPath}/drivers/gpio
115+
${SdkRootDirPath}/drivers/lpflexcomm
116+
${SdkRootDirPath}/drivers/lpflexcomm/lpuart
117+
${SdkRootDirPath}/drivers/lpflexcomm/lpi2c
118+
${SdkRootDirPath}/drivers/xspi
119+
${SdkRootDirPath}/drivers/reset
120+
${SdkRootDirPath}/drivers/clock
121+
${SdkRootDirPath}/drivers/glikey
122+
${SdkRootDirPath}/drivers/mu1
123+
${SdkRootDirPath}/drivers/power
124+
${SdkRootDirPath}/drivers/iopctl
125+
${SdkRootDirPath}/components/str
126+
)
127+
128+
set(EXECUTORCH_BUILD_PYBIND OFF)
129+
set(EXECUTORCH_BUILD_TESTS OFF)
130+
set(EXECUTORCH_BUILD_DEVTOOLS OFF)
131+
set(EXECUTORCH_BUILD_EXECUTOR_RUNNER OFF)
132+
set(EXECUTORCH_BUILD_CPUINFO OFF)
133+
set(EXECUTORCH_BUILD_PTHREADPOOL OFF)
134+
set(EXECUTORCH_BUILD_EXTENSION_RUNNER_UTIL ON)
135+
set(EXECUTORCH_BUILD_PORTABLE_OPS ON)
136+
set(EXECUTORCH_BUILD_KERNELS_QUANTIZED ON)
137+
set(CMAKE_POSITION_INDEPENDENT_CODE OFF)
138+
add_subdirectory(${EXECUTORCH_ROOT_DIR} EXCLUDE_FROM_ALL executorch)
139+
140+
target_link_libraries(
141+
${MCUX_SDK_PROJECT_NAME}
142+
PRIVATE -Wl,--start-group
143+
executorch
144+
executorch_core
145+
extension_runner_util
146+
quantized_kernels
147+
portable_kernels
148+
${NEUTRON_LIB_DIR}/libNeutronDriver.a
149+
${NEUTRON_LIB_DIR}/libNeutronFirmware.a
150+
-Wl,--end-group
151+
)
Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
1+
#!/bin/bash
2+
# Copyright 2026 NXP
3+
#
4+
# This source code is licensed under the BSD-style license found in the
5+
# LICENSE file in the root directory of this source tree.
6+
7+
cd "$(dirname "$0")"
8+
9+
if [ -z ${ARMGCC_DIR+x} ]; then
10+
echo "ARMGCC_DIR needs to be set in the environment!"
11+
exit 1;
12+
fi
13+
14+
if [ -z ${SdkRootDirPath+x} ]; then
15+
echo "SdkRootDirPath needs to be set in the environment!"
16+
exit 1;
17+
fi
18+
19+
if [ ! -f model_pte.h ]; then
20+
echo "Cannot find model_pte.h!"
21+
exit 1;
22+
fi
23+
24+
if [ ! -f ${NEUTRON_LIB_DIR}/libNeutronDriver.a ]; then
25+
echo "Neutron driver not found in ${NEUTRON_LIB_DIR}!"
26+
exit 1;
27+
fi
28+
29+
if [ ! -f ${NEUTRON_LIB_DIR}/libNeutronFirmware.a ]; then
30+
echo "Neutron firmware not found in ${NEUTRON_LIB_DIR}!"
31+
exit 1;
32+
fi
33+
34+
mkdir -p cmake-out
35+
36+
cd cmake-out
37+
38+
cmake -DSdkRootDirPath=${SdkRootDirPath} \
39+
-DCMAKE_TOOLCHAIN_FILE=${SdkRootDirPath}/cmake/toolchain/armgcc.cmake \
40+
-DNEUTRON_LIB_DIR=${NEUTRON_LIB_DIR} \
41+
-DCMAKE_BUILD_TYPE=flash_release \
42+
-G "Unix Makefiles" \
43+
..
44+
45+
make -j 6 executorch_cifarnet.elf

0 commit comments

Comments
 (0)