Skip to content

OwlCodeTech/Embedded

Repository files navigation

Embedded Hardware Template

This repository is a general hardware and cross-compilation template for VS Code, CMake, Ninja, and script-driven workflows.

The current stage is the native minimum loop only. It validates the command structure, CMake configure/build flow, VS Code task entry points, local configuration files, and documentation before hardware-specific backends are added.

No flashing, serial monitor, debug server, GDB launch, reset, or board-specific embedded support is implemented in this stage.

Current Scope

Implemented now:

python scripts/hw.py doctor
python scripts/hw.py list-boards
python scripts/hw.py configure
python scripts/hw.py build
python scripts/hw.py clean
python scripts/hw.py rebuild
python scripts/hw.py size

Planned later:

  1. Cortex-M plus arm-none-eabi build output.
  2. OpenOCD flashing with confirmation.
  3. Serial monitor.
  4. Debug server and GDB integration.
  5. ESP32, RP2040/RP2350, RISC-V MCU, and Linux ARM as separate backends.

First Use

Run these commands from the project root:

python scripts/hw.py doctor
python scripts/hw.py list-boards
python scripts/hw.py configure
python scripts/hw.py build
python scripts/hw.py size

configure writes .build-config/current.yaml. That file is local machine state and is ignored by Git.

For a non-interactive default configuration:

python scripts/hw.py configure --non-interactive

For an explicit generator and build type:

python scripts/hw.py configure --build-type Debug --generator Ninja --non-interactive

Supported build types in this stage:

  • Debug
  • Release
  • RelWithDebInfo
  • MinSizeRel

Reserved generator options:

  • Ninja
  • MinGW Makefiles
  • MSYS Makefiles
  • NMake Makefiles
  • Visual Studio 17 2022

Ninja is the default recommended generator, but it is not the only supported design path. The selected generator is stored in .build-config/current.yaml, and build reads that file.

Cleaning

python scripts/hw.py clean
python scripts/hw.py rebuild

clean prints the configured build_dir and only removes that directory under build/. It does not remove source files or the project root.

Tool Checks

Use:

python scripts/hw.py doctor

doctor checks:

  • Python version
  • pip
  • Python packages: pyyaml, rich
  • Git
  • CMake
  • Ninja
  • gcc
  • g++
  • cl.exe
  • mingw32-make
  • make

The script reports OK, WARN, or FAIL. It does not install tools, modify PATH, or change system settings.

Manual verification commands:

cmake --version
ninja --version
python -m pip --version

Dependencies

This stage expects these tools to be installed and available in PATH:

  • Python 3.10 or newer
  • CMake 3.20 or newer
  • Ninja, recommended by default
  • Git
  • A native compiler, such as GCC/G++ or MSVC Build Tools
  • Python packages from requirements.txt

For Python packages, prefer a project-local virtual environment:

python -m venv .venv
.\.venv\Scripts\Activate.ps1
python -m pip install -r requirements.txt

If Python packages are missing, run:

python -m pip install -r requirements.txt

Dashboard: Board Center and Operation Status

The dashboard is a local read-only board workbench. It emphasizes the board itself, hardware specs, key pins, wiring, demo status, operation status, artifacts, and flash/debug configuration. Fixed environment paths and command references are still available, but they are folded under Advanced instead of being main page content.

Commands:

python scripts/hw.py status
python scripts/hw.py dashboard
python scripts/hw.py dashboard --open
python scripts/hw.py dashboard-live

Generated files:

reports/dashboard/index.html
reports/dashboard/status.json
reports/dashboard/history.json

reports/dashboard/ is a local generated report directory and should not be committed. It is ignored by Git.

The static dashboard contains:

  • Summary status bar
  • Current Board
  • Board Visuals
  • Hardware Specs
  • Key Pins
  • Demo Status
  • Wiring / Connection
  • Operation Status
  • Build Artifacts Summary
  • Flash Configuration
  • Debug Configuration
  • Recent Operations
  • collapsed Advanced section with Quick Commands, Environment Details, and System Events

dashboard-live starts a foreground local HTTP server on localhost:8765 by default. It uses Python standard library http.server; it does not start a background service. The page polls status.json every 2 seconds, and the server refreshes status.json on request.

