Skip to content

Build & flash (RP)

This page walks the Raspberry Pi Pico (RP2040 / RP2350) path.

Prerequisites

Rust toolchain

Terminal window
# RP2040 (Cortex-M0+)
rustup target add thumbv6m-none-eabi
# RP2350 (Cortex-M33) — only needed if targeting Pico 2
rustup target add thumbv8m.main-none-eabihf

C cross-compiler (for FreeRTOS)

Terminal window
# macOS
brew install arm-none-eabi-gcc
# Ubuntu/Debian
sudo apt install gcc-arm-none-eabi

Rust tools

Terminal window
cargo install flip-link
cargo install probe-rs-tools --locked # installs probe-rs
cargo install elf2uf2-rs # optional: needed for --uf2 flag

Local CI (pre-commit hook)

The pre-commit hook runs Java formatting check, cargo fmt, APK build, Clippy (RP2040, RP2350, and sim), firmware build, and tests before each commit.

Install the hook after cloning by symlinking so it stays in sync with scripts/pre-commit:

Terminal window
ln -s ../../scripts/pre-commit .git/hooks/pre-commit

To skip the hook in exceptional cases: git commit --no-verify.

Java Development Kit (JDK 11+)

App sources are compiled by the Gradle multi-project under the repo root. The ./gradlew wrapper ships in-tree, so no separate Gradle install is required — only a JDK. App code targets Java 1.8 (configured in build.gradle.kts), but JDK 11 or later is required because the Java formatter tool needs it.

Compilation is followed by verifyApiContract, which fails the build for any java.* class or member pico-jvm does not implement (see the compatibility matrix and troubleshooting). scripts/build-apk.sh --board <name> — passed automatically by build.sh, flash.sh and sim.sh — also rejects classes that board excludes from its framework.

Terminal window
# macOS
brew install openjdk
brew link openjdk --force
# Ubuntu/Debian
sudo apt install default-jdk

Verify: javac --version

Java formatting (google-java-format)

Java source files must follow Google Java Style. No separate installation needed — the formatter JAR is downloaded automatically on first use.

Terminal window
# Reformat all Java files in-place
./scripts/format_java.sh format
# Check formatting without modifying files (runs in pre-commit hook and CI)
./scripts/format_java.sh check

Building and Flashing

Terminal window
# Clone with submodules (third_party/FreeRTOS-Kernel, vendor/lvgl,
# vendor/freertos-plus-tcp, vendor/cyw43-driver)
git clone --recurse-submodules https://github.com/shivrajora/picodroid-rs
cd picodroid-rs
# Build firmware with the default example (helloworld) for testbench_rp2350
./scripts/build.sh
# Flash to Pico and view RTT log output
./scripts/flash.sh

Choosing a board

Both scripts accept a --board flag. The default is testbench_rp2350.

FlagMCUTarget
--board testbench_rp2040RP2040Raspberry Pi Pico
--board testbench_rp2350RP2350Raspberry Pi Pico 2
--board testbench_rp2350wRP2350Raspberry Pi Pico 2 W (adds WiFi via cyw43 + FreeRTOS+TCP; WiFi credentials are baked in at build time — see WiFi & networking setup)
--board pico_enviro_monRP2350Pico Enviro Mon (1.14” 240x135 ST7789, no touch)
--board pico_enviro_mon_wRP2350Pico Enviro Mon on a Pico 2 W — same wiring plus WiFi (credentials baked in at build time; see WiFi & networking setup)
Terminal window
# Build / flash for Pico (RP2040)
./scripts/build.sh --board testbench_rp2040
./scripts/flash.sh --board testbench_rp2040

For day-to-day work, the per-board cargo aliases (cargo b-testbench-rp2040, cargo r-testbench-rp2350w, etc.) skip the script and call cargo directly — see Cargo aliases.

Choosing an example

Pass --app <name> to select which example to build or flash:

Terminal window
./scripts/build.sh --app blinky # default board
./scripts/build.sh --app uart --board testbench_rp2040 # RP2040
./scripts/build.sh --app helloworld --release
./scripts/flash.sh --app blinky
./scripts/flash.sh --app uart --board testbench_rp2040
./scripts/flash.sh --app helloworld --release

The --app flag selects which example to build. build.sh compiles the Java sources into a .papk file and embeds it into the firmware — no Cargo feature flags are involved.

Shrinking class names

Both build.sh and flash.sh accept --shrink, which applies the active release class-name shrink map (off by default):

Terminal window
./scripts/build.sh --app helloworld --release --shrink
./scripts/flash.sh --app helloworld --release --shrink

Firmware and PAPK must be built with the same setting, or the install is rejected with a version mismatch — see Class-name shrinker.

Generating a UF2 file

Pass --uf2 to build.sh to convert the ELF to a UF2 file after building. This is useful for flashing without a debug probe — just drag-and-drop the .uf2 onto the Pico’s USB Mass Storage drive.

Terminal window
./scripts/build.sh --app blinky --uf2
./scripts/build.sh --app blinky --board testbench_rp2350 --release --uf2

The UF2 is written alongside the ELF (e.g. target/thumbv6m-none-eabi/debug/picodroid.uf2). Requires elf2uf2-rs (cargo install elf2uf2-rs).

Next steps