feat(schematic): replace L7805 with TPS61088 boost converter
Remove the L7805 linear regulator (12V→5V) and its input/output caps, replacing it with a TPS61088 boost converter circuit (5V→12V) for the A4988 stepper driver. The ESP32 is now powered directly from the 5V input rail. Includes integration script and project sym-lib-table for the custom TPS61088 symbol library.
This commit is contained in:
+2171
-799
File diff suppressed because it is too large
Load Diff
@@ -0,0 +1,772 @@
|
||||
#!/usr/bin/env python3
|
||||
"""
|
||||
Transform firstpcb.kicad_sch:
|
||||
1. Remove the L7805 voltage regulator and associated components
|
||||
2. Insert the TPS61088 5V→12V boost converter circuit
|
||||
3. Keep all other components intact
|
||||
|
||||
The +5V and +12V nets connect automatically via KiCad global power symbols.
|
||||
"""
|
||||
|
||||
import re
|
||||
import uuid
|
||||
import sys
|
||||
|
||||
|
||||
def uid():
|
||||
return str(uuid.uuid4())
|
||||
|
||||
|
||||
ROOT_UUID = "4ce690e5-6d5b-4693-bd2e-f4090f26df1f"
|
||||
|
||||
|
||||
# ── UUIDs of components to REMOVE (L7805 circuit) ──
|
||||
|
||||
REMOVE_UUIDS = {
|
||||
# L7805 regulator
|
||||
"b5b8c784-5cbd-46af-b962-5f07e5e5ce66",
|
||||
# C1 (0.33uF) - output cap
|
||||
"be10cf51-2c79-49d9-968c-f16a919adeee",
|
||||
# C2 (0.1uF) - input cap
|
||||
"58617ce4-1b01-4ae9-be22-0491e474e52d",
|
||||
# #PWR15 (+5V at L7805 output)
|
||||
"dd887245-ee3f-48b0-ab57-caf2a8bdfdef",
|
||||
# #PWR19 (+5V at C2)
|
||||
"fd8b730d-5d7d-4216-98e6-0f769c039626",
|
||||
# #PWR14 (+12V at L7805 input)
|
||||
"ea5b2f5d-6233-46fc-93b4-4b52ebc256b5",
|
||||
# #PWR17 (+12V at C1)
|
||||
"ec47b49b-69a3-415f-b119-7b90e03df83a",
|
||||
# #PWR16 (GND under L7805)
|
||||
"940ddbc7-3e82-42b5-ad91-3df87e10ff89",
|
||||
# #PWR18 (GND under C1)
|
||||
"565f28b7-cc4b-427c-be9a-9e09337daabd",
|
||||
# #PWR20 (GND under C2)
|
||||
"e7fe0926-923d-41aa-92e6-413304613139",
|
||||
}
|
||||
|
||||
REMOVE_WIRE_UUIDS = {
|
||||
# Wire: C2 top to L7805 output rail
|
||||
"dba247d2-ddb5-46ff-a6bd-5fb718c4599e",
|
||||
# Wire: L7805 input to +12V symbol
|
||||
"e3772378-2aa5-420d-92e3-94a8234f86b5",
|
||||
# Wire: C1 to +12V symbol
|
||||
"ee45c424-04dc-4913-92e9-0eec7ac6b273",
|
||||
# Wire: L7805 output to +5V symbol
|
||||
"48aefa74-f6f4-40ae-9135-90c2565ceadc",
|
||||
}
|
||||
|
||||
# Also remove the L7805 lib_symbol definition
|
||||
REMOVE_LIB_SYMBOL = "Regulator_Linear:L7805"
|
||||
|
||||
|
||||
def find_block_end(text, start_pos):
|
||||
"""Find the end of a parenthesized block starting at start_pos.
|
||||
start_pos should point to the opening '('."""
|
||||
depth = 0
|
||||
i = start_pos
|
||||
while i < len(text):
|
||||
if text[i] == '(':
|
||||
depth += 1
|
||||
elif text[i] == ')':
|
||||
depth -= 1
|
||||
if depth == 0:
|
||||
return i
|
||||
i += 1
|
||||
return -1
|
||||
|
||||
|
||||
def remove_blocks_by_uuid(text, uuids):
|
||||
"""Remove top-level blocks (symbol, wire, junction) containing matching UUIDs."""
|
||||
for u in uuids:
|
||||
# Find the UUID in the text
|
||||
pattern = f'(uuid "{u}")'
|
||||
idx = text.find(pattern)
|
||||
if idx == -1:
|
||||
print(f" WARNING: UUID {u} not found, skipping", file=sys.stderr)
|
||||
continue
|
||||
|
||||
# Walk backward from UUID to find the containing block's opening
|
||||
# Look for a tab-indented opening paren: \n\t(symbol, \n\t(wire, etc.
|
||||
search_start = idx
|
||||
block_start = -1
|
||||
while search_start > 0:
|
||||
# Find the previous newline
|
||||
nl = text.rfind('\n', 0, search_start)
|
||||
if nl == -1:
|
||||
break
|
||||
line = text[nl+1:search_start]
|
||||
# Check if this line starts a top-level block
|
||||
stripped = line.lstrip()
|
||||
if stripped.startswith('(symbol') or stripped.startswith('(wire') or \
|
||||
stripped.startswith('(junction') or stripped.startswith('(no_connect'):
|
||||
block_start = nl + 1
|
||||
# Find the start of the actual paren
|
||||
paren_pos = text.index('(', block_start)
|
||||
block_start = paren_pos
|
||||
break
|
||||
search_start = nl
|
||||
|
||||
if block_start == -1:
|
||||
print(f" WARNING: Could not find block start for UUID {u}", file=sys.stderr)
|
||||
continue
|
||||
|
||||
block_end = find_block_end(text, block_start)
|
||||
if block_end == -1:
|
||||
print(f" WARNING: Could not find block end for UUID {u}", file=sys.stderr)
|
||||
continue
|
||||
|
||||
# Remove the block (including trailing newline)
|
||||
end = block_end + 1
|
||||
if end < len(text) and text[end] == '\n':
|
||||
end += 1
|
||||
|
||||
# Also remove leading whitespace/tabs on the same line
|
||||
while block_start > 0 and text[block_start-1] in '\t ':
|
||||
block_start -= 1
|
||||
|
||||
print(f" Removing block with UUID {u[:12]}... ({end - block_start} chars)")
|
||||
text = text[:block_start] + text[end:]
|
||||
|
||||
return text
|
||||
|
||||
|
||||
def remove_lib_symbol(text, lib_id):
|
||||
"""Remove a lib_symbol definition from the lib_symbols section."""
|
||||
pattern = f'(symbol "{lib_id}"'
|
||||
idx = text.find(pattern)
|
||||
if idx == -1:
|
||||
print(f" WARNING: lib_symbol {lib_id} not found", file=sys.stderr)
|
||||
return text
|
||||
|
||||
# Find the containing (symbol block - walk back to find the right indentation
|
||||
# In lib_symbols, entries are indented with two tabs
|
||||
search = idx
|
||||
while search > 0 and text[search-1] != '\n':
|
||||
search -= 1
|
||||
block_start = search
|
||||
|
||||
block_paren = text.index('(', block_start)
|
||||
block_end = find_block_end(text, block_paren)
|
||||
|
||||
end = block_end + 1
|
||||
if end < len(text) and text[end] == '\n':
|
||||
end += 1
|
||||
|
||||
print(f" Removing lib_symbol {lib_id}")
|
||||
text = text[:block_start] + text[end:]
|
||||
return text
|
||||
|
||||
|
||||
# ── TPS61088 boost converter circuit to INSERT ──
|
||||
|
||||
def gen_symbol(lib_id, ref, value, x, y, rot=0, pins=None, extra_props=""):
|
||||
"""Generate a symbol placement block."""
|
||||
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'\t\t(pin "{pnum}"\n\t\t\t(uuid "{pins[pnum]}")\n\t\t)\n'
|
||||
|
||||
return f"""\t(symbol
|
||||
\t\t(lib_id "{lib_id}")
|
||||
\t\t(at {round(x, 2)} {round(y, 2)} {rot})
|
||||
\t\t(unit 1)
|
||||
\t\t(exclude_from_sim no)
|
||||
\t\t(in_bom yes)
|
||||
\t\t(on_board yes)
|
||||
\t\t(dnp no)
|
||||
\t\t(uuid "{u}")
|
||||
\t\t(property "Reference" "{ref}"
|
||||
\t\t\t(at {round(x + 2.54, 2)} {round(y - 2.54, 2)} 0)
|
||||
\t\t\t(effects
|
||||
\t\t\t\t(font
|
||||
\t\t\t\t\t(size 1.27 1.27)
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(justify left)
|
||||
\t\t\t)
|
||||
\t\t)
|
||||
\t\t(property "Value" "{value}"
|
||||
\t\t\t(at {round(x + 2.54, 2)} {round(y + 2.54, 2)} 0)
|
||||
\t\t\t(effects
|
||||
\t\t\t\t(font
|
||||
\t\t\t\t\t(size 1.27 1.27)
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(justify left)
|
||||
\t\t\t)
|
||||
\t\t)
|
||||
\t\t(property "Footprint" ""
|
||||
\t\t\t(at {round(x, 2)} {round(y, 2)} 0)
|
||||
\t\t\t(effects
|
||||
\t\t\t\t(font
|
||||
\t\t\t\t\t(size 1.27 1.27)
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(hide yes)
|
||||
\t\t\t)
|
||||
\t\t)
|
||||
\t\t(property "Datasheet" ""
|
||||
\t\t\t(at {round(x, 2)} {round(y, 2)} 0)
|
||||
\t\t\t(effects
|
||||
\t\t\t\t(font
|
||||
\t\t\t\t\t(size 1.27 1.27)
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(hide yes)
|
||||
\t\t\t)
|
||||
\t\t)
|
||||
\t\t(property "Description" ""
|
||||
\t\t\t(at {round(x, 2)} {round(y, 2)} 0)
|
||||
\t\t\t(effects
|
||||
\t\t\t\t(font
|
||||
\t\t\t\t\t(size 1.27 1.27)
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(hide yes)
|
||||
\t\t\t)
|
||||
\t\t){extra_props}
|
||||
{pin_str}\t\t(instances
|
||||
\t\t\t(project ""
|
||||
\t\t\t\t(path "/{ROOT_UUID}"
|
||||
\t\t\t\t\t(reference "{ref}")
|
||||
\t\t\t\t\t(unit 1)
|
||||
\t\t\t\t)
|
||||
\t\t\t)
|
||||
\t\t)
|
||||
\t)"""
|
||||
|
||||
|
||||
def gen_pwr(lib_id, value, x, y, ref):
|
||||
"""Generate a power symbol block."""
|
||||
return f"""\t(symbol
|
||||
\t\t(lib_id "{lib_id}")
|
||||
\t\t(at {round(x, 2)} {round(y, 2)} 0)
|
||||
\t\t(unit 1)
|
||||
\t\t(exclude_from_sim no)
|
||||
\t\t(in_bom yes)
|
||||
\t\t(on_board yes)
|
||||
\t\t(dnp no)
|
||||
\t\t(uuid "{uid()}")
|
||||
\t\t(property "Reference" "{ref}"
|
||||
\t\t\t(at {round(x, 2)} {round(y - 2.54, 2)} 0)
|
||||
\t\t\t(effects
|
||||
\t\t\t\t(font
|
||||
\t\t\t\t\t(size 1.27 1.27)
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(hide yes)
|
||||
\t\t\t)
|
||||
\t\t)
|
||||
\t\t(property "Value" "{value}"
|
||||
\t\t\t(at {round(x, 2)} {round(y + 3.81, 2)} 0)
|
||||
\t\t\t(effects
|
||||
\t\t\t\t(font
|
||||
\t\t\t\t\t(size 1.27 1.27)
|
||||
\t\t\t\t)
|
||||
\t\t\t)
|
||||
\t\t)
|
||||
\t\t(property "Footprint" ""
|
||||
\t\t\t(at {round(x, 2)} {round(y, 2)} 0)
|
||||
\t\t\t(effects
|
||||
\t\t\t\t(font
|
||||
\t\t\t\t\t(size 1.27 1.27)
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(hide yes)
|
||||
\t\t\t)
|
||||
\t\t)
|
||||
\t\t(property "Datasheet" ""
|
||||
\t\t\t(at {round(x, 2)} {round(y, 2)} 0)
|
||||
\t\t\t(effects
|
||||
\t\t\t\t(font
|
||||
\t\t\t\t\t(size 1.27 1.27)
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(hide yes)
|
||||
\t\t\t)
|
||||
\t\t)
|
||||
\t\t(property "Description" ""
|
||||
\t\t\t(at {round(x, 2)} {round(y, 2)} 0)
|
||||
\t\t\t(effects
|
||||
\t\t\t\t(font
|
||||
\t\t\t\t\t(size 1.27 1.27)
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(hide yes)
|
||||
\t\t\t)
|
||||
\t\t)
|
||||
\t\t(pin "1"
|
||||
\t\t\t(uuid "{uid()}")
|
||||
\t\t)
|
||||
\t\t(instances
|
||||
\t\t\t(project ""
|
||||
\t\t\t\t(path "/{ROOT_UUID}"
|
||||
\t\t\t\t\t(reference "{ref}")
|
||||
\t\t\t\t\t(unit 1)
|
||||
\t\t\t\t)
|
||||
\t\t\t)
|
||||
\t\t)
|
||||
\t)"""
|
||||
|
||||
|
||||
def gen_wire(x1, y1, x2, y2):
|
||||
return f"""\t(wire
|
||||
\t\t(pts
|
||||
\t\t\t(xy {round(x1, 2)} {round(y1, 2)}) (xy {round(x2, 2)} {round(y2, 2)})
|
||||
\t\t)
|
||||
\t\t(stroke
|
||||
\t\t\t(width 0)
|
||||
\t\t\t(type default)
|
||||
\t\t)
|
||||
\t\t(uuid "{uid()}")
|
||||
\t)"""
|
||||
|
||||
|
||||
def gen_junction(x, y):
|
||||
return f"""\t(junction
|
||||
\t\t(at {round(x, 2)} {round(y, 2)})
|
||||
\t\t(diameter 0)
|
||||
\t\t(color 0 0 0 0)
|
||||
\t\t(uuid "{uid()}")
|
||||
\t)"""
|
||||
|
||||
|
||||
def gen_label(x, y, name, rot=0):
|
||||
return f"""\t(label "{name}"
|
||||
\t\t(at {round(x, 2)} {round(y, 2)} {rot})
|
||||
\t\t(effects
|
||||
\t\t\t(font
|
||||
\t\t\t\t(size 1.27 1.27)
|
||||
\t\t\t)
|
||||
\t\t)
|
||||
\t\t(uuid "{uid()}")
|
||||
\t)"""
|
||||
|
||||
|
||||
def gen_no_connect(x, y):
|
||||
return f"""\t(no_connect
|
||||
\t\t(at {round(x, 2)} {round(y, 2)})
|
||||
\t\t(uuid "{uid()}")
|
||||
\t)"""
|
||||
|
||||
|
||||
def gen_text(x, y, text):
|
||||
return f"""\t(text "{text}"
|
||||
\t\t(exclude_from_sim no)
|
||||
\t\t(at {round(x, 2)} {round(y, 2)} 0)
|
||||
\t\t(effects
|
||||
\t\t\t(font
|
||||
\t\t\t\t(size 1.27 1.27)
|
||||
\t\t\t)
|
||||
\t\t\t(justify left)
|
||||
\t\t)
|
||||
\t\t(uuid "{uid()}")
|
||||
\t)"""
|
||||
|
||||
|
||||
# ── TPS61088 lib_symbol definition ──
|
||||
|
||||
TPS61088_LIB_SYMBOL = """\t\t(symbol "TPS61088:TPS61088"
|
||||
\t\t\t(exclude_from_sim no)
|
||||
\t\t\t(in_bom yes)
|
||||
\t\t\t(on_board yes)
|
||||
\t\t\t(property "Reference" "U"
|
||||
\t\t\t\t(at 0 16.51 0)
|
||||
\t\t\t\t(effects (font (size 1.27 1.27)))
|
||||
\t\t\t)
|
||||
\t\t\t(property "Value" "TPS61088"
|
||||
\t\t\t\t(at 0 13.97 0)
|
||||
\t\t\t\t(effects (font (size 1.27 1.27)))
|
||||
\t\t\t)
|
||||
\t\t\t(property "Footprint" "Package_DFN_QFN:QFN-20-1EP_3.5x3.5mm_P0.5mm_EP2.1x2.1mm"
|
||||
\t\t\t\t(at 0 -20.32 0)
|
||||
\t\t\t\t(effects (font (size 1.27 1.27)) (hide yes))
|
||||
\t\t\t)
|
||||
\t\t\t(property "Datasheet" "https://www.ti.com/lit/ds/symlink/tps61088.pdf"
|
||||
\t\t\t\t(at 0 -22.86 0)
|
||||
\t\t\t\t(effects (font (size 1.27 1.27)) (hide yes))
|
||||
\t\t\t)
|
||||
\t\t\t(property "Description" "10A Fully-Integrated Synchronous Boost Converter"
|
||||
\t\t\t\t(at 0 -25.4 0)
|
||||
\t\t\t\t(effects (font (size 1.27 1.27)) (hide yes))
|
||||
\t\t\t)
|
||||
\t\t\t(symbol "TPS61088_0_1"
|
||||
\t\t\t\t(rectangle
|
||||
\t\t\t\t\t(start -10.16 12.7)
|
||||
\t\t\t\t\t(end 10.16 -12.7)
|
||||
\t\t\t\t\t(stroke (width 0.254) (type default))
|
||||
\t\t\t\t\t(fill (type background))
|
||||
\t\t\t\t)
|
||||
\t\t\t)
|
||||
\t\t\t(symbol "TPS61088_1_1"
|
||||
\t\t\t\t(pin power_in line
|
||||
\t\t\t\t\t(at -12.7 10.16 0) (length 2.54)
|
||||
\t\t\t\t\t(name "VIN" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t\t(number "1" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(pin input line
|
||||
\t\t\t\t\t(at -12.7 5.08 0) (length 2.54)
|
||||
\t\t\t\t\t(name "EN" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t\t(number "3" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(pin passive line
|
||||
\t\t\t\t\t(at -12.7 0 0) (length 2.54)
|
||||
\t\t\t\t\t(name "SS/TR" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t\t(number "4" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(pin passive line
|
||||
\t\t\t\t\t(at -12.7 -5.08 0) (length 2.54)
|
||||
\t\t\t\t\t(name "COMP" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t\t(number "5" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(pin input line
|
||||
\t\t\t\t\t(at -12.7 -10.16 0) (length 2.54)
|
||||
\t\t\t\t\t(name "FB" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t\t(number "6" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(pin passive line
|
||||
\t\t\t\t\t(at 12.7 10.16 180) (length 2.54)
|
||||
\t\t\t\t\t(name "SW" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t\t(number "12" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(pin passive line
|
||||
\t\t\t\t\t(at 12.7 5.08 180) (length 2.54)
|
||||
\t\t\t\t\t(name "BST" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t\t(number "11" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(pin power_out line
|
||||
\t\t\t\t\t(at 12.7 0 180) (length 2.54)
|
||||
\t\t\t\t\t(name "VOUT" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t\t(number "9" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(pin open_collector line
|
||||
\t\t\t\t\t(at 12.7 -5.08 180) (length 2.54)
|
||||
\t\t\t\t\t(name "PGOOD" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t\t(number "8" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(pin power_in line
|
||||
\t\t\t\t\t(at 0 -15.24 90) (length 2.54)
|
||||
\t\t\t\t\t(name "PGND" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t\t(number "15" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t)
|
||||
\t\t\t\t(pin power_in line
|
||||
\t\t\t\t\t(at -5.08 -15.24 90) (length 2.54)
|
||||
\t\t\t\t\t(name "AGND" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t\t(number "7" (effects (font (size 1.27 1.27))))
|
||||
\t\t\t\t)
|
||||
\t\t\t)
|
||||
\t\t\t(embedded_fonts no)
|
||||
\t\t)"""
|
||||
|
||||
|
||||
def generate_boost_circuit():
|
||||
"""Generate all the schematic elements for the TPS61088 boost converter.
|
||||
Returns (junctions, wires, labels, no_connects, texts, symbols) as lists of strings.
|
||||
|
||||
Placed below the main circuit, centered around (80, 140).
|
||||
"""
|
||||
junctions = []
|
||||
wires = []
|
||||
labels = []
|
||||
no_connects = []
|
||||
texts = []
|
||||
symbols = []
|
||||
|
||||
pwr_idx = [30] # start well after existing power refs (existing go up to #PWR23)
|
||||
def next_pwr():
|
||||
pwr_idx[0] += 1
|
||||
return f"#PWR{pwr_idx[0]:02d}"
|
||||
|
||||
# IC center
|
||||
cx, cy = 80.01, 140.97
|
||||
|
||||
# Pin absolute positions
|
||||
VIN = (cx - 12.7, cy - 10.16)
|
||||
EN = (cx - 12.7, cy - 5.08)
|
||||
SS = (cx - 12.7, cy)
|
||||
COMP = (cx - 12.7, cy + 5.08)
|
||||
FB = (cx - 12.7, cy + 10.16)
|
||||
SW = (cx + 12.7, cy - 10.16)
|
||||
BST = (cx + 12.7, cy - 5.08)
|
||||
VOUT = (cx + 12.7, cy)
|
||||
PG = (cx + 12.7, cy + 5.08)
|
||||
PGND = (cx, cy + 15.24)
|
||||
AGND = (cx - 5.08, cy + 15.24)
|
||||
|
||||
# Place TPS61088 IC
|
||||
ic_pins = {str(i): uid() for i in [1, 3, 4, 5, 6, 7, 8, 9, 11, 12, 15]}
|
||||
symbols.append(gen_symbol("TPS61088:TPS61088", "U1", "TPS61088", cx, cy, pins=ic_pins))
|
||||
|
||||
# ── INPUT SECTION ──
|
||||
vin_rail_y = VIN[1]
|
||||
pwr5v_x = 39.37
|
||||
c1_x = 44.45
|
||||
c2_x = 52.07
|
||||
en_tap_x = 59.69
|
||||
|
||||
# +5V source
|
||||
ref = next_pwr()
|
||||
symbols.append(gen_pwr("power:+5V", "+5V", pwr5v_x, vin_rail_y - 5.08, ref))
|
||||
wires.append(gen_wire(pwr5v_x, vin_rail_y - 5.08, pwr5v_x, vin_rail_y))
|
||||
|
||||
# VIN rail (segmented)
|
||||
wires.append(gen_wire(pwr5v_x, vin_rail_y, c1_x, vin_rail_y))
|
||||
wires.append(gen_wire(c1_x, vin_rail_y, c2_x, vin_rail_y))
|
||||
wires.append(gen_wire(c2_x, vin_rail_y, en_tap_x, vin_rail_y))
|
||||
wires.append(gen_wire(en_tap_x, vin_rail_y, VIN[0], vin_rail_y))
|
||||
|
||||
# C1 input cap (22µF) — using Device:C (pins at ±3.81)
|
||||
c1_cy = vin_rail_y + 6.35
|
||||
symbols.append(gen_symbol("Device:C", "C4", "22uF", c1_x, c1_cy,
|
||||
pins={"1": uid(), "2": uid()}))
|
||||
wires.append(gen_wire(c1_x, c1_cy - 3.81, c1_x, vin_rail_y))
|
||||
ref = next_pwr()
|
||||
symbols.append(gen_pwr("power:GND", "GND", c1_x, c1_cy + 6.35, ref))
|
||||
wires.append(gen_wire(c1_x, c1_cy + 3.81, c1_x, c1_cy + 6.35))
|
||||
|
||||
# C2 input cap (22µF)
|
||||
c2_cy = vin_rail_y + 6.35
|
||||
symbols.append(gen_symbol("Device:C", "C5", "22uF", c2_x, c2_cy,
|
||||
pins={"1": uid(), "2": uid()}))
|
||||
wires.append(gen_wire(c2_x, c2_cy - 3.81, c2_x, vin_rail_y))
|
||||
ref = next_pwr()
|
||||
symbols.append(gen_pwr("power:GND", "GND", c2_x, c2_cy + 6.35, ref))
|
||||
wires.append(gen_wire(c2_x, c2_cy + 3.81, c2_x, c2_cy + 6.35))
|
||||
|
||||
# EN tied to VIN
|
||||
wires.append(gen_wire(EN[0], EN[1], en_tap_x, EN[1]))
|
||||
wires.append(gen_wire(en_tap_x, EN[1], en_tap_x, vin_rail_y))
|
||||
|
||||
# ── SOFT-START ──
|
||||
ss_x = 59.69
|
||||
c3_cy = SS[1] + 6.35
|
||||
wires.append(gen_wire(SS[0], SS[1], ss_x, SS[1]))
|
||||
symbols.append(gen_symbol("Device:C", "C6", "22nF", ss_x, c3_cy,
|
||||
pins={"1": uid(), "2": uid()}))
|
||||
wires.append(gen_wire(ss_x, SS[1], ss_x, c3_cy - 3.81))
|
||||
ref = next_pwr()
|
||||
symbols.append(gen_pwr("power:GND", "GND", ss_x, c3_cy + 6.35, ref))
|
||||
wires.append(gen_wire(ss_x, c3_cy + 3.81, ss_x, c3_cy + 6.35))
|
||||
|
||||
# ── COMPENSATION ──
|
||||
comp_x = 52.07
|
||||
r1_y = COMP[1] + 6.35
|
||||
wires.append(gen_wire(COMP[0], COMP[1], comp_x, COMP[1]))
|
||||
symbols.append(gen_symbol("Device:R", "R3", "30.1k", comp_x, r1_y, # COMP resistor
|
||||
pins={"1": uid(), "2": uid()}))
|
||||
wires.append(gen_wire(comp_x, COMP[1], comp_x, r1_y - 3.81))
|
||||
|
||||
c4_y = r1_y + 10.16
|
||||
symbols.append(gen_symbol("Device:C", "C8", "47pF", comp_x, c4_y,
|
||||
pins={"1": uid(), "2": uid()}))
|
||||
wires.append(gen_wire(comp_x, r1_y + 3.81, comp_x, c4_y - 3.81))
|
||||
ref = next_pwr()
|
||||
symbols.append(gen_pwr("power:GND", "GND", comp_x, c4_y + 6.35, ref))
|
||||
wires.append(gen_wire(comp_x, c4_y + 3.81, comp_x, c4_y + 6.35))
|
||||
|
||||
# ── IC GROUND ──
|
||||
gnd_y = PGND[1] + 5.08
|
||||
ref = next_pwr()
|
||||
symbols.append(gen_pwr("power:GND", "GND", PGND[0], gnd_y, ref))
|
||||
wires.append(gen_wire(PGND[0], PGND[1], PGND[0], gnd_y))
|
||||
wires.append(gen_wire(AGND[0], AGND[1], AGND[0], gnd_y))
|
||||
wires.append(gen_wire(AGND[0], gnd_y, PGND[0], gnd_y))
|
||||
junctions.append(gen_junction(PGND[0], gnd_y))
|
||||
|
||||
# ── OUTPUT SECTION ──
|
||||
c5_x = 97.79
|
||||
l1_x = 102.87
|
||||
l1_y = SW[1]
|
||||
l1_pin1 = (l1_x - 3.81, l1_y)
|
||||
l1_pin2 = (l1_x + 3.81, l1_y)
|
||||
|
||||
symbols.append(gen_symbol("Device:L", "L1", "2.2uH", l1_x, l1_y, rot=90,
|
||||
pins={"1": uid(), "2": uid()}))
|
||||
|
||||
# SW → C5 junction → L1
|
||||
wires.append(gen_wire(SW[0], SW[1], c5_x, SW[1]))
|
||||
wires.append(gen_wire(c5_x, SW[1], l1_pin1[0], l1_pin1[1]))
|
||||
|
||||
# Bootstrap cap C5 (100nF)
|
||||
c5_cy = SW[1] + 3.81
|
||||
symbols.append(gen_symbol("Device:C", "C9", "100nF", c5_x, c5_cy,
|
||||
pins={"1": uid(), "2": uid()}))
|
||||
junctions.append(gen_junction(c5_x, SW[1]))
|
||||
wires.append(gen_wire(c5_x, c5_cy + 3.81, BST[0], BST[1]))
|
||||
|
||||
# VOUT rail
|
||||
vout_rail_x = 115.57
|
||||
wires.append(gen_wire(l1_pin2[0], l1_pin2[1], vout_rail_x, l1_y))
|
||||
wires.append(gen_wire(VOUT[0], VOUT[1], vout_rail_x, VOUT[1]))
|
||||
wires.append(gen_wire(vout_rail_x, l1_y, vout_rail_x, VOUT[1]))
|
||||
|
||||
# Output caps
|
||||
c6_x = 120.65
|
||||
c7_x = 128.27
|
||||
|
||||
wires.append(gen_wire(vout_rail_x, l1_y, c6_x, l1_y))
|
||||
wires.append(gen_wire(c6_x, l1_y, c7_x, l1_y))
|
||||
|
||||
c6_cy = l1_y + 6.35
|
||||
symbols.append(gen_symbol("Device:C", "C10", "22uF", c6_x, c6_cy,
|
||||
pins={"1": uid(), "2": uid()}))
|
||||
wires.append(gen_wire(c6_x, c6_cy - 3.81, c6_x, l1_y))
|
||||
ref = next_pwr()
|
||||
symbols.append(gen_pwr("power:GND", "GND", c6_x, c6_cy + 6.35, ref))
|
||||
wires.append(gen_wire(c6_x, c6_cy + 3.81, c6_x, c6_cy + 6.35))
|
||||
|
||||
c7_cy = l1_y + 6.35
|
||||
symbols.append(gen_symbol("Device:C", "C11", "22uF", c7_x, c7_cy,
|
||||
pins={"1": uid(), "2": uid()}))
|
||||
wires.append(gen_wire(c7_x, c7_cy - 3.81, c7_x, l1_y))
|
||||
ref = next_pwr()
|
||||
symbols.append(gen_pwr("power:GND", "GND", c7_x, c7_cy + 6.35, ref))
|
||||
wires.append(gen_wire(c7_x, c7_cy + 3.81, c7_x, c7_cy + 6.35))
|
||||
|
||||
# +12V output
|
||||
ref = next_pwr()
|
||||
symbols.append(gen_pwr("power:+12V", "+12V", c7_x, l1_y - 5.08, ref))
|
||||
wires.append(gen_wire(c7_x, l1_y, c7_x, l1_y - 5.08))
|
||||
junctions.append(gen_junction(c7_x, l1_y))
|
||||
|
||||
# ── FEEDBACK DIVIDER ──
|
||||
fb_x = vout_rail_x
|
||||
r2_y = VOUT[1] + 6.35
|
||||
symbols.append(gen_symbol("Device:R", "R4", "190k", fb_x, r2_y,
|
||||
pins={"1": uid(), "2": uid()}))
|
||||
wires.append(gen_wire(fb_x, VOUT[1], fb_x, r2_y - 3.81))
|
||||
junctions.append(gen_junction(fb_x, VOUT[1]))
|
||||
|
||||
r3_y = r2_y + 10.16
|
||||
symbols.append(gen_symbol("Device:R", "R5", "10k", fb_x, r3_y,
|
||||
pins={"1": uid(), "2": uid()}))
|
||||
wires.append(gen_wire(fb_x, r2_y + 3.81, fb_x, r3_y - 3.81))
|
||||
|
||||
# FB tap label
|
||||
fb_tap_y = r2_y + 3.81
|
||||
wires.append(gen_wire(fb_x, fb_tap_y, fb_x + 5.08, fb_tap_y))
|
||||
labels.append(gen_label(fb_x + 5.08, fb_tap_y, "FB"))
|
||||
junctions.append(gen_junction(fb_x, fb_tap_y))
|
||||
|
||||
# FB label at IC
|
||||
wires.append(gen_wire(FB[0], FB[1], FB[0] - 5.08, FB[1]))
|
||||
labels.append(gen_label(FB[0] - 5.08, FB[1], "FB", rot=180))
|
||||
|
||||
# R3 to GND
|
||||
ref = next_pwr()
|
||||
symbols.append(gen_pwr("power:GND", "GND", fb_x, r3_y + 6.35, ref))
|
||||
wires.append(gen_wire(fb_x, r3_y + 3.81, fb_x, r3_y + 6.35))
|
||||
|
||||
# PGOOD no connect
|
||||
no_connects.append(gen_no_connect(PG[0], PG[1]))
|
||||
|
||||
# ── NOTES ──
|
||||
nx = 39.37
|
||||
ny = 177.8
|
||||
texts.append(gen_text(nx, ny, "TPS61088 Boost: 5V to 12V @ 2A"))
|
||||
texts.append(gen_text(nx, ny + 3.81, "VOUT = 0.6V x (1 + 190k/10k) = 12.06V"))
|
||||
|
||||
return junctions, wires, labels, no_connects, texts, symbols
|
||||
|
||||
|
||||
def main():
|
||||
infile = "firstpcb.kicad_sch"
|
||||
outfile = "firstpcb.kicad_sch"
|
||||
|
||||
print(f"Reading {infile}...")
|
||||
with open(infile, "r") as f:
|
||||
text = f.read()
|
||||
|
||||
# Step 1: Remove L7805 lib_symbol
|
||||
print("\nRemoving L7805 lib_symbol...")
|
||||
text = remove_lib_symbol(text, REMOVE_LIB_SYMBOL)
|
||||
|
||||
# Step 2: Remove wires first (they reference removed components)
|
||||
print("\nRemoving L7805 circuit wires...")
|
||||
text = remove_blocks_by_uuid(text, REMOVE_WIRE_UUIDS)
|
||||
|
||||
# Step 3: Remove components and power symbols
|
||||
print("\nRemoving L7805 circuit components...")
|
||||
text = remove_blocks_by_uuid(text, REMOVE_UUIDS)
|
||||
|
||||
# Step 4: Add TPS61088 lib_symbol to lib_symbols section
|
||||
print("\nAdding TPS61088 lib_symbol...")
|
||||
# Find end of lib_symbols section (look for the closing paren before first junction/wire/label/symbol)
|
||||
# The lib_symbols section ends with a line like "\t)"
|
||||
# Find the pattern: a tab + ) that comes after all symbol definitions
|
||||
lib_end_marker = "\n\t)\n"
|
||||
# Find the FIRST occurrence of this pattern after "(lib_symbols"
|
||||
lib_start = text.find("(lib_symbols")
|
||||
if lib_start == -1:
|
||||
print("ERROR: Could not find lib_symbols section", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
# Find the end of lib_symbols by tracking paren depth
|
||||
lib_paren = text.index("(", lib_start)
|
||||
lib_end = find_block_end(text, lib_paren)
|
||||
# Insert before the closing paren
|
||||
insert_pos = lib_end
|
||||
# Read Device:L lib_symbol from KiCad library (not embedded in this schematic)
|
||||
device_l_sym = ""
|
||||
kicad_sym_paths = [
|
||||
"/nix/store/pbwczj1nsp823njj1kkw75a99jmkz958-kicad-symbols-884133df0a/share/kicad/symbols/Device.kicad_sym",
|
||||
"/nix/store/6yiq36yhskjhga4mw63ypbw2wcb4f4m9-kicad-symbols-884133df0a/share/kicad/symbols/Device.kicad_sym",
|
||||
]
|
||||
for path in kicad_sym_paths:
|
||||
try:
|
||||
with open(path) as lf:
|
||||
ltext = lf.read()
|
||||
ls = ltext.find('\n\t(symbol "L"')
|
||||
if ls != -1:
|
||||
ls += 1
|
||||
li = ls
|
||||
while ltext[li] != '(':
|
||||
li += 1
|
||||
ldepth = 0
|
||||
lpos = li
|
||||
while lpos < len(ltext):
|
||||
if ltext[lpos] == '(':
|
||||
ldepth += 1
|
||||
elif ltext[lpos] == ')':
|
||||
ldepth -= 1
|
||||
if ldepth == 0:
|
||||
device_l_sym = ltext[ls:lpos+1]
|
||||
device_l_sym = device_l_sym.replace('(symbol "L"', '(symbol "Device:L"', 1)
|
||||
# Add extra tab for nesting inside lib_symbols
|
||||
device_l_sym = '\n'.join('\t' + line for line in device_l_sym.split('\n'))
|
||||
print(f" Loaded Device:L from {path}")
|
||||
break
|
||||
lpos += 1
|
||||
if device_l_sym:
|
||||
break
|
||||
except FileNotFoundError:
|
||||
continue
|
||||
|
||||
text = text[:insert_pos] + "\n" + TPS61088_LIB_SYMBOL + "\n" + device_l_sym + "\n\t" + text[insert_pos:]
|
||||
|
||||
# Step 5: Generate and insert boost converter circuit
|
||||
print("\nGenerating TPS61088 boost converter circuit...")
|
||||
juncs, wires, lbls, ncs, txts, syms = generate_boost_circuit()
|
||||
|
||||
# Insert before (sheet_instances
|
||||
sheet_marker = "\t(sheet_instances"
|
||||
sheet_pos = text.find(sheet_marker)
|
||||
if sheet_pos == -1:
|
||||
print("ERROR: Could not find sheet_instances", file=sys.stderr)
|
||||
sys.exit(1)
|
||||
|
||||
insert_blocks = []
|
||||
insert_blocks.extend(juncs)
|
||||
insert_blocks.extend(ncs)
|
||||
insert_blocks.extend(wires)
|
||||
insert_blocks.extend(lbls)
|
||||
insert_blocks.extend(txts)
|
||||
insert_blocks.extend(syms)
|
||||
|
||||
insert_text = "\n".join(insert_blocks) + "\n"
|
||||
text = text[:sheet_pos] + insert_text + text[sheet_pos:]
|
||||
|
||||
# Step 6: Write output
|
||||
print(f"\nWriting {outfile}...")
|
||||
with open(outfile, "w") as f:
|
||||
f.write(text)
|
||||
|
||||
print("Done! Open in KiCad to review.")
|
||||
|
||||
|
||||
if __name__ == "__main__":
|
||||
main()
|
||||
@@ -0,0 +1,4 @@
|
||||
(sym_lib_table
|
||||
(version 7)
|
||||
(lib (name "TPS61088")(type "KiCad")(uri "${KIPRJMOD}/../TPS61088.kicad_sym")(options "")(descr "TPS61088 Boost Converter"))
|
||||
)
|
||||
Reference in New Issue
Block a user