From 13f0fe04565e3bd409aa67f696f93906e7e1ae40 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 5 Sep 2024 19:13:10 +0200 Subject: [PATCH 01/27] Add: power, uart, I2c, RS232 components - B0505 isolated DCDC converter - CH344x quad usb uart bridge - DE-9 RS232 connector - ISO1540 isolated RS485 tranceiver - PowerMux base module - TPS2116 Power mux - RS232 tranceiver --- src/faebryk/library/B0505S.py | 61 ++++++++ src/faebryk/library/CH344.py | 75 ++++++++++ src/faebryk/library/CH344Q.py | 134 ++++++++++++++++++ src/faebryk/library/CH344Q_ReferenceDesign.py | 77 ++++++++++ src/faebryk/library/DE9Connector.py | 37 +++++ src/faebryk/library/DE9RS232Connector.py | 51 +++++++ src/faebryk/library/ISO1540DR.py | 62 ++++++++ src/faebryk/library/PowerMux.py | 17 +++ src/faebryk/library/RS232TranceiverBase.py | 52 +++++++ src/faebryk/library/RS232_3D5R_Tranceiver.py | 40 ++++++ src/faebryk/library/TPS2116.py | 44 ++++++ src/faebryk/library/_F.py | 13 +- 12 files changed, 662 insertions(+), 1 deletion(-) create mode 100644 src/faebryk/library/B0505S.py create mode 100644 src/faebryk/library/CH344.py create mode 100644 src/faebryk/library/CH344Q.py create mode 100644 src/faebryk/library/CH344Q_ReferenceDesign.py create mode 100644 src/faebryk/library/DE9Connector.py create mode 100644 src/faebryk/library/DE9RS232Connector.py create mode 100644 src/faebryk/library/ISO1540DR.py create mode 100644 src/faebryk/library/PowerMux.py create mode 100644 src/faebryk/library/RS232TranceiverBase.py create mode 100644 src/faebryk/library/RS232_3D5R_Tranceiver.py create mode 100644 src/faebryk/library/TPS2116.py diff --git a/src/faebryk/library/B0505S.py b/src/faebryk/library/B0505S.py new file mode 100644 index 00000000..0c08736e --- /dev/null +++ b/src/faebryk/library/B0505S.py @@ -0,0 +1,61 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class B0505S(Module): + """ + Isolated 5V DC to 5V DC converter + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + power_in: F.ElectricPower + power_out: F.ElectricPower + + # ---------------------------------------- + # traits + # ---------------------------------------- + designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + + datasheet = L.f_field(F.has_datasheet_defined)( + "https://wmsc.lcsc.com/wmsc/upload/file/pdf/v2/lcsc/2307211806_EVISUN-B0505S-1WR3_C7465178.pdf" + ) + + @L.rt_field + def can_attach_to_footprint(self): + return F.can_attach_to_footprint_via_pinmap( + pinmap={ + "1": self.power_in.lv, + "2": self.power_in.hv, + "3": self.power_out.lv, + "4": self.power_out.hv, + } + ) + + # self.add_trait(can_bridge_defined(self.power_in, self.power_out)) + def __preinit__(self): + # ---------------------------------------- + # parametrization + # ---------------------------------------- + self.power_in.get_trait(F.can_be_decoupled).decouple().capacitance.merge( + F.Constant(4.7 * P.uF) + ) + self.power_out.get_trait(F.can_be_decoupled).decouple().capacitance.merge( + F.Constant(10 * P.uF) + ) + + # ---------------------------------------- + # connections + # ---------------------------------------- + self.power_in.voltage.merge(F.Range(4.3 * P.V, 9 * P.V)) + self.power_out.voltage.merge(F.Range.from_center(5 * P.V, 0.5 * P.V)) diff --git a/src/faebryk/library/CH344.py b/src/faebryk/library/CH344.py new file mode 100644 index 00000000..82306e88 --- /dev/null +++ b/src/faebryk/library/CH344.py @@ -0,0 +1,75 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class CH344(Module): + """ + Quad UART to USB bridge + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + usb: F.USB2_0 + uart = L.list_field(4, F.UART) + tnow = L.list_field(4, F.ElectricLogic) + act: F.ElectricLogic + tx_indicator: F.ElectricLogic + rx_indicator: F.ElectricLogic + osc = L.list_field(2, F.Electrical) + reset: F.ElectricLogic + test: F.ElectricLogic + cfg: F.ElectricLogic + gpio = L.list_field(16, F.ElectricLogic) + power: F.ElectricPower + + # ---------------------------------------- + # traits + # ---------------------------------------- + @L.rt_field + def single_electric_reference(self): + return F.has_single_electric_reference_defined( + F.ElectricLogic.connect_all_module_references(self) + ) + + datasheet = L.f_field(F.has_datasheet_defined)( + "https://wch-ic.com/downloads/CH344DS1_PDF.html" + ) + + designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + + def __preinit__(self): + # ------------------------------------ + # connections + # ------------------------------------ + self.gpio[0].connect(self.uart[0].cts) + self.gpio[1].connect(self.uart[0].rts) + self.gpio[2].connect(self.uart[1].cts) + self.gpio[3].connect(self.uart[1].rts) + self.gpio[4].connect(self.uart[2].cts) + self.gpio[5].connect(self.uart[2].rts) + self.gpio[6].connect(self.uart[3].cts) + self.gpio[7].connect(self.uart[3].rts) + self.gpio[8].connect(self.uart[0].dtr) + self.gpio[9].connect(self.uart[1].dtr) + self.gpio[10].connect(self.uart[2].dtr) + self.gpio[11].connect(self.uart[3].dtr) + self.gpio[12].connect(self.uart[0].dcd) + self.gpio[13].connect(self.uart[0].ri) + self.gpio[14].connect(self.uart[0].dsr) + self.gpio[15].connect(self.uart[1].dcd) + + self.test.pulled.pull(up=False).resistance.merge(4.7 * P.kOhm) + # ------------------------------------ + # parametrization + # ------------------------------------ + self.power.voltage.merge(3.3 * P.V) diff --git a/src/faebryk/library/CH344Q.py b/src/faebryk/library/CH344Q.py new file mode 100644 index 00000000..3d1675d0 --- /dev/null +++ b/src/faebryk/library/CH344Q.py @@ -0,0 +1,134 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.picker.picker import DescriptiveProperties +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class CH344Q(F.CH344): + """ + Quad UART to USB bridge + """ + + def enable_tnow_mode(self, uart: F.UART): + """ + Set TNOW mode for specified UART for use with RS485 tranceivers. + The TNOW pin can be connected to the tx_enable and rx_enable + pins of the RS485 tranceiver for automatic half-duplex control. + """ + assert ( + uart in self.uart + ), f"{uart.get_full_name()} is not a part of the CH344Q module" + + uart.dtr.pulled.pull(up=False).resistance.merge(4.7 * P.kOhm) + uart.dtr.connect(self.tnow[self.uart.index(uart)]) + + def enable_chip_default_settings(self): + """ + Use the chip default settings instead of the ones stored in the internal EEPROM + """ + self.uart[0].rts.pulled.pull(up=False).resistance.merge(4.7 * P.kOhm) + + def enable_status_outputs(self, modem_signals: bool = False): + """ + Enable rx, tx and usb status signal outputs instead of UART modem signals. + """ + if modem_signals: + self.uart[3].rts.pulled.pull(up=False).resistance.merge(4.7 * P.kOhm) + return + self.act.connect(self.uart[3].dcd) + self.tx_indicator.connect(self.uart[3].ri) + self.rx_indicator.connect(self.uart[3].dsr) + + def enable_hardware_flow_conrol(self): + """ + Enable UART hardware flow control + """ + self.uart[3].dcd.pulled.pull(up=False).resistance.merge(4.7 * P.kOhm) + # TODO: check if this should just be connected to gnd as there is an + # internal pull-up resistor + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + # ---------------------------------------- + # traits + # ---------------------------------------- + @L.rt_field + def can_attach_to_footprint(self): + return F.can_attach_to_footprint_via_pinmap( + pinmap={ + # 1 nc + "2": self.uart[2].dsr.signal, + "3": self.uart[2].ri.signal, + "4": self.uart[2].dcd.signal, + "5": self.osc[1], + "6": self.osc[0], + "7": self.reset.signal, + "8": self.power.lv, + "9": self.power.hv, + "10": self.uart[1].cts.signal, + "11": self.uart[1].rts.signal, + "12": self.uart[1].base_uart.tx.signal, + "13": self.uart[1].base_uart.rx.signal, + "14": self.uart[3].dcd.signal, + "15": self.uart[3].ri.signal, + "16": self.uart[3].dsr.signal, + "17": self.uart[1].dsr.signal, + "18": self.uart[1].dtr.signal, + "19": self.uart[2].dtr.signal, + "20": self.power.lv, + "21": self.uart[2].base_uart.tx.signal, + "22": self.uart[2].base_uart.rx.signal, + "23": self.power.lv, + "24": self.power.hv, + "25": self.uart[1].ri.signal, + "26": self.uart[2].cts.signal, + "27": self.uart[2].rts.signal, + "28": self.uart[1].dcd.signal, + "29": self.uart[0].dsr.signal, + "30": self.uart[0].base_uart.tx.signal, + "31": self.uart[0].base_uart.rx.signal, + "32": self.uart[0].ri.signal, + "33": self.uart[0].dcd.signal, + "34": self.uart[3].dtr.signal, + "35": self.power.lv, + "36": self.power.hv, + "37": self.uart[3].base_uart.tx, + "38": self.uart[3].base_uart.rx, + "39": self.uart[0].dtr.signal, + "40": self.uart[0].rts.signal, + "41": self.uart[0].cts.signal, + "42": self.usb.usb_if.d.n, + "43": self.usb.usb_if.d.p, + "44": self.test.signal, + "45": self.uart[3].rts.signal, + "46": self.uart[3].cts.signal, + "47": self.power.lv, + "48": self.power.hv, + } + ) + + def __preinit__(self): + ... + # ------------------------------------ + # connections + # ------------------------------------ + self.power.decoupled.decouple().capacitance.merge(1 * P.uF) # TODO: per pin + # ------------------------------------ + # parametrization + # ------------------------------------ + self.add( + F.has_descriptive_properties_defined( + { + DescriptiveProperties.manufacturer: "WCH", + DescriptiveProperties.partno: "CH344Q", + }, + ) + ) diff --git a/src/faebryk/library/CH344Q_ReferenceDesign.py b/src/faebryk/library/CH344Q_ReferenceDesign.py new file mode 100644 index 00000000..6d35e4b4 --- /dev/null +++ b/src/faebryk/library/CH344Q_ReferenceDesign.py @@ -0,0 +1,77 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class CH344Q_ReferenceDesign(Module): + """ + Minimal implementation of the CH344Q quad UART to USB bridge + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + usb: F.USB2_0 + usb_fuse: F.Fuse + usb_uart_converter: F.CH344Q + oscillator: F.Crystal_Oscillator + ldo: F.LDO + rx_led: F.PoweredLED + tx_led: F.PoweredLED + act_led: F.PoweredLED + power_led: F.PoweredLED + # reset_lowpass: F.FilterElectricalRC TODO: implement FilterElectricalRC + + # ---------------------------------------- + # traits + # ---------------------------------------- + + def __preinit__(self): + # ------------------------------------ + # aliases + # ------------------------------------ + vbus = self.usb.usb_if.buspower + vbus_fused = F.ElectricPower() + gnd = vbus.lv + pwr_3v3 = self.usb_uart_converter.power + # ------------------------------------ + # connections + # ------------------------------------ + vbus.hv.connect_via(self.usb_fuse, vbus_fused.hv) + gnd.connect(vbus_fused.lv) + vbus_fused.connect_via(self.ldo, pwr_3v3) + # TODO: use protect function + + self.usb.connect(self.usb_uart_converter.usb) + # TODO: add esd protection to usb + + self.power_led.power.connect(pwr_3v3) + self.usb_uart_converter.act.signal.connect_via(self.act_led, pwr_3v3.hv) + self.usb_uart_converter.rx_indicator.signal.connect_via(self.rx_led, pwr_3v3.hv) + self.usb_uart_converter.tx_indicator.signal.connect_via(self.tx_led, pwr_3v3.hv) + + self.usb_uart_converter.osc[1].connect(self.oscillator.p) + self.usb_uart_converter.osc[0].connect(self.oscillator.n) + self.oscillator.power.connect(pwr_3v3) + + # self.usb_uart_converter.reset.signal.filter(type=LOWPASS) + # TODO: implement FilterElectricalRC + # ------------------------------------ + # parametrization + # ------------------------------------ + self.usb_uart_converter.enable_status_outputs() + + self.oscillator.crystal.frequency.merge(8 * P.MHz) + self.oscillator.crystal.frequency_tolerance.merge( + F.Range.upper_bound(40 * P.ppm) + ) + + self.ldo.output_current.merge(F.Range.lower_bound(500 * P.mA)) diff --git a/src/faebryk/library/DE9Connector.py b/src/faebryk/library/DE9Connector.py new file mode 100644 index 00000000..647860da --- /dev/null +++ b/src/faebryk/library/DE9Connector.py @@ -0,0 +1,37 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class DE9Connector(Module): + """ + DE-9 connector + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + unnamed = L.list_field(9, F.Electrical) + + # ---------------------------------------- + # traits + # ---------------------------------------- + designator_prefix = L.f_field(F.has_designator_prefix_defined)("X") + + def __preinit__(self): + # ------------------------------------ + # connections + # ------------------------------------ + + # ------------------------------------ + # parametrization + # ------------------------------------ + pass diff --git a/src/faebryk/library/DE9RS232Connector.py b/src/faebryk/library/DE9RS232Connector.py new file mode 100644 index 00000000..46558373 --- /dev/null +++ b/src/faebryk/library/DE9RS232Connector.py @@ -0,0 +1,51 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class DE9RS232Connector(F.DE9Connector): + """ + Standard RS232 bus on DE-9 connector + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + rs232: F.RS232 + gnd: F.Electrical + shield: F.Electrical + + # ---------------------------------------- + # traits + # ---------------------------------------- + @L.rt_field + def can_attach_to_footprint(self): + pinmap = {f"{i}": ei for i, ei in enumerate(self.unnamed)} + pinmap.update({"10": self.shield}) + return F.can_attach_to_footprint_via_pinmap(pinmap) + + def __preinit__(self): + # ------------------------------------ + # connections + # ------------------------------------ + self.rs232.tx.signal.connect(self.unnamed[3]) + self.rs232.rx.signal.connect(self.unnamed[2]) + self.rs232.dtr.signal.connect(self.unnamed[4]) + self.rs232.dcd.signal.connect(self.unnamed[1]) + self.rs232.dsr.signal.connect(self.unnamed[6]) + self.rs232.ri.signal.connect(self.unnamed[9]) + self.rs232.rts.signal.connect(self.unnamed[7]) + self.rs232.cts.signal.connect(self.unnamed[8]) + + self.gnd.connect(self.unnamed[5]) + + # ------------------------------------ + # parametrization + # ------------------------------------ diff --git a/src/faebryk/library/ISO1540DR.py b/src/faebryk/library/ISO1540DR.py new file mode 100644 index 00000000..1cdb6569 --- /dev/null +++ b/src/faebryk/library/ISO1540DR.py @@ -0,0 +1,62 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class ISO1540(Module): + """ + ISO1540 Low-Power Bidirectional I2C Isolator + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + power: F.ElectricPower + i2c: F.I2C + power_iso: F.ElectricPower + i2c_iso: F.I2C + + # ---------------------------------------- + # traits + # ---------------------------------------- + datasheet = L.f_field(F.has_datasheet_defined)( + "https://wmsc.lcsc.com/wmsc/upload/file/pdf/v2/lcsc/2304140030_Texas-Instruments-ISO1540DR_C179739.pdf" + ) + designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + + @L.rt_field + def can_attach_to_footprint(self): + return F.can_attach_to_footprint_via_pinmap( + pinmap={ + "1": self.power.hv, + "2": self.i2c.sda, + "3": self.i2c.scl, + "4": self.power.lv, + "5": self.power_iso.lv, + "6": self.i2c_iso.scl, + "7": self.i2c_iso.sda, + "8": self.power_iso.hv, + } + ) + + def __preinit__(self): + # ------------------------------------ + # connections + # ------------------------------------ + + # ------------------------------------ + # parametrization + # ------------------------------------ + self.power.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) + self.power_iso.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) + + self.power.decoupled.decouple().capacitance.merge(10 * P.uF) + self.power_iso.decoupled.decouple().capacitance.merge(10 * P.uF) diff --git a/src/faebryk/library/PowerMux.py b/src/faebryk/library/PowerMux.py new file mode 100644 index 00000000..c2f83ec7 --- /dev/null +++ b/src/faebryk/library/PowerMux.py @@ -0,0 +1,17 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class PowerMux(Module): + power_in = L.list_field(2, F.ElectricPower) + power_out: F.ElectricPower + select: F.ElectricLogic diff --git a/src/faebryk/library/RS232TranceiverBase.py b/src/faebryk/library/RS232TranceiverBase.py new file mode 100644 index 00000000..d0a3d99f --- /dev/null +++ b/src/faebryk/library/RS232TranceiverBase.py @@ -0,0 +1,52 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class RS232TranceiverBase(Module): + """ + Common base module for RS232 tranceivers + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + c1: F.ElectricPower + c2: F.ElectricPower + vp: F.ElectricPower + vn: F.ElectricPower + power: F.ElectricPower + + enable: F.ElectricLogic + + # ---------------------------------------- + # traits + # ---------------------------------------- + designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + + def __preinit__(self): + # ------------------------------------ + # connections + # ------------------------------------ + for pwr in self.get_children(direct_only=True, types=F.ElectricPower): + cap = pwr.decoupled.decouple() + # TODO: min values according to self.power.voltage + # 3.0V to 3.6V > C_all = 0.1μF + # 4.5V to 5.5V > C1 = 0.047µF, C2,Cvp, Cvn = 0.33µF + # 3.0V to 5.5V > C_all = 0.22μF + # + cap.capacitance.merge(0.22 * P.uF) + cap.rated_voltage.merge(F.Range.lower_bound(16 * P.V)) + + # ------------------------------------ + # parametrization + # ------------------------------------ + self.power.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) diff --git a/src/faebryk/library/RS232_3D5R_Tranceiver.py b/src/faebryk/library/RS232_3D5R_Tranceiver.py new file mode 100644 index 00000000..a0308cd4 --- /dev/null +++ b/src/faebryk/library/RS232_3D5R_Tranceiver.py @@ -0,0 +1,40 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class RS232_3D5R_Tranceiver(F.RS232TranceiverBase): + """ + Generic 3 drivers + 5 receivers RS232 Tranceiver + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + uart_logic = F.UART + uart_rs232 = F.RS232 + + enable: F.ElectricLogic + online: F.ElectricLogic + status: F.ElectricLogic + + # ---------------------------------------- + # traits + # ---------------------------------------- + + def __preinit__(self): + # ------------------------------------ + # connections + # ------------------------------------ + + # ------------------------------------ + # parametrization + # ------------------------------------ + pass diff --git a/src/faebryk/library/TPS2116.py b/src/faebryk/library/TPS2116.py new file mode 100644 index 00000000..c60c8f65 --- /dev/null +++ b/src/faebryk/library/TPS2116.py @@ -0,0 +1,44 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class TPS2116(F.PowerMux): + """ + 2to1 1.6 V to 5.5 V, 2.5-A Low IQ Power Mux with Manual and Priority Switchover + """ + + power_in = L.list_field(2, F.ElectricPower) + power_out: F.ElectricPower + select: F.Electrical + mode: F.ElectricLogic + status: F.ElectricLogic + + # ---------------------------------------- + # traits + # ---------------------------------------- + designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + + datasheet = L.f_field(F.has_datasheet_defined)( + "https://www.ti.com/lit/ds/symlink/tps2116.pdf" + ) + + @L.rt_field + def single_electric_reference(self): + return F.has_single_electric_reference_defined( + F.ElectricLogic.connect_all_module_references(self, gnd_only=True) + ) + + def __preinit__(self): + gnd = self.power_out.lv + + for power in [self.power_in[0], self.power_in[1], self.power_out]: + power.voltage.merge(F.Range(1.6 * P.V, 5.5 * P.V)) + power.lv.connect(gnd) diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index c713858e..e05d2390 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -81,6 +81,8 @@ from faebryk.library.Pad import Pad from faebryk.library.Button import Button from faebryk.library.Common_Mode_Filter import Common_Mode_Filter +from faebryk.library.Crystal import Crystal +from faebryk.library.DE9Connector import DE9Connector from faebryk.library.GDT import GDT from faebryk.library.Header import Header from faebryk.library.PJ398SM import PJ398SM @@ -108,7 +110,6 @@ from faebryk.library.KicadFootprint import KicadFootprint from faebryk.library.TVS import TVS from faebryk.library.Capacitor import Capacitor -from faebryk.library.Crystal import Crystal from faebryk.library.Fuse import Fuse from faebryk.library.Inductor import Inductor from faebryk.library.Resistor import Resistor @@ -138,6 +139,7 @@ from faebryk.library.can_be_surge_protected_defined import can_be_surge_protected_defined from faebryk.library.can_be_decoupled_defined import can_be_decoupled_defined from faebryk.library.ElectricPower import ElectricPower +from faebryk.library.B0505S import B0505S from faebryk.library.Battery import Battery from faebryk.library.Comparator import Comparator from faebryk.library.Fan import Fan @@ -158,7 +160,9 @@ from faebryk.library.LDO import LDO from faebryk.library.MultiSPI import MultiSPI from faebryk.library.Pinmux import Pinmux +from faebryk.library.PowerMux import PowerMux from faebryk.library.RS232 import RS232 +from faebryk.library.RS232TranceiverBase import RS232TranceiverBase from faebryk.library.SK9822_EC20 import SK9822_EC20 from faebryk.library.SNx4LVC541A import SNx4LVC541A from faebryk.library.SPI import SPI @@ -174,6 +178,7 @@ from faebryk.library.Logic74xx import Logic74xx from faebryk.library.BH1750FVI_TR import BH1750FVI_TR from faebryk.library.EEPROM import EEPROM +from faebryk.library.ISO1540DR import ISO1540 from faebryk.library.M24C08_FMN6TP import M24C08_FMN6TP from faebryk.library.OLED_Module import OLED_Module from faebryk.library.QWIIC import QWIIC @@ -183,6 +188,8 @@ from faebryk.library.ME6211C33M5G_N import ME6211C33M5G_N from faebryk.library.SPIFlash import SPIFlash from faebryk.library.RP2040Pinmux import RP2040Pinmux +from faebryk.library.TPS2116 import TPS2116 +from faebryk.library.DE9RS232Connector import DE9RS232Connector from faebryk.library.SWDConnector import SWDConnector from faebryk.library.HLK_LD2410B_P import HLK_LD2410B_P from faebryk.library.PM1006 import PM1006 @@ -196,8 +203,10 @@ from faebryk.library.CD4011 import CD4011 from faebryk.library.Winbond_Elec_W25Q128JVSIQ import Winbond_Elec_W25Q128JVSIQ from faebryk.library.RP2040 import RP2040 +from faebryk.library.RS232_3D5R_Tranceiver import RS232_3D5R_Tranceiver from faebryk.library.CBM9002A_56ILG import CBM9002A_56ILG from faebryk.library.CH340x import CH340x +from faebryk.library.CH344 import CH344 from faebryk.library.ESP32_C3 import ESP32_C3 from faebryk.library.MCP2221A import MCP2221A from faebryk.library.USB2_0_ESD_Protection import USB2_0_ESD_Protection @@ -209,12 +218,14 @@ from faebryk.library.RP2040_ReferenceDesign import RP2040_ReferenceDesign from faebryk.library.CBM9002A_56ILG_Reference_Design import CBM9002A_56ILG_Reference_Design from faebryk.library.USB_RS485 import USB_RS485 +from faebryk.library.CH344Q import CH344Q from faebryk.library.ESP32_C3_MINI_1 import ESP32_C3_MINI_1 from faebryk.library.USB_C_PSU_Vertical import USB_C_PSU_Vertical from faebryk.library.USB3_connector import USB3_connector from faebryk.library.USB_C import USB_C from faebryk.library.PowerSwitchMOSFET import PowerSwitchMOSFET from faebryk.library.PowerSwitchStatic import PowerSwitchStatic +from faebryk.library.CH344Q_ReferenceDesign import CH344Q_ReferenceDesign from faebryk.library.ESP32_C3_MINI_1_Reference_Design import ESP32_C3_MINI_1_Reference_Design from faebryk.library.USB_C_5V_PSU import USB_C_5V_PSU from faebryk.library.USB_C_PowerOnly import USB_C_PowerOnly From f8a33de451dffd8a98dd86b293f0a7dabf076eef Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 5 Sep 2024 19:13:19 +0200 Subject: [PATCH 02/27] Add: missing module interfaces --- src/faebryk/library/RS232.py | 6 ++++++ src/faebryk/library/UART.py | 2 ++ 2 files changed, 8 insertions(+) diff --git a/src/faebryk/library/RS232.py b/src/faebryk/library/RS232.py index 33fad49f..2b82dd83 100644 --- a/src/faebryk/library/RS232.py +++ b/src/faebryk/library/RS232.py @@ -9,6 +9,12 @@ class RS232(ModuleInterface): tx: F.ElectricLogic rx: F.ElectricLogic + dtr: F.ElectricLogic + dcd: F.ElectricLogic + dsr: F.ElectricLogic + ri: F.ElectricLogic + rts: F.ElectricLogic + cts: F.ElectricLogic @L.rt_field def single_electric_reference(self): diff --git a/src/faebryk/library/UART.py b/src/faebryk/library/UART.py index 8d7975c2..ce06605e 100644 --- a/src/faebryk/library/UART.py +++ b/src/faebryk/library/UART.py @@ -11,3 +11,5 @@ class UART(ModuleInterface): cts: F.ElectricLogic dtr: F.ElectricLogic dsr: F.ElectricLogic + dcd: F.ElectricLogic + ri: F.ElectricLogic From 5766e3fb88c9ad93ac0195f52d5d3a65ee363b77 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 5 Sep 2024 22:58:32 +0200 Subject: [PATCH 03/27] Add: CH342F --- src/faebryk/library/CH342.py | 64 ++++++++ src/faebryk/library/CH342F.py | 148 ++++++++++++++++++ src/faebryk/library/CH342F_ReferenceDesign.py | 71 +++++++++ src/faebryk/library/_F.py | 3 + 4 files changed, 286 insertions(+) create mode 100644 src/faebryk/library/CH342.py create mode 100644 src/faebryk/library/CH342F.py create mode 100644 src/faebryk/library/CH342F_ReferenceDesign.py diff --git a/src/faebryk/library/CH342.py b/src/faebryk/library/CH342.py new file mode 100644 index 00000000..82ec4ae3 --- /dev/null +++ b/src/faebryk/library/CH342.py @@ -0,0 +1,64 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging +from enum import Enum, auto + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class CH342(Module): + """ + Base class for CH342x USB to double UART converter + """ + + class DuplexMode(Enum): + FULL = auto() + HALF = auto() + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + usb: F.USB2_0 + uart = L.list_field(2, F.UART) + tnow = L.list_field(2, F.ElectricLogic) + ri = L.list_field(2, F.ElectricLogic) + dcd = L.list_field(2, F.ElectricLogic) + + reset = F.ElectricLogic() + active = F.ElectricLogic() + + vdd_5v = F.ElectricPower() + v_io = F.ElectricPower() + v_3v = F.ElectricPower() + + # ---------------------------------------- + # traits + # ---------------------------------------- + datasheet = L.f_field(F.has_datasheet_defined)( + "https://wch-ic.com/downloads/CH342DS1_PDF.html" + ) + + def __preinit__(self): + # ---------------------------------------- + # aliasess + # ---------------------------------------- + gnd = self.usb.usb_if.buspower.lv + + # ---------------------------------------- + # parametrization + # ---------------------------------------- + self.vdd_5v.voltage.merge(F.Range(4 * P.V, 5.5 * P.V)) + self.v_3v.voltage.merge(F.Constant(3.3 * P.V)) + self.v_io.voltage.merge(F.Range(1.7 * P.V, 3.6 * P.V)) + + # ---------------------------------------- + # connections + # ---------------------------------------- + for powerrail in [self.vdd_5v, self.v_io, self.v_3v]: + powerrail.lv.connect(gnd) diff --git a/src/faebryk/library/CH342F.py b/src/faebryk/library/CH342F.py new file mode 100644 index 00000000..3054beaf --- /dev/null +++ b/src/faebryk/library/CH342F.py @@ -0,0 +1,148 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.picker.picker import DescriptiveProperties +from faebryk.libs.units import P # noqa: F401 +from faebryk.libs.util import NotNone + +logger = logging.getLogger(__name__) + + +class CH342F(Module): + """ + Dual UART-USB converter + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + usb: F.USB2_0 + uart = L.list_field(2, F.UART) + + tnow = L.list_field(2, F.ElectricLogic) + ri = L.list_field(2, F.ElectricLogic) + dcd = L.list_field(2, F.ElectricLogic) + + reset: F.ElectricLogic + active: F.ElectricLogic + + vdd_5v: F.ElectricPower + v_io: F.ElectricPower + v_3v: F.ElectricPower + + designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + + # ---------------------------------------- + # traits + # ---------------------------------------- + datasheet = L.f_field(F.has_datasheet_defined)( + "https://wch-ic.com/downloads/CH342DS1_PDF.html" + ) + + @L.rt_field + def can_attach_to_footprint(self): + return F.can_attach_to_footprint_via_pinmap( + { + "1": self.ri[0].signal, + "2": self.usb.usb_if.buspower.lv, + "3": self.usb.usb_if.d.p, + "4": self.usb.usb_if.d.n, + "5": self.v_io.hv, + "6": self.v_3v.hv, + "7": self.vdd_5v.hv, + "8": self.usb.usb_if.buspower.hv, + "9": self.reset.signal, + "10": self.uart[1].cts.signal, + "11": self.uart[1].rts.signal, + "12": self.uart[1].base_uart.rx.signal, + "13": self.uart[1].base_uart.tx.signal, + "14": self.uart[1].dsr.signal, + "15": self.uart[1].dtr.signal, + "16": self.dcd[1].signal, + "17": self.ri[1].signal, + "18": self.uart[0].cts.signal, + "19": self.uart[0].rts.signal, + "20": self.uart[0].base_uart.rx.signal, + "21": self.uart[0].base_uart.tx.signal, + "22": self.uart[0].dsr.signal, + "23": self.uart[0].dtr.signal, + "24": self.dcd[0].signal, + "25": self.usb.usb_if.buspower.lv, + } + ) + + def __init__( + self, + duplex_mode_uart_0: F.CH342.DuplexMode = F.CH342.DuplexMode.FULL, + duplex_mode_uart_1: F.CH342.DuplexMode = F.CH342.DuplexMode.FULL, + ): + super().__init__() + self._duplex_mode_uart_0 = duplex_mode_uart_0 + self._duplex_mode_uart_1 = duplex_mode_uart_1 + + def __preinit__(self) -> None: + # ---------------------------------------- + # aliasess + # ---------------------------------------- + # ---------------------------------------- + # parametrization + # ---------------------------------------- + self.vdd_5v.voltage.merge(F.Range(4 * P.V, 5.5 * P.V)) + self.v_3v.voltage.merge(F.Constant(3.3 * P.V)) + self.v_io.voltage.merge(F.Range(1.7 * P.V, 3.6 * P.V)) + + # set the duplex mode + if self._duplex_mode_uart_0 == F.CH342.DuplexMode.HALF: + self.uart[0].dtr.get_trait(F.ElectricLogic.can_be_pulled).pull(up=False) + NotNone( + self.uart[0].dtr.get_trait(F.ElectricLogic.has_pulls).get_pulls()[1] + ).resistance.merge(F.Constant(4.7 * P.kohm)) + self.tnow[0].connect(self.uart[0].dtr) + if self._duplex_mode_uart_1 == F.CH342.DuplexMode.HALF: + self.uart[1].dtr.get_trait(F.ElectricLogic.can_be_pulled).pull(up=False) + NotNone( + self.uart[1].dtr.get_trait(F.ElectricLogic.has_pulls).get_pulls()[1] + ).resistance.merge(F.Constant(4.7 * P.kohm)) + self.tnow[1].connect(self.uart[1].dtr) + + # ---------------------------------------- + # connections + # ---------------------------------------- + # configure for 3.3V GPIO operation with internal LDO + self.vdd_5v.connect(self.usb.usb_if.buspower) + self.v_3v.connect(self.v_io) + + self.vdd_5v.get_trait(F.can_be_decoupled).decouple().capacitance.merge( + F.Constant(1 * P.uF) + ) + self.v_3v.get_trait(F.can_be_decoupled).decouple().capacitance.merge( + F.Constant(0.1 * P.uF) + ) + self.v_io.get_trait(F.can_be_decoupled).decouple().capacitance.merge( + F.Constant(1 * P.uF) + ) + + F.can_attach_to_footprint().attach( + F.QFN( + pin_cnt=24, + exposed_thermal_pad_cnt=1, + size_xy=(4 * P.mm, 4 * P.mm), + pitch=0.5 * P.mm, + exposed_thermal_pad_dimensions=(2.65 * P.mm, 2.65 * P.mm), + has_thermal_vias=False, + ) + ) + + self.add( + F.has_descriptive_properties_defined( + { + DescriptiveProperties.manufacturer: "WCH", + DescriptiveProperties.partno: "CH342F", + }, + ) + ) diff --git a/src/faebryk/library/CH342F_ReferenceDesign.py b/src/faebryk/library/CH342F_ReferenceDesign.py new file mode 100644 index 00000000..79eeb68c --- /dev/null +++ b/src/faebryk/library/CH342F_ReferenceDesign.py @@ -0,0 +1,71 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 +from faebryk.libs.util import NotNone + +logger = logging.getLogger(__name__) + + +class CH342F_ReferenceDesign(Module): + """ + Minimal reference implementation of the CH342F + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + ch324: F.CH342F + + def __init__( + self, + duplex_mode_uart_0: F.CH342.DuplexMode = F.CH342.DuplexMode.FULL, + duplex_mode_uart_1: F.CH342.DuplexMode = F.CH342.DuplexMode.FULL, + ) -> None: + super().__init__() + self._duplex_mode_uart_0 = duplex_mode_uart_0 + self._duplex_mode_uart_1 = duplex_mode_uart_1 + + def __preinit__(self): + # ---------------------------------------- + # aliasess + # ---------------------------------------- + # ---------------------------------------- + # parametrization + # ---------------------------------------- + # set the duplex mode + if self._duplex_mode_uart_0 == F.CH342.DuplexMode.HALF: + self.ch324.uart[0].dtr.get_trait(F.ElectricLogic.can_be_pulled).pull( + up=False + ) + NotNone( + self.ch324.uart[0] + .dtr.get_trait(F.ElectricLogic.has_pulls) + .get_pulls()[1] + ).resistance.merge(F.Constant(4.7 * P.kohm)) + self.ch324.tnow[0].connect(self.ch324.uart[0].dtr) + if self._duplex_mode_uart_1 == F.CH342.DuplexMode.HALF: + self.ch324.uart[1].dtr.get_trait(F.ElectricLogic.can_be_pulled).pull( + up=False + ) + NotNone( + self.ch324.uart[1] + .dtr.get_trait(F.ElectricLogic.has_pulls) + .get_pulls()[1] + ).resistance.merge(F.Constant(4.7 * P.kohm)) + self.ch324.tnow[1].connect(self.ch324.uart[1].dtr) + + # ---------------------------------------- + # connections + # ---------------------------------------- + # configure for 3.3V GPIO operation with internal LDO + self.ch324.vdd_5v.connect(self.ch324.usb.usb_if.buspower) + self.ch324.v_3v.connect(self.ch324.v_io) + + self.ch324.vdd_5v.get_trait(F.can_be_decoupled).decouple() + self.ch324.v_3v.get_trait(F.can_be_decoupled).decouple() diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index e05d2390..f522a2b8 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -206,6 +206,7 @@ from faebryk.library.RS232_3D5R_Tranceiver import RS232_3D5R_Tranceiver from faebryk.library.CBM9002A_56ILG import CBM9002A_56ILG from faebryk.library.CH340x import CH340x +from faebryk.library.CH342 import CH342 from faebryk.library.CH344 import CH344 from faebryk.library.ESP32_C3 import ESP32_C3 from faebryk.library.MCP2221A import MCP2221A @@ -218,6 +219,7 @@ from faebryk.library.RP2040_ReferenceDesign import RP2040_ReferenceDesign from faebryk.library.CBM9002A_56ILG_Reference_Design import CBM9002A_56ILG_Reference_Design from faebryk.library.USB_RS485 import USB_RS485 +from faebryk.library.CH342F import CH342F from faebryk.library.CH344Q import CH344Q from faebryk.library.ESP32_C3_MINI_1 import ESP32_C3_MINI_1 from faebryk.library.USB_C_PSU_Vertical import USB_C_PSU_Vertical @@ -225,6 +227,7 @@ from faebryk.library.USB_C import USB_C from faebryk.library.PowerSwitchMOSFET import PowerSwitchMOSFET from faebryk.library.PowerSwitchStatic import PowerSwitchStatic +from faebryk.library.CH342F_ReferenceDesign import CH342F_ReferenceDesign from faebryk.library.CH344Q_ReferenceDesign import CH344Q_ReferenceDesign from faebryk.library.ESP32_C3_MINI_1_Reference_Design import ESP32_C3_MINI_1_Reference_Design from faebryk.library.USB_C_5V_PSU import USB_C_5V_PSU From f1a51ddf1351d516f6ea4cd8ce1ebc09a4f7695d Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 5 Sep 2024 23:45:04 +0200 Subject: [PATCH 04/27] Various fixes and additions --- .../library/{B0505S.py => B0505S_1WR3.py} | 14 +++++++++-- src/faebryk/library/CH342.py | 10 ++++---- src/faebryk/library/CH344.py | 2 +- src/faebryk/library/DE9Connector.py | 1 + src/faebryk/library/DE9RS232Connector.py | 25 +++++++++---------- .../library/{ISO1540DR.py => ISO1540.py} | 10 ++++++++ src/faebryk/library/RS232_3D5R_Tranceiver.py | 13 ++++------ .../{RS232TranceiverBase.py => SP3243E.py} | 21 +++++++++++++--- src/faebryk/library/_F.py | 6 ++--- 9 files changed, 67 insertions(+), 35 deletions(-) rename src/faebryk/library/{B0505S.py => B0505S_1WR3.py} (84%) rename src/faebryk/library/{ISO1540DR.py => ISO1540.py} (85%) rename src/faebryk/library/{RS232TranceiverBase.py => SP3243E.py} (70%) diff --git a/src/faebryk/library/B0505S.py b/src/faebryk/library/B0505S_1WR3.py similarity index 84% rename from src/faebryk/library/B0505S.py rename to src/faebryk/library/B0505S_1WR3.py index 0c08736e..9883f4a8 100644 --- a/src/faebryk/library/B0505S.py +++ b/src/faebryk/library/B0505S_1WR3.py @@ -6,14 +6,16 @@ import faebryk.library._F as F # noqa: F401 from faebryk.core.module import Module from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P # noqa: F401 logger = logging.getLogger(__name__) -class B0505S(Module): +class B0505S_1WR3(Module): """ - Isolated 5V DC to 5V DC converter + Isolated 5V DC to 5V DC converter. + R suffix is for shortcircuit protection """ # ---------------------------------------- @@ -59,3 +61,11 @@ def __preinit__(self): # ---------------------------------------- self.power_in.voltage.merge(F.Range(4.3 * P.V, 9 * P.V)) self.power_out.voltage.merge(F.Range.from_center(5 * P.V, 0.5 * P.V)) + + self.add( + F.has_descriptive_properties_defined( + { + DescriptiveProperties.partno: "B0505S-1WR3", + }, + ) + ) diff --git a/src/faebryk/library/CH342.py b/src/faebryk/library/CH342.py index 82ec4ae3..a573f0c3 100644 --- a/src/faebryk/library/CH342.py +++ b/src/faebryk/library/CH342.py @@ -30,12 +30,12 @@ class DuplexMode(Enum): ri = L.list_field(2, F.ElectricLogic) dcd = L.list_field(2, F.ElectricLogic) - reset = F.ElectricLogic() - active = F.ElectricLogic() + reset: F.ElectricLogic + active: F.ElectricLogic - vdd_5v = F.ElectricPower() - v_io = F.ElectricPower() - v_3v = F.ElectricPower() + vdd_5v: F.ElectricPower + v_io: F.ElectricPower + v_3v: F.ElectricPower # ---------------------------------------- # traits diff --git a/src/faebryk/library/CH344.py b/src/faebryk/library/CH344.py index 82306e88..87844c1d 100644 --- a/src/faebryk/library/CH344.py +++ b/src/faebryk/library/CH344.py @@ -68,7 +68,7 @@ def __preinit__(self): self.gpio[14].connect(self.uart[0].dsr) self.gpio[15].connect(self.uart[1].dcd) - self.test.pulled.pull(up=False).resistance.merge(4.7 * P.kOhm) + self.test.pulled.pull(up=False).resistance.merge(4.7 * P.kohm) # ------------------------------------ # parametrization # ------------------------------------ diff --git a/src/faebryk/library/DE9Connector.py b/src/faebryk/library/DE9Connector.py index 647860da..7f69cc02 100644 --- a/src/faebryk/library/DE9Connector.py +++ b/src/faebryk/library/DE9Connector.py @@ -20,6 +20,7 @@ class DE9Connector(Module): # modules, interfaces, parameters # ---------------------------------------- unnamed = L.list_field(9, F.Electrical) + shield: F.Electrical # ---------------------------------------- # traits diff --git a/src/faebryk/library/DE9RS232Connector.py b/src/faebryk/library/DE9RS232Connector.py index 46558373..c5419528 100644 --- a/src/faebryk/library/DE9RS232Connector.py +++ b/src/faebryk/library/DE9RS232Connector.py @@ -19,15 +19,14 @@ class DE9RS232Connector(F.DE9Connector): # modules, interfaces, parameters # ---------------------------------------- rs232: F.RS232 - gnd: F.Electrical - shield: F.Electrical + signal_gnd: F.Electrical # ---------------------------------------- # traits # ---------------------------------------- @L.rt_field def can_attach_to_footprint(self): - pinmap = {f"{i}": ei for i, ei in enumerate(self.unnamed)} + pinmap = {f"{i+1}": ei for i, ei in enumerate(self.unnamed)} pinmap.update({"10": self.shield}) return F.can_attach_to_footprint_via_pinmap(pinmap) @@ -35,16 +34,16 @@ def __preinit__(self): # ------------------------------------ # connections # ------------------------------------ - self.rs232.tx.signal.connect(self.unnamed[3]) - self.rs232.rx.signal.connect(self.unnamed[2]) - self.rs232.dtr.signal.connect(self.unnamed[4]) - self.rs232.dcd.signal.connect(self.unnamed[1]) - self.rs232.dsr.signal.connect(self.unnamed[6]) - self.rs232.ri.signal.connect(self.unnamed[9]) - self.rs232.rts.signal.connect(self.unnamed[7]) - self.rs232.cts.signal.connect(self.unnamed[8]) - - self.gnd.connect(self.unnamed[5]) + self.rs232.tx.signal.connect(self.unnamed[2]) + self.rs232.rx.signal.connect(self.unnamed[1]) + self.rs232.dtr.signal.connect(self.unnamed[3]) + self.rs232.dcd.signal.connect(self.unnamed[0]) + self.rs232.dsr.signal.connect(self.unnamed[5]) + self.rs232.ri.signal.connect(self.unnamed[8]) + self.rs232.rts.signal.connect(self.unnamed[6]) + self.rs232.cts.signal.connect(self.unnamed[7]) + + self.signal_gnd.connect(self.unnamed[4]) # ------------------------------------ # parametrization diff --git a/src/faebryk/library/ISO1540DR.py b/src/faebryk/library/ISO1540.py similarity index 85% rename from src/faebryk/library/ISO1540DR.py rename to src/faebryk/library/ISO1540.py index 1cdb6569..f5c6770b 100644 --- a/src/faebryk/library/ISO1540DR.py +++ b/src/faebryk/library/ISO1540.py @@ -6,6 +6,7 @@ import faebryk.library._F as F # noqa: F401 from faebryk.core.module import Module from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P # noqa: F401 logger = logging.getLogger(__name__) @@ -60,3 +61,12 @@ def __preinit__(self): self.power.decoupled.decouple().capacitance.merge(10 * P.uF) self.power_iso.decoupled.decouple().capacitance.merge(10 * P.uF) + + self.add( + F.has_descriptive_properties_defined( + { + DescriptiveProperties.manufacturer: "Texas Instruments", + DescriptiveProperties.partno: "ISO1540DR", + }, + ) + ) diff --git a/src/faebryk/library/RS232_3D5R_Tranceiver.py b/src/faebryk/library/RS232_3D5R_Tranceiver.py index a0308cd4..dac75a7c 100644 --- a/src/faebryk/library/RS232_3D5R_Tranceiver.py +++ b/src/faebryk/library/RS232_3D5R_Tranceiver.py @@ -4,26 +4,23 @@ import logging import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module from faebryk.libs.library import L # noqa: F401 from faebryk.libs.units import P # noqa: F401 logger = logging.getLogger(__name__) -class RS232_3D5R_Tranceiver(F.RS232TranceiverBase): +class RS232_3D5R_Tranceiver(Module): """ - Generic 3 drivers + 5 receivers RS232 Tranceiver + Generic 3 drivers + 5 receivers RS232 Tranceiver base """ # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- - uart_logic = F.UART - uart_rs232 = F.RS232 - - enable: F.ElectricLogic - online: F.ElectricLogic - status: F.ElectricLogic + uart_logic: F.UART + uart_rs232: F.RS232 # ---------------------------------------- # traits diff --git a/src/faebryk/library/RS232TranceiverBase.py b/src/faebryk/library/SP3243E.py similarity index 70% rename from src/faebryk/library/RS232TranceiverBase.py rename to src/faebryk/library/SP3243E.py index d0a3d99f..486ffa0e 100644 --- a/src/faebryk/library/RS232TranceiverBase.py +++ b/src/faebryk/library/SP3243E.py @@ -4,14 +4,14 @@ import logging import faebryk.library._F as F # noqa: F401 -from faebryk.core.module import Module from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P # noqa: F401 logger = logging.getLogger(__name__) -class RS232TranceiverBase(Module): +class SP3243E(F.RS232_3D5R_Tranceiver): """ Common base module for RS232 tranceivers """ @@ -26,11 +26,16 @@ class RS232TranceiverBase(Module): power: F.ElectricPower enable: F.ElectricLogic + online: F.ElectricLogic + status: F.ElectricLogic # ---------------------------------------- # traits # ---------------------------------------- designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + datasheet = L.f_field(F.has_datasheet_defined)( + "https://assets.maxlinear.com/web/documents/sp3243e.pdf" + ) def __preinit__(self): # ------------------------------------ @@ -44,9 +49,19 @@ def __preinit__(self): # 3.0V to 5.5V > C_all = 0.22μF # cap.capacitance.merge(0.22 * P.uF) - cap.rated_voltage.merge(F.Range.lower_bound(16 * P.V)) + # cap.rated_voltage.override(F.Range.lower_bound(16 * P.V)) + # TODO: merge conflict # ------------------------------------ # parametrization # ------------------------------------ self.power.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) + + self.add( + F.has_descriptive_properties_defined( + { + DescriptiveProperties.manufacturer: "MaxLinear", + DescriptiveProperties.partno: "SP3243EBEA-L/TR", + }, + ) + ) diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index f522a2b8..d368848d 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -139,7 +139,7 @@ from faebryk.library.can_be_surge_protected_defined import can_be_surge_protected_defined from faebryk.library.can_be_decoupled_defined import can_be_decoupled_defined from faebryk.library.ElectricPower import ElectricPower -from faebryk.library.B0505S import B0505S +from faebryk.library.B0505S_1WR3 import B0505S_1WR3 from faebryk.library.Battery import Battery from faebryk.library.Comparator import Comparator from faebryk.library.Fan import Fan @@ -162,7 +162,6 @@ from faebryk.library.Pinmux import Pinmux from faebryk.library.PowerMux import PowerMux from faebryk.library.RS232 import RS232 -from faebryk.library.RS232TranceiverBase import RS232TranceiverBase from faebryk.library.SK9822_EC20 import SK9822_EC20 from faebryk.library.SNx4LVC541A import SNx4LVC541A from faebryk.library.SPI import SPI @@ -178,7 +177,7 @@ from faebryk.library.Logic74xx import Logic74xx from faebryk.library.BH1750FVI_TR import BH1750FVI_TR from faebryk.library.EEPROM import EEPROM -from faebryk.library.ISO1540DR import ISO1540 +from faebryk.library.ISO1540 import ISO1540 from faebryk.library.M24C08_FMN6TP import M24C08_FMN6TP from faebryk.library.OLED_Module import OLED_Module from faebryk.library.QWIIC import QWIIC @@ -217,6 +216,7 @@ from faebryk.library.PowerSwitch import PowerSwitch from faebryk.library.TI_CD4011BE import TI_CD4011BE from faebryk.library.RP2040_ReferenceDesign import RP2040_ReferenceDesign +from faebryk.library.SP3243E import SP3243E from faebryk.library.CBM9002A_56ILG_Reference_Design import CBM9002A_56ILG_Reference_Design from faebryk.library.USB_RS485 import USB_RS485 from faebryk.library.CH342F import CH342F From b1246f401e5f600721f4f0816260033b16accbfc Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Fri, 6 Sep 2024 15:40:44 +0200 Subject: [PATCH 05/27] Fix: comply with most of fabll code guidelines --- src/faebryk/library/B0505S_1WR3.py | 20 +++++----- ...n.py => CBM9002A_56ILG_ReferenceDesign.py} | 2 +- src/faebryk/library/CH342.py | 12 +++--- src/faebryk/library/CH342F.py | 36 ++++++++---------- src/faebryk/library/CH344Q.py | 17 +++++---- src/faebryk/library/DE9Connector.py | 2 +- src/faebryk/library/DE9RS232Connector.py | 37 ++++++++++++------- ....py => ESP32_C3_MINI_1_ReferenceDesign.py} | 2 +- src/faebryk/library/ISO1540.py | 18 ++++----- src/faebryk/library/RP2040_ReferenceDesign.py | 13 ++++--- src/faebryk/library/SP3243E.py | 31 +++++++++------- src/faebryk/library/TPS2116.py | 15 ++++++-- src/faebryk/library/_F.py | 6 +-- 13 files changed, 116 insertions(+), 95 deletions(-) rename src/faebryk/library/{CBM9002A_56ILG_Reference_Design.py => CBM9002A_56ILG_ReferenceDesign.py} (98%) rename src/faebryk/library/{ESP32_C3_MINI_1_Reference_Design.py => ESP32_C3_MINI_1_ReferenceDesign.py} (97%) diff --git a/src/faebryk/library/B0505S_1WR3.py b/src/faebryk/library/B0505S_1WR3.py index 9883f4a8..af7ebb7d 100644 --- a/src/faebryk/library/B0505S_1WR3.py +++ b/src/faebryk/library/B0505S_1WR3.py @@ -44,16 +44,24 @@ def can_attach_to_footprint(self): } ) + @L.rt_field + def has_descriptive_properties_defined(self): + return F.has_descriptive_properties_defined( + { + DescriptiveProperties.partno: "B0505S-1WR3", + }, + ) + # self.add_trait(can_bridge_defined(self.power_in, self.power_out)) def __preinit__(self): # ---------------------------------------- # parametrization # ---------------------------------------- self.power_in.get_trait(F.can_be_decoupled).decouple().capacitance.merge( - F.Constant(4.7 * P.uF) + 4.7 * P.uF ) self.power_out.get_trait(F.can_be_decoupled).decouple().capacitance.merge( - F.Constant(10 * P.uF) + 10 * P.uF ) # ---------------------------------------- @@ -61,11 +69,3 @@ def __preinit__(self): # ---------------------------------------- self.power_in.voltage.merge(F.Range(4.3 * P.V, 9 * P.V)) self.power_out.voltage.merge(F.Range.from_center(5 * P.V, 0.5 * P.V)) - - self.add( - F.has_descriptive_properties_defined( - { - DescriptiveProperties.partno: "B0505S-1WR3", - }, - ) - ) diff --git a/src/faebryk/library/CBM9002A_56ILG_Reference_Design.py b/src/faebryk/library/CBM9002A_56ILG_ReferenceDesign.py similarity index 98% rename from src/faebryk/library/CBM9002A_56ILG_Reference_Design.py rename to src/faebryk/library/CBM9002A_56ILG_ReferenceDesign.py index 8abb6018..1d44afa5 100644 --- a/src/faebryk/library/CBM9002A_56ILG_Reference_Design.py +++ b/src/faebryk/library/CBM9002A_56ILG_ReferenceDesign.py @@ -7,7 +7,7 @@ from faebryk.libs.units import P -class CBM9002A_56ILG_Reference_Design(Module): +class CBM9002A_56ILG_ReferenceDesign(Module): """ Minimal working example for the CBM9002A_56ILG """ diff --git a/src/faebryk/library/CH342.py b/src/faebryk/library/CH342.py index a573f0c3..4641743c 100644 --- a/src/faebryk/library/CH342.py +++ b/src/faebryk/library/CH342.py @@ -44,21 +44,23 @@ class DuplexMode(Enum): "https://wch-ic.com/downloads/CH342DS1_PDF.html" ) + @L.rt_field + def single_electric_reference(self): + return F.has_single_electric_reference_defined( + F.ElectricLogic.connect_all_module_references(self, gnd_only=True) + ) + def __preinit__(self): # ---------------------------------------- # aliasess # ---------------------------------------- - gnd = self.usb.usb_if.buspower.lv - # ---------------------------------------- # parametrization # ---------------------------------------- self.vdd_5v.voltage.merge(F.Range(4 * P.V, 5.5 * P.V)) - self.v_3v.voltage.merge(F.Constant(3.3 * P.V)) + self.v_3v.voltage.merge(3.3 * P.V) self.v_io.voltage.merge(F.Range(1.7 * P.V, 3.6 * P.V)) # ---------------------------------------- # connections # ---------------------------------------- - for powerrail in [self.vdd_5v, self.v_io, self.v_3v]: - powerrail.lv.connect(gnd) diff --git a/src/faebryk/library/CH342F.py b/src/faebryk/library/CH342F.py index 3054beaf..c430930d 100644 --- a/src/faebryk/library/CH342F.py +++ b/src/faebryk/library/CH342F.py @@ -76,6 +76,15 @@ def can_attach_to_footprint(self): } ) + @L.rt_field + def descriptive_properties(self): + return F.has_descriptive_properties_defined( + { + DescriptiveProperties.manufacturer: "WCH", + DescriptiveProperties.partno: "CH342F", + }, + ) + def __init__( self, duplex_mode_uart_0: F.CH342.DuplexMode = F.CH342.DuplexMode.FULL, @@ -93,7 +102,7 @@ def __preinit__(self) -> None: # parametrization # ---------------------------------------- self.vdd_5v.voltage.merge(F.Range(4 * P.V, 5.5 * P.V)) - self.v_3v.voltage.merge(F.Constant(3.3 * P.V)) + self.v_3v.voltage.merge(3.3 * P.V) self.v_io.voltage.merge(F.Range(1.7 * P.V, 3.6 * P.V)) # set the duplex mode @@ -101,13 +110,13 @@ def __preinit__(self) -> None: self.uart[0].dtr.get_trait(F.ElectricLogic.can_be_pulled).pull(up=False) NotNone( self.uart[0].dtr.get_trait(F.ElectricLogic.has_pulls).get_pulls()[1] - ).resistance.merge(F.Constant(4.7 * P.kohm)) + ).resistance.merge(4.7 * P.kohm) self.tnow[0].connect(self.uart[0].dtr) if self._duplex_mode_uart_1 == F.CH342.DuplexMode.HALF: self.uart[1].dtr.get_trait(F.ElectricLogic.can_be_pulled).pull(up=False) NotNone( self.uart[1].dtr.get_trait(F.ElectricLogic.has_pulls).get_pulls()[1] - ).resistance.merge(F.Constant(4.7 * P.kohm)) + ).resistance.merge(4.7 * P.kohm) self.tnow[1].connect(self.uart[1].dtr) # ---------------------------------------- @@ -117,15 +126,9 @@ def __preinit__(self) -> None: self.vdd_5v.connect(self.usb.usb_if.buspower) self.v_3v.connect(self.v_io) - self.vdd_5v.get_trait(F.can_be_decoupled).decouple().capacitance.merge( - F.Constant(1 * P.uF) - ) - self.v_3v.get_trait(F.can_be_decoupled).decouple().capacitance.merge( - F.Constant(0.1 * P.uF) - ) - self.v_io.get_trait(F.can_be_decoupled).decouple().capacitance.merge( - F.Constant(1 * P.uF) - ) + self.vdd_5v.get_trait(F.can_be_decoupled).decouple().capacitance.merge(1 * P.uF) + self.v_3v.get_trait(F.can_be_decoupled).decouple().capacitance.merge(0.1 * P.uF) + self.v_io.get_trait(F.can_be_decoupled).decouple().capacitance.merge(1 * P.uF) F.can_attach_to_footprint().attach( F.QFN( @@ -137,12 +140,3 @@ def __preinit__(self) -> None: has_thermal_vias=False, ) ) - - self.add( - F.has_descriptive_properties_defined( - { - DescriptiveProperties.manufacturer: "WCH", - DescriptiveProperties.partno: "CH342F", - }, - ) - ) diff --git a/src/faebryk/library/CH344Q.py b/src/faebryk/library/CH344Q.py index 3d1675d0..3d91c0a4 100644 --- a/src/faebryk/library/CH344Q.py +++ b/src/faebryk/library/CH344Q.py @@ -60,6 +60,15 @@ def enable_hardware_flow_conrol(self): # ---------------------------------------- # traits # ---------------------------------------- + @L.rt_field + def descriptive_properties(self): + return F.has_descriptive_properties_defined( + { + DescriptiveProperties.manufacturer: "WCH", + DescriptiveProperties.partno: "CH344Q", + }, + ) + @L.rt_field def can_attach_to_footprint(self): return F.can_attach_to_footprint_via_pinmap( @@ -124,11 +133,3 @@ def __preinit__(self): # ------------------------------------ # parametrization # ------------------------------------ - self.add( - F.has_descriptive_properties_defined( - { - DescriptiveProperties.manufacturer: "WCH", - DescriptiveProperties.partno: "CH344Q", - }, - ) - ) diff --git a/src/faebryk/library/DE9Connector.py b/src/faebryk/library/DE9Connector.py index 7f69cc02..7a3ef73d 100644 --- a/src/faebryk/library/DE9Connector.py +++ b/src/faebryk/library/DE9Connector.py @@ -19,7 +19,7 @@ class DE9Connector(Module): # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- - unnamed = L.list_field(9, F.Electrical) + contact = L.list_field(9, F.Electrical) shield: F.Electrical # ---------------------------------------- diff --git a/src/faebryk/library/DE9RS232Connector.py b/src/faebryk/library/DE9RS232Connector.py index c5419528..8f4f400d 100644 --- a/src/faebryk/library/DE9RS232Connector.py +++ b/src/faebryk/library/DE9RS232Connector.py @@ -4,13 +4,14 @@ import logging import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module from faebryk.libs.library import L # noqa: F401 from faebryk.libs.units import P # noqa: F401 logger = logging.getLogger(__name__) -class DE9RS232Connector(F.DE9Connector): +class DE9RS232Connector(Module): """ Standard RS232 bus on DE-9 connector """ @@ -18,32 +19,40 @@ class DE9RS232Connector(F.DE9Connector): # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- + connector: F.DE9Connector rs232: F.RS232 - signal_gnd: F.Electrical # ---------------------------------------- # traits # ---------------------------------------- @L.rt_field def can_attach_to_footprint(self): - pinmap = {f"{i+1}": ei for i, ei in enumerate(self.unnamed)} - pinmap.update({"10": self.shield}) + pinmap = {f"{i+1}": ei for i, ei in enumerate(self.connector.contact)} + pinmap.update({"10": self.connector.shield}) return F.can_attach_to_footprint_via_pinmap(pinmap) + @L.rt_field + def single_electric_reference(self): + return F.has_single_electric_reference_defined( + F.ElectricLogic.connect_all_module_references(self) + ) + def __preinit__(self): # ------------------------------------ # connections # ------------------------------------ - self.rs232.tx.signal.connect(self.unnamed[2]) - self.rs232.rx.signal.connect(self.unnamed[1]) - self.rs232.dtr.signal.connect(self.unnamed[3]) - self.rs232.dcd.signal.connect(self.unnamed[0]) - self.rs232.dsr.signal.connect(self.unnamed[5]) - self.rs232.ri.signal.connect(self.unnamed[8]) - self.rs232.rts.signal.connect(self.unnamed[6]) - self.rs232.cts.signal.connect(self.unnamed[7]) - - self.signal_gnd.connect(self.unnamed[4]) + self.rs232.tx.signal.connect(self.connector.contact[2]) + self.rs232.rx.signal.connect(self.connector.contact[1]) + self.rs232.dtr.signal.connect(self.connector.contact[3]) + self.rs232.dcd.signal.connect(self.connector.contact[0]) + self.rs232.dsr.signal.connect(self.connector.contact[5]) + self.rs232.ri.signal.connect(self.connector.contact[8]) + self.rs232.rts.signal.connect(self.connector.contact[6]) + self.rs232.cts.signal.connect(self.connector.contact[7]) + + self.rs232.get_trait( + F.has_single_electric_reference + ).get_reference().lv.connect(self.connector.contact[4]) # ------------------------------------ # parametrization diff --git a/src/faebryk/library/ESP32_C3_MINI_1_Reference_Design.py b/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py similarity index 97% rename from src/faebryk/library/ESP32_C3_MINI_1_Reference_Design.py rename to src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py index 5a0db2ec..e72435aa 100644 --- a/src/faebryk/library/ESP32_C3_MINI_1_Reference_Design.py +++ b/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py @@ -10,7 +10,7 @@ logger = logging.getLogger(__name__) -class ESP32_C3_MINI_1_Reference_Design(Module): +class ESP32_C3_MINI_1_ReferenceDesign(Module): """ESP32_C3_MINI_1 Module reference design""" esp32_c3_mini_1: F.ESP32_C3_MINI_1 diff --git a/src/faebryk/library/ISO1540.py b/src/faebryk/library/ISO1540.py index f5c6770b..06da02cc 100644 --- a/src/faebryk/library/ISO1540.py +++ b/src/faebryk/library/ISO1540.py @@ -33,6 +33,15 @@ class ISO1540(Module): ) designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + @L.rt_field + def descriptive_properties(self): + return F.has_descriptive_properties_defined( + { + DescriptiveProperties.manufacturer: "Texas Instruments", + DescriptiveProperties.partno: "ISO1540DR", + }, + ) + @L.rt_field def can_attach_to_footprint(self): return F.can_attach_to_footprint_via_pinmap( @@ -61,12 +70,3 @@ def __preinit__(self): self.power.decoupled.decouple().capacitance.merge(10 * P.uF) self.power_iso.decoupled.decouple().capacitance.merge(10 * P.uF) - - self.add( - F.has_descriptive_properties_defined( - { - DescriptiveProperties.manufacturer: "Texas Instruments", - DescriptiveProperties.partno: "ISO1540DR", - }, - ) - ) diff --git a/src/faebryk/library/RP2040_ReferenceDesign.py b/src/faebryk/library/RP2040_ReferenceDesign.py index 6dab0e51..4b577c7e 100644 --- a/src/faebryk/library/RP2040_ReferenceDesign.py +++ b/src/faebryk/library/RP2040_ReferenceDesign.py @@ -3,17 +3,18 @@ import logging -import faebryk.library._F as F # noqa: F401 -from faebryk.core.module import Module -from faebryk.exporters.pcb.layout.heuristic_decoupling import ( +from tmp.faebryk.src.faebryk.exporters.pcb.layout.heuristic_decoupling import ( LayoutHeuristicElectricalClosenessDecouplingCaps, ) -from faebryk.exporters.pcb.layout.heuristic_pulls import ( +from tmp.faebryk.src.faebryk.exporters.pcb.layout.heuristic_pulls import ( LayoutHeuristicElectricalClosenessPullResistors, ) -from faebryk.libs.library import L # noqa: F401 + +import faebryk.library._F as F +from faebryk.core.module import Module +from faebryk.libs.library import L from faebryk.libs.picker.picker import DescriptiveProperties -from faebryk.libs.units import P # noqa: F401 +from faebryk.libs.units import P logger = logging.getLogger(__name__) diff --git a/src/faebryk/library/SP3243E.py b/src/faebryk/library/SP3243E.py index 486ffa0e..96a35b3d 100644 --- a/src/faebryk/library/SP3243E.py +++ b/src/faebryk/library/SP3243E.py @@ -19,11 +19,16 @@ class SP3243E(F.RS232_3D5R_Tranceiver): # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- - c1: F.ElectricPower - c2: F.ElectricPower - vp: F.ElectricPower - vn: F.ElectricPower + voltage_doubler_charge_pump_power: F.ElectricPower + """Terminal of the voltage doubler charge-pump capacitor """ + inverting_charge_pump_power: F.ElectricPower + """Terminal of the inverting charge-pump capacitor """ + positive_charge_pump_power: F.ElectricPower + """Regulated +5.5V output generated by the charge pump """ + negative_charge_pump_power: F.ElectricPower + """Regulated -5.5V output generated by the charge pump """ power: F.ElectricPower + """Power input to the module""" enable: F.ElectricLogic online: F.ElectricLogic @@ -37,6 +42,15 @@ class SP3243E(F.RS232_3D5R_Tranceiver): "https://assets.maxlinear.com/web/documents/sp3243e.pdf" ) + @L.rt_field + def descriptive_properties(self): + return F.has_descriptive_properties_defined( + { + DescriptiveProperties.manufacturer: "MaxLinear", + DescriptiveProperties.partno: "SP3243EBEA-L/TR", + }, + ) + def __preinit__(self): # ------------------------------------ # connections @@ -56,12 +70,3 @@ def __preinit__(self): # parametrization # ------------------------------------ self.power.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) - - self.add( - F.has_descriptive_properties_defined( - { - DescriptiveProperties.manufacturer: "MaxLinear", - DescriptiveProperties.partno: "SP3243EBEA-L/TR", - }, - ) - ) diff --git a/src/faebryk/library/TPS2116.py b/src/faebryk/library/TPS2116.py index c60c8f65..0cd66c19 100644 --- a/src/faebryk/library/TPS2116.py +++ b/src/faebryk/library/TPS2116.py @@ -15,6 +15,9 @@ class TPS2116(F.PowerMux): 2to1 1.6 V to 5.5 V, 2.5-A Low IQ Power Mux with Manual and Priority Switchover """ + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- power_in = L.list_field(2, F.ElectricPower) power_out: F.ElectricPower select: F.Electrical @@ -37,8 +40,14 @@ def single_electric_reference(self): ) def __preinit__(self): - gnd = self.power_out.lv - + # ------------------------------------ + # connections + # ------------------------------------ + self.power_in[0].connect_shallow(self.power_out) + self.power_in[1].connect_shallow(self.power_out) + + # ------------------------------------ + # parametrization + # ------------------------------------ for power in [self.power_in[0], self.power_in[1], self.power_out]: power.voltage.merge(F.Range(1.6 * P.V, 5.5 * P.V)) - power.lv.connect(gnd) diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index d368848d..daaf5579 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -16,8 +16,8 @@ # flake8: noqa: E501 from faebryk.library.TBD import TBD -from faebryk.library.Constant import Constant from faebryk.library.Range import Range +from faebryk.library.Constant import Constant from faebryk.library.has_esphome_config import has_esphome_config from faebryk.library.is_esphome_bus import is_esphome_bus from faebryk.library.has_pcb_position import has_pcb_position @@ -217,7 +217,7 @@ from faebryk.library.TI_CD4011BE import TI_CD4011BE from faebryk.library.RP2040_ReferenceDesign import RP2040_ReferenceDesign from faebryk.library.SP3243E import SP3243E -from faebryk.library.CBM9002A_56ILG_Reference_Design import CBM9002A_56ILG_Reference_Design +from faebryk.library.CBM9002A_56ILG_ReferenceDesign import CBM9002A_56ILG_ReferenceDesign from faebryk.library.USB_RS485 import USB_RS485 from faebryk.library.CH342F import CH342F from faebryk.library.CH344Q import CH344Q @@ -229,7 +229,7 @@ from faebryk.library.PowerSwitchStatic import PowerSwitchStatic from faebryk.library.CH342F_ReferenceDesign import CH342F_ReferenceDesign from faebryk.library.CH344Q_ReferenceDesign import CH344Q_ReferenceDesign -from faebryk.library.ESP32_C3_MINI_1_Reference_Design import ESP32_C3_MINI_1_Reference_Design +from faebryk.library.ESP32_C3_MINI_1_ReferenceDesign import ESP32_C3_MINI_1_ReferenceDesign from faebryk.library.USB_C_5V_PSU import USB_C_5V_PSU from faebryk.library.USB_C_PowerOnly import USB_C_PowerOnly from faebryk.library.Powered_Relay import Powered_Relay From b6528b32fb61b0b4c95f655c99895d525e857ecd Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Fri, 6 Sep 2024 23:23:55 +0200 Subject: [PATCH 06/27] Add: INA288 --- src/faebryk/library/INA228.py | 80 +++++++++++++++++++ src/faebryk/library/INA228_ReferenceDesign.py | 79 ++++++++++++++++++ src/faebryk/library/_F.py | 2 + 3 files changed, 161 insertions(+) create mode 100644 src/faebryk/library/INA228.py create mode 100644 src/faebryk/library/INA228_ReferenceDesign.py diff --git a/src/faebryk/library/INA228.py b/src/faebryk/library/INA228.py new file mode 100644 index 00000000..f6d132a0 --- /dev/null +++ b/src/faebryk/library/INA228.py @@ -0,0 +1,80 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F +from faebryk.core.module import Module +from faebryk.libs.library import L +from faebryk.libs.units import P + +logger = logging.getLogger(__name__) + + +class INA228(Module): + def set_address(self, address: int = 0x00) -> None: + """Set the I2C address of the INA228""" + # allias + gnd = self.power.lv + vs = self.power.hv + sda = self.i2c.sda + scl = self.i2c.scl + + address_map = { + 0b0000: (gnd, gnd), + 0b0001: (gnd, vs), + 0b0010: (gnd, sda), + 0b0011: (gnd, scl), + 0b0100: (vs, gnd), + 0b0101: (vs, vs), + 0b0110: (vs, sda), + 0b0111: (vs, scl), + 0b1000: (sda, gnd), + 0b1001: (sda, vs), + 0b1010: (sda, sda), + 0b1011: (sda, scl), + 0b1100: (scl, gnd), + 0b1101: (scl, vs), + 0b1110: (scl, sda), + 0b1111: (scl, scl), + } + address |= 0b1000000 + # address looks like 0b100xxxx + + a1_connect, a0_connect = address_map.get(address, (gnd, gnd)) + self.address_config_pin[0].connect(a0_connect) + self.address_config_pin[1].connect(a1_connect) + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + i2c: F.I2C + power: F.ElectricPower + address_config_pin = L.list_field(2, F.ElectricLogic) + alert: F.ElectricLogic + bus_voltage_sense: F.Electrical + differential_input: F.DifferentialPair + + # ---------------------------------------- + # traits + # ---------------------------------------- + designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + datasheet = L.f_field(F.has_datasheet_defined)( + "https://www.ti.com/lit/ds/symlink/ina228.pdf" + ) + + @L.rt_field + def single_electric_reference(self): + return F.has_single_electric_reference_defined( + F.ElectricLogic.connect_all_module_references(self) + ) + + def __preinit__(self): + # ------------------------------------ + # connections + # ------------------------------------ + + # ------------------------------------ + # parametrization + # ------------------------------------ + self.power.voltage.merge(F.Range(2.7 * P.V, 5.5 * P.V)) diff --git a/src/faebryk/library/INA228_ReferenceDesign.py b/src/faebryk/library/INA228_ReferenceDesign.py new file mode 100644 index 00000000..fb9d267b --- /dev/null +++ b/src/faebryk/library/INA228_ReferenceDesign.py @@ -0,0 +1,79 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F +from faebryk.core.module import Module +from faebryk.libs.library import L +from faebryk.libs.units import P + +logger = logging.getLogger(__name__) + + +class INA228_ReferenceDesign(Module): + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + shunt: F.Resistor + ina288: F.INA228 + + pwr_load: F.ElectricPower + pwr_source: F.ElectricPower + + # ---------------------------------------- + # traits + # ---------------------------------------- + @L.rt_field + def can_bridge(self): + (F.can_bridge_defined(self.pwr_load, self.pwr_source)) + + @L.rt_field + def single_electric_reference(self): + return F.has_single_electric_reference_defined( + F.ElectricLogic.connect_all_module_references(self, gnd_only=True) + ) + + def __init__(self, filtered: bool = False): + super().__init__() + self._filtered = filtered + + def __preinit__(self): + # ---------------------------------------- + # parametrization + # ---------------------------------------- + self.shunt.resistance.merge(15 * P.mohm) + self.shunt.rated_power.merge(2 * P.W) + # TODO: calculate according to datasheet p36 + + if self._filtered: + filter_cap = F.Capacitor() + filter_resistors = L.list_field(2, F.Resistor) + + filter_cap.capacitance.merge(0.1 * P.uF) + filter_cap.rated_voltage.merge(170 * P.V) + for res in filter_resistors: + res.resistance.merge(10 * P.kohm) + # TODO: auto calculate, see: https://www.ti.com/lit/ug/tidu473/tidu473.pdf + + # ---------------------------------------- + # connections + # ---------------------------------------- + self.pwr_load.hv.connect_via(self.shunt, self.pwr_source.hv) + self.ina288.bus_voltage_sense.connect(self.pwr_load.hv) + if self._filtered: + self.pwr_load.hv.connect_via(filter_cap, self.pwr_source.hv) + self.ina288.differential_input.n.connect_via( + filter_resistors[1], self.pwr_load.hv + ) + self.ina288.differential_input.p.connect_via( + filter_resistors[0], self.pwr_source.hv + ) + else: + self.ina288.differential_input.n.connect(self.pwr_load.hv) + self.ina288.differential_input.p.connect(self.pwr_source.hv) + + # decouple power rail + self.ina288.power.get_trait(F.can_be_decoupled).decouple().capacitance.merge( + 0.1 * P.uF + ) diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index daaf5579..62e078d8 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -177,6 +177,7 @@ from faebryk.library.Logic74xx import Logic74xx from faebryk.library.BH1750FVI_TR import BH1750FVI_TR from faebryk.library.EEPROM import EEPROM +from faebryk.library.INA228 import INA228 from faebryk.library.ISO1540 import ISO1540 from faebryk.library.M24C08_FMN6TP import M24C08_FMN6TP from faebryk.library.OLED_Module import OLED_Module @@ -202,6 +203,7 @@ from faebryk.library.CD4011 import CD4011 from faebryk.library.Winbond_Elec_W25Q128JVSIQ import Winbond_Elec_W25Q128JVSIQ from faebryk.library.RP2040 import RP2040 +from faebryk.library.INA228_ReferenceDesign import INA228_ReferenceDesign from faebryk.library.RS232_3D5R_Tranceiver import RS232_3D5R_Tranceiver from faebryk.library.CBM9002A_56ILG import CBM9002A_56ILG from faebryk.library.CH340x import CH340x From 2b4c5ae1e7c89ed01c0ccaee3a9381cd57acbb80 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 12 Sep 2024 11:45:59 +0200 Subject: [PATCH 07/27] Fix: references Add: - AP2552W6 - ElectricalRCFilter - USB2514B ref design - ResistorVoltageDivider --- src/faebryk/library/B0505S_1WR3.py | 4 +- src/faebryk/library/CH342.py | 4 +- src/faebryk/library/CH342F.py | 4 +- src/faebryk/library/CH344.py | 6 +- src/faebryk/library/CH344Q.py | 20 ++- src/faebryk/library/CH344Q_ReferenceDesign.py | 31 ++-- .../library/Diodes_Incorporated_AP2552W6_7.py | 134 ++++++++++++++++++ src/faebryk/library/FilterElectricalRC.py | 64 +++++++++ src/faebryk/library/OLED_Module.py | 4 +- src/faebryk/library/RS232_3D5R_Tranceiver.py | 4 +- src/faebryk/library/RS485_Bus_Protection.py | 122 ++++++++-------- src/faebryk/library/ResistorVoltageDivider.py | 27 ++++ src/faebryk/library/SP3243E.py | 70 ++++++++- src/faebryk/library/USB2514B.py | 2 +- .../library/USB2514B_ReferenceDesign.py | 122 ++++++++++++++++ src/faebryk/library/_F.py | 8 +- 16 files changed, 529 insertions(+), 97 deletions(-) create mode 100644 src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py create mode 100644 src/faebryk/library/FilterElectricalRC.py create mode 100644 src/faebryk/library/ResistorVoltageDivider.py create mode 100644 src/faebryk/library/USB2514B_ReferenceDesign.py diff --git a/src/faebryk/library/B0505S_1WR3.py b/src/faebryk/library/B0505S_1WR3.py index af7ebb7d..5e93f58d 100644 --- a/src/faebryk/library/B0505S_1WR3.py +++ b/src/faebryk/library/B0505S_1WR3.py @@ -58,10 +58,10 @@ def __preinit__(self): # parametrization # ---------------------------------------- self.power_in.get_trait(F.can_be_decoupled).decouple().capacitance.merge( - 4.7 * P.uF + F.Range.from_center_rel(4.7 * P.uF, 0.1) ) self.power_out.get_trait(F.can_be_decoupled).decouple().capacitance.merge( - 10 * P.uF + F.Range.from_center_rel(10 * P.uF, 0.1) ) # ---------------------------------------- diff --git a/src/faebryk/library/CH342.py b/src/faebryk/library/CH342.py index 4641743c..24becc7d 100644 --- a/src/faebryk/library/CH342.py +++ b/src/faebryk/library/CH342.py @@ -58,8 +58,8 @@ def __preinit__(self): # parametrization # ---------------------------------------- self.vdd_5v.voltage.merge(F.Range(4 * P.V, 5.5 * P.V)) - self.v_3v.voltage.merge(3.3 * P.V) - self.v_io.voltage.merge(F.Range(1.7 * P.V, 3.6 * P.V)) + self.v_3v.voltage.merge(F.Range.from_center(3.3 * P.V, 0.3 * P.V)) + self.v_io.voltage.merge(F.Range(1.7 * P.V, 5.5 * P.V)) # ---------------------------------------- # connections diff --git a/src/faebryk/library/CH342F.py b/src/faebryk/library/CH342F.py index c430930d..55f91865 100644 --- a/src/faebryk/library/CH342F.py +++ b/src/faebryk/library/CH342F.py @@ -102,8 +102,8 @@ def __preinit__(self) -> None: # parametrization # ---------------------------------------- self.vdd_5v.voltage.merge(F.Range(4 * P.V, 5.5 * P.V)) - self.v_3v.voltage.merge(3.3 * P.V) - self.v_io.voltage.merge(F.Range(1.7 * P.V, 3.6 * P.V)) + self.v_3v.voltage.merge(F.Range.from_center(3.3 * P.V, 0.3 * P.V)) + self.v_io.voltage.merge(F.Range(1.7 * P.V, 5.5 * P.V)) # set the duplex mode if self._duplex_mode_uart_0 == F.CH342.DuplexMode.HALF: diff --git a/src/faebryk/library/CH344.py b/src/faebryk/library/CH344.py index 87844c1d..42ee4d48 100644 --- a/src/faebryk/library/CH344.py +++ b/src/faebryk/library/CH344.py @@ -68,8 +68,10 @@ def __preinit__(self): self.gpio[14].connect(self.uart[0].dsr) self.gpio[15].connect(self.uart[1].dcd) - self.test.pulled.pull(up=False).resistance.merge(4.7 * P.kohm) + self.test.pulled.pull(up=False).resistance.merge( + F.Range.from_center_rel(4.7 * P.kohm, 0.05) + ) # ------------------------------------ # parametrization # ------------------------------------ - self.power.voltage.merge(3.3 * P.V) + self.power.voltage.merge(F.Range.from_center(3.3 * P.V, 0.3 * P.V)) diff --git a/src/faebryk/library/CH344Q.py b/src/faebryk/library/CH344Q.py index 3d91c0a4..757b4a3d 100644 --- a/src/faebryk/library/CH344Q.py +++ b/src/faebryk/library/CH344Q.py @@ -26,21 +26,27 @@ def enable_tnow_mode(self, uart: F.UART): uart in self.uart ), f"{uart.get_full_name()} is not a part of the CH344Q module" - uart.dtr.pulled.pull(up=False).resistance.merge(4.7 * P.kOhm) + uart.dtr.pulled.pull(up=False).resistance.merge( + F.Range.from_center_rel(4.7 * P.kOhm, 0.05) + ) uart.dtr.connect(self.tnow[self.uart.index(uart)]) def enable_chip_default_settings(self): """ Use the chip default settings instead of the ones stored in the internal EEPROM """ - self.uart[0].rts.pulled.pull(up=False).resistance.merge(4.7 * P.kOhm) + self.uart[0].rts.pulled.pull(up=False).resistance.merge( + F.Range.from_center_rel(4.7 * P.kOhm, 0.05) + ) def enable_status_outputs(self, modem_signals: bool = False): """ Enable rx, tx and usb status signal outputs instead of UART modem signals. """ if modem_signals: - self.uart[3].rts.pulled.pull(up=False).resistance.merge(4.7 * P.kOhm) + self.uart[3].rts.pulled.pull(up=False).resistance.merge( + F.Range.from_center_rel(4.7 * P.kOhm, 0.05) + ) return self.act.connect(self.uart[3].dcd) self.tx_indicator.connect(self.uart[3].ri) @@ -50,7 +56,9 @@ def enable_hardware_flow_conrol(self): """ Enable UART hardware flow control """ - self.uart[3].dcd.pulled.pull(up=False).resistance.merge(4.7 * P.kOhm) + self.uart[3].dcd.pulled.pull(up=False).resistance.merge( + F.Range.from_center_rel(4.7 * P.kOhm, 0.05) + ) # TODO: check if this should just be connected to gnd as there is an # internal pull-up resistor @@ -129,7 +137,9 @@ def __preinit__(self): # ------------------------------------ # connections # ------------------------------------ - self.power.decoupled.decouple().capacitance.merge(1 * P.uF) # TODO: per pin + self.power.decoupled.decouple().capacitance.merge( + F.Range.from_center_rel(1 * P.uF, 0.05) + ) # TODO: per pin # ------------------------------------ # parametrization # ------------------------------------ diff --git a/src/faebryk/library/CH344Q_ReferenceDesign.py b/src/faebryk/library/CH344Q_ReferenceDesign.py index 6d35e4b4..487c9d61 100644 --- a/src/faebryk/library/CH344Q_ReferenceDesign.py +++ b/src/faebryk/library/CH344Q_ReferenceDesign.py @@ -24,11 +24,11 @@ class CH344Q_ReferenceDesign(Module): usb_uart_converter: F.CH344Q oscillator: F.Crystal_Oscillator ldo: F.LDO - rx_led: F.PoweredLED - tx_led: F.PoweredLED - act_led: F.PoweredLED + rx_led = L.f_field(F.LEDIndicator)(use_mosfet=False) + tx_led = L.f_field(F.LEDIndicator)(use_mosfet=False) + act_led = L.f_field(F.LEDIndicator)(use_mosfet=False) power_led: F.PoweredLED - # reset_lowpass: F.FilterElectricalRC TODO: implement FilterElectricalRC + reset_lowpass: F.FilterElectricalRC # ---------------------------------------- # traits @@ -53,25 +53,34 @@ def __preinit__(self): self.usb.connect(self.usb_uart_converter.usb) # TODO: add esd protection to usb - self.power_led.power.connect(pwr_3v3) - self.usb_uart_converter.act.signal.connect_via(self.act_led, pwr_3v3.hv) - self.usb_uart_converter.rx_indicator.signal.connect_via(self.rx_led, pwr_3v3.hv) - self.usb_uart_converter.tx_indicator.signal.connect_via(self.tx_led, pwr_3v3.hv) + self.usb_uart_converter.act.connect(self.act_led.logic_in) + self.usb_uart_converter.rx_indicator.connect(self.rx_led.logic_in) + self.usb_uart_converter.tx_indicator.connect(self.tx_led.logic_in) + pwr_3v3.connect(self.power_led.power) self.usb_uart_converter.osc[1].connect(self.oscillator.p) self.usb_uart_converter.osc[0].connect(self.oscillator.n) self.oscillator.power.connect(pwr_3v3) - # self.usb_uart_converter.reset.signal.filter(type=LOWPASS) - # TODO: implement FilterElectricalRC + self.reset_lowpass.out.connect(self.usb_uart_converter.reset) + self.usb_uart_converter.reset.pulled.pull(up=True) + # ------------------------------------ # parametrization # ------------------------------------ self.usb_uart_converter.enable_status_outputs() - self.oscillator.crystal.frequency.merge(8 * P.MHz) + self.oscillator.crystal.frequency.merge( + F.Range.from_center_rel(8 * P.MHz, 0.001) + ) self.oscillator.crystal.frequency_tolerance.merge( F.Range.upper_bound(40 * P.ppm) ) self.ldo.output_current.merge(F.Range.lower_bound(500 * P.mA)) + + # reset lowpass + self.reset_lowpass.response.merge(F.Filter.Response.LOWPASS) + self.reset_lowpass.cutoff_frequency.merge( + F.Range.from_center_rel(100 * P.Hz, 0.1) + ) diff --git a/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py b/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py new file mode 100644 index 00000000..cabd06a5 --- /dev/null +++ b/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py @@ -0,0 +1,134 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.core.parameter import Parameter +from faebryk.exporters.pcb.layout.absolute import LayoutAbsolute +from faebryk.exporters.pcb.layout.extrude import LayoutExtrude +from faebryk.exporters.pcb.layout.typehierarchy import LayoutTypeHierarchy +from faebryk.library.has_pcb_position import has_pcb_position +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.picker.picker import DescriptiveProperties +from faebryk.libs.units import P, Quantity # noqa: F401 + +logger = logging.getLogger(__name__) + + +class Diodes_Incorporated_AP2552W6_7(Module): + """ + Power Distribution Switch. Mostly used in USB applications. + 2.7V~5.5V 70mΩ 2.1A SOT-26 + """ + + def set_current_limit(self, current: Parameter[Quantity]) -> None: + self.current_limit.merge(current) + + current_limit_setting_resistor = self.ilim.get_trait( + F.ElectricLogic.can_be_pulled + ).pull(up=False) + + # TODO: + # self.ilim.connect_via( + # current_limit_setting_resistor, self.power_in.lv + # ) + + # Rlim is in Kohm + # current is in mA + # Rlim_min = (20.08 / (current)) ^ (1 / 0.956) * P.kohm + # Rlim_max = (20.08 / (current)) ^ (1 / 0.904) * P.kohm + + # TODO: Rlim = Range(Rlim_min, Rlim_max) + Rlim = F.Constant(51 * P.kohm) # ~0.52A typical current limit + assert Rlim.is_subset_of( + F.Range(10 * P.kohm, 210 * P.kohm) + ), f"{self.get_full_name()} Rlim must be in the range 10kOhm to 210kOhm but is {Rlim}" # noqa: E501 + + current_limit_setting_resistor.resistance.merge(Rlim) + Rlim = F.Range(10 * P.kohm, 210 * P.kohm) + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + power_in: F.ElectricPower + power_out: F.ElectricPower + enable: F.ElectricLogic + fault: F.ElectricLogic + ilim: F.ElectricLogic # TODO: hack to add resistor, should be Electrical() + + current_limit: F.TBD[Quantity] + # ---------------------------------------- + # traits + # ---------------------------------------- + designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + descriptive_properties = L.f_field(F.has_descriptive_properties_defined)( + { + DescriptiveProperties.manufacturer: "Diodes Incorporated", + DescriptiveProperties.partno: "AP2552W6-7", + } + ) + datasheet = L.f_field(F.has_datasheet_defined)( + "https://wmsc.lcsc.com/wmsc/upload/file/pdf/v2/lcsc/2304140030_Diodes-Incorporated-AP2552W6-7_C441824.pdf" # noqa: E501 + ) + + @L.rt_field + def pin_association_heuristic(self): + return F.has_pin_association_heuristic_lookup_table( + mapping={ + self.power_in.hv: ["IN"], + self.power_in.lv: ["GND"], + self.enable.signal: ["EN/EN#"], + self.fault.signal: ["FAULT#"], + self.ilim.signal: ["ILIM"], + self.power_out.hv: ["OUT"], + }, + accept_prefix=False, + case_sensitive=False, + ) + + @L.rt_field + def can_bridge(self): + return F.can_bridge_defined(self.power_in, self.power_out) + + @L.rt_field + def single_electric_reference(self): + return F.has_single_electric_reference_defined( + F.ElectricLogic.connect_all_module_references(self) + ) + + @L.rt_field + def has_defined_layout(self): + # pcb layout + Point = has_pcb_position.Point + L = has_pcb_position.layer_type + LVL = LayoutTypeHierarchy.Level + + layouts = [ + LVL( + mod_type=F.Resistor, + layout=LayoutAbsolute( + Point((0, -3, 90, L.NONE)), + ), + ), + LVL( + mod_type=F.Capacitor, + layout=LayoutExtrude( + base=Point((-0.95, 3.25, 270, L.NONE)), + vector=(-6.5, 0, 180), + dynamic_rotation=True, + ), + ), + ] + return F.has_pcb_layout_defined(LayoutTypeHierarchy(layouts)) + + def __preinit__(self): + # ------------------------------------ + # connections + # ------------------------------------ + + # ------------------------------------ + # parametrization + # ------------------------------------ + pass diff --git a/src/faebryk/library/FilterElectricalRC.py b/src/faebryk/library/FilterElectricalRC.py new file mode 100644 index 00000000..eab17126 --- /dev/null +++ b/src/faebryk/library/FilterElectricalRC.py @@ -0,0 +1,64 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging +import math + +import faebryk.library._F as F # noqa: F401 +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class FilterElectricalRC(F.Filter): + """ + Basic Electrical RC filter + """ + + in_: F.SignalElectrical + out: F.SignalElectrical + capacitor: F.Capacitor + resistor: F.Resistor + + def __preinit__(self): ... + + @L.rt_field + def construction_dependency(self): + class _(F.has_construction_dependency.impl()): + def _construct(_self): + if F.Constant(F.Filter.Response.LOWPASS).is_subset_of(self.response): + self.response.merge(F.Filter.Response.LOWPASS) + + # TODO other orders + self.order.merge(1) + + R = self.resistor.resistance + C = self.capacitor.capacitance + fc = self.cutoff_frequency + + # TODO requires parameter constraint solving implemented + # fc.merge(1 / (2 * math.pi * R * C)) + + # instead assume fc being the driving param + realistic_C = F.Range(1 * P.pF, 1 * P.mF) + R.merge(1 / (2 * math.pi * realistic_C * fc)) + C.merge(1 / (2 * math.pi * R * fc)) + + # TODO consider splitting C / L in a typical way + + # low pass + self.in_.signal.connect_via( + (self.resistor, self.capacitor), + self.in_.reference.lv, + ) + + self.in_.signal.connect_via(self.resistor, self.out.signal) + return + + if isinstance(self.response, F.Constant): + raise F.has_construction_dependency.NotConstructableEver() + + raise F.has_construction_dependency.NotConstructableYet() + + return _() diff --git a/src/faebryk/library/OLED_Module.py b/src/faebryk/library/OLED_Module.py index ca5a3fd7..9357164b 100644 --- a/src/faebryk/library/OLED_Module.py +++ b/src/faebryk/library/OLED_Module.py @@ -44,6 +44,8 @@ class DisplayController(Enum): def __preinit__(self): self.power.voltage.merge(F.Range(3.0 * P.V, 5 * P.V)) - self.power.decoupled.decouple() + self.power.decoupled.decouple().capacitance.merge( + F.Range(100 * P.uF, 220 * P.uF) + ) designator_prefix = L.f_field(F.has_designator_prefix_defined)("OLED") diff --git a/src/faebryk/library/RS232_3D5R_Tranceiver.py b/src/faebryk/library/RS232_3D5R_Tranceiver.py index dac75a7c..cf78d5bf 100644 --- a/src/faebryk/library/RS232_3D5R_Tranceiver.py +++ b/src/faebryk/library/RS232_3D5R_Tranceiver.py @@ -19,8 +19,8 @@ class RS232_3D5R_Tranceiver(Module): # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- - uart_logic: F.UART - uart_rs232: F.RS232 + uart: F.UART + rs232: F.RS232 # ---------------------------------------- # traits diff --git a/src/faebryk/library/RS485_Bus_Protection.py b/src/faebryk/library/RS485_Bus_Protection.py index 82089a6d..20c3d72d 100644 --- a/src/faebryk/library/RS485_Bus_Protection.py +++ b/src/faebryk/library/RS485_Bus_Protection.py @@ -44,6 +44,66 @@ def __init__(self, termination: bool = True, polarization: bool = True) -> None: rs485_out: F.RS485 earth: F.Electrical + @L.rt_field + def has_defined_layout(self): + # PCB layout + Point = F.has_pcb_position.Point + L = F.has_pcb_position.layer_type + LVL = LayoutTypeHierarchy.Level + self.gnd_couple_resistor.add( + F.has_pcb_layout_defined( + LayoutAbsolute( + Point((-10, 0, 90, L.NONE)), + ) + ) + ) + layouts = [ + LVL( + mod_type=F.GDT, + layout=LayoutAbsolute( + Point((0, 0, 0, L.NONE)), + ), + ), + # TODO: fix + # LVL( + # mod_type=F.TVS, + # layout=LayoutAbsolute( + # Point((0, 11, 0, L.NONE)), + # ), + # ), + LVL( + mod_type=F.Common_Mode_Filter, + layout=LayoutAbsolute( + Point((0, 19, 90, L.NONE)), + ), + ), + LVL( + mod_type=F.Diode, + layout=LayoutExtrude( + base=Point((-3.5, 14.5, 90, L.NONE)), + vector=(0, 3.5, 0), + ), + ), + LVL( + mod_type=F.Resistor, + layout=LayoutExtrude( + base=Point((-2, 7, 90, L.NONE)), + vector=(0, 4, 0), + ), + ), + # LVL( + # mod_type=F.Capacitor, + # layout=LayoutAbsolute( + # Point((10, 0, 90, L.NONE)), + # ), + # ), + ] + return F.has_pcb_layout_defined(LayoutTypeHierarchy(layouts)) + + @L.rt_field + def can_bridge(self): + return F.can_bridge_defined(self.rs485_in, self.rs485_out) + def __preinit__(self): if self._termination: termination_resistor = self.add(F.Resistor(), name="termination_resistor") @@ -129,65 +189,3 @@ def __preinit__(self): # TODO: layout is only working when bbox is implemented or # when using specific components - - # PCB layout - Point = F.has_pcb_position.Point - L = F.has_pcb_position.layer_type - self.gnd_couple_resistor.add( - F.has_pcb_layout_defined( - LayoutAbsolute( - Point((-10, 0, 90, L.NONE)), - ) - ) - ) - self.add( - F.has_pcb_layout_defined( - LayoutTypeHierarchy( - layouts=[ - LayoutTypeHierarchy.Level( - mod_type=F.GDT, - layout=LayoutAbsolute( - Point((0, 0, 0, L.NONE)), - ), - ), - # TODO: fix - # LayoutTypeHierarchy.Level( - # mod_type=F.TVS, - # layout=LayoutAbsolute( - # Point((0, 11, 0, L.NONE)), - # ), - # ), - LayoutTypeHierarchy.Level( - mod_type=F.Common_Mode_Filter, - layout=LayoutAbsolute( - Point((0, 19, 90, L.NONE)), - ), - ), - LayoutTypeHierarchy.Level( - mod_type=F.Diode, - layout=LayoutExtrude( - base=Point((-3.5, 14.5, 90, L.NONE)), - vector=(0, 3.5, 0), - ), - ), - LayoutTypeHierarchy.Level( - mod_type=F.Resistor, - layout=LayoutExtrude( - base=Point((-2, 7, 90, L.NONE)), - vector=(0, 4, 0), - ), - ), - # LayoutTypeHierarchy.Level( - # mod_type=F.Capacitor, - # layout=LayoutAbsolute( - # Point((10, 0, 90, L.NONE)), - # ), - # ), - ] - ), - ) - ) - - @L.rt_field - def can_bridge(self): - return F.can_bridge_defined(self.rs485_in, self.rs485_out) diff --git a/src/faebryk/library/ResistorVoltageDivider.py b/src/faebryk/library/ResistorVoltageDivider.py new file mode 100644 index 00000000..8ba17374 --- /dev/null +++ b/src/faebryk/library/ResistorVoltageDivider.py @@ -0,0 +1,27 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F +from faebryk.core.module import Module +from faebryk.libs.library import L + +logger = logging.getLogger(__name__) + + +class ResistorVoltageDivider(Module): + resistor = L.list_field(2, F.Resistor) + + node = L.list_field(3, F.Electrical) + + ratio: F.TBD[float] + max_current: F.TBD[float] + + @L.rt_field + def can_bridge(self): + return F.can_bridge_defined(self.node[0], self.node[1]) + + def __preinit__(self): + self.node[0].connect_via(self.resistor[0], self.node[1]) + self.node[1].connect_via(self.resistor[1], self.node[2]) diff --git a/src/faebryk/library/SP3243E.py b/src/faebryk/library/SP3243E.py index 96a35b3d..edf3fc51 100644 --- a/src/faebryk/library/SP3243E.py +++ b/src/faebryk/library/SP3243E.py @@ -4,6 +4,7 @@ import logging import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module from faebryk.libs.library import L # noqa: F401 from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P # noqa: F401 @@ -11,11 +12,17 @@ logger = logging.getLogger(__name__) -class SP3243E(F.RS232_3D5R_Tranceiver): +class SP3243E(Module): """ - Common base module for RS232 tranceivers + 250Kbps RS232 Transceiver 3tx/5rx SSOP28 """ + def enable_chip(self): + self.enable.set(on=True) + + def enable_auto_online(self): + self.online.set(on=False) + # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- @@ -30,10 +37,15 @@ class SP3243E(F.RS232_3D5R_Tranceiver): power: F.ElectricPower """Power input to the module""" + uart: F.UART + rs232: F.RS232 + enable: F.ElectricLogic online: F.ElectricLogic status: F.ElectricLogic + cts_inverted: F.ElectricLogic + # ---------------------------------------- # traits # ---------------------------------------- @@ -51,7 +63,51 @@ def descriptive_properties(self): }, ) + @L.rt_field + def pin_association_heuristic(self): + return F.has_pin_association_heuristic_lookup_table( + mapping={ + self.inverting_charge_pump_power.hv: ["C2+"], + self.rs232.rts.signal: ["T2OUT"], + self.rs232.dtr.signal: ["T3OUT"], + self.uart.dtr.signal: ["T3IN"], + self.uart.rts.signal: ["T2IN"], + self.uart.base_uart.tx.signal: ["T1IN"], + self.uart.ri.signal: ["R5OUT"], + self.uart.dcd.signal: ["R4OUT"], + self.uart.dsr.signal: ["R3OUT"], + self.uart.cts.signal: ["R2OUT"], + self.uart.base_uart.rx.signal: ["R1OUT"], + self.inverting_charge_pump_power.lv: ["C2-"], + self.cts_inverted.signal: ["R2OUT#"], + self.status.signal: ["STATUS#"], + self.enable.signal: ["SHUTDOWN#"], + self.online.signal: ["ONLINE#"], + self.voltage_doubler_charge_pump_power.lv: ["C1-"], + self.power.lv: ["GND"], + self.power.hv: ["VCC"], + self.positive_charge_pump_power.hv: ["V+"], + self.voltage_doubler_charge_pump_power.hv: ["C1+"], + self.negative_charge_pump_power.lv: ["V-"], + self.rs232.rx.signal: ["R1IN"], + self.rs232.cts.signal: ["R2IN"], + self.rs232.dsr.signal: ["R3IN"], + self.rs232.dcd.signal: ["R4IN"], + self.rs232.ri.signal: ["R5IN"], + self.rs232.tx.signal: ["T1OUT"], + }, + accept_prefix=False, + case_sensitive=False, + ) + def __preinit__(self): + # ------------------------------------ + # parametrization + # ------------------------------------ + self.power.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) + + self.uart.base_uart.baud.merge(F.Range.upper_bound(250 * P.kbaud)) + # ------------------------------------ # connections # ------------------------------------ @@ -62,9 +118,13 @@ def __preinit__(self): # 4.5V to 5.5V > C1 = 0.047µF, C2,Cvp, Cvn = 0.33µF # 3.0V to 5.5V > C_all = 0.22μF # - cap.capacitance.merge(0.22 * P.uF) - # cap.rated_voltage.override(F.Range.lower_bound(16 * P.V)) - # TODO: merge conflict + cap.capacitance.merge(F.Range.from_center(0.22 * P.uF, 0.22 * 0.05 * P.uF)) + if isinstance(pwr.voltage.get_most_narrow(), F.TBD): + pwr.voltage.merge( + F.Constant(8 * P.V) + # F.Range.lower_bound(16 * P.V) + ) # TODO: fix in merge + # TODO: merge conflict # ------------------------------------ # parametrization diff --git a/src/faebryk/library/USB2514B.py b/src/faebryk/library/USB2514B.py index ab68fa63..81f1d6c5 100644 --- a/src/faebryk/library/USB2514B.py +++ b/src/faebryk/library/USB2514B.py @@ -34,7 +34,7 @@ class NonRemovablePortConfiguration(Enum): VBUS_DET: F.Electrical usb_downstream = L.list_field(4, F.DifferentialPair) - usb_upstream = F.DifferentialPair + usb_upstream: F.DifferentialPair XTALIN: F.Electrical XTALOUT: F.Electrical diff --git a/src/faebryk/library/USB2514B_ReferenceDesign.py b/src/faebryk/library/USB2514B_ReferenceDesign.py new file mode 100644 index 00000000..5c38413d --- /dev/null +++ b/src/faebryk/library/USB2514B_ReferenceDesign.py @@ -0,0 +1,122 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F +from faebryk.core.module import Module +from faebryk.exporters.pcb.layout.absolute import LayoutAbsolute +from faebryk.exporters.pcb.layout.typehierarchy import LayoutTypeHierarchy +from faebryk.libs.brightness import TypicalLuminousIntensity +from faebryk.libs.library import L +from faebryk.libs.units import P + +logger = logging.getLogger(__name__) + + +class USB2514B_ReferenceDesign(Module): + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + hub_controller: F.USB2514B + vbus_voltage_divider: F.ResistorVoltageDivider + ldo_3v3: F.LDO + suspend_indicator: F.PoweredLED + power_3v3_indicator: F.PoweredLED + power_distribution_switch = L.list_field(4, F.Diodes_Incorporated_AP2552W6_7) + usb_dfp_power_indicator = L.list_field(4, F.PoweredLED) + bias_resistor: F.Resistor + crystal_oscillator: F.Crystal_Oscillator # TODO: Connect Crystal oscillator + + usb_ufp: F.USB2_0 + usb_dfp = L.list_field(4, F.USB2_0) + + # ---------------------------------------- + # traits + # ---------------------------------------- + @L.rt_field + def has_defined_layout(self): + Point = F.has_pcb_position.Point + L = F.has_pcb_position.layer_type + LVL = LayoutTypeHierarchy.Level + + layouts = [ + LVL( + mod_type=F.PoweredLED, + layout=LayoutAbsolute( + Point((2.50, 180, L.NONE)), + ), + ), + ] + + return F.has_pcb_layout_defined(LayoutTypeHierarchy(layouts)) + + def __preinit__(self): + # ---------------------------------------- + # aliasess + # ---------------------------------------- + vbus = self.usb_ufp.usb_if.buspower + gnd = vbus.lv + + # ---------------------------------------- + # parametrization + # ---------------------------------------- + # crystal oscillator + self.hub_controller.XTALOUT.connect_via( + self.crystal_oscillator, self.hub_controller.XTALIN + ) + # TODO: this is a property of the crystal. remove this + self.crystal_oscillator.crystal.load_capacitance.merge( + F.Range(8 * P.pF, 15 * P.pF) + ) + self.crystal_oscillator.crystal.frequency.merge( + F.Range.from_center_rel(24 * P.MHz, 0.01) + ) + self.crystal_oscillator.crystal.frequency_tolerance.merge( + F.Range.upper_bound(50 * P.ppm) + ) + + # ---------------------------------------- + # connections + # ---------------------------------------- + for i, dfp in enumerate(self.usb_dfp): + vbus.connect_via(self.power_distribution_switch[i], dfp.usb_if.buspower) + dfp.usb_if.d.connect(self.hub_controller.usb_downstream[i]) + # TODO: connect hub controller overcurrent and power control signals + self.power_distribution_switch[i].enable.connect( + self.hub_controller.PRTPWR[i] + ) + self.power_distribution_switch[i].fault.connect( + self.hub_controller.OCS_N[i] + ) + self.power_distribution_switch[i].power_out.hv.connect_via( + self.usb_dfp_power_indicator[i], gnd + ) + self.usb_dfp_power_indicator[i].led.color.merge(F.LED.Color.YELLOW) + self.usb_dfp_power_indicator[i].led.brightness.merge( + # F.Range( + # 10 * P.millicandela, 100 * P.millicandela + # ) # + TypicalLuminousIntensity.APPLICATION_LED_INDICATOR_INSIDE.value.value + ) + for pds in self.power_distribution_switch: + pds.set_current_limit(F.Range.from_center_rel(520 * P.mA, 0.01)) + + # Bias resistor + self.bias_resistor.resistance.merge(F.Range.from_center_rel(12 * P.kohm, 0.01)) + self.hub_controller.RBIAS.connect_via(self.bias_resistor, gnd) + + self.usb_ufp.usb_if.d.connect(self.hub_controller.usb_upstream) + + # LEDs + self.power_3v3_indicator.power.connect(self.ldo_3v3.power_out) + self.hub_controller.SUSP_IND.signal.connect_via(self.suspend_indicator, gnd) + # TODO: remove, should be fixed by using LEDIndicator + self.suspend_indicator.power.voltage.merge(self.ldo_3v3.power_out.voltage) + + # TODO: do elsewhere + for led in [self.suspend_indicator, self.power_3v3_indicator]: + led.led.color.merge(F.LED.Color.GREEN) + led.led.brightness.merge( + TypicalLuminousIntensity.APPLICATION_LED_INDICATOR_INSIDE.value.value + ) diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index 62e078d8..c068106e 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -130,6 +130,7 @@ from faebryk.library.Crystal_Oscillator import Crystal_Oscillator from faebryk.library.DifferentialPair import DifferentialPair from faebryk.library.Potentiometer import Potentiometer +from faebryk.library.ResistorVoltageDivider import ResistorVoltageDivider from faebryk.library.Resistor_Voltage_Divider import Resistor_Voltage_Divider from faebryk.library.is_surge_protected_defined import is_surge_protected_defined from faebryk.library.is_decoupled_nodes import is_decoupled_nodes @@ -153,6 +154,8 @@ from faebryk.library.PoweredLED import PoweredLED from faebryk.library.ElectricLogic import ElectricLogic from faebryk.library.FilterElectricalLC import FilterElectricalLC +from faebryk.library.FilterElectricalRC import FilterElectricalRC +from faebryk.library.Diodes_Incorporated_AP2552W6_7 import Diodes_Incorporated_AP2552W6_7 from faebryk.library.ElectricLogicGate import ElectricLogicGate from faebryk.library.GenericBusProtection import GenericBusProtection from faebryk.library.I2C import I2C @@ -205,12 +208,14 @@ from faebryk.library.RP2040 import RP2040 from faebryk.library.INA228_ReferenceDesign import INA228_ReferenceDesign from faebryk.library.RS232_3D5R_Tranceiver import RS232_3D5R_Tranceiver +from faebryk.library.SP3243E import SP3243E from faebryk.library.CBM9002A_56ILG import CBM9002A_56ILG from faebryk.library.CH340x import CH340x from faebryk.library.CH342 import CH342 from faebryk.library.CH344 import CH344 from faebryk.library.ESP32_C3 import ESP32_C3 from faebryk.library.MCP2221A import MCP2221A +from faebryk.library.USB2514B_ReferenceDesign import USB2514B_ReferenceDesign from faebryk.library.USB2_0_ESD_Protection import USB2_0_ESD_Protection from faebryk.library.USBLC6_2P6 import USBLC6_2P6 from faebryk.library.USB_Type_C_Receptacle_14_pin_Vertical import USB_Type_C_Receptacle_14_pin_Vertical @@ -218,7 +223,6 @@ from faebryk.library.PowerSwitch import PowerSwitch from faebryk.library.TI_CD4011BE import TI_CD4011BE from faebryk.library.RP2040_ReferenceDesign import RP2040_ReferenceDesign -from faebryk.library.SP3243E import SP3243E from faebryk.library.CBM9002A_56ILG_ReferenceDesign import CBM9002A_56ILG_ReferenceDesign from faebryk.library.USB_RS485 import USB_RS485 from faebryk.library.CH342F import CH342F @@ -230,9 +234,9 @@ from faebryk.library.PowerSwitchMOSFET import PowerSwitchMOSFET from faebryk.library.PowerSwitchStatic import PowerSwitchStatic from faebryk.library.CH342F_ReferenceDesign import CH342F_ReferenceDesign -from faebryk.library.CH344Q_ReferenceDesign import CH344Q_ReferenceDesign from faebryk.library.ESP32_C3_MINI_1_ReferenceDesign import ESP32_C3_MINI_1_ReferenceDesign from faebryk.library.USB_C_5V_PSU import USB_C_5V_PSU from faebryk.library.USB_C_PowerOnly import USB_C_PowerOnly from faebryk.library.Powered_Relay import Powered_Relay from faebryk.library.LEDIndicator import LEDIndicator +from faebryk.library.CH344Q_ReferenceDesign import CH344Q_ReferenceDesign From 38fb306c378a22b6e0be66cee088be671c7af292 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 12 Sep 2024 11:46:42 +0200 Subject: [PATCH 08/27] Add: common designater prefixes --- src/faebryk/library/has_designator_prefix.py | 151 ++++++++++++++++++ .../library/has_designator_prefix_defined.py | 2 +- 2 files changed, 152 insertions(+), 1 deletion(-) diff --git a/src/faebryk/library/has_designator_prefix.py b/src/faebryk/library/has_designator_prefix.py index 5d28121c..e816465f 100644 --- a/src/faebryk/library/has_designator_prefix.py +++ b/src/faebryk/library/has_designator_prefix.py @@ -2,10 +2,161 @@ # SPDX-License-Identifier: MIT from abc import abstractmethod +from enum import StrEnum, auto from faebryk.core.module import Module class has_designator_prefix(Module.TraitT): + class Prefix(StrEnum): + A = auto() + """Separable assembly or sub-assembly (e.g. printed circuit assembly)""" + AT = auto() + """Attenuator or isolator""" + BR = auto() + """ + Bridge rectifier (four diodes in a package) > often changed to "D" for diode + """ + B = auto() + """Often shortened to "B" for Battery or battery holder""" + BT = auto() + """Battery or battery holder > often shortened to "B" """ + BAT = auto() + """Battery or battery holder > often shortened to "B" """ + C = auto() + """Capacitor""" + CB = auto() + """Circuit breaker""" + CN = auto() + """Capacitor network > may be simplified to "C" for capacitor""" + D = auto() + """ + Diode (all types, including LED), thyristor > "D" is preferred for various types + of diodes + """ + CR = auto() + """ + Diode (all types, including LED), thyristor > "D" is preferred for various types + of diodes + """ + DL = auto() + """Delay line""" + DN = auto() + """Diode network > may be simplified to "D" for diode""" + DS = auto() + """Display, general light source, lamp, signal light""" + F = auto() + """Fuse""" + FB = auto() + """Ferrite bead > sometimes changed to "L" for inductor, though "E" was used in + the currently inactive standard IEEE 315 (see Clause 22.4)""" + L = auto() + """Inductor or coil or ferrite bead > sometimes changed from "FB" for ferrite + bead""" + FD = auto() + """Fiducial""" + FL = auto() + """Filter""" + G = auto() + """Generator or oscillator""" + OSC = auto() + """Generator or oscillator""" + GL = auto() + """Graphical logo""" + GN = auto() + """General network""" + H = auto() + """Hardware, e.g., screws, nuts, washers, also used for drilled holes > + sometimes hardware is expanded to "HW" """ + HW = auto() + """Expanded form of "H" for hardware""" + HY = auto() + """Circulator or directional coupler""" + IR = auto() + """Infrared diode > often changed to "D" for diode""" + J = auto() + """Jack (least-movable connector of a connector pair), jack connector (connector + may have "male" pin contacts and/or "female" socket contacts) > all types of + connectors, including pin headers.""" + JP = auto() + """Jumper (link)""" + K = auto() + """Relay or contactor""" + LD = auto() + """LED > often changed to "D" for diode""" + LED = auto() + """LED > often changed to "D" for diode""" + LS = auto() + """Loudspeaker or buzzer""" + SPK = auto() + """Loudspeaker or buzzer""" + M = auto() + """Motor""" + MK = auto() + """Microphone""" + MIC = auto() + """Microphone""" + MP = auto() + """Mechanical part (including screws and fasteners)""" + OP = auto() + """Opto-isolator > often changed to "U" for IC""" + U = auto() + """Shorter form of "U" (unit) preferred for Integrated Circuit instead of "IC" + """ + IC = auto() + """Integrated circuit (IC) > often shortened to "U" """ + P = auto() + """Plug (most-movable connector of a connector pair), plug connector (connector + may have "male" pin contacts and/or "female" socket contacts)""" + PS = auto() + """Power supply""" + Q = auto() + """Transistor (all types)""" + R = auto() + """Resistor""" + RN = auto() + """Resistor network > sometimes simplified to "R" for resistor, or "N" for + network""" + N = auto() + """Often used for networks, sometimes simplified from resistor network "RN" """ + RT = auto() + """Thermistor > sometimes simplified to "R" for resistor""" + RV = auto() + """Varistor, variable resistor""" + S = auto() + """Switch (all types, including buttons) > sometimes "SW" is erroneously used""" + SW = auto() + """Sometimes erroneously used for Switch instead of "S" """ + SA = auto() + """Spark arrester""" + T = auto() + """Transistor > often changed to "Q", but sometimes "T" is used for bipolar + transistors and "Q" for FETs.""" + TC = auto() + """Thermocouple""" + TP = auto() + """Test point""" + TR = auto() + """Transformer > sometimes changed to "L" for inductor""" + TUN = auto() + """Tuner""" + V = auto() + """Vacuum tube""" + VR = auto() + """Voltage regulator (voltage reference), or variable resistor (potentiometer / + trimmer / rheostat) > voltage regulators are often "U" for IC, pots and trimmers + often "R" for resistor""" + X = auto() + """Socket connector for another item not P or J, paired with the letter symbol + for that item (XV for vacuum tube socket, XF for fuse holder, XA for printed + circuit assembly connector, XU for integrated circuit connector, XDS for light + socket, etc.)""" + XTAL = auto() + """Crystal, ceramic resonator, powered oscillator""" + Y = auto() + """Crystal, ceramic resonator, powered oscillator""" + ZD = auto() + """Zener diode > often changed to "D" for diode""" + @abstractmethod def get_prefix(self) -> str: ... diff --git a/src/faebryk/library/has_designator_prefix_defined.py b/src/faebryk/library/has_designator_prefix_defined.py index ed174514..acc2f292 100644 --- a/src/faebryk/library/has_designator_prefix_defined.py +++ b/src/faebryk/library/has_designator_prefix_defined.py @@ -5,7 +5,7 @@ class has_designator_prefix_defined(F.has_designator_prefix.impl()): - def __init__(self, prefix: str) -> None: + def __init__(self, prefix: str | F.has_designator_prefix.Prefix) -> None: super().__init__() self.prefix = prefix From 5a89b32f091739682c9174344c9c104a45313c10 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 12 Sep 2024 11:47:01 +0200 Subject: [PATCH 09/27] Fix: libadd pin duplication --- src/faebryk/tools/libadd.py | 8 ++++++-- 1 file changed, 6 insertions(+), 2 deletions(-) diff --git a/src/faebryk/tools/libadd.py b/src/faebryk/tools/libadd.py index 7f1a23d3..8ae8110f 100644 --- a/src/faebryk/tools/libadd.py +++ b/src/faebryk/tools/libadd.py @@ -199,7 +199,9 @@ def module( nodes.append( "#TODO: Change auto-generated interface types to actual high level types" ) - nodes += [f"{pin_name}: F.Electrical" for pin_name in interface_names.values()] + nodes += [ + f"{pin_name}: F.Electrical" for pin_name in set(interface_names.values()) + ] if noname: nodes.append(f"unnamed = L.list_field({len(noname)}, F.Electrical)") @@ -209,7 +211,9 @@ def pin_association_heuristic(self): return F.has_pin_association_heuristic_lookup_table( mapping={{ {", ".join([f"self.{interface_names[pin_name]}: ['{pin_name}']" - for _,pin_name in pins] + [ + for pin_name in sorted( + {pin_name for _, pin_name in pins})] + + [ f"self.unnamed[{i}]: ['{pin_num}']" for pin_num, i in noname.items() ])} From 6dc8d5aeca8f37b07d264afa0460241a8a4076a7 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:24:23 +0200 Subject: [PATCH 10/27] Fix: led power --- src/faebryk/library/CH344Q_ReferenceDesign.py | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/src/faebryk/library/CH344Q_ReferenceDesign.py b/src/faebryk/library/CH344Q_ReferenceDesign.py index 487c9d61..017023f8 100644 --- a/src/faebryk/library/CH344Q_ReferenceDesign.py +++ b/src/faebryk/library/CH344Q_ReferenceDesign.py @@ -56,7 +56,12 @@ def __preinit__(self): self.usb_uart_converter.act.connect(self.act_led.logic_in) self.usb_uart_converter.rx_indicator.connect(self.rx_led.logic_in) self.usb_uart_converter.tx_indicator.connect(self.tx_led.logic_in) - pwr_3v3.connect(self.power_led.power) + pwr_3v3.connect( + self.power_led.power, + self.rx_led.power_in, + self.tx_led.power_in, + self.act_led.power_in, + ) self.usb_uart_converter.osc[1].connect(self.oscillator.p) self.usb_uart_converter.osc[0].connect(self.oscillator.n) From a7bc950567327d901cdd28e516947e3d3265dc59 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 12 Sep 2024 13:25:11 +0200 Subject: [PATCH 11/27] Fix: recursion --- src/faebryk/library/ElectricLogic.py | 8 ++++++++ src/faebryk/library/PowerSwitchStatic.py | 2 ++ 2 files changed, 10 insertions(+) diff --git a/src/faebryk/library/ElectricLogic.py b/src/faebryk/library/ElectricLogic.py index f98dcc7d..c496c848 100644 --- a/src/faebryk/library/ElectricLogic.py +++ b/src/faebryk/library/ElectricLogic.py @@ -1,6 +1,7 @@ # This file is part of the faebryk project # SPDX-License-Identifier: MIT +import sys from abc import abstractmethod from enum import Enum, auto from typing import Self @@ -129,3 +130,10 @@ def connect_shallow( self.reference.lv.connect(other.reference.lv) return super().connect_shallow(other) + + def connect(self, *other: Self, linkcls=None): + recursion_depth = sys.getrecursionlimit() + sys.setrecursionlimit(10000) + ret = super().connect(*other, linkcls=linkcls) + sys.setrecursionlimit(recursion_depth) + return ret diff --git a/src/faebryk/library/PowerSwitchStatic.py b/src/faebryk/library/PowerSwitchStatic.py index 780efb80..40c2f8e6 100644 --- a/src/faebryk/library/PowerSwitchStatic.py +++ b/src/faebryk/library/PowerSwitchStatic.py @@ -11,6 +11,8 @@ class PowerSwitchStatic(F.PowerSwitch): This is useful when transforming an F.ElectricLogic to an F.ElectricPower """ + picked: has_part_picked_remove + def __init__(self) -> None: super().__init__(normally_closed=False) From 07ed6b80cfe9b9cc6801c69b581de3a19465ab6d Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:13:58 +0200 Subject: [PATCH 12/27] Fix: CH344Q ref des and ISO1540 --- src/faebryk/library/CH344Q_ReferenceDesign.py | 10 ++--- src/faebryk/library/ISO1540.py | 8 +++- src/faebryk/library/RS232_3D5R_Tranceiver.py | 37 ------------------- src/faebryk/library/_F.py | 1 - 4 files changed, 9 insertions(+), 47 deletions(-) delete mode 100644 src/faebryk/library/RS232_3D5R_Tranceiver.py diff --git a/src/faebryk/library/CH344Q_ReferenceDesign.py b/src/faebryk/library/CH344Q_ReferenceDesign.py index 017023f8..7b40ea50 100644 --- a/src/faebryk/library/CH344Q_ReferenceDesign.py +++ b/src/faebryk/library/CH344Q_ReferenceDesign.py @@ -20,7 +20,6 @@ class CH344Q_ReferenceDesign(Module): # modules, interfaces, parameters # ---------------------------------------- usb: F.USB2_0 - usb_fuse: F.Fuse usb_uart_converter: F.CH344Q oscillator: F.Crystal_Oscillator ldo: F.LDO @@ -39,19 +38,14 @@ def __preinit__(self): # aliases # ------------------------------------ vbus = self.usb.usb_if.buspower - vbus_fused = F.ElectricPower() - gnd = vbus.lv pwr_3v3 = self.usb_uart_converter.power # ------------------------------------ # connections # ------------------------------------ - vbus.hv.connect_via(self.usb_fuse, vbus_fused.hv) - gnd.connect(vbus_fused.lv) + vbus_fused = vbus.fused() vbus_fused.connect_via(self.ldo, pwr_3v3) - # TODO: use protect function self.usb.connect(self.usb_uart_converter.usb) - # TODO: add esd protection to usb self.usb_uart_converter.act.connect(self.act_led.logic_in) self.usb_uart_converter.rx_indicator.connect(self.rx_led.logic_in) @@ -82,6 +76,8 @@ def __preinit__(self): F.Range.upper_bound(40 * P.ppm) ) + vbus_fused.max_current.merge(F.Range.lower_bound(500 * P.mA)) + self.ldo.output_current.merge(F.Range.lower_bound(500 * P.mA)) # reset lowpass diff --git a/src/faebryk/library/ISO1540.py b/src/faebryk/library/ISO1540.py index 06da02cc..477b2ab9 100644 --- a/src/faebryk/library/ISO1540.py +++ b/src/faebryk/library/ISO1540.py @@ -68,5 +68,9 @@ def __preinit__(self): self.power.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) self.power_iso.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) - self.power.decoupled.decouple().capacitance.merge(10 * P.uF) - self.power_iso.decoupled.decouple().capacitance.merge(10 * P.uF) + self.power.decoupled.decouple().capacitance.merge( + F.Range.from_center_rel(10 * P.uF, 0.01) + ) + self.power_iso.decoupled.decouple().capacitance.merge( + F.Range.from_center_rel(10 * P.uF, 0.01) + ) diff --git a/src/faebryk/library/RS232_3D5R_Tranceiver.py b/src/faebryk/library/RS232_3D5R_Tranceiver.py deleted file mode 100644 index cf78d5bf..00000000 --- a/src/faebryk/library/RS232_3D5R_Tranceiver.py +++ /dev/null @@ -1,37 +0,0 @@ -# This file is part of the faebryk project -# SPDX-License-Identifier: MIT - -import logging - -import faebryk.library._F as F # noqa: F401 -from faebryk.core.module import Module -from faebryk.libs.library import L # noqa: F401 -from faebryk.libs.units import P # noqa: F401 - -logger = logging.getLogger(__name__) - - -class RS232_3D5R_Tranceiver(Module): - """ - Generic 3 drivers + 5 receivers RS232 Tranceiver base - """ - - # ---------------------------------------- - # modules, interfaces, parameters - # ---------------------------------------- - uart: F.UART - rs232: F.RS232 - - # ---------------------------------------- - # traits - # ---------------------------------------- - - def __preinit__(self): - # ------------------------------------ - # connections - # ------------------------------------ - - # ------------------------------------ - # parametrization - # ------------------------------------ - pass diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index c068106e..a58cfad9 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -207,7 +207,6 @@ from faebryk.library.Winbond_Elec_W25Q128JVSIQ import Winbond_Elec_W25Q128JVSIQ from faebryk.library.RP2040 import RP2040 from faebryk.library.INA228_ReferenceDesign import INA228_ReferenceDesign -from faebryk.library.RS232_3D5R_Tranceiver import RS232_3D5R_Tranceiver from faebryk.library.SP3243E import SP3243E from faebryk.library.CBM9002A_56ILG import CBM9002A_56ILG from faebryk.library.CH340x import CH340x From 4c87071419c62c4e8e3a3655c4c838961a5e72a0 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:14:58 +0200 Subject: [PATCH 13/27] Add: fused to ElectricPower --- src/faebryk/library/ElectricPower.py | 15 +++++++++++++++ 1 file changed, 15 insertions(+) diff --git a/src/faebryk/library/ElectricPower.py b/src/faebryk/library/ElectricPower.py index 78f43a97..25cab71e 100644 --- a/src/faebryk/library/ElectricPower.py +++ b/src/faebryk/library/ElectricPower.py @@ -50,6 +50,7 @@ def protect(self): lv: F.Electrical voltage: F.TBD[Quantity] + max_current: F.TBD[Quantity] surge_protected: can_be_surge_protected_power decoupled: can_be_decoupled_power @@ -58,6 +59,20 @@ def protect(self): def single_electric_reference(self): return F.has_single_electric_reference_defined(self) + def fused(self): + fused_power = type(self)() + fuse = fused_power.add(F.Fuse()) + + fuse.trip_current.merge(self.max_current) # TODO: maybe add a margin + + fused_power.hv.connect_via(fuse, self.hv) + fused_power.lv.connect(self.lv) + + fused_power.voltage.merge(self.voltage) + fused_power.max_current.merge(self.max_current) + + return fused_power + def __preinit__(self) -> None: ... # self.voltage.merge( From 0db176c9d45e14deac3f48621e1572fad96ee23c Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:15:54 +0200 Subject: [PATCH 14/27] Add: ElectricPower fused test --- test/library/nodes/test_electricpower.py | 28 ++++++++++++++++++++++++ 1 file changed, 28 insertions(+) create mode 100644 test/library/nodes/test_electricpower.py diff --git a/test/library/nodes/test_electricpower.py b/test/library/nodes/test_electricpower.py new file mode 100644 index 00000000..158a2c5a --- /dev/null +++ b/test/library/nodes/test_electricpower.py @@ -0,0 +1,28 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import unittest + + +class TestFusedPower(unittest.TestCase): + def test_fused_power(self): + import faebryk.library._F as F + from faebryk.libs.units import P + + power_in = F.ElectricPower() + power_out = F.ElectricPower() + + power_in.voltage.merge(10 * P.V) + power_in.max_current.merge(500 * P.mA) + + power_in_fused = power_in.fused() + + power_in_fused.connect(power_out) + + fuse = next(iter(power_in_fused.get_children(direct_only=False, types=F.Fuse))) + + self.assertIsNotNone(fuse) + self.assertIsInstance(fuse, F.Fuse) + self.assertEqual(fuse.trip_current.get_most_narrow(), 500 * P.mA) + self.assertEqual(power_out.voltage.get_most_narrow(), 10 * P.V) + self.assertEqual(power_out.max_current.get_most_narrow(), 500 * P.mA) From 7d874d5443e0a388dc927efd33f0bd4cada8189d Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:30:12 +0200 Subject: [PATCH 15/27] Add: sink trait --- src/faebryk/library/Power.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/faebryk/library/Power.py b/src/faebryk/library/Power.py index abf48d0a..594a3c39 100644 --- a/src/faebryk/library/Power.py +++ b/src/faebryk/library/Power.py @@ -11,10 +11,18 @@ class is_power_source(ModuleInterface.TraitT): ... class is_power_source_defined(is_power_source.impl()): ... + class is_power_sink(ModuleInterface.TraitT): ... + + class is_power_sink_defined(is_power_sink.impl()): ... + def make_source(self): self.add(self.is_power_source_defined()) return self + def make_sink(self): + self.add(self.is_power_sink_defined()) + return self + def _on_connect(self, other: "Power"): if self.has_trait(self.is_power_source) and other.has_trait( self.is_power_source From 322321f2bf13550e44298476ccacb8fadcc1f208 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:30:49 +0200 Subject: [PATCH 16/27] Fix: connections --- src/faebryk/library/ESP32_C3_MINI_1.py | 6 ++-- .../ESP32_C3_MINI_1_ReferenceDesign.py | 29 ++++++++++++++++++- src/faebryk/library/ME6211C33M5G_N.py | 2 +- 3 files changed, 32 insertions(+), 5 deletions(-) diff --git a/src/faebryk/library/ESP32_C3_MINI_1.py b/src/faebryk/library/ESP32_C3_MINI_1.py index 9baab85d..77d4b8a9 100644 --- a/src/faebryk/library/ESP32_C3_MINI_1.py +++ b/src/faebryk/library/ESP32_C3_MINI_1.py @@ -95,8 +95,8 @@ def attach_to_footprint(self): "27": self.gpio[19].signal, # 28 is not connected # 29 is not connected - "30": self.uart.rx.signal, - "31": self.uart.tx.signal, + "30": self.gpio[20].signal, # uart.rx, + "31": self.gpio[21].signal, # uart.tx, # 32 is not connected # 33 is not connected # 34 is not connected @@ -134,5 +134,5 @@ def attach_to_footprint(self): designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") datasheet = L.f_field(F.has_datasheet_defined)( - "https://www.espressif.com/sites/default/files/russianDocumentation/esp32-c3-mini-1_datasheet_en.pdf" + "https://www.espressif.com/sites/default/files/documentation/esp32-c3-mini-1_datasheet_en.pdf" ) diff --git a/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py b/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py index e72435aa..5f07b3f9 100644 --- a/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py +++ b/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py @@ -49,7 +49,34 @@ def __preinit__(self): # TODO: set the following in the pinmux # jtag gpio 4,5,6,7 - # USB gpio 18,19 + self.esp32_c3_mini_1.esp32_c3.usb.usb_if.d.n.connect( + self.esp32_c3_mini_1.esp32_c3.gpio[18].signal + ) + self.esp32_c3_mini_1.esp32_c3.usb.usb_if.d.p.connect( + self.esp32_c3_mini_1.esp32_c3.gpio[19].signal + ) + # UART0 gpio 30/31 (default) + self.esp32_c3_mini_1.esp32_c3.uart[0].rx.connect( + self.esp32_c3_mini_1.esp32_c3.gpio[20] + ) + self.esp32_c3_mini_1.esp32_c3.uart[0].tx.connect( + self.esp32_c3_mini_1.esp32_c3.gpio[21] + ) + + # UART1 gpio 8/9 + self.esp32_c3_mini_1.esp32_c3.uart[1].rx.connect( + self.esp32_c3_mini_1.esp32_c3.gpio[8] + ) + self.esp32_c3_mini_1.esp32_c3.uart[1].tx.connect( + self.esp32_c3_mini_1.esp32_c3.gpio[7] + ) + # i2c + self.esp32_c3_mini_1.esp32_c3.i2c.sda.connect( + self.esp32_c3_mini_1.esp32_c3.gpio[3] # default 21 + ) + self.esp32_c3_mini_1.esp32_c3.i2c.scl.connect( + self.esp32_c3_mini_1.esp32_c3.gpio[2] # default 22 + ) # connect USB self.usb.connect(self.esp32_c3_mini_1.esp32_c3.usb) diff --git a/src/faebryk/library/ME6211C33M5G_N.py b/src/faebryk/library/ME6211C33M5G_N.py index 8d81ebd0..3c51aa11 100644 --- a/src/faebryk/library/ME6211C33M5G_N.py +++ b/src/faebryk/library/ME6211C33M5G_N.py @@ -32,7 +32,7 @@ def attach_to_footprint(self): { "1": self.power_in.hv, "2": self.power_in.lv, - "3": self.enable, + "3": self.enable.signal, "5": self.power_out.hv, } ) From 102cba286f8cc3766e951d407ac1eec2cb10038d Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Thu, 12 Sep 2024 20:31:46 +0200 Subject: [PATCH 17/27] Fix: Create file/path if not existing --- src/faebryk/exporters/parameters/parameters_to_file.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/src/faebryk/exporters/parameters/parameters_to_file.py b/src/faebryk/exporters/parameters/parameters_to_file.py index 801dc832..c532d959 100644 --- a/src/faebryk/exporters/parameters/parameters_to_file.py +++ b/src/faebryk/exporters/parameters/parameters_to_file.py @@ -22,6 +22,9 @@ def export_parameters_to_file(module: Module, path: Path): ] logger.info(f"Writing parameters to {path}") + if not path.exists() or not path.is_file(): + path.touch() + if path.suffix == ".txt": with open(path, "w") as f: for module_name, paras in sorted(parameters.items()): From 43b662dfda4f32c4d8e90c1003baa7300b136ab0 Mon Sep 17 00:00:00 2001 From: iopapamanoglou Date: Fri, 13 Sep 2024 13:06:15 +0200 Subject: [PATCH 18/27] proper path usage in export_parameters --- .../parameters/parameters_to_file.py | 61 +++++++++---------- 1 file changed, 28 insertions(+), 33 deletions(-) diff --git a/src/faebryk/exporters/parameters/parameters_to_file.py b/src/faebryk/exporters/parameters/parameters_to_file.py index c532d959..4c4dabdd 100644 --- a/src/faebryk/exporters/parameters/parameters_to_file.py +++ b/src/faebryk/exporters/parameters/parameters_to_file.py @@ -22,42 +22,37 @@ def export_parameters_to_file(module: Module, path: Path): ] logger.info(f"Writing parameters to {path}") - if not path.exists() or not path.is_file(): - path.touch() - + out = "" if path.suffix == ".txt": - with open(path, "w") as f: - for module_name, paras in sorted(parameters.items()): - if paras: - f.write(f"{module_name}\n") - f.writelines( - [ - f" {par_name}: {par_value}\n" - for par_dict in paras - for par_name, par_value in par_dict.items() - ] - ) - f.write("\n") - f.close() + for module_name, paras in sorted(parameters.items()): + if paras: + out += f"{module_name}\n" + out += "\n".join( + [ + f" {par_name}: {par_value}\n" + for par_dict in paras + for par_name, par_value in par_dict.items() + ] + ) + out += "\n" elif path.suffix == ".md": - with open(path, "w") as f: - f.write("# Module Parameters\n") - for module_name, paras in sorted(parameters.items()): - if paras: - f.write(f"**{module_name.replace("|","|")}**\n") - f.write("| Parameter Name | Parameter Value |\n") - f.write("| --- | --- |\n") - f.writelines( - [ - f"| {par_name.replace("|","|")} | {str(par_value).replace("|","|")} |\n" # noqa E501 - for par_dict in paras - for par_name, par_value in par_dict.items() - ] - ) - f.write("\n") - f.write("\n") - f.close() + out += "# Module Parameters\n" + for module_name, paras in sorted(parameters.items()): + if paras: + out += f"**{module_name.replace("|","|")}**\n" + out += "| Parameter Name | Parameter Value |\n" + out += "| --- | --- |\n" + out += "\n".join( + [ + f"| {par_name.replace("|","|")} | {str(par_value).replace("|","|")} |\n" # noqa E501 + for par_dict in paras + for par_name, par_value in par_dict.items() + ] + ) + out += "\n" else: AssertionError( f"Export to file extension [{path.suffix}] not supported in {path}" ) + + path.write_text(out) From a809c7ee897d90877139c9fb042ed28b29cee61a Mon Sep 17 00:00:00 2001 From: iopapamanoglou Date: Fri, 13 Sep 2024 13:38:22 +0200 Subject: [PATCH 19/27] Add electriclogic helper --- src/faebryk/library/CH342.py | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/src/faebryk/library/CH342.py b/src/faebryk/library/CH342.py index 24becc7d..fe161c82 100644 --- a/src/faebryk/library/CH342.py +++ b/src/faebryk/library/CH342.py @@ -24,11 +24,13 @@ class DuplexMode(Enum): # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- + # TODO not a full USB usb: F.USB2_0 uart = L.list_field(2, F.UART) tnow = L.list_field(2, F.ElectricLogic) ri = L.list_field(2, F.ElectricLogic) dcd = L.list_field(2, F.ElectricLogic) + vbus_detect: F.ElectricLogic reset: F.ElectricLogic active: F.ElectricLogic @@ -44,12 +46,6 @@ class DuplexMode(Enum): "https://wch-ic.com/downloads/CH342DS1_PDF.html" ) - @L.rt_field - def single_electric_reference(self): - return F.has_single_electric_reference_defined( - F.ElectricLogic.connect_all_module_references(self, gnd_only=True) - ) - def __preinit__(self): # ---------------------------------------- # aliasess @@ -64,3 +60,7 @@ def __preinit__(self): # ---------------------------------------- # connections # ---------------------------------------- + F.ElectricLogic.connect_all_module_references(self, gnd_only=True) + F.ElectricLogic.connect_all_module_references( + self, exclude={self.vdd_5v, self.v_3v, self.vbus_detect} + ) From f4e4aecb7686838d7d29959ef6b442ad0515769f Mon Sep 17 00:00:00 2001 From: iopapamanoglou Date: Fri, 13 Sep 2024 14:12:40 +0200 Subject: [PATCH 20/27] fix once; improve fused() --- src/faebryk/library/CH344Q.py | 2 +- src/faebryk/library/CH344Q_ReferenceDesign.py | 10 +++-- src/faebryk/library/ElectricPower.py | 6 ++- src/faebryk/libs/util.py | 31 +++++++++------ test/libs/test_util.py | 39 ++++++++++++++++++- 5 files changed, 70 insertions(+), 18 deletions(-) diff --git a/src/faebryk/library/CH344Q.py b/src/faebryk/library/CH344Q.py index 757b4a3d..c55c13a5 100644 --- a/src/faebryk/library/CH344Q.py +++ b/src/faebryk/library/CH344Q.py @@ -72,7 +72,7 @@ def enable_hardware_flow_conrol(self): def descriptive_properties(self): return F.has_descriptive_properties_defined( { - DescriptiveProperties.manufacturer: "WCH", + DescriptiveProperties.manufacturer.value: "WCH", DescriptiveProperties.partno: "CH344Q", }, ) diff --git a/src/faebryk/library/CH344Q_ReferenceDesign.py b/src/faebryk/library/CH344Q_ReferenceDesign.py index 7b40ea50..3c6a8510 100644 --- a/src/faebryk/library/CH344Q_ReferenceDesign.py +++ b/src/faebryk/library/CH344Q_ReferenceDesign.py @@ -29,6 +29,10 @@ class CH344Q_ReferenceDesign(Module): power_led: F.PoweredLED reset_lowpass: F.FilterElectricalRC + @L.rt_field + def vbus_fused(self): + return self.usb.usb_if.buspower.fused() + # ---------------------------------------- # traits # ---------------------------------------- @@ -37,13 +41,11 @@ def __preinit__(self): # ------------------------------------ # aliases # ------------------------------------ - vbus = self.usb.usb_if.buspower pwr_3v3 = self.usb_uart_converter.power # ------------------------------------ # connections # ------------------------------------ - vbus_fused = vbus.fused() - vbus_fused.connect_via(self.ldo, pwr_3v3) + self.vbus_fused.connect_via(self.ldo, pwr_3v3) self.usb.connect(self.usb_uart_converter.usb) @@ -76,7 +78,7 @@ def __preinit__(self): F.Range.upper_bound(40 * P.ppm) ) - vbus_fused.max_current.merge(F.Range.lower_bound(500 * P.mA)) + self.vbus_fused.max_current.merge(F.Range.lower_bound(500 * P.mA)) self.ldo.output_current.merge(F.Range.lower_bound(500 * P.mA)) diff --git a/src/faebryk/library/ElectricPower.py b/src/faebryk/library/ElectricPower.py index 25cab71e..a446b6db 100644 --- a/src/faebryk/library/ElectricPower.py +++ b/src/faebryk/library/ElectricPower.py @@ -7,6 +7,7 @@ import faebryk.library._F as F from faebryk.core.moduleinterface import ModuleInterface +from faebryk.core.node import Node from faebryk.libs.library import L from faebryk.libs.units import P, Quantity from faebryk.libs.util import RecursionGuard @@ -59,7 +60,7 @@ def protect(self): def single_electric_reference(self): return F.has_single_electric_reference_defined(self) - def fused(self): + def fused(self, attach_to: Node | None = None): fused_power = type(self)() fuse = fused_power.add(F.Fuse()) @@ -71,6 +72,9 @@ def fused(self): fused_power.voltage.merge(self.voltage) fused_power.max_current.merge(self.max_current) + if attach_to is not None: + attach_to.add(fused_power) + return fused_power def __preinit__(self) -> None: diff --git a/src/faebryk/libs/util.py b/src/faebryk/libs/util.py index 8cdfa79a..31549c4b 100644 --- a/src/faebryk/libs/util.py +++ b/src/faebryk/libs/util.py @@ -804,20 +804,29 @@ def __() -> T: def once[T, **P](f: Callable[P, T]) -> Callable[P, T]: - class _once: - def __init__(self) -> None: - self.cache = {} + def wrapper(*args: P.args, **kwargs: P.kwargs) -> Any: + lookup = (args, tuple(kwargs.items())) + if lookup in wrapper.cache: + return wrapper.cache[lookup] - def __call__(self, *args: P.args, **kwds: P.kwargs) -> Any: - lookup = (args, tuple(kwds.items())) - if lookup in self.cache: - return self.cache[lookup] + result = f(*args, **kwargs) + wrapper.cache[lookup] = result + return result - result = f(*args, **kwds) - self.cache[lookup] = result - return result + wrapper.cache = {} + return wrapper - return _once() + +def assert_once[**P](f: Callable[P, None]) -> Callable[P, None]: + def wrapper(*args: P.args, **kwargs: P.kwargs) -> None: + if not wrapper.called: + wrapper.called = True + return f(*args, **kwargs) + else: + raise AssertionError("Function called more than once") + + wrapper.called = False + return wrapper class PostInitCaller(type): diff --git a/test/libs/test_util.py b/test/libs/test_util.py index 445c4bf6..42754e68 100644 --- a/test/libs/test_util.py +++ b/test/libs/test_util.py @@ -5,7 +5,7 @@ from itertools import combinations from faebryk.libs.logging import setup_basic_logging -from faebryk.libs.util import SharedReference, once, zip_non_locked +from faebryk.libs.util import SharedReference, assert_once, once, zip_non_locked class TestUtil(unittest.TestCase): @@ -85,6 +85,12 @@ def do(cls): ran = True return cls + @once + def do_inst(self, arg: int): + global ran + ran = True + return arg + self.assertEqual(A.do(), A) self.assertTrue(ran) ran = False @@ -92,6 +98,37 @@ def do(cls): self.assertEqual(A.do(), A) self.assertFalse(ran) + ran = False + a = A() + self.assertEqual(a.do_inst(5), 5) + self.assertTrue(ran) + ran = False + self.assertEqual(a.do_inst(5), 5) + self.assertFalse(ran) + + def test_assert_once(self): + class A: + def __init__(self): + self.a = 1 + + @assert_once + def do(self): + print("do") + self.a = 5 + + @assert_once + def do_with_arg(self, arg: int): + print("do_with_arg", arg) + self.a = arg + + a = A() + a.do() + self.assertEqual(a.a, 5) + self.assertRaises(AssertionError, a.do) + a.do_with_arg(3) + self.assertEqual(a.a, 3) + self.assertRaises(AssertionError, a.do_with_arg, 2) + if __name__ == "__main__": setup_basic_logging() From 1221d906168b099234ea40ab47e36201dc76a2af Mon Sep 17 00:00:00 2001 From: iopapamanoglou Date: Fri, 13 Sep 2024 14:59:02 +0200 Subject: [PATCH 21/27] minor fixes --- src/faebryk/library/ElectricLogic.py | 2 ++ src/faebryk/library/ElectricPower.py | 4 +++ src/faebryk/library/ISO1540.py | 37 +++++++++++++++------------- src/faebryk/library/SP3243E.py | 2 +- src/faebryk/libs/util.py | 4 +-- 5 files changed, 29 insertions(+), 20 deletions(-) diff --git a/src/faebryk/library/ElectricLogic.py b/src/faebryk/library/ElectricLogic.py index c496c848..8fb7e4bd 100644 --- a/src/faebryk/library/ElectricLogic.py +++ b/src/faebryk/library/ElectricLogic.py @@ -8,6 +8,7 @@ import faebryk.library._F as F from faebryk.libs.library import L +from faebryk.libs.util import assert_once class ElectricLogic(F.SignalElectrical, F.Logic): @@ -107,6 +108,7 @@ def set(self, on: bool): r = self.reference self.signal.connect(r.hv if on else r.lv) + @assert_once def set_weak(self, on: bool): return self.get_trait(self.can_be_pulled).pull(up=on) diff --git a/src/faebryk/library/ElectricPower.py b/src/faebryk/library/ElectricPower.py index a446b6db..657c4aec 100644 --- a/src/faebryk/library/ElectricPower.py +++ b/src/faebryk/library/ElectricPower.py @@ -52,6 +52,10 @@ def protect(self): voltage: F.TBD[Quantity] max_current: F.TBD[Quantity] + """ + Only for this particular power interface + Does not propagate to connections + """ surge_protected: can_be_surge_protected_power decoupled: can_be_decoupled_power diff --git a/src/faebryk/library/ISO1540.py b/src/faebryk/library/ISO1540.py index 477b2ab9..98164c29 100644 --- a/src/faebryk/library/ISO1540.py +++ b/src/faebryk/library/ISO1540.py @@ -5,6 +5,7 @@ import faebryk.library._F as F # noqa: F401 from faebryk.core.module import Module +from faebryk.core.moduleinterface import ModuleInterface from faebryk.libs.library import L # noqa: F401 from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P # noqa: F401 @@ -17,13 +18,15 @@ class ISO1540(Module): ISO1540 Low-Power Bidirectional I2C Isolator """ + class I2CandPower(ModuleInterface): + i2c: F.I2C + power: F.ElectricPower + # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- - power: F.ElectricPower - i2c: F.I2C - power_iso: F.ElectricPower - i2c_iso: F.I2C + non_iso: I2CandPower + iso: I2CandPower # ---------------------------------------- # traits @@ -37,7 +40,7 @@ class ISO1540(Module): def descriptive_properties(self): return F.has_descriptive_properties_defined( { - DescriptiveProperties.manufacturer: "Texas Instruments", + DescriptiveProperties.manufacturer.value: "Texas Instruments", DescriptiveProperties.partno: "ISO1540DR", }, ) @@ -46,14 +49,14 @@ def descriptive_properties(self): def can_attach_to_footprint(self): return F.can_attach_to_footprint_via_pinmap( pinmap={ - "1": self.power.hv, - "2": self.i2c.sda, - "3": self.i2c.scl, - "4": self.power.lv, - "5": self.power_iso.lv, - "6": self.i2c_iso.scl, - "7": self.i2c_iso.sda, - "8": self.power_iso.hv, + "1": self.non_iso.power.hv, + "2": self.non_iso.i2c.sda, + "3": self.non_iso.i2c.scl, + "4": self.non_iso.power.lv, + "5": self.iso.power.lv, + "6": self.iso.i2c.scl, + "7": self.iso.i2c.sda, + "8": self.iso.power.hv, } ) @@ -65,12 +68,12 @@ def __preinit__(self): # ------------------------------------ # parametrization # ------------------------------------ - self.power.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) - self.power_iso.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) + self.non_iso.power.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) + self.iso.power.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) - self.power.decoupled.decouple().capacitance.merge( + self.non_iso.power.decoupled.decouple().capacitance.merge( F.Range.from_center_rel(10 * P.uF, 0.01) ) - self.power_iso.decoupled.decouple().capacitance.merge( + self.iso.power.decoupled.decouple().capacitance.merge( F.Range.from_center_rel(10 * P.uF, 0.01) ) diff --git a/src/faebryk/library/SP3243E.py b/src/faebryk/library/SP3243E.py index edf3fc51..e942231e 100644 --- a/src/faebryk/library/SP3243E.py +++ b/src/faebryk/library/SP3243E.py @@ -58,7 +58,7 @@ def enable_auto_online(self): def descriptive_properties(self): return F.has_descriptive_properties_defined( { - DescriptiveProperties.manufacturer: "MaxLinear", + DescriptiveProperties.manufacturer.value: "MaxLinear", DescriptiveProperties.partno: "SP3243EBEA-L/TR", }, ) diff --git a/src/faebryk/libs/util.py b/src/faebryk/libs/util.py index 31549c4b..32601e1f 100644 --- a/src/faebryk/libs/util.py +++ b/src/faebryk/libs/util.py @@ -817,8 +817,8 @@ def wrapper(*args: P.args, **kwargs: P.kwargs) -> Any: return wrapper -def assert_once[**P](f: Callable[P, None]) -> Callable[P, None]: - def wrapper(*args: P.args, **kwargs: P.kwargs) -> None: +def assert_once[T, **P](f: Callable[P, T]) -> Callable[P, T]: + def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: if not wrapper.called: wrapper.called = True return f(*args, **kwargs) From 52ccbdba58bb53cb20954a1d77a71aa9f6d475a7 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Sun, 15 Sep 2024 14:40:32 +0200 Subject: [PATCH 22/27] Up quality of modules. Add ModuleExeption --- src/faebryk/core/module.py | 7 + src/faebryk/library/Button.py | 4 +- src/faebryk/library/CH342.py | 116 +++++++++++--- src/faebryk/library/CH342F.py | 147 +++++++++--------- src/faebryk/library/CH342F_ReferenceDesign.py | 53 ++----- src/faebryk/library/CH342K.py | 62 ++++++++ src/faebryk/library/CH342K_ReferenceDesign.py | 46 ++++++ src/faebryk/library/CH344.py | 20 +-- src/faebryk/library/CH344Q.py | 39 +++-- src/faebryk/library/CH344Q_ReferenceDesign.py | 23 +-- src/faebryk/library/DE9Connector.py | 10 +- src/faebryk/library/DE9RS232Connector.py | 5 - .../library/Diodes_Incorporated_AP2552W6_7.py | 45 +++--- .../ESP32_C3_MINI_1_ReferenceDesign.py | 76 ++++----- src/faebryk/library/ElectricLogic.py | 6 + src/faebryk/library/INA228.py | 43 ++++- src/faebryk/library/INA228_ReferenceDesign.py | 96 +++++++----- src/faebryk/library/ISO1540.py | 37 +++-- .../library/ISO1540_ReferenceDesign.py | 30 ++++ src/faebryk/library/Logic.py | 7 + src/faebryk/library/PowerMux.py | 8 +- src/faebryk/library/SP3243E.py | 14 -- .../library/SP3243E_ReferenceDesign.py | 46 ++++++ src/faebryk/library/TPS2116.py | 39 +++-- src/faebryk/library/_F.py | 36 +++-- 25 files changed, 670 insertions(+), 345 deletions(-) create mode 100644 src/faebryk/library/CH342K.py create mode 100644 src/faebryk/library/CH342K_ReferenceDesign.py create mode 100644 src/faebryk/library/ISO1540_ReferenceDesign.py create mode 100644 src/faebryk/library/SP3243E_ReferenceDesign.py diff --git a/src/faebryk/core/module.py b/src/faebryk/core/module.py index 2cf5ef12..9c76d52a 100644 --- a/src/faebryk/core/module.py +++ b/src/faebryk/core/module.py @@ -6,6 +6,7 @@ from faebryk.core.moduleinterface import GraphInterfaceModuleSibling from faebryk.core.node import Node, f_field from faebryk.core.trait import Trait +from faebryk.libs.exceptions import FaebrykException from faebryk.libs.util import unique_ref if TYPE_CHECKING: @@ -14,6 +15,12 @@ logger = logging.getLogger(__name__) +class ModuleException(FaebrykException): + def __init__(self, module: "Module", *args: object) -> None: + self.module = module + super().__init__(*args) + + class Module(Node): class TraitT(Trait): ... diff --git a/src/faebryk/library/Button.py b/src/faebryk/library/Button.py index 122451e9..a74cf6d4 100644 --- a/src/faebryk/library/Button.py +++ b/src/faebryk/library/Button.py @@ -15,7 +15,9 @@ class Button(Module): unnamed = L.list_field(2, F.Electrical) height: F.TBD[Quantity] - designator_prefix = L.f_field(F.has_designator_prefix_defined)("SW") + designator_prefix = L.f_field(F.has_designator_prefix_defined)( + F.has_designator_prefix.Prefix.S + ) @L.rt_field def can_bridge(self): diff --git a/src/faebryk/library/CH342.py b/src/faebryk/library/CH342.py index fe161c82..6c6d03fe 100644 --- a/src/faebryk/library/CH342.py +++ b/src/faebryk/library/CH342.py @@ -5,9 +5,10 @@ from enum import Enum, auto import faebryk.library._F as F # noqa: F401 -from faebryk.core.module import Module +from faebryk.core.module import Module, ModuleException from faebryk.libs.library import L # noqa: F401 -from faebryk.libs.units import P # noqa: F401 +from faebryk.libs.units import P +from faebryk.libs.util import assert_once # noqa: F401 logger = logging.getLogger(__name__) @@ -17,27 +18,94 @@ class CH342(Module): Base class for CH342x USB to double UART converter """ - class DuplexMode(Enum): - FULL = auto() - HALF = auto() + class IntegratedLDO(Module): + power_in: F.ElectricPower + power_out: F.ElectricPower + + def __preinit__(self): + F.ElectricLogic.connect_all_module_references(self, gnd_only=True) + + self.power_out.voltage.merge(F.Range.from_center(3.3 * P.V, 0.3 * P.V)) + self.power_in.voltage.merge(F.Range(4 * P.V, 5.5 * P.V)) + + @L.rt_field + def bridge(self): + return F.can_bridge_defined(self.power_in, self.power_out) + + class IOPowerConfiguration(Enum): + USB_5V = auto() + """IO powered by USB 5V""" + INTERNAL_3V3 = auto() + """IO powered by the integrated 3.3V regulator""" + EXTERNAL = auto() + """IO powered by an external 1.8V-5V source""" + + class ChipPowerConfiguration(Enum): + USB_5V = auto() + """Chip powered by USB 5V""" + EXTERNAL_5V = auto() + """Chip powered by an external 5V source""" + EXTERNAL_3V3 = auto() + """Chip powered by an external 3.3V source""" + + @assert_once + def set_power_configuration( + self, + chip_power_configuration: ChipPowerConfiguration = ChipPowerConfiguration.USB_5V, # noqa: E501 + io_voltage_configuration: IOPowerConfiguration = IOPowerConfiguration.INTERNAL_3V3, # noqa: E501 + ): + """Configure how the chip is powered, and what the io voltage will be.""" + # how is the chip powered + if chip_power_configuration == self.ChipPowerConfiguration.EXTERNAL_3V3: + # short the integrated regulator power input to the output to disable + self.integrated_regulator.power_in.connect(self.power_3v) + elif chip_power_configuration == self.ChipPowerConfiguration.USB_5V: + # use the USB power to power the chip + self.usb.usb_if.buspower.connect(self.integrated_regulator.power_in) + else: + # use an external 5V power source for the chip + ... + + # how is the IO powered + if io_voltage_configuration == self.IOPowerConfiguration.INTERNAL_3V3: + # check if the integrated regulator is not disabled + if chip_power_configuration == self.ChipPowerConfiguration.EXTERNAL_3V3: + raise ModuleException( + self, + "Cannot power IO from the integrated regulator when it is disabled, use 'EXTERNAL' power configuration instead", # noqa: E501 + ) + # io is 3v3 and powered by the integrated regulator (10mA max) + self.power_io.connect(self.power_3v) + F.ElectricLogic.connect_all_module_references( + self, + exclude={ + self.integrated_regulator.power_in, + }, + ) + elif io_voltage_configuration == self.IOPowerConfiguration.USB_5V: + # io is 5v and powered by USB + self.power_io.connect(self.usb.usb_if.buspower) + F.ElectricLogic.connect_all_module_references( + self, + exclude={ + self.integrated_regulator.power_in, + self.integrated_regulator.power_out, + self.power_3v, + }, + ) + else: + # io is 1.8V-5V and powered by an external source + ... # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- - # TODO not a full USB usb: F.USB2_0 - uart = L.list_field(2, F.UART) - tnow = L.list_field(2, F.ElectricLogic) - ri = L.list_field(2, F.ElectricLogic) - dcd = L.list_field(2, F.ElectricLogic) - vbus_detect: F.ElectricLogic - - reset: F.ElectricLogic - active: F.ElectricLogic + # uart_base = L.list_field(2, F.UART_Base) - vdd_5v: F.ElectricPower - v_io: F.ElectricPower - v_3v: F.ElectricPower + integrated_regulator: IntegratedLDO + power_io: F.ElectricPower + power_3v: F.ElectricPower # ---------------------------------------- # traits @@ -45,6 +113,9 @@ class DuplexMode(Enum): datasheet = L.f_field(F.has_datasheet_defined)( "https://wch-ic.com/downloads/CH342DS1_PDF.html" ) + designator_prefix = L.f_field(F.has_designator_prefix_defined)( + F.has_designator_prefix.Prefix.U + ) def __preinit__(self): # ---------------------------------------- @@ -53,14 +124,13 @@ def __preinit__(self): # ---------------------------------------- # parametrization # ---------------------------------------- - self.vdd_5v.voltage.merge(F.Range(4 * P.V, 5.5 * P.V)) - self.v_3v.voltage.merge(F.Range.from_center(3.3 * P.V, 0.3 * P.V)) - self.v_io.voltage.merge(F.Range(1.7 * P.V, 5.5 * P.V)) + self.power_3v.voltage.merge(F.Range.from_center(3.3 * P.V, 0.3 * P.V)) + self.power_io.voltage.merge(F.Range(1.7 * P.V, 5.5 * P.V)) # ---------------------------------------- # connections # ---------------------------------------- F.ElectricLogic.connect_all_module_references(self, gnd_only=True) - F.ElectricLogic.connect_all_module_references( - self, exclude={self.vdd_5v, self.v_3v, self.vbus_detect} - ) + + # chip internal connection + self.integrated_regulator.power_out.connect(self.power_3v) diff --git a/src/faebryk/library/CH342F.py b/src/faebryk/library/CH342F.py index 55f91865..06fa117d 100644 --- a/src/faebryk/library/CH342F.py +++ b/src/faebryk/library/CH342F.py @@ -4,57 +4,61 @@ import logging import faebryk.library._F as F # noqa: F401 -from faebryk.core.module import Module +from faebryk.core.module import ModuleException from faebryk.libs.library import L # noqa: F401 from faebryk.libs.picker.picker import DescriptiveProperties -from faebryk.libs.units import P # noqa: F401 -from faebryk.libs.util import NotNone +from faebryk.libs.util import assert_once, times logger = logging.getLogger(__name__) -class CH342F(Module): +class CH342F(F.CH342): """ - Dual UART-USB converter + USB to double Base UART converter + + QFN-24-EP(4x4) """ + @assert_once + def enable_tnow_mode(self, uart: F.UART): + """ + Set TNOW mode for specified UART for use with RS485 tranceivers. + The TNOW pin can be connected to the tx_enable and rx_enable + pins of the RS485 tranceiver for automatic half-duplex control. + """ + if uart not in self.uart: + raise ModuleException( + self, f"{uart.get_full_name()} is not a part of this module" + ) + + uart.dtr.set_weak(on=False) + uart.dtr.connect(self.tnow[self.uart.index(uart)]) + # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- - usb: F.USB2_0 - uart = L.list_field(2, F.UART) - tnow = L.list_field(2, F.ElectricLogic) - ri = L.list_field(2, F.ElectricLogic) - dcd = L.list_field(2, F.ElectricLogic) + vbus_detect: F.ElectricLogic reset: F.ElectricLogic active: F.ElectricLogic - vdd_5v: F.ElectricPower - v_io: F.ElectricPower - v_3v: F.ElectricPower - - designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + uart = times(2, F.UART) # ---------------------------------------- # traits # ---------------------------------------- - datasheet = L.f_field(F.has_datasheet_defined)( - "https://wch-ic.com/downloads/CH342DS1_PDF.html" - ) - @L.rt_field def can_attach_to_footprint(self): return F.can_attach_to_footprint_via_pinmap( { - "1": self.ri[0].signal, + "1": self.uart[0].ri.signal, "2": self.usb.usb_if.buspower.lv, "3": self.usb.usb_if.d.p, "4": self.usb.usb_if.d.n, - "5": self.v_io.hv, - "6": self.v_3v.hv, - "7": self.vdd_5v.hv, + "5": self.power_io.hv, + "6": self.power_3v.hv, + "7": self.integrated_regulator.power_in.hv, "8": self.usb.usb_if.buspower.hv, "9": self.reset.signal, "10": self.uart[1].cts.signal, @@ -63,80 +67,75 @@ def can_attach_to_footprint(self): "13": self.uart[1].base_uart.tx.signal, "14": self.uart[1].dsr.signal, "15": self.uart[1].dtr.signal, - "16": self.dcd[1].signal, - "17": self.ri[1].signal, + "16": self.uart[1].dcd.signal, + "17": self.uart[1].ri.signal, "18": self.uart[0].cts.signal, "19": self.uart[0].rts.signal, "20": self.uart[0].base_uart.rx.signal, "21": self.uart[0].base_uart.tx.signal, "22": self.uart[0].dsr.signal, "23": self.uart[0].dtr.signal, - "24": self.dcd[0].signal, + "24": self.uart[0].dcd.signal, "25": self.usb.usb_if.buspower.lv, } ) @L.rt_field - def descriptive_properties(self): - return F.has_descriptive_properties_defined( - { - DescriptiveProperties.manufacturer: "WCH", - DescriptiveProperties.partno: "CH342F", + def pin_association_heuristic(self): + return F.has_pin_association_heuristic_lookup_table( + mapping={ + self.uart[0].cts.signal: ["CTS0"], + self.uart[1].cts.signal: ["CTS1"], + self.uart[0].dcd.signal: ["DCD0"], + self.uart[1].dcd.signal: ["DCD1"], + self.uart[0].dsr.signal: ["DSR0"], + self.uart[1].dsr.signal: ["DSR1"], + self.uart[0].dtr.signal: ["DTR0"], + self.uart[1].dtr.signal: ["DTR1"], + # self.power_3v.lv: ["EP"], + self.power_3v.lv: ["GND"], + self.uart[0].ri.signal: ["RI0"], + self.uart[1].ri.signal: ["RI1"], + self.reset.signal: ["RST"], + self.uart[0].rts.signal: ["RTS0"], + self.uart[1].rts.signal: ["RTS1"], + self.uart[0].base_uart.rx.signal: ["RXD0"], + self.uart[1].base_uart.rx.signal: ["RXD1"], + self.uart[0].base_uart.tx.signal: ["TXD0"], + self.uart[1].base_uart.tx.signal: ["TXD1"], + self.usb.usb_if.d.p: ["UD+"], + self.usb.usb_if.d.n: ["UD-"], + self.power_3v.hv: ["V3"], + self.vbus_detect.signal: ["VBUS"], + self.integrated_regulator.power_in.hv: ["VDD5"], + self.power_io.hv: ["VIO"], }, + accept_prefix=False, + case_sensitive=False, ) - def __init__( - self, - duplex_mode_uart_0: F.CH342.DuplexMode = F.CH342.DuplexMode.FULL, - duplex_mode_uart_1: F.CH342.DuplexMode = F.CH342.DuplexMode.FULL, - ): - super().__init__() - self._duplex_mode_uart_0 = duplex_mode_uart_0 - self._duplex_mode_uart_1 = duplex_mode_uart_1 + descriptive_properties = L.f_field(F.has_descriptive_properties_defined)( + { + DescriptiveProperties.manufacturer: "WCH(Jiangsu Qin Heng)", + DescriptiveProperties.partno: "CH342F", + } + ) def __preinit__(self) -> None: # ---------------------------------------- # aliasess # ---------------------------------------- + # ---------------------------------------- # parametrization # ---------------------------------------- - self.vdd_5v.voltage.merge(F.Range(4 * P.V, 5.5 * P.V)) - self.v_3v.voltage.merge(F.Range.from_center(3.3 * P.V, 0.3 * P.V)) - self.v_io.voltage.merge(F.Range(1.7 * P.V, 5.5 * P.V)) - - # set the duplex mode - if self._duplex_mode_uart_0 == F.CH342.DuplexMode.HALF: - self.uart[0].dtr.get_trait(F.ElectricLogic.can_be_pulled).pull(up=False) - NotNone( - self.uart[0].dtr.get_trait(F.ElectricLogic.has_pulls).get_pulls()[1] - ).resistance.merge(4.7 * P.kohm) - self.tnow[0].connect(self.uart[0].dtr) - if self._duplex_mode_uart_1 == F.CH342.DuplexMode.HALF: - self.uart[1].dtr.get_trait(F.ElectricLogic.can_be_pulled).pull(up=False) - NotNone( - self.uart[1].dtr.get_trait(F.ElectricLogic.has_pulls).get_pulls()[1] - ).resistance.merge(4.7 * P.kohm) - self.tnow[1].connect(self.uart[1].dtr) # ---------------------------------------- # connections # ---------------------------------------- - # configure for 3.3V GPIO operation with internal LDO - self.vdd_5v.connect(self.usb.usb_if.buspower) - self.v_3v.connect(self.v_io) - - self.vdd_5v.get_trait(F.can_be_decoupled).decouple().capacitance.merge(1 * P.uF) - self.v_3v.get_trait(F.can_be_decoupled).decouple().capacitance.merge(0.1 * P.uF) - self.v_io.get_trait(F.can_be_decoupled).decouple().capacitance.merge(1 * P.uF) - - F.can_attach_to_footprint().attach( - F.QFN( - pin_cnt=24, - exposed_thermal_pad_cnt=1, - size_xy=(4 * P.mm, 4 * P.mm), - pitch=0.5 * P.mm, - exposed_thermal_pad_dimensions=(2.65 * P.mm, 2.65 * P.mm), - has_thermal_vias=False, - ) - ) + pass + # TODO: specialize base uarts from CH342 base class + # uarts = times(2, F.UART) + # for uart, uart_base in zip(uarts, self.uart_base): + # uart_base.specialize(uart) + # self.add(uart) diff --git a/src/faebryk/library/CH342F_ReferenceDesign.py b/src/faebryk/library/CH342F_ReferenceDesign.py index 79eeb68c..1d46b33b 100644 --- a/src/faebryk/library/CH342F_ReferenceDesign.py +++ b/src/faebryk/library/CH342F_ReferenceDesign.py @@ -7,29 +7,22 @@ from faebryk.core.module import Module from faebryk.libs.library import L # noqa: F401 from faebryk.libs.units import P # noqa: F401 -from faebryk.libs.util import NotNone logger = logging.getLogger(__name__) class CH342F_ReferenceDesign(Module): """ - Minimal reference implementation of the CH342F + Minimal reference implementation of the CH342F. + + - Single power source (USB) + - IO at 3.3V """ # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- - ch324: F.CH342F - - def __init__( - self, - duplex_mode_uart_0: F.CH342.DuplexMode = F.CH342.DuplexMode.FULL, - duplex_mode_uart_1: F.CH342.DuplexMode = F.CH342.DuplexMode.FULL, - ) -> None: - super().__init__() - self._duplex_mode_uart_0 = duplex_mode_uart_0 - self._duplex_mode_uart_1 = duplex_mode_uart_1 + usb_uart_converter: F.CH342F def __preinit__(self): # ---------------------------------------- @@ -38,34 +31,16 @@ def __preinit__(self): # ---------------------------------------- # parametrization # ---------------------------------------- - # set the duplex mode - if self._duplex_mode_uart_0 == F.CH342.DuplexMode.HALF: - self.ch324.uart[0].dtr.get_trait(F.ElectricLogic.can_be_pulled).pull( - up=False - ) - NotNone( - self.ch324.uart[0] - .dtr.get_trait(F.ElectricLogic.has_pulls) - .get_pulls()[1] - ).resistance.merge(F.Constant(4.7 * P.kohm)) - self.ch324.tnow[0].connect(self.ch324.uart[0].dtr) - if self._duplex_mode_uart_1 == F.CH342.DuplexMode.HALF: - self.ch324.uart[1].dtr.get_trait(F.ElectricLogic.can_be_pulled).pull( - up=False - ) - NotNone( - self.ch324.uart[1] - .dtr.get_trait(F.ElectricLogic.has_pulls) - .get_pulls()[1] - ).resistance.merge(F.Constant(4.7 * P.kohm)) - self.ch324.tnow[1].connect(self.ch324.uart[1].dtr) + self.usb_uart_converter.set_power_configuration( + F.CH342.ChipPowerConfiguration.USB_5V, + F.CH342.IOPowerConfiguration.INTERNAL_3V3, + ) # ---------------------------------------- # connections # ---------------------------------------- - # configure for 3.3V GPIO operation with internal LDO - self.ch324.vdd_5v.connect(self.ch324.usb.usb_if.buspower) - self.ch324.v_3v.connect(self.ch324.v_io) - - self.ch324.vdd_5v.get_trait(F.can_be_decoupled).decouple() - self.ch324.v_3v.get_trait(F.can_be_decoupled).decouple() + self.usb_uart_converter.integrated_regulator.power_in.get_trait( + F.can_be_decoupled + ).decouple() + self.usb_uart_converter.power_3v.get_trait(F.can_be_decoupled).decouple() + self.usb_uart_converter.power_io.get_trait(F.can_be_decoupled).decouple() diff --git a/src/faebryk/library/CH342K.py b/src/faebryk/library/CH342K.py new file mode 100644 index 00000000..725dccb4 --- /dev/null +++ b/src/faebryk/library/CH342K.py @@ -0,0 +1,62 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.picker.picker import DescriptiveProperties +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class CH342K(F.CH342): + """ + USB to double Base UART converter (no modem signals) + + ESSOP-10-150mil + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + uart_base = L.list_field(2, F.UART_Base) + # ---------------------------------------- + # traits + # ---------------------------------------- + descriptive_properties = L.f_field(F.has_descriptive_properties_defined)( + { + DescriptiveProperties.manufacturer: "WCH(Jiangsu Qin Heng)", + DescriptiveProperties.partno: "CH342K", + } + ) + + @L.rt_field + def pin_association_heuristic(self): + return F.has_pin_association_heuristic_lookup_table( + mapping={ + self.power_3v.lv: ["GND"], + self.uart_base[0].rx.signal: ["RXD0"], + self.uart_base[0].tx.signal: ["TXD0"], + self.uart_base[1].rx.signal: ["RXD1"], + self.uart_base[1].tx.signal: ["TXD1"], + self.usb.usb_if.d.p: ["UD+"], + self.usb.usb_if.d.n: ["UD-"], + self.power_3v.hv: ["V3"], + self.integrated_regulator.power_in.hv: ["VDD5"], + self.power_io.hv: ["VIO"], + }, + accept_prefix=False, + case_sensitive=False, + ) + + def __preinit__(self): + # ------------------------------------ + # connections + # ------------------------------------ + + # ------------------------------------ + # parametrization + # ------------------------------------ + pass diff --git a/src/faebryk/library/CH342K_ReferenceDesign.py b/src/faebryk/library/CH342K_ReferenceDesign.py new file mode 100644 index 00000000..fe899194 --- /dev/null +++ b/src/faebryk/library/CH342K_ReferenceDesign.py @@ -0,0 +1,46 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class CH342K_ReferenceDesign(Module): + """ + Minimal reference implementation of the CH342K. + + - Single power source (USB) + - IO at 3.3V + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + usb_uart_converter: F.CH342K + + def __preinit__(self): + # ---------------------------------------- + # aliasess + # ---------------------------------------- + # ---------------------------------------- + # parametrization + # ---------------------------------------- + self.usb_uart_converter.set_power_configuration( + F.CH342.ChipPowerConfiguration.USB_5V, + F.CH342.IOPowerConfiguration.INTERNAL_3V3, + ) + + # ---------------------------------------- + # connections + # ---------------------------------------- + self.usb_uart_converter.integrated_regulator.power_in.get_trait( + F.can_be_decoupled + ).decouple() + self.usb_uart_converter.power_3v.get_trait(F.can_be_decoupled).decouple() + self.usb_uart_converter.power_io.get_trait(F.can_be_decoupled).decouple() diff --git a/src/faebryk/library/CH344.py b/src/faebryk/library/CH344.py index 42ee4d48..4bfd2f9d 100644 --- a/src/faebryk/library/CH344.py +++ b/src/faebryk/library/CH344.py @@ -6,7 +6,8 @@ import faebryk.library._F as F # noqa: F401 from faebryk.core.module import Module from faebryk.libs.library import L # noqa: F401 -from faebryk.libs.units import P # noqa: F401 +from faebryk.libs.units import P +from faebryk.libs.util import NotNone # noqa: F401 logger = logging.getLogger(__name__) @@ -19,12 +20,12 @@ class CH344(Module): # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- - usb: F.USB2_0 + usb: F.USB2_0 # TODO not a full USB, only data bus uart = L.list_field(4, F.UART) tnow = L.list_field(4, F.ElectricLogic) act: F.ElectricLogic - tx_indicator: F.ElectricLogic - rx_indicator: F.ElectricLogic + indicator_tx: F.ElectricLogic + indicator_rx: F.ElectricLogic osc = L.list_field(2, F.Electrical) reset: F.ElectricLogic test: F.ElectricLogic @@ -38,14 +39,16 @@ class CH344(Module): @L.rt_field def single_electric_reference(self): return F.has_single_electric_reference_defined( - F.ElectricLogic.connect_all_module_references(self) + NotNone(F.ElectricLogic.connect_all_module_references(self)) ) datasheet = L.f_field(F.has_datasheet_defined)( "https://wch-ic.com/downloads/CH344DS1_PDF.html" ) - designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + designator_prefix = L.f_field(F.has_designator_prefix_defined)( + F.has_designator_prefix.Prefix.U + ) def __preinit__(self): # ------------------------------------ @@ -68,9 +71,8 @@ def __preinit__(self): self.gpio[14].connect(self.uart[0].dsr) self.gpio[15].connect(self.uart[1].dcd) - self.test.pulled.pull(up=False).resistance.merge( - F.Range.from_center_rel(4.7 * P.kohm, 0.05) - ) + self.test.set_weak(on=False) + # ------------------------------------ # parametrization # ------------------------------------ diff --git a/src/faebryk/library/CH344Q.py b/src/faebryk/library/CH344Q.py index c55c13a5..000a25f0 100644 --- a/src/faebryk/library/CH344Q.py +++ b/src/faebryk/library/CH344Q.py @@ -4,9 +4,11 @@ import logging import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import ModuleException from faebryk.libs.library import L # noqa: F401 from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P # noqa: F401 +from faebryk.libs.util import assert_once # noqa: F401 logger = logging.getLogger(__name__) @@ -16,49 +18,46 @@ class CH344Q(F.CH344): Quad UART to USB bridge """ + @assert_once def enable_tnow_mode(self, uart: F.UART): """ Set TNOW mode for specified UART for use with RS485 tranceivers. The TNOW pin can be connected to the tx_enable and rx_enable pins of the RS485 tranceiver for automatic half-duplex control. """ - assert ( - uart in self.uart - ), f"{uart.get_full_name()} is not a part of the CH344Q module" + if uart not in self.uart: + raise ModuleException( + self, f"{uart.get_full_name()} is not a part of this module" + ) - uart.dtr.pulled.pull(up=False).resistance.merge( - F.Range.from_center_rel(4.7 * P.kOhm, 0.05) - ) + uart.dtr.set_weak(on=False) uart.dtr.connect(self.tnow[self.uart.index(uart)]) + @assert_once def enable_chip_default_settings(self): """ Use the chip default settings instead of the ones stored in the internal EEPROM """ - self.uart[0].rts.pulled.pull(up=False).resistance.merge( - F.Range.from_center_rel(4.7 * P.kOhm, 0.05) - ) + self.uart[0].rts.set_weak(on=False) - def enable_status_outputs(self, modem_signals: bool = False): + @assert_once + def enable_status_or_modem_signals(self, modem_signals: bool = False): """ Enable rx, tx and usb status signal outputs instead of UART modem signals. """ if modem_signals: - self.uart[3].rts.pulled.pull(up=False).resistance.merge( - F.Range.from_center_rel(4.7 * P.kOhm, 0.05) - ) + self.uart[3].rts.set_weak(on=False) return self.act.connect(self.uart[3].dcd) - self.tx_indicator.connect(self.uart[3].ri) - self.rx_indicator.connect(self.uart[3].dsr) + self.indicator_tx.connect(self.uart[3].ri) + self.indicator_rx.connect(self.uart[3].dsr) + @assert_once def enable_hardware_flow_conrol(self): """ Enable UART hardware flow control """ - self.uart[3].dcd.pulled.pull(up=False).resistance.merge( - F.Range.from_center_rel(4.7 * P.kOhm, 0.05) - ) + self.uart[3].dcd.set_weak(on=False) # TODO: check if this should just be connected to gnd as there is an # internal pull-up resistor @@ -137,9 +136,7 @@ def __preinit__(self): # ------------------------------------ # connections # ------------------------------------ - self.power.decoupled.decouple().capacitance.merge( - F.Range.from_center_rel(1 * P.uF, 0.05) - ) # TODO: per pin + # ------------------------------------ # parametrization # ------------------------------------ diff --git a/src/faebryk/library/CH344Q_ReferenceDesign.py b/src/faebryk/library/CH344Q_ReferenceDesign.py index 3c6a8510..4fb76880 100644 --- a/src/faebryk/library/CH344Q_ReferenceDesign.py +++ b/src/faebryk/library/CH344Q_ReferenceDesign.py @@ -23,9 +23,9 @@ class CH344Q_ReferenceDesign(Module): usb_uart_converter: F.CH344Q oscillator: F.Crystal_Oscillator ldo: F.LDO - rx_led = L.f_field(F.LEDIndicator)(use_mosfet=False) - tx_led = L.f_field(F.LEDIndicator)(use_mosfet=False) - act_led = L.f_field(F.LEDIndicator)(use_mosfet=False) + led_rx = L.f_field(F.LEDIndicator)(use_mosfet=False) + led_tx = L.f_field(F.LEDIndicator)(use_mosfet=False) + led_act = L.f_field(F.LEDIndicator)(use_mosfet=False) power_led: F.PoweredLED reset_lowpass: F.FilterElectricalRC @@ -45,18 +45,21 @@ def __preinit__(self): # ------------------------------------ # connections # ------------------------------------ + self.usb_uart_converter.power.decoupled.decouple().capacitance.merge( + F.Range.from_center_rel(1 * P.uF, 0.05) + ) # TODO: per pin self.vbus_fused.connect_via(self.ldo, pwr_3v3) self.usb.connect(self.usb_uart_converter.usb) - self.usb_uart_converter.act.connect(self.act_led.logic_in) - self.usb_uart_converter.rx_indicator.connect(self.rx_led.logic_in) - self.usb_uart_converter.tx_indicator.connect(self.tx_led.logic_in) + self.usb_uart_converter.act.connect(self.led_act.logic_in) + self.usb_uart_converter.indicator_rx.connect(self.led_rx.logic_in) + self.usb_uart_converter.indicator_tx.connect(self.led_tx.logic_in) pwr_3v3.connect( self.power_led.power, - self.rx_led.power_in, - self.tx_led.power_in, - self.act_led.power_in, + self.led_rx.power_in, + self.led_tx.power_in, + self.led_act.power_in, ) self.usb_uart_converter.osc[1].connect(self.oscillator.p) @@ -69,7 +72,7 @@ def __preinit__(self): # ------------------------------------ # parametrization # ------------------------------------ - self.usb_uart_converter.enable_status_outputs() + self.usb_uart_converter.enable_status_or_modem_signals() self.oscillator.crystal.frequency.merge( F.Range.from_center_rel(8 * P.MHz, 0.001) diff --git a/src/faebryk/library/DE9Connector.py b/src/faebryk/library/DE9Connector.py index 7a3ef73d..ae37c19a 100644 --- a/src/faebryk/library/DE9Connector.py +++ b/src/faebryk/library/DE9Connector.py @@ -25,7 +25,15 @@ class DE9Connector(Module): # ---------------------------------------- # traits # ---------------------------------------- - designator_prefix = L.f_field(F.has_designator_prefix_defined)("X") + designator_prefix = L.f_field(F.has_designator_prefix_defined)( + F.has_designator_prefix.Prefix.X + ) + + @L.rt_field + def can_attach_to_footprint(self): + pinmap = {f"{i+1}": ei for i, ei in enumerate(self.contact)} + pinmap.update({"10": self.shield}) + return F.can_attach_to_footprint_via_pinmap(pinmap) def __preinit__(self): # ------------------------------------ diff --git a/src/faebryk/library/DE9RS232Connector.py b/src/faebryk/library/DE9RS232Connector.py index 8f4f400d..b05b2c51 100644 --- a/src/faebryk/library/DE9RS232Connector.py +++ b/src/faebryk/library/DE9RS232Connector.py @@ -25,11 +25,6 @@ class DE9RS232Connector(Module): # ---------------------------------------- # traits # ---------------------------------------- - @L.rt_field - def can_attach_to_footprint(self): - pinmap = {f"{i+1}": ei for i, ei in enumerate(self.connector.contact)} - pinmap.update({"10": self.connector.shield}) - return F.can_attach_to_footprint_via_pinmap(pinmap) @L.rt_field def single_electric_reference(self): diff --git a/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py b/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py index cabd06a5..0fcd2730 100644 --- a/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py +++ b/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py @@ -4,7 +4,7 @@ import logging import faebryk.library._F as F # noqa: F401 -from faebryk.core.module import Module +from faebryk.core.module import Module, ModuleException from faebryk.core.parameter import Parameter from faebryk.exporters.pcb.layout.absolute import LayoutAbsolute from faebryk.exporters.pcb.layout.extrude import LayoutExtrude @@ -12,7 +12,8 @@ from faebryk.library.has_pcb_position import has_pcb_position from faebryk.libs.library import L # noqa: F401 from faebryk.libs.picker.picker import DescriptiveProperties -from faebryk.libs.units import P, Quantity # noqa: F401 +from faebryk.libs.units import P, Quantity +from faebryk.libs.util import NotNone, assert_once # noqa: F401 logger = logging.getLogger(__name__) @@ -23,31 +24,31 @@ class Diodes_Incorporated_AP2552W6_7(Module): 2.7V~5.5V 70mΩ 2.1A SOT-26 """ + @assert_once def set_current_limit(self, current: Parameter[Quantity]) -> None: self.current_limit.merge(current) - current_limit_setting_resistor = self.ilim.get_trait( - F.ElectricLogic.can_be_pulled - ).pull(up=False) + current_limit_setting_resistor = self.add(F.Resistor()) - # TODO: - # self.ilim.connect_via( - # current_limit_setting_resistor, self.power_in.lv - # ) + self.ilim.signal.connect_via( + current_limit_setting_resistor, self.ilim.reference.lv + ) # TODO: bit ugly + # TODO: # Rlim is in Kohm # current is in mA - # Rlim_min = (20.08 / (current)) ^ (1 / 0.956) * P.kohm - # Rlim_max = (20.08 / (current)) ^ (1 / 0.904) * P.kohm + # Rlim_min = (20.08 / (self.current_limit * P.mA)) ^ (1 / 0.956) * P.kohm + # Rlim_max = (20.08 / (self.current_limit * P.mA)) ^ (1 / 0.904) * P.kohm - # TODO: Rlim = Range(Rlim_min, Rlim_max) - Rlim = F.Constant(51 * P.kohm) # ~0.52A typical current limit - assert Rlim.is_subset_of( - F.Range(10 * P.kohm, 210 * P.kohm) - ), f"{self.get_full_name()} Rlim must be in the range 10kOhm to 210kOhm but is {Rlim}" # noqa: E501 + # Rlim = Range(Rlim_min, Rlim_max) + Rlim = F.Constant(51 * P.kohm) # TODO: remove: ~0.52A typical current limit + if not Rlim.is_subset_of(F.Range(10 * P.kohm, 210 * P.kohm)): + raise ModuleException( + self, + f"Rlim must be in the range 10kOhm to 210kOhm but is {Rlim.get_most_narrow()}", # noqa: E501 + ) current_limit_setting_resistor.resistance.merge(Rlim) - Rlim = F.Range(10 * P.kohm, 210 * P.kohm) # ---------------------------------------- # modules, interfaces, parameters @@ -56,7 +57,7 @@ def set_current_limit(self, current: Parameter[Quantity]) -> None: power_out: F.ElectricPower enable: F.ElectricLogic fault: F.ElectricLogic - ilim: F.ElectricLogic # TODO: hack to add resistor, should be Electrical() + ilim: F.SignalElectrical current_limit: F.TBD[Quantity] # ---------------------------------------- @@ -92,12 +93,6 @@ def pin_association_heuristic(self): def can_bridge(self): return F.can_bridge_defined(self.power_in, self.power_out) - @L.rt_field - def single_electric_reference(self): - return F.has_single_electric_reference_defined( - F.ElectricLogic.connect_all_module_references(self) - ) - @L.rt_field def has_defined_layout(self): # pcb layout @@ -127,8 +122,8 @@ def __preinit__(self): # ------------------------------------ # connections # ------------------------------------ + F.ElectricLogic.connect_all_module_references(self, exclude={self.power_out}) # ------------------------------------ # parametrization # ------------------------------------ - pass diff --git a/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py b/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py index 5f07b3f9..ba70a194 100644 --- a/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py +++ b/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py @@ -13,10 +13,22 @@ class ESP32_C3_MINI_1_ReferenceDesign(Module): """ESP32_C3_MINI_1 Module reference design""" + class DebouncedButton(Module): + button: F.Button + lp_filter: F.FilterElectricalRC + + logic_out: F.ElectricLogic + + def __preinit__(self): + self.lp_filter.in_.signal.connect_via( + self.button, self.logic_out.reference.lv + ) + self.lp_filter.cutoff_frequency.merge(F.Range(100 * P.Hz, 200 * P.Hz)) + self.lp_filter.response.merge(F.Filter.Response.LOWPASS) + esp32_c3_mini_1: F.ESP32_C3_MINI_1 - # TODO make switch debounced - boot_switch: F.Button # TODO: this cannot be picked Switch(F.Electrical) - reset_switch: F.Button # TODO: this cannot be picked Switch(F.Electrical) + boot_switch: DebouncedButton + reset_switch: DebouncedButton low_speed_crystal_clock: F.Crystal_Oscillator vdd3v3: F.ElectricPower @@ -25,18 +37,16 @@ class ESP32_C3_MINI_1_ReferenceDesign(Module): usb: F.USB2_0 def __preinit__(self): - gnd = self.vdd3v3.lv + esp32c3mini1 = self.esp32_c3_mini_1 + esp32c3 = esp32c3mini1.esp32_c3 # connect power - self.vdd3v3.connect(self.esp32_c3_mini_1.vdd3v3) + self.vdd3v3.connect(esp32c3mini1.vdd3v3) - # TODO: set default boot mode (GPIO[8] pull up with 10k resistor) + (GPIO[2] pull up with 10k resistor) # noqa: E501 - self.esp32_c3_mini_1.esp32_c3 + esp32c3.set_default_boot_mode() # boot and enable switches - # TODO: Fix bridging of (boot and reset) switches - self.esp32_c3_mini_1.chip_enable.signal.connect_via(self.boot_switch, gnd) - # TODO: lowpass chip_enable - self.esp32_c3_mini_1.gpio[9].signal.connect_via(self.reset_switch, gnd) + esp32c3mini1.chip_enable.connect(self.boot_switch.logic_out) + esp32c3mini1.gpio[9].connect(self.reset_switch.logic_out) # connect low speed crystal oscillator self.low_speed_crystal_clock.xtal_if.xin.connect( @@ -49,48 +59,38 @@ def __preinit__(self): # TODO: set the following in the pinmux # jtag gpio 4,5,6,7 - self.esp32_c3_mini_1.esp32_c3.usb.usb_if.d.n.connect( - self.esp32_c3_mini_1.esp32_c3.gpio[18].signal - ) - self.esp32_c3_mini_1.esp32_c3.usb.usb_if.d.p.connect( - self.esp32_c3_mini_1.esp32_c3.gpio[19].signal - ) + esp32c3.usb.usb_if.d.n.connect(esp32c3.gpio[18].signal) + esp32c3.usb.usb_if.d.p.connect(esp32c3.gpio[19].signal) # UART0 gpio 30/31 (default) - self.esp32_c3_mini_1.esp32_c3.uart[0].rx.connect( - self.esp32_c3_mini_1.esp32_c3.gpio[20] - ) - self.esp32_c3_mini_1.esp32_c3.uart[0].tx.connect( - self.esp32_c3_mini_1.esp32_c3.gpio[21] - ) + esp32c3.uart[0].rx.connect(esp32c3.gpio[20]) + esp32c3.uart[0].tx.connect(esp32c3.gpio[21]) # UART1 gpio 8/9 - self.esp32_c3_mini_1.esp32_c3.uart[1].rx.connect( - self.esp32_c3_mini_1.esp32_c3.gpio[8] - ) - self.esp32_c3_mini_1.esp32_c3.uart[1].tx.connect( - self.esp32_c3_mini_1.esp32_c3.gpio[7] - ) + esp32c3.uart[1].rx.connect(esp32c3.gpio[8]) + esp32c3.uart[1].tx.connect(esp32c3.gpio[9]) # i2c - self.esp32_c3_mini_1.esp32_c3.i2c.sda.connect( - self.esp32_c3_mini_1.esp32_c3.gpio[3] # default 21 + esp32c3.i2c.sda.connect( + esp32c3.gpio[3] # default 21 ) - self.esp32_c3_mini_1.esp32_c3.i2c.scl.connect( - self.esp32_c3_mini_1.esp32_c3.gpio[2] # default 22 + esp32c3.i2c.scl.connect( + esp32c3.gpio[2] # default 22 ) # connect USB - self.usb.connect(self.esp32_c3_mini_1.esp32_c3.usb) + self.usb.connect(esp32c3.usb) # connect UART[0] - self.uart.connect(self.esp32_c3_mini_1.esp32_c3.uart[0]) + self.uart.connect(esp32c3.uart[0]) # default to SPI flash boot mode - self.esp32_c3_mini_1.esp32_c3.set_default_boot_mode() + esp32c3.set_default_boot_mode() # ------------------------------------ # parametrization # ------------------------------------ - self.low_speed_crystal_clock.crystal.frequency.merge(32.768 * P.kHz) + self.low_speed_crystal_clock.crystal.frequency.merge( + F.Range.from_center_rel(32.768 * P.kHz, 0.001) + ) self.low_speed_crystal_clock.crystal.frequency_tolerance.merge( - F.Range.lower_bound(20 * P.ppm) + F.Range.lower_bound(F.Range.from_center_rel(20 * P.ppm, 0.001)) ) diff --git a/src/faebryk/library/ElectricLogic.py b/src/faebryk/library/ElectricLogic.py index 8fb7e4bd..2de6427b 100644 --- a/src/faebryk/library/ElectricLogic.py +++ b/src/faebryk/library/ElectricLogic.py @@ -104,12 +104,18 @@ def pulled(self): # functions # ---------------------------------------- def set(self, on: bool): + """ + Set the logic signal by directly connecting to the reference. + """ super().set(on) r = self.reference self.signal.connect(r.hv if on else r.lv) @assert_once def set_weak(self, on: bool): + """ + Set the logic signal by connecting to the reference via a pull resistor. + """ return self.get_trait(self.can_be_pulled).pull(up=on) def connect_shallow( diff --git a/src/faebryk/library/INA228.py b/src/faebryk/library/INA228.py index f6d132a0..f3774a0c 100644 --- a/src/faebryk/library/INA228.py +++ b/src/faebryk/library/INA228.py @@ -6,12 +6,19 @@ import faebryk.library._F as F from faebryk.core.module import Module from faebryk.libs.library import L +from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P +from faebryk.libs.util import assert_once logger = logging.getLogger(__name__) class INA228(Module): + """ + INA228 high or low side current shunt and voltage monitor with I2C interface + """ + + @assert_once def set_address(self, address: int = 0x00) -> None: """Set the I2C address of the INA228""" # allias @@ -42,8 +49,8 @@ def set_address(self, address: int = 0x00) -> None: # address looks like 0b100xxxx a1_connect, a0_connect = address_map.get(address, (gnd, gnd)) - self.address_config_pin[0].connect(a0_connect) - self.address_config_pin[1].connect(a1_connect) + self.address_config_pin[0].signal.connect(a0_connect) + self.address_config_pin[1].signal.connect(a1_connect) # ---------------------------------------- # modules, interfaces, parameters @@ -52,27 +59,47 @@ def set_address(self, address: int = 0x00) -> None: power: F.ElectricPower address_config_pin = L.list_field(2, F.ElectricLogic) alert: F.ElectricLogic - bus_voltage_sense: F.Electrical - differential_input: F.DifferentialPair + bus_voltage_sense: F.SignalElectrical + shunt_input: F.DifferentialPair # ---------------------------------------- # traits # ---------------------------------------- - designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") datasheet = L.f_field(F.has_datasheet_defined)( "https://www.ti.com/lit/ds/symlink/ina228.pdf" ) + descriptive_properties = L.f_field(F.has_descriptive_properties_defined)( + { + DescriptiveProperties.manufacturer: "Texas Instruments", + DescriptiveProperties.partno: "INA228AIDGSR", + } + ) + @L.rt_field - def single_electric_reference(self): - return F.has_single_electric_reference_defined( - F.ElectricLogic.connect_all_module_references(self) + def pin_association_heuristic(self): + return F.has_pin_association_heuristic_lookup_table( + mapping={ + self.address_config_pin[0].signal: ["A0"], + self.address_config_pin[1].signal: ["A1"], + self.alert.signal: ["ALERT"], + self.power.lv: ["GND"], + self.shunt_input.p: ["IN+"], + self.shunt_input.n: ["IN–"], + self.i2c.scl.signal: ["SCL"], + self.i2c.sda.signal: ["SDA"], + self.bus_voltage_sense.signal: ["VBUS"], + self.power.hv: ["VS"], + }, + accept_prefix=False, + case_sensitive=False, ) def __preinit__(self): # ------------------------------------ # connections # ------------------------------------ + F.ElectricLogic.connect_all_module_references(self, exclude={self.shunt_input}) # ------------------------------------ # parametrization diff --git a/src/faebryk/library/INA228_ReferenceDesign.py b/src/faebryk/library/INA228_ReferenceDesign.py index fb9d267b..eb57c50b 100644 --- a/src/faebryk/library/INA228_ReferenceDesign.py +++ b/src/faebryk/library/INA228_ReferenceDesign.py @@ -12,68 +12,94 @@ class INA228_ReferenceDesign(Module): + """ + TODO: add description + """ + + class ShuntedElectricPower(Module): + power_in: F.ElectricPower + power_out: F.ElectricPower + shunt_sense: F.DifferentialPair + + shunt: F.Resistor + + @L.rt_field + def can_bridge(self): + (F.can_bridge_defined(self.power_in, self.power_out)) + + def __init__(self, lowside: bool = False, filtered: bool = False): + super().__init__() + self._lowside = lowside + self._filtered = filtered + + def __preinit__(self): + self.shunt_sense.p.connect_via(self.shunt, self.shunt_sense.n) + if self._lowside: + self.power_in.hv.connect_via(self.shunt, self.power_out.hv) + self.power_in.lv.connect(self.power_out.lv) + else: + self.power_in.lv.connect_via(self.shunt, self.power_out.lv) + self.power_in.hv.connect(self.power_out.hv) + + # TODO: add filtered option + # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- - shunt: F.Resistor ina288: F.INA228 - pwr_load: F.ElectricPower - pwr_source: F.ElectricPower + power_load: F.ElectricPower + power_source: F.ElectricPower # ---------------------------------------- # traits # ---------------------------------------- @L.rt_field def can_bridge(self): - (F.can_bridge_defined(self.pwr_load, self.pwr_source)) - - @L.rt_field - def single_electric_reference(self): - return F.has_single_electric_reference_defined( - F.ElectricLogic.connect_all_module_references(self, gnd_only=True) - ) + (F.can_bridge_defined(self.power_load, self.power_source)) - def __init__(self, filtered: bool = False): + def __init__(self, filtered: bool = False, lowside: bool = False): super().__init__() self._filtered = filtered + self._lowside = lowside def __preinit__(self): # ---------------------------------------- # parametrization # ---------------------------------------- - self.shunt.resistance.merge(15 * P.mohm) - self.shunt.rated_power.merge(2 * P.W) + shunted_power = self.add( + L.f_field(self.ShuntedElectricPower)( + lowside=self._lowside, filtered=self._filtered + ) + ) + shunted_power.shunt.resistance.merge(F.Range.from_center_rel(15 * P.mohm, 0.01)) + shunted_power.shunt.rated_power.merge(F.Range.from_center_rel(2 * P.W, 0.01)) # TODO: calculate according to datasheet p36 - if self._filtered: - filter_cap = F.Capacitor() - filter_resistors = L.list_field(2, F.Resistor) - - filter_cap.capacitance.merge(0.1 * P.uF) - filter_cap.rated_voltage.merge(170 * P.V) - for res in filter_resistors: - res.resistance.merge(10 * P.kohm) + # TODO: add filtered option + # if self._filtered: + # filter_cap = self.add(F.Capacitor()) + # filter_resistors = L.list_field(2, F.Resistor) + # + # filter_cap.capacitance.merge(F.Range.from_center_rel(0.1 * P.uF, 0.01)) + # filter_cap.rated_voltage.merge(F.Range.from_center_rel(170 * P.V, 0.01)) + # for res in filter_resistors: + # res.resistance.merge(10 * P.kohm) # TODO: auto calculate, see: https://www.ti.com/lit/ug/tidu473/tidu473.pdf # ---------------------------------------- # connections # ---------------------------------------- - self.pwr_load.hv.connect_via(self.shunt, self.pwr_source.hv) - self.ina288.bus_voltage_sense.connect(self.pwr_load.hv) - if self._filtered: - self.pwr_load.hv.connect_via(filter_cap, self.pwr_source.hv) - self.ina288.differential_input.n.connect_via( - filter_resistors[1], self.pwr_load.hv - ) - self.ina288.differential_input.p.connect_via( - filter_resistors[0], self.pwr_source.hv - ) - else: - self.ina288.differential_input.n.connect(self.pwr_load.hv) - self.ina288.differential_input.p.connect(self.pwr_source.hv) + F.ElectricLogic.connect_all_module_references(self, gnd_only=True) + + self.power_load.connect_via(shunted_power, self.power_source) + self.ina288.bus_voltage_sense.signal.connect( + self.power_load.hv if self._lowside else self.power_load.lv + ) + + self.ina288.shunt_input.connect(shunted_power.shunt_sense) # decouple power rail self.ina288.power.get_trait(F.can_be_decoupled).decouple().capacitance.merge( - 0.1 * P.uF + F.Range.from_center_rel(0.1 * P.uF, 0.01) ) diff --git a/src/faebryk/library/ISO1540.py b/src/faebryk/library/ISO1540.py index 98164c29..d86d2416 100644 --- a/src/faebryk/library/ISO1540.py +++ b/src/faebryk/library/ISO1540.py @@ -15,7 +15,7 @@ class ISO1540(Module): """ - ISO1540 Low-Power Bidirectional I2C Isolator + Low-Power Bidirectional I2C Isolator """ class I2CandPower(ModuleInterface): @@ -31,18 +31,34 @@ class I2CandPower(ModuleInterface): # ---------------------------------------- # traits # ---------------------------------------- + designator_prefix = L.f_field(F.has_designator_prefix_defined)( + F.has_designator_prefix.Prefix.U + ) + descriptive_properties = L.f_field(F.has_descriptive_properties_defined)( + { + DescriptiveProperties.manufacturer: "Texas Instruments", + DescriptiveProperties.partno: "ISO1540DR", + } + ) datasheet = L.f_field(F.has_datasheet_defined)( "https://wmsc.lcsc.com/wmsc/upload/file/pdf/v2/lcsc/2304140030_Texas-Instruments-ISO1540DR_C179739.pdf" ) - designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") @L.rt_field - def descriptive_properties(self): - return F.has_descriptive_properties_defined( - { - DescriptiveProperties.manufacturer.value: "Texas Instruments", - DescriptiveProperties.partno: "ISO1540DR", + def pin_association_heuristic(self): + return F.has_pin_association_heuristic_lookup_table( + mapping={ + self.non_iso.power.lv: ["GND1"], + self.iso.power.lv: ["GND2"], + self.non_iso.i2c.scl.signal: ["SCL1"], + self.iso.i2c.scl.signal: ["SCL2"], + self.non_iso.i2c.sda.signal: ["SDA1"], + self.iso.i2c.sda.signal: ["SDA2"], + self.non_iso.power.hv: ["VCC1"], + self.iso.power.hv: ["VCC2"], }, + accept_prefix=False, + case_sensitive=False, ) @L.rt_field @@ -70,10 +86,3 @@ def __preinit__(self): # ------------------------------------ self.non_iso.power.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) self.iso.power.voltage.merge(F.Range(3.0 * P.V, 5.5 * P.V)) - - self.non_iso.power.decoupled.decouple().capacitance.merge( - F.Range.from_center_rel(10 * P.uF, 0.01) - ) - self.iso.power.decoupled.decouple().capacitance.merge( - F.Range.from_center_rel(10 * P.uF, 0.01) - ) diff --git a/src/faebryk/library/ISO1540_ReferenceDesign.py b/src/faebryk/library/ISO1540_ReferenceDesign.py new file mode 100644 index 00000000..9033c095 --- /dev/null +++ b/src/faebryk/library/ISO1540_ReferenceDesign.py @@ -0,0 +1,30 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class ISO1540_ReferenceDesign(Module): + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + isolator: F.ISO1540 + + # ---------------------------------------- + # traits + # ---------------------------------------- + + def __preinit__(self): + self.isolator.non_iso.power.decoupled.decouple().capacitance.merge( + F.Range.from_center_rel(10 * P.uF, 0.01) + ) + self.isolator.iso.power.decoupled.decouple().capacitance.merge( + F.Range.from_center_rel(10 * P.uF, 0.01) + ) diff --git a/src/faebryk/library/Logic.py b/src/faebryk/library/Logic.py index 8edc33ba..e4c510a0 100644 --- a/src/faebryk/library/Logic.py +++ b/src/faebryk/library/Logic.py @@ -1,12 +1,19 @@ # This file is part of the faebryk project # SPDX-License-Identifier: MIT +from enum import IntEnum + import faebryk.library._F as F from faebryk.libs.library import L class Logic(F.Signal): + class ActiveState(IntEnum): + ACTIVE_HIGH = True + ACTIVE_LOW = False + state = L.f_field(F.Range)(False, True) + active_state = L.f_field(F.Range)(ActiveState.ACTIVE_HIGH, ActiveState.ACTIVE_LOW) def set(self, on: bool): self.state.merge(on) diff --git a/src/faebryk/library/PowerMux.py b/src/faebryk/library/PowerMux.py index c2f83ec7..0920d1ad 100644 --- a/src/faebryk/library/PowerMux.py +++ b/src/faebryk/library/PowerMux.py @@ -14,4 +14,10 @@ class PowerMux(Module): power_in = L.list_field(2, F.ElectricPower) power_out: F.ElectricPower - select: F.ElectricLogic + select: F.SignalElectrical + + def __preinit__(self): + # TODO: this will also connect the power_ins to each other + # self.power_in[0].connect_shallow(self.power_out) + # self.power_in[1].connect_shallow(self.power_out) + ... diff --git a/src/faebryk/library/SP3243E.py b/src/faebryk/library/SP3243E.py index e942231e..19c3fd13 100644 --- a/src/faebryk/library/SP3243E.py +++ b/src/faebryk/library/SP3243E.py @@ -111,20 +111,6 @@ def __preinit__(self): # ------------------------------------ # connections # ------------------------------------ - for pwr in self.get_children(direct_only=True, types=F.ElectricPower): - cap = pwr.decoupled.decouple() - # TODO: min values according to self.power.voltage - # 3.0V to 3.6V > C_all = 0.1μF - # 4.5V to 5.5V > C1 = 0.047µF, C2,Cvp, Cvn = 0.33µF - # 3.0V to 5.5V > C_all = 0.22μF - # - cap.capacitance.merge(F.Range.from_center(0.22 * P.uF, 0.22 * 0.05 * P.uF)) - if isinstance(pwr.voltage.get_most_narrow(), F.TBD): - pwr.voltage.merge( - F.Constant(8 * P.V) - # F.Range.lower_bound(16 * P.V) - ) # TODO: fix in merge - # TODO: merge conflict # ------------------------------------ # parametrization diff --git a/src/faebryk/library/SP3243E_ReferenceDesign.py b/src/faebryk/library/SP3243E_ReferenceDesign.py new file mode 100644 index 00000000..afe106c1 --- /dev/null +++ b/src/faebryk/library/SP3243E_ReferenceDesign.py @@ -0,0 +1,46 @@ +# This file is part of the faebryk project +# SPDX-License-Identifier: MIT + +import logging + +import faebryk.library._F as F # noqa: F401 +from faebryk.core.module import Module +from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.units import P # noqa: F401 + +logger = logging.getLogger(__name__) + + +class SP3243E_ReferenceDesign(Module): + """ + Reference design for the SP3243E RS232 transceiver. + """ + + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + sp3243e: F.SP3243E + + # ---------------------------------------- + # traits + # ---------------------------------------- + + def __preinit__(self): + # ---------------------------------------- + # connections + # ---------------------------------------- + for pwr in self.get_children(direct_only=True, types=F.ElectricPower): + cap = pwr.decoupled.decouple() + # TODO: min values according to self.power.voltage + # 3.0V to 3.6V > C_all = 0.1μF + # 4.5V to 5.5V > C1 = 0.047µF, C2,Cvp, Cvn = 0.33µF + # 3.0V to 5.5V > C_all = 0.22μF + # + cap.capacitance.merge(F.Range.from_center(0.22 * P.uF, 0.22 * 0.05 * P.uF)) + + if isinstance(pwr.voltage.get_most_narrow(), F.TBD): + pwr.voltage.merge( + F.Constant(8 * P.V) + # F.Range.lower_bound(16 * P.V) + ) # TODO: fix merge + # TODO: merge conflict diff --git a/src/faebryk/library/TPS2116.py b/src/faebryk/library/TPS2116.py index 0cd66c19..8acce271 100644 --- a/src/faebryk/library/TPS2116.py +++ b/src/faebryk/library/TPS2116.py @@ -5,6 +5,7 @@ import faebryk.library._F as F # noqa: F401 from faebryk.libs.library import L # noqa: F401 +from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P # noqa: F401 logger = logging.getLogger(__name__) @@ -12,39 +13,55 @@ class TPS2116(F.PowerMux): """ - 2to1 1.6 V to 5.5 V, 2.5-A Low IQ Power Mux with Manual and Priority Switchover + 2 to 1 1.6 V to 5.5 V, 2.5-A Low IQ Power Mux with Manual and Priority Switchover """ # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- - power_in = L.list_field(2, F.ElectricPower) - power_out: F.ElectricPower - select: F.Electrical mode: F.ElectricLogic status: F.ElectricLogic # ---------------------------------------- # traits # ---------------------------------------- - designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") - + designator_prefix = L.f_field(F.has_designator_prefix_defined)( + F.has_designator_prefix.Prefix.U + ) + descriptive_properties = L.f_field(F.has_descriptive_properties_defined)( + { + DescriptiveProperties.manufacturer: "Texas Instruments", + DescriptiveProperties.partno: "TPS2116DRLR", + } + ) datasheet = L.f_field(F.has_datasheet_defined)( "https://www.ti.com/lit/ds/symlink/tps2116.pdf" ) @L.rt_field - def single_electric_reference(self): - return F.has_single_electric_reference_defined( - F.ElectricLogic.connect_all_module_references(self, gnd_only=True) + def pin_association_heuristic(self): + return F.has_pin_association_heuristic_lookup_table( + mapping={ + self.power_in[0].lv: ["GND"], + self.mode.signal: ["MODE"], + self.select.signal: ["PR1"], + self.status.signal: ["ST"], + self.power_in[0].hv: ["VIN1"], + self.power_in[1].hv: ["VIN2"], + self.power_out.hv: ["VOUT"], + }, + accept_prefix=False, + case_sensitive=False, ) def __preinit__(self): # ------------------------------------ # connections # ------------------------------------ - self.power_in[0].connect_shallow(self.power_out) - self.power_in[1].connect_shallow(self.power_out) + F.ElectricLogic.connect_all_module_references(self, gnd_only=True) + F.ElectricLogic.connect_all_module_references( + self, exclude=[self.power_out, self.power_in[1]] + ) # ------------------------------------ # parametrization diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index a58cfad9..906d1f5f 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -21,6 +21,8 @@ from faebryk.library.has_esphome_config import has_esphome_config from faebryk.library.is_esphome_bus import is_esphome_bus from faebryk.library.has_pcb_position import has_pcb_position +from faebryk.library.has_designator_prefix import has_designator_prefix +from faebryk.library.has_single_electric_reference import has_single_electric_reference from faebryk.library.Power import Power from faebryk.library.Signal import Signal from faebryk.library.has_construction_dependency import has_construction_dependency @@ -29,10 +31,8 @@ from faebryk.library.has_overriden_name import has_overriden_name from faebryk.library.Operation import Operation from faebryk.library.has_linked_pad import has_linked_pad -from faebryk.library.has_single_electric_reference import has_single_electric_reference from faebryk.library.can_bridge import can_bridge from faebryk.library.has_designator import has_designator -from faebryk.library.has_designator_prefix import has_designator_prefix from faebryk.library.has_descriptive_properties import has_descriptive_properties from faebryk.library.has_simple_value_representation import has_simple_value_representation from faebryk.library.has_capacitance import has_capacitance @@ -53,15 +53,15 @@ from faebryk.library.has_pcb_position_defined import has_pcb_position_defined from faebryk.library.has_pcb_position_defined_relative import has_pcb_position_defined_relative from faebryk.library.has_pcb_position_defined_relative_to_parent import has_pcb_position_defined_relative_to_parent +from faebryk.library.has_designator_prefix_defined import has_designator_prefix_defined +from faebryk.library.has_single_electric_reference_defined import has_single_electric_reference_defined from faebryk.library.Filter import Filter from faebryk.library.Logic import Logic from faebryk.library.Footprint import Footprint from faebryk.library.has_overriden_name_defined import has_overriden_name_defined from faebryk.library.has_linked_pad_defined import has_linked_pad_defined -from faebryk.library.has_single_electric_reference_defined import has_single_electric_reference_defined from faebryk.library.can_bridge_defined import can_bridge_defined from faebryk.library.has_designator_defined import has_designator_defined -from faebryk.library.has_designator_prefix_defined import has_designator_prefix_defined from faebryk.library.has_descriptive_properties_defined import has_descriptive_properties_defined from faebryk.library.has_simple_value_representation_based_on_params import has_simple_value_representation_based_on_params from faebryk.library.has_simple_value_representation_defined import has_simple_value_representation_defined @@ -73,6 +73,12 @@ from faebryk.library.is_representable_by_single_value_defined import is_representable_by_single_value_defined from faebryk.library.XtalIF import XtalIF from faebryk.library.has_pin_association_heuristic import has_pin_association_heuristic +from faebryk.library.Common_Mode_Filter import Common_Mode_Filter +from faebryk.library.Crystal import Crystal +from faebryk.library.Header import Header +from faebryk.library.PJ398SM import PJ398SM +from faebryk.library.RJ45_Receptacle import RJ45_Receptacle +from faebryk.library.Relay import Relay from faebryk.library.LogicOps import LogicOps from faebryk.library.can_attach_to_footprint import can_attach_to_footprint from faebryk.library.can_attach_via_pinmap import can_attach_via_pinmap @@ -80,14 +86,9 @@ from faebryk.library.has_kicad_footprint import has_kicad_footprint from faebryk.library.Pad import Pad from faebryk.library.Button import Button -from faebryk.library.Common_Mode_Filter import Common_Mode_Filter -from faebryk.library.Crystal import Crystal -from faebryk.library.DE9Connector import DE9Connector from faebryk.library.GDT import GDT -from faebryk.library.Header import Header -from faebryk.library.PJ398SM import PJ398SM -from faebryk.library.RJ45_Receptacle import RJ45_Receptacle -from faebryk.library.Relay import Relay +from faebryk.library.Ethernet import Ethernet +from faebryk.library.RS485 import RS485 from faebryk.library.has_pin_association_heuristic_lookup_table import has_pin_association_heuristic_lookup_table from faebryk.library.LogicGate import LogicGate from faebryk.library.has_footprint_defined import has_footprint_defined @@ -115,6 +116,8 @@ from faebryk.library.Resistor import Resistor from faebryk.library.Switch import Switch from faebryk.library.B4B_ZR_SM4_TF import B4B_ZR_SM4_TF +from faebryk.library.DE9Connector import DE9Connector +from faebryk.library.USB_Type_C_Receptacle_24_pin import USB_Type_C_Receptacle_24_pin from faebryk.library.pf_533984002 import pf_533984002 from faebryk.library.DIP import DIP from faebryk.library.QFN import QFN @@ -134,9 +137,6 @@ from faebryk.library.Resistor_Voltage_Divider import Resistor_Voltage_Divider from faebryk.library.is_surge_protected_defined import is_surge_protected_defined from faebryk.library.is_decoupled_nodes import is_decoupled_nodes -from faebryk.library.Ethernet import Ethernet -from faebryk.library.RS485 import RS485 -from faebryk.library.USB_Type_C_Receptacle_24_pin import USB_Type_C_Receptacle_24_pin from faebryk.library.can_be_surge_protected_defined import can_be_surge_protected_defined from faebryk.library.can_be_decoupled_defined import can_be_decoupled_defined from faebryk.library.ElectricPower import ElectricPower @@ -155,6 +155,7 @@ from faebryk.library.ElectricLogic import ElectricLogic from faebryk.library.FilterElectricalLC import FilterElectricalLC from faebryk.library.FilterElectricalRC import FilterElectricalRC +from faebryk.library.PowerMux import PowerMux from faebryk.library.Diodes_Incorporated_AP2552W6_7 import Diodes_Incorporated_AP2552W6_7 from faebryk.library.ElectricLogicGate import ElectricLogicGate from faebryk.library.GenericBusProtection import GenericBusProtection @@ -163,7 +164,6 @@ from faebryk.library.LDO import LDO from faebryk.library.MultiSPI import MultiSPI from faebryk.library.Pinmux import Pinmux -from faebryk.library.PowerMux import PowerMux from faebryk.library.RS232 import RS232 from faebryk.library.SK9822_EC20 import SK9822_EC20 from faebryk.library.SNx4LVC541A import SNx4LVC541A @@ -176,6 +176,7 @@ from faebryk.library.XL_3528RGBW_WS2812B import XL_3528RGBW_WS2812B from faebryk.library.can_switch_power import can_switch_power from faebryk.library.pf_74AHCT2G125 import pf_74AHCT2G125 +from faebryk.library.TPS2116 import TPS2116 from faebryk.library.ElectricLogicGates import ElectricLogicGates from faebryk.library.Logic74xx import Logic74xx from faebryk.library.BH1750FVI_TR import BH1750FVI_TR @@ -191,7 +192,6 @@ from faebryk.library.ME6211C33M5G_N import ME6211C33M5G_N from faebryk.library.SPIFlash import SPIFlash from faebryk.library.RP2040Pinmux import RP2040Pinmux -from faebryk.library.TPS2116 import TPS2116 from faebryk.library.DE9RS232Connector import DE9RS232Connector from faebryk.library.SWDConnector import SWDConnector from faebryk.library.HLK_LD2410B_P import HLK_LD2410B_P @@ -207,6 +207,7 @@ from faebryk.library.Winbond_Elec_W25Q128JVSIQ import Winbond_Elec_W25Q128JVSIQ from faebryk.library.RP2040 import RP2040 from faebryk.library.INA228_ReferenceDesign import INA228_ReferenceDesign +from faebryk.library.ISO1540_ReferenceDesign import ISO1540_ReferenceDesign from faebryk.library.SP3243E import SP3243E from faebryk.library.CBM9002A_56ILG import CBM9002A_56ILG from faebryk.library.CH340x import CH340x @@ -222,9 +223,11 @@ from faebryk.library.PowerSwitch import PowerSwitch from faebryk.library.TI_CD4011BE import TI_CD4011BE from faebryk.library.RP2040_ReferenceDesign import RP2040_ReferenceDesign +from faebryk.library.SP3243E_ReferenceDesign import SP3243E_ReferenceDesign from faebryk.library.CBM9002A_56ILG_ReferenceDesign import CBM9002A_56ILG_ReferenceDesign from faebryk.library.USB_RS485 import USB_RS485 from faebryk.library.CH342F import CH342F +from faebryk.library.CH342K import CH342K from faebryk.library.CH344Q import CH344Q from faebryk.library.ESP32_C3_MINI_1 import ESP32_C3_MINI_1 from faebryk.library.USB_C_PSU_Vertical import USB_C_PSU_Vertical @@ -233,6 +236,7 @@ from faebryk.library.PowerSwitchMOSFET import PowerSwitchMOSFET from faebryk.library.PowerSwitchStatic import PowerSwitchStatic from faebryk.library.CH342F_ReferenceDesign import CH342F_ReferenceDesign +from faebryk.library.CH342K_ReferenceDesign import CH342K_ReferenceDesign from faebryk.library.ESP32_C3_MINI_1_ReferenceDesign import ESP32_C3_MINI_1_ReferenceDesign from faebryk.library.USB_C_5V_PSU import USB_C_5V_PSU from faebryk.library.USB_C_PowerOnly import USB_C_PowerOnly From 5e443b005d44c557c288a72b6a15d3319e48b2b0 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Sun, 15 Sep 2024 18:30:38 +0200 Subject: [PATCH 23/27] Fix more modules. revert assert_once (it's broken) --- .../library/CBM9002A_56ILG_ReferenceDesign.py | 2 +- src/faebryk/library/CH342.py | 2 +- src/faebryk/library/CH342F.py | 4 +- src/faebryk/library/CH344Q.py | 8 +- src/faebryk/library/CH344Q_ReferenceDesign.py | 6 +- .../library/Diodes_Incorporated_AP2552W6_7.py | 4 +- .../ESP32_C3_MINI_1_ReferenceDesign.py | 2 +- src/faebryk/library/ElectricLogic.py | 2 - src/faebryk/library/ElectricPower.py | 1 - src/faebryk/library/INA228.py | 3 +- src/faebryk/library/RP2040_ReferenceDesign.py | 9 +- src/faebryk/library/SignalElectrical.py | 9 +- src/faebryk/library/USB2514B.py | 338 +++++++++++++----- .../library/USB2514B_ReferenceDesign.py | 79 ++-- src/faebryk/library/_F.py | 20 +- test/library/nodes/test_electricpower.py | 1 - 16 files changed, 334 insertions(+), 156 deletions(-) diff --git a/src/faebryk/library/CBM9002A_56ILG_ReferenceDesign.py b/src/faebryk/library/CBM9002A_56ILG_ReferenceDesign.py index 1d44afa5..9a853bcf 100644 --- a/src/faebryk/library/CBM9002A_56ILG_ReferenceDesign.py +++ b/src/faebryk/library/CBM9002A_56ILG_ReferenceDesign.py @@ -82,5 +82,5 @@ def __preinit__(self): F.Range.from_center_rel(24 * P.Mhertz, 0.05) ) self.oscillator.crystal.frequency_tolerance.merge( - F.Range.upper_bound(20 * P.ppm) + F.Range(0 * P.ppm, 20 * P.ppm) ) diff --git a/src/faebryk/library/CH342.py b/src/faebryk/library/CH342.py index 6c6d03fe..2cc5e0d2 100644 --- a/src/faebryk/library/CH342.py +++ b/src/faebryk/library/CH342.py @@ -48,7 +48,7 @@ class ChipPowerConfiguration(Enum): EXTERNAL_3V3 = auto() """Chip powered by an external 3.3V source""" - @assert_once + # @assert_once TODO: this breaks when we use both CH342F and CH342K in 1 design def set_power_configuration( self, chip_power_configuration: ChipPowerConfiguration = ChipPowerConfiguration.USB_5V, # noqa: E501 diff --git a/src/faebryk/library/CH342F.py b/src/faebryk/library/CH342F.py index 06fa117d..417c2141 100644 --- a/src/faebryk/library/CH342F.py +++ b/src/faebryk/library/CH342F.py @@ -7,7 +7,7 @@ from faebryk.core.module import ModuleException from faebryk.libs.library import L # noqa: F401 from faebryk.libs.picker.picker import DescriptiveProperties -from faebryk.libs.util import assert_once, times +from faebryk.libs.util import times logger = logging.getLogger(__name__) @@ -19,7 +19,7 @@ class CH342F(F.CH342): QFN-24-EP(4x4) """ - @assert_once + # @assert_once TODO: broken def enable_tnow_mode(self, uart: F.UART): """ Set TNOW mode for specified UART for use with RS485 tranceivers. diff --git a/src/faebryk/library/CH344Q.py b/src/faebryk/library/CH344Q.py index 000a25f0..567597bc 100644 --- a/src/faebryk/library/CH344Q.py +++ b/src/faebryk/library/CH344Q.py @@ -18,7 +18,7 @@ class CH344Q(F.CH344): Quad UART to USB bridge """ - @assert_once + # @assert_once TODO: broken def enable_tnow_mode(self, uart: F.UART): """ Set TNOW mode for specified UART for use with RS485 tranceivers. @@ -33,14 +33,14 @@ def enable_tnow_mode(self, uart: F.UART): uart.dtr.set_weak(on=False) uart.dtr.connect(self.tnow[self.uart.index(uart)]) - @assert_once + # @assert_once TODO: broken def enable_chip_default_settings(self): """ Use the chip default settings instead of the ones stored in the internal EEPROM """ self.uart[0].rts.set_weak(on=False) - @assert_once + # @assert_once TODO: broken def enable_status_or_modem_signals(self, modem_signals: bool = False): """ Enable rx, tx and usb status signal outputs instead of UART modem signals. @@ -52,7 +52,7 @@ def enable_status_or_modem_signals(self, modem_signals: bool = False): self.indicator_tx.connect(self.uart[3].ri) self.indicator_rx.connect(self.uart[3].dsr) - @assert_once + # @assert_once TODO: broken def enable_hardware_flow_conrol(self): """ Enable UART hardware flow control diff --git a/src/faebryk/library/CH344Q_ReferenceDesign.py b/src/faebryk/library/CH344Q_ReferenceDesign.py index 4fb76880..c9ed22a4 100644 --- a/src/faebryk/library/CH344Q_ReferenceDesign.py +++ b/src/faebryk/library/CH344Q_ReferenceDesign.py @@ -62,9 +62,9 @@ def __preinit__(self): self.led_act.power_in, ) - self.usb_uart_converter.osc[1].connect(self.oscillator.p) - self.usb_uart_converter.osc[0].connect(self.oscillator.n) - self.oscillator.power.connect(pwr_3v3) + self.usb_uart_converter.osc[1].connect(self.oscillator.xtal_if.xin) + self.usb_uart_converter.osc[0].connect(self.oscillator.xtal_if.xout) + self.oscillator.gnd.connect(pwr_3v3.lv) self.reset_lowpass.out.connect(self.usb_uart_converter.reset) self.usb_uart_converter.reset.pulled.pull(up=True) diff --git a/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py b/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py index 0fcd2730..7fb27100 100644 --- a/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py +++ b/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py @@ -13,7 +13,7 @@ from faebryk.libs.library import L # noqa: F401 from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P, Quantity -from faebryk.libs.util import NotNone, assert_once # noqa: F401 +from faebryk.libs.util import assert_once # noqa: F401 logger = logging.getLogger(__name__) @@ -24,7 +24,7 @@ class Diodes_Incorporated_AP2552W6_7(Module): 2.7V~5.5V 70mΩ 2.1A SOT-26 """ - @assert_once + # @assert_once TODO: broken def set_current_limit(self, current: Parameter[Quantity]) -> None: self.current_limit.merge(current) diff --git a/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py b/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py index ba70a194..32158062 100644 --- a/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py +++ b/src/faebryk/library/ESP32_C3_MINI_1_ReferenceDesign.py @@ -92,5 +92,5 @@ def __preinit__(self): F.Range.from_center_rel(32.768 * P.kHz, 0.001) ) self.low_speed_crystal_clock.crystal.frequency_tolerance.merge( - F.Range.lower_bound(F.Range.from_center_rel(20 * P.ppm, 0.001)) + F.Range(0 * P.ppm, 20 * P.ppm) ) diff --git a/src/faebryk/library/ElectricLogic.py b/src/faebryk/library/ElectricLogic.py index 2de6427b..a0733cf2 100644 --- a/src/faebryk/library/ElectricLogic.py +++ b/src/faebryk/library/ElectricLogic.py @@ -8,7 +8,6 @@ import faebryk.library._F as F from faebryk.libs.library import L -from faebryk.libs.util import assert_once class ElectricLogic(F.SignalElectrical, F.Logic): @@ -111,7 +110,6 @@ def set(self, on: bool): r = self.reference self.signal.connect(r.hv if on else r.lv) - @assert_once def set_weak(self, on: bool): """ Set the logic signal by connecting to the reference via a pull resistor. diff --git a/src/faebryk/library/ElectricPower.py b/src/faebryk/library/ElectricPower.py index 657c4aec..5eab1ecb 100644 --- a/src/faebryk/library/ElectricPower.py +++ b/src/faebryk/library/ElectricPower.py @@ -74,7 +74,6 @@ def fused(self, attach_to: Node | None = None): fused_power.lv.connect(self.lv) fused_power.voltage.merge(self.voltage) - fused_power.max_current.merge(self.max_current) if attach_to is not None: attach_to.add(fused_power) diff --git a/src/faebryk/library/INA228.py b/src/faebryk/library/INA228.py index f3774a0c..c5ecbe5d 100644 --- a/src/faebryk/library/INA228.py +++ b/src/faebryk/library/INA228.py @@ -8,7 +8,6 @@ from faebryk.libs.library import L from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P -from faebryk.libs.util import assert_once logger = logging.getLogger(__name__) @@ -18,7 +17,7 @@ class INA228(Module): INA228 high or low side current shunt and voltage monitor with I2C interface """ - @assert_once + # @assert_once TODO: broken def set_address(self, address: int = 0x00) -> None: """Set the I2C address of the INA228""" # allias diff --git a/src/faebryk/library/RP2040_ReferenceDesign.py b/src/faebryk/library/RP2040_ReferenceDesign.py index 4b577c7e..41fbb68b 100644 --- a/src/faebryk/library/RP2040_ReferenceDesign.py +++ b/src/faebryk/library/RP2040_ReferenceDesign.py @@ -3,15 +3,14 @@ import logging -from tmp.faebryk.src.faebryk.exporters.pcb.layout.heuristic_decoupling import ( +import faebryk.library._F as F +from faebryk.core.module import Module +from faebryk.exporters.pcb.layout.heuristic_decoupling import ( LayoutHeuristicElectricalClosenessDecouplingCaps, ) -from tmp.faebryk.src.faebryk.exporters.pcb.layout.heuristic_pulls import ( +from faebryk.exporters.pcb.layout.heuristic_pulls import ( LayoutHeuristicElectricalClosenessPullResistors, ) - -import faebryk.library._F as F -from faebryk.core.module import Module from faebryk.libs.library import L from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P diff --git a/src/faebryk/library/SignalElectrical.py b/src/faebryk/library/SignalElectrical.py index e782d7de..780fa2bd 100644 --- a/src/faebryk/library/SignalElectrical.py +++ b/src/faebryk/library/SignalElectrical.py @@ -61,10 +61,15 @@ def connect_all_node_references( @classmethod def connect_all_module_references( - cls, node: Module | ModuleInterface, gnd_only=False + cls, + node: Module | ModuleInterface, + gnd_only=False, + exclude: Iterable[Node] = (), ) -> F.ElectricPower: return cls.connect_all_node_references( - node.get_children(direct_only=True, types=(Module, ModuleInterface)), + node.get_children( + direct_only=True, types=(Module, ModuleInterface) + ).difference(set(exclude)), gnd_only=gnd_only, ) diff --git a/src/faebryk/library/USB2514B.py b/src/faebryk/library/USB2514B.py index 81f1d6c5..36a851e3 100644 --- a/src/faebryk/library/USB2514B.py +++ b/src/faebryk/library/USB2514B.py @@ -5,124 +5,282 @@ from enum import Enum, auto import faebryk.library._F as F -from faebryk.core.module import Module +from faebryk.core.module import Module, ModuleException from faebryk.libs.library import L +from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P +# from faebryk.libs.util import assert_once + logger = logging.getLogger(__name__) class USB2514B(Module): - class InterfaceConfiguration(Enum): + class ConfigurableUSB(Module): + """ + USB port wrapper with configuration pins and power enable pin. + """ + + usb: F.USB2_0_IF.Data + usb_power_enable: F.ElectricLogic + usb_port_disable_p: F.ElectricLogic + usb_port_disable_n: F.ElectricLogic + over_current_sense: F.ElectricLogic + battery_charging_enable: F.ElectricLogic + + class ConfigurationSource(Enum): DEFAULT = auto() - SMBUS = auto() + """ + - Strap options enabled + - Self-powered operation enabled + - Individual power switching + - Individual over-current sensing + """ BUS_POWERED = auto() + """ + Default configuration with the following overrides: + - Bus-powered operation + """ + SMBUS = auto() + """" + The hub is configured externally over SMBus (as an SMBus slave device): + - Strap options disabled + - All registers configured over SMBus + """ EEPROM = auto() + """ + The hub is configured over 2-wire I2C EEPROM: + - Strap options disabled + - All registers configured by I2C EEPROM + """ + + # @assert_once + def set_configuration_source( + self, + configuration_source: ConfigurationSource = ConfigurationSource.DEFAULT, + ): + """ + Set the source of configuration settings for the USB2514B. + """ + if configuration_source == USB2514B.ConfigurationSource.DEFAULT: + self.configuration_source_input[0].pulled.pull(up=False) + self.configuration_source_input[1].pulled.pull(up=False) + elif configuration_source == USB2514B.ConfigurationSource.BUS_POWERED: + self.configuration_source_input[0].pulled.pull(up=False) + self.configuration_source_input[1].pulled.pull(up=True) + elif configuration_source == USB2514B.ConfigurationSource.SMBUS: + self.configuration_source_input[0].pulled.pull(up=True) + self.configuration_source_input[1].pulled.pull(up=False) + elif configuration_source == USB2514B.ConfigurationSource.EEPROM: + self.configuration_source_input[0].pulled.pull(up=True) + self.configuration_source_input[1].pulled.pull(up=True) class NonRemovablePortConfiguration(Enum): ALL_PORTS_REMOVABLE = auto() - PORT_1_NOT_REMOVABLE = auto() - PORT_1_2_NOT_REMOVABLE = auto() - PORT_1_2_3_NOT_REMOVABLE = auto() - - VDD33: F.ElectricPower - VDDA33: F.ElectricPower + PORT_0_NOT_REMOVABLE = auto() + PORT_0_1_NOT_REMOVABLE = auto() + PORT_0_1_2_NOT_REMOVABLE = auto() - PLLFILT: F.ElectricPower - CRFILT: F.ElectricPower + # @assert_once + def set_non_removable_ports( + self, + non_removable_port_configuration: NonRemovablePortConfiguration, + ): + """ + Set the non-removable port configuration of the USB2514. + """ + if ( + non_removable_port_configuration + == USB2514B.NonRemovablePortConfiguration.ALL_PORTS_REMOVABLE + ): + self.usb_removability_configuration_intput[0].set_weak(on=False) + self.usb_removability_configuration_intput[1].set_weak(on=False) + elif ( + non_removable_port_configuration + == USB2514B.NonRemovablePortConfiguration.PORT_0_NOT_REMOVABLE + ): + self.usb_removability_configuration_intput[0].set_weak(on=True) + self.usb_removability_configuration_intput[1].set_weak(on=False) + elif ( + non_removable_port_configuration + == USB2514B.NonRemovablePortConfiguration.PORT_0_1_NOT_REMOVABLE + ): + self.usb_removability_configuration_intput[0].set_weak(on=False) + self.usb_removability_configuration_intput[1].set_weak(on=True) + elif ( + non_removable_port_configuration + == USB2514B.NonRemovablePortConfiguration.PORT_0_1_2_NOT_REMOVABLE + ): + self.usb_removability_configuration_intput[0].set_weak(on=True) + self.usb_removability_configuration_intput[1].set_weak(on=True) - VBUS_DET: F.Electrical + # @assert_once # TODO: this function can be called 1ce per port + def configure_usb_port( + self, + usb_port: ConfigurableUSB, + enable_usb: bool = True, + enable_battery_charging: bool = True, + ): + """ + Configure the specified USB port. + """ + if usb_port not in self.configurable_downstream_usb: + raise ModuleException( + self, f"{usb_port.get_full_name()} is not part of this module" + ) - usb_downstream = L.list_field(4, F.DifferentialPair) - usb_upstream: F.DifferentialPair + # enable/disable usb port + if not enable_usb: + usb_port.usb_port_disable_p.set_weak(on=True) + usb_port.usb_port_disable_n.set_weak(on=True) - XTALIN: F.Electrical - XTALOUT: F.Electrical + # enable/disable battery charging + if not enable_battery_charging: + usb_port.battery_charging_enable.set_weak(on=False) - TEST: F.Electrical - SUSP_IND: F.ElectricLogic - RESET_N: F.Electrical - RBIAS: F.Electrical - NON_REM = L.list_field(2, F.ElectricLogic) - LOCAL_PWR: F.Electrical - CLKIN: F.Electrical - CFG_SEL = L.list_field(2, F.ElectricLogic) + # ---------------------------------------- + # modules, interfaces, parameters + # ---------------------------------------- + power_3v3: F.ElectricPower + power_3v3_analog: F.ElectricPower + power_pll: F.ElectricPower + power_core: F.ElectricPower - HS_IND: F.ElectricLogic + usb_upstream: F.USB2_0_IF.Data - PRTPWR = L.list_field(4, F.ElectricLogic) - PRT_DIS_P = L.list_field(4, F.ElectricLogic) - PRT_DIS_M = L.list_field(4, F.ElectricLogic) - OCS_N = L.list_field(4, F.ElectricLogic) - BC_EN = L.list_field(4, F.ElectricLogic) + xtal_if: F.XtalIF + external_clock_input: F.ElectricLogic - i2c: F.I2C - gnd: F.Electrical + usb_bias_resistor_input: F.SignalElectrical + vbus_detect: F.SignalElectrical - interface_configuration: F.TBD[InterfaceConfiguration] - non_removable_port_configuration: F.TBD[NonRemovablePortConfiguration] + test: F.Electrical + reset: F.ElectricLogic + local_power_detection: F.SignalElectrical - designator_prefix = L.f_field(F.has_designator_prefix_defined)("U") + usb_removability_configuration_intput = L.list_field(2, F.ElectricLogic) + configuration_source_input = L.list_field(2, F.ElectricLogic) - def __preinit__(self): - if self.interface_configuration == USB2514B.InterfaceConfiguration.DEFAULT: - self.CFG_SEL[0].pulled.pull(up=False) - self.CFG_SEL[1].pulled.pull(up=False) - elif self.interface_configuration == USB2514B.InterfaceConfiguration.SMBUS: - self.CFG_SEL[0].pulled.pull(up=True) - self.CFG_SEL[1].pulled.pull(up=False) - elif ( - self.interface_configuration == USB2514B.InterfaceConfiguration.BUS_POWERED - ): - self.CFG_SEL[0].pulled.pull(up=False) - self.CFG_SEL[1].pulled.pull(up=True) - elif self.interface_configuration == USB2514B.InterfaceConfiguration.EEPROM: - self.CFG_SEL[0].pulled.pull(up=True) - self.CFG_SEL[1].pulled.pull(up=True) + suspense_indicator: F.ElectricLogic + high_speed_upstream_indicator: F.ElectricLogic - # Add decoupling capacitors to power pins and connect all lv to gnd - # TODO: decouple with 1.0uF and 0.1uF and maybe 4.7uF - for g in self.get_children(direct_only=True, types=F.ElectricPower): - g.decoupled.decouple() - g.lv.connect(self.gnd) + configurable_downstream_usb = L.list_field(4, ConfigurableUSB) - x = self + i2c: F.I2C - x.CFG_SEL[0].connect(x.i2c.scl) - x.CFG_SEL[1].connect(x.HS_IND) - x.NON_REM[0].connect(x.SUSP_IND) - x.NON_REM[1].connect(x.i2c.sda) + # ---------------------------------------- + # traits + # ---------------------------------------- + designator_prefix = L.f_field(F.has_designator_prefix_defined)( + F.has_designator_prefix.Prefix.U + ) + descriptive_properties = L.f_field(F.has_descriptive_properties_defined)( + { + DescriptiveProperties.manufacturer: "Microchip Tech", + DescriptiveProperties.partno: "USB2514B-AEZC-TR", + } + ) + datasheet = L.f_field(F.has_datasheet_defined)( + "https://ww1.microchip.com/downloads/aemDocuments/documents/UNG/ProductDocuments/DataSheets/USB251xB-xBi-Data-Sheet-DS00001692.pdf" + ) - x.RESET_N.connect(self.gnd) + @L.rt_field + def pin_association_heuristic(self): + return F.has_pin_association_heuristic_lookup_table( + mapping={ + self.power_core.hv: ["CRFILT"], + self.power_core.lv: ["EP"], + self.configuration_source_input[1].signal: ["HS_IND/CFG_SEL1"], + self.configurable_downstream_usb[0].over_current_sense.signal: [ + "OCS_N1" + ], + self.configurable_downstream_usb[1].over_current_sense.signal: [ + "OCS_N2" + ], + self.configurable_downstream_usb[2].over_current_sense.signal: [ + "OCS_N3" + ], + self.configurable_downstream_usb[3].over_current_sense.signal: [ + "OCS_N4" + ], + self.power_pll.hv: ["PLLFILT"], + self.configurable_downstream_usb[0].battery_charging_enable.signal: [ + "PRTPWR1/BC_EN1" + ], + self.configurable_downstream_usb[1].battery_charging_enable.signal: [ + "PRTPWR2/BC_EN2" + ], + self.configurable_downstream_usb[2].battery_charging_enable.signal: [ + "PRTPWR3/BC_EN3" + ], + self.configurable_downstream_usb[3].battery_charging_enable.signal: [ + "PRTPWR4/BC_EN4" + ], + self.usb_bias_resistor_input.signal: ["RBIAS"], + self.reset.signal: ["RESET_N"], + self.configuration_source_input[0].signal: ["SCL/SMBCLK/CFG_SEL0"], + self.usb_removability_configuration_intput[1].signal: [ + "SDA/SMBDATA/NON_REM1" + ], + self.usb_removability_configuration_intput[0].signal: [ + "SUSP_IND/LOCAL_PWR/NON_REM0" + ], + self.test: ["TEST"], + self.configurable_downstream_usb[0].usb.n: ["USBDM_DN1/PRT_DIS_M1"], + self.configurable_downstream_usb[1].usb.n: ["USBDM_DN2/PRT_DIS_M2"], + self.configurable_downstream_usb[2].usb.n: ["USBDM_DN3/PRT_DOS_M3"], + self.configurable_downstream_usb[3].usb.n: ["USBDM_DN4/PRT_DIS_M4"], + self.usb_upstream.p: ["USBDM_UP"], + self.configurable_downstream_usb[0].usb.n: ["USBDP_DN1/PRT_DIS_P1"], + self.configurable_downstream_usb[1].usb.n: ["USBDP_DN2/PRT_DIS_P2"], + self.configurable_downstream_usb[2].usb.n: ["USBDP_DN3/PRT_DIS_P3"], + self.configurable_downstream_usb[3].usb.n: ["USBDP_DN4/PRT_DIS_P4"], + self.usb_upstream.p: ["USBDP_UP"], + self.vbus_detect.signal: ["VBUS_DET"], + self.power_3v3.hv: ["VDD33"], + self.power_3v3_analog.hv: ["VDDA33"], + self.xtal_if.xin: ["XTALIN/CLKIN"], + self.xtal_if.xout: ["XTALOUT"], + }, + accept_prefix=False, + case_sensitive=False, + ) - self.PLLFILT.voltage.merge(1.8 * P.V) - self.CRFILT.voltage.merge(1.8 * P.V) + def __preinit__(self): + # ---------------------------------------- + # connections + # ---------------------------------------- + self.configuration_source_input[0].connect(self.i2c.scl) + self.configuration_source_input[1].connect(self.high_speed_upstream_indicator) + self.usb_removability_configuration_intput[0].signal.connect( + self.suspense_indicator.signal, + self.local_power_detection.signal, + ) + self.usb_removability_configuration_intput[1].connect(self.i2c.sda) + for usb_port in self.configurable_downstream_usb: + usb_port.usb.p.connect(usb_port.usb_port_disable_p.signal) + usb_port.usb.n.connect(usb_port.usb_port_disable_n.signal) + usb_port.usb_power_enable.connect(usb_port.battery_charging_enable) + self.test.connect(self.power_core.lv) - if ( - self.non_removable_port_configuration - == USB2514B.NonRemovablePortConfiguration.ALL_PORTS_REMOVABLE - ): - self.NON_REM[0].get_trait(F.ElectricLogic.can_be_pulled).pull(up=False) - self.NON_REM[1].get_trait(F.ElectricLogic.can_be_pulled).pull(up=False) - elif ( - self.non_removable_port_configuration - == USB2514B.NonRemovablePortConfiguration.PORT_1_NOT_REMOVABLE - ): - self.NON_REM[0].get_trait(F.ElectricLogic.can_be_pulled).pull(up=True) - self.NON_REM[1].get_trait(F.ElectricLogic.can_be_pulled).pull(up=False) - elif ( - self.non_removable_port_configuration - == USB2514B.NonRemovablePortConfiguration.PORT_1_2_NOT_REMOVABLE - ): - self.NON_REM[0].get_trait(F.ElectricLogic.can_be_pulled).pull(up=False) - self.NON_REM[1].get_trait(F.ElectricLogic.can_be_pulled).pull(up=True) - elif ( - self.non_removable_port_configuration - == USB2514B.NonRemovablePortConfiguration.PORT_1_2_3_NOT_REMOVABLE - ): - self.NON_REM[0].get_trait(F.ElectricLogic.can_be_pulled).pull(up=True) - self.NON_REM[1].get_trait(F.ElectricLogic.can_be_pulled).pull(up=True) + F.ElectricLogic.connect_all_module_references(self, gnd_only=True) + F.ElectricLogic.connect_all_module_references( + self, + exclude={ + self.power_3v3_analog, + self.power_pll, + self.power_core, + }, + ) - datasheet = L.f_field(F.has_datasheet_defined)( - "https://ww1.microchip.com/downloads/aemDocuments/documents/UNG/ProductDocuments/DataSheets/USB251xB-xBi-Data-Sheet-DS00001692.pdf" - ) + # ---------------------------------------- + # parametrization + # ---------------------------------------- + self.power_pll.voltage.merge( + F.Range.from_center_rel(1.8 * P.V, 0.05) + ) # datasheet does not specify a voltage range + self.power_core.voltage.merge( + F.Range.from_center_rel(1.8 * P.V, 0.05) + ) # datasheet does not specify a voltage range + self.power_3v3.voltage.merge(F.Range.from_center(3.3 * P.V, 0.3 * P.V)) + self.power_3v3_analog.voltage.merge(F.Range.from_center(3.3 * P.V, 0.3 * P.V)) diff --git a/src/faebryk/library/USB2514B_ReferenceDesign.py b/src/faebryk/library/USB2514B_ReferenceDesign.py index 5c38413d..e0f7278a 100644 --- a/src/faebryk/library/USB2514B_ReferenceDesign.py +++ b/src/faebryk/library/USB2514B_ReferenceDesign.py @@ -15,18 +15,24 @@ class USB2514B_ReferenceDesign(Module): + """ + Reference implementation of the USB2514B quad port USB hub controller. + + - + """ + # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- hub_controller: F.USB2514B vbus_voltage_divider: F.ResistorVoltageDivider ldo_3v3: F.LDO - suspend_indicator: F.PoweredLED + suspend_indicator = L.f_field(F.LEDIndicator)(use_mosfet=False) power_3v3_indicator: F.PoweredLED power_distribution_switch = L.list_field(4, F.Diodes_Incorporated_AP2552W6_7) usb_dfp_power_indicator = L.list_field(4, F.PoweredLED) bias_resistor: F.Resistor - crystal_oscillator: F.Crystal_Oscillator # TODO: Connect Crystal oscillator + crystal_oscillator: F.Crystal_Oscillator usb_ufp: F.USB2_0 usb_dfp = L.list_field(4, F.USB2_0) @@ -34,12 +40,17 @@ class USB2514B_ReferenceDesign(Module): # ---------------------------------------- # traits # ---------------------------------------- + datasheet = L.f_field(F.has_datasheet_defined)( + "https://ww1.microchip.com/downloads/aemDocuments/documents/OTH/ProductDocuments/BoardDesignFiles/EVB-USB2514BC_A3-sch.pdf" # noqa: E501 + ) + @L.rt_field def has_defined_layout(self): Point = F.has_pcb_position.Point L = F.has_pcb_position.layer_type LVL = LayoutTypeHierarchy.Level + # TODO: layouts = [ LVL( mod_type=F.PoweredLED, @@ -61,11 +72,20 @@ def __preinit__(self): # ---------------------------------------- # parametrization # ---------------------------------------- - # crystal oscillator - self.hub_controller.XTALOUT.connect_via( - self.crystal_oscillator, self.hub_controller.XTALIN + self.hub_controller.set_non_removable_ports( + F.USB2514B.NonRemovablePortConfiguration.ALL_PORTS_REMOVABLE + ) + self.hub_controller.set_configuration_source( + F.USB2514B.ConfigurationSource.DEFAULT ) - # TODO: this is a property of the crystal. remove this + for dsf_usb in self.hub_controller.configurable_downstream_usb: + self.hub_controller.configure_usb_port( + dsf_usb, + enable_usb=True, + enable_battery_charging=True, + ) + + # TODO: load_capacitance is a property of the crystal. remove this self.crystal_oscillator.crystal.load_capacitance.merge( F.Range(8 * P.pF, 15 * P.pF) ) @@ -76,47 +96,48 @@ def __preinit__(self): F.Range.upper_bound(50 * P.ppm) ) + # usb transceiver bias resistor + self.bias_resistor.resistance.merge(F.Range.from_center_rel(12 * P.kohm, 0.01)) + + for led in [self.suspend_indicator.led, self.power_3v3_indicator]: + led.led.color.merge(F.LED.Color.GREEN) + led.led.brightness.merge( + TypicalLuminousIntensity.APPLICATION_LED_INDICATOR_INSIDE.value.value + ) + # ---------------------------------------- # connections # ---------------------------------------- + # crystal oscillator + self.crystal_oscillator.xtal_if.connect(self.hub_controller.xtal_if) + self.crystal_oscillator.gnd.connect(gnd) + for i, dfp in enumerate(self.usb_dfp): vbus.connect_via(self.power_distribution_switch[i], dfp.usb_if.buspower) - dfp.usb_if.d.connect(self.hub_controller.usb_downstream[i]) + dfp.usb_if.d.connect(self.hub_controller.configurable_downstream_usb[i].usb) # TODO: connect hub controller overcurrent and power control signals self.power_distribution_switch[i].enable.connect( - self.hub_controller.PRTPWR[i] + self.hub_controller.configurable_downstream_usb[i].usb_power_enable ) self.power_distribution_switch[i].fault.connect( - self.hub_controller.OCS_N[i] - ) - self.power_distribution_switch[i].power_out.hv.connect_via( - self.usb_dfp_power_indicator[i], gnd + self.hub_controller.configurable_downstream_usb[i].over_current_sense ) + dfp.usb_if.buspower.connect(self.usb_dfp_power_indicator[i].power) self.usb_dfp_power_indicator[i].led.color.merge(F.LED.Color.YELLOW) self.usb_dfp_power_indicator[i].led.brightness.merge( - # F.Range( - # 10 * P.millicandela, 100 * P.millicandela - # ) # TypicalLuminousIntensity.APPLICATION_LED_INDICATOR_INSIDE.value.value ) - for pds in self.power_distribution_switch: - pds.set_current_limit(F.Range.from_center_rel(520 * P.mA, 0.01)) + self.power_distribution_switch[i].set_current_limit( + F.Range.from_center_rel(520 * P.mA, 0.01) + ) # Bias resistor - self.bias_resistor.resistance.merge(F.Range.from_center_rel(12 * P.kohm, 0.01)) - self.hub_controller.RBIAS.connect_via(self.bias_resistor, gnd) + self.hub_controller.usb_bias_resistor_input.signal.connect_via( + self.bias_resistor, gnd + ) # TODO: replace with pull? self.usb_ufp.usb_if.d.connect(self.hub_controller.usb_upstream) # LEDs self.power_3v3_indicator.power.connect(self.ldo_3v3.power_out) - self.hub_controller.SUSP_IND.signal.connect_via(self.suspend_indicator, gnd) - # TODO: remove, should be fixed by using LEDIndicator - self.suspend_indicator.power.voltage.merge(self.ldo_3v3.power_out.voltage) - - # TODO: do elsewhere - for led in [self.suspend_indicator, self.power_3v3_indicator]: - led.led.color.merge(F.LED.Color.GREEN) - led.led.brightness.merge( - TypicalLuminousIntensity.APPLICATION_LED_INDICATOR_INSIDE.value.value - ) + self.hub_controller.suspense_indicator.connect(self.suspend_indicator.logic_in) diff --git a/src/faebryk/library/_F.py b/src/faebryk/library/_F.py index 906d1f5f..e5b77714 100644 --- a/src/faebryk/library/_F.py +++ b/src/faebryk/library/_F.py @@ -20,8 +20,8 @@ from faebryk.library.Constant import Constant from faebryk.library.has_esphome_config import has_esphome_config from faebryk.library.is_esphome_bus import is_esphome_bus -from faebryk.library.has_pcb_position import has_pcb_position from faebryk.library.has_designator_prefix import has_designator_prefix +from faebryk.library.has_pcb_position import has_pcb_position from faebryk.library.has_single_electric_reference import has_single_electric_reference from faebryk.library.Power import Power from faebryk.library.Signal import Signal @@ -50,10 +50,10 @@ from faebryk.library.Set import Set from faebryk.library.has_esphome_config_defined import has_esphome_config_defined from faebryk.library.is_esphome_bus_defined import is_esphome_bus_defined +from faebryk.library.has_designator_prefix_defined import has_designator_prefix_defined from faebryk.library.has_pcb_position_defined import has_pcb_position_defined from faebryk.library.has_pcb_position_defined_relative import has_pcb_position_defined_relative from faebryk.library.has_pcb_position_defined_relative_to_parent import has_pcb_position_defined_relative_to_parent -from faebryk.library.has_designator_prefix_defined import has_designator_prefix_defined from faebryk.library.has_single_electric_reference_defined import has_single_electric_reference_defined from faebryk.library.Filter import Filter from faebryk.library.Logic import Logic @@ -74,7 +74,6 @@ from faebryk.library.XtalIF import XtalIF from faebryk.library.has_pin_association_heuristic import has_pin_association_heuristic from faebryk.library.Common_Mode_Filter import Common_Mode_Filter -from faebryk.library.Crystal import Crystal from faebryk.library.Header import Header from faebryk.library.PJ398SM import PJ398SM from faebryk.library.RJ45_Receptacle import RJ45_Receptacle @@ -87,8 +86,6 @@ from faebryk.library.Pad import Pad from faebryk.library.Button import Button from faebryk.library.GDT import GDT -from faebryk.library.Ethernet import Ethernet -from faebryk.library.RS485 import RS485 from faebryk.library.has_pin_association_heuristic_lookup_table import has_pin_association_heuristic_lookup_table from faebryk.library.LogicGate import LogicGate from faebryk.library.has_footprint_defined import has_footprint_defined @@ -111,13 +108,13 @@ from faebryk.library.KicadFootprint import KicadFootprint from faebryk.library.TVS import TVS from faebryk.library.Capacitor import Capacitor +from faebryk.library.Crystal import Crystal from faebryk.library.Fuse import Fuse from faebryk.library.Inductor import Inductor from faebryk.library.Resistor import Resistor from faebryk.library.Switch import Switch from faebryk.library.B4B_ZR_SM4_TF import B4B_ZR_SM4_TF from faebryk.library.DE9Connector import DE9Connector -from faebryk.library.USB_Type_C_Receptacle_24_pin import USB_Type_C_Receptacle_24_pin from faebryk.library.pf_533984002 import pf_533984002 from faebryk.library.DIP import DIP from faebryk.library.QFN import QFN @@ -137,6 +134,9 @@ from faebryk.library.Resistor_Voltage_Divider import Resistor_Voltage_Divider from faebryk.library.is_surge_protected_defined import is_surge_protected_defined from faebryk.library.is_decoupled_nodes import is_decoupled_nodes +from faebryk.library.Ethernet import Ethernet +from faebryk.library.RS485 import RS485 +from faebryk.library.USB_Type_C_Receptacle_24_pin import USB_Type_C_Receptacle_24_pin from faebryk.library.can_be_surge_protected_defined import can_be_surge_protected_defined from faebryk.library.can_be_decoupled_defined import can_be_decoupled_defined from faebryk.library.ElectricPower import ElectricPower @@ -188,7 +188,6 @@ from faebryk.library.QWIIC import QWIIC from faebryk.library.QWIIC_Connector import QWIIC_Connector from faebryk.library.SCD40 import SCD40 -from faebryk.library.USB2514B import USB2514B from faebryk.library.ME6211C33M5G_N import ME6211C33M5G_N from faebryk.library.SPIFlash import SPIFlash from faebryk.library.RP2040Pinmux import RP2040Pinmux @@ -200,14 +199,15 @@ from faebryk.library.TXS0102DCUR_UART import TXS0102DCUR_UART from faebryk.library.UART import UART from faebryk.library.UART_RS485 import UART_RS485 +from faebryk.library.USB2514B import USB2514B from faebryk.library.USB2_0 import USB2_0 from faebryk.library.USB3_IF import USB3_IF from faebryk.library.can_switch_power_defined import can_switch_power_defined from faebryk.library.CD4011 import CD4011 -from faebryk.library.Winbond_Elec_W25Q128JVSIQ import Winbond_Elec_W25Q128JVSIQ -from faebryk.library.RP2040 import RP2040 from faebryk.library.INA228_ReferenceDesign import INA228_ReferenceDesign from faebryk.library.ISO1540_ReferenceDesign import ISO1540_ReferenceDesign +from faebryk.library.Winbond_Elec_W25Q128JVSIQ import Winbond_Elec_W25Q128JVSIQ +from faebryk.library.RP2040 import RP2040 from faebryk.library.SP3243E import SP3243E from faebryk.library.CBM9002A_56ILG import CBM9002A_56ILG from faebryk.library.CH340x import CH340x @@ -215,7 +215,6 @@ from faebryk.library.CH344 import CH344 from faebryk.library.ESP32_C3 import ESP32_C3 from faebryk.library.MCP2221A import MCP2221A -from faebryk.library.USB2514B_ReferenceDesign import USB2514B_ReferenceDesign from faebryk.library.USB2_0_ESD_Protection import USB2_0_ESD_Protection from faebryk.library.USBLC6_2P6 import USBLC6_2P6 from faebryk.library.USB_Type_C_Receptacle_14_pin_Vertical import USB_Type_C_Receptacle_14_pin_Vertical @@ -243,3 +242,4 @@ from faebryk.library.Powered_Relay import Powered_Relay from faebryk.library.LEDIndicator import LEDIndicator from faebryk.library.CH344Q_ReferenceDesign import CH344Q_ReferenceDesign +from faebryk.library.USB2514B_ReferenceDesign import USB2514B_ReferenceDesign diff --git a/test/library/nodes/test_electricpower.py b/test/library/nodes/test_electricpower.py index 158a2c5a..32b462f6 100644 --- a/test/library/nodes/test_electricpower.py +++ b/test/library/nodes/test_electricpower.py @@ -25,4 +25,3 @@ def test_fused_power(self): self.assertIsInstance(fuse, F.Fuse) self.assertEqual(fuse.trip_current.get_most_narrow(), 500 * P.mA) self.assertEqual(power_out.voltage.get_most_narrow(), 10 * P.V) - self.assertEqual(power_out.max_current.get_most_narrow(), 500 * P.mA) From 5978ce45c8b7175ff5ecd2815d4e74273d663454 Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Sun, 15 Sep 2024 18:47:48 +0200 Subject: [PATCH 24/27] Revert noqa deletion and Activestate --- src/faebryk/library/Logic.py | 7 ------- src/faebryk/library/RP2040_ReferenceDesign.py | 6 +++--- 2 files changed, 3 insertions(+), 10 deletions(-) diff --git a/src/faebryk/library/Logic.py b/src/faebryk/library/Logic.py index e4c510a0..8edc33ba 100644 --- a/src/faebryk/library/Logic.py +++ b/src/faebryk/library/Logic.py @@ -1,19 +1,12 @@ # This file is part of the faebryk project # SPDX-License-Identifier: MIT -from enum import IntEnum - import faebryk.library._F as F from faebryk.libs.library import L class Logic(F.Signal): - class ActiveState(IntEnum): - ACTIVE_HIGH = True - ACTIVE_LOW = False - state = L.f_field(F.Range)(False, True) - active_state = L.f_field(F.Range)(ActiveState.ACTIVE_HIGH, ActiveState.ACTIVE_LOW) def set(self, on: bool): self.state.merge(on) diff --git a/src/faebryk/library/RP2040_ReferenceDesign.py b/src/faebryk/library/RP2040_ReferenceDesign.py index 41fbb68b..14180ad3 100644 --- a/src/faebryk/library/RP2040_ReferenceDesign.py +++ b/src/faebryk/library/RP2040_ReferenceDesign.py @@ -3,7 +3,7 @@ import logging -import faebryk.library._F as F +import faebryk.library._F as F # noqa: E401 from faebryk.core.module import Module from faebryk.exporters.pcb.layout.heuristic_decoupling import ( LayoutHeuristicElectricalClosenessDecouplingCaps, @@ -11,9 +11,9 @@ from faebryk.exporters.pcb.layout.heuristic_pulls import ( LayoutHeuristicElectricalClosenessPullResistors, ) -from faebryk.libs.library import L +from faebryk.libs.library import L # noqa: E401 from faebryk.libs.picker.picker import DescriptiveProperties -from faebryk.libs.units import P +from faebryk.libs.units import P # noqa: E401 logger = logging.getLogger(__name__) From 79f5da658468fefd70a8ab7e18c1d65da8e99b6c Mon Sep 17 00:00:00 2001 From: ruben-iteng <94007802+ruben-iteng@users.noreply.github.com> Date: Sun, 15 Sep 2024 18:48:50 +0200 Subject: [PATCH 25/27] Revert noqa deletion again --- src/faebryk/library/RP2040_ReferenceDesign.py | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/src/faebryk/library/RP2040_ReferenceDesign.py b/src/faebryk/library/RP2040_ReferenceDesign.py index 14180ad3..6dab0e51 100644 --- a/src/faebryk/library/RP2040_ReferenceDesign.py +++ b/src/faebryk/library/RP2040_ReferenceDesign.py @@ -3,7 +3,7 @@ import logging -import faebryk.library._F as F # noqa: E401 +import faebryk.library._F as F # noqa: F401 from faebryk.core.module import Module from faebryk.exporters.pcb.layout.heuristic_decoupling import ( LayoutHeuristicElectricalClosenessDecouplingCaps, @@ -11,9 +11,9 @@ from faebryk.exporters.pcb.layout.heuristic_pulls import ( LayoutHeuristicElectricalClosenessPullResistors, ) -from faebryk.libs.library import L # noqa: E401 +from faebryk.libs.library import L # noqa: F401 from faebryk.libs.picker.picker import DescriptiveProperties -from faebryk.libs.units import P # noqa: E401 +from faebryk.libs.units import P # noqa: F401 logger = logging.getLogger(__name__) From e14e241ed7ec71c8fe7de63135aa8e99b3d34cf4 Mon Sep 17 00:00:00 2001 From: iopapamanoglou Date: Mon, 16 Sep 2024 15:02:36 +0200 Subject: [PATCH 26/27] fix tests --- src/faebryk/library/ElectricPower.py | 7 ++++--- src/faebryk/libs/util.py | 22 +++++++++++++++++++++- test/library/nodes/test_electricpower.py | 10 +++++++--- test/library/test_basic.py | 3 ++- 4 files changed, 34 insertions(+), 8 deletions(-) diff --git a/src/faebryk/library/ElectricPower.py b/src/faebryk/library/ElectricPower.py index 5eab1ecb..d8b4dfad 100644 --- a/src/faebryk/library/ElectricPower.py +++ b/src/faebryk/library/ElectricPower.py @@ -68,12 +68,13 @@ def fused(self, attach_to: Node | None = None): fused_power = type(self)() fuse = fused_power.add(F.Fuse()) - fuse.trip_current.merge(self.max_current) # TODO: maybe add a margin - fused_power.hv.connect_via(fuse, self.hv) fused_power.lv.connect(self.lv) - fused_power.voltage.merge(self.voltage) + self.connect_shallow(fused_power) + + fuse.trip_current.merge(F.Range(0 * P.A, self.max_current)) + # fused_power.max_current.merge(F.Range(0 * P.A, fuse.trip_current)) if attach_to is not None: attach_to.add(fused_power) diff --git a/src/faebryk/libs/util.py b/src/faebryk/libs/util.py index 32601e1f..28b41e64 100644 --- a/src/faebryk/libs/util.py +++ b/src/faebryk/libs/util.py @@ -15,6 +15,7 @@ from typing import ( Any, Callable, + Concatenate, Iterable, Iterator, List, @@ -814,10 +815,29 @@ def wrapper(*args: P.args, **kwargs: P.kwargs) -> Any: return result wrapper.cache = {} + wrapper._is_once_wrapper = True return wrapper -def assert_once[T, **P](f: Callable[P, T]) -> Callable[P, T]: +def assert_once[T, O, **P]( + f: Callable[Concatenate[O, P], T], +) -> Callable[Concatenate[O, P], T]: + def wrapper(obj: O, *args: P.args, **kwargs: P.kwargs) -> T: + if not hasattr(obj, "_assert_once_called"): + setattr(obj, "_assert_once_called", set()) + + wrapper_set = getattr(obj, "_assert_once_called") + + if wrapper not in wrapper_set: + wrapper_set.add(wrapper) + return f(obj, *args, **kwargs) + else: + raise AssertionError("Function called more than once") + + return wrapper + + +def assert_once_global[T, **P](f: Callable[P, T]) -> Callable[P, T]: def wrapper(*args: P.args, **kwargs: P.kwargs) -> T: if not wrapper.called: wrapper.called = True diff --git a/test/library/nodes/test_electricpower.py b/test/library/nodes/test_electricpower.py index 32b462f6..94402774 100644 --- a/test/library/nodes/test_electricpower.py +++ b/test/library/nodes/test_electricpower.py @@ -21,7 +21,11 @@ def test_fused_power(self): fuse = next(iter(power_in_fused.get_children(direct_only=False, types=F.Fuse))) - self.assertIsNotNone(fuse) - self.assertIsInstance(fuse, F.Fuse) - self.assertEqual(fuse.trip_current.get_most_narrow(), 500 * P.mA) + self.assertEqual( + fuse.trip_current.get_most_narrow(), F.Range(0 * P.A, 500 * P.mA) + ) self.assertEqual(power_out.voltage.get_most_narrow(), 10 * P.V) + # self.assertEqual( + # power_in_fused.max_current.get_most_narrow(), F.Range(0 * P.A, 500 * P.mA) + # ) + self.assertEqual(power_out.max_current.get_most_narrow(), F.TBD()) diff --git a/test/library/test_basic.py b/test/library/test_basic.py index be33905e..aa08e031 100644 --- a/test/library/test_basic.py +++ b/test/library/test_basic.py @@ -20,7 +20,8 @@ def test_symbol_types(self): for k, v in vars(F).items() if not k.startswith("_") and (not isinstance(v, type) or not issubclass(v, (Node, Namespace))) - and not type(v).__name__ == "_once" + # allow once wrappers for type generators + and not getattr(v, "_is_once_wrapper", False) } self.assertFalse(symbols, f"Found unexpected symbols: {symbols}") From 3fcda2ea9f9a7525c59f3c9e33dbbb2331ab6fe1 Mon Sep 17 00:00:00 2001 From: iopapamanoglou Date: Mon, 16 Sep 2024 15:51:17 +0200 Subject: [PATCH 27/27] fix assert_once calls --- src/faebryk/core/module.py | 7 +- src/faebryk/library/CH342.py | 4 +- src/faebryk/library/CH342F.py | 99 +++++++++---------- src/faebryk/library/CH344.py | 1 - src/faebryk/library/CH344Q.py | 40 ++++---- .../library/Diodes_Incorporated_AP2552W6_7.py | 4 +- src/faebryk/library/INA228.py | 3 +- src/faebryk/library/USB2514B.py | 51 +++++----- .../library/USB2514B_ReferenceDesign.py | 3 +- src/faebryk/libs/util.py | 2 +- 10 files changed, 104 insertions(+), 110 deletions(-) diff --git a/src/faebryk/core/module.py b/src/faebryk/core/module.py index 9c76d52a..a23bf857 100644 --- a/src/faebryk/core/module.py +++ b/src/faebryk/core/module.py @@ -4,9 +4,8 @@ from typing import TYPE_CHECKING, Callable, Iterable from faebryk.core.moduleinterface import GraphInterfaceModuleSibling -from faebryk.core.node import Node, f_field +from faebryk.core.node import Node, NodeException, f_field from faebryk.core.trait import Trait -from faebryk.libs.exceptions import FaebrykException from faebryk.libs.util import unique_ref if TYPE_CHECKING: @@ -15,10 +14,10 @@ logger = logging.getLogger(__name__) -class ModuleException(FaebrykException): +class ModuleException(NodeException): def __init__(self, module: "Module", *args: object) -> None: self.module = module - super().__init__(*args) + super().__init__(module, *args) class Module(Node): diff --git a/src/faebryk/library/CH342.py b/src/faebryk/library/CH342.py index 2cc5e0d2..810643b7 100644 --- a/src/faebryk/library/CH342.py +++ b/src/faebryk/library/CH342.py @@ -8,7 +8,7 @@ from faebryk.core.module import Module, ModuleException from faebryk.libs.library import L # noqa: F401 from faebryk.libs.units import P -from faebryk.libs.util import assert_once # noqa: F401 +from faebryk.libs.util import assert_once logger = logging.getLogger(__name__) @@ -48,7 +48,7 @@ class ChipPowerConfiguration(Enum): EXTERNAL_3V3 = auto() """Chip powered by an external 3.3V source""" - # @assert_once TODO: this breaks when we use both CH342F and CH342K in 1 design + @assert_once def set_power_configuration( self, chip_power_configuration: ChipPowerConfiguration = ChipPowerConfiguration.USB_5V, # noqa: E501 diff --git a/src/faebryk/library/CH342F.py b/src/faebryk/library/CH342F.py index 417c2141..55a9c466 100644 --- a/src/faebryk/library/CH342F.py +++ b/src/faebryk/library/CH342F.py @@ -4,10 +4,10 @@ import logging import faebryk.library._F as F # noqa: F401 -from faebryk.core.module import ModuleException +from faebryk.core.module import Module from faebryk.libs.library import L # noqa: F401 from faebryk.libs.picker.picker import DescriptiveProperties -from faebryk.libs.util import times +from faebryk.libs.util import assert_once, times logger = logging.getLogger(__name__) @@ -19,31 +19,30 @@ class CH342F(F.CH342): QFN-24-EP(4x4) """ - # @assert_once TODO: broken - def enable_tnow_mode(self, uart: F.UART): - """ - Set TNOW mode for specified UART for use with RS485 tranceivers. - The TNOW pin can be connected to the tx_enable and rx_enable - pins of the RS485 tranceiver for automatic half-duplex control. - """ - if uart not in self.uart: - raise ModuleException( - self, f"{uart.get_full_name()} is not a part of this module" - ) - - uart.dtr.set_weak(on=False) - uart.dtr.connect(self.tnow[self.uart.index(uart)]) + class UARTWrapper(Module): + uart: F.UART + tnow: F.ElectricLogic + ... + + @assert_once + def enable_tnow_mode(self): + """ + Set TNOW mode for specified UART for use with RS485 tranceivers. + The TNOW pin can be connected to the tx_enable and rx_enable + pins of the RS485 tranceiver for automatic half-duplex control. + """ + self.uart.dtr.set_weak(on=False) + self.uart.dtr.connect(self.tnow) # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- - tnow = L.list_field(2, F.ElectricLogic) vbus_detect: F.ElectricLogic reset: F.ElectricLogic active: F.ElectricLogic - uart = times(2, F.UART) + uart = times(2, UARTWrapper) # ---------------------------------------- # traits @@ -52,7 +51,7 @@ def enable_tnow_mode(self, uart: F.UART): def can_attach_to_footprint(self): return F.can_attach_to_footprint_via_pinmap( { - "1": self.uart[0].ri.signal, + "1": self.uart[0].uart.ri.signal, "2": self.usb.usb_if.buspower.lv, "3": self.usb.usb_if.d.p, "4": self.usb.usb_if.d.n, @@ -61,21 +60,21 @@ def can_attach_to_footprint(self): "7": self.integrated_regulator.power_in.hv, "8": self.usb.usb_if.buspower.hv, "9": self.reset.signal, - "10": self.uart[1].cts.signal, - "11": self.uart[1].rts.signal, - "12": self.uart[1].base_uart.rx.signal, - "13": self.uart[1].base_uart.tx.signal, - "14": self.uart[1].dsr.signal, - "15": self.uart[1].dtr.signal, - "16": self.uart[1].dcd.signal, - "17": self.uart[1].ri.signal, - "18": self.uart[0].cts.signal, - "19": self.uart[0].rts.signal, - "20": self.uart[0].base_uart.rx.signal, - "21": self.uart[0].base_uart.tx.signal, - "22": self.uart[0].dsr.signal, - "23": self.uart[0].dtr.signal, - "24": self.uart[0].dcd.signal, + "10": self.uart[1].uart.cts.signal, + "11": self.uart[1].uart.rts.signal, + "12": self.uart[1].uart.base_uart.rx.signal, + "13": self.uart[1].uart.base_uart.tx.signal, + "14": self.uart[1].uart.dsr.signal, + "15": self.uart[1].uart.dtr.signal, + "16": self.uart[1].uart.dcd.signal, + "17": self.uart[1].uart.ri.signal, + "18": self.uart[0].uart.cts.signal, + "19": self.uart[0].uart.rts.signal, + "20": self.uart[0].uart.base_uart.rx.signal, + "21": self.uart[0].uart.base_uart.tx.signal, + "22": self.uart[0].uart.dsr.signal, + "23": self.uart[0].uart.dtr.signal, + "24": self.uart[0].uart.dcd.signal, "25": self.usb.usb_if.buspower.lv, } ) @@ -84,25 +83,25 @@ def can_attach_to_footprint(self): def pin_association_heuristic(self): return F.has_pin_association_heuristic_lookup_table( mapping={ - self.uart[0].cts.signal: ["CTS0"], - self.uart[1].cts.signal: ["CTS1"], - self.uart[0].dcd.signal: ["DCD0"], - self.uart[1].dcd.signal: ["DCD1"], - self.uart[0].dsr.signal: ["DSR0"], - self.uart[1].dsr.signal: ["DSR1"], - self.uart[0].dtr.signal: ["DTR0"], - self.uart[1].dtr.signal: ["DTR1"], + self.uart[0].uart.cts.signal: ["CTS0"], + self.uart[1].uart.cts.signal: ["CTS1"], + self.uart[0].uart.dcd.signal: ["DCD0"], + self.uart[1].uart.dcd.signal: ["DCD1"], + self.uart[0].uart.dsr.signal: ["DSR0"], + self.uart[1].uart.dsr.signal: ["DSR1"], + self.uart[0].uart.dtr.signal: ["DTR0"], + self.uart[1].uart.dtr.signal: ["DTR1"], # self.power_3v.lv: ["EP"], self.power_3v.lv: ["GND"], - self.uart[0].ri.signal: ["RI0"], - self.uart[1].ri.signal: ["RI1"], + self.uart[0].uart.ri.signal: ["RI0"], + self.uart[1].uart.ri.signal: ["RI1"], self.reset.signal: ["RST"], - self.uart[0].rts.signal: ["RTS0"], - self.uart[1].rts.signal: ["RTS1"], - self.uart[0].base_uart.rx.signal: ["RXD0"], - self.uart[1].base_uart.rx.signal: ["RXD1"], - self.uart[0].base_uart.tx.signal: ["TXD0"], - self.uart[1].base_uart.tx.signal: ["TXD1"], + self.uart[0].uart.rts.signal: ["RTS0"], + self.uart[1].uart.rts.signal: ["RTS1"], + self.uart[0].uart.base_uart.rx.signal: ["RXD0"], + self.uart[1].uart.base_uart.rx.signal: ["RXD1"], + self.uart[0].uart.base_uart.tx.signal: ["TXD0"], + self.uart[1].uart.base_uart.tx.signal: ["TXD1"], self.usb.usb_if.d.p: ["UD+"], self.usb.usb_if.d.n: ["UD-"], self.power_3v.hv: ["V3"], diff --git a/src/faebryk/library/CH344.py b/src/faebryk/library/CH344.py index 4bfd2f9d..a2aeb4d3 100644 --- a/src/faebryk/library/CH344.py +++ b/src/faebryk/library/CH344.py @@ -22,7 +22,6 @@ class CH344(Module): # ---------------------------------------- usb: F.USB2_0 # TODO not a full USB, only data bus uart = L.list_field(4, F.UART) - tnow = L.list_field(4, F.ElectricLogic) act: F.ElectricLogic indicator_tx: F.ElectricLogic indicator_rx: F.ElectricLogic diff --git a/src/faebryk/library/CH344Q.py b/src/faebryk/library/CH344Q.py index 567597bc..1a619d7d 100644 --- a/src/faebryk/library/CH344Q.py +++ b/src/faebryk/library/CH344Q.py @@ -4,11 +4,11 @@ import logging import faebryk.library._F as F # noqa: F401 -from faebryk.core.module import ModuleException +from faebryk.core.module import Module from faebryk.libs.library import L # noqa: F401 from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P # noqa: F401 -from faebryk.libs.util import assert_once # noqa: F401 +from faebryk.libs.util import assert_once logger = logging.getLogger(__name__) @@ -18,29 +18,31 @@ class CH344Q(F.CH344): Quad UART to USB bridge """ - # @assert_once TODO: broken - def enable_tnow_mode(self, uart: F.UART): - """ - Set TNOW mode for specified UART for use with RS485 tranceivers. - The TNOW pin can be connected to the tx_enable and rx_enable - pins of the RS485 tranceiver for automatic half-duplex control. - """ - if uart not in self.uart: - raise ModuleException( - self, f"{uart.get_full_name()} is not a part of this module" - ) + class UARTWrapper(Module): + uart: F.UART + tnow: F.ElectricLogic + ... + + @assert_once + def enable_tnow_mode(self): + """ + Set TNOW mode for specified UART for use with RS485 tranceivers. + The TNOW pin can be connected to the tx_enable and rx_enable + pins of the RS485 tranceiver for automatic half-duplex control. + """ + self.uart.dtr.set_weak(on=False) + self.uart.dtr.connect(self.tnow) - uart.dtr.set_weak(on=False) - uart.dtr.connect(self.tnow[self.uart.index(uart)]) + uartwrapper = L.list_field(4, UARTWrapper) - # @assert_once TODO: broken + @assert_once def enable_chip_default_settings(self): """ Use the chip default settings instead of the ones stored in the internal EEPROM """ self.uart[0].rts.set_weak(on=False) - # @assert_once TODO: broken + @assert_once def enable_status_or_modem_signals(self, modem_signals: bool = False): """ Enable rx, tx and usb status signal outputs instead of UART modem signals. @@ -52,7 +54,7 @@ def enable_status_or_modem_signals(self, modem_signals: bool = False): self.indicator_tx.connect(self.uart[3].ri) self.indicator_rx.connect(self.uart[3].dsr) - # @assert_once TODO: broken + @assert_once def enable_hardware_flow_conrol(self): """ Enable UART hardware flow control @@ -136,6 +138,8 @@ def __preinit__(self): # ------------------------------------ # connections # ------------------------------------ + for uart, uartwrapper in zip(self.uart, self.uartwrapper): + uart.connect(uartwrapper.uart) # ------------------------------------ # parametrization diff --git a/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py b/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py index 7fb27100..3cfebbab 100644 --- a/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py +++ b/src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py @@ -13,7 +13,7 @@ from faebryk.libs.library import L # noqa: F401 from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P, Quantity -from faebryk.libs.util import assert_once # noqa: F401 +from faebryk.libs.util import assert_once logger = logging.getLogger(__name__) @@ -24,7 +24,7 @@ class Diodes_Incorporated_AP2552W6_7(Module): 2.7V~5.5V 70mΩ 2.1A SOT-26 """ - # @assert_once TODO: broken + @assert_once def set_current_limit(self, current: Parameter[Quantity]) -> None: self.current_limit.merge(current) diff --git a/src/faebryk/library/INA228.py b/src/faebryk/library/INA228.py index c5ecbe5d..f3774a0c 100644 --- a/src/faebryk/library/INA228.py +++ b/src/faebryk/library/INA228.py @@ -8,6 +8,7 @@ from faebryk.libs.library import L from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P +from faebryk.libs.util import assert_once logger = logging.getLogger(__name__) @@ -17,7 +18,7 @@ class INA228(Module): INA228 high or low side current shunt and voltage monitor with I2C interface """ - # @assert_once TODO: broken + @assert_once def set_address(self, address: int = 0x00) -> None: """Set the I2C address of the INA228""" # allias diff --git a/src/faebryk/library/USB2514B.py b/src/faebryk/library/USB2514B.py index 36a851e3..4946b7e3 100644 --- a/src/faebryk/library/USB2514B.py +++ b/src/faebryk/library/USB2514B.py @@ -5,12 +5,11 @@ from enum import Enum, auto import faebryk.library._F as F -from faebryk.core.module import Module, ModuleException +from faebryk.core.module import Module from faebryk.libs.library import L from faebryk.libs.picker.picker import DescriptiveProperties from faebryk.libs.units import P - -# from faebryk.libs.util import assert_once +from faebryk.libs.util import assert_once logger = logging.getLogger(__name__) @@ -28,6 +27,24 @@ class ConfigurableUSB(Module): over_current_sense: F.ElectricLogic battery_charging_enable: F.ElectricLogic + @assert_once + def configure_usb_port( + self, + enable_usb: bool = True, + enable_battery_charging: bool = True, + ): + """ + Configure the specified USB port. + """ + # enable/disable usb port + if not enable_usb: + self.usb_port_disable_p.set_weak(on=True) + self.usb_port_disable_n.set_weak(on=True) + + # enable/disable battery charging + if not enable_battery_charging: + self.battery_charging_enable.set_weak(on=False) + class ConfigurationSource(Enum): DEFAULT = auto() """ @@ -54,7 +71,7 @@ class ConfigurationSource(Enum): - All registers configured by I2C EEPROM """ - # @assert_once + @assert_once def set_configuration_source( self, configuration_source: ConfigurationSource = ConfigurationSource.DEFAULT, @@ -81,7 +98,7 @@ class NonRemovablePortConfiguration(Enum): PORT_0_1_NOT_REMOVABLE = auto() PORT_0_1_2_NOT_REMOVABLE = auto() - # @assert_once + @assert_once def set_non_removable_ports( self, non_removable_port_configuration: NonRemovablePortConfiguration, @@ -114,30 +131,6 @@ def set_non_removable_ports( self.usb_removability_configuration_intput[0].set_weak(on=True) self.usb_removability_configuration_intput[1].set_weak(on=True) - # @assert_once # TODO: this function can be called 1ce per port - def configure_usb_port( - self, - usb_port: ConfigurableUSB, - enable_usb: bool = True, - enable_battery_charging: bool = True, - ): - """ - Configure the specified USB port. - """ - if usb_port not in self.configurable_downstream_usb: - raise ModuleException( - self, f"{usb_port.get_full_name()} is not part of this module" - ) - - # enable/disable usb port - if not enable_usb: - usb_port.usb_port_disable_p.set_weak(on=True) - usb_port.usb_port_disable_n.set_weak(on=True) - - # enable/disable battery charging - if not enable_battery_charging: - usb_port.battery_charging_enable.set_weak(on=False) - # ---------------------------------------- # modules, interfaces, parameters # ---------------------------------------- diff --git a/src/faebryk/library/USB2514B_ReferenceDesign.py b/src/faebryk/library/USB2514B_ReferenceDesign.py index e0f7278a..41da64c5 100644 --- a/src/faebryk/library/USB2514B_ReferenceDesign.py +++ b/src/faebryk/library/USB2514B_ReferenceDesign.py @@ -79,8 +79,7 @@ def __preinit__(self): F.USB2514B.ConfigurationSource.DEFAULT ) for dsf_usb in self.hub_controller.configurable_downstream_usb: - self.hub_controller.configure_usb_port( - dsf_usb, + dsf_usb.configure_usb_port( enable_usb=True, enable_battery_charging=True, ) diff --git a/src/faebryk/libs/util.py b/src/faebryk/libs/util.py index 28b41e64..425f2b3c 100644 --- a/src/faebryk/libs/util.py +++ b/src/faebryk/libs/util.py @@ -832,7 +832,7 @@ def wrapper(obj: O, *args: P.args, **kwargs: P.kwargs) -> T: wrapper_set.add(wrapper) return f(obj, *args, **kwargs) else: - raise AssertionError("Function called more than once") + raise AssertionError(f"{f.__name__} called on {obj} more than once") return wrapper