-
Notifications
You must be signed in to change notification settings - Fork 748
Summary: Add Initial support to pico2 (Arm Cortex M) #12518
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,98 @@ | ||
| #!/bin/bash | ||
| # Copyright (c) Meta Platforms, Inc. and affiliates. | ||
| # All rights reserved. | ||
| # | ||
| # This source code is licensed under the BSD-style license found in the | ||
| # LICENSE file in the root directory of this source tree. | ||
|
|
||
| #!/bin/bash | ||
| # build_firmware_pico.sh | ||
| # Simple script to cross-compile ExecuTorch and build Pico2 firmware with optional model input | ||
|
|
||
| set -e | ||
|
|
||
| # Paths | ||
| ROOT_DIR="$(cd "$(dirname "$0")/../.." && pwd)" # examples/rpi/ -> root dir | ||
| PICO2_DIR="${ROOT_DIR}/examples/rpi/pico2" | ||
| BUILD_DIR="${PICO2_DIR}/build" | ||
| EXECUTORCH_BUILD_DIR="${ROOT_DIR}/cmake-out" | ||
|
|
||
| # Default model | ||
| DEFAULT_MODEL="default_model.pte" | ||
|
|
||
| usage() { | ||
| echo "Usage: $0 [--clean] [--model=path/to/model.pte]" | ||
| echo " --clean Clean build directories" | ||
| echo " --model=FILE Specify model file to embed (relative to pico2/)" | ||
| exit 1 | ||
| } | ||
|
|
||
| # Parse args | ||
| MODEL_INPUT="" | ||
| CLEAN_BUILD=0 | ||
|
|
||
| for arg in "$@"; do | ||
| case $arg in | ||
| --clean) | ||
| CLEAN_BUILD=1 | ||
| shift | ||
| ;; | ||
| --model=*) | ||
| MODEL_INPUT="${arg#*=}" | ||
| shift | ||
| ;; | ||
| *) | ||
| usage | ||
| ;; | ||
| esac | ||
| done | ||
|
|
||
| # Clean if requested | ||
| if [ $CLEAN_BUILD -eq 1 ]; then | ||
| echo "Cleaning build directories..." | ||
| rm -rf "${EXECUTORCH_BUILD_DIR}" "${BUILD_DIR}" | ||
| echo "Clean complete." | ||
| exit 0 | ||
| fi | ||
|
|
||
| # Step 1: Cross compile ExecuTorch from root dir | ||
| echo "Cross compiling ExecuTorch baremetal ARM..." | ||
|
|
||
| cmake -B "${EXECUTORCH_BUILD_DIR}" \ | ||
| -DCMAKE_TOOLCHAIN_FILE="${ROOT_DIR}/examples/arm/ethos-u-setup/arm-none-eabi-gcc.cmake" \ | ||
| -DTARGET_CPU=cortex-m0plus \ | ||
| -DEXECUTORCH_BUILD_ARM_BAREMETAL=ON \ | ||
| -DEXECUTORCH_PAL_DEFAULT=minimal \ | ||
| -DEXECUTORCH_DTYPE_SELECTIVE_BUILD=ON \ | ||
| -DCMAKE_BUILD_TYPE=MinSizeRel \ | ||
| -DEXECUTORCH_ENABLE_LOGGING=OFF \ | ||
| -DEXECUTORCH_SELECT_ALL_OPS=OFF \ | ||
| -DEXECUTORCH_BUILD_EXECUTOR_RUNNER=OFF \ | ||
| -DCMAKE_INSTALL_PREFIX="${EXECUTORCH_BUILD_DIR}" \ | ||
| "${ROOT_DIR}" | ||
|
|
||
| cmake --build "${EXECUTORCH_BUILD_DIR}" --target install -j$(nproc) | ||
|
|
||
| echo "ExecuTorch cross compile complete." | ||
|
|
||
| # Step 2: Build firmware for Pico2 with model input | ||
|
|
||
| cd "${PICO2_DIR}" | ||
|
|
||
| if [ -n "$MODEL_INPUT" ]; then | ||
| # Use specified model | ||
| if [ ! -f "${MODEL_INPUT}" ]; then | ||
| echo "Error: Specified model file '${MODEL_INPUT}' not found in pico2 directory." | ||
| exit 1 | ||
| fi | ||
| echo "Building firmware with model: ${MODEL_INPUT}" | ||
| cmake -B "${BUILD_DIR}" -DPICO_BOARD=pico2 -DINPUT_MODEL="./${MODEL_INPUT}" -DCMAKE_BUILD_TYPE=Release | ||
| else | ||
| # Use default model | ||
| echo "Building firmware with default model: ${DEFAULT_MODEL}" | ||
| cmake -B "${BUILD_DIR}" -DPICO_BOARD=pico2 -DINPUT_MODEL="./${DEFAULT_MODEL}" -DCMAKE_BUILD_TYPE=Release | ||
| fi | ||
|
|
||
| cmake --build "${BUILD_DIR}" -j$(nproc) | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. FWIW nproc won't work on a macos |
||
|
|
||
| echo "Firmware build complete. Output in ${BUILD_DIR}, Binary: executorch_pico.uf2" | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,143 @@ | ||
| # Copyright (c) Meta Platforms, Inc. and affiliates. | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. nit s/rpi/raspberrypi |
||
| # All rights reserved. | ||
| # | ||
| # This source code is licensed under the BSD-style license found in the LICENSE | ||
| # file in the root directory of this source tree. | ||
|
|
||
| cmake_minimum_required(VERSION 3.13) | ||
|
|
||
| # Include FetchContent for Pico SDK | ||
| include(FetchContent) | ||
|
|
||
| FetchContent_Declare( | ||
| pico_sdk | ||
| GIT_REPOSITORY https://github.com/raspberrypi/pico-sdk.git | ||
| GIT_TAG 2.0.0 | ||
| ) | ||
|
|
||
| FetchContent_MakeAvailable(pico_sdk) | ||
| set(PICO_SDK_PATH ${pico_sdk_SOURCE_DIR}) | ||
| include(${PICO_SDK_PATH}/pico_sdk_init.cmake) | ||
|
|
||
| project(executorch_pico C CXX ASM) | ||
| pico_sdk_init() | ||
|
|
||
| set(EXECUTORCH_ROOT ${CMAKE_CURRENT_SOURCE_DIR}/../../../..) | ||
| set(CMAKE_EXPORT_COMPILE_COMMANDS ON) | ||
|
|
||
| # Configure input model file | ||
| set(INPUT_MODEL | ||
| "default_model.pte" | ||
| CACHE STRING "Input PTE model file to embed" | ||
| ) | ||
|
|
||
| # Convert relative paths to absolute | ||
| if(NOT IS_ABSOLUTE "${INPUT_MODEL}") | ||
| set(INPUT_MODEL "${CMAKE_CURRENT_SOURCE_DIR}/${INPUT_MODEL}") | ||
| endif() | ||
|
|
||
| message(STATUS "Using model file: ${INPUT_MODEL}") | ||
|
|
||
| # Validate model file exists | ||
| if(NOT EXISTS "${INPUT_MODEL}") | ||
| message(FATAL_ERROR "Model file '${INPUT_MODEL}' does not exist.") | ||
| endif() | ||
|
|
||
| # Create model_pte.c if it doesn't exist | ||
| set(MODEL_PTE_C "${CMAKE_CURRENT_SOURCE_DIR}/model_pte.c") | ||
| if(NOT EXISTS "${MODEL_PTE_C}") | ||
| file( | ||
| WRITE "${MODEL_PTE_C}" | ||
| "#include \"model_pte.h\"\n" | ||
| "\n" | ||
| "const uint8_t model_pte[] __attribute__((aligned(8))) = {\n" | ||
| " // Model data will be injected here\n" | ||
| "};\n" | ||
| "\n" | ||
| "const unsigned int model_pte_len = sizeof(model_pte);\n" | ||
| ) | ||
| message(STATUS "Created initial model_pte.c") | ||
| endif() | ||
|
|
||
| # Use a stamp file instead of declaring model_pte.c as OUTPUT | ||
| set(MODEL_STAMP "${CMAKE_CURRENT_BINARY_DIR}/model_pte.stamp") | ||
|
|
||
| add_custom_command( | ||
| OUTPUT ${MODEL_STAMP} | ||
| COMMAND python3 ${EXECUTORCH_ROOT}/executorch/examples/rpi/pte_to_array.py | ||
| --model ${INPUT_MODEL} --file ${MODEL_PTE_C} | ||
| COMMAND ${CMAKE_COMMAND} -E touch ${MODEL_STAMP} | ||
| DEPENDS ${INPUT_MODEL} | ||
| ${EXECUTORCH_ROOT}/executorch/examples/rpi/pte_to_array.py | ||
| COMMENT "Injecting PTE data from '${INPUT_MODEL}' into model_pte.c" | ||
| VERBATIM | ||
| ) | ||
|
|
||
| # Target to ensure model injection happens | ||
| add_custom_target(inject_model_data ALL DEPENDS ${MODEL_STAMP}) | ||
|
|
||
| # Check if source files exist | ||
| if(NOT EXISTS "${CMAKE_CURRENT_SOURCE_DIR}/main.cpp") | ||
| message(FATAL_ERROR "main.cpp not found in ${CMAKE_CURRENT_SOURCE_DIR}") | ||
| endif() | ||
|
|
||
| # Create the executable | ||
| add_executable( | ||
| executorch_pico main.cpp ${MODEL_PTE_C} # Use the full path to be explicit | ||
| ) | ||
|
|
||
| # Ensure model data is injected before building | ||
| add_dependencies(executorch_pico inject_model_data) | ||
|
|
||
| # Set correct target properties for Pico2/RP2350 | ||
| set_target_properties( | ||
| executorch_pico PROPERTIES SUFFIX ".elf" OUTPUT_NAME "executorch_pico" | ||
| ) | ||
|
|
||
| # Configure Pico-specific settings | ||
| pico_enable_stdio_usb(executorch_pico 1) | ||
| pico_enable_stdio_uart(executorch_pico 0) | ||
|
|
||
| # Set correct flags for Pico2 (RP2350) | ||
| target_compile_options( | ||
| executorch_pico PRIVATE -mcpu=cortex-m33 -mfloat-abi=soft -mthumb | ||
| ) | ||
|
|
||
| target_include_directories( | ||
| executorch_pico | ||
| PRIVATE ${EXECUTORCH_ROOT} ${EXECUTORCH_ROOT}/executorch/third-party | ||
| ${EXECUTORCH_ROOT}/executorch/runtime/core/portable_type/c10 | ||
| ) | ||
|
|
||
| target_compile_definitions( | ||
| executorch_pico | ||
| PRIVATE C10_USING_CUSTOM_GENERATED_MACROS EXECUTORCH_ENABLE_LOGGING=OFF | ||
| EXECUTORCH_PAL_DEFAULT=minimal | ||
| ) | ||
|
|
||
| # Optimization flags | ||
| target_compile_options( | ||
| executorch_pico PRIVATE -Os -ffunction-sections -fdata-sections | ||
| ) | ||
|
|
||
| set(CMAKE_EXE_LINKER_FLAGS "${CMAKE_EXE_LINKER_FLAGS} -Wl,--gc-sections") | ||
|
|
||
| set(BAREMETAL_BUILD_DIR ${EXECUTORCH_ROOT}/executorch/cmake-out/) | ||
|
|
||
| # Link ExecuTorch and Pico libraries | ||
| target_link_libraries( | ||
| executorch_pico | ||
| PRIVATE ${BAREMETAL_BUILD_DIR}/lib/libexecutorch.a | ||
| ${BAREMETAL_BUILD_DIR}/lib/libexecutorch_core.a | ||
| -Wl,--whole-archive | ||
| ${BAREMETAL_BUILD_DIR}/lib/libportable_ops_lib.a | ||
| -Wl,--no-whole-archive | ||
| ${BAREMETAL_BUILD_DIR}/lib/libportable_kernels.a | ||
| pico_stdlib | ||
| pico_stdio_usb | ||
| ) | ||
|
|
||
| # Only add extra outputs if the target builds successfully | ||
| if(TARGET executorch_pico) | ||
| pico_add_extra_outputs(executorch_pico) | ||
| endif() | ||
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,45 @@ | ||
| # Overview | ||
|
Contributor
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. let's make a web doc as well? it can be same content. Add a picture or gif too :) |
||
| This document outlines the steps required to run a simple Add Module on the Pico2 microcontroller using executorch. | ||
|
|
||
| ## (Pre-requisistes) Prepare the Environment for Arm | ||
| 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. | ||
| 2. Make sure you have the toolchain configured correctly. | ||
| ```bash | ||
| which arm-none-eabi-gcc | ||
| --> 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 | ||
| ``` | ||
|
|
||
| ## Build Pico2 Firmware with Executorch | ||
|
|
||
| This step involves two sub steps | ||
|
|
||
| 1. Cross Compile Executorch for Arm Cortex M, Pico2 target | ||
| 2. Build the firmware with the input model provided (If not provided, it will use the default_model.pte) | ||
|
|
||
| Use the following command to build the firmware: | ||
| ``` bash | ||
| executorch/examples/rpi/build_firmware_pico.sh --model=<path_to_model.pte> | ||
| ``` | ||
|
|
||
| ### Flash Firmware | ||
| 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. | ||
|
|
||
| ### Verify Execution | ||
| Check that the Pico2's LED blinks 10 times at 500 ms interval to confirm successful firmware execution. | ||
| The Pico2's LED should blink 10 times at 500 ms intervals, indicating successful firmware execution. If connected via serial, you should see: | ||
|
|
||
| ```bash | ||
| Method loaded [forward] | ||
| Output: 13.000000, 136.000000, 24.000000, 131.000000 | ||
| ``` | ||
|
|
||
| ### Debugging via Serial Terminal | ||
| On macOS or Linux, open a serial terminal with: | ||
| ```bash | ||
| screen /dev/tty.usbmodem1101 115200 | ||
| ``` | ||
|
|
||
| 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. | ||
|
|
||
| These steps complete running the simple model on Pico2 using ExecuTorch. | ||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.