main
John Lauer Component record TPS16850VMAR: files batch 1 6db00ed 18h ago
#!/usr/bin/env python3
"""Build TI's VMA0023A LQFN-CLIP-23 package (TPS1685x) from the PACKAGE OUTLINE drawing, SLVSHA1D p.54
(4230225/A 11/2023), in KiCad's 3D frame: Z up, seated on z = 0, centred on the package centre lines (= the
footprint origin), X right, Y up (the datasheet's top view; KiCad footprint y = -Y). Pin 1 (ILIM) at (-2.75, +0.5).

TI prints the bottom view turned over about the X axis (pin 1 below the centre line there); every y read from it
is negated here, so the terminals sit under the land-pattern pads of p.55.

Printed values used (nominal = middle of min/max):
  D 5.9..6.1 -> 6.0 (X), E 4.9..5.1 -> 5.0 (Y), A 1.3..1.5 -> 1.4, A1 0.00..0.05 -> 0.025 (terminal stand-off)
  terminal width 28X 0.2..0.3 -> 0.25; pin 7 teeth 4X 0.15..0.25 -> 0.20; pin 6 leg 0.25..0.35 -> 0.30
  side terminals: left (1-5) 0.4..0.6 -> 0.50, right (11-16) 10X 0.35..0.55 -> 0.45, top (18-21) 4X 0.3..0.5 -> 0.40,
  bottom (8, 9) 3X 0.45..0.65 -> 0.55; pin 23 1.0..1.2 -> 1.10; pin 10 bar 0.35..0.45 -> 0.40 centred 2.05;
  pin 22 bar edge 0.475..0.675 -> 0.575 from the package edge, centre 2.05; exposed pad 3.4 x 2.35 (+-0.1) centred
  0.075 off the package centre line, pin-1 chamfer 45 deg x 0.25; terminal exposure on the side walls (0.2) TYP.
Positions are the drawing's basic (boxed) dimensions and match the land pattern of p.55.
Undimensioned, measured off the drawing at 118 px/mm (300 dpi): pin 7 bar inner edge 1.95 from the centre line,
notch depth 0.25 on pins 7, 10 and 22. Terminal thickness taken as the (0.2) side exposure; inner terminal ends
rounded as drawn.
Colours from TI's VMA package render (DigiKey image MFG_296~4230225~VMA~23): dark grey mould, silver (NiPdAu)
terminal faces, copper where the terminals are sawn through at the side walls.

usage: build_vma23.py out.step [--detail full|low|superlow]
  full: as drawn; low: square inner terminal ends; superlow: square ends and one terminal part without the
  copper end slices (every terminal, comb teeth included, kept).
Writes an assembly: body (mould), pins (terminal faces), pin_ends (sawn copper ends on the side walls).
"""
import sys
import cadquery as cq

out = sys.argv[1]
detail = sys.argv[sys.argv.index("--detail") + 1] if "--detail" in sys.argv else "full"
D, E, A, A1, T = 6.0, 5.0, 1.4, 0.025, 0.20
HX, HY = D / 2, E / 2
SAW = 0.02
RND = detail == "full"

def rect(x1, y1, x2, y2): return [(x1, y1), (x2, y1), (x2, y2), (x1, y2)]

def solid_poly(pts, z0=0.0, h=T, simplify=True):
    return cq.Workplane("XY").workplane(offset=z0).polyline(pts).close().extrude(h)

def lead(x1, y1, x2, y2, inner):
    w = cq.Workplane("XY").polyline(rect(x1, y1, x2, y2)).close().extrude(T)
    if RND:
        if inner in ("+x", "-x"):
            r = (y2 - y1) / 2; cx = x2 - r if inner == "+x" else x1 + r; cy = (y1 + y2) / 2
            box = rect(cx, y1, x2, y2) if inner == "+x" else rect(x1, y1, cx, y2)
        else:
            r = (x2 - x1) / 2; cy = y2 - r if inner == "+y" else y1 + r; cx = (x1 + x2) / 2
            box = rect(x1, cy, x2, y2) if inner == "+y" else rect(x1, y1, x2, cy)
        w = w.cut(solid_poly(box, -0.01, T + 0.02, False)).union(cq.Workplane("XY").center(cx, cy).circle(r).extrude(T))
    return w

W = 0.25
terms = []
for y in (0.5, 0.0, -0.5, -1.0, -1.5):                         # 1-5, L 0.50
    terms.append(lead(-HX, y - W/2, -HX + 0.50, y + W/2, "+x"))
for y in (-0.925, -0.425, 0.075, 0.575, 1.075, 1.575):         # 11-16, L 0.45
    terms.append(lead(HX - 0.45, y - W/2, HX, y + W/2, "-x"))
