From b4d811ff3283e25df3c4569ac7fdf1877ee5bc8c Mon Sep 17 00:00:00 2001 From: Jiri Ocenasek Date: Wed, 22 Jul 2026 14:23:22 +0200 Subject: [PATCH] NXP backend: Building MCUXpresso example --- .github/workflows/pull.yml | 19 +++ .../backends/nxp/nxp-mcuxpresso-example.md | 139 +++++++++++++++++ docs/source/backends/nxp/nxp-overview.md | 5 + docs/source/backends/nxp/terminal.png | Bin 0 -> 45222 bytes .../executorch_cifarnet/CMakeLists.txt | 144 ++++++++++++++++++ .../executorch_cifarnet/build_example.sh | 48 ++++++ .../executorch_cifarnet/prepare_model.sh | 32 ++++ .../test_build_from_scratch.sh | 58 +++++++ 8 files changed, 445 insertions(+) create mode 100644 docs/source/backends/nxp/nxp-mcuxpresso-example.md create mode 100644 docs/source/backends/nxp/terminal.png create mode 100644 examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/CMakeLists.txt create mode 100755 examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/build_example.sh create mode 100755 examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/prepare_model.sh create mode 100755 examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/test_build_from_scratch.sh diff --git a/.github/workflows/pull.yml b/.github/workflows/pull.yml index a190dc132d1..30d3849a25e 100644 --- a/.github/workflows/pull.yml +++ b/.github/workflows/pull.yml @@ -1727,3 +1727,22 @@ jobs: echo "Neutron backend library not found!" exit 1 fi + + nxp-mcuxpresso-test: + name: nxp-mcuxpresso-test + uses: pytorch/test-infra/.github/workflows/linux_job_v2.yml@main + permissions: + id-token: write + contents: read + with: + runner: linux.2xlarge + docker-image: ci-image:executorch-ubuntu-22.04-arm-sdk + submodules: 'recursive' + ref: ${{ github.event_name == 'pull_request' && github.event.pull_request.head.sha || github.sha }} + timeout: 90 + script: | + # The generic Linux job chooses to use base env, not the one setup by the image + CONDA_ENV=$(conda env list --json | jq -r ".envs | .[-1]") + conda activate "${CONDA_ENV}" + + ./examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/test_build_from_scratch.sh diff --git a/docs/source/backends/nxp/nxp-mcuxpresso-example.md b/docs/source/backends/nxp/nxp-mcuxpresso-example.md new file mode 100644 index 00000000000..8f8bb93fda3 --- /dev/null +++ b/docs/source/backends/nxp/nxp-mcuxpresso-example.md @@ -0,0 +1,139 @@ +# Using the MCUXpresso Example + +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. + +> **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. + +All scripts described in this guide are located in the following directory of the ExecuTorch repository: + +```text +examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/ +``` + +## 1. Install the Arm GNU Toolchain + +First, download the Arm GCC cross-compilation toolchain that is supported by the RT700 platform: + +```text +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 +``` + +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. + +Example on Linux: + +```bash +export ARMGCC_DIR=/path/to/arm-gnu-toolchain-15.2.rel1-x86_64-arm-none-eabi +``` + +To verify the installation, you can run: + +```bash +$ARMGCC_DIR/bin/arm-none-eabi-gcc --version +``` + +The command should print the installed compiler version. + +## 2. Download the MCUXpresso SDK + +Next, download MCUXpresso SDK for the RT700 device family using the west tool: + +```bash +pip install west +west init -m https://github.com/nxp-mcuxpresso/mcuxsdk-manifests.git mcuxpresso-sdk +pushd mcuxpresso-sdk +west update_board --set board mimxrt700evk +popd +``` + +Afterwards, configure the `SdkRootDirPath` environment variable to point to the mcuxsdk directory in the downloaded dir. + +Example on Linux: + +```bash +export SdkRootDirPath=/path/to/mcuxpresso-sdk/mcuxsdk +``` + +The build system relies on this variable to locate board support packages, middleware components, startup code, linker scripts, and device-specific libraries. + +## 3. Prepare the Model Header File + +Before building the application, a compiled model must be provided as a C header file named `model_pte.h` and placed in the current directory. Run the provided helper script to generate it: + +```bash +./prepare_model.sh +``` + +The script performs the following steps: + +1. Installs ExecuTorch and its Python dependencies. +2. Installs the `eiq-neutron-sdk` Python package in the version that has been tested with the current ExecuTorch release. +3. Compiles the CifarNet model using the NXP ExecuTorch ahead-of-time (AoT) pipeline and produces a `.pte` model file. +4. Converts the `.pte` file into the `model_pte.h` C header, with the correct memory-section attributes for the RT700 target. + +> **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. + +Once the script finishes, verify that `model_pte.h` was created in the project directory before proceeding to the build step. + +## 4. Build the Application + +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: + +```bash +export NEUTRON_LIB_DIR=/path/to/eiq_neutron_sdk/libs +``` + +The build script expects the following libraries to exist in that directory: + +- `libNeutronDriver.a` +- `libNeutronFirmware.a` + +Then build the project by executing the provided script: + +```bash +./build_example.sh +``` + +The script validates all required inputs, configures CMake, compiles the source code, links the application, and generates the executable image: + +```text +flash_release/executorch_cifarnet.elf +``` + +If the build completes successfully, the ELF file will be available and ready for programming onto the target board. + +## 5. Flash the Application + +The generated application can be programmed onto the RT700 device using SEGGER J-Link tools. + +### Linux + +```bash +echo "loadfile flash_release/executorch_cifarnet.elf" | \ +/opt/SEGGER/JLink_V796k/JLinkExe \ + -IF SWD \ + -speed auto \ + -Device MIMXRT798S_M33_0 +``` + +Before flashing, ensure that: + +- The board is powered on. +- The JLink debugger probe is flashed on device, if not see [documentation](https://mcuxpresso.nxp.com/mcuxsdk/latest/html/boards/RT/mimxrt700evk/gettingStartedXplorer/topics/program_lpc-link2_with_segger_j-link.html) how to flash it. +- The J-Link debugger is connected to the target. +- The SWD interface is available and correctly wired. +- No other debugging application is currently using the J-Link connection. + +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. + +## 6. Running the Example + +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. + +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. + +A successful run produces output similar to the following: + +![example](terminal.png "Example") + +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. diff --git a/docs/source/backends/nxp/nxp-overview.md b/docs/source/backends/nxp/nxp-overview.md index 581c375d038..604b480e614 100644 --- a/docs/source/backends/nxp/nxp-overview.md +++ b/docs/source/backends/nxp/nxp-overview.md @@ -52,6 +52,11 @@ For more finegrained tutorial, visit [this manual page](https://mcuxpresso.nxp.c 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 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. +## Using the MCUXpresso Example + +[This page](nxp-mcuxpresso-example.md) demonstrates how to build and run the ExecuTorch CIFARNet example from MCUXpresso SDK. + + ## Reference **→{doc}`nxp-partitioner` — Partitioner options.** diff --git a/docs/source/backends/nxp/terminal.png b/docs/source/backends/nxp/terminal.png new file mode 100644 index 0000000000000000000000000000000000000000..9a4f1d70ee84311ae5838c767c03cc908a0a5d05 GIT binary patch literal 45222 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

