molecule
12 V to 5 V / 1 A Buck Molecule (TPS54202), built in Altium Designer
Public Unreviewedby Colby Knox
A 12 V to 5 V, 1 A TPS54202 buck molecule designed and built by AI in Altium Designer from one sentence, with the Altium project, Gerbers, BOM, simulation and current and heat analysis.
main
Colby Knox
Altium Designer build of the TPS54202 buck molecule: Altium project, manufacturing set, STEP and GLB, design, simulatio…
845dd0d
4d ago
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112
#!/usr/bin/env python3
"""TPS54202 12 V -> 5 V / 1 A buck: every value from the datasheet equations (SLVSD26C).
Run: python3 calcs.py -> prints the design table and writes calcs.json.
"""
import itertools, json, math
# ---- brief --------------------------------------------------------------
VIN_NOM, VIN_MAX, VIN_MIN = 12.0, 16.0, 9.0 # 12 V bench/control-panel rail; design margin to 16 V
VOUT, IOUT = 5.0, 1.0
FSW = 500e3 # fixed, datasheet 5.5 (390..630 kHz)
VREF = 0.596 # datasheet 5.5, 0.581..0.611
RHS, RLS = 0.148, 0.078 # FET on-resistance, 25 C
ILIM_HS_MIN = 2.5
out = {}
# ---- feedback divider from Adom-stocked 0402 values (E24 subset, 41 values) ----
STOCK = [1, 1.5, 2.2, 3.3, 4.7, 6.8, 10, 15, 22, 33, 47, 68, 100, 120, 150, 220, 330, 470, 680,
1e3, 1.5e3, 2e3, 2.2e3, 3.3e3, 4.7e3, 5.6e3, 6.8e3, 10e3, 15e3, 22e3, 33e3, 47e3, 68e3,
100e3, 150e3, 220e3, 330e3, 470e3, 680e3, 1e6]
cands = []
single = [r for r in STOCK if 5e3 <= r <= 1e6]
pairs = [(a, b) for a, b in itertools.combinations_with_replacement(single, 2)]
for rtop_parts in [(r,) for r in single] + pairs:
rtop = sum(rtop_parts)
for rbot_parts in [(r,) for r in single] + pairs:
rbot = sum(rbot_parts)
if not (5e3 <= rbot <= 30e3) or not (50e3 <= rtop <= 250e3):
continue # keep divider current 20..100 uA, Rtop in the Cff range
v = VREF * (1 + rtop / rbot)
n = len(rtop_parts) + len(rbot_parts)
cands.append((abs(v - VOUT), n, rtop_parts, rbot_parts, v))
cands.sort(key=lambda c: (c[1] > 3, round(c[0], 3), c[1]))
err, n, rt, rb, v = cands[0]
out["feedback"] = {"Rtop_parts_ohm": rt, "Rbot_parts_ohm": rb, "Rtop": sum(rt), "Rbot": sum(rb),
"vout_nominal": round(v, 4), "error_pct": round(100 * (v - VOUT) / VOUT, 2),
"vout_range_vref_tol": [round(0.581 * (1 + sum(rt) / sum(rb)), 3),
round(0.611 * (1 + sum(rt) / sum(rb)), 3)]}
# ---- inductor (eq 8/9/10) ----------------------------------------------
KIND = 0.3
LMIN = VOUT * (VIN_MAX - VOUT) / (VIN_MAX * KIND * IOUT * FSW)
L = 15e-6
ripple = lambda vin: VOUT * (vin - VOUT) / (vin * L * FSW)
out["inductor"] = {"Lmin_uH": round(LMIN * 1e6, 2), "L_uH": 15,
"ripple_A_at_12V": round(ripple(VIN_NOM), 3), "ripple_A_at_16V": round(ripple(VIN_MAX), 3),
"Ipeak_A_at_16V": round(IOUT + ripple(VIN_MAX) / 2, 3),
"Irms_A": round(math.sqrt(IOUT**2 + ripple(VIN_MAX)**2 / 12), 3),
"Isat_required_A": ILIM_HS_MIN,
"note": ("Isat 3.7 A / Irms 3.5 A (AMPLH5030S-150M datasheet p2) >= the 2.5 A HS current-limit minimum, DCR 98 typ / 118 max mOhm. "
"15 uH chosen over Lmin 22.9 uH (KIND 0.3 at 16 V): it is the 5 V value in TI Table 7-2, which the internal slope compensation is tuned for; "
"ripple 0.39 A (39 pct) at 12 V and 0.46 A (46 pct) at 16 V, peak 1.23 A, within 20-50 pct for low-ESR ceramic outputs")}
# ---- output capacitance (eq 11/12/13/14) -------------------------------
dI_step, dV_allow = 1.0, 0.15 # 0 -> 1 A step, 3 % droop budget
CO_step = 2 * dI_step / (FSW * dV_allow)
CO_ripple = 1 / (8 * FSW * (0.010 / ripple(VIN_MAX))) # 10 mV ripple target
N_COUT, C_EACH, DERATE = 3, 22e-6, 0.55 # CL21A226MPQNNNE 0805 X5R 10 V; ~45 % loss at 5 V DC bias
CO_eff = N_COUT * C_EACH * DERATE
fo = 3.95e3 / (VOUT * CO_eff * 1e6) * 1e3 # eq 14, fo in Hz (Cout in uF, result kHz)
out["cout"] = {"C_step_min_uF": round(CO_step * 1e6, 1), "C_ripple_min_uF": round(CO_ripple * 1e6, 1),
"chosen": f"{N_COUT} x 22 uF 0805 X5R 10 V (Adom stock)", "effective_uF": round(CO_eff * 1e6, 1),
"fo_kHz_eq14": round(fo / 1e3, 1), "fo_limit_kHz": 40,
"ripple_mV_at_16V": round(ripple(VIN_MAX) / (8 * FSW * CO_eff) * 1e3, 2),
"Icout_rms_each_mA": round(ripple(VIN_MAX) / math.sqrt(12) / N_COUT * 1e3, 1)}
# ---- feed-forward capacitor (eq 16) ------------------------------------
CFF = 1 / (2 * math.pi * fo * out["feedback"]["Rtop"])
out["cff"] = {"calc_pF": round(CFF * 1e12, 1), "chosen_pF": 68,
"note": "C0G 0402 stock; verified by the loop-gain sim"}
# ---- input capacitance --------------------------------------------------
D = VOUT / VIN_NOM
ICIN_RMS = IOUT * math.sqrt(D * (1 - D))
CIN_eff = 2 * 10e-6 * 0.6
dVin = IOUT * D * (1 - D) / (CIN_eff * FSW)
out["cin"] = {"Irms_A": round(ICIN_RMS, 3), "chosen": "2 x 10 uF 1206 X7R 25 V (Mouser) + 100 nF 0603 X7R 50 V (Adom stock) at the VIN pin",
"effective_uF": CIN_eff * 1e6, "vin_ripple_mV": round(dVin * 1e3, 1),
"bulk": "47 uF 35 V aluminium electrolytic: damps the supply cable inductance against the low-ESR ceramics (hot-plug ringing), datasheet 7.3"}
# ---- EN UVLO divider (stocked values) ----------------------------------
IP, IH, VEN_R, VEN_F = 0.7e-6, 1.55e-6, 1.21, 1.19
R_EN_TOP, R_EN_BOT = 1e6, 150e3
vstart = R_EN_TOP * (VEN_R / R_EN_BOT - IP) + VEN_R
vstop = R_EN_TOP * (VEN_F / R_EN_BOT - IP - IH) + VEN_F
ven_max = VIN_MAX * R_EN_BOT / (R_EN_TOP + R_EN_BOT)
out["uvlo"] = {"R_top": R_EN_TOP, "R_bot": R_EN_BOT, "start_V": round(vstart, 2), "stop_V": round(vstop, 2),
"hysteresis_V": round(vstart - vstop, 2), "EN_at_16V": round(ven_max, 2), "EN_abs_max": 5.5,
"EN_at_28V": round(28 * R_EN_BOT / (R_EN_TOP + R_EN_BOT), 2)}
# ---- losses + thermal ---------------------------------------------------
DCR = 0.118 # Abracon AMPLH5030S-150MT (Mouser 815-AMPLH5030S-150T)
Irms = out["inductor"]["Irms_A"]
p_cond = Irms**2 * (D * RHS * 1.4 + (1 - D) * RLS * 1.4) # hot Rds(on) x1.4
p_sw = 0.5 * VIN_NOM * IOUT * (15e-9 + 15e-9) * FSW # ~15 ns edges, estimate
p_gate = 0.01
p_ic = p_cond + p_sw + p_gate
p_l = Irms**2 * DCR
eff = VOUT * IOUT / (VOUT * IOUT + p_ic + p_l)
out["thermal"] = {"P_ic_W": round(p_ic, 3), "P_inductor_W": round(p_l, 3), "efficiency_est": round(eff, 3),
"Tj_rise_C_RthJA_118.6": round(p_ic * 118.6, 1), "Tj_rise_C_RthJA_EVM_57.2": round(p_ic * 57.2, 1),
"note": "I^2R at hot Rds(on) over the duty + switching estimate; SOT-23 has no pad, heat leaves through the pins: GND/VIN copper is the heatsink"}
# ---- LED ----------------------------------------------------------------
out["led"] = {"R_ohm": 2.2e3, "I_mA": round((VOUT - 2.0) / 2.2e3 * 1e3, 2), "note": "power-good indicator on VOUT; 0603 green (Adom stock)"}
json.dump(out, open("calcs.json", "w"), indent=1)
for k, v in out.items():
print(f"== {k}")
for kk, vv in v.items():
print(f" {kk}: {vv}")