Skip to content
This repository was archived by the owner on Dec 10, 2024. It is now read-only.

Library: Additions and fixes #117

Merged
merged 5 commits into from
Nov 3, 2024
Merged
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
127 changes: 127 additions & 0 deletions src/faebryk/library/Analog_Devices_ADM2587EBRWZ.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,127 @@
# 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
from faebryk.libs.util import assert_once # noqa: F401

logger = logging.getLogger(__name__)


class Analog_Devices_ADM2587EBRWZ(Module):
"""
Signal and power isolated RS-485 full/half-duplex transceiver with
±15 kV ESD protection
"""

# ----------------------------------------
# modules, interfaces, parameters
# ----------------------------------------
power_unisolated: F.ElectricPower
power_isolated_out: F.ElectricPower
power_isolated_in: F.ElectricPower
uart: F.UART_Base
read_enable: F.ElectricLogic
write_enable: F.ElectricLogic
rs485: F.RS485HalfDuplex

# ----------------------------------------
# traits
# ----------------------------------------
lcsc_id = L.f_field(F.has_descriptive_properties_defined)({"LCSC": "C12081"})
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: "Analog Devices",
DescriptiveProperties.partno: "ADM2587EBRWZ-REEL7",
}
)
datasheet = L.f_field(F.has_datasheet_defined)(
"https://www.lcsc.com/datasheet/lcsc_datasheet_1809121646_Analog-Devices-ADM2587EBRWZ-REEL7_C12081.pdf" # noqa: E501
)

@L.rt_field
def can_attach_to_footprint(self):
return F.can_attach_to_footprint_via_pinmap(
pinmap={
"1": self.power_unisolated.lv,
"2": self.power_unisolated.hv,
"3": self.power_unisolated.lv,
"4": self.uart.rx.signal,
"5": self.read_enable.signal,
"6": self.write_enable.signal,
"7": self.uart.tx.signal,
"8": self.power_unisolated.hv,
"9": self.power_unisolated.lv,
"10": self.power_unisolated.lv,
"11": self.power_isolated_out.lv,
"12": self.power_isolated_out.hv,
"13": self.rs485.diff_pair.p.signal,
"14": self.power_isolated_out.lv,
"15": self.rs485.diff_pair.n.signal,
"16": self.power_isolated_out.lv,
"17": self.rs485.diff_pair.n.signal,
"18": self.rs485.diff_pair.p.signal,
"19": self.power_isolated_in.hv,
"20": self.power_isolated_out.lv,
}
)

@L.rt_field
def pin_association_heuristic(self):
return F.has_pin_association_heuristic_lookup_table(
mapping={
self.rs485.diff_pair.p.signal: ["A"],
self.rs485.diff_pair.n.signal: ["B"],
self.write_enable.signal: ["DE"],
self.power_unisolated.lv: ["GND1"],
self.power_isolated_out.lv: ["GND2"],
self.read_enable.signal: ["RE#"],
self.uart.rx.signal: ["RXD"],
self.uart.tx.signal: ["TXD"],
self.power_unisolated.hv: ["VCC"],
self.power_isolated_in.hv: ["VISOIN"],
self.power_isolated_out.hv: ["VISOOUT"],
self.rs485.diff_pair.p.signal: ["Y"],
self.rs485.diff_pair.n.signal: ["Z"],
},
accept_prefix=False,
case_sensitive=False,
)

def __init__(self, full_duplex: bool = False):
self._full_duplex = full_duplex
if full_duplex:
raise NotImplementedError("Full duplex RS485 not implemented")

def __preinit__(self):
# ------------------------------------
# connections
# ------------------------------------

# ------------------------------------
# parametrization
# ------------------------------------
self.power_isolated_out.voltage.merge(F.Range.from_center_rel(3.3 * P.V, 0.1))
self.power_unisolated.voltage.merge(F.Range(3.3 * P.V, 5 * P.V))

F.ElectricLogic.connect_all_module_references(
self,
exclude=[
self.power_unisolated,
self.uart,
self.read_enable,
self.write_enable,
],
)

# TODO: ugly
self.rs485.diff_pair.n.reference.connect(self.power_isolated_out)
self.rs485.diff_pair.p.reference.connect(self.power_isolated_out)
87 changes: 87 additions & 0 deletions src/faebryk/library/Analog_Devices_ADM2587EBRWZ_ReferenceDesign.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,87 @@
# This file is part of the faebryk project
# SPDX-License-Identifier: MIT

import itertools
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 Analog_Devices_ADM2587EBRWZ_ReferenceDesign(Module):
"""
Reference implementation of ADM2587EBRWZ isolated RS485 transceiver
"""

# ----------------------------------------
# modules, interfaces, parameters
# ----------------------------------------
transceiver = L.f_field(F.Analog_Devices_ADM2587EBRWZ)(full_duplex=False)

# ----------------------------------------
# traits
# ----------------------------------------
@L.rt_field
def pcb_layout(self):
from faebryk.exporters.pcb.layout.absolute import LayoutAbsolute
from faebryk.exporters.pcb.layout.typehierarchy import LayoutTypeHierarchy

Point = F.has_pcb_position.Point
L = F.has_pcb_position.layer_type
LVL = LayoutTypeHierarchy.Level

return F.has_pcb_layout_defined(
layout=LayoutTypeHierarchy(
layouts=[
LVL(
mod_type=F.Analog_Devices_ADM2587EBRWZ,
layout=LayoutAbsolute(Point((0, 0, 0, L.NONE))),
),
]
)
)

