c86a05dd2e
Reorganize component placement with clean left-to-right power flow, segmented rail wires for proper ERC connections, correct KiCad Device:C pin positions (±3.81mm), and FB label instead of long crossing wire. 0 ERC errors.
884 lines
28 KiB
Python
884 lines
28 KiB
Python
#!/usr/bin/env python3
|
|
"""
|
|
Generate a KiCad 9 schematic for a TPS61088 5V-to-12V boost converter.
|
|
|
|
Reference design for driving a stepper motor (via A4988) at 12V/2A
|
|
from a 5V Raspberry Pi power bus.
|
|
|
|
Layout: clean left-to-right power flow, modeled after TI datasheet Fig 8-1.
|
|
|
|
Output: tps61088_boost.kicad_sch
|
|
"""
|
|
|
|
import uuid
|
|
|
|
|
|
def uid():
|
|
return str(uuid.uuid4())
|
|
|
|
|
|
# ── Symbol library definitions ──────────────────────────────────────
|
|
|
|
LIB_TPS61088 = """\
|
|
(symbol "custom:TPS61088"
|
|
(exclude_from_sim no)
|
|
(in_bom yes)
|
|
(on_board yes)
|
|
(property "Reference" "U"
|
|
(at 0 16.51 0)
|
|
(effects (font (size 1.27 1.27)))
|
|
)
|
|
(property "Value" "TPS61088"
|
|
(at 0 13.97 0)
|
|
(effects (font (size 1.27 1.27)))
|
|
)
|
|
(property "Footprint" "Package_DFN_QFN:QFN-20-1EP_3.5x3.5mm_P0.5mm_EP2.1x2.1mm"
|
|
(at 0 -20.32 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Datasheet" "https://www.ti.com/lit/ds/symlink/tps61088.pdf"
|
|
(at 0 -22.86 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Description" "10A Fully-Integrated Synchronous Boost Converter"
|
|
(at 0 -25.4 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(symbol "TPS61088_0_1"
|
|
(rectangle
|
|
(start -10.16 12.7)
|
|
(end 10.16 -12.7)
|
|
(stroke (width 0.254) (type default))
|
|
(fill (type background))
|
|
)
|
|
)
|
|
(symbol "TPS61088_1_1"
|
|
(pin power_in line
|
|
(at -12.7 10.16 0) (length 2.54)
|
|
(name "VIN" (effects (font (size 1.27 1.27))))
|
|
(number "1" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin input line
|
|
(at -12.7 5.08 0) (length 2.54)
|
|
(name "EN" (effects (font (size 1.27 1.27))))
|
|
(number "3" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin passive line
|
|
(at -12.7 0 0) (length 2.54)
|
|
(name "SS/TR" (effects (font (size 1.27 1.27))))
|
|
(number "4" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin passive line
|
|
(at -12.7 -5.08 0) (length 2.54)
|
|
(name "COMP" (effects (font (size 1.27 1.27))))
|
|
(number "5" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin input line
|
|
(at -12.7 -10.16 0) (length 2.54)
|
|
(name "FB" (effects (font (size 1.27 1.27))))
|
|
(number "6" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin passive line
|
|
(at 12.7 10.16 180) (length 2.54)
|
|
(name "SW" (effects (font (size 1.27 1.27))))
|
|
(number "12" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin passive line
|
|
(at 12.7 5.08 180) (length 2.54)
|
|
(name "BST" (effects (font (size 1.27 1.27))))
|
|
(number "11" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin power_out line
|
|
(at 12.7 0 180) (length 2.54)
|
|
(name "VOUT" (effects (font (size 1.27 1.27))))
|
|
(number "9" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin open_collector line
|
|
(at 12.7 -5.08 180) (length 2.54)
|
|
(name "PGOOD" (effects (font (size 1.27 1.27))))
|
|
(number "8" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin power_in line
|
|
(at 0 -15.24 90) (length 2.54)
|
|
(name "PGND" (effects (font (size 1.27 1.27))))
|
|
(number "15" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin power_in line
|
|
(at -5.08 -15.24 90) (length 2.54)
|
|
(name "AGND" (effects (font (size 1.27 1.27))))
|
|
(number "7" (effects (font (size 1.27 1.27))))
|
|
)
|
|
)
|
|
)"""
|
|
|
|
LIB_CAPACITOR = """\
|
|
(symbol "Device:C"
|
|
(exclude_from_sim no)
|
|
(in_bom yes)
|
|
(on_board yes)
|
|
(property "Reference" "C"
|
|
(at 1.27 0 0)
|
|
(effects (font (size 1.27 1.27)) (justify left))
|
|
)
|
|
(property "Value" "C"
|
|
(at 1.27 -2.54 0)
|
|
(effects (font (size 1.27 1.27)) (justify left))
|
|
)
|
|
(property "Footprint" ""
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Datasheet" "~"
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Description" "Unpolarized capacitor"
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(symbol "C_0_1"
|
|
(polyline
|
|
(pts (xy -2.032 -0.762) (xy 2.032 -0.762))
|
|
(stroke (width 0.508) (type default))
|
|
(fill (type none))
|
|
)
|
|
(polyline
|
|
(pts (xy -2.032 0.762) (xy 2.032 0.762))
|
|
(stroke (width 0.508) (type default))
|
|
(fill (type none))
|
|
)
|
|
)
|
|
(symbol "C_1_1"
|
|
(pin passive line
|
|
(at 0 3.81 270) (length 2.794)
|
|
(name "~" (effects (font (size 1.27 1.27))))
|
|
(number "1" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin passive line
|
|
(at 0 -3.81 90) (length 2.794)
|
|
(name "~" (effects (font (size 1.27 1.27))))
|
|
(number "2" (effects (font (size 1.27 1.27))))
|
|
)
|
|
)
|
|
)"""
|
|
|
|
LIB_RESISTOR = """\
|
|
(symbol "Device:R"
|
|
(exclude_from_sim no)
|
|
(in_bom yes)
|
|
(on_board yes)
|
|
(property "Reference" "R"
|
|
(at 2.032 0 90)
|
|
(effects (font (size 1.27 1.27)))
|
|
)
|
|
(property "Value" "R"
|
|
(at 0 0 90)
|
|
(effects (font (size 1.27 1.27)))
|
|
)
|
|
(property "Footprint" ""
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Datasheet" "~"
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Description" "Resistor"
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(symbol "R_0_1"
|
|
(rectangle
|
|
(start -1.016 -2.54)
|
|
(end 1.016 2.54)
|
|
(stroke (width 0.254) (type default))
|
|
(fill (type none))
|
|
)
|
|
)
|
|
(symbol "R_1_1"
|
|
(pin passive line
|
|
(at 0 3.81 270) (length 1.27)
|
|
(name "~" (effects (font (size 1.27 1.27))))
|
|
(number "1" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin passive line
|
|
(at 0 -3.81 90) (length 1.27)
|
|
(name "~" (effects (font (size 1.27 1.27))))
|
|
(number "2" (effects (font (size 1.27 1.27))))
|
|
)
|
|
)
|
|
)"""
|
|
|
|
LIB_INDUCTOR = """\
|
|
(symbol "Device:L"
|
|
(exclude_from_sim no)
|
|
(in_bom yes)
|
|
(on_board yes)
|
|
(property "Reference" "L"
|
|
(at -1.016 0 90)
|
|
(effects (font (size 1.27 1.27)))
|
|
)
|
|
(property "Value" "L"
|
|
(at 1.016 0 90)
|
|
(effects (font (size 1.27 1.27)))
|
|
)
|
|
(property "Footprint" ""
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Datasheet" "~"
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Description" "Inductor"
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(symbol "L_0_1"
|
|
(arc
|
|
(start 0 -2.54) (mid 0.6323 -1.905) (end 0 -1.27)
|
|
(stroke (width 0) (type default))
|
|
(fill (type none))
|
|
)
|
|
(arc
|
|
(start 0 -1.27) (mid 0.6323 -0.635) (end 0 0)
|
|
(stroke (width 0) (type default))
|
|
(fill (type none))
|
|
)
|
|
(arc
|
|
(start 0 0) (mid 0.6323 0.635) (end 0 1.27)
|
|
(stroke (width 0) (type default))
|
|
(fill (type none))
|
|
)
|
|
(arc
|
|
(start 0 1.27) (mid 0.6323 1.905) (end 0 2.54)
|
|
(stroke (width 0) (type default))
|
|
(fill (type none))
|
|
)
|
|
)
|
|
(symbol "L_1_1"
|
|
(pin passive line
|
|
(at 0 3.81 270) (length 1.27)
|
|
(name "~" (effects (font (size 1.27 1.27))))
|
|
(number "1" (effects (font (size 1.27 1.27))))
|
|
)
|
|
(pin passive line
|
|
(at 0 -3.81 90) (length 1.27)
|
|
(name "~" (effects (font (size 1.27 1.27))))
|
|
(number "2" (effects (font (size 1.27 1.27))))
|
|
)
|
|
)
|
|
)"""
|
|
|
|
|
|
def lib_power(name, shape_text):
|
|
return f"""\
|
|
(symbol "power:{name}"
|
|
(power)
|
|
(exclude_from_sim no)
|
|
(in_bom yes)
|
|
(on_board yes)
|
|
(property "Reference" "#PWR"
|
|
(at 0 -3.81 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Value" "{name}"
|
|
(at 0 3.81 0)
|
|
(effects (font (size 1.27 1.27)))
|
|
)
|
|
(property "Footprint" ""
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Datasheet" ""
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Description" "Power symbol creates a global label with name \\"{name}\\""
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
{shape_text}
|
|
)"""
|
|
|
|
|
|
POWER_UP_SHAPE = """\
|
|
(symbol "{name}_0_1"
|
|
(polyline
|
|
(pts (xy -0.762 1.27) (xy 0 2.54))
|
|
(stroke (width 0) (type default))
|
|
(fill (type none))
|
|
)
|
|
(polyline
|
|
(pts (xy 0 0) (xy 0 2.54))
|
|
(stroke (width 0) (type default))
|
|
(fill (type none))
|
|
)
|
|
(polyline
|
|
(pts (xy 0 2.54) (xy 0.762 1.27))
|
|
(stroke (width 0) (type default))
|
|
(fill (type none))
|
|
)
|
|
)
|
|
(symbol "{name}_1_1"
|
|
(pin power_in line
|
|
(at 0 0 90) (length 0)
|
|
(name "{name}" (effects (font (size 1.27 1.27))))
|
|
(number "1" (effects (font (size 1.27 1.27))))
|
|
)
|
|
)"""
|
|
|
|
GND_SHAPE = """\
|
|
(symbol "GND_0_1"
|
|
(polyline
|
|
(pts (xy 0 0) (xy 0 -1.27) (xy 1.27 -1.27) (xy 0 -2.54) (xy -1.27 -1.27) (xy 0 -1.27))
|
|
(stroke (width 0) (type default))
|
|
(fill (type none))
|
|
)
|
|
)
|
|
(symbol "GND_1_1"
|
|
(pin power_in line
|
|
(at 0 0 270) (length 0)
|
|
(name "GND" (effects (font (size 1.27 1.27))))
|
|
(number "1" (effects (font (size 1.27 1.27))))
|
|
)
|
|
)"""
|
|
|
|
LIB_PLUS5V = lib_power("+5V", POWER_UP_SHAPE.format(name="+5V"))
|
|
LIB_PLUS12V = lib_power("+12V", POWER_UP_SHAPE.format(name="+12V"))
|
|
LIB_GND = lib_power("GND", GND_SHAPE)
|
|
|
|
LIB_PWR_FLAG = """\
|
|
(symbol "power:PWR_FLAG"
|
|
(power)
|
|
(exclude_from_sim no)
|
|
(in_bom yes)
|
|
(on_board yes)
|
|
(property "Reference" "#FLG"
|
|
(at 0 1.905 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Value" "PWR_FLAG"
|
|
(at 0 3.81 0)
|
|
(effects (font (size 1.27 1.27)))
|
|
)
|
|
(property "Footprint" ""
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Datasheet" "~"
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Description" "Special symbol for telling ERC where power comes from"
|
|
(at 0 0 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(symbol "PWR_FLAG_0_0"
|
|
(pin power_out line
|
|
(at 0 0 90) (length 0)
|
|
(name "pwr" (effects (font (size 1.27 1.27))))
|
|
(number "1" (effects (font (size 1.27 1.27))))
|
|
)
|
|
)
|
|
(symbol "PWR_FLAG_0_1"
|
|
(polyline
|
|
(pts (xy 0 0) (xy 0 1.27) (xy -1.016 1.905) (xy 0 2.54) (xy 1.016 1.905) (xy 0 1.27))
|
|
(stroke (width 0) (type default))
|
|
(fill (type none))
|
|
)
|
|
)
|
|
)"""
|
|
|
|
|
|
# ── Schematic builder ───────────────────────────────────────────────
|
|
|
|
class Schematic:
|
|
def __init__(self):
|
|
self.root_uuid = uid()
|
|
self.symbols = []
|
|
self.wires = []
|
|
self.junctions = []
|
|
self.labels = []
|
|
self.notes = []
|
|
self.no_connects = []
|
|
self._pwr_idx = 0
|
|
self._flg_idx = 0
|
|
|
|
def _next_pwr(self):
|
|
self._pwr_idx += 1
|
|
return f"#PWR{self._pwr_idx:02d}"
|
|
|
|
def place(self, lib_id, ref, value, x, y, rot=0, pins=None):
|
|
u = uid()
|
|
if pins is None:
|
|
pins = {}
|
|
pin_str = ""
|
|
for pnum in sorted(pins.keys(), key=lambda k: int(k) if k.isdigit() else k):
|
|
pin_str += f' (pin "{pnum}"\n (uuid "{pins[pnum]}")\n )\n'
|
|
|
|
self.symbols.append(f"""\
|
|
(symbol
|
|
(lib_id "{lib_id}")
|
|
(at {x} {y} {rot})
|
|
(unit 1)
|
|
(exclude_from_sim no)
|
|
(in_bom yes)
|
|
(on_board yes)
|
|
(dnp no)
|
|
(uuid "{u}")
|
|
(property "Reference" "{ref}"
|
|
(at {x + 2.54} {y - 2.54} 0)
|
|
(effects (font (size 1.27 1.27)) (justify left))
|
|
)
|
|
(property "Value" "{value}"
|
|
(at {x + 2.54} {y + 2.54} 0)
|
|
(effects (font (size 1.27 1.27)) (justify left))
|
|
)
|
|
(property "Footprint" ""
|
|
(at {x} {y} 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Datasheet" ""
|
|
(at {x} {y} 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Description" ""
|
|
(at {x} {y} 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
{pin_str}\
|
|
(instances
|
|
(project ""
|
|
(path "/{self.root_uuid}"
|
|
(reference "{ref}")
|
|
(unit 1)
|
|
)
|
|
)
|
|
)
|
|
)""")
|
|
|
|
def pwr(self, lib_id, value, x, y):
|
|
ref = self._next_pwr()
|
|
u = uid()
|
|
self.symbols.append(f"""\
|
|
(symbol
|
|
(lib_id "{lib_id}")
|
|
(at {x} {y} 0)
|
|
(unit 1)
|
|
(exclude_from_sim no)
|
|
(in_bom yes)
|
|
(on_board yes)
|
|
(dnp no)
|
|
(uuid "{u}")
|
|
(property "Reference" "{ref}"
|
|
(at {x} {y - 2.54} 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Value" "{value}"
|
|
(at {x} {y + 3.81} 0)
|
|
(effects (font (size 1.27 1.27)))
|
|
)
|
|
(property "Footprint" ""
|
|
(at {x} {y} 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Datasheet" ""
|
|
(at {x} {y} 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Description" ""
|
|
(at {x} {y} 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(pin "1"
|
|
(uuid "{uid()}")
|
|
)
|
|
(instances
|
|
(project ""
|
|
(path "/{self.root_uuid}"
|
|
(reference "{ref}")
|
|
(unit 1)
|
|
)
|
|
)
|
|
)
|
|
)""")
|
|
|
|
def pwr_flag(self, x, y):
|
|
self._flg_idx += 1
|
|
ref = f"#FLG{self._flg_idx:02d}"
|
|
u = uid()
|
|
self.symbols.append(f"""\
|
|
(symbol
|
|
(lib_id "power:PWR_FLAG")
|
|
(at {x} {y} 0)
|
|
(unit 1)
|
|
(exclude_from_sim no)
|
|
(in_bom yes)
|
|
(on_board yes)
|
|
(dnp no)
|
|
(uuid "{u}")
|
|
(property "Reference" "{ref}"
|
|
(at {x} {y - 2.54} 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Value" "PWR_FLAG"
|
|
(at {x} {y + 3.81} 0)
|
|
(effects (font (size 1.27 1.27)))
|
|
)
|
|
(property "Footprint" ""
|
|
(at {x} {y} 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Datasheet" ""
|
|
(at {x} {y} 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(property "Description" ""
|
|
(at {x} {y} 0)
|
|
(effects (font (size 1.27 1.27)) (hide yes))
|
|
)
|
|
(pin "1"
|
|
(uuid "{uid()}")
|
|
)
|
|
(instances
|
|
(project ""
|
|
(path "/{self.root_uuid}"
|
|
(reference "{ref}")
|
|
(unit 1)
|
|
)
|
|
)
|
|
)
|
|
)""")
|
|
|
|
def wire(self, x1, y1, x2, y2):
|
|
self.wires.append(f"""\
|
|
(wire
|
|
(pts (xy {x1} {y1}) (xy {x2} {y2}))
|
|
(stroke (width 0) (type default))
|
|
(uuid "{uid()}")
|
|
)""")
|
|
|
|
def junc(self, x, y):
|
|
self.junctions.append(f"""\
|
|
(junction
|
|
(at {x} {y})
|
|
(diameter 0)
|
|
(color 0 0 0 0)
|
|
(uuid "{uid()}")
|
|
)""")
|
|
|
|
def label(self, x, y, name, rot=0):
|
|
self.labels.append(f"""\
|
|
(label "{name}"
|
|
(at {x} {y} {rot})
|
|
(effects (font (size 1.27 1.27)))
|
|
(uuid "{uid()}")
|
|
)""")
|
|
|
|
def note(self, x, y, text):
|
|
self.notes.append(f"""\
|
|
(text "{text}"
|
|
(exclude_from_sim no)
|
|
(at {x} {y} 0)
|
|
(effects (font (size 1.27 1.27)) (justify left))
|
|
(uuid "{uid()}")
|
|
)""")
|
|
|
|
def no_connect(self, x, y):
|
|
self.no_connects.append(f"""\
|
|
(no_connect
|
|
(at {x} {y})
|
|
(uuid "{uid()}")
|
|
)""")
|
|
|
|
def cap_down(self, ref, value, x, rail_y):
|
|
"""Place a cap hanging down from a rail. Top pin on rail, GND below.
|
|
Cap pins at ±3.81 from center (matching KiCad Device:C library)."""
|
|
cy = rail_y + 6.35 # cap center (so top pin at cy-3.81 = rail_y+2.54)
|
|
self.place("Device:C", ref, value, x, cy,
|
|
pins={"1": uid(), "2": uid()})
|
|
self.wire(x, cy - 3.81, x, rail_y) # top pin to rail
|
|
self.pwr("power:GND", "GND", x, cy + 6.35)
|
|
self.wire(x, cy + 3.81, x, cy + 6.35) # bottom pin to GND
|
|
|
|
def render(self):
|
|
sections = []
|
|
sections.append(f"""\
|
|
(kicad_sch
|
|
(version 20250114)
|
|
(generator "python_gen")
|
|
(generator_version "9.0")
|
|
(uuid "{self.root_uuid}")
|
|
(paper "A3")
|
|
(lib_symbols
|
|
{LIB_TPS61088}
|
|
{LIB_CAPACITOR}
|
|
{LIB_RESISTOR}
|
|
{LIB_INDUCTOR}
|
|
{LIB_PLUS5V}
|
|
{LIB_PLUS12V}
|
|
{LIB_GND}
|
|
{LIB_PWR_FLAG}
|
|
)""")
|
|
for j in self.junctions:
|
|
sections.append(j)
|
|
for nc in self.no_connects:
|
|
sections.append(nc)
|
|
for w in self.wires:
|
|
sections.append(w)
|
|
for lb in self.labels:
|
|
sections.append(lb)
|
|
for n in self.notes:
|
|
sections.append(n)
|
|
for sym in self.symbols:
|
|
sections.append(sym)
|
|
sections.append("""\
|
|
(sheet_instances
|
|
(path "/"
|
|
(page "1")
|
|
)
|
|
)
|
|
(embedded_fonts no)
|
|
)""")
|
|
return "\n".join(sections)
|
|
|
|
|
|
# ── Schematic layout ───────────────────────────────────────────────
|
|
|
|
def generate():
|
|
s = Schematic()
|
|
|
|
# ================================================================
|
|
# IC placement — center of schematic
|
|
# ================================================================
|
|
cx, cy = 127.0, 76.2
|
|
|
|
# IC pin absolute positions
|
|
VIN = (cx - 12.7, cy - 10.16) # (114.3, 66.04)
|
|
EN = (cx - 12.7, cy - 5.08) # (114.3, 71.12)
|
|
SS = (cx - 12.7, cy) # (114.3, 76.2)
|
|
COMP = (cx - 12.7, cy + 5.08) # (114.3, 81.28)
|
|
FB = (cx - 12.7, cy + 10.16) # (114.3, 86.36)
|
|
SW = (cx + 12.7, cy - 10.16) # (139.7, 66.04)
|
|
BST = (cx + 12.7, cy - 5.08) # (139.7, 71.12)
|
|
VOUT = (cx + 12.7, cy) # (139.7, 76.2)
|
|
PG = (cx + 12.7, cy + 5.08) # (139.7, 81.28)
|
|
PGND = (cx, cy + 15.24) # (127.0, 91.44)
|
|
AGND = (cx - 5.08, cy + 15.24) # (121.92, 91.44)
|
|
|
|
# Place IC
|
|
ic_pins = {str(i): uid() for i in
|
|
[1, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15]}
|
|
s.place("custom:TPS61088", "U1", "TPS61088", cx, cy, pins=ic_pins)
|
|
|
|
# ================================================================
|
|
# INPUT SECTION — left side, +5V rail flowing right into VIN
|
|
# ================================================================
|
|
vin_rail_y = VIN[1] # 66.04 — horizontal rail
|
|
|
|
# +5V source (far left)
|
|
pwr5v_x = 86.36
|
|
s.pwr("power:+5V", "+5V", pwr5v_x, vin_rail_y - 5.08)
|
|
s.wire(pwr5v_x, vin_rail_y - 5.08, pwr5v_x, vin_rail_y)
|
|
|
|
# PWR_FLAG on +5V net (tells ERC this is externally supplied)
|
|
s.pwr_flag(pwr5v_x + 5.08, vin_rail_y)
|
|
s.wire(pwr5v_x, vin_rail_y, pwr5v_x + 5.08, vin_rail_y)
|
|
|
|
# Component X positions (declared before wiring)
|
|
c1_x = 91.44
|
|
c2_x = 99.06
|
|
en_tap_x = 106.68
|
|
|
|
# VIN rail: segmented so each T-junction is at a wire endpoint
|
|
s.wire(pwr5v_x, vin_rail_y, c1_x, vin_rail_y)
|
|
s.wire(c1_x, vin_rail_y, c2_x, vin_rail_y)
|
|
s.wire(c2_x, vin_rail_y, en_tap_x, vin_rail_y)
|
|
s.wire(en_tap_x, vin_rail_y, VIN[0], vin_rail_y)
|
|
|
|
# Input cap C1 (22µF) — hanging down from rail
|
|
s.cap_down("C1", "22uF", c1_x, vin_rail_y)
|
|
|
|
# Input cap C2 (22µF) — second cap, spaced right
|
|
s.cap_down("C2", "22uF", c2_x, vin_rail_y)
|
|
|
|
# PWR_FLAG on GND net (on C1's GND connection)
|
|
c1_gnd_y = vin_rail_y + 6.35 + 6.35 # cap center + GND offset
|
|
s.pwr_flag(c1_x + 5.08, c1_gnd_y)
|
|
s.wire(c1_x, c1_gnd_y, c1_x + 5.08, c1_gnd_y)
|
|
s.junc(c1_x, c1_gnd_y)
|
|
|
|
# EN tied to VIN rail (always enabled)
|
|
s.wire(EN[0], EN[1], en_tap_x, EN[1]) # EN pin left to tap point
|
|
s.wire(en_tap_x, EN[1], en_tap_x, vin_rail_y) # tap up to rail
|
|
|
|
# ================================================================
|
|
# SOFT-START — C3 hanging below SS pin
|
|
# ================================================================
|
|
ss_wire_x = 106.68
|
|
s.wire(SS[0], SS[1], ss_wire_x, SS[1]) # SS pin left to C3
|
|
c3_y = SS[1] + 6.35 # cap center (top pin at c3_y - 3.81)
|
|
s.place("Device:C", "C3", "22nF", ss_wire_x, c3_y,
|
|
pins={"1": uid(), "2": uid()})
|
|
s.wire(ss_wire_x, SS[1], ss_wire_x, c3_y - 3.81) # wire to cap top
|
|
s.pwr("power:GND", "GND", ss_wire_x, c3_y + 6.35)
|
|
s.wire(ss_wire_x, c3_y + 3.81, ss_wire_x, c3_y + 6.35)
|
|
|
|
# ================================================================
|
|
# COMPENSATION — R1 + C4 series from COMP pin to GND
|
|
# ================================================================
|
|
comp_wire_x = 99.06
|
|
s.wire(COMP[0], COMP[1], comp_wire_x, COMP[1]) # COMP pin left
|
|
|
|
# R1 below COMP
|
|
r1_y = COMP[1] + 6.35 # 87.63
|
|
s.place("Device:R", "R1", "30.1k", comp_wire_x, r1_y,
|
|
pins={"1": uid(), "2": uid()})
|
|
s.wire(comp_wire_x, COMP[1], comp_wire_x, r1_y - 3.81) # to R1 top
|
|
|
|
# C4 below R1
|
|
c4_y = r1_y + 10.16 # enough space for R1 bottom pin + gap + C4 top pin
|
|
s.place("Device:C", "C4", "47pF", comp_wire_x, c4_y,
|
|
pins={"1": uid(), "2": uid()})
|
|
s.wire(comp_wire_x, r1_y + 3.81, comp_wire_x, c4_y - 3.81) # R1 bot to C4 top
|
|
s.pwr("power:GND", "GND", comp_wire_x, c4_y + 6.35)
|
|
s.wire(comp_wire_x, c4_y + 3.81, comp_wire_x, c4_y + 6.35)
|
|
|
|
# ================================================================
|
|
# IC GROUND — PGND and AGND tied together
|
|
# ================================================================
|
|
gnd_y = PGND[1] + 5.08 # 96.52
|
|
s.pwr("power:GND", "GND", PGND[0], gnd_y)
|
|
s.wire(PGND[0], PGND[1], PGND[0], gnd_y)
|
|
s.wire(AGND[0], AGND[1], AGND[0], gnd_y)
|
|
s.wire(AGND[0], gnd_y, PGND[0], gnd_y)
|
|
s.junc(PGND[0], gnd_y)
|
|
|
|
# ================================================================
|
|
# OUTPUT SECTION — SW → L1 → VOUT rail → +12V
|
|
# ================================================================
|
|
|
|
# Inductor L1 (2.2µH, horizontal, between SW and VOUT rail)
|
|
# Rotated 90°: pin1 at (x-3.81, y), pin2 at (x+3.81, y)
|
|
# (90° CCW rotation: original top pin goes left)
|
|
l1_x = 149.86
|
|
l1_y = SW[1] # 66.04
|
|
l1_pin1 = (l1_x - 3.81, l1_y) # 146.05 — connects to SW net
|
|
l1_pin2 = (l1_x + 3.81, l1_y) # 153.67 — connects to VOUT rail
|
|
s.place("Device:L", "L1", "2.2uH 10A", l1_x, l1_y, rot=90,
|
|
pins={"1": uid(), "2": uid()})
|
|
|
|
# Bootstrap cap C5 (100nF) — vertical, between SW wire and BST pin
|
|
c5_x = 144.78
|
|
|
|
# Wire SW pin → through C5 junction → to L1 pin1 (segmented)
|
|
s.wire(SW[0], SW[1], c5_x, SW[1])
|
|
s.wire(c5_x, SW[1], l1_pin1[0], l1_pin1[1])
|
|
c5_y = SW[1] + 3.81 # center so top pin (c5_y-3.81) lands on SW wire
|
|
s.place("Device:C", "C5", "100nF", c5_x, c5_y,
|
|
pins={"1": uid(), "2": uid()})
|
|
# C5 top pin at (c5_x, SW[1]) sits on SW wire
|
|
s.junc(c5_x, SW[1])
|
|
# C5 bottom pin at (c5_x, c5_y+3.81) — wire to BST pin
|
|
s.wire(c5_x, c5_y + 3.81, BST[0], BST[1])
|
|
|
|
# VOUT rail — vertical line on the right
|
|
vout_rail_x = 162.56
|
|
# L1 output → VOUT rail top
|
|
s.wire(l1_pin2[0], l1_pin2[1], vout_rail_x, l1_y)
|
|
# VOUT pin → VOUT rail bottom
|
|
s.wire(VOUT[0], VOUT[1], vout_rail_x, VOUT[1])
|
|
# Connect top to bottom
|
|
s.wire(vout_rail_x, l1_y, vout_rail_x, VOUT[1])
|
|
|
|
# Output caps and +12V — segmented output rail
|
|
c6_x = 167.64
|
|
c7_x = 175.26
|
|
|
|
# Output rail segments
|
|
s.wire(vout_rail_x, l1_y, c6_x, l1_y)
|
|
s.wire(c6_x, l1_y, c7_x, l1_y)
|
|
|
|
# Output cap C6 (22µF)
|
|
s.cap_down("C6", "22uF", c6_x, l1_y)
|
|
|
|
# Output cap C7 (22µF)
|
|
s.cap_down("C7", "22uF", c7_x, l1_y)
|
|
|
|
# +12V output symbol
|
|
s.pwr("power:+12V", "+12V", c7_x, l1_y - 5.08)
|
|
s.wire(c7_x, l1_y, c7_x, l1_y - 5.08)
|
|
s.junc(c7_x, l1_y)
|
|
|
|
# ================================================================
|
|
# FEEDBACK DIVIDER — R2 (190k) / R3 (10k) sets VOUT = 12V
|
|
# Connected to FB pin via label (avoids long crossing wire)
|
|
# ================================================================
|
|
fb_x = vout_rail_x # 162.56 — hangs off VOUT rail
|
|
|
|
# R2 (top resistor, VOUT to FB tap)
|
|
r2_y = VOUT[1] + 6.35 # 82.55
|
|
s.place("Device:R", "R2", "190k", fb_x, r2_y,
|
|
pins={"1": uid(), "2": uid()})
|
|
s.wire(fb_x, VOUT[1], fb_x, r2_y - 3.81) # VOUT rail down to R2 top
|
|
s.junc(fb_x, VOUT[1]) # T-junction on VOUT vertical rail
|
|
|
|
# R3 (bottom resistor, FB tap to GND)
|
|
r3_y = r2_y + 10.16 # 92.71
|
|
s.place("Device:R", "R3", "10k", fb_x, r3_y,
|
|
pins={"1": uid(), "2": uid()})
|
|
s.wire(fb_x, r2_y + 3.81, fb_x, r3_y - 3.81) # R2 bottom to R3 top
|
|
|
|
# FB tap label at divider midpoint
|
|
fb_tap_y = r2_y + 3.81 # 86.36 — R2 bottom pin
|
|
s.wire(fb_x, fb_tap_y, fb_x + 5.08, fb_tap_y)
|
|
s.label(fb_x + 5.08, fb_tap_y, "FB")
|
|
s.junc(fb_x, fb_tap_y)
|
|
|
|
# FB label at IC pin (connects by name)
|
|
s.wire(FB[0], FB[1], FB[0] - 5.08, FB[1])
|
|
s.label(FB[0] - 5.08, FB[1], "FB", rot=180)
|
|
|
|
# R3 bottom to GND
|
|
s.pwr("power:GND", "GND", fb_x, r3_y + 6.35)
|
|
s.wire(fb_x, r3_y + 3.81, fb_x, r3_y + 6.35)
|
|
|
|
# ================================================================
|
|
# PGOOD — no connect (optional, wire if monitoring needed)
|
|
# ================================================================
|
|
s.no_connect(PG[0], PG[1])
|
|
|
|
# ================================================================
|
|
# DESIGN NOTES — below the circuit, well separated
|
|
# ================================================================
|
|
nx = 78.74
|
|
ny = 116.84
|
|
|
|
s.note(nx, ny, "TPS61088 Boost Converter Reference Design")
|
|
s.note(nx, ny + 5, "Input: +5V from Raspberry Pi 5V bus")
|
|
s.note(nx, ny + 8, "Output: +12V @ 2A for A4988 stepper driver (VMOT)")
|
|
s.note(nx, ny + 13, "VOUT = 0.6V x (1 + R2/R3) = 0.6 x (1 + 190k/10k) = 12.06V")
|
|
s.note(nx, ny + 18, "Component Selection:")
|
|
s.note(nx, ny + 21, " L1: 2.2uH, >=10A Isat, low DCR (Coilcraft XAL7030-222ME)")
|
|
s.note(nx, ny + 24, " C1-C2, C6-C7: 22uF 25V X5R ceramic (input & output)")
|
|
s.note(nx, ny + 27, " C5: 100nF bootstrap (ceramic)")
|
|
s.note(nx, ny + 30, " C3: 22nF soft-start (sets startup ramp time)")
|
|
s.note(nx, ny + 33, " R1, C4: Loop compensation (see TPS61088 datasheet Table 2)")
|
|
s.note(nx, ny + 38, "PCB Layout Notes:")
|
|
s.note(nx, ny + 41, " - Keep SW node, BST cap, and inductor loop as tight as possible")
|
|
s.note(nx, ny + 44, " - Place input and output caps directly adjacent to IC pins")
|
|
s.note(nx, ny + 47, " - Solid ground plane under IC with thermal vias to EP pad")
|
|
s.note(nx, ny + 50, " - Route FB trace far from SW/inductor (sensitive to noise)")
|
|
|
|
return s.render()
|
|
|
|
|
|
if __name__ == "__main__":
|
|
sch = generate()
|
|
outfile = "tps61088_boost.kicad_sch"
|
|
with open(outfile, "w") as f:
|
|
f.write(sch)
|
|
print(f"Generated {outfile}")
|
|
print("Open in KiCad Schematic Editor to review.")
|