All dashboard/status commands are read-only with respect to firmware and hardware. They do not build, flash, debug, erase, reset, or modify PATH. Copy buttons only copy commands to the clipboard; they do not execute commands.

Status color semantics:

  • success, ok, ready, supported, and verified are green.
  • fail, error, and missing are red.
  • warn and pending are yellow.
  • no record, n/a, and unknown are neutral gray. A missing recent flash/debug record is not treated as a warning.

Board images can be configured in a board profile:

images:
  board_photo: assets/boards/stm32f103_bluepill/board
  pinout: assets/boards/stm32f103_bluepill/pinout

The paths may also include an explicit extension:

images:
  board_photo: assets/boards/stm32f103_bluepill/board.jpg
  pinout: assets/boards/stm32f103_bluepill/pinout.png

Place images under:

assets/boards/stm32f103_bluepill/board.jpg
assets/boards/stm32f103_bluepill/board.png
assets/boards/stm32f103_bluepill/board.webp
assets/boards/stm32f103_bluepill/pinout.png
assets/boards/stm32f103_bluepill/pinout.jpg
assets/boards/stm32f103_bluepill/pinout.webp

Recommended names are board.jpg or board.png for the board photo, and pinout.png or pinout.jpg for the pinout. The dashboard also checks .jpg, .jpeg, .png, .webp, .bmp, .gif, and .svg, including common uppercase variants such as .JPG and .PNG.

If images are missing, the dashboard shows board image not available or pinout image not available and continues normally. The generated status.json records both the configured image path and the resolved file path that was actually used.

When the dashboard is generated, resolved local images are copied into the generated report directory, for example:

reports/dashboard/assets/boards/stm32f103_bluepill/board.jpg
reports/dashboard/assets/boards/stm32f103_bluepill/pinout.png

The original image files are not renamed or modified. The copied files are local report assets and are covered by the reports/dashboard/ Git ignore rule. This makes both dashboard --open and dashboard-live serve images from the same report directory. Dashboard operation status notes:

  • Flash dry-run and real flash are tracked separately.
  • Command-line GDB debug and VS Code GUI debug are tracked separately.
  • dashboard-live startup may be recorded once, but automatic status.json refreshes are not appended to history.
  • The dashboard summary bar shows board, readiness, build status, flash dry-run status, real flash status, command-line debug status, VS Code GUI debug status, artifact count, and last refresh time.

Board image paths for STM32F103 BluePill:

assets/boards/stm32f103_bluepill/board.jpg
assets/boards/stm32f103_bluepill/board.png
assets/boards/stm32f103_bluepill/board.webp
assets/boards/stm32f103_bluepill/pinout.png
assets/boards/stm32f103_bluepill/pinout.jpg
assets/boards/stm32f103_bluepill/pinout.webp

Stage 8: Status and Static Dashboard

This stage adds read-only project status views for the terminal and a local static HTML dashboard.

Terminal status:

python scripts/hw.py status

Static dashboard generation:

python scripts/hw.py dashboard
python scripts/hw.py dashboard --open

The dashboard is generated at:

reports/dashboard/index.html

status and dashboard only read project state. They do not build, flash, debug, erase, reset, modify PATH, or start a background service.

The dashboard can be used to inspect:

  • current board
  • current build configuration
  • board information
  • toolchain status
  • build artifacts
  • flash configuration
  • debug configuration
  • common commands

reports/dashboard/ is a local generated report directory and is ignored by Git by default.

Stage 7: VS Code Cortex-Debug Graphical Debugging

This stage adds a VS Code graphical debug configuration for stm32f103_bluepill using the Cortex-Debug extension, OpenOCD, ST-Link, and arm-none-eabi-gdb.

Prerequisites:

  • Cortex-Debug extension installed: marus25.cortex-debug
  • OpenOCD available in PATH
  • arm-none-eabi-gdb available in PATH
  • ST-Link connected over SWD
  • stm32f103_bluepill built successfully
  • The matching firmware has already been flashed with python scripts/hw.py flash

Recommended setup before starting VS Code debugging:

