2026-06-29 16:31:02 -04:00
# 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).
2026-07-01 20:28:30 -04:00
## ▶ RESUME HERE (session handoff, 2026-07-01)
2026-07-01 22:11:24 -04:00
**State:** branch `port/strip-phase` . Sheets in `carrier/` : root `CM5IO` , `CM5_GPIO` ,
2026-07-02 07:22:16 -04:00
`CM5_HighSpeed` (reference, stripped), `M2_Ekey` , `Power` (stages 1– 4), `GPS_PPS` . **ALL
rev-A circuit blocks are now captured.** Baseline anchor: `analysis/baseline/carrier_stripped.json` .
**Done:** strip phase (microSD/HDMI/MIPI/PCIe-M2); M.2 E-key sheet (PCIe × 1); Power stage 1
(LM74700 → `VIN_PROT` ), stage 2 (LM61460-Q1 → `+5v` 5 A, SPICE 5.02 V), stage 3 (LM61460-Q1 →
`+3V3_RF` 4 A, SPICE 3.32 V, EN ← `PCIE_PWR_EN` ), stage 4 (TPS54202 → `+3V3_AUX` ~1 A, SPICE
3.315 V); **GPS + PPS sheet ** (`carrier/GPS_PPS.kicad_sch` via `tools/build_gps.py` : J_GPS
5-pin per Pinout_BOM §6, PPS → PESD3V3 TVS → 74LVC1G17 @ +3V3_AUX → `PPS_CLEAN` → Rs 33Ω →
`SYNC_OUT` (CM5 pin 18 + J2.6) + J_PPS1/J_PPS2 taps; NMEA on **UART2 GPIO4/GPIO5 ** per
correction C2 — netlist: GPIO4 = Module1.54+J8.7+J_GPS.3, GPIO5 = Module1.34+J8.29+J_GPS.2).
The `SYNC_OUT` /`GPIO4` /`GPIO5` local labels on CM5_GPIO were converted to **global ** labels
(names unchanged, nothing else used them) to reach the new sheet without root plumbing.
Current whole-design **ERC = 133 ** (all pre-existing types; a good edit adds **zero new ** ).
**NEXT ACTION → design-review + close-out passes** (no new blocks):
1. **Power-budget review ** of the whole tree (loads vs ratings; the kicad skill's power-tree
check) + re-read PORT_STATUS "Confirm vs datasheet" leftovers (stage-1 C_VCAP/FET pick,
stage-2/3 L saturation ≥ Ipk, RT freq).
2. **Hygiene pass ** (checklist in kicad-port skill): refdes numbering (un-numbered generated
refs `J_E` /`J_PWR` /`U_BUCK5` … trip kicad-cli "annotation errors" — decide whether to number
them), title blocks, netlist-vs-BOM sanity, design notes.
3. Then merge `port/strip-phase` → main and start layout prep (DF40 placement copy from ref).
2026-07-01 20:28:30 -04:00
**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.
2026-06-29 16:31:02 -04:00
## 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 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
## Strip phase — DONE (microSD + HDMI + MIPI + PCIe-M2), ERC 182 → 133, 0 new violations, 0 regressions
2026-06-29 16:31:02 -04:00
| 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 |
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
| **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).
2026-06-29 16:31:02 -04:00
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
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
1. ~~Drop the PCIe-M2 sheet entirely~~ **DONE ** (see strip table). Confirmed E-key-only (no M-key SSD).
Add M.2 E-key (Wi-Fi) sheet; wire PCIe x1 to freed CM5 lanes
First add-phase block. New carrier/M2_Ekey.kicad_sch (generated by
tools/build_ekey.py) places J_E = Connector:Bus_M.2_Socket_E
(fp Connector_PCBEdge:M.2_2230-xx-E) for an AsiaRF AW7915 / MT7915
Wi-Fi card. Reuses the single CM5 PCIe x1 Gen2 lane freed by the
PCIe-M2 drop (design confirmed E-key-only, no M-key SSD).
- PCIe link-0 wired to the 9 freed CM5 pins via global labels
(TX/RX/CLK +/-, nRST, nCLKREQ, nWAKE) - netlist-confirmed J_E<->Module1
- +3V3_RF (pins 2/4/72/74) + 10uF||2x0.1uF decoupling + temp PWR_FLAG
- W_DISABLE1/2 10k pull-ups; 11 GND; ~41 NC (USB/BT, SDIO, UART, etc.)
- RX NOT AC-coupled on carrier (card supplies TX coupling per M.2 spec);
corrected Pinout_BOM, dropped C_PCIE
- CM5_HighSpeed: replaced the 9 PCIe-pin NC markers with global labels
(106/PCIE_PWR_EN stays NC, reserved for the +3V3_RF buck EN)
- root + .kicad_pro: registered the M2_Ekey sub-sheet
- tools/build_ekey.py: new generator (place connector + auto-NC unused
pins + by-name labels; grid-snap; cross-connector ERC pin retyping)
Verify: ERC 133->133 (zero new violations); analyzer diff +7 added,
0 regressions; netlist confirms all 9 PCIe nets span J_E and Module1.
Open (power phase): wire PCIE_PWR_EN->buck EN, drop temp PWR_FLAG once
the +3V3_RF buck drives the rail.
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-06-30 14:58:09 -04:00
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).
2026-06-30 16:41:22 -04:00
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.
Power stage 2: LM61460-Q1 15V->+5v 5A sync buck (SPICE-verified 5.02V)
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>
2026-07-01 18:31:26 -04:00
- **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.
2026-07-01 22:11:24 -04:00
- **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.)
2026-07-02 07:03:31 -04:00
- **Stage 4 — U_BUCK33A 15→`+3V3_AUX` ~1A ✅ DONE (power sheet complete).** `TPS54202` (SOT-23-6, sync, fixed 500kHz, VFB=0.596V). **Abs-max gate PASSED but thin: ** VIN abs-max **30V ** vs SMBJ18A clamp ≤29.2V at full rated 600W surge → 0.8V transient margin (operating max 28V is not the surge number). Custom symbol `CM5IO:TPS54202` (the KiCad lib symbol `extends TPS54302` — no own pins, can't embed standalone) + bare copy in `carrier/CM5IO.kicad_sym` . FB per TI's 3.3V table row: **100k/22.1k + Cff 56pF → 3.29V (SPICE: vfb 0.597V, inrush settles 3.315V) ** . L 10µH/2.5A (ΔI~0.52A), Cout 2× 22µF/16V, Cboot 100n, Cin 10µF/50V+100n. **EN abs-max is only 7V → NO direct VIN tie ** (unlike LM61460): UVLO divider **866k/110k ** (solved from Ip=0.7µA/Ih=1.55µA, VEN 1.21/1.19V) → **start 10.13V / stop 8.61V ** , EN ~1.9V at 15V in (~3.5V at 29V clamp — safe). FB+EN pins typed `passive` (divider-only nets). Verify: ERC 133→133 zero new; analyzer +65/− 0 zero regressions (warn/error set identical to stage 3); SPICE 23 pass / 2 benign warn / 0 fail / 0 skip. **New tooling gap found: ** `simulate_subcircuits.py` lowercases refdeses into SPICE names — `C_IN33A` vs stage-3 `C_IN33a` collided ("device already exists") and silently SKIPPED the whole VIN_PROT decoupling group → renamed to `C_IN33Aa` . Rule: **never create refdeses differing only by case. **
2026-07-02 07:22:16 -04:00
5. **GPS + PPS distribution ✅ DONE ** (`carrier/GPS_PPS.kicad_sch` , generated by `tools/build_gps.py` ).
Per Pinout_BOM §6 (the authority — it CORRECTS the design doc): J_GPS 5-pin (1=PPS, 2=NMEA_RX←GPS TX,
3=NMEA_TX→GPS RX, 4=+3V3_AUX, 5=GND); `GPS_PPS_RAW` → TVS_PPS `PESD3V3L1BA` → U_PPS `74LVC1G17`
(SOT-23-5, +3V3_AUX, pin 1 true-NC) → `PPS_CLEAN` → R_PPS 33Ω → `SYNC_OUT` + J_PPS1 (UWB) / J_PPS2
(scope), 2-pin taps. **NMEA = UART2 on GPIO4/GPIO5 ** (correction C2; UART0/GPIO14-15 stays debug).
Cross-sheet wiring: converted the 6 local labels (`SYNC_OUT` × 2, `GPIO4` × 2, `GPIO5` × 2 on CM5_GPIO) to
**global ** labels — net names unchanged so no multi-label (LB-001) findings, ERC-neutral (133→133);
GPS sheet uses the same global names, root sheet-symbol has NO pins. J_GPS pins 1/2 re-typed `output`
(GPS module drives PPS + TX) so the analyzer's no_driver gate passes — same trick as the E-key socket.
**Verify: ** ERC 133→133 zero new; analyzer +73/− 0 **0 regressions ** (only the pre-existing MPN-coverage
counter moved 50→57 parts); netlist confirms all 6 cross-sheet nets (SYNC_OUT = Module1.18+J2.6+R_PPS.2);
SPICE 24 pass / 2 benign warn / 0 fail / 0 skip.
2026-06-29 16:31:02 -04:00
## 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.