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>
69 lines
3.4 KiB
Markdown
69 lines
3.4 KiB
Markdown
# 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`
|