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
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
import pcbnew
def abs(x):
if x < 0:
return -x
return x
class QFPWizard(pcbnew.FootprintWizardPlugin):
def __init__(self):
pcbnew.FootprintWizardPlugin.__init__(self)
self.name = "QFP"
self.description = "QFP Footprint Wizard"
self.parameters = {
"Pads": {
"*n": 100,
"pitch": pcbnew.FromMM(0.5),
"width": pcbnew.FromMM(0.25),
"length": pcbnew.FromMM(1.5),
"horizontal pitch": pcbnew.FromMM(15),
"vertical pitch": pcbnew.FromMM(15),
"*oval": "True"
},
"Package": {
"width": pcbnew.FromMM(14),
"height": pcbnew.FromMM(14)
}
}
self.ClearErrors()
def smd_rect_pad(self, module, size, pos, name):
pad = pcbnew.D_PAD(module)
pad.SetSize(size)
if self.parameters['Pads'].get('*oval', "true").lower() == "true":
pad.SetShape(pcbnew.PAD_OVAL)
else:
pad.SetShape(pcbnew.PAD_RECT)
pad.SetAttribute(pcbnew.PAD_SMD)
pad.SetLayerMask(pcbnew.PAD_SMD_DEFAULT_LAYERS)
pad.SetPos0(pos)
pad.SetPosition(pos)
pad.SetPadName(name)
return pad
def CheckParameters(self):
errors = ""
pads = self.parameters
num_pads = pads["Pads"]["*n"]
if (num_pads < 1):
self.parameter_errors["Pads"]["*n"] = "Must be positive"
errors +="Pads/n has wrong value, "
pads["Pads"]["*n"] = int(num_pads) # Reset to int instead of float
return errors
def BuildFootprint(self):
if self.has_errors():
print "Cannot build footprint: Parameters have errors:"
print self.parameter_errors
return
print "Building new QFP footprint with the following parameters:"
self.print_parameter_table()
self.module = pcbnew.MODULE(None) # create a new module
pads = self.parameters
num_pads = int(pads["Pads"]["*n"])
pad_width = pads["Pads"]["width"]
pad_length = pads["Pads"]["length"]
pad_pitch = pads["Pads"]["pitch"]
pad_horizontal_pitch = pads["Pads"]["horizontal pitch"]
pad_vertical_pitch = pads["Pads"]["vertical pitch"]
package_width = pads["Package"]["width"]
package_height = pads["Package"]["height"]
side_length = pad_pitch * ((num_pads / 4) - 1)
offsetX = pad_pitch * ((num_pads / 4) - 1) / 2
text_size = pcbnew.wxSize(pcbnew.FromMM(0.8), pcbnew.FromMM(0.8))
self.module.SetReference("QFP %d" % int(num_pads))
self.module.Reference().SetPos0(pcbnew.wxPoint(0, pcbnew.FromMM(-0.8)))
self.module.Reference().SetTextPosition(self.module.Reference().GetPos0())
self.module.Reference().SetSize(text_size)
self.module.SetValue("U**")
self.module.Value().SetPos0(pcbnew.wxPoint(0, pcbnew.FromMM(+0.8)))
self.module.Value().SetTextPosition(self.module.Value().GetPos0())
self.module.Value().SetSize(text_size)
fpid = pcbnew.FPID(self.module.GetReference()) #the name in library
self.module.SetFPID( fpid )
pad_size_left_right = pcbnew.wxSize(pad_length, pad_width)
pad_size_bottom_top = pcbnew.wxSize(pad_width, pad_length)
for cur_pad in range(0, num_pads):
side = int(cur_pad / (num_pads / 4)) # 0 -> left, 1 -> bottom, 2 -> right, 3 -> top
if side == 0 or side == 2:
pad_size = pad_size_left_right
pad_pos_x = -(pad_horizontal_pitch / 2)
if side == 2:
pad_pos_x = -pad_pos_x
pad_pos_y = (cur_pad % (num_pads / 4)) * pad_pitch - (side_length / 2)
else:
pad_size = pad_size_bottom_top
pad_pos_x = (cur_pad % (num_pads / 4)) * pad_pitch - (side_length / 2)
pad_pos_y = -(pad_vertical_pitch / 2)
if side == 1:
pad_pos_y = -pad_pos_y
pad_pos = pcbnew.wxPoint(pad_pos_x, pad_pos_y)
pad = self.smd_rect_pad(self.module, pad_size, pad_pos, str(cur_pad + 1))
self.module.Add(pad)
half_package_width = package_width / 2
half_package_height = package_height / 2
package_pad_height_offset = abs(package_height - side_length) / 2 - pad_pitch
package_pad_width_offset = abs(package_width - side_length) / 2 - pad_pitch
# Bottom Left Edge, vertical line
outline = pcbnew.EDGE_MODULE(self.module)
outline.SetWidth(pcbnew.FromMM(0.2))
outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
outline.SetShape(pcbnew.S_SEGMENT)
start = pcbnew.wxPoint(-half_package_width, half_package_height - package_pad_height_offset)
end = pcbnew.wxPoint(-half_package_width, half_package_height)
outline.SetStartEnd(start, end)
self.module.Add(outline)
# Bottom Left Edge, horizontal line
outline = pcbnew.EDGE_MODULE(self.module)
outline.SetWidth(pcbnew.FromMM(0.2))
outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
outline.SetShape(pcbnew.S_SEGMENT)
start = pcbnew.wxPoint(-half_package_width, half_package_height)
end = pcbnew.wxPoint(-half_package_width + package_pad_width_offset, half_package_height)
outline.SetStartEnd(start, end)
self.module.Add(outline)
# Bottom Right Edge, vertical line
outline = pcbnew.EDGE_MODULE(self.module)
outline.SetWidth(pcbnew.FromMM(0.2))
outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
outline.SetShape(pcbnew.S_SEGMENT)
start = pcbnew.wxPoint(half_package_width, half_package_height - package_pad_height_offset)
end = pcbnew.wxPoint(half_package_width, half_package_height)
outline.SetStartEnd(start, end)
self.module.Add(outline)
# Bottom Right Edge, horizontal line
outline = pcbnew.EDGE_MODULE(self.module)
outline.SetWidth(pcbnew.FromMM(0.2))
outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
outline.SetShape(pcbnew.S_SEGMENT)
start = pcbnew.wxPoint(half_package_width, half_package_height)
end = pcbnew.wxPoint(half_package_width - package_pad_width_offset, half_package_height)
outline.SetStartEnd(start, end)
self.module.Add(outline)
# Top Right Edge, vertical line
outline = pcbnew.EDGE_MODULE(self.module)
outline.SetWidth(pcbnew.FromMM(0.2))
outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
outline.SetShape(pcbnew.S_SEGMENT)
start = pcbnew.wxPoint(half_package_width, -half_package_height + package_pad_height_offset)
end = pcbnew.wxPoint(half_package_width, -half_package_height)
outline.SetStartEnd(start, end)
self.module.Add(outline)
# Top Right Edge, horizontal line
outline = pcbnew.EDGE_MODULE(self.module)
outline.SetWidth(pcbnew.FromMM(0.2))
outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
outline.SetShape(pcbnew.S_SEGMENT)
start = pcbnew.wxPoint(half_package_width, -half_package_height)
end = pcbnew.wxPoint(half_package_width - package_pad_width_offset, -half_package_height)
outline.SetStartEnd(start, end)
self.module.Add(outline)
# Top Left Edge, straight line
outline = pcbnew.EDGE_MODULE(self.module)
outline.SetWidth(pcbnew.FromMM(0.2))
outline.SetLayer(pcbnew.SILKSCREEN_N_FRONT)
outline.SetShape(pcbnew.S_SEGMENT)
start = pcbnew.wxPoint(-half_package_width, -half_package_height + package_pad_height_offset)
end = pcbnew.wxPoint(-half_package_width + package_pad_width_offset, -half_package_height)
outline.SetStartEnd(start, end)
self.module.Add(outline)
def print_parameter_table(self):
for name, section in self.parameters.iteritems():
print " %s:" % name
for key, value in section.iteritems():
unit = ""
if (type(value) is int or type(value) is float) and not "*" in key:
unit = "mm"
if "*" in key:
key = key[1:]
else:
value = pcbnew.ToMM(value)
print " %s: %s%s" % (key, value, unit)
def has_errors(self):
for name, section in self.parameter_errors.iteritems():
for k, v in section.iteritems():
if v:
return True
return False
QFPWizard().register()