Pico with C/C++
Pico with C/C++
π§° 1. Prerequisites
Tool | Purpose |
---|---|
VS Code | Editor |
CMake + Ninja | Build system |
pico-sdk |
Raspberry Pi official C/C++ SDK |
arm-none-eabi |
GCC toolchain for ARM Cortex-M0+ |
OpenOCD |
Debugging (optional for SWD) |
UF2 uploader | Flashing firmware via USB (drag-and-drop or tools) |
π§ 2. Pico SDK Workflow Overview
[ C Code ] β [ CMake ] β [ Ninja ] β [ ELF/BIN/UF2 ] β [ Raspberry Pi Pico ]
π₯οΈ 3. Install Toolchain on Linux (Ubuntu)
sudo apt update
sudo apt install cmake gcc-arm-none-eabi build-essential ninja-build libnewlib-arm-none-eabi git
On Windows/macOS: use Raspberry Pi Pico official getting started guide
π 4. Project Structure
pico-project/
βββ CMakeLists.txt # Top-level
βββ blink/
β βββ CMakeLists.txt
β βββ blink.c
βββ pico-sdk/ # Submodule or symlink to SDK
π 5. blink.c
Example
#include "pico/stdlib.h"
int main() {
const uint LED_PIN = 25;
(LED_PIN);
gpio_init(LED_PIN, GPIO_OUT);
gpio_set_dir
while (true) {
(LED_PIN, 1);
gpio_put(500);
sleep_ms(LED_PIN, 0);
gpio_put(500);
sleep_ms}
}
βοΈ 6. blink/CMakeLists.txt
add_executable(blink
blink.c
)
target_link_libraries(blink pico_stdlib)
pico_add_extra_outputs(blink)
π§± 7. Top-level CMakeLists.txt
cmake_minimum_required(VERSION 3.13)
include(pico-sdk/pico_sdk_init.cmake)
project(pico_project C CXX ASM)
pico_sdk_init()
add_subdirectory(blink)
π 8. Building the Project
# First-time setup
git clone -b master https://github.com/raspberrypi/pico-sdk.git
cd pico-sdk
git submodule update --init
# Back to project
cd ..
mkdir build && cd build
cmake .. -DPICO_SDK_PATH=../pico-sdk -G Ninja
ninja
You should see:
[100%] Built target blink
π 9. Flash to Pico (UF2)
- Hold BOOTSEL, plug in Pico β it shows up as a USB drive
- Copy
blink.uf2
frombuild/
to that drive
cp blink.uf2 /media/YOUR_USER/RPI-RP2/
Or use picotool
:
sudo apt install picotool
picotool load blink.uf2 -f
π 10. Set Up VS Code
Extensions to install:
- C/C++ (by Microsoft)
- CMake Tools
- Cortex-Debug (if using SWD debugging)
- CMake Tools Helper (optional)
- CodeLLDB (optional for debugging with
picoprobe
)
.vscode/settings.json
{
"cmake.generator": "Ninja",
"cmake.configureSettings": {
"PICO_SDK_PATH": "${workspaceFolder}/pico-sdk"
},
"C_Cpp.default.configurationProvider": "ms-vscode.cmake-tools"
}
.vscode/launch.json
(for debugging via SWD)
{
"version": "0.2.0",
"configurations": [
{
"name": "Cortex Debug",
"type": "cortex-debug",
"request": "launch",
"servertype": "openocd",
"executable": "build/blink.elf",
"cwd": "${workspaceRoot}",
"device": "RP2040",
"configFiles": [
"interface/picoprobe.cfg",
"target/rp2040.cfg"
]
}
]
}
π§ͺ 11. Testing with Serial Output
Use USB UART (CDC) via USB connection.
(); // Enables printf over USB
stdio_init_all
("Hello from Pico!\n"); printf
Use:
screen /dev/ttyACM0 115200
or
picocom -b 115200 /dev/ttyACM0
π§ 12. Tips & Best Practices
Tip | Description |
---|---|
Use pico_add_extra_outputs() |
Builds .uf2 , .elf , .bin for flashing |
Donβt forget pico_sdk_init() |
Required in top-level CMakeLists.txt |
Use Git submodule for SDK | Keeps SDK in sync with your project |
Debug with SWD or USB CDC logging | Debug via UART or SWD using picoprobe |
Use build/ for all CMake outputs |
Keep source tree clean |
π Further Reading
β Summary
Task | Command / Tool |
---|---|
Build | cmake .. && ninja |
Flash (USB) | Drag .uf2 to Pico drive |
Debug (optional) | picoprobe + OpenOCD |
Serial Print Debugging | stdio_init_all() , then picocom |