python scripts/hw.py configure --board stm32f103_bluepill --build-type Debug --generator Ninja --non-interactive
python scripts/hw.py build
python scripts/hw.py size
python scripts/hw.py flash --dry-run
python scripts/hw.py flash

Then in VS Code:

  1. Open Run and Debug.
  2. Select HW: Debug STM32F103 BluePill.
  3. Click Start Debugging.
  4. Set breakpoints, step, continue, inspect variables, and inspect the call stack from the VS Code UI.

The launch configuration uses:

  • type: cortex-debug
  • servertype: openocd
  • configFiles: interface/stlink.cfg, target/stm32f1x.cfg
  • gdbPath: arm-none-eabi-gdb
  • executable: build/stm32f103_bluepill/Ninja/Debug/stm32f103_bluepill.elf

The launch configuration does not execute load, does not erase Flash, and does not flash firmware. It assumes the board already contains firmware matching the selected .elf. If the flashed firmware and .elf do not match, breakpoints and stepping may behave incorrectly.

Common issues:

  • Cortex-Debug extension is not installed.
  • arm-none-eabi-gdb is not found in PATH.
  • OpenOCD is not found in PATH.
  • localhost:3333 is occupied by another OpenOCD instance.
  • ST-Link is busy in another program.
  • The ELF path does not exist because the project was not built.
  • The build directory is not Ninja/Debug; update the launch config or rebuild with the documented command.
  • Current configured board is not stm32f103_bluepill.
  • Breakpoints do not hit because the board firmware does not match the ELF.
  • GDB may warn about host encoding; this has not affected command-line debugging in the current setup.

A common ST-LINK V2 supports SWD flashing and debugging. It does not provide a normal serial monitor. Serial monitor requires a separate USB-UART adapter or another board-specific serial path and is intentionally not part of this stage.

Stage 6: OpenOCD + GDB Debug

This stage adds command-line SWD debugging for stm32f103_bluepill using OpenOCD and arm-none-eabi-gdb.

Scope:

  • Supported board: stm32f103_bluepill
  • Probe: ST-LINK V2 over SWD
  • GDB server: OpenOCD on localhost:3333
  • GDB client: arm-none-eabi-gdb

A common ST-LINK V2 supports SWD flashing and debugging. It is not the same thing as a USB-to-serial adapter, so this stage does not implement serial monitor.

Build and flash the firmware first so the target contains the same program as the .elf symbols:

python scripts/hw.py configure --board stm32f103_bluepill --build-type Debug --generator Ninja --non-interactive
python scripts/hw.py build
python scripts/hw.py size
python scripts/hw.py flash --dry-run
python scripts/hw.py flash

Use two terminals for debugging.

Terminal 1:

python scripts/hw.py debug-server

Terminal 2:

python scripts/hw.py debug

The debug command starts GDB with the current .elf file and runs:

target remote localhost:3333
monitor reset halt
break main
continue

It does not execute load, does not erase Flash, and does not flash firmware. Flashing and debugging are intentionally separate operations.

Useful GDB commands:

break main
continue
next
step
info registers
x/16xw 0x08000000
quit

Common issues:

  • localhost:3333 connection failed: start python scripts/hw.py debug-server in another terminal first.
  • ST-Link is busy: close OpenOCD, STM32CubeProgrammer, or other tools using the probe.
  • OpenOCD not started: check terminal 1 output.
  • .elf does not match flashed firmware: rebuild and flash again.
  • Breakpoints do not work: confirm symbols are from the same .elf and the target halted correctly.
  • Stepping looks strange: compiler optimization can affect source-level stepping; use Debug builds.

Stage 3: OpenOCD Flash Dry Run

This stage prepares flashing for stm32f103_bluepill only. It uses OpenOCD with ST-Link and keeps the operation guarded by dry-run output and an explicit confirmation prompt.

Current scope:

  • Supported board: stm32f103_bluepill
  • Flash method: OpenOCD
  • Interface config: interface/stlink.cfg
  • Target config: target/stm32f1x.cfg
  • Artifact: .elf

Not implemented in this stage:

  • serial monitor
  • debug server
  • GDB debug launch
  • standalone reset command
  • erase command
  • other platform backends

