Skip to the content
4 layers170 × 120 mmCm5, the printed circuit board in 3D

Three KiCad 10 PCBs designed entirely as Python code with layered verification

Size
170 × 120 mm
Copper layers
4
Thickness
1.6 mm
Parts
243
Nets
360
Pads
1,283
Tracks, vias
1,695, 524
Pours
24
Routed
Yes
KiCad
KiCad 10.0 (file 20260206)
Created
9 Oct 2026
Updated
5 Nov 2026

Overview

Cm5 is an open-source printed circuit board by YORROY123, from the YORROY123/kicad-scripted-pcb repository on GitHub, published under the MIT licence. It is a 4-layer board of 170 × 120 mm with 243 parts on 360 nets, routed with 1,695 tracks and 524 vias.

It is built around the IP804AR, LAN7800/Y9X and TPS568230RJER, with the AP2171WG, FSUSB42MUX and TPS2051CDBV among its other parts. Its parts include 129 capacitors, 52 resistors, 12 diodes, 11 ICs and 10 connectors. It belongs with the computers and single-board computers boards and the ESP32, RISC-V and Raspberry Pi (Linux) boards of this library.

Main components

12

README

README.md

kicad-scripted-pcb

繁體中文

Three KiCad 10 boards designed entirely as code: Python scripts produce the schematic, the PCB placement, the routing (via freerouting) and the copper pours, and each board rebuilds from scratch with one command. The KiCad GUI is never opened.

The point is verification. Every build runs several independent checks, because each one is blind to errors the others catch. Some of those errors turned up while these boards were being built and are listed below.

BoardResult
usbc-ldousbc-ldo: USB-C 5 V → 3.3 V LDO → LED. 40 × 24 mm, 2 layers. Includes an ngspice power-path simulation.ERC 0, DRC 0, schematic parity
esp32c3esp32c3: ESP32-C3 minimal board with native USB, LP38693 LDO, RESET/BOOT, LEDs and an 8-pin header. 32 × 49 mm.ERC 0, DRC 0, schematic parity, pin-by-pin netlist check
relay8relay8: ESP32-C3 + ULN2803 driving 8 mains relays from one mains cable: on-board HLK-10M05 AC-DC (100–240 VAC), T8A fuse, varistor, L/N bus traces, per-channel NO · N · NC terminals, isolation slots and custom mains clearance rules. 232 × 110 mm. Not safety-certified.ERC 0, DRC errors 0 (40 silkscreen-clipped-by-slot/edge warnings listed), schematic parity

Each ESP32 board has a FIRMWARE.md with the pin map, flashing steps, a first program, and, for relay8, the mains wiring.

Pipeline

text
gen/board.py ──► .kicad_sch ──► ERC ──► netlist ──► netlist check (vs expected_nets.json)
                                                     │
                                                     ▼
                                     design review (lib/review.py, datasheet rules)
                                                     │
gen/pcb.py ◄─────────────────────────────────────────┘   place footprints, board outline,
   │                                                     net classes, placement self-check
   ▼
.kicad_pcb ──► Specctra DSN ──► freerouting ──► SES ──► import + GND pour ──► DRC (+ schematic parity)
                                                                                   │
                     lcsc.json ──► lib/lcsc.py (online, run by hand) ──► lcsc-check.json
                                                                                   │
                                                       lib/fab.py ◄────────────────┘
                                     Gerber + drill zip, JLCPCB BOM / CPL, hand-solder list

Every step stops the build on failure; nothing is passed downstream with a known error.

kicad-cli has no "update PCB from schematic" command, so lib/pcbgen.py builds the board from the exported netlist with pcbnew.

What each check catches, and what it missed

