Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
93 commits
Select commit Hold shift + click to select a range
8b5af5c
reg layout concept
ducky64 Jun 7, 2026
fcb48cc
clean up prerouted examples
ducky64 Jun 7, 2026
db5ccaf
wip converter layout
ducky64 Jun 7, 2026
c3ce048
speaker preroute
ducky64 Jun 7, 2026
5d8c86c
layout wip
ducky64 Jun 7, 2026
5f32710
line2line
ducky64 Jun 7, 2026
1321ece
wip
ducky64 Jun 7, 2026
916af59
power routing
ducky64 Jun 7, 2026
75dedff
Update IotFan.kicad_pcb
ducky64 Jun 7, 2026
c937b3b
wip
ducky64 Jun 7, 2026
d42500d
refactor connectors
ducky64 Jun 7, 2026
f434af7
global route wip
ducky64 Jun 8, 2026
a75b77d
new concept
ducky64 Jun 8, 2026
055e135
wip
ducky64 Jun 8, 2026
10c7db6
Update IotFan.kicad_pcb
ducky64 Jun 8, 2026
8280498
checkpoint
ducky64 Jun 8, 2026
7f4f12b
layout tuning
ducky64 Jun 8, 2026
9d854c6
control board floorplan
ducky64 Jun 8, 2026
37c3a81
wip
ducky64 Jun 8, 2026
610b84b
wip keyboard layout
ducky64 Jun 8, 2026
7c7a7e8
macropad layout wip
ducky64 Jun 8, 2026
dbd919c
Update Keyboard.kicad_pcb
ducky64 Jun 8, 2026
589bcc7
Update Keyboard.kicad_pcb
ducky64 Jun 8, 2026
7037b5b
Update Keyboard.kicad_pcb
ducky64 Jun 8, 2026
5aa366c
generate in row order
ducky64 Jun 9, 2026
ff3885c
Update Keyboard.kicad_pcb
ducky64 Jun 9, 2026
9fdc923
Update Keyboard.kicad_pcb
ducky64 Jun 9, 2026
47825cb
Update Keyboard.kicad_pcb
ducky64 Jun 9, 2026
8084497
Update Keyboard.kicad_pcb
ducky64 Jun 9, 2026
1ed0593
keyboard doneish
ducky64 Jun 9, 2026
ed1afac
power routing that doesn't fully duck
ducky64 Jun 10, 2026
ca5c49c
Update IotFan.kicad_pcb
ducky64 Jun 10, 2026
9b2fe50
base layout complete
ducky64 Jun 11, 2026
c759967
layout wip
ducky64 Jun 12, 2026
53865ba
Update IotFan_control.kicad_pcb
ducky64 Jun 12, 2026
b5cf2db
Update IotFan_control.kicad_pcb
ducky64 Jun 12, 2026
b4a4a9f
routing
ducky64 Jun 13, 2026
016340a
Update IotFan_control.kicad_pcb
ducky64 Jun 13, 2026
639d911
wip
ducky64 Jun 13, 2026
07e8730
wip
ducky64 Jun 13, 2026
3882a89
fan design complete
ducky64 Jun 13, 2026
f435164
Update IotFan.kicad_pcb
ducky64 Jun 13, 2026
517478d
reduce footprint crtyd
ducky64 Jun 13, 2026
acc9d05
Update IotFan.kicad_pcb
ducky64 Jun 13, 2026
19bcbf6
wip
ducky64 Jun 13, 2026
1f79b7e
add drc excludes
ducky64 Jun 13, 2026
ec239f0
wip
ducky64 Jun 13, 2026
9df8b14
ble joystick floorplanning
ducky64 Jun 13, 2026
c1c3362
Update BleJoystick_btns.kicad_pcb
ducky64 Jun 13, 2026
b78ee3f
wip
ducky64 Jun 13, 2026
8d14754
wip
ducky64 Jun 13, 2026
b808335
Update BleJoystick_btns.kicad_pcb
ducky64 Jun 13, 2026
f96e479
rotations
ducky64 Jun 13, 2026
19564bb
Update BleJoystick_btns.kicad_pcb
ducky64 Jun 13, 2026
c5cdcba
npx chain
ducky64 Jun 13, 2026
1053a07
pre-rearchitecting
ducky64 Jun 14, 2026
dcd1416
wip
ducky64 Jun 14, 2026
4ce0ab8
almost there w/ new arch
ducky64 Jun 14, 2026
89c119c
buttons board done
ducky64 Jun 14, 2026
b64984f
wip new layout architecture
ducky64 Jun 14, 2026
ceedcc6
Update BleJoystick.kicad_pcb
ducky64 Jun 14, 2026
7441c8a
wip
ducky64 Jun 14, 2026
1f14fd4
wip floorplanning
ducky64 Jun 14, 2026
c171518
Update BleJoystick.kicad_pcb
ducky64 Jun 14, 2026
d426f3a
optional flip sense
ducky64 Jun 14, 2026
a1d8449
coming together
ducky64 Jun 14, 2026
04a8ed8
refdes placement
ducky64 Jun 14, 2026
32b418f
Update IotFan.kicad_pcb
ducky64 Jun 14, 2026
df5d6b4
floorplanning
ducky64 Jun 14, 2026
2107b68
backbone floorplanning
ducky64 Jun 14, 2026
69f1333
magnetometer cleanup
ducky64 Jun 14, 2026
57a545e
Update BleJoystick.kicad_pcb
ducky64 Jun 14, 2026
aec5686
Update BleJoystick.kicad_pcb
ducky64 Jun 14, 2026
8e95fd8
Update BleJoystick.kicad_pcb
ducky64 Jun 14, 2026
d969c43
Update BleJoystick.kicad_pcb
ducky64 Jun 14, 2026
ad301fe
Update BleJoystick.kicad_pcb
ducky64 Jun 14, 2026
9d42d91
wip
ducky64 Jun 14, 2026
3fedcdf
wip
ducky64 Jun 15, 2026
8d28916
wip
ducky64 Jun 15, 2026
1be6a7c
drc cleanish
ducky64 Jun 15, 2026
eede44c
polishing
ducky64 Jun 15, 2026
7f2f5b2
drc exclude updates
ducky64 Jun 15, 2026
bfc7d87
socket-tab pair
ducky64 Jun 15, 2026
c85a83f
wip
ducky64 Jun 15, 2026
790a46e
done
ducky64 Jun 15, 2026
adb80bc
fix
ducky64 Jun 15, 2026
231ce94
load switch and routing wip
ducky64 Jun 16, 2026
2f3bcce
wip
ducky64 Jun 16, 2026
7c34952
clean
ducky64 Jun 16, 2026
ec1cd1d
finally done probably
ducky64 Jun 16, 2026
deee4d6
cleaned up routing
ducky64 Jun 17, 2026
f17b0e2
regenerate netlists, fix deprecations
ducky64 Jun 17, 2026
26b97af
fixes
ducky64 Jun 17, 2026
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
49 changes: 49 additions & 0 deletions edg/circuits/DigitalAmplifiers.py
Original file line number Diff line number Diff line change
Expand Up @@ -5,6 +5,55 @@
from ..abstract_parts import *


