Step 1: Requirements Capture
| Category | Requirement | Target Value |
|---|---|---|
| MCU | STM32F446RE (100-pin LQFP) | 180 MHz Cortex-M4F |
| Power Input | USB-C or Barrel Jack | 5V, 2A max |
| Regulators | 3.3V main + 1.2V core (if needed) | LDO: AP2112K-3.3 |
| Debug | SWD header (10-pin Cortex) | ST-Link v3 compatible |
| USB | USB 2.0 Full Speed (device) | USB-C connector |
| GPIO Breakout | 2 × 20-pin headers | UART, SPI, I2C, ADC, PWM |
| Status LEDs | Power + User (×2) | Green power, Red/Blue user |
| PCB | 4-layer, 1.6mm, ENIG finish | 100 × 60 mm board |
Step 2: Schematic Design
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} Ω")
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.
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.