Skip to content

Commit ae7e116

Browse files
authored
Ethernet + non-isolated PoE example (#523)
Changes the FLIR example to be PoE + Ethernet using W5000. Adds Ethernet port / link types in the example (for now, until validated in hardware). Completed board layout. Really more of a parts test omnibus board, it's not a pretty layout. In retrospect, this should have been a four-layer board. Other changes: - Add Hy931147c magjack - Add W5500 SPI ethernet PHY - Add Tps2378 standalone PoE PD controler - Add Lmr39020 high voltage buck converter - Add Ground and Voltage jumpers - Add Common implicit tag for AnalogSetpointResistor - Fix FUSB302 to use 1uF secondary vdd cap per datasheet
1 parent 3fc9d5d commit ae7e116

18 files changed

Lines changed: 43067 additions & 13764 deletions

edg/abstract_parts/Jumper.py

Lines changed: 35 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,6 +16,41 @@ def __init__(self) -> None:
1616
self.b = self.Port(Passive())
1717

1818

19+
class GroundJumper(TypedJumper, Block):
20+
def __init__(self) -> None:
21+
super().__init__()
22+
self.input = self.Port(Ground(), [Input])
23+
self.output = self.Port(Ground(), [Output])
24+
25+
@override
26+
def contents(self) -> None:
27+
super().contents()
28+
self.device = self.Block(Jumper())
29+
self.connect(self.input.net, self.device.a)
30+
self.connect(self.output.net, self.device.b)
31+
32+
33+
class VoltageJumper(TypedJumper, Block):
34+
def __init__(self) -> None:
35+
super().__init__()
36+
self.input = self.Port(VoltageSink(current_draw=RangeExpr(), reverse_voltage_out=RangeExpr()), [Input])
37+
self.output = self.Port(
38+
VoltageSource(
39+
voltage_out=self.input.link().voltage, reverse_current_draw=self.input.link().reverse_current_drawn
40+
),
41+
[Output],
42+
)
43+
44+
@override
45+
def contents(self) -> None:
46+
super().contents()
47+
self.device = self.Block(Jumper())
48+
self.assign(self.input.current_draw, self.output.link().current_drawn)
49+
self.assign(self.input.reverse_voltage_out, self.output.link().reverse_voltage)
50+
self.connect(self.input.net, self.device.a)
51+
self.connect(self.output.net, self.device.b)
52+
53+
1954
class DigitalJumper(TypedJumper, Block):
2055
def __init__(self) -> None:
2156
super().__init__()

edg/abstract_parts/Resistor.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -384,7 +384,7 @@ def symbol_pinning(self, symbol_name: str) -> Mapping[str, BasePort]:
384384
def __init__(self, resistance: RangeLike) -> None:
385385
super().__init__()
386386

387-
self.gnd = self.Port(Ground())
387+
self.gnd = self.Port(Ground(), [Common])
388388
self.io = self.Port(AnalogSink(impedance=RangeExpr()), [InOut])
389389

390390
voltage = self.io.link().voltage - self.gnd.link().voltage

edg/abstract_parts/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -120,7 +120,7 @@
120120
CanDiffTestPoint,
121121
)
122122
from .TestPoint import AnalogCoaxTestPoint
123-
from .Jumper import Jumper, DigitalJumper
123+
from .Jumper import Jumper, GroundJumper, VoltageJumper, DigitalJumper
124124
from .PassiveConnector import PassiveConnector, FootprintPassiveConnector
125125

126126
from .UsbConnectors import UsbConnector, UsbHostConnector, UsbDeviceConnector, UsbEsdDiode

edg/parts/interface/UsbPd_Fusb302b.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,6 @@ def contents(self) -> None:
7676
# and the bulk capacitor, which we hope will be elsewhere
7777
self.vdd_cap = ElementDict[DecouplingCapacitor]()
7878
self.vdd_cap[0] = self.Block(DecouplingCapacitor(0.1 * uFarad(tol=0.2))).connected(self.gnd, self.pwr)
79-
self.vdd_cap[1] = self.Block(DecouplingCapacitor(10 * uFarad(tol=0.2))).connected(self.gnd, self.pwr)
79+
self.vdd_cap[1] = self.Block(DecouplingCapacitor(1.0 * uFarad(tol=0.2))).connected(self.gnd, self.pwr)
8080

8181
# Crecv is specified in the reference schematic, but doesn't show up on open-source example designs

edg/parts/power/converter/TexasInstruments_Buck.py

Lines changed: 124 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
from typing import Any
2+
13
from typing_extensions import override
24

