Back to Embedded Systems Hardware Engineering Series

Template 1: STM32 Custom PCB Walkthrough

April 17, 2026 Wasil Zafar 50 min read

Complete step-by-step template for designing a custom STM32F4 PCB from requirements capture through schematic, layout, Gerber generation, assembly, and first power-on.

Table of Contents

  1. Requirements Capture
  2. Schematic Design
  3. PCB Layout
  4. Manufacturing Files
  5. Assembly & Bring-Up
  6. PCB Checklist Tool
  7. Conclusion

Step 1: Requirements Capture

CategoryRequirementTarget Value
MCUSTM32F446RE (100-pin LQFP)180 MHz Cortex-M4F
Power InputUSB-C or Barrel Jack5V, 2A max
Regulators3.3V main + 1.2V core (if needed)LDO: AP2112K-3.3
DebugSWD header (10-pin Cortex)ST-Link v3 compatible
USBUSB 2.0 Full Speed (device)USB-C connector
GPIO Breakout2 × 20-pin headersUART, SPI, I2C, ADC, PWM
Status LEDsPower + User (×2)Green power, Red/Blue user
PCB4-layer, 1.6mm, ENIG finish100 × 60 mm board

Step 2: Schematic Design

STM32F446 Custom PCB — Schematic Block Diagram
flowchart TD
    A["USB-C / Barrel
5V Input"] --> B["AP2112K
3.3V LDO"] B --> C["STM32F446RE
LQFP-100"] C -->|SWD| D["10-pin Debug
Header"] C -->|USB| E["USB-C
Device Port"] C -->|UART/SPI/I2C| F["2×20 GPIO
Headers"] C --> G["HSE Crystal
8 MHz"] C --> H["LSE Crystal
32.768 kHz"] B --> I["Decoupling
100nF × 7 + 4.7µF"] A --> J["Power LED
Green"] C --> K["User LEDs
Red + Blue"] style C fill:#3B9797,color:#fff
# KiCad schematic checklist — run before proceeding to layout

echo "=== STM32 Schematic Design Checklist ==="
echo ""
echo "POWER SUPPLY:"
echo "  [✓] USB-C CC resistors (5.1kΩ to GND on CC1, CC2)"
echo "  [✓] Reverse polarity protection (if barrel jack)"
echo "  [✓] LDO input cap (10µF ceramic, X7R)"
echo "  [✓] LDO output cap (10µF + 100nF ceramic)"
echo "  [✓] VDDA filtered (ferrite bead + 1µF + 100nF)"
echo ""
echo "MCU CONNECTIONS:"
echo "  [✓] All VDD pins connected to 3.3V"
echo "  [✓] All VSS pins connected to GND"
echo "  [✓] NRST: 100nF to GND + 10kΩ pull-up"
echo "  [✓] BOOT0: 10kΩ to GND (normal boot)"
echo "  [✓] HSE: 8MHz crystal + 20pF load caps"
echo "  [✓] LSE: 32.768kHz crystal + 6.8pF load caps"
echo "  [✓] VCAP1/VCAP2: 2.2µF to GND each"
echo ""
echo "DEBUG & PROGRAMMING:"
echo "  [✓] SWD: SWDIO, SWCLK, SWO, NRST, VDD, GND"
echo "  [✓] 10-pin Cortex Debug header pinout verified"
echo "  [✓] UART1 TX/RX routed to header for serial debug"
echo ""
echo "USB DEVICE:"
echo "  [✓] USB_DM (PA11), USB_DP (PA12) — 22Ω series resistors"
echo "  [✓] 1.5kΩ pull-up on DP (Full Speed identification)"
echo "  [✓] ESD protection diodes (USBLC6-2SC6)"
echo ""
echo "ERC: Run Electrical Rules Check — 0 errors, 0 warnings"

Step 3: PCB Layout

# 4-layer PCB stackup calculator for STM32 board
# Standard JLC/OSHPARK stackup: Sig-GND-PWR-Sig

import numpy as np

# Standard 4-layer 1.6mm stackup
layers = {
    "Layer 1 (Top Signal)":    {"copper_oz": 1, "thickness_mm": 0.035},
    "Prepreg 1":               {"material": "FR-4", "thickness_mm": 0.200},
    "Layer 2 (GND Plane)":     {"copper_oz": 1, "thickness_mm": 0.035},
    "Core":                    {"material": "FR-4", "thickness_mm": 1.065},
    "Layer 3 (Power Plane)":   {"copper_oz": 1, "thickness_mm": 0.035},
    "Prepreg 2":               {"material": "FR-4", "thickness_mm": 0.200},
    "Layer 4 (Bottom Signal)": {"copper_oz": 1, "thickness_mm": 0.035},
}

# Impedance calculation (microstrip on Layer 1 to GND on Layer 2)
er = 4.4           # FR-4 dielectric constant
h = 0.200          # Dielectric height to GND plane (mm)
w = 0.152          # Trace width for 50Ω (mm) — ~6 mil
t = 0.035          # Copper thickness (mm) — 1 oz

# Microstrip impedance (IPC-2141 approximation)
w_eff = w + (t / np.pi) * np.log(4 * np.e / np.sqrt((t/h)**2 + (t/(w*np.pi + 1.1*t*np.pi))**2))
z0 = (87 / np.sqrt(er + 1.41)) * np.log(5.98 * h / (0.8 * w_eff + t))

total_mm = sum(l["thickness_mm"] for l in layers.values())

print("4-Layer PCB Stackup — STM32 Custom Board")
print("=" * 55)
for name, spec in layers.items():
    mat = spec.get("material", f"{spec.get('copper_oz', '')} oz Cu")
    print(f"  {name:<28} {spec['thickness_mm']:.3f} mm  ({mat})")
print(f"\n  {'Total board thickness:':<28} {total_mm:.3f} mm")
print(f"\n50Ω Microstrip (Layer 1 → Layer 2 GND):")
print(f"  Trace width:   {w*1000:.0f} µm ({w/0.0254:.1f} mil)")
print(f"  Dielectric:    {h:.3f} mm (Er = {er})")
print(f"  Impedance:     {z0:.1f} Ω")
Layout Best Practices: Place the MCU center-board with decoupling capacitors within 2 mm of each VDD pin. Route HSE crystal traces < 10 mm with guard ground ring. Keep USB differential pair length-matched to ±0.1 mm with 90Ω differential impedance. Pour solid GND on Layer 2 under the MCU — no splits.

Step 4: Manufacturing Files

# Gerber generation checklist — KiCad 8.x output

echo "=== Gerber & Drill File Generation ==="
echo ""
echo "FILE SET (required by most fabs):"
echo "  board-F_Cu.gbr        — Front copper"
echo "  board-In1_Cu.gbr      — Inner layer 1 (GND)"
echo "  board-In2_Cu.gbr      — Inner layer 2 (Power)"
echo "  board-B_Cu.gbr        — Back copper"
echo "  board-F_SilkS.gbr     — Front silkscreen"
echo "  board-B_SilkS.gbr     — Back silkscreen"
echo "  board-F_Mask.gbr      — Front solder mask"
echo "  board-B_Mask.gbr      — Back solder mask"
echo "  board-Edge_Cuts.gbr   — Board outline"
echo "  board-F_Paste.gbr     — Front paste (stencil)"
echo "  board.drl             — PTH drill file"
echo "  board-NPTH.drl        — Non-plated holes"
echo ""
echo "ASSEMBLY FILES (for PCBA):"
echo "  board-BOM.csv         — Bill of materials"
echo "  board-CPL.csv         — Component placement list"
echo "  board-top.pos         — Pick-and-place (top)"
echo ""
echo "VERIFICATION:"
echo "  [✓] DRC passed — 0 errors"
echo "  [✓] Gerber viewer check (GerbView or tracespace.io)"
echo "  [✓] Drill file verified (correct units, plating)"
echo "  [✓] Board outline closed path"
echo "  [✓] Minimum annular ring ≥ 0.15mm"
echo "  [✓] Minimum trace/space ≥ 0.15mm / 0.15mm"

Step 5: Assembly & Bring-Up

/* First power-on bring-up sequence — STM32F446 custom PCB
   Systematic verification: power → clock → debug → peripherals */

#include <stdint.h>

/* BRING-UP CHECKLIST (execute in order):
 *
 * Phase 1: Pre-Power Visual Inspection
 *   [ ] No solder bridges under QFP (magnified inspection)
 *   [ ] All passives present and oriented correctly
 *   [ ] USB-C connector pins aligned
 *   [ ] Crystal cans grounded
 *
 * Phase 2: Power Rails (current-limited supply at 5V, 100mA limit)
 *   [ ] 5V rail: measure at USB-C VBUS test point
 *   [ ] 3.3V rail: measure at LDO output (expect 3.30V ±2%)
 *   [ ] VDDA:    measure at ferrite bead output (3.30V ±2%)
 *   [ ] Quiescent current: < 20mA (MCU in reset)
 *   [ ] No components hot to touch after 30 seconds
 *
 * Phase 3: Clock Verification
 *   [ ] HSE: probe 8.000 MHz on OSC_OUT pin
 *   [ ] LSE: probe 32.768 kHz on OSC32_OUT pin
 *   [ ] PLL lock: SYSCLK = 180 MHz (verify via SWO)
 *
 * Phase 4: SWD Debug Connection
 *   [ ] ST-Link detected in STM32CubeProgrammer
 *   [ ] Read device ID: 0x421 (STM32F446)
 *   [ ] Flash erase + write test pattern
 *   [ ] LED blink firmware runs
 *
 * Phase 5: Peripheral Smoke Test
 *   [ ] UART1 TX: "Hello from custom PCB\r\n" at 115200
 *   [ ] USB enumeration: CDC ACM device appears
 *   [ ] GPIO: toggle all header pins, verify with logic analyzer
 *   [ ] ADC: read VREFINT (expect ~1.21V)
 *   [ ] I2C scan: detect any connected devices
 */

/* Minimal blink test — first firmware for bring-up */
#define RCC_AHB1ENR  (*(volatile uint32_t*)0x40023830)
#define GPIOA_MODER  (*(volatile uint32_t*)0x40020000)
#define GPIOA_ODR    (*(volatile uint32_t*)0x40020014)

/* PA5 = User LED (typical STM32 boards) */
/* This is the absolute minimum bring-up test:
 * If the LED blinks, clock + power + flash are all working */

PCB Design Checklist Generator

PCB Design Checklist

Generate a customized PCB design checklist. Download as Word, Excel, or PDF.

Draft auto-saved

Conclusion

This template provides a repeatable workflow for custom STM32 PCB design: requirements capture, schematic with complete decoupling and ESD protection, 4-layer layout with controlled impedance, Gerber verification, and systematic bring-up. Use this as a starting point for any Cortex-M4 project.

Next Template

In Template 2: KiCad & Altium Professional Template, we’ll create production-ready schematic and layout templates with library management, design rules, and CI/CD integration.