R2 底板改 4 层(D15):规则 / 几何 / 背面摆位 / 4 层布线与铺铜,已下发
- 规则:铜层 2→4,差分 0.28/0.18,间距 0.15,过孔 0.3/0.2(rules_base) - 几何:98×98 板框 + 4×M3,槽阵居中,L1 12V 大铜 + 指头(pcb_base) - 摆位:五插槽留 L1,其余 133 件翻到 L4;背面镜像规则实测;Hub 放走廊 2、 东移 2.5 mm;扇出圈 / 小件间距 1.5(去耦例外)/ 9 A 过孔阵禁区(place_base) - 叠层按用户决定改为 L1 槽面 / L2 整层 +3V3 / L3 整层 GND / L4 器件面 - 布线:D± 七对按构造布通(USB3 掉头、USB1/2 北去掉头、USB4/5 东绕、 J23 桥),+3V3 / GND / +12V 平面网每脚一孔,0.125 网格 + PathFinder 开关(route_base、remote_route.ps1);剩 37 个网待手工补 - 铺铜:4 层重写,入口链自南向北切段 + 断面校核(pour_base); 已下发布线 / 缝合孔 / 铜面轮廓,填铜未成功(待查) - 工具:plot_base / plot_routes / shot_base,board_check 通孔两层都算 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_0168Bu6SEx3cXXCJLkdnE6zB
这个提交包含在:
+247
-245
@@ -1,245 +1,247 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
u"""六对**长差分**(USB1~5 的 U32↔U5n + UPSTREAM 的 U32↔J23)+ Hub 西缘被 D± 夹住的两条 +3V3 车道。
|
||||
|
||||
**v5 版(2026-09-06,载板全部底层、接口边朝板边)。** v3 版存档在 `obsolete/pcb2_dp_long_v3_2026-09-06.py`。
|
||||
被 `pcb2_route_dp.py` import;校核 / 下发都用那个脚本,这里只放坐标。
|
||||
|
||||
## 出发点:U32 西缘的 12 条车道
|
||||
|
||||
U32(QFN-64,**底层**,中心 (100, 68))的 D± 全在**西缘 x 95.55**,0.5 脚距、南→北:
|
||||
|
||||
1DM 64.25 | 1DP 64.75 | 2DM 65.25 | 2DP 65.75 | pin5 +3V3 66.25 |
|
||||
3DM 66.75 | 3DP 67.25 | 4DM 67.75 | 4DP 68.25 | pin10 +3V3 68.75 |
|
||||
5DM 69.25 | 5DP 69.75 | pin13 GND 70.25 | 14~16 NC
|
||||
|
||||
目的地却是四面八方:1→西北远处 (U51 22/24, 87)、2→正北 (U52 94/96, 87)、3→东北 (U53 165/167, 87)、
|
||||
4→西南 (U54 88.6/90.5, 48)、5→东南 (U55 160/162, 48)、UP→正东 (J23 212, 61~62)。
|
||||
|
||||
### 定下来的走法(理由都在代码注释里)
|
||||
|
||||
| 车道 | 层 | 走法 |
|
||||
|---|---|---|
|
||||
| pair 1 | 底 | 直着西行 y 64.25/64.75 到 x 22.34/22.82,北上进 U51 |
|
||||
| pair 2 | 底 | 西行到 89.27/89.75 北上,y 80 处 45° 斜到 93.84/95.74 进 U52 |
|
||||
| pin 5 | 底→顶 | 西行到 90.4,跟着 pair 3 北上到 70.5 打孔翻顶层,西去 (88.2, 70.5) 再下来进 C747 |
|
||||
| pair 3 | 底 | 西行到 91.05/91.53 北上,y 76.50/76.98 东行,过了 pair 5 之后压到 75.40/75.88 从 MH 焊盘下面钻过去,x 165 北上 |
|
||||
| pair 4 | **顶** | 西行到 x 92.2 打孔上顶层(DM 67.95 / DP 68.85),沿 x 91.5/91.98 南下到 y 52,斜到 (89.6/90.5, 50.3) 下来进 U54 |
|
||||
| pin 10 | 底 | 西行到 92.95,跟着 pair 5 北上,斜到 (92.5, 70.0) 进 C748;(92.5, 70.0) 上有一个孔接顶层 +3V3 干线 |
|
||||
| pair 5 | 底 | 西行到 93.47/93.95 北上,y 75.50/75.98 东行到 110.30/110.78 南下,**y 59.2~61.6 翻顶层跨过 UP**,y 52.5/52.98 东行,x 160.1/162 南下进 U55 |
|
||||
| UP | 底 | 南缘 pin58/59 从 C743/C745 之间的竖井下到 60.12/60.60,一路东行,x 205 抬到 61.25/61.75 进 J23 B6/A7 |
|
||||
| +3V3 干线 | 顶 | U31 pin2 旁 (90.3, 61.65) 打孔上顶层,北上到 (90.4, 70.5)(与 pin5 的孔汇合),东去 (92.5, 70.0) 下来进 C748 |
|
||||
|
||||
### 三条关键约束
|
||||
|
||||
1. **0.5 脚距的车道之间打不了孔**:孔要离两边车道各 0.645,所以只有当邻居车道都拐走之后才能打。
|
||||
北边的先拐(pair 5 → pin 10 → pair 4 打孔 → pair 3 → pin 5 → pair 2),像剥洋葱。
|
||||
pair 4 的两个孔卡在 DP3 的横车道(y 67.25,要求孔心 ≥ 67.895)和 pin10 北上车道(x 92.95,要求孔心 x ≤ 92.305)之间,
|
||||
所以 DP4 得先在 x 93.1→92.5 抬到 68.85 再打孔,两孔上下错 0.9。
|
||||
2. **顶层只走 Inner1 是 GND 的地方**:Hub 周围 x ≥ 87(VO4 岛东界已从 89 收到 87)、y < 75.5(VO2 的 Hub 北横带以南)是一整片 GND;
|
||||
pair 4 全程、pair 5 跨 UP 的那 2.4 mm、+3V3 干线都在这片里。pair 5 的跨越点 x 110~111.5 也在 VO4/VO5 之间的 GND 窗口里。
|
||||
3. **平行 45° 斜段要保持 0.48 间距**:两根线各自的拐点不能同 x/同 y,第一拐**内侧**那根要早拐 0.2
|
||||
(0.48·(√2−1)),否则斜段上的垂直间距只剩 0.34。文件里所有成对斜段都按这个写。
|
||||
|
||||
### 每个站点最后一段
|
||||
|
||||
U5n 朝 Hub 那排的 DP/DM 相距 1.9 mm,车道并排 0.48 到最后 1.4 mm 再用 45° 分开,
|
||||
分开的那根一律是**转弯时的外侧**,所以到站不用交叉 —— 五对都核过了
|
||||
(转弯规则:向右拐时左边那根变成外侧,连拐两次回到原样)。
|
||||
"""
|
||||
import math
|
||||
|
||||
L_TOP, L_BOT = 1, 2
|
||||
W = 0.28
|
||||
|
||||
|
||||
def chamfer(pts, r=0.35):
|
||||
u"""把折线的拐点切成 45°。换层点(相邻两点层不同)不切。
|
||||
|
||||
⚠ 点的 layer/width 语义是「从这一点到下一点」,所以在拐点 b 处插入的
|
||||
b1 用**前一段**的层/宽(它承担斜切段),b2 用 b 自己的。
|
||||
"""
|
||||
if len(pts) < 3:
|
||||
return list(pts)
|
||||
out = [pts[0]]
|
||||
for i in range(1, len(pts) - 1):
|
||||
a, b, c = pts[i - 1], pts[i], pts[i + 1]
|
||||
if a[2] != b[2] or b[2] != c[2]: # 拐点两侧不同层 -> 这是过孔点
|
||||
out.append(b)
|
||||
continue
|
||||
ax, ay = b[0] - a[0], b[1] - a[1]
|
||||
cx, cy = c[0] - b[0], c[1] - b[1]
|
||||
la, lc = math.hypot(ax, ay), math.hypot(cx, cy)
|
||||
if la < 1e-9 or lc < 1e-9:
|
||||
out.append(b)
|
||||
continue
|
||||
# 共线就不用切;**已经是 45° 的拐(正 + 斜)也不切** —— 再切一刀会变成两个 22.5°,
|
||||
# 而且切出来的那一小段会向内侧挪 0.1 mm,实测把 DP4 的抬升段切进了 pin10 车道的净距圈(0.125)。
|
||||
dot = max(-1.0, min(1.0, (ax * cx + ay * cy) / (la * lc)))
|
||||
if math.degrees(math.acos(dot)) <= 46.0:
|
||||
out.append(b)
|
||||
continue
|
||||
d = min(r, la / 2.0, lc / 2.0)
|
||||
out.append((round(b[0] - ax / la * d, 4), round(b[1] - ay / la * d, 4), a[2], a[3]))
|
||||
out.append((round(b[0] + cx / lc * d, 4), round(b[1] + cy / lc * d, 4), b[2], b[3]))
|
||||
out.append(pts[-1])
|
||||
return out
|
||||
|
||||
|
||||
def P(*pts):
|
||||
u"""(x, y[, layer[, width]]) -> 规范化四元组;层/宽省略时沿用上一点。"""
|
||||
out, lay, w = [], L_BOT, W
|
||||
for t in pts:
|
||||
x, y = t[0], t[1]
|
||||
lay = t[2] if len(t) > 2 else lay
|
||||
w = t[3] if len(t) > 3 else w
|
||||
out.append((round(x, 4), round(y, 4), lay, w))
|
||||
return out
|
||||
|
||||
|
||||
PAD_X = 95.55 # U32 西缘焊盘中心(焊盘 x 95.125~95.975,hh 0.15)
|
||||
# 0.28 的线直着从 0.5 脚距的焊盘出来,两边净距 0.21,不用让位。
|
||||
|
||||
# ══════════ pair 1 → U51(西北远处)══════════
|
||||
# 直着西行:y 64.25/64.75 从 x 95.55 到 x 22~23 一路无障碍(U31 pin1 顶 63.35、J31 底排焊盘底 65.38、
|
||||
# R721/R722 顶 61.77、U34 顶 ~62)。西行时 DM 在南 = 左侧,右拐北上后左侧变西 ⇒ DM 走西车道 22.34(正对 U51.6),
|
||||
# DP 在 22.82,到 y 84.3 再 45° 分到 24.24 进 U51.4。
|
||||
SITE1 = {
|
||||
'USB1_DM': [(PAD_X, 64.25), (22.34, 64.25), (22.34, 86.475)],
|
||||
'USB1_DP': [(PAD_X, 64.75), (22.82, 64.75), (22.82, 84.30), (24.24, 85.72), (24.24, 86.475)],
|
||||
}
|
||||
|
||||
# ══════════ pair 2 → U52(正北)══════════
|
||||
# 西行到 x 89.27/89.75 右拐北上(DM 西)。北上车道左边是 J31 最东一列焊盘(x ≤ 86.98),右边是 pin5 的北上车道 90.4。
|
||||
# 一直到 y 80 才 45° 斜向东北 —— 必须过了 pair 3 / pair 5 东行车道(y ≤ 76.97)之后才能往东挪,
|
||||
# 而且要绕开 site2 的定位孔 H1 (89.39, 85.36)。斜段直接斜到各自焊盘正下方:DM 到 93.84、DP 一口气到 95.74。
|
||||
# 内侧(DP,东)早拐 0.2 保持斜段 0.48 间距。
|
||||
SITE2 = {
|
||||
'USB2_DM': [(PAD_X, 65.25), (89.27, 65.25), (89.27, 80.00), (93.84, 84.57), (93.84, 86.475)],
|
||||
'USB2_DP': [(PAD_X, 65.75), (89.75, 65.75), (89.75, 79.80), (95.74, 85.79), (95.74, 86.475)],
|
||||
}
|
||||
|
||||
# ══════════ pair 3 → U53(东北)══════════
|
||||
# 西行到 91.05/91.53 右拐北上(DM 西),再右拐东行(西车道变北车道 ⇒ DM 76.98 / DP 76.50),
|
||||
# 这一段在 pair 5 东行车道(75.50/75.98)的北边;pair 5 在 x 110.78 南下之后,pair 3 在 x 112 压到 75.40/75.88 ——
|
||||
# 因为 MH (148.1, 79.5) 的 Ø6 焊盘底在 76.5,北车道上沿必须 ≤ 76.16。
|
||||
# 到 x 165 左拐北上:北车道(DM)是内侧变西 ⇒ DM 165.34 正对 U53.6,DP 在 165.82 到 y 84.6 再分到 167.24。
|
||||
# 下压的斜段:第一拐向右(东→东南),内侧是南车道 DP,早拐 0.2。
|
||||
SITE3 = {
|
||||
'USB3_DM': [(PAD_X, 66.75), (91.05, 66.75), (91.05, 76.98), (112.00, 76.98), (113.10, 75.88),
|
||||
(165.34, 75.88), (165.34, 86.475)],
|
||||
'USB3_DP': [(PAD_X, 67.25), (91.53, 67.25), (91.53, 76.50), (111.80, 76.50), (112.90, 75.40),
|
||||
(165.82, 75.40), (165.82, 84.60), (167.24, 86.02), (167.24, 86.475)],
|
||||
}
|
||||
|
||||
# ══════════ pair 4 → U54(西南)—— 全程顶层 ══════════
|
||||
# 它北边是 pin10(要跟 pair 5 北上)、南边是 pair 3(北上)、pair 2、pair 1 全都横在西边 —— 底层无路,
|
||||
# 一出焊盘就打孔上顶层。两个孔:DM4 (92.2, 67.95)(离 DP3 横车道 67.39 有 0.255)、DP4 (92.2, 68.85)(上下错 0.9),
|
||||
# DP4 先在 x 93.1→92.5 斜抬到 68.85 再西行到孔,避开 DM4 的孔(孔顶 68.255 vs 车道底 68.11 才 0.055)。
|
||||
# 顶层:DP 西车道 91.5 / DM 91.98 南下到 y 52,45° 斜到 (89.6, 50.3) / (90.5, 50.3) 打孔回底层,
|
||||
# 进 U54.4 (88.6, 48.149) / U54.6 (90.5, 48.149)。DM 的孔正对焊盘、直下;DP 的孔再斜 1 mm 到 88.6。
|
||||
# 顶层这一段底下 Inner1:x ≥ 87 全是 GND(VO4 岛东界 87、site4 岛 x ≤ 84.75、VO2 从 y 75.5 起)。
|
||||
SITE4 = {
|
||||
'USB4_DM': [(PAD_X, 67.75), (92.60, 67.75), (92.40, 67.95), (92.20, 67.95),
|
||||
(92.20, 67.95, L_TOP), (91.98, 67.73), (91.98, 52.00), (90.50, 50.52), (90.50, 50.30),
|
||||
(90.50, 50.30, L_BOT), (90.50, 48.685)],
|
||||
'USB4_DP': [(PAD_X, 68.25), (93.10, 68.25), (92.50, 68.85), (92.20, 68.85),
|
||||
(92.20, 68.85, L_TOP), (91.50, 68.85), (91.50, 52.50), (89.60, 50.60), (89.60, 50.30),
|
||||
(89.60, 50.30, L_BOT), (88.60, 49.30), (88.60, 48.685)],
|
||||
}
|
||||
|
||||
# ══════════ pair 5 → U55(东南)—— 绕 Hub 北边走 ══════════
|
||||
# 最北的一对,出来就右拐北上(DM 西 93.47 / DP 东 93.95;DP 的东沿离 C751 焊盘 94.295 只剩 0.205,
|
||||
# 再东一点 pin13 的 GND 就打不了孔了 —— 给它留的孔位是 (94.6, 71.4))。
|
||||
# 北上到 75.50/75.98(C751 顶 74.974,DP 拐角的 45° 切角离它 0.24)右拐东行(DM 北),到 x 110.30/110.78 右拐南下(南车道 DP 是内侧变西 ⇒ DP 110.30)。
|
||||
# 南下时 x 110.3 离 R711/R716/R720 的东沿 109.62 有 0.54、离 J64 焊盘 107.43 有 2.7。
|
||||
# **y 59.2~61.6 翻到顶层跨过 UP 的两根横线**(60.12/60.60):DP 的孔在 110.30,DM 的孔错到 111.3(两孔 1.0)。
|
||||
# 到 y 52.5/52.98 左拐东行(东车道 DM 是内侧变北 ⇒ DM 52.98),DP 在 x 160.10 南下进 U55.4,DM 到 162.00 进 U55.6。
|
||||
SITE5 = {
|
||||
'USB5_DM': [(PAD_X, 69.25), (93.47, 69.25), (93.47, 75.98), (110.78, 75.98),
|
||||
(110.78, 62.60), (111.30, 62.08), (111.30, 61.60),
|
||||
(111.30, 61.60, L_TOP), (111.30, 59.20),
|
||||
(111.30, 59.20, L_BOT), (111.30, 58.72), (110.78, 58.20),
|
||||
(110.78, 52.98), (162.00, 52.98), (162.00, 48.685)],
|
||||
'USB5_DP': [(PAD_X, 69.75), (93.95, 69.75), (93.95, 75.50), (110.30, 75.50),
|
||||
(110.30, 61.60),
|
||||
(110.30, 61.60, L_TOP), (110.30, 59.20),
|
||||
(110.30, 59.20, L_BOT), (110.30, 52.50), (160.10, 52.50), (160.10, 48.685)],
|
||||
}
|
||||
|
||||
# ══════════ UPSTREAM → J23(U32 南缘 → 板子正东)══════════
|
||||
# pin59 UP_DP (98.75, 63.55) / pin58 UP_DM (99.25, 63.55) 直着南下,从 C743(x ≤ 97.62)与 C745(x ≥ 99.78)之间的
|
||||
# 竖井下到 y 60.12/60.60(那排 0402 的焊盘底 60.98),一路东行到 x 205 —— 中间 y 60~61 从 x 99 到 208 全空。
|
||||
# J23(底层 rot 270):B6 UP_DP 61.25 / A7 UP_DM 61.75 / A6 UP_DP 62.25 / B7 UP_DM 62.75,B5 CC2 在 60.25、A8 空脚 60.75。
|
||||
# 车道压在 60.17 会把 B5 的 CC2 走线堵死(R718 在 59.5),所以 x 205 就抬到 61.25/61.75 平着进 B6/A7。
|
||||
# 抬升是左拐再右拐,第一拐内侧是北车道 DM ⇒ DM 早拐 0.2。
|
||||
UP = {
|
||||
'UP_DP': [(98.75, 63.55), (98.75, 60.12), (205.00, 60.12), (206.13, 61.25), (212.392, 61.25)],
|
||||
'UP_DM': [(99.25, 63.55), (99.25, 60.60), (204.80, 60.60), (205.95, 61.75), (212.392, 61.75)],
|
||||
}
|
||||
|
||||
# ══════════ J23 的 A6↔B6 / A7↔B7 短接(USB-C 正反插的一对重复脚)══════════
|
||||
# 几何照抄 v3(那一版过了 DRC),只是 J23 翻到底层之后网络对调:61.25↔62.25 这一对现在是 UP_DP(B6/A6),
|
||||
# 61.75↔62.75 是 UP_DM(A7/B7);出线在底层,跨越段翻到**顶层**。
|
||||
# ⚠ 表贴焊盘只到 x=213.04,过孔要离它 0.505 ⇒ 最西只能放到 213.55;出线前 0.65 mm 必须平着走(阵列上方起坡会蹭隔壁脚)。
|
||||
# 另一根的 61.75 横线离 (213.85, 62.25) 那个孔只有 0.165 —— 这是同一对的两根(UP_DP vs UP_DM),按对内 0.15 判。
|
||||
J23_TIE = {
|
||||
'UP_DP#2': [(212.392, 62.25, L_BOT, W), (213.85, 62.25), (213.85, 62.25, L_TOP),
|
||||
(213.85, 60.70), (213.85, 60.70, L_BOT), (213.50, 61.25),
|
||||
(213.20, 61.25), (212.392, 61.25)],
|
||||
'UP_DM#2': [(212.392, 61.75, L_BOT, W), (213.20, 61.75), (213.50, 61.75),
|
||||
(214.25, 61.30), (214.75, 61.30), (214.75, 61.30, L_TOP),
|
||||
(214.75, 63.20), (214.75, 63.20, L_BOT), (214.25, 63.20),
|
||||
(213.50, 62.75), (213.20, 62.75), (212.392, 62.75)],
|
||||
}
|
||||
|
||||
|
||||
# ══════════ Hub 西缘 pin5 / pin10 的 +3V3(被 D± 夹住,只能在这里一起画)══════════
|
||||
# 后面的信号布线器(pcb2_route_sig.py)把这些线当**已有障碍**,别删。
|
||||
# pin5 (66.25) 夹在 DP2 (65.75) 与 DM3 (66.75) 之间:西行到 90.4(pair 3 拐走之后)跟着北上,到 (90.4, 70.5) 打孔翻顶层
|
||||
# —— 孔离 DP2 车道 89.75 / DM3 车道 91.05 各 0.65。顶层西去 (88.2, 70.5) 再下来进 C747(底层 rot 90,x 88.2,
|
||||
# 在 J31 最东列 86.98 与 DM2 车道 89.27 之间)。(88.2, 70.5) 的孔离 VO2 岛东界 87.3 有 0.9,反焊盘不碰岛。
|
||||
# pin10 (68.75) 夹在 DP4 (68.25) 与 DM5 (69.25) 之间:西行到 92.95 跟着 pair 5 北上(离 DM5 车道 0.24、离 pair 4 的孔 0.305),
|
||||
# y 69.55 起 45° 斜到 (92.5, 70.0),直进 C748(底层 rot 90,x 92.5,夹在 DP3 车道 91.53 与 DM5 车道 93.47 中间)。
|
||||
# +3V3 干线:U31 pin2(+3V3 输出,(90.47, 60.5) 焊盘 y ≤ 61.05)旁 (90.3, 61.65) 打孔上顶层,沿 x 90.3 北上
|
||||
# (pair 4 的顶层车道在 91.5 以东),到 (90.4, 70.5) 与 pin5 的孔汇合,再东去 (92.5, 70.0) 打孔下来进 C748。
|
||||
# 顶层这三段底下 Inner1 都是 GND(x 87.3~100.5、y 65.15~75.5 之间没有任何岛)。
|
||||
# 电容的哪个焊盘是 +3V3 由 build() 从障碍表里查,不写死。
|
||||
V_P5, V_P5W = (90.40, 70.50), (88.20, 70.50)
|
||||
V_P10 = (92.50, 70.00)
|
||||
V_TRUNK = (90.30, 61.65)
|
||||
|
||||
|
||||
def _pad(pads, ref, net):
|
||||
for p in pads:
|
||||
if p['ref'] == ref and p['net'] == net:
|
||||
return (p['x'], p['y'])
|
||||
raise SystemExit(u'障碍表里找不到 %s 的 %s 焊盘(先 --dump)' % (ref, net))
|
||||
|
||||
|
||||
def power_lanes(pads):
|
||||
c747 = _pad(pads, 'C747', '+3V3_HUB')
|
||||
c748 = _pad(pads, 'C748', '+3V3_HUB')
|
||||
for p in pads: # 干线起点必须真的落在 U31 pin2(+3V3 输出)里
|
||||
if p['ref'] == 'U31' and p['num'] == '2':
|
||||
assert abs(p['x'] - 90.47) < 0.05 and abs(p['y'] - 60.5) < 0.05, u'U31 pin2 挪了,改 V_TRUNK'
|
||||
return {
|
||||
'+3V3_HUB#p5': [(PAD_X, 66.25), (90.40, 66.25), (V_P5[0], V_P5[1]),
|
||||
(V_P5[0], V_P5[1], L_TOP), (V_P5W[0], V_P5W[1]),
|
||||
(V_P5W[0], V_P5W[1], L_BOT), (c747[0], c747[1])],
|
||||
'+3V3_HUB#p10': [(PAD_X, 68.75), (92.95, 68.75), (92.95, 69.55), (V_P10[0], V_P10[1]),
|
||||
(c748[0], c748[1])],
|
||||
'+3V3_HUB#trunk': [(90.30, 61.00), (V_TRUNK[0], V_TRUNK[1]),
|
||||
(V_TRUNK[0], V_TRUNK[1], L_TOP), (90.30, 70.40), (V_P5[0], V_P5[1]),
|
||||
(V_P10[0], V_P10[1]), (V_P10[0], V_P10[1], L_BOT), (c748[0], c748[1])],
|
||||
}
|
||||
|
||||
|
||||
def build(pads=None):
|
||||
out = {}
|
||||
for grp in (SITE1, SITE2, SITE3, SITE4, SITE5, UP, J23_TIE):
|
||||
for net, pts in grp.items():
|
||||
out[net] = chamfer(P(*pts))
|
||||
if pads is not None:
|
||||
for net, pts in power_lanes(pads).items():
|
||||
out[net] = chamfer(P(*pts))
|
||||
return out
|
||||
# -*- coding: utf-8 -*-
|
||||
u"""六对**长差分**(USB1~5 的 U32↔U5n + UPSTREAM 的 U32↔J23)+ Hub 西缘被 D± 夹住的两条 +3V3 车道。
|
||||
|
||||
**v5 版(2026-09-06,载板全部底层、接口边朝板边)。** v3 版存档在 `obsolete/pcb2_dp_long_v3_2026-09-06.py`。
|
||||
被 `pcb2_route_dp.py` import;校核 / 下发都用那个脚本,这里只放坐标。
|
||||
|
||||
## 出发点:U32 西缘的 12 条车道
|
||||
|
||||
U32(QFN-64,**底层**,中心 (100, 68))的 D± 全在**西缘 x 95.55**,0.5 脚距、南→北:
|
||||
|
||||
1DM 64.25 | 1DP 64.75 | 2DM 65.25 | 2DP 65.75 | pin5 +3V3 66.25 |
|
||||
3DM 66.75 | 3DP 67.25 | 4DM 67.75 | 4DP 68.25 | pin10 +3V3 68.75 |
|
||||
5DM 69.25 | 5DP 69.75 | pin13 GND 70.25 | 14~16 NC
|
||||
|
||||
目的地却是四面八方:1→西北远处 (U51 22/24, 87)、2→正北 (U52 94/96, 87)、3→东北 (U53 165/167, 87)、
|
||||
4→西南 (U54 88.6/90.5, 48)、5→东南 (U55 160/162, 48)、UP→正东 (J23 212, 61~62)。
|
||||
|
||||
### 定下来的走法(理由都在代码注释里)
|
||||
|
||||
| 车道 | 层 | 走法 |
|
||||
|---|---|---|
|
||||
| pair 1 | 底 | 直着西行 y 64.25/64.75 到 x 22.34/22.82,北上进 U51 |
|
||||
| pair 2 | 底 | 西行到 89.27/89.75 北上,y 80 处 45° 斜到 93.84/95.74 进 U52 |
|
||||
| pin 5 | 底→顶 | 西行到 90.4,跟着 pair 3 北上到 70.5 打孔翻顶层,西去 (88.2, 70.5) 再下来进 C747 |
|
||||
| pair 3 | 底 | 西行到 91.05/91.53 北上,y 76.50/76.98 东行,过了 pair 5 之后压到 75.40/75.88 从 MH 焊盘下面钻过去,x 165 北上 |
|
||||
| pair 4 | **顶** | 西行到 x 92.2 打孔上顶层(DM 67.95 / DP 68.85),沿 x 91.5/91.98 南下到 y 52,斜到 (89.6/90.5, 50.3) 下来进 U54 |
|
||||
| pin 10 | 底 | 西行到 92.95,跟着 pair 5 北上,斜到 (92.5, 70.0) 进 C748;(92.5, 70.0) 上有一个孔接顶层 +3V3 干线 |
|
||||
| pair 5 | 底 | 西行到 93.47/93.95 北上,y 75.50/75.98 东行到 110.30/110.78 南下,**y 59.2~61.6 翻顶层跨过 UP**,y 52.5/52.98 东行,x 160.1/162 南下进 U55 |
|
||||
| UP | 底 | 南缘 pin58/59 从 C743/C745 之间的竖井下到 60.12/60.60,一路东行,x 205 抬到 61.25/61.75 进 J23 B6/A7 |
|
||||
| +3V3 干线 | 顶 | U31 pin2 旁 (90.3, 61.65) 打孔上顶层,北上到 (90.4, 70.5)(与 pin5 的孔汇合),东去 (92.5, 70.0) 下来进 C748 |
|
||||
|
||||
### 三条关键约束
|
||||
|
||||
1. **0.5 脚距的车道之间打不了孔**:孔要离两边车道各 0.645,所以只有当邻居车道都拐走之后才能打。
|
||||
北边的先拐(pair 5 → pin 10 → pair 4 打孔 → pair 3 → pin 5 → pair 2),像剥洋葱。
|
||||
pair 4 的两个孔卡在 DP3 的横车道(y 67.25,要求孔心 ≥ 67.895)和 pin10 北上车道(x 92.95,要求孔心 x ≤ 92.305)之间,
|
||||
所以 DP4 得先在 x 93.1→92.5 抬到 68.85 再打孔,两孔上下错 0.9。
|
||||
2. **顶层只走 Inner1 是 GND 的地方**:Hub 周围 x ≥ 87(VO4 岛东界已从 89 收到 87)、y < 75.5(VO2 的 Hub 北横带以南)是一整片 GND;
|
||||
pair 4 全程、pair 5 跨 UP 的那 2.4 mm、+3V3 干线都在这片里。pair 5 的跨越点 x 110~111.5 也在 VO4/VO5 之间的 GND 窗口里。
|
||||
3. **平行 45° 斜段要保持 0.48 间距**:两根线各自的拐点不能同 x/同 y,第一拐**内侧**那根要早拐 0.2
|
||||
(0.48·(√2−1)),否则斜段上的垂直间距只剩 0.34。文件里所有成对斜段都按这个写。
|
||||
|
||||
### 每个站点最后一段
|
||||
|
||||
U5n 朝 Hub 那排的 DP/DM 相距 1.9 mm,车道并排 0.48 到最后 1.4 mm 再用 45° 分开,
|
||||
分开的那根一律是**转弯时的外侧**,所以到站不用交叉 —— 五对都核过了
|
||||
(转弯规则:向右拐时左边那根变成外侧,连拐两次回到原样)。
|
||||
"""
|
||||
import math
|
||||
import sys as _s, os as _o; _s.path.insert(0, _o.path.dirname(_o.path.abspath(__file__)))
|
||||
KSEP = chr(0) # 路径 key 的分隔符,与 pcb2_route_dp.KSEP 同值(不能 import:route_dp --dump 会反过来 import 本模块,循环)
|
||||
|
||||
L_TOP, L_BOT = 1, 2
|
||||
W = 0.28
|
||||
|
||||
|
||||
def chamfer(pts, r=0.35):
|
||||
u"""把折线的拐点切成 45°。换层点(相邻两点层不同)不切。
|
||||
|
||||
⚠ 点的 layer/width 语义是「从这一点到下一点」,所以在拐点 b 处插入的
|
||||
b1 用**前一段**的层/宽(它承担斜切段),b2 用 b 自己的。
|
||||
"""
|
||||
if len(pts) < 3:
|
||||
return list(pts)
|
||||
out = [pts[0]]
|
||||
for i in range(1, len(pts) - 1):
|
||||
a, b, c = pts[i - 1], pts[i], pts[i + 1]
|
||||
if a[2] != b[2] or b[2] != c[2]: # 拐点两侧不同层 -> 这是过孔点
|
||||
out.append(b)
|
||||
continue
|
||||
ax, ay = b[0] - a[0], b[1] - a[1]
|
||||
cx, cy = c[0] - b[0], c[1] - b[1]
|
||||
la, lc = math.hypot(ax, ay), math.hypot(cx, cy)
|
||||
if la < 1e-9 or lc < 1e-9:
|
||||
out.append(b)
|
||||
continue
|
||||
# 共线就不用切;**已经是 45° 的拐(正 + 斜)也不切** —— 再切一刀会变成两个 22.5°,
|
||||
# 而且切出来的那一小段会向内侧挪 0.1 mm,实测把 DP4 的抬升段切进了 pin10 车道的净距圈(0.125)。
|
||||
dot = max(-1.0, min(1.0, (ax * cx + ay * cy) / (la * lc)))
|
||||
if math.degrees(math.acos(dot)) <= 46.0:
|
||||
out.append(b)
|
||||
continue
|
||||
d = min(r, la / 2.0, lc / 2.0)
|
||||
out.append((round(b[0] - ax / la * d, 4), round(b[1] - ay / la * d, 4), a[2], a[3]))
|
||||
out.append((round(b[0] + cx / lc * d, 4), round(b[1] + cy / lc * d, 4), b[2], b[3]))
|
||||
out.append(pts[-1])
|
||||
return out
|
||||
|
||||
|
||||
def P(*pts):
|
||||
u"""(x, y[, layer[, width]]) -> 规范化四元组;层/宽省略时沿用上一点。"""
|
||||
out, lay, w = [], L_BOT, W
|
||||
for t in pts:
|
||||
x, y = t[0], t[1]
|
||||
lay = t[2] if len(t) > 2 else lay
|
||||
w = t[3] if len(t) > 3 else w
|
||||
out.append((round(x, 4), round(y, 4), lay, w))
|
||||
return out
|
||||
|
||||
|
||||
PAD_X = 95.55 # U32 西缘焊盘中心(焊盘 x 95.125~95.975,hh 0.15)
|
||||
# 0.28 的线直着从 0.5 脚距的焊盘出来,两边净距 0.21,不用让位。
|
||||
|
||||
# ══════════ pair 1 → U51(西北远处)══════════
|
||||
# 直着西行:y 64.25/64.75 从 x 95.55 到 x 22~23 一路无障碍(U31 pin1 顶 63.35、J31 底排焊盘底 65.38、
|
||||
# R721/R722 顶 61.77、U34 顶 ~62)。西行时 DM 在南 = 左侧,右拐北上后左侧变西 ⇒ DM 走西车道 22.34(正对 U51.6),
|
||||
# DP 在 22.82,到 y 84.3 再 45° 分到 24.24 进 U51.4。
|
||||
SITE1 = {
|
||||
'USB1_DM': [(PAD_X, 64.25), (22.34, 64.25), (22.34, 86.475)],
|
||||
'USB1_DP': [(PAD_X, 64.75), (22.82, 64.75), (22.82, 84.30), (24.24, 85.72), (24.24, 86.475)],
|
||||
}
|
||||
|
||||
# ══════════ pair 2 → U52(正北)══════════
|
||||
# 西行到 x 89.27/89.75 右拐北上(DM 西)。北上车道左边是 J31 最东一列焊盘(x ≤ 86.98),右边是 pin5 的北上车道 90.4。
|
||||
# 一直到 y 80 才 45° 斜向东北 —— 必须过了 pair 3 / pair 5 东行车道(y ≤ 76.97)之后才能往东挪,
|
||||
# 而且要绕开 site2 的定位孔 H1 (89.39, 85.36)。斜段直接斜到各自焊盘正下方:DM 到 93.84、DP 一口气到 95.74。
|
||||
# 内侧(DP,东)早拐 0.2 保持斜段 0.48 间距。
|
||||
SITE2 = {
|
||||
'USB2_DM': [(PAD_X, 65.25), (89.27, 65.25), (89.27, 80.00), (93.84, 84.57), (93.84, 86.475)],
|
||||
'USB2_DP': [(PAD_X, 65.75), (89.75, 65.75), (89.75, 79.80), (95.74, 85.79), (95.74, 86.475)],
|
||||
}
|
||||
|
||||
# ══════════ pair 3 → U53(东北)══════════
|
||||
# 西行到 91.05/91.53 右拐北上(DM 西),再右拐东行(西车道变北车道 ⇒ DM 76.98 / DP 76.50),
|
||||
# 这一段在 pair 5 东行车道(75.50/75.98)的北边;pair 5 在 x 110.78 南下之后,pair 3 在 x 112 压到 75.40/75.88 ——
|
||||
# 因为 MH (148.1, 79.5) 的 Ø6 焊盘底在 76.5,北车道上沿必须 ≤ 76.16。
|
||||
# 到 x 165 左拐北上:北车道(DM)是内侧变西 ⇒ DM 165.34 正对 U53.6,DP 在 165.82 到 y 84.6 再分到 167.24。
|
||||
# 下压的斜段:第一拐向右(东→东南),内侧是南车道 DP,早拐 0.2。
|
||||
SITE3 = {
|
||||
'USB3_DM': [(PAD_X, 66.75), (91.05, 66.75), (91.05, 76.98), (112.00, 76.98), (113.10, 75.88),
|
||||
(165.34, 75.88), (165.34, 86.475)],
|
||||
'USB3_DP': [(PAD_X, 67.25), (91.53, 67.25), (91.53, 76.50), (111.80, 76.50), (112.90, 75.40),
|
||||
(165.82, 75.40), (165.82, 84.60), (167.24, 86.02), (167.24, 86.475)],
|
||||
}
|
||||
|
||||
# ══════════ pair 4 → U54(西南)—— 全程顶层 ══════════
|
||||
# 它北边是 pin10(要跟 pair 5 北上)、南边是 pair 3(北上)、pair 2、pair 1 全都横在西边 —— 底层无路,
|
||||
# 一出焊盘就打孔上顶层。两个孔:DM4 (92.2, 67.95)(离 DP3 横车道 67.39 有 0.255)、DP4 (92.2, 68.85)(上下错 0.9),
|
||||
# DP4 先在 x 93.1→92.5 斜抬到 68.85 再西行到孔,避开 DM4 的孔(孔顶 68.255 vs 车道底 68.11 才 0.055)。
|
||||
# 顶层:DP 西车道 91.5 / DM 91.98 南下到 y 52,45° 斜到 (89.6, 50.3) / (90.5, 50.3) 打孔回底层,
|
||||
# 进 U54.4 (88.6, 48.149) / U54.6 (90.5, 48.149)。DM 的孔正对焊盘、直下;DP 的孔再斜 1 mm 到 88.6。
|
||||
# 顶层这一段底下 Inner1:x ≥ 87 全是 GND(VO4 岛东界 87、site4 岛 x ≤ 84.75、VO2 从 y 75.5 起)。
|
||||
SITE4 = {
|
||||
'USB4_DM': [(PAD_X, 67.75), (92.60, 67.75), (92.40, 67.95), (92.20, 67.95),
|
||||
(92.20, 67.95, L_TOP), (91.98, 67.73), (91.98, 52.00), (90.50, 50.52), (90.50, 50.30),
|
||||
(90.50, 50.30, L_BOT), (90.50, 48.685)],
|
||||
'USB4_DP': [(PAD_X, 68.25), (93.10, 68.25), (92.50, 68.85), (92.20, 68.85),
|
||||
(92.20, 68.85, L_TOP), (91.50, 68.85), (91.50, 52.50), (89.60, 50.60), (89.60, 50.30),
|
||||
(89.60, 50.30, L_BOT), (88.60, 49.30), (88.60, 48.685)],
|
||||
}
|
||||
|
||||
# ══════════ pair 5 → U55(东南)—— 绕 Hub 北边走 ══════════
|
||||
# 最北的一对,出来就右拐北上(DM 西 93.47 / DP 东 93.95;DP 的东沿离 C751 焊盘 94.295 只剩 0.205,
|
||||
# 再东一点 pin13 的 GND 就打不了孔了 —— 给它留的孔位是 (94.6, 71.4))。
|
||||
# 北上到 75.50/75.98(C751 顶 74.974,DP 拐角的 45° 切角离它 0.24)右拐东行(DM 北),到 x 110.30/110.78 右拐南下(南车道 DP 是内侧变西 ⇒ DP 110.30)。
|
||||
# 南下时 x 110.3 离 R711/R716/R720 的东沿 109.62 有 0.54、离 J64 焊盘 107.43 有 2.7。
|
||||
# **y 59.2~61.6 翻到顶层跨过 UP 的两根横线**(60.12/60.60):DP 的孔在 110.30,DM 的孔错到 111.3(两孔 1.0)。
|
||||
# 到 y 52.5/52.98 左拐东行(东车道 DM 是内侧变北 ⇒ DM 52.98),DP 在 x 160.10 南下进 U55.4,DM 到 162.00 进 U55.6。
|
||||
SITE5 = {
|
||||
'USB5_DM': [(PAD_X, 69.25), (93.47, 69.25), (93.47, 75.98), (110.78, 75.98),
|
||||
(110.78, 62.60), (111.30, 62.08), (111.30, 61.60),
|
||||
(111.30, 61.60, L_TOP), (111.30, 59.20),
|
||||
(111.30, 59.20, L_BOT), (111.30, 58.72), (110.78, 58.20),
|
||||
(110.78, 52.98), (162.00, 52.98), (162.00, 48.685)],
|
||||
'USB5_DP': [(PAD_X, 69.75), (93.95, 69.75), (93.95, 75.50), (110.30, 75.50),
|
||||
(110.30, 61.60),
|
||||
(110.30, 61.60, L_TOP), (110.30, 59.20),
|
||||
(110.30, 59.20, L_BOT), (110.30, 52.50), (160.10, 52.50), (160.10, 48.685)],
|
||||
}
|
||||
|
||||
# ══════════ UPSTREAM → J23(U32 南缘 → 板子正东)══════════
|
||||
# pin59 UP_DP (98.75, 63.55) / pin58 UP_DM (99.25, 63.55) 直着南下,从 C743(x ≤ 97.62)与 C745(x ≥ 99.78)之间的
|
||||
# 竖井下到 y 60.12/60.60(那排 0402 的焊盘底 60.98),一路东行到 x 205 —— 中间 y 60~61 从 x 99 到 208 全空。
|
||||
# J23(底层 rot 270):B6 UP_DP 61.25 / A7 UP_DM 61.75 / A6 UP_DP 62.25 / B7 UP_DM 62.75,B5 CC2 在 60.25、A8 空脚 60.75。
|
||||
# 车道压在 60.17 会把 B5 的 CC2 走线堵死(R718 在 59.5),所以 x 205 就抬到 61.25/61.75 平着进 B6/A7。
|
||||
# 抬升是左拐再右拐,第一拐内侧是北车道 DM ⇒ DM 早拐 0.2。
|
||||
UP = {
|
||||
'UP_DP': [(98.75, 63.55), (98.75, 60.12), (205.00, 60.12), (206.13, 61.25), (212.392, 61.25)],
|
||||
'UP_DM': [(99.25, 63.55), (99.25, 60.60), (204.80, 60.60), (205.95, 61.75), (212.392, 61.75)],
|
||||
}
|
||||
|
||||
# ══════════ J23 的 A6↔B6 / A7↔B7 短接(USB-C 正反插的一对重复脚)══════════
|
||||
# 几何照抄 v3(那一版过了 DRC),只是 J23 翻到底层之后网络对调:61.25↔62.25 这一对现在是 UP_DP(B6/A6),
|
||||
# 61.75↔62.75 是 UP_DM(A7/B7);出线在底层,跨越段翻到**顶层**。
|
||||
# ⚠ 表贴焊盘只到 x=213.04,过孔要离它 0.505 ⇒ 最西只能放到 213.55;出线前 0.65 mm 必须平着走(阵列上方起坡会蹭隔壁脚)。
|
||||
# 另一根的 61.75 横线离 (213.85, 62.25) 那个孔只有 0.165 —— 这是同一对的两根(UP_DP vs UP_DM),按对内 0.15 判。
|
||||
J23_TIE = {
|
||||
'UP_DP' + KSEP + '2': [(212.392, 62.25, L_BOT, W), (213.85, 62.25), (213.85, 62.25, L_TOP),
|
||||
(213.85, 60.70), (213.85, 60.70, L_BOT), (213.50, 61.25),
|
||||
(213.20, 61.25), (212.392, 61.25)],
|
||||
'UP_DM' + KSEP + '2': [(212.392, 61.75, L_BOT, W), (213.20, 61.75), (213.50, 61.75),
|
||||
(214.25, 61.30), (214.75, 61.30), (214.75, 61.30, L_TOP),
|
||||
(214.75, 63.20), (214.75, 63.20, L_BOT), (214.25, 63.20),
|
||||
(213.50, 62.75), (213.20, 62.75), (212.392, 62.75)],
|
||||
}
|
||||
|
||||
|
||||
# ══════════ Hub 西缘 pin5 / pin10 的 +3V3(被 D± 夹住,只能在这里一起画)══════════
|
||||
# 后面的信号布线器(pcb2_route_sig.py)把这些线当**已有障碍**,别删。
|
||||
# pin5 (66.25) 夹在 DP2 (65.75) 与 DM3 (66.75) 之间:西行到 90.4(pair 3 拐走之后)跟着北上,到 (90.4, 70.5) 打孔翻顶层
|
||||
# —— 孔离 DP2 车道 89.75 / DM3 车道 91.05 各 0.65。顶层西去 (88.2, 70.5) 再下来进 C747(底层 rot 90,x 88.2,
|
||||
# 在 J31 最东列 86.98 与 DM2 车道 89.27 之间)。(88.2, 70.5) 的孔离 VO2 岛东界 87.3 有 0.9,反焊盘不碰岛。
|
||||
# pin10 (68.75) 夹在 DP4 (68.25) 与 DM5 (69.25) 之间:西行到 92.95 跟着 pair 5 北上(离 DM5 车道 0.24、离 pair 4 的孔 0.305),
|
||||
# y 69.55 起 45° 斜到 (92.5, 70.0),直进 C748(底层 rot 90,x 92.5,夹在 DP3 车道 91.53 与 DM5 车道 93.47 中间)。
|
||||
# +3V3 干线:U31 pin2(+3V3 输出,(90.47, 60.5) 焊盘 y ≤ 61.05)旁 (90.3, 61.65) 打孔上顶层,沿 x 90.3 北上
|
||||
# (pair 4 的顶层车道在 91.5 以东),到 (90.4, 70.5) 与 pin5 的孔汇合,再东去 (92.5, 70.0) 打孔下来进 C748。
|
||||
# 顶层这三段底下 Inner1 都是 GND(x 87.3~100.5、y 65.15~75.5 之间没有任何岛)。
|
||||
# 电容的哪个焊盘是 +3V3 由 build() 从障碍表里查,不写死。
|
||||
V_P5, V_P5W = (90.40, 70.50), (88.20, 70.50)
|
||||
V_P10 = (92.50, 70.00)
|
||||
V_TRUNK = (90.30, 61.65)
|
||||
|
||||
|
||||
def _pad(pads, ref, net):
|
||||
for p in pads:
|
||||
if p['ref'] == ref and p['net'] == net:
|
||||
return (p['x'], p['y'])
|
||||
raise SystemExit(u'障碍表里找不到 %s 的 %s 焊盘(先 --dump)' % (ref, net))
|
||||
|
||||
|
||||
def power_lanes(pads):
|
||||
c747 = _pad(pads, 'C747', '+3V3_HUB')
|
||||
c748 = _pad(pads, 'C748', '+3V3_HUB')
|
||||
for p in pads: # 干线起点必须真的落在 U31 pin2(+3V3 输出)里
|
||||
if p['ref'] == 'U31' and p['num'] == '2':
|
||||
assert abs(p['x'] - 90.47) < 0.05 and abs(p['y'] - 60.5) < 0.05, u'U31 pin2 挪了,改 V_TRUNK'
|
||||
return {
|
||||
'+3V3_HUB' + KSEP + 'p5': [(PAD_X, 66.25), (90.40, 66.25), (V_P5[0], V_P5[1]),
|
||||
(V_P5[0], V_P5[1], L_TOP), (V_P5W[0], V_P5W[1]),
|
||||
(V_P5W[0], V_P5W[1], L_BOT), (c747[0], c747[1])],
|
||||
'+3V3_HUB' + KSEP + 'p10': [(PAD_X, 68.75), (92.95, 68.75), (92.95, 69.55), (V_P10[0], V_P10[1]),
|
||||
(c748[0], c748[1])],
|
||||
'+3V3_HUB' + KSEP + 'trunk': [(90.30, 61.00), (V_TRUNK[0], V_TRUNK[1]),
|
||||
(V_TRUNK[0], V_TRUNK[1], L_TOP), (90.30, 70.40), (V_P5[0], V_P5[1]),
|
||||
(V_P10[0], V_P10[1]), (V_P10[0], V_P10[1], L_BOT), (c748[0], c748[1])],
|
||||
}
|
||||
|
||||
|
||||
def build(pads=None):
|
||||
out = {}
|
||||
for grp in (SITE1, SITE2, SITE3, SITE4, SITE5, UP, J23_TIE):
|
||||
for net, pts in grp.items():
|
||||
out[net] = chamfer(P(*pts))
|
||||
if pads is not None:
|
||||
for net, pts in power_lanes(pads).items():
|
||||
out[net] = chamfer(P(*pts))
|
||||
return out
|
||||
|
||||
在新工单中引用
屏蔽一个用户