Skip to content

FEAT: split via, convert via hole to conical shape #1096

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 3 commits into from
Apr 4, 2025
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
83 changes: 80 additions & 3 deletions src/pyedb/dotnet/database/edb_data/padstacks_data.py
Original file line number Diff line number Diff line change
Expand Up @@ -510,7 +510,7 @@ def via_layers(self):
list
List of layers.
"""
return self._padstack_def_data.GetLayerNames()
return list(self._padstack_def_data.GetLayerNames())

@property
def via_start_layer(self):
Expand All @@ -521,7 +521,7 @@ def via_start_layer(self):
str
Name of the starting layer.
"""
return list(self.via_layers)[0]
return self.via_layers[0]

@property
def via_stop_layer(self):
Expand All @@ -532,7 +532,7 @@ def via_stop_layer(self):
str
Name of the stopping layer.
"""
return list(self.via_layers)[-1]
return self.via_layers[-1]

@property
def hole_params(self):
Expand Down Expand Up @@ -2141,3 +2141,80 @@ def get_reference_pins(self, reference_net="GND", search_radius=5e-3, max_limit=
max_limit=max_limit,
component_only=component_only,
)

def split(self):
"""Split padstack instance into multiple instances. The new instances only connect adjacent layers."""
pdef_name = self.padstack_definition
position = self.position
net_name = self.net_name
name = self.name
stackup_layer_range = list(self._pedb.stackup.signal_layers.keys())
start_idx = stackup_layer_range.index(self.start_layer)
stop_idx = stackup_layer_range.index(self.stop_layer)
for idx, (l1, l2) in enumerate(
list(zip(stackup_layer_range[start_idx:stop_idx], stackup_layer_range[start_idx + 1 : stop_idx + 1]))
):
self._pedb.padstacks.place(position, pdef_name, net_name, f"{name}_{idx}", fromlayer=l1, tolayer=l2)
self.delete()

def convert_hole_to_conical_shape(self, angle=75):
"""Convert actual padstack instance to microvias 3D Objects with a given aspect ratio.

Parameters
----------
angle : float, optional
Angle of laser penetration in degrees. The angle defines the lowest hole diameter with this formula:
HoleDiameter -2*tan(laser_angle* Hole depth). Hole depth is the height of the via (dielectric thickness).
The default is ``75``.
The lowest hole is ``0.75*HoleDepth/HoleDiam``.

Returns
-------
"""
pos = self.position
stackup_layers = self._pedb.stackup.stackup_layers
signal_layers = self._pedb.stackup.signal_layers
layer_idx = list(signal_layers.keys()).index(self.start_layer)

_layer_idx = list(stackup_layers.keys()).index(self.start_layer)
diel_layer_idx = list(stackup_layers.keys())[_layer_idx + 1]
diel_thickness = stackup_layers[diel_layer_idx].thickness

rad_large = self.definition.hole_diameter / 2
rad_small = rad_large - diel_thickness * 1 / math.tan(math.radians(angle))

if layer_idx + 1 < len(signal_layers) / 2: # upper half of stack
rad_u = rad_large
rad_l = rad_small
else:
rad_u = rad_small
rad_l = rad_large

layout = self._pedb.active_layout
cloned_circle = self._edb.cell.primitive.circle.create(
layout,
self.start_layer,
self._edb_padstackinstance.GetNet(),
self._pedb.edb_value(pos[0]),
self._pedb.edb_value(pos[1]),
self._pedb.edb_value(rad_u),
)
cloned_circle2 = self._edb.cell.primitive.circle.create(
layout,
self.stop_layer,
self._edb_padstackinstance.GetNet(),
self._pedb.edb_value(pos[0]),
self._pedb.edb_value(pos[1]),
self._pedb.edb_value(rad_l),
)
s3d = self._pedb._edb.Cell.Hierarchy.Structure3D.Create(
layout, generate_unique_name("via3d_" + self.aedt_name.replace("via_", ""), n=3)
)
s3d.AddMember(cloned_circle.prim_obj)
s3d.AddMember(cloned_circle2.prim_obj)
s3d.SetMaterial(self.definition.material)
s3d.SetMeshClosureProp(self._pedb._edb.Cell.Hierarchy.Structure3D.TClosure.EndsClosed)

hole_override_enabled = True
hole_override_diam = 0
self._edb_object.SetHoleOverride(hole_override_enabled, self._pedb.edb_value(hole_override_diam))
3 changes: 3 additions & 0 deletions tests/legacy/system/test_edb_padstacks.py
Original file line number Diff line number Diff line change
Expand Up @@ -241,6 +241,9 @@ def test_microvias(self):
def test_split_microvias(self):
"""Convert padstack definition to multiple microvias definitions."""
edbapp = Edb(self.target_path4, edbversion=desktop_version)
edbapp.padstacks.instances_by_name["via219"].split()
assert "via219_2" in [i.name for i in edbapp.padstacks.definitions["BALL_VIA_1"].instances]
edbapp.padstacks.instances_by_name["via218"].convert_hole_to_conical_shape()
assert len(edbapp.padstacks.definitions["C4_POWER_1"].split_to_microvias()) > 0
edbapp.close()

Expand Down
Loading