pixalynx/cm5-minimal-carrier

A 4-layer Raspberry Pi CM5 carrier board routes USB‑C 5V power through an RT9742 load switch with TVS protection and capacitive filtering, while providing ESD-protected HDMI output, CM5 connectors, test points, and ground/power planes.

Version
0.1.1
License
unset
Stars
0

scripts/deliverables.py

import json,pathlib,csv,hashlib,html
R=pathlib.Path(__file__).resolve().parents[1];D=json.loads((R/'lib/design.json').read_text());j=json.loads((R/'dist/index/circuit.json').read_text());out=R/'output'
def csvfile(name,header,rows):
 with (out/name).open('w',newline='') as f:
  w=csv.writer(f);w.writerow(header);w.writerows(rows)
M=json.loads((R/'lib/manufacturing.json').read_text())
parts=D['parts'];groups={}
for p in parts:groups.setdefault(p['mpn'],[]).append(p)
csvfile('bom.csv',['Designators','Quantity','Manufacturer','Manufacturer Part Number','LCSC Part Number','Footprint','Purpose','Assembly'],[[','.join(p['ref'] for p in g),len(g),g[0]['manufacturer'],mpn,g[0]['lcsc'],g[0]['footprint'],g[0]['purpose'],'Confirm JLC stock/basic-extended and sourcing before ordering'] for mpn,g in groups.items()])
csvfile('jlcpcb-bom.csv',['Comment','Designator','Footprint','LCSC Part #'],[[mpn,','.join(p['ref'] for p in g),g[0]['footprint'],g[0]['lcsc']] for mpn,g in groups.items()])
# Fabrication origin is (68,130) in KiCad: board bottom-left in tscircuit is (-32,-30).
# Component body/footprint centroids in emitted JSON are starting points, not certified JLC rotations.
sc={e['source_component_id']:e['name'] for e in j if e['type']=='source_component'}
pc={sc[e['source_component_id']]:e for e in j if e['type']=='pcb_component'}
csvfile('jlcpcb-cpl-REVIEW.csv',['Designator','Mid X','Mid Y','Layer','Rotation'],[[p['ref'],f"{pc[p['ref']]['center']['x']+32:.6f}mm",f"{pc[p['ref']]['center']['y']+30:.6f}mm",'Top' if p['layer']=='top' else 'Bottom',p['rotation']] for p in parts])
pinout=json.loads((R/'lib/cm5-pinout.json').read_text());ports=[]
for n in range(1,201):
 ref='J1' if n<=100 else 'J2';local=n if n<=100 else n-100;p=next(p for p in parts if p['ref']==ref);ports.append([n,ref,local,pinout[str(n)],p['nets'].get(str(local),'NC - intentionally unused')])
