Route to inner plane layers with a via, not pad to pad
On a four-layer board with a GND plane on an inner power layer, freeroute ignored the plane (it only used zones on routing layers) and chained every GND pad to the next with tracks across the board. Now a through-hole pad inside a plane is joined to it already, and for a net with a plane every other group connects straight to the plane: a route may end on any cell inside it where a via fits (checked lazily, like other vias), and ending there places that via. Signal nets are unaffected. Tested on a four-layer DSN: three SMD GND pads each get a short stub and their own via, the THT GND pad needs nothing, and no track crosses the board. Ahead of the TerraHawk ESC, a four-layer board.
This commit is contained in:
@@ -164,3 +164,50 @@ def test_cli_names_the_connections_it_could_not_route(tmp_path, capsys):
|
||||
assert main([str(dsn), "--engine", "exact", "-do", str(tmp_path / "out.ses")]) == 0
|
||||
err = capsys.readouterr().err
|
||||
assert "1 connection(s) not routed" in err and "N: A-1 to B-1" in err
|
||||
|
||||
|
||||
# --- inner plane layers (a 4-layer board with a GND plane on In1.Cu) --------
|
||||
|
||||
def _four_layer_dsn():
|
||||
return """(pcb four (parser) (resolution um 10) (unit um)
|
||||
(structure
|
||||
(layer F.Cu (type signal)) (layer In1.Cu (type power))
|
||||
(layer In2.Cu (type power)) (layer B.Cu (type signal))
|
||||
(boundary (path pcb 0 0 0 30000 0 30000 -30000 0 -30000 0 0))
|
||||
(plane GND (polygon In1.Cu 0 500 -500 29500 -500 29500 -29500 500 -29500 500 -500))
|
||||
(via "Via[0-3]_600:300_um") (rule (width 250) (clearance 150)))
|
||||
(placement
|
||||
(component S (place G1 5000 -5000 front 0) (place G2 25000 -5000 front 0)
|
||||
(place G3 15000 -25000 front 0) (place A 5000 -15000 front 0) (place B 25000 -15000 front 0))
|
||||
(component T (place GT 15000 -15000 front 0)))
|
||||
(library
|
||||
(image S (pin smd 1 0 0))
|
||||
(image T (pin tht 1 0 0))
|
||||
(padstack smd (shape (rect F.Cu -300 -300 300 300)) (attach off))
|
||||
(padstack tht (shape (circle F.Cu 1000)) (shape (circle B.Cu 1000)) (attach off))
|
||||
(padstack "Via[0-3]_600:300_um" (shape (circle F.Cu 600)) (shape (circle B.Cu 600)) (attach off)))
|
||||
(network (net GND (pins G1-1 G2-1 G3-1 GT-1)) (net SIG (pins A-1 B-1))))"""
|
||||
|
||||
|
||||
def test_smd_pads_reach_an_inner_plane_by_their_own_via():
|
||||
dsn = parse_dsn(_four_layer_dsn())
|
||||
result, scale, names = route_dsn_board_exact(dsn)
|
||||
gnd = next(i + 1 for i, n in enumerate(dsn.nets) if n.name == "GND")
|
||||
sig = next(i + 1 for i, n in enumerate(dsn.nets) if n.name == "SIG")
|
||||
assert len(result.result.vias.get(gnd, [])) == 3 # one per SMD pad, none for the THT pad
|
||||
for _layer, pts in result.result.wires.get(gnd, []): # stubs, not tracks across the board
|
||||
length = sum(abs(q.x - p.x) + abs(q.y - p.y) for p, q in zip(pts, pts[1:], strict=False))
|
||||
assert length < 3000 * scale # under 3 mm: a stub to its via
|
||||
assert sig in result.result.routed_net_numbers # signals still route on the outer layers
|
||||
assert all(names[layer] in ("F.Cu", "B.Cu") for segs in result.result.wires.values() for layer, _ in segs)
|
||||
|
||||
|
||||
def test_a_through_hole_pad_inside_a_plane_needs_no_route():
|
||||
from freeroute.route.grid_router import _connected_groups
|
||||
|
||||
board = build_board(parse_dsn(_four_layer_dsn()))
|
||||
plane = [z for z in board.get_conduction_areas() if z.name == "GND"]
|
||||
gnd_pins = [p for p in board.get_pins() if p.component_ref in ("G1", "G2", "G3", "GT")]
|
||||
groups = _connected_groups(gnd_pins, plane, frozenset(id(z) for z in plane))
|
||||
hub = next(g for g in groups if g[1])
|
||||
assert [p.component_ref for p in hub[0]] == ["GT"]
|
||||
|
||||
Reference in New Issue
Block a user