- Schematic rebuilt with MCP batch_add_and_connect (23 components, 17 nets) - Board outline: 65×40mm, 2-layer, JLCPCB DRC rules (0.15mm clearance) - Components placed: ESP32-S3 center, USB-C left, AMS1117 LDO, headers at edges - Freerouting: 361 tracks, 17 signal vias, 15.7s autoroute - GND copper pour on F.Cu + B.Cu, 77 stitching vias - DRC: 208 violations (77 via_dangling = zone fill artifacts, resolve on KiCad GUI fill) - Gerbers + drill + BOM + pick-and-place exported to gerbers/ - Netlist verified: 20 components, 16 nets all properly connected
87 lines
2.6 KiB
Python
87 lines
2.6 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
ESP32-S3 Sensor Node — Specctra DSN Generator v2
|
|
Uses exact format from known-working DSN file.
|
|
"""
|
|
import os
|
|
|
|
PROJ = os.path.expanduser("~/Documents/KiCad/10.0/esp32-s3-sensor-node")
|
|
TEMPLATE = os.path.expanduser("~/Documents/KiCad/10.0/USB_PD_ESP32S3/freerouting.dsn")
|
|
|
|
def gen():
|
|
templ = open(TEMPLATE).read()
|
|
|
|
# Replace key sections
|
|
# 1. Board outline
|
|
templ = templ.replace(
|
|
'(rect 0 0 100000 80000)',
|
|
'(rect 0 0 65000 40000)'
|
|
)
|
|
|
|
# 2. Keepout zones (after GND layer)
|
|
# Find the end of layer definitions and add keepout
|
|
keepout_section = '''
|
|
(place_rule (F.Cu (clearance 200)))
|
|
(place_rule (B.Cu (clearance 200)))
|
|
(rule (clearance 150))
|
|
(rule "3V3" (clearance 250))
|
|
(rule "VBUS" (clearance 250))
|
|
(rule "USB_D_P" (clearance 150))
|
|
(rule "USB_D_N" (clearance 150))
|
|
(keepout F.Cu (rect 46000 28000 65000 40000))
|
|
(keepout B.Cu (rect 46000 28000 65000 40000))
|
|
)'''
|
|
|
|
# Find structure closing
|
|
struct_end = templ.find('\n )\n', templ.find('(structure'))
|
|
if struct_end > 0:
|
|
templ = templ[:struct_end] + keepout_section + templ[struct_end:]
|
|
|
|
# 3. Replace nets
|
|
nets_section = gen_nets()
|
|
net_start = templ.find('(network\n')
|
|
net_end = templ.find('\n)', net_start) + 2
|
|
if net_start > 0:
|
|
templ = templ[:net_start] + nets_section + templ[net_end:]
|
|
|
|
# Write
|
|
dsn = os.path.join(PROJ, "esp32-s3-sensor-node.dsn")
|
|
open(dsn, 'w').write(templ)
|
|
print(f"Written: {dsn} ({len(templ)} bytes)")
|
|
|
|
NETS = {
|
|
"GND": ["J1-SH","J1-A1","J1-B1","U2-1","U1-1","U1-16","U1-40",
|
|
"C1-2","C2-2","C3-2","C4-2","C5-2","C6-2",
|
|
"D1-1","R4-2","R7-2","R8-2","J2-4","J3-1"],
|
|
"3V3": ["U2-2","U1-2","C1-1","C2-1","C3-1","C6-1",
|
|
"R2-2","R3-2","R5-2","R6-2","J2-1","J3-4"],
|
|
"VBUS": ["J1-A4","J1-B4","U2-3","C5-1"],
|
|
"EN": ["U1-3","R2-1","C4-1"],
|
|
"IO0": ["U1-27","R3-1"],
|
|
"IO12": ["U1-20","R4-1"],
|
|
"SDA": ["U1-4","R5-1","J2-2"],
|
|
"SCL": ["U1-5","R6-1","J2-3"],
|
|
"USB_D_P": ["J1-A6","J1-B6","U1-14"],
|
|
"USB_D_N": ["J1-A7","J1-B7","U1-13"],
|
|
"CC1": ["J1-A5","R7-1"],
|
|
"CC2": ["J1-B5","R8-1"],
|
|
"IO2_LED": ["U1-38","R1-1"],
|
|
"D1_A": ["R1-2","D1-2"],
|
|
"RXD0": ["U1-36","J3-2"],
|
|
"TXD0": ["U1-37","J3-3"],
|
|
}
|
|
|
|
def gen_nets():
|
|
lines = ['(network']
|
|
for name, pins in NETS.items():
|
|
lines.append(f' (net "{name}"')
|
|
for pin in pins:
|
|
ref, pn = pin.split('-')
|
|
lines.append(f' (pin {ref} {pn})')
|
|
lines.append(f' )')
|
|
lines.append(')')
|
|
return '\n'.join(lines)
|
|
|
|
if __name__ == "__main__":
|
|
gen()
|