astra/am3352-sbc
A 4-layer AM3352 single-board computer with 128‑MiB DDR3, PMIC power regulation, USB‑C 5‑V PD input, dual USB host ports, HDMI output with ESD protection, microSD/UART/JTAG interfaces, addressable RGB indicators, and a PWM-driven buzzer.
- Version
- 0.1.19
- License
- unset
- Stars
- 0
scripts/diagnose-cpu-via-access.py
"""Compare local BGA via access with and without the saved reference constraint."""
from pathlib import Path
exec(compile((Path(__file__).parent/'route-power-distribution.py').read_text().split("print('geometry loaded'")[0],str(Path(__file__).parent/'route-power-distribution.py'),'exec'))
from scipy.ndimage import label
from shapely import contains_xy
ref=json.loads((ROOT/'output/reference-baseline.audit.json').read_text());planes=[];lines=[]
for e in ref:
if e['type']=='pcb_copper_pour' and e['layer']=='top':
b=e['brep_shape'];planes.append(Polygon([(p['x'],p['y']) for p in b['outer_ring']['vertices']], [[(p['x'],p['y']) for p in h['vertices']] for h in b['inner_rings']]))
if e['type']=='pcb_trace' and e['pcb_trace_id'].startswith('saved_phase_'):
for a,b in zip(e['route'],e['route'][1:]):
if a['route_type']==b['route_type']=='wire' and a['layer']==b['layer']=='inner1':lines.append(LineString([(a['x'],a['y']),(b['x'],b['y'])]))
protected=unary_union(planes).intersection(unary_union(lines).buffer(.1));results=[]
for pin in ['E16','R1','J3','B11']:
t=next(t for t in terminals if t['selector']==f'.U1 > .{pin}');n=t['net'];a=(t['x'],t['y']);area=Point(a).buffer(5)
foreign=[(g,ls) for g,ls,k in geoms if k!=n and g.intersects(area)]
top=unary_union([g for g,ls in foreign if 'top' in ls]).buffer(.153)
via=unary_union([g for g,ls in foreign]).buffer(.253)
# Do not infer permission for via-in-pad from same-net copper.
own=unary_union([g for g,ls,k in geoms if k==n and g.intersects(area)]).buffer(.16)
via=via.union(own)
xs=a[0]+np.arange(-80,81)*.05;ys=a[1]+np.arange(-80,81)*.05
states=[]
for protect in [False,True]:
barrier=top.union(protected.buffer(.183)) if protect else top
drill=via.union(protected.buffer(.283)) if protect else via
blocked=contains_xy(barrier,xs[None,:],ys[:,None]);regions,num=label(~blocked,structure=np.ones((3,3)))
region=regions[80,80];openings=(regions==region)&(region>0)&~contains_xy(drill,xs[None,:],ys[:,None]);yy,xx=np.where(openings)
sites=sorted([(float(xs[x]),float(ys[y])) for x,y in zip(xx,yy)],key=lambda p:math.dist(a,p))
states.append({'protectReference':protect,'reachableCells':int(np.sum(regions==region)) if region else 0,'availableViaSites':len(sites),'nearestSites':sites[:5]})
results.append({'pin':pin,'net':labels.get(n,n),'states':states})
print(json.dumps(results,indent=2));(ROOT/'output/cpu-via-access-diagnostic.json').write_text(json.dumps(results,indent=2))