Skip to content
This repository has been archived by the owner on Oct 7, 2020. It is now read-only.

Allow custom numbering scheme in PadArray and QFN scripts #371

Merged
merged 2 commits into from
Jan 5, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
5 changes: 4 additions & 1 deletion KicadModTree/nodes/specialized/PadArray.py
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,7 @@
# (C) 2017 by @SchrodingersGat
# (C) 2017 by Thomas Pointhuber, <[email protected]>

from types import GeneratorType
from KicadModTree.nodes.base.Pad import *
from KicadModTree.nodes.specialized.ChamferedPad import *
from KicadModTree.nodes.Node import Node
Expand Down Expand Up @@ -208,8 +209,10 @@ def _createPads(self, **kwargs):
pad_numbers = [self.initialPin]
for idx in range(1, self.pincount):
pad_numbers.append(self.increment(pad_numbers[-1]))
elif type(self.increment) == GeneratorType:
pad_numbers = [next(self.increment) for i in range(self.pincount)]
else:
raise TypeError("Wrong type for increment. It must be either a int or callable.")
raise TypeError("Wrong type for increment. It must be either a int, callable or generator.")

end_pad_params = copy(kwargs)
if kwargs.get('end_pads_size_reduction'):
Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -326,13 +326,14 @@ def __createFootprintVariant(self, device_params, device_dimensions, with_therma
pad_shape_details['maximum_radius'] = configuration['round_rect_max_radius']

if device_dimensions['has_EP']:
ep_pad_number = device_params.get('EP_pin_number', pincount+1)
if with_thermal_vias:
thermals = device_params['thermal_vias']
paste_coverage = thermals.get('EP_paste_coverage',
device_params.get('EP_paste_coverage', DEFAULT_PASTE_COVERAGE))

kicad_mod.append(ExposedPad(
number=pincount+1, size=EP_size,
number=ep_pad_number, size=EP_size,
at=EP_center,
paste_layout=thermals.get('EP_num_paste_pads', device_params.get('EP_num_paste_pads', 1)),
paste_coverage=paste_coverage,
Expand All @@ -350,7 +351,7 @@ def __createFootprintVariant(self, device_params, device_dimensions, with_therma
))
else:
kicad_mod.append(ExposedPad(
number=pincount+1, size=EP_size,
number=ep_pad_number, size=EP_size,
at=EP_center,
paste_layout=device_params.get('EP_num_paste_pads', 1),
paste_coverage=device_params.get('EP_paste_coverage', DEFAULT_PASTE_COVERAGE),
Expand Down
160 changes: 160 additions & 0 deletions scripts/tools/pad_number_generators.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,160 @@
"""
Pad number generator functions.

Some ICs have a non-standard pin numbering scheme.
Using the generators an iterable is generated following the scheme.

Available generators:
----------------------
- increment: Is a simple generator that increments the pin number by one.
- cw_dual: Generates pin numbers counting clockwise from the starting position
- ccw_dual: Generates pin numbers counting counter-clockwise from the starting position

Examples:
---------
To use a generator add the following to the device config:

pad_numbers:
generator: 'ccw_dual'
axis: 'x'

"""


def increment(pincount, init=1, **kwargs):
i = init
while i <= pincount:
yield i
i += 1


def _get_pin_cw(pincount, loc):
"""Helper function to locate pin number for cw_dual.

Args:
pincount: Total number of pins
loc: Starting location

Returns:
pin_number: Starting pin number
"""
pins_per_side = pincount // 2
if loc == "top_left":
return 0
elif loc == "bottom_left":
return pins_per_side * 2 + 1
elif loc == "bottom_right":
return pins_per_side
elif loc == "top_right":
return pins_per_side + 1
return 0


def _get_pin_ccw(pincount, loc):
"""Helper function to locate pin number for ccw_dual.

Args:
pincount: Total number of pins
loc: Starting location

Returns:
pin_number: Starting pin number
"""
pins_per_side = pincount // 2
if loc == "top_left":
return 0
elif loc == "bottom_left":
return pins_per_side + 1
elif loc == "bottom_right":
return pins_per_side
elif loc == "top_right":
return pins_per_side * 2 + 1
return 0


def clockwise_dual(pincount, init=1, start="top_left", axis="x", **kwargs):
"""Generator for dual row packages counting clockwise.

Args:
pincount: Total number of pins
init: Initial starting count (default: 1)
start: The starting corner, top/bottom - left/right
axis: Pin axis, either x or y. Is depended on num_pins_{x,y}
**kwargs: Other keyword arguments

Returns:
Iterator
"""
i = _get_pin_cw(pincount, start)

if axis == "y":
pins = iter(range(pincount, 0, -1))
else:
pins = iter(range(pincount))

for ind in pins:
yield ((i + ind) % pincount) + init


def counter_clockwise_dual(pincount, init=1, start="top_left", axis="x", **kwargs):
"""Generator for dual row packages counting counter clockwise.

Args:
pincount: Total number of pins
init: Initial starting count (default: 1)
start: The starting corner, top/bottom - left/right
axis: Pin axis, either x or y. Is depended on num_pins_{x,y}
**kwargs: Other keyword arguments

Returns:
Iterator
"""
i = _get_pin_ccw(pincount, start)

if axis == "x":
pins = iter(range(pincount, 0, -1))
else:
pins = iter(range(pincount))

for ind in pins:
yield ((i + ind) % pincount) + init


# Add available generators to the dictionary
generators = {
"increment": increment,
"cw_dual": clockwise_dual,
"ccw_dual": counter_clockwise_dual,
}


def get_generator(device_params):
"""Returns a pad number iterator based on device_params and selected generator.
Fallback to plain increment.

Args:
device_params: Device parameters dictionary

Returns:
Pad number iterator

Raises:
KeyError: If generator not available
"""
# Fallback to plain increment
pincount = device_params["num_pins_x"] * 2 + device_params["num_pins_y"] * 2
pad_nums = device_params.get("pad_numbers")

if not pad_nums:
return generators["increment"](pincount)

init = pad_nums.get("init", 1)

gen = generators.get(pad_nums.get("generator"))
if not gen:
gens = ", ".join(generators.keys())
pad_generator = pad_nums.get("generator")
raise KeyError("{}: Use one of [{}]".format(pad_generator, gens))

iterator = gen(pincount, init, **pad_nums)
return iterator
44 changes: 35 additions & 9 deletions scripts/tools/quad_dual_pad_border.py
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
import sys, os
sys.path.append(os.path.join(sys.path[0],"..","..")) # load kicad_mod path
from KicadModTree import * # NOQA

from pad_number_generators import get_generator

def add_dual_or_quad_pad_border(kicad_mod, configuration, pad_details, device_params):
pad_shape_details = {}
Expand All @@ -29,13 +29,17 @@ def add_dual_or_quad_pad_border(kicad_mod, configuration, pad_details, device_pa

def add_dual_pad_border_y(kicad_mod, pad_details, device_params, pad_shape_details):
init = 1
increment = get_generator(device_params)

pa = PadArray(
initial= init,
type=Pad.TYPE_SMT,
layers=Pad.LAYERS_SMT,
pincount=device_params['num_pins_y'],
x_spacing=0, y_spacing=device_params['pitch'],
**pad_details['left'], **pad_shape_details)
increment=increment,
**pad_details['left'], **pad_shape_details,
)
kicad_mod.append(pa)
init += device_params['num_pins_y']
kicad_mod.append(PadArray(
Expand All @@ -44,7 +48,10 @@ def add_dual_pad_border_y(kicad_mod, pad_details, device_params, pad_shape_detai
layers=Pad.LAYERS_SMT,
pincount=device_params['num_pins_y'],
x_spacing=0, y_spacing=-device_params['pitch'],
**pad_details['right'], **pad_shape_details))
increment=increment,
**pad_details['right'], **pad_shape_details,
)
)

pads = pa.getVirtualChilds()
pad = pads[0]
Expand All @@ -54,13 +61,17 @@ def add_dual_pad_border_y(kicad_mod, pad_details, device_params, pad_shape_detai
def add_dual_pad_border_x(kicad_mod, pad_details, device_params, pad_shape_details):
#for devices with clockwise numbering
init = 1
increment = get_generator(device_params)

pa = PadArray(
initial= init,
type=Pad.TYPE_SMT,
layers=Pad.LAYERS_SMT,
pincount=device_params['num_pins_x'],
y_spacing=0, x_spacing=device_params['pitch'],
**pad_details['top'], **pad_shape_details)
increment=increment,
**pad_details['top'], **pad_shape_details,
)
kicad_mod.append(pa)
init += device_params['num_pins_x']
kicad_mod.append(PadArray(
Expand All @@ -69,7 +80,10 @@ def add_dual_pad_border_x(kicad_mod, pad_details, device_params, pad_shape_detai
layers=Pad.LAYERS_SMT,
pincount=device_params['num_pins_x'],
y_spacing=0, x_spacing=-device_params['pitch'],
**pad_details['bottom'], **pad_shape_details))
increment=increment,
**pad_details['bottom'], **pad_shape_details,
)
)

pads = pa.getVirtualChilds()
pad = pads[0]
Expand All @@ -89,6 +103,7 @@ def add_quad_pad_border(kicad_mod, pad_details, device_params, pad_shape_details
corner_first = CornerSelection({CornerSelection.TOP_RIGHT: True})
corner_last = CornerSelection({CornerSelection.BOTTOM_RIGHT: True})
pad_size_reduction = {'x+': pad_size_red} if pad_size_red > 0 else None
increment = get_generator(device_params)

pa = PadArray(
initial= init,
Expand All @@ -100,7 +115,9 @@ def add_quad_pad_border(kicad_mod, pad_details, device_params, pad_shape_details
chamfer_corner_selection_first=corner_first,
chamfer_corner_selection_last=corner_last,
end_pads_size_reduction = pad_size_reduction,
**pad_details['left'], **pad_shape_details)
increment=increment,
**pad_details['left'], **pad_shape_details,
)
kicad_mod.append(pa)

init += device_params['num_pins_y']
Expand All @@ -118,7 +135,10 @@ def add_quad_pad_border(kicad_mod, pad_details, device_params, pad_shape_details
chamfer_corner_selection_first=corner_first,
chamfer_corner_selection_last=corner_last,
end_pads_size_reduction = pad_size_reduction,
**pad_details['bottom'], **pad_shape_details))
increment=increment,
**pad_details['bottom'], **pad_shape_details,
)
)

init += device_params['num_pins_x']
corner_first = copy(corner_first).rotateCCW()
Expand All @@ -135,7 +155,10 @@ def add_quad_pad_border(kicad_mod, pad_details, device_params, pad_shape_details
chamfer_corner_selection_first=corner_first,
chamfer_corner_selection_last=corner_last,
end_pads_size_reduction = pad_size_reduction,
**pad_details['right'], **pad_shape_details))
increment=increment,
**pad_details['right'], **pad_shape_details,
)
)

init += device_params['num_pins_y']
corner_first = copy(corner_first).rotateCCW()
Expand All @@ -152,7 +175,10 @@ def add_quad_pad_border(kicad_mod, pad_details, device_params, pad_shape_details
chamfer_corner_selection_first=corner_first,
chamfer_corner_selection_last=corner_last,
end_pads_size_reduction = pad_size_reduction,
**pad_details['top'], **pad_shape_details))
increment=increment,
**pad_details['top'], **pad_shape_details,
)
)

pads = pa.getVirtualChilds()
pad = pads[0]
Expand Down