Skip to content

Commit 452f8f7

Browse files
sidartGithub Executorch
authored andcommitted
Summary: PoC to run/infer a simple mode on raspberry pi pico2
Test Plan: 1 Build pico2 firmware executorch/examples/rpi/build_firmware_pico.sh 2. Flash the firmware : 'executorch_pico.uf2' 3. Verify that it successfully runs / infers the simple add module Reviewers: Subscribers: Tasks: Tags:
1 parent 62f8a8e commit 452f8f7

File tree

7 files changed

+701
-0
lines changed

7 files changed

+701
-0
lines changed
Lines changed: 98 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,98 @@
1+
#!/bin/bash
2+
# Copyright (c) Meta Platforms, Inc. and affiliates.
3+
# All rights reserved.
4+
#
5+
# This source code is licensed under the BSD-style license found in the
6+
# LICENSE file in the root directory of this source tree.
7+
8+
#!/bin/bash
9+
# build_firmware_pico.sh
10+
# Simple script to cross-compile ExecuTorch and build Pico2 firmware with optional model input
11+
12+
set -e
13+
14+
# Paths
15+
ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)" # examples/rpi/ -> root dir
16+
PICO2_DIR="${ROOT_DIR}/examples/rpi/pico2"
17+
BUILD_DIR="${PICO2_DIR}/build"
18+
EXECUTORCH_BUILD_DIR="${ROOT_DIR}/cmake-out"
19+
20+
# Default model
21+
DEFAULT_MODEL="default_model.pte"
22+
23+
usage() {
24+
echo "Usage: $0 [--clean] [--model=path/to/model.pte]"
25+
echo " --clean Clean build directories"
26+
echo " --model=FILE Specify model file to embed (relative to pico2/)"
27+
exit 1
28+
}
29+
30+
# Parse args
31+
MODEL_INPUT=""
32+
CLEAN_BUILD=0
33+
34+
for arg in "$@"; do
35+
case $arg in
36+
--clean)
37+
CLEAN_BUILD=1
38+
shift
39+
;;
40+
--model=*)
41+
MODEL_INPUT="${arg#*=}"
42+
shift
43+
;;
44+
*)
45+
usage
46+
;;
47+
esac
48+
done
49+
50+
# Clean if requested
51+
if [ $CLEAN_BUILD -eq 1 ]; then
52+
echo "Cleaning build directories..."
53+
rm -rf "${EXECUTORCH_BUILD_DIR}" "${BUILD_DIR}"
54+
echo "Clean complete."
55+
exit 0
56+
fi
57+
58+
# Step 1: Cross compile ExecuTorch from root dir
59+
echo "Cross compiling ExecuTorch baremetal ARM..."
60+
61+
cmake -B "${EXECUTORCH_BUILD_DIR}" \
62+
-DCMAKE_TOOLCHAIN_FILE="${ROOT_DIR}/examples/arm/ethos-u-setup/arm-none-eabi-gcc.cmake" \
63+
-DTARGET_CPU=cortex-m0plus \
64+
-DEXECUTORCH_BUILD_ARM_BAREMETAL=ON \
65+
-DEXECUTORCH_PAL_DEFAULT=minimal \
66+
-DEXECUTORCH_DTYPE_SELECTIVE_BUILD=ON \
67+
-DCMAKE_BUILD_TYPE=MinSizeRel \
68+
-DEXECUTORCH_ENABLE_LOGGING=OFF \
69+
-DEXECUTORCH_SELECT_ALL_OPS=OFF \
70+
-DEXECUTORCH_BUILD_EXECUTOR_RUNNER=OFF \
71+
-DCMAKE_INSTALL_PREFIX="${EXECUTORCH_BUILD_DIR}" \
72+
"${ROOT_DIR}"
73+
74+
cmake --build "${EXECUTORCH_BUILD_DIR}" --target install -j$(nproc)
75+
76+
echo "ExecuTorch cross compile complete."
77+
78+
# Step 2: Build firmware for Pico2 with model input
79+
80+
cd "${PICO2_DIR}"
81+
82+
if [ -n "$MODEL_INPUT" ]; then
83+
# Use specified model
84+
if [ ! -f "${MODEL_INPUT}" ]; then
85+
echo "Error: Specified model file '${MODEL_INPUT}' not found in pico2 directory."
86+
exit 1
87+
fi
88+
echo "Building firmware with model: ${MODEL_INPUT}"
89+
cmake -B "${BUILD_DIR}" -DPICO_BOARD=pico2 -DINPUT_MODEL="./${MODEL_INPUT}" -DCMAKE_BUILD_TYPE=Release
90+
else
91+
# Use default model
92+
echo "Building firmware with default model: ${DEFAULT_MODEL}"
93+
cmake -B "${BUILD_DIR}" -DPICO_BOARD=pico2 -DINPUT_MODEL="./${DEFAULT_MODEL}" -DCMAKE_BUILD_TYPE=Release
94+
fi
95+
96+
cmake --build "${BUILD_DIR}" -j$(nproc)
97+
98+
echo "Firmware build complete. Output in ${BUILD_DIR}, Binary: executorch_pico.uf2"

