main
Caleb Publish 0.1.1 d05c478 1d ago
#!/usr/bin/env python3
"""Build TI's RDN0011B (QFN-FCMOD, 11 terminals, 3.5 x 4.5 x 2.0 mm) for TPSM33620S5QRDNRQ1, hand-built in CadQuery by
Adom (tier 3) from the TPSM336xx-Q1 datasheet SNVSCS7E, PACKAGE OUTLINE RDN0011B, drawing 4231197/C 05/2026 (PDF p.46),
cross-checked with the EXAMPLE BOARD LAYOUT (p.47).

Printed (mm): D 3.4-3.6, E 4.4-4.6, A 1.9-2.1, A1 0-0.05; pads 4/5 1.05-1.15 x 2.0-2.1 with 8X (0.25) tabs to the body
edge, (0.2) long, at 6X [0.5] from 2X [0.3]; pins 2/3/6/7 width 0.15-0.35, length 0.8-1.0 at [0.65] / [1.15]; pins 1/8
height 0.325-0.425, length 0.825-1.025; pins 9/11 width 0.15-0.35 at x = [0.5], length 0.55-0.65; pin 10 width 0.2-0.4,
1.3-1.4 from the body edge; terminal thickness on the side wall (0.2) TYP. Modelled at the mid values: body 3.50 x 4.50,
A 2.00 with A1 0 (terminals flush with the mould bottom), terminal thickness 0.20.
Measured off the bottom view (157.6 px/mm at 400 dpi, calibrated on the body outline 3.5 x 4.5; every printed dimension
measures true): pin 1 / 8 centred 1.96 from the package centre (the land pattern prints (1.96)), their outer ends notched to
0.25 high over the last 0.2 mm, pin 1's inner top corner chamfered 0.2 x 0.2 (pin-1 indicator), pin 8's inner corners
rounded; racetrack terminals with semicircular inner ends; pads 4/5 inner corners R0.1.
Not modelled: the outline's second line 0.05 inside the body edge (reference only), the tie-bar ticks at the bottom edge.
Frame: STEP = top view, X right, Y up (= footprint -y), Z up, seated on z = 0, centred; the bottom view maps by y -> -y.
usage: build_rdn0011b.py out.step [name]"""
import sys
import cadquery as cq

D, E, A, T = 3.5, 4.5, 2.0, 0.20

def rect(x0, x1, y0, y1):
    return cq.Workplane('XY').box(x1 - x0, y1 - y0, T, centered=False).translate((x0, y0, 0))

def racetrack_h(x_edge, x_tip, yc, w):
    """Terminal from the body edge x_edge to a semicircular tip at x_tip (bottom-view y = yc)."""
    r = w / 2; s = 1 if x_tip > x_edge else -1
    body = rect(min(x_edge, x_tip - s * r), max(x_edge, x_tip - s * r), yc - r, yc + r)
    cap = cq.Workplane('XY').circle(r).extrude(T).translate((x_tip - s * r, yc, 0))
    return body.union(cap)

def racetrack_v(y_edge, y_tip, xc, w):
    r = w / 2; s = 1 if y_tip > y_edge else -1
    body = rect(xc - r, xc + r, min(y_edge, y_tip - s * r), max(y_edge, y_tip - s * r))
    cap = cq.Workplane('XY').circle(r).extrude(T).translate((xc, y_tip - s * r, 0))
    return body.union(cap)

def bottom_view_terminals():
    """Terminals in bottom-view coordinates (x right, y toward pads 4/5)."""
    t = {}
    for name, sx in (('4', -1), ('5', 1)):
        main = (cq.Workplane('XY').rect(1.10, 2.05).extrude(T).translate((sx * 1.00, 1.005, 0)))
        main = main.edges('|Z').edges('<X' if sx > 0 else '>X').fillet(0.1)
        for yc in (0.30, 0.80, 1.30, 1.80):
            main = main.union(rect(*(sorted((sx * 1.55, sx * 1.75))), yc - 0.125, yc + 0.125))
        t[name] = main
    t['3'] = racetrack_h(-1.75, -0.85, -0.65, 0.25); t['2'] = racetrack_h(-1.75, -0.85, -1.15, 0.25)
    t['6'] = racetrack_h(1.75, 0.85, -0.65, 0.25);   t['7'] = racetrack_h(1.75, 0.85, -1.15, 0.25)
    t['11'] = racetrack_v(-2.25, -1.65, -0.5, 0.25); t['9'] = racetrack_v(-2.25, -1.65, 0.5, 0.25)
    t['10'] = racetrack_v(-2.25, -0.90, 0.0, 0.30)
    yt, yb, yn = -1.775, -2.145, -2.02            # pin 1 / 8: 0.37 high centred at -1.96, outer 0.2 mm notched to -2.02
    p1 = (cq.Workplane('XY').polyline([(-1.75, yt), (-1.025, yt), (-0.825, yt - 0.2), (-0.825, yb), (-1.55, yb), (-1.55, yn), (-1.75, yn)])
          .close().extrude(T))
    p8 = (cq.Workplane('XY').polyline([(1.75, yt), (0.825, yt), (0.825, yb), (1.55, yb), (1.55, yn), (1.75, yn)]).close().extrude(T))
    p8 = p8.edges('|Z').edges('<X').fillet(0.1)
    t['1'], t['8'] = p1, p8
    return t

def build():
    terms = {k: v.mirror('XZ') for k, v in bottom_view_terminals().items()}   # bottom view y -> top view Y = -y
    body = cq.Workplane('XY').box(D, E, A, centered=(True, True, False))
    for v in terms.values(): body = body.cut(v)
    dot = cq.Workplane('XY').circle(0.25).extrude(0.05).translate((-1.15, 1.65, A - 0.05))   # pin-1 index area (top-left)
    body = body.cut(dot)
    pins = None
    for k in sorted(terms, key=int):
        pins = terms[k] if pins is None else pins.union(terms[k])
    return body, pins, dot

if __name__ == '__main__':
    out = sys.argv[1]; name = sys.argv[2] if len(sys.argv) > 2 else 'RDN0011B'
    body, pins, dot = build()
    a = cq.Assembly(name=name)
    a.add(body, name='body', color=cq.Color(0.10, 0.10, 0.10))
    a.add(pins, name='pins', color=cq.Color(0.82, 0.82, 0.78))
    a.add(dot, name='mark', color=cq.Color(0.60, 0.60, 0.58))
    a.export(out)
    print(out)