for x in (1.85, 1.35, 0.85, 0.35):                             # 18-21, L 0.40
    terms.append(lead(x - W/2, HY - 0.40, x + W/2, HY, "-y"))
for x in (0.225, 1.275):                                       # 8, 9, L 0.55
    terms.append(lead(x - W/2, -HY, x + W/2, -HY + 0.55, "+y"))
terms.append(lead(-HX, 1.55 - W/2, -HX + 1.10, 1.55 + W/2, "+x"))   # 23, L 1.10
# 6: bar along the -x edge at y -2.0 (+-0.125) and a 0.30 leg at x -2.65 to the -y edge
terms.append(solid_poly([(-HX, -1.875), (-2.5, -1.875), (-2.5, -HY), (-2.8, -HY), (-2.8, -2.125), (-HX, -2.125)]))
# 17: 0.25 leg at x 2.35 to the +y edge, 0.25 bar at y 2.025 to the +x edge
terms.append(solid_poly([(2.225, HY), (2.475, HY), (2.475, 2.15), (HX, 2.15), (HX, 1.9), (2.225, 1.9)]))
# 7: bar y -2.25..-1.95, x -1.70..-0.15, teeth 0.20 wide at x -1.6 -1.15 -0.7 -0.25 to the -y edge
terms.append(solid_poly([(-1.70, -1.95), (-0.15, -1.95), (-0.15, -HY), (-0.35, -HY), (-0.35, -2.25), (-0.60, -2.25),
                         (-0.60, -HY), (-0.80, -HY), (-0.80, -2.25), (-1.05, -2.25), (-1.05, -HY), (-1.25, -HY),
                         (-1.25, -2.25), (-1.50, -2.25), (-1.50, -HY), (-1.70, -HY)]))
# 10: bar y -2.25..-1.85 from x 1.65 to the +x edge, teeth 0.25 wide at x 1.775, 2.275 to the -y edge
terms.append(solid_poly([(1.65, -1.85), (HX, -1.85), (HX, -2.25), (2.40, -2.25), (2.40, -HY), (2.15, -HY),
                         (2.15, -2.25), (1.90, -2.25), (1.90, -HY), (1.65, -HY)]))
# 22: bar y 1.925..2.25 from x -1.0 to -2.75, stub to the -x edge at y 1.925..2.175, teeth 0.25 wide at
#     x -2.625 -2.125 -1.625 -1.125 to the +y edge
terms.append(solid_poly([(-HX, 1.925), (-1.0, 1.925), (-1.0, HY), (-1.25, HY), (-1.25, 2.25), (-1.5, 2.25),
                         (-1.5, HY), (-1.75, HY), (-1.75, 2.25), (-2.0, 2.25), (-2.0, HY), (-2.25, HY),
                         (-2.25, 2.25), (-2.5, 2.25), (-2.5, HY), (-2.75, HY), (-2.75, 2.175), (-HX, 2.175)]))
# 24: exposed pad 3.4 x 2.35 at (0, +0.075), 0.25 x 45 deg chamfer at the pin-1 corner (-x, +y)
ex1, ex2, ey1, ey2, chf = -1.7, 1.7, 0.075 - 1.175, 0.075 + 1.175, 0.25
terms.append(solid_poly([(ex1, ey1), (ex2, ey1), (ex2, ey2), (ex1 + chf, ey2), (ex1, ey2 - chf)], simplify=False))

pins = terms[0]
for t in terms[1:]: pins = pins.union(t)
body = cq.Workplane("XY").box(D, E, A - A1, centered=(True, True, False)).translate((0, 0, A1)).cut(pins)
frame = cq.Workplane("XY").box(D, E, 1, centered=(True, True, False)).translate((0, 0, -0.5)).cut(
    cq.Workplane("XY").box(D - 2 * SAW, E - 2 * SAW, 2, centered=(True, True, False)).translate((0, 0, -1)))
asm = cq.Assembly(name="VMA0023A_LQFN-CLIP-23")
asm.add(body, name="body", color=cq.Color(0.16, 0.16, 0.17))
if detail == "superlow":
    asm.add(pins, name="pins", color=cq.Color(0.80, 0.80, 0.78))
else:
    asm.add(pins.cut(frame), name="pins", color=cq.Color(0.80, 0.80, 0.78))
    asm.add(pins.intersect(frame), name="pin_ends", color=cq.Color(0.80, 0.50, 0.33))
asm.save(out, exportType="STEP")
bb = asm.toCompound().BoundingBox()
print(f"OK {out} detail={detail} bbox x {bb.xmin:.3f}..{bb.xmax:.3f} y {bb.ymin:.3f}..{bb.ymax:.3f} z {bb.zmin:.3f}..{bb.zmax:.3f}")