From bb731bed4305a819fa519107fe5349b3200cf6dd Mon Sep 17 00:00:00 2001 From: Richard Lin Date: Sun, 31 May 2026 16:51:25 -0700 Subject: [PATCH 1/8] everythign except micro and motion controllers --- edg/electronics_model/CircuitBlock.py | 13 +++++++++---- edg/electronics_model/KiCadSchematicBlock.py | 3 +-- edg/parts/connector/UsbPorts.py | 18 +++++------------- edg/parts/display/oled/Nhd_312_25664uc.py | 9 ++------- edg/parts/human_interface/Joystick_Xbox.py | 7 ++----- edg/parts/interface/UsbInterface_Ft232h.py | 17 +++-------------- edg/parts/interface/UsbPd_Fusb302b.py | 7 ++----- edg/parts/sensor/FlirLepton.py | 12 +----------- 8 files changed, 25 insertions(+), 61 deletions(-) diff --git a/edg/electronics_model/CircuitBlock.py b/edg/electronics_model/CircuitBlock.py index 4c0ce4ffa..0f51c8ac0 100644 --- a/edg/electronics_model/CircuitBlock.py +++ b/edg/electronics_model/CircuitBlock.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Generic, Any, Optional, List, Mapping, Dict, Union, TYPE_CHECKING +from typing import Generic, Any, Optional, Mapping, Dict, Union, TYPE_CHECKING, Tuple, Iterable from deprecated import deprecated from typing_extensions import TypeVar, override @@ -36,12 +36,11 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.fp_pnp_offset_x = self.Parameter(FloatExpr()) self.fp_pnp_offset_y = self.Parameter(FloatExpr()) - # TODO: allow value to be taken from parameters, ideally w/ string concat from params def footprint( self, refdes: StringLike, footprint: StringLike, - pinning: Mapping[str, Union["Passive", "HasPassivePort"]], + pinning: Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]], mfr: Optional[StringLike] = None, part: Optional[StringLike] = None, value: Optional[StringLike] = None, @@ -80,7 +79,13 @@ def footprint( pin_port = pin_port.net if not isinstance(pin_port, (CircuitPort, Passive)): raise EdgTypeError(f"Footprint(...) pin", pin_port, Passive) - pinning_array.append(f"{pin_name}={pin_port._name_from(self)}") + + if isinstance(pin_name, str): + pin_tuples: Tuple[str, ...] = (pin_name,) + else: + pin_tuples = tuple(iter(pin_name)) + for pin in pin_tuples: + pinning_array.append(f"{pin}={pin_port._name_from(self)}") self.assign(self.fp_pinning, pinning_array) self.assign(self.fp_footprint, footprint) diff --git a/edg/electronics_model/KiCadSchematicBlock.py b/edg/electronics_model/KiCadSchematicBlock.py index a0bd74a74..f3b4d0fb0 100644 --- a/edg/electronics_model/KiCadSchematicBlock.py +++ b/edg/electronics_model/KiCadSchematicBlock.py @@ -86,12 +86,11 @@ def __init__( @override def generate(self) -> None: super().generate() - mapping = {pin_name: self.ports.append_elt(Passive(), pin_name) for pin_name in self.get(self.kicad_pins)} self.ports.defined() self.footprint( self.kicad_refdes_prefix, self.kicad_footprint, - mapping, + {pin_name: self.ports.append_elt(Passive(), pin_name) for pin_name in self.get(self.kicad_pins)}, part=self.kicad_part, value=self.kicad_value, datasheet=self.kicad_datasheet, diff --git a/edg/parts/connector/UsbPorts.py b/edg/parts/connector/UsbPorts.py index ba9d03436..406de4591 100644 --- a/edg/parts/connector/UsbPorts.py +++ b/edg/parts/connector/UsbPorts.py @@ -61,22 +61,14 @@ def contents(self) -> None: "J", "Connector_USB:USB_C_Receptacle_XKB_U262-16XN-4BVC11", { - "A1": self.gnd, - "B12": self.gnd, - "A4": self.pwr, - "B9": self.pwr, - "A5": self.cc.cc1, - "A6": self.usb.dp, - "A7": self.usb.dm, + ("A1", "B12", "B1", "A12"): self.gnd, + ("A4", "B9", "B4", "A9"): self.pwr, + ("A6", "B6"): self.usb.dp, + ("A7", "B7"): self.usb.dm, # 'A8': sbu1, # 'B8': sbu2 - "B7": self.usb.dm, - "B6": self.usb.dp, + "A5": self.cc.cc1, "B5": self.cc.cc2, - "B4": self.pwr, - "A9": self.pwr, - "B1": self.gnd, - "A12": self.gnd, "S1": self.shield, }, mfr="Sparkfun", diff --git a/edg/parts/display/oled/Nhd_312_25664uc.py b/edg/parts/display/oled/Nhd_312_25664uc.py index 0bdda0fe1..1a330bd2b 100644 --- a/edg/parts/display/oled/Nhd_312_25664uc.py +++ b/edg/parts/display/oled/Nhd_312_25664uc.py @@ -43,16 +43,11 @@ def contents(self) -> None: "2": self.vdd, # '3': # no connect "4": self.dc, - "5": self.vss, # R/nW in parallel interface - "6": self.vss, # E/nRD in parallel interface + ("5", "6"): self.vss, # R/nW, E/nRD in parallel interface "7": self.sclk, "8": self.sdin, # '9' # no connect # DB2 in parallel interface - "10": self.vss, # DB3 in parallel interface - "11": self.vss, # DB4 in parallel interface - "12": self.vss, # DB5 in parallel interface - "13": self.vss, # DB6 in parallel interface - "14": self.vss, # DB7 in parallel interface + ("10", "11", "12", "13", "14"): self.vss, # DB3-DB7 in parallel interface # '15': # no connect "16": self.nres, "17": self.ncs, diff --git a/edg/parts/human_interface/Joystick_Xbox.py b/edg/parts/human_interface/Joystick_Xbox.py index 44597ba4f..91b56d33b 100644 --- a/edg/parts/human_interface/Joystick_Xbox.py +++ b/edg/parts/human_interface/Joystick_Xbox.py @@ -30,12 +30,9 @@ def contents(self) -> None: "edg:Joystick_XboxElite2", { "1": self.sw, - "2": self.gnd, - "3": self.gnd, + ("2", "3", "8"): self.gnd, + ("5", "6"): self.pwr, "4": self.ax1, - "5": self.pwr, - "6": self.pwr, "7": self.ax2, - "8": self.gnd, }, ) diff --git a/edg/parts/interface/UsbInterface_Ft232h.py b/edg/parts/interface/UsbInterface_Ft232h.py index d9bb62cac..37438a7a5 100644 --- a/edg/parts/interface/UsbInterface_Ft232h.py +++ b/edg/parts/interface/UsbInterface_Ft232h.py @@ -94,22 +94,11 @@ def contents(self) -> None: "37": self.vcca, "38": self.vcccore, "39": self.vccd, - "12": self.vccio, - "24": self.vccio, - "46": self.vccio, + ("12", "24", "46"): self.vccio, "8": self.vpll, "3": self.vphy, - "4": self.gnd, # AGND - "9": self.gnd, # AGND - "41": self.gnd, # AGND - "10": self.gnd, - "11": self.gnd, - "22": self.gnd, - "23": self.gnd, - "35": self.gnd, - "36": self.gnd, - "47": self.gnd, - "48": self.gnd, + ("4", "9", "41"): self.gnd, # AGND + ("10", "11", "22", "23", "35", "36", "47", "48"): self.gnd, "1": self.osc.xtal_in, "2": self.osc.xtal_out, "5": self.ref, diff --git a/edg/parts/interface/UsbPd_Fusb302b.py b/edg/parts/interface/UsbPd_Fusb302b.py index 300c9b85c..97ce2d509 100644 --- a/edg/parts/interface/UsbPd_Fusb302b.py +++ b/edg/parts/interface/UsbPd_Fusb302b.py @@ -34,19 +34,16 @@ def contents(self) -> None: { "1": self.cc.cc2, "2": self.vbus, - "3": self.vdd, - "4": self.vdd, + ("3", "4"): self.vdd, "5": self.int_n, "6": self.i2c.scl, "7": self.i2c.sda, - "8": self.gnd, - "9": self.gnd, + ("8", "9", "15"): self.gnd, "10": self.cc.cc1, "11": self.cc.cc1, "12": self.vconn, "13": self.vconn, "14": self.cc.cc2, - "15": self.gnd, }, mfr="ON Semiconductor", part="FUSB302B11MPX", # actual several compatible variants diff --git a/edg/parts/sensor/FlirLepton.py b/edg/parts/sensor/FlirLepton.py index a16982192..169b92b38 100644 --- a/edg/parts/sensor/FlirLepton.py +++ b/edg/parts/sensor/FlirLepton.py @@ -48,17 +48,7 @@ def contents(self) -> None: "U", "edg:Molex_1050281001", { - "1": self.gnd, - "6": self.gnd, - "8": self.gnd, - "9": self.gnd, - "10": self.gnd, - "15": self.gnd, - "18": self.gnd, - "20": self.gnd, - "25": self.gnd, - "27": self.gnd, - "30": self.gnd, + ("1", "6", "8", "9", "10", "15", "18", "20", "25", "27", "30"): self.gnd, "33": self.gnd, # socket shield "2": self.vsync, # aka GPIO3 # '3': GPIO2, reserved, "should not be connected" From 6c2436dd7cfc53161743dcd3d91ccc611bd59996 Mon Sep 17 00:00:00 2001 From: Richard Lin Date: Sun, 31 May 2026 17:01:56 -0700 Subject: [PATCH 2/8] wip --- edg/electronics_model/CircuitBlock.py | 33 ++++++++++++++++++- edg/parts/power/converter/LinearRegulators.py | 4 +-- 2 files changed, 34 insertions(+), 3 deletions(-) diff --git a/edg/electronics_model/CircuitBlock.py b/edg/electronics_model/CircuitBlock.py index 0f51c8ac0..b8c76cf8c 100644 --- a/edg/electronics_model/CircuitBlock.py +++ b/edg/electronics_model/CircuitBlock.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Generic, Any, Optional, Mapping, Dict, Union, TYPE_CHECKING, Tuple, Iterable +from typing import Generic, Any, Optional, Mapping, Dict, Union, TYPE_CHECKING, Tuple, Iterable, overload from deprecated import deprecated from typing_extensions import TypeVar, override @@ -36,6 +36,21 @@ def __init__(self, *args: Any, **kwargs: Any) -> None: self.fp_pnp_offset_x = self.Parameter(FloatExpr()) self.fp_pnp_offset_y = self.Parameter(FloatExpr()) + @overload + def footprint( + self, + refdes: StringLike, + footprint: StringLike, + pinning: Mapping[str, Union[Passive, HasPassivePort]], + mfr: Optional[StringLike] = None, + part: Optional[StringLike] = None, + value: Optional[StringLike] = None, + datasheet: Optional[StringLike] = None, + pnp_rot: Optional[float] = None, + pnp_offset: Optional[tuple[float, float]] = None, + ) -> None: ... + + @overload def footprint( self, refdes: StringLike, @@ -47,6 +62,22 @@ def footprint( datasheet: Optional[StringLike] = None, pnp_rot: Optional[float] = None, pnp_offset: Optional[tuple[float, float]] = None, + ) -> None: ... + + def footprint( + self, + refdes: StringLike, + footprint: StringLike, + pinning: Union[ + Mapping[str, Union[Passive, HasPassivePort]], + Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]], + ], + mfr: Optional[StringLike] = None, + part: Optional[StringLike] = None, + value: Optional[StringLike] = None, + datasheet: Optional[StringLike] = None, + pnp_rot: Optional[float] = None, + pnp_offset: Optional[tuple[float, float]] = None, ) -> None: """Creates a footprint in this circuit block. Value is a one-line description of the part, eg 680R, 0.01uF, LPC1549, to be used as an aid during layout or diff --git a/edg/parts/power/converter/LinearRegulators.py b/edg/parts/power/converter/LinearRegulators.py index 9fa9b15f6..250807c8d 100644 --- a/edg/parts/power/converter/LinearRegulators.py +++ b/edg/parts/power/converter/LinearRegulators.py @@ -1,4 +1,4 @@ -from typing import Dict +from typing import Dict, Mapping from typing_extensions import override @@ -584,7 +584,7 @@ def generate(self) -> None: self.assign(self.pwr_out.voltage_out, part_output_voltage) if footprint == "Package_TO_SOT_SMD:SOT-23-5": - pinning: Dict[str, HasPassivePort] = { + pinning: Mapping[str, HasPassivePort] = { "1": self.pwr_in, "2": self.gnd, "3": self.en, From 100caadbb485b9bb16e803feb794076170a56c6a Mon Sep 17 00:00:00 2001 From: Richard Lin Date: Sun, 31 May 2026 17:06:34 -0700 Subject: [PATCH 3/8] refactor motion controllers --- edg/parts/power/motor/Bldc_Drv8313.py | 9 +++------ edg/parts/power/motor/MotorDriver_L293dd.py | 9 +-------- edg/parts/power/motor/StepperDriver_A4988.py | 5 ++--- 3 files changed, 6 insertions(+), 17 deletions(-) diff --git a/edg/parts/power/motor/Bldc_Drv8313.py b/edg/parts/power/motor/Bldc_Drv8313.py index f7e5caffd..d033b7824 100644 --- a/edg/parts/power/motor/Bldc_Drv8313.py +++ b/edg/parts/power/motor/Bldc_Drv8313.py @@ -77,23 +77,22 @@ def contents(self) -> None: "1": self.cpl, "2": self.cph, "3": self.vcp, - "4": self.vm, + ("4", "11"): self.vm, "5": self.outs["1"], "6": self.pgnds["1"], "7": self.pgnds["2"], "8": self.outs["2"], "9": self.outs["3"], "10": self.pgnds["3"], - "11": self.vm, "12": self.gnd, # compp, can be grounded if unused (datasheet 10.1) "13": self.gnd, # compn, can be grounded if unused (datasheet 10.1) - "14": self.gnd, + ("14", "20", "28"): self.gnd, + "29": self.gnd, # exposed pad "15": self.v3p3, "16": self.nreset, "17": self.nsleep, "18": self.nfault, # open-drain fault status (requires external pullup) "19": self.gnd, # ncompo, can be grounded if unused (datasheet 10.1) - "20": self.gnd, "21": self.gnd, # NC, grounded when unused in example layouts "22": self.ens["3"], "23": self.ins["3"], @@ -101,8 +100,6 @@ def contents(self) -> None: "25": self.ins["2"], "26": self.ens["1"], "27": self.ins["1"], - "28": self.gnd, - "29": self.gnd, # exposed pad }, mfr="Texas Instruments", part="DRV8313PWP", diff --git a/edg/parts/power/motor/MotorDriver_L293dd.py b/edg/parts/power/motor/MotorDriver_L293dd.py index 87492b072..6dd9b7b3d 100644 --- a/edg/parts/power/motor/MotorDriver_L293dd.py +++ b/edg/parts/power/motor/MotorDriver_L293dd.py @@ -61,20 +61,13 @@ def contents(self) -> None: "1": self.en1, "2": self.in1, "3": self.out1, - "4": self.gnd, - "5": self.gnd, - "6": self.gnd, - "7": self.gnd, + ("4", "5", "6", "7", "14", "15", "16", "17"): self.gnd, "8": self.out2, "9": self.in2, "10": self.vs, "11": self.en2, "12": self.in3, "13": self.out3, - "14": self.gnd, - "15": self.gnd, - "16": self.gnd, - "17": self.gnd, "18": self.out4, "19": self.in4, "20": self.vss, diff --git a/edg/parts/power/motor/StepperDriver_A4988.py b/edg/parts/power/motor/StepperDriver_A4988.py index be5048ea3..f52ddfed1 100644 --- a/edg/parts/power/motor/StepperDriver_A4988.py +++ b/edg/parts/power/motor/StepperDriver_A4988.py @@ -89,8 +89,8 @@ def contents(self) -> None: "15": self.vdd, "16": self.step, "17": self.ref, - "3": self.gnd, - "18": self.gnd, + ("3", "18"): self.gnd, + "29": self.gnd, # GNDs must be tied together externally by connecting to PAD GND "19": self.dir, # pin 20 NC "21": self.out1b, @@ -103,7 +103,6 @@ def contents(self) -> None: "28": self.vbb2, "1": self.out2b, "2": self.enable, - "29": self.gnd, # GNDs must be tied together externally by connecting to PAD GND }, mfr="Allegro MicroSystems", part="A4988SETTR-R", From a946cc1b92976d431363eddc2f95bb53cb5a57ed Mon Sep 17 00:00:00 2001 From: Richard Lin Date: Sun, 31 May 2026 17:13:25 -0700 Subject: [PATCH 4/8] upgrade mcu pin style --- edg/abstract_parts/BaseIoControllerWrapped.py | 2 +- edg/parts/microcontroller/Esp32.py | 5 +---- edg/parts/microcontroller/Esp32c3.py | 6 ++---- edg/parts/microcontroller/Esp32s3.py | 6 +----- edg/parts/microcontroller/Ice40up.py | 3 +-- edg/parts/microcontroller/Rp2040.py | 10 ++-------- edg/parts/microcontroller/nRF52840.py | 10 ++-------- 7 files changed, 10 insertions(+), 32 deletions(-) diff --git a/edg/abstract_parts/BaseIoControllerWrapped.py b/edg/abstract_parts/BaseIoControllerWrapped.py index 2c8e8493c..cc0c5eccc 100644 --- a/edg/abstract_parts/BaseIoControllerWrapped.py +++ b/edg/abstract_parts/BaseIoControllerWrapped.py @@ -121,7 +121,7 @@ def _remap_assigns_to_value(assigns: Dict[str, Tuple[Optional[str], Optional[str return pin_assigns def _make_pinning( - self, fixed_pinning: Dict[str, Union[Passive, HasPassivePort]], remapping: Dict[str, str] + self, fixed_pinning: Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]], remapping: Dict[str, str] ) -> Dict[str, Union[Passive, HasPassivePort]]: """Creates the footprint pinning dict for the wrapped footprint, given the fixed pinning and remapping from pin name to this footprint's pin number. diff --git a/edg/parts/microcontroller/Esp32.py b/edg/parts/microcontroller/Esp32.py index 1ca0c95ea..ba6147af9 100644 --- a/edg/parts/microcontroller/Esp32.py +++ b/edg/parts/microcontroller/Esp32.py @@ -117,10 +117,7 @@ def generate(self) -> None: def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: return { "2": self.pwr, - "1": self.gnd, - "15": self.gnd, - "38": self.gnd, - "39": self.gnd, # EP + ("1", "15", "38", "39"): self.gnd, "3": self.chip_pu, "25": self.io0, "24": self.io2, diff --git a/edg/parts/microcontroller/Esp32c3.py b/edg/parts/microcontroller/Esp32c3.py index 9db467c2a..6e516caf1 100644 --- a/edg/parts/microcontroller/Esp32c3.py +++ b/edg/parts/microcontroller/Esp32c3.py @@ -38,8 +38,7 @@ class Esp32c3_Device(Esp32c3_Interfaces, BaseIoControllerPinmapGenerator, Intern @override def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: return { - "31": self.vdda, - "32": self.vdda, + ("31", "32"): self.vdda, "33": self.gnd, "6": self.io2, "7": self.en, @@ -51,8 +50,7 @@ def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: "11": self.vdd3p3_rtc, "17": self.vdd3p3_cpu, "18": self.vdd_spi, - "2": self.vdd3p3, - "3": self.vdd3p3, + ("2", "3"): self.vdd3p3, "30": self.xtal.xtal_in, "29": self.xtal.xtal_out, } diff --git a/edg/parts/microcontroller/Esp32s3.py b/edg/parts/microcontroller/Esp32s3.py index 6ac10ae48..78d147921 100644 --- a/edg/parts/microcontroller/Esp32s3.py +++ b/edg/parts/microcontroller/Esp32s3.py @@ -115,8 +115,7 @@ def generate(self) -> None: def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: return { "2": self.pwr, # including VDD3V3, VDD3P3_RTC, VDD_SPI, VDD3P3_CPU - "1": self.gnd, - "40": self.gnd, + ("1", "40"): self.gnd, "41": self.gnd, # EP "3": self.chip_pu, "27": self.io0, @@ -314,7 +313,6 @@ def __init__(self, **kwargs: Any) -> None: self.gnd = self.Port(Ground.empty(), optional=True) self.v3v3 = self.Port(Passive.empty(), optional=True) self.vusb = self.Port(Passive.empty(), optional=True) # VUsb - self.cam_sccb = self.Port(I2cController.empty(), optional=True) # internally connected to camera self.generator_param(self.pin_assigns) self._generator_param_all_ios() @@ -330,8 +328,6 @@ def generate(self) -> None: "1": self.v3v3, "21": self.gnd, "20": self.vusb, - "3": self.cam_sccb.sda, - "4": self.cam_sccb.scl, }, self._PIN_REMAPPING, ), diff --git a/edg/parts/microcontroller/Ice40up.py b/edg/parts/microcontroller/Ice40up.py index baf404abd..ccf7e9764 100644 --- a/edg/parts/microcontroller/Ice40up.py +++ b/edg/parts/microcontroller/Ice40up.py @@ -144,8 +144,7 @@ def _system_pinmap( ) -> Dict[str, Union[Passive, HasPassivePort]]: # names consistent with pinout spreadsheet return { "29": self.vcc_pll, - "5": self.vcc, - "30": self.vcc, + ("5", "30"): self.vcc, "22": self.vccio_1, "33": self.vccio_0, "1": self.vccio_2, diff --git a/edg/parts/microcontroller/Rp2040.py b/edg/parts/microcontroller/Rp2040.py index 67ccbba26..2ccdc4cf3 100644 --- a/edg/parts/microcontroller/Rp2040.py +++ b/edg/parts/microcontroller/Rp2040.py @@ -172,14 +172,8 @@ def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: "25": self.swd.swdio, "26": self.run, "19": self.gnd, # TESTEN, connect to gnd - "1": self.iovdd, - "10": self.iovdd, - "22": self.iovdd, - "33": self.iovdd, - "42": self.iovdd, - "49": self.iovdd, - "23": self.dvdd, - "50": self.dvdd, + ("1", "10", "22", "33", "42", "49"): self.iovdd, + ("23", "50"): self.dvdd, "44": self.vreg_vin, "45": self.vreg_vout, "48": self.usb_vdd, diff --git a/edg/parts/microcontroller/nRF52840.py b/edg/parts/microcontroller/nRF52840.py index 4b0493924..0b7066517 100644 --- a/edg/parts/microcontroller/nRF52840.py +++ b/edg/parts/microcontroller/nRF52840.py @@ -134,11 +134,7 @@ def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: "28": self.pwr, # Vdd "30": self.pwr, # VddH # "31": DccH is disconnected - from section 8.3 for input voltage <3.6v - "1": self.gnd, - "2": self.gnd, - "15": self.gnd, - "33": self.gnd, - "55": self.gnd, + ("1", "2", "15", "33", "55"): self.gnd, "32": self.pwr_usb, "40": self.nreset, } @@ -484,9 +480,7 @@ def generate(self) -> None: self._make_pinning( { "14": self.vdd_nrf, - "1": self.gnd, - "25": self.gnd, - "37": self.gnd, + ("1", "25", "37"): self.gnd, "22": self.vbus, "21": self.p0_18, }, From 972e5cbd30f06eae8b8e031d49e036bd5aa99b42 Mon Sep 17 00:00:00 2001 From: Richard Lin Date: Sun, 31 May 2026 17:20:04 -0700 Subject: [PATCH 5/8] refactor micros --- edg/abstract_parts/BaseIoControllerWrapped.py | 11 +++++++---- edg/abstract_parts/IoController.py | 6 +++--- edg/parts/microcontroller/Esp32.py | 2 +- edg/parts/microcontroller/Esp32c3.py | 2 +- edg/parts/microcontroller/Esp32s3.py | 2 +- edg/parts/microcontroller/Ice40up.py | 5 ++--- edg/parts/microcontroller/Lpc1549.py | 2 +- edg/parts/microcontroller/Rp2040.py | 2 +- edg/parts/microcontroller/Stm32f103.py | 2 +- edg/parts/microcontroller/Stm32f303.py | 4 ++-- edg/parts/microcontroller/Stm32g031.py | 2 +- edg/parts/microcontroller/Stm32g431.py | 2 +- edg/parts/microcontroller/Stm32l432.py | 2 +- edg/parts/microcontroller/nRF52840.py | 2 +- 14 files changed, 24 insertions(+), 22 deletions(-) diff --git a/edg/abstract_parts/BaseIoControllerWrapped.py b/edg/abstract_parts/BaseIoControllerWrapped.py index cc0c5eccc..a0abb4186 100644 --- a/edg/abstract_parts/BaseIoControllerWrapped.py +++ b/edg/abstract_parts/BaseIoControllerWrapped.py @@ -121,8 +121,10 @@ def _remap_assigns_to_value(assigns: Dict[str, Tuple[Optional[str], Optional[str return pin_assigns def _make_pinning( - self, fixed_pinning: Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]], remapping: Dict[str, str] - ) -> Dict[str, Union[Passive, HasPassivePort]]: + self, + fixed_pinning: Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]], + remapping: Dict[str, str], + ) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: """Creates the footprint pinning dict for the wrapped footprint, given the fixed pinning and remapping from pin name to this footprint's pin number. This generates pinning for all BaseIoController IOs. @@ -132,9 +134,10 @@ def _make_pinning( """ remapped_pin_assigns = self._remap_model_pin_assigns(remapping, self.get(self.pin_assigns)) pin_dict = self._generator_pin_dict() - fixed_pinning.update(self._remap_to_footprint_pinning(remapped_pin_assigns, pin_dict)) + pinning = dict(fixed_pinning) + pinning.update(self._remap_to_footprint_pinning(remapped_pin_assigns, pin_dict)) self.assign(self.actual_pin_assigns, self._remap_assigns_to_value(remapped_pin_assigns)) - return fixed_pinning + return pinning class BaseIoControllerWrapper(BaseIoController): diff --git a/edg/abstract_parts/IoController.py b/edg/abstract_parts/IoController.py index f0a9ccfaa..628beda79 100644 --- a/edg/abstract_parts/IoController.py +++ b/edg/abstract_parts/IoController.py @@ -1,5 +1,5 @@ from itertools import chain -from typing import List, Dict, Tuple, Type, Optional, Any, Union, Callable +from typing import List, Dict, Tuple, Type, Optional, Any, Union, Callable, Mapping, Iterable from typing_extensions import override from deprecated import deprecated @@ -272,7 +272,7 @@ def contents(self) -> None: self.generator_param(self.pin_assigns) self._generator_param_all_ios() # defined in contents() so subclass __init__ can define additional _io_ports - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: """Implement me. Defines the fixed pin mappings from pin number to port.""" raise NotImplementedError @@ -280,7 +280,7 @@ def _io_pinmap(self) -> PinMapUtil: """Implement me. Defines the assignable IO pinmaps.""" raise NotImplementedError - def _make_pinning(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _make_pinning(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: allocation_list = [] for io_port in self._io_ports: if isinstance(io_port, Vector): # derive Vector connections from requested diff --git a/edg/parts/microcontroller/Esp32.py b/edg/parts/microcontroller/Esp32.py index ba6147af9..7181c3851 100644 --- a/edg/parts/microcontroller/Esp32.py +++ b/edg/parts/microcontroller/Esp32.py @@ -114,7 +114,7 @@ def generate(self) -> None: ) @override - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: return { "2": self.pwr, ("1", "15", "38", "39"): self.gnd, diff --git a/edg/parts/microcontroller/Esp32c3.py b/edg/parts/microcontroller/Esp32c3.py index 6e516caf1..3bd12a367 100644 --- a/edg/parts/microcontroller/Esp32c3.py +++ b/edg/parts/microcontroller/Esp32c3.py @@ -36,7 +36,7 @@ class Esp32c3_Device(Esp32c3_Interfaces, BaseIoControllerPinmapGenerator, Intern } @override - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: return { ("31", "32"): self.vdda, "33": self.gnd, diff --git a/edg/parts/microcontroller/Esp32s3.py b/edg/parts/microcontroller/Esp32s3.py index 78d147921..15ecd520d 100644 --- a/edg/parts/microcontroller/Esp32s3.py +++ b/edg/parts/microcontroller/Esp32s3.py @@ -112,7 +112,7 @@ def generate(self) -> None: ) @override - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: return { "2": self.pwr, # including VDD3V3, VDD3P3_RTC, VDD_SPI, VDD3P3_CPU ("1", "40"): self.gnd, diff --git a/edg/parts/microcontroller/Ice40up.py b/edg/parts/microcontroller/Ice40up.py index ccf7e9764..2a8d2fe9c 100644 --- a/edg/parts/microcontroller/Ice40up.py +++ b/edg/parts/microcontroller/Ice40up.py @@ -139,9 +139,8 @@ def __init__(self, **kwargs: Any) -> None: self.spi_config_cs = self.Port(self._dpio1_model) @override - def _system_pinmap( - self, - ) -> Dict[str, Union[Passive, HasPassivePort]]: # names consistent with pinout spreadsheet + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: + # names consistent with pinout spreadsheet return { "29": self.vcc_pll, ("5", "30"): self.vcc, diff --git a/edg/parts/microcontroller/Lpc1549.py b/edg/parts/microcontroller/Lpc1549.py index e819eac71..46eb29c19 100644 --- a/edg/parts/microcontroller/Lpc1549.py +++ b/edg/parts/microcontroller/Lpc1549.py @@ -58,7 +58,7 @@ def __init__(self, **kwargs: Any) -> None: self._io_ports.insert(0, self.swd) @override - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: return VariantPinRemapper( { "VddA": self.pwr, diff --git a/edg/parts/microcontroller/Rp2040.py b/edg/parts/microcontroller/Rp2040.py index 2ccdc4cf3..fba96530e 100644 --- a/edg/parts/microcontroller/Rp2040.py +++ b/edg/parts/microcontroller/Rp2040.py @@ -158,7 +158,7 @@ def generate(self) -> None: # Pin/peripheral resource definitions (table 3) @override - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: return { "51": self.qspi_sd3, "52": self.qspi.sck, diff --git a/edg/parts/microcontroller/Stm32f103.py b/edg/parts/microcontroller/Stm32f103.py index dca5196df..a1ea54054 100644 --- a/edg/parts/microcontroller/Stm32f103.py +++ b/edg/parts/microcontroller/Stm32f103.py @@ -63,7 +63,7 @@ def __init__(self, **kwargs: Any) -> None: self._io_ports.insert(0, self.swd) @override - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: return VariantPinRemapper( { # Pin/peripheral resource definitions (table 3) "Vbat": self.pwr, diff --git a/edg/parts/microcontroller/Stm32f303.py b/edg/parts/microcontroller/Stm32f303.py index 2dea0d730..22ebf0b3c 100644 --- a/edg/parts/microcontroller/Stm32f303.py +++ b/edg/parts/microcontroller/Stm32f303.py @@ -183,7 +183,7 @@ class Stm32f303_Device(Stm32f303_Ios, IoController, InternalSubcircuit, Generato SYSTEM_PIN_REMAP: Dict[str, Union[str, List[str]]] @override - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: return VariantPinRemapper( { # 'Vbat': self.vdd, @@ -242,7 +242,7 @@ def _vddio_vdda(self) -> Tuple[Port[VoltageLink], Port[VoltageLink]]: return self.pwr_out, self.pwr_out @override - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: if self.get(self.pwr.is_connected()): # board sinks power self.require(~self.vusb_out.is_connected(), "can't source USB power if power input connected") self.require(~self.pwr_out.is_connected(), "can't source 3v3 power if power input connected") diff --git a/edg/parts/microcontroller/Stm32g031.py b/edg/parts/microcontroller/Stm32g031.py index d3d4c948e..0342142b6 100644 --- a/edg/parts/microcontroller/Stm32g031.py +++ b/edg/parts/microcontroller/Stm32g031.py @@ -44,7 +44,7 @@ def __init__(self, **kwargs: Any) -> None: self.nrst = self.Port(DigitalSink.empty(), optional=True) # internally pulled up @override - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: return VariantPinRemapper( { # Pin/peripheral resource definitions (section 4) "Vdd": self.pwr, diff --git a/edg/parts/microcontroller/Stm32g431.py b/edg/parts/microcontroller/Stm32g431.py index 3f9c48da5..3b5135095 100644 --- a/edg/parts/microcontroller/Stm32g431.py +++ b/edg/parts/microcontroller/Stm32g431.py @@ -41,7 +41,7 @@ def __init__(self, **kwargs: Any) -> None: self.nrst = self.Port(DigitalSink.empty(), optional=True) # internally pulled up @override - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: return VariantPinRemapper( { "Vdd": self.pwr, diff --git a/edg/parts/microcontroller/Stm32l432.py b/edg/parts/microcontroller/Stm32l432.py index 90a7686d5..c91c82279 100644 --- a/edg/parts/microcontroller/Stm32l432.py +++ b/edg/parts/microcontroller/Stm32l432.py @@ -46,7 +46,7 @@ def __init__(self, **kwargs: Any) -> None: self.nrst = self.Port(DigitalSink.empty(), optional=True) # internally pulled up @override - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: return VariantPinRemapper( { # Pin/peripheral resource definitions (section 4) "Vdd": self.pwr, diff --git a/edg/parts/microcontroller/nRF52840.py b/edg/parts/microcontroller/nRF52840.py index 0b7066517..bc4427506 100644 --- a/edg/parts/microcontroller/nRF52840.py +++ b/edg/parts/microcontroller/nRF52840.py @@ -129,7 +129,7 @@ def generate(self) -> None: ) @override - def _system_pinmap(self) -> Dict[str, Union[Passive, HasPassivePort]]: + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: return { "28": self.pwr, # Vdd "30": self.pwr, # VddH From 1aec5279b4ed058ca64dda7dabdb4a7a647d58e1 Mon Sep 17 00:00:00 2001 From: Richard Lin Date: Sun, 31 May 2026 17:41:32 -0700 Subject: [PATCH 6/8] refactor the rest --- edg/parts/microcontroller/Esp32.py | 1 - edg/parts/microcontroller/Esp32c3.py | 2 - edg/parts/microcontroller/Lpc1549.py | 8 +- edg/parts/microcontroller/Stm32f103.py | 147 ++++++--------- edg/parts/microcontroller/Stm32f303.py | 242 +++++++++++-------------- edg/parts/microcontroller/Stm32g031.py | 108 ++++------- edg/parts/microcontroller/Stm32g431.py | 109 ++++------- edg/parts/microcontroller/Stm32l432.py | 112 +++++------- 8 files changed, 286 insertions(+), 443 deletions(-) diff --git a/edg/parts/microcontroller/Esp32.py b/edg/parts/microcontroller/Esp32.py index 7181c3851..f4e9eda35 100644 --- a/edg/parts/microcontroller/Esp32.py +++ b/edg/parts/microcontroller/Esp32.py @@ -264,7 +264,6 @@ class Esp32_Wroom_32( def __init__(self) -> None: super().__init__() - self.ic: Esp32_Wroom_32_Device self.generator_param(self.reset.is_connected()) @override diff --git a/edg/parts/microcontroller/Esp32c3.py b/edg/parts/microcontroller/Esp32c3.py index 3bd12a367..3e0c9db58 100644 --- a/edg/parts/microcontroller/Esp32c3.py +++ b/edg/parts/microcontroller/Esp32c3.py @@ -214,7 +214,6 @@ class Esp32c3( def __init__(self) -> None: super().__init__() - self.ic: Esp32c3_Device self.generator_param(self.reset.is_connected(), self.pin_assigns, self.gpio.requested()) self._io2_ext_connected: bool = False @@ -434,7 +433,6 @@ class Esp32c3_Wroom02( def __init__(self) -> None: super().__init__() - self.ic: Esp32c3_Wroom02_Device self.generator_param(self.reset.is_connected(), self.pin_assigns, self.gpio.requested()) self._io2_ext_connected: bool = False diff --git a/edg/parts/microcontroller/Lpc1549.py b/edg/parts/microcontroller/Lpc1549.py index 46eb29c19..5e214fd4e 100644 --- a/edg/parts/microcontroller/Lpc1549.py +++ b/edg/parts/microcontroller/Lpc1549.py @@ -5,6 +5,10 @@ from ...circuits import * from ...vendor_parts.jlc.JlcPart import JlcPart +# This file use an old style that uses inheritance to allow variations of the same chip. +# This is no longer used elsewhere. +# TODO: find a unified way to support variations of the same chip + @non_library class Lpc1549Base_Device( @@ -75,7 +79,9 @@ def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, Ha "RTCXOUT": self.xtal_rtc.xtal_out, "RESET": self.reset, } - ).remap(self.SYSTEM_PIN_REMAP) + ).remap( + self.SYSTEM_PIN_REMAP + ) # type: ignore @override def _io_pinmap(self) -> PinMapUtil: diff --git a/edg/parts/microcontroller/Stm32f103.py b/edg/parts/microcontroller/Stm32f103.py index a1ea54054..288bcfff5 100644 --- a/edg/parts/microcontroller/Stm32f103.py +++ b/edg/parts/microcontroller/Stm32f103.py @@ -6,8 +6,7 @@ from ...vendor_parts.jlc.JlcPart import JlcPart -@abstract_block -class Stm32f103Base_Device( +class Stm32f103_Device( IoControllerI2cTarget, IoControllerCan, IoControllerUsb, @@ -17,13 +16,43 @@ class Stm32f103Base_Device( JlcPart, FootprintBlock, ): - PACKAGE: str # package name for footprint(...) - PART: str # part name for footprint(...) - LCSC_PART: str - LCSC_BASIC_PART: bool - - SYSTEM_PIN_REMAP: Dict[str, Union[str, List[str]]] # pin name in base -> pin name(s) - RESOURCE_PIN_REMAP: Dict[str, str] # resource name in base -> pin name + _PIN_MAPPING = { + "PC13": "2", + "PC14": "3", + "PC15": "4", + "PA0": "10", + "PA1": "11", + "PA2": "12", + "PA3": "13", + "PA4": "14", + "PA5": "15", + "PA6": "16", + "PA7": "17", + "PB0": "18", + "PB1": "19", + "PB2": "20", + "PB10": "21", + "PB11": "22", + "PB12": "25", + "PB13": "26", + "PB14": "27", + "PB15": "28", + "PA8": "29", + "PA9": "30", + "PA10": "31", + "PA11": "32", + "PA12": "33", + "PA13": "34", + "PA14": "37", + "PA15": "38", + "PB3": "39", + "PB4": "40", + "PB5": "41", + "PB6": "42", + "PB7": "43", + "PB8": "45", + "PB9": "46", + } def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) @@ -64,19 +93,17 @@ def __init__(self, **kwargs: Any) -> None: @override def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: - return VariantPinRemapper( - { # Pin/peripheral resource definitions (table 3) - "Vbat": self.pwr, - "VddA": self.pwr, - "VssA": self.gnd, - "Vss": self.gnd, - "Vdd": self.pwr, - "BOOT0": self.gnd, - "OSC_IN": self.osc.xtal_in, # TODO remappable to PD0 - "OSC_OUT": self.osc.xtal_out, # TODO remappable to PD1 - "NRST": self.nrst, - } - ).remap(self.SYSTEM_PIN_REMAP) + return { + "1": self.pwr, # Vbat + "9": self.pwr, # VddA + "8": self.gnd, # VssA + ("23", "35", "47"): self.gnd, # Vss + ("24", "36", "48"): self.pwr, # Vdd + "44": self.gnd, # BOOT0 + "5": self.osc.xtal_in, # TODO remappable to PD0 + "6": self.osc.xtal_out, # TODO remappable to PD1 + "7": self.nrst, + } @override def _io_pinmap(self) -> PinMapUtil: @@ -198,7 +225,7 @@ def _io_pinmap(self) -> PinMapUtil: {"scl": ["PB6", "PB8"], "sda": ["PB7", "PB9"]}, # TODO shared resource w/ I2C controller ), ] - ).remap_pins(self.RESOURCE_PIN_REMAP) + ).remap_pins(self._PIN_MAPPING) @override def generate(self) -> None: @@ -206,71 +233,15 @@ def generate(self) -> None: self.footprint( "U", - self.PACKAGE, + "Package_QFP:LQFP-48_7x7mm_P0.5mm", self._make_pinning(), mfr="STMicroelectronics", - part=self.PART, + part="STM32F103xxT6", datasheet="https://www.st.com/resource/en/datasheet/stm32f103c8.pdf", pnp_rot=-90, ) - self.assign(self.lcsc_part, self.LCSC_PART) - self.assign(self.actual_basic_part, self.LCSC_BASIC_PART) - - -class Stm32f103_48_Device(Stm32f103Base_Device): - SYSTEM_PIN_REMAP = { - "Vbat": "1", - "VddA": "9", - "VssA": "8", - "Vss": ["23", "35", "47"], - "Vdd": ["24", "36", "48"], - "BOOT0": "44", - "OSC_IN": "5", - "OSC_OUT": "6", - "NRST": "7", - } - RESOURCE_PIN_REMAP = { - "PC13": "2", - "PC14": "3", - "PC15": "4", - "PA0": "10", - "PA1": "11", - "PA2": "12", - "PA3": "13", - "PA4": "14", - "PA5": "15", - "PA6": "16", - "PA7": "17", - "PB0": "18", - "PB1": "19", - "PB2": "20", - "PB10": "21", - "PB11": "22", - "PB12": "25", - "PB13": "26", - "PB14": "27", - "PB15": "28", - "PA8": "29", - "PA9": "30", - "PA10": "31", - "PA11": "32", - "PA12": "33", - "PA13": "34", - "PA14": "37", - "PA15": "38", - "PB3": "39", - "PB4": "40", - "PB5": "41", - "PB6": "42", - "PB7": "43", - "PB8": "45", - "PB9": "46", - } - PACKAGE = "Package_QFP:LQFP-48_7x7mm_P0.5mm" - PART = "STM32F103xxT6" - LCSC_PART = "C8304" # max memory CBT6 variant - # C77994 for GD32F103C8T6, probably mostly drop-in compatible, NOT basic part - LCSC_BASIC_PART = True + self.assign(self.lcsc_part, "C8304") # max memory CBT6 variant + self.assign(self.actual_basic_part, False) class UsbDpPullUp(InternalSubcircuit, Block): @@ -284,8 +255,7 @@ def __init__(self, resistance: RangeLike): self.connect(self.usb.dp.net, self.dp.b) -@abstract_block -class Stm32f103Base( +class Stm32f103_48( Resettable, IoControllerI2cTarget, IoControllerCan, @@ -296,7 +266,6 @@ class Stm32f103Base( IoControllerPowerRequired, GeneratorBlock, ): - DEVICE: Type[Stm32f103Base_Device] = Stm32f103Base_Device DEFAULT_CRYSTAL_FREQUENCY = 8 * MHertz(tol=0.005) # as in common dev boards / eval boards def __init__(self, **kwargs: Any) -> None: @@ -314,7 +283,7 @@ def contents(self) -> None: super().contents() with self.implicit_connect(ImplicitConnect(self.pwr, [Power]), ImplicitConnect(self.gnd, [Common])) as imp: - self.ic = imp.Block(self.DEVICE(pin_assigns=ArrayStringExpr())) + self.ic = imp.Block(Stm32f103_Device(pin_assigns=ArrayStringExpr())) self.connect(self.xtal_node, self.ic.osc) self.connect(self.swd_node, self.ic.swd) self.connect(self.reset_node, self.ic.nrst) @@ -354,7 +323,3 @@ def _crystal_required(self) -> bool: # crystal needed for CAN or USB b/c tighte or len(self.get(self.usb.requested())) > 0 or super()._crystal_required() ) - - -class Stm32f103_48(Stm32f103Base): - DEVICE = Stm32f103_48_Device diff --git a/edg/parts/microcontroller/Stm32f303.py b/edg/parts/microcontroller/Stm32f303.py index 22ebf0b3c..f4a27855b 100644 --- a/edg/parts/microcontroller/Stm32f303.py +++ b/edg/parts/microcontroller/Stm32f303.py @@ -1,28 +1,111 @@ -from abc import abstractmethod from typing import * +from deprecated import deprecated from typing_extensions import override from ...circuits import * @non_library -class Stm32f303_Ios(IoControllerI2cTarget, IoControllerDac, IoControllerCan, BaseIoControllerPinmapGenerator): - """Base class for STM32F303x6/8 devices (separate from STM32F303xB/C). - Unlike other microcontrollers, this one also supports dev boards (Nucleo-32) which can be - a power source, so there's a bit more complexity here.""" +class Stm32f303_Interfaces(IoControllerI2cTarget, IoControllerDac, IoControllerCan): + """Base class for STM32F303x6/8 devices (separate from STM32F303xB/C).""" - RESOURCE_PIN_REMAP: Dict[str, str] - @abstractmethod - def _vddio_vdda(self) -> Tuple[Port[VoltageLink], Port[VoltageLink]]: - """Returns VDDIO, VDDA (either can be VoltageSink or VoltageSource).""" - ... +@deprecated("not maintained") +class Nucleo_F303k8( + IoControllerUsbOut, + IoControllerPowerOut, + IoController, + Stm32f303_Interfaces, + BaseIoControllerPinmapGenerator, + GeneratorBlock, + FootprintBlock, +): + """Nucleo32 F303K8 configured as power source from USB.""" + + _PIN_MAPPING = { + "PA9": "1", # CN3.1, D1 + "PA10": "2", # CN3.2, D0 + # 'NRST': '3' # CN3.3, RESET + "PA12": "5", # CN3.5, D2 + "PB0": "6", # CN3.6, D3 + "PB7": "7", # CN3.7, D4 + "PB6": "8", # CN3.8, D5 + "PB1": "9", # CN3.9, D6 + "PF0": "10", # CN3.10, D7 + "PF1": "11", # CN3.11, D8 + "PA8": "12", # CN3.12, D9 + "PA11": "13", # CN3.13, D10 + "PB5": "14", # CN3.14, D11 + "PB4": "15", # CN3.15, D12 + # 'NRST': '18' # CN4.3, RESET + "PA2": "20", # CN4.5, A7 + "PA7": "21", # CN4.6, A6 + "PA6": "22", # CN4.7, A5 + "PA5": "23", # CN4.8, A4 + "PA4": "24", # CN4.9, A3 + "PA3": "25", # CN4.10, A2 + "PA1": "26", # CN4.11, A1 + "PA0": "27", # CN4.12, A0 + "PB3": "30", # CN4.15, D13 + } + + @override + def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: + return { + ("4", "17"): self.gnd, + "29": self.pwr if self.get(self.pwr.is_connected()) else self.pwr_out, + "19": self.vusb_out, + "16": self.pwr, + } + + def __init__(self) -> None: + super().__init__() + + self.gnd.init_from(Ground()) + self.pwr.init_from( + VoltageSink( # assumes single-rail module + voltage_limits=(2, 3.6) * Volt, # table 19 + current_draw=(0.00055, 80) * mAmp + self.io_current_draw.upper(), # table 25 Idd standby to max + ) + ) + + self.vusb_out.init_from( + VoltageSource( + voltage_out=(4.75 - 0.58, 5.1) + * Volt, # 4.75V USB - 0.58v BAT60JFILM drop to 5.1 from LD1117S50TR, ignoring ST890CDR + current_limits=(0, 0.5) * Amp, # max USB draw # TODO higher from external power + ) + ) + self.pwr_out.init_from( + VoltageSource( + voltage_out=3.3 * Volt(tol=0.03), # LD39050PU33R worst-case Vout accuracy + current_limits=(0, 0.5) * Amp, # max USB current draw, LDO also guarantees 500mA output current + ) + ) + + self.generator_param(self.pwr.is_connected()) + + @override + def generate(self) -> None: + super().generate() - def _vdd_model(self) -> VoltageSink: - return VoltageSink( # assumes single-rail module - voltage_limits=(2, 3.6) * Volt, # table 19 - current_draw=(0.00055, 80) * mAmp + self.io_current_draw.upper(), # table 25 Idd standby to max + self.require( + self.pwr.is_connected().implies(~self.vusb_out.is_connected()), + "can't source USB power if power input connected", + ) + self.require( + self.pwr.is_connected().implies(~self.pwr_out.is_connected()), + "can't source 3v3 power if power input connected", + ) + + self.footprint( + "U", + "edg:Nucleo32", + self._make_pinning(), + mfr="STMicroelectronics", + part="NUCLEO-F303K8", + datasheet="https://www.st.com/resource/en/user_manual/dm00231744.pdf", ) @override @@ -30,7 +113,12 @@ def _io_pinmap(self) -> PinMapUtil: """Returns the mappable for a STM32F303 device with the input power and ground references. This allows a shared definition between discrete chips and microcontroller boards""" # these are common to all IO blocks - vdd, vdda = self._vddio_vdda() + if self.get(self.pwr.is_connected()): # board sinks power + vdd: Port[VoltageLink] = self.pwr + vdda: Port[VoltageLink] = self.pwr + else: + vdd = self.pwr_out + vdda = self.pwr_out input_threshold_factor = (0.3, 0.7) # TODO relaxed (but more complex) bounds available for different IO blocks current_limits = (-20, 20) * mAmp # Section 6.3.14, TODO loose with relaxed VOL/VOH @@ -172,126 +260,4 @@ def _io_pinmap(self) -> PinMapUtil: {"swdio": "PA13", "swclk": "PA14", "reset": "NRST"}, # TODO some are FTf pins # note: SWO is PB3 ), ] - ).remap_pins(self.RESOURCE_PIN_REMAP) - - -@non_library -class Stm32f303_Device(Stm32f303_Ios, IoController, InternalSubcircuit, GeneratorBlock, FootprintBlock): - """STM32F303 chip. - TODO IMPLEMENT ME""" - - SYSTEM_PIN_REMAP: Dict[str, Union[str, List[str]]] - - @override - def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: - return VariantPinRemapper( - { - # 'Vbat': self.vdd, - # 'VddA': self.vdda, - # 'VssA': self.gnd, - "Vss": self.gnd, - "Vdd": self.pwr, - # 'BOOT0': self.gnd, - } - ).remap(self.SYSTEM_PIN_REMAP) - - -class Nucleo_F303k8( - IoControllerUsbOut, IoControllerPowerOut, IoController, Stm32f303_Ios, GeneratorBlock, FootprintBlock -): - """Nucleo32 F303K8 configured as power source from USB.""" - - SYSTEM_PIN_REMAP: Dict[str, Union[str, List[str]]] = { - "Vss": ["4", "17"], - "Vdd": "29", - "Vusb": "19", - "Vin": "16", - } - RESOURCE_PIN_REMAP = { - "PA9": "1", # CN3.1, D1 - "PA10": "2", # CN3.2, D0 - # 'NRST': '3' # CN3.3, RESET - "PA12": "5", # CN3.5, D2 - "PB0": "6", # CN3.6, D3 - "PB7": "7", # CN3.7, D4 - "PB6": "8", # CN3.8, D5 - "PB1": "9", # CN3.9, D6 - "PF0": "10", # CN3.10, D7 - "PF1": "11", # CN3.11, D8 - "PA8": "12", # CN3.12, D9 - "PA11": "13", # CN3.13, D10 - "PB5": "14", # CN3.14, D11 - "PB4": "15", # CN3.15, D12 - # 'NRST': '18' # CN4.3, RESET - "PA2": "20", # CN4.5, A7 - "PA7": "21", # CN4.6, A6 - "PA6": "22", # CN4.7, A5 - "PA5": "23", # CN4.8, A4 - "PA4": "24", # CN4.9, A3 - "PA3": "25", # CN4.10, A2 - "PA1": "26", # CN4.11, A1 - "PA0": "27", # CN4.12, A0 - "PB3": "30", # CN4.15, D13 - } - - @override - def _vddio_vdda(self) -> Tuple[Port[VoltageLink], Port[VoltageLink]]: - if self.get(self.pwr.is_connected()): # board sinks power - return self.pwr, self.pwr - else: - return self.pwr_out, self.pwr_out - - @override - def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: - if self.get(self.pwr.is_connected()): # board sinks power - self.require(~self.vusb_out.is_connected(), "can't source USB power if power input connected") - self.require(~self.pwr_out.is_connected(), "can't source 3v3 power if power input connected") - return VariantPinRemapper( - { - "Vdd": self.pwr, - "Vss": self.gnd, - } - ).remap(self.SYSTEM_PIN_REMAP) - else: # board sources power (default) - return VariantPinRemapper( - { - "Vdd": self.pwr_out, - "Vss": self.gnd, - "Vusb": self.vusb_out, - } - ).remap(self.SYSTEM_PIN_REMAP) - - def __init__(self) -> None: - super().__init__() - - self.gnd.init_from(Ground()) - self.pwr.init_from(self._vdd_model()) - - self.vusb_out.init_from( - VoltageSource( - voltage_out=(4.75 - 0.58, 5.1) - * Volt, # 4.75V USB - 0.58v BAT60JFILM drop to 5.1 from LD1117S50TR, ignoring ST890CDR - current_limits=(0, 0.5) * Amp, # max USB draw # TODO higher from external power - ) - ) - self.pwr_out.init_from( - VoltageSource( - voltage_out=3.3 * Volt(tol=0.03), # LD39050PU33R worst-case Vout accuracy - current_limits=(0, 0.5) * Amp, # max USB current draw, LDO also guarantees 500mA output current - ) - ) - - self.generator_param(self.pwr.is_connected()) - - @override - def generate(self) -> None: - super().generate() - - self.footprint( - "U", - "edg:Nucleo32", - self._make_pinning(), - mfr="STMicroelectronics", - part="NUCLEO-F303K8", - datasheet="https://www.st.com/resource/en/user_manual/dm00231744.pdf", - ) + ).remap_pins(self._PIN_MAPPING) diff --git a/edg/parts/microcontroller/Stm32g031.py b/edg/parts/microcontroller/Stm32g031.py index 0342142b6..fddb95b0b 100644 --- a/edg/parts/microcontroller/Stm32g031.py +++ b/edg/parts/microcontroller/Stm32g031.py @@ -6,8 +6,7 @@ from ...vendor_parts.jlc.JlcPart import JlcPart -@abstract_block -class Stm32g031Base_Device( +class Stm32g031_Device( IoControllerI2cTarget, IoControllerCan, IoControllerUsb, @@ -17,13 +16,33 @@ class Stm32g031Base_Device( JlcPart, FootprintBlock, ): - PACKAGE: str # package name for footprint(...) - PART: str # part name for footprint(...) - LCSC_PART: str - LCSC_BASIC_PART: bool - - SYSTEM_PIN_REMAP: Dict[str, Union[str, List[str]]] # pin name in base -> pin name(s) - RESOURCE_PIN_REMAP: Dict[str, str] # resource name in base -> pin name + _PIN_MAPPING = { + "PC14": "1", + "PC15": "2", + "PA0": "6", + "PA1": "7", + "PA2": "8", + "PA3": "9", + "PA4": "10", + "PA5": "11", + "PA6": "12", + "PA7": "13", + "PB0": "14", + "PB1": "15", + "PA8": "16", + "PC6": "17", + "PA11": "18", + "PA12": "19", + "PA13": "20", + "PA14": "21", + "PA15": "22", + "PB3": "23", + "PB4": "24", + "PB5": "25", + "PB6": "26", + "PB7": "27", + "PB8": "28", + } def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) @@ -45,13 +64,11 @@ def __init__(self, **kwargs: Any) -> None: @override def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: - return VariantPinRemapper( - { # Pin/peripheral resource definitions (section 4) - "Vdd": self.pwr, - "Vss": self.gnd, - "PF2-NRST": self.nrst, - } - ).remap(self.SYSTEM_PIN_REMAP) + return { + "3": self.pwr, + "4": self.gnd, + "5": self.nrst, + } @override def _io_pinmap(self) -> PinMapUtil: @@ -174,7 +191,7 @@ def _io_pinmap(self) -> PinMapUtil: }, ), ] - ).remap_pins(self.RESOURCE_PIN_REMAP) + ).remap_pins(self._PIN_MAPPING) @override def generate(self) -> None: @@ -182,59 +199,18 @@ def generate(self) -> None: self.footprint( "U", - self.PACKAGE, + "Package_DFN_QFN:QFN-28_4x4mm_P0.5mm", self._make_pinning(), mfr="STMicroelectronics", - part=self.PART, + part="STM32G031Gxxx", datasheet="https://www.st.com/resource/en/datasheet/stm32g031c6.pdf", pnp_rot=90, ) - self.assign(self.lcsc_part, self.LCSC_PART) + self.assign(self.lcsc_part, "C432211") # G8U6 variant self.assign(self.actual_basic_part, False) -class Stm32g031_G_Device(Stm32g031Base_Device): - """ "STM32G031 GxU in UFQFPN28 package.""" - - SYSTEM_PIN_REMAP = { - "Vdd": "3", - "Vss": "4", - "PF2-NRST": "5", - } - RESOURCE_PIN_REMAP = { - "PC14": "1", - "PC15": "2", - "PA0": "6", - "PA1": "7", - "PA2": "8", - "PA3": "9", - "PA4": "10", - "PA5": "11", - "PA6": "12", - "PA7": "13", - "PB0": "14", - "PB1": "15", - "PA8": "16", - "PC6": "17", - "PA11": "18", - "PA12": "19", - "PA13": "20", - "PA14": "21", - "PA15": "22", - "PB3": "23", - "PB4": "24", - "PB5": "25", - "PB6": "26", - "PB7": "27", - "PB8": "28", - } - PACKAGE = "Package_DFN_QFN:QFN-28_4x4mm_P0.5mm" - PART = "STM32G031Gxxx" - LCSC_PART = "C432211" # G8U6 variant - - -@abstract_block -class Stm32g031Base( +class Stm32g031_G( Resettable, IoControllerI2cTarget, Microcontroller, @@ -242,11 +218,9 @@ class Stm32g031Base( IoControllerPowerRequired, GeneratorBlock, ): - DEVICE: Type[Stm32g031Base_Device] = Stm32g031Base_Device def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) - self.ic: Stm32g031Base_Device self.generator_param(self.reset.is_connected(), self.pin_assigns, self.gpio.requested()) @override @@ -254,7 +228,7 @@ def contents(self) -> None: super().contents() with self.implicit_connect(ImplicitConnect(self.pwr, [Power]), ImplicitConnect(self.gnd, [Common])) as imp: - self.ic = imp.Block(self.DEVICE(pin_assigns=ArrayStringExpr())) + self.ic = imp.Block(Stm32g031_Device(pin_assigns=ArrayStringExpr())) self.connect(self.swd_node, self.ic.swd) self.connect(self.reset_node, self.ic.nrst) @@ -271,7 +245,3 @@ def generate(self) -> None: if self.get(self.reset.is_connected()): self.connect(self.reset, self.ic.nrst) # otherwise NRST has internal pull-up - - -class Stm32g031_G(Stm32g031Base): - DEVICE = Stm32g031_G_Device diff --git a/edg/parts/microcontroller/Stm32g431.py b/edg/parts/microcontroller/Stm32g431.py index 3b5135095..7222f4848 100644 --- a/edg/parts/microcontroller/Stm32g431.py +++ b/edg/parts/microcontroller/Stm32g431.py @@ -6,8 +6,7 @@ from ...circuits import * -@abstract_block -class Stm32g431Base_Device( +class Stm32g431_Device( IoControllerI2cTarget, IoControllerCan, IoControllerUsb, @@ -18,13 +17,32 @@ class Stm32g431Base_Device( JlcPart, FootprintBlock, ): - PACKAGE: str # package name for footprint(...) - PART: str # part name for footprint(...) - LCSC_PART: str - LCSC_BASIC_PART: bool - - SYSTEM_PIN_REMAP: Dict[str, Union[str, List[str]]] # pin name in base -> pin name(s) - RESOURCE_PIN_REMAP: Dict[str, str] # resource name in base -> pin name + _PIN_MAPPING = { + "PF0": "2", + "PF1": "3", + "PA0": "5", + "PA1": "6", + "PA2": "7", + "PA3": "8", + "PA4": "9", + "PA5": "10", + "PA6": "11", + "PA7": "12", + "PA8": "18", + "PA9": "19", + "PA10": "20", + "PA11": "21", + "PA12": "22", + "PA13": "23", + "PA14": "24", + "PA15": "25", + "PB0": "13", + "PB3": "26", + "PB4": "27", + "PB5": "28", + "PB6": "29", + "PB7": "30", + } def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) @@ -42,16 +60,12 @@ def __init__(self, **kwargs: Any) -> None: @override def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: - return VariantPinRemapper( - { - "Vdd": self.pwr, - "Vss": self.gnd, - # 'VddA': self.pwr, - # 'VssA': self.gnd, - "BOOT0": self.gnd, - "PG10-NRST": self.nrst, - } - ).remap(self.SYSTEM_PIN_REMAP) + return { + ("1", "15", "17"): self.pwr, # 15 VDDA + ("14", "16", "32"): self.gnd, # 14 VSSA + "31": self.gnd, # BOOT0 + "4": self.nrst, + } @override def _io_pinmap(self) -> PinMapUtil: @@ -205,63 +219,24 @@ def _io_pinmap(self) -> PinMapUtil: PeripheralFixedResource("USB", UsbDevicePort(DigitalBidir.empty()), {"dm": ["PA11"], "dp": ["PA12"]}), PeripheralFixedResource("USBCC", UsbCcPort(pullup_capable=True), {"cc1": ["PB6"], "cc2": ["PB4"]}), ] - ).remap_pins(self.RESOURCE_PIN_REMAP) + ).remap_pins(self._PIN_MAPPING) @override def generate(self) -> None: super().generate() self.footprint( "U", - self.PACKAGE, + "Package_DFN_QFN:UFQFPN-32-1EP_5x5mm_P0.5mm_EP3.5x3.5mm", self._make_pinning(), mfr="STMicroelectronics", - part=self.PART, + part="STM32G431KB", datasheet="https://www.st.com/resource/en/datasheet/stm32g431kb.pdf", ) - self.assign(self.lcsc_part, self.LCSC_PART) + self.assign(self.lcsc_part, "C1341901") # STM32G431KBU3 self.assign(self.actual_basic_part, False) -class Stm32g431_G_Device(Stm32g431Base_Device): - SYSTEM_PIN_REMAP = { - "Vdd": ["1", "15", "17"], # 15 VDDA - "Vss": ["14", "16", "32"], # 14 VSSA - "BOOT0": "31", - "PG10-NRST": "4", - } - RESOURCE_PIN_REMAP = { - "PF0": "2", - "PF1": "3", - "PA0": "5", - "PA1": "6", - "PA2": "7", - "PA3": "8", - "PA4": "9", - "PA5": "10", - "PA6": "11", - "PA7": "12", - "PA8": "18", - "PA9": "19", - "PA10": "20", - "PA11": "21", - "PA12": "22", - "PA13": "23", - "PA14": "24", - "PA15": "25", - "PB0": "13", - "PB3": "26", - "PB4": "27", - "PB5": "28", - "PB6": "29", - "PB7": "30", - } - PACKAGE = "Package_DFN_QFN:UFQFPN-32-1EP_5x5mm_P0.5mm_EP3.5x3.5mm" - PART = "STM32G431KB" - LCSC_PART = "C1341901" # STM32G431KBU3 - - -@abstract_block -class Stm32g431Base( +class Stm32g431kb( Resettable, IoControllerI2cTarget, Microcontroller, @@ -269,8 +244,6 @@ class Stm32g431Base( IoControllerPowerRequired, GeneratorBlock, ): - DEVICE: Type[Stm32g431Base_Device] = Stm32g431Base_Device - def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) self.generator_param(self.reset.is_connected(), self.pin_assigns, self.gpio.requested()) @@ -279,7 +252,7 @@ def __init__(self, **kwargs: Any) -> None: def contents(self) -> None: super().contents() with self.implicit_connect(ImplicitConnect(self.pwr, [Power]), ImplicitConnect(self.gnd, [Common])) as imp: - self.ic = imp.Block(self.DEVICE(pin_assigns=ArrayStringExpr())) + self.ic = imp.Block(Stm32g431_Device(pin_assigns=ArrayStringExpr())) self.connect(self.swd_node, self.ic.swd) self.connect(self.reset_node, self.ic.nrst) @@ -300,7 +273,3 @@ def generate(self) -> None: if self.get(self.reset.is_connected()): self.connect(self.reset, self.ic.nrst) # otherwise NRST has internal pull-up - - -class Stm32g431kb(Stm32g431Base): - DEVICE = Stm32g431_G_Device diff --git a/edg/parts/microcontroller/Stm32l432.py b/edg/parts/microcontroller/Stm32l432.py index c91c82279..63f969900 100644 --- a/edg/parts/microcontroller/Stm32l432.py +++ b/edg/parts/microcontroller/Stm32l432.py @@ -6,8 +6,7 @@ from ...vendor_parts.jlc.JlcPart import JlcPart -@abstract_block -class Stm32l432Base_Device( +class Stm32l432_Device( IoControllerI2cTarget, IoControllerDac, IoControllerCan, @@ -18,13 +17,34 @@ class Stm32l432Base_Device( JlcPart, FootprintBlock, ): - PACKAGE: str # package name for footprint(...) - PART: str # part name for footprint(...) - LCSC_PART: str - LCSC_BASIC_PART: bool - - SYSTEM_PIN_REMAP: Dict[str, Union[str, List[str]]] # pin name in base -> pin name(s) - RESOURCE_PIN_REMAP: Dict[str, str] # resource name in base -> pin name + _PIN_MAPPING = { + "PC14": "2", + "PC15": "3", + "PA0": "6", + "PA1": "7", + "PA2": "8", + "PA3": "9", + "PA4": "10", + "PA5": "11", + "PA6": "12", + "PA7": "13", + "PB0": "14", + "PB1": "15", + "PA8": "18", + "PA9": "19", + "PA10": "20", + "PA11": "21", + "PA12": "22", + "PA13": "23", + "PA14": "24", + "PA15": "25", + "PB3": "26", + "PB4": "27", + "PB5": "28", + "PB6": "29", + "PB7": "30", + "PH3": "31", + } def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) @@ -47,14 +67,12 @@ def __init__(self, **kwargs: Any) -> None: @override def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, HasPassivePort]]: - return VariantPinRemapper( - { # Pin/peripheral resource definitions (section 4) - "Vdd": self.pwr, - "VddA": self.pwr, - "Vss": self.gnd, - "NRST": self.nrst, - } - ).remap(self.SYSTEM_PIN_REMAP) + return { + ("16", "32", "33"): self.gnd, # recommended to connect EP to PCB ground + ("17", "1"): self.pwr, + "5": self.pwr, # VddA + "4": self.nrst, + } @override def _io_pinmap(self) -> PinMapUtil: @@ -173,7 +191,7 @@ def _io_pinmap(self) -> PinMapUtil: }, ), ] - ).remap_pins(self.RESOURCE_PIN_REMAP) + ).remap_pins(self._PIN_MAPPING) @override def generate(self) -> None: @@ -181,60 +199,17 @@ def generate(self) -> None: self.footprint( "U", - self.PACKAGE, + "Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.45x3.45mm", self._make_pinning(), mfr="STMicroelectronics", - part=self.PART, + part="STM32L432Kxxx", datasheet="https://www.st.com/resource/en/datasheet/stm32l432kc.pdf", ) - self.assign(self.lcsc_part, self.LCSC_PART) + self.assign(self.lcsc_part, "C1337280") # KCU6 variant, maximum memory variant self.assign(self.actual_basic_part, False) -class Stm32l432k_Device(Stm32l432Base_Device): - """ "STM32L432Kx in UFQFPN32 package.""" - - SYSTEM_PIN_REMAP = { - "Vdd": ["17", "1"], - "Vss": ["16", "32", "33"], # recommended to connect EP to PCB ground - "VddA": "5", - "NRST": "4", - } - RESOURCE_PIN_REMAP = { - "PC14": "2", - "PC15": "3", - "PA0": "6", - "PA1": "7", - "PA2": "8", - "PA3": "9", - "PA4": "10", - "PA5": "11", - "PA6": "12", - "PA7": "13", - "PB0": "14", - "PB1": "15", - "PA8": "18", - "PA9": "19", - "PA10": "20", - "PA11": "21", - "PA12": "22", - "PA13": "23", - "PA14": "24", - "PA15": "25", - "PB3": "26", - "PB4": "27", - "PB5": "28", - "PB6": "29", - "PB7": "30", - "PH3": "31", - } - PACKAGE = "Package_DFN_QFN:QFN-32-1EP_5x5mm_P0.5mm_EP3.45x3.45mm" - PART = "STM32L432Kxxx" - LCSC_PART = "C1337280" # KCU6 variant, maximum memory variant - - -@abstract_block -class Stm32l432Base( +class Stm32l432k( Resettable, IoControllerDac, IoControllerCan, @@ -246,7 +221,6 @@ class Stm32l432Base( IoControllerPowerRequired, GeneratorBlock, ): - DEVICE: Type[Stm32l432Base_Device] = Stm32l432Base_Device def __init__(self, **kwargs: Any) -> None: super().__init__(**kwargs) @@ -257,7 +231,7 @@ def contents(self) -> None: super().contents() with self.implicit_connect(ImplicitConnect(self.pwr, [Power]), ImplicitConnect(self.gnd, [Common])) as imp: - self.ic = imp.Block(self.DEVICE(pin_assigns=ArrayStringExpr())) + self.ic = imp.Block(Stm32l432_Device(pin_assigns=ArrayStringExpr())) self.connect(self.swd_node, self.ic.swd) self.connect(self.reset_node, self.ic.nrst) @@ -283,7 +257,3 @@ def generate(self) -> None: def _crystal_required(self) -> bool: # crystal needed for CAN b/c tighter freq tolerance # note: no crystal needed for USB, has clock recovery system (CRS) trimming for USB only return len(self.get(self.can.requested())) > 0 or super()._crystal_required() - - -class Stm32l432k(Stm32l432Base): - DEVICE = Stm32l432k_Device From ec57cd31f0a09f5a75aed3ba156af11b30792fd4 Mon Sep 17 00:00:00 2001 From: Richard Lin Date: Sun, 31 May 2026 17:57:58 -0700 Subject: [PATCH 7/8] Update Stm32f303.py --- edg/parts/microcontroller/Stm32f303.py | 2 -- 1 file changed, 2 deletions(-) diff --git a/edg/parts/microcontroller/Stm32f303.py b/edg/parts/microcontroller/Stm32f303.py index f4a27855b..ed03e19c6 100644 --- a/edg/parts/microcontroller/Stm32f303.py +++ b/edg/parts/microcontroller/Stm32f303.py @@ -11,7 +11,6 @@ class Stm32f303_Interfaces(IoControllerI2cTarget, IoControllerDac, IoControllerC """Base class for STM32F303x6/8 devices (separate from STM32F303xB/C).""" -@deprecated("not maintained") class Nucleo_F303k8( IoControllerUsbOut, IoControllerPowerOut, @@ -56,7 +55,6 @@ def _system_pinmap(self) -> Mapping[Union[Iterable[str], str], Union[Passive, Ha ("4", "17"): self.gnd, "29": self.pwr if self.get(self.pwr.is_connected()) else self.pwr_out, "19": self.vusb_out, - "16": self.pwr, } def __init__(self) -> None: From 69e45e65871d8be0ae011249dd7fadecfeedc1eb Mon Sep 17 00:00:00 2001 From: Richard Lin Date: Sun, 31 May 2026 18:08:12 -0700 Subject: [PATCH 8/8] fixes --- edg/electronics_model/CircuitBlock.py | 5 ++++- edg/parts/microcontroller/Lpc1549.py | 2 +- 2 files changed, 5 insertions(+), 2 deletions(-) diff --git a/edg/electronics_model/CircuitBlock.py b/edg/electronics_model/CircuitBlock.py index b8c76cf8c..8c9847f78 100644 --- a/edg/electronics_model/CircuitBlock.py +++ b/edg/electronics_model/CircuitBlock.py @@ -1,6 +1,6 @@ from __future__ import annotations -from typing import Generic, Any, Optional, Mapping, Dict, Union, TYPE_CHECKING, Tuple, Iterable, overload +from typing import Generic, Any, Optional, Mapping, Dict, Union, TYPE_CHECKING, Tuple, Iterable, overload, Set from deprecated import deprecated from typing_extensions import TypeVar, override @@ -105,6 +105,7 @@ def footprint( self.fp_is_footprint = self.Metadata("") pinning_array = [] + assigned_pins: Set[str] = set() for pin_name, pin_port in pinning.items(): if isinstance(pin_port, HasPassivePort): pin_port = pin_port.net @@ -117,6 +118,8 @@ def footprint( pin_tuples = tuple(iter(pin_name)) for pin in pin_tuples: pinning_array.append(f"{pin}={pin_port._name_from(self)}") + assert pin not in assigned_pins, f"duplicate pin name {pin} in footprint pinning" + assigned_pins.add(pin) self.assign(self.fp_pinning, pinning_array) self.assign(self.fp_footprint, footprint) diff --git a/edg/parts/microcontroller/Lpc1549.py b/edg/parts/microcontroller/Lpc1549.py index 5e214fd4e..3b17ac83e 100644 --- a/edg/parts/microcontroller/Lpc1549.py +++ b/edg/parts/microcontroller/Lpc1549.py @@ -5,7 +5,7 @@ from ...circuits import * from ...vendor_parts.jlc.JlcPart import JlcPart -# This file use an old style that uses inheritance to allow variations of the same chip. +# This file uses an old style that uses inheritance to allow variations of the same chip. # This is no longer used elsewhere. # TODO: find a unified way to support variations of the same chip