UQ4}l8| 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/dev/null || sysctl -n hw.ncpu) + 1 )) executorch_cifarnet.elf diff --git a/examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/prepare_model.sh b/examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/prepare_model.sh new file mode 100755 index 00000000000..9a5c29022f5 --- /dev/null +++ b/examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/prepare_model.sh @@ -0,0 +1,32 @@ +#!/bin/bash +# Copyright 2026 NXP +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -ue + +pushd "$(dirname "$0")/../../../../.." + +./install_executorch.sh +./devtools/install_requirements.sh + +pip install -r backends/nxp/requirements-eiq.txt + +python3 -m examples.nxp.aot_neutron_compile -m cifar10 -d -q --use_channels_last_dim_order --remove-quant-io-ops +mv cifar10_nxp_delegate.pte model.pte + +popd + +cat > model_pte.h <<'EOF' +#ifdef __MCUXPRESSO +#define __PLACEMENT __attribute__((section(".data.$modeldata"))) +#else +#define __PLACEMENT __attribute__((section(".modeldata"))) +#endif + +static const uint8_t model_pte[] __ALIGNED(16) __PLACEMENT = { +EOF + + +xxd -i "$(dirname "$0")/../../../../../model.pte" | grep -v unsigned >> model_pte.h diff --git a/examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/test_build_from_scratch.sh b/examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/test_build_from_scratch.sh new file mode 100755 index 00000000000..f734d1b79a1 --- /dev/null +++ b/examples/nxp/mcuxpresso/imxrt700/executorch_cifarnet/test_build_from_scratch.sh @@ -0,0 +1,58 @@ +#!/bin/bash +# Copyright 2026 NXP +# +# This source code is licensed under the BSD-style license found in the +# LICENSE file in the root directory of this source tree. + +set -ue +ARM_TOOLCHAIN_URL="${ARM_TOOLCHAIN_URL:-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}" + +# Get arm gcc +echo Downloading ARM GCC toolchain +if [ ! -d arm-toolchain ]; then + mkdir -p arm-toolchain + pushd arm-toolchain + wget $ARM_TOOLCHAIN_URL + tar -xvf *.tar.xz + rm *.tar.xz + popd +fi +export ARMGCC_DIR=$(pwd)/$(find arm-toolchain -maxdepth 1 -type d | tail -1) + +# Prepare model +# Side effect: the neutron SDK is installed +echo Preparing model and installing neutron SDK +$(dirname $0)/prepare_model.sh +# Check the model exists +if [ ! -f model_pte.h ]; then + echo "Cannot create the model_pte.h!" + exit 1; +fi + +# Locate Neutron SDK +NEUTRON_LIB_DIR=$(python3 -c "import eiq_neutron_sdk; print(eiq_neutron_sdk.__path__[0])") +export NEUTRON_LIB_DIR=${NEUTRON_LIB_DIR}/target/imxrt700/rt700/cm33 + +# Get MCUX SDK +echo Downloading MCUXpresso SDK +if [ ! -d mcuxpresso-sdk ]; then + pip install west + west init -m https://github.com/nxp-mcuxpresso/mcuxsdk-manifests.git mcuxpresso-sdk + pushd mcuxpresso-sdk + west update_board --set board mimxrt700evk + popd +fi +export SdkRootDirPath=$(pwd)/mcuxpresso-sdk/mcuxsdk + +# Build now +echo Building the example +$(dirname $0)/build_example.sh + +# Test the result +if [ ! -f cmake-out/flash_release/executorch_cifarnet.elf ]; then + echo "Build not successful!" + exit 1; +else + echo "Build successful." + exit 0; +fi