Embedded project setup
Skill Victory-7291/project-scaffold-setup-skills/skills/embedded-project-setup
Reusable agent skills for scaffolding C++ and embedded projects
npx -y skills add Victory-7291/project-scaffold-setup-skills --skill embedded-project-setupAssembled from the repository path, not quoted from the project. Check it against their README if it does not work.
2 things to look at
- 23 days oldThe repository was created 23 days ago. New is not bad, but a brand new repository carrying a familiar-sounding name is the shape a typosquat arrives in, and there has been no time for anyone else to find a problem with it.
- 7 stars7 stars. Stars are a popularity signal and not a quality one, but at this level it is likely that nobody has read this closely except its author, and you would be relying on your own review.
What its author says it does
Copied from the file, not written here
Embedded firmware setup: STM32, ESP32, AVR, RP2040, Nordic nRF, Zephyr/RTOS, vendor SDKs, CMake/CMakePresets, VS Code/clangd, cross toolchains, flash/debug, Docker/CI. Use for MCU scaffolds, existing firmware modernization, BSPs, linker/startup files, SDK package selection, and embedded CI; prefer cpp-project-setup for host-side C++.
SKILL.md
15.1 KB, as published. Nobody here has run it
Modern Embedded Project Setup
Overview
Create or modernize embedded firmware around a shared engineering pipeline, then adapt the target-specific compiler, SDK, flashing, and debug pieces to the selected MCU:
VS Code -> clangd -> clang-format -> clang-tidy -> CMake/CMakePresets -> Ninja -> target compiler/SDK -> firmware artifacts -> flash/debug -> MCU
Treat editor analysis, static checks, build generation, cross compilation, artifact generation, flashing, and debug as separate stages. First classify the user's working directory and host platform, then either generate a greenfield scaffold or modernize the existing firmware pipeline.
Workflow
-
Determine the user's working directory and whether firmware already exists.
- Check the user-provided path or current working directory before writing files.
- Treat the directory as an existing firmware project if it already has source files, linker scripts, startup files, CubeMX files, CMake/Make/build scripts, vendor trees, flash/debug scripts, editor settings, CI, docs, or git history.
- For existing firmware, inventory the full development pipeline before editing: build system, toolchain file, compiler version, MCU/board assumptions, linker/startup flow, vendor dependency model, flash/debug flow, tests or host-side checks, formatting/linting/static analysis, CI, and firmware artifacts.
-
Detect the user's host development environment.
- Determine OS and architecture: macOS/Linux/Windows plus arm64 or x64. Use local commands such as
uname -s,uname -m, or PowerShell/.NET runtime information where appropriate. - Select a host profile:
macos-arm64,macos-x64,linux-x64,linux-arm64,windows-x64, orwindows-arm64. - If the agent is running somewhere other than the user's real development machine, ask for the user's OS/architecture instead of assuming the sandbox matches their workstation.
- Determine OS and architecture: macOS/Linux/Windows plus arm64 or x64. Use local commands such as
-
Identify the firmware target before writing files.
- Capture target ecosystem first: STM32/Cortex-M, ESP32/ESP-IDF, AVR/Arduino or bare-metal avr-gcc, RP2040/Pico SDK, Nordic nRF/nRF Connect SDK or Zephyr, Zephyr/RTOS board target, or another MCU family.
- Capture the concrete MCU or board, firmware package/SDK, dependency path, package version/tag, debug probe, flash/RAM map when relevant, CPU core, FPU/float ABI when relevant, flash tool, debug server, and whether the project will use vendor HAL/SDK, RTOS APIs, CMSIS, bare-metal register access, or a mix.
- If the user has not provided the target, ask for the MCU/board and preferred framework before writing files. Do not silently default to any STM32, ESP32, AVR, RP2040, Nordic, or Zephyr board.
- If the user explicitly wants a target-agnostic starter before hardware is known, generate only a portable build-smoke scaffold with no hardware register writes, no final flash command assumptions, and clear TODOs for target selection.
-
Choose and pin the firmware package or SDK before generating build files.
- Read
references/firmware-package-matrix.mdwhen selecting or validating packages for STM32, ESP32, AVR, RP2040/RP2350, Nordic nRF, Zephyr, or standalone RTOS projects. - Record four facts before writing source lists or include paths: package name, source URL or package manager, local path such as
vendor/STM32CubeG0or an external SDK workspace, and pinned version/tag/manifest revision. - CMSIS is the common Cortex-M processor/device layer when official Cortex-M device headers exist. Do not claim CMSIS is required for non-Arm targets such as AVR or ESP32.
- Prefer the ecosystem's normal dependency model: STM32Cube packages can live under
vendor/as a submodule or recursive clone; ESP-IDF usually lives outside the app asIDF_PATHor in an external/submodule path; Pico SDK can be a submodule or external SDK path; nRF Connect SDK and Zephyr should usually be managed bywest; AVR bare-metal normally uses AVR GNU Toolchain plus AVR-LibC and only adds Microchip.atpackfiles when device support is missing or needs pinning. - If fetching packages requires network access or would add a large dependency tree, ask for approval or document the exact command and leave non-fake placeholders. Do not invent CMSIS/HAL paths or copy unrelated vendor examples into the project.
- Read
-
Choose the target toolchain profile.
- Use this matrix to choose the actual compiler, build driver, artifact tools, flash command, debug server, Docker image, and CI commands before generating files:
| Target/platform | Compiler and build tools to configure | Firmware artifacts | Flash/debug tools to configure |
|---|---|---|---|
| STM32 MCU | arm-none-eabi-gcc/g++, arm-none-eabi-objcopy, arm-none-eabi-size, arm-none-eabi-gdb, CMake, Ninja, selected CMSIS Device/Core and STM32 HAL/LL sources from STM32Cube<series>. Use GNU Tools for STM32 or ST Arm Clang instead when the project requests ST's toolchain. | .elf, .bin, .hex, .map | OpenOCD or STM32CubeProgrammer/ST-LINK GDB server, ST-Link or J-Link, Cortex-Debug or STM32 VS Code debug configuration. |
| ESP32 family | ESP-IDF, CMake, Ninja, idf.py; configure xtensa-esp-elf-gcc/g++ for Xtensa ESP32 variants and riscv32-esp-elf-gcc/g++ for RISC-V ESP32 variants through ESP-IDF tooling. | ESP-IDF app/bootloader/partition .bin images, .elf, .map | idf.py flash, esptool.py, idf.py monitor, Espressif OpenOCD/JTAG and ESP-IDF debug configuration when hardware debug is requested. |
| AVR | AVR GNU Toolchain: avr-gcc/g++, avr-objcopy, avr-size, avr-objdump, AVR Libc, CMake or Make. Configure -mmcu=<device> from the exact AVR MCU. | .elf, .hex, .eep, .map when configured | avrdude with the user's programmer and port, or the existing Arduino/Microchip upload flow. |
| RP2040/RP2350 | Pico SDK, CMake, Ninja or Make, arm-none-eabi-gcc/g++, Pico SDK tools such as elf2uf2; configure PICO_SDK_PATH and board settings. | .elf, .uf2, .bin, .hex, .map | USB bootloader drag-and-drop, picotool, Picoprobe/OpenOCD, arm-none-eabi-gdb, Cortex-Debug when debugging is requested. |
| Nordic nRF | Prefer nRF Connect SDK / Zephyr SDK with west, CMake, Ninja, and the SDK-managed Arm toolchain. For direct bare-metal nRF projects, configure arm-none-eabi-gcc/g++, CMSIS/nrfx, CMake, and Ninja. | Zephyr/nRF merged .hex and .elf, or direct bare-metal .elf, .bin, .hex, .map | west flash, nrfjprog, J-Link tools, OpenOCD where supported, west debug, or Cortex-Debug/J-Link configuration. |
| Zephyr/RTOS | Zephyr SDK or the vendor RTOS toolchain selected by board architecture; configure west, CMake, Ninja, devicetree, Kconfig, and board overlays. Use architecture-specific toolchains such as arm-zephyr-eabi, RISC-V, Xtensa, x86, ARC, or vendor-provided compilers as required by the board. | Zephyr .elf, .hex, .bin, merged images, signed images, or RTOS/vendor-specific outputs | west flash, west debug, board runner config, OpenOCD/J-Link/pyOCD/vendor runners as selected by Zephyr or the RTOS. |
- The shared workflow is editor/build-system/quality/CI consistency. The compiler and flash/debug tools must come from the selected target profile.
- Do not generate a generic
arm-none-eabi-gcctoolchain file for ESP32, AVR, Zephyr non-Arm boards, or any platform whose SDK owns toolchain selection.
- Generate or update the project.
- For greenfield scaffolding, run from this skill directory:
python3 scripts/scaffold_embedded_project.py \
--name firmware \
--out /path/to/workspace/firmware \
--host-platform macos-arm64 \
--target-family <target-family> \
--board <board-name> \
--mcu <mcu-name> \
--cpu <cpu-core>
- Use the bundled scaffold script only for direct CMake-style Cortex-M projects that fit the
arm-none-eabi-gccflow. For STM32 HAL/LL projects, pair the shared CMake/editor scaffold with an explicitSTM32Cube<series>package path and selected CMSIS/HAL source list. For ESP-IDF, AVR, Pico SDK, Zephyr, or other ecosystems, either adapt the generated standard configs carefully or create/update the ecosystem-native files directly. - For a concrete Cortex-M target, pass explicit target values:
python3 scripts/scaffold_embedded_project.py \
--name sensor_fw \
--out /path/to/workspace/sensor_fw \
--target-family nrf52 \
--board custom-nrf52840-board \
--mcu nrf52840 \
--device-define NRF52840_XXAA \
--cpu cortex-m4 \
--fpu fpv4-sp-d16 \
--float-abi hard \
--flash-origin 0x00000000 \
--flash-kb 1024 \
--ram-origin 0x20000000 \
--ram-kb 256 \
--openocd-interface jlink \
--openocd-target nrf52
- The scaffold script renders reusable standard configuration from
assets/for CMake, presets, clangd/tidy, VS Code, Docker, and debug tasks. Update assets when the shared firmware standard changes; update the Python script when generation logic, MCU arguments, linker/startup defaults, BSP templates, or command entry points change. - For existing firmware, inspect
CMakeLists.txt,CMakePresets.json, toolchain files, linker scripts, startup files,.vscode/,.clangd,.clang-tidy, flash/debug scripts, Dockerfile, CI workflows, and local docs before editing. - Omit
--host-platformonly when generating on the same machine where the project will be developed; the script will auto-detect that host.
-
Preserve the embedded layer model.
- Keep application logic above board support and drivers.
- Keep the BSP thin and explicit: board wiring belongs there, reusable chip drivers belong below it, application behavior belongs above it.
- Use CMSIS Core plus CMSIS Device as the lowest common Cortex-M/device layer when vendor headers are available; do not apply CMSIS expectations to AVR, ESP-IDF, or other non-Cortex-M targets.
- Use vendor HALs, SDK drivers, ESP-IDF components, Pico SDK libraries, Arduino cores, Zephyr drivers, or RTOS APIs when they match the chosen ecosystem; use lower-level APIs or direct registers only for startup, BSP smoke tests, bootloaders, or performance-critical code.
- Treat RTOS selection separately from silicon support. Zephyr and nRF Connect SDK can own startup/linker/drivers through their board model; standalone FreeRTOS still needs the vendor firmware package or device support layer underneath it.
- Do not vendor-copy large SDK trees blindly; prefer a documented submodule, package manager, west manifest, generated vendor directory, or user-provided dependency path.
-
Wire the toolchain.
- Use CMake presets named from a target-neutral prefix, by default
firmware-debug,firmware-release, andfirmware-analyze. - Configure the compiler and build driver from the selected target profile: create a CMake toolchain file for direct bare-metal GCC flows, use ESP-IDF's
idf.pyand managed toolchains for ESP32, use AVR GCC and-mmcusettings for AVR, use Pico SDK variables for RP2040/RP2350, and preservewest/Zephyr SDK or vendor RTOS toolchain selection for Zephyr/RTOS projects. - Keep generated
CMakePresets.json, VS Code settings/tasks/launch configs, shell/PowerShell scripts, Dockerfile, and GitHub Actions workflow aligned with that selected compiler and build command. - Export
compile_commands.jsonfor clangd. - Pass the embedded target triple to clangd and clang-tidy when the target compiler flags require it.
- Use Ninja for builds.
- Produce the firmware artifacts expected by the target ecosystem, such as
.elf,.bin,.hex,.map,.uf2, or vendor-specific images.
- Use CMake presets named from a target-neutral prefix, by default
-
Wire editor, flashing, and debug.
- Recommend VS Code extensions that match the target: clangd and CMake Tools for CMake flows, Cortex-Debug for Cortex-M GDB flows, and ecosystem-specific extensions only when they help the selected target.
- Disable competing IntelliSense when clangd owns semantic analysis.
- Use OpenOCD with ST-Link or J-Link when that is the right GDB server for the selected target.
- Set flash/debug config from the actual target and probe. Do not invent OpenOCD target names; ask the user or inspect existing project files when uncertain.
- Keep shell and PowerShell command entry points for build, format, analyze, flash, and debug-server startup when generating a cross-platform scaffold.
Validation
Run what is available locally. For the bundled direct Cortex-M scaffold, use:
cmake --preset firmware-debug
cmake --build --preset firmware-debug
bash scripts/format.sh --check
cmake --preset firmware-analyze
cmake --build --preset firmware-analyze
On Windows, use the generated PowerShell entry points such as pwsh scripts/build.ps1, pwsh scripts/format.ps1 -Check, and pwsh scripts/analyze.ps1.
For ESP-IDF, AVR, Pico SDK, Zephyr, or RTOS projects, use the ecosystem-native validation commands after adding the shared editor/format/CI layers, for example idf.py build, west build, Pico SDK CMake presets, avr-gcc/avrdude smoke commands, or the existing project scripts.
Also validate the firmware package decision itself:
- STM32: confirm
vendor/STM32Cube<series>or the documented external package path exists, is pinned to a tag/commit, and exposesDrivers/CMSISplus the selectedDrivers/STM32<series>xx_HAL_Driverpaths. - ESP-IDF: run
idf.py --version, confirm the chosenIDF_PATHor submodule path, then runidf.py set-target <chip>andidf.py buildwhen tools are installed. - AVR: confirm
avr-gcc -mmcu=<device>recognizes the MCU, and record whether AVR-LibC or a Microchip.atpacksupplies headers/startup/device libraries. - Pico SDK: confirm
PICO_SDK_PATHor the submodule path and run the Pico SDK CMake configure/build that produces.uf2. - Nordic nRF / Zephyr: run
west listto verify the manifest-resolved SDK modules, thenwest build -b <board>andwest flashonly when hardware is attached.
For the bundled direct Cortex-M scaffold, run flashing or debug validation only when hardware is attached and the user expects hardware access:
bash scripts/flash.sh
bash scripts/openocd_server.sh
If clang-format, clang-tidy, the selected target compiler, flash/debug tools, or hardware are unavailable, report the skipped step and leave the project ready for that tool.
References
- Read
references/embedded-project-blueprint.mdwhen choosing directory layout, CMake/toolchain settings, target ecosystem layers, target-family parameters, flashing/debug flow, or CI design. - Read
references/firmware-package-matrix.mdwhen choosing or validating vendor firmware packages, SDK paths,vendor/directories,.atpackfiles,westmanifests, ESP-IDF/Pico SDK setup, CMSIS applicability, or RTOS package layering. - Read the scaffold script before changing generated linker/startup defaults, supported MCU arguments, or generated command entry points.
- Read
assets/before changing standard generated configuration files; treat those files as templates and keep board-, MCU-, probe-, and project-specific values behind@PLACEHOLDER@variables.