Files
rpicarrierboard/PORT_STATUS.md
noise 1d169476fb Strip PCIe-M2 (M-key/NVMe) sheet; re-baseline stripped carrier
Drops the unused M.2 M-key/NVMe block — design is 1x M.2 E-key (Wi-Fi)
only, since the CM5 exposes a single PCIe x1 lane (datasheet SC1466),
reserved for the E-key. The 10 freed PCIE_* lanes are NC on Module1
unit 2, to be rewired to a fresh E-key sheet in the add phase.

- CM5_HighSpeed: retire PCIE_* labels/wires, NC pins 102,104,106,109,
  110,112,116,118,122,124
- root CM5IO: drop whole PCIe-M2 (sheet) block; strip dangling PCIE_*
  pins off the kept CM5_HighSpeed sheet symbol
- delete carrier/PCIe-M2.kicad_sch; clean .kicad_pro sheets array + ERC
  exclusion
- retire_block.py: add --drop-sheet FILE (remove whole (sheet) block +
  sheet_instances path)
- analysis/baseline/carrier_stripped.json: new add-phase diff anchor

Verify: ERC 136->133 (zero new violation types); analyzer diff +0/~0
(cumulative -41 removed vs original ref); netlist confirms +5v/+3.3v/
GND/+1.8v intact (U8's M2_3v3 was a local rail, not board +3.3v).

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 11:27:41 -04:00

7.0 KiB
Raw Blame History

CM5 Carrier Port — Status & Handoff

Handoff doc for whoever (human or LLM) continues this work. Read this first, then .claude/skills/kicad-port/SKILL.md (the mandatory workflow/verify-loop), then CM5_Carrier_Design.md (frozen rev-A spec).

What this repo is

Two intertwined goals:

  1. Improve Claude's EDA tooling — the kicad-happy skill suite (kicad, datasheets, spice, …), wired in as Claude Code skills via ~/.claude/skills/{kicad,datasheets,spice} -> kicad-happy/skills/* symlinks. The toolkit clones (kicad-happy/, kicad-claude-toolkit/, MCP-KiCad/) are gitignored — re-clone if missing.
  2. Port the Raspberry Pi CM5IO reference into a custom CM5 carrier board — the real test bed (PTP/timing instrumentation node: 15V→5V front end, GbE magjack, M.2 E-key Wi-Fi (AW7915/MT7915), 2×USB-A, USB-C programming, RTC, GPS-PPS distribution).

Method is diff-from-reference: refs/ holds the untouched CM5IO reference; carrier/ is the working copy. Every edit is verified against analysis/baseline/cm5io.json.

Environment / tooling state (macOS, Homebrew)

  • kicad-cli (/opt/homebrew/bin/kicad-cli) — ERC + netlist export
  • poppler (pdftotext) — datasheet page selection
  • ngspice spice skill; full verify loop validated on the reference (8 subcircuits pass)
  • Python ≥3.10 (Homebrew 3.14)

The verify loop (run after EVERY schematic edit)

SCH=carrier/CM5IO.kicad_sch ; KSCR=~/.claude/skills/kicad/scripts
kicad-cli sch erc --exit-code-violations --format json -o /tmp/erc.json "$SCH"   # hard gate
python3 $KSCR/analyze_schematic.py "$SCH" -o /tmp/head.json                       # structural
python3 $KSCR/diff_analysis.py analysis/baseline/cm5io.json /tmp/head.json --text # vs baseline
  • Track the ERC DELTA, not the absolute — the reference already has 182 pre-existing violations (mostly unconnected_wire_endpoint). A good edit introduces zero new types.
  • The analyzer diff is the semantic gate (names broken design intent); ERC is the hygiene gate.
  • For kept-block integrity, also diff kicad-cli sch export netlist before/after — it caught a mis-inventoried part (see R8 below).

Datasheet extraction (done)

CM5 module extracted to datasheets/extracted/SC1466_43a9ec.json (200 pins, score 8.7/10, queryable via ~/.claude/skills/datasheets/scripts/datasheet_features.py). Drove the NC pin lists for every strip (e.g. HDMI Module1 pins = all pins whose datasheet name starts HDMI).

The strip tool: tools/retire_block.py

General block-retirement for these s-expr sheets. Capabilities:

  • excise symbols by Reference; retire nets by name-glob (all label types: local / hierarchical / global)
  • anchor-aware wire removal (union-find): removes a wire only if its connected component reaches no kept anchor (kept non-power pin or kept label) AND is seeded by this edit — so shared nets survive and pre-existing dangles are untouched
  • place (no_connect) on exposed Module1 pins (pin coords via a validated transform abs=(px+rot(lx,ly).x, py-rot(lx,ly).y), rot0/no-mirror; refuses other orientations)
  • clean orphaned power flags, dangling NCs, orphaned labels
  • --sheet-ports NAME,... removes root-sheet hierarchical pins + connecting wires

Usage: python3 tools/retire_block.py <sheet> --symbols J7,U18 --nets 'SD_*' --nc-pins 57,61 [--sheet-ports ...] [--apply] (dry-run without --apply).

Known gap (next improvement): does NOT auto-prune orphaned power-label/wire stubs left after a connector is removed (e.g. leftover +3.3v/HDMI_5v labels). Those were cleaned manually — see git history.

Strip phase — DONE (microSD + HDMI + MIPI + PCIe-M2), ERC 182 → 133, 0 new violations, 0 regressions

Block Sheet(s) Command(s) (run with --apply)
microSD CM5_GPIO --symbols J7,U18,C5 --nets 'SD_*' --nc-pins 57,61,62,63,67,69,75
HDMI CM5_HighSpeed --symbols J22,J10 --nets 'HDMI0_*,HDMI1_*,HDMI_5v' --nc-pins 143,145,146,147,148,149,151,152,153,154,158,160,164,166,170,172,176,178,182,184,188,190,199,200
MIPI/camera CM5_HighSpeed, CM5_GPIO, CM5IO(root) (1) HighSpeed --symbols J5,J16 --nets 'DPHY0_*,DPHY1_*,SCL1,SDA1' --nc-pins 115,117,121,123,127,129,133,135,139,141,175,177,181,183,187,189,193,194,195,196 (2) GPIO --nc-pins 80,82,97,100 (3) root --sheet-ports SCL0,SDA0,CAM_GPIO0,CAM_GPIO1 (4) HighSpeed --symbols R8 --nets 'SCL0,SDA0' (5) manual: remove 3 orphaned +3.3v labels + 2 wire stubs
PCIe-M2 (M-key/NVMe) CM5_HighSpeed, CM5IO(root), .kicad_pro (1) HighSpeed --nets 'PCIE_*' --nc-pins 102,104,106,109,110,112,116,118,122,124 (2) root --drop-sheet PCIe-M2.kicad_sch (3) root --sheet-ports PCIE_CLK_P,PCIE_CLK_N,PCIE_TX_P,PCIE_TX_N,PCIE_nRST,PCIE_RX_P,PCIE_RX_N,PCIE_nCLKREQ,PCIE_PWR_EN,PCIE_nWAKE (strip dangling HighSpeed sheet-symbol pins) (4) git rm carrier/PCIe-M2.kicad_sch (5) manual: remove PCIe-M2 entry from .kicad_pro sheets array + its ERC exclusion. Design confirmed: 1× M.2 E-key (Wi-Fi) only, 0× M-key SSD — the single CM5 PCIe ×1 lane is reserved for the E-key; the freed PCIE_* lanes (now NC on Module1 unit 2) will be rewired to the fresh E-key sheet in the add phase.

retire_block.py gained --drop-sheet FILE: removes the whole (sheet …) block by Sheetfile + its sheet_instances path (run on the parent sheet). .kicad_pro sheets-array + ERC-exclusion cleanup is still manual (next tool gap).

Notes that bit us (don't re-learn the hard way):

  • MIPI lanes are labeled DPHY0_*/DPHY1_*, NOT MIPI*. The connectors J5/J16 are camera FFCs bundling DPHY + cross-sheet I2C0 (SCL0/SDA0) + CAM_GPIO0/1 — a 3-sheet hierarchical block.
  • R8 is a camera pull-up, not USB (the Explore-agent inventory was wrong). Confirmed via kicad-cli sch export netlist (R8.2 → J16.17). Always verify inventory against the netlist.
  • SCL0/SDA0 (I2C0) are camera-only 2-node nets (netlist-proven). NC'd to reserve I2C0 for a future external I2C RTC (CM5's own RTC is on-module via VBAT). If you add an external RTC, wire it here.

Next steps

  1. Drop the PCIe-M2 sheet entirely DONE (see strip table). Confirmed E-key-only (no M-key SSD).
  2. Re-baseline: capture a new analyzer baseline of carrier/ so the add phase diffs against the stripped design, not the original reference. (analyze_schematic.py carrier/CM5IO.kicad_sch -o analysis/baseline/carrier_stripped.json)
  3. Add phase: 15V→5V buck front-end (reverse-protection + TVS), M.2 E-key (PCIe Gen2 ×1 + CLKREQ/PERST/RF_KILL + 3.3V), GPS connector, PPS distribution (GPS PPS → TVS → Schmitt buffer → fan-out: CM5 Ethernet_SYNC_OUT + 2 header taps). SPICE-validate the buck divider + PPS network.

Out-of-repo notes

Richer running notes live in this machine's Claude memory: ~/.claude/projects/-Users-noise-Documents-obsidian-rpiboard/memory/ (project-cm5-eda, port-progress, eda-tooling-gaps, tooling-installs-cm5). This doc is the portable subset.