Install OpenOCD manually if needed. The scripts do not install OpenOCD and do not modify PATH. On Windows, prefer non-C-drive locations such as:

  • E:\Tools\openocd
  • E:\EmbeddedTools\openocd
  • E:\vscode_code\Tools\openocd

After installation, add the directory containing openocd.exe to PATH and verify:

where openocd
openocd --version
python scripts/hw.py doctor

Before flashing, build and inspect the command:

python scripts/hw.py configure --board stm32f103_bluepill --build-type Debug --generator Ninja --non-interactive
python scripts/hw.py build
python scripts/hw.py size
python scripts/hw.py flash --dry-run

flash --dry-run only prints the OpenOCD command. It does not connect to hardware and does not write Flash.

After dry-run output is correct and hardware is connected, run:

python scripts/hw.py flash

Real flash prints the OpenOCD command, warns that target Flash will be written, and requires typing yes. Any other input cancels the operation.

Common issues:

  • openocd not found: install OpenOCD and add the directory containing openocd.exe to PATH.
  • ST-Link not detected: check USB cable, driver, ST-Link firmware, and device manager.
  • target voltage not detected: check target power and SWD wiring.
  • access denied: close other tools using ST-Link and check USB permissions.
  • wrong target config: this stage uses target/stm32f1x.cfg for STM32F103.
  • BOOT0/BOOT1 or reset state abnormal: return BOOT0/BOOT1 to the expected boot state and retry after reset.

Stage 2: Cortex-M Firmware Build

This stage adds a minimum Cortex-M cross-compilation loop for stm32f103_bluepill. It only builds firmware artifacts. It does not flash, monitor serial output, start a debug server, launch GDB, or reset hardware.

Configure and build native regression first:

python scripts/hw.py configure --board native --build-type Debug --generator Ninja --non-interactive
python scripts/hw.py build
python scripts/hw.py size

Configure and build STM32F103 BluePill firmware:

python scripts/hw.py configure --board stm32f103_bluepill --build-type Debug --generator Ninja --non-interactive
python scripts/hw.py build
python scripts/hw.py size

The STM32F103 BluePill profile uses:

  • backend: cortex_m
  • toolchain: arm-none-eabi
  • startup: startup/stm32/startup_stm32f103xb.s
  • linker script: linker/stm32f103c8t6.ld
  • CPU flags: -mcpu=cortex-m3 -mthumb -mfloat-abi=soft

Expected firmware outputs under build/stm32f103_bluepill/Ninja/Debug:

  • stm32f103_bluepill.elf
  • stm32f103_bluepill.bin
  • stm32f103_bluepill.hex
  • stm32f103_bluepill.map

The size command calls arm-none-eabi-size for Cortex-M boards. If the tool is not found, verify that the official Arm GNU Toolchain bin directory is in PATH.

Install Official Arm GNU Toolchain

The future Cortex-M stage will require the official Arm GNU Toolchain for Arm Embedded, usually exposed through these commands:

arm-none-eabi-gcc --version
arm-none-eabi-g++ --version
arm-none-eabi-objcopy --version
arm-none-eabi-size --version
arm-none-eabi-gdb --version
python scripts/hw.py doctor

This toolchain is needed for bare-metal ARM Cortex-M cross-compilation. Future board profiles such as STM32F103 BluePill and other Cortex-M targets will depend on it.

Use the vendor official Arm GNU Toolchain as the default recommendation. Do not use the MSYS2 arm-none-eabi package as the default project path. MSYS2 is still useful for native Windows tools such as gcc, cmake, ninja, and make, but the embedded ARM toolchain should come from the official Arm GNU Toolchain unless a later project deliberately chooses otherwise.

If you use reasonix to install or manage the toolchain, select the official Arm GNU Toolchain release and choose a non-C-drive installation path when possible. This repository does not call reasonix automatically, does not install software, and does not modify PATH.

Recommended Windows install roots:

  • E:\Toolchains\arm-gnu-toolchain
  • E:\Tools\arm-gnu-toolchain
  • E:\EmbeddedTools\arm-gnu-toolchain
  • E:\vscode_code\Tools\arm-gnu-toolchain

After installation, add the actual bin directory to PATH. Depending on the extracted package layout, that may be something like:

