Skip to the content
PCBKitNew board
2 layers41 × 31 mmSTM32, the printed circuit board in 3D

CI workflow that flashes a STM32F103 board I designed on KiCad and runs Pytest-based HITL validation.

Size
41 × 31 mm
Copper layers
2
Thickness
1.6 mm
Parts
34
Nets
46
Pads
132
Tracks, vias
214, 26
Pours
4
Routed
Yes
KiCad
KiCad 9.0 (file 20241229)
Created
30 Nov 2025
Updated
8 Dec 2025

Overview

STM32 is an open-source printed circuit board by coreyjharrington-sys, from the coreyjharrington-sys/STM32DevBoardTestingProject repository on GitHub, published under the MIT licence. It is a 2-layer board of 41 × 31 mm with 34 parts on 46 nets, routed with 214 tracks and 26 vias.

It is built around the STM32F103C8T6 and AMS1117-3.3. Its parts include 13 capacitors, 5 resistors, 4 connectors, 2 ICs and 1 diode. It belongs with the STM32 boards of this library.

Main components

2

README

README.md

STM32Devboard – Firmware + HITL Simulation in CI

Test Setup Test Setup

A combined hardware + firmware + automated test demonstration project

This project demonstrates a Hardware-In-The-Loop (HITL)-style automated test pipeline using a custom STM32F103C8T6 development board that I designed in KiCad, combined with firmware validation using Pytest and GitHub Actions.

When code is pushed or a pull request is opened, the CI workflow automatically:

  1. Builds the firmware
  2. Flashes the STM32F103C8T6 board connected to the GitHub Actions runner
  3. Runs Pytest-based functional tests against the physical device
  4. Reports pass/fail status back to GitHub

This pipeline simulates a professional HITL test system, showing how real hardware can be validated automatically using continuous integration.


📦 Project Structure

text
Test_Serial/
│
├── firmware/              # Embedded C firmware for STM32F103C8T6
│   ├── src/
│   ├── include/
│   └── (build artifacts ignored via .gitignore)
│
├── tests/                 # Pytest functional tests for HITL validation
│   ├── test_commands.py
│   ├── test_math_ops.py
│   ├── dut_config.json    # PID/VID → auto-detect COM port
│   └── helpers/
│
├── hardware/              # Full KiCad project for the custom STM32 board
│   ├── *.kicad_pro
│   ├── *.kicad_sch
│   ├── *.kicad_pcb
│   ├── symbols/
│   └── footprints/
│
├── scripts/               # Optional Python helper scripts
│
├── requirements.txt       # Python dependencies for Pytest HITL tests
├── .gitignore
└── README.md

The KiCad project is intentionally included to showcase the board design to recruiters/employers. Only temporary, generated, and fabrication files are ignored via .gitignore.


🔧 Hardware Overview (Custom STM32F103C8T6 Board)

The DUT is a custom development board designed in KiCad. The design includes:

  • STM32F103C8T6 microcontroller
  • USB-to-UART for firmware testing
  • SWD debug header
  • Power regulation and filtering
  • Breakouts for serial, GPIO, and test pins

The PCB and schematic files are included so reviewers can inspect routing, component selection, layout style, and design organization.

This hardware is used directly in the HITL CI workflow.

Note: If you wish to run this demo yourself a Blue Pill Developement board can be sustituted.

Note: Credit to Phil's Lab for board design tutorial https://www.youtube.com/watch?v=aVUqaB0IMh4


🧩 Firmware Overview

The embedded firmware is intentionally minimal and built for testing. It implements a UART command interface supporting:

  • A command/response handshake

  • Four arithmetic operations:

    • Add
    • Subtract
    • Multiply
    • Divide
  • A small set of additional commands used by the test suite

This makes the board ideal for CI-driven firmware verification.

Note: If running this demo use ST-LINK V2 Programmer for flashing the board.


📦 Dependencies 🛠 Development Dependencies These are tools used during development and design, not required on the CI runner itself:

  • STM32CubeMX → generates firmware scaffolding, peripheral initialization code, and startup files for the STM32F103C8T6
  • KiCad → full PCB and schematic design for the custom STM32 development board

🖥️ Runner Dependencies These must be installed and available on the self‑hosted runner before the HITL workflow can execute:

  • Docker → builds STM32 firmware inside a reproducible container
  • STM32CubeProgrammer CLI (CubeProgrammerCLI) → flashes firmware to the STM32 board via SWD
  • Python 3.x → interpreter for running HITL test suites
  • Conda → environment manager for reproducible Python dependencies
  • Git → required by actions/checkout to pull the repository ✅ Verification Checklist Run these commands on the runner to confirm installation: docker --version CubeProgrammerCLI --version python --version conda --version git --version

