AnasSarkiz/muse-voice-remote
Muse Voice Remote — bare ESP32-S3R8, 155 TOP JLCPCB parts with real supplier CAD, native 3D assembly and GLB exports. Revised 17 mm case allocation; 0.30 mm via drill /0.45 mm pad. Checked prototype PCB; mechanical, RF and MUSE qualification pending.
- Version
- 1.3.2
- License
- unset
- Stars
- 0
scripts/chip_native.py
"""Seed short RF/clock paths and a continuous inner ground reference.
Footprints and pads come from the retained JLCPCB imports. This adds board
copper, not component geometry. RF impedance and matching need fab/VNA review.
"""
import pcbnew
def seed_chip_copper(board, nets):
footprints = {f.GetReference(): f for f in board.GetFootprints()}
if footprints["U1"].GetValue() != "ESP32-S3R8":
return
def at(ref, number):
p = next(p for p in footprints[ref].Pads() if p.GetNumber() == str(number))
return (pcbnew.ToMM(p.GetPosition().x), pcbnew.ToMM(p.GetPosition().y))
def path(net, points, width):
for a, b in zip(points, points[1:]):
if a == b:
continue
t = pcbnew.PCB_TRACK(board)
t.SetStart(pcbnew.VECTOR2I(pcbnew.FromMM(a[0]), pcbnew.FromMM(a[1])))
t.SetEnd(pcbnew.VECTOR2I(pcbnew.FromMM(b[0]), pcbnew.FromMM(b[1])))
t.SetLayer(pcbnew.F_Cu)
t.SetWidth(pcbnew.FromMM(width))
t.SetNet(nets[net])
t.SetLocked(True)
board.Add(t)
# RF stays on the top layer, with no RF signal vias or meanders. These
# widths are design targets; the fabrication stackup must establish 50 ohm.
path("RF_LNA", [at("L_RF_MATCH", 2), at("C_RF_LNA", 1), at("U1", 1)], 0.18)
path("RF_3V3", [at("U1",2),at("U1",3)],0.2)
# The connector's signal exits south of its two large shield lands.
path("RF_ANT", [at("J_RF", 2), (-12.7,-4.3), (-12.7,-3.8), (-11.0,-3.8),
(-10.5,-4.3), (-10.5,at("D_RF_ESD",1)[1]), at("D_RF_ESD", 1),
at("C_RF_ANT", 1), at("L_RF_MATCH", 1)], 0.18)
path("XTAL_P_CHIP", [at("U1", 54), at("L_XTAL", 1)], 0.15)
path("XTAL_P", [at("L_XTAL", 2), (-1.8, -8.0), (-1.1, -8.7), at("Y1", 1)], 0.15)
path("XTAL_P", [at("Y1", 1), (-3.0, at("Y1", 1)[1]), at("C_XTAL_P", 1)], 0.15)
path("XTAL_N", [at("U1", 53), (-1.4, -6.25), (-0.8, -6.85), (2.4, -6.85), (2.4, at("Y1", 3)[1]), at("Y1", 3)], 0.15)
path("XTAL_N", [(2.4, at("C_XTAL_N", 1)[1]), at("C_XTAL_N", 1)], 0.15)
plane = pcbnew.ZONE(board)
plane.SetLayer(pcbnew.In1_Cu)
plane.SetNet(nets["GND"])
plane.SetLocalClearance(pcbnew.FromMM(0.15))
plane.SetMinThickness(pcbnew.FromMM(0.15))
plane.SetPadConnection(pcbnew.ZONE_CONNECTION_FULL)
outline = plane.Outline()
outline.NewOutline()
for x, y in [(-32.4,-23.4),(32.4,-23.4),(32.4,23.4),(-32.4,23.4)]:
outline.Append(pcbnew.FromMM(x), pcbnew.FromMM(y))
board.Add(plane)
# Fill from a reloaded board/project in a separate process. KiCad 9's
# zone filler crashes on freshly constructed boards without project state.