E:\Toolchains\arm-gnu-toolchain\bin

or a versioned subdirectory's bin folder. Verify from the same PowerShell session that VS Code will use:

arm-none-eabi-gcc --version
arm-none-eabi-g++ --version
arm-none-eabi-objcopy --version
arm-none-eabi-size --version
arm-none-eabi-gdb --version
python scripts/hw.py doctor

Do not commit local installation paths. If a path needs to be recorded, put it in one of these ignored local files:

  • config/toolchains.local.yaml
  • CMakeUserPresets.json
  • .build-config/current.yaml

config/toolchains.example.yaml documents the expected command names and recommended install roots without storing private machine paths.

Windows Install Guidance

The scripts do not install anything automatically. On Windows, prefer installing tools outside the C drive when possible, for example:

  • E:\Tools\ninja
  • E:\vscode_code\Tools\ninja
  • E:\msys64
  • E:\SDK
  • E:\EmbeddedTools
  • E:\Toolchains

After installing Ninja, add the directory containing ninja.exe to PATH, then verify:

ninja --version

If an installer defaults to C:\Program Files, C:\Program Files (x86), or C:\Users\<name>\AppData, choose a custom install path on E: when the tool supports it.

MSYS2 / MSYS64 Notes

MSYS2 can be a practical Windows source for gcc, g++, cmake, ninja, and make. A reasonable install location is:

E:\msys64

Prefer one environment consistently, usually UCRT64 or MINGW64. Avoid mixing tools from different sources in one shell, such as CMake from one installation, GCC from another, and Ninja from a third. Mixed toolchains often cause generator, path, runtime, and compiler-detection failures.

The scripts may detect common E:\msys64\ucrt64\bin or E:\msys64\mingw64\bin locations and print a hint, but they do not modify PATH.

If Build Fails

Check these first:

python scripts/hw.py doctor
cmake --version
ninja --version

Then inspect .build-config/current.yaml:

Get-Content .build-config/current.yaml

Common causes:

  • Ninja is selected but ninja.exe is not in PATH.
  • CMake is not in PATH.
  • The selected generator does not match the compiler available in the current shell.
  • GCC/G++ or MSVC is not available in the current shell.
  • Tools from MSYS2, Visual Studio, standalone CMake, and standalone Ninja are mixed inconsistently.

Git Policy

Commit these files:

  • scripts/, boards/examples/, boards/templates/
  • toolchains/, cmake/, config/defaults.yaml, config/toolchains.example.yaml
  • .vscode/tasks.json, .vscode/settings.json, .vscode/extensions.json
  • CMakeLists.txt, CMakePresets.json, requirements.txt, .gitignore, README.md, AGENTS.md
  • template source files under src/ and include/

Do not commit these files:

  • build/
  • .build-config/
  • .venv/
  • CMakeUserPresets.json
  • config/toolchains.local.yaml
  • generated firmware or binary outputs

Keep private SDK, compiler, and tool paths in ignored local files such as:

  • CMakeUserPresets.json
  • config/toolchains.local.yaml
  • .build-config/current.yaml

Layout

  • scripts/hw.py is the unified command entry.
  • scripts/hwlib/ contains reusable command, config, process, CMake, and backend logic.
  • boards/ contains board profiles and templates.
  • toolchains/ contains CMake toolchain files.
  • cmake/ contains reusable CMake modules.
  • config/ contains shared defaults and example local configuration.
  • .build-config/ contains current local selection state and is ignored by Git.
  • .vscode/ contains lightweight task shortcuts only.

Extension Plan

Recommended order:

  1. Keep the native backend as a regression target.
  2. Add a minimal Cortex-M backend with arm-none-eabi build output only.
  3. Add size, binary, hex, and map generation for embedded targets.
  4. Add OpenOCD flashing with explicit confirmation and dry-run support.
  5. Add serial monitoring.
  6. Add debug server and GDB integration.
  7. Add ESP-IDF, RP2040/RP2350, RISC-V MCU, and Linux ARM as separate backends rather than forcing every platform into one flow.

About

Embedded hardware cross-compilation template supporting native and Cortex-M targets

Resources

Stars

Watchers

Forks

Releases

No releases published

Packages

 
 
 

Contributors