All commands should return valid version information. If any fail, install or update the missing dependency before running the workflow


🐍 Python Dependencies (via Conda) The Python environment is defined in environment.yml and updated in CI with: conda env update --file environment.yml --name testframework --prune

Key libraries include:

  • pytest → functional test framework for HITL validation
  • pyserial → serial communication with the STM32 board
  • utility modules → logging, JSON parsing, device enumeration, and test orchestration

🧪 HITL Test Flow (Pytest)

After flashing the firmware, GitHub Actions triggers Pytest to validate real hardware behavior:

  • A Python script scans the system’s USB devices

  • It loads the dut_config.json file to locate the board based on:

    • PID
    • VID
    • Baudrate
  • The test suite opens the serial port and sends each supported command

  • Responses are parsed and validated

Example Pytest coverage:

  • Handshake / ping test
  • Add / subtract / multiply / divide
  • Error format tests
  • Command framing validation

Test artifacts (logs, HTML output, temp files) are fully ignored via .gitignore.


🐳 Dockerized Firmware Build

A Docker container is provided for reproducible STM32F103 firmware builds. It includes the ARM toolchain and necessary libraries.

Usage

Build the Docker image once:

bash
docker build -t stm32devboardcompiler .

Compile firmware from your local source by mounting the repo:

bash
docker run --rm -v ${PWD}:/workspace -w /workspace/firmware stm32devboardcompiler make all

To clean and rebuild:

bash
docker run --rm -v ${PWD}:/workspace -w /workspace/firmware stm32devboardcompiler make clean all

Notes:

  • The container is purely for building firmware; Python HITL tests run on the host to access the physical board.
  • Source code and Makefile remain on the host, so edits are immediately reflected in builds.

⚙️ GitHub Actions CI