class LoadSwitch(PowerSwitch, Block):
"""A high-side PMOS load switch, for when Vcontrol = Vout. The switch conducts when the control voltage
is low, and blocking when the control voltage is high.

Blocks in the forward direction only, uncontrolled reverse conduction is possible via the body diode.

This wraps a single PMOS device and provides higher-level electrical modeling."""

def __init__(
self,
max_rds: FloatLike = 1 * Ohm,
frequency: RangeLike = RangeExpr.ZERO,
) -> None:
super().__init__()
self.max_rds = self.ArgParameter(max_rds)
self.frequency = self.ArgParameter(frequency)

self.gnd = self.Port(Ground(), [Common]) # not physically used, only as a standoff voltage reference
self.pwr_in = self.Port(VoltageSink(current_draw=RangeExpr()), [Power])

self.control = self.Port(DigitalSink(), [Input])
self.pwr_out = self.Port(VoltageSource(voltage_out=self.pwr_in.link().voltage), [Output])

@override
def contents(self) -> None:
super().contents()

self.fet = self.Block(
SwitchFet.PFet(
drain_voltage=self.pwr_in.link().voltage - self.gnd.link().voltage,
drain_current=self.pwr_out.link().current_drawn,
gate_voltage=self.control.link().voltage - self.gnd.link().voltage,
gate_threshold_voltage=(
self.control.link().output_thresholds.lower() - self.gnd.link().voltage.lower(),
self.control.link().output_thresholds.upper() - self.gnd.link().voltage.upper(),
),
rds_on=(0, self.max_rds),
frequency=self.frequency,
drive_current=self.pwr_out.link().current_limits,
)
)

self.assign(self.pwr_in.current_draw, self.pwr_out.link().current_drawn)

self.connect(self.pwr_in.net, self.fet.source)
self.connect(self.control.net, self.fet.gate)
self.connect(self.pwr_out.net, self.fet.drain)


