Skip to content

Commit cfd9b68

Browse files
psiddhsidart
andauthored
Summary: Add Initial support to pico2 (Arm Cortex M) (#12518)
Test Plan: 1\ executorch/examples/rpi/build_firmware_pico.sh 2\ Flash the firmware - Hold BOOTSEL - Plug in Pico 2 - Mounts as RPI-RP2 - Copy executorch_pico.uf2 to that drive 3\ Check that LED light blinks 10 times (with 500 ms interval) , indicating that inference has been successful ### Summary [PLEASE REMOVE] See [CONTRIBUTING.md's Pull Requests](https://github.com/pytorch/executorch/blob/main/CONTRIBUTING.md#pull-requests) for ExecuTorch PR guidelines. [PLEASE REMOVE] If this PR closes an issue, please add a `Fixes #<issue-id>` line. [PLEASE REMOVE] If this PR introduces a fix or feature that should be the upcoming release notes, please add a "Release notes: <area>" label. For a list of available release notes labels, check out [CONTRIBUTING.md's Pull Requests](https://github.com/pytorch/executorch/blob/main/CONTRIBUTING.md#pull-requests). ### Test plan [PLEASE REMOVE] How did you test this PR? Please write down any manual commands you used and note down tests that you have written if applicable. Co-authored-by: sidart <[email protected]>
1 parent 7060fc5 commit cfd9b68

File tree

7 files changed

+713
-0
lines changed

7 files changed

+713
-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: 143 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,143 @@
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
30+
"default_model.pte"
31+
CACHE STRING "Input PTE model file to embed"
32+
)
33+
34+
# Convert relative paths to absolute
35+
if(NOT IS_ABSOLUTE "${INPUT_MODEL}")
36+
set(INPUT_MODEL "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_MODEL}")
37+
endif()
38+
39+
message(STATUS "Using model file: ${INPUT_MODEL}")
40+
41+
# Validate model file exists
42+
if(NOT EXISTS "${INPUT_MODEL}")
43+
message(FATAL_ERROR "Model file '${INPUT_MODEL}' does not exist.")
44+
endif()
45+
46+
# Create model_pte.c if it doesn't exist
47+
set(MODEL_PTE_C "${CMAKE_CURRENT_SOURCE_DIR}/model_pte.c")
48+
if(NOT EXISTS "${MODEL_PTE_C}")
49+
file(
50+
WRITE "${MODEL_PTE_C}"
51+
"#include \"model_pte.h\"\n"
52+
"\n"
53+
"const uint8_t model_pte[] __attribute__((aligned(8))) = {\n"
54+
" // Model data will be injected here\n"
55+
"};\n"
56+
"\n"
57+
"const unsigned int model_pte_len = sizeof(model_pte);\n"
58+
)
59+
message(STATUS "Created initial model_pte.c")
60+
endif()
61+
62+
# Use a stamp file instead of declaring model_pte.c as OUTPUT
63+
set(MODEL_STAMP "${CMAKE_CURRENT_BINARY_DIR}/model_pte.stamp")
64+
65+
add_custom_command(
66+
OUTPUT ${MODEL_STAMP}
67+
COMMAND python3 ${EXECUTORCH_ROOT}/executorch/examples/rpi/pte_to_array.py
68+
--model ${INPUT_MODEL} --file ${MODEL_PTE_C}
69+
COMMAND ${CMAKE_COMMAND} -E touch ${MODEL_STAMP}
70+
DEPENDS ${INPUT_MODEL}
71+
${EXECUTORCH_ROOT}/executorch/examples/rpi/pte_to_array.py
72+
COMMENT "Injecting PTE data from '${INPUT_MODEL}' into model_pte.c"
73+
VERBATIM
74+
)
75+
76+
# Target to ensure model injection happens
77+
add_custom_target(inject_model_data ALL DEPENDS ${MODEL_STAMP})
78+
79+
# Check if source files exist
80+
if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp")
81+
message(FATAL_ERROR "main.cpp not found in ${CMAKE_CURRENT_SOURCE_DIR}")
82+
endif()
83+
84+
# Create the executable
85+
add_executable(
86+
executorch_pico main.cpp ${MODEL_PTE_C} # Use the full path to be explicit
87+
)
88+
89+
# Ensure model data is injected before building
90+
add_dependencies(executorch_pico inject_model_data)
91+
92+
# Set correct target properties for Pico2/RP2350
93+
set_target_properties(
94+
executorch_pico PROPERTIES SUFFIX ".elf" 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 -mcpu=cortex-m33 -mfloat-abi=soft -mthumb
104+
)
105+
106+
target_include_directories(
107+
executorch_pico
108+
PRIVATE ${EXECUTORCH_ROOT} ${EXECUTORCH_ROOT}/executorch/third-party
109+
${EXECUTORCH_ROOT}/executorch/runtime/core/portable_type/c10
110+
)
111+
112+
target_compile_definitions(
113+
executorch_pico
114+
PRIVATE C10_USING_CUSTOM_GENERATED_MACROS EXECUTORCH_ENABLE_LOGGING=OFF
115+
EXECUTORCH_PAL_DEFAULT=minimal
116+
)
117+
118+
# Optimization flags
119+
target_compile_options(
120+
executorch_pico PRIVATE -Os -ffunction-sections -fdata-sections
121+
)
122+
123+
set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections")
124+
125+
set(BAREMETAL_BUILD_DIR ${EXECUTORCH_ROOT}/executorch/cmake-out/)
126+
127+
# Link ExecuTorch and Pico libraries
128+
target_link_libraries(
129+
executorch_pico
130+
PRIVATE ${BAREMETAL_BUILD_DIR}/lib/libexecutorch.a
131+
${BAREMETAL_BUILD_DIR}/lib/libexecutorch_core.a
132+
-Wl,--whole-archive
133+
${BAREMETAL_BUILD_DIR}/lib/libportable_ops_lib.a
134+
-Wl,--no-whole-archive
135+
${BAREMETAL_BUILD_DIR}/lib/libportable_kernels.a
136+
pico_stdlib
137+
pico_stdio_usb
138+
)
139+
140+
# Only add extra outputs if the target builds successfully
141+
if(TARGET executorch_pico)
142+
pico_add_extra_outputs(executorch_pico)
143+
endif()

examples/rpi/pico2/README.md

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,45 @@
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 --model=<path_to_model.pte>
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
43+
the LED blinks 10 times at 100 ms intervals, your program hit an error state—check the logs here.
44+
45+
These steps complete running the simple model on Pico2 using ExecuTorch.

0 commit comments

Comments
 (0)