def __preinit__(self):
# ------------------------------------
# connections
# ------------------------------------
self.transceiver.power_isolated_in.connect(self.transceiver.power_isolated_out)

# ------------------------------------
# parametrization
# ------------------------------------
# decoupling unisolated power
power_unisolated_capacitors = (
self.transceiver.power_unisolated.decoupled.decouple()
.specialize(F.MultiCapacitor(4))
.capacitors
)
capacitance_values = [100, 10] # in nF

for cap, value in zip(
power_unisolated_capacitors, itertools.cycle(capacitance_values)
):
cap.capacitance.merge(F.Range.from_center_rel(value * P.nF, 0.05))

# decoupling isolated power in
for i, cap in enumerate(
self.transceiver.power_isolated_in.decoupled.decouple()
.specialize(F.MultiCapacitor(2))
.capacitors
):
cap.capacitance.merge(
F.Range.from_center_rel(capacitance_values[i] * P.nF, 0.05)
)
# decoupling isolated power out
for i, cap in enumerate(
self.transceiver.power_isolated_out.decoupled.decouple()
.specialize(F.MultiCapacitor(2))
.capacitors
):
cap.capacitance.merge(
F.Range.from_center_rel(capacitance_values[i] * P.nF, 0.05)
)
4 changes: 2 additions & 2 deletions src/faebryk/library/CH344Q.py
Original file line number Diff line number Diff line change
@@ -122,8 +122,8 @@ def can_attach_to_footprint(self):
"39": self.uart[0].dtr.signal,
"40": self.uart[0].rts.signal,
"41": self.uart[0].cts.signal,
"42": self.usb.n,
"43": self.usb.p,
"42": self.usb.n.signal,
"43": self.usb.p.signal,
"44": self.test.signal,
"45": self.uart[3].rts.signal,
"46": self.uart[3].cts.signal,
32 changes: 21 additions & 11 deletions src/faebryk/library/CH344Q_ReferenceDesign.py
Original file line number Diff line number Diff line change
@@ -29,10 +29,6 @@ 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
# ----------------------------------------
@@ -55,21 +51,23 @@ def pcb_layout(self):
),
LVL(
mod_type=F.Crystal_Oscillator,
layout=LayoutAbsolute(Point((0, -8, 0, L.NONE))),
layout=LayoutAbsolute(Point((-1, 10.75, 180, L.NONE))),
),
LVL(
mod_type=F.LDO,
layout=LayoutAbsolute(Point((9.5, 0, 0, L.NONE))),
layout=LayoutAbsolute(Point((7.5, -9.25, 270, L.NONE))),
),
LVL(
mod_type=F.LEDIndicator,
layout=LayoutExtrude(
base=Point((-5.75, 7.5, 0, L.NONE)), vector=(-1.75, 0, 90)
base=Point((8, 9.5, 0, L.NONE)),
vector=(-1.75, 0, 90),
reverse_order=True,
),
),
LVL(
mod_type=F.PoweredLED,
layout=LayoutAbsolute(Point((5, -8, 90, L.NONE))),
layout=LayoutAbsolute(Point((-6.5, 9.5, 270, L.NONE))),
),
LVL(
mod_type=F.FilterElectricalRC,
@@ -90,7 +88,7 @@ def __preinit__(self):
self.usb_uart_converter.power.decoupled.decouple().specialize(
F.MultiCapacitor(4)
).set_equal_capacitance_each(F.Range.from_center_rel(100 * P.nF, 0.05))
self.vbus_fused.connect_via(self.ldo, pwr_3v3)
self.usb.usb_if.buspower.connect_via(self.ldo, pwr_3v3)

self.usb.usb_if.d.connect(self.usb_uart_converter.usb)

@@ -101,10 +99,17 @@ def __preinit__(self):

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.oscillator.xtal_if.gnd.connect(pwr_3v3.lv)

self.reset_lowpass.out.connect(self.usb_uart_converter.reset)
self.usb_uart_converter.reset.pulled.pull(up=True)
self.reset_lowpass.in_.signal.connect(
self.usb_uart_converter.reset.reference.hv
)
self.reset_lowpass.in_.reference.connect(
self.usb_uart_converter.reset.reference
)
# TODO: already done by lowpass filter
# self.usb_uart_converter.reset.pulled.pull(up=True)

# ------------------------------------
# parametrization
@@ -143,3 +148,8 @@ def __preinit__(self):
self.reset_lowpass.cutoff_frequency.merge(
F.Range.from_center_rel(100 * P.Hz, 0.1)
)

# Specialize
special = self.reset_lowpass.specialize(F.FilterElectricalRC())
# Construct
special.get_trait(F.has_construction_dependency).construct()
7 changes: 3 additions & 4 deletions src/faebryk/library/Crystal_Oscillator.py
Original file line number Diff line number Diff line change
@@ -19,7 +19,6 @@ class Crystal_Oscillator(Module):
current_limiting_resistor: F.Resistor

xtal_if: F.XtalIF
gnd: F.Electrical

# ----------------------------------------
# parameters
@@ -49,9 +48,9 @@ def __preinit__(self):
# ----------------------------------------
# connections
# ----------------------------------------
self.crystal.gnd.connect(self.gnd)
self.crystal.unnamed[0].connect_via(self.capacitors[0], self.gnd)
self.crystal.unnamed[1].connect_via(self.capacitors[1], self.gnd)
self.crystal.gnd.connect(self.xtal_if.gnd)
self.crystal.unnamed[0].connect_via(self.capacitors[0], self.xtal_if.gnd)
self.crystal.unnamed[1].connect_via(self.capacitors[1], self.xtal_if.gnd)

self.crystal.unnamed[0].connect_via(
self.current_limiting_resistor, self.xtal_if.xout
21 changes: 15 additions & 6 deletions src/faebryk/library/Diodes_Incorporated_AP2552W6_7.py
Original file line number Diff line number Diff line change
@@ -6,8 +6,9 @@
import faebryk.library._F as F # noqa: F401
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
from faebryk.exporters.pcb.layout.heuristic_decoupling import Params
from faebryk.exporters.pcb.layout.next_to import LayoutNextTo
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
@@ -25,10 +26,10 @@ class Diodes_Incorporated_AP2552W6_7(Module):
"""

@assert_once
def set_current_limit(self, current: Parameter[Quantity]) -> None:
def set_current_limit(self, current: Parameter[Quantity]) -> F.Resistor:
self.current_limit.merge(current)

current_limit_setting_resistor = self.add(F.Resistor())
current_limit_setting_resistor = self.ilim.add(F.Resistor())

self.ilim.signal.connect_via(
current_limit_setting_resistor, self.ilim.reference.lv
@@ -41,7 +42,9 @@ def set_current_limit(self, current: Parameter[Quantity]) -> None:
# Rlim_max = (20.08 / (self.current_limit * P.mA)) ^ (1 / 0.904) * P.kohm

# Rlim = Range(Rlim_min, Rlim_max)
Rlim = F.Constant(51 * P.kohm) # TODO: remove: ~0.52A typical current limit
Rlim = F.Range.from_center_rel(
51 * P.kohm, 0.01
) # TODO: remove: ~0.52A typical current limit
if not Rlim.is_subset_of(F.Range(10 * P.kohm, 210 * P.kohm)):
raise ModuleException(
self,
@@ -50,6 +53,8 @@ def set_current_limit(self, current: Parameter[Quantity]) -> None:

current_limit_setting_resistor.resistance.merge(Rlim)

return current_limit_setting_resistor

# ----------------------------------------
# modules, interfaces, parameters
# ----------------------------------------
@@ -105,8 +110,12 @@ def has_defined_layout(self):
layouts = [
LVL(
mod_type=F.Resistor,
layout=LayoutAbsolute(
Point((0, -3, 90, L.NONE)),
layout=LayoutNextTo(
self.ilim.signal,
params=Params(
distance_between_pad_edges=1,
extra_rotation_of_footprint=90,
),
),
),
LVL(
2 changes: 1 addition & 1 deletion src/faebryk/library/ElecSuper_PSM712_ES.py
Original file line number Diff line number Diff line change
@@ -23,7 +23,7 @@ class ElecSuper_PSM712_ES(Module):
# ----------------------------------------
# modules, interfaces, parameters
# ----------------------------------------
rs485: F.RS485
rs485: F.RS485HalfDuplex

# ----------------------------------------
# traits
68 changes: 68 additions & 0 deletions src/faebryk/library/PANASONIC_AQY212EHAX.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,68 @@
# 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, has_part_picked_remove
from faebryk.libs.units import P # noqa: F401

logger = logging.getLogger(__name__)


class PANASONIC_AQY212EHAX(Module):
"""
PhotoMOS GE 1 Form A(SPST-NO) 1.25V 60V 850mΩ 550mA SOP-4-2.54mm Solid State Relays
"""

# ----------------------------------------
# modules, interfaces, parameters
# ----------------------------------------
led: F.LED
switch = L.f_field(F.Switch(F.Electrical))()

# ----------------------------------------
# traits
# ----------------------------------------
lcsc_id = L.f_field(F.has_descriptive_properties_defined)({"LCSC": "C29276"})
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: "PANASONIC",
DescriptiveProperties.partno: "AQY212EHAX",
}
)
datasheet = L.f_field(F.has_datasheet_defined)(
"https://www.lcsc.com/datasheet/lcsc_datasheet_1809191827_PANASONIC-AQY212EHAX_C29276.pdf" # noqa: E501
)

@L.rt_field
def pin_association_heuristic(self):
return F.has_pin_association_heuristic_lookup_table(
mapping={
self.led.anode: ["A"],
self.led.cathode: ["K"],
self.switch.unnamed[0]: ["S"],
self.switch.unnamed[1]: ["S1"],
},
accept_prefix=False,
case_sensitive=False,
)

def __preinit__(self):
# ------------------------------------
# connections
# ------------------------------------
self.led.add(has_part_picked_remove())
self.switch.add(has_part_picked_remove())

# ------------------------------------
# parametrization
# ------------------------------------
self.led.max_current.merge(F.Range(1.2 * P.mA, 3.0 * P.mA))
self.led.reverse_working_voltage.merge(F.Range.upper_bound(5.0 * P.V))
self.led.forward_voltage.merge(F.Range(1.25 * P.V, 2.0 * P.V))
9 changes: 7 additions & 2 deletions src/faebryk/library/PowerSwitchStatic.py
Original file line number Diff line number Diff line change
@@ -20,5 +20,10 @@ def __init__(self) -> None:

def __preinit__(self):
self.power_in.connect(self.switched_power_out)
self.logic_in.reference.connect(self.power_in)
self.logic_in.set(True)
if self._normally_closed:
self.logic_in.reference.hv.connect(self.power_in.hv)
self.logic_in.signal.connect(self.power_in.lv)
else:
self.logic_in.reference.lv.connect(self.power_in.lv)
self.logic_in.signal.connect(self.power_in.hv)
self.logic_in.reference.voltage.merge(self.power_in.voltage)
Original file line number Diff line number Diff line change
@@ -5,5 +5,5 @@
from faebryk.core.moduleinterface import ModuleInterface


class RS485(ModuleInterface):
class RS485HalfDuplex(ModuleInterface):
diff_pair: F.DifferentialPair
4 changes: 2 additions & 2 deletions src/faebryk/library/RS485_Bus_Protection.py
Original file line number Diff line number Diff line change
@@ -40,8 +40,8 @@ def __init__(self, termination: bool = True, polarization: bool = True) -> None:
common_mode_filter: F.Common_Mode_Filter

power: F.ElectricPower
rs485_dfp: F.RS485
rs485_ufp: F.RS485
rs485_dfp: F.RS485HalfDuplex
rs485_ufp: F.RS485HalfDuplex
earth: F.Electrical

@L.rt_field
131 changes: 131 additions & 0 deletions src/faebryk/library/RaspberryPiPico.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,131 @@
# 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.exporters.pcb.layout.heuristic_decoupling import (
LayoutHeuristicElectricalClosenessDecouplingCaps,
)
from faebryk.exporters.pcb.layout.heuristic_pulls import (
LayoutHeuristicElectricalClosenessPullResistors,
)
from faebryk.libs.library import L # noqa: F401
from faebryk.libs.units import P # noqa: F401

logger = logging.getLogger(__name__)


class RaspberryPiPico(Module):
"""
Raspberry Pi Pico clone.
"""

# ----------------------------------------
# modules, interfaces, parameters
# ----------------------------------------
base: F.RaspberryPiPicoBase_ReferenceDesign
header = L.list_f_field(2, F.Header)(horizonal_pin_count=20, vertical_pin_count=1)
usb_connector: F.USB_Type_C_Receptacle_16_pin
# ----------------------------------------
# traits
# ----------------------------------------
datasheet = L.f_field(F.has_datasheet_defined)(
"https://datasheets.raspberrypi.com/pico/pico-datasheet.pdf"
)

@L.rt_field
def designator_prefix(self):
return F.has_designator_prefix_defined(F.has_designator_prefix.Prefix.MOD)

@L.rt_field
def pcb_layout(self):
from faebryk.exporters.pcb.layout.absolute import LayoutAbsolute
from faebryk.exporters.pcb.layout.extrude import LayoutExtrude
from faebryk.exporters.pcb.layout.typehierarchy import LayoutTypeHierarchy

Point = F.has_pcb_position.Point
L = F.has_pcb_position.layer_type
LVL = LayoutTypeHierarchy.Level

layout = F.has_pcb_layout_defined(
layout=LayoutTypeHierarchy(
layouts=[
LVL(
mod_type=F.RaspberryPiPicoBase_ReferenceDesign,
layout=LayoutAbsolute(
Point((0, 0, 0, L.NONE)),
),
),
LVL(
mod_type=F.Header,
layout=LayoutExtrude(
base=Point((0, 0, L.NONE)), vector=(17.78, 0)
),
),
LVL(
mod_type=F.USB_Type_C_Receptacle_16_pin,
layout=LayoutAbsolute(
Point((17.78 / 2, 0, L.NONE)),
),
),
]
)
)

LayoutHeuristicElectricalClosenessDecouplingCaps.add_to_all_suitable_modules(
self
)
LayoutHeuristicElectricalClosenessPullResistors.add_to_all_suitable_modules(
self
)

return layout

def __preinit__(self):
# ------------------------------------
# connections
# ------------------------------------
power_3v3 = self.base.ldo.power_out
gnd = power_3v3.lv

gpio_count = 0
for i, pin in enumerate(self.header[0].contact):
if i in [2, 7, 12, 17]:
pin.connect(gnd)
else:
pin.connect(self.base.rp2040.gpio[gpio_count].signal)
self.base.rp2040.pinmux.enable(self.base.rp2040.gpio[gpio_count])
gpio_count += 1
for i, pin in enumerate(self.header[1].contact):
if i in [2, 7, 12, 17]:
pin.connect(gnd)
elif i == 9:
pin.connect(self.base.rp2040.run.signal)
elif i == 14:
... # TODO: ADC_VREF is not implemented
elif i == 15:
pin.connect(power_3v3.hv)
elif i == 16:
pin.connect(self.base.ldo.enable.signal)
elif i == 18:
pin.connect(self.base.ldo.power_in.hv)
elif i == 19:
pin.connect(self.base.usb.usb_if.buspower.hv)
else:
if gpio_count == 23:
gpio_count += 3 # skip 23, 24, 25
pin.connect(self.base.rp2040.gpio[gpio_count].signal)
self.base.rp2040.pinmux.enable(self.base.rp2040.gpio[gpio_count])
gpio_count += 1

# ------------------------------------
# parametrization
# ------------------------------------
for header in self.header:
header.pin_pitch.merge(2.54 * P.mm)
header.mating_pin_lenght.merge(F.Range.from_center_rel(6 * P.mm, 0.1))
header.pad_type.merge(F.Header.PadType.THROUGH_HOLE)
header.pin_type.merge(F.Header.PinType.MALE)
header.angle.merge(F.Header.Angle.STRAIGHT)
20 changes: 17 additions & 3 deletions src/faebryk/library/RaspberryPiPicoBase_ReferenceDesign.py
Original file line number Diff line number Diff line change
@@ -80,8 +80,15 @@ def __preinit__(self):
)
# self.reference_out.voltage.merge(F.Range(2 * P.V, 3 * P.V))

self.power_in.connect(self.rc_filter.in_.reference)
self.power_in.hv.connect(self.rc_filter.in_.signal)
self.reference_out.hv.connect(self.rc_filter.out.signal)
self.reference_out.lv.connect(self.rc_filter.out.reference.lv)

# Specialize
special = self.rc_filter.specialize(F.FilterElectricalRC())
# Construct
special.get_trait(F.has_construction_dependency).construct()

# ----------------------------------------
# modules, interfaces, parameters
@@ -157,7 +164,8 @@ def __preinit__(self):
)

# USB
terminated_usb = self.usb.usb_if.d.terminated()
terminated_usb = self.rp2040.usb.terminated()
self.add(terminated_usb)
terminated_usb.impedance.merge(F.Range.from_center_rel(27.4 * P.ohm, 0.05))

# Flash
@@ -228,7 +236,7 @@ def __preinit__(self):
self.flash.qspi.connect(self.rp2040.qspi)
self.flash.qspi.chip_select.connect(self.boot_selector.logic_out)

terminated_usb.connect(self.rp2040.usb)
terminated_usb.connect(self.usb.usb_if.d)

self.rp2040.xtal_if.connect(self.clock_source.xtal_if)

@@ -241,7 +249,7 @@ def __preinit__(self):
)

self.status_led.logic_in.connect(self.rp2040.gpio[25])
# self.status_led.power_in.connect(power_3v3)
self.rp2040.pinmux.enable(self.rp2040.gpio[25])

@L.rt_field
def pcb_layout(self):
@@ -305,6 +313,12 @@ def pcb_layout(self):
Point((-3.5, -8, 0, L.NONE)),
),
),
LVL(
mod_type=F.Resistor,
layout=LayoutExtrude(
base=Point((4, -9.75, 0, L.NONE)), vector=(0, 1.25, 180)
),
),
LVL(
mod_type=self.PICO_DebugHeader,
layout=LayoutAbsolute(
75 changes: 75 additions & 0 deletions src/faebryk/library/SK6812.py
Original file line number Diff line number Diff line change
@@ -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.picker.picker import DescriptiveProperties
from faebryk.libs.units import P # noqa: F401

logger = logging.getLogger(__name__)


class SK6812(Module):
"""
RGB digital LED with SK6812 controller
SMD5050-4P
RGB LEDs(Built-in IC) ROHS
"""

# ----------------------------------------
# modules, interfaces, parameters
# ----------------------------------------
power: F.ElectricPower
data_in: F.ElectricLogic
data_out: F.ElectricLogic

# ----------------------------------------
# traits
# ----------------------------------------
@L.rt_field
def can_bridge(self):
return F.can_bridge_defined(self.data_in, self.data_out)

lcsc_id = L.f_field(F.has_descriptive_properties_defined)({"LCSC": "C5378720"})
designator_prefix = L.f_field(F.has_designator_prefix_defined)(
F.has_designator_prefix.Prefix.LED
)
descriptive_properties = L.f_field(F.has_descriptive_properties_defined)(
{
DescriptiveProperties.manufacturer: "OPSCO Optoelectronics",
DescriptiveProperties.partno: "SK6812",
}
)
datasheet = L.f_field(F.has_datasheet_defined)(
"https://wmsc.lcsc.com/wmsc/upload/file/pdf/v2/lcsc/2303300930_OPSCO-Optoelectronics-SK6812_C5378720.pdf" # noqa: E501
)

@L.rt_field
def pin_association_heuristic(self):
return F.has_pin_association_heuristic_lookup_table(
mapping={
self.data_in.signal: ["DIN"],
self.data_out.signal: ["DOUT"],
self.power.lv: ["VSS", "GND"],
self.power.hv: ["VDD"],
},
accept_prefix=False,
case_sensitive=False,
)

def __preinit__(self):
# ------------------------------------
# connections
# ------------------------------------
self.power.decoupled.decouple()
F.ElectricLogic.connect_all_module_references(self, gnd_only=True)
F.ElectricLogic.connect_all_module_references(self, exclude=[self.power])

# ------------------------------------
# parametrization
# ------------------------------------
self.power.voltage.merge(F.Range(3.3 * P.V, 5.5 * P.V))
2 changes: 1 addition & 1 deletion src/faebryk/library/TD541S485H.py
Original file line number Diff line number Diff line change
@@ -16,7 +16,7 @@ class TD541S485H(Module):
power_iso_in: F.ElectricPower
power_iso_out: F.ElectricPower
uart: F.UART_Base
rs485: F.RS485
rs485: F.RS485HalfDuplex
read_enable: F.ElectricLogic
write_enable: F.ElectricLogic

36 changes: 30 additions & 6 deletions src/faebryk/library/TPS2116.py
Original file line number Diff line number Diff line change
@@ -2,12 +2,13 @@
# SPDX-License-Identifier: MIT

import logging
from enum import Enum
from enum import Enum, auto

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
from faebryk.libs.units import P
from faebryk.libs.util import assert_once # noqa: F401

logger = logging.getLogger(__name__)

@@ -35,14 +36,37 @@ class Mode(Enum):
Disables device.
"""

def set_mode(self, mode: Mode):
class SwitchoverVoltage(Enum):
_5V = auto()
_3V3 = auto()
_1V8 = auto()
CUSTOM = auto()

@assert_once
def set_mode(self, mode: Mode, switchover_voltage: SwitchoverVoltage):
if mode == self.Mode.PRIORITY:
self.mode.signal.connect(self.power_in[1].hv)
resistor_devider = self.add(F.ResistorVoltageDivider())
resistor_devider = self.select.add(F.ResistorVoltageDivider())
self.power_in[0].hv.connect_via(resistor_devider, self.select.signal)
resistor_devider.node[2].connect(self.mode.reference.lv)
resistor_devider.node[2].connect(self.power_in[0].lv)
if switchover_voltage != self.SwitchoverVoltage.CUSTOM:
resistor_devider.resistor[1].resistance.merge(
F.Range.from_center_rel(5 * P.kohm, 0.01)
)
if switchover_voltage == self.SwitchoverVoltage._5V:
resistor_devider.resistor[0].resistance.merge(
F.Range.from_center_rel(16.9 * P.kohm, 0.01)
)
elif switchover_voltage == self.SwitchoverVoltage._3V3:
resistor_devider.resistor[0].resistance.merge(
F.Range.from_center_rel(9.53 * P.kohm, 0.01)
)
elif switchover_voltage == self.SwitchoverVoltage._1V8:
resistor_devider.resistor[0].resistance.merge(
F.Range.from_center_rel(2.80 * P.kohm, 0.01)
)
else:
pass
raise NotImplementedError(f"Mode {mode} not implemented")

# ----------------------------------------
# modules, interfaces, parameters
2 changes: 1 addition & 1 deletion src/faebryk/library/UART_RS485.py
Original file line number Diff line number Diff line change
@@ -14,7 +14,7 @@
class UART_RS485(Module):
power: F.ElectricPower
uart: F.UART_Base
rs485: F.RS485
rs485: F.RS485HalfDuplex
read_enable: F.ElectricLogic
write_enable: F.ElectricLogic

23 changes: 14 additions & 9 deletions src/faebryk/library/USB2514B.py
Original file line number Diff line number Diff line change
@@ -142,10 +142,11 @@ def set_non_removable_ports(
# ----------------------------------------
# modules, interfaces, parameters
# ----------------------------------------
power_3v3: F.ElectricPower
power_3v3_regulator: F.ElectricPower
power_3v3_analog: F.ElectricPower
power_pll: F.ElectricPower
power_core: F.ElectricPower
power_io: F.ElectricPower

usb_upstream: F.USB2_0_IF.Data
configurable_downstream_usb = L.list_field(4, ConfigurableUSB)
@@ -192,19 +193,19 @@ def can_attach_to_footprint(self):
"2": self.configurable_downstream_usb[0].usb.p.signal,
"3": self.configurable_downstream_usb[1].usb.n.signal,
"4": self.configurable_downstream_usb[1].usb.p.signal,
"5": self.power_3v3.hv,
"5": self.power_3v3_analog.hv,
"6": self.configurable_downstream_usb[2].usb.n.signal,
"7": self.configurable_downstream_usb[2].usb.p.signal,
"8": self.configurable_downstream_usb[3].usb.n.signal,
"9": self.configurable_downstream_usb[3].usb.p.signal,
"10": self.power_3v3.hv,
"10": self.power_3v3_analog.hv,
"11": self.test,
"12": self.configurable_downstream_usb[
0
].battery_charging_enable.signal,
"13": self.configurable_downstream_usb[0].over_current_sense.signal,
"14": self.power_core.hv,
"15": self.power_3v3.hv,
"15": self.power_3v3_regulator.hv,
"16": self.configurable_downstream_usb[
1
].battery_charging_enable.signal,
@@ -218,7 +219,7 @@ def can_attach_to_footprint(self):
].battery_charging_enable.signal,
"21": self.configurable_downstream_usb[3].over_current_sense.signal,
"22": self.usb_removability_configuration_intput[1].signal,
"23": self.power_3v3.hv,
"23": self.power_io.hv,
"24": self.configuration_source_input[0].signal,
"25": self.configuration_source_input[1].signal,
"26": self.reset.signal,
@@ -231,8 +232,8 @@ def can_attach_to_footprint(self):
"33": self.xtal_if.xin,
"34": self.power_pll.hv,
"35": self.usb_bias_resistor_input.signal,
"36": self.power_3v3.hv,
"37": self.power_3v3.lv,
"36": self.power_3v3_analog.hv,
"37": self.power_3v3_analog.lv,
}
)