class HighSideSwitch(PowerSwitch, KiCadSchematicBlock, GeneratorBlock):
"""A high-side FET switch, using a two switch architecture, a main pass PFET with a amplifier NFET to drive its gate.
If clamp_voltage is nonzero, a zener clamp is generated to limit the PFET gate voltage.
Expand Down
18 changes: 9 additions & 9 deletions edg/circuits/SwitchMatrix.py
Original file line number Diff line number Diff line change
Expand Up @@ -80,12 +80,12 @@ def contents(self) -> None:
@abstract_block_default(lambda: SwitchDiodeMatrix)
class SwitchMatrix(InternalBlock, Block):

def __init__(self, nrows: IntLike, ncols: IntLike, voltage_drop: RangeLike = (0, 0.7) * Volt):
def __init__(self, ncols: IntLike, nrows: IntLike, voltage_drop: RangeLike = (0, 0.7) * Volt):
super().__init__()

self.voltage_drop = self.ArgParameter(voltage_drop)
self.nrows = self.ArgParameter(nrows)
self.ncols = self.ArgParameter(ncols)
self.nrows = self.ArgParameter(nrows)

self.rows = self.Port(Vector(DigitalSink.empty()))
self.cols = self.Port(Vector(DigitalSource.empty()))
Expand Down Expand Up @@ -213,16 +213,16 @@ def __init__(self, *args: Any, **kwargs: Any) -> None:
def generate(self) -> None:
super().generate()

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

self.sw = ElementDict[SwitchCell]()
for col in range(self.get(self.ncols)):
col_port = self.cols.append_elt(DigitalSource.empty(), str(col))
for row in range(self.get(self.nrows)):
for row in range(self.get(self.nrows)):
row_port = self.rows.append_elt(DigitalSink.empty(), str(row))
for col in range(self.get(self.ncols)):
cell = self.sw[f"{col},{row}"] = self.Block(SwitchCell(voltage_drop=self.voltage_drop))
self.connect(cell.col, col_port)
self.connect(cell.row, self.rows[str(row)])
self.connect(cell.col, self.cols[str(col)])
self.connect(cell.row, row_port)

self.rows.defined()
self.cols.defined()
Expand Down
2 changes: 1 addition & 1 deletion edg/circuits/__init__.py
Original file line number Diff line number Diff line change
Expand Up @@ -23,7 +23,7 @@
from .ResistiveSensor import ConnectorResistiveSensor

from .ControlCircuits import CompensatorType2
from .DigitalAmplifiers import HighSideSwitch, OpenDrainDriver
from .DigitalAmplifiers import LoadSwitch, HighSideSwitch, OpenDrainDriver

from .I2cBitBang import I2cControllerBitBang
from .I2cPullup import I2cPullup
Expand Down
45 changes: 34 additions & 11 deletions edg/parts/analog/opamp/Ina219.py
Original file line number Diff line number Diff line change
@@ -1,3 +1,6 @@
import warnings
from typing import Any

from typing_extensions import override

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


class Ina219(CurrentSensor, Block):
"""Current/voltage/power monitor with I2C interface"""
class Ina219(CurrentSensor, GeneratorBlock):
"""Bidirectional current/voltage/power monitor with I2C interface"""

def __init__(self, shunt_resistor: RangeLike = 2.0 * mOhm(tol=0.05), *, addr_lsb: IntLike = 0):
def __init__(
self, shunt_resistor: RangeLike = 2.0 * mOhm(tol=0.05), *, addr_lsb: IntLike = 0, flip_sense: BoolLike = False
):
super().__init__()
self.flip_sense = self.ArgParameter(flip_sense)
self.generator_param(self.flip_sense)

self.ic = self.Block(Ina219_Device(addr_lsb))
self.pwr = self.Export(self.ic.vs, [Power])
self.gnd = self.Export(self.ic.gnd, [Common])
self.i2c = self.Export(self.ic.i2c)

self.vs_cap = self.Block(DecouplingCapacitor(0.1 * uFarad(tol=0.2))).connected(self.gnd, self.pwr)

self.Rs = self.Block(
CurrentSenseResistor(
resistance=shunt_resistor,
)
)

self.sense_pos = self.Export(self.Rs.pwr_in)
self.sense_neg = self.Export(self.Rs.pwr_out)
self.sense_pwr_in = self.Export(self.Rs.pwr_in)
self.sense_pwr_out = self.Export(self.Rs.pwr_out)

@override
def contents(self) -> None:
super().contents()
self.connect(self.Rs.sense_in, self.ic.in_pos)
self.connect(self.Rs.sense_out, self.ic.in_neg)
def generate(self) -> None:
super().generate()
self.vs_cap = self.Block(DecouplingCapacitor(0.1 * uFarad(tol=0.2))).connected(self.gnd, self.pwr)

if not self.get(self.flip_sense):
self.connect(self.Rs.sense_in, self.ic.in_pos)
self.connect(self.Rs.sense_out, self.ic.in_neg)
else:
self.connect(self.Rs.sense_in, self.ic.in_neg)
self.connect(self.Rs.sense_out, self.ic.in_pos)

def __getattr__(self, item: str) -> Any:
if item == "sense_pos":
warnings.warn(f"Use sense_pwr_in instead.", DeprecationWarning, stacklevel=2)
return self.sense_pwr_in
elif item == "sense_neg":
warnings.warn(f"Use sense_pwr_out instead.", DeprecationWarning, stacklevel=2)
return self.sense_pwr_out
else:
# ideally we'd use super().__getattr__(...), but that's not defined in base classes
raise AttributeError(item)
2 changes: 1 addition & 1 deletion edg/parts/connector/Connectors.py
Original file line number Diff line number Diff line change
Expand Up @@ -4,7 +4,7 @@
from typing_extensions import override

from ...circuits import *
from .Headers import JstShSmHorizontal
from .Jst import JstShSmHorizontal


@abstract_block
Expand Down
Loading
Loading