Software Power Switch using Dirctional Switch
Closed this issue · 1 comments
Suke0811 commented
Current implementation
FetPowerGateNoBtn
PolymorphicBlocks/examples/test_multimeter.py
Lines 156 to 217 in 969ee73
class FetPowerGateNoBtn(PowerSwitch, KiCadSchematicBlock, Block): | |
"""A high-side PFET power gate that has a button to power on, can be latched | |
on by an external signal, and provides the button output as a signal. | |
""" | |
def __init__(self): | |
super().__init__() | |
self.pwr_in = self.Port(VoltageSink.empty(), [Input]) | |
self.pwr_out = self.Port(VoltageSource.empty(), [Output]) | |
self.gnd = self.Port(Ground.empty(), [Common]) | |
self.btn_out = self.Port(DigitalSingleSource.empty()) | |
self.control = self.Port(DigitalSink.empty()) # digital level control - gnd-referenced NFET gate | |
def contents(self): | |
super().contents() | |
max_voltage = self.control.link().voltage.upper() | |
max_current = self.pwr_out.link().current_drawn.upper() | |
self.pull_res = self.Block(Resistor( | |
resistance=10*kOhm(tol=0.05) # TODO kind of arbitrary | |
)) | |
self.pwr_fet = self.Block(Fet.PFet( | |
drain_voltage=(0, max_voltage), | |
drain_current=(0, max_current), | |
gate_voltage=(max_voltage, max_voltage), # TODO this ignores the diode drop | |
)) | |
self.amp_res = self.Block(Resistor( | |
resistance=10*kOhm(tol=0.05) # TODO kind of arbitrary | |
)) | |
self.amp_fet = self.Block(Fet.NFet( | |
drain_voltage=(0, max_voltage), | |
drain_current=(0, 0), # effectively no current | |
gate_voltage=(self.control.link().output_thresholds.upper(), self.control.link().voltage.upper()) | |
)) | |
self.ctl_diode = self.Block(Diode( | |
reverse_voltage=(0, max_voltage), | |
current=RangeExpr.ZERO, # effectively no current | |
voltage_drop=(0, 0.4)*Volt, # TODO kind of arbitrary - should be parameterized | |
reverse_recovery_time=RangeExpr.ALL | |
)) | |
self.import_kicad(self.file_path("resources", f"{self.__class__.__name__}.kicad_sch"), | |
conversions={ | |
'pwr_in': VoltageSink( | |
current_draw=self.pwr_out.link().current_drawn, | |
voltage_limits=RangeExpr.ALL, | |
), | |
'pwr_out': VoltageSource( | |
voltage_out=self.pwr_in.link().voltage, | |
current_limits=RangeExpr.ALL, | |
), | |
'control': DigitalSink(), # TODO more modeling here? | |
'gnd': Ground(), | |
'btn_out': DigitalSingleSource( | |
voltage_out=self.gnd.link().voltage, # TODO model diode drop, | |
output_thresholds=(self.gnd.link().voltage.upper(), float('inf')), | |
low_signal_driver=True | |
) | |
}) |
Original FetPowerGate
- With added switch
PolymorphicBlocks/examples/test_multimeter.py
Lines 219 to 229 in 969ee73
class FetPowerGate(FetPowerGateNoBtn): def contents(self): max_voltage = self.control.link().voltage.upper() self.btn_diode = self.Block(Diode( reverse_voltage=(0, max_voltage), current=RangeExpr.ZERO, # effectively no current voltage_drop=(0, 0.4)*Volt, # TODO kind of arbitrary - should be parameterized reverse_recovery_time=RangeExpr.ALL )) self.btn = self.Block(Switch(voltage=0*Volt(tol=0))) # TODO - actually model switch voltage super().contents()
With DirSwitch
- Using FetPowerGateNoBtn, adding directional switch to be used as the power button
PolymorphicBlocks/examples/components_lib.py
Lines 61 to 107 in 969ee73
class OrPowerGateDirSw(OrPowerGate): @init_in_parent def __init__(self, diode_voltage_drop: RangeLike, fet_rds_on: RangeLike) -> None: super().__init__(diode_voltage_drop, fet_rds_on) self.dir = self.Block(DigitalDirectionSwitch()) self.dir_a = self.Export(self.dir.a) self.dir_b = self.Export(self.dir.b) self.dir_c = self.Export(self.dir.c) self.dir_d = self.Export(self.dir.d) def contents(self): Block.contents(self) # TODO: generalize the base class, currently completely overwriting it # POWER with self.implicit_connect( ImplicitConnect(self.gnd, [Common]), ) as imp: (self.fuse, self.gate, self.prot, self.tp), _ = self.chain( self.pwr_lo, imp.Block(SeriesPowerPptcFuse((2, 4)*Amp)), imp.Block(FetPowerGateNoBtn()), imp.Block(ProtectionZenerDiode(voltage=(4.5, 6.0)*Volt)), self.Block(VoltageTestPoint())) self.vbatt = self.connect(self.gate.pwr_out) # downstream of fuse self.connect(self.dir.gnd, self.gnd) max_voltage = self.gate.btn_out.link().voltage.upper() self.btn_diode = imp.Block(Diode( reverse_voltage=(0, max_voltage), current=RangeExpr.ZERO, # effectively no current voltage_drop=(0, 0.4)*Volt, # TODO kind of arbitrary - should be parameterized reverse_recovery_time=RangeExpr.ALL )) self.gate_btn_out = self.connect(self.gate.btn_out, self.btn_diode.cathode.adapt_to(DigitalSink())) self.connect(self.dir.with_mixin(DigitalDirectionSwitchCenter()).center, self.gate.btn_out) self.connect(self.btn_diode.anode.adapt_to(DigitalSink()), self.btn_out) self.pwr_or = self.Block(PriorityPowerOr( # also does reverse protection self.diode_voltage_drop, self.fet_rds_on )).connected_from(self.gnd, self.pwr_hi, self.gate.pwr_out) self.connect(self.pwr_or.pwr_out, self.pwr_out) # Power gait self.connect(self.gate.control, self.control)
Usage
PolymorphicBlocks/examples/test_ballu.py
Lines 41 to 42 in 969ee73
self.gate = self.Block(OrPowerGateDirSw((0, 1)*Volt, (0, 0.1)*Ohm)).connected_from(self.gnd, self.vusb, self.batt.pwr) | |
self.pwr = self.connect(self.gate.pwr_out) |