@@ -305,7 +306,7 @@ def pin_association_heuristic(self):
],
self.usb_upstream.p.signal: ["USBDP_UP"],
self.vbus_detect.signal: ["VBUS_DET"],
self.power_3v3.hv: ["VDD33"],
self.power_3v3_regulator.hv: ["VDD33"],
self.power_3v3_analog.hv: ["VDDA33"],
self.xtal_if.xin: ["XTALIN/CLKIN"],
self.xtal_if.xout: ["XTALOUT"],
@@ -333,6 +334,7 @@ def __preinit__(self):
exclude={
self.power_pll,
self.power_core,
self.power_io,
self.vbus_detect,
self.local_power_detection,
},
@@ -347,5 +349,8 @@ def __preinit__(self):
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_regulator.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))
self.power_io.voltage.merge(F.Range.from_center(3.3 * P.V, 0.3 * P.V))
110 changes: 89 additions & 21 deletions src/faebryk/library/USB2514B_ReferenceDesign.py
Original file line number Diff line number Diff line change
@@ -39,6 +39,24 @@ class PowerSwitchedUSB2_0(Module):
def can_bridge(self):
return F.can_bridge_defined(self.usb_ufp_d, self.usb_dfp_d)

@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( # Diodes Incorporated AP2552W6_7
mod_type=F.Diodes_Incorporated_AP2552W6_7,
layout=LayoutAbsolute(Point((0, 0, 0, L.NONE))),
),
LVL( # PoweredLED
mod_type=F.PoweredLED,
layout=LayoutAbsolute(Point((0, -2.75, 180, L.NONE))),
),
]
return F.has_pcb_layout_defined(LayoutTypeHierarchy(layouts))

