circuits/mcu_core.py using the authoritative KiCad MCU_RaspberryPi:RP2350A symbol. Minimal design per RP "Hardware design with RP2350" (RP-008280): - Core SMPS: VREG_VIN<-3V3, VREG_LX->3.3uH->DVDD, VREG_FB senses DVDD; VREG_AVDD via 33ohm+4.7uF RC filter; ADC_AVDD filtered; 100nF per power pin. - 12MHz crystal, MCLK-LESS (RP2350 makes I2S BCK/LRCK/DIN; PCM5102A uses its internal PLL) -- no audio oscillator, no MCLK net. Cheaper/simpler/robust; inaudible difference for a metronome (decided with the user). - W25Q128JVS QSPI flash (Fig-8 pinout); BOOTSEL = QSPI_SS via 1k + button; RUN 10k pull-up + reset button; SWD header; USB D+/D- via 27ohm series. - Full GPIO map assigned (DESIGN.md s7.1 + audio control: SPI/I2C/ADC/buttons/LED + I2S + relay-enable/mute/gnd-lift + DAC_XSMT). ERC 0 errors; netlist 0 errors. CONFIRM at layout: crystal load caps, QFN-60 footprint, and the USB-C connector + USBLC6-2 ESD + CC resistors (USB sub-block; D+/D- exit on 27R). Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
122 lines
6.8 KiB
Python
122 lines
6.8 KiB
Python
#!/usr/bin/env python3
|
|
"""PM_K-1 RP2350 core (SKiDL): MCU + QSPI flash + 12MHz crystal (MCLK-less) + USB + boot/reset + SWD.
|
|
|
|
Run INSIDE the EDA container:
|
|
cd hardware/eda && ./run.sh python3 ../eda/circuits/mcu_core.py
|
|
Outputs ERC + hardware/kicad/mcu_core.net.
|
|
|
|
VERIFIED
|
|
* RP2350A pinout: the authoritative KiCad MCU_RaspberryPi:RP2350A library symbol
|
|
(datasheet-derived). Power/clock/QSPI/USB/debug pins referenced by NUMBER, GPIO by name.
|
|
* Minimal design per RP "Hardware design with RP2350" (RP-008280): core SMPS
|
|
VREG_LX -> 3.3uH -> DVDD, VREG_FB sense to DVDD; VREG_AVDD via 33ohm+4.7uF RC filter;
|
|
100nF per power pin; W25Q128JVS QSPI flash (Fig 8 pinout); BOOTSEL = QSPI_SS via 1k +
|
|
button; RUN 10k pull-up + reset button; USB D+/D- via 27ohm series.
|
|
* CLOCK = 12MHz crystal, MCLK-LESS: RP2350 generates I2S BCK/LRCK/DIN; the PCM5102A
|
|
derives its own clock (internal PLL), so no separate audio oscillator and no MCLK net.
|
|
|
|
CONFIRM AT LAYOUT (flagged, not guessed): crystal load-cap value (~15pF, per chosen
|
|
crystal) + possible XOUT series R; QFN-60 footprint variant; and the USB-C connector +
|
|
USBLC6-2 ESD + CC resistors (a small USB sub-block; parts in BOM) -- their pinouts to be
|
|
verified then. Here USB exits via 27ohm series to USB_DP_CONN/USB_DM_CONN.
|
|
|
|
GPIO MAP (DESIGN.md s7.1 + audio control): see assignments at the bottom.
|
|
"""
|
|
import os
|
|
from skidl import *
|
|
set_default_tool(KICAD9)
|
|
P = Pin.types
|
|
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)
|
|
|
|
# ---- nets ----
|
|
p3v3, gnd, dvdd, vbus = Net("+3V3"), Net("GND"), Net("DVDD"), Net("VBUS_5V")
|
|
for n in (p3v3, vbus): n.drive = POWER
|
|
gnd.drive = POWER; dvdd.drive = POWER
|
|
xin, xout = Net("XIN"), Net("XOUT")
|
|
qsck,qd0,qd1,qd2,qd3,qcs = (Net("QSPI_SCLK"),Net("QSPI_SD0"),Net("QSPI_SD1"),Net("QSPI_SD2"),Net("QSPI_SD3"),Net("QSPI_SS"))
|
|
usb_dp_c, usb_dm_c = Net("USB_DP_CONN"), Net("USB_DM_CONN")
|
|
# audio + control (shared with audio chain / interconnect by name)
|
|
i2s_bck,i2s_lrck,i2s_din = Net("I2S_BCK"),Net("I2S_LRCK"),Net("I2S_DIN")
|
|
sel_linst,mute_en,gndlift_en,dac_xsmt = Net("SEL_LINST"),Net("MUTE_EN"),Net("GNDLIFT_EN"),Net("DAC_XSMT")
|
|
sig_led,clip_led,gndlift_sw,lineinst_sw = Net("SIG_LED"),Net("CLIP_LED"),Net("GNDLIFT_SW"),Net("LINEINST_SW")
|
|
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"))
|
|
|
|
# ---- RP2350A (authoritative KiCad symbol) ----
|
|
rp = Part("MCU_RaspberryPi","RP2350A", footprint="Package_DFN_QFN:QFN-60-1EP_7x7mm_P0.4mm_EP3.6x3.6mm", ref="U1")
|
|
|
|
# power: IOVDD x6, DVDD x3, plus the special supplies (by pin number)
|
|
for n in (1,11,20,30,38,45): rp[n] += p3v3 # IOVDD
|
|
for n in (6,23,39): rp[n] += dvdd # DVDD (1.1V core out)
|
|
rp[53] += p3v3; rp[54] += p3v3; rp[49] += p3v3 # USB_OTP_VDD, QSPI_IOVDD, VREG_VIN
|
|
rp[47] += gnd; rp[61] += gnd # VREG_PGND, GND/EP
|
|
# core SMPS: VREG_LX(48) -> 3.3uH -> DVDD ; VREG_FB(50) senses DVDD
|
|
lcore = Part("Device","L", value="3.3uH", footprint="Inductor_SMD:L_0806_2016Metric", ref="L1")
|
|
rp[48] += lcore[1]; lcore[2] += dvdd; rp[50] += dvdd
|
|
ccore = C("1uF","Capacitor_SMD:C_0402_1005Metric"); dvdd += ccore[1]; ccore[2] += gnd
|
|
cvin = C("4.7uF","Capacitor_SMD:C_0805_2012Metric"); rp[49] += cvin[1]; cvin[2] += gnd
|
|
# VREG_AVDD(46): 33ohm + 4.7uF RC filter from 3V3
|
|
rav = R(value="33"); cav = C("4.7uF","Capacitor_SMD:C_0805_2012Metric")
|
|
p3v3 += rav[1]; rav[2] += rp[46]; rp[46] += cav[1]; cav[2] += gnd
|
|
# ADC_AVDD(44): ferrite/0R + 100nF
|
|
rad = R(value="0"); cad = C("100nF"); p3v3 += rad[1]; rad[2] += rp[44]; rp[44] += cad[1]; cad[2] += gnd
|
|
# bulk decoupling (per-power-pin 100nF; placement is a layout concern)
|
|
for _ in range(6):
|
|
c = C("100nF"); p3v3 += c[1]; c[2] += gnd
|
|
for _ in range(2):
|
|
c = C("100nF"); dvdd += c[1]; c[2] += gnd
|
|
|
|
# ---- 12MHz crystal (MCLK-less) ----
|
|
rp[21] += xin; rp[22] += xout
|
|
xtal = Part("Device","Crystal", value="12MHz", footprint="Crystal:Crystal_SMD_3225-4Pin_3.2x2.5mm", ref="Y1")
|
|
xin += xtal[1]; xout += xtal[2]
|
|
cx1 = C("15pF"); cx2 = C("15pF"); xin += cx1[1]; cx1[2] += gnd; xout += cx2[1]; cx2[2] += gnd
|
|
|
|
# ---- QSPI flash W25Q128JVS (pinout per RP2350 hw-design Fig 8) ----
|
|
FL = Part(name="W25Q128JVS", tool=SKIDL, dest=TEMPLATE, ref_prefix="U",
|
|
footprint="Package_SO:SOIC-8_5.23x5.23mm_P1.27mm",
|
|
pins=[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)])
|
|
fl = FL(ref="U2")
|
|
fl["CLK"]+=qsck; fl["IO0"]+=qd0; fl["IO1"]+=qd1; fl["IO2"]+=qd2; fl["IO3"]+=qd3; fl["CS"]+=qcs
|
|
fl["VCC"]+=p3v3; fl["GND"]+=gnd
|
|
cfl = C("100nF"); p3v3 += cfl[1]; cfl[2] += gnd
|
|
rp[56]+=qsck; rp[57]+=qd0; rp[59]+=qd1; rp[58]+=qd2; rp[55]+=qd3; rp[60]+=qcs # QSPI_SCLK/SD0/SD1/SD2/SD3/SS
|
|
|
|
# ---- BOOTSEL: QSPI_SS -> 1k -> button -> GND ----
|
|
rboot = R(value="1k"); swboot = Part("Switch","SW_Push", footprint="Button_Switch_SMD:SW_SPST_SKQG_WithStem", ref="SW1")
|
|
qcs += rboot[1]; rboot[2] += swboot[1]; swboot[2] += gnd
|
|
|
|
# ---- RUN: 10k pull-up + reset button + 100nF ----
|
|
rrun = R(value="10k"); swrun = Part("Switch","SW_Push", footprint="Button_Switch_SMD:SW_SPST_SKQG_WithStem", ref="SW2")
|
|
p3v3 += rrun[1]; rrun[2] += rp[26]; rp[26] += swrun[1]; swrun[2] += gnd
|
|
crun = C("100nF"); rp[26] += crun[1]; crun[2] += gnd
|
|
|
|
# ---- SWD debug header (SWDIO/SWCLK/GND/3V3) ----
|
|
swd = Part("Connector_Generic","Conn_01x04", footprint="Connector_PinHeader_1.27mm:PinHeader_1x04_P1.27mm_Vertical", ref="J2")
|
|
swd[1]+=p3v3; swd[2]+=rp[25]; swd[3]+=rp[24]; swd[4]+=gnd # SWDIO=25, SWCLK=24
|
|
|
|
# ---- USB D+/D- via 27ohm series (USB-C connector + ESD = separate sub-block) ----
|
|
rdp = R(value="27"); rdm = R(value="27")
|
|
rp[52]+=rdp[1]; rdp[2]+=usb_dp_c # USB_DP
|
|
rp[51]+=rdm[1]; rdm[2]+=usb_dm_c # USB_DM
|
|
|
|
# ---- GPIO assignments (DESIGN.md s7.1 + audio control) ----
|
|
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
|
|
|
|
ERC()
|
|
out = os.path.abspath(os.path.join(os.path.dirname(__file__), "..", "..", "kicad", "mcu_core.net"))
|
|
generate_netlist(file_=out)
|
|
print("MCU core netlist ->", out)
|