Files
diodeinc__pcb/lib/std/generics/Crystal.zen
Akhil Velagapudi 256bf1df69 Smol symbols (#887)
* Use small KiCad symbols for stdlib generics

* Add color variants for stdlib LED symbols
2026-06-17 14:29:07 -04:00

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",
)