mirror of
https://github.com/diodeinc/pcb.git
synced 2026-09-14 20:17:19 +08:00
256bf1df69
* Use small KiCad symbols for stdlib generics * Add color variants for stdlib LED symbols
157 lines
5.0 KiB
Python
157 lines
5.0 KiB
Python
load("../io.zen", "io")
|
|
load("../interfaces.zen", "Net")
|
|
load("../units.zen", "Capacitance", "Frequency", "Resistance")
|
|
load("../utils.zen", "format_value")
|
|
|
|
Mount = enum("SMD")
|
|
Package = enum(
|
|
"0603_4Pin",
|
|
"2012_2Pin",
|
|
"3215_2Pin",
|
|
"5032_2Pin",
|
|
"3225_4Pin",
|
|
"2520_4Pin",
|
|
"2016_4Pin",
|
|
"1210_4Pin",
|
|
"0603_2Pin",
|
|
)
|
|
package = config(Package)
|
|
frequency = config(Frequency)
|
|
mpn = config(str, optional=True, help="Manufacturer Part Number")
|
|
manufacturer = config(str, optional=True, help="Manufacturer")
|
|
mount = config(Mount, default=Mount("SMD"), optional=True, help="Mounting type")
|
|
load_capacitance = config(Capacitance, optional=True, help="Load capacitance for oscillator circuit")
|
|
esr = config(Resistance, optional=True, help="Equivalent series resistance")
|
|
properties = {
|
|
"value": format_value(frequency, load_capacitance),
|
|
"package": package,
|
|
"frequency": frequency,
|
|
}
|
|
|
|
if load_capacitance:
|
|
properties["load_capacitance"] = load_capacitance
|
|
if esr:
|
|
properties["esr"] = esr
|
|
|
|
# For 2-pin crystals
|
|
XIN = io(Net)
|
|
XOUT = io(Net)
|
|
|
|
# Additional pins for 4-pin crystals
|
|
GND = io(Net) if "4Pin" in str(package) else None
|
|
|
|
|
|
def _symbol(package: Package):
|
|
if "2Pin" in str(package):
|
|
return "../kicad-symbols/Device.kicad_symdir/Crystal_Small.kicad_sym"
|
|
else:
|
|
return "../kicad-symbols/Device.kicad_symdir/Crystal_GND24_Small.kicad_sym"
|
|
|
|
|
|
def _footprint(package: Package):
|
|
_footprints = {
|
|
Package("2012_2Pin"): "../kicad-footprints/Crystal.pretty/Crystal_SMD_2012-2Pin_2.0x1.2mm.kicad_mod",
|
|
Package("3215_2Pin"): "../kicad-footprints/Crystal.pretty/Crystal_SMD_3215-2Pin_3.2x1.5mm.kicad_mod",
|
|
Package("5032_2Pin"): "../kicad-footprints/Crystal.pretty/Crystal_SMD_5032-2Pin_5.0x3.2mm.kicad_mod",
|
|
Package("3225_4Pin"): "../kicad-footprints/Crystal.pretty/Crystal_SMD_3225-4Pin_3.2x2.5mm.kicad_mod",
|
|
Package("2520_4Pin"): "../kicad-footprints/Crystal.pretty/Crystal_SMD_2520-4Pin_2.5x2.0mm.kicad_mod",
|
|
Package("2016_4Pin"): "../kicad-footprints/Crystal.pretty/Crystal_SMD_2016-4Pin_2.0x1.6mm.kicad_mod",
|
|
Package("1210_4Pin"): "../kicad-footprints/Crystal.pretty/Crystal_SMD_1210-4Pin_1.2x1.0mm.kicad_mod",
|
|
Package("0603_2Pin"): "../kicad-footprints/Crystal.pretty/Crystal_SMD_0603-2Pin_6.0x3.5mm.kicad_mod",
|
|
Package("0603_4Pin"): "../kicad-footprints/Crystal.pretty/Crystal_SMD_0603-4Pin_6.0x3.5mm.kicad_mod",
|
|
}
|
|
|
|
return _footprints[package]
|
|
|
|
|
|
def _pin_maps(package: Package, XIN: Net, XOUT: Net, GND: Net | None):
|
|
if "4Pin" in str(package):
|
|
if not GND:
|
|
error("GND is required for 4-pin crystals")
|
|
return (
|
|
{
|
|
"XIN": "1",
|
|
"GND_2": "2",
|
|
"XOUT": "3",
|
|
"GND_4": "4",
|
|
},
|
|
{
|
|
"XIN": XIN,
|
|
"GND_2": GND,
|
|
"XOUT": XOUT,
|
|
"GND_4": GND,
|
|
},
|
|
)
|
|
|
|
return (
|
|
{
|
|
"1": "1",
|
|
"2": "2",
|
|
},
|
|
{
|
|
"1": XIN,
|
|
"2": XOUT,
|
|
},
|
|
)
|
|
|
|
|
|
def _spice_subcircuit_name(package: Package):
|
|
"""Returns the appropriate SPICE subcircuit name based on package."""
|
|
if "4Pin" in str(package):
|
|
return "XTAL_4PIN"
|
|
else:
|
|
return "XTAL_2PIN"
|
|
|
|
|
|
def _spice_nets(package: Package, XIN: Net, XOUT: Net, GND: Net | None):
|
|
"""Returns the nets list for SPICE model based on package."""
|
|
if "4Pin" in str(package):
|
|
if not GND:
|
|
error("GND is required for 4-pin crystal SPICE model")
|
|
return [XIN, XOUT, GND]
|
|
else:
|
|
return [XIN, XOUT]
|
|
|
|
|
|
def _spice_args(frequency, load_capacitance, package):
|
|
"""Returns SPICE arguments based on crystal parameters."""
|
|
args = {
|
|
"FREQ": str(frequency.value), # Frequency in Hz
|
|
"Cm": "10f", # Motional capacitance (typical 10fF)
|
|
"Rm": "50", # ESR/motional resistance (typical 50 ohms)
|
|
"Cp": "3p", # Parallel capacitance (typical 3pF)
|
|
}
|
|
|
|
# Add case capacitance for 4-pin crystals
|
|
if "4Pin" in str(package):
|
|
args["Ccase"] = "1p" # Case capacitance to ground (typical 1pF)
|
|
|
|
# If load capacitance is specified, adjust Cp accordingly
|
|
# The parallel capacitance contributes to the load capacitance
|
|
if load_capacitance:
|
|
# Cp is typically much smaller than CL
|
|
args["Cp"] = str(load_capacitance.value / 5) # Rough approximation
|
|
|
|
return args
|
|
|
|
|
|
pin_defs, pins = _pin_maps(package, XIN, XOUT, GND)
|
|
|
|
Component(
|
|
name="Y",
|
|
part=builtin.Part(mpn=mpn, manufacturer=manufacturer) if mpn and manufacturer else None,
|
|
prefix="Y",
|
|
symbol=Symbol(_symbol(package)),
|
|
pin_defs=pin_defs,
|
|
footprint=File(_footprint(package)),
|
|
spice_model=SpiceModel(
|
|
"spice/Crystal.lib",
|
|
_spice_subcircuit_name(package),
|
|
nets=_spice_nets(package, XIN, XOUT, GND),
|
|
args=_spice_args(frequency, load_capacitance, package),
|
|
),
|
|
pins=pins,
|
|
properties=properties,
|
|
type="crystal",
|
|
)
|