csvfile('cm5-pin-audit.csv',['Official CM5 pin','Carrier connector','Local contact number','Official signal','Carrier net'],ports)
netlist={n:sorted([f"{p['ref']}.{k}" for p in parts for k,v in p['nets'].items() if v==n]+[f"{p['ref']}.1" for p in M['testPoints'] if p['net']==n]) for n in D['nets']};(out/'netlist.json').write_text(json.dumps(netlist,indent=2)+'\n')
hashes={str(p.relative_to(R)):hashlib.sha256(p.read_bytes()).hexdigest() for p in sorted((R/'references').glob('*')) if p.is_file() and p.suffix in ['.pdf','.kicad_pcb','.kicad_mod']};(out/'reference-sha256.json').write_text(json.dumps(hashes,indent=2)+'\n')
report=json.loads((out/'validation.json').read_text());rows=''.join(f"<tr><td>{','.join(p['ref'] for p in g)}</td><td>{len(g)}</td><td>{html.escape(g[0]['manufacturer'])}</td><td>{html.escape(mpn)}</td><td><a href='https://www.lcsc.com/product-detail/{g[0]['lcsc']}.html'>{g[0]['lcsc']}</a></td></tr>" for mpn,g in groups.items());sheets=sorted((out/'schematics').glob('*.svg'))
page='''<!doctype html><html lang="en"><meta charset="utf-8"><meta name="viewport" content="width=device-width"><title>CM5 Minimal Carrier | V1 engineering review</title><style>
:root{font:16px/1.5 system-ui;color:#e1e9ef;background:#101923}body{max-width:1150px;margin:40px auto;padding:0 24px}h1{font-size:40px;margin-bottom:8px}h2{margin-top:36px}p{max-width:850px;color:#adbdcc}a{color:#65d4c4}button,select{background:#233443;color:#fff;border:1px solid #466071;padding:10px 14px;border-radius:5px;margin:4px;cursor:pointer}.badge{display:inline-block;background:#173f38;padding:5px 12px;color:#8be8c0}.pending{background:#453720;color:#f6dca9;padding:14px;border-left:3px solid #e5b865}.grid{display:grid;grid-template-columns:repeat(4,1fr);gap:14px}.metric{background:#1c2b37;padding:18px}.metric b{display:block;font-size:24px}img{max-width:100%;border:1px solid #314450}.viewer{background:#0a121b;padding:14px}table{width:100%;border-collapse:collapse;font-size:14px}td,th{padding:10px;border-bottom:1px solid #314450;text-align:left}pre{background:#1c2b37;padding:20px;overflow:auto}summary{cursor:pointer;padding:12px;background:#20303e}footer{padding:32px 0;color:#91a6b9}@media(max-width:700px){.grid{grid-template-columns:1fr 1fr}table{font-size:11px}}
</style><body><div class="badge">V1 REV B · electrical and copper checks pass</div><h1>CM5 Minimal Carrier</h1><p>USB-C power and full-size HDMI. A 64 × 60 mm, four-layer carrier for a pre-programmed, non-wireless eMMC Compute Module 5.</p><div class="pending">Fabrication release pending: controlled impedance approval, assembly review, power and thermal qualification, and HDMI prototype tests. Review exports are not a production release.</div><h2>Design at a glance</h2><div class="grid"><div class="metric"><b>15</b>placed components</div><div class="metric"><b>5 V / 5 A</b>recommended USB-PD supply</div><div class="metric"><b>0 / 0</b>KiCad DRC / unrouted</div><div class="metric"><b>0 vias</b>HDMI signal paths</div></div><pre>USB-C ── 5 V plane ── CM5 ── low-capacitance ESD ── HDMI Type-A
  └──── CC1 / CC2 ─── onboard USB-PD controller
5 V ── current-limited switch ───────────────────── HDMI pin 18</pre><h2>PCB copper</h2><p>Board top view; +Y is up. Bottom artwork is viewed through the board. The CM5 outline reserves all top-side space beneath the module.</p><div>'''
page+=''.join(f"<button onclick=\"document.getElementById('pcb').src='pcb-{l}.svg'\">{label}</button>" for l,label in [('top','L1 · signals / parts'),('inner1','L2 · ground'),('inner2','L3 · 5 V'),('bottom','L4 · support routing')])
page+='</div><div class="viewer"><img id="pcb" src="pcb-top.svg" alt="PCB copper view"></div><h2>Populated carrier preview</h2><p>All 15 carrier component bodies are included. CM5 is not installed in this view. The HDMI body is the official IO-board visual proxy; exact EDAC mechanical verification remains open.</p><img src="assembly-3d.png" alt="Populated carrier in 3D"><h2>Schematic sheets</h2><p>J2 contacts 1–100 map to official CM5 pins 101–200. Every unused module pin is explicitly NC. Shared USB-C lands retain their physical contact aliases in the source footprint.</p>'
page+=''.join(f'<details><summary>{html.escape(p.stem.replace("_"," "))}</summary><a href="schematics/{p.name}">Open full-resolution SVG</a><img src="schematics/{p.name}" alt="{p.stem}"></details>' for p in sheets)
page+='<h2>Bill of materials</h2><p>All 15 fitted parts have LCSC IDs. JLC assembly stock and placement rotations must still be confirmed. The CM5, power supply, HDMI cable and mounting hardware are separate.</p><table><tr><th>References</th><th>Qty</th><th>Manufacturer</th><th>MPN</th><th>LCSC</th></tr>'+rows+'</table><h2>Revision B manufacturing review</h2><p><a href="assembly-review.html">Assembly drawings and pad-1 coordinates</a> · <a href="manufacturing-audit.json">CAM checks and hashes</a> · <a href="cm5-minimal-revB-manufacturing-review.zip">Download review bundle</a> · <a href="../docs/minima-comparison.md">MINIMA comparison</a></p><p>Six bare bottom-side probe pads add voltage test access without additional fitted parts. Gerber, drill and placement files now share the board bottom-left origin.</p><h2>Review package</h2><p><a href="bom.csv">Full BOM</a> · <a href="jlcpcb-bom.csv">JLC BOM</a> · <a href="jlcpcb-cpl-REVIEW.csv">CPL for review</a> · <a href="cm5-pin-audit.csv">200-pin audit</a> · <a href="validation.json">Validation</a> · <a href="drc.json">Independent DRC</a> · <a href="../docs/fabrication-checklist.md">Fabrication checklist</a></p><footer>Generated from the tsCircuit project. No DRC exclusions, modified tool checks, or deleted diagnostic records.</footer></body></html>'
(out/'review.html').write_text(page)