CheckCatchesMissed here (caught by something else)
schgen.crossing_pins() / overlapping_wires()a wire running across a pin (silent short), two nets merged by overlapping wires—
KiCad ERCunconnected pins, undriven powerLED wired backwards (two passive pins, ERC is fine with it). Found by reading the netlist while building the PCB.
check_netlist.py vs expected_nets.jsonwrong pin→net, single-pin netsERC ignores "global label appears only once" by default, so a label typo creates an isolated net with no ERC error. Proven with a deliberate typo (mutation test).
placement self-checkpad nets vs netlist, footprints off-board, courtyard overlapUses real courtyard polygons. The ESP32 module's courtyard is T-shaped, and bounding boxes reject legal positions.
DRC + --schematic-parityclearance, track width, edge clearance, schematic vs PCB—
custom DRC rules (relay8.kicad_dru)mains ↔ low voltage ≥ 3.0 mm, mains ↔ mains ≥ 2.4 mmCreepage around the slots is not checked by DRC. Needs a human.
ngspice simulation (usbc-ldo/sim)design marginsThe first board's 1.1 V-dropout LDO falls out of regulation at USB's 4.40 V minimum, and its input capacitance injects ~124 µC on hot-plug (USB 2.0 limit: 50 µC). All three boards now use LP38693 (12 V input rating): esp32c3/sim showed that with only 1 µF on VBUS, hot-plug cable ringing reaches 7.7–8.6 V, above the 6.5 V rating of the AP2112K the ESP32 boards first used.
lib/review.py design review (datasheet rules on the netlist)wrong intent: diode/TVS polarity, LED current from the real Vf range, decoupling and rail ranges per datasheet, USB-C CC pull-downs, ESP32-C3 EN RC / strapping pins / GPIO18-19, relay flyback path and pickup voltage, capacitor voltage and polarity, per-supply current budget, LDO junction temperature, USB VBUS capacitanceusbc-ldo's SMAJ5.0A TVS was wired backwards: anode on +5 V, cathode on GND, a short the moment USB is plugged in. KiCad's symbol names the cathode pin "A1". ERC, DRC, the netlist check and the SPICE model (which had it the right way round) all passed. It also found a blue LED on a 3.3 V GPIO (Vf up to 3.6 V) and green power LEDs at ~0.45 mA. lib/review_test.py breaks the real netlists 20 ways and expects each rule to fire.
lib/lcsc.py + lib/fab.pyLCSC part number vs model, stock, package size, R/C value, LED colour; symbol default footprint vs assigned footprint; drill count; BOM/CPL/board refdesAll three boards used the USBLC6-2P6 symbol (SOT-666) on a SOT-23-6 footprint: same pinout, so nothing else noticed, but a BOM by value buys parts that do not fit. The SMAJ5.0A part number first chosen had zero stock.