def __preinit__(self):
# ----------------------------------------
# parametrization
@@ -88,40 +106,52 @@ def has_defined_layout(self):

layouts = [
LVL( # USB2514B
mod_type=F.USB2514B, layout=LayoutAbsolute(Point((0, 0, 0, L.NONE)))
),
LVL( # PowerSwitchedUSB2_0
mod_type=self.PowerSwitchedUSB2_0,
layout=LayoutExtrude(base=Point((11, -9, 0, L.NONE)), vector=(0, 6, 0)),
children_layout=LayoutTypeHierarchy(
layouts=[
LVL( # Diodes Incorporated AP2552W6_7
mod_type=F.Diodes_Incorporated_AP2552W6_7,
layout=LayoutAbsolute(Point((0, 0, 0, L.NONE))),
),
LVL( # PoweredLED
mod_type=F.PoweredLED,
layout=LayoutAbsolute(Point((0, -2.75, 180, L.NONE))),
),
]
layout=LayoutExtrude(
base=Point((13.5, 11, 180, L.NONE)),
vector=(9, 0, 0),
reverse_order=True,
),
),
LVL( # LEDIndicator
mod_type=type(self.suspend_indicator),
layout=LayoutAbsolute(Point((-6.5, -5.75, 0, L.NONE))),
),
LVL( # PoweredLED
mod_type=type(self.power_3v3_indicator),
layout=LayoutAbsolute(Point((5.5, 6, 180, L.NONE))),
layout=LayoutAbsolute(Point((10.25, -4, 0, L.NONE))),
),
LVL( # ResistorVoltageDivider
mod_type=type(self.vbus_voltage_divider),
layout=LayoutAbsolute(Point((-10, 0, 0, L.NONE))),
layout=LayoutAbsolute(Point((-3, -5.25, 270, L.NONE))),
children_layout=LayoutTypeHierarchy(
layouts=[
LVL( # Resistor
mod_type=F.Resistor,
layout=LayoutExtrude(
base=Point((0, 0, 180, L.NONE)),
vector=(0, -1.25, 180),
dynamic_rotation=True,
reverse_order=True,
),
),
]
),
),
LVL( # Resistor
mod_type=type(self.bias_resistor),
layout=LayoutAbsolute(Point((-4.5, 3, 270, L.NONE))),
),
LVL( # LDO
mod_type=F.LDO,
layout=LayoutAbsolute(Point((1.5, 7, 270, L.NONE))),
layout=LayoutAbsolute(Point((12, 0, 180, L.NONE))),
),
LVL( # Crystal Oscillator
mod_type=F.Crystal_Oscillator,
layout=LayoutAbsolute(Point((-7.5, 0, 270, L.NONE))),
layout=LayoutAbsolute(Point((-10, 0, 270, L.NONE))),
children_layout=LayoutTypeHierarchy(
layouts=[
LVL(
@@ -142,9 +172,6 @@ def has_defined_layout(self):
],
),
),
LVL( # USB2514B
mod_type=F.USB2514B, layout=LayoutAbsolute(Point((0, 0, 0, L.NONE)))
),
]

return F.has_pcb_layout_defined(LayoutTypeHierarchy(layouts))
@@ -203,20 +230,54 @@ def __preinit__(self):
F.Range.from_center_rel(100 * P.nF, 0.1)
)

# Hub controller power rails decoupling
regulator_decoupling_caps = (
self.hub_controller.power_3v3_regulator.decoupled.decouple().specialize(
F.MultiCapacitor(2)
)
)
regulator_decoupling_caps.capacitors[0].capacitance.merge(
F.Range.from_center_rel(100 * P.nF, 0.05)
)
regulator_decoupling_caps.capacitors[1].capacitance.merge(
F.Range.from_center_rel(4.7 * P.uF, 0.05)
)
self.hub_controller.power_3v3_analog.decoupled.decouple().specialize(
F.MultiCapacitor(4)
).set_equal_capacitance_each(F.Range.from_center_rel(100 * P.nF, 0.05))
self.hub_controller.power_pll.decoupled.decouple().capacitance.merge(
F.Range.from_center_rel(100 * P.nF, 0.5)
)
self.hub_controller.power_core.decoupled.decouple().capacitance.merge(
F.Range.from_center_rel(100 * P.nF, 0.5)
)
self.hub_controller.power_io.decoupled.decouple().capacitance.merge(
F.Range.from_center_rel(100 * P.nF, 0.5)
)

# VBUS detect
for r in self.vbus_voltage_divider.resistor:
r.resistance.merge(F.Range.from_center_rel(100 * P.kohm, 0.01))

# reset
self.hub_controller.reset.set_weak(on=True).resistance.merge(
F.Range.from_center_rel(100 * P.kohm, 0.01)
)

# ----------------------------------------
# connections
# ----------------------------------------
# power
vbus.connect(self.ldo_3v3.power_in)
power_3v3.connect(
self.hub_controller.power_3v3,
self.hub_controller.power_3v3_regulator,
self.hub_controller.power_3v3_analog,
)
self.ldo_3v3.enable_output()

# crystal oscillator
self.crystal_oscillator.xtal_if.connect(self.hub_controller.xtal_if)
self.crystal_oscillator.gnd.connect(gnd)
self.crystal_oscillator.xtal_if.gnd.connect(gnd)

for i, dfp in enumerate(self.usb_dfp):
# USB data
@@ -239,6 +300,13 @@ def __preinit__(self):
self.bias_resistor, gnd
) # TODO: replace with pull?