examples/rpi/pico2/CMakeLists.txt

Lines changed: 148 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,148 @@
1+
# Copyright (c) Meta Platforms, Inc. and affiliates.
2+
# All rights reserved.
3+
4+
# This source code is licensed under the BSD-style license found in the LICENSE
5+
# file in the root directory of this source tree.
6+
7+
cmake_minimum_required(VERSION 3.13)
8+
9+
# Include FetchContent for Pico SDK
10+
include(FetchContent)
11+
12+
FetchContent_Declare(
13+
pico_sdk
14+
GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk.git
15+
GIT_TAG 2.0.0
16+
)
17+
18+
FetchContent_MakeAvailable(pico_sdk)
19+
set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR})
20+
include(${PICO_SDK_PATH}/pico_sdk_init.cmake)
21+
22+
project(executorch_pico C CXX ASM)
23+
pico_sdk_init()
24+
25+
set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../..)
26+
set(CMAKE_EXPORT_COMPILE_COMMANDS ON)
27+
28+
# Configure input model file
29+
set(INPUT_MODEL "default_model.pte" CACHE STRING "Input PTE model file to embed")
30+
31+
# Convert relative paths to absolute
32+
if(NOT IS_ABSOLUTE "${INPUT_MODEL}")
33+
set(INPUT_MODEL "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_MODEL}")
34+
endif()
35+
36+
message(STATUS "Using model file: ${INPUT_MODEL}")
37+
38+
# Validate model file exists
39+
if(NOT EXISTS "${INPUT_MODEL}")
40+
message(FATAL_ERROR "Model file '${INPUT_MODEL}' does not exist.")
41+
endif()
42+
43+
# Create model_pte.c if it doesn't exist
44+
set(MODEL_PTE_C "${CMAKE_CURRENT_SOURCE_DIR}/model_pte.c")
45+
if(NOT EXISTS "${MODEL_PTE_C}")
46+
file(WRITE "${MODEL_PTE_C}"
47+
"#include \"model_pte.h\"
48+
49+
const uint8_t model_pte[] __attribute__((aligned(8))) = {
50+
// Model data will be injected here
51+
};
52+
53+
const unsigned int model_pte_len = sizeof(model_pte);
54+
")
55+
message(STATUS "Created initial model_pte.c")
56+
endif()
57+
58+
# Use a stamp file instead of declaring model_pte.c as OUTPUT
59+
set(MODEL_STAMP "${CMAKE_CURRENT_BINARY_DIR}/model_pte.stamp")
60+
61+
add_custom_command(
62+
OUTPUT ${MODEL_STAMP}
63+
COMMAND python3 ${EXECUTORCH_ROOT}/executorch/examples/rpi/pte_to_array.py
64+
--model ${INPUT_MODEL}
65+
--file ${MODEL_PTE_C}
66+
COMMAND ${CMAKE_COMMAND} -E touch ${MODEL_STAMP}
67+
DEPENDS ${INPUT_MODEL} ${EXECUTORCH_ROOT}/executorch/examples/rpi/pte_to_array.py
68+
COMMENT "Injecting PTE data from '${INPUT_MODEL}' into model_pte.c"
69+
VERBATIM
70+
)
71+
72+
# Target to ensure model injection happens
73+
add_custom_target(inject_model_data ALL DEPENDS ${MODEL_STAMP})
74+
75+
# Check if source files exist
76+
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp")
77+
message(FATAL_ERROR "main.cpp not found in ${CMAKE_CURRENT_SOURCE_DIR}")
78+
endif()
79+
80+
# Create the executable
81+
add_executable(executorch_pico
82+
main.cpp
83+
${MODEL_PTE_C} # Use the full path to be explicit
84+
)
85+
86+
# Ensure model data is injected before building
87+
add_dependencies(executorch_pico inject_model_data)
88+
89+
# Set correct target properties for Pico2/RP2350
90+
set_target_properties(
91+
executorch_pico
92+
PROPERTIES
93+
SUFFIX ".elf"
94+
OUTPUT_NAME "executorch_pico"
95+
)
96+
97+
# Configure Pico-specific settings
98+
pico_enable_stdio_usb(executorch_pico 1)
99+
pico_enable_stdio_uart(executorch_pico 0)
100+
101+
# Set correct flags for Pico2 (RP2350)
102+
target_compile_options(
103+
executorch_pico PRIVATE
104+
-mcpu=cortex-m33 # Correct CPU for Pico2
105+
-mfloat-abi=soft
106+
-mthumb
107+
)
108+
109+
target_include_directories(
110+
executorch_pico
111+
PRIVATE ${EXECUTORCH_ROOT}
112+
${EXECUTORCH_ROOT}/executorch/third-party/
113+
${EXECUTORCH_ROOT}/executorch/runtime/core/portable_type/c10
114+
)
115+
116+
add_compile_definitions(C10_USING_CUSTOM_GENERATED_MACROS)
117+
118+
# Optimization flags
119+
set(CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -Os -ffunction-sections -fdata-sections")
120+
set(CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -Os -ffunction-sections -fdata-sections")
121+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
122+
123+
# Size optimization definitions
124+
add_compile_definitions(
125+
EXECUTORCH_ENABLE_LOGGING=OFF
126+
EXECUTORCH_PAL_DEFAULT=minimal
127+
)
128+
129+
set(BAREMETAL_BUILD_DIR ${EXECUTORCH_ROOT}/executorch/cmake-out/)
130+
131+
# Link ExecuTorch and Pico libraries
132+
target_link_libraries(
133+
executorch_pico
134+
PRIVATE
135+
${BAREMETAL_BUILD_DIR}/lib/libexecutorch.a
136+
${BAREMETAL_BUILD_DIR}/lib/libexecutorch_core.a
137+
-Wl,--whole-archive
138+
${BAREMETAL_BUILD_DIR}/lib/libportable_ops_lib.a
139+
-Wl,--no-whole-archive
140+
${BAREMETAL_BUILD_DIR}/lib/libportable_kernels.a
141+
pico_stdlib
142+
pico_stdio_usb
143+
)
144+
145+
# Only add extra outputs if the target builds successfully
146+
if(TARGET executorch_pico)
147+
pico_add_extra_outputs(executorch_pico)
148+
endif()

examples/rpi/pico2/README.md

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
# Overview
2+
This document outlines the steps required to run a simple Add Module on the Pico2 microcontroller using executorch.
3+
4+
## (Pre-requisistes) Prepare the Environment for Arm
5+
1. See <a href="https://docs.pytorch.org/executorch/main/tutorial-arm.html#set-up-the-developer-environment"/> for instructions on setting up the environment for Arm.
6+
2. Make sure you have the toolchain configured correctly.
7+
```bash
8+
which arm-none-eabi-gcc
9+
--> return something like executorch/examples/arm/ethos-u-scratch/arm-gnu-toolchain-13.3.rel1-x86_64-arm-none-eabi/bin/arm-none-eabi-gcc
10+
```
11+
12+
## Build Pico2 Firmware with Executorch
13+
14+
This step involves two sub steps
15+
16+
1. Cross Compile Executorch for Arm Cortex M, Pico2 target
17+
2. Build the firmware with the input model provided (If not provided, it will use the default_model.pte)
18+
19+
Use the following command to build the firmware:
20+
``` bash
21+
executorch/examples/rpi/build_firmware_pico.sh
22+
```
23+
24+
### Flash Firmware
25+
Hold the BOOTSEL button on the Pico2 and connect it to your computer; it will mount as RPI-RP2. Copy the executorch_pico.uf2 file to this drive.
26+
27+
### Verify Execution
28+
Check that the Pico2's LED blinks 10 times at 500 ms interval to confirm successful firmware execution.
29+
The Pico2's LED should blink 10 times at 500 ms intervals, indicating successful firmware execution. If connected via serial, you should see:
30+
31+
```bash
32+
Method loaded [forward]
33+
Output: 13.000000, 136.000000, 24.000000, 131.000000
34+
```
35+
36+
### Debugging via Serial Terminal
37+
On macOS or Linux, open a serial terminal with:
38+
```bash
39+
screen /dev/tty.usbmodem1101 115200
40+
```
41+
42+
Replace /dev/tty.usbmodem1101 with your device path. This terminal shows program logs and errors. If the LED blinks 10 times at 100 ms intervals, your program hit an error state—check the logs here.
43+
44+
These steps complete running the simple model on Pico2 using ExecuTorch.

0 commit comments

Comments
 (0)