Things that cost time (so they don't cost yours)

  • freerouting-cli 2.5.0 crashes on KiCad 10 DSN files (freerouting#957). Use the jar, which needs Java 25.
  • freerouting's automatic neck-down narrows tracks to 0.125 mm beside 0402 pads, below JLCPCB's 0.127 mm minimum. Use --router.automatic_neckdown=false --router.neck_width_um=150.
  • The DSN carries no copper-to-edge rule. Pass --router.copper_to_edge_clearance_um. That setting does not cover internal slots, so put keepouts around slots.
  • Net classes live in .kicad_pro, not .kicad_pcb. Save with pcbnew.SaveBoard(), which writes both.
  • board.Remove(zone) from Python can raise 'SwigPyObject' has no attribute 'thisown' or crash pcbnew (0xC0000005). Use board.Delete().
  • freerouting reports pin-to-pin "violations" inside fine-pitch footprints where KiCad's DRC is clean. The cause is KiCad's DSN exporter inflating every edge of a rounded-rect pad (specctra_export.cpp) by the arc-approximation margin.
  • Windows PowerShell 5.1 reads BOM-less UTF-8 scripts as ANSI. The build scripts here are ASCII-only for that reason.

Requirements

  • Windows (the build scripts are PowerShell; the Python parts are cross-platform)
  • KiCad 10 (uses its bundled Python for pcbnew, and its ngspice). Set KICAD_BIN / KICAD_SHARE if it is not in the default location.
  • Python 3.10+ on PATH for schematic generation and the design review (standard library only). The simulations and the field solver need numpy, scipy and matplotlib.
  • Network access only for lib/lcsc.py (JLCPCB parts API). The build itself runs offline.
  • freerouting 2.5.0 jar + a Java 25 runtime. Run tools\setup-tools.ps1 once; it downloads both into tools\ with pinned SHA-256 checks.

Quick start

powershell
powershell -ExecutionPolicy Bypass -File tools\setup-tools.ps1
powershell -ExecutionPolicy Bypass -File boards\esp32c3\build.ps1
python lib\review_test.py          # design-review mutation tests; needs the boards built once

The build ends with boards/<b>/fab/:

FileUse
<b>-gerber.zipupload to JLCPCB as the PCB
<b>-bom.csv, <b>-cpl.csvupload for SMT assembly (parts LCSC can supply)
hand-solder.csvparts LCSC cannot supply (relay8: mains terminals, fuse holders)
rotation-review.csvevery part's CPL rotation and where it came from. None is hardware-verified: compare each part in JLCPCB's placement preview

Also written to boards/<b>/: review.txt (design review, including the inferred net voltages) and lcsc-check.json (part numbers as checked against JLCPCB, with stock and attributes).

Layout

text
lib/schgen.py, ksym.py, netlabel.py   schematic writer (symbols flattened from the KiCad library)
lib/check_netlist.py                  netlist vs expected_nets.json
lib/review.py, review_test.py         design review rules + mutation tests
lib/pcbgen.py, route.py               PCB builder (BoardSpec), freerouting round trip, GND pour
lib/lcsc.py, fab.py, jlc_rotations.json   part-number check, fabrication outputs
lib/field2d.py, field2d_check.py      2-D field solver for trace impedance + validation
boards/<b>/gen/board.py   the circuit (pin -> net table)
boards/<b>/gen/pcb.py     placement (BoardSpec)
boards/<b>/lcsc.json      hand-written LCSC part numbers ("value|footprint" -> part)
boards/<b>/review-waivers.json   accepted review findings, each with a reason
boards/<b>/build.ps1      one-command build
boards/<b>/sim/           ngspice and field-solver studies
tools/      setup-tools.ps1 (downloads are git-ignored)

Want to add a board or a review rule? See CONTRIBUTING.md.

Code comments are in Chinese. The boards were built while comparing AI-assisted workflows in KiCad and EasyEDA Pro.

Limits

These are two-layer boards with modules and simple power. There is no controlled-impedance routing, no length matching, no BGA and no SI/PI analysis; freerouting does none of these (lib/field2d.py can tell you whether a trace needs it). The fabrication files are complete enough to order, but nobody has built these boards yet: CPL rotations are unverified and the design review is a set of rules, not an engineer. Have a person review before ordering. This applies above all to relay8, which switches mains voltage.

License

MIT. freerouting (GPL-3.0) and the Temurin JRE (GPL-2.0 with Classpath Exception) are downloaded at setup time and are not part of this repository.

Parts

243
QtyValueFootprintReferences
70100nFCapacitor_SMD:C_0402_1005MetricC101, C102, C103, C104, C106, C107, C108, C109, C111, C112, C113, C114, C115, C120, C121, C131 +54
1610kResistor_SMD:R_0402_1005MetricR18, R74, R75, R76, R77, R78, R102, R103, R132, R133, R205, R206, R207, R208, R209, R230
1447uFCapacitor_SMD:C_1210_3225MetricC30, C31, C32, C33, C34, C40, C41, C42, C43, C45, C46, C50, C220, C221
71uFCapacitor_SMD:C_0402_1005MetricC48, C105, C117, C135, C147, C210, C213
64.7uFCapacitor_SMD:C_1210_3225MetricC11, C12, C13, C14, C15, C16
6470Resistor_SMD:R_0402_1005MetricR60, R61, R104, R105, R134, R135
54.7uFCapacitor_SMD:C_0603_1608MetricC84, C85, C86, C87, C201
4100kResistor_SMD:R_0402_1005MetricR25, R202, R203, R204
410uFCapacitor_SMD:C_0805_2012MetricC100, C110, C130, C140
427pFCapacitor_SMD:C_0402_1005MetricC118, C119, C148, C149
475Resistor_SMD:R_0603_1608MetricR80, R81, R82, R83
4MountingHole_2.7mm_M2.5MountingHole:MountingHole_2.7mm_M2.5H5, H6, H7, H8
4MountingHole_3.2mm_M3MountingHole:MountingHole_3.2mm_M3H1, H2, H3, H4
312kResistor_SMD:R_0402_1005MetricR101, R131, R210
35.1kResistor_SMD:R_0402_1005MetricR24, R200, R201
3GREENLED_SMD:LED_0805_2012MetricD40, D42, D51
3SM6T68ADiode_SMD:D_SMBD20, D60, D61
3USBLC6-2SC6Package_TO_SOT_SMD:SOT-23-6D70, D71, D72
21.5AFuse:Fuse_1206_3216MetricF40, F41
2100nFCapacitor_SMD:C_0805_2012MetricC92, C93
2100uFCapacitor_SMD:CP_Elec_6.3x7.7C211, C214
21kResistor_SMD:R_0402_1005MetricR50, R51
21nF 2kVCapacitor_SMD:C_1206_3216MetricC90, C91
222pFCapacitor_SMD:C_0402_1005MetricC208, C209
225MHzCrystal:Crystal_SMD_3225-4Pin_3.2x2.5mmY40, Y41
22kResistor_SMD:R_0402_1005MetricR100, R130
23.3uHInductor_SMD:L_1008_2520MetricL40, L41
2AP2171WPackage_TO_SOT_SMD:SOT-23-5U62, U63
2G2423SCM5:Transformer_CNDtek_G2423ST40, T41
2LAN7800/Y9XPackage_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.3x5.3mmU40, U41
2TPD4EUSB30Package_SON:USON-10_2.5x1.0mm_P0.5mmU30, U31
2YELLOWLED_SMD:LED_0805_2012MetricD41, D43
11.5uH IHLP4040Inductor_SMD:L_Vishay_IHLP-4040L20
1100nFCapacitor_SMD:C_0603_1608MetricC17
1100pFCapacitor_SMD:C_0402_1005MetricC44
1100uFCapacitor_THT:CP_Radial_D12.5mm_P5.00mmC10
112.4kResistor_SMD:R_0402_1005MetricR11
1150Resistor_SMD:R_0402_1005MetricR17
1150pFCapacitor_SMD:C_0402_1005MetricC23
115pFCapacitor_SMD:C_0402_1005MetricC19
11MResistor_SMD:R_0402_1005MetricR211
11uFCapacitor_SMD:C_1206_3216MetricC82
12.2uFCapacitor_SMD:C_0603_1608MetricC20
120kResistor_SMD:R_0402_1005MetricR22
123.2kResistor_SMD:R_0402_1005MetricR14
124MHzCrystal:Crystal_SMD_2520-4Pin_2.5x2.0mmY60
13.3uH SPM10065VTInductor_SMD:L_Bourns_SRP1050WAL10
133.2kResistor_SMD:R_0402_1005MetricR12
1330kResistor_SMD:R_0402_1005MetricR23
14.42kResistor_SMD:R_0402_1005MetricR15
1402kResistor_SMD:R_0805_2012MetricR10
1412Resistor_SMD:R_0805_2012MetricR13
147nFCapacitor_SMD:C_0402_1005MetricC18
147uFCapacitor_SMD:CP_Elec_10x10C83
14A 63VFuse:Fuse_1206_3216MetricF1
154V INTerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-2-5.08_1x02_P5.08mm_HorizontalJ20
16.8nFCapacitor_SMD:C_0402_1005MetricC22
17.5kResistor_SMD:R_0402_1005MetricR16
1820pFCapacitor_SMD:C_0402_1005MetricC24
191kResistor_SMD:R_0402_1005MetricR21
1BSC070N10NS5Package_TO_SOT_SMD:TDSON-8-1Q11
1BSC160N10NS3GPackage_TO_SOT_SMD:TDSON-8-1Q10
1CM5 pins 1-100CM5:Amphenol_10164227-1001A1RLF_2x50_P0.4mmJ1
1CM5 pins 101-200CM5:Amphenol_10164227-1001A1RLF_2x50_P0.4mmJ2
1CR2032Battery:BatteryHolder_Keystone_3034_1x20mmBT50
1FANConnector_JST:JST_SH_SM04B-SRSS-TB_1x04-1MP_P1.00mm_HorizontalJ81
1FLASH/RUNButton_Switch_SMD:SW_SPDT_PCM12SW51
1FSUSB42MUXPackage_SO:MSOP-10_3x3mm_P0.5mmU60
1GPIO 40-pinConnector_PinHeader_2.54mm:PinHeader_2x20_P2.54mm_VerticalJ80
1HDMIConnector_Video:HDMI_A_Molex_208658-1001_HorizontalJ70
1HR911130ACM5:RJ45_Hanrun_HR911130A_HorizontalJ30
1IP804ARPackage_DFN_QFN:QFN-48-1EP_7x7mm_P0.5mm_EP5.3x5.3mmU50
1LM5146RGYRPackage_DFN_QFN:Texas_RGY_R-PVQFN-N20_EP2.05x3.05mmU10
1M.2 M-keyCM5:M.2_Socket_M_TE_1-2199230-6J60
1POE0Connector_RJ:RJ45_Amphenol_RJHSE5380J40
1POE1Connector_RJ:RJ45_Amphenol_RJHSE5380J41
1POWERButton_Switch_SMD:SW_Push_1P1T_NO_CK_KMR2SW50
1REDLED_SMD:LED_0805_2012MetricD50
1TPS2051CDBVPackage_TO_SOT_SMD:SOT-23-5U70
1TPS568230RJERPackage_DFN_QFN:Texas_RJE0020A_VQFN-20-1EP_3x3mm_P0.45mm_EP0.675x0.76mmU20

The 239 most common of 243 parts.

More from YORROY123/kicad-scripted-pcb

3
  • 2 layers232 × 110 mmRelay8, the printed circuit board in 3D

    Relay8

    YORROY123/kicad-scripted-pcb

    Three KiCad 10 PCBs designed entirely as Python code with layered verification

    65 parts1MIT
  • 2 layers32 × 49 mmEsp32c3, the printed circuit board in 3D

    Esp32c3

    YORROY123/kicad-scripted-pcb

    Three KiCad 10 PCBs designed entirely as Python code with layered verification

    26 parts1MIT
  • 2 layers40 × 24 mmUsbc ldo, the printed circuit board in 3D

    Usbc ldo

    YORROY123/kicad-scripted-pcb

    Three KiCad 10 PCBs designed entirely as Python code with layered verification

    16 parts1MIT

Similar boards

  • 4 layers160 × 100 mmSmu main, the printed circuit board in 3D

    Smu main

    PaulBichl/vibepcb-smu

    VibePCB example: 4-quadrant SMU (+-30 V / +-1 A, USB-C PD, Ethernet) designed with an LLM

    244 parts1
  • 13 layers46.3 × 44.2 mmPower, the printed circuit board in 3D

    Power

    murexrobotics/electrical

    Highly integrated electronics design and printed circuit boards (PCBs) for the MATE ROV Competition. Attempt the impossible.

    82 parts192MIT
  • 10 layers90 × 60 mmZebra X, the printed circuit board in 3D

    Zebra X

    Dylanfg123/Zebra-X

    A Xilinx Zynq Demo Board based on Phil's Lab ZettBrett board

    424 parts
  • 2 layers50.3 × 54 mmJK BMS CAN, the printed circuit board in 3D

    JK BMS CAN

    dremeier/Arduino-JK-BMS-To-Pylontech-CAN-PCB

    PCB and Case for the Arduino JK-BMS To Pylontech CAN converter

    66 parts9
  • 4 layers70 × 110 mmNixon phone, the printed circuit board in 3D

    Nixon phone

    rrruark/nixon_phone

    Analog Telephone Adapter Audio Player

    117 partsMIT
  • 2 layers175 × 105 mmKsz9563 lan7800 switch, the printed circuit board in 3D

    Ksz9563 lan7800 switch

    flannellab/AI_Design_Generation

    Collection of things for AI generation of PCB designs (Components, Schematics, PCBs, Docs)

    48 parts
  • 4 layers82.7 × 32.1 mmUsbToGB Adapter, the printed circuit board in 3D

    UsbToGB Adapter

    izzeldeenakloub/Gigabit-Ethernet-to-USB-C-Adapter

    A KiCad design project for a USB-C to Gigabit Ethernet adapter and my first complete 4-layer PCB layout.

    84 parts

Questions

How big is the Cm5 PCB?

It measures 170 × 120 mm and has 4 copper layers, 1.6 mm thick.

What parts does the Cm5 use?

243 parts, built around the IP804AR, LAN7800/Y9X, TPS568230RJER and AP2171WG. 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 Cm5 KiCad files?

From the YORROY123/kicad-scripted-pcb repository on GitHub, at the commit this page was made from: the board is boards/cm5/cm5.kicad_pcb and its schematic boards/cm5/cm5.kicad_sch. PCBKit opens the board in the browser, with nothing to install.

Can I use the Cm5 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).