Files
rpicarrierboard/PORT_STATUS.md
noise 261bf48bb4 Power stage 3: LM61460-Q1 15V->+3V3_RF 4A buck; EN from CM5 PCIE_PWR_EN
- Second LM61460-Q1 (U_BUCK33R), FB 23.2k/10.0k -> 3.32V (SPICE: vfb 0.994V,
  inrush settles 3.32V); shared BOM with stage 2 (L 4.7uH/7A, RT 31.6k ~420kHz)
- BIAS -> +3V3_RF (datasheet-valid >=3.1V, falls back to VIN below)
- EN <- PCIE_PWR_EN: Module1 pin 106 NC swapped for a global label on
  CM5_HighSpeed + 100k pull-down (mirrors reference R14) so the Wi-Fi rail
  stays off until CM5 asserts it; netlist-verified 3-node net
- Removed the E-key temp PWR_FLAG (#FLG33RF); buck PWR_FLAG on L33.2 is now
  the sole +3V3_RF driver
- Verify: ERC 133->133 zero new; analyzer +49/-0 zero regressions;
  SPICE 17 pass / 2 benign warn / 0 fail

Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2026-07-01 22:11:24 -04:00

145 lines
13 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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).
## ▶ RESUME HERE (session handoff, 2026-07-01)
**State:** branch `port/strip-phase`. Sheets in `carrier/`: root `CM5IO`, `CM5_GPIO`,
`CM5_HighSpeed` (reference, stripped), `M2_Ekey` (E-key, done), `Power` (stages 13 done).
Baseline anchor: `analysis/baseline/carrier_stripped.json`.
**Done:** strip phase (microSD/HDMI/MIPI/PCIe-M2); M.2 E-key sheet (PCIe ×1 to CM5); Power
stage 1 (LM74700 ideal-diode input protection → `VIN_PROT`); Power stage 2 (LM61460-Q1
15→`+5v` 5 A sync buck, SPICE-verified 5.02 V); Power stage 3 (LM61460-Q1 15→`+3V3_RF` 4 A,
SPICE-verified 3.32 V; EN ← CM5 `PCIE_PWR_EN`/106 + 100k pull-down like reference R14; E-key
temp PWR_FLAG removed — buck is the sole `+3V3_RF` driver). Current whole-design **ERC = 133**
(all pre-existing types; a good edit adds **zero new**).
**NEXT ACTION → Power Stage 4: `U_BUCK33A` 15→`+3V3_AUX` ~1 A.** Candidate part TPS54202
(28 V sync) — datasheet-verify first (KiCad has `Regulator_Switching:TPS54202DDC`). One check
that MUST pass: the SMBJ18A clamp (~29 V at rated Ipp) vs the part's VIN abs-max — if the
datasheet says <30 V abs-max, pick a 36 V-class sync part instead (LMR51430/TPS54360-class)
or justify why the surge case is acceptable. FB divider per that part's VREF; SPICE-verify.
`+3V3_AUX` is a NEW net → **global** label. Then the GPS + PPS sheet, then power-budget review.
**How to build/verify (every change):**
- Sheets are generated wholesale — edit `tools/build_ekey.py` / `tools/build_power.py`, then
`python3 tools/build_power.py --apply`. Custom IC symbols go in `carrier/CM5IO.kicad_sym`
(bare name) AND embed in the sheet as `CM5IO:<name>` — else ERC `lib_symbol_issues`.
- Verify loop (judge by the **integrated root** run, not standalone sub-sheets):
`kicad-cli sch erc --format json -o /tmp/e.json carrier/CM5IO.kicad_sch` (track delta vs 133,
zero new types) → `analyze_schematic.py carrier/CM5IO.kicad_sch` + `diff_analysis.py
analysis/baseline/carrier_stripped.json …` (zero regressions) → for bucks, `simulate_subcircuits.py`.
- Gotchas (full list in memory `port-progress`): grid-snap all coords to 1.27 mm or labels don't
bind; PWR_FLAG/GND must sit on a real pin coord; pre-existing `+5v` is hierarchical (not global);
type feedback pins `passive`; connector/module pin types may need remodeling for cross-part ERC.
## 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→`+3V3_RF` 4A ✅ DONE.** Second `LM61460-Q1` (shared BOM with stage 2: L 4.7µH/7A ripple ~1.3A=33%, Cin 2×10µ/50V, Cout 2×47µ/16V, RT 31.6k ~420kHz, Cboot 100n+Rboot 4.7). FB divider R_FBT33 23.2k / R_FBB33 10.0k = **3.32V (SPICE: vfb 0.994V, inrush settles 3.32V)**. BIAS→`+3V3_RF` (datasheet: valid ≥3.1V, auto-falls back to VIN below). **EN ← CM5 `PCIE_PWR_EN`** (Module1 pin 106: NC swapped for a global label on `CM5_HighSpeed`) + **R_EN33 100k pull-down** (mirrors reference R14 — netlist-verified `Module1.106 + U_BUCK33R.7 + R_EN33.1`) so the Wi-Fi rail is OFF until the CM5 asserts it. **E-key temp `#FLG33RF` PWR_FLAG removed** (build_ekey); the buck's PWR_FLAG on L33.2 is now the sole `+3V3_RF` driver — netlist shows buck + all 4 J_E power pins + pull-ups + decoupling on one net. Verify: ERC 133→133 zero new; analyzer +49 added **0 regressions**; SPICE 17 pass / 2 benign warn (the L/C_BOOT "LC filter" mis-detect, once per buck) / 0 fail. (Note: `kicad-cli` netlist export prints a pre-existing "annotation errors" warning — un-numbered generated refdeses like `J_E`/`J_PWR`; present at fd627f5 too, cosmetic.)
- **Stage 4** U_BUCK33A 15→3.3V ~1A → `+3V3_AUX`. SPICE-validate the feedback divider (see NEXT ACTION above for the part-selection gate).
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.