metronome/hardware/eda/circuits/board.py
Me Here adc92c7c02 PM_K-1 hardware: fix the 2 real import issues (crystal footprint + USB shield error)
- Crystal Y1: footprint was a 4-pad type (Crystal_SMD_3225-4Pin) on a 2-pin symbol ->
  pads 3/4 had no symbol pin. Switched to Crystal_SMD_2012-2Pin to match (set to the
  chosen crystal's real footprint at BOM time; ground the case pads if 4-pad).
- USB-C J5: the library symbol's shield pin "S1" mismatches older KiCad footprints that
  name the shell pads "SH" -> "pad S1 not found" ERROR. Dropped the shield net from the
  schematic; the USB shell->chassis is now a layout-time tie (direct or 1Mohm||cap),
  which is version-independent and standard practice. Error resolved; ERC 0.

The remaining ~46 import warnings are HARMLESS: "no net for pad N" on intentionally
unconnected pins (spare RP2350 GPIOs, unused relay NO contacts, unused ULN2003/74LVC14
channels, IC NC pins) -- expected on any board, nothing to fix.

Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
2026-05-31 19:30:48 -05:00

319 lines
23 KiB
Python

#!/usr/bin/env python3
"""PM_K-1 FULL BOARD (SKiDL): the whole core board as one netlist for PCB layout.
Run INSIDE the EDA container:
cd hardware/eda && ./run.sh python3 ../eda/circuits/board.py
Outputs ERC + hardware/kicad/board.net (the master netlist to import into Pcbnew).
This re-implements every block (power, MCU, audio chain, RTC, MIDI-DNP, interconnects,
SIG/CLIP-DNP, speaker-DNP) with SHARED net objects and NO forced reference designators --
SKiDL auto-numbers them, so refs are unique board-wide (the per-block files have colliding
refs by design; this file is the single integrated source of truth, like audio_chain.py is
for the audio stages). All IC pinouts datasheet-verified in the per-block files.
MCLK-LESS: the PCM5102A SCK is tied to GND (internal-PLL operation) -- no audio oscillator.
"""
import os
from skidl import *
set_default_tool(KICAD9)
P = Pin.types
def mk(name, pins, ref="U", fp="Package_SO:SOIC-8_3.9x4.9mm_P1.27mm"):
return Part(name=name, tool=SKIDL, dest=TEMPLATE, ref_prefix=ref, footprint=fp, pins=pins)
R = Part("Device","R", dest=TEMPLATE, footprint="Resistor_SMD:R_0402_1005Metric")
def C(v, fp="Capacitor_SMD:C_0402_1005Metric"): return Part("Device","C", value=v, footprint=fp)
D = Part("Device","D", dest=TEMPLATE, footprint="Diode_SMD:D_SOD-323")
DS = Part("Device","D_Schottky", dest=TEMPLATE, footprint="Diode_SMD:D_SOD-323")
L = Part("Device","L", dest=TEMPLATE, footprint="Inductor_SMD:L_1210_3225Metric") # placeholder; set per actual inductor (Wuerth/EPCOS/Abracon) at layout
def grp(n): g = Group(n); g.__enter__(); return g # tag a block as a "sheet" -> KiCad select-by-block
def endgrp(g): g.__exit__(None, None, None)
# ============================ shared nets ============================
vbus,p5,p18,n18,p15,n15,p3v3,dvdd,gnd = (Net("VBUS_5V"),Net("+5V"),Net("+18V"),Net("-18V"),
Net("+15V"),Net("-15V"),Net("+3V3"),Net("DVDD"),Net("GND"))
for nn in (vbus,p5,p18,n18,p15,n15,p3v3,dvdd): nn.drive = POWER
gnd.drive = POWER
vref = Net("VREF")
# audio
ain_hot,ain_cold,rx_hot_in,rx_out,di_in,di_out = (Net("AIN_HOT"),Net("AIN_COLD"),Net("RX_HOT_IN"),
Net("RX_OUT"),Net("DI_IN"),Net("DI_OUT"))
stage1_out,click_out,mix_out,aout_hot,aout_cold,chassis = (Net("STAGE1_OUT"),Net("CLICK_OUT"),
Net("MIX_OUT"),Net("AOUT_HOT"),Net("AOUT_COLD"),Net("CHASSIS"))
# DAC clocks/control (MCLK-less: no MCLK net)
i2s_bck,i2s_lrck,i2s_din,dac_xsmt = Net("I2S_BCK"),Net("I2S_LRCK"),Net("I2S_DIN"),Net("DAC_XSMT")
sel_linst,mute_en,gndlift_en = Net("SEL_LINST"),Net("MUTE_EN"),Net("GNDLIFT_EN")
sig_led,clip_led,gndlift_sw,lineinst_sw = Net("SIG_LED"),Net("CLIP_LED"),Net("GNDLIFT_SW"),Net("LINEINST_SW")
k1d,k2d,k3d = Net("K1_DRV"),Net("K2_DRV"),Net("K3_DRV")
spk_p,spk_n,spk_sd = Net("SPK_P"),Net("SPK_N"),Net("SPK_SD")
# digital ribbon
spi_sck,spi_mosi,lcd_cs,lcd_dc,lcd_rst = Net("SPI_SCK"),Net("SPI_MOSI"),Net("LCD_CS"),Net("LCD_DC"),Net("LCD_RST")
i2c_sda,i2c_scl,ws2812,btn_a,btn_b,joy_x,joy_y = (Net("I2C_SDA"),Net("I2C_SCL"),Net("WS2812"),
Net("BTN_A"),Net("BTN_B"),Net("JOY_X"),Net("JOY_Y"))
# QSPI / clock / USB / MIDI / RTC
qsck,qd0,qd1,qd2,qd3,qcs = (Net("QSPI_SCLK"),Net("QSPI_SD0"),Net("QSPI_SD1"),Net("QSPI_SD2"),Net("QSPI_SD3"),Net("QSPI_SS"))
xin,xout = Net("XIN"),Net("XOUT")
usb_dp_c,usb_dm_c = Net("USB_DP_CONN"),Net("USB_DM_CONN")
midi_tx,midi_rx = Net("MIDI_TX"),Net("MIDI_RX")
mo_a,mo_b,mi_a,mi_b,mt_a,mt_b = (Net("MIDI_OUT_A"),Net("MIDI_OUT_B"),Net("MIDI_IN_A"),Net("MIDI_IN_B"),
Net("MIDI_THRU_A"),Net("MIDI_THRU_B"))
vdd_rtc,rtc_int = Net("VDD_RTC"),Net("RTC_INT")
def dcp(rail, val="100nF"):
c = C(val); rail += c[1]; c[2] += gnd
# ============================ POWER TREE ============================
g = grp("Power")
TPS65131 = mk("TPS65131",[Pin(num=1,name="INP",func=P.PASSIVE),Pin(num=24,name="INP2",func=P.PASSIVE),
Pin(num=2,name="PGND",func=P.PWRIN),Pin(num=3,name="PGND2",func=P.PWRIN),Pin(num=4,name="VIN",func=P.PWRIN),
Pin(num=5,name="INN",func=P.PASSIVE),Pin(num=6,name="INN2",func=P.PASSIVE),Pin(num=7,name="BSW",func=P.OUTPUT),
Pin(num=8,name="ENP",func=P.INPUT),Pin(num=9,name="PSP",func=P.INPUT),Pin(num=10,name="ENN",func=P.INPUT),
Pin(num=11,name="PSN",func=P.INPUT),Pin(num=12,name="NC12",func=P.NOCONNECT),Pin(num=20,name="NC20",func=P.NOCONNECT),
Pin(num=13,name="OUTN",func=P.PASSIVE),Pin(num=14,name="OUTN2",func=P.PASSIVE),Pin(num=15,name="VNEG",func=P.INPUT),
Pin(num=16,name="FBN",func=P.INPUT),Pin(num=17,name="VREF",func=P.PWROUT),Pin(num=18,name="CN",func=P.PASSIVE),
Pin(num=19,name="AGND",func=P.PWRIN),Pin(num=21,name="CP",func=P.PASSIVE),Pin(num=22,name="FBP",func=P.INPUT),
Pin(num=23,name="VPOS",func=P.INPUT),Pin(num=25,name="EP",func=P.PWRIN)],fp="Package_DFN_QFN:QFN-24-1EP_4x4mm_P0.5mm_EP2.65x2.65mm")
def ldo(name): return mk(name,[Pin(num=1,name="OUT",func=P.PWROUT),Pin(num=2,name="FB",func=P.INPUT),
Pin(num=3,name="NC",func=P.NOCONNECT),Pin(num=4,name="GND",func=P.PWRIN),Pin(num=5,name="EN",func=P.INPUT),
Pin(num=6,name="NR",func=P.PASSIVE),Pin(num=7,name="DNC",func=P.NOCONNECT),Pin(num=8,name="IN",func=P.PWRIN),
Pin(num=9,name="EP",func=P.PWRIN)],fp="Package_SO:HVSSOP-8-1EP_3x3mm_P0.65mm_EP1.57x1.89mm")
AP2112 = mk("AP2112K-3.3",[Pin(num=1,name="VIN",func=P.PWRIN),Pin(num=2,name="GND",func=P.PWRIN),
Pin(num=3,name="EN",func=P.INPUT),Pin(num=4,name="NC",func=P.NOCONNECT),Pin(num=5,name="VOUT",func=P.PWROUT)],
fp="Package_TO_SOT_SMD:SOT-23-5")
sw = TPS65131(); pos = ldo("TPS7A4901")(); neg = ldo("TPS7A3001")(); reg3 = AP2112()
fb1 = L(value="600R"); vbus += fb1[1]; fb1[2] += p5
cbk = C("10uF","Capacitor_SMD:C_1206_3216Metric"); p5 += cbk[1]; cbk[2] += gnd
sw["VIN"]+=p5; sw["PGND"]+=gnd; sw["PGND2"]+=gnd; sw["AGND"]+=gnd; sw["EP"]+=gnd
sw["ENP"]+=p5; sw["ENN"]+=p5; sw["PSP"]+=gnd; sw["PSN"]+=gnd
c1=C("4.7uF"); p5+=c1[1]; c1[2]+=gnd; c2=C("4.7uF"); p5+=c2[1]; c2[2]+=gnd
l1=L(value="4.7uH"); p5+=l1[1]; l1[2]+=Net("SW_BOOST"); swb=l1[2]; sw["INP"]+=swb; sw["INP2"]+=swb
d1=DS(value="MBRM120"); d1[2]+=swb; d1[1]+=p18
c4=C("22uF","Capacitor_SMD:C_1206_3216Metric"); p18+=c4[1]; c4[2]+=gnd; sw["VPOS"]+=p18
r1=R(value="1.4M"); r2=R(value="100k"); c9=C("6.8pF"); p18+=r1[1]; r1[2]+=Net("FBP"); fbp=r1[2]
c9[1]+=p18; c9[2]+=fbp; r2[1]+=fbp; r2[2]+=gnd; sw["FBP"]+=fbp
r7=R(value="100"); c3=C("100nF"); p5+=r7[1]; r7[2]+=Net("INN_F"); innf=r7[2]; c3[1]+=innf; c3[2]+=gnd
sw["INN"]+=innf; sw["INN2"]+=innf
l2=L(value="4.7uH"); swi=Net("SW_INV"); sw["OUTN"]+=swi; sw["OUTN2"]+=swi
l2[1]+=swi; l2[2]+=gnd; d2=DS(value="MBRM120"); d2[1]+=swi; d2[2]+=n18
c5=C("22uF","Capacitor_SMD:C_1206_3216Metric"); n18+=c5[1]; c5[2]+=gnd; sw["VNEG"]+=n18
r3=R(value="1.5M"); r4=R(value="100k"); c10=C("7.5pF"); n18+=r3[1]; r3[2]+=Net("FBN"); fbn=r3[2]
c10[1]+=n18; c10[2]+=fbn; r4[1]+=vref; r4[2]+=fbn; sw["FBN"]+=fbn
sw["VREF"]+=vref; c8=C("220nF"); vref+=c8[1]; c8[2]+=gnd
c7=C("4.7nF"); sw["CP"]+=c7[1]; c7[2]+=gnd; c6=C("10nF"); sw["CN"]+=c6[1]; c6[2]+=gnd
pos["IN"]+=p18; ci=C("1uF"); p18+=ci[1]; ci[2]+=gnd; pos["OUT"]+=p15; co=C("2.2uF"); p15+=co[1]; co[2]+=gnd
pos["GND"]+=gnd; pos["EP"]+=gnd; pos["EN"]+=p18
rtp=R(value="116k"); rbp=R(value="10k"); p15+=rtp[1]; rtp[2]+=pos["FB"]; rbp[1]+=pos["FB"]; rbp[2]+=gnd
cnp=C("10nF"); pos["NR"]+=cnp[1]; cnp[2]+=gnd
neg["IN"]+=n18; cin=C("1uF"); n18+=cin[1]; cin[2]+=gnd; neg["OUT"]+=n15; con=C("2.2uF"); n15+=con[1]; con[2]+=gnd
neg["GND"]+=gnd; neg["EP"]+=gnd; neg["EN"]+=n18
rtn=R(value="117k"); rbn=R(value="10k"); n15+=rtn[1]; rtn[2]+=neg["FB"]; rbn[1]+=neg["FB"]; rbn[2]+=gnd
cnn=C("10nF"); neg["NR"]+=cnn[1]; cnn[2]+=gnd
reg3["VIN"]+=p5; reg3["EN"]+=p5; reg3["GND"]+=gnd; reg3["VOUT"]+=p3v3
ci3=C("1uF"); p5+=ci3[1]; ci3[2]+=gnd; co3=C("1uF"); p3v3+=co3[1]; co3[2]+=gnd
endgrp(g)
# ============================ RP2350 CORE ============================
g = grp("MCU")
rp = Part("MCU_RaspberryPi","RP2350A", footprint="Package_DFN_QFN:QFN-60-1EP_7x7mm_P0.4mm_EP3.4x3.4mm")
for n in (1,11,20,30,38,45): rp[n]+=p3v3
for n in (6,23,39): rp[n]+=dvdd
rp[53]+=p3v3; rp[54]+=p3v3; rp[49]+=p3v3; rp[47]+=gnd; rp[61]+=gnd
lc=L(value="3.3uH"); rp[48]+=lc[1]; lc[2]+=dvdd; rp[50]+=dvdd
cc=C("1uF"); dvdd+=cc[1]; cc[2]+=gnd; cvin=C("4.7uF"); rp[49]+=cvin[1]; cvin[2]+=gnd
rav=R(value="33"); cav=C("4.7uF"); p3v3+=rav[1]; rav[2]+=rp[46]; rp[46]+=cav[1]; cav[2]+=gnd
rad=R(value="0"); cad=C("100nF"); p3v3+=rad[1]; rad[2]+=rp[44]; rp[44]+=cad[1]; cad[2]+=gnd
for _ in range(6): dcp(p3v3)
for _ in range(2): dcp(dvdd)
rp[21]+=xin; rp[22]+=xout
xt=Part("Device","Crystal",value="12MHz",footprint="Crystal:Crystal_SMD_2012-2Pin_2.0x1.2mm") # 2-pin matches the 2-pin symbol (was a 4-pad fp -> Y1 pads 3/4 had no symbol pin). Set to your chosen crystal's footprint; if 4-pad, ground the case pads.
xin+=xt[1]; xout+=xt[2]; cx1=C("15pF"); cx2=C("15pF"); xin+=cx1[1]; cx1[2]+=gnd; xout+=cx2[1]; cx2[2]+=gnd
FL=mk("W25Q128JVS",[Pin(num=1,name="CS",func=P.INPUT),Pin(num=2,name="IO1",func=P.BIDIR),Pin(num=3,name="IO2",func=P.BIDIR),
Pin(num=4,name="GND",func=P.PWRIN),Pin(num=5,name="IO0",func=P.BIDIR),Pin(num=6,name="CLK",func=P.INPUT),
Pin(num=7,name="IO3",func=P.BIDIR),Pin(num=8,name="VCC",func=P.PWRIN)],fp="Package_SO:SOIC-8_5.3x5.3mm_P1.27mm")
fl=FL(); fl["CLK"]+=qsck; fl["IO0"]+=qd0; fl["IO1"]+=qd1; fl["IO2"]+=qd2; fl["IO3"]+=qd3; fl["CS"]+=qcs
fl["VCC"]+=p3v3; fl["GND"]+=gnd; dcp(p3v3)
rp[56]+=qsck; rp[57]+=qd0; rp[59]+=qd1; rp[58]+=qd2; rp[55]+=qd3; rp[60]+=qcs
rbt=R(value="1k"); swb2=Part("Switch","SW_Push",footprint="Button_Switch_SMD:SW_SPST_SKQG_WithStem")
qcs+=rbt[1]; rbt[2]+=swb2[1]; swb2[2]+=gnd
rru=R(value="10k"); swr=Part("Switch","SW_Push",footprint="Button_Switch_SMD:SW_SPST_SKQG_WithStem")
p3v3+=rru[1]; rru[2]+=rp[26]; rp[26]+=swr[1]; swr[2]+=gnd; cru=C("100nF"); rp[26]+=cru[1]; cru[2]+=gnd
swd=Part("Connector_Generic","Conn_01x04",footprint="Connector_PinHeader_1.27mm:PinHeader_1x04_P1.27mm_Vertical")
swd[1]+=p3v3; swd[2]+=rp[25]; swd[3]+=rp[24]; swd[4]+=gnd
rdp=R(value="27"); rdm=R(value="27"); rp[52]+=rdp[1]; rdp[2]+=usb_dp_c; rp[51]+=rdm[1]; rdm[2]+=usb_dm_c
rp["GPIO2"]+=spi_sck; rp["GPIO3"]+=spi_mosi; rp["GPIO5"]+=lcd_cs; rp["GPIO6"]+=lcd_dc; rp["GPIO7"]+=lcd_rst
rp["GPIO8"]+=i2c_sda; rp["GPIO9"]+=i2c_scl; rp["GPIO10"]+=i2s_bck; rp["GPIO11"]+=i2s_lrck; rp["GPIO13"]+=i2s_din
rp["GPIO12"]+=ws2812; rp["GPIO14"]+=btn_b; rp["GPIO15"]+=btn_a
rp["GPIO16"]+=sel_linst; rp["GPIO17"]+=gndlift_en; rp["GPIO18"]+=mute_en
rp["GPIO19"]+=sig_led; rp["GPIO20"]+=clip_led; rp["GPIO21"]+=gndlift_sw; rp["GPIO22"]+=lineinst_sw
rp["GPIO26/ADC0"]+=joy_x; rp["GPIO27/ADC1"]+=joy_y; rp["GPIO0"]+=dac_xsmt
rp["GPIO4"]+=midi_tx; rp["GPIO1"]+=midi_rx
endgrp(g)
# ============================ AUDIO CHAIN ============================
g = grp("Audio")
THAT1240=mk("THAT1240",[Pin(num=1,name="REF",func=P.INPUT),Pin(num=2,name="IN-",func=P.INPUT),Pin(num=3,name="IN+",func=P.INPUT),
Pin(num=4,name="V-",func=P.PWRIN),Pin(num=5,name="SENSE",func=P.PASSIVE),Pin(num=6,name="OUT",func=P.OUTPUT),
Pin(num=7,name="V+",func=P.PWRIN),Pin(num=8,name="NC",func=P.NOCONNECT)])
OPA1641=mk("OPA1641",[Pin(num=1,name="NC1",func=P.NOCONNECT),Pin(num=2,name="-IN",func=P.INPUT),Pin(num=3,name="+IN",func=P.INPUT),
Pin(num=4,name="V-",func=P.PWRIN),Pin(num=5,name="NC5",func=P.NOCONNECT),Pin(num=6,name="OUT",func=P.OUTPUT),
Pin(num=7,name="V+",func=P.PWRIN),Pin(num=8,name="NC8",func=P.NOCONNECT)])
OPA1612=mk("OPA1612",[Pin(num=1,name="OUTA",func=P.OUTPUT),Pin(num=2,name="-INA",func=P.INPUT),Pin(num=3,name="+INA",func=P.INPUT),
Pin(num=4,name="V-",func=P.PWRIN),Pin(num=5,name="+INB",func=P.INPUT),Pin(num=6,name="-INB",func=P.INPUT),
Pin(num=7,name="OUTB",func=P.OUTPUT),Pin(num=8,name="V+",func=P.PWRIN)])
THAT1646=mk("THAT1646",[Pin(num=1,name="OUT-",func=P.OUTPUT),Pin(num=2,name="SNS-",func=P.INPUT),Pin(num=3,name="GND",func=P.PWRIN),
Pin(num=4,name="IN",func=P.INPUT),Pin(num=5,name="V-",func=P.PWRIN),Pin(num=6,name="V+",func=P.PWRIN),
Pin(num=7,name="SNS+",func=P.INPUT),Pin(num=8,name="OUT+",func=P.OUTPUT)])
PCM5102A=mk("PCM5102A",[Pin(num=1,name="CPVDD",func=P.PWRIN),Pin(num=2,name="CAPP",func=P.PASSIVE),Pin(num=3,name="CPGND",func=P.PWRIN),
Pin(num=4,name="CAPM",func=P.PASSIVE),Pin(num=5,name="VNEG",func=P.PASSIVE),Pin(num=6,name="OUTL",func=P.OUTPUT),
Pin(num=7,name="OUTR",func=P.OUTPUT),Pin(num=8,name="AVDD",func=P.PWRIN),Pin(num=9,name="AGND",func=P.PWRIN),
Pin(num=10,name="DEMP",func=P.INPUT),Pin(num=11,name="FLT",func=P.INPUT),Pin(num=12,name="SCK",func=P.INPUT),
Pin(num=13,name="BCK",func=P.INPUT),Pin(num=14,name="DIN",func=P.INPUT),Pin(num=15,name="LRCK",func=P.INPUT),
Pin(num=16,name="FMT",func=P.INPUT),Pin(num=17,name="XSMT",func=P.INPUT),Pin(num=18,name="LDOO",func=P.PWROUT),
Pin(num=19,name="DGND",func=P.PWRIN),Pin(num=20,name="DVDD",func=P.PWRIN)],fp="Package_SO:TSSOP-20_4.4x6.5mm_P0.65mm")
TQ2=mk("TQ2SA-5V",[Pin(num=1,name="COIL_A",func=P.PASSIVE),Pin(num=10,name="COIL_B",func=P.PASSIVE),
Pin(num=3,name="P1_COM",func=P.PASSIVE),Pin(num=4,name="P1_NC",func=P.PASSIVE),Pin(num=2,name="P1_NO",func=P.PASSIVE),
Pin(num=8,name="P2_COM",func=P.PASSIVE),Pin(num=7,name="P2_NC",func=P.PASSIVE),Pin(num=9,name="P2_NO",func=P.PASSIVE),
Pin(num=5,name="NC5",func=P.NOCONNECT),Pin(num=6,name="NC6",func=P.NOCONNECT)],ref="K",fp="pm_k1:Relay_DPDT_Panasonic_TQ2-SA")
ULN=mk("ULN2003A",[Pin(num=1,name="1B",func=P.INPUT),Pin(num=2,name="2B",func=P.INPUT),Pin(num=3,name="3B",func=P.INPUT),
Pin(num=4,name="4B",func=P.INPUT),Pin(num=5,name="5B",func=P.INPUT),Pin(num=6,name="6B",func=P.INPUT),Pin(num=7,name="7B",func=P.INPUT),
Pin(num=8,name="GND",func=P.PWRIN),Pin(num=9,name="COM",func=P.PWRIN),Pin(num=10,name="7C",func=P.OPENCOLL),
Pin(num=11,name="6C",func=P.OPENCOLL),Pin(num=12,name="5C",func=P.OPENCOLL),Pin(num=13,name="4C",func=P.OPENCOLL),
Pin(num=14,name="3C",func=P.OPENCOLL),Pin(num=15,name="2C",func=P.OPENCOLL),Pin(num=16,name="1C",func=P.OPENCOLL)],
fp="Package_SO:SOIC-16_3.9x9.9mm_P1.27mm")
rx=THAT1240(); dib=OPA1641(); dac=PCM5102A(); oa=OPA1612(); drv=THAT1646()
k1=TQ2(); k2=TQ2(); k3=TQ2(); uln=ULN()
def protect_bal(src):
cb=C("2.2uF","Capacitor_SMD:C_1206_3216Metric"); rs=R(value="1k"); rb=R(value="1Meg")
dp=D(value="1N4148WS"); dn=D(value="1N4148WS"); node=Net()
src+=cb[1]; cb[2]+=rs[1]; rs[2]+=node; rb[1]+=node; rb[2]+=gnd
dp[1]+=p15; dp[2]+=node; dn[1]+=node; dn[2]+=n15; return node
rx["IN+"]+=protect_bal(rx_hot_in); rx["IN-"]+=protect_bal(ain_cold)
rx["REF"]+=gnd; rx["SENSE"]+=rx_out; rx["OUT"]+=rx_out; rx["V+"]+=p15; rx["V-"]+=n15; dcp(p15); dcp(n15)
# DI buffer
cbk2=C("100nF","Capacitor_SMD:C_1206_3216Metric"); rbias=R(value="1Meg"); dpi=D(value="1N4148WS"); dni=D(value="1N4148WS"); dn_=Net()
di_in+=cbk2[1]; cbk2[2]+=dn_; rbias[1]+=dn_; rbias[2]+=gnd; dpi[1]+=p15; dpi[2]+=dn_; dni[1]+=dn_; dni[2]+=n15
dib["+IN"]+=dn_; rf2=R(value="3k"); rg2=R(value="1k"); dib["OUT"]+=di_out; rf2[1]+=di_out; rf2[2]+=dib["-IN"]
rg2[1]+=dib["-IN"]; rg2[2]+=gnd; dib["V+"]+=p15; dib["V-"]+=n15; dcp(p15); dcp(n15)
# select relay K1
k1["P1_COM"]+=ain_hot; k1["P1_NC"]+=rx_hot_in; k1["P1_NO"]+=di_in
k1["P2_COM"]+=stage1_out; k1["P2_NC"]+=rx_out; k1["P2_NO"]+=di_out; k1["COIL_A"]+=p5; k1["COIL_B"]+=k1d
# DAC
for pin in ("AVDD","CPVDD","DVDD"): dac[pin]+=p3v3
for pin in ("AGND","DGND","CPGND"): dac[pin]+=gnd
for pin in ("AVDD","CPVDD","DVDD"): dcp(p3v3)
cbd=C("10uF","Capacitor_SMD:C_1206_3216Metric"); dac["AVDD"]+=cbd[1]; cbd[2]+=gnd
cfly=C("2.2uF"); dac["CAPP"]+=cfly[1]; dac["CAPM"]+=cfly[2]; cvn=C("2.2uF"); dac["VNEG"]+=cvn[1]; cvn[2]+=gnd
cld=C("1uF"); dac["LDOO"]+=cld[1]; cld[2]+=gnd
dac["DEMP"]+=gnd; dac["FLT"]+=gnd; dac["FMT"]+=gnd; dac["SCK"]+=gnd # MCLK-less: SCK to GND (internal PLL)
dac["XSMT"]+=dac_xsmt; rpu=R(value="10k"); dac_xsmt+=rpu[1]; rpu[2]+=p3v3
dac["BCK"]+=i2s_bck; dac["DIN"]+=i2s_din; dac["LRCK"]+=i2s_lrck
rld=R(value="2.2k"); dac["OUTR"]+=rld[1]; rld[2]+=gnd
# recon filter = OPA1612 A
rfa=R(value="1.5k"); rfb=R(value="1.5k"); ca=C("2.2nF"); cbq=C("1nF"); rca=Net()
dac["OUTL"]+=rfa[1]; rfa[2]+=rca; rfb[1]+=rca; rfb[2]+=oa["+INA"]; ca[1]+=rca; ca[2]+=oa["OUTA"]
cbq[1]+=oa["+INA"]; cbq[2]+=gnd; oa["-INA"]+=oa["OUTA"]; oa["OUTA"]+=click_out
oa["V+"]+=p15; oa["V-"]+=n15; dcp(p15); dcp(n15)
# summer = OPA1612 B
ris=R(value="10k"); ric=R(value="10k"); rfs=R(value="10k")
stage1_out+=ris[1]; ris[2]+=oa["-INB"]; click_out+=ric[1]; ric[2]+=oa["-INB"]
rfs[1]+=oa["-INB"]; rfs[2]+=oa["OUTB"]; oa["+INB"]+=gnd; oa["OUTB"]+=mix_out
# level trim + THAT1646 + build-out
RV=Part("Device","R_Potentiometer",dest=TEMPLATE,footprint="Potentiometer_THT:Potentiometer_Bourns_3296W_Vertical")
rv1=RV(value="10k"); mix_out+=rv1[1]; rv1[3]+=gnd; rv1[2]+=drv["IN"]
drv["SNS-"]+=drv["OUT-"]; drv["SNS+"]+=drv["OUT+"]; drv["GND"]+=gnd; drv["V+"]+=p15; drv["V-"]+=n15; dcp(p15); dcp(n15)
rbo=R(value="47"); rbc=R(value="47"); drv["OUT-"]+=rbo[1]; rbo[2]+=aout_hot; drv["OUT+"]+=rbc[1]; rbc[2]+=aout_cold
# mute K2 + ground-lift K3
k2["P1_COM"]+=aout_hot; k2["P1_NC"]+=gnd; k2["P2_COM"]+=aout_cold; k2["P2_NC"]+=gnd; k2["COIL_A"]+=p5; k2["COIL_B"]+=k2d
k3["P1_COM"]+=gnd; k3["P1_NC"]+=chassis; rl=R(value="100"); cl=C("10nF")
rl[1]+=gnd; rl[2]+=chassis; cl[1]+=gnd; cl[2]+=chassis; k3["COIL_A"]+=p5; k3["COIL_B"]+=k3d
# shared relay driver
uln["1B"]+=sel_linst; uln["1C"]+=k1d; uln["2B"]+=mute_en; uln["2C"]+=k2d; uln["3B"]+=gndlift_en; uln["3C"]+=k3d
uln["GND"]+=gnd; uln["COM"]+=p5
endgrp(g)
# ============================ RTC ============================
g = grp("RTC")
RV8803=mk("RV-8803-C7",[Pin(num=1,name="SDA",func=P.BIDIR),Pin(num=2,name="CLKOUT",func=P.OUTPUT),Pin(num=3,name="VDD",func=P.PWRIN),
Pin(num=4,name="CLKOE",func=P.INPUT),Pin(num=5,name="VSS",func=P.PWRIN),Pin(num=6,name="INT",func=P.OPENCOLL),
Pin(num=7,name="EVI",func=P.INPUT),Pin(num=8,name="SCL",func=P.INPUT)],fp="pm_k1:RV-8803-C7")
rtc=RV8803(); rtc["VDD"]+=vdd_rtc; rtc["VSS"]+=gnd; rtc["SDA"]+=i2c_sda; rtc["SCL"]+=i2c_scl
rtc["CLKOE"]+=gnd; rtc["EVI"]+=gnd; rtc["INT"]+=rtc_int
db1=DS(value="BAT54"); db2=DS(value="BAT54"); p3v3+=db1[2]; db1[1]+=vdd_rtc
bt=Part("Device","Battery_Cell",value="CR2032",footprint="Battery:BatteryHolder_Keystone_1060_1x2032")
bt["+"]+=db2[2]; db2[1]+=vdd_rtc; bt["-"]+=gnd; crt=C("100nF"); vdd_rtc+=crt[1]; crt[2]+=gnd
for net in (i2c_sda,i2c_scl):
rpu2=R(value="4.7k"); net+=rpu2[1]; rpu2[2]+=p3v3
rint=R(value="10k"); rtc_int+=rint[1]; rint[2]+=p3v3
endgrp(g)
# ============================ MIDI (DNP) ============================
g = grp("MIDI")
H11L1=mk("H11L1",[Pin(num=1,name="A",func=P.PASSIVE),Pin(num=2,name="C",func=P.PASSIVE),Pin(num=3,name="NC",func=P.NOCONNECT),
Pin(num=4,name="GND",func=P.PWRIN),Pin(num=5,name="VO",func=P.OPENCOLL),Pin(num=6,name="VCC",func=P.PWRIN)],fp="Package_DIP:DIP-6_W7.62mm")
LVC14=mk("74LVC14",[Pin(num=1,name="1A",func=P.INPUT),Pin(num=2,name="1Y",func=P.OUTPUT),Pin(num=3,name="2A",func=P.INPUT),
Pin(num=4,name="2Y",func=P.OUTPUT),Pin(num=5,name="3A",func=P.INPUT),Pin(num=6,name="3Y",func=P.OUTPUT),Pin(num=7,name="GND",func=P.PWRIN),
Pin(num=8,name="4Y",func=P.OUTPUT),Pin(num=9,name="4A",func=P.INPUT),Pin(num=10,name="5Y",func=P.OUTPUT),Pin(num=11,name="5A",func=P.INPUT),
Pin(num=12,name="6Y",func=P.OUTPUT),Pin(num=13,name="6A",func=P.INPUT),Pin(num=14,name="VCC",func=P.PWRIN)],fp="Package_SO:TSSOP-14_4.4x5mm_P0.65mm")
opto=H11L1(); buf=LVC14()
rin=R(value="220"); dpr=D(value="1N4148WS"); mi_a+=rin[1]; rin[2]+=opto["A"]; opto["C"]+=mi_b
dpr[2]+=opto["C"]; dpr[1]+=opto["A"]; opto["VCC"]+=p3v3; opto["GND"]+=gnd
rvo=R(value="10k"); opto["VO"]+=midi_rx; midi_rx+=rvo[1]; rvo[2]+=p3v3; dcp(p3v3)
buf["1A"]+=midi_tx; buf["1Y"]+=Net(); buf["2A"]+=buf["1Y"]; rob=R(value="33"); buf["2Y"]+=rob[1]; rob[2]+=mo_b
roa=R(value="33"); p3v3+=roa[1]; roa[2]+=mo_a
buf["3A"]+=midi_rx; buf["3Y"]+=Net(); buf["4A"]+=buf["3Y"]; rtb=R(value="33"); buf["4Y"]+=rtb[1]; rtb[2]+=mt_b
rta=R(value="33"); p3v3+=rta[1]; rta[2]+=mt_a; buf["5A"]+=gnd; buf["6A"]+=gnd; buf["VCC"]+=p3v3; buf["GND"]+=gnd; dcp(p3v3)
endgrp(g)
# ============================ INDICATOR (DNP) ============================
g = grp("Indicator")
LM393=mk("LM393",[Pin(num=1,name="OUT1",func=P.OPENCOLL),Pin(num=2,name="-IN1",func=P.INPUT),Pin(num=3,name="+IN1",func=P.INPUT),
Pin(num=4,name="V-",func=P.PWRIN),Pin(num=5,name="+IN2",func=P.INPUT),Pin(num=6,name="-IN2",func=P.INPUT),
Pin(num=7,name="OUT2",func=P.OPENCOLL),Pin(num=8,name="V+",func=P.PWRIN)])
cmp=LM393(); cmp["V+"]+=p15; cmp["V-"]+=gnd; dcp(p15)
def peak(src):
d=DS(value="BAT54"); ch=C("100nF"); rb=R(value="100k"); node=Net()
src+=d[2]; d[1]+=node; ch[1]+=node; ch[2]+=gnd; rb[1]+=node; rb[2]+=gnd; return node
def thr(t,b):
n=Net(); rt=R(value=t); rb=R(value=b); rt[1]+=p15; rt[2]+=n; rb[1]+=n; rb[2]+=gnd; return n
cmp["+IN1"]+=peak(stage1_out); cmp["-IN1"]+=thr("1Meg","10k")
cmp["+IN2"]+=peak(mix_out); cmp["-IN2"]+=thr("100k","68k")
rsl=R(value="10k"); cmp["OUT1"]+=sig_led; sig_led+=rsl[1]; rsl[2]+=p3v3
rcl=R(value="10k"); cmp["OUT2"]+=clip_led; clip_led+=rcl[1]; rcl[2]+=p3v3
endgrp(g)
# ============================ SPEAKER (DNP) ============================
g = grp("Speaker")
PAM=mk("PAM8302A",[Pin(num=1,name="SD",func=P.INPUT),Pin(num=2,name="NC",func=P.NOCONNECT),Pin(num=3,name="IN+",func=P.INPUT),
Pin(num=4,name="IN-",func=P.INPUT),Pin(num=5,name="VO+",func=P.OUTPUT),Pin(num=6,name="VDD",func=P.PWRIN),
Pin(num=7,name="GND",func=P.PWRIN),Pin(num=8,name="VO-",func=P.OUTPUT)])
amp=PAM(); amp["VDD"]+=p5; amp["GND"]+=gnd; cba=C("1uF"); p5+=cba[1]; cba[2]+=gnd; dcp(p5)
rsd=R(value="100k"); spk_sd+=rsd[1]; rsd[2]+=p5; amp["SD"]+=spk_sd
cia=C("1uF"); ria=R(value="68k"); mix_out+=cia[1]; cia[2]+=ria[1]; ria[2]+=amp["IN+"]
cim=C("1uF"); amp["IN-"]+=cim[1]; cim[2]+=gnd; amp["VO+"]+=spk_p; amp["VO-"]+=spk_n
endgrp(g)
# ============================ INTERCONNECTS ============================
g = grp("Interconnect")
def hdr(name,fp): return Part("Connector_Generic",name,footprint=fp)
j3=hdr("Conn_02x13_Odd_Even","Connector_PinHeader_2.54mm:PinHeader_2x13_P2.54mm_Vertical")
for pin,net in {1:p5,2:gnd,3:p3v3,4:gnd,5:spi_sck,6:gnd,7:spi_mosi,8:lcd_cs,9:lcd_dc,10:lcd_rst,11:gnd,12:i2c_sda,
13:i2c_scl,14:gnd,15:joy_x,16:joy_y,17:btn_a,18:btn_b,19:ws2812,20:gnd,21:gndlift_sw,22:lineinst_sw,
23:sig_led,24:clip_led,25:gnd,26:gnd}.items(): j3[pin]+=net
j4=hdr("Conn_02x05_Odd_Even","Connector_PinHeader_2.54mm:PinHeader_2x05_P2.54mm_Vertical")
for pin,net in {1:aout_hot,2:gnd,3:aout_cold,4:chassis,5:ain_hot,6:gnd,7:ain_cold,8:spk_p,9:gnd,10:spk_n}.items(): j4[pin]+=net
j5=hdr("Conn_01x08","Connector_PinHeader_2.54mm:PinHeader_1x08_P2.54mm_Vertical")
for pin,net in {1:mo_a,2:mo_b,3:mi_a,4:mi_b,5:mt_a,6:mt_b,7:p5,8:gnd}.items(): j5[pin]+=net
j1=Part("Connector","USB_C_Receptacle",footprint="Connector_USB:USB_C_Receptacle_HRO_TYPE-C-31-M-12")
j1["VBUS"]+=vbus; j1["GND"]+=gnd; j1["D+"]+=usb_dp_c; j1["D-"]+=usb_dm_c
# USB shell/shield -> chassis is tied at LAYOUT (the symbol's shield pin "S1" mismatches older
# KiCad footprints that name the shell pads "SH" -> would error on import). Ground the shell to
# CHASSIS in Pcbnew directly, or via the usual 1Mohm || small-cap.
rc1=R(value="5.1k"); rc2=R(value="5.1k"); j1["CC1"]+=rc1[1]; rc1[2]+=gnd; j1["CC2"]+=rc2[1]; rc2[2]+=gnd
ESD=mk("USBLC6-2SC6",[Pin(num=1,name="IO1",func=P.PASSIVE),Pin(num=2,name="GND",func=P.PWRIN),Pin(num=3,name="IO2",func=P.PASSIVE),
Pin(num=4,name="IO2b",func=P.PASSIVE),Pin(num=5,name="VBUS",func=P.PASSIVE),Pin(num=6,name="IO1b",func=P.PASSIVE)],fp="Package_TO_SOT_SMD:SOT-23-6")
esd=ESD(); esd[1]+=usb_dp_c; esd[6]+=usb_dp_c; esd[3]+=usb_dm_c; esd[4]+=usb_dm_c; esd[2]+=gnd; esd[5]+=vbus
endgrp(g)
ERC()
out = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "kicad", "board.net"))
generate_netlist(file_=out)
print("FULL BOARD netlist ->", out)