component
TMC2262
Public Made by Adomby adom
Analog Devices TMC2262 65 V, 4 A RMS smart stepper driver with step/dir, SPI and encoder input, 30-pin FC2QFN 6x6. KiCad, Fusion and Altium libraries, datasheet-built 3D model, every pin cited to the data sheet.
main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135
"""Finish the two footprints from adom-footprint's output (KiCad Y down, top view).
python3 tools/footprints.py <build/fp>
LAN8770M: Microchip land pattern C04-3268 Rev A (DS00002550C Figure 3-3). adom-footprint writes the 32 oval pads,
the 3.20 mm exposed pad and the 3 x 3 grid of 0.33 mm thermal vias (EV 1.20 mm); this adds a split paste stencil
on the exposed pad and the 3D model.
TMC2262: ADI land pattern 90-100245 Rev B (package 21-100708 Rev A). adom-footprint writes the 10 side bars, the
16 small pads and the 1.45 x 4.05 mm exposed pad with its heatsink vias; this adds the four L-shaped corner pads
(pins 6, 15, 21, 30) as KiCad custom pads with the drawing's R0.150 inner corner, a split paste stencil, the
silkscreen (the corner pads reach 0.3 mm past the body, so the outline sits outside the copper) and the model.
"""
import json, math, os, re, subprocess, sys
OUT = sys.argv[1] if len(sys.argv) > 1 else 'build/fp'
H = os.path.dirname(os.path.abspath(__file__))
def run(cmd):
r = subprocess.run(cmd, capture_output=True, text=True)
if r.returncode:
raise SystemExit('%s failed: %s %s' % (cmd, r.stdout[-500:], r.stderr[-500:]))
return r.stdout + r.stderr
def f(v):
s = ('%.4f' % v).rstrip('0').rstrip('.')
return '0' if s in ('-0', '') else s
def paste_windows(cx, cy, nx, ny, w, h, pitch_x, pitch_y):
out = []
for i in range(nx):
for j in range(ny):
x = cx + (i - (nx - 1) / 2) * pitch_x
y = cy + (j - (ny - 1) / 2) * pitch_y
out.append(' (pad "" smd rect (at %s %s) (size %s %s)\n (layers "F.Paste"))' % (f(x), f(y), f(w), f(h)))
return out
def model(slug):
return (' (model "${KIPRJMOD}/%s-etched.step"\n (offset (xyz 0 0 0))\n (scale (xyz 1 1 1))\n'
' (rotate (xyz 0 0 0))\n )' % slug)
def finish(text, ep, extra, slug, drop_silk=False):
# the exposed pad keeps copper + mask; its paste goes into separate windows
text = re.sub(r'(\(pad "%s" smd rect \(at [^)]*\) \(size [^)]*\)\n \(layers "F.Cu") "F.Paste" ("F.Mask"\))' % ep,
r'\1 \2', text, count=1)
if drop_silk:
text = re.sub(r' \(fp_line \(start [^)]*\) \(end [^)]*\)\n \(stroke [^\n]*\(layer "F.SilkS"\)\)\n', '', text)
text = text.rstrip()
assert text.endswith(')')
return text[:-1].rstrip() + '\n' + '\n'.join(extra) + '\n' + model(slug) + '\n)\n'
# ------------------------------------------------------------------------------------------------ LAN8770M
print(run(['adom-footprint', 'create', '--file', os.path.join(OUT, 'lan8770m-create.json'), '--out', os.path.join(OUT, 'lan8770m')]).strip().splitlines()[-3:])
lan = os.path.join(OUT, 'lan8770m', 'lan8770m.kicad_mod')
t = open(lan).read()
extra = paste_windows(0, 0, 2, 2, 1.25, 1.25, 1.6, 1.6) # 4 x 1.5625 mm2 = 61 % of the 3.2 mm pad
# pin 1: a filled dot at the pad-1 corner (the hero generator and every EDA tool read a filled mark as pin 1),
# in place of adom-footprint's bare line
t = t.replace(' (fp_line (start -2.8 -2.8) (end -2.2 -2.8)\n (stroke (width 0.12) (type default)) (layer "F.SilkS"))\n', '')
extra.append(' (fp_circle (center -3 -2.3) (end -2.9 -2.3)\n (stroke (width 0.05) (type default)) (fill solid) (layer "F.SilkS"))')
t = finish(t, 'EP', extra, 'lan8770m')
t = t.replace(' (fp_rect (start -2.5 -2.5) (end 2.5 2.5)\n (stroke (width 0.1) (type default)) (fill none) (layer "F.Fab"))',
' (fp_poly (pts (xy -2 -2.5) (xy 2.5 -2.5) (xy 2.5 2.5) (xy -2.5 2.5) (xy -2.5 -2))\n (stroke (width 0.1) (type default)) (fill none) (layer "F.Fab"))')
open(lan, 'w').write(t)
print('OK', lan, len(re.findall(r'\(pad "', t)), 'pads')
# ------------------------------------------------------------------------------------------------ TMC2262
e = 0.5
pads = []
bars = [-1.73, -0.855, 0.0, 0.855, 1.73] # KiCad y of pins 1..5 (top to bottom)
for i, y in enumerate(bars):
pads.append(dict(number=str(1 + i), x=-2.1625, y=y, dx=2.275, dy=0.59, shape='rect')) # x -3.3 .. -1.025
pads.append(dict(number=str(20 - i), x=2.1625, y=y, dx=2.275, dy=0.59, shape='rect')) # pin 20 top right
small = [-1.9, -1.4, -0.9, -0.4, 0.4, 0.9, 1.4, 1.9]
for i, x in enumerate(small):
pads.append(dict(number=str(7 + i), x=x, y=2.9375, dx=0.30, dy=0.725, shape='rect')) # bottom row, 7..14
pads.append(dict(number=str(29 - i), x=x, y=-2.9375, dx=0.30, dy=0.725, shape='rect')) # top row, 29..22
pads.append(dict(number='EP', x=0, y=0, dx=1.45, dy=4.05, shape='rect'))
cj = dict(footprintName='tmc2262', description='Analog Devices TMC2262 30L FC2QFN 6x6x0.75 mm (F306A6F+1F), 0.5 mm pitch; '
'land pattern 90-100245 Rev B, package outline 21-100708 Rev A',
tags='TMC2262 TMC2262AFV+ FC2QFN-30 6x6 stepper driver', pads=pads,
body=dict(x1=-3.0, y1=-3.0, x2=3.0, y2=3.0), courtyard=dict(x1=-3.75, y1=-3.75, x2=3.75, y2=3.75),
heatsinkVias=dict(pad='EP', drill_mm=0.3, pitch_mm=0.7, ring_mm=0.15, tented=True))
os.makedirs(os.path.join(OUT, 'tmc2262'), exist_ok=True)
json.dump(cj, open(os.path.join(OUT, 'tmc2262-create.json'), 'w'), indent=1)
print(run(['adom-footprint', 'create', '--file', os.path.join(OUT, 'tmc2262-create.json'), '--out', os.path.join(OUT, 'tmc2262')]).strip().splitlines()[-3:])
tp = os.path.join(OUT, 'tmc2262', 'tmc2262.kicad_mod')
t = open(tp).read()
def corner(num, sx, sy):
"""The L pad from 90-100245: a 0.450 wide leg from the outer edge (6.6 mm) 0.975 inward at x = sx*2.525, and a
0.450 high leg from y = sy*2.325 .. sy*2.775 out to the side edge; R0.150 on the corner that faces the die."""
ax, ay = sx * 2.525, sy * 2.8 # anchor: inside the vertical leg
r = 0.15
# polygon in absolute coordinates for the top-right corner (sx = sy = +1 means x right, y DOWN in KiCad);
# built for sx=+1, sy=-1 (top right in KiCad) and mirrored
pts = [(2.30, -3.30), (2.75, -3.30), (2.75, -2.775), (3.30, -2.775), (3.30, -2.325), (2.30 + r, -2.325)]
cx, cy = 2.30 + r, -2.325 - r
for k in range(1, 8): # fillet from (2.45,-2.325) to (2.30,-2.475)
a = math.pi / 2 + k * (math.pi / 2) / 8
pts.append((cx + r * math.cos(a), cy + r * math.sin(a)))
pts.append((2.30, -2.325 - r))
mx, my = (1 if sx > 0 else -1), (1 if sy < 0 else -1)
pts = [(px * mx, py * my) for px, py in pts]
if mx * my < 0:
pts.reverse()
rel = ' '.join('(xy %s %s)' % (f(px - ax), f(py - ay)) for px, py in pts)
return (' (pad "%s" smd custom (at %s %s) (size 0.4 0.4)\n (layers "F.Cu" "F.Paste" "F.Mask")\n'
' (options (clearance outline) (anchor rect))\n'
' (primitives\n (gr_poly (pts %s) (width 0) (fill yes))\n )\n )') % (num, f(ax), f(ay), rel)
extra = [corner('30', -1, -1), corner('21', +1, -1), corner('6', -1, +1), corner('15', +1, +1)]
extra += paste_windows(0, 0, 1, 4, 1.15, 0.85, 0, 1.0) # 4 x 0.98 mm2 = 66 % of the 5.87 mm2 pad
# silkscreen: corner brackets 0.16 mm clear of the 6.6 mm copper extent, pin-1 dot beside pad 1
s = 3.52
for qx in (-1, 1):
for qy in (-1, 1):
x0, y0 = qx * s, qy * s
extra.append(' (fp_line (start %s %s) (end %s %s)\n (stroke (width 0.12) (type default)) (layer "F.SilkS"))' % (f(x0), f(y0), f(x0 - qx * 0.6), f(y0)))
extra.append(' (fp_line (start %s %s) (end %s %s)\n (stroke (width 0.12) (type default)) (layer "F.SilkS"))' % (f(x0), f(y0), f(x0), f(y0 - qy * 0.6)))
extra.append(' (fp_circle (center -3.72 -1.73) (end -3.6 -1.73)\n (stroke (width 0.12) (type default)) (fill solid) (layer "F.SilkS"))')
t = finish(t, 'EP', extra, 'tmc2262', drop_silk=True)
# pin-1 chamfer on the fab outline
t = t.replace(' (fp_rect (start -3 -3) (end 3 3)\n (stroke (width 0.1) (type default)) (fill none) (layer "F.Fab"))',
' (fp_poly (pts (xy -2.5 -3) (xy 3 -3) (xy 3 3) (xy -3 3) (xy -3 -2.5))\n (stroke (width 0.1) (type default)) (fill none) (layer "F.Fab"))')
open(tp, 'w').write(t)
print('OK', tp, len(re.findall(r'\(pad "', t)), 'pads')