Files
chicken-coop-door/gen_boost_schematic.py
0xWheatyz c86a05dd2e refactor(schematic): redesign TPS61088 boost converter layout for clarity
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.
2026-04-20 16:41:00 -04:00

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.")