文件
phonerail/刀片式方案规划-R2.md
T
zhou yang和Claude Opus 5 efcba30a0c 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
2026-09-10 21:02:10 +08:00

175 KiB
原始文件 Blame 文件历史

PhoneRail R2 · 刀片式 方案规划

这份文档的地位:R2 是新架构,与 R1(五路直供电源板设计.md,一块下板 + 一块载板对插) 并存,R1 的工程、原理图、PCB、固件一律保留不动。 R2 只写「与 R1 不同的部分」和「新的约束」;所有没有改变的计算与选型(功率级、 调压网络、保护链、小米8 侧接口、USB 子系统配置)仍以 R1 文档的对应章节为准, 本文用 R1 §x.y 引用,不重复抄写。

更新:2026-09-08 初稿(架构定稿,未开画)


0. 决策与前提

0.1 已拍板(不再讨论)

# 决定 依据
D1 拆成「底板 + 5 片相同刀片」,取代 R1 的「下板 + 载板」 打样成本 / 返工成本 / 可扩展性,见 §2
D2 跨连接器的是 12V,不是 4V 连接器电流 4 A → 1.5 A,R1 §22.2 那套「3 针并联 + 正对面 3 针地」的约束整个消失
D3 连接器用 PCI-E 插槽 + 刀片板边金手指 刀片侧零连接器成本;差分对天然夹地;插槽提供机械定位与保持
D4 刀片竖插(PCIe 常规姿势) 风道沿槽间通道垂直贯通;底板占地最小
D5 底板 2 层,刀片 4 层 ⇒ 2026-09-10 被 D15 取代 底板上五路 Buck 已搬走,2 层放得下;条件见 §6.2
D6 USB Hub 回到底板,坐在 5 个槽的几何正中 D3 之后差分不再怕过连接器;R1 §22.1「四样东西必须一起上载板」作废
D7 不支持带电插拔 省掉热插拔控制器与 staggered finger 软起;PRSNT# 只做在位检测
D8 底板加 TCA9548A I²C 多路器,一槽一路 五片刀片可用完全相同的 I²C 地址、零 strap 电阻;顺带做故障隔离
D9 每片刀片用一颗 PCA9555 取代 R1 的 74HC595 链 少 4 根跨板信号;复位态天然安全(上电为高阻输入 + 栅极 100 k 下拉)
D10 每片刀片的 12V 入口串 2 A 慢断保险 + TVS 一片刀片短路不拖垮 12V 母线和另外四台
D11 DAC 沿用 DAC63204 固件 A4 驱动、NVM 安全默认值、R1 §4.5 三条外围硬要求零改动
D11b ⚠️ 2026-09-08 改判:DAC 不放刀片,放底板 —— 2 颗喂 5 路(就是 R1 的 U6/U7 那套原样搬) 5 颗 → 2 颗;刀片再省 5 个无源件与一个 I²C 设备。敢跨连接器的依据是设计文档 §4.4 的失效表:VDAC 断线 = Rinj 悬空 = 3.890 V(正好是目标值)、对地短路 = 4.010 V,注入增益只有 0.2007,噪声与两板地差到输出衰减 5 倍。见 §15
D12 D± 留一条退路:刀片与底板各引 4 pin 1.25 mm 座 金手指那条路万一不稳,割断改飞 5 根短线;代价 ¥2
D14 刀片板框硬上限 98 × 98 mm(不是 100 × 100) 用户要求刀片控制在 10×10 cm 内。留 2 mm 余量是因为 100.0 正好压在嘉立创特价档的边界上,尺寸判定没有余地。当前实际 98 × 76,两个方向都有富余。
D13 ESP32-S3 的原生 USB 接到 Hub 的第 6 个下行口,删掉 J22 调试 USB-C,改留一个 5 针 UART 应急口 全机只剩一根线到电脑(5 台手机 + 控制器共用上游)。详见 §8.2
D15 底板改 4 层、板框硬上限 98 × 98,插槽面只放 5 个插槽,其余器件全部放背面(2026-09-10 用户拍板,取代 D5) 2 层版布到 63 条卡死:D± 墙(19 个网 0 通过)+ 西侧 12V 干道(18 个网只能走底层跳)。4 层后 L2/L3 两块完整地给 D± 和所有信号当参考,墙不存在;背面没有刀片投影,高件不限位置;U32 可直接坐在中间槽正下方。叠层:L1 插槽面 = 槽焊盘 + 12V 大铺铜 + 少量线 / L2 GND ⇒ L2 整层 +3V3(2026-09-10 用户拍板,见下)/ L3 GND / L4 器件面 = 全部器件 + 信号 + D±(参考 L3)+ 5V 局部铜。
L2 改 +3V3 的理由:4 层布线跑了十轮,信号网卡在 37~38 个,大头是 +3V3 这棵 47 只脚、跨全板的电源树。L3 保持整层地(L4 上全部器件与 D± 的参考不变,M5「D± 参考层 L3 无开口」原样成立);L2 让出来做一整块 +3V3,+3V3 每脚打孔下去、不再布线。L1 上仅有的几段 D±(USB6 / 上行、USB4 的一跳)参考的是一整块 +3V3,同样不跨分割。曾考虑在 L3 分区,被否:L3 在 D± 下必须留地条,会把 +3V3 切成几块,+5V 平面也排不开。98 的理由同 D14。插槽手焊,工厂只贴背面。代价:2 层版布局布线作废(存档 .claude/r2/archive_base2L/);背面最高 12 mm(C2/C3 直立电解),底板下要 ≥ 15 mm 铜柱,外壳跟着改

0.2 本文档按这些默认值展开(要改说一声)

# 默认 备选
A1 插槽用 PCI-E x4(64 针 / 槽体 39 mm),针数只用 ~25,其余全接地 x8(56 mm)更稳但占地大;x1(25 mm)太短,刀片会晃
A2 手机主板整块装在刀片上(7 个定位孔 + 侧键顶针 + 尾插全在刀片) 刀片只做电路、主板由打印件托住——公差链会跨两个零件,不建议
A3 保留 R1 §22.6 的两路风扇电路,物理上做成槽阵一端的风墙;首板只装一只 竖插后一只轴流可能就够,省一颗 MOS + 一路 PWM/TACH
A4 槽距 20.32 mm(PCIe / PC 机箱标准) 15 mm 可把底板再压窄 26 mm,但风道变窄、标准导轨用不上

0.3 待实测 / 待选型(开画前要有数)

