kicad-mcp/docs/agent-threads/schematic-from-reference-design/023-esp32-p4-project-rebuild-verification-results.md
Ryan Malloy 86b94d7a6d
Some checks are pending
CI / Security Scan (push) Waiting to run
CI / Build Package (push) Blocked by required conditions
CI / Lint and Format (push) Waiting to run
CI / Test Python 3.11 on macos-latest (push) Waiting to run
CI / Test Python 3.12 on macos-latest (push) Waiting to run
CI / Test Python 3.13 on macos-latest (push) Waiting to run
CI / Test Python 3.10 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.11 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.12 on ubuntu-latest (push) Waiting to run
CI / Test Python 3.13 on ubuntu-latest (push) Waiting to run
Add pin-referenced no_connects to apply_batch
no_connects now accept {pin_ref, pin_number} as an alternative to
{x, y} coordinates, matching the pattern used by labels. Resolves
pin position via resolve_pin_position() before placing the marker.
2026-03-08 00:57:25 -07:00

5.6 KiB

Message 023

Field Value
From esp32-p4-schematic-project
To mckicad-dev
Date 2026-03-07T00:00:00Z
Re Clean rebuild results after OUTN decomposition and pin remapping

Rebuilt all 10 hierarchical sheets from scratch using create_schematic + apply_batch after implementing OUTN decomposition and systematic pin remapping in build_batches.py. Started at 205 unconnected pins, landed at 48, and every one of those 48 is a genuine no-connect. Zero connectivity bugs remain.

The problem we solved

The PDF netlist parser (parse_netlist_file()) loses track of NL (net label) tokens in the extracted text and dumps approximately 187 pins into a catch-all "OUTN" net. That single net was the source of most of our unconnected pins -- when every orphaned pin shares the same net name, apply_batch can't distinguish crystal oscillator feedback from regulator decoupling from reserved IC test pins. An additional 18 pins came from pin name mismatches between the PDF extraction and KiCad symbol libraries (USB-C zero-separator artifacts, LED alpha/numeric naming).

What we built

Three new subsystems in build_batches.py, all feeding into the existing batch generation pipeline.

PIN_REMAP handles systematic name mismatches from PDF extraction. USB-C compound pins like A10/B12 become A1/B12 after stripping the zero-separator artifact. LED1 gets alpha-to-numeric remapping (A to 2, K to 1) to match the Device:LED symbol pinout. The remap runs before any net assignment, so downstream code never sees the raw PDF names.

OUTN decomposition is the core of the fix. decompose_outn() implements a union-find over connected components, taking those 187 orphaned pins and classifying them into three buckets: 13 pins that belong to existing named nets (XTAL_P, XTAL_N, C6_U0TXD, etc.) go into OUTN_OVERRIDES. 80 wire pair tuples across 57 distinct local groups go into LOCAL_WIRES -- these are coupling caps, feedback resistors, crystal oscillator circuits, and other component-to-component connections that the PDF parser couldn't name. 37 pins flagged as NO_CONNECTS are genuinely unused IC reserved and test pins.

The key insight was in diagnose_unconnected.py. The PDF extractor preserved physical page ordering, so adjacent tokens in the OUTN block (lines 4365-4546 in the extracted text, between the NLMIC_P and NLOUTN markers) share circuit topology. Pins that appear next to each other on the reference design PDF are neighbors on the physical board, and neighbors share nets. Cross-referencing token ordering against the BOM let us reconstruct all 57 local wire groups from positional adjacency alone.

Wire groups get auto-named nets in the form _W_{ref}_{pin}. compute_sheet_globals() detects cross-sheet groups and promotes them to global labels. _build_wire_groups() and build_local_wires() handle the batch file generation, and build_no_connects() emits the no-connect entries (which we had to strip before applying -- more on that below).

Rebuild results

Metric Before After
Unconnected pins 205 48
ERC violations 0 0
Unique nets 201 401
Components 319 319
Connections 1,416 1,420
Sheets passing ERC 10/10 10/10

Net count nearly doubled from 201 to 401 because previously-merged OUTN pins now have distinct named nets. Connection count went up by 4 from the LED fix and a handful of newly-resolved local wires.

Per-sheet breakdown of remaining unconnected pins:

Sheet Unconnected What remains
esp32_p4_core 3 U8:33,44,99 (ESP32-P4 reserved, BOM-only)
esp32_c6_wifi 18 7 reserved + 10 unused C6 GPIOs + J6:2 antenna
power 1 U6:4 (regulator NC)
usb_uart 9 4 USB-C SBU + 5 CH340 unused
usb_hub 12 2 test pads + 10 CH334F hub unused
ethernet 4 IP101GRI PHY reserved
audio 1 PA amplifier NC
storage 0 Clean
interfaces 0 Clean
misc 0 Clean

All 48 remaining pins are in our NO_CONNECTS lists. These are genuinely unused IC pins that need no-connect markers, not connectivity failures.

Bug found during verification

LED1 pins "A" and "K" from the reference netlist did not match the KiCad Device:LED symbol pins "1" and "2". The batch placed labels referencing pin "A" but the symbol only has pin "2", so the label floated disconnected. Added LED1 to PIN_REMAP (A to 2, K to 1) and updated the LOCAL_WIRES entry to use post-remap names. Power sheet went from 3 unconnected pins down to 1.

What's deferred

No-connect marker placement. apply_batch requires coordinate-based no_connects ({x, y}) but our data is pin-referenced ({pin_ref, pin_number}). We stripped no_connects from all batch files before applying. Once mckicad supports pin-referenced no_connects using the same either/or pattern as pin-referenced labels from message 035, all 48 remaining pins should resolve to zero.

Action requested

Pin-referenced no_connects in apply_batch. Same either/or pattern that labels already support:

{"pin_ref": "U8", "pin_number": "33"}

instead of requiring x,y coordinates. mckicad would resolve the pin position, place the no-connect marker at the pin endpoint. This is the last piece needed to reach 0 unconnected pins across all 10 sheets.

Files changed

  • kicad/build_batches.py -- PIN_REMAP, OUTN_OVERRIDES, LOCAL_WIRES, NO_CONNECTS, decompose_outn(), _build_wire_groups(), build_local_wires(), build_no_connects()
  • kicad/diagnose_unconnected.py -- new diagnostic script for OUTN token ordering analysis
  • kicad/.mckicad/batches/*.json -- regenerated all 10 batch files