Skip to content

Commit

Permalink
Add: test_protected_charger for testing reverse protection
Browse files Browse the repository at this point in the history
Fix: revert test_pcbbot changes
Fix: PMOS charger protection m1 being flipped
  • Loading branch information
Suke0811 committed Apr 1, 2024
1 parent 8842bcf commit 47ac586
Show file tree
Hide file tree
Showing 4 changed files with 93 additions and 232 deletions.
215 changes: 5 additions & 210 deletions electronics_lib/PowerConditioning.py
Original file line number Diff line number Diff line change
Expand Up @@ -265,156 +265,6 @@ def connected_from(self, gnd: Optional[Port[VoltageLink]] = None, pwr_hi: Option
cast(Block, builder.get_enclosing_block()).connect(pwr_lo, self.pwr_lo)
return self

class PmosReverseProtection(PowerConditioner, Block):
"""
, here is a tradeoff between the Gate discharge time and Zener biasing.
In most cases, 100R-330R is good if there are chances for the appearance of sudden reverse voltage in the circuit.
But if there are no chances of sudden reverse voltage during the continuous working of the circuit, anything from the 1k-50k resistor value can be used.
"""
@init_in_parent
def __init__(self, clamp_voltage: RangeLike, gate_resistor: RangeLike):
super().__init__()
self.gnd = self.Port(Ground.empty(), [Common])
self.pwr_in = self.Port(VoltageSink.empty()) # high-priority higher-voltage source
self.pwr_out = self.Port(VoltageSource.empty())

self.clamp_voltage = self.ArgParameter(clamp_voltage)
self.gate_resistor = self.ArgParameter(gate_resistor)

def contents(self):
super().contents()

output_current_draw = self.pwr_out.link().current_drawn
# Pfet
self.fet = self.Block(Fet.PFet(
drain_voltage=(0, self.pwr_out.link().voltage.upper()),
drain_current=output_current_draw,
# gate voltage accounts for a possible power on transient
gate_voltage=(self.clamp_voltage.upper(), (self.clamp_voltage.upper())),
))

self.res = self.Block(Resistor(self.gate_resistor))
self.diode = self.Block(ZenerDiode(self.clamp_voltage))
# PFet gate to res to gnd
self.connect(self.fet.gate, self.res.a)
self.connect(self.gnd, self.res.b.adapt_to(Ground()))
# pwr going through the PFet
self.connect(self.pwr_in, self.fet.source.adapt_to(VoltageSink()))
self.connect(self.pwr_out, self.fet.drain.adapt_to(VoltageSource()))
# Connectign the diode from the gate to the pwr out side
self.connect(self.fet.drain, self.diode.cathode)
self.connect(self.fet.gate, self.diode.anode)




class PmosChargerProtection(PowerConditioner, Block):
@init_in_parent
def __init__(self, r1: RangeLike = 100*kOhm(tol=0.01), r2:RangeLike = 100*kOhm(tol=0.01), rds_on: RangeLike =(0, 0.1)*Ohm):
super().__init__()

self.gnd = self.Port(Ground.empty(), [Common])
self.pwr_out = self.Port(VoltageSource.empty(),) # Load
self.vbatt = self.Port(VoltageSink.empty(),) # Battery
self.vcharger = self.Port(VoltageSink.empty(),) # Charger

self.r1_val = self.ArgParameter(r1)
self.r2_val = self.ArgParameter(r2)
self.rds_on = self.ArgParameter(rds_on)

def contents(self):
super().contents()
max_vcharge_voltage = self.vcharger.link().voltage.upper()
max_vcharge_current = self.vcharger.link().current_drawn.upper()
max_vbatt_voltage = self.vbatt.link().voltage.upper()
max_vbatt_current = self.vbatt.link().current_drawn.upper()
# Create the PMOS transistors and resistors based on the provided schematic
self.mp1 = self.Block(Fet.PFet(
drain_voltage=(0, max_vcharge_voltage), drain_current=(0, max_vcharge_current),
gate_voltage=(- max_vbatt_voltage, max_vbatt_voltage),
rds_on=self.rds_on,
power=(0, max_vcharge_voltage * max_vcharge_current)
))
self.mp2 = self.Block(Fet.PFet(
drain_voltage=(0, max_vbatt_voltage), drain_current=(0, max_vbatt_current),
gate_voltage=(0, max_vcharge_voltage),
rds_on=self.rds_on,
power=(0, max_vbatt_voltage * max_vbatt_current)
))
self.r1 = self.Block(Resistor(resistance=self.r1_val))
self.r2 = self.Block(Resistor(resistance=self.r2_val))

self.connect(self.mp1.source.adapt_to(VoltageSink()), self.vcharger)
self.connect(self.mp2.source.adapt_to(VoltageSink()), self.vcharger)
self.connect(self.r2.a.adapt_to(VoltageSink()), self.vcharger)

# Connect the source of MP1 to the battery, gate of MP1 to the charger through R1
self.connect(self.mp2.drain.adapt_to(VoltageSink()), self.vbatt)
self.connect(self.mp1.gate.adapt_to(VoltageSink()), self.vbatt)
self.connect(self.r2.b.adapt_to(VoltageSink()), self.vbatt)

self.mp1_drain = self.connect(self.mp1.drain.adapt_to(VoltageSink()), self.r1.a.adapt_to(VoltageSink()))
self.connect(self.mp2.gate.adapt_to(VoltageSink()), self.mp1_drain)
#self.mp1_drain = self.connect(self.mp1.drain.adapt_to(VoltageSink()), self.mp2.gate.adapt_to(VoltageSink()))
# self.connect(self.mp1_drain, self.r1.a.adapt_to(VoltageSink()))

self.connect(self.r1.b.adapt_to(Ground()), self.gnd)
self.connect(self.pwr_out, self.vcharger)



class PmosChargerReverseProtection(PowerConditioner, KiCadSchematicBlock, Block):
@init_in_parent
def __init__(self, r1: RangeLike = 100*kOhm(tol=0.01), r2:RangeLike = 100*kOhm(tol=0.01), rds_on: RangeLike =(0, 0.1)*Ohm):
super().__init__()

self.gnd = self.Port(Ground.empty(), [Common])
self.pwr_out = self.Port(VoltageSource.empty(),) # Load
self.vbatt = self.Port(VoltageSink.empty(),) # Battery
self.vcharger = self.Port(VoltageSink.empty(),) # Charger

self.r1_val = self.ArgParameter(r1)
self.r2_val = self.ArgParameter(r2)
self.rds_on = self.ArgParameter(rds_on)

def contents(self):
super().contents()
max_vcharge_voltage = self.vcharger.link().voltage.upper()
max_vcharge_current = self.vcharger.link().current_drawn.upper()
max_vbatt_voltage = self.vbatt.link().voltage.upper()
max_vbatt_current = self.vbatt.link().current_drawn.upper()
# Create the PMOS transistors and resistors based on the provided schematic
self.mp1 = self.Block(Fet.PFet(
drain_voltage=(0, max_vcharge_voltage), drain_current=(0, max_vcharge_current),
gate_voltage=(- max_vbatt_voltage, max_vbatt_voltage),
rds_on=self.rds_on,
power=(0, max_vcharge_voltage * max_vcharge_current)
))
self.mp2 = self.Block(Fet.PFet(
drain_voltage=(0, max_vbatt_voltage), drain_current=(0, max_vbatt_current),
gate_voltage=(0, max_vcharge_voltage),
rds_on=self.rds_on,
power=(0, max_vbatt_voltage * max_vbatt_current)
))
self.r1 = self.Block(Resistor(resistance=self.r1_val))
self.r2 = self.Block(Resistor(resistance=self.r2_val))



self.import_kicad(
self.file_path("resources", f"{self.__class__.__name__}.kicad_sch"),
conversions={
'vbatt': VoltageSink(
current_draw=max_vbatt_current
),
'vcharger': VoltageSink(
current_draw=max_vcharge_current
),
'pwr_out': VoltageSource(
voltage_out=max_vcharge_voltage),
'gnd': Ground(),
})


class PmosReverseProtection(PowerConditioner, Block):
"""
Expand Down Expand Up @@ -459,81 +309,26 @@ def contents(self):



class PmosChargerProtection(PowerConditioner, Block):
@init_in_parent
def __init__(self, r1: RangeLike = 100*kOhm(tol=0.01), r2:RangeLike = 100*kOhm(tol=0.01), rds_on: RangeLike =(0, 0.1)*Ohm):
super().__init__()

self.gnd = self.Port(Ground.empty(), [Common])
self.pwr_out = self.Port(VoltageSource.empty(),) # Load
self.vbatt = self.Port(VoltageSink.empty(),) # Battery
self.vcharger = self.Port(VoltageSink.empty(),) # Charger

self.r1_val = self.ArgParameter(r1)
self.r2_val = self.ArgParameter(r2)
self.rds_on = self.ArgParameter(rds_on)

def contents(self):
super().contents()
max_vcharge_voltage = self.vcharger.link().voltage.upper()
max_vcharge_current = self.vcharger.link().current_drawn.upper()
max_vbatt_voltage = self.vbatt.link().voltage.upper()
max_vbatt_current = self.vbatt.link().current_drawn.upper()
# Create the PMOS transistors and resistors based on the provided schematic
self.mp1 = self.Block(Fet.PFet(
drain_voltage=(0, max_vcharge_voltage), drain_current=(0, max_vcharge_current),
gate_voltage=(- max_vbatt_voltage, max_vbatt_voltage),
rds_on=self.rds_on,
power=(0, max_vcharge_voltage * max_vcharge_current)
))
self.mp2 = self.Block(Fet.PFet(
drain_voltage=(0, max_vbatt_voltage), drain_current=(0, max_vbatt_current),
gate_voltage=(0, max_vcharge_voltage),
rds_on=self.rds_on,
power=(0, max_vbatt_voltage * max_vbatt_current)
))
self.r1 = self.Block(Resistor(resistance=self.r1_val))
self.r2 = self.Block(Resistor(resistance=self.r2_val))

self.connect(self.mp1.source.adapt_to(VoltageSink()), self.vcharger)
self.connect(self.mp2.source.adapt_to(VoltageSink()), self.vcharger)
self.connect(self.r2.a.adapt_to(VoltageSink()), self.vcharger)

# Connect the source of MP1 to the battery, gate of MP1 to the charger through R1
self.connect(self.mp2.drain.adapt_to(VoltageSink()), self.vbatt)
self.connect(self.mp1.gate.adapt_to(VoltageSink()), self.vbatt)
self.connect(self.r2.b.adapt_to(VoltageSink()), self.vbatt)

self.mp1_drain = self.connect(self.mp1.drain.adapt_to(VoltageSink()), self.r1.a.adapt_to(VoltageSink()))
self.connect(self.mp2.gate.adapt_to(VoltageSink()), self.mp1_drain)
#self.mp1_drain = self.connect(self.mp1.drain.adapt_to(VoltageSink()), self.mp2.gate.adapt_to(VoltageSink()))
# self.connect(self.mp1_drain, self.r1.a.adapt_to(VoltageSink()))

self.connect(self.r1.b.adapt_to(Ground()), self.gnd)
self.connect(self.pwr_out, self.vcharger)



class PmosChargerReverseProtection(PowerConditioner, KiCadSchematicBlock, Block):
@init_in_parent
def __init__(self, r1: RangeLike = 100*kOhm(tol=0.01), r2:RangeLike = 100*kOhm(tol=0.01), rds_on: RangeLike =(0, 0.1)*Ohm):
def __init__(self, r1_val: RangeLike = 100*kOhm(tol=0.01), r2_val: RangeLike = 100*kOhm(tol=0.01), rds_on: RangeLike =(0, 0.1)*Ohm):
super().__init__()

self.gnd = self.Port(Ground.empty(), [Common])
self.pwr_out = self.Port(VoltageSource.empty(),) # Load
self.vbatt = self.Port(VoltageSink.empty(),) # Battery
self.chg = self.Port(VoltageSink.empty(),) # Charger

self.r1_val = self.ArgParameter(r1)
self.r2_val = self.ArgParameter(r2)
self.r1_val = self.ArgParameter(r1_val)
self.r2_val = self.ArgParameter(r2_val)
self.rds_on = self.ArgParameter(rds_on)

def contents(self):
super().contents()
max_vcharge_voltage = self.chg.link().voltage.upper()
max_vcharge_current = self.chg.link().current_drawn.upper()
max_vbatt_voltage = self.vbatt.link().voltage.upper()
max_vbatt_current = self.vbatt.link().current_drawn.upper()
max_vbatt_current = self.vbatt.link().current_limits.upper() # TODO: check if we should use current_limit or current_draw
# Create the PMOS transistors and resistors based on the provided schematic
self.mp1 = self.Block(Fet.PFet(
drain_voltage=(0, max_vcharge_voltage), drain_current=(0, max_vcharge_current),
Expand All @@ -552,7 +347,7 @@ def contents(self):

chg_adapter = self.Block(PassiveAdapterVoltageSink())
setattr(self, '(adapter)chg', chg_adapter) # hack so the netlister recognizes this as an adapter
self.connect(self.mp1.drain, chg_adapter.src)
self.connect(self.mp1.source, chg_adapter.src)
self.connect(self.chg, chg_adapter.dst)

self.import_kicad(
Expand Down
28 changes: 14 additions & 14 deletions electronics_lib/resources/PmosChargerReverseProtection.kicad_sch
Original file line number Diff line number Diff line change
Expand Up @@ -241,10 +241,10 @@
(uuid 414f0070-564b-405d-b71b-214b1d92e219)
)
(junction (at 152.4 86.36) (diameter 0) (color 0 0 0 0)
(uuid 940d6e88-14e8-4a8c-9086-4044ac4fc7f5)
(uuid 886a151f-c6c3-4d9e-a86d-cacbfd10639e)
)
(junction (at 152.4 73.66) (diameter 0) (color 0 0 0 0)
(uuid 9aa805d7-cf25-448e-85e5-54dcd69acaac)
(uuid 921f02ca-3043-464e-8d30-5a83209e363c)
)
(wire (pts (xy 165.1 83.82) (xy 175.26 83.82))
Expand All @@ -259,10 +259,6 @@
(stroke (width 0) (type default))
(uuid 1d5f332d-27e6-4f0c-ac09-a1a0e71bc341)
)
(wire (pts (xy 152.4 83.82) (xy 152.4 86.36))
(stroke (width 0) (type default))
(uuid 2ddbb025-427a-41c6-bfa4-0c2e5acdbb2c)
)
(wire (pts (xy 160.02 78.74) (xy 165.1 78.74))
(stroke (width 0) (type default))
(uuid 3dd7ff86-72ff-43b5-b894-0e5a62f25699)
Expand All @@ -283,10 +279,6 @@
(stroke (width 0) (type default))
(uuid 7c3d3d02-ed81-48d3-a207-98a8631ab8ed)
)
(wire (pts (xy 143.51 73.66) (xy 152.4 73.66))
(stroke (width 0) (type default))
(uuid 7cab5b0d-9153-424d-9095-a6419ddc6b5d)
)
(wire (pts (xy 124.46 101.6) (xy 127 101.6))
(stroke (width 0) (type default))
(uuid 864c531c-87c9-485b-a44e-d9aa537f522b)
Expand All @@ -295,17 +287,25 @@
(stroke (width 0) (type default))
(uuid 9817d9d6-40c8-4a6e-8baa-964fd7e97de8)
)
(wire (pts (xy 152.4 83.82) (xy 152.4 86.36))
(stroke (width 0) (type default))
(uuid 9848f6af-1634-4e92-bab4-6b1ff52cdda6)
)
(wire (pts (xy 143.51 66.04) (xy 143.51 73.66))
(stroke (width 0) (type default))
(uuid a087cf6a-b08b-4dbd-9e78-ded1fa1740e3)
)
(wire (pts (xy 143.51 73.66) (xy 152.4 73.66))
(stroke (width 0) (type default))
(uuid b6506fce-b46b-42ad-84fe-68ff496aed77)
)
(wire (pts (xy 182.88 83.82) (xy 187.96 83.82))
(stroke (width 0) (type default))
(uuid c7edf471-f510-4ced-ae0e-fa0b4de75aca)
)
(wire (pts (xy 152.4 73.66) (xy 175.26 73.66))
(stroke (width 0) (type default))
(uuid ebdc34cc-c823-4107-bc50-c07b68d3b9bc)
(uuid e141ea76-4b1b-417c-ae27-ff704152d25e)
)
(wire (pts (xy 185.42 66.04) (xy 143.51 66.04))
(stroke (width 0) (type default))
Expand Down Expand Up @@ -363,16 +363,16 @@
)
)
(symbol (lib_id "Device:Q_PMOS_DGS") (at 154.94 78.74 0) (mirror y) (unit 1)
(symbol (lib_id "Device:Q_PMOS_DGS") (at 154.94 78.74 180) (unit 1)
(in_bom yes) (on_board yes) (dnp no)
(uuid 39f44928-01d2-4e2e-9e28-a7bb035b6c2b)
(property "Reference" "mp1" (at 157.48 81.28 90)
(property "Reference" "mp1" (at 157.48 76.2 90)
(effects (font (size 1.27 1.27)))
)
(property "Value" "~" (at 146.05 78.74 90)
(effects (font (size 1.27 1.27)))
)
(property "Footprint" "" (at 149.86 76.2 0)
(property "Footprint" "" (at 149.86 81.28 0)
(effects (font (size 1.27 1.27)) hide)
)
(property "Datasheet" "~" (at 154.94 78.74 0)
Expand Down
10 changes: 2 additions & 8 deletions examples/test_pcbbot.py
Original file line number Diff line number Diff line change
Expand Up @@ -70,15 +70,9 @@ def contents(self) -> None:
)
self.v3v3 = self.connect(self.reg_3v3.pwr_out)

self.pmos = imp.Block(PmosChargerReverseProtection())
# self.pmos = imp.Block(PmosChargerReverseProtection())
self.pmos = imp.Block(PmosChargerReverseProtection())

(self.charger, ), _ = self.chain(
self.vusb, imp.Block(Mcp73831(200*mAmp(tol=0.2))), self.pmos.chg # self.pmos.vcharger,
self.vusb, imp.Block(Mcp73831(200*mAmp(tol=0.2))), self.batt.chg
)
self.connect(self.pmos.vbatt, self.batt.chg)
self.pvbatt = self.connect(self.pmos.pwr_out)
(self.charge_led, ), _ = self.chain(
self.Block(IndicatorSinkLed(Led.Yellow)), self.charger.stat
)
Expand Down Expand Up @@ -245,4 +239,4 @@ def refinements(self) -> Refinements:

class PcbBotTestCase(unittest.TestCase):
def test_design(self) -> None:
compile_board_inplace(PcbBot)
compile_board_inplace(PcbBot)
Loading

0 comments on commit 47ac586

Please sign in to comment.