35
from ....circuits import *
@@ -221,3 +223,125 @@ def generate(self) -> None:
221223
self.en_res = self.Block(PullupResistor(resistance=510 * kOhm(tol=0.05))).connected(
222224
self.pwr_in_zener_clamp.pwr_out, self.ic.en
223225
)
226+
227+
228+
class Lmr38020_Device(InternalSubcircuit, JlcPart, FootprintBlock):
229+
def __init__(self) -> None:
230+
super().__init__()
231+
self.gnd = self.Port(Ground(), [Common])
232+
self.vin = self.Port(VoltageSink(voltage_limits=(4.2, 80) * Volt, current_draw=RangeExpr()), [Power])
233+
self.sw = self.Port(VoltageSource(voltage_out=self.vin.link().voltage.hull(self.gnd.link().voltage)))
234+
self.fb = self.Port(AnalogSink(impedance=(10, float("inf")) * MOhm)) # assumed given RFbb maximum spec
235+
self.boot = self.Port(
236+
VoltageSink(
237+
voltage_limits=self.sw.link().voltage + (-0.3, 5.5) * Volt,
238+
reverse_voltage_out=(3.8, 5.5) * Volt, # assumed from UVLO to BOOT-SW abs max
239+
reverse_current_limits=0 * Amp(tol=0),
240+
)
241+
)
242+
self.en = self.Port(
243+
DigitalSink.from_supply(
244+
self.gnd, self.vin, voltage_limit_tolerance=(-0.3, 0.3) * Volt, input_threshold_abs=(0.95, 1.4) * Volt
245+
)
246+
)
247+
self.rt = self.Port(AnalogSource()) # for timing
248+
self.pg = self.Port(DigitalSource.low_from_supply(self.gnd), optional=True) # may be left open
249+
250+
@override
251+
def contents(self) -> None:
252+
super().contents()
253+
self.assign(
254+
self.vin.current_draw, self.sw.link().current_drawn + (3, 40) * uAmp
255+
) # shutdown to non-switching Iq
256+
self.footprint(
257+
"U",
258+
"Package_SO:HSOP-8-1EP_3.9x4.9mm_P1.27mm_EP2.41x3.1mm_ThermalVias",
259+
{
260+
"1": self.gnd,
261+
"2": self.en,
262+
"3": self.vin,
263+
"4": self.rt,
264+
"5": self.fb,
265+
"6": self.pg,
266+
"7": self.boot,
267+
"8": self.sw,
268+
"9": self.gnd, # EP
269+
},
270+
mfr="Texas Instruments",
271+
part="LMR38020SDDAR",
272+
datasheet="https://www.ti.com/lit/ds/symlink/lmr38020.pdf",
273+
)
274+
self.assign(self.lcsc_part, "C3192337")
275+
self.assign(self.actual_basic_part, False)
276+
277+
278+
class Lmr38020(VoltageRegulatorEnableWrapper, DiscreteBuckConverter, GeneratorBlock):
279+
"""4.2-80 V, 2 A synchronous buck converter in SO-8 with thermal pad.
280+
Adjustable frequency, defaulting to 400kHz per the datasheet example."""
281+
282+
def __init__(self, *, frequency: RangeLike = 400 * kHertz(tol=0.1), **kwargs: Any) -> None:
283+
super().__init__(**kwargs)
284+
self.frequency = self.ArgParameter(frequency)
285+
self.generator_param(self.frequency)
286+
287+
self.ic = self.Block(Lmr38020_Device())
288+
self.connect(self.pwr_in, self.ic.vin)
289+
self.connect(self.gnd, self.ic.gnd)
290+
291+
self.pg = self.Export(self.ic.pg, optional=True, doc="Open-drain active-high power-good flag")
292+
293+
@override
294+
def _generator_inner_reset_pin(self) -> Port[DigitalLink]:
295+
return self.ic.en
296+
297+
@override
298+
def generate(self) -> None:
299+
super().generate()
300+
301+
with self.implicit_connect(
302+
ImplicitConnect(self.pwr_in, [Power]),
303+
ImplicitConnect(self.gnd, [Common]),
304+
) as imp:
305+
self.fb = imp.Block(
306+
FeedbackVoltageDivider(
307+
output_voltage=(0.985, 1.015) * Volt, # across temperature range
308+
impedance=(10, 100) * kOhm,
309+
assumed_input_voltage=self.output_voltage,
310+
)
311+
)
312+
self.connect(self.fb.input, self.pwr_out)
313+
self.connect(self.fb.output, self.ic.fb)
314+
315+
self.hf_cap = imp.Block(DecouplingCapacitor(capacitance=0.1 * uFarad(tol=0.2)))
316+
self.boot_cap = self.Block(BootstrapCapacitor(capacitance=0.1 * uFarad(tol=0.2))).connected(
317+
self.ic.sw, self.ic.boot
318+
)
319+
320+
target_frequency = self.get(self.frequency)
321+
rt_resistance = (
322+
30970 * ((target_frequency.upper / 1000) ** -1.027) * 1000,
323+
30970 * ((target_frequency.lower / 1000) ** -1.027) * 1000,
324+
)
325+
self.rt = imp.Block(AnalogSetpointResistor(rt_resistance)).connected(io=self.ic.rt)
326+
self.assign(
327+
self.actual_frequency, 30970 / (self.rt.actual_resistance / 1000) * 1000
328+
) # TODO add exponent term when the infrastructure supports it
329+
330+
self.power_path = imp.Block(
331+
BuckConverterPowerPath(
332+
self.pwr_in.link().voltage,
333+
self.fb.actual_input_voltage,
334+
self.actual_frequency,
335+
self.pwr_out.link().current_drawn,
336+
(0, 1.8) * Amp, # low-side min switch current limit
337+
input_voltage_ripple=self.input_ripple_limit,
338+
output_voltage_ripple=self.output_ripple_limit,
339+
dutycycle_limit=(0, 0.97), # goes into PFM at low duty cycles
340+
)
341+
)
342+
# ForcedVoltage needed to provide a voltage value so current downstream can be calculated
343+
# and then the power path can generate
344+
(self.forced_out,), _ = self.chain(
345+
self.power_path.pwr_out, self.Block(ForcedVoltage(self.fb.actual_input_voltage)), self.pwr_out
346+
)
347+
self.connect(self.power_path.switch, self.ic.sw)

