| name | ltspice-to-kicad-workflow |
| description | Use when taking a power-supply or analog-circuit idea all the way from LTspice simulation to a verifiable KiCad project (schematic + PCB + footprints + ERC/DRC). Covers ADI/LTC µModule demo-board adaptation, ASC → KiCad conversion, BGA functional-pad footprints, 4-layer stackup conversion, input protection hardening, datasheet-driven pin verification, kicad-cli-driven verification, and the structural ASC ↔ KiCad netlist cross-check. Companion to any project-specific LTspice skill — use that one for simulation, this one for everything between sim and a clean DRC pass. Out of scope: gerber generation as an acceptance artifact, certification/compliance, mechanical/thermal proof, custom IC design. |
LTspice → KiCad Workflow
End-to-end recipe for going from a circuit idea through LTspice validation
to a KiCad project that loads cleanly, passes ERC and DRC under kicad-cli,
and is honest about what is verified vs. inferred. Distilled from a 48V →
5V → 1V/10A two-stage µModule design (LTM8064 + LTM4658) and the bugs
that surfaced along the way.
When to use this skill
Trigger this skill when the user:
- Has an LTspice
.asc (or wants to create one) for an analog / power
circuit and intends to fabricate a board.
- Asks to generate, fix, or review a KiCad project derived from an LTspice
schematic.
- Asks to harden a prototype-review board for production: cap derating,
input protection, layer-count upgrade, real footprints.
- Wants to verify a KiCad project against the source
.asc topology.
- Hits "Failed to load board" or DRC violations on a hand-edited
.kicad_pcb.
If the user is only doing simulation work (no PCB), hand off to whatever
LTspice-only skill they already have. If they want gerbers, certification,
or thermal/mechanical analysis, those are out of scope.
High-level flow
1. Idea / specs → V_in, V_out, I_load, transient targets
2. Part selection → ADI / LTC µModule catalog, demo-board match
3. LTspice schematic → copy demo values; add load; .tran startup
4. Sim validation → vbus_avg, vcore_avg, iload_avg within tol
5. KiCad generation → symbols, footprints, sch, pcb, netlist
6. Hardening pass → cap V ratings, input protection, layer count,
real footprints
7. kicad-cli verification → erc, drc (--refill-zones --save-board),
jumper-strip drc gate, netlist re-export
8. Structural cross-check → netlist_comparison.py (ASC ↔ KiCad nets)
9. Document deferred work → README + drc.rpt / erc.rpt match reality
Each stage below lists the artefacts to produce, the gotchas to avoid,
and the verification check that gates moving to the next stage.
Stage 1 — Specs
Pin down before touching tools:
- Input voltage range and worst-case transient
- Output voltage(s) and per-rail load current
- Switching frequency target (sets external R_T values)
- Protection envelope (fuse rating, max V on TVS, expected ESD class)
- Layer count and copper weight constraints (cost vs. current density)
For high-current rails write down the load resistance you'll simulate
with (V_out / I_load, e.g. 1V / 10A = 0.1 Ω) — this is the Rload that
must be deleted from the PCB later.
Stage 2 — Part selection
For ADI/LTC µModules:
- Match the demo board (e.g. DC2237A for LTM8064 5V output, DC2861A
for LTM4658) — copy its component values verbatim into the ASC. The
feedback resistor formulas vary by part; the demo's RFB / RT values
encode the right answer and the LTspice model agrees.
- Note the package: BGA-25 / BGA-108 / LGA / etc. and the ball pitch.
Used in Stage 5 footprint work.
Stage 3 — LTspice schematic
Conventions that pay off downstream:
Stage 4 — Sim validation
Two passes:
- Smoke —
.tran 1m startup, just confirm convergence and no
model errors.
- Steady-state — extend to 2.5m, measurement window 2m–2.5m so the
averages reflect settled operation. Compare
vbus_avg, vcore_avg,
iload_avg against spec; ±2% is typical.
Save the validation .asc separately (don't overwrite the source) so
the "this design simulates to spec" evidence is traceable.
Stage 5 — KiCad generation
The artefacts you need:
*.kicad_pro, *.kicad_sch, *.kicad_pcb (project, schematic, board)
<lib>.kicad_sym with symbol definitions for each unique part
<lib>.pretty/<footprint>.kicad_mod for any custom footprints (the
µModule BGAs typically)
sym-lib-table, fp-lib-table listing the local libs + any KiCad
standard libs the project uses (Capacitor_SMD, Resistor_SMD,
Diode_SMD, Fuse, TestPoint, TerminalBlock_Phoenix)
Decisions to make up front:
- Pad numbering for BGAs. Two schemes, with a hard boundary between
them:
- Function-named pads. Pad number is "VIN" / "GND" / "VOUT" / etc.,
so the schematic symbol can use the same names as pin numbers and
net-mapping is automatic. Requires
duplicate_pad_numbers_are_jumpers yes
on the footprint. Review-grade only — the result is NOT fabricable.
The jumper flag asserts the component itself bridges same-numbered
pads, so DRC passes with no physical copper between them (the rev A
reference board hid 94 unconnected pads this way — every GND return,
the 10A output, both feedback balls). The Stage 7 jumper-strip gate
exposes this.
- Ball-numbered pads. Pad number is "A1" / "M9" / etc. — one pad per
ball, real fanout, no jumper flags. Required for production. The
working pattern (from the rev B reference board):
- Symbol: one visible pin per function, plus hidden passive
duplicates stacked at the same coordinates — every ball gets its
net assignment while wires stay attached to the single visible pin.
- BGA power/ground: strap mesh across same-net ball clusters plus
dogbone vias into the inner planes (the GND via field doubles as
the thermal path).
- Fine-pitch interior balls (e.g. 0.65 mm): escape between balls
with 0.12 mm track / 0.1 mm clearance rules — confirm the fab can
hold them before ordering.
- Where the F.Cu fill would split into islands, add explicit B.Cu
bridges. KiCad's DRC does not credit "the inner plane will carry
it" unless the connecting copper is actually drawn and stitched.
Start with scheme 2 unless the board is explicitly a throwaway review;
converting 1 → 2 later is a full footprint + symbol + fanout rebuild,
not an edit (the rev A → rev B transition was a scripted rebuild).
- Layer count. 2-layer is fine for low-power. For ≥5 A rails on a
small board, default to 4-layer (signal / GND / power / signal). The
hardening pass converts 2 → 4 if needed.
Stage 6 — Hardening pass (the part most generators skip)
Six checks. Walk them every time.
6a. Cap voltage ratings
Aim for ≥2× the DC working voltage on MLCC, more if you care about
de-rating under DC bias. Bulk caps need transient margin too.
Common mistakes inherited from demo boards:
- 6.3V cap on a 5V rail → bump to 16V.
- 100V cap on 48V → marginal; add a 100V/22µF aluminum-polymer bulk.
6b. Remove sim-only parts
Rload (the load resistor) must come out of:
- the KiCad schematic instance
- the PCB footprint instance and any routes that only go to it
- the static
schematic.net export
Keep it in the ASC if you want re-runnable simulation evidence.
6c. Input protection
For 48V inputs add (at minimum):
| Part | Footprint | Net wiring |
|---|
| F1 | Fuse:Fuse_1206_3216Metric | series J1 → F1 → IN48 |
| D1 | Diode_SMD:D_SMB (SMBJ58A) | K=IN48, A=GND |
| C8 | Capacitor_SMD:CP_Elec_10x10 | + = IN48, − = GND, 22µF/100V |
A new net IN48_RAW sits between J1 and F1; everything else stays on
IN48. Update the symbol library if you didn't have a Fuse or D_TVS
symbol — examples in references/protection_symbols.kicad_sym.
6d. Layer-stack conversion (2 → 4)
In the PCB (layers …) block, add inner layers between F.Cu and B.Cu.
Use this exact form (signal type, IDs in the free even-number range):
(layers
(0 "F.Cu" signal)
(4 "In1.Cu" signal)
(6 "In2.Cu" signal)
(2 "B.Cu" signal)
; … user layers unchanged
)
Do not use power as the layer type — KiCad 10's PCB loader rejects
it with a generic "Failed to load board" error.
For each via, the (layers …) field is start-layer end-layer, NOT a
list of every layer touched. A through-via stays (layers "F.Cu" "B.Cu")
even on a 4-layer board; the copper rings on inner layers are implicit.
Writing (layers "F.Cu" "In1.Cu" "In2.Cu" "B.Cu") makes the file
unloadable.
Add these zones (declare polygons, skip (filled_polygon …) — let
kicad-cli pcb drc --refill-zones --save-board compute them):
In1.Cu / GND / full-board rectangle
In2.Cu / GND / full-board rectangle (priority 0 — gets overridden by
power islands)
In2.Cu / IN48 / island enclosing input components, priority 1
In2.Cu / BUS5 / island enclosing stage 1 output, priority 2
In2.Cu / OUT1V / island enclosing stage 2 output, priority 3
6e. Real BGA land patterns
Replace any "functional pads" / "review" footprint with the
datasheet-accurate one:
- Ball pitch and body size exactly per ADI datasheet.
- Pad diameter: NSMD, 75–80% of ball diameter (e.g. 0.30 mm for the
0.40 mm balls of an LTM4658, 0.60 mm for the ~0.75 mm balls of an
LTM8064).
- Annotate ball positions (A1, B2, … M9) on F.Fab so reviewers can
cross-check the datasheet.
- Retain perimeter SMD "fan-out" rectangles if the original
footprint had them. They are not visual review aids — they are
bridging copper that PCB routes terminate on, and
duplicate_pad_ numbers_are_jumpers merges them with the same-name balls. Removing
them silently breaks ~17 same-net connections per part.
- Verify the GND fill convention by web-sampling at least one ball per
bank against the datasheet pin table.
6f. Schematic & PCB consistency
If you renamed a net (e.g. IN48 → IN48_RAW for the section ahead of the
fuse), update all four places:
- the schematic label (
label "IN48_RAW" on the J1-side wire)
- the PCB pad
(net "…") field on J1.1
- the netlist export (
schematic.net)
- the validation script's expected-net table
Stage 7 — kicad-cli verification
This is the difference between "looks right" and "actually loads".
$cli = 'C:\Program Files\KiCad\10.0\bin\kicad-cli.exe'
$proj = '<path to project>'
# Hard checks
& $cli sch erc --severity-error --output "$proj\erc.rpt" "$proj\*.kicad_sch"
& $cli pcb drc --refill-zones --save-board --severity-error `
--output "$proj\drc.rpt" "$proj\*.kicad_pcb"
# Regenerate the netlist
& $cli sch export netlist --output "$proj\schematic.net" "$proj\*.kicad_sch"
# Optional: broader inspection
& $cli pcb drc --schematic-parity --severity-all `
--output "$proj\drc_full.rpt" "$proj\*.kicad_pcb"
Expectation after the hardening pass: 0 ERC errors, 0 DRC errors,
0 unconnected pads — and 0 unconnected items in the jumper-strip run
below, if it applies. Schematic-parity warnings about stale Value /
ASC_REF strings on inline PCB footprints are cosmetic; the user can
clear them with Tools → Update PCB from Schematic in the GUI. Treat
net_conflict parity warnings as real until each one is individually
read — they can hide pad-number swaps (see pitfalls table).
Jumper-strip gate (mandatory if any footprint uses duplicate_pad_numbers_are_jumpers)
Normal DRC is blind to missing copper on these footprints: the jumper
flag asserts the component bridges same-numbered pads even when the
"bridge" pads lie outside the package body. Test the physical copper by
stripping the flag from a copy of the board:
$strip = "$proj\drc_strip_check.kicad_pcb"
$text = Get-Content "$proj\<project>.kicad_pcb" -Raw
$text = $text -replace '(?m)^[ \t]*\(duplicate_pad_numbers_are_jumpers yes\)[ \t]*\r?\n', ''
# UTF-8 WITHOUT BOM — Set-Content writes a BOM and KiCad then fails
# with "Failed to load board"
[System.IO.File]::WriteAllText($strip, $text, [System.Text.UTF8Encoding]::new($false))
& $cli pcb drc --refill-zones --output "$proj\drc_strip.rpt" $strip
Remove-Item $strip # or it gets swept up by later *.kicad_pcb wildcards
The unconnected-items count in drc_strip.rpt is the physical-copper
truth. The rev A reference board passed normal DRC clean and showed
94 unconnected pads here (all GND returns, the 10A output, both
feedback balls). Anything non-zero means the board relies on virtual
bridging and is not fabricable — go back to Stage 5 and build scheme 2
footprints. On a scheme-2 board the flag doesn't exist and this gate is
a no-op.
If pcb drc fails with "Failed to load board" and no line number,
work backward through the recent edits — most often the via (layers …)
mistake from 6d, or a layer type other than signal / user. Bisect
by reverting commits or by progressively removing recent additions.
Stage 8 — Structural cross-check (ASC ↔ KiCad)
Behavioral sim says "the values work." Structural check says "the KiCad
net topology matches the ASC." Both are needed because either can
silently break without the other noticing.
validation/netlist_comparison.py (template in
references/netlist_comparison.py):
- Parses ASC
SYMATTR InstName lines to enumerate the ASC's components.
- Parses the KiCad-exported
schematic.net for component refs and net
membership.
- Uses a hardcoded
EXPECTED_ASC_TO_KICAD map (ASC name → KiCad ref) and
EXPECTED_NETS table (key nets → expected member refs) to do the
comparison.
- Tolerates a
KICAD_ONLY_REFS set for KiCad-only additions (J1
replacing V1, J2/J3 monitors, TP1–TP9, F1/D1/C8 protection).
Do not try to parse LTspice net connectivity geometrically — the
ASC format requires symbol library pin offsets that aren't reliably
shipped with the project. The hardcoded expected-net table is the
honest approach.
Stage 9 — Document deferred work
If something can't be auto-checked here, write it down. README sections
that pay off:
- Verification log — exact
kicad-cli invocations, the numerical
results, and the date / KiCad version.
- Important limitations — what's verified vs. inferred (e.g.
"67 GND-by-convention balls sampled across 9 of 12 banks").
- Remaining work — what the user must do in the GUI before fab
(typically: Update PCB from Schematic for parity hints, then cross-
check footprints against the latest ADI mechanical drawing for the
ordering code).
Common pitfalls & fixes
| Symptom | Cause | Fix |
|---|
kicad-cli pcb drc → "Failed to load board" | Via (layers …) lists all 4 layers instead of start/end | Revert to (layers "F.Cu" "B.Cu") for through-vias |
| Same error after layer-type change | Used power or mixed instead of signal / user in (layers …) | Use only signal or user |
| 17+ unconnected pads after BGA footprint "cleanup" | Removed perimeter fan-out rectangles | Restore them; they're bridging copper, not visual decor |
| DRC reports clearance violations on existing pads after refill | Stale filled_polygon from before the recent additions | Run pcb drc --refill-zones --save-board once |
| "Via dangling" warnings on new vias inside an inner-layer zone | Zone fill hasn't anchored to the via | Cosmetic; F.Cu zone of same net provides the load-bearing path |
| 259 schematic-parity warnings on Value / ASC_REF mismatches | PCB inline footprint properties stale vs. schematic | Tools → Update PCB from Schematic in the GUI |
Netlist comparison flags IN48_RAW missing | Forgot to update one of: schematic label, PCB pad net, schematic.net, expected-table | Update all four |
ERC reports 100+ endpoint_off_grid warnings | Generator emitted pins on a non-100mil grid | Filter with --severity-error; the warnings are cosmetic |
Schematic-parity net_conflict warnings dismissed as net-name noise | Real pad-number swaps buried in the noise (rev A: J1/J2/J3 power and GND pads swapped vs. schematic pins, under 199 net-name-prefix warnings) | Sync net-name forms (/NET vs NET) first, then re-read every remaining net_conflict individually |
Folder layout
project_root/
├─ <project>.kicad_pro
├─ <project>.kicad_sch
├─ <project>.kicad_pcb
├─ <project>.kicad_prl
├─ <lib>.kicad_sym
├─ <lib>.pretty/
│ ├─ <bga1>.kicad_mod
│ └─ <bga2>.kicad_mod
├─ sym-lib-table
├─ fp-lib-table
├─ schematic.net ; KiCad-exported, do not hand-edit if possible
├─ erc.rpt ; from kicad-cli sch erc --severity-error
├─ drc.rpt ; from kicad-cli pcb drc --refill-zones --save-board
├─ README.md ; verification log, limitations, deferred work
└─ validation/
├─ <project>_validation.asc ; extended .tran for measurements
├─ ltspice_validation_summary.md ; sim numbers + cross-check approach
└─ netlist_comparison.py ; ASC ↔ KiCad structural diff
References
references/netlist_comparison.py — template for stage 8
references/protection_symbols.kicad_sym — Fuse + D_TVS symbol snippets
references/four_layer_zones.kicad_pcb_snippet — In1.Cu / In2.Cu zone declarations
- ADI demo board manuals (DC22…, DC28…) carry the canonical RFB / RT values
- KiCad 10.0 documentation for the
kicad-cli subcommand surface
What to hand back
When this skill finishes, the user should have:
- A KiCad project that loads cleanly under
kicad-cli.
erc.rpt and drc.rpt documenting 0 errors and 0 unconnected pads
(plus drc_strip.rpt if any footprint carries the jumper flag).
- A
validation/ directory whose Python script passes against the
project's own ASC.
- A README that names every revision and the date / KiCad version that
verified it.