Skip to content

Commit 3fc9d5d

Browse files
authored
Example boards layout and library fixes (#519)
Board layouts for the IoT fan / addressable strip driver, BLE joystick v2, and keyboard. Library changes: - Add PMOS only load switch - Changes the keyboard switchmatrix args to be ncols first (x dimension) and for internal switch ordering (which matters for refdesing) to advance along a row - Add option to flip sense resistor in INA219. Not used. - Change INA219 to use sense_pwr_in and sense_pwr_out, for consistency. - Add 2mm header, socket, and socket-pair - Split out JST and Molex connectors
1 parent 6356d57 commit 3fc9d5d

50 files changed

Lines changed: 163545 additions & 23680 deletions

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

edg/circuits/DigitalAmplifiers.py

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,55 @@
55
from ..abstract_parts import *
66

77

8+
class LoadSwitch(PowerSwitch, Block):
9+
"""A high-side PMOS load switch, for when Vcontrol = Vout. The switch conducts when the control voltage
10+
is low, and blocking when the control voltage is high.
11+
12+
Blocks in the forward direction only, uncontrolled reverse conduction is possible via the body diode.
13+
14+
This wraps a single PMOS device and provides higher-level electrical modeling."""
15+
16+
def __init__(
17+
self,
18+
max_rds: FloatLike = 1 * Ohm,
19+
frequency: RangeLike = RangeExpr.ZERO,
20+
) -> None:
21+
super().__init__()
22+
self.max_rds = self.ArgParameter(max_rds)
23+
self.frequency = self.ArgParameter(frequency)
24+
25+
self.gnd = self.Port(Ground(), [Common]) # not physically used, only as a standoff voltage reference
26+
self.pwr_in = self.Port(VoltageSink(current_draw=RangeExpr()), [Power])
27+
28+
self.control = self.Port(DigitalSink(), [Input])
29+
self.pwr_out = self.Port(VoltageSource(voltage_out=self.pwr_in.link().voltage), [Output])
30+
31+
@override
32+
def contents(self) -> None:
33+
super().contents()
34+
35+
self.fet = self.Block(
36+
SwitchFet.PFet(
37+
drain_voltage=self.pwr_in.link().voltage - self.gnd.link().voltage,
38+
drain_current=self.pwr_out.link().current_drawn,
39+
gate_voltage=self.control.link().voltage - self.gnd.link().voltage,
40+
gate_threshold_voltage=(
41+
self.control.link().output_thresholds.lower() - self.gnd.link().voltage.lower(),
42+
self.control.link().output_thresholds.upper() - self.gnd.link().voltage.upper(),
43+
),
44+
rds_on=(0, self.max_rds),
45+
frequency=self.frequency,
46+
drive_current=self.pwr_out.link().current_limits,
47+
)
48+
)
49+
50+
self.assign(self.pwr_in.current_draw, self.pwr_out.link().current_drawn)
51+
52+
self.connect(self.pwr_in.net, self.fet.source)
53+
self.connect(self.control.net, self.fet.gate)
54+
self.connect(self.pwr_out.net, self.fet.drain)
55+
56+
857
class HighSideSwitch(PowerSwitch, KiCadSchematicBlock, GeneratorBlock):
958
"""A high-side FET switch, using a two switch architecture, a main pass PFET with a amplifier NFET to drive its gate.
1059
If clamp_voltage is nonzero, a zener clamp is generated to limit the PFET gate voltage.

edg/circuits/SwitchMatrix.py

Lines changed: 9 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -80,12 +80,12 @@ def contents(self) -> None:
8080
@abstract_block_default(lambda: SwitchDiodeMatrix)
8181
class SwitchMatrix(InternalBlock, Block):
8282

83-
def __init__(self, nrows: IntLike, ncols: IntLike, voltage_drop: RangeLike = (0, 0.7) * Volt):
83+
def __init__(self, ncols: IntLike, nrows: IntLike, voltage_drop: RangeLike = (0, 0.7) * Volt):
8484
super().__init__()
8585

8686
self.voltage_drop = self.ArgParameter(voltage_drop)
87-
self.nrows = self.ArgParameter(nrows)
8887
self.ncols = self.ArgParameter(ncols)
88+
self.nrows = self.ArgParameter(nrows)
8989

9090
self.rows = self.Port(Vector(DigitalSink.empty()))
9191
self.cols = self.Port(Vector(DigitalSource.empty()))
@@ -213,16 +213,16 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
213213
def generate(self) -> None:
214214
super().generate()
215215

216-
for row in range(self.get(self.nrows)):
217-
self.rows.append_elt(DigitalSink.empty(), str(row))
216+
for col in range(self.get(self.ncols)):
217+
self.cols.append_elt(DigitalSource.empty(), str(col))
218218

219219
self.sw = ElementDict[SwitchCell]()
220-
for col in range(self.get(self.ncols)):
221-
col_port = self.cols.append_elt(DigitalSource.empty(), str(col))
222-
for row in range(self.get(self.nrows)):
220+
for row in range(self.get(self.nrows)):
221+
row_port = self.rows.append_elt(DigitalSink.empty(), str(row))
222+
for col in range(self.get(self.ncols)):
223223
cell = self.sw[f"{col},{row}"] = self.Block(SwitchCell(voltage_drop=self.voltage_drop))
224-
self.connect(cell.col, col_port)
225-
self.connect(cell.row, self.rows[str(row)])
224+
self.connect(cell.col, self.cols[str(col)])
225+
self.connect(cell.row, row_port)
226226

227227
self.rows.defined()
228228
self.cols.defined()

edg/circuits/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@
2323
from .ResistiveSensor import ConnectorResistiveSensor
2424

2525
from .ControlCircuits import CompensatorType2
26-
from .DigitalAmplifiers import HighSideSwitch, OpenDrainDriver
26+
from .DigitalAmplifiers import LoadSwitch, HighSideSwitch, OpenDrainDriver
2727

2828
from .I2cBitBang import I2cControllerBitBang
2929
from .I2cPullup import I2cPullup

edg/parts/analog/opamp/Ina219.py

Lines changed: 34 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,6 @@
1+
import warnings
2+
from typing import Any
3+
14
from typing_extensions import override
25

36
from ....circuits import *
@@ -73,29 +76,49 @@ def generate(self) -> None:
7376
self.assign(self.actual_basic_part, False)
7477

7578

76-
class Ina219(CurrentSensor, Block):
77-
"""Current/voltage/power monitor with I2C interface"""
79+
class Ina219(CurrentSensor, GeneratorBlock):
80+
"""Bidirectional current/voltage/power monitor with I2C interface"""
7881

79-
def __init__(self, shunt_resistor: RangeLike = 2.0 * mOhm(tol=0.05), *, addr_lsb: IntLike = 0):
82+
def __init__(
83+
self, shunt_resistor: RangeLike = 2.0 * mOhm(tol=0.05), *, addr_lsb: IntLike = 0, flip_sense: BoolLike = False
84+
):
8085
super().__init__()
86+
self.flip_sense = self.ArgParameter(flip_sense)
87+
self.generator_param(self.flip_sense)
88+
8189
self.ic = self.Block(Ina219_Device(addr_lsb))
8290
self.pwr = self.Export(self.ic.vs, [Power])
8391
self.gnd = self.Export(self.ic.gnd, [Common])
8492
self.i2c = self.Export(self.ic.i2c)
8593

86-
self.vs_cap = self.Block(DecouplingCapacitor(0.1 * uFarad(tol=0.2))).connected(self.gnd, self.pwr)
87-
8894
self.Rs = self.Block(
8995
CurrentSenseResistor(
9096
resistance=shunt_resistor,
9197
)
9298
)
9399

94-
self.sense_pos = self.Export(self.Rs.pwr_in)
95-
self.sense_neg = self.Export(self.Rs.pwr_out)
100+
self.sense_pwr_in = self.Export(self.Rs.pwr_in)
101+
self.sense_pwr_out = self.Export(self.Rs.pwr_out)
96102

97103
@override
98-
def contents(self) -> None:
99-
super().contents()
100-
self.connect(self.Rs.sense_in, self.ic.in_pos)
101-
self.connect(self.Rs.sense_out, self.ic.in_neg)
104+
def generate(self) -> None:
105+
super().generate()
106+
self.vs_cap = self.Block(DecouplingCapacitor(0.1 * uFarad(tol=0.2))).connected(self.gnd, self.pwr)
107+
108+
if not self.get(self.flip_sense):
109+
self.connect(self.Rs.sense_in, self.ic.in_pos)
110+
self.connect(self.Rs.sense_out, self.ic.in_neg)
111+
else:
112+
self.connect(self.Rs.sense_in, self.ic.in_neg)
113+
self.connect(self.Rs.sense_out, self.ic.in_pos)
114+
115+
def __getattr__(self, item: str) -> Any:
116+
if item == "sense_pos":
117+
warnings.warn(f"Use sense_pwr_in instead.", DeprecationWarning, stacklevel=2)
118+
return self.sense_pwr_in
119+
elif item == "sense_neg":
120+
warnings.warn(f"Use sense_pwr_out instead.", DeprecationWarning, stacklevel=2)
121+
return self.sense_pwr_out
122+
else:
123+
# ideally we'd use super().__getattr__(...), but that's not defined in base classes
124+
raise AttributeError(item)

edg/parts/connector/Connectors.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44
from typing_extensions import override
55

66
from ...circuits import *
7-
from .Headers import JstShSmHorizontal
7+
from .Jst import JstShSmHorizontal
88

99

1010
@abstract_block

0 commit comments

Comments
 (0)