pi_pico/CLAUDE.md
Mohamed Salem 3687e48684 Add complete firmware stack with USB-CDC proof of life
Dockerized build system (Dockerfile, docker-compose, build.sh) with
Pico SDK cross-compilation. Modular CMake split into project_config,
mcu_config, and sources_config under cmake/. Component architecture
following inc/prg/cfg convention: STD_TYPES, MCU_USB, HAL_COM,
APP_CLSW, SYS_ECU. Full call chain SYS_ECU -> APP_CLSW -> HAL_COM
-> MCU_USB verified end-to-end on RP2040-Zero hardware over USB-CDC.
Includes flash.sh for automated .uf2 flashing on macOS and
devcontainer config for VS Code.

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-12 18:23:24 +02:00

3.4 KiB

CLAUDE.md

This file provides guidance to Claude Code (claude.ai/code) when working with code in this repository.

Project

Raspberry Pi Pico firmware that sends commands over UART to a host computer. Written entirely in C using the Pico SDK (RP2040 / Cortex-M0+).

Build System

All builds run inside Docker — no local toolchain required.

  • docker compose build — build the container image (first time / after Dockerfile changes)
  • docker compose run --rm pico-build bash build.sh — compile the firmware, output lands in build/
  • docker compose run --rm pico-build bash — interactive shell for debugging
  • ./flash.sh — flash the .uf2 to a Pico in BOOTSEL mode (host-side only, not Docker)
  • docker compose run --rm pico-build bash build.sh && ./flash.sh — build + flash in one command

The build uses CMake with the Pico SDK's ARM cross-compilation toolchain. The final artifact is a .uf2 file in build/. Flashing must run on the host macOS because it copies to /Volumes/RPI-RP2 (the Pico's USB mass storage mount).

Repository layout

color_switcher/
├── cmake/                          # all build-system files
│   ├── CMakeLists.txt              # thin orchestrator, drives build phases in order
│   ├── pico_sdk_import.cmake       # Pico SDK bootstrap (copied from SDK)
│   └── cmake_config/
│       ├── project_config.cmake    # project-wide vars (name, version, languages)
│       ├── mcu_config.cmake        # MCU helpers: mcu_init / mcu_sdk_config / mcu_link_target
│       └── sources_config.cmake    # source glob + include dir list
├── src/
│   ├── STD_TYPES/inc/              # shared fixed-width types, status enums, macros
│   ├── MCU_UART/{inc,prg,cfg}/     # hardware UART peripheral abstraction
│   ├── MCU_USB/{inc,prg,cfg}/      # USB-CDC (virtual serial port) abstraction
│   ├── HAL_COM/{inc,prg,cfg}/      # transport-agnostic comm layer (dispatches to UART/USB)
│   ├── APP_CLSW/{inc,prg,cfg}/    # color switcher application logic
│   └── SYS_ECU/prg/                # top-level app orchestrator (main entry)
├── build.sh                        # out-of-source build wrapper
├── Dockerfile / docker-compose.yml # containerized build env

Component file convention

Each component uses three subfolders:

  • inc/ — public API headers (safe for any other component to #include)
  • prg/ — private header (*_priv.h) + implementation (*_prg.c)
  • cfg/ — configuration header and definitions (*_cfg.h / *_cfg.c)

CMake build phases

The top-level cmake/CMakeLists.txt runs in a strict order dictated by the Pico SDK:

  1. include(project_config) — defines variables
  2. include(mcu_config) — defines helper macros (no side effects)
  3. mcu_init() — includes pico_sdk_import.cmake (must be before project())
  4. project(...)
  5. mcu_sdk_config() — calls pico_sdk_init()
  6. include(sources_config) — sets PROJECT_SOURCES and PROJECT_INCLUDE_DIRS
  7. add_executable(...)
  8. mcu_link_target(...)target_link_libraries, stdio routing, UF2 output

PROJECT_ROOT_DIR is computed in the top-level CMakeLists.txt as the parent of cmake/ and used everywhere that refers to paths outside the build system (e.g. src/).

Conventions

  • Always add descriptive comments to all code and config files
  • Avoid magic numbers — use named constants in config.h