Raspberry Pi Pico Build Prerequisites (CMake)
This guide describes how to build a no-OS project for the Raspberry Pi Pico (RP2040) platform using the CMake build system, which is the only supported build flow for the Pico platform.
The CMake build is driven by board presets (defined in
board_configs/pico/CMakePresets.json) and project defconfigs (Kconfig
fragments inside each project). The rpi-pico preset selects the board and
toolchain, while PROJECT_DEFCONFIG selects the project and variant to
build.
The Pico SDK is vendored as a git submodule under libraries/pico-sdk, so no
external SDK install is required. no-OS uses the Pico SDK's own CMake
(pico_sdk_init()) to provide the SDK sources, headers, the second-stage
bootloader, the linker script and the libc/soft-float wrapping, linking them
into the no-OS executable automatically.
Note
Pico platform builds are supported on Linux only. The build targets the Raspberry Pi Pico (RP2040).
Supported boards
The following Pico board (preset) is available out of the box:
Preset / Board
Target chip
rpi-picorp2040
Prerequisites
CMake 3.28 or newer (presets v7 are used).
Ninja (the presets use the Ninja generator).
Python 3. The build creates a private virtual environment under
.no_os_venvon first configure and installs the dependencies listed intools/scripts/requirements.txt(kconfiglib,pylink-squareand, on Windows,windows-curses).An ARM cross toolchain (
arm-none-eabi-gcc) available onPATH. Unlike the Maxim and STM32 platforms, no vendor toolchain is used: the Pico SDK is vendored in-tree and the build uses thearm-none-eabiGCC found onPATH.OpenOCD 0.12.0 or newer for flashing and debugging (RP2040 support is included from 0.12.0):
$ sudo apt install openocd
Initialize the Pico SDK submodule
The Pico SDK is vendored as a git submodule. Initialize it from the root of the no-OS repository before configuring:
$ git submodule update --init libraries/pico-sdk
Note
Use --init (not --recursive): an RP2040 no-OS build does not need the
Pico SDK's own submodules (tinyusb, cyw43, lwip, ...).
Note
The build always uses this vendored copy: PICO_SDK_PATH is pinned to
libraries/pico-sdk internally, so any externally exported value is
ignored. This avoids a stale PICO_SDK_PATH in the environment breaking
the build. If the submodule is not initialized, configuration fails with a
message pointing at the git submodule update --init command above.
Install picotool (optional)
Install picotool to generate the
.uf2 image used for USB Mass Storage flashing. When picotool is unavailable,
the .elf and .hex are still produced and the .uf2 step is skipped
with a status message.
picotool is a separate tool from the Pico SDK and is not vendored, so it has to
be built from source. Install its build dependencies (cmake, a host C/C++
compiler and libusb-1.0 development headers), then clone and build it
against the vendored Pico SDK (use the same version as the SDK):
# Build dependencies (Debian/Ubuntu) $ sudo apt install cmake build-essential pkg-config libusb-1.0-0-dev # Clone and build picotool against the Pico SDK $ git clone https://github.com/raspberrypi/picotool.git $ cd picotool $ mkdir build && cd build $ PICO_SDK_PATH=/path/to/no-OS/libraries/pico-sdk cmake .. $ make -j$(nproc)
Make the resulting picotool binary available to the no-OS build either by
adding its directory to PATH or by passing -DPICOTOOL_PATH=... at
configure time.
(Optional) For visual debugging, install Visual Studio Code and the Cortex-Debug extension. IDE project files are generated automatically as part of the build, including a
no-os.code-workspacefile at the repository root.Important
To build, debug and run a project from VS Code you must open the generated
no-os.code-workspacefile, not just the no-OS folder. The debug launch configuration and include paths live in that workspace; opening the folder on its own will not pick them up. Open it with:$ code no-os.code-workspace
or from VS Code via
File > Open Workspace from File....VS Code does not always prompt to open the workspace on its own (the notification is shown at most once per folder and is suppressed once dismissed), so open it explicitly as shown above.
Listing build combinations
From the no-OS repository root, list the valid combinations and filter to the Pico board:
$ python tools/scripts/no_os_build.py list --board rpi-pico
Each row is a PROJECT VARIANT BOARD PLATFORM tuple that can be fed back
to the build subcommand.
Building a project
Recommended: the build helper
The simplest way to configure and build is via no_os_build.py, which selects
the right preset, defconfig and board config for you:
$ python tools/scripts/no_os_build.py build \ --project iio_demo --variant iio --board rpi-pico
Useful options:
--clean— remove the build directory before configuring.
-j N/--jobs N— parallel compile jobs.
--parallel— build different boards in parallel.
--probe {openocd,jlink}— select the debug probe (needed for flashing).
--flash— flash after a successful build (requires--probe).
--dry-run— print thecmakecommands without running them.
Each combination is built into its own directory named
build-<project>-<variant>-<board> at the repo root (override the location
with --build-dir). The build artifacts (.elf, .hex, .bin and,
when picotool is available, .uf2) are placed in <build-dir>/build.
Manual CMake invocation
You can also drive CMake directly. Configure with the board preset and select
the project/variant with PROJECT_DEFCONFIG (a path relative to projects/
of the form <project>/<variant>.conf):
$ cmake --preset rpi-pico -B build-iio_demo-iio-rpi-pico \ -DPROJECT_DEFCONFIG=iio_demo/iio.conf
Then build the project target (the target name is the project directory name):
$ cmake --build build-iio_demo-iio-rpi-pico --target iio_demo
The build artifacts (.elf, .hex, .bin and, when picotool is
available, .uf2) are placed in build-iio_demo-iio-rpi-pico/build.
Note
When the project provides board variants under
projects/<project>/boards/<variant>/<board>.conf, the matching board
config is layered on top automatically based on the preset's BOARD
value.
Note
If no CMAKE_BUILD_TYPE is given, the build defaults to
RelWithDebInfo so the ELF contains debug info. Use
-DCMAKE_BUILD_TYPE=Debug for an unoptimized build, or MinSizeRel /
Release for size/speed.
Note
The Pico flash region size defaults to 2 MiB (the Raspberry Pi Pico). Pass
-DPICO_FLASH_SIZE_BYTES=... to target a board with a different flash size.
Flashing and Debugging
Flashing requires a debug probe to be selected at configure time via
-DPROBE=.... Two probes are supported:
openocd(default) — a second Raspberry Pi Pico running thedebugprobe/picoprobefirmware (a CMSIS-DAP probe), driven by OpenOCD. OpenOCD's cmsis-dap driver handles the RP2040 SWD multidrop correctly.
jlink— a SEGGER J-Link via thepylink-squarePython package.
Configure with the desired probe, build, then run the flash target:
$ cmake --preset rpi-pico -B build-iio_demo-iio-rpi-pico \ -DPROJECT_DEFCONFIG=iio_demo/iio.conf -DPROBE=openocd $ cmake --build build-iio_demo-iio-rpi-pico --target iio_demo $ cmake --build build-iio_demo-iio-rpi-pico --target flash
When the OpenOCD probe is selected, the following additional targets are available:
flash— program the.elfto the target and reset.
erase— erase the device flash.
debug— start OpenOCD and attach GDB (Linux/macOS).
debug_server— start OpenOCD and wait for a GDB connection.$ cmake --build build-iio_demo-iio-rpi-pico --target debug
The OpenOCD configuration for the RP2040 (cmsis-dap interface and
target/rp2040.cfg) is generated automatically into openocd.cfg in the
project build directory.
CMSIS-DAP / picoprobe probe
The default openocd probe expects a CMSIS-DAP debugger. Flash a spare
Raspberry Pi Pico with the debugprobe firmware to turn it into one: download
debugprobe_on_pico.uf2 from the debugprobe releases, hold the BOOTSEL button
while connecting the probe Pico over USB, and copy the .uf2 onto the mounted
USB Mass Storage device. Then wire the probe Pico to the target board's SWD pads:
Probe Pico
Target Pico
GP2
SWCLK (left SWD pad)
GP3
SWDIO (right SWD pad)
GND
GND (middle SWD pad)
VSYS / 3V3
VSYS / 3V3 (to power target)
J-Link probe
OpenOCD's J-Link driver fails the RP2040 SWD multidrop selection
(Failed to connect multidrop rp2040.dap0), so the jlink probe uses the
native SEGGER tooling via pylink-square instead. Install the
J-Link software
and wire the J-Link's SWD pins to the target Pico's SWD pads (SWDIO, SWCLK,
GND); power the Pico separately over USB or VSYS.
Flashing via .uf2
If picotool is available, the generated .uf2 image can also be flashed
without a probe by holding the BOOTSEL button while connecting the board over
USB and copying the .uf2 file onto the mounted USB Mass Storage device.
To debug graphically from VS Code, open the generated no-os.code-workspace
(see the install step above) and launch the debug configuration from there;
opening the no-OS folder without the workspace will not load the debug setup.