#!/usr/bin/env python3 """Single-source component and connectivity data for the GNSS/IMU FPGA PCB. Generated KiCad, BOM, pinout, and assembly data import this module. Ti375 ball data comes from the Efinity 2025.2 C529 resource DB, never a hand transcription. """ from __future__ import annotations import csv from dataclasses import dataclass, field from pathlib import Path ROOT = Path(__file__).resolve().parents[1] @dataclass class Pin: number: str name: str net: str | None etype: str = "passive" @dataclass class Component: ref: str value: str mpn: str manufacturer: str footprint: str pins: list[Pin] description: str = "" assembly: str = "SMT" dnp: bool = False fields: dict[str, str] = field(default_factory=dict) def p(number: str | int, name: str, net: str | None, etype: str = "passive") -> Pin: return Pin(str(number), name, net, etype) components: list[Component] = [] _refs = {"R": 0, "C": 0, "L": 0, "FB": 0, "TP": 0} def add(component: Component) -> Component: assert not any(c.ref == component.ref for c in components), component.ref components.append(component) return component def two_pin(prefix: str, value: str, mpn: str, manufacturer: str, footprint: str, net1: str, net2: str, description: str, *, dnp: bool = False, ref: str | None = None) -> Component: if ref is None: _refs[prefix] += 1 ref = f"{prefix}{_refs[prefix]}" return add(Component(ref, value, mpn, manufacturer, footprint, [p(1, "1", net1), p(2, "2", net2)], description, dnp=dnp)) def r(value: str, net1: str, net2: str, *, mpn: str = "", description: str = "Resistor", dnp: bool = False) -> Component: values = { "0R": "RC0402JR-070RL", "22R": "RC0402FR-0722RL", "27R": "RC0402FR-0727RL", "33R": "RC0402FR-0733RL", "825R": "RC0402FR-07825RL", "1K": "RC0402FR-071KL", "1.24K": "RC0402FR-071K24L", "2.1K": "RC0402FR-072K1L", "2.2K": "RC0402FR-072K2L", "4.7K": "RC0402FR-074K7L", "10K": "RC0402FR-0710KL", "12K": "RC0402FR-0712KL", "15K": "RC0402FR-0715KL", "22.1K": "RC0402FR-0722K1L", "100K": "RC0402FR-07100KL", "133K": "RC0402FR-07133KL", "205K": "RC0402FR-07205KL", "232K": "RC0402FR-07232KL", "383K": "RC0402FR-07383KL", "442K": "RC0402FR-07442KL", "900K": "RC0402FR-07909KL", "1M": "RC0402FR-071ML", } return two_pin("R", value, mpn or values.get(value, ""), "Yageo", "Resistor_SMD:R_0402_1005Metric", net1, net2, description, dnp=dnp) def c(value: str, net1: str, net2: str, *, mpn: str = "", footprint: str = "Capacitor_SMD:C_0402_1005Metric", description: str = "MLCC", dnp: bool = False) -> Component: values = { "10pF": "GRM1555C1H100JA01D", "15pF": "GRM1555C1H150JA01D", "27pF": "600L270JT200T", "750pF": "GRM1555C1H751JA01D", "1.8nF": "GRM155R71H182KA01D", "4.7nF": "GRM155R71H472KA01D", "10nF": "GRM155R71H103KA88D", "100nF": "GRM155R71A104KA01D", "470nF": "GCM155C71A474KE36D", "1uF": "GRM155R60J105KE19D", "10uF": "GRM188R60J106ME47D", "22uF": "GRM21BZ70J226ME44L", "47uF": "GRM32ER70J476ME19L", "100uF": "GRT32EC70J107ME13L", } return two_pin("C", value, mpn or values.get(value, ""), "Murata", footprint, net1, net2, description, dnp=dnp) def tp(net: str, label: str) -> Component: _refs["TP"] += 1 return add(Component(f"TP{_refs['TP']}", label, "", "", "TestPoint:TestPoint_Pad_D1.0mm", [p(1, label, net)], "Local labelled SMT bring-up test pad", "SMT")) def add_ic(ref: str, value: str, mpn: str, manufacturer: str, footprint: str, pins: list[Pin], description: str) -> Component: return add(Component(ref, value, mpn, manufacturer, footprint, pins, description)) # Ti375 C529: represent every package ball exactly once. pinout = {row["ball"]: row for row in csv.DictReader( (ROOT / "docs" / "ti375_pinout.csv").open(newline=""))} package = list(csv.DictReader((ROOT / "docs" / "ti375_c529_package.csv").open(newline=""))) def fpga_net(row: dict[str, str]) -> str | None: ball = row["ball"] if ball in pinout: return pinout[ball]["signal"] name = row["official_pad_name"] if name in ("GND", "VQPS"): return "GND" if name == "VCC" or name.startswith("VCCA_") or name == "VDD_SOC": return "VCC0V95" if name == "VCCAUX": return "VCC1V8" vccio = { "VCCIO4C": "VCC1V8", "VCCIO4A_4B": "VCC1V8", "VCCIO4D": "VCC1V8", "VCCIO2A": "VCC1V8", "VCCIO2B": "VCC1V8", "VCCIO2C": "VCC1V8", "VCCIO2D": "VCC1V8", "VCCIO2E": "VCC1V8", "VCCIO33_BR0": "VCC3V0_DIG", "VCCIO33_TR0": "VCC3V0_DIG", "VCCIO33_TR1": "VCC3V3", "VCCIO33_TR2": "VCC3V3", "VCCIO33_BR3_BR4": "VCC3V3", "VCCIO33_TL1_TL5": "VCC3V3", "VCCIO33_BL2_BL3": "VCC3V3", } if name in vccio: return vccio[name] if name.startswith("REF_RES_"): return name # JTAG_VCCIO_SEL floats for 3.3-V BR3/BR4. Official NC, unused DDR # signals, and unused DDR rails remain open per Efinix's unused table. return None fpga_pins = [] for row in package: etype = {"power": "power_in", "input": "input", "output": "output"}.get( row["direction"], "bidirectional") fpga_pins.append(p(row["ball"], row["official_pad_name"], fpga_net(row), etype)) add_ic("U1", "Ti375C529C3", "Ti375C529C3", "Efinix", "Package_BGA:BGA-529_19x19mm_Layout23x23_P0.8mm", fpga_pins, "Titanium Ti375 FPGA, commercial standard-power 0.95-V option, C529") for name in ("REF_RES_4A", "REF_RES_4B", "REF_RES_4D", "REF_RES_2E", "REF_RES_2A"): r("10K", name, "GND", description="Efinix mandatory 10-kohm 1% reference resistor") # USB-C debug port (JTAG/UART only). This connector never sources SYS5: its # VBUS pins only feed local presence-sensing dividers, so a host attached here # can never be back-fed and dedicated USB power input J7 stays the only USB # source of board power. See J7 below for the power port and its TUSB320. add_ic("J1", "USB-C USB2 sink", "USB4105-GF-A-120", "GCT", "Connector_USB:USB_C_Receptacle_GCT_USB4105-xx-A_16P_TopMnt_Horizontal", [ p("A1", "GND", "GND"), p("A4", "VBUS", "DBG_VBUS_RAW"), p("A5", "CC1", "USB_CC1"), p("A6", "D+", "USB_D_P"), p("A7", "D-", "USB_D_N"), p("A8", "SBU1", None), p("A9", "VBUS", "DBG_VBUS_RAW"), p("A12", "GND", "GND"), p("B1", "GND", "GND"), p("B4", "VBUS", "DBG_VBUS_RAW"), p("B5", "CC2", "USB_CC2"), p("B6", "D+", "USB_D_P"), p("B7", "D-", "USB_D_N"), p("B8", "SBU2", None), p("B9", "VBUS", "DBG_VBUS_RAW"), p("B12", "GND", "GND"), p("SH", "SHIELD", "USB_SHIELD")], "USB 2.0 Type-C receptacle, UFP/sink, debug data only") add_ic("U5", "TUSB320LAI", "TUSB320LAIRSW(R)", "Texas Instruments", "Package_DFN_QFN:Texas_X2QFN-12_1.6x1.6mm_P0.4mm", [ p(1, "CC1", "USB_CC1", "bidirectional"), p(2, "CC2", "USB_CC2", "bidirectional"), p(3, "PORT", "GND", "input"), p(4, "VBUS_DET", "USB_VBUS_DET", "input"), p(5, "ADDR", None), p(6, "OUT3", None, "output"), p(7, "OUT1", None, "output"), p(8, "OUT2", None, "output"), p(9, "ID", None, "output"), p(10, "GND", "GND", "power_in"), p(11, "EN_N", "GND", "input"), p(12, "VDD", "VCC3V3_AUX", "power_in")], "USB Type-C port controller in UFP GPIO mode; integrated Rd on CC1/CC2; " "current-advertisement outputs unused since this port never sources SYS5") r("900K", "DBG_VBUS_RAW", "USB_VBUS_DET", description="TUSB320 VBUS_DET current limiter") r("10K", "VCC3V3_AUX", "TUSB_OUT1", description="TUSB320 open-drain OUT1 pull-up") r("10K", "VCC3V3_AUX", "TUSB_OUT2", description="TUSB320 open-drain OUT2 pull-up") c("100nF", "VCC3V3_AUX", "GND", description="TUSB320 local bypass") add_ic("U6", "TPD2EUSB30A", "TPD2EUSB30ADRTR", "Texas Instruments", "Package_TO_SOT_SMD:Texas_DRT-3", [p(1, "IO1", "USB_D_P"), p(2, "GND", "GND"), p(3, "IO2", "USB_D_N")], "Low-capacitance USB 2.0 ESD protection") c("4.7nF", "USB_SHIELD", "GND", description="USB shield HF coupling") r("1M", "USB_SHIELD", "GND", description="USB shield bleed") r("0R", "USB_SHIELD", "GND", description="Optional direct shield bond", dnp=True) add_ic("J3", "EXT_5V", "1935161", "Phoenix Contact", "TerminalBlock_Phoenix:TerminalBlock_Phoenix_MKDS-1,5-2_1x02_P5.00mm_Horizontal", [ p(1, "EXT_5V", "EXT5_RAW", "power_in"), p(2, "GND", "GND", "power_in")], "Clearly labelled external regulated 5-V input") components[-1].assembly = "THT" def add_efuse(ref: str, input_net: str, output_net: str, ilim: str) -> None: add_ic(ref, "TPS259470A", "TPS259470ARPWR", "Texas Instruments", "board:Texas_RPW0010A_QFN10", [ p(1, "EN/UVLO", f"{ref}_ENUV", "input"), p(2, "OVLO", f"{ref}_OV", "input"), p(3, "AUXOFF", None, "open_collector"), p(4, "FLT", f"{ref}_FLT", "open_collector"), p(5, "IN", input_net, "power_in"), p(6, "OUT", output_net, "power_out"), p(7, "DVDT", f"{ref}_DVDT", "output"), p(8, "GND", "GND", "power_in"), p(9, "ILM", f"{ref}_ILM", "output"), p(10, "ITIMER", None)], "True-reverse-blocking eFuse; UV/OV/current/inrush protection") r("232K", input_net, f"{ref}_ENUV", description="4.0-V nominal eFuse UV divider top") r("100K", f"{ref}_ENUV", "GND", description="eFuse UV divider bottom") r("383K", input_net, f"{ref}_OV", description="5.8-V nominal eFuse OV divider top") r("100K", f"{ref}_OV", "GND", description="eFuse OV divider bottom") r(ilim, f"{ref}_ILM", "GND", description="eFuse RILM=3334/ILIM") c("4.7nF", f"{ref}_DVDT", "GND", description="eFuse output slew control") c("1uF", input_net, "GND", description="eFuse local input bypass") c("10uF", output_net, "GND", description="eFuse local output bypass") tp(f"{ref}_FLT", f"{ref} FLT") add_efuse("U7", "VBUS_RAW", "USB5_PROT", "1.24K") # 2.69 A typical, <3 A max. add_efuse("U8", "EXT5_RAW", "EXT5_PROT", "825R") # 4.04 A typical. add_ic("U9", "TPS2121", "TPS2121RUXR", "Texas Instruments", "board:Texas_RUX0012A_VQFN12", [ p(1, "OUT", "SYS5", "power_out"), p(2, "IN2", "EXT5_PROT", "power_in"), p(3, "CP2", "VCC3V3_AUX", "input"), p(4, "OV2", "MUX_OV2", "input"), p(5, "OV1", "MUX_OV1", "input"), p(6, "PR1", "GND", "input"), p(7, "IN1", "USB5_PROT", "power_in"), p(8, "OUT", "SYS5", "power_out"), p(9, "ST", "MUX_ST", "output"), p(10, "ILM", "MUX_ILM", "output"), p(11, "SS", "MUX_SS", "output"), p(12, "GND", "GND", "power_in")], "4.5-A power mux. PR1=GND disables priority mode; CP2 tied to VCC3V3_AUX " "is what selects IN2 (external 5 V) once the aux rail is up") r("442K", "USB5_PROT", "MUX_OV1", description="TPS2121 IN1 5.75-V OV divider top") r("100K", "MUX_OV1", "GND", description="TPS2121 IN1 OV divider bottom") r("442K", "EXT5_PROT", "MUX_OV2", description="TPS2121 IN2 5.75-V OV divider top") r("100K", "MUX_OV2", "GND", description="TPS2121 IN2 OV divider bottom") r("22.1K", "MUX_ILM", "GND", description="TPS2121 4.5-A typical output limit") c("10nF", "MUX_SS", "GND", description="TPS2121 soft-start") # ST is open-drain and needs an external 6-20 kohm pull-up (TPS2121 data # sheet, Recommended Operating Conditions, RST). It is added at the end of # this file rather than here: reference designators are assigned in call # order, so inserting a resistor mid-file would renumber every later one and # invalidate the routed board. for _ in range(2): c("47uF", "SYS5", "GND", footprint="Capacitor_SMD:C_1210_3225Metric", description="5-V system bulk") add_ic("U10", "SN74LVC2G02", "SN74LVC2G02DCUR", "Texas Instruments", "Package_SO:VSSOP-8_2.3x2mm_P0.5mm", [ p(1, "1Y", "USB_3A_OK", "output"), p(2, "1A", "TUSB_OUT1", "input"), p(3, "1B", "TUSB_OUT2", "input"), p(4, "GND", "GND", "power_in"), p(5, "2A", "MUX_ST", "input"), p(6, "2B", "MUX_ST", "input"), p(7, "2Y", "EXT_SELECTED", "output"), p(8, "VCC", "VCC3V3_AUX", "power_in")], "USB 3-A advertisement NOR decode and mux-status inversion") add_ic("U11", "SN74LVC1G32", "SN74LVC1G32DBVR", "Texas Instruments", "Package_TO_SOT_SMD:SOT-23-5", [ p(1, "A", "USB_3A_OK", "input"), p(2, "B", "EXT_SELECTED", "input"), p(3, "GND", "GND", "power_in"), p(4, "Y", "MAIN_EN", "output"), p(5, "VCC", "VCC3V3_AUX", "power_in")], "Main-rail enable OR: qualified 3-A USB or selected external 5 V") c("100nF", "VCC3V3_AUX", "GND", description="Power-qualification logic local bypass") c("100nF", "VCC3V3_AUX", "GND", description="Power qualification logic bypass") # Rail generation and Efinix sequencing. def add_ldo(ref: str, value: str, mpn: str, vin: str, vout: str, enable: str, desc: str) -> None: add_ic(ref, value, mpn, "Texas Instruments", "Package_TO_SOT_SMD:SOT-23-5", [ p(1, "IN", vin, "power_in"), p(2, "GND", "GND", "power_in"), p(3, "EN", enable, "input"), p(4, "NC", None), p(5, "OUT", vout, "power_out")], desc) c("1uF", vin, "GND", description=f"{ref} local input capacitor") c("1uF", vout, "GND", description=f"{ref} low-noise LDO output capacitor") add_ldo("U12", "TPS7A2033", "TPS7A2033PDBVR", "SYS5", "VCC3V3_AUX", "SYS5", "Always-on 300-mA auxiliary 3.3-V LDO") add_ic("U13", "TPS6287B15HA0", "TPS6287B15HA0WRZVR", "Texas Instruments", "board:Texas_RZV0024A_WQFN24", [ p(1, "VOSNS", "CORE_SENSE_P", "input"), p(2, "EN", "CORE_EN_R", "input"), p(3, "VSET1", "GND", "input"), p(4, "VSET2", "SYS5", "input"), p(5, "VIN", "SYS5", "power_in"), p(6, "VIN", "SYS5", "power_in"), p(7, "GND", "GND", "power_in"), p(8, "GND", "GND", "power_in"), p(9, "SW", "CORE_SW", "power_out"), p(10, "SW", "CORE_SW", "power_out"), p(11, "SW", "CORE_SW", "power_out"), p(12, "SW", "CORE_SW", "power_out"), p(13, "GND", "GND", "power_in"), p(14, "GND", "GND", "power_in"), p(15, "VIN", "SYS5", "power_in"), p(16, "VIN", "SYS5", "power_in"), p(17, "SYNCOUT", None, "output"), p(18, "MODE/SYNC", "SYS5", "input"), p(19, "SDA", "GND", "bidirectional"), p(20, "SCL", "GND", "bidirectional"), p(21, "PG", "CORE_PG", "open_collector"), p(22, "AGND", "GND", "power_in"), p(23, "COMP", "CORE_COMP", "input"), p(24, "GOSNS", "CORE_SENSE_N", "input"), p(25, "THERMAL_PADS", "GND", "power_in")], "15-A synchronous 0.95-V FPGA core/VCCA/VDD_SOC buck, fixed PWM") r("15K", "MAIN_EN", "CORE_EN_R", description="TPS6287B mandatory >=15-kohm EN series resistor") r("0R", "VCC0V95", "CORE_SENSE_P", description="Remote positive sense link at FPGA PDN") r("0R", "GND", "CORE_SENSE_N", description="Remote ground sense link at FPGA PDN") r("2.1K", "CORE_COMP", "CORE_COMP_RC", description="TPS6287B calculated compensation RZ") c("1.8nF", "CORE_COMP_RC", "GND", description="TPS6287B calculated compensation CC") c("10pF", "CORE_COMP", "GND", description="TPS6287B HF compensation bypass CC2") two_pin("L", "100nH", "XEL4030-101MEC", "Coilcraft", "board:Coilcraft_XEL4030", "CORE_SW", "VCC0V95", "Core inductor: 30-A saturation, 1.5-mohm DCR") for _ in range(4): c("22uF", "SYS5", "GND", mpn="GCM31CR71A226KE02L", footprint="Capacitor_SMD:C_1206_3216Metric", description="Core buck butterfly input capacitor") for _ in range(4): c("100uF", "VCC0V95", "GND", footprint="Capacitor_SMD:C_1210_3225Metric", description="Core output; 400-uF nominal, >=195-uF effective target") r("10K", "VCC3V3_AUX", "CORE_PG", description="Core buck PG pull-up") def add_tps62867(ref: str, output: str, sw: str, en: str, pg: str, vset: str, value: str) -> None: add_ic(ref, f"TPS62867 {value}", "TPS62867RQYR", "Texas Instruments", "board:Texas_RQY0009A_VQFN9", [ p(1, "AGND", "GND", "power_in"), p(2, "PGND", "GND", "power_in"), p(3, "VIN", "SYS5", "power_in"), p(4, "EN", en, "input"), p(5, "PG", pg, "open_collector"), p(6, "VSET/MODE", f"{ref}_VSET", "input"), p(7, "SW", sw, "power_out"), p(8, "VOS", output, "input"), p(9, "FB", output, "input")], f"6-A synchronous {value} FPGA auxiliary/I/O buck") r(vset, f"{ref}_VSET", "GND", description=f"TPS62867 fixed {value} VSET resistor") two_pin("L", "240nH", "DFE201612E-R24M=P2", "Murata", "board:Murata_DFE201612E", sw, output, "TPS62867 manufacturer-recommended 6.6-A inductor") for _ in range(2): c("10uF", "SYS5", "GND", description=f"{ref} input capacitor") for _ in range(2): c("22uF", output, "GND", footprint="Capacitor_SMD:C_0805_2012Metric", description=f"{ref} output capacitor") add_tps62867("U14", "VCC1V8", "BUCK1V8_SW", "SEQ_FLAG1", "PG_1V8", "133K", "1.8 V") add_tps62867("U15", "VCC3V3", "BUCK3V3_SW", "SEQ_FLAG2", "PG_3V3", "205K", "3.3 V") add_ic("U16", "LM3880-1AA", "LM3880MF-1AA/NOPB", "Texas Instruments", "Package_TO_SOT_SMD:SOT-23-6", [ p(1, "VCC", "VCC3V3_AUX", "power_in"), p(2, "GND", "GND", "power_in"), p(3, "EN", "CORE_PG", "input"), p(4, "FLAG3", "SEQ_FLAG3", "open_collector"), p(5, "FLAG2", "SEQ_FLAG2", "open_collector"), p(6, "FLAG1", "SEQ_FLAG1", "open_collector")], "Three-rail sequencer, 10-ms delay per rail") for net in ("SEQ_FLAG1", "SEQ_FLAG2"): r("10K", "VCC3V3_AUX", net, description="LM3880 open-drain flag pull-up") c("100nF", "VCC3V3_AUX", "GND", description="LM3880 bypass") # Keep the four independent rail-valid indications separate from CRESET_N. # They are combined below by always-on logic; this prevents an intentional # configuration reset from corrupting the power-good state used to isolate the # FTDI drivers. r("10K", "VCC1V8", "FPGA_CRESET_N", description="FPGA CRESET_N configuration-rail pull-up") r("0R", "SEQ_FLAG3", "PWR_SEQ_OK", description="Sequencer final-flag sense link") r("0R", "PG_1V8", "PWR_1V8_OK", description="1.8-V buck power-good sense link") r("0R", "PG_3V3", "PWR_3V3_OK", description="3.3-V buck power-good sense link") add_ldo("U17", "TPS7A2030", "TPS7A2030PDBVR", "VCC3V3", "VCC3V0_RF", "VCC3V3", "Dedicated low-noise 3.0-V MAX2771 analog LDO") add_ldo("U18", "TPS7A2030", "TPS7A2030PDBVR", "VCC3V3", "VCC3V0_DIG", "VCC3V3", "Dedicated low-noise 3.0-V MAX2771 digital and FPGA-bank LDO") add_ldo("U19", "TPS7A2030", "TPS7A2030PDBVR", "VCC3V3", "VCC3V0_CLK", "VCC3V3", "Dedicated low-noise 3.0-V oscillator LDO") add_ldo("U20", "TPS7A2033", "TPS7A2033PDBVR", "SYS5", "VCC3V3_ANT", "MAIN_EN", "Clean 3.3-V active-antenna bias LDO") # The supervisor is powered from the always-on auxiliary rail, so its open-drain # output remains authoritative even while the monitored 3.0-V FPGA I/O rail is # absent. Its 20-ms (CT open) timeout also guarantees the configuration delay # after the last FPGA supply becomes valid. Power-good is kept separate from # user/FTDI reset so the JTAG buffers stay enabled during deliberate resets. add_ic("U28", "TPS3808G30", "TPS3808G30DBVR", "Texas Instruments", "Package_TO_SOT_SMD:SOT-23-6", [ p(1, "RESET_N", "FPGA_POWER_OK_N", "open_collector"), p(2, "GND", "GND", "power_in"), p(3, "MR_N", "VCC3V3_AUX", "input"), p(4, "CT", None, "input"), p(5, "SENSE", "VCC3V0_DIG", "input"), p(6, "VDD", "VCC3V3_AUX", "power_in")], "3.0-V FPGA-bank supervisor; open-drain reset with 20-ms release delay") # Always-on AND tree creates a true all-rail-valid signal. The fourth gate # includes LM3880 FLAG3, so both the programmed power-up interval and every # converter/supervisor indication must be valid before FPGA-facing FTDI # drivers are enabled or CRESET_N is released. add_ic("U34", "SN74LVC08A", "SN74LVC08APWR", "Texas Instruments", "Package_SO:TSSOP-14_4.4x5mm_P0.65mm", [ p(1, "1A", "CORE_PG", "input"), p(2, "1B", "PWR_1V8_OK", "input"), p(3, "1Y", "PWR_OK_A", "output"), p(4, "2A", "PWR_3V3_OK", "input"), p(5, "2B", "FPGA_POWER_OK_N", "input"), p(6, "2Y", "PWR_OK_B", "output"), p(7, "GND", "GND", "power_in"), p(8, "3Y", "PWR_OK_C", "output"), p(9, "3A", "PWR_OK_A", "input"), p(10, "3B", "PWR_OK_B", "input"), p(11, "4Y", "ALL_FPGA_POWER_OK", "output"), p(12, "4A", "PWR_OK_C", "input"), p(13, "4B", "PWR_SEQ_OK", "input"), p(14, "VCC", "VCC3V3_AUX", "power_in")], "Always-on all-rail power-valid logic for reset release and debug isolation") # Dense reference-design-style bypassing plus one bulk group per rail. for _ in range(18): c("100nF", "VCC0V95", "GND", description="Ti375 core/VCCA/VDD_SOC HF bypass") for _ in range(4): c("10uF", "VCC0V95", "GND", description="Ti375 core local bulk") for _ in range(6): c("100nF", "VCC1V8", "GND", description="Ti375 VCCAUX/HSIO/config bypass") for _ in range(2): c("10uF", "VCC1V8", "GND", description="Ti375 1.8-V local bulk") for rail in ("VCC3V3", "VCC3V0_DIG"): for _ in range(4): c("100nF", rail, "GND", description=f"Ti375 HVIO bank bypass on {rail}") c("10uF", rail, "GND", description=f"Ti375 I/O-rail bulk on {rail}") # MAX2771 direct MIXIN_HI path and OFF/3.3-V/5-V active-antenna bias. add_ic("J2", "GPS L1 SMA", "132289", "Amphenol RF", "Connector_Coaxial:SMA_Amphenol_132289_EdgeMount", [p(1, "RF", "RF_SMA"), p(2, "GND", "GND")], "Edge-launch 50-ohm active GNSS antenna input") components[-1].assembly = "THT" add_ic("D1", "ESD501", "ESD501DPYR", "Texas Instruments", "board:Texas_DPY0002A_X1SON", [p(1, "RF", "RF_SMA"), p(2, "GND", "GND")], "0.3-pF bidirectional 12-V RF ESD protector") c("27pF", "RF_SMA", "RF_PRE_SAW", mpn="600L270JT200T", footprint="board:Kyocera_600L_0402", description="High-Q 200-V C0G GNSS RF DC block") add_ic("FL1", "GPS L1/L1C SAW", "SF14-1582M5UUS2", "Kyocera", "board:Kyocera_SF14_5pad", [ p(1, "IN", "RF_PRE_SAW"), p(2, "GND", "GND"), p(3, "GND", "GND"), p(4, "OUT", "RF_POST_SAW"), p(5, "GND", "GND")], "1565.19-1585.65-MHz SAW, 1.2-dB typical insertion loss") c("DNP", "RF_POST_SAW", "GND", mpn="", description="RF tuning shunt C1", dnp=True) r("0R", "RF_POST_SAW", "MAX_MIXIN_HI", description="RF tuning series link") c("DNP", "MAX_MIXIN_HI", "GND", mpn="", description="RF tuning shunt C2", dnp=True) add_ic("J5", "ANT BIAS OFF/3V3/5V", "61300311121", "Wuerth Elektronik", "Connector_PinHeader_2.54mm:PinHeader_1x03_P2.54mm_Vertical", [ p(1, "3V3", "VCC3V3_ANT", "power_in"), p(2, "SELECT", "ANT_BIAS_SEL", "power_in"), p(3, "5V", "SYS5", "power_in")], "One-shunt hardware antenna bias selection; no shunt is OFF") components[-1].assembly = "THT" add_ic("U27", "TPS22944", "TPS22944DCKR", "Texas Instruments", "Package_TO_SOT_SMD:SOT-353_SC-70-5", [ p(1, "VOUT", "ANT_BIAS_SW", "power_out"), p(2, "GND", "GND", "power_in"), p(3, "OC", "ANT_BIAS_OC", "open_collector"), p(4, "ON", "ANT_BIAS_ON", "input"), p(5, "VIN", "ANT_BIAS_SEL", "power_in")], "Fixed 100-mA current-limited active-antenna load switch") r("100K", "ANT_BIAS_SEL", "ANT_BIAS_ON", description="Bias switch follows selected source") r("100K", "ANT_BIAS_ON", "GND", description="No-jumper default OFF") r("10K", "VCC3V3_AUX", "ANT_BIAS_OC", description="Antenna overcurrent pull-up") c("1uF", "ANT_BIAS_SEL", "GND", description="Bias-switch input bypass") c("1uF", "ANT_BIAS_SW", "GND", description="Bias-switch output bypass before choke") two_pin("L", "56nH", "0402HPH-56NXJRW", "Coilcraft", "Inductor_SMD:L_0402_1005Metric", "ANT_BIAS_SW", "RF_SMA", "L1 bias-tee choke: SRF 2.1 GHz, Q 64, 330 mA") tp("ANT_BIAS_OC", "ANT OC") add_ic("U21", "MAX2771", "MAX2771ETI+", "Analog Devices", "Package_DFN_QFN:QFN-28-1EP_5x5mm_P0.5mm_EP3.25x3.25mm", [ p(1, "CPOUT", "MAX_CPOUT", "output"), p(2, "VCCCP", "VCC3V0_RF", "power_in"), p(3, "XTAL", "MAX_XTAL", "input"), p(4, "CLKOUT", "MAX_CLKOUT_SRC", "output"), p(5, "ADC_CLKIN", "MAX_ADC_CLKIN", "input"), p(6, "VCCD", "VCC3V0_DIG", "power_in"), p(7, "SDATA", "MAX_SDATA_DEV", "bidirectional"), p(8, "SCLK", "MAX_SCLK_DEV", "input"), p(9, "CSN", "MAX_CSN_DEV", "input"), p(10, "Q1", "MAX_Q1_DEV", "output"), p(11, "Q0", "MAX_Q0_DEV", "output"), p(12, "I0", "MAX_I0_DEV", "output"), p(13, "I1", "MAX_I1_DEV", "output"), p(14, "VCCADC", "VCC3V0_DIG", "power_in"), p(15, "ANAIPOUT", None, "output"), p(16, "ANAINOUT", None, "output"), p(17, "LD", "MAX_LD_DEV", "output"), p(18, "SHDN", "MAX_SHDN_DEV", "input"), p(19, "LNAIN_HI", None, "input"), p(20, "LNAIN_LO", None, "input"), p(21, "NC", None), p(22, "VCCRF", "VCC3V0_RF", "power_in"), p(23, "LNAOUT_LO", None, "output"), p(24, "LNAOUT_HI", None, "output"), p(25, "MIXIN_HI", "MAX_MIXIN_HI", "input"), p(26, "MIXIN_LO", None, "input"), p(27, "VCCIF", "VCC3V0_RF", "power_in"), p(28, "VCCVCO", "VCC3V0_RF", "power_in"), p(29, "EP", "GND", "power_in")], "GNSS receiver; both LNAs disabled; direct high-band mixer input") # Official typical topology: CPOUT has a small direct capacitor and an R-C # series integrating branch to ground. c("15pF", "MAX_CPOUT", "GND", description="MAX2771 PLL loop-filter shunt capacitor") r("15K", "MAX_CPOUT", "MAX_LOOP_RC", description="MAX2771 PLL loop-filter resistor") c("750pF", "MAX_LOOP_RC", "GND", description="MAX2771 PLL loop integrating capacitor") c("10nF", "TCXO16_OUT", "MAX_XTAL", description="MAX2771 external reference AC coupling") r("33R", "OSC40_OUT", "MAX_ADC_CLKIN", description="40-MHz ADC-clock source termination") for signal in ("MAX_CLKOUT", "MAX_I0", "MAX_I1", "MAX_Q0", "MAX_Q1", "MAX_LD"): source = f"{signal}_SRC" if signal == "MAX_CLKOUT" else f"{signal}_DEV" r("22R", source, signal, description="MAX2771 source-series digital damping") for signal in ("MAX_SCLK", "MAX_CSN", "MAX_SDATA", "MAX_SHDN"): r("22R", signal, f"{signal}_DEV", description="MAX2771 serial/control source damping") r("100K", "MAX_SHDN_DEV", "GND", description="MAX2771 remains shut down before FPGA configuration") for rail, count in (("VCC3V0_RF", 5), ("VCC3V0_DIG", 2)): for _ in range(count): c("100nF", rail, "GND", description=f"MAX2771 local {rail} bypass") c("1uF", rail, "GND", description=f"MAX2771 local {rail} bulk") add_ic("U23", "16.368 MHz TCXO", "X1G005441030125", "Epson", "board:Epson_TG2016SMN", [ p(1, "NC", None), p(2, "GND", "GND", "power_in"), p(3, "OUT", "TCXO16_OUT", "output"), p(4, "VCC", "VCC3V0_CLK", "power_in")], "TG2016SMN clipped-sine ±0.5-ppm MAX2771 reference") c("100nF", "VCC3V0_CLK", "GND", description="16.368-MHz TCXO bypass") c("1uF", "VCC3V0_CLK", "GND", description="Clock-rail local bulk") add_ic("U24", "40.000 MHz XO", "X1G004171041100", "Epson", "Oscillator:Oscillator_SMD_SeikoEpson_SG210-4Pin_2.5x2.0mm", [ p(1, "ST", "VCC3V0_CLK", "input"), p(2, "GND", "GND", "power_in"), p(3, "OUT", "OSC40_OUT", "output"), p(4, "VCC", "VCC3V0_CLK", "power_in")], "SG-210STF ±25-ppm CMOS FPGA/system ADC oscillator") r("33R", "OSC40_OUT", "CLK_40M_FPGA", description="40-MHz FPGA-clock source termination") c("100nF", "VCC3V0_CLK", "GND", description="40-MHz oscillator bypass") # Exact Murata SCH16T-K01-1 SafeSPI pinout and carrier-board capacitors. add_ic("U22", "SCH16T-K01-1", "SCH16T-K01-1", "Murata", "board:Murata_SCH16T_K01", [ p(1, "HS_GND", "GND", "power_in"), p(2, "RESERVED", None), p(3, "TA9_GND", "GND", "power_in"), p(4, "TA8_GND", "GND", "power_in"), p(5, "RESERVED_GND", "GND", "power_in"), p(6, "EXTRESN", "IMU_EXTRESN", "input"), p(7, "RESERVED_GND", "GND", "power_in"), p(8, "V3P3", "IMU_3V3", "power_in"), p(9, "GND", "GND", "power_in"), p(10, "VREGA2", "IMU_VREGA2", "power_out"), p(11, "VREGA", "IMU_VREGA2", "power_out"), p(12, "GND", "GND", "power_in"), p(13, "GND", "GND", "power_in"), p(14, "VREGD2", "IMU_VREGD", "power_out"), p(15, "VREGD", "IMU_VREGD", "power_out"), p(16, "GND", "GND", "power_in"), p(17, "V3P3", "IMU_3V3", "power_in"), p(18, "VDDIO", "VCC3V3", "power_in"), p(19, "MISO", "IMU_MISO_DEV", "output"), p(20, "DRY_SYNC", "IMU_DRY_SYNC", "bidirectional"), p(21, "SCK", "IMU_SCK_DEV", "input"), p(22, "CS", "IMU_CS_DEV", "input"), p(23, "MOSI", "IMU_MOSI_DEV", "input"), p(24, "HS_GND", "GND", "power_in")], "Six-DoF SafeSPI IMU, exact K01-1 variant") two_pin("FB", "600R@100MHz", "BLM15AG601SN1D", "Murata", "Inductor_SMD:L_0402_1005Metric", "VCC3V3", "IMU_3V3", "IMU supply ferrite isolation") for signal in ("IMU_SCK", "IMU_MOSI", "IMU_CS"): r("22R", signal, f"{signal}_DEV", description="SafeSPI source-series damping") r("22R", "IMU_MISO_DEV", "IMU_MISO", description="SafeSPI MISO source damping at IMU") r("10K", "IMU_EXTRESN", "GND", description="Hold IMU reset until FPGA releases it") c("100nF", "IMU_3V3", "GND", description="Murata V3P3 HF bypass") c("1uF", "IMU_3V3", "GND", description="Murata V3P3 local capacitor") c("10uF", "IMU_VREGA2", "GND", description="Murata required VREGA2 capacitor") c("1uF", "IMU_VREGD", "GND", description="Murata required VREGD capacitor") c("100nF", "VCC3V3", "GND", description="Murata VDDIO bypass") # FT4232H follows the Efinix development-kit interface order: # A/interface 0 = RISC-V JTAG, B/interface 1 = FPGA hard JTAG. ftdi_pins = [ p(1, "EECS", "FTDI_EECS", "output"), p(2, "VCORE", "FTDI_1V8", "power_in"), p(3, "OSCI", "FTDI_OSCI", "input"), p(4, "OSCO", None, "output"), p(5, "VPHY", "FTDI_VPHY", "power_in"), p(6, "REF", "FTDI_REF", "input"), p(7, "DM", "FTDI_D_N", "bidirectional"), p(8, "DP", "FTDI_D_P", "bidirectional"), p(9, "VPLL", "FTDI_VPLL", "power_in"), p(10, "TEST", "GND", "input"), p(11, "RESET_N", "FTDI_RESET_N", "input"), p(12, "ADBUS0/TCK", "FTDI_A_TCK_SRC", "bidirectional"), p(13, "ADBUS1/TDI", "FTDI_A_TDI_SRC", "bidirectional"), p(14, "ADBUS2/TDO", "FTDI_A_TDO_SRC", "bidirectional"), p(15, "ADBUS3/TMS", "FTDI_A_TMS_SRC", "bidirectional"), p(16, "VCCIO", "VCC3V3_AUX", "power_in"), p(17, "ADBUS4", None, "bidirectional"), p(18, "ADBUS5", None, "bidirectional"), p(19, "ADBUS6", None, "bidirectional"), p(20, "ADBUS7", None, "bidirectional"), p(21, "GND", "GND", "power_in"), p(22, "BDBUS0/TCK", "FTDI_B_TCK_SRC", "bidirectional"), p(23, "BDBUS1/TDI", "FTDI_B_TDI_SRC", "bidirectional"), p(24, "BDBUS2/TDO", "FTDI_B_TDO_SRC", "bidirectional"), p(25, "BDBUS3/TMS", "FTDI_B_TMS_SRC", "bidirectional"), p(26, "BDBUS4", "FTDI_B_RESET_N_SRC", "bidirectional"), p(27, "BDBUS5", None, "bidirectional"), p(28, "BDBUS6", None, "bidirectional"), p(29, "BDBUS7", None, "bidirectional"), p(30, "SUSPEND_N", None, "output"), p(31, "VCORE", "FTDI_1V8", "power_in"), p(32, "CDBUS0/TXD", "FTDI_C_TXD_SRC", "bidirectional"), p(33, "CDBUS1/RXD", "FTDI_C_RXD_SRC", "bidirectional"), p(34, "CDBUS2", None, "bidirectional"), p(35, "CDBUS3", None, "bidirectional"), p(36, "VCCIO", "VCC3V3_AUX", "power_in"), p(37, "CDBUS4", None, "bidirectional"), p(38, "CDBUS5", None, "bidirectional"), p(39, "CDBUS6", None, "bidirectional"), p(40, "CDBUS7", None, "bidirectional"), p(41, "GND", "GND", "power_in"), p(42, "DDBUS0/TXD", "FTDI_D_TXD_SRC", "bidirectional"), p(43, "VREGOUT", "FTDI_1V8", "power_out"), p(44, "VREGIN", "VCC3V3_AUX", "power_in"), p(45, "GND", "GND", "power_in"), p(46, "DDBUS1/RXD", "FTDI_D_RXD_SRC", "bidirectional"), p(47, "DDBUS2/RTS", "FTDI_D_DBG_SRC", "bidirectional"), p(48, "DDBUS3", None, "bidirectional"), p(49, "DDBUS4", None, "bidirectional"), p(50, "VCCIO", "VCC3V3_AUX", "power_in"), p(51, "DDBUS5", None, "bidirectional"), p(52, "DDBUS6", None, "bidirectional"), p(53, "DDBUS7", None, "bidirectional"), p(54, "PWREN_N", None, "output"), p(55, "EEDATA", "FTDI_EEDATA", "bidirectional"), p(56, "EECLK", "FTDI_EECLK", "output"), p(57, "EP", "GND", "power_in")] add_ic("U2", "FT4232H-56Q", "FT4232H-56Q-REEL", "FTDI", "board:FTDI_VQFN56_EP5p9", ftdi_pins, "Quad high-speed USB bridge; all four channels assigned") r("27R", "USB_D_P", "FTDI_D_P", description="FTDI USB D+ series termination") r("27R", "USB_D_N", "FTDI_D_N", description="FTDI USB D- series termination") r("12K", "FTDI_REF", "GND", description="FT4232H USB PHY reference resistor, 1%") r("4.7K", "DBG_VBUS_RAW", "FTDI_RESET_N", description="Self-powered VBUS-present reset divider top") r("10K", "FTDI_RESET_N", "GND", description="Self-powered VBUS-present reset divider bottom") for _ in range(2): c("100nF", "VCC3V3_AUX", "GND", description="FT4232H VCCIO/VREGIN bypass") for _ in range(2): c("100nF", "FTDI_1V8", "GND", description="FT4232H VCORE bypass") c("1uF", "FTDI_1V8", "GND", description="FT4232H regulator output capacitor") two_pin("FB", "600R@100MHz", "BLM15AG601SN1D", "Murata", "Inductor_SMD:L_0402_1005Metric", "VCC3V3_AUX", "FTDI_VPHY", "FTDI USB-PHY supply ferrite") two_pin("FB", "600R@100MHz", "BLM15AG601SN1D", "Murata", "Inductor_SMD:L_0402_1005Metric", "VCC3V3_AUX", "FTDI_VPLL", "FTDI PLL supply ferrite") c("100nF", "FTDI_VPHY", "GND", description="FTDI VPHY bypass") c("100nF", "FTDI_VPLL", "GND", description="FTDI VPLL bypass") add_ic("U25", "12.000 MHz XO", "ECS-2520MV-120-BN-TR", "ECS", "Oscillator:Oscillator_SMD_ECS_2520MV-xxx-xx-4Pin_2.5x2.0mm", [ p(1, "OE", "VCC3V3_AUX", "input"), p(2, "GND", "GND", "power_in"), p(3, "OUT", "FTDI_OSC12", "output"), p(4, "VDD", "VCC3V3_AUX", "power_in")], "Current-production 12-MHz CMOS FT4232H clock") r("33R", "FTDI_OSC12", "FTDI_OSCI", description="FTDI oscillator source termination") c("100nF", "VCC3V3_AUX", "GND", description="FTDI oscillator local bypass") add_ic("U3", "93LC56B x16", "93LC56BT-I/OT", "Microchip", "Package_TO_SOT_SMD:SOT-23-6", [ p(1, "CS", "FTDI_EECS", "input"), p(2, "CLK", "FTDI_EECLK", "input"), p(3, "DI", "FTDI_EEDATA", "input"), p(4, "DO", "FTDI_EEDO", "output"), p(5, "VSS", "GND", "power_in"), p(6, "VCC", "VCC3V3_AUX", "power_in")], "FTDI descriptor/channel-mode EEPROM, fixed 16-bit organization") r("2.2K", "FTDI_EEDO", "FTDI_EEDATA", description="EEPROM shared-data isolation") r("10K", "FTDI_EEDO", "VCC3V3_AUX", description="EEPROM DO pull-up") c("100nF", "VCC3V3_AUX", "GND", description="FTDI EEPROM bypass") # FTDI is intentionally powered from the always-on debug rail. All signals # that can drive the FPGA therefore pass through Ioff-capable buffers powered # by the FPGA's 3.3-V I/O rail. When the FPGA rail is absent, the buffer # outputs are high impedance and no unpowered FPGA pin can be back-driven. add_ic("U29", "SN74LVC244A", "SN74LVC244APWR", "Texas Instruments", "Package_SO:TSSOP-20_4.4x6.5mm_P0.65mm", [ p(1, "1OE_N", "FTDI_FPGA_BUF_OE_N", "input"), p(2, "1A1", "FTDI_A_TCK_SRC", "input"), p(18, "1Y1", "BUF_A_TCK", "output"), p(4, "1A2", "FTDI_A_TDI_SRC", "input"), p(16, "1Y2", "BUF_A_TDI", "output"), p(6, "1A3", "FTDI_A_TMS_SRC", "input"), p(14, "1Y3", "BUF_A_TMS", "output"), p(8, "1A4", "FTDI_B_TCK_SRC", "input"), p(12, "1Y4", "BUF_B_TCK", "output"), p(19, "2OE_N", "FTDI_FPGA_BUF_OE_N", "input"), p(11, "2A1", "FTDI_B_TDI_SRC", "input"), p(9, "2Y1", "BUF_B_TDI", "output"), p(13, "2A2", "FTDI_B_TMS_SRC", "input"), p(7, "2Y2", "BUF_B_TMS", "output"), p(15, "2A3", "FTDI_C_TXD_SRC", "input"), p(5, "2Y3", "BUF_C_TXD", "output"), p(17, "2A4", "FTDI_D_TXD_SRC", "input"), p(3, "2Y4", "BUF_D_TXD", "output"), p(10, "GND", "GND", "power_in"), p(20, "VCC", "VCC3V3", "power_in")], "Ioff-protected FPGA-input buffer; automatically isolates when FPGA 3.3 V is off") add_ic("U30", "SN74LVC1G125", "SN74LVC1G125DBVR", "Texas Instruments", "Package_TO_SOT_SMD:SOT-23-5", [p(1, "OE_N", "FTDI_FPGA_BUF_OE_N", "input"), p(2, "A", "FTDI_D_DBG_SRC", "input"), p(3, "GND", "GND", "power_in"), p(4, "Y", "BUF_D_DBG", "output"), p(5, "VCC", "VCC3V3", "power_in")], "Ioff-protected tri-state debug-GPIO buffer powered from FPGA 3.3 V") add_ic("U31", "SN74LVC1G07", "SN74LVC1G07DBVR", "Texas Instruments", "Package_TO_SOT_SMD:SOT-23-5", [p(1, "NC", None), p(2, "A", "FTDI_B_RESET_N_SRC", "input"), p(3, "GND", "GND", "power_in"), p(4, "Y_OD", "FPGA_CRESET_N", "open_collector"), p(5, "VCC", "VCC3V3_AUX", "power_in")], "Open-drain FTDI reset request into FPGA CRESET_N") add_ic("U32", "SN74LVC1G07", "SN74LVC1G07DBVR", "Texas Instruments", "Package_TO_SOT_SMD:SOT-23-5", [p(1, "NC", None), p(2, "A", "ALL_FPGA_POWER_OK", "input"), p(3, "GND", "GND", "power_in"), p(4, "Y_OD", "FPGA_CRESET_N", "open_collector"), p(5, "VCC", "VCC3V3_AUX", "power_in")], "Open-drain all-rail-valid translation into FPGA CRESET_N") add_ic("U33", "SN74LVC1G07", "SN74LVC1G07DBVR", "Texas Instruments", "Package_TO_SOT_SMD:SOT-23-5", [p(1, "NC", None), p(2, "A", "EXT_RESET_FILTER_N", "input"), p(3, "GND", "GND", "power_in"), p(4, "Y_OD", "FPGA_CRESET_N", "open_collector"), p(5, "VCC", "VCC1V8", "power_in")], "Open-drain external/manual reset isolation into FPGA CRESET_N") add_ic("Q1", "MMBT3904", "MMBT3904LT1G", "onsemi", "Package_TO_SOT_SMD:SOT-23", [ p(1, "B", "FTDI_BUF_OE_BASE", "input"), p(2, "E", "GND", "power_in"), p(3, "C", "FTDI_FPGA_BUF_OE_N", "open_collector")], "Power-good inverter: enables FTDI-to-FPGA buffers only after all rails are valid") for src, dst in (("BUF_B_TCK", "HARD_TCK"), ("BUF_B_TMS", "HARD_TMS"), ("BUF_B_TDI", "HARD_TDI"), ("HARD_TDO", "FTDI_B_TDO_SRC")): r("33R", src, dst, description="FTDI interface-1 hard-JTAG source damping") r("10K", "VCC3V3", "HARD_TMS", description="Efinix-required hard-JTAG weak pull-up") c("100nF", "VCC3V3_AUX", "GND", description="Additional FT4232H channel-A VCCIO bypass") for src, dst in (("BUF_A_TCK", "RISCV_TCK"), ("BUF_A_TDI", "RISCV_TDI"), ("BUF_A_TMS", "RISCV_TMS"), ("RISCV_TDO", "FTDI_A_TDO_SRC"), ("BUF_C_TXD", "UART0_RX"), ("UART0_TX", "FTDI_C_RXD_SRC"), ("BUF_D_TXD", "UART1_RX"), ("UART1_TX", "FTDI_D_RXD_SRC"), ("BUF_D_DBG", "FTDI_DBG_GPIO")): r("33R", src, dst, description="FT4232H channel signal damping") # Active-serial flash and four compact Digilent-format PMOD connectors. add_ic("U26", "512-Mbit QSPI flash", "IS25WP512M-JLLE", "ISSI", "Package_SON:WSON-8-1EP_6x5mm_P1.27mm_EP3.4x4.3mm", [ p(1, "CS_N", "QSPI_CS_N", "input"), p(2, "SO/IO1", "QSPI_IO1", "bidirectional"), p(3, "WP_N/IO2", "QSPI_IO2", "bidirectional"), p(4, "GND", "GND", "power_in"), p(5, "SI/IO0", "QSPI_IO0", "bidirectional"), p(6, "SCLK", "QSPI_SCLK", "input"), p(7, "HOLD_N/IO3", "QSPI_IO3", "bidirectional"), p(8, "VCC", "VCC1V8", "power_in"), p(9, "EP", "GND", "power_in")], "1.8-V 512-Mbit FPGA active-serial configuration flash") r("10K", "VCC1V8", "QSPI_CS_N", description="Configuration flash CS pull-up") r("10K", "VCC1V8", "FPGA_TEST_N", description="Efinix mandatory TEST_N weak pull-up") r("10K", "VCC1V8", "FPGA_CSI", description="Efinix mandatory CSI weak pull-up") for net in ("QSPI_IO2", "QSPI_IO3"): r("10K", "VCC1V8", net, description="Configuration flash hold/write-protect pull-up") c("100nF", "VCC1V8", "GND", description="Configuration flash bypass") c("1uF", "VCC1V8", "GND", description="Configuration flash local bulk") def add_pmod(ref: str, prefix: str, rail: str, voltage: str) -> None: pins = [p(i, f"IO{i}", f"{prefix}_{i}") for i in (1, 2, 3, 4)] pins += [p(5, "GND", "GND"), p(6, voltage, rail)] pins += [p(i, f"IO{i}", f"{prefix}_{i}") for i in (7, 8, 9, 10)] pins += [p(11, "GND", "GND"), p(12, voltage, rail)] add_ic(ref, f"PMOD {voltage}", "67997-412HLF", "Amphenol ICC", "board:Digilent_PMOD_2x6_P2.54mm", pins, f"Digilent 2x6 PMOD: eight {voltage} GPIO, two GND, two {voltage}") components[-1].assembly = "THT" add_pmod("JPMOD1", "PMOD1", "VCC3V3", "3.3 V") add_pmod("JPMOD2", "PMOD2", "VCC3V3", "3.3 V") add_pmod("JPMOD3", "PMOD3", "VCC1V8", "1.8 V") add_pmod("JPMOD4", "PMOD4", "VCC1V8", "1.8 V") for net, label in (("VBUS_RAW", "USB VBUS"), ("EXT5_RAW", "EXT 5V"), ("SYS5", "SYS 5V"), ("VCC3V3_AUX", "AUX 3V3"), ("VCC0V95", "CORE 0V95"), ("VCC1V8", "1V8"), ("VCC3V3", "3V3"), ("VCC3V0_RF", "RF 3V0"), ("VCC3V0_DIG", "DIG 3V0"), ("FPGA_CRESET_N", "CRESET_N"), ("FPGA_CDONE", "CDONE"), ("GND", "GND")): tp(net, label) # Configuration/JTAG pulls are located on the FPGA side of the isolation # buffers and use the voltage of their respective I/O bank. r("10K", "VCC1V8", "FPGA_CDONE", description="Efinix-required CDONE open-drain pull-up") for net in ("HARD_TCK", "HARD_TDI", "HARD_TDO"): r("10K", "VCC3V3", net, description="Efinix-required hard-JTAG weak pull-up") for net in ("RISCV_TCK", "RISCV_TMS", "RISCV_TDI", "RISCV_TDO"): r("10K", "VCC3V3", net, description="RISC-V JTAG idle-state pull-up") # Supervisor support and reset-request fan-in. FTDI BDBUS4 uses the # Efinix-compatible active-low convention. Independent open-drain paths avoid # output contention and allow JTAG to remain live while CRESET_N is asserted. r("10K", "VCC3V3_AUX", "FTDI_B_RESET_N_SRC", description="FTDI FPGA-reset request default release") r("10K", "VCC3V3_AUX", "FPGA_POWER_OK_N", description="TPS3808 open-drain power-good pull-up") r("10K", "VCC3V3", "FTDI_FPGA_BUF_OE_N", description="Keep FTDI-to-FPGA buffers disabled until power-good") r("10K", "ALL_FPGA_POWER_OK", "FTDI_BUF_OE_BASE", description="All-rail-good inverter base-current limiter") r("100K", "FTDI_BUF_OE_BASE", "GND", description="Power-good inverter default-off base pull-down") r("10K", "VCC1V8", "EXT_RESET_FILTER_N", description="External/manual reset input pull-up") r("1K", "EXT_RESET_N", "EXT_RESET_FILTER_N", description="External-reset input current and ESD limiting") r("10K", "VCC3V3_AUX", "PWR_SEQ_OK", description="LM3880 final-flag pull-up for all-power logic") r("10K", "VCC3V3_AUX", "PWR_1V8_OK", description="1.8-V power-good pull-up for all-power logic") r("10K", "VCC3V3_AUX", "PWR_3V3_OK", description="3.3-V power-good pull-up for all-power logic") c("4.7nF", "VCC3V0_DIG", "GND", description="TPS3808 SENSE transient filter") c("4.7nF", "EXT_RESET_FILTER_N", "GND", description="Manual/external reset cable-noise filter") c("100nF", "VCC3V3_AUX", "GND", description="TPS3808 local bypass") c("100nF", "VCC3V3", "GND", description="SN74LVC244A local bypass") c("100nF", "VCC3V3", "GND", description="SN74LVC1G125 local bypass") c("100nF", "VCC3V3_AUX", "GND", description="SN74LVC1G07 local bypass") c("100nF", "VCC3V3_AUX", "GND", description="Power-good open-drain buffer local bypass") c("100nF", "VCC1V8", "GND", description="External-reset open-drain buffer local bypass") c("100nF", "VCC3V3_AUX", "GND", description="All-rail-valid logic local bypass") add_ic("J4", "EXT RESET_N", "SM02B-SRSS-TB(LF)(SN)", "JST", "Connector_JST:JST_SH_SM02B-SRSS-TB_1x02-1MP_P1.00mm_Horizontal", [ p(1, "EXT_RESET_N", "EXT_RESET_N", "input"), p(2, "GND", "GND", "power_in")], "External active-low open-drain reset input; JST-SH 1.0-mm") add_ic("SW1", "FPGA RESET", "B3U-1000P", "Omron", "Button_Switch_SMD:SW_SPST_B3U-1000P", [ p(1, "RESET", "EXT_RESET_FILTER_N", "passive"), p(2, "GND", "GND", "passive")], "User-accessible momentary FPGA configuration reset") add_ic("D2", "RESET ESD", "ESD5Z3.3T1G", "onsemi", "Diode_SMD:D_SOD-523", [ p(1, "K", "EXT_RESET_N", "passive"), p(2, "A", "GND", "passive")], "External-reset connector ESD clamp") # Dedicated USB-C power input, physically and electrically separate from the # J1 debug/JTAG/UART port. Its VBUS feeds eFuse U7 (unchanged: U7 already # reads net "VBUS_RAW", which now belongs to this connector instead of J1) so # it goes through the same reverse-blocking protection as before and arrives # at the same TPS2121 IN1 input. U9 keeps external EXT5_PROT (J3) as the # higher-priority source, so external power and this USB-C power input can # never feed SYS5 at the same time. D+/D-/SBU are power-only and left # unconnected; the shield ties to the same USB_SHIELD net as J1. add_ic("J7", "USB-C power input", "USB4105-GF-A-120", "GCT", "Connector_USB:USB_C_Receptacle_GCT_USB4105-xx-A_16P_TopMnt_Horizontal", [ p("A1", "GND", "GND"), p("A4", "VBUS", "VBUS_RAW"), p("A5", "CC1", "PWR_CC1"), p("A6", "D+", None), p("A7", "D-", None), p("A8", "SBU1", None), p("A9", "VBUS", "VBUS_RAW"), p("A12", "GND", "GND"), p("B1", "GND", "GND"), p("B4", "VBUS", "VBUS_RAW"), p("B5", "CC2", "PWR_CC2"), p("B6", "D+", None), p("B7", "D-", None), p("B8", "SBU2", None), p("B9", "VBUS", "VBUS_RAW"), p("B12", "GND", "GND"), p("SH", "SHIELD", "USB_SHIELD")], "USB 2.0 Type-C receptacle, UFP/sink, power input only") add_ic("U35", "TUSB320LAI", "TUSB320LAIRSW(R)", "Texas Instruments", "Package_DFN_QFN:Texas_X2QFN-12_1.6x1.6mm_P0.4mm", [ p(1, "CC1", "PWR_CC1", "bidirectional"), p(2, "CC2", "PWR_CC2", "bidirectional"), p(3, "PORT", "GND", "input"), p(4, "VBUS_DET", "PWR_USB_VBUS_DET", "input"), p(5, "ADDR", None), p(6, "OUT3", None, "output"), p(7, "OUT1", "TUSB_OUT1", "output"), p(8, "OUT2", "TUSB_OUT2", "output"), p(9, "ID", None, "output"), p(10, "GND", "GND", "power_in"), p(11, "EN_N", "GND", "input"), p(12, "VDD", "VCC3V3_AUX", "power_in")], "USB Type-C port controller in UFP GPIO mode for the power input; " "integrated Rd on CC1/CC2; OUT1/OUT2 3-A advertisement drives U10/U11 MAIN_EN gating") # TUSB_OUT1/TUSB_OUT2 pull-ups already exist beside U5 (net names are reused, # not the physical position); adding a second pair here would halve their # effective value instead of moving them. r("900K", "VBUS_RAW", "PWR_USB_VBUS_DET", description="TUSB320 VBUS_DET current limiter") c("100nF", "VCC3V3_AUX", "GND", description="TUSB320 local bypass") # TPS2121 ST is an open-drain status output: it is driven low only while IN2 # (the external 5 V header) is sourcing OUT, and is high-impedance whenever IN1 # (USB-C) is sourcing or the output is off. U10 gate 2 inverts it into # EXT_SELECTED, and MAIN_EN = USB_3A_OK OR EXT_SELECTED enables the core buck, # so without this pull-up the gate input floats on USB-C power and MAIN_EN can # assert regardless of what the TUSB320 advertised. 10 k is inside the # datasheet's 6-20 kohm range and matches the other open-drain pull-ups here. r("10K", "VCC3V3_AUX", "MUX_ST", description="TPS2121 open-drain status pull-up (RST, 6-20 kohm)") def validate() -> None: refs = [x.ref for x in components] assert len(refs) == len(set(refs)) u1 = next(x for x in components if x.ref == "U1") assert len(u1.pins) == 529 and len({x.number for x in u1.pins}) == 529 assert next(x for x in u1.pins if x.number == "G10").net == "HARD_TCK" assert {pin.number: pin.net for pin in u1.pins if pin.number in { "G10", "G12", "G9", "G13", "F12", "V19", "P18", "T18" }} == { "G10": "HARD_TCK", "G12": "HARD_TMS", "G9": "HARD_TDI", "G13": "HARD_TDO", "F12": "RISCV_TCK", "V19": "RISCV_TDI", "P18": "RISCV_TMS", "T18": "RISCV_TDO", } assert next(x for x in u1.pins if x.number == "B11").net == "MAX_CLKOUT" maxic = next(x for x in components if x.ref == "U21") assert next(x for x in maxic.pins if x.number == "25").net == "MAX_MIXIN_HI" assert all(next(x for x in maxic.pins if x.number == n).net is None for n in ("19", "20", "23", "24", "26")) pmods = [next(x for x in components if x.ref == f"JPMOD{i}") for i in range(1, 5)] assert all(len(x.pins) == 12 for x in pmods) assert all(sum(pin.net == "GND" for pin in x.pins) == 2 for x in pmods) assert all(sum((pin.net or "").startswith("PMOD") for pin in x.pins) == 8 for x in pmods) assert all(sum(pin.net == "VCC3V3" for pin in x.pins) == 2 for x in pmods[:2]) assert all(sum(pin.net == "VCC1V8" for pin in x.pins) == 2 for x in pmods[2:]) assert not any((pin.net or "").startswith("EXP_") for pin in u1.pins) u2 = next(x for x in components if x.ref == "U2") assert {pin.number: pin.net for pin in u2.pins if pin.number in { "12", "13", "14", "15", "22", "23", "24", "25" }} == { "12": "FTDI_A_TCK_SRC", "13": "FTDI_A_TDI_SRC", "14": "FTDI_A_TDO_SRC", "15": "FTDI_A_TMS_SRC", "22": "FTDI_B_TCK_SRC", "23": "FTDI_B_TDI_SRC", "24": "FTDI_B_TDO_SRC", "25": "FTDI_B_TMS_SRC", } assert not any(c.ref in {"U4", "J6"} for c in components) assert not any((pin.net or "").startswith("FTDI_HARD_") or pin.net == "JTAG_SW_OE_N" for c in components for pin in c.pins) def has_link(net_a: str, net_b: str, value: str = "33R") -> bool: return any(c.value == value and len(c.pins) == 2 and {c.pins[0].net, c.pins[1].net} == {net_a, net_b} for c in components) for src, dst in ( ("BUF_A_TCK", "RISCV_TCK"), ("BUF_A_TMS", "RISCV_TMS"), ("BUF_A_TDI", "RISCV_TDI"), ("FTDI_A_TDO_SRC", "RISCV_TDO"), ("BUF_B_TCK", "HARD_TCK"), ("BUF_B_TMS", "HARD_TMS"), ("BUF_B_TDI", "HARD_TDI"), ("FTDI_B_TDO_SRC", "HARD_TDO"), ): assert has_link(src, dst), (src, dst) assert next(pin for pin in u2.pins if pin.number == "26").net == "FTDI_B_RESET_N_SRC" u28 = next(x for x in components if x.ref == "U28") assert {pin.name: pin.net for pin in u28.pins} == { "RESET_N": "FPGA_POWER_OK_N", "GND": "GND", "MR_N": "VCC3V3_AUX", "CT": None, "SENSE": "VCC3V0_DIG", "VDD": "VCC3V3_AUX"} u34 = next(x for x in components if x.ref == "U34") assert {pin.number: pin.net for pin in u34.pins if pin.number in {"1", "2", "4", "5", "12", "13"}} == { "1": "CORE_PG", "2": "PWR_1V8_OK", "4": "PWR_3V3_OK", "5": "FPGA_POWER_OK_N", "12": "PWR_OK_C", "13": "PWR_SEQ_OK"} assert next(pin for pin in next(x for x in components if x.ref == "U32").pins if pin.number == "2").net == "ALL_FPGA_POWER_OK" assert not any(c.value == "0R" and "FPGA_CRESET_N" in {pin.net for pin in c.pins} for c in components) for net, rail in (("FPGA_CDONE", "VCC1V8"), ("HARD_TCK", "VCC3V3"), ("HARD_TMS", "VCC3V3"), ("HARD_TDI", "VCC3V3"), ("HARD_TDO", "VCC3V3")): assert has_link(net, rail, "10K"), (net, rail) assert {pin.net for pin in next(x for x in components if x.ref == "J4").pins} == { "EXT_RESET_N", "GND"} assert [x.ref for x in components if x.ref.startswith("TP")] == [f"TP{i}" for i in range(1, 16)] j5 = next(x for x in components if x.ref == "J5") assert {x.net for x in j5.pins} == {"VCC3V3_ANT", "ANT_BIAS_SEL", "SYS5"} validate()