# 项 为什么卡住
T1 ✅ 已定 2026-09-08:槽距 20.32 mm,不需要实测。原 §3.2 的预算用错了安装方式(写「立柱 3.0」,实际是 R1 §22.3e 定稿的 1.0 mm 中框式焊盘)。改正后 h_phone + g = 14.72,即使把 h_phone 取成小米8 整机厚度 7.6 mm(物理上限)仍余 7.1 mm 空气 ⇒ 结论对这个数不敏感。见 §21.1
T2 ✅ 已定:10.5 mm(C3828985 6.3TPV2200M10X10.5 SMD,Ø10 罐)。这个数 2026-09-06 换矮封装时就有了,只是没回填。放在 A 面没有手机压着的那两列,可用 11.713.7 mm ⇒ 余 1.23.2 mm。见 §21.2
T3 ✅ 已定:做斜边(下单勾「金手指 + 斜边」)。理由是斜边的加价压在已经要付的金手指工艺费之上,而它挡掉的失效是「插拔刮伤已焊死的插槽簧片」—— 五个座子换一个都要拆焊,且功能测试测不出来。顺带纠正 §5.3:金手指区要电镀硬金,不是 ENIG。见 §21.3
T4 ✅ 已完成 2026-09-08:PCI-E CEM 引脚表逐脚核对 揪出两处记忆错(B3 是 +12V 不是 RSVD、B12 是 CLKREQ#),+5V 改挂 A19/A32。定稿表在 §5.2
T5 R1 §24.3 那位没有实证的镜像位(BM24 哪一排是奇数排) 老账,仍未解决;好消息是现在它只影响刀片这一小块板
T6 USB2517I 在 CFG_SEL=110 下 7 个口是否全部使能 D13 要占用第 6 个口,R1 §21.5 只核过 5 口的分配
T7 ✅ 已完成 2026-09-08:F1 = F1206SB2000V063TM(C310998) 2A 慢断 1206/63V 原因写反了 —— lib_Device.search 能翻页(itemsOfPage/page),翻页之后 AEM F1206 全系都在库里。⚠ 刀片满载 1.45 A = 额定的 73%,裕量只有一档,见 §20.7

1. 架构

                     ┌─ J1 12V/10A DC 座 ─ F1 ─ D1 TVS ─ Q1 反接 ─ 大电容 ─ 12V 母线
                     ├─ U19 12V→3V3 · U30 12V→5V · U29 母线泄放
   底板(背板)      ├─ U20 ESP32-S3 · U35 TCA9548A · U13 INA226(输入侧) · Rs6 5 mΩ
   110 × 125 · 2 层  ├─ U32 USB2517I + Y1 + U31 LDO + J23 上游 USB-C   ← 坐在槽阵正中
   1 oz              │      └ 口1~5 → 五个插槽    口6 → ESP32 原生 USB(D13)
                     ├─ 风墙:两路 4 线 PWM 风扇(R1 §22.6,首板装一只)
                     │
                     └─ 5 × PCI-E x4 插槽 ─┬─ +12V ×4 针(1.5 A 峰值)
                                            ├─ GND ×38 针
                                            ├─ +3V3 ×3 / +5V(VBUS) ×2
                                            ├─ D+ / D−(两侧夹地)
                                            ├─ SDA / SCL(本槽的 mux 分支)
                                            ├─ INT#(开漏,五槽 wire-OR)
                                            └─ PRSNT#
                                                  │  金手指
   刀片 ×5           ┌──────────────────────────┴──────────────────────────────────┐
   98 × 76 · 4 层    │ 12V ─ F1 2A ─ D1 TVS ─ U1 TPS54622 ─ Rs1 ─ U2 eFuse ─ VO_P   │
   (5 片全部用上)  │ FB 分压 + Rinj ← U4 DAC63204(CH0)                            │
                     │ U3 INA226(V/I)· U5 PCA9555(3 键 + EDL + VBUS_EN + 状态入)│
                     │ Q1 反相 + Q2 放电 MOS + R19 10 Ω(EN 硬件联锁)               │
                     │ U6 TPS22918 VBUS 开关 · EDL 1.25 mm 座 · C801 2200 µF        │
                     │ 小米8 主板:7 定位孔 · 侧键顶针 ×3 · J600 P+/P− · BM24 尾插   │
                     └──────────────────────────────────────────────────────────────┘

   对电脑:**一根 USB-C 线**(插 J23)= 5 台手机的 adb + ESP32 的烧录与控制台

分界线只有一条:跨连接器的是 12V + 低速 I²C + 一对 USB,别的都不过。


2. 为什么这么拆(成本模型)

R1 R2
四层板面积 下板 160×125 = 200 cm²
载板 220×135 = 297 cm²
合计 497 cm² 四层
刀片 98×76 = 74.5 cm² 四层
底板 110×125 = 137.5 cm² 双面
是否落在 100×100 特价档 两块都超档,按面积计价 刀片整片在档内
最小起订 5 片的利用率 5 载板 + 5 下板,各用 1 片 → 浪费 80% 刀片 5 片正好等于要用的 5 片
改一版手机侧电路 重打 297 cm² 四层 重打 74.5 cm² 四层
底板层数 4 2

具体报价下单页拉。量级上:打样费砍掉一半以上,手机侧返工费砍掉八成,底板从"按面积计价的四层"降到双面板。

比省钱更重要的一条:手机侧那一坨(P+/P− 焊边、侧键顶针、EDL、BM24 尾插、R1 §13.5 的两个硬问题、 §24.3 那位没有实证的镜像位)是全设计最可能返工的部分,现在它单独占最小的一块板。

2.1 顺手解掉的六个 R1 约束

  1. 连接器电流 4 A → 1.5 A:R1 §22.2 的三针并联、§25.10「4 A 电源面穿不过排母地针行」全部消失。
  2. R1 §22.1「Hub / U31 / U24~U28 / J23 四样必须一起上载板」作废——当初唯一的理由是 2.54 排针过不了 USB 差分。
  3. 五路独立回地(R1 §6.4)从"要靠平面分割去争"变成天然成立:每片刀片的地只经自己那组金手指回到底板星点。
  4. I²C 地址冲突用 mux 一次解决:五片刀片完全同构、零 strap。
  5. R1 §22.3d 排针叠高冲突、§25.2「别让 12 mm 电解撞上底层元件」:两板不再面对面叠合,13 mm 净空整条约束链没有了。
  6. 可扩展:要 3 台或 8 台只改底板槽数,刀片一版不动。

3. 机械与热

3.1 尺寸

值
刀片板框 98 × 76 mm(硬上限 98×98,见 D14),1.6 mm 厚(金手指要求),四角 R2
底板板框 110 × 125 mm ⇒ ≤ 98 × 98 mm、4 层(D15,2026-09-10),1.6 mm 厚(插槽保持力),四角 R5
槽距 20.32 mm(A4),5 槽跨度 81.28 mm
插槽 PCI-E x4 直插,槽体 39 mm(A1)

2026-09-08 用户拍板:主板长边与底板平行,压低整体高度。 手机主板的 67.09 那条长边本来就贴着金手指边(短边 44.66 才是竖向的), 所以真正能砍的是功率级的位置:从「手机正下方的一条 21 mm 横带」 挪成「手机侧面的一条 26 mm 竖列」。刀片 95 → 76 mm 高(宽 85 → 98 mm,面积几乎不变)。

板框余量核账(D14:硬上限 98 × 98): 宽 = 3 + 手机 67.09 + 2 + 功率列 26 = 98.09 → 取 98(手机左边距压到 2.9); 高 = 金手指 11 + 服务带 18 + 手机 44.66 + 上边距 2.34 = 76,竖向还剩 22 mm 富余。 ⇒ 后续要塞东西优先往上长,宽度这一维已经贴死。

刀片分区(板左下角为原点,金手指边朝下):

y 76.00 ┬─────────────────────────────────────┬────────────────┐
        │                                     │   功率列 26mm   │
        │      小米8 主板 67.09 × 44.66        │  Buck / L / Cin │
        │      (长边水平,短边竖向)           │  eFuse / Rs     │
y 29.00 ┼──── 接口边(全部接口都在这条边)──────┤  INA / DAC      │
        │ 服务带 18 mm                         │  PCA9555        │
        │ C801 / TP / EDL 座 / BM24 / 顶针 ×3  │  ← 内侧安静     │
y 11.00 ┼─────────────────────────────────────┴────────────────┤
        │  金手指区 11 mm(PCI-E x4,槽体高度 ~9 mm 要让开)      │
y  0.00 ┴─────────────────── 板边 ─────────────────────────────┘
        x 0    3 ─── 手机主板 ─── 70.09    72 ── 功率列 ── 98

高度账:刀片 76 mm,其中约 9 mm 插进槽里 ⇒ 露出 67 mm。 机箱内高 ≈ 槽体 11 + 67 + 导轨余量 5 ≈ 83 mm(旧版 ≈ 102 mm)。

⚠️ 功率列的内部排序有讲究:功率级和手机主板现在共面、只隔 2 mm, 不再像 R1 那样隔着 13 mm 净空分居两块板。 ⇒ 按「离手机越远越吵」排:SW 节点 / 电感 / Cin 靠外边(x 8898), FB 分压、DAC、INA226、PCA9555 靠内(x 7284);L2 完整地平面必须一路铺到板边。 见风险 R-12。

刀片 98 mm 宽、插槽只有 39 mm 长 ⇒ 上端必须加 3D 打印导轨(PC 机箱卡导轨那种), 否则悬臂 29.5 mm 会晃。若不想做导轨,可把 A1 换成 **x8(56 mm)或 x16(89 mm)**槽体—— 多出来的针全部接地,代价是金手指面积变大(T3 的工艺费按面积算)。

3.2 高度预算 ✅ T1 已定:槽距 20.32 mm

⚠️ 这一节 2026-09-08 重算过。原来的版本用错了安装方式 —— 它写「立柱 3」, 那是 R1 已经作废的顶针方案;现行是 R1 §22.3e 定稿的中框式焊盘、螺柱间隙 1.0 mm (螺丝把主板压在刀片上,主板自己的弹片直接压裸铜盘)。差这 2 mm 就是 T1 一直卡着的原因。

槽距 P = 刀片 PCB 1.6 + A 面(螺柱间隙 1.0 + 手机主板含屏蔽罩 h_phone) + B 面元件 h_B + 空气 g

h_B = 3.0(B 面最高件 = L1 SPM6530T-4R7M),P = 20.32 ⇒ h_phone + g = 14.72。

h_phone 取值 来源 剩余空气 g
3.2 mm 0.8 裸板 + 1.4 侧键面屏蔽罩(实测)+ 正面按 1.0 估 11.5
5.0 mm 常见手机主板总厚 9.7
6.3 mm 旧版本写的「超过就要放到 22 mm」告警阈值 8.4
7.6 mm 小米8 整机厚度 —— 主板是它的子集,这是物理上限 7.1

⇒ 结论对 h_phone 完全不敏感:连物理上限都富余 7 mm。 槽距定 20.32 mm(PCIe / PC 机箱标准,导轨和插槽都是现成的),T1 不再是开画前提。

⚠️ 2026-09-09 更正(§26):下表「B 面 ≤ 3.0」是把 L1 的高度当预算写的,不是净空。 真正的净空分两段:手机投影下 20.32 − 1.6 − 1.0 − 7.6 = 10.1(h_phone 取物理上限), 服务带 20.32 − 1.6 = 18.7(A 面服务带清空之后对面是空的)。C60(10.5) 因此能下到 B 面服务带。

面 可用高度(按 g 留 2~4 mm) 落地
B 面(背面,全板) ≤ 3.0 已用满 → 手机投影下 10.1 / 服务带 18.7(§26) L1 SPM6530T 3.0;C60/J2/J3 在服务带
A 面 手机区 1.0 + h_phone 螺柱间隙 + 主板,见上表
A 面 服务带 + 功率列(没有手机压着) 11.7 ~ 13.7 C60 2200 µF 只能放这两处(T2 = 10.5,余 1.2~3.2)

⚠️ 仍要在装配首件确认的一个数(但它不影响槽距,只影响压板): R1 §22.3e 里有一处自相矛盾——「侧键面(贴合面)最高件 = 屏蔽罩 1.4 mm」 与两天后写的「贴合面上元件全都低于 1 mm」对不上,而螺柱间隙就是按 1.0 定的。 1.4 那个读数若指的是贴合面,1.0 mm 间隙会顶到屏蔽罩。首件用塞尺量一次, 真顶到就把间隙垫片从 1.0 换 1.5(槽距这边有 7 mm 富余,随便加)。

3.3 风道

竖插的天然优势:5 条 20.32 mm 的平行通道,风墙放槽阵一端,沿通道直吹。 风扇电路沿用 R1 §22.6(两路 4 线 PWM + TACH,FAN_12V_SW 0.8 mm 线宽), 位置从「3D 打印外壳上」改为「底板槽阵一端」,首板只装一只(A3)。

外壳要重画:R1 的平铺外壳完全不能用。


4. 电气分界(BOM 归属)

归属 器件 数量 来源
底板 J1 DC-005 座 / F1 10A / D1 TVS / Q1 反接 P-MOS / C_in 2×470 µF 1 套 R1 §9.1 原样
底板 U19 LMR51430Y(3V3)/ U30 LMR51430Y(5V)/ L3 / 分压 1 套 R1 §9.3 / §9.4
底板 U29 母线泄放 TL431 + MOS + 10 Ω/5 W 1 R1 §15.2
底板 U20 ESP32-S3-WROOM-1 1 R1 §9.1;J22 调试 USB-C 删除(D13)
底板 J33 调试应急口 5P 1.25 mm(GND / TXD0 / RXD0 / EN / IO0) 1 R2 新增(D13 的退路)
底板 U35 TCA9548A I²C 八路多路器 1 R2 新增(D8)
底板 U13 INA226(输入侧)+ Rs6 5 mΩ 1 R1 §19
底板 U32 USB2517I + Y1 24 MHz + R708 12k + U31 AMS1117-3.3 + J23 上游 USB-C 1 套 R1 §21,CFG_SEL[2:0]=110 不变(R1 §21.6b)
底板 风扇:Q7/Q9/Q10 + J26~J30 + RT601/602 1 套 R1 §22.6
底板 5 × PCI-E x4 插槽 5 R2 新增
底板 D± 退路座 4pin 1.25 mm 5 R2 新增(D12)
刀片 ×5 FB1 2 A 慢断保险 + D2 TVS(12V 入口) 1 R2 新增(D10)
刀片 U1 TPS54622 + L1 4.7 µH + Cin/Cout 1 套 R1 §3 / §9.2 原样
刀片 R1/R2/Rinj 分压注入 + 1 kΩ/10 nF 低通 1 套 R1 §4.2 / §4.3 原样
刀片 底板 DAC63204 ×2(8 通道用 5 路,U6 0x4A / U7 0x4B,位号与通道映射表沿用 R1 §17.2) 2 R1 §4.5,D11b
刀片 Rs1 5 mΩ 2512 + U8 INA226 1 套 R1 §9.1
刀片 U14 eFuse(OVP 4.45 V / 限流 4.5 A) 1 R1 §5 第二层
刀片 Q_dis 放电 MOS + R_dis 10 Ω/1 W + Q_inv 反相联锁 1 套 R1 §7.2 / §7.3 原样
刀片 U23 PCA9555 1 R2(D9),取代 R1 的 74HC595 链
刀片 Q_key ×3 + R_kg 1 k ×3 + R_kp 100 k ×3 1 套 R1 §13.3
刀片 U24 TPS22918 + C701/C711/C721 + R701 100 k 1 套 R1 §18 原样
刀片 EDL 1.25 mm 2P 座 + 模拟开关 1 套 R1 §22.4
刀片 C801 2200 µF + C_fast + C_hf 阻尼组 1 套 R1 §6.3,位置见 §3.2
刀片 侧键顶针 ×3 + BM24-50DS 尾插 + P+/P− 焊盘 1 套 R1 §13 / §24
刀片 7 个 Ø2.5 NPTH 定位孔 + 尼龙立柱 1 套 R1 §22.3a / §25.2 第 3 条

BOM 净变化:+5 DAC63204(原 2)、+5 PCA9555(原 1)、+1 TCA9548A、+5 保险 +5 TVS、 −3 74HC595、−2 排针排母、−1 USB-C(J22)−2 CC 电阻、+1 5P 排针 ⇒ 约 +¥55~75。相对省下的板费可以忽略。

R1 里被 R2 作废的:J24/J25 两条 2×20 排针(R1 §22.2 整节)、74HC595 链、 J22 调试 USB-C(D13)、载板 220×135 板框。


5. 连接器:PCI-E x4 金手指

5.1 针数预算

用途 针数 说明
+12V 5 1.5 A 峰值 ÷ 5 = 0.30 A/针(T4 之后从 4 针变 5 针,见 §5.2)
GND 39 x1 段的地针 + x4 段所有 lane 针 + B12/B17/B30 全部接地
+3V3 3 刀片逻辑(INA226 + PCA9555)≈ 3 mA
+5V(VBUS) 2 ≤ 0.5 A
D+ / D− 2 两侧天然夹地
SDA / SCL 2 本槽 mux 分支
EFUSE_EN 1 直连底板 ESP32 GPIO,不经 PCA9555(见 §7.3 的框)
VDAC 1 D11b:DAC 在底板,模拟量跨金手指进来,直接去刀片的 R8/C12 低通 + Rinj
INT# 1 开漏,五槽 wire-OR
PRSNT# 2 刀片上短接
悬空 6 A5~A8(JTAG)、B9(TRST#)、B10(+3.3Vaux,必须悬空)

64 针分配完毕:19 根有名信号 + 39 根地 + 6 根悬空(b4_edge.py 的 PIN_NET 是唯一事实来源)。 原来「备用差分对 A16/A17」这一条取消:那对差分在刀片上没有对端,留着也用不了, A16 让给 VDAC(上下两针都是地,是全连接器夹得最干净的位置),A17 接地。

5.2 针位分配原则:对齐真实 PCI-E 的语义

✅ T4 已完成(2026-09-08):对着 PCI-E CEM 的引脚表逐脚核过, 原来凭记忆写的表里有两处是错的,其中一处会烧板:

针 本节原来写的 CEM 实际 后果
B3 「RSVD,拿来做 +5V」 +12V(B1 / B2 / B3 三针都是 +12V) ⛔ 刀片误插进真 PC 槽:主板把 12 V 灌进刀片的 +5V 轨 —— U5 TPS22918(abs max 6 V)与手机 VBUS 全灭。反方向(真卡插进底板槽)只是它的 12V 少拿了电压,不致命
B12 「RSVD」 CEM 1.x = RSVD,2.0 起 = CLKREQ# 真主板上有 3.3 V 上拉、真卡上是开漏输出,不能当自由针;本方案改成接地(两个方向都无害)

⇒ +5V 改挂 A19 / A32:这两针在 CEM 1.x~5.0 每一版里都是 RSVD, 真主板不接、真卡也不接,是两个方向都安全的仅有选择。

定稿针位表(唯一事实来源是 .claude/r2/b4_edge.py 的 PIN_NET,改这里必须同步改它):

我们的信号 借用的 PCIe 针 为什么选它
+12V B1 / B2 / B3 / A2 / A3 真 PCIe 的 +12V 针(五根,不是四根)。误插真显卡时它只会拿到正确的 12V
+3V3 B8 / A9 / A10 ��� PCIe 的 +3.3V 针
+5V(VBUS) A19 / A32(RSVD) ⚠️ 绝不能借 B10 的 +3.3Vaux,也不能借 B3(是 +12V)、B12(是 CLKREQ#)、B30(是 PWRBRK#)
SDA / SCL B6 / B5(SMDAT / SMCLK) 语义完全相符,本来就是 I²C
INT# B11(WAKE#) 开漏 wire-OR,语义相符
PRSNT# A1 / B31(PRSNT1# / PRSNT2#) 用 x4 段末端那根 B31(不是 x1 的 B17),判的是全长在位;B17 在本板当地用
D+ / D− B14 / B15(PETp0 / PETn0) 两侧 B13 / B16 就是 GND,天然的夹地差分位
EFUSE_EN A11(PERST#) 真 PCIe 的复位针,语义上同样是「主机直接拉的那根线」
VDAC A16(PERp0) 上下两针 A15 / A17 都是地,全连接器夹得最干净的位置(模拟量要这个)
GND 所有 GND 针 + 全部 lane 针 + B12 / B17 / B30 回流。这三根在主板侧要么开漏、要么 AC 耦合,接地两个方向都无害
悬空 A5~A8(JTAG)/ B9(TRST#)/ B10(+3.3Vaux) B10 是必须悬空的那一根:真卡插进底板槽时,底板若在这针上给 5 V 会直接打穿它的 aux 域

底板不是 PCI-E,只是借用机械、电源针位与语义。 插槽旁必须丝印警告:NOT PCIe — PhoneRail blade only。

5.3 金手指工艺 ✅ T3 已定(2026-09-08)

项 要求
板厚 1.6 mm(PCIe 卡标准,插槽夹持力按这个设计)
表面处理 板面 ENIG;金手指区必须是「电镀硬金」,⛔ 不是 ENIG
斜边 ✅ 做,30°(下单页勾「金手指」+「斜边」)。⚠ 不是 20° —— 见 §22.2
插拔寿命 插槽标称 ≥ 50 次;本项目 D7 不带电插拔,实际只有装配 + 偶尔维修

⚠️ 表面处理这一条原来写错了:ENIG 的金层只有 0.050.1 µm 且底下是镍磷层, 是为焊接设计的,不是为插拔设计的 —— 金手指反复摩擦会很快磨穿见镍。 真正的金手指工艺是电镀硬金(11.5 µm 金 + 钴/镍硬化), 嘉立创下单页的「金手指」选项本身就是这个,勾了就有,不用另外说明。 原文「金手指区不能用喷锡」是对的,但结论要从「用 ENIG」改成「用硬金」。

5.4 退路(T3 已定为「做」,这条现在只是备案)

金手指工艺费贵到不划算,就退回 1.27 mm 2×20 排针 / 排母: 针数够(40 针),USB 2.0 HS 也能过(PC 前面板就是 2.54 排针过 USB 2.0), 代价是失去插槽的机械保持——刀片要另加固定件,且不能盲插。

⚠️ 2026-09-08 起这条退路的代价变小了:底板的插槽已经换成贴片立式的 PCIE-64P11L(§20.3),保持力本来就只靠焊盘剪切,M4 无论如何都要给刀片加固定件。 ⇒ 触发这条退路的唯一理由只剩「金手指报价离谱」,机械那一半的代价已经付过了。


6. 底板设计(2 层)

⛔ 2026-09-10 起本节(2 层版)作废,按 D15 重做:4 层、≤ 98 × 98、插槽面只放插槽、其余全在背面。 §6.2 三条硬约束只剩第 2 条(U32 居中)保留 —— 而且更好做:插槽底下的背面现在是空的。 §6.5 / §6.6 的分区与刀片投影限高不再适用(背面没有刀片)。§6.3 D± 与 §6.4 12V 断面的数仍然有效。 新版几何随 M5 落地补在本节末尾;2 层版的脚本与缓存存档在 .claude/r2/archive_base2L/。 2026-09-10 用户拍板:Hub(U32)在中间槽正南的走廊 2,mux/DAC 在正北的走廊 3(与分区草图对调)。 理由:U32 翻到背面后只能 rot 270(下行口朝北、USB1 在西),南去的几对要绕 U32 东侧; Hub 在走廊 3 要绕三对、D± 最远 ≈ 80 mm,走廊 2 只绕两对、最远 ≈ 58 mm(估算 45/23/3/40/58)。 M5 验收的「D± ≤ 45 mm」只有 U32 进中间槽正下方的过孔带才做得到,没选;两层版是 ~70 mm。

6.1 叠层

层 用途 铜厚
L1 信号 + 12V 宽铜 + 所有元件 1 oz
L2 完整地平面 1 oz

为什么只能 1 oz:U32 是 0.5 mm 间距 QFN-64,2 oz 下最小线宽 0.2 mm 出不来(同 R1 §10.1)。 ⇒ 10 A 的输入链靠铺宽解决,不靠加厚——这正是 PCB1 已经在做的事 (实测断面 4.5~12.75 mm),pcb1_pour.py 那套断面校核线可以整套搬过来复用。

6.2 三条硬约束(违反任何一条,2 层就不成立)

这三条是 D5 成立的前提,不是收尾检查项。布线时它们优先于一切其它考虑。

  1. L2 必须是完整地平面,D± 走廊下方一刀不许割。 双面板上每一次跳线都是在地平面上开口 ⇒ 所有跳线排到 D± 走廊之外。
  2. U32 必须坐在 5 个槽的几何正中,六对 D± 从它径向直接扎出去,不许绕。 摆位一旦妥协,方案就废了。
  3. 每个插槽的 D± 必须分配在「靠 Hub 那一端」的针位上。 (x4 槽体 39 mm,两端差 39 mm,占最远那对线长的一半。)

6.3 D± 的账

R1 载板上 Hub 到最远那台是 92 mm(R1 §25.2 就是为这个把 Hub 压在通道正中的)。 R2 里 Hub 坐在槽阵正中、D± 又排在近端针位:

值
U32 位置 (55, 38)
槽阵 5 槽,中心 x = 14.4 / 34.7 / 55.0 / 75.3 / 95.6,槽体 y 45~84
最远一对(槽 1 / 槽 5) √(40.6² + 8²) ≈ 41 mm(D± 排在槽的 y=45 近端)
最近一对(槽 3) ≈ 8 mm
第 6 对(→ ESP32,D13) ESP32 在 y 84~114,穿过槽阵,≈ 55 mm

USB 2.0 不要求 pair-to-pair 等长,只管 intra-pair skew(目标 ≤ 1 mm), 所以 8 mm 与 41 mm 并存没问题。

阻抗估算(1.6 mm 双面板 1 oz 微带,εr ≈ 4.3):

线宽 / 间距 估算 Zdiff
0.4 / 0.2 ~137 Ω ❌
1.0 / 0.2 ~101 Ω
1.2 / 0.2 ~94 Ω ✅

这种几何下耦合是「对内强、对地弱」,差分阻抗比「两条独立 50 Ω」低得多, 不需要 2.9 mm 那种线宽。一对占 2.6 mm,六对连间隔约 22 mm 板宽——放得下。

⚠️ 这几个数是公式估算。下单前用嘉立创的阻抗计算器/工艺表核一遍; 真要控阻抗还得下单时勾「阻抗控制」(2 层可做,加钱,可能锁板厚)。 首板可以不勾,按估算画、把线长压在 45 mm 内。

6.4 12V 分配与断面要求

段 电流 1 oz 外层需要的净铜宽(IPC-2221,ΔT 20 ℃)
J1 → F1 → Q1 → 母线 9.0 A(5×1.5 峰值 + U30 1.3 + U19 0.2) ≥ 8 mm
母线 → 单槽 1.5 A ≥ 1.2 mm(给 1.5 mm)
单槽 12V 针 0.375 A / 针 × 4 —

校核办法沿用 R1:在铺铜上画断面线、按实测铜量宽度(pcb1_pour.py 的 CUTS 机制)。

6.5 摆位分区

坐标约定:x = 槽距方向(5 槽并排),y = 槽长方向 / 板深。 刀片竖立在槽里,刀片的 100 mm 宽度沿 y 铺开,所以刀片在底板上的投影是 y 14.5 ~ 114.5 那一条 100 mm 宽的带(下称刀片投影)。

y 125 ┬──────────────────────────────────────────────┐
      │  风墙:J26~J30 风扇座(投影外,可高)           │
y 114 ┼──────────────────────────────────────────────┤ ← 刀片投影上沿
      │  U20 ESP32-S3 · J33 应急口 · U35 mux          │
      │  U19 3V3 · U30 5V · U29 泄放(全部 ≤8 mm)     │
 y 84 ┼──────────────────────────────────────────────┤
      │   ▮槽1    ▮槽2    ▮槽3    ▮槽4    ▮槽5        │  ← 槽体 y 45~84
 y 45 ┤   14.4    34.7    55.0    75.3    95.6        │
      ╞═════════ D± 走廊(L2 禁止开口)═══════════════╡
      │  Hub 区:U32(55,38) · Y1 · U31 · J23 · 退路座  │
 y 20 ┼──────────────────────────────────────────────┤
y 14.5┼──────────────────────────────────────────────┤ ← 刀片投影下沿
      │  输入链:J1 板边 / F1 / D1 / Q1 / C_in 直立     │
      │  U13 + Rs6(投影外,唯一允许放高元件的地方)    │
 y  0 ┴──────────────────────────────────────────────┘
      x 0                                          110

6.6 ⚠️ 刀片投影规则(竖插 + 降高度带来的新约束)

插槽把刀片底边抬到底板上方约 11 mm,所以:

区域 元件高度
刀片投影内(y 14.5~114.5) ≤ 8 mm(留 3 mm 余量)
投影外(y < 14.5 和 y > 114.5) 不限

⇒ 两颗 470 µF 直立电解(~20 mm)、DC-005 座、F1 全部只能放在 y < 14.5 那一条, 这也正好让 DC 座落在板边。布局时先钉死这一条,再排别的——它是硬碰撞,不是净距问题。

矮件(Hub、ESP32 模组、mux、辅助 Buck 的电感 3 mm、USB-C 座 ~4 mm)随便压在投影里。

⚠️ ESP32 那一对 D±(D13)要从 y 84 往下穿过槽阵扎到 U32,会穿过整个槽区。 它和五对槽 D± 一样受 §6.2 第 1 条约束:其下方的 L2 不许开口。


7. 刀片设计(4 层)

7.1 叠层

沿用 R1 §10.1 的四层配置:外层 1 oz / 内层 0.5 oz。

层 用途
L1 功率器件 + 信号(D± 从金手指到 BM24 走这一层,以 L2 为参考面)
L2 完整地平面(不许割断)
L3 12V 灌铜 + 本路 VO 灌铜
L4 控制信号

走线方向规则沿用 R1 §10.1b:顶层水平、底层纵向。

7.2 关键回路

R1 §10.2 的四条关键回路一条不变,而且因为刀片小、只有一路,比 R1 好做得多:

  • Buck 输入回路(Cin ↔ U1)面积最小化
  • SW 节点面积最小化
  • FB 分压走线远离 SW,Rinj 的 RC 放在 DAC 侧(R1 §4.5 末条)
  • Rs 取样用 Kelvin 接法(R1 §19.2),INA226 的取样脚必须落在 Rs 的取样焊盘上,不许就近扎孔

7.2b 刀片位号规则(M2a 定稿)

刀片是独立的一块板,位号只要在刀片内唯一,不再用 R1「通道号 = 位号百位」那一套:

位号 器件 页
U1 TPS54622 同步 Buck B1-POWER
U2 TPS25940A eFuse B1-POWER
U3 INA226(跟着 Rs1 走,取样脚不跨页) B1-POWER
U4 PCA9555 B2-CTRL
U5 TPS22918 VBUS 开关 B3-PHONE
U6 TS5A3157 EDL 模拟开关 B3-PHONE
DAC63204 D11b 起在底板(U6/U7,底板位号) B2-CTRL A3-CTRL
R1~R19 C1~C14 Q1 Q2 L1 Rs1 F1 D1 功率级(位号 = R1 去掉百位) B1-POWER
R40~R47 C40 Q3~Q5 控制与侧键(M2b 实际用到的) B2-CTRL
J1 金手指 / J2 D± 退路座 / J3 EDL / J4 BM24 / J5 电池排线 4 焊盘 / K1~K3 侧键触点 / K4 侧键公共地 B3/B4
U7 USBLC6-2SC6(D± ESD) B3B-USB
R60~R65 C60~C69 手机侧(阻尼组 / TEMP / ID / Rp / 口温 / 开关外围) B3 / B3B

7.3 刀片上的 I²C 设备(五片完全相同)

器件 地址 用途
U3 INA226 0x40(五片同址) 本路输出 V / I。取样脚落在 Rs1 的 Kelvin 焊盘上,既不跨页也不跨板
U4 PCA9555 0x20(五片同址) 见下表
DAC63204 — D11b 起在底板,只有 VDAC 这一路模拟量跨金手指进刀片

五片刀片地址全部相同,靠底板 TCA9548A 分通道区分(D8)。

PCA9555 位分配:

位 方向 网络 复位态
P0.0 OUT KEY_PWR → Q_key 栅极 高阻 + 100 k 下拉 = 按键松开 ✅
P0.1 OUT KEY_VUP 同上
P0.2 OUT KEY_VDN 同上
P0.3 OUT EDL_EN 同上
P0.4 OUT VBUS_EN → TPS22918 ON 高阻 + R701 100 k 下拉 = VBUS 断开 ✅
P0.5 — 备用 ⚠ EFUSE_EN 不在这里,见下面的框
P0.6~7 — 备用
P1.0 IN EFUSE_FLT#
P1.1 IN BUCK_PG
P1.2 IN INA_ALERT(INA226 的 ALERT 接回本刀片) 不占跨板针
P1.3 IN EFUSE_PG —— 原表漏了它,而 B1-POWER 确实吐出这个端口(§14.2)
P1.4~7 — 备用

⚠️⚠️ EFUSE_EN 不能挂在 PCA9555 上(2026-09-08 画 B1-POWER 时改的)。 R1 §16.4 把它定为「ESP32 GPIO 直连,安全关键」,因为它是 §5 第三层 (软件监控)唯一的执行手段。挂到 I²C 扩展器后面之后, 「mux 失联 ⇒ 全部断电」这条判据(§8.1 的 A10)自己就执行不了了 —— 要断电,得先能通信。 ⇒ EFUSE_EN 单独占一根金手指针(§5.1 的针数预算已含), 刀片上仍保留 R14 100 k 下拉,ESP32 复位期间输出关断。 代价是每槽多一根针(x4 有 64 针,用不完),换回 R1 已经定稿的安全链。

D9 的安全收益:PCA9555 上电为高阻输入,配栅极 100 k 下拉 ⇒ 按键必然松开、VBUS 必然断开。 R1 那套 74HC595 要靠 KEY_OE# 上拉(R609)才能做到同一件事,少一颗电阻就失效。

7.4 保护链在 R2 的落点(R1 §5 三层不变,多一层隔离)

层 位置 内容
第一层 拓扑限幅 刀片 R1 §4.4,硬件上限 4.01 V,软件越不过去
第二层 eFuse 独立 OVP 刀片 R1 §5,OVP 4.45 V / 限流 4.5 A
第三层 软件监控 底板 ESP32 经 mux 读各刀片 INA226
(新)第零层 故障隔离 刀片 12V 入口 2 A 保险 + TVS(D10):一片刀片短路不拖垮另外四台

8. 控制、USB 拓扑与固件影响

8.1 固件改动

任务包 影响
A2 HAL 无
A3 INA226 驱动 无(地址表从「六片不同地址」变成「五片同地址 + 一片输入侧」)
A4 DAC63204 驱动 无(D11 的全部意义)。D11b 之后连地址表都不用改:仍是 R1 的 U6 0x4A / U7 0x4B 两颗、通道映射表原样,而且 DAC 挂主干总线,写 DAC 不用进 mux 事务
A5 74HC595 驱动 ⛔ 作废(D9 改用 PCA9555)。代码保留但不再挂进链路
A6 PCA9555 驱动 复用,从 1 个实例变 5 个实例;「接地脚永远是输入」那条硬约束照旧
A7 五路配置表 加一个 mux_ch 字段;表驱动结构不变,这是唯一的结构性改动
A8 任务骨架 / 两把锁 I²C 事务必须「选通道 → 操作」原子化:mux 通道选择和随后的读写要在同一把 I²C 锁里,否则两个任务会互相踩通道
A9 执行器状态机 无(按键从 595 位改成 PCA9555 位,接口层的事)
A10 安全巡检 加两条:mux 失联 ⇒ 全部断电(单点);PRSNT# 为空的槽不许上电
A11 事件日志 加事件类型(往 log_ev_t 末尾加,见 firmware/HANDOFF.md 的约定)
新增 TCA9548A 驱动(写一个字节选通道)+ PRSNT# 在位检测读入

8.2 ⭐ D13:一根线连电脑

做法:ESP32-S3 的原生 USB(GPIO19 = D−、GPIO20 = D+)接到 U32 的第 6 个下行口, J23 上游 USB-C 插电脑。于是一根线上同时有:

  • 5 台手机的 adb / fastboot(经各自的槽 → 刀片 → BM24 尾插)
  • ESP32 的 烧录 + 控制台(USB-Serial-JTAG,ESP-IDF 原生支持从这个口烧)
  • 将来上位机的 CDC-ACM 控制通道

为什么现在能做、R1 时不能:U32 是 7 口 Hub,R1 §21.5 只分配了 5 口给手机、 明说有 2 个口空着。R1 里 ESP32 的调试口 J22 是独立的第二根线, 是因为当时 Hub 在载板、ESP32 在下板,两者之间没有可用的差分通路。R2 里两者同板。

代价与注意事项

# 事项 处理
1 ESP32-S3 只有一个原生 USB PHY,接了 Hub 就不能再接 J22 删掉 J22(省一个 USB-C + 2 颗 CC 电阻)
2 ⚠️ HUB_RST 由 ESP32 驱动,而 ESP32 的控制台在 Hub 后面 —— 固件一旦误复位 Hub,等于自断控制台,而且下一次烧录也进不来 ① 保留 J33 5P 应急口(GND/TXD0/RXD0/EN/IO0),UART 永远能进;② HUB_RST 在固件里只在启动自检时脉冲一次,运行期不许再动;③ 该脚外部上拉,ESP32 复位期间 Hub 保持工作
3 板子是自供电 Hub(12V→5V→3V3),不是总线供电 上游只取 D±,VBUS 只用于「电脑在不在」检测(沿用 R1 的 UP_VBUS_DET)
4 上游 480 Mbps 由 6 个设备共享 挂机农场的 adb 流量很小;大文件传输会互相分带宽,可接受
5 底板多一对 D± 要走(§6.3 第 6 对,≈25 mm) 同样受 §6.2 第 1 条约束
6 T6:CFG_SEL=110 下 7 个口是否默认全开 开画前对 datasheet 核一遍;若需要禁用多余口,改的是 strap 而不是电路

净收益:桌面上从「一根 USB 到 Hub 上游 + 一根 USB 到 ESP32 调试口」变成一根线, 且省掉一个 USB-C 座。


9. 从 R1 复用什么

R1 页 / 产物 R2 去向
P2-CHANNEL(单路母版) → 刀片,几乎原样,去掉五路复制
C4-SITEn(顶针 / EDL / P+P− / 电容组 / VBUS 开关) → 刀片,与上面那页合并成一页
P1-INPUT / P1B-5V → 底板,原样
P6-FAN-EDL → 底板,风扇部分原样;EDL 部分挪去刀片
P3-CONTROL / P3B-EXPAND → 底板,删掉挪到刀片上的部分,加 TCA9548A;J22 删除、加 J33(D13)
P4B-HUB(USB2517I + strap + Y1) → 底板,几乎原样;只多接一个下行口给 ESP32(D13)
P4-USB / P5-HARNESS 拆进刀片
P5-BTB(80 针排针表) ⛔ 作废,换成金手指表(§5.2)
自建封装 BM24-50DS / fp_body / 顶针封装 全部复用
pcb1_pour.py 的断面校核机制 复用到底板 12V 链
pcb1_netlist.py / verify_sch.py / xpage.py 复用
固件 A1~A11 见 §8.1

原理图工作量估计:约六成是搬运,新画的只有金手指符号、5 个插槽、TCA9548A、刀片拼页。


10. 风险登记

# 风险 缓解
R-1 底板 D± 不控阻抗,五片手机枚举不稳 长度压 ≤45 mm;L2 走廊不割;D12 的 1.25 mm 座退路(割断改飞线,¥2)
R-2 金手指工艺费吃掉板费 §5.4 退回 1.27 mm 排针(失去盲插与机械保持)
R-3 TCA9548A 是单点:它挂了五路全瞎 复位脚接 ESP32;A10 加判据「mux 失联 ⇒ 全部断电」
R-4 槽距不够(T1 实测 h_phone > 6.3 mm) 槽距放 22 mm,底板 +8 mm 宽
R-5 C801 高度与竖插冲突(T2) 只放没有手机压着的空白列 / 服务带;或改低高度聚合物电容
R-6 竖插外壳要重画,R1 的平铺外壳全废 归入 M7
R-7 R1 §24.3 BM24 镜像位仍无实证 老账;好消息是现在只影响 80 cm² 的一块板
R-8 手机主板 7 孔 ±0.5 mm 公差搬到刀片 孔做 Ø2.5 沉孔或长圆槽;以 H2/H5 做主基准(R1 §22.3a)
R-9 误插真 PCI-E 卡 / 刀片误插进 PC §5.2 电源针位对齐真 PCIe 语义 + 插槽旁丝印警告
R-10 刀片 30.5 mm 悬臂晃动 上端 3D 打印导轨;或 A1 换 x8 / x16 槽体(§3.1)
R-12 功率级与手机主板共面、只隔 2 mm(降高度 + 收窄到 98 的代价):480 kHz 开关噪声离手机天线更近 SW/电感/Cin 排在功率列最外边(x 88~98);L2 完整地平面铺到板边;必要时功率列加屏蔽罩
R-11 D13 的自锁:固件复位 Hub = 自断控制台与烧录口 J33 UART 应急口 + HUB_RST 只在自检脉冲一次 + 外部上拉(§8.2 第 2 条)

11. 执行计划

里程碑 内容 验收判据
M0 核 T1(主板厚度)/ T2(C801 高度)/ T3(金手指报价)/ T4(CEM 引脚表)/ T6(Hub 口使能) 五项都有数,槽距与针位表定稿
M1 新建 EasyEDA 工程 PhoneRail-R2,建两块板的文档骨架 ✅ 已完成 2026-09-08,见 §13
M2 ✅ 刀片原理图 4 5 页全部画完(2026-09-08) verify_sch --nets 六项全过;port_audit 146 个可疑 0;xpage 漏接 0
M2a ✅ B1-POWER(2026-09-08) 42 件 / 218 段 / 31 旗 / 13 端口,六项全过、可疑 0,见 §14
M2b ✅ B2-CTRL(2026-09-08) 13 件 / 55 段 / 13 旗 / 20 端口,六项全过、可疑 0,见 §15
M2c ✅ B3-PHONE + B3B-USB(2026-09-08,拆成两页) 17 件 + 9 件,六项全过、可疑 0,见 §16
M2d ✅ B4-EDGE(2026-09-08) 2 件 / 85 段 / 7 旗 / 15 端口,六项全过、可疑 0、交叉 0,见 §17。M2 至此收口
M3 底板原理图 6 页(P1 + P1B + P3 + P4B + P6 + mux + 5 槽 + D13 的第 6 个 Hub 口) 同上
M3a ✅ A1-INPUT(2026-09-08) 25 件 / 101 段 / 18 旗 / 10 端口,六项全过、可疑 0、交叉 0,见 §18
M3b ✅ A2-AUX(2026-09-08) 17 件 / 56 段 / 15 旗 / 8 端口,六项全过、可疑 0,见 §19
M4 刀片 PCB(4 层,98×76) 板框 ≤98×98(D14);关键回路按 §7.2 复核;功率列按「离手机越远越吵」排;DRC 0
M5 底板 PCB(2 层,110×125 ⇒ 4 层,≤98×98,器件全在背面,D15) 12V 断面 ≥ §6.4;六对 D± ≤45 mm、参考层 L3 无开口;插槽面只有插槽
M6 先只打刀片,用实验室电源直接喂 12V 验证单路 R1 §11 的上电顺序照跑;不用等底板
M7 打底板 + 外壳 + 联调 R1 §14 实测记录表;验收一条:只插一根 USB-C,电脑同时看到 5 台 adb 设备 + ESP32 串口

M6 是这个架构白送的:刀片只需要 12V 就能独立验证, 可以在底板还没画完的时候先打样、先调通、先把 R1 §13.5 / §24.3 那些手机侧的老账清掉。 一次刀片打样的钱远小于一次整板打样。


12. 与 R1 的关系

  • R1 的工程、原理图、PCB、文档全部保留,不删不改。
  • R1 文档 五路直供电源板设计.md 仍是所有未变更计算的事实来源。
  • R2 若最终落地,R1 转为「历史方案」,但在那之前两条线互不干扰。
  • 固件仓库共用一套,按 §8.1 的表做增量改动;A5 那一包会被架空,代码保留。

13. M1 落地记录(2026-09-08)

工程已建好并逐项回读验证。R1 工程(1e5745f4caff4b15a921694d2fd912e4 五路手机直供电源板)一个字节没动。

13.1 UUID(唯一事实来源是 .claude/r2/r2-uuids.json)

名称 UUID
工程 PhoneRail-R2 05a65c22f14846b8b95360ef8d3c1e2e
板 1 BLADE(刀片 98×76 四层) —
├ 原理图 r2-blade ec5f3ca5108b618d
├ PCB BLADE-PCB 3b9c4e39c8d164db
├ 页 B1-POWER 5338949298dcff35
├ 页 B2-CTRL 4f458d678c50f7a4
├ 页 B3-PHONE cf32a688430fc2d1
├ 页 B3B-USB(2026-09-08 新增) 4ce5bfe35e90e560
└ 页 B4-EDGE c8f10dbd1286853b
板 2 BASE(底板 110×125 双面) —
├ 原理图 r2-base 372e2399adb7a6db
├ PCB BASE-PCB 7b9524b6aaf6f235
├ 页 A1-INPUT 9d86e72abb1a6571
├ 页 A2-AUX 3361444ab04474c5
├ 页 A3-CTRL 38327f806bc13133
├ 页 A4-HUB 09d583ff95cd35d9
├ 页 A5-SLOTS 2c73c5bf77f34053
└ 页 A6-FAN 68c9ffaa578572d3

各页内容分工见 r2-uuids.json 的 page_contents 字段。 回读工程树:/c/Python314/python .claude/eda.py .claude/r2/tree.js

13.2 建工程时踩到的三条 API 经验

  1. dmt_Project.createProject() 传 teamUuid + description 会静默失败: 返回 undefined,工程列表里查无此项,不抛异常。 只传 friendlyName(可再带 projectName)就成功。 ⇒ 判据是「回列表里查得到」,不是「调用没报错」。
  2. dmt_Schematic.createSchematic(boardName) / dmt_Pcb.createPcb(boardName) 建不出新板: 传一个不存在的板名时两者都返回 undefined、什么也不建。 正解是 先 dmt_Board.createBoard()(无参)——它会连原理图带 PCB 一起建好、 自动命名 Board1,再用 modifyBoardName / modifySchematicName / modifyPcbName 改名。
  3. modifySchematicName() 会把名字转成小写(R2-BLADE → r2-blade),板名和 PCB 名不会。 不影响使用,但按名字查原理图时要注意大小写。

⚠️ API 没有删除工程的接口。试参数时误建的空工程 PhoneRail-R2b (ab94ce71a50b48348f845017fb57d557)要在工程树里右键手动删除。

13.3 下一步(M2 之前)

M0 的五项实测/核对(§0.3 的 T1~T6)没有做完,其中 T1(主板含屏蔽罩厚度) 直接决定槽距 20.32 够不够,**T4(PCIe CEM 引脚表)**决定 B4-EDGE 那一页能不能开画。 建议先补这两项,B1-POWER / A1-INPUT 这些不依赖它们的页可以并行开工。


14. M2a 落地记录:B1-POWER(2026-09-08)

14.1 做法:搬 R1 的版图,不重排

P2-CHANNEL 在 R1 上已经过六项几何验证 + 人眼确认,是全工程最成熟的一页。 .claude/r2/dump_page.py 把它整页读回(40 元件 / 213 段导线 / 29 旗 / 12 端口, 含每个引脚的坐标),.claude/r2/b1_power.py 做三件事再重放:

内容
位号映射 C1xx→Cx / R1xx→Rx / Rs101→Rs1 / L101→L1 / Q101→Q1 / Q102→Q2;
芯片按刀片编号:U1 Buck、U8→U3 INA226、U14→U2 eFuse
网络去后缀 VO1→VO、VO1_P→VO_P、VDAC1→VDAC、EFUSE_*1→EFUSE_*;
+12V→+12V_F(Buck 吃的是保险丝之后那一段)
新增 12V 入口保护:+12V(金手指) → F1 → +12V_F,D1 TVS 钳到地(D10)

结果:42 件 / 218 段导线 / 31 旗 / 13 端口 / 8 条文字。 verify_sch --nets 六项全过(悬空 0 / 单引脚网络 0 / 无名旗端口 0 / 一网多名 0), port_audit 44 个旗端口可疑 0。

14.2 跨页网络(B2 / B3 / B4 要对上)

网络 方向 对端
+12V 入 B4-EDGE 金手指
+3V3 / GND — B4-EDGE
VDAC 入 B2-CTRL 的 DAC63204 CH0
EFUSE_EN 入 B4-EDGE(直连底板 ESP32,不经 PCA9555)
EFUSE_FLT / EFUSE_PG / BUCK_PG / INA_ALERT 出 B2-CTRL 的 PCA9555 输入
SDA / SCL 双向 B4-EDGE
VO_P 出 B3-PHONE(P+/P− 焊盘 + C801 阻尼组)

+12V_F 是刀片内部轨,只在本页出现(电源旗 10 个引脚),不跨页。

14.3 ⚠️ 跨工程搬版图踩到的三条(已并入 skill §3c / §3e / §6f)

  1. create() 会把元件坐标吸附到 5 的倍数 —— R1 页上 679/639/654/589 那些位置 放下去会差 1~2 个单位,「按坐标精确认领位号」42 件只认到 28 件。 ⇒ 就近认领(容差 3)+ 认完 setState_X/Y 拉回精确坐标。
  2. 42 件里有 27 件的 create(rot=270) 语义与 R1 相反。 25 件是两脚对称件(只有编号互换,无害),但 C10 / C14 两颗 33nF 是 +20/−15 的 不对称跨距,翻过来坐标真的差 5,照 R1 的坐标画线会断在这两颗上。 ⇒ 脚本里做了「对不上就翻 180 再回读」的自动修正循环。 ⚠️ 第一轮看起来没生效:create(270) 与 setState_Rotation(270) 差 180°, 要翻两次才落位(日志里同一批 27 件连打两行「翻转…重试」是正常的)。
  3. rot=180 的旗/端口读回来带浮点尾巴(789.9999999999999), 不取整的话「坐标必须是 5 的倍数」「必须落在导线端点」两道自检全部误报。

14.4 还欠的

  • T7:✅ 已结(2026-09-08),F1 = F1206SB2000V063TM(C310998)。见 §20.7。
  • port_audit.py 的页面清单是 R1 硬编码的,在 R2 工程里它会对着当前页跑 11 遍 (数字仍然可信,但要写一个 R2 版)。
  • 人眼截图确认:.claude/r2/B1-POWER.png。

15. M2b 落地记录:B2-CTRL(2026-09-08)

脚本 .claude/r2/b2_ctrl.py(幂等,--push 清页重画)。 13 件 / 55 段导线 / 13 旗 / 20 端口 / 9 条文字, verify_sch --nets 六项全过(悬空 0 / 单引脚 0 / 无名旗端口 0 / 一网多名 0), port_audit --r2 BLADE 44+33 个旗端口可疑 0,本地交叉点 0。 截图 .claude/r2/B2-CTRL.png。

15.1 页面内容

位号 器件 说明
U4 PCA9555PW,0x20(A0/A1/A2 接地) P0.0P0.2 三个侧键 / P0.3 EDL_EN / P0.4 VBUS_EN 输出;P1.0P1.3 收 EFUSE_FLT / BUCK_PG / INA_ALERT / EFUSE_PG
Q3~Q5 + R42~R47 2N7002 + 1k 串阻 + 100k 下拉 侧键低边 MOS,R1 §13.3 原样;漏极出 KPAD_PWR/VUP/VDN 去 B3-PHONE
R40/R41 4.7k 本槽 mux 分支的 I²C 上拉(INA226 与 PCA9555 共用)
C40 100nF PCA9555 去耦

15.2 ⚠️ D11b:DAC 挪到底板之后这一页少了什么

原方案里这一页还有 U4 DAC63204 + C40/C41/C42 + R42/R43(VREF 上拉、GPIO 下拉)。 D11b 之后全部删掉,位号顺移:PCA9555 U5 → U4,B3-PHONE 的 TPS22918 U6 → U5、TS5A3157 U7 → U6(§7.2b 已同步)。

B1-POWER 一个字节没改 —— 它的 Netport-IN VDAC 原本就是「从别处进来」, 只是对端从 B2-CTRL 变成 B4-EDGE 的金手指。 §4.5 要求的 R8 1k + C12 10nF 低通本来就在 Rinj 的 DAC 侧、在刀片上, 正好把长线拾到的噪声滤掉,位置不用动。

15.3 三样故意不放在这一页的东西(别在这里找)

东西 放哪 为什么
EDL_EN / VBUS_EN 的 100k 下拉 B3-PHONE 贴各自的负载(R1 的 R741 / R701 就在那边)
INT# 的上拉 底板 A3-CTRL 五槽 wire-OR 共用一颗 10k;每片刀片各挂一颗会并成 2k
EFUSE_EN 不经 PCA9555 安全链第三层唯一的执行手段,走金手指专用针直连底板 ESP32(§7.3 的框)

15.4 给 B3 / B4 / A3 留的接口

网络 方向 对端
KPAD_PWR / KPAD_VUP / KPAD_VDN 出 B3-PHONE 的三个中框式侧键焊盘(R1 §22.3e)
EDL_EN / VBUS_EN 出 B3-PHONE(各自带 100k 下拉)
EFUSE_FLT / EFUSE_PG / BUCK_PG / INA_ALERT 入 B1-POWER(已对上)
SDA / SCL 双向 B4-EDGE 金手指(本槽 mux 分支)
INT# 出 B4-EDGE 金手指 → 底板 wire-OR
VDAC — 不经本页:B4-EDGE 金手指直接进 B1-POWER

15.5 顺带做掉的两件小事

  1. port_audit.py 加了 --r2 BLADE / --r2 BASE(页表读 .claude/r2/r2-uuids.json), 取代 §14.4 里「对着当前页跑 11 遍」那个 R1 硬编码清单。
  2. b2_ctrl.py 里加了一条文字越界自检(按 skill §12 的宽度经验值算右边界, y < 192 的行按标题栏边界 455 判)。这一类问题几何验证一条都抓不到 —— 上一版最后一行注释就压在了标题栏上,只有截图看得见。

16. M2c 落地记录:B3-PHONE + B3B-USB(2026-09-08)

16.1 ⚠️ 为什么拆成两页

R1 把同样的内容铺在四页上(C4-SITE1 电池/阻尼/顶针/EDL、C5-J1401A 尾插座、 C5-AUX ESD/Rp/口温、C3-USB VBUS 开关)。硬塞进一张 A4 的结果是 「所有东西都能放下、但没有一根线走得开」—— 试排的时候光是 TS5A3157 那 6 个脚 就绕不出无交叉的走法。⇒ 拆成两页,M2 从 4 页变 5 页。

页 UUID 内容 规模
B3-PHONE cf32a688430fc2d1 J5 电池排线 + C60~C65 阻尼组 + K1~K4 侧键焊盘 + EDL(J3/U6/R63/C69) 17 件 / 56 段 / 16 旗 / 5 端口
B3B-USB 4ce5bfe35e90e560 J4 BM24 尾插座 + U7 ESD + R64 Rp + R65 口温 + U5 TPS22918(C66~C68/R62) 9 件 / 53 段 / 10 旗 / 16 端口

两页都:verify_sch --nets 六项全过、port_audit --r2 BLADE 可疑 0、本地交叉点 0。 截图 .claude/r2/B3-PHONE.png / B3B-USB.png。

dmt_Schematic.createSchematicPage(schUuid, name) 的 name 参数被忽略, 建出来叫 P1,要再 modifySchematicPageName() 改名(页名不会被转小写, 和 §13.2 第 3 条里的 modifySchematicName 不一样)。

16.2 J4 的脚号→网络:照抄 R1,并且每次跑都对账

R1 §24 那一轮把「手机 J1401 的 Hirose 脚号」经原厂排线映射到座子焊盘号, 中间隔着一次实测。所以 b3b_usb.py 的 PIN_NET 不是按 §13.4 推的, 而是从 C5-J1401A 的 J71 原样读回来,并且脚本启动时重新反推一遍源页网表逐脚比对 (18 个脚,对不上直接 SystemExit)。

座子脚 网络 座子脚 网络
51(大触点 G2) VBUS 52(大触点 G1) GND
4 USB_DMJ 6 USB_DPJ
14 USB_THERM 22 CC1
1,2,8,12,16,19,23,24,29,37,41,47 GND 其余 34 个 不接(NC 清单)

16.3 ⚠️ 又两处「rot 语义与 R1 相反」(skill §6c 的新样本)

器件 R1 那一页 本轮实测 后果
C60 2200µF 电解 C4-SITE1 rot270 → pin1(+) 在上 rot270 → pin1 在下 第一次推下去极性接反:网表里是 C60.2 挂 VO_P。⚠ 几何验证、DRC、port_audit 四道全过,只有网表明细看得出来
U5 TPS22918 C3-USB rot270 → 1/2/3 在上排 rot270 → 1/2/3 在下排 引脚断言直接拦下;注意这是镜像不是 180°,所以「翻 180 重试」那个循环修不了,会在两个状态之间来回跳

⇒ 两条规矩:

  1. 极性件不能只比坐标集合,必须按脚号断言(b3_phone.py 里 C60 单独列出来)。
  2. 引脚断言失败时先看失败的是不是镜像:是镜像就去实测三个角度(create 出来读回), 把实测表写进脚本,别指望自动翻转循环。

16.4 三样故意分开放的东西

东西 放在 为什么
EDL_EN 的 100k 下拉 R63 B3-PHONE(贴 U6.IN) PCA9555 复位时高阻,全靠它保证模拟开关断开
VBUS_EN 的 100k 下拉 R62 B3B-USB(贴 U5.ON) datasheet 明令 ON 脚不得悬空;同上,保证 VBUS 默认断开
R64 56k Rp B3B-USB R1 里这颗藏在「USB-A 转 C 线的 C 头」里(§23.2),本方案没有那根线,必须自己放,否则手机判不出「有主机插入」

16.5 跨页对账现状(xpage.py)

刀片 5 页跑完,只剩 4 个单实例网络 → B4-EDGE 画完之后清零(2026-09-08): +5V / INT# / USB_DM / USB_DP / VDAC / EFUSE_EN 都在金手指那一页找到了对端, 真正漏接 0 个。

唯一保留的单实例是 PRSNT#,它进了 xpage.py 的 NAMING_ONLY: 金手指 A1↔B31 是刀片内部短接,对端在底板的 A5-SLOTS(另一份原理图,xpage 看不到); 那个端口纯粹为了给网络起名,不放的话 EasyEDA 会给个 $4N… 默认名,PCB 侧脚本按名字认不出来。


17. M2d 落地记录:B4-EDGE(2026-09-08)

17.1 器件

位号 器件 说明
J1 PCIE-X4-EDGE-64P(个人库自建,.claude/r2/dev_edge.py) 符号借系统库 Samtec PCIE-064-02-F-D-TH 的 64 脚符号 —— 它的脚号正好就是 A1~A32/B1~B32,和 CEM 命名一一对应,不用自己画。⛔ 封装还没建(64 个板边焊盘、1.0 mm 间距、正反两面),等 T3(斜边做不做)定了再画,属 M4
J2 A1251WV-S-4P(C225106) D± 退路座(D12)。1=+5V 2=D+ 3=D− 4/5/6=GND

⚠️ lib_Device.create() 会把系统库符号复制一份进个人库(uuid 变了,不是引用), 所以判据是「有符号 + 放下去 64 个脚对得上」,不是「uuid 等于源符号」。 ⚠️ 器件属性里的 Add into BOM API 改不动(和 MI8-KEY-PAD 同一个坑,见 eda-parts.json): 金手指是板边本身、没有东西可买,要在客户端手工把它改成不进 BOM。

17.2 版图:地母线甩到最左/最右,信号端口排在母线与引脚之间

抄 b3b_usb 的 J4(50 脚 BM24)那一套:地是长横线一路拉到母线,信号是短横线接端口, 两者 y 不同所以永不交叉(本页交叉点 0)。竖线只在同一网络的几针之间用, 且都躲在母线之外的空白区 —— 母线在这种页面上是一堵墙,任何信号都别想横穿过去。

一个例外要记住:右侧地母线在 B8(+3V3)那一行故意断开。 B9/B10 本来就悬空,这一段是全页唯一能让 +3V3 横穿到母线以东挂电源旗的通道, 否则右半边被梳子封死。断开处两段各自带一面地旗(母线断了就得各挂各的旗, 不然那一段会拿到默认网名)。

17.3 ⚠️ ALLOW_SPLIT 放宽了,补了一层更硬的判据

连接器页天然靠同名端口/旗成网,不是靠导线:GND(三段梳子)、+12V(A/B 两排)、 +3V3(A/B 两排)、+5V(A19/A32 两针)、USB_DP/DM(金手指 + 退路座)都是分块的, schcheck 的「漏连」这条检查因此失效。所以 b4_edge.py 多做一件事:

逐脚断言「这根针踩着的那段导线,声明的网络名 == PIN_NET 里写的」(check_pin_nets)。

少接一根、接错一根都会当场报出来。改针位表就是改 PIN_NET,别去改导线。

17.4 D12(D± 退路)在 PCB 上还欠一件事

J2 是直接并联在 USB_DP / USB_DM / +5V / GND 上的(没有 0Ω 跳线,BOM 不加件)。 按 D12「割断改飞线」的原意,M4 画刀片 PCB 时要在金手指到 J2 之间留一段带丝印的割断位, 否则真要走退路时两条路并联 = 一根长残桩。割断位必须在金手指与 J2 分叉点之间, 割完金手指那一侧才是死的、J2 单独喂手机。


18. M3a 落地记录:A1-INPUT(2026-09-08)

做法同 B1-POWER:搬 R1 的版图,不重排。R1 的 P1-INPUT(9a6096762e036e23) 整页读回在 .claude/r2/_p1_live.json,.claude/r2/a1_input.py 按三条改,其余坐标一个字不动。

18.1 三条改动

内容
删 U19 3V3 Buck 那一块(U19 C7 L2 C9 C10 R2 R3 C8,8 件)→ 挪到 A2-AUX,和 U30 5V Buck 放同一页(就是 §11 里 A2-AUX 原本的计划)
加 入口链三个节点的网络名:VIN_RAW(J1→F1)/ VIN_FUSED(F1→Q1 源)/ VIN_SW(Q1 漏→Rs6)
换 文字整套重写(R1 那一页 90 条文字里大量是重复叠印的旧版本,而且好几句已经过时)

拆页拆得干净是有依据的,不是靠眼力:这一页是**「每个引脚各自一小段导线接自己的旗」**的画法, 把 33 个导线组按引脚归属分类之后,没有任何一组同时挂着「要留的件」和「要走的件」 —— 脚本里 keep_grp 那一段就是断言这件事,混了就直接终止。

位号沿用 R1(方案 §4 的 BOM 归属表就是这么写的): J1 F1 Q1 D1 DZ1 R1 C1~C6 U13 Rs6 U29 R4~R6 Q3 R9A~E C11。 R2 / R3 空出来留给 A2-AUX。

18.2 为什么要给入口链三个节点起名

R1 上这三段是无名网络,PCB 侧只能按 $1N223 / $1N227 / $1N236 认。 第三十四轮那次「+12V 从 4 个碎片炸成 23 个」的假象就出在这一带。 底板这一段要过 9 A、要铺铜 + 断面校核(§6.4),按名字认比按 $1N… 认稳得多。 三面都是 Power 旗,天然单实例,已进 xpage.py 的 NAMING_ONLY。

泄放那几个短节点(Q3 漏极、R9A~E 之间的 4 个串联节点)故意不起名: 只走 1.33 A 突发、走线两三毫米,不铺铜也不做断面校核,沿用 R1 的自动命名。

18.3 新加的两条本地检查(a1_input.py,值得往别的页推)

R1 那一页的文字坐标压在元件行上(y 700~790 与 y 190~270)。本页元件位置一个没动, 照抄文字坐标就会盖住 J1/F1/Q1/D1/C2 和 R4/R5/R6/U29 —— 第一版推下去就是这样, 截图才看出来。⇒ 补两条检查:

检查 抓什么 判据
text_clash() 文字压住导线 / 引脚 / 旗端口 宽度按 skill §12 的经验值,高度取 ±0.8 字号
flag_clash() 两面旗/端口的符号叠在一起(crossings() 查不到,旗不是导线) 横向 <20 且 纵向 <10 才算叠;同 x 上下差一格排开是正常写法

flag_clash 当场抓到一个真的:VIN_RAW 旗原本放在 (190,660), 正压在 J1.3 那面 GND 旗 (185,665) 上。

18.4 ⚠️ 顺带修掉一个所有页都在吃的放件缺陷(skill §6f-2)

create(..., rot) 与 setState_Rotation(rot) 差 180°(skill §6b)。 schcheck.place() 原来靠「读回对不上就翻 180 重试」的循环去凑, 本页 14 件 rot 90/270 的件每次都要空转两轮才通过。

⇒ 在 create 之后加一遍「用同一个角度把 rotation 再写一次」,第一次读回就是真的, 一轮直接过。更要紧的是:盲翻循环有可能替一个真放错的件「碰」出一个假的通过 (最多转 4 轮,rot+180/+360/+540 里总有一个可能与错误的期望值凑上)。 已并入 .claude/r2/schcheck.py,五页刀片脚本一起受益。

18.5 三个新器件已进 eda-parts.json

R1 后期加的件没进过缓存:C310990 F1206HC12A0TM(12 A 保险,⚠ 与刀片那颗 2 A 的 F1 同名不同物)、 C2570006 RHC2512FT2R00(2 Ω 2 W 2512,5 颗串联 = 10 Ω/10 W)、 C9900017043 DC-005-5.5*2.5(圆形 DC 座,⚠ 额定 2~5 A 而整机最坏 9.99 A —— 已知风险、用户明确接受)。

18.6 现在 xpage 剩的三个单实例是正常的

SDA / SCL / INA_ALERT 只出现在 A1-INPUT,对端在还没画的 A3-CTRL(U20 + U35 + 两颗 DAC)。 底板六页画完之前,这三条不算漏接。


19. M3b 落地记录:A2-AUX(2026-09-08)

两路辅助电源同页,两块都是从 R1 整块搬过来的,块内坐标一个字不动:

块 来源 平移
3V3(U19 C7~C10 L2 R2 R3,8 件) R1 P1-INPUT,正是 a1_input.py 里 DROP 掉的那 8 件 上移 230
5V(U30 C731~C735 L3 R706 R707,9 件) R1 P1B-5V 整页 下移 110

两块原来的 y 都在 390 附近、x 有 460~795 的重叠段,不平移就是叠在一起。 平移量按两块的实测 bbox 算出来,assert_no_overlap() 每次重算,改坐标改出重叠会当场终止。

19.1 一处改名:BST → BST3V3

R1 的 3V3 块把三个内部节点用端口起了名:SW3V3 / FB3V3 / BST —— 前两个带后缀,第三个没有。 现在两个 Buck 同页,隔壁 5V 那颗的自举节点就在旁边,BST 这个名字是个等着人踩的坑 (下一页随手写个 BST 就静默并网了)。⇒ 加后缀。

5V 那三个内部节点(SW / BST / FB)沿用 R1 不起名:紧凑画法、各自只有两三厘米导线, 不跨页也不铺铜,没有 A1-INPUT 里 VIN_* 那种理由。

19.2 ⚠️ 两处叠字,两处都改了 —— 值被读错就是另一颗器件

R1 两页各有一处标签压在一起,缩略图上看不出来,放大才现形:

处 现象 改法
C733(5V 自举电容) 「100nF」压在「U30」位号上,渲染成 100uF0 C733 连同它自己两根短脚线左移 40
C7(3V3 输入电容) 「2.2uF」被 BST3V3 端口的标签划穿 BST3V3/FB3V3 两个端口右移到 225、夹在中间的 +12V 旗右移到 245

端口的符号 + 标签往锚点左边伸出去约 70 个单位(实测), 这是 flag_clash() 那条「横向 <20」判据覆盖不到的距离 —— 它查的是符号叠符号, 标签压标签得靠放大截图。两处都只动被压的那一颗和它自己的短脚线, U19 / U30 / C731 / C732 / L3 全部原地不动,改动表逐条断言必须命中。

19.3 保留的两处交叉(放大确认过,不改)

crossings() 报了 2 个,都在 5V 块里、都是从 R1 P1B-5V 带过来的:

GND      x  BST(C733.1+U30.6)   @ (565,550)
SW(C733.2+L3.1)  x  +12V        @ (550,480)

放大截图确认:两处都没有节点圆点,EasyEDA 靠圆点表示连接,所以读图不会误解。 其中 SW × +12V 那处离 C731.1 的圆点只有 10 个单位,一开始担心会被误读成短路, 放大之后确认圆点只画在 C732.1 / C731.1 / SW 节点三处,交叉点是干净的。

试过消掉它:U30 的 SW 在左侧 y=600、VIN 在左侧 y=590,而 L3 在下方 —— SW 竖线必然要穿过 VIN 那条进线,除非从 x<460(撞 +12V 进线的竖段) 或 x>565(穿 IC 符号本体)绕,两条都更差。⇒ 保留 R1 的走法。

19.4 本页不含的两件事

  • U31 AMS1117-3.3(Hub 专用 3V3)在 A4-HUB。R1 的 P1B-5V 页上有两行讲它的文字, 是说明不是电路,本页改写成「它不在这页」。
  • +5V 的去处(Hub U32 + 五个槽的 VBUS)在 A4-HUB / A5-SLOTS, 所以现在 xpage 里 +5V 是单实例,正常。

19.5 现在 xpage 剩的四个单实例都有主

网络 对端在
SDA / SCL / INA_ALERT A3-CTRL(U20 + U35 + 两颗 DAC)
+5V A4-HUB(U32/U31)与 A5-SLOTS(五槽 VBUS)

20. M3 收口:底板剩下四页一次做完(2026-09-08)

四页由四个子代理并行设计、主代理串行下发。 之所以不能并行下发:全机只有一个 EasyEDA 客户端,openDocument 是全局状态, 两个脚本同时推会把图元放进别人的页 —— 而且六项几何验证照样全过。

页 元件 导线 旗 端口 verify_sch 交叉
A3-CTRL 30 197 段 27 65 ✅(NC 20) 0
A4-HUB 31 124 段 16 61 ✅(NC 32) 0
A5-SLOTS(槽 1~3) 3 195 段 24 30 ✅(NC 18) 0
A5B-SLOTS(槽 4~5 + 5 个退路座) 7 255 段 26 35 ✅(NC 12) 0
A6-FAN 30 90 段 26 11 ✅ 0

全工程收口:xpage 真正漏接 0、port_audit --r2 BASE 372 个旗/端口可疑 0。

20.1 ⛔ 差点烧进去的一条:PRSNT# 在底板上不能镜像刀片

原来给子代理的契约写的是「A1 和 B31 都叫 PRSNT{n}#」(照抄刀片)。这是错的。

A1(PRSNT1#) B31(PRSNT2#)
真 PCIe 主板 = 本底板 接地 上拉 + 被读
PCIe add-in card = 刀片 ←── 两针短接(b4_edge.py,插上才把 B31 拉到地)──→

底板若也并成一个网,整条回路里一个对地通路都没有 ⇒ ESP32 靠上拉永远读到高, 插不插刀片都报「未插入」,而 DRC / ERC / verify_sch / xpage 四道一道都不响。 落地在 a5_slots.py 的 ROLE_OVERRIDE = {'A1': 'GND'},表头有完整对照。

20.2 ✅ T6 结了,而且结论与方案 §8.2 的问法相反

对 DS00001598C(Microchip 重排版的 SMSC 2517 Rev 2.8)逐条核:

手册位置 默认值 结论
Table 5-2 110 Internal Default Configuration,strap 全部禁用 PRT_DIS_* / NON_REM[1:0] 一个都不采样
Table 7-1 0Ah PDS / 0Bh PDB 00h '0' = available ⇒ 七个口全开
Table 7-1 06h CFG1 bit7 SELF_BUS_PWR = 1 自供电(110 不改它)

⇒ 第 6 口不用改 strap,要做的只是连线。方案 §8.2 表第 6 条「若需禁用多余口,改的是 strap」 问反了方向。口 7 全开但悬空是故意的(§21.6b):strap 停采样后那两颗 10k 会把 D+ 分到 1.98 V, 正压在全速「已插入」的 2.0 V 判据上 → 幽灵口反复枚举;悬空被内部 15k 拉低 = 空闲,无害。

20.3 ✅ T8 已结:换成 PC 标准的便宜插槽 PCIE-64P11L(2026-09-08)

J34~J38 原来挂的是 SAMTEC PCIE-064-02-F-D-TH(C4597619,贵料)。 用户要求换 PC 标准的便宜料 ⇒ 定为 SOFNG(硕方)PCIE-64P11L(C19188869), 「PCIE 64PIN 镀金加强 贴片立式 阻燃材质」。

根因先修掉了:lib_Device.search 不是只能回 38 条 —— 它的完整签名是 search(key, libraryUuid, classification, symbolType, itemsOfPage, page), 带上 itemsOfPage / page 就能翻页(单次请求仍受桥接 30 s 限制,一个关键词最多翻 3 页)。 T7 那颗 2A 慢断保险丝当场就用同样的办法找到了,见 §20.7。

选型时踩到的一个坑:立创描述里写「PCI-E 4X」的,有两颗其实是 x1

器件 LCSC 实测引脚 判定
PCIE-64P11L(SOFNG) C19188869 65(1~64 + 65 屏蔽) ✅ 真 x4
10018783-11110TLF(Amphenol,直插) C598487 36(A1A18 / B1B18) ❌ 其实是 x1
10061913-103TLF(Amphenol,贴片) C4697499 38(A1A18/B1B18 + 2 屏蔽) ❌ 其实是 x1
X3091WR-64B-9TV15(XKB) C30167381 — ❌ 弯插(卡平躺),与 D4「刀片竖插」冲突
91613-110141D / 91619-110141D(友贸) C1509727 / C5210922 — ❌ 夹板式(跨板边),是延长线/转接用的

⇒ 描述不可信,判据是把符号放到空页上读回引脚数。

换料对图纸的影响:只有脚号,版图一个字没动

刀片 PCIE-X4-EDGE-64P(金手指) 底板 PCIE-64P11L(插槽)
脚号 A1A32 / B1B32 1~64(脚名才是 A1~B32)
引脚相对坐标 A 排 x=−35 / B 排 x=+35,y = 155−10(n−1) 完全一致
额外引脚 无 65 = 外壳/屏蔽,在 (0,+175)

换算 A(n) → n、B(n) → 32+n,落在 a5_slots.py 的 slot_pin() + SLOT_REL; PIN_NET / 母线 / 端口位置 / check_pin_nets 全部按 CEM 针名,一行没改。 65 脚接地:不往上引再挂旗(那一带是页眉文字的地盘,A5B 上当场撞了), 而是往左 35 接进 A1 那根地短线的中段 —— 回读确认 J34.1 J34.65 [GND] 同网。

⛔ 换来的一个新风险:贴片立式

原来那颗是直插,新的是 SMD ——保持力只靠焊盘剪切。 五片刀片各驮一块小米8 主板,插拔又是常态动作。 ⇒ M4 布板时必须另加固定件(槽间梳齿 / 上压条 / 刀片顶边卡扣),不能只靠插槽。 已写进 eda-parts.json 的 role、A5-SLOTS 与 A5B-SLOTS 两页的页面文字。

20.4 为什么底板从 6 页变成 7 页

每槽 64 针两排同高 pitch 10 ⇒ 引脚跨度 310;把「地梳齿 + 母线 + 信号端口排在母线与引脚之间」 (抄 b4_edge §17.2)压到最紧,每槽净宽仍要 355:

排法 宽 / 高 结论
5 槽一行 1815 ❌ 页面可用 1125
3 槽一行 1085 ✅ 余 40
两行 3+2 820 高 ❌ > 802,且下面一行必然压进标题栏

⇒ A5-SLOTS 放槽 13,新开 A5B-SLOTS(e493f8bce3a51aae) 放槽 45 + 全部 5 个 D± 退路座。 建页用 dmt_Schematic.createSchematicPage(schematicUuid) + modifySchematicPageName(名字会被转小写,§13.2 第 3 条)。

20.5 ⚠️ 这一轮又交了五次「几何验证抓不到」的学费

五处全部是靠放大截图发现的,verify_sch 六项 + xpage + port_audit 一处都没响:

# 页 问题 判据为什么够不着
1 A4 R1 搬来的 R721/R722 + UP_VBUS_DET 整块落进标题栏 几何验证只管连接性,不管图元落在哪
2 A4 C737 钽电容 rot 语义与假设相反、跨距也不对 推送时 place() 四轮翻转全对不上才暴露 —— 这一条是唯一被自动抓到的
3 A4 U31 说明文字被 R1 带来的地旗 (60,270) 压穿 flag_clash 只看锚点距离,不建模旗的标签占地(Ground rot=0 往下伸约 38)
4 A6 RT601 的型号文字「NCP18XH103F03RB」(≈65 宽)压住 C736 的值 同 A2-AUX 的 100uF0:文字 vs 元件位号/值没有任何检查
5 A3 说明块第一行压住 R611 的「10kΩ」 同上

教训(已并入 skill):create() 之后读回的引脚坐标是唯一可信的方向来源 —— C737 空页四个角度实测是 rot0 → 1脚(正)在上、跨距 ±20, 而 p1b-pins.json 里那个 ±15 是另一个封装的电容(skill §8d:跨距因符号而异,必须读回)。 排版类的三条(1/3/4/5)目前只能靠人眼截图,建议下一轮给检查器补两个盒子模型: ① 旗的「符号+标签」矩形;② 元件位号/值文字的矩形。

20.6 底板 ESP32-S3 的 GPIO 重排(_esp32_pinmap.json 的 r2_base)

R1 的 new 表不能直接用:5 个 VBUS_EN* + 4 个 KEY_* 随 D9/D13 空了出来, 新增 PRSNT#×5 与 MUX_RST#。共 26 脚(23 信号 + USB6_D± + IO0/TXD0/RXD0/EN)。

  • NTC1 = IO1 / NTC2 = IO2 —— 必须 ADC1(ADC2 与 WiFi 冲突),脚本里有断言。
  • USB6_DM = IO19 / USB6_DP = IO20 —— 原生 USB 硬定死,脚名脚号从 _p3_live.json 查的。
  • ⚠️ 模组是 R8(八线 PSRAM)还是 N8 没定:本页按可能上 R8 保守处理,IO35/36/37 全部不接。 若确定 N8,这三脚可放出来当 GPIO —— 现在全板只剩 IO47/IO48 两个备用脚。

20.7 ✅ T7 也一起结了:F1 = F1206SB2000V063TM(2026-09-08)

翻页搜索修好之后顺手做掉的。AEM 的 F1206 全系都在库里,型号规则是 F1206 + 系列 + 电流 + V + 耐压 + TM:

系列 含义 2A 那一颗
SB Slow Blow(慢断) F1206SB2000V063TM = C310998,63V / 分断 50A / 熔断 I²t 0.63 A²s ✅ 选它
HI High Inrush(耐涌,也是延时型) F1206HI2000V063TM = C246768,I²t 0.8
FA Fast Acting(快断) D10 要慢断,排除
HC High Current 占位用过的 10A(C310989)、底板 F1 的 12A(C310990)就是这一系

D10 写的是「2A 慢断」,SB 是字面对应的那一系,所以选 SB 不选 HI。

⚠ 封装 uuid 和占位件不一样(bceff889… vs 66116fae…,10A/150A 分断那颗焊盘更大)。 刀片 PCB 还没布(M4),没有影响;原理图侧的导线本来就按读回的引脚坐标算,自动跟随 (实测新件引脚仍是 ±20,与占位件相同,218 段导线一段没动)。

⚠ 裕量只有一档 —— 这是选型本身的问题,不是换料带来的

刀片满载约 1.45 A(16 W 手机 ÷ 92% 效率 ÷ 12 V)= 2A 额定的 73%, 正压在保险丝「连续 ≤ 75%」的降额线上,而机箱内 40~50 ℃ 还要再降一截。 ⇒ 首板可以先按 D10 装 2A;若出现无故熔断,换 F1206SB2500V032TM(C310999, 2.5A / 32V / I²t 0.9)—— 同封装,改 b1_power.py 的 FUSE 一个常量即可。 (2.5 A 仍远低于 eFuse U2 的 ILIM 4.45 A 与 TVS 的钳位能力,保护链的层次不变。)

20.8 这一轮真正的收获:lib_Device.search 会翻页

T7 与 T8 卡了整整一个里程碑,根因是同一句错误的经验: 「这个客户端的 lib_Device.search 只回 38 条,够不着立创全库」。

实际上它的完整签名是

search(key, libraryUuid, classification, symbolType, itemsOfPage, page)

itemsOfPage 给 50、page 从 1 往上翻,一个关键词能拿到几百条 (单次桥接请求仍是 30 s 上限,所以一次最多翻 3 页、只跑一个关键词,多了会超时)。

判据别信描述,要放到空页上读回引脚数 —— 这一轮就有两颗立创描述写「PCI-E 4X」 的其实是 x1(36 / 38 脚,见 §20.3)。


21. T1 / T2 / T3 收口(2026-09-08)

三项「开画前要有数」的待办一次结清。其中两项根本不需要新的实测 —— 它们卡了这么久是因为预算表里用了一个已经作废的安装方式,以及一个 2026-09-06 就已经拿到、但没有回填的数。

21.1 ✅ T1:槽距 20.32 mm,不必实测主板厚度

根因:§3.2 的公式里写的是「立柱 3.0」——那是 R1 顶针方案的高度, 而顶针方案 2026-09-06 就被中框式焊盘取代了(R1 §22.3e,螺柱间隙 1.0 mm)。 差的这 2 mm 让整个预算看起来很紧,于是「量主板厚度」被当成了开画前提。

改正后:

h_phone + g = P − 刀片PCB − 间隙 − B面最高件
            = 20.32 − 1.6 − 1.0 − 3.0 = 14.72 mm
h_phone 来源 剩余空气 g
3.2 0.8 裸板 + 1.4 屏蔽罩(实测)+ 正面估 1.0 11.5
5.0 常见手机主板总厚 9.7
6.3 旧文档的告警阈值 8.4
7.6 小米8 整机厚度 —— 主板是它的子集,物理上限 7.1

⇒ 连物理上限都富余 7 mm,结论对这个数不敏感。 槽距定 20.32(PCIe / PC 机箱标准)。

⚠️ 仍要在装配首件确认一次(但它影响的是压板,不是槽距): R1 §22.3e 里有一处自相矛盾 —— 「侧键面(贴合面)最高件 = 屏蔽罩 1.4 mm」 vs 两天后的「贴合面上元件全都低于 1 mm」,而螺柱间隙正是按 1.0 定的。 真顶到屏蔽罩就把间隙垫片 1.0 → 1.5,槽距这边有的是余量。

21.2 ✅ T2:C60 高 10.5 mm

答案 2026-09-06 就存在,只是没回填到 T2 这一行: C3828985 = 6.3TPV2200M10X10.5(2200 µF / 6.3 V 普通铝电解,SMD Ø10 × 10.5), 当时正是为了降高度才把 R1 的 C49256788(10 × 16 插件)换掉的。

落点:A 面「没有手机压着」的服务带 / 功率列,可用 11.7 ~ 13.7 mm(g 取 4~2)⇒ 余 1.2 ~ 3.2 mm。 ⛔ 它不能放 B 面(那面只有 3.0 mm),也不能放在手机投影里。M4 摆位时先钉死这一颗。

⚠️ 别把它换回聚合物电容:C49256788 的 role 里写着,同尺寸的聚合物版 ESR 只有 12 mΩ, Q 会从 0.19 回到 4.5 而振铃 —— 这颗要的就是普通铝电解那几十 mΩ 的 ESR(R1 §6.3 阻尼组)。

21.3 ✅ T3:做斜边,20° / 1.0 mm;金手指区改电镀硬金

⚠️ 2026-09-08 M4a 修正角度:本节原写 20°/1.0 mm。20° 是 PCI/PCIe 的行业标准角 (德系板厂 multi-cb 的表里就是 20°),但嘉立创只提供 30° 和 45°,并建议优先 30°, 20° 根本下不了单。改为 30°,深度由板厂按指长配。见 §22.2。

决定:做。 三条理由:

  1. 加价压在已经要付的工艺费之上。 金手指本身是一道独立工序(下单页勾选), 斜边是它的附加项 —— 不是「从 0 到 1」,是「从 1 到 1.x」。
  2. 它挡掉的失效很贵且测不出来。 没有倒角的 1.6 mm 直边插进插槽, 尖角会刮/顶插槽的接触簧片。而底板上那 5 个座子是焊死的贴片件, 换一个要拆焊 64 个脚;更糟的是接触退化只表现为偶发的 USB 掉线或 I²C 超时, 功能测试测不出来 —— 这正是本项目反复吃亏的那一类。
  3. D7 不带电插拔 ≠ 不插拔。 5 片刀片 × 装配 + 维修,几十次是有的, 而 ENIG 那层金根本扛不住(见下)。

顺带纠正 §5.3 一个错:原来写「表面处理:沉金(ENIG)」。 ENIG 的金层只有 0.050.1 µm、底下是镍磷层,是为焊接设计的,不是为插拔设计的, 金手指反复摩擦会很快磨穿见镍。金手指要的是电镀硬金(11.5 µm + 钴/镍硬化)—— 嘉立创的「金手指」选项本身就是这个工艺,勾了就有。

对 M4 的两条约束(B4-EDGE 的金手指封装现在可以开画了):

  • 斜边会吃掉手指前端约 1.0 mm 的镀层 ⇒ M4a 实测这条不成立,但结论不变: CEM 的金手指本来就离板边留 1.3 mm 裸边(指尖不到板边),斜边啃的是那 1.3 mm 的裸 FR4, 一点镀层都吃不到。金手指长度仍然照 CEM 画(4.3 mm),别自己缩短。
  • 板厚必须是 1.6 mm(插槽的夹持力按这个设计),下单时不能被「1.2 更便宜」换掉。

唯一会推翻这个决定的:金手指工艺费报价离谱到吃掉板费。那时走 §5.4 的退路 (1.27 mm 排针)—— 而且现在这条退路的代价比原来小:底板插槽已经换成贴片立式 (§20.3),机械固定件本来就要加。


22. M4a 落地记录:金手指封装(2026-09-08)

PCIE-X4-EDGE-64P 从「只有符号」变成「符号 + 封装」,M4 的最后一个前置条件清空。

封装名 EDGE-64P-P1.00_PCIE-X4-GF
UUID 569096fb8fed4743b85c69f4b6581ead(个人库;已写进 .claude/r2/r2-uuids.json)
脚本 .claude/r2/fp_edge.py —— 几何的唯一事实来源,--push 幂等重画 + 读回校验
判据 64 焊盘逐脚对坐标/层/尺寸、板框缺口 16 段折线闭合且两端点落在板边、丝印零侵入指区

22.1 几何不是凭记忆写的

M2d 那两处「凭记忆写错针位」的教训之后,这一版的每个数都有出处:主源是 KiCad 官方 Connector_PCBEdge.pretty/BUS_PCIexpress_x4.kicad_mod(其 descr 注明摘自 PCI-E CEM 的 add-in card edge-finger 图),再拿三处独立资料交叉核对。

项 取值 交叉核对
间距 1.00 mm CEM / 立创资料 / KiCad 三处一致
手指宽 0.70 mm(净距 0.30) 同上
手指长 4.30 mm 中文资料常写 4.0,同量级
指尖到板边 1.30 mm multi-cb 给 PCIe 荐值 1.4,另一处给 0.6~1.5 窗口 ⇒ 1.3 在窗口内
缺口 11/12 号针之间,宽 1.9、深 7.45,口部两个 0.5×45° 导入角 KiCad 的 x1 与 x4 两个封装完全一致
缺口到 11/12 号指 铜边距 0.20 mm 直段两侧对称,selfcheck 里断言死
A 排 / B 排 A = 底层,B = 顶层 同 KiCad

A1 / B31 是短指(3.2,指尖再退 1.10),远端与长指齐平。这不是装饰:本方案的在位检测 就是这两根(底板 A1=GND / B31=PRSNT{n}#,刀片上短接)。做成等长指,刀片插一半就报 「已插入」,而这一类错误功能测试测不出来 —— 与 §20.1 是同一个坑的两面。

22.2 ⛔ 两条与既有文档冲突的,已经改掉文档

  1. T3 的「20° 斜边」在嘉立创下不了单。 嘉立创《金手指斜边设计注意事项》写明 只有 30° 和 45°,并建议优先 30°。⇒ §5.3 / §21.3 已改成 30°。
  2. 「斜边吃掉 1.0 mm 镀层」不成立。 CEM 的金手指本来就离板边留 1.3 mm 裸边, 斜边啃的是那段裸 FR4。结论不变(照 CEM 画、别缩短),但理由换了 —— 那 1.3 mm 的用途就是给斜边的。

嘉立创另外三条已核:金手指处必须开通窗(焊盘自带,且本封装不在指区放任何丝印); 斜边板单片长宽 ≥ 50 mm(刀片 98×76,过);板厚 ≥ 0.4(1.6,过)。

22.3 板框:缺口跟着封装走,外框归 PCB

封装在 板框层(11) 只画缺口那一段(两个导入角 + 两条竖线 + 12 段折线近似的顶部半圆)。 刀片 98×76 的外框在 PCB 文档里画,底边必须在 x = -6.45 和 x = -3.55(相对封装原点) 断开,两段拼成一个闭合外框。坐标从 fp_edge.notch_mouth() 取,不要手抄。

⇒ 缺口忘不掉(跟着封装走),而外框尺寸仍归 PCB;拼不上时 DRC 会报开口外框。

22.4 这一轮踩到的四条 API 坑(都已写进脚本注释)

坑 现象 做法
pcb_PrimitiveArc 只写不读 create() 返回成功、画面上也确实画出来了,但 getAll() / getAllPrimitiveId() 一律返回空 ⇒ 既校验不了也删不掉,重画一次多一批 半圆改用 12 段折线(弦高误差 < 0.01 mm)。发现时已经堆了 5 个删不掉的弧,整个封装删掉重建
lib_Device.modify 的 association 在第 5 位 dev_edge.py 当初把它写到第 6 位(description),所以一直「关联改不动」 位序是 (uuid, lib, name, classification, association, description, property)
addIntoBom 是 boolean 不是字符串 dev_edge.py 传的是 'no',于是「API 改不动、只能去客户端手工改」 传 false 就改掉了 —— eda-parts.json 里 MI8-KEY-PAD 那条同样的结论要一起翻案
助焊(锡膏)扩展关不死 给 -0.35 mm,客户端夹到 -0.035 mm 「金手指区钢网不开口」只能下单时另外说明(同 fp_keypad.py 那颗接触盘)

另两条无害但费时间的:系统库封装不能 openInEditor(返回 false),lib_Footprint.copy 从系统库复制到个人库也静默失败 ⇒ 想读系统库封装的几何,只能放到空 PCB 里读回。

22.5 坐标系:PCB 里 y 向上为正

封装原点 = 金手指阵列的 X 中心 × 卡的底边,手指朝 +Y(板内)。 第一版画反了(手指长到板外),四道几何校验全过,是截图看出来的 —— 又一次 「几何验证证明不了看着对」。判据留在脚本注释里:板边基准线画在文档层 y=0, 截图上它必须在手指下方。


23. M4b 落地记录:刀片板框 + 导入(2026-09-08)

步 结果
板框 98 × 76,四角 R2,画在 BLADE-PCB(3b9c4e39c8d164db)。脚本 .claude/r2/pcb_blade.py
金手指 J1 摆在 (49.00, 0),rot 0,layer 1。64 个焊盘的网络逐脚读回正确
导入 83 件全部导入(--probe 报 83 增 / 0 删 / 0 改),--verify 位号+封装逐件对上

坐标系:板左下角 (0,0),x 右 y 上,就是 §3.1 那张分区图的坐标。

23.1 金手指为什么摆在 x=49(板宽正中)

刀片 98 宽、插槽体只有 39 ⇒ 两侧各悬出 29.5。居中让左边(手机主板)和右边 (功率列,压着 2200 µF 和电感)的悬臂等长 —— 插槽是贴片立式、保持力只靠焊盘剪切 (§20.3),不该让任何一边偏重。代价:+12V 在 B1/B2/B3(阵列左端), 到功率列要横穿 ~40 mm;这一段走 L3 的 12V 灌铜,不是走线,无所谓。

⛔ 底板的 5 个插槽必须按同一个数摆:槽中心 = 刀片中心。这是两块板之间唯一的 硬对位关系,M5 画底板时从 pcb_blade.J1_X 取。

23.2 板框底边是断开的,这是设计不是错误

缺口(防呆键)画在封装的板框层里,PCB 这边的底边在 x = 42.55 / 45.45 断开, 两段拼成闭合外框。pcb_blade.py --verify 的判据就是「板框上有且只有两个自由端点, 且正好落在缺口口部」—— 拼错一格会当场报出来。

23.3 两个坑

  1. pcb_Document.importChanges() 在本机一律返回 false、对话框都不弹 (带/不带 schematic uuid 都试过)⇒ 导入只能沿用 R1 那套驱动 GUI 的做法, 新脚本 .claude/r2/pcb_import.py(刀片/底板通用,--base 切板)。
  2. 原理图里已经放下的元件会把「器件没有封装」这个状态缓存住。 J1 在 M2d 放下时器件还没封装,M4a 建好封装并挂上去之后, B4-EDGE 页上的 J1 读回来仍然是 footprint.uuid = "", BOM 里显示成 [object Object],导入 PCB 会缺件。 解法:重跑 b4_edge.py --push 整页重画(幂等),J1 才会带上新封装。 ⇒ 以后凡是「先放件、后补封装」的器件,都要回去重画那一页。

23.4 M4 接下来的顺序

  1. 设计规则(照 pcb1_rules.py 改:刀片只有一路,PWR12V / SWNODE / PWR4A / PWR1A 四档 + USB_DP/DM 一对差分)
  2. 摆位:先钉死三颗 —— J1(已定)、C60(Ø10×10.5,只能放服务带/功率列,§21.2)、 J4 BM24 尾插(接口边);再按 §3.1 的分区放其余 80 件, 功率列内部按「离手机越远越吵」排(SW/L/Cin 靠 x=98 那一边)
  3. 布线:L1 信号+功率、L2 完整地平面(不许割断)、L3 12V/VO 灌铜、L4 控制信号; D± 走 L1 以 L2 为参考
  4. 灌铜 + DRC 清零,再截图人眼确认

24. M4c 落地记录:规则 / 摆位 / 铺铜(2026-09-08)

24.1 ⛔ 刀片 PCB 建出来是 2 层,不是 4 层

M1 建文档骨架时没设铜层数,BLADE-PCB 一直是 2 层。 表面上看不出来 —— pcb_Layer.getAllLayers() 照样列出 Inner1 / Inner2(那是层定义, 不是启用的铜层),设计规则也照建不误。唯一露馅的地方是规则审计里那句 getTheNumberOfCopperLayers() = 2,以及规则配置的基准集叫 「JLCPCB Capability(Two Layers Board)」。

⇒ setTheNumberOfCopperLayers(4) 改掉,然后规则要重下一遍(换层数会换基准能力集)。 ⚠ 底板 BASE-PCB 是 2 层(§6.1),那一块不要改。

24.2 设计规则(.claude/r2/pcb_rules.py)

照搬 R1 pcb1_rules.py 的那一套,四个坑一个没变。和 R1 不同的四处写在脚本头上, 其中两处值得在这里重复:

  • PWR12V 从 2.0 降到 0.8:刀片 12V 满载只有 1.45 A(§20.7 那颗 2 A 保险就是按它选的)。 R1 的 2.0 mm 是给整机 8~10 A 干路的,照抄过来只会把 12 mm 宽的功率列挤死。
  • 两对差分,不是一对:USB_DP/DM(金手指 → U7)和 USB_DPJ/DMJ(U7 → J4) 被 ESD 管隔成两段,各自成对。只建一对,另一段就退回默认间距规则。

⛔ 安全间距是 0.15,不是 R1 的 0.2。 抬到 0.2 会刷出 23 条「贴片焊盘到贴片焊盘」, 全部在 J4 BM24-50DS 内部 —— 0.4 mm 间距的尾插座,相邻焊盘净距 0.168~0.171, 是买来的封装本身的几何,改摆位修不掉。0.15 仍远高于嘉立创四层 0.09 的能力线。 ⚠ 顺带发现 R1 那份的间距循环只抬不降,所以把下限改小是改不动的 —— 这里改成了「≤0.2 的格子一律赋成下限,0.254/0.3 那几格(孔/板边相关)不动」。

24.3 摆位(.claude/r2/pcb_place.py):三类件三种定位

  1. 机械锚定(位置由小米8 主板决定):K1~K4 侧键触点盘、J5 电池排线焊盘、 J4 尾插座 —— 坐标从 .claude/mi8_mech.json 换算,不手抄。 手机落点 PHONE_ORG = (3, 29),接口边(v=0,J600/J1401/侧键都在上面)朝下。
  2. 手工钉死:J1(49,0) / C60(37.5,19) / J2(62,15) / J3(66.5,25)。
  3. 其余 70 件:按功能分组、按电流流向排序,货架式排布器塞进四个区。 顺序是设计意图,坐标不是 —— 要改布局改 GROUPS,别去改坐标。

三条落地时改掉的:

  • 功率列自下而上 = 输出端 → 输入端(和电流方向相反)。VO_P 是 4 A, 出口必须离服务带的 C60/J5 近;+12V 只有 1.45 A 又走灌铜,爬到板子上半段无所谓。
  • U3 INA226 挪进 POWER_OUT 并紧挨 Rs1。原来它在内条,隔着一整列 —— §7.2 第四条「取样脚落在 Rs 的 Kelvin 焊盘上」就做不到了。
  • 每个组占一条完整横带(区里放一个 y 游标)。不这么做小件会回填进前一组的空隙, 功能级在 y 上互相咬,L3 的 12V / VO 岛就切不出来。

B 面留空:§3.2 把 L1 电感算成「B 面最高件 3.0」,但同一张表里 A 面功率列可用 11.7~13.7 —— 3.0 的电感放 A 面绰绰有余,还能贴着 U1 摆、SW 节点不打过孔。 83 件全在 A 面,h_B 从 3.0 变 0,槽距只会更宽裕。

24.4 ⛔ 全贴片的板子:不打缝合过孔,四层里有三层的铜面会被整块删掉

六块铜面(GND-TOP/L2/L3/BOT + VO-L3 + V12-L3)下发后,只有 GND-TOP 填出来 (213 块),另外五块一块铜都没有。根因:这块板一个通孔焊盘都没有(全贴片), 内层铜面因此一个连接点都没有,「移除孤岛」把整块删了。

三个地方都不报错:rebuildCopperRegion() 返回成功、铺铜管理器显示「0/0」、 DRC 的间距那一支干干净净。只有把内层截一张图才看得出来是空的。

⇒ 顺序必须是 摆位 → GND 缝合过孔 → 布线 → 铺铜。 pcb_route.py --stitch 按 5 mm 网格、避开所有焊盘 0.6 mm 打 196 个 GND 过孔。 同理 VO_P / +12V 也不能只靠灌铜:让自动布线器拉线,它换层打的过孔 正好把 L3 的两个岛接上。

24.5 铺铜结果:6 块里 4 块填出来了,2 块等布线

打完 196 个 GND 缝合过孔再重铺,GND-TOP / GND-L2 / GND-L3 / GND-BOT 四块全部填上, L2 是一整块没有割断的地平面(§7.1 的硬要求,截图 .claude/r2/M4c-blade-L2-gnd.png 为证)。

剩下 VO-L3 / V12-L3 两块仍是空的 —— 这是对的:VO_P 和 +12V 现在一根线都没布, L3 上那两个岛还没有任何过孔可接。布完线(换层过孔会穿过 L3)它们自然就填上了。

DRC:间距错误 0,连接性错误 252(= 还没布线)。

24.6 ⛔ 自动布线在这台客户端上跑不出一根铜

两条路都试过,都不行:

路子 结果
pcb_Document.autoRouting(...) 这个 API 在本机客户端上不存在:autoRouting is not a function(文档里有,实现里没有)
GUI:布线 → 自动布线... 对话框能开、图层能勾(已取消内层,只留顶/底层)、运行 点得下去,对话框立刻关闭,铜线数量 0,不报错、不弹进度、不弹失败

⇒ 布线这一步没有自动化的路可走,只剩两条: ① 我按脚本逐网络布(要自己写一个够用的布线器:约 55 个网络 / 361 个焊盘); ② 用户在客户端里手动跑一次自动布线(可能要登录 / 要额度),或直接手工布关键几条。

⚠ 无论走哪条,内层不许布线这一条不能破(L2 是地平面、L3 是电源岛), 而且 §7.2 那四条关键回路(Buck 输入环路 / SW 面积 / FB 远离 SW / Kelvin 取样) 自动布线器一条都不认识,跑完必须逐条复核。


25. M5 落地记录:器件翻到 B 面 + 功率级手排(2026-09-08)

用户要求:卡片(刀片)上的器件放到手机主板的另一面;优化器件布局; 尾插排线座与电池排线焊盘按之前的处理放置。

25.1 分面:A 面只留 10 件

小米8 主板压在 A 面,J600 的电池排线和 J1401 的尾插排线贴着 A 面折下来 落到服务带。所以 A 面只留下面这些,其余 73 件全部搬到 B 面:

A 面留守 为什么非在 A 面不可
K1~K4 侧键触点盘 主板弹片直接压在裸铜盘上(R1 §22.3e)
J5 电池排线焊盘 / J4 BM24 尾插座 排线折下来焊在 A 面。坐标和层一个数没改(用户指定)
C60 2200 µF 高 10.5 mm,B 面预算只有 3.0(§3.2)
J2 D± 退路座 / J3 EDL 座 线座约 5 mm 高,同样超 B 面预算;且要能插拔
J1 金手指 板边卡,两面都是指

换面赚到的三件事(这才是「优化」的实质,不是重排坐标):

  1. 两条排线底下彻底空了。原来服务带塞着 30 多个小件,排线是贴着板面躺过去的。
  2. 侧键 MOS 挪到 K1~K4 正背面。漏极是手机侧键线(机内 100 k 上拉、高阻、最怕拾噪), 从 20 mm 缩到 3.96.3 mm。这块地方原来是「手机投影,只许放 K1~K4」,翻面才解锁。
  3. USB / 阻尼 / EDL 三组落到 J4 / J5+C60 / J3 的正背面。

h_B 最高件 = L1 SPM6530T 3.0 mm,正好等于 §3.2 给 B 面的预算 —— 按原预算用满, 不是超支(h_phone 取物理上限 7.6 时仍余 7.1 mm 空气)。

25.2 ⛔ 功率级改成手排:货架排布器不认识回路

M4c 那一版把功率级也交给货架排布器,§7.2 的四条关键回路破了三条, 而重叠 / 越框 / 禁布区的几何自检全绿:

§7.2 M4c(货架排布) M5(手排)
Buck 输入环路 Cin 离 U1 12.4 mm 最近一颗 1.36 mm
SW 面积 U1→L1 绕了 ~7 mm 焊盘对焊盘 0.65 mm,外接矩形 22.7 mm²
FB 远离 SW 压在 SW 那一带 2.27 mm
Kelvin 勉强 4.84/4.85 mm,对称、不交叉

关键一步是 U1 转 270°:TPS54622 的 VIN/GND 在一条长边、SW 在对边,不转的话 Cin 和电感必然分居左右 —— 而 §3.1 要求 SW / 电感 / Cin 同时靠板外边。 转成 VIN/GND 朝上、SW 朝下之后,竖着堆成一条: D1/F1 → Cin×4 → U1 → L1 → Cout → eFuse → 分流 → INA,电流自上而下, 出口 VO_P 正好落在 VO-L3 岛(y ≤ 28.8)里。

新增 .claude/r2/loop_check.py:把 §7.2 四条写成摆位阶段的机器判据 (读真实焊盘坐标算距离 / 面积 / 线段是否交叉)。摆位一改就跑,别再靠布完线截图看。

25.3 ⛔ 底层的旋转语义:rot=90 是逆时针

实测(C1 四个角度全试):B 面(layer 2)先按 y 镜像,再 rot=θ 是 (x,y) → R(+θ)·(x,y)。也就是 rot=90 把 (-1,0) 送到 (0,-1)。 第一版按顺时针推,结果 VIN 和 SW 上下颠倒,读回焊盘坐标才发现。 ⇒ 手排任何非 0 角度之前,先 pcb_route.py --dump 读回来对一眼,别推。

25.4 ⛔ 布线器身上抓出四个 bug(三个是静默的)

bug 现象 判据
route_net 的失败从来不写日志 报「0 条没搞定」,实际 29~42 处没接上;网上只剩一小段 0.02 mm 引出脚,getNetLength() 非 0 所以也看不出来 只有 EasyEDA 的连接性 DRC 会报,而那一支平时被当成「还没布线」忽略
引出脚按「谁包住我的盘心」排除自身焊盘 J4(0.35 mm 间距)的邻脚膨胀后吞掉本脚盘心 ⇒ 邻脚被当成自己跳过,引出脚贴着它走,实测净距 0.047 mm 改成按矩形本身排除;引出脚净距用规则值 0.15(不是干线的 0.18),下限 0.15 mm
同网过孔可以叠在一起 占用图按网可进 ⇒ 两条支路在同一点换层,DRC 报「钻孔到钻孔 0 mil」 dedupe_vias():同网中心距 < 0.6 mm 就合并
焊盘对焊盘的短接 A* 进不去 SWNODE 2.0 mm 干线口径 ⇒ U1 的 SW 脚周围一个格点都不空,报「出不来」 direct_links():同层同网、净距 ≤ 2.2 mm、走廊无第三者 ⇒ 直接画一段铜,宽度取两个焊盘垂直方向的较小者(电流瓶颈本来就是 IC 的脚)。直连之后才按焊盘封顶干线宽度

另外把下网顺序从「跨度大的先布」改成「引出脚少的先布」—— 细间距 IC 的内侧脚 一旦被邻线占住出口就再也出不来(INA_ALERT 就是这么卡住的)。

25.5 当前状态与没做完的

  • 摆位:83 件(A 面 10 / B 面 73),读回校验位置与层全对;几何自检 7 项 + loop_check 4 条全过。
  • 布线:797 段 / 122 过孔 / 134 缝合过孔,router_check 自算净距 0 条。
  • 铺铜:19 块,18 块填出来(V12-L3 暂时没有可接的铜)。
  • DRC:间距错误 3 条(同一处:$1N126 的铜压在 C9 的 GND 盘上)、物理错误 0。
  • ⛔ 还有 29 处连接没布通,清单在 .claude/r2/_blade_open_nets.txt。 集中在 U2(WQFN-20) / U4(TSSOP-24) / J4(0.35 mm) 的内侧脚和金手指扇出。 这不是这一轮引入的 —— 老版本同样没布通,只是布线器不报而已(见 §25.4 第一条)。

25.6 ⛔ 两层正交:器件面纵向、另一面横向

2026-09-08 用户定的走线方向约定(和 R1「顶层横向、底层纵向」一致):

层 方向 说明
L4 底层 = 器件面(73 件在这儿) 纵向(沿 y) 焊盘阵的引出方向大多是上下,顺着走
L1 顶层(只有 10 件,几乎全空) 横向(沿 x) 长距离横穿服务带靠它

布线器里的做法是加钱不是封死(LAYER_DIR / CROSS_COST=3.0):逆着优选方向 走一格要贵 3 倍,斜线算「半逆」。于是拐弯自然变成「换层拐」,两层互补; 但引出脚那种非横即竖走不了的地方仍然出得去,不会把细间距的脚憋死。

⚠ 配套要把 VIA_COST 压低(12 → 8):正交布线本来就靠频繁换层拐弯, 换层太贵等于逼线逆着方向硬走。

25.7 ⚠️ 铺铜不落盘(新发现,待查)

实测:API 建的铺铜在客户端 location.reload() 之后只剩 2 块(VO-L3 / V12-L3), 17 块 GND 铜面全没了;同一次调用里建的丝印线却留下来了,走线和过孔也都在。 ⇒ 不是「保存没执行」,是铺铜这一类图元没跟着存。

影响:谁重开客户端都要重跑 pcb_pour.py --push(两分钟)。 在查清楚之前,不要把「铺铜已完成」当成落盘状态;§24.5 记的那一版大概率也是这样丢的。

25.8 ⛔ 布线器身上又抓出四个会做出短路板子的缺陷(2026-09-08 第二轮)

用户要求「把 29 处没布通的接完」。结果是:没接完,但把「29」这个数字本身证伪了 —— 那 29 是一个在四个方向上撒谎的布线器报出来的。逐条:

# 缺陷 现象 判据 / 修法
1 种子焊盘的引出脚画到了 A* 没走的那个出口上 src 放的是种子的全部出口(那是对的),可引出脚只画到 starts[0]。A* 从别的出口起步时,铜和焊盘之间是断的,而「路找到了」所以一个字不报。KPAD_PWR 的 K1 引出脚停在 (7.75,34.25)、干线从 (8.75,33.25) 起步,中间 1.4 mm 空着 改成惰性:note_seed(path[0]),谁真被用上就给谁补引出脚
2 U1 的散热焊盘被当成一个点 VQFN-14 的散热盘是 POLYGON 形状,没有 w/h 字段 ⇒ 导出成 0×0。布线器于是从这块 4.32×2.03 的 GND 大铜上直接压过去 —— 对地短路。DRC 报 贴片焊盘(GND): e41 距离 0mil pcb_route.dump_pads 按多边形点列算外接框
3 多边形外接框又被按 rotation 转了一次 修完 2 之后短路还在:外接框已经是板面绝对坐标,不该再对调宽高。对调一次就把 4.32×2.03 的横盘记成 2.03×4.32 的竖盘,露出来的那半块正好让过孔落上去 poly 标志,多边形不参与 rot 对调
4 VO_P 的落孔只避了自己那一层 通孔穿两层,却只查了焊盘所在层 ⇒ 压在另一面 C60 的 GND 盘上(净距 0.125) 候选点加 free_via()(两层都要让得开)

⇒ 新增 check_connected():按几何做并查集,只看铜、不看布线器的账本。 这是唯一能抓住第 1 类缺陷的判据 —— A* 报「布通了」只说明它自己觉得布通了。 (VO_P / +12V 靠 L3 铜岛成网,几何上本来就是分开的几块,判据里单独放行。)

25.9 ⛔ 第五个缺陷:QFN 散热盘是十字形,不能用外接框

修完 25.8 的第 2/3 条之后 U1 的四只侧脚反而全「出不来」了 —— 因为我用外接框 近似那块多边形:真实形状是十字(横臂只有 0.24 mm 高),外接框 4.32×2.03 把 两侧引脚所在的那一圈(y 48.75 / 50.25)也封死了,而那里其实是空的。

⇒ dump_pads 按扫描线把多边形拆成若干矩形(这块盘拆成 5 块),逐块当障碍。 拆完 U1 的 p1/p7/p8/p14 就出得来了,没接上的从 40 降到 31。

⚠ 顺带:JS 模板里写 % 要写 %% —— 漏了会让 dump_pads 抛 TypeError 而 不重写文件,于是「改了没生效」,看上去像修法无效。

25.10 ⛔ 第六个缺陷:引出脚的净距检查从盘心开始采样

$1N138(BOOT) 用「关键网绝对优先」都接不上,空占用图上 U1.13 明明有 8 个出口。 把那一刻的占用图按归属网打出来才看清:左边(x ≤ 87.75)整片是空的, 但引出脚的「已布铜」检查是从盘心出发逐点采样的,而盘心那一格被隔壁 0.5 mm 外那根 SW 直连段的避让区盖住了 —— 第一个采样点就判死。

⇒ 盘心在它自己的焊盘里,那儿有铜本来就是合法的,这一段不该参与净距判断。 _stub_clear 加一个 own 参数,落在自己盘框里的采样点跳过。

这一条不止影响 BOOT —— 凡是「焊盘紧挨着一根粗线」的脚都被同一条逻辑判死, U1 / U2 那一圈正是如此。修完没接完的从 34 降到 14 个网。

25.11 布线现状(诚实版)

值
导线 / 过孔 689 段 / 273 过孔 + 131 个 GND 缝合过孔
自算净距(0.15 判据) 0 条
DRC 间距错误 0 / 物理错误 0,连接性 55
没接完的网络 13 个,清单 .claude/r2/_blade_open_nets.txt

⚠️ 「16 个网」比上一轮记的「29 处」看着少,但两个数不可比 —— 上一轮的 29 是一个 在五个方向上撒谎的布线器报出来的;现在这 16 个是几何并查集数出来的,是基线。

✅ Buck 的命门都接上了:$1N137(SW) 15.8 mm、$1N138(BOOT) 8.97 mm、 $1N126(FB) 11.86 mm、VO 50.8 mm、+12V_F 47.2 mm。

没接完的 13 个:VBUS_EN EFUSE_EN $1N164 USB_DPJ $1N151 SCL KEY_PWR INT# PRSNT# +3V3 VBUS EFUSE_FLT EFUSE_PG (逐轮会换一批,说明是拥塞而不是某几条固有不可布)。 其中 +12V_F / +3V3 / VBUS 是只差一段没连成一片(「铜分成 2 块」), VBUS(给手机供电)和 KEY_PWR(侧键)是功能必需,其余多为状态信号。

25.12 ⚠️ U4(PCA9555) 的朝向:转 180° 才对

不转的话正好装反 —— 需要往左/往下走的(INT# 去金手指、KEY_* 去最左边的侧键 MOS、 VBUS_EN 去 U5、EDL_EN 去 U6)全在朝上那一排;需要往右/往上走的 (EFUSE_PG/FLT 去 U2、BUCK_PG 去 U1、INA_ALERT 去 U3)全在朝下那一排。 两排各绕整颗芯片一圈,这一颗一家就占了 4 处「没布通」。

转过来之后 SDA / SCL / INT# / EDL_EN 全通了,代价是换来 INA_ALERT / BUCK_PG (它们改成绕行了),净减一个。

照着这条把所有 IC 都体检了一遍(每只信号脚「出线方向」与「目的地方向」的夹角, 四个朝向各算一次,只用摆位 + 网表,脚本见下)。结论:

位号 现朝向 四个朝向的平均夹角 结论
U6 0 0:132 90:87 180:48 270:93 已改 180
J2 0 0:96 90:23 180:84 270:157 排线座,转了出线方向就变,留给用户定
U4 180 0:71 90:48 180:109 270:132 已改 90
J1 0 — ⛔ 金手指,绝不能转(判据不认识这件事)
U1 U2 U3 U7 J4 U5 — — 已经在最优或差 <10°,不动

⚠️ 但实测「朝向更顺」不等于「布得通」:U4→90 + U6→180 之后没接完的仍是 13 个 (只是换了一批网)。这个判据能挑出明显装反的(U4 原来 180 那一版就是它挑出来的), 但挡不住拥塞——最后这一段是拥塞主导,不是朝向主导。

集中在 U2(WQFN-20) / U4(TSSOP-24) / J4(0.35 mm) / U1 的细间距内侧脚。 把失败点在失败那一刻的占用图打出来看,全是别的网已经布下的铜 —— 不是几何不够、也不是顺序不对(顺序、扇出、过路费、L 形引出脚、正交方向、 拆线重布六种手段都试过,42 → 40 之间反复)。

下一步的两条路(都不该再靠调参数):

  1. 协商式拥塞布线(PathFinder):允许暂时重叠,按历史拥塞代价迭代收敛。 这是教科书解法,也是唯一对症的 —— 现在这个「一次布死、不回退」的 A* 到头了。
  2. 在客户端里手工布这 40 条:交互式布线器处理这种局部拥塞比脚本强得多, 几何已经全对(间距 0、短路 0),剩下的是纯手工活。

26. M6 落地记录:屏蔽窗去掉、器件全到 B 面、排线穿板槽(2026-09-09)

用户拍板三条:去掉刀片上的两个挖槽;器件在背面整体布局;加电池排线槽和尾插排线槽。

26.1 为什么三条是一件事

  • 两个屏蔽窗是 §24 那一轮「屏蔽罩轮廓没实测所以全挖」的保守项,而 R1 §22.3e 的定稿本来 就是「载板不挖空:用户实测贴合面元件全低于 1 mm」。去掉后 L2 地平面整块(§7.1 的硬要求)、 板子恢复刚度,B 面手机投影 67×44 全部解锁。
  • 器件全到 B 面之后 A 面服务带清空,B 面服务带对面是空的,净空 20.32 − 1.6 = 18.7, C60(10.5) / J2 / J3(5) 都能下去 —— 以前留在 A 面的理由(「B 面只有 3.0」)本来就是 把 L1 的高度当净空写的(§3.2 已更正)。
  • J5 / J4 到了 B 面,排线就必须穿板:这正是 R1 pcb2_place.SLOTS 的做法 (2026-09-06 实测排线:电池 8×38、尾插 18×55)。排线翻过接口边 → A 面服务带 → 接口边外侧 2.7 mm 的槽 → 穿板 → U 形折回 B 面往 +y 走到手机投影下方的连接器, 所以连接器要落在槽的北边,也就是需要解锁的那块地方。

26.2 几何(事实来源 pcb_blade.py / pcb_place.py)

项 值
电池槽 BAT x 20.7732.77 × y 24.8027.80(12×3,中心对 J600 u 23.77;§22.3b 标 ±2 所以比 R1 的 10 宽 2)
尾插槽 TAIL x 46.5866.58 × y 24.8027.80(20×3,中心对 J1401 本体中心 u 53.58)
槽的实现 layer 12 (MULTI) 填充 = 挖槽区域(pcb_PrimitiveFill,R1 同),不是板框内环;DRC 认「挖槽区域到导线」
排线车道(B 面,一件不放) BAT x 22.2731.27 / TAIL x 47.0866.08,从槽顶到连接器顶
J5 (26.77, 32.0) 底层 rot 0;排线长 4.6+5+2.7+1.6+5.7 ≈ 19.6 ≤ 35
J4 (56.58, 33.0) 底层 rot 0;2.5+5+2.7+1.6+6.7 ≈ 18.5 ≤ 50
C60 (40.0, 18.5) B 面,夹在两槽之间的服务带(西余 1.7 / 东余 1.1)
J2 (61.8, 18.0) B 面 rot 270(读回:信号盘在西 60.35;rot 90 会跑到东边)
J3 (70.4, 33.0) B 面 rot 0,尾插车道东侧走廊,信号盘朝南对着槽 —— EDL 两根飞线跟着尾插排线穿槽去 TP1204/1205
A 面 只有 K1~K4 + J1,其余 78 件全在 B 面

J1401 的 x 改了 4.8 mm:pcb_place 原来锚在 mi8_mech.contacts_up.J1401 = 48.76, 但设计文档 §22.3b 按本体矩形匹配到的中心是 53.58(±0.3,本体 12.25 宽)。 TP1204/1205 两份数据吻合到 0.1 ⇒ 坐标系相同、只是 J1401 取的点不同(48.76 是西端)。 按 53.58 定之后尾插车道西沿 47.1 正好让开 H4 螺钉头 (44.9 + 2.2),与 R1 自洽 —— 按 48.76 定则车道压在 H4 上。

26.3 J5/J4 为什么底层 rot 0(几何校验抓不到接反,写清楚推导)

排线绕槽折回是绕 x 轴翻 180°:板坐标里 x 不变、y 镜像。立创底层放件恰好是 「先 y 镜像再转 rot」(§25.3 实测)。于是把 A 面那一版的坐标原样搬到底层、rot 不动, 焊盘图案就是折回后排线触点的图案。读回实测:J5.1(VO_P = P+) 仍在西端 23.77(与 §13.5 用户实测「P+ 在左」一致);J4 奇数排从北翻到南、pin51(VBUS) 仍在西端。 R1 §25.16 v4 对 J7n 的结论也是「底层 rot 0」。装配首件仍要两点通断复核。

26.4 摆位 / 校验

  • TOP_ONLY = [J1, K1~K4];高度自检改成分段(H_B_PHONE 10.12 / H_B_SVC 18.72), HEIGHT 里的件进手机投影会被拦。
  • 排布器障碍:铣穿槽(+0.5)+ 两条车道 + 七个螺钉头圈;U7/U5/U6 不再手排 (J4 现在也在 B 面,它们只能在插头背后),交给 SVC_R / SVC_E 区。
  • 读回 83 件位置/层全对(A 面 5 / B 面 78);截图 .claude/r2/M6-place-bot.png / M6-place-top.png。
  • pcb_pour.gnd_tiles 重写成通用的竖条分解(原来的横带写法假设各窗 y 不重叠, 两条并排的槽会把槽本身当成一条带铺进去)。
  • 布线:旧 797 段全部作废(clearRouting 30 s 超时但实际执行了 —— 判据是读回四个铜层 0 段), 缝合过孔重打 182 个,路由结果见 §26.5。

26.5 布线 / 铺铜 / DRC 结果

第一轮 router --replan 报 23 条,其中 6 条是同一个根因:VO_P: J5.1 / C61~C65.2 找不到落过孔的地方 —— J5 和阻尼组挪到了电池槽北边(y 29~40),跑出了 VO_ISLAND(y ≤ 28.8)。 ⇒ pcb_pour.VO_LOBE = (20, 28.8, 46, 46),岛改成 L 形单环(vo_poly(),不是第二块铜), router 落孔判据改成两块矩形任一块。第二轮:

值
导线 / 过孔 714 段 / 289 过孔 + 182 个 GND 缝合过孔
铺铜 24 块全填(VO-L3 L 形岛 / V12-L3 / L2 8 块 / 顶底各 7 块),截图 M6-L3-islands.png / M6-L2-gnd.png
DRC 间距错误 0 / 物理错误 0,连接性 36(= 没布完),差分对 35(USBPAIR 规则,脚本布线器不做对内等长/间距,与 §25.11 同)
没接完 16 处 / 10 个网:VO(2 块) +3V3(3 块) VBUS(2 块) SDA(2 块) VDAC: R8.2 $1N147: U2.15 $1N156 EFUSE_PG: U2.2 $1N165: R16.1 —— 全在功率列 U2/U4 细间距周围,与 §25.11 是同一类拥塞,不是这轮摆位引入的

⚠ DRC 一开始报 5 条间距错误,全是同一处:USB_DP 干线(x 48.5,从 J2 下来)在 y 12 收尾, 正压在 USB_DM 的金手指扇出过孔 (48.5, 11.75) 上 —— 扇出行的过孔是按几何直接放的, 布线器的干线收尾不查它(§24 就提过 LAUNCH_Y 那一排「不查焊盘」)。手工改成 (48.5,20)→(48.5,12.9)→(47.75,12.05)→(47.5,11.75),两条斜边到 DM 孔与旁边那颗 GND 缝合孔 (47.5, 13) 的净距算过都 ≥ 0.19。这三段不在 _blade_routes.json 缓存里 —— 下次 router.py --push(不带 --replan)会把短路那版推回去,要么先 --replan,要么推完再改一次。

⚠ pcb_route.py --clear 的 clearRouting('all') 会撞桥接的 30 s 超时,但实际执行了; 判据是读回四个铜层的线段数为 0,不是返回值。

26.6 「继续布完」:四种办法都到不了,剩下的交互式布(2026-09-09)

板上实际铜的连通性(router.check_connected 按几何并查集)只欠 5 个网 / 5 只脚: $1N147: U2.15、$1N156: U2.17 + R11.1、EFUSE_PG: U2.2、$1N165: R16.1、VDAC: R8.2 (DRC 的 36 条连接性是按焊盘对数出来的)。这五只脚的共同点:出口被自家邻脚的引出脚 / 过孔封死 —— U2.15 上方 0.25 mm 处是 EFUSE_EN 的孔 (89.5,31),只剩 0.04 mm 能动;U2.17 前面横着 $1N158 的斜线;U2.2 下面是 $1N164 的孔;R16.1 四面是 $1N151/EFUSE_FLT/+3V3 的孔, 顶层又被 +3V3 的 y=30.75 母线(x 46.5~80.25)和缝合孔那一排(y=28)封住。

试法 结果 结论
只补线(repair_route.py:在现有铜之上只布这几个网) 5 只脚照样「出不来」 不是拥塞,是脚本身出不来
把五个网排到 FIRST_NETS 最前 这五个通了,换来 20 处别的没通 出口总数就那么几个,谁先谁活
PathFinder(--pf,30 轮) 冲突格点卡在 ~600,精确修复后 31 处 §25.12 的结论没变
交错两排过孔扇出(--viafan,新写,U2/U4/U3,Ø0.5 孔) 只扇出 23 只脚,33 处 扇出落点自己在顶层也「出不来」(0.25 网格表示不了 0.5 节距的两排孔);代码留着,默认关
手工绕(hand_check.py 精确净距逐段算) $1N147 从口袋出去的四个方向全被母线 / 孔封死 要动的是别的网的线,不是补一根

⇒ 板子定格在 714 段 / 289 过孔 + 182 缝合孔,铺铜 24 块全填,DRC 间距 0 / 物理 0,欠 5 只脚。 作业单 .claude/r2/HANDROUTE-M6.md(每个网的全部焊盘坐标 + 现有铜长度 + 该先挪开谁)。 交互式布线器一条一条挪开挡路的引出脚就能拉通 —— 这是人比这套脚本强的地方,§25.12 已经说过一次。

⚠ 三条经验:

  • router.py --replan、--pf、--viafan 都会覆盖 _blade_routes.json 缓存。好的那一版备份在 _blade_routes_m6_good.json;这一轮就是靠它把板子从「20 处」的试验版恢复回来的。
  • USB_DP 收尾压 DM 扇出孔那处仍是手改(三段),恢复缓存后要再改一次(脚本在 §26.5 的坐标)。
  • 「铜分成 N 块」这类报法在缓存和板上会不一样(板上多了直连段 / 引出脚),判据只认板上读回的铜。

27. M7 落地记录:板框失踪 + B 面重排 + 自动布线复盘(2026-09-09)

用户要求:重排卡片(刀片)板器件 → 先用 EDA 自动布线 → 再优化。 并给出关键线索:之前点自动布线,EDA 提示的是**「没有板框」**。

27.1 ⛔ 根因:板框在板上一根都不剩(不是「开口」,是「没有」)

pcb_PrimitiveLine.getAll() 按层统计:layer 11(Board Outline Layer)= 0 条, pcb_PrimitivePolyline / pcb_PrimitiveArc / pcb_PrimitiveRegion 也全空。 M4b 画的 37 段板框、M6 之后的状态,全都不在了(何时被删无从追溯; 同一轮里 182 个 GND 缝合过孔也全没了,过孔只剩 65 个,铜 770 段 ≠ M6 的 714)。 ⇒ §24.6 那条「自动布线对话框秒关、0 根铜、不报错」的结论要改写: 至少最后这一次,客户端是有明确报错的,只是它弹在 toast 里、脚本不去读 DOM 就看不见。

复现与判据(这次是真的抓到了报错原文):程序化点开 布线 → 自动布线..., 勾选层,点 运行,然后读 DOM 里的 toast ——

请先绘制板框!查看更多

27.2 板框重画:缺口那 16 段不能画两份

pcb_blade.py --outline 重画之后仍然报同一句。原因是本项目的板框是拼出来的: 文档里 37 段(底边在缺口口部断开)+ 金手指封装 J1 内部的 16 段缺口。 一度试着把缺口也画进文档(53 段,文档级闭合)——报错没变, 而且 location.reload() 之后 getAll() 变成 69 段: 封装内部那 16 段在重载后也会被 getAll() 列出来,于是缺口处每一段都有两条完全重合的线。

⇒ 判据与做法:

  • 重合边 = 无效板框。按坐标分组去重(16 组),删掉文档里那一份、留封装那一份, 板上回到 53 段、逐点闭合。删完再点运行,「请先绘制板框」不再出现。
  • ⚠ getAll() 会不会返回封装内部的板框线,取决于客户端有没有重载过。 「读回 N 段」这个判据必须记清楚是哪种状态下的 N(37 / 53 / 69 都出现过)。

27.3 ⛔⛔ 真正的根因:板框画成了导线,不是折线

板框重画之后自动布线仍然一根铜不出,而且什么都不报:console.error / onerror / unhandledrejection 全钩上一条没有,fetch / XMLHttpRequest / new Worker 全钩上 一次调用都没有,getAutoRouteJsonFile() 一直返回 undefined。一度写成 「这台客户端的自动布线功能本身是死的」——错的。

是用户在客户端里一眼看出来的:选中板框,属性面板的 图层 那一格是空白的。 按这条线索去抠 DOM:

<div data-attr-key="attr-layerid" data-value="11"><span class="text_HpHUx"></span>…

data-value=11 没错(板框层),但显示文字是空的,而且属性面板给这个对象的标题是 「导线」,还带 网络 / 网络长度 两个字段。

⇒ pcb_PrimitiveLine 在嘉立创里是「导线」(铜),不是图形线。 把它建在层 11 上,客户端照样渲染成品红、DRC 也不报(M4b 起四道几何校验全过), 但板框识别只认图形图元,所以它一路认为「没有板框」。 图层 下拉里只有铜层,板框层不在选项里 —— 这就是那一格空白的由来, 也是几何验证永远抓不到这一类错的原因:坐标、闭合、外接矩形全对,对象类型错了。

改法(pcb_blade.py):板框改成一条闭合折线 pcb_PrimitivePolyline, 缺口不再靠封装拼,而是用 outline_polygon() 把 fp_edge 的缺口点列插进底边中间 (几何仍然只有 fp_edge 一个出处,这里只做平移 + 顺序调整):54 个点,首尾重合。 判据从「37 段线两两端点相接」换成 「层 11 上有且只有 1 条折线 + 首尾重合 + 外接矩形 098 × 076」,另外允许层 11 上留着 J1 封装内部那 16 条缺口导线(重复的图形,无害)。

改完选中板框,属性面板 图层 显示 板框层;点运行,toast 变成 「自动布线中...(25%)」, 铜哗哗往上涨。这一步是这一整轮的分水岭。

⚠ 顺带订正 §24.6:那张表里两条结论都要打折扣 —— autoRouting API 确实不存在, 但「GUI 点了没反应」不是客户端的毛病,是板框从来就没被认出来过。

⚠ 另外两条实测(供以后少走弯路):

  • 客户端对板框有缓存:用 API 改完层 11 之后不 location.reload(), 它仍然按加载时的状态判「有没有板框」。DRC 的连接性那一支也是同一个毛病(见 drc_read.py)。
  • getAll() 会不会返回封装内部的板框线取决于有没有重载过(37 / 53 / 69 三种读数都出现过)。 重合的两份线要按坐标去重,否则会以为板框画了两遍。

27.4 B 面重排(用户拍板「B 面全部重排」)

不动的:§7.2 那四条关键回路靠的功率链手排(U1/L1/Cin/U2/Rs1/U3 的相对关系)、 机械锚定件(K1~K4 / J5 / J4 / J1 / 七个螺钉孔)、A 面只留 5 件。 动的(全部落在 .claude/r2/pcb_place.py 的常量里,坐标是算出来的):

改动 为什么
排布器节距 PACK_GAP 1.1 → 1.8 M6 欠的 5 只脚全是「出口被自家邻脚封死」;1.1 只够过一根 0.2 的线。板面占用率只有 6%,加节距是白捡的
U4 PCA9555 (76.3, 18.5) → (48, 52),rot 仍 90 它 8×8 的本体正卡在「功率列内条 × 金手指北岸」那个口袋里,五只不通的脚全在它周边一圈。rot 不能跟着改:rot90 下 24 脚是东西两列,西列去侧键、东列去功率列,转任何别的角度都会让一整排信号绕芯片一圈
C40 改手排到 U4 的 p24/p19~21 上 交给排布器它会落到区的西南角,去耦离电源脚 5 mm 以上等于没有
EFUSE_AUX 9.5×11.5 → 11.7×16,东沿退到 84.0 给 U2 西边留 2.55 的扇出通道(M6 只有 1.55,R11/R16 就是死在这里);南沿定在 20.0 是因为货架排布器自下而上填,给到 13 会把 12 件全堆到离 U2 最远那头
U2 上下的缝 1.8 → 2.6 / 2.4;U1_Y 49.5 → 50.9 WQFN-20 上下两排脚要横着爬出去(M6 的 U2.15/17/2 三只脚死在这两条缝);抬 U1 是抵掉链条下移,否则链尾 U3 底排五只 0.5 mm 间距的脚离金手指禁布区只剩 1.67 mm
KEY 东沿 8.5 → 13.0、DIS 上沿 18.8 → 24.0、SVC_M / SVC_E 上沿放宽、SVC_R 北沿 44 → 46 1.8 节距下这几个区原来的尺寸放不下(自检直接报「放不下」)

⛔ 顺手修掉一个 M5 遗留的 bug:plan() 里把 anchors()(J2/J3/J4/J5/C60) 从排布器的障碍表里排除掉,理由是「它们在 A 面」—— 而 M6 已经把这些全翻到 B 面了, 排除条件没跟着改。M6 没暴露是因为当时没有哪个区压到连接器上;M7 的 EFUSE_AUX 一往西扩, Q1 就被摆进了 J3 的本体里。是自检(同面重叠)拦下来的,不是 DRC。

落地:83 件下发 + 读回校验(位置 / 层全部对上),DRC 间距错误 0, 连接性 317(= 一根线都还没布)。截图 .claude/r2/M7-place-bot.png / M7-place-power.png。 旧铜(770 段 + 65 过孔 + 15 块灌铜)已全部删除,删之前快照在 _blade_snapshot_20260909.json。

⚠ pcb_Document.clearRouting() 调下去不返回(30 s 超时,客户端也没弹框), 清铜只能自己按 primitiveId 分批删(120 个一批)。

27.5 M7 布局二版:从「按面积塞」改成「按连线就近落位」(2026-09-09)

用户看了第一版就指出两处,两处都指向同一个根子:货架排布器只按面积从下往上塞, 位置和这件连到哪儿毫无关系。

用户说的 根因 改法
「U2 的相关器件没有摆顺」 U2 是 WQFN-20,四条边都有脚,而 12 件外围全被塞在西边 —— 接东边 p17~p20 的四件要绕整颗芯片 拆出 EFUSE_E 区(U2 东边那条 5.4 mm 的缝),目标点精确到焊盘,一列排下来自然是 p17→p20 的顺序
「PCA9555 及其相关器件移到左下角」(用户自己拖了 U4) — U4 定在 (12.5, 15.6);⚠ 用户拖的 y=10.67 会让本体下沿落到 6.7,压进金手指区(插槽体要夹住 y<11),已抬到贴着禁布区上沿
「检查一下其他器件类似的问题」 没有判据 新写 place_audit.py,把「摆错边」变成一条能算的判据

排布器现在的做法(pcb_place.plan()):候选位置仍按 0.5 mm 扫,但选的是 离目标点最近的那个空位,目标点 = 「每个网取离本区最近的那个对端焊盘」。

三条踩过的坑,都写进了代码注释:

  • 目标点按器件中心算不行 —— U2 周围 12 件的目标点全是同一个点,排出来还是乱的;
  • 目标点按同网所有对端的质心算不行 —— C66 是 U5 的 +5V 输入电容,而 +5V 上 还挂着金手指,质心把它拽到 10 mm 外;
  • 有芯片对端时只认芯片 —— C11 是 U1 的补偿电容,同网还有 R6,按「最近」会跟着 R6 跑。

27.6 place_audit.py:「外围件摆错边」的可计算判据

⛔ 这类错 DRC 不报、几何自检不报,布线器只会报「XXX 出不来」(症状不是病因)。

判据交了两次学费:

  1. 「直线穿不穿本体」不行 —— U1.14 到 U4.14 隔着 81 mm,从本体上方蹭过去 绕行代价才 2 mm,64 处里全是这种噪声;
  2. 「绕行最短路 − 直线」也不行 —— 芯片的焊盘本来就在本体框里,线段起点落在障碍 内部,最短路直接算成无解、返回 0,于是 U1.1(EN 在西边) 配 R3(在东边) 这种 教科书式的摆错边一条都报不出来。

⇒ 最终判据是判「侧」:脚离哪条边近,那条边的外法线就是它的出线方向;外围件在反方向 (点积 < −0.3)就是摆到对面去了。再加三个门槛(对端 ≤ 3 脚、相距 < 20 mm、 绕行 > 1.5 mm 且 > 10%)滤掉噪声。连接器(脚 > 24)不判 —— 它们的脚排成一长条, 「离哪条边近」对端头的脚没有意义。

它当场抓出 R3(U1 的 EN 分压摆在了东边的 BUCK_FB 区)—— 那正是布线器一直报 「$1N128: U1.1 没布通」的病因。R3 挪进 U1 西边那个口袋(L1 顶 / U1 西沿 / D1 南沿夹出来的 1.3×2.8)之后,这条就通了。

27.7 布线:自己布,714 段 / 全部脚位接通

⛔ 官方自动布线彻底放弃(§27.3),改用 router.py。中间修掉三个布线器自己的毛病:

毛病 现象 判据
已布的铜进占用图时漏了净距(VIA_D/2 + halfw,少了 CLR) 后布的线贴着别人的过孔走 DRC「导线到过孔 0 mil」
已布的线只进了导线口径那张图,没进过孔口径那张 别人的过孔直接落在这根线上 同上
引出脚(stub_path)只判「蹭没蹭到别的焊盘」,不判过孔和已布的铜 L 形拐点贴在别人的孔边上 同上

⚠ 第三条不能当硬条件:拿它否决候选的话,「落点挑得出来、引出脚发不出来」, 一下多报 3~4 个脚「一根铜都没有」——丢一只脚比蹭 0.05 mm 严重得多。 ⇒ 占用图那一关只用来排序(先要既不蹭盘也不蹭孔的,没有就退回老判据)。

⚠ 还有一条顺序上的坑:布线器会把板上已有的铜当障碍。改完代码不 --clear 就 --replan,等于在上一版的铜上再布一遍,结果比什么都不改还差(6 → 20 条没搞定), 而且看着像是「改坏了」。

27.8 M7 结果

项 数
铜 714 段 / 2563 mm,过孔 316 + GND 缝合 131
铺铜 24 块全填;L2 是一整块没割断的地平面(截图 M7-L2-gnd.png)
板上连通性(board_check.py,按板上读回的铜做并查集) 57 个网里 56 个全连通;GND 靠铜面成网(检查器读不了填充多边形)
DRC 间距错误 4 条,全是同一件事:PCIe 缺口到 11/12 号指的铜边距 0.2 mm,而规则要 0.3
DRC 差分对 35 条(USB_DP/DM 没按差分对布)—— 底板那段本来就不控阻抗(风险 R-1),退路是 J2(D12)

那 4 条缺口间距是 PCIe 几何本身定死的:1.0 mm 间距 / 0.7 mm 指宽 / 1.9 mm 缺口宽 ⇒ 缺口边到 11、12 号指的铜边只有 (3.0−1.9)/2 − 0.35 = 0.2 mm,任何 PCIe 卡都是这个数。 ⚠ 它以前不报,是因为板框那时候是「导线」(§27.3),DRC 根本没把它当板框。 ⇒ 要么下单时和嘉立创确认「金手指缺口处铜到板边 0.2 mm 可做」,要么把缺口收窄到 CEM 的 1.6 mm(clearance 变 0.35,但防呆筋的配合余量少 0.15)。这一条需要用户拍板。

27.9 新增/改动的脚本

脚本 干什么
.claude/r2/place_audit.py 摆位体检:外围件摆错边 / 被第三个件挡住 / 去耦离电源脚太远
.claude/r2/board_check.py 从板上读回铜做并查集判连通(缓存、getNetLength、DRC 三个都不可信,见文件头的表)
.claude/r2/grid_snap.py 算焊盘的局部偏移,让 pcb_place 把件微调到 0.25 布线网格上(8 → 83 个焊盘对齐)
pcb_place.py 目标驱动排布器 + ctrl_hand(U4 卫星件跟着引脚走)+ 网格微调 + 冲突回退
pcb_route.py 缝合过孔避让已布导线(M7 的顺序是先布线后缝合,和 M6 相反)
router.py 三处净距漏洞(见 §27.7)+ KEY_* 三根排进 FIRST_NETS 最前

27.10 直角走线全部改 45° 斜切(miter.py)

用户要求「优化所有直角走线」。做成后处理脚本 .claude/r2/miter.py, 只去铜、不加铜 —— 新斜边完全落在原直角的三角形里,任何「铜到铜」的净距只会变大, 所以不用重跑布线器、也不会引入新的 DRC(实测前后 DRC 间距错误都是 4 条,一条没多)。

两轮 + 一次放宽,切了 174 个直角(改 289 段、加 174 段斜边):

轮次 切了 说明
第 1 轮 136 常规拐角
第 2 轮 28 第一轮改短了腿长之后新露出来的
第 3 轮 10 放宽「两段线宽不同」那一档(见下)

剩下的 90° 都是结构性的,不该切:

剩下 个数 为什么不切
拐点坐在焊盘/过孔上 12 拐角落在铜盘里面,本来就不是一个「弯」
T 型分支(干线直穿 + 支路 90° 引出) 104 支路垂直引出是正常画法
三段交汇且没有直穿(真拐角 + 挂了根支路) 3 切角会把第三段从拐点上拽下来,要另外补线,收益不值
腿太短(< 0.2 mm) 10 切角深度会超过腿长的一半

⚠ 宽窄不同的拐角只在两边都 ≤ 0.45 mm 时才切,斜边取窄的那个宽度: 取宽的会在窄腿两侧多出 (W−w)/2 的铜 —— 那是加铜,可能破净距; 取窄的等于把拐角缩到窄腿口径,对 0.8 mm 的 12V 干线就是掐脖子。 实测这一档只有金手指那 9 个「地指 0.2 接地母线 0.4」加一个 +3V3 引出,都是小电流。

⛔ 顺序:布线 → 下发 → 缝合过孔 → 斜切 → 铺铜。 router.py --push 会按缓存重画,斜切会被覆盖,重跑布线器就要重跑 miter.py。

27.11 ⛔ 斜切第一版留下了「小碎块」——端点归并写成了「固定分桶」

用户放大 KPAD_VUP / $2N139 那一带,圈出两处悬空的小铜块。根因在 miter.py:

def key(p): return (round(p[0] / EPS), round(p[1] / EPS))   # ⛔ 错的

这是把坐标切成固定的桶,相差 0.011 mm 的两个点会掉进相邻的两个桶。 后果:同一个拐角被看成「两个各只连一条线的点」,两条腿被当成互不相干的段 —— 于是同一个角被切了两次(一次 d=0.25、一次 d=0.125),原来的直角腿反而留在板上, 变成 0.125 mm 的碎块。板上一共留下 31 处断头铜。

⇒ 改成空间哈希 + 就近归并(在 3×3 相邻桶里找已有代表点,距离 ≤ EPS 就用它)。

这一类错三道自动判据全过:DRC 不报(碎块没有间距问题)、 board_check 不报(每个网仍然是一整块,碎块挂在网上)、router_check 不报(它看的是缓存)。 ⇒ 新写了一条判据 断头铜:线段的某个端点既不挨别的线段、也不挨过孔/焊盘。 修完从 31 处降到 7 处,剩下的都是布线器本来就有的: 4 处是金手指地母线故意外伸 1 mm(finger_escape 里那句「整段都被对排信号占着 → 母线往外伸」), 3 处是 0.5 mm 的引出脚余量。

⚠ 顺带一条操作顺序的教训:router.py --push 不会先清,重复 push 会把整套铜再加一遍。 这一轮是靠 --clear + 重新 --push + 重新贴两处手改的过孔,才把碎块彻底洗掉的。

⚠ miter.py --push 现在自动跑到收敛为止(新加的两条 45° 斜边之间可能又是直角, NE 接 NW 就是 90°):实测 3 轮 —— 148 + 67 + 12 = 227 个直角。


28. M8 落地记录:底板 PCB(2026-09-09)

BASE-PCB = 7b9524b6aaf6f235,2 层,110 × 125,四角 R5。 脚本:pcb_base.py(板级几何,唯一事实来源)/ rules_base.py / place_base.py / route_base.py / pour_base.py;miter.py、board_check.py、drc_read.py 加了 --base。

28.1 板框又是那个坑(第二次了)

建工程时文档里留着 4 条 pcb_PrimitiveLine,画的正好是 110×125 的矩形,层号 11。 和刀片 M4b~M6 一模一样:渲染成品红、DRC 干净、外接矩形量出来分毫不差, 而客户端不认它是板框(§27.3)。已删掉,改成一条 45 点的闭合 pcb_PrimitivePolyline。

⇒ 教训固化成判据:pcb_base.verify() 里「层 11 上还有导线」是一条硬错误, 不是警告。新建任何一块 PCB 文档,第一件事就是把默认板框删掉重画。

28.2 三条朝向:推导出来,再用读回断言钉死

几何验证证明不了「朝向对」。这三条都做成了 place_base.verify() 里的断言, 从板上读回的焊盘坐标判,不是从计划判:

# 断言 错了会怎样
1 U32 下行口在北边(rot 270) 转 90 就朝南,五对 D± 要从芯片底下绕出来
2 U32 北排 USB1 在东、USB5 在西 决定了插槽的物理顺序(见 28.3)
3 插槽 rot 90 ⇒ +12V 在南、D± 在东列 12V 针跑到北边就离入口链最远

封装的原生朝向全部是读回来的(_base_pads.json),不是照着手册猜: U32 的 pin1~16 在 dx=−4.45(西边)、插槽的 A 排在 dy=+3.6、U20 的天线在 +y (三面有焊盘、北面 7 mm 没有)。

28.3 ⛔ 插槽的物理顺序是反的:西 → 东 = J38 J37 J36 J35 J34

U32 转 270° 之后,北排的 x 顺序是 USB1 最东、USB5 最西。 若按位号自然顺序把 J34 摆在最西,五对 D± 就必须互相交叉; 两层板上交叉只能打过孔换到 L2 —— 那正好是在 D± 走廊的正下方割地平面, 是 §6.2 第 1 条明令禁止、也是整个 2 层方案成立的前提。

⇒ 宁可位号顺序看着别扭。丝印上要写清楚哪个槽是哪一路, 装配和固件调试都按丝印来(EFUSE_EN1 对 J34 对最东那个槽)。

28.4 hub 带只有 28 mm,U32 的 y 是算出来的不是放出来的

hub 带 = 刀片投影下沿 15.5 到槽体南沿 43.5,28 mm 是几何定死的 (刀片 98 宽居中压在 42 长的插槽上,两边各露 28)。里面要塞四样东西:

mm 干什么
12V 横脊 5.0 y 15.8~20.8
U32 南边逃逸 4.3 7 根 strap + HUB_RST + VBUS_DET
U32 本体 9.75 y 25.1~34.9
U32 北边 D± 扇出 8.6 五对 D± 在这里分东西两路

⛔ 第一版把 U32 放在 y=37(横脊 8 mm),北沿离插槽焊盘只剩 1.6 mm —— 一对 D± 就要 2.7 mm,扇不开。布线器的现象是 USB2 布了 0 段, 而摆位自检、朝向断言、DRC 全过。⇒ 拥塞类的错只有布线器会报,摆位阶段看不出来。

28.5 ⛔ 9 A 的 12V 分配:三版才对

版本 做法 为什么不行
v1 入口链交给排布器 「离目标最近」把 F1/Q1/D1 摊到整条 110 mm,VIN_FUSED 一个网的焊盘外框 42 mm 宽,四段铜面互相重叠 ⇒ 入口链整条手排
v2 槽阵南沿一条 4.7 mm 横杠 五对 D± 要竖着穿过它,两层板上一根竖线就把横杠整个切断,剁成五段各自找电 —— 而铺铜管理器 / DRC / 断面校核三个都只说「有铜」
v3 每槽一根铺铜「齿」走两列焊盘之间那条 5.2 mm 无盘带 槽的第 65 脚(屏蔽脚 3.0×5.0,接 GND)正坐在那条带的正中,断面量出来 0.00 mm。典型的「按焊盘外框想当然」——外框里看着空,其实有一只大脚
定稿 BUS_IN(6391 × 0.816.0) + SPINE(291 × 15.820.8),五条支路交给布线器画 1.5 mm 支路只有 1.5 A,1 oz 外层 1.5 mm 带 3.2 A;脊上最大 ~6 A(进料在东段,往西只带 3 个槽 + 两颗 Buck),5 mm 够

断面校核(pour_base.py)比 R1 那一版严了两处: ① 逐刀切取最窄一刀(第一版取了最大值,等于没查); ② 跳过串联元件本身的窗口 —— 最窄的一刀永远落在 2512 分流电阻或 DC 座的三只脚上, 量到的是元件宽度不是铜宽度。元件本身的载流由选型保证。

⚠ VIN_RAW 1.70 mm / VIN_FUSED 6.35 mm 不强制:瓶颈是 DC-005 的三只脚和 1206 保险本身,板上加铜救不了那一处 —— 和「插座超额定 9 A」是同一条已知风险(设计文档 §22.6)。

28.6 布线器必须知道铺铜的存在

顶层的电源铜面按各自的网打进占用图(route_base.pour_blocks())。 不喂进去的话,布线器会大大方方从 12V 母线中间穿过去,铺铜时那根线把母线整段切断。 标成本网的归属号之后:别的网进不去(被逼到底层跳线或绕行),+12V 自己照走不误。

⚠ 「逼到底层」在这里是安全的:母线全在 y < 21,位于 U32 南边, 头上没有任何 D±(D± 是从 U32 北沿往北走的),不违反 §6.2 第 1 条。

28.7 两层板给布线器加的两条约束

  1. 底层是完整地平面 ⇒ 全层收过路费 BOT_PEN=6(不封死:§6.2 允许 D± 走廊之外跳线)。 ⛔ 过路费要在每次 pen_pads 之后重打 —— 它头一句就是 reset_pen(), 直接写 g.pen 会被静默清掉,现象是底层突然多出一堆长线。
  2. D± 分两相布:第一相七对只走顶层(底层整层封死);第二相把第一相的铜按 1.5 mm 膨胀在底层封死,再布其余所有网。于是任何跳线都不可能钻到 D± 底下。

差分对靠「贴着走」的过路费成对:DP 布完之后给整个顶层打一层过路费、 只把 DP 铜周围 2.2 mm 内留成 0,DM 自然贴着走。中心距落在网格的 1.5 mm (1.2 线宽 + 0.3 缝),Zdiff 比 §6.3 那张表(1.2/0.2 → 94 Ω)略高,仍在 90 Ω ±15% 内。

⛔ 第一相的顺序是「离 Hub 由远到近」,不是 USB1..USB5。按编号布的实测结果: USB4(→J37)先占了扇出带的西半边、绕了 41 段,紧接着更远的 USB5(→J38) 一段都布不出来。扇出带只有 8.6 mm 高,最远的必须先挑路。

28.8 ⛔ 通孔焊盘:router.py 原来直接漏掉

刀片是全贴片的,build_grid 里一句 if lay not in LAY: continue 就把 layer 12(多层)的焊盘全滤掉了 —— 底板有 DC 座 / 两个风扇座 / 应急排针 / 两颗直立电解 / 四个 M3 孔,漏掉的后果是布线器直接从通孔焊盘上压过去。 (这次是响的:pad_nodes 拿 g.own[12] 去查,直接 KeyError。算运气好。) ⇒ route_base.split_th() 把每只通孔脚拆成两条记录:顶层那条参与布线, 底层那条只当障碍(脚号加 #b 后缀,bypad 里滤掉)。

⚠ 四个 M3 安装孔是 pcb_PrimitivePad、不是元件引脚,不在 _base_pads.json 里。 靠 pcb_base.phone_holes() 单独喂给布线器(那个函数名是从刀片沿用的, 在底板上返回的是安装孔)。

28.9 ⛔ 线宽「按焊盘封顶」对电源网是静默降载

route_groups 会按「这个网最小的那只脚」给干线封顶。实测把 +12V 从 1.5 压到 0.30、 VIN_SW 从 2.0 压到 0.30 —— 0.30 mm 1 oz 外层只带 0.65 A,而槽支路要 1.5 A。 铺铜只盖到母线,支路那一段没有铜面兜底。 ⇒ 新增 router.NO_CAP(默认空,刀片行为一字未变),底板把七对 D± 和全部电源网放进去。 缩颈仍由 stub_w 负责(只缩引出脚,不缩干线)。

28.10 用户拍板:最远一路 D± 接受 ~70 mm

§6.3 预估 41 mm,前提是 §6.2 第 3 条「D± 排在靠 Hub 那一端的针位」。 但 M2d 定稿的针位表把 USB_DP/DM 放在 B14/B15 —— 换算到底板 y=63/64, 正好在 42 mm 长插槽的正中。Hub 只能坐在槽阵南边,于是每一路都要 「出脚 → 沿 y≈40 走 x → 拐进走廊 → 北上 20 mm」,而端槽的 x 距离 40.6 mm 是几何定死的。

⇒ 最远 ~70 / 最近 ~30。仍远短于 R1 载板的 92 mm,全程 L2 完整地平面做参考, 且 J39~J43 五个 D± 退路座(D12)本来就是为这一条留的。 §11 里 M5 的验收判据「六对 D± ≤45 mm」据此改写成 ≤75 mm。

改针位到 A5/A6(空针,y=52/53)只能省掉 11 mm 的 y 绕行,x 方向那 40.6 mm 省不掉, 而代价是刀片原理图 + 已布完线的刀片 PCB 全部返工。不划算,不做。

28.11 ⛔ 用户拍板:底板上的 5 个 D± 退路座 J39~J43 全部删掉(2026-09-09)

原理图 A5B-SLOTS 与 PCB 两侧都已删干净: 原理图 138 件(verify_sch 六项全过 / xpage 真正漏接 0 / port_audit --r2 BASE 347 个可疑 0), PCB 138 件逐件对上,设计规则审计六项仍全过。

连带影响两条,都要写进设计文档:

  1. 底板侧不再有 D± 退路 —— USBn_DP/DM 从 U32 直达槽针,一条路走到黑。
  2. §28.10 那条「接受 ~70 mm」的理由少了一条:当初拍板时的依据之一是 「J39~J43 本来就是为这一条留的」。现在没有退路座了,D± 只能一次做对。 ⇒ 首板务必按 §6.3 的做法实测:adb 长稳 + 眼图;不合格就只能改板。
  3. 刀片上的 J2(B4-EDGE 那个同款 A1251 4P 座)失去了对端。它还留在刀片上 (刀片 PCB 已布完线,不动),但除非另配线束,否则用不上。D12 这条退路实质上作废。

28.12 ⛔ 重抓封装外框必须按 rot 反转回封装朝向

_base_bbox.json 是从板上读回来的,读到的是板坐标的外框。摆位下发之后再抓一次, 转了 90° 的件(5 个插槽、J1)宽高就是反的;而 place_base.wh() 又会按 rot 再转一次 —— 转两次等于没转,自检立刻报「五个插槽互相重叠 + 出板」。

还有一层更隐蔽的:p.x/p.y 是板坐标,而 pad[1]/[2](焊盘宽高)是封装坐标。 件转了 90° 之后不把焊盘的宽高也换过来,就是拿转过的中心配没转的尺寸 —— 实测把插槽的 42.0×9.2 量成 44.0×7.9(多边形焊盘除外,它算出来本来就是板坐标)。 两处都修在 place_base.dump_bbox() / BBOX_JS 里。

28.13 每对 D± 一条专属车道

U32 北边那条扇出带只有 8.6 mm 高,一对 D± 就占 2.7。A* 只认「最短 + 过路费」, 先布的那一对会在带子里蜿蜒(实测 USB5 一对布出 37 段)、把带子占满, 后布的那一对一段都布不出来。三次尝试的账:

做法 结果
按 USB1..USB5 编号顺序布 USB5(最远)布 0 段
改成「离 Hub 由远到近」 USB5 通了 37 段,轮到 USB4 布 0 段
再关掉「顶层偏好横向」(LAYER_DIR) 锯齿变本加厉,USB1 一对 55 段
给每对分一条 y 车道 USB1 一对 12 段,路径是干净的 L 形

车道:USB1/USB5 → y=42.1(最远的两路走最靠北那条,爬升最短)、 USB2/USB4 → 39.4、USB3 → 36.7。布某一对时把扇出带里不属于它那条道的格点在顶层封死, 只开两个口:U32 本体那一段(要从焊盘竖着爬到自己的道上,必然横穿别人的道) 和目标走廊那一段(要从道上竖着拐进走廊)。

⚠ LAYER_DIR 在底板上是空的(八个方向同价):刀片的「顶层横向 / 底层纵向」到了底板 变成「每往北走一格贵 3 倍」,而 D± 全是南北向的。分车道之后不再需要那条偏好来规整路径。

28.14 ⛔ ESP32 天线原来是埋在板中央的(2026-09-09 用户看出来的)

用户一句「esp32 天线朝向有问题」。查下来比「朝向」更严重:模组根本没在板边上。

原来 U20(ESP32-S3-WROOM-1)在 (17.0, 96.0) rot=0,天线朝北,净空只有 place_base 里手写的那一块 20 × 7.5(焊盘北沿往北)。实测周围:

方向 天线尖到最近的金属
北(正前方) 1.0 mm —— 净空一到头就是重新铺起来的整块地平面
北 3 mm 风扇带的 RT601/RT602/R660/R661
东 / 西 净空只比模组宽 0.5 mm,出去就是铜
到真正的板北边 还有 12.2 mm,中间全是铜和器件

而设计文档 §PCB 要点写的是「天线区域下方禁止铺铜、禁止走线,模组放板边」—— 「放板边」那半条从来没做到,「禁止走线」那半条根本没人执行(见下)。 天线正前方 1 mm 一整块地平面 = 给它加了块反射板,谐振点跑掉。

⇒ 用户拍板:西板边 + 板材挖缺口。U20 转 **rot=90(天线朝西)**挪到西板边, 天线那 7.5 mm 下方的板材整块挖掉,天线完全悬空、背对着 5 片刀片上的手机金属。

几何(全部从 _base_pads.json 量出来,不抄封装库)

模组本体 18.0 × 25.5;焊盘外框实测 19.002 × 18.99(三面出脚,每边比本体宽 0.5) ⇒ 天线段 = 25.5 − (19.0 − 0.5×2) = 7.0 mm,ANT_LEN 取 7.5 留余量。

pcb_base.ANT_NOTCH = (0.0, 85.0, 7.5, 107.0)   # 板框在西边内凹出这一块
place_base.hand()['U20'] = (18.0, 96.0, 90)    # 焊盘西沿 8.5,离缺口边 1.0

天线段 x 1.08.5,其中 x 7.58.5 那 1 mm 压在无铜的 FR4 上(天线根部,可接受), 其余整段悬空。内角由 Ø2 铣刀自然带圆角,板框里不必画。

⛔ 三处「几何验证抓不到」的,这次一起补上

  1. 净空写死了朝北。 antenna_keepout() 原来是「焊盘北沿之外 7.5 mm」一个硬编码矩形。 模组一转 90°,净空还留在北边 —— 铺铜照样把铜铺到天线底下,而 摆位自检 / DRC / board_check / 几何校验一条都不会响。已改成跟着 rot 转 (0/90/180/270 四个方向,rot 是 CCW,与 U32 rot=270「西→北」同一套语义)。
  2. 布线器根本不知道有净空这回事。 place_base 认、pour_base 认, route_base 里一个字都没有 ⇒ A* 可以大大方方从天线底下穿线过去。 已加 ant_blocks():净空 + 缺口两层全封死。 ⚠ 净空只往外膨胀(西/南/北),朝模组那一侧不膨胀 —— 否则把最西边几只脚的出口封死。
  3. 铺铜的几何是矩形不是板框。 pour_base.tiles() 按 BW × BH 切瓦片,不认板框折线, 不把缺口喂进 keepouts() 就会往板外的空气里铺铜。

另外 _base_bbox.json 只抓焊盘外框(19 × 19),模组本体 25.5 里那 7 mm 天线 从来没进过碰撞模型 —— 一直是靠 place_base 里那条手写净空撑着。

验收(读回,不是算出来的)

  • 板框折线读回 49 点,缺口四点 (0,85) (7.5,85) (7.5,107) (0,107) 对上,外接仍 110×125
  • 摆位 138 件逐件对上,新增第四条朝向断言:pin1/pin40(紧挨天线那一头的两只脚) 的中点必须在模组西侧,且天线尖(中点 − ANT_LEN)落在缺口的深度里。 ⇒ 以后谁改 U20 的 rot,这条会当场响。
  • R610 被排布器自动让开到 (29.5, 92.25);缺口以东最近的件 22 mm
  • 截图 .claude/r2/M8-ant-notch.png —— 天线蛇形朝西、整段悬在缺口里

代价(已知、可接受)

转 90° 之后引脚面全变:pin1~14(FAN_* / PRSNT / USB6 D±)→ 南排、 pin15~26(EFUSE_EN1~5)→ 东列、pin27~40(I²C / NTC / UART)→ 北排。 风扇那几根要绕模组东侧往北走 ~40 mm,都是低速信号。

29. M9:底板整块重做 —— 槽阵转 90°(2026-09-09 用户拍板)

29.1 ⛔ 为什么 M8 的分带布局在两层板上是死的

M8 摆位定稿之后第一次整板布线,314 条连接里 173 条布不出来,四轮打平 (173 / 174 / 175 / 173),换 BOT_PEN(6→2,让跳线下底层)更差(178,底层铜从 23% 涨到 30%)。 诊断(diag_escape:只建一次占用图,逐脚查有没有起步格点):

一个起步格点都没有的脚:3 只 / 共 420 只   (全在 J23 USB-C 的 VBUS 上)

⇒ 不是「扇不出来」,是「有出口但没路」。再按网看分布:

网 没搞定 说明
+3V3 45 47 只脚的大网,A* 当一棵树布
+12V 20 全是 J34/J35/J36 的 5 只 12V 针
+5V / +3V3_HUB 6 / 5
VDAC1~5 / SCL / SDA / INT# / PRSNT# … 97 几乎全是 ctrl 带 → 槽

根因是一道几何上的横墙:五对 D± 在扇出带(y 28.943.5)里是横着跑的, USB5(去最西槽)和 USB1(去最东槽)共用 y=41.4 那条道,两段拼起来 x 24.5 一直到 105.1,横贯整块板。而 12V 入口在南(y<16)、槽针在北(y 4850), 中间只有两处竖井能穿:西 23 mm、东 3.4 mm。穿过去之后没有横向通道—— 槽阵那 42 mm 被 5 个槽体 + 每槽两端 5.0×3.0 的屏蔽脚横向堵死(这正是 「齿曾经也是铺铜、断面量出来 0.00 mm」那条),唯一的横向路是 ctrl 带, 而它塞着 57 个件、还要过 7.5 A(要 8 mm 净铜)。西边那条还正好撞上新挖的天线缺口。

⇒ 槽 3/4/5 的 12V 在两层板上没有合法路径。 不是布线器不行,是拓扑不成立。

29.2 用户拍板的解法:槽阵转 90°,D± 走西缘、电源走东缘

槽体长轴沿 x、五片刀片沿 y 堆叠。于是走廊变成横向的, D± 从西边进、12V 从东边进,走廊里全是平行车道,一个交叉都没有。

判据来自针位实测(把槽转成 A1 端朝东):

东  x 74.5  +12V(5)      ← 紧贴东缘,12V 铜墙只进走廊 2.5 mm
    x 70.5  SCL/SDA      x 67.5  +3V3(3)     x 64.5  EFUSE_EN / INT#
    x 59.5  D±           x 57.5  VDAC        x 54.5 / 41.5  +5V
西  x 42.5  PRSNT#

x > 72 只有 +12V 一个网 ⇒ 12V 的铜可以在每条走廊东端做成「顶天立地」的一堵墙 (同时够到上下两排焊盘),而不挡任何别的东西。这条写进了 pcb_base.selfcheck(), 它是新布局能成立的判据本身。

29.3 定稿几何(pcb_base.py 是唯一事实来源)

槽心 y   22.86 / 43.18 / 63.50 / 83.82 / 104.14   间距 20.32(机械定死),阵列比板心北移 1 mm
走廊     0~18.26 | 27.46~38.58 | 47.78~58.90 | 68.10~79.22 | 88.42~99.54 | 108.74~125
纵向     西区 0~29(U32 + D± 通道 29~37 + ESP32 + DAC/mux)| 中区 37~79(槽体)| 东区 79~110(12V)
12V      南带进料 x93~109.5 → 东缘高速路 x99.5~109.5(10 mm,9 A 要 ≥8)→ 6 堵铜墙 x72~99.5
分区     input 0~18.26(高件)| array(限高 8)| fan 108.74~125(高件)

⚠ 阵列北移 1 mm 是被 DC-005 的 14.5 mm 桶身逼的(南带 17.26 差 1 mm)。 ⚠ 槽体长轴中心取 x=58 不是板心 55:西区要塞下 ESP32 的「天线 7.5 + 焊盘 19 = 26.5」。

29.4 ⛔ 这一轮又交了三处「几何验证抓不到」的学费

  1. 12V 铜墙没伸进槽体 ⇒ 一只 12V 脚都碰不到。焊盘中心距槽心 3.6、盘高 2.0, 占的是槽体边缘往里 0~2.0 那一段;只画走廊本身的话铜墙一只脚都够不着, 而铺铜管理器和 DRC 都不会响。RIB_OVER = 2.0,判据是「10 排 12V 焊盘全被盖住」。
  2. D± 焊盘在槽体里(y = 槽心 + 3.6,比走廊南沿还低 1 mm)。 按走廊边界封锁「不属于本对的地方」= 把目标本身封死 ⇒ USB1 布了 0 段,看着像拥塞。
  3. 槽针是 1.0 mm 脚距,1.2 mm 的 D± 干线在它四周一个起步格点都没有 (实测 J34.46 = 0)。M8 侥幸能布是因为那时槽转 90°、焊盘长边(2.0)正好顺着走线方向; 转过来之后长边朝南北,侥幸就没了。⇒ pair_escape():槽针 / U20 / USB-C 三处 都先用 0.25 mm 细线扇到 1.5 间距再起干线(和 hub_escape 同一套办法)。 ⚠ USB-C 那种一网两只脚的(A6/B6 都是 DP)要挑分得最开的一对,挑内侧会一出脚就压。
  4. 顺带修掉 pour_base.tiles() 一个真 bug:两个禁区 y 区间嵌套时切点会配错对 (天线缺口 84.5107.5 套着天线净空 86106),GND 瓦片照样铺进缺口 —— 只有 selfcheck 那条「压进净空区」看得出来。已改成先合并区间再配对。
  5. 阵列北边要留一条 4 mm 过道(DP_N_LANE):最北那槽的 D± 焊盘在北排, 北侧走廊就是风扇带本身,不留的话逃逸落点掉进风扇块里(J38.launch 起步格点 0)。

29.5 ⛔ ESP32 的 EFUSE / PRSNT 引脚重新分配(2026-09-09 用户提出)

槽阵转 90° 之后,五个槽沿 y 从南到北是 1→5,而 U20 上这两组脚正好是反的:

U20 东沿(南→北):EFUSE_EN5  EN4  EN3  EN2  EN1      ← 与槽序完全相反
U20 南沿(西→东):PRSNT4#  PRSNT3#  PRSNT2#  PRSNT1#  ← 先转东的应该在最东

五根线因此互相全交叉,两层板上每个交叉都要打过孔换层。这不是布线器的问题, 是引脚分配的问题 —— 布线器只会报「出不来 / 没布通」,那是症状不是病因。

组内互换零电气风险:EFUSE_EN* 是普通 GPIO 输出、PRSNT*# 是普通 GPIO 输入, 全部走 GPIO matrix;互换不碰 strapping(IO0/45/46)、不碰 ADC1(NTC 要 IO1~IO10)、 不碰 USB PHY(IO19/20)。换的只是固件里的编号。

定稿(模块脚号 → 网;括号是 WROOM-1 的 IO 号)

模块脚 换前 换后 IO
17 EFUSE_EN5 EFUSE_EN1 IO9
18 EFUSE_EN4 EFUSE_EN2 IO10
19 EFUSE_EN3 EFUSE_EN3 IO11
20 EFUSE_EN2 EFUSE_EN4 IO12
21 EFUSE_EN1 EFUSE_EN5 IO13
8 PRSNT4# PRSNT1# IO15
9 PRSNT3# PRSNT2# IO16
10 PRSNT2# PRSNT3# IO17
11 PRSNT1# PRSNT4# IO18
22 PRSNT5# PRSNT5# IO14

⚠ 固件还没跟:firmware/main/rail_cfg.c 的 k_cfg 是 R1 的表 (EFUSE 39/48/6/41/8),R2 底板的固件尚未开写,所以这次换脚当前不影响任何代码; 但写 R2 固件时必须按上表,不能沿用 R1 那张。

怎么改的(脚本 pinmap_base.py / pcb_pinswap.py)

⚠️⚠️ setState_Net 对 netport 是坏的(R1 pinmap.py 2026-09-06 实测): 调完网名变空字符串、标签也没了,而几何验证抓不到。⇒ 端口只能删掉重建 (createNetPort,方向从 getState_Component().name 读回原样传回去)。

PCB 侧没有走「从原理图导入变更」对话框:那条路按内部通道 ID 重新配对, R1 §交接二 踩过一次(配错一格,把一个本来正确的风扇块打乱,要 pcb1_uid_sync.py 才救得回来)。 这里只有 9 只脚换名、元件身份一个没动 ⇒ 定点改焊盘网名更安全,判据也简单:读回逐个对上。

验收:原理图端口读回 8 个逐个对上;xpage 每个 EFUSE_EN 2 个端口 / 每个 PRSNT 3 个, 真正漏接 0;PCB 焊盘读回 9 只脚逐个对上。


30. +3V3 铜墙(2026-09-10 用户拍板)

30.1 为什么要做

M9 第一次整板布线,158 条没布通里 +3V3 一个网占 46 条(47 只脚,全网崩)。 原因和 §29.1 那道横墙不是一回事 —— 这次是网太大:A* 把 47 只脚当一棵树布, 一只脚出不来就整棵树塌,摆位动一点结果就翻天。 ⇒ 与 12V 同一套办法:脚位那一段直接做成铜,脚从 A* 里摘掉。

30.2 ⛔ 3V3 的墙不能像 12V 那样顶天立地

12V 之所以能做成一堵横贯走廊的墙,是因为 §29.2 那条判据:x > 72 只有 +12V 一个网。 3V3 不在东缘尽头,而在信号中间 —— 把槽针按 x 排开就看得很清楚:

南排 … GND(67)  EFUSE_EN(70)  3V3(71)  3V3(72)  NC(73~76)  GND(77)  12V(78,79)  GND(80)
北排 … GND(67)  INT#(70)      NC(71)   NC(72)   3V3(73)    GND(74)  SDA(75)  SCL(76)  GND(77)  12V(78~80)

每个槽的 SDA_i/SCL_i 在北排 x 75/76,要一路往西去 U35(x≈10~16)。 ⇒ 任何一条从 x>73 连到 x<70 的顶层南北向铜,都会把这十根线拦腰截断, 而布线器只会报「没布通」,DRC 和铺铜管理器一个字都不说。

⇒ 定稿:墙只在槽体那一段(顶层),走廊那一段走底层桥。

件 层 几何 事实来源
五块槽墙 L1 每块 5 个同网矩形,x 70.60~73.40,y 槽心 ±6.0 pcb_base.wall3v3_rects()
四段走廊桥 L2 x=72.0,宽 0.8,长 9.52,两端各一个过孔 pcb_base.wall3v3_bridges()
北端到 U19/L2 — 交给 A*(一条普通短网,不被 I²C 挡) route_base

代价是地平面上多四道 9.5 mm×0.8 的窄缝,都在 x=72。 D± 全在 x<66,不碰 §6.2 第 1 条(D± 走廊下方一刀不许割)。

30.3 ⛔ 墙的 x 逐排不同:一个方块盖不住两排,还会压上 NC 针

南排的 3V3 在 71/72、北排的在 73,而它们各自旁边就是没有网的 NC 针 (南排 73、北排 71/72)。一个 70.6~73.4 的方块会同时压上 NC 针 —— 铺铜会绕开它们、把墙在针排上切碎,而铺铜管理器和 DRC 都只说「有铜」。

⇒ 拆成五段同网矩形(同网重叠是允许的,12V 那几块本来也是接在一起的):

走廊帽  x 70.60~73.40   y 槽心−6.00 ~ −4.85     整宽,给桥的过孔一个圆整落点
南段    x 70.60~72.40   y 槽心−4.90 ~ −2.30     穿过南排,盖住 71/72
中段    x 70.60~73.40   y 槽心−2.35 ~ +2.35     两排之间那 5.2 mm
北段    x 72.60~73.40   y 槽心+2.30 ~ +4.90     穿过北排,盖住 73
走廊帽  x 70.60~73.40   y 槽心+4.85 ~ +6.00

x 全部从 PIN_U 算(EN 针右沿 +0.25 / GND(74) 针左沿 −0.25 / NC 针各让 0.25),不手抄。

30.4 判据

pour_base.wall_check()(拿实测焊盘表比,三条缺一不可):

  1. 15 只槽脚全被盖住(与 12V 那条「10 排焊盘全被盖住」同理);
  2. 一只异网针都不许压到,NC 空网也算异网;
  3. 桥的过孔要落在墙里,否则过孔与铜面靠「碰巧」相接。

⚠ board_check 里 +3V3 从此进 PLANE 名单(靠铜面成网),并新增 covered(): 被计划中的同网铜面盖住的脚先摘掉,否则每次都刷 15 条假漏。


31. 底板 PCIe 插槽再旋转 180°(2026-09-10 用户拍板)

BASE-PCB 上 J34~J38 从 M9 的 rot=180 统一改为 rot=0,已通过 EasyEDA 桥接定点下发,五个读回角度都是 0°。其他 133 件坐标未随之移动。

该变更把长轴针位左右互换:

网络组 M9 方向 新方向(约)
+12V 东侧 x=80 西侧 x=47
D± x=64~65 x=62~63
+3V3 x=71~73 x=54~56
+5V / PRSNT# 西侧 东侧 x=79~80

所以 §29 / §30 的“12V 东侧高速路 + 铜墙、3V3 槽墙”几何全部作废, 不能把旧铜保留下来凑数。旧导线 / 过孔 / 铜面已清空,两个下发脚本加了 SLOT_ROT != 180 硬阻断。底板当前只是经机械方向确认的布局稿,重做电源/信号分区与布线前不可投板。

读回截图:.claude/r2/M10-slots-rot180.png。


32. M11:按原理图功能模块优化底板布局(2026-09-10)

插槽方向改为 rot=0 后,不在旧坐标上做局部挪件,而是把整板按电源流向与原理图页功能重新分区:

区域 几何 原理图功能模块
西侧功率干道 x=0.5~32.5 A1-INPUT 的 12V 输入/保护/检流 + 五槽 12V 分配
中部槽阵 x=25.5~67.5 A5/A5B-SLOTS,南→北 J38~J34
东侧高速通道 x=67.5~81 A4-HUB 到五槽的 USB2 D±,通道内不放件
东侧控制列 x=81~110 A4-HUB + A3-CTRL:U32/U20/U35/U6/U7/U31
南带 y<18.26 DC 输入链 + 上行 USB-C
北带 y>108.74 A2-AUX 两路 Buck + A6-FAN + J33

槽阵中心改为 x=46.5,使东侧正好留出 13.5 mm 高速通道。U32 在东侧且下行口朝西; USB1 在北、USB5 在南,所以槽位号的物理顺序同步反转,保证五对 D± 不交叉。

模块内不只按页聚类,还按实际焊盘位置收紧关键环路: C1/R1/DZ1 贴 Q1 GATE;C734/C735 回到 U30/L3;C737/C752/C753 围绕 U31; C603/C736/C739 贴 U20 EN/NTC;C742/C743 贴 U32 的 VDD18/VDD18PLL; U6/U7 的参考 RC 按新方向的引脚侧重排。

ESP32 天线转向东边,板框缺口改为 x=102.5~110 / y=86~108。读回验收: 138 件坐标/角度全对,五槽均 0°,板框 49 点闭合,4 个安装孔齐, 重叠/越框/限高/槽带侵入/天线净空均为 0。截图 .claude/r2/M11-functional-layout.png。

当前刻意保持纯布局状态(导线/过孔/铜面 0/0/0)。旧布线器仍是西侧 D± 通道假设, 已有硬阻断;它按新通道镜像重写、再跑连通性/DRC 之前,底板不可投板。

32.1 相关 R/C 的二次收紧(M11b)

按原理图页聚类只是第一层;第二层用板上读回的真实焊盘坐标,检查每颗 R/C 到直接相连芯片脚的距离与所在侧。 重点改动:

  • U19/U30:C7/C731/C732 回到 12V 输入脚,C9/C10 回到 3V3 输出;
  • U20:C601/C602/R601/C603 收紧 3V3/EN,R606~R610 顺着 PRSNT GPIO 实际脚序排列;
  • U35:C604/R602/R603 收紧 VCC/SDA/SCL;
  • U6/U7:C607~C612/R614~R617 按实际脚侧分两组,C608/C611 的信号端通过 180°旋转朝向芯片;
  • U32/U31:C744~C751 是 Hub 去耦阵列,R710/R711/R712/R720/R716 是 strap/reset 阵列, 两列物理分开;C737/C752/C753 围绕 LDO;
  • Q1:C1/R1/DZ1 回到 GATE/VIN_FUSED 引脚。

结果:明确的 6777 mm Buck 去耦跨板问题清零;审计剩下的电容距离提示中, 4 条是 3.03.2 mm,另 1 条是两风扇座共用的 C738(6.3 mm,位于两座中间)。

北边保留相邻的 J27@x70 / J26@x83。J33 是 ESP32 的 GND/TXD0/RXD0/EN/IO0 应急口,用户在客户端定稿为 (107.06,76.83,270°):位于 U20 下方的右板边,从侧边接插,不再占用北侧风扇模块。 J33 的本体横向范围约 x=105.8~108.3,而刀片投影只到 x=95.5,所以虽然 y 落在槽阵带, 11.5 mm 插座高度仍无机械干涉。布局检查器的限高判据已从“只看 y”改为“同时落入 x/y 投影”。

32.2 NTC 改为直接监测两个最高热密度点

RT601 放在 U31 右侧 (92.0,24.5,270°)。U31 在 Hub 最坏 0.42 A 时耗散 0.42×(5-3.3)=0.71 W,是持续热点。RT602 放在 J1/DC-005 右侧 (72.5,10.0,180°):整机最坏 9.99 A,插座家族额定只有 2~5 A,接触弹片是优先安全热点, 邻近 Q1 在 10 A / 5 mΩ 上限下另有约 0.5 W 导通损耗。

NTC1/NTC2 的滤波电容 C736/C739 继续贴 U20 ADC1 脚,将远端传感线的噪声在 MCU 端滤除。 读回确认 RT601.1=NTC1@(92.00,25.25),RT602.1=NTC2@(73.25,10.00)。

32.3 Q6 / Q10 / U13 定点优化

  • U13=(19.0,5.5,0°),位于 Rs6 正下方。读回 8/9/10 脚在 y=7.61、朝上对着 Rs6 y=11,避免了原先在东侧控制列的跨板 Kelvin 线,也修掉了“位置回来但采样脚朝外”的 180° 方向错。
  • Q6=(72.5,113.5,180°) 和 R733/R734 归到 J27 下方的 PWM 整形块; Q6.3/FAN_PWM_L 朝接口。
  • Q10=(98.0,114.5,90°) 和 R754~R757 归到 U20 上方的 TACH_OUT 整形块; Q10.3/FAN_TACH_OUT 朝南对着 U20。
  • D2/R747/R748/R753 为新的两个小信号块让位,R660/R661 移到 U20 ADC 附近。

32.4 电源输入链按用户截图定稿

本节覆盖 §32.2 里 RT602 的旧坐标,也覆盖 §32.3 里 U13 的旧坐标。 客户端实测布局按 16 件整组固化:

J1/F1/Q1/D1/C1/R1/DZ1/C4/C5/C6/C2/C3/Rs6/U13/RT602/C11。 主电流按左→右排成 J1 → F1 → Q1 → D1/C2/C3 → Rs6,U13 在 Rs6 上方。

器件 定稿坐标 / 角度
J1 / F1 / Q1 (20.83,10.79,90) / (31.08,3.63,0) / (37.08,6.63,0)
C2 / C3 (68.12,4.30,270) / (68.12,13.19,90)
Rs6 / U13 (75.99,8.74,90) / (76.71,16.89,180)
RT602 (32.07,9.16,0),位于 F1/Q1 热点中间

U13 的 8/9/10 脚在 y=14.78,与 Rs6 的 y=5.68/11.81 两端实行独立 Kelvin 引线。 U13 本体向北越过 D± 预留通道的南界约 0.8 mm,必须在新路由器中作为固定障碍, 不得继续把该处当成全宽空通道。

32.5 LIVE 布局快照成为当前唯一位置基线

place_base.py --adopt-live --verify 已从 EasyEDA 读取当前 BASE-PCB 的全部 138 件, 将 x/y/角度/层写入 .claude/r2/_base_place_live.json。只要该文件存在, place_base.plan() 就以它为最高优先级,跳过旧的镜像排布、0.25 mm 吸附和自动翻转。 验收为 138 件逐件读回一致,全部布局几何检查通过。 D2 及 R748/R753/R755/R757 随接口重排让位,不再夹在 J33 与 U20 之间。


33. M12:底板布线逻辑迁移与预检(2026-09-10)

M10 旋转插槽后,旧路由器不是单纯左右镜像:D± 从插槽北排换到南排, 物理槽位也从南→北 USB1~5 变为 USB5~1。新逻辑因此将「USB 编号」和 「物理槽位」拆成两个概念:USB1~5 -> J34~J38,分别使用对应插槽的南侧走廊。

五对下行 D± 不再交给 A* 自由蜕行,而是 U32 西排细线扇出、东侧三条专属车道、 槽端向南逃逸的构造路径。较短线在自己的竖向车道内向外加 45° 微蛇形; 离线结果为五对净距 0 错,对内长差均 0.25 mm,满足 ≤1 mm 规则。

电源面也改为按实测针排分段:12V 使用 14 mm 西侧干道和每槽四块「宽帽 + 窄指」, 覆盖 25/25 只槽电源脚且不压 GND/外壳盘;3V3 修正上下排的 NC 边界,覆盖 15/15。 VIN_SW 铜面不再把 U13.10 Kelvin 监测脚当主电流脚;强制断面为 VIN_SW 12.17 mm / +12V 14.00 mm,均过线。

路由缓存增加 schema + 插槽方向 + USB 映射校验,任一条不同即重算; 只要仍有未布通记录,--push 就拒绝写板。

⚠️ 当前仍未完成全板路由:完整试算两轮为 105 / 104 个未完成连接, 优先级重排几乎无改善,证明是东侧密脚区的出线容量问题。R610 / R722 恰好堵住 U32→U20 的 USB6 通道,已规划移到 (78,109.5) / (78,111) 并通过布局自检; 但 EasyEDA 窗口断开导致定点下发 HTTP 500,板端尚未移动。重连后要先下发这两件、 重抓 _base_pads.json,再重跑完整路由 / 连通性 / DRC。