Second power stage. U_BUCK5 = LM61460-Q1 (6A, 42V abs-max synchronous). No KiCad symbol existed, so built one from the TI datasheet (SNVSB70F: 14-pin HTSSOP-1EP + EP, VREF=1.0V) and added it to the project library carrier/CM5IO.kicad_sym as CM5IO:LM61460-Q1. - FB divider R_FBT5 40.2k / R_FBB5 10.0k -> 5.02V (SPICE-confirmed vfb=1.0V=VREF at 5.02V); L5 4.7uH, Cout 2x47u/16V, Cin 2x10u/50V, Cboot 100n+Rboot, RT 31.6k (~400kHz), BIAS->+5v, EN->VIN_PROT - +5v pre-exists in the carrier as a hierarchical net -> exposed via a hierarchical label + a +5v sheet pin on the Power symbol, tied into the root +5v net (a global label would trip same_local_global_label). Netlist confirms the buck now sources Module1 + GPIO headers + USB. - FB pin typed passive (high-Z sense) to clear an analyzer no_driver - build_power.py: register_lm61460(), Device:L, HIER_NETS/emit_hlabel Verify: ERC 133->133 (zero new); analyzer +32 added, 0 regressions; SPICE 12/13 pass, 0 fail (1 benign warn: L5/Cboot mis-grouped as LC). Confirm vs datasheet: RT freq, L saturation >=7A, EP=pad15, EN UVLO. Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
112 lines
10 KiB
Markdown
112 lines
10 KiB
Markdown
# 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`](https://github.com/aklofas/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)
|
||
|
||
```bash
|
||
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~~ **DONE** — `analysis/baseline/carrier_stripped.json` is the add-phase diff anchor.
|
||
3. **M.2 E-key sheet** ✅ **DONE** (`carrier/M2_Ekey.kicad_sch`, generated by `tools/build_ekey.py`).
|
||
J_E = KiCad `Connector:Bus_M.2_Socket_E`, fp `Connector_PCBEdge:M.2_2230-xx-E`. PCIe link-0 wired to the
|
||
9 freed CM5 pins via **global labels** (PCIE_TX/RX/CLK ±, nRST, nCLKREQ, nWAKE — netlist-confirmed J_E↔Module1);
|
||
`+3V3_RF` (4 pins) + 10µF∥2×0.1µF decoupling + temp PWR_FLAG; 11 GND; W_DISABLE1/2 10k pull-ups to +3V3_RF;
|
||
~41 NC (USB/BT, PCM/I2S, SDIO, UART, COEX, I2C, link-1). RX **not** coupled on carrier (card-side per M.2; BOM C_PCIE removed).
|
||
**Verify:** ERC 133→133 (zero new); analyzer diff +7 added, **0 regressions**.
|
||
Connector-symbol pin types remodeled for cross-connector ERC: lines CM5 drives → `passive`; lines the card
|
||
drives into CM5 inputs (RX pair + CLKREQ#/WAKE#) → `output`.
|
||
**Open items (review/next):** (a) CM5 `PCIE_PWR_EN` (pin 106) still NC — wire to the +3V3_RF buck EN in the
|
||
power sheet; (b) the temp PWR_FLAG on +3V3_RF must be REMOVED once the buck drives it (else dual-driver ERC);
|
||
(c) optionally route `WIFI_DISABLE#` to a CM5 GPIO for SW radio control; (d) analyzer CG-AUD 5:1 sig/gnd on J_E
|
||
is inherent to the M.2 connector (INFO, not fixable). New tool: `tools/build_ekey.py` (place connector + auto-NC + labels).
|
||
4. **Power sheet** (`carrier/Power.kicad_sch`, generated by `tools/build_power.py`) — staged, **sync + datasheet-built parts** (user choice). **Spec rating fix:** the spec's buck candidates miss its own ≥20V-Vin rule (TPS54424=17V, TPS54560=async) — selecting synchronous ≥30V parts instead (LM61460-class 6A for +5V & +3V3_RF/4A; TPS54202 28V for +3V3_AUX), each verified vs datasheet before commit.
|
||
- **Stage 1 — input protection ✅ DONE.** J_PWR(15V) → D_REV `LM74700-Q1` ideal-diode + Q_REV N-FET (reverse-polarity/-current) → `VIN_PROT`; `SMBJ18A` TVS + 100µF/25V ∥ 10µF/50V bulk; C_VCAP charge-pump cap. Netlist-verified topology; ERC 133→133 (zero new); analyzer 0 regressions. **Confirm vs LM74700-Q1 datasheet:** C_VCAP value, EN-to-+15V_IN, FET pick (Vds≥30V, SOA/inrush) + optional gate R.
|
||
- **Stage 2 — U_BUCK5 15→`+5v` 5A ✅ DONE.** `LM61460-Q1` (6A, 42V absmax sync; **custom symbol built from the datasheet** → `carrier/CM5IO.kicad_sym` as `CM5IO:LM61460-Q1`, fp `Package_SO:Texas_HTSSOP-14-1EP…ThermalVias`). VREF=1.0V → FB divider R_FBT5 40.2k / R_FBB5 10.0k = **5.02V (SPICE-confirmed vfb=1.0V)**. L5 4.7µH, Cout 2×47µF/16V, Cin 2×10µF/50V, Cboot 100n+Rboot 4.7Ω, RT 31.6k(~400kHz), BIAS→+5v, EN→VIN_PROT, PGOOD 100k→+5v. **`+5v` kept HIERARCHICAL** (pre-existing carrier net; global would collide `same_local_global_label`) — Power sheet exposes a `+5v` sheet pin, tied into the root `+5v` net; netlist-verified it drives Module1 + GPIO + USB. ERC 133→133 (zero new); analyzer +32 added **0 regressions**; SPICE 12/13 pass, 1 benign warn (L5/Cboot mis-detected as LC filter). **Confirm vs datasheet:** RT freq, L sat ≥7A, EP=pad15, optional EN UVLO divider.
|
||
- **Stage 3** U_BUCK33R 15→3.3V 4A → `+3V3_RF` (then REMOVE the E-key temp PWR_FLAG; wire buck EN ← CM5 `PCIE_PWR_EN`/106). **Stage 4** U_BUCK33A 15→3.3V 1A → `+3V3_AUX`. SPICE-validate each feedback divider.
|
||
5. **GPS + PPS distribution**: GPS connector (PPS+UART+3V3+GND); PPS → TVS → Schmitt (LVC1G17) →
|
||
fan-out: CM5 `Ethernet_SYNC_OUT` (J2 pin-6 net, 3.3V, no translator) + 2 header taps. SPICE/timing check.
|
||
|
||
## 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.
|