Source code for jitxlib.landpatterns.generators.bga

"""
The BGA Landpattern Generator
=============================

BGA (Ball Grid Array) packages use an array of solder balls on the bottom
surface instead of peripheral leads. This module provides generators for
creating BGA landpatterns with customizable grid configurations.

The BGA landpattern has three entry points:

- :py:class:`~BGA`: Complete generator with A1 alphanumeric numbering
  (rows A-Z, columns 1-N, e.g., ``.p['A1']``, ``.p['B3']``)
- :py:class:`~BGADecorated`: With silkscreen but no numbering scheme
- :py:class:`~BGABase`: Basic pads only

Constructor Parameters:
    num_rows: Number of rows in the ball grid (vertical)
    num_cols: Number of columns in the ball grid (horizontal)
    ball_diameter: Diameter of solder balls (typical: 0.3-0.6mm)
    pitch: Center-to-center spacing between balls (typical: 0.4-1.27mm)

    >>> from jitx import Component, Port
    >>> from jitxlib.landpatterns.generators.bga import BGA
    >>>
    >>> class MyBGA(Component):
    ...     # 10x10 BGA = 100 balls
    ...     pins = {f'{chr(65+r)}{c+1}': Port() for r in range(10) for c in range(10)}
    ...     def __init__(self):
    ...         self.landpattern = BGA(
    ...             num_rows=10,
    ...             num_cols=10,
    ...             ball_diameter=0.4,  # 0.4mm balls
    ...             pitch=0.8,          # 0.8mm pitch
    ...         )

Note:
    BGA packages require careful PCB design for routing escape paths.
    Consider via-in-pad or dog-bone patterns for dense arrays.
"""

from collections.abc import Iterable

from jitx.anchor import Anchor
from jitx.shapes.primitive import Circle
from jitx.transform import Transform

from ..courtyard import ExcessCourtyard
from ..grid_layout import A1, AlphaDictNumbering, GridLandpatternGenerator, GridPosition
from ..grid_planner import GridPlannerMixin
from ..pads import GridPadShapeGeneratorMixin
from ..silkscreen.labels import ReferenceDesignatorMixin
from ..silkscreen.marker import Pad1Marker
from ..silkscreen.outlines import SilkscreenOutline


[docs] class BGABase( GridPlannerMixin, GridPadShapeGeneratorMixin, GridLandpatternGenerator, ): """BGA Landpattern Generator Base""" def __init__( self, num_rows: int, num_cols: int, ball_diameter: float, pitch: float | tuple[float, float], ): super().__init__() self._num_rows = num_rows self._num_cols = num_cols # self.__ball_diameter = ball_diameter if not isinstance(pitch, tuple): pitch = (pitch, pitch) assert len(pitch) == 2, "pitch must be a tuple of two values" self.__pitch = pitch self.pad_shape(Circle(diameter=ball_diameter)) def _generate_layout(self) -> Iterable[GridPosition]: num_rows = self._num_rows num_cols = self._num_cols hpitch, vpitch = self.__pitch center_row = (num_rows - 1) / 2.0 center_col = (num_cols - 1) / 2.0 # TODO: not sure how to handle this, anchoring is useful for creating # sub-landpatterns that can be placed relative to an anchor; but I # don't know what the anchor point should be. Center of the grid # position at the appropriate corner? # half_width = pitch * (num_cols - 1) / 2.0 # half_height = pitch * (num_rows - 1) / 2.0 # bounds = (-half_width, -half_height, half_width, half_height) # center_x, center_y = self._get_anchor().flip().to_point(bounds) center_x, center_y = 0, 0 for r in range(num_rows): row_y = (center_row - r) * vpitch + center_y for c in range(num_cols): x = (c - center_col) * hpitch + center_x yield GridPosition(r, c, Transform.translate(x, row_y))
[docs] class BGADecorated( SilkscreenOutline, Pad1Marker, ReferenceDesignatorMixin, ExcessCourtyard, BGABase ): def __base_init__(self): super().__base_init__() self.pad_1_marker_direction(Anchor.W)
[docs] class BGA(A1, AlphaDictNumbering, BGADecorated): """BGA Landpattern Generator"""