Deploy a machine learning application to the Arm Ethos-U65 NPU on NXP FRDM i.MX 93 with Topo
Introduction
Understand the architecture of the machine learning application
Understand the toolchains used in the Topo Project
Build the Topo Project from scratch
Clone and deploy the application with Topo
Next Steps
Deploy a machine learning application to the Arm Ethos-U65 NPU on NXP FRDM i.MX 93 with Topo
Prepare the target
Before deploying the Topo Project, confirm that the FRDM i.MX 93 board is reachable from your host and that it’s ready for deployment:
topo health --target <user>@<target-ip>
Replace <target-ip> with the IP address or hostname of your board.
Resolve any errors before continuing.
The target section includes successful checks similar to:
Host
----
Topo: ✅ (topo)
SSH: ✅ (ssh)
Curl: ✅ (curl)
Container Engine: ✅ (docker)
Target
------
Destination: ssh://<target-ip>
Connectivity: ✅
Container Engine: ✅ (docker)
Remoteproc Runtime: ✅ (remoteproc-runtime)
Remoteproc Shim: ✅ (containerd-shim-remoteproc-v1)
Hardware Info: ✅ (lscpu)
Subsystem Driver (remoteproc): ✅ (imx-rproc)
If remoteproc-runtime is missing, install it with Topo:
topo install remoteproc-runtime --target <user>@<target-ip>
Run the health check again:
topo health --target <user>@<target-ip>
Reserve memory in the device tree
The web application and Cortex-M33 firmware exchange data through reserved physical memory. The target device tree must reserve memory for the model/input buffer and for the Ethos-U65. This prevents Linux from allocating memory that the firmware and Ethos-U65 need to access by physical address.
You’ll now modify the device tree and reboot the target so that these modifications take effect.
Back up the board’s original device tree before modifying it. The exact boot partition can differ between Linux images, so check the paths on your board before copying files.
On your host, create a working directory and dump the live device tree from the target:
mkdir -p devicetree
ssh <user>@<target-ip> 'cat /sys/firmware/fdt' > devicetree/live.dtb
dtc -I dtb -O dts -o devicetree/live.dts devicetree/live.dtb
Open devicetree/live.dts in a text editor of your choice. Then, under remoteproc-cm33, add the CM33 power domain if it’s not already present:
power-domains = <0x61>;
Under reserved-memory, add the model memory range:
model@c0000000 {
reg = <0x00 0xc0000000 0x00 0x400000>;
no-map;
};
Update the Ethos-U reserved-memory node so it’s reserved and not reusable:
ethosu_region@A8000000 {
compatible = "shared-dma-pool";
reg = <0x00 0xa8000000 0x00 0x8000000>;
no-map;
phandle = <0x60>;
};
Add iomem=relaxed to chosen.bootargs. For example:
bootargs = "clk-imx93.mcore_booted console=ttyLP0,115200 earlycon root=/dev/mmcblk1p2 rootwait rw iomem=relaxed";
Return to your host machine terminal and build the patched device tree:
dtc -I dts -O dtb -o devicetree/patched.dtb devicetree/live.dts
Copy it to the board:
scp devicetree/patched.dtb <user>@<target-ip>:/tmp/patched.dtb
Install it on the board. Adjust the boot partition path if your image uses a different location:
ssh <user>@<target-ip>
cp /run/media/boot-mmcblk1p1/imx93-11x11-frdm.dtb \
/run/media/boot-mmcblk1p1/imx93-11x11-frdm.dtb.bak
cp /tmp/patched.dtb \
/run/media/boot-mmcblk1p1/imx93-11x11-frdm.dtb
sync
reboot
After the board reboots, run the Topo health check again from the host and verify everything is still correct:
topo health --target <user>@<target-ip>
Deploy to the board
You can choose to deploy from the original Topo Project, or from the project you built from scratch. If you haven’t already cloned the original project, clone it now:
topo clone https://github.com/Arm-Examples/topo-imx93-npu-deployment.git
Topo prompts for optional build cache image arguments. Accept the defaults unless you have your own cache images.
If you build without cache images, the first build can take a long time and requires about 25 GB of free disk space. The first build involves downloading and building ExecuTorch, the Arm GNU toolchain, MCUX SDK components, RPMsg-Lite, and the Cortex-M33 runner sources. Later builds are faster when Docker can reuse local cache layers or import the configured GHCR cache layers.
Then cd into the correct directory:
cd topo-imx93-npu-deployment
Or:
cd new-topo-npu-template
Deploy the project to your target:
topo deploy --target <user>@<target-ip>
During deployment, Topo builds the required images, transfers them to the target, starts the Cortex-M33 firmware through remoteproc-runtime, and starts the web application.
When deployment succeeds, the output includes a successful service startup. You can also check the deployed services:
topo ps --target <user>@<target-ip>
The output shows a process on both the Cortex-M33 and the Linux Host, and is similar to:
Image Status Processing Domain Address
topo-imx93-npu-deployment-cm33-runner Up 50 minutes imx-rproc
topo-imx93-npu-deployment-webapp Up 50 minutes Linux Host imx93-scorpio.cambridge.arm.com:3001, [::]:3001%
Open the web application
Open the web application in a browser:
http://<target-ip>:3001
If you need to use a different target port, set WEBAPP_PORT when deploying. For example:
WEBAPP_PORT=3002 topo deploy --target <user>@<target-ip>
Then open:
http://<target-ip>:3002
The application shows:
- an image selector
- a Classify button
- board prerequisite checks
- classification results
- an expandable analysis section with runtime details
Image classification web app showing correctly classified German Shepherd
When you choose an image in the browser and select Classify, the web application:
- Resizes and normalizes the image to classify into an input tensor compatible with the MobileNetV2 model.
- Writes the ExecuTorch
.pteprogram and input tensor into reserved physical memory. - Sends a
RUNcommand to the Cortex-M33 runner overRPMsg. - Waits for the Cortex-M33 firmware to run inference using Ethos-U65 acceleration.
- Displays the top-1 and top-5 ImageNet classification results in the browser.
Try this out with an image from an ImageNet-supported class.
What you’ve accomplished
You’ve prepared an FRDM i.MX 93 board for shared-memory NPU inference, deployed the topo-imx93-npu-deployment Topo Project with Topo, and started Cortex-M33 firmware through remoteproc-runtime. You used a browser-based application to stage the ExecuTorch .pte program and input tensor for MobileNetV2 classification with Ethos-U65 acceleration.
You can now use the deployed application as a reference for your own heterogeneous Arm applications, or adapt the model, firmware runner, web interface, or Topo metadata for another target.