Skip to content

Commit 74dcedd

Browse files
Suke0811ducky64
andauthored
SoftwarePowerGate (#334)
Add: SoftPowerGate and switch Originally from #329 --------- Co-authored-by: Richard Lin <[email protected]>
1 parent e6a7bf7 commit 74dcedd

File tree

9 files changed

+2221
-1300
lines changed

9 files changed

+2221
-1300
lines changed

electronics_lib/PowerConditioning.py

Lines changed: 108 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -377,3 +377,111 @@ def contents(self):
377377
),
378378
'gnd': Ground(),
379379
})
380+
381+
382+
class SoftPowerGate(PowerSwitch, KiCadSchematicBlock, Block): # migrate from the multimater
383+
"""A high-side PFET power gate that has a button to power on, can be latched on by an external signal,
384+
and provides the button output as a signal.
385+
"""
386+
387+
@init_in_parent
388+
def __init__(self, pull_resistance: RangeLike = 10 * kOhm(tol=0.05), amp_resistance: RangeLike = 10 * kOhm(tol=0.05),
389+
diode_drop: RangeLike = (0, 0.4) * Volt):
390+
super().__init__()
391+
self.pwr_in = self.Port(VoltageSink.empty(), [Input])
392+
self.pwr_out = self.Port(VoltageSource.empty(), [Output], doc="Gate controlled power out")
393+
self.gnd = self.Port(Ground.empty(), [Common])
394+
395+
self.btn_out = self.Port(DigitalSingleSource.empty(), optional=True,
396+
doc="Allows the button state to be read independently of the control signal")
397+
self.btn_in = self.Port(DigitalBidir.empty(), doc="Should be connected to a button output. Do not connect IO")
398+
self.control = self.Port(DigitalSink.empty(), doc="external control to latch the power on") # digital level control - gnd-referenced NFET gate
399+
400+
self.pull_resistance = self.ArgParameter(pull_resistance)
401+
self.amp_resistance = self.ArgParameter(amp_resistance)
402+
self.diode_drop = self.ArgParameter(diode_drop)
403+
404+
def contents(self):
405+
super().contents()
406+
control_voltage = self.btn_in.link().voltage.hull(self.gnd.link().voltage)
407+
pwr_voltage = self.pwr_out.link().voltage.hull(self.gnd.link().voltage)
408+
pwr_current = self.pwr_out.link().current_drawn.hull(RangeExpr.ZERO)
409+
410+
self.pull_res = self.Block(Resistor(
411+
resistance=self.pull_resistance
412+
))
413+
self.pwr_fet = self.Block(Fet.PFet(
414+
drain_voltage=pwr_voltage,
415+
drain_current=pwr_current,
416+
gate_voltage=(-control_voltage.upper(), control_voltage.upper()), # TODO this ignores the diode drop
417+
))
418+
419+
self.amp_res = self.Block(Resistor(
420+
resistance=self.amp_resistance
421+
))
422+
self.amp_fet = self.Block(Fet.NFet(
423+
drain_voltage=control_voltage,
424+
drain_current=RangeExpr.ZERO, # effectively no current
425+
gate_voltage=(self.control.link().output_thresholds.upper(), self.control.link().voltage.upper())
426+
))
427+
428+
self.ctl_diode = self.Block(Diode(
429+
reverse_voltage=control_voltage,
430+
current=RangeExpr.ZERO, # effectively no current
431+
voltage_drop=self.diode_drop,
432+
reverse_recovery_time=RangeExpr.ALL
433+
))
434+
435+
self.btn_diode = self.Block(Diode(
436+
reverse_voltage=control_voltage,
437+
current=RangeExpr.ZERO, # effectively no current
438+
voltage_drop=self.diode_drop,
439+
reverse_recovery_time=RangeExpr.ALL
440+
))
441+
442+
self.import_kicad(self.file_path("resources", f"{self.__class__.__name__}.kicad_sch"),
443+
conversions={
444+
'pwr_in': VoltageSink(
445+
current_draw=self.pwr_out.link().current_drawn,
446+
voltage_limits=RangeExpr.ALL,
447+
),
448+
'pwr_out': VoltageSource(
449+
voltage_out=self.pwr_in.link().voltage,
450+
current_limits=RangeExpr.ALL,
451+
),
452+
'control': DigitalSink(), # TODO more modeling here?
453+
'gnd': Ground(),
454+
'btn_out': DigitalSingleSource(
455+
voltage_out=self.gnd.link().voltage,
456+
output_thresholds=(self.gnd.link().voltage.upper(), float('inf')),
457+
low_signal_driver=True
458+
),
459+
'btn_in': DigitalBidir(
460+
voltage_out=self.gnd.link().voltage,
461+
output_thresholds=(self.gnd.link().voltage.upper(), float('inf')),
462+
pullup_capable=True,
463+
)
464+
})
465+
466+
467+
class SoftPowerSwitch(PowerSwitch, Block):
468+
"""A software power switch that adds a power button a user can turn on
469+
"""
470+
@init_in_parent
471+
def __init__(self, pull_resistance: RangeLike = 10 * kOhm(tol=0.05), amp_resistance: RangeLike = 10 * kOhm(tol=0.05),
472+
diode_drop: RangeLike = (0, 0.4) * Volt):
473+
super().__init__()
474+
self.pwr_gate = self.Block(SoftPowerGate(pull_resistance, amp_resistance, diode_drop))
475+
self.gnd = self.Export(self.pwr_gate.gnd, [Common])
476+
self.pwr_in = self.Export(self.pwr_gate.pwr_in, [Input])
477+
self.pwr_out = self.Export(self.pwr_gate.pwr_out, [Output])
478+
self.btn_out = self.Export(self.pwr_gate.btn_out)
479+
self.control = self.Export(self.pwr_gate.control)
480+
481+
def contents(self):
482+
super().contents()
483+
with self.implicit_connect(
484+
ImplicitConnect(self.gnd, [Common]),
485+
) as imp:
486+
self.btn = imp.Block(DigitalSwitch())
487+
self.connect(self.pwr_gate.btn_in, self.btn.out)

electronics_lib/__init__.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -68,7 +68,7 @@
6868
from .SwitchedCap_TexasInstruments import Lm2664
6969
from .BuckConverter_Custom import CustomSyncBuckConverterIndependent
7070
from .BuckBoostConverter_Custom import CustomSyncBuckBoostConverterPwm
71-
from .PowerConditioning import BufferedSupply, Supercap, SingleDiodePowerMerge, DiodePowerMerge, PriorityPowerOr, PmosReverseProtection, PmosChargerReverseProtection
71+
from .PowerConditioning import BufferedSupply, Supercap, SingleDiodePowerMerge, DiodePowerMerge, PriorityPowerOr, SoftPowerGate, SoftPowerSwitch, PmosReverseProtection, PmosChargerReverseProtection
7272
from .LedDriver_Al8861 import Al8861
7373
from .ResetGenerator_Apx803s import Apx803s
7474
from .BootstrapVoltageAdder import BootstrapVoltageAdder

0 commit comments

Comments
 (0)