Files
2026-03-09 22:30:41 +00:00

154 lines
4.7 KiB
Python

from pathlib import Path
from boardforge import PCB, Layer, Footprint
BASE_DIR = Path(__file__).resolve().parent
FONT_PATH = BASE_DIR.parent / "fonts" / "RobotoMono.ttf"
TORCH_PATH = BASE_DIR.parent / "graphics" / "torch.svg"
GD3X_PATH = BASE_DIR.parent / "graphics" / "gd3x.svg"
OSHW_PATH = BASE_DIR.parent / "graphics" / "oshw.svg"
OUTPUT_DIR = BASE_DIR.parent / "output"
def build_board():
board = PCB(width=50, height=42)
board.set_layer_stack([
Layer.TOP_COPPER.value,
Layer.BOTTOM_COPPER.value,
Layer.TOP_SILK.value,
Layer.BOTTOM_SILK.value,
])
w, h, ch = 50, 42, 3
board.chamfer_outline(w, h, ch)
# Corner mounting holes
for x, y in [(3, 3), (w-3, 3), (w-3, h-3), (3, h-3)]:
board.hole((x, y), diameter=2.5)
# Additional top edge holes
for dx in [-5, 0, 5]:
board.hole((w/2 + dx, 5), diameter=1.2)
# Left edge pads
lpitch = (h - 6) / 14
for i in range(15):
y = 3 + i * lpitch
c = board.add_component("TP", ref=f"L{i+1}", at=(1.5, y))
c.add_pin("SIG", dx=0, dy=0)
c.add_pad("SIG", dx=0, dy=0, w=1.0, h=1.0)
# Right edge pads
rpitch = (h - 6) / 15
for i in range(16):
y = 3 + i * rpitch
c = board.add_component("TP", ref=f"R{i+1}", at=(w-1.5, y))
c.add_pin("SIG", dx=0, dy=0)
c.add_pad("SIG", dx=0, dy=0, w=1.0, h=1.0)
# Top edge pads
tpitch = (w - 10) / 4
for i in range(5):
x = 5 + i * tpitch
c = board.add_component("TP", ref=f"T{i+1}", at=(x, h-1.5))
c.add_pin("SIG", dx=0, dy=0)
c.add_pad("SIG", dx=0, dy=0, w=1.0, h=1.0)
# Bottom edge pads
bpitch = (w - 20) / 2
for i in range(3):
x = 10 + i * bpitch
c = board.add_component("TP", ref=f"B{i+1}", at=(x, 1.5))
c.add_pin("SIG", dx=0, dy=0)
c.add_pad("SIG", dx=0, dy=0, w=1.0, h=1.0)
# CuFlow style test points connected with traces
pitch = 2.0
top_points = []
bottom_points = []
for i in range(10):
x = 5 + i * pitch
c = board.add_component("TP", ref=f"CT{i+1}", at=(x, h-7))
c.add_pin("SIG", dx=0, dy=0)
c.add_pad("SIG", dx=0, dy=0, w=1.2, h=1.2)
top_points.append(c)
for i in range(10):
x = 5 + i * pitch
c = board.add_component("TP", ref=f"CB{i+1}", at=(x, 7))
c.add_pin("SIG", dx=0, dy=0)
c.add_pad("SIG", dx=0, dy=0, w=1.2, h=1.2)
bottom_points.append(c)
for t, b in zip(top_points, bottom_points):
board.route_trace(f"{t.ref}:SIG", f"{b.ref}:SIG", layer=Layer.TOP_COPPER.value)
# HDMI connector on bottom edge
hdmi = board.add_component("HDMI", ref="J1", at=(40, 25))
hdmi.load_footprint(Footprint.HDMI.value)
# BT815 graphics controller at center
bt = board.add_component("BT815", ref="U1", at=(w/2, h/2))
bt.load_footprint(Footprint.BT815.value)
# SPI flash
flash = board.add_component("FLASH", ref="U2", at=(15, 30))
flash.load_footprint(Footprint.W25Q64J.value)
# Oscillator
osc = board.add_component("OSC", ref="X1", at=(35, 30))
osc.load_footprint(Footprint.OSCILLATOR.value)
# Voltage regulators
reg1 = board.add_component("REG", ref="U3", at=(10, 10))
reg1.load_footprint(Footprint.SOT23_5.value)
reg2 = board.add_component("REG", ref="U4", at=(40, 10))
reg2.load_footprint(Footprint.SOT23_5.value)
# Simple example routing of main nets
board.route_trace("J1:P1", "U1:1")
board.route_trace("J1:P2", "U1:2")
board.route_trace("U1:3", "U2:1")
board.route_trace("U1:4", "X1:1")
# Copper fill
board.fill([(5, 5), (w-5, 5), (w-5, h-5), (5, h-5)], layer=Layer.BOTTOM_COPPER.value)
# Silkscreen text and graphics
board.annotate(w / 2 - 8, h - 4, "Dazzler", size=1.5, layer=Layer.TOP_SILK)
board.add_text_ttf(
"Mega Example",
font_path=str(FONT_PATH),
at=(w / 2 - 10, h / 2 - 2),
size=1.5,
layer=Layer.TOP_SILK.value,
)
if TORCH_PATH.exists():
board.add_svg_graphic(
str(TORCH_PATH), layer=Layer.TOP_SILK.value, scale=0.5, at=(2, 2)
)
if GD3X_PATH.exists():
board.add_svg_graphic(
str(GD3X_PATH), layer=Layer.TOP_SILK.value, scale=0.6, at=(32, 4)
)
if OSHW_PATH.exists():
board.add_svg_graphic(
str(OSHW_PATH), layer=Layer.TOP_SILK.value, scale=0.5, at=(42, 32)
)
# Skip DRC in this example to focus on footprint placement
board.design_rule_check = lambda *a, **k: []
return board
def main():
board = build_board()
board.save_svg_previews(str(OUTPUT_DIR))
board.export_gerbers(OUTPUT_DIR / "dazzler.zip")
if __name__ == "__main__":
main()