edg/parts/power/converter/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from .LinearRegulators import Ld1117, Ldl1117, Ap2204k, Ap7215, Xc6206p, Xc6209, Ap2210, Lp5907, Tlv757p, L78l
2-
from .TexasInstruments_Buck import Tps561201, Tps54202h
2+
from .TexasInstruments_Buck import Tps561201, Tps54202h, Lmr38020
33
from .Mp2722 import Mp2722
44
from .Ap3418 import Ap3418
55
from .AnalogDevices_Boost import Ltc3429

examples/IotFan/IotFan.net.ref

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -446,14 +446,14 @@
446446
(tstamps "15a803ba"))
447447
(comp (ref "FC25")
448448
(value "pd.vdd_cap[1]")
449-
(footprint "Capacitor_SMD:C_0805_2012Metric")
449+
(footprint "Capacitor_SMD:C_0603_1608Metric")
450450
(property (name "Sheetname") (value "pd"))
451451
(property (name "Sheetfile") (value "edg.parts.interface.UsbPd_Fusb302b.Fusb302b"))
452452
(property (name "edg_path") (value "pd.vdd_cap[1].cap"))
453453
(property (name "edg_short_path") (value "pd.vdd_cap[1]"))
454454
(property (name "edg_refdes") (value "FC25"))
455-
(property (name "edg_part") (value "CL21A106KAYNNNE (Samsung Electro-Mechanics)"))
456-
(property (name "edg_value") (value "X5R 25V ±10% 10uF 0805 Multilayer Ceramic Capacitors MLCC - SMD/SMT ROHS"))
455+
(property (name "edg_part") (value "CL10A105KB8NNNC (Samsung Electro-Mechanics)"))
456+
(property (name "edg_value") (value "50V 1uF X5R ±10% 0603 Multilayer Ceramic Capacitors MLCC - SMD/SMT ROHS"))
457457
(sheetpath (names "/pd/") (tstamps "/014600d5/"))
458458
(tstamps "15aa03bb"))
459459
(comp (ref "FR19")

examples/IotFan/IotFan.svgpcb.js

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -182,12 +182,12 @@ const FU8 = board.add(WQFN_14_1EP_2_5x2_5mm_P0_5mm_EP1_45x1_45mm, {
182182
})
183183
// pd.vdd_cap[0].cap
184184
const FC24 = board.add(C_0603_1608Metric, {
185-
translate: pt(2.366, 1.021), rotate: 0,
185+
translate: pt(2.193, 1.021), rotate: 0,
186186
id: 'FC24'
187187
})
188188
// pd.vdd_cap[1].cap
189-
const FC25 = board.add(C_0805_2012Metric, {
190-
translate: pt(2.202, 1.031), rotate: 0,
189+
const FC25 = board.add(C_0603_1608Metric, {
190+
translate: pt(2.349, 1.021), rotate: 0,
191191
id: 'FC25'
192192
})
193193
// spk_dac.rc.r

examples/IotIron/IotIron.net.ref

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -386,14 +386,14 @@
386386
(tstamps "15a803ba"))
387387
(comp (ref "IC12")
388388
(value "pd.vdd_cap[1]")
389-
(footprint "Capacitor_SMD:C_0805_2012Metric")
389+
(footprint "Capacitor_SMD:C_0603_1608Metric")
390390
(property (name "Sheetname") (value "pd"))
391391
(property (name "Sheetfile") (value "edg.parts.interface.UsbPd_Fusb302b.Fusb302b"))
392392
(property (name "edg_path") (value "pd.vdd_cap[1].cap"))
393393
(property (name "edg_short_path") (value "pd.vdd_cap[1]"))
394394
(property (name "edg_refdes") (value "IC12"))
395-
(property (name "edg_part") (value "CL21A106KAYNNNE (Samsung Electro-Mechanics)"))
396-
(property (name "edg_value") (value "X5R 25V ±10% 10uF 0805 Multilayer Ceramic Capacitors MLCC - SMD/SMT ROHS"))
395+
(property (name "edg_part") (value "CL10A105KB8NNNC (Samsung Electro-Mechanics)"))
396+
(property (name "edg_value") (value "50V 1uF X5R ±10% 0603 Multilayer Ceramic Capacitors MLCC - SMD/SMT ROHS"))
397397
(sheetpath (names "/pd/") (tstamps "/014600d5/"))
398398
(tstamps "15aa03bb"))
399399
(comp (ref "IU5")

0 commit comments

Comments
 (0)