-
Notifications
You must be signed in to change notification settings - Fork 0
/
soic.py
179 lines (154 loc) · 6.9 KB
/
soic.py
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
# Generate two-sided gull-wing package footprints, for instance for SOIC, SO, SOP, TSSOP packages
#
# This package type is defined in a lot of standards, for example:
# SOIC: EIAJ - 5.3mm (208mil) body, 1.27mm (50mil) pitch
# SOIC: JEDEC MS-012 - 3.9mm (150mil) body, 1.27mm (50mil) pitch - E=6.00, E1=3.90
# SOIC: JEDEC MS-013 - 7.5mm (300mil) body, 1.27mm (50mil) pitch - L=0.4-1.27, L1=1.04, b=0.31-0.51
# SSOP: JEDEC MO-150 - 5.3mm body, 0.65mm (25.6mil) pitch
# TSSOP: JEDEC MO-153 - 4.4mm body, 0.65mm pitch
#
import re
from common import Package, Line, Pad, Rectangle
class Params(object):
pass
class Soic(object):
def __init__(self):
self.params = Params()
self.params.density = "N" # IPC-7351 density level (L, N or M)
self.params.termwidth = None # [mm] maximum terminal (lead) width.
self.params.termlen = 1.40 # [mm] "L1" in JEDEC drawings (toe-to-package length)
self.params.footlen = 0.60 # [mm] "L" in JEDEC drawings (toe-to-heel length)
self.params.silkwidth = 0.15 # [mm] silkscreen line width and clearance
self.params.pitch = None # [mm] package pitch (distance between pin centers) (JEDEC "b")
self.params.l = None # [mm] package toe-to-toe width (lead span) (JEDEC "E")
self.params.pincount = None # total number of pins on package
self.courtyard_excess = None
def parse_ipc_name(self, name):
"""Parse IPC name (like SOIC127P600-14) and set parameters from it"""
match = re.match("(SOIC|SOP)(\d+)P(\d+)(X\d+)?-(\d+)(.)?", name)
if match is None:
return None
p = self.params
p.pitch = int(match.group(2)) / 100.0
p.l = int(match.group(3)) / 100.0
p.pincount = int(match.group(5))
if match.group(6) is not None:
p.density = match.group(6)
self.recalculate_params()
def set_density(self, density):
"""Set parameters for density level L, N or M"""
self.params.density = density
self.recalculate_params()
def recalculate_params(self):
"""Recalculate pad sizes depending on the density level"""
params = self.params
if params.density == "0": # No protrusion at all (for debugging)
params.JT = 0
params.JH = 0
params.JS = 0
params.courtyard_excess = 0
elif params.density == "L": # Least density level
params.JT = 0.15
params.JH = 0.25
if params.pitch > 0.625:
params.JS = 0.01
else:
params.JS = -0.04
params.courtyard_excess = 0.10
elif params.density == "N": # Nominal density level
params.JT = 0.35
params.JH = 0.35
if params.pitch > 0.625:
params.JS = 0.03
else:
params.JS = -0.02
params.courtyard_excess = 0.25
elif params.density == "M": # Most density level
params.JT = 0.55
params.JH = 0.45
if params.pitch > 0.625:
params.JS = 0.05
else:
params.JS = 0.01
params.courtyard_excess = 0.50
else:
raise "Invalid density (need L,N or M)"
if self.params.termwidth is None:
# Pick defaults from JEDEC standards
self.params.termwidth = 0.1 # Ridiculous
if self.params.pitch <= 0.45:
self.params.termwidth = 0.23 # 0.65 pitch, from MO-153
elif self.params.pitch <= 0.55:
self.params.termwidth = 0.27 # 0.65 pitch, from MO-153
elif self.params.pitch <= 0.70:
self.params.termwidth = 0.30 # 0.65 pitch, from MO-153
elif self.params.pitch <= 0.90:
self.params.termwidth = 0.45
else:
self.params.termwidth = 0.51 # 1.27 pitch, from MS-012F
def generate(self, **kwargs):
"""Generate data using previously loaded name and parameters. Returns a list."""
data = []
params = self.params
package = Package()
body = params.l - 2*params.termlen
package.description = "SOP-%d, %.02fmm pitch, %.2f mm body" % (
params.pincount, params.pitch, body)
l = params.l # Package lead span
# Positions and sizes of things relative to data center
padtoe = l / 2 + params.JT
padheel = l / 2 - params.footlen - params.JH
padlen = padtoe - padheel
padcenter = padtoe - padlen / 2.0
padwidth = params.termwidth + params.JS
pins_per_side = params.pincount // 2
first_pad_x = - (pins_per_side - 1) * params.pitch / 2.0
packagew = ((pins_per_side - 1) * params.pitch + 1.0) / 2.0 # About right, for small chips
packageh = l / 2 - params.termlen
courtyardw = packagew + params.courtyard_excess
courtyardh = padtoe + params.courtyard_excess
outlinew = packagew + params.silkwidth/2.0
outlineh = packageh + params.silkwidth/2.0
# Draw courtyard on package layer
rect = Rectangle( (-courtyardw, -courtyardh), (courtyardw, courtyardh))
rect.layer = "package"
data.append(rect)
# Draw package size on package layer
rect = Rectangle( (-packagew, -packageh), (packagew, packageh))
rect.layer = "package"
data.append(rect)
# Draw outline on silkscreen
rect = Rectangle( (-outlinew, -outlineh), (outlinew, outlineh))
rect.width = params.silkwidth
data.append(rect)
marksize = 0.75
rect = Rectangle( (-outlinew, -marksize), (-outlinew + marksize, marksize))
rect.width = params.silkwidth
data.append(rect)
# Draw orientation marker by pin 1 on silkscreen
markx = first_pad_x - padwidth / 2.0 - params.silkwidth * 2
line = Line( (markx, padcenter - params.silkwidth*2), (markx, padcenter))
line.width = params.silkwidth
data.append(line)
# Add pads, starting with pin 1 in lower-left (negative X, positive Y) corner
# Pads are drawn on the bottom side and rotated into place
pinno = 1
for side in range(0, 2):
th = side * 180 # Coordinate system rotation for this side
# Pad center coordinates
x = first_pad_x
y = padcenter
for pin in range(0, pins_per_side):
pad = Pad(pinno)
pad.x = x
pad.y = y
pad.ysize = padlen
pad.xsize = padwidth
pad.rotate(th)
data.append(pad)
pinno += 1
x += params.pitch
# All done!
package.data = data
package.courtyard = ((-courtyardw, -courtyardh), (courtyardw, courtyardh))
return package