# voltage divider
vbus.hv.connect_via(
self.vbus_voltage_divider, self.hub_controller.vbus_detect.signal
)
self.vbus_voltage_divider.node[2].connect(vbus.lv)

# USB upstream
self.usb_ufp.usb_if.d.connect(self.hub_controller.usb_upstream)

# LEDs
6 changes: 3 additions & 3 deletions src/faebryk/library/USB_RS485.py
Original file line number Diff line number Diff line change
@@ -17,7 +17,7 @@ class USB_RS485(Module):
termination: F.Resistor
polarization = L.list_field(2, F.Resistor)
usb: F.USB2_0
rs485: F.RS485
rs485: F.RS485HalfDuplex

def __preinit__(self):
self.usb.connect(self.usb_uart.usb)
@@ -36,11 +36,11 @@ def __preinit__(self):
)

# connect polarization resistors to RS485 A and B
self.uart_rs485.rs485.diff_pair.p.connect_via(
self.uart_rs485.rs485.diff_pair.p.signal.connect_via(
self.polarization[0],
self.uart_rs485.power.hv,
)
self.uart_rs485.rs485.diff_pair.n.connect_via(
self.uart_rs485.rs485.diff_pair.n.signal.connect_via(
self.polarization[1],
self.uart_rs485.power.lv,
)
17 changes: 11 additions & 6 deletions src/faebryk/library/_F.py
Original file line number Diff line number Diff line change
@@ -18,14 +18,14 @@
from faebryk.library.TBD import TBD
from faebryk.library.Range import Range
from faebryk.library.has_designator_prefix import has_designator_prefix
from faebryk.library.has_pcb_position import has_pcb_position
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_construction_dependency import has_construction_dependency
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
from faebryk.library.has_footprint import has_footprint
from faebryk.library.Mechanical import Mechanical
from faebryk.library.has_overriden_name import has_overriden_name
@@ -49,12 +49,12 @@
from faebryk.library.ANY import ANY
from faebryk.library.Electrical import Electrical
from faebryk.library.has_designator_prefix_defined import has_designator_prefix_defined
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_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.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_single_electric_reference_defined import has_single_electric_reference_defined
from faebryk.library.Filter import Filter
from faebryk.library.Logic import Logic
@@ -149,6 +149,7 @@
from faebryk.library.SignalElectrical import SignalElectrical
from faebryk.library.can_be_decoupled_rails import can_be_decoupled_rails
from faebryk.library.ButtonCell import ButtonCell
from faebryk.library.PANASONIC_AQY212EHAX import PANASONIC_AQY212EHAX
from faebryk.library.PoweredLED import PoweredLED
from faebryk.library.DifferentialPair import DifferentialPair
from faebryk.library.ElectricLogic import ElectricLogic
@@ -157,7 +158,7 @@
from faebryk.library.PowerMux import PowerMux
from faebryk.library.Shenzhen_Kinghelm_Elec_KH_BNC75_3511 import Shenzhen_Kinghelm_Elec_KH_BNC75_3511
from faebryk.library.Ethernet import Ethernet
from faebryk.library.RS485 import RS485
from faebryk.library.RS485HalfDuplex import RS485HalfDuplex
from faebryk.library.USB_Type_C_Receptacle_16_pin import USB_Type_C_Receptacle_16_pin
from faebryk.library.USB_Type_C_Receptacle_24_pin import USB_Type_C_Receptacle_24_pin
from faebryk.library.Diodes_Incorporated_AP2552W6_7 import Diodes_Incorporated_AP2552W6_7
@@ -169,6 +170,7 @@
from faebryk.library.MultiSPI import MultiSPI
from faebryk.library.Pinmux import Pinmux
from faebryk.library.RS232 import RS232
from faebryk.library.SK6812 import SK6812
from faebryk.library.SK9822_EC20 import SK9822_EC20
from faebryk.library.SNx4LVC541A import SNx4LVC541A
from faebryk.library.SPI import SPI
@@ -198,6 +200,7 @@
from faebryk.library.RP2040Pinmux import RP2040Pinmux
from faebryk.library.DE9RS232Connector import DE9RS232Connector
from faebryk.library.SWDConnector import SWDConnector
from faebryk.library.Analog_Devices_ADM2587EBRWZ import Analog_Devices_ADM2587EBRWZ
from faebryk.library.HLK_LD2410B_P import HLK_LD2410B_P
from faebryk.library.PM1006 import PM1006
from faebryk.library.TD541S485H import TD541S485H
@@ -215,6 +218,7 @@
from faebryk.library.Winbond_Elec_W25Q128JVSIQ import Winbond_Elec_W25Q128JVSIQ
from faebryk.library.Winbond_W25Q16JVUXIQ import Winbond_W25Q16JVUXIQ
from faebryk.library.RP2040 import RP2040
from faebryk.library.Analog_Devices_ADM2587EBRWZ_ReferenceDesign import Analog_Devices_ADM2587EBRWZ_ReferenceDesign
from faebryk.library.CH344 import CH344
from faebryk.library.SP3243E import SP3243E
from faebryk.library.CBM9002A_56ILG import CBM9002A_56ILG
@@ -252,3 +256,4 @@
from faebryk.library.CH344Q_ReferenceDesign import CH344Q_ReferenceDesign
from faebryk.library.RaspberryPiPicoBase_ReferenceDesign import RaspberryPiPicoBase_ReferenceDesign
from faebryk.library.USB2514B_ReferenceDesign import USB2514B_ReferenceDesign
from faebryk.library.RaspberryPiPico import RaspberryPiPico