Our CI/CD pipeline is defined in .github/workflows/*.yml files using GitHub Actions syntax.
Each workflow specifies triggers under the on: key and jobs under the jobs: key.

🔔 Triggers

The workflow runs automatically on:

  • Push → any branch pushed to the remote repo
  • Pull request → PRs targeting main
  • workflow_dispatch → manual trigger from the Actions tab

🛠 Workflow steps

The hitl-test job runs on a self‑hosted runner (with STM32 hardware attached) and performs:

  • Checkout repo – pulls the latest code
  • Ensure Docker – verifies Docker is installed
  • Build firmware – compiles with Dockerized ARM toolchain (make clean all)
  • Check CubeProgrammerCLI – verifies ST’s programmer tool is available on the runner
  • Flash firmware – programs the STM32F103C8T6 via CubeProgrammerCLI
  • Verify Python & Conda – ensures Python and Conda are available
  • Update Conda environment – applies environment.yml to the testframework environment (with pruning)
  • Run HITL tests – activates the Conda environment and executes pytest against the physical device 🔄 Feedback loop This setup provides a fully automated feedback loop:
  • Firmware is built and flashed
  • Hardware‑in‑the‑loop tests validate behavior
  • Results are collected and surfaced directly in GitHub

🔄 Feedback loop

This setup provides a fully automated feedback loop:

  • Firmware is built and flashed
  • Hardware‑in‑the‑loop tests validate behavior
  • Results are collected and surfaced directly in GitHub

🐍 Python Environment

🐍 Python Environment This CI workflow uses Conda to manage dependencies reproducibly.

Update the environment locally with: conda env update --file environment.yml --name testframework --prune

Activate the environment: conda activate testframework

Run tests: python -m pytest --maxfail=1 --disable-warnings -q

Key libraries include:

  • pytest
  • pyserial
  • Utility modules for device enumeration and communications

🔌 DUT Configuration File (dut_config.json)

This file determines which device to test against:

json
{
    "pid": "0x1234",
    "vid": "0x5678",
    "baudrate": 115200
}

Pytest uses these identifiers to automatically determine the correct COM port.

This avoids any hard-coding and ensures the CI system always targets the correct board.


📝 License

This project is licensed under the MIT General Public License (GPL). See the LICENSE file for details.


🛠️ Future Improvements

  • SQL logging of test metrics
  • More extensive command set
  • Automated hardware reset between test cycles
  • Multi-device testing support
  • Hardware fault injection
  • Coverage reporting and test data visualization
  • Linting and SCA of Embedded Code
  • Add I2C and UART communcation
  • Add automated testing with logic analyzer
  • ccache in Docker for faster builds

Parts

34
QtyValueFootprintReferences
5100nCapacitor_SMD:C_0402_1005MetricC4, C5, C6, C7, C11
41.5kResistor_SMD:R_0402_1005MetricR1, R3, R4, R5
4MountingHoleMountingHole:MountingHole_2.2mm_M2H1, H2, H3, H4
3Conn_01x04_PinConnector_PinHeader_2.54mm:PinHeader_1x04_P2.54mm_VerticalJ2, J3, J4
210pCapacitor_SMD:C_0402_1005MetricC12, C13
21uCapacitor_SMD:C_0402_1005MetricC9, C10
222uCapacitor_SMD:C_0805_2012MetricC1, C2
110kResistor_SMD:R_0402_1005MetricR2
110nCapacitor_SMD:C_0402_1005MetricC8
110uCapacitor_SMD:C_0603_1608MetricC3
1120RInductor_SMD:L_0603_1608MetricFB1
116MHzCrystal:Crystal_SMD_3225-4Pin_3.2x2.5mmY1
1AMS1117-3.3Package_TO_SOT_SMD:SOT-223-3_TabPin2U1
1LOGOLOGOG***
1RedLED_SMD:LED_0603_1608MetricD1
1STM32F103C8T6Package_QFP:LQFP-48_7x7mm_P0.5mmU2
1SW_SPDTButton_Switch_SMD:SW_SPDT_PCM12SW1
1USB_B_MicroConnector_USB:USB_Micro-B_Wuerth_629105150521J1

The 33 most common of 34 parts.

Questions

How big is the STM32 PCB?

It measures 41 × 31 mm and has 2 copper layers, 1.6 mm thick.

What parts does the STM32 use?

34 parts, built around the STM32F103C8T6 and AMS1117-3.3. The full list of its parts is on this page, with links to each part's symbol and footprint where PCBKit's library has them.

Where can I download the STM32 KiCad files?

From the coreyjharrington-sys/STM32DevBoardTestingProject repository on GitHub, at the commit this page was made from: the board is hardware/STM32.kicad_pcb and its schematic hardware/STM32.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the STM32 design in my own project?

Its repository publishes it under the MIT licence: you may reuse it on that licence's terms (keep the author's notice, and for a copyleft licence share your changes alike).

Similar boards

  • 2 layers68 × 40 mmStm32-io extend, the printed circuit board in 3D

    Stm32-io extend

    hardenedlinux/cheap-pcb

    Cheap PCB: Better understanding the current status of hardware supply chain

    44 parts170CC0-1.0
  • 2 layers99.1 × 58.4 mmHEAT, the printed circuit board in 3D

    HEAT

    milar111/HEAT

    An open-source STM32 SMD assembly station for precision soldering. Uses a custom Smart Pulse & Coast algorithm to drive 400W mains heaters via SSR. Features OLED UI, NTC feedback, and safety cooling.

    57 parts9
  • 2 layers71.3 × 25.4 mmUSB DALI, the printed circuit board in 3D

    USB DALI

    even-notodd/USB-DALI

    USB-DALI interface converter

    43 parts4
  • 2 layers78 × 60 mmDC Motor Controller, the printed circuit board in 3D

    DC Motor Controller

    minhle4397/Line-Follower-Robot-v2

    Improved Hardware and Firmware for Line Follower Robot

    53 parts3
  • 4 layers36 × 36 mmTrackMAG, the printed circuit board in 3D

    TrackMAG

    mupfdev/TrackMAG

    An open hardware development board primarily intended for the development of accessible input devices.

    58 parts3
  • 2 layers154.7 × 113 mmDeskMixer, the printed circuit board in 3D

    DeskMixer

    RaduAndre/DeskMixer

    DeskMixer is a software that allows control of application volumes with real sliders, and action mapping on buttons using arduino like platforms. The project was inspired originally by deej.

    113 parts3
  • 2 layers42 × 33 mmSTM32 course, the printed circuit board in 3D

    STM32 course

    abda-s/STM32-Phill-s-Lab-PCB-Course

    A beginner-friendly introduction to STM32 hardware design and KiCad

    32 parts2
  • 2 layers53.3 × 35.6 mmStm32 minimal dev, the printed circuit board in 3D

    Stm32 minimal dev

    amrithHN/stm32_minimal_dev

    stm32 based minimal dev board

    33 parts2GPL-3.0