布线(窗口整体重布,已下发): - 拆窗口内 43 段(用户手布的那批,用户选「拆掉重来」),补 139 段 / 7 孔, GND 回流孔 10 个;fan_check 对板上真实快照逐项净距达标(含「新孔 vs 内层线」)。 - ⛔ 根因:pcb_base.PD_L1 里的 L1 走廊是按**旧摆位**开的(注释坐标全是旧的), 用户重摆后与件对不上 ⇒ 四条长途网必然布不通。重开六条走廊后未完成 4 → 2。 走廊必须盖住焊盘正上方,只盖沿途不行。断面:几何 11.80 / 铺铜后实测 9.82(要 8.0)。 - 与拆线前逐网对比:没引入任何新的连通性问题(GND 未接 58→48、+3V3 2→0、 两路 TACH 2/1→0、+12V 一字不差)。 定版:板上铜以**用户自己布好的那版**为准,不再改动。 丝印(silk_base.py,已下发并读回核对 150/150): - 压焊盘 128→4、压过孔 48→8、越框 8→3、互相重叠 34 对→0;字号不变。 - 三条坑:rotation 是度且不归一化(900=180°);别拿「本体≥5mm」当保留白名单 (会豁免掉 R9A/D3/U13 这些该重排的件);「离本体」必须设硬上限 + 降级策略。 新工具:silk_base.py(丝印重排)、l1_section.py(L1 12V 主块逐 y 断面核算)、 fan_rip.py(按窗口拆线,拆前后比对全板线/孔总数防连带删除)。 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_0168Bu6SEx3cXXCJLkdnE6zB
235 KiB
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 常规姿势) | 风道沿槽间通道垂直贯通;底板占地最小 |
| 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 正好压在嘉立创特价档的边界上,尺寸判定没有余地。 |
| D16 | 底板电源入口改 USB-C PD 取电(2026-09-11 用户拍板「走方案 B」,取代决策 #20 的 DC-005):C 座 + CH224A 只请求 20V → LM61495 降压到 12V,12V 母线及以下不改 | 兼容各家手机氮化镓充电器的只有 PD(私有 100 |
| 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 改 +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 待实测 / 待选型(开画前要有数)
| # | 项 | 为什么卡住 |
|---|---|---|
✅ 已定 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 |
||
✅ 已定:10.5 mm(C3828985 6.3TPV2200M10X10.5 SMD,Ø10 罐)。这个数 2026-09-06 换矮封装时就有了,只是没回填。放在 A 面没有手机压着的那两列,可用 11.7 |
||
| ✅ 已定:做斜边(下单勾「金手指 + 斜边」)。理由是斜边的加价压在已经要付的金手指工艺费之上,而它挡掉的失效是「插拔刮伤已焊死的插槽簧片」—— 五个座子换一个都要拆焊,且功能测试测不出来。顺带纠正 §5.3:金手指区要电镀硬金,不是 ENIG。见 §21.3 | ||
| ✅ 已完成 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 口的分配 |
✅ 已完成 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 约束
- 连接器电流 4 A → 1.5 A:R1 §22.2 的三针并联、§25.10「4 A 电源面穿不过排母地针行」全部消失。
- R1 §22.1「Hub / U31 / U24~U28 / J23 四样必须一起上载板」作废——当初唯一的理由是 2.54 排针过不了 USB 差分。
- 五路独立回地(R1 §6.4)从"要靠平面分割去争"变成天然成立:每片刀片的地只经自己那组金手指回到底板星点。
- I²C 地址冲突用 mux 一次解决:五片刀片完全同构、零 strap。
- R1 §22.3d 排针叠高冲突、§25.2「别让 12 mm 电解撞上底层元件」:两板不再面对面叠合,13 mm 净空整条约束链没有了。
- 可扩展:要 3 台或 8 台只改底板槽数,刀片一版不动。
3. 机械与热
3.1 尺寸
| 值 | |
|---|---|
| 刀片板框 | |
| 底板板框 | |
| 槽距 | 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 面(背面,全板) | 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 不变000:PRT_SWP1~3 上拉(口 1~3 片内对调,北去三对不再 U 形掉头)、PRT_SWP4~6 下拉,+ R723 1 MΩ 跨晶振(检查清单 required,R1 起漏了)。接法见 .claude/r2/a4_hub.py 文件头 |
| 底板 | 风扇: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。 2026-09-11 用户拍板:「插槽过孔带不放件」在 U32 正南 / 正北各开一条窄带的口子(58.2 / y 30.2place_base.HUB_STRIPS: J37 北排投影 x 4434、J36 南排投影 x 4458 / y 43.446.4)。走廊 2 净高 11.12 而 U32 占 9.75, 按检查清单「VDDA33 / VDD33 每脚 0.1 µF 紧贴」,南排 46 脚和北排 5 / 10 脚的去耦只有放进这两条才能 ≈1.3 mm (不放开是 78 mm / >15 mm)。代价:这两段槽针的过孔改打到两排之间;5 / 10 脚去耦的地孔拟打在正上方 J36 GND 针的盘中孔。
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 成立的前提,不是收尾检查项。布线时它们优先于一切其它考虑。
- L2 必须是完整地平面,
D±走廊下方一刀不许割。 双面板上每一次跳线都是在地平面上开口 ⇒ 所有跳线排到 D± 走廊之外。 - U32 必须坐在 5 个槽的几何正中,六对 D± 从它径向直接扎出去,不许绕。 摆位一旦妥协,方案就废了。
- 每个插槽的 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(≤ 150 mil = 3.81 mm), 所以 8 mm 与 41 mm 并存没问题。
2026-09-10 用户定:底板 skew 由 1 mm 放宽到 150 mil。底板 D± 是按构造画的(北去 U 形掉头、南去东绕), 实测六对长度差 56~136 mil,全部超 1 mm;USB 2.0 HS 480 Mbps 下 150 mil ≈ 25 ps,是常用预算,不必加蛇形。 规则在
rules_base.DIFF['differentailPairLenTolerMax']。
阻抗估算(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 |
D11b 起在底板(U6/U7,底板位号) |
||
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(五片同址) | 见下表 |
| — | 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 驱动 | 地址表从「六片不同地址」变成「五片同地址 + 一片输入侧」。⚠ 底板输入侧 U13(0x43)的 IN+ / IN− 对调接(2026-09-11,A1-INPUT:IN+ 接 Rs6 下游 +12V、IN− 接上游 VIN_SW —— 为了让两条 Kelvin 在 PCB 上不交叉;原来 IN− 绕 37 mm 把 U13 的 I²C 圈死)⇒ 芯片读数为负。驱动已加 ina226_set_reversed()(默认全部正接 = R1 行为),R2 固件启动时必须调 ina226_set_reversed(INA226_ADDR_INPUT, true),否则 SW-8 反灌判据会把正常供电当成反灌 |
| 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 | ✅ 刀片原理图 |
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( |
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 经验
dmt_Project.createProject()传teamUuid+description会静默失败: 返回undefined,工程列表里查无此项,不抛异常。 只传friendlyName(可再带projectName)就成功。 ⇒ 判据是「回列表里查得到」,不是「调用没报错」。dmt_Schematic.createSchematic(boardName)/dmt_Pcb.createPcb(boardName)建不出新板: 传一个不存在的板名时两者都返回undefined、什么也不建。 正解是 先dmt_Board.createBoard()(无参)——它会连原理图带 PCB 一起建好、 自动命名Board1,再用modifyBoardName/modifySchematicName/modifyPcbName改名。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)
create()会把元件坐标吸附到 5 的倍数 —— R1 页上 679/639/654/589 那些位置 放下去会差 1~2 个单位,「按坐标精确认领位号」42 件只认到 28 件。 ⇒ 就近认领(容差 3)+ 认完setState_X/Y拉回精确坐标。- 42 件里有 27 件的
create(rot=270)语义与 R1 相反。 25 件是两脚对称件(只有编号互换,无害),但 C10 / C14 两颗 33nF 是 +20/−15 的 不对称跨距,翻过来坐标真的差 5,照 R1 的坐标画线会断在这两颗上。 ⇒ 脚本里做了「对不上就翻 180 再回读」的自动修正循环。 ⚠️ 第一轮看起来没生效:create(270)与setState_Rotation(270)差 180°, 要翻两次才落位(日志里同一批 27 件连打两行「翻转…重试」是正常的)。 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.0EDL_EN / P0.4 VBUS_EN 输出;P1.0EFUSE_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 顺带做掉的两件小事
port_audit.py加了--r2 BLADE/--r2 BASE(页表读.claude/r2/r2-uuids.json), 取代 §14.4 里「对着当前页跑 11 遍」那个 R1 硬编码清单。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 重试」那个循环修不了,会在两个状态之间来回跳 |
⇒ 两条规矩:
- 极性件不能只比坐标集合,必须按脚号断言(
b3_phone.py里C60单独列出来)。 - 引脚断言失败时先看失败的是不是镜像:是镜像就去实测三个角度(
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 本页不含的两件事
U31AMS1117-3.3(Hub 专用 3V3)在A4-HUB。R1 的 P1B-5V 页上有两行讲它的文字, 是说明不是电路,本页改写成「它不在这页」。+5V的去处(HubU32+ 五个槽的 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(A1 |
❌ 其实是 x1 |
10061913-103TLF(Amphenol,贴片) |
C4697499 |
38(A1 |
❌ 其实是 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,新开 5 + 全部 5 个 D± 退路座。
建页用 A5B-SLOTS(e493f8bce3a51aae) 放槽 4dmt_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/NTC2—— 必须 ADC1(ADC2 与 WiFi 冲突),脚本里有断言。⇒ 2026-09-11 方案 B 改为NTC1 = IO1/NTC2 = IO2NTC1 = IO4/NTC2 = IO5(仍是 ADC1,见 §29.6)。USB6_DM = IO19/USB6_DP = IO20—— 原生 USB 硬定死,脚名脚号从_p3_live.json查的。- ⚠️ 模组是 R8(八线 PSRAM)还是 N8 没定:本页按可能上 R8 保守处理,
IO35/36/37全部不接。 若确定 N8,这三脚可放出来当 GPIO。现在全板只剩⇒ 方案 B 之后IO47/IO48两个备用脚IO47/IO48给了风扇,备用脚变成IO1/IO2(模块脚 39/38,都是 ADC1)。
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。
决定:做。 三条理由:
- 加价压在已经要付的工艺费之上。 金手指本身是一道独立工序(下单页勾选), 斜边是它的附加项 —— 不是「从 0 到 1」,是「从 1 到 1.x」。
- 它挡掉的失效很贵且测不出来。 没有倒角的 1.6 mm 直边插进插槽, 尖角会刮/顶插槽的接触簧片。而底板上那 5 个座子是焊死的贴片件, 换一个要拆焊 64 个脚;更糟的是接触退化只表现为偶发的 USB 掉线或 I²C 超时, 功能测试测不出来 —— 这正是本项目反复吃亏的那一类。
- 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 ⛔ 两条与既有文档冲突的,已经改掉文档
- T3 的「20° 斜边」在嘉立创下不了单。 嘉立创《金手指斜边设计注意事项》写明 只有 30° 和 45°,并建议优先 30°。⇒ §5.3 / §21.3 已改成 30°。
- 「斜边吃掉 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 两个坑
pcb_Document.importChanges()在本机一律返回false、对话框都不弹 (带/不带 schematic uuid 都试过)⇒ 导入只能沿用 R1 那套驱动 GUI 的做法, 新脚本.claude/r2/pcb_import.py(刀片/底板通用,--base切板)。- 原理图里已经放下的元件会把「器件没有封装」这个状态缓存住。
J1在 M2d 放下时器件还没封装,M4a 建好封装并挂上去之后,B4-EDGE页上的J1读回来仍然是footprint.uuid = "", BOM 里显示成[object Object],导入 PCB 会缺件。 解法:重跑b4_edge.py --push整页重画(幂等),J1 才会带上新封装。 ⇒ 以后凡是「先放件、后补封装」的器件,都要回去重画那一页。
23.4 M4 接下来的顺序
- 设计规则(照
pcb1_rules.py改:刀片只有一路,PWR12V/SWNODE/PWR4A/PWR1A四档 +USB_DP/DM一对差分) - 摆位:先钉死三颗 ——
J1(已定)、C60(Ø10×10.5,只能放服务带/功率列,§21.2)、J4BM24 尾插(接口边);再按 §3.1 的分区放其余 80 件, 功率列内部按「离手机越远越吵」排(SW/L/Cin 靠 x=98 那一边) - 布线:L1 信号+功率、L2 完整地平面(不许割断)、L3 12V/VO 灌铜、L4 控制信号; D± 走 L1 以 L2 为参考
- 灌铜 + 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):三类件三种定位
- 机械锚定(位置由小米8 主板决定):
K1~K4侧键触点盘、J5电池排线焊盘、J4尾插座 —— 坐标从.claude/mi8_mech.json换算,不手抄。 手机落点PHONE_ORG = (3, 29),接口边(v=0,J600/J1401/侧键都在上面)朝下。 - 手工钉死:
J1(49,0) /C60(37.5,19) /J2(62,15) /J3(66.5,25)。 - 其余 70 件:按功能分组、按电流流向排序,货架式排布器塞进四个区。
顺序是设计意图,坐标不是 —— 要改布局改
GROUPS,别去改坐标。
三条落地时改掉的:
- 功率列自下而上 = 输出端 → 输入端(和电流方向相反)。
VO_P是 4 A, 出口必须离服务带的C60/J5近;+12V只有 1.45 A 又走灌铜,爬到板子上半段无所谓。 U3INA226 挪进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 金手指 |
板边卡,两面都是指 |
换面赚到的三件事(这才是「优化」的实质,不是重排坐标):
- 两条排线底下彻底空了。原来服务带塞着 30 多个小件,排线是贴着板面躺过去的。
- 侧键 MOS 挪到
K1~K4正背面。漏极是手机侧键线(机内 100 k 上拉、高阻、最怕拾噪), 从20 mm 缩到 3.96.3 mm。这块地方原来是「手机投影,只许放 K1~K4」,翻面才解锁。 - 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_check4 条全过。 - 布线: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 之间反复)。
下一步的两条路(都不该再靠调参数):
- 协商式拥塞布线(PathFinder):允许暂时重叠,按历史拥塞代价迭代收敛。 这是教科书解法,也是唯一对症的 —— 现在这个「一次布死、不回退」的 A* 到头了。
- 在客户端里手工布这 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 面,排线就必须穿板:这正是 R1pcb2_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.77 |
尾插槽 TAIL |
x 46.58 |
| 槽的实现 | layer 12 (MULTI) 填充 = 挖槽区域(pcb_PrimitiveFill,R1 同),不是板框内环;DRC 认「挖槽区域到导线」 |
| 排线车道(B 面,一件不放) | BAT x 22.27 |
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_PHONE10.12 /H_B_SVC18.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 段全部作废(
clearRouting30 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 出不来」(症状不是病因)。
判据交了两次学费:
- 「直线穿不穿本体」不行 ——
U1.14到U4.14隔着 81 mm,从本体上方蹭过去 绕行代价才 2 mm,64 处里全是这种噪声; - 「绕行最短路 − 直线」也不行 —— 芯片的焊盘本来就在本体框里,线段起点落在障碍
内部,最短路直接算成无解、返回 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)。这一条需要用户拍板。 ⇒ ✅ 2026-09-11 晚 用户拍板 1.6,已落地(§35.7),刀片 DRC 0 条。
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(63SPINE(2 |
支路只有 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 两层板给布线器加的两条约束
- 底层是完整地平面 ⇒ 全层收过路费
BOT_PEN=6(不封死:§6.2 允许 D± 走廊之外跳线)。 ⛔ 过路费要在每次pen_pads之后重打 —— 它头一句就是reset_pen(), 直接写g.pen会被静默清掉,现象是底层突然多出一堆长线。 - 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 件逐件对上,设计规则审计六项仍全过。
连带影响两条,都要写进设计文档:
- 底板侧不再有 D± 退路 ——
USBn_DP/DM从U32直达槽针,一条路走到黑。 - §28.10 那条「接受 ~70 mm」的理由少了一条:当初拍板时的依据之一是
「
J39~J43本来就是为这一条留的」。现在没有退路座了,D± 只能一次做对。 ⇒ 首板务必按 §6.3 的做法实测:adb 长稳 + 眼图;不合格就只能改板。 - 刀片上的
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 铣刀自然带圆角,板框里不必画。
⛔ 三处「几何验证抓不到」的,这次一起补上
- 净空写死了朝北。
antenna_keepout()原来是「焊盘北沿之外 7.5 mm」一个硬编码矩形。 模组一转 90°,净空还留在北边 —— 铺铜照样把铜铺到天线底下,而 摆位自检 / DRC /board_check/ 几何校验一条都不会响。已改成跟着 rot 转 (0/90/180/270 四个方向,rot 是 CCW,与U32rot=270「西→北」同一套语义)。 - 布线器根本不知道有净空这回事。
place_base认、pour_base认,route_base里一个字都没有 ⇒ A* 可以大大方方从天线底下穿线过去。 已加ant_blocks():净空 + 缺口两层全封死。 ⚠ 净空只往外膨胀(西/南/北),朝模组那一侧不膨胀 —— 否则把最西边几只脚的出口封死。 - 铺铜的几何是矩形不是板框。
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)里是横着跑的,
50),
中间只有两处竖井能穿:西 23 mm、东 3.4 mm。穿过去之后没有横向通道——
槽阵那 42 mm 被 5 个槽体 + 每槽两端 5.0×3.0 的屏蔽脚横向堵死(这正是
「齿曾经也是铺铜、断面量出来 0.00 mm」那条),唯一的横向路是 ctrl 带,
而它塞着 57 个件、还要过 7.5 A(要 8 mm 净铜)。西边那条还正好撞上新挖的天线缺口。USB5(去最西槽)和 USB1(去最东槽)共用 y=41.4 那条道,两段拼起来
x 24.5 一直到 105.1,横贯整块板。而 12V 入口在南(y<16)、槽针在北(y 48
⇒ 槽 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 ⛔ 这一轮又交了三处「几何验证抓不到」的学费
- 12V 铜墙没伸进槽体 ⇒ 一只 12V 脚都碰不到。焊盘中心距槽心 3.6、盘高 2.0,
占的是槽体边缘往里 0~2.0 那一段;只画走廊本身的话铜墙一只脚都够不着,
而铺铜管理器和 DRC 都不会响。
RIB_OVER = 2.0,判据是「10 排 12V 焊盘全被盖住」。 - D± 焊盘在槽体里(y = 槽心 + 3.6,比走廊南沿还低 1 mm)。
按走廊边界封锁「不属于本对的地方」= 把目标本身封死 ⇒
USB1 布了 0 段,看着像拥塞。 - 槽针是 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)要挑分得最开的一对,挑内侧会一出脚就压。 - 顺带修掉
pour_base.tiles()一个真 bug:两个禁区 y 区间嵌套时切点会配错对 (天线缺口 84.5107.5 套着天线净空 86106),GND 瓦片照样铺进缺口 —— 只有selfcheck那条「压进净空区」看得出来。已改成先合并区间再配对。 - 阵列北边要留一条 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 只脚逐个对上。
29.6 ⛔ ESP32 的 NTC / 风扇 / UP_VBUS_DET / PRSNT5# 引脚重新分配(方案 B,2026-09-11 用户拍板)
底板 4 层布线做到第 26 轮,U20 周围约 10 个网(INT#、NTC1/2、EFUSE_EN35、PRSNT…)断在同一道横贯全板、两层都封死的墙上。
查墙上各网的两端(PROGRESS「U20 一簇诊断」):NTC1/NTC2 在北排东头(IO1/IO2)却要去南边的热敏电阻(RT601 (85,26) / RT602 (19,8)),
**风扇那组在南排(IO4IO7)却要去西北角风扇电路** —— 两组方向全反,风扇线横穿全板就是那道墙。布线器层面四轮 A/B 都是此消彼长。
服务器上先只改布线器读到的焊盘网名做试算(route_base --u20-remap),六组重分配里方案 B 最好:离线断开 29 → 27。
| 模块脚 | IO | 换前 | 换后 |
|---|---|---|---|
| 4 / 5 | IO4 / IO5(ADC1_CH3/CH4) | FAN_TACH_OUT / FAN_TACH_IN |
NTC1 / NTC2 |
| 6 / 7 | IO6 / IO7 | FAN_PWM / FAN_EN |
UP_VBUS_DET / PRSNT5# |
| 22 / 23 | IO14 / IO21 | PRSNT5# / UP_VBUS_DET |
FAN_TACH_OUT / FAN_TACH_IN |
| 24 / 25 | IO47 / IO48 | 备用 | FAN_PWM / FAN_EN |
| 38 / 39 | IO2 / IO1 | NTC2 / NTC1 |
备用(仍是 ADC1) |
电气约束:全部走 GPIO matrix,不碰 USB(IO19/20)/ UART0(IO43/44)/ strapping(IO0/3/45/46)/ R8 PSRAM(IO35~37);
NTC 仍在 ADC1。s3_pin_audit.audit() 按 R8 八线严格口径:ERROR 0,WARN 与换前相同(IO0 strapping、UART0 两脚,均有意为之)。
风扇测速线原理图上有 10k/3.3k 分压(最高 2.98 V),接任意 GPIO 都安全;FAN_EN 复位高阻由 A6 的 100k 下拉保证关断,IO48 非 strapping。
怎么改的:原理图 u20_remap_b.py(删端口重建;24/25 新接线、38/39 删端口删线;J33 从 (430,455) 挪到 (450,420) 给 24/25 两行让位,
地线改接 U20 地干线节点 (320,440));PCB pcb_pinswap.py(WANT 加这 10 只,38/39 置空);源头表 a3_ctrl.py 的 PINMAP / U20_NC /
J33 画法、_esp32_pinmap.json 的 r2_base 一起改(顺带把 §29.5 那 9 只一直没同步进 a3_ctrl.py 的网名也更正了)。
验收:原理图读回改后状态逐项对上;verify_sch 单脚网络 0、无名端口 0(悬空只剩 20 只有意空脚,数目与换前相同);
xpage 真正漏接 0;port_audit --r2 BASE 354 个可疑 0;PCB 焊盘读回 19 只逐个对上;「从原理图导入变更」0 条变更。
⚠ 固件:R2 底板固件尚未开写;写的时候按本节 + §29.5 的表(_esp32_pinmap.json 的 r2_base 是机器可读版)。
代价:第 31 轮试算里 RXD0(应急 UART)与 PRSNT2# 在所有重分配变体都断 —— 布线器问题(RXD0 的扇出孔落在北排焊盘南侧),另补。
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()(拿实测焊盘表比,三条缺一不可):
- 15 只槽脚全被盖住(与 12V 那条「10 排焊盘全被盖住」同理);
- 一只异网针都不许压到,
NC空网也算异网; - 桥的过孔要落在墙里,否则过孔与铜面靠「碰巧」相接。
⚠ 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。
34. 刀片压到 90 × 68(2026-09-11 用户拍板)
用户要求:刀片 98×76 → 90×68。先做可行性核账(几何两个方向都放得下, 真正要取舍的只有 C60 和功率列宽度),两处交用户拍板: 手机上移、C60 留在两槽之间;删掉 J2。
34.1 几何(事实来源 pcb_blade.py,与手机绑定的一律从 PHONE_ORG 推)
| 项 | 旧(M7) | 新 |
|---|---|---|
| 板框 | 98 × 76 | 90 × 68,四角 R2,一条闭合折线(读回 54 点、外接 0 |
| 手机原点 | (3, 29) | (1.5, 22.34) |
| 左边距 | H2 离板边 3.7 | 2.2:M1.6 尼龙螺钉头 Ø3.2 还剩 0.6 |
| 服务带(金手指区上沿 → 接口边) | 18 | 11.34 = C60 本体 11 + 0.34 |
| 手机顶 → 板边 | 2.34 | 1.0 ⇒ ⚠ 顶边导轨只能咬 ≤ 1 mm,否则压到主板 |
| 功率列 | x 72~98(26) | x 70.59~90(19.4):整块西移 8,§7.2 四条回路的相对关系一点没动 |
| 排线槽 y | 24.8~27.8 | 18.14~21.14(接口边外 1.2~4.2,跟手机走,不再写死) |
| 金手指 | x=49 | x=45(仍居中;底板插槽不用改,只是悬臂两侧各短 4 mm) |
| 七个孔 | — | H1 (2.90,32.24) H2 (2.20,49.64) H3 (3.20,61.04) H4 (43.40,24.24) H5 (58.90,63.54) H6 (66.10,50.44) H7 (66.30,54.74) |
C60 定在 (38.175, 16.5):x 取两槽正中,y 贴着金手指区上沿(本体 11 的下沿 = 11.0)。
居中(上下各余 0.17)时 H4 的螺钉头圈只剩 2.07 < HOLE_KEEP 2.2;贴下沿之后上沿离接口边 0.34、离 H4 2.24。
⚠ 它的焊盘外沿 12.9 宽,离两侧铣槽各只有 0.45(本体按 11 算是 1.4;项目 MILL_KEEP 0.5 是按本体判的,
嘉立创铣槽到铜下限约 0.3)—— 投板前再确认一次。
34.2 原理图两处(B4-EDGE / B3B-USB 整页重画,截图已自查)
- 删
J2(D± 退路座):底板J39~J43在 §28.11 已删,刀片这头没了对端,D12 实质作废; 旧版 D± 往东绕到 x≈60 就是为了它。 U7两侧对调:1/3 脚 = 金手指侧USB_DM/DP,6/4 脚 = 手机侧USB_DMJ/DPJ(R1 相反)。 手性推导:U7在 B 面,信号从 4/6 那排流向 1/3 那排时 DP 永远在前进方向右手边(旋转不改手性,只有镜像改); 而金手指(DP 在西、向北出线)和 J4(DPJ 在东、从北边进)两头都要 DP 在左手边 ⇒ 旧接法前后各要交叉一次(旧版 DP/DM 各 6~7 个孔)。1↔6、3↔4 内部直通,电气等价。J1改为不进 BOM(§17 遗留)。- 验证:两页
verify_sch --netsPASS、xpage漏接 0、port_audit --r2 BLADE142 个可疑 0。
⚠ 整页重画让 B3B 那 9 件的 uniqueId 整体差 1(skill §9o-2),导入对话框一度提出「J2 换成 BM24 封装、J4 换成 SOT-23-6」。
uid_sync_base.py --blade(新加)按位号两阶段写回;「PCB 有、原理图没有」的件(J2)占着的号正是错位那一串要用的 ⇒
同一次写入把它挪到 zzdel_J2。对齐后对话框只剩真实差异(删 J2、U7 四只脚改网、R62/R64/R65/C67/C68 两脚互换 = 无极性件重画后脚号翻转),
应用后 82 件逐件对上。
34.3 摆位(pcb_place.py)
- 所有 M7 手排坐标改成「M7 值 + 平移」:跟手机的加
DX/DY = (−1.5, −6.66),功率区加PX = −8。 侧键 MOS 只移 y(Q4 本来就贴板边)。 J3(EDL 座)挪到服务带里、尾插槽东头,rot 270,读回信号盘在西 x 67.18、正对槽口。U7手排在 J4 那两只 D± 脚正北 (51.40, 30.55),下排直直往南 ~2 mm 接 J4;它北边 B 面留一块换层孔的空地。DIS(泄放 R19 2512 + Q2)第三版挪到电池车道正北、手机投影下(R19 (22.07, 31.0) / Q2 (29.50, 31.0),B 面、都 < 1 mm 高): 前两版放在电池槽正下方,而服务带压到 11.34 之后,槽下那条 6.4 mm 高的带是 U4(左下角)往东去的唯一走廊 (~8 个网:SDA/SCL/BUCK_PG/EDL_EN/VBUS_EN/EFUSE_FLT/INA_ALERT/EFUSE_PG),R19+Q2 把 B 面那一层从 x 18 到 32 整段占满。 第三轮服务器试「三个长网先布」:它们通了,SDA 整网断成 4 块 —— 典型的此消彼长,是走廊容量问题不是顺序问题。 新位置紧挨电池座 J5(R19 本来就接 VO_P = 电池正),正下方是 VO-L3 北叶,就地扎孔照旧。- VO-L3 岛西沿 17.5、北叶跟手机走,V12-L3 岛跟板边走。
- 分区第二版(第一轮服务器布线之后改的,见 §34.5):
EFUSE_AUX回到 M7 的 11.2 宽、整块放到 J3 以北 (x 64.876 × y 20.740);SVC_E在 J3 正北一小块、GROUPS里排在 EFUSE_AUX 前面(两区重叠,谁先摆谁先挑);SVC_R只留 U7 换层孔空地以东。 - 读回 82 件位置 / 层全对;自检(重叠 / 越框 / 金手指区 / 槽与车道 / 螺钉头 / 分段限高)全过。
place_audit报 11 处「摆错边」/ 8 处「去耦 > 3 mm」:U4 上拉、U1 FB、C6/C7 与 M7 相对位置完全相同; 仍偏远的是 U5 那一簇(C68CT 9 mm、C67VBUS 7.2 mm、R64绕 U5)—— 都是低速 / 直流网,暂接受。
34.4 D± 构造(router.dp_blade(),不交给 A*)
金手指 B14/B15 顶层直上 → 并拢成 W 0.28 / S 0.18 → 尾插槽上沿以北 45° 东让 H4(线边离孔边 0.53)→ 北上 → 东去到 U7 正上方 → 南下、在 U7 上排北边各一个孔下 B 面;U7 下排 → J4 在 B 面 0.18 宽(BM24 0.35 节距)。 中心线折线 + 左右各偏 0.23、斜接 ⇒ 45° 拐角处线距不变。
| 旧(M7,A* 分开布) | 新 | |
|---|---|---|
| USB_DP / USB_DM | 59.6 / 63.4 mm,0.531 / 0.15 宽,7 / 6 孔 | 42.05 / 40.52 mm,0.28 / 0.28,1 / 1 孔 |
| USB_DPJ / USB_DMJ | 11.0 / 25.8 mm(差 14.8) | 2.42 / 2.34 mm(差 0.08) |
本机静态校核(纯几何):净距 < 0.15 的 0 处,最紧 0.17(进 J4 那 0.8 mm,节距定死的)。
对内长度差 1.52 mm 来自两个右拐角内侧线短(规则容差 5.0;底板 UP 那对是 1.9)。
pcb_rules.DIFF 的差分线宽下限 0.20 → 0.15(否则整对 USBPHONE 在 DRC 里刷线宽)。
顺带:旧版 USB_DP 被撑到 0.531 = U7 焊盘宽 —— 线宽被焊盘封顶逻辑反向拉宽了;构造之后这两对不再经过那段逻辑。
34.5 布线上服务器
CLAUDE.md 的「布线运算只在 10.5.5.13」原来只落实在底板(remote_route.ps1)。刀片补上:
router.py:--replan/--pf在本机硬阻断(没有DCDC_ROUTE_SERVER直接退出); 离线时板上已有过孔改读_blade_board_vias.json(--snapshot-vias写)。remote_blade.sh ['变体' ...]:快照 → 打包(不带_base_*/ png)→ 服务器每个变体一份副本、PyPy 并行 → 拉回_blade_routes.var<k>.json/.log,不自动覆盖缓存。MODE=stitch同一套流程算 GND 缝合孔落点 (pcb_route.py --stitch-plan,本机--stitch只下发)。- ⚠ 第一版脚本把远程命令写成
cat > run.sh && setsid … &:结尾的&把整条 && 链(连 cat)放后台, ssh 一返回 stdin 就关 ⇒ run.sh 0 字节、一个变体都没起、done永远不出现,本机空转。 已改成「先 scp 上传 run.sh、另起一次 ssh 启动」,并在 5 秒内查不到v*.log就退出。
第一轮(v0 默认 19 条没搞定 / v1 --pf 21 条,M7 是全通),按根因分三类:
+12V整条没布(五根指全失败、F1.1 一根铜都没有):不是 D± 挡的 —— M7 那条 0.8 的 12V 是 B 面 x≈36 从阻尼电容两盘之间北上、y≈60 顶层东去 F1,全程在 D± 顶端(y 35.7)以北。这回五根指(x 28~31)出口被封: 北边电池槽(y 18.14),B 面正上方 R19/Q2,而+3V3(在FIRST_NETS里)先布、一根 y 15.5 的顶层长线把槽下走廊封死。 服务带 18 mm 时这事吸收得了,11.34 就不行 ⇒+12V排到FIRST_NETS最前。- 我自己引入的摆位退化:EFUSE_AUX 西边少 4.3 mm(
$1N165: R16.1)、U6 被挤到离 J3 20 mm($3N45)、 C68 离 U5 7.9 mm($5N71)⇒ 分区第二版(§34.3)。 - U1/U2 一带
+3V3 / EFUSE_EN / EFUSE_PG / $1N136 / $1N173各断成两块 —— 同一片拥塞,看第二轮。
第二 ~ 四轮:
- 第二轮(+12V 排最前 + 分区第二版):v0 自报 11 条,但按铜判只断 3 个网(
$1N173/BUCK_PG/EDL_EN,都是从 U4 / Q2 所在的西南角出发的长网); 布线器自报的+3V3 / VBUS / SCL / SDA / $1N136「铜分成 2 块」全是误报 ⇒ 新写blade_conn.py(离线按铜重叠并查集),比较变体只看它。 - 第三轮(
router.py --first把三个长网提前,4 组变体):三个长网通了,SDA 整网断成 4 块 —— 此消彼长。 量化:U4 往东约 8 个网,唯一走廊是电池槽下那条 6.4 mm 高的带,DIS(R19+Q2)把 B 面那一层整段占满 ⇒ DIS 第三版挪走(§34.3)。 - 第四轮(DIS 挪走后 6 组变体):最好的 v3(三长网先布 +
--pf)按铜只断 2 个网(+12V_F: R4.1、+5V: U5.1,都是局部被围)。 但router_check精确净距查出六组全部在 U2 角上有两处孔压线(−0.095)+ 两处线距 0.054,另有若干 0.125(< 0.15)。
第五 / 六轮(修 FIRST_NETS 循环之后):
- 第五轮(只修过孔图口径):六组逐段不变 ⇒ 否掉那个假设。
- 第六轮(补上「已放的过孔进占用图」):非
--pf的三组精确净距 0 条(U2 角孔压线、0.054 线距全消失); 代价是按铜真断开升到 5~7 个网 —— 以前「少失败」有一部分是靠线压着别人的孔换来的,去掉之后露出真实的容量瓶颈。--pf三组仍有一批 0.125(它自己那条路的口径另有问题),不采用。 - 选 v2(三长网先布、不带
--pf)做底:净距 0,断 5 个网 —— U2 角$1N147(U2.15) /EFUSE_PG(U2.2)(M6/M7 就是最难的那两只)、U4 角INA_ALERT(U4.15) /SDA(U4.23·R40.1·U3.4 都断开)、$5N71(U5.4,C68 摆得远)。缓存r6-v2;下一步只对这 5 个网在服务器上补线(MODE=repair)。
这一轮顺带修掉的四个工具毛病:
| 毛病 | 后果 | 改法 |
|---|---|---|
router_check.py 现算 pcb_route.stitch_points() |
本机扫孔位(违反 CLAUDE.md);板上还没铜时算出不避让导线的 5 mm 格点 ⇒ 一排「+12V 线 vs GND 过孔 −0.895」、三处「孔压孔 −0.041」全是假问题 | 只读服务器算好的 _blade_stitch_pts.json,没有就不算 |
plan_all() 的 FIRST_NETS 循环往过孔图打线时少了 VIA_D/2 + CLR − halfw |
表里先布的网的孔可以落在更早那根线旁 0.2 mm 内。底板在 route_groups / grid_now 早修过(VIA_MAP_FIX),刀片这条路没跟上 |
同 _block_stub 的口径 + exact_v。⚠ 第五轮 A/B:六组逐段不变 —— 这不是 U2 角那两处的原因(方向猜反了) |
⛔ 同一个循环从来没把本轮已放的过孔打进占用图(build_grid 只含板上旧孔 / D± / VO_P 孔) |
金手指 launch 孔、表里先布的网的孔只靠挂在上面的短线间接挡着(0.15 线只护住孔心 ±0.31),后布的线压进 Ø0.6 的孔:$1N164 的孔压 EFUSE_PG、EFUSE_EN 的孔压 $1N147(−0.095)—— 和 route_groups 注释里 M7 记过的是同一对,那边早修了、这边漏了 |
g / gt 两张图都按 route_groups 的口径把 vias 打进去 |
board_check.py 在刀片上把 +3V3 当铜面网 |
只查「脚挨不挨铜」,刀片 +3V3 的真实连通一直没验过(条件是给底板槽墙写的,写反了) | 两块板都按布线网查 |
repair_route.py 只能读 M6 的板上读回 |
没法在服务器上对缓存补线 | --cache 读 _blade_routes.json、写 _blade_routes.repaired.json;本机硬阻断;MODE=repair |
34.6 布线 / 铺铜 / DRC 结果(2026-09-11 晚,板上现状)
板上 = 服务器第六轮 r6-v2(缓存 _blade_routes.r6-v2.json,router_check 精确净距 0)+ 斜切 + 缝合孔 + 铺铜:
| 项 | 数 |
|---|---|
| 铜 | L1 728 + L4 479 = 1207 段(斜切 3 轮 241 个直角)/ 过孔 359(布线 281,其中 GND 23 = 金手指地指母线;缝合 78) |
| D± | USB_DP / DM 42.0 / 40.5 mm、每根 1 孔;DPJ / DMJ 2.4 mm |
| +12V | 144 mm,1.19 宽(FIRST_NETS 那条路按「本网最小焊盘边」取宽,F1 1206 盘 ⇒ 1.19;比规则 0.8 宽,电气无害,DRC 不报) |
| 铺铜 | 25 / 25 块全填 |
board_check |
51 / 57 网全通;没通 = 下面 5 个网 + GND(它读不了铺铜) |
| DRC 间距 | 4 条 = PCIe 缺口到 A11/A12/B11/B12 指 7.9 mil(§27.8 老问题,几何定死,待用户拍板) |
| DRC 连接性 | 39 条 = 5 个信号网 12 条 + GND 27 条(铺铜够不着的细间距焊盘) |
还没接上的 5 个信号网(作业单 .claude/r2/HANDROUTE-90x68.md):$1N147(U2.15)、EFUSE_PG(U2.2)、
INA_ALERT(U4.15↔U3.3)、SDA(U4.23 / R40.1 / U3.4)、$5N71(U5.4↔C68.2)。
结构原因:+12V 在 L4 上 x≈42.5 从 y 13 竖到 y 61,和 L1 上的 D± 墙(x 4445.4,y 435.7)并排只剩 1 mm,
⇒ **y 1335.7 东西向两层都过不去**,左下角 U4 去东边的网只能爬到手机底下横过去。服务器定点补线(MODE=repair)也接不上。
铺铜够不着的 27 个 GND 焊盘(DRC 连接性原文):J4(BM24 0.35 节距)1/2/8/12/16/19/23/24/29/37/41/47 + 大地盘;
U2 1/16/21(EP);U3 1/2/7;U1 2/3;U4 20/21;Q4.2、K4.1、C13.2;一个 GND 孔。
刀片布线器一直 SKIP = ('GND',) 靠铺铜,而 0.35 / 0.5 节距的盘之间铺铜进不去 —— 要给这些盘各打引出线 + 过孔下 L2
(U2 的 EP 用盘中孔),流程里还没有这一步(底板 route_base 有「GND 打孔」)。M7 大概率同样存在,只是当时没数连接性。
收尾时又抓到两个工具毛病(都已修):
pcb_route.stitch()下发前「删掉板上所有 GND 孔」—— 会连布线器的 23 个地指母线孔一起删(地指下到 L2 的唯一通路)。改成只删不在布线缓存里的。 另:它第一次重写时字符串拼接和%格式化的优先级写错,下发直接抛异常 —— 而收尾链用| tail接管道,退出码被 tail 吃掉,链子没停, 一路跑到了斜切 / 重载。以后链子一律set -o pipefail。miter.py的「只去铜不加铜」只对拐角外侧成立,斜边凹侧会加铜(见其模块头更正):1.19 宽的 +12V 拐角斜切后压上凹侧一个$3N30孔 (DRC 导线 / 钻孔到过孔 0 mil)。板上那个角已恢复成直角(DRC 间距 7 → 4);脚本加了新斜边的精确净距校核。
35. 主板转 180°、两条排线槽到顶部、U4 到右侧(2026-09-11 晚 用户拍板)
用户:「重新优化刀片板布局」→「将排线插槽和排线移到顶部,主板不旋转」。核账:电池排线 38 mm 够不到顶边 (J600 在 v 4.6,光跨主板就要 40.05 —— R1 §25.16 v3b 早核过同一件事),尾插 55 mm 余约 4 mm。 摆给用户三条路之后,用户改为 「都挪,主板跟着旋转」,随后又补一条 「U4 移到右侧」。板框仍是 90 × 68。
35.1 几何(事实来源 pcb_blade.py:PHONE_ROT = 180 + phone_xy(u, v) 唯一实现旋转)
| 项 | §34(90×68 第一版) | 新 |
|---|---|---|
| 主板 | 接口边朝下,原点 (1.5, 22.34) | 转 180°,接口边朝上;投影 x 1.5 |
| 服务带 | 底部 11.34(金手指区之上) | 顶部 12.34(接口边 55.66 → 板顶 68) |
| 两条槽 | y 18.14~21.14 | y 56.86~59.86;尾插槽 x 5.01 |
| 排线在 B 面 | 穿槽后往 +y 到 J5/J4 | 穿槽后往 −y;J5 (44.82, 52.66) / J4 (15.01, 51.66) 底层 rot 180 |
| C60 | (38.175, 16.5),贴金手指区 | (31.915, 61.5),两槽之间;H4 螺钉头圈 2.2 定下沿 56.0,上沿离板边 1.0 |
| J3 | 服务带尾插槽东头 rot 270 | 尾插槽正北 (20.3, 63.3) rot 0,信号盘朝南对槽口 |
| 七个孔 | — | H1 (67.19,45.76) H2 (67.89,28.36) H3 (66.89,16.96) H4 (26.69,53.76) H5 (11.19,14.46) H6 (3.99,27.56) H7 (3.79,23.26) |
| 侧键 K1~K4 | 左下 | 右上 (64 |
⚠ 机械上要确认:SIM 卡托(u 大的那一端)转过来在左边,装着卡托会伸出板左沿 ~1.8 mm;C60 上沿离板顶 1.0(顶边导轨只能咬 ≤ 1 mm,同原来手机顶那条)。
35.2 为什么功率链也整块转 180°
12V 从金手指(底部 x 28.5~30.5)进,VO_P 要去 J5 / C60(现在都在顶部)⇒ 功率链改成 F1 在底、U3 在顶。
做法:STACK_UP/DN / HAND 仍按「F1 在顶」的旧锚 (81, 50.9) 算,再 flip_pwr() 刚体转到新锚 (80, 27.5),
§7.2 四条回路一个相对数都不动(F1 例外保留 rot 90,让 +12V 脚朝南)。顺带的好处:
- U2 刚体转成 rot 0 之后,全部信号脚(p2/p3/p14/p15/p17~p20)朝西(朝手机、朝 U4),外围 EFUSE_E / EFUSE_AUX 和脚在同一侧
—— 原来 EFUSE_AUX 摆在西边、p2/p15 却在东半边,
U2.2 / U2.15从 M6 起就出不来; - U1 的 FB/COMP 转到西边(贴手机那一侧),正好是 §3.1「内条放最怕吵的」;L1 离手机右沿 ~8 mm(原 8.6)。
35.3 L3 两个岛上下对调,+12V 不再走线
VO_P岛(pcb_pour.VO_RECTS):上半 x 2689.5 / y 3856.3,加两个上叶夹着电池槽(C60 / Rs1·U3),U 形单环。+12V岛:x 2784 / y 920,金手指 12V 三指 → F1。+12V 从此是「每个焊盘打孔进岛」(router.PLANE_VIA_NETS), L1 / L4 上不再有 12V 走线 —— §34 那根 L4 x≈42.5 的竖线就是把板子东西切两半、5 个网布不通的主因。§7.1 本来就写 L3 = 12V + VO 灌铜。 金手指这头:B1(对排 A1 = PRSNT#,不能打孔)在 L1 上横接到 B2 的孔;B2/B3 各两个孔(y 11.75 / 10.5)。- 大电流焊盘多打孔(
VIAS_PER_PAD):J5 / Rs1 各 3、C60 / F1 各 2。⚠ 顺带查出的老问题:§34 那版 Rs1.1 的 4 A 只靠 Kelvin 线上那一个 Ø0.3 孔进岛 (Kelvin 焊盘被整个排除在平面孔之外)。现在只排除 U3 那头的取样脚(KELVIN_SENSE)。
35.4 D±(router.dp_blade())
U7 跟 J4 一起转 180° ⇒ 在 J4 正南,下排 3(DP 西)/1(DM 东) 直接朝着金手指。走法:金手指直上 → 并拢 → y 13 起 45° 往西北 → 直上进 U7 下排,每根 1 个孔。USB_DP / USB_DM 53.07 / 53.07 mm(§34 是 42.0 / 40.5,差 1.5);DPJ/DMJ 2.48 / 2.54。 手性零交叉(先左转再右转,DP 一直在左手边;两个转角内外侧长度抵掉)。静态最紧 0.17(进 J4 那段,节距定死)。
35.5 离线试布线:先合成焊盘、服务器比变体,再下发
板上还是 §34 的旧摆位 + 旧铜,所以试布线不碰板:synth_pads.py 把改摆位前抓的焊盘表(r2/archive_blade_prerot_0911/)
按新摆位刚体变换(底层 90° 按 §25.3 实测的「先镜像再逆时针」);remote_blade.sh 加 NOSNAP=1 跳过抓板,过孔快照写 []。
下发后必须 pcb_route.py --dump 重抓、pads_diff.py 和合成表逐脚对账,不过不许下铜。
服务器几轮(每轮 4 组,PyPy 各 ~30 s)按铜判断(blade_conn.py):
| 轮 | 改了什么 | 断开的信号网 |
|---|---|---|
| 1 | 新布局第一版 | 4:U2.2 / U2.15 / U2.20 出不来 + SDA(U4.23) |
| 2 | 调 FIRST_NETS 顺序 | 4~5:换顺序 = 换一批 U2 的脚断(p2/p15/p20 ↔ p3/p14/p18) |
| 3 | 细间距芯片「禁换层圈」VIA_KEEP_M 0.9 / 1.2;--gndvia 先打孔 |
4;--gndvia 放在信号前面 ⇒ 9~10(GND 孔抢出口) |
| 4 | U2 对格(U1_Y 27.5 → 27.6);--gndvia 挪到信号之后 |
4(U2.2 / U2.15 仍出不来);--gndvia 不再伤信号 |
| 5 | 排布器按「芯片脚→外围件连线不交叉」换位;上拉不按 +3V3 找去向 | 5~6:U2 西北 / 西南角的对端顺序顺了,U2.2 / U2.15 仍出不来 |
| 6 | U2 角上四只脚预扇出(router.QFN_FAN,--nofan 对照) |
带禁换层圈 6(扇出端点被逼在 L4 上挤不出去);关禁换层圈 2(U2.17 + U4.7)⇒ VIA_KEEP_M 默认改 0 |
| 7 | 同上,四组都关禁换层圈 | 2;--gndvia(放在最后)也是 2 ⇒ GND 打孔不再伤信号 |
| 8 | U2 西列 p17~p20 也预扇出 | 2:EDL_EN(U4.7) + EFUSE_FLT(U2.20) |
| 9 | U4 北排 p7/p8 扇出后就地落孔换 L1(拓扑交叉:它们往西、西边的 KEY 往东北) | 1:$1N156(U2.17);定点补线补上后 router_check 查出 8 条:GND 引出脚压 USB_THERM(--gndvia 只核落点没核引出脚)、$1N158 从扇出端点斜着压 C14.2(虚拟焊盘名 fan: 被当成金手指落点、不查邻盘)⇒ 两处都修 |
| 10 | 同上修完 | 1:$1N158(U2.18),补线补不上 —— C14 的 GND 盘朝着 U2、信号盘在远端 |
| 11 | 排布器 flip_2pin():两脚件在 rot 0/180 之间挑「接芯片的盘朝芯片」 |
0(v0 --gndvia --first EFUSE_FLT,EDL_EN 与 v2 --first EFUSE_FLT 都是 0);router_check 精确净距 0 条 |
结果(第十一轮 v0,缓存 _blade_routes.r11new-v0.json):678 段 / 275 孔(GND 51,其中 --gndvia 打的细间距地脚孔)/ 总长 2012 mm;
信号网按铜全通;D± 53.07 / 53.07。没打上孔的 GND 脚 16 只(多是 QFN 散热盘分瓣、SOT-23 地脚),等铺铜后按 DRC 连接性核。
§34 那版:断 5 个网 + 27 只 GND 脚铺铜够不着。
35.6 下发与板上结果(2026-09-11 晚,用户确认)
⚠ 下发前抓板发现:板上铜层 0 段 / 0 孔(§34 那版的铜已经不在了)、15 件被用户在客户端里挪过(U4 放右侧那一类尝试)——
与交接记录不符,问过用户后覆盖;下发前整板快照 _blade_board_prerot_0911.json。
| 步骤 | 结果 |
|---|---|
| 槽 / 孔重画 | 两条槽 y 56.86~59.86、七个孔,pcb_blade --verify 过 |
| 摆位 | 82 件读回全对;pads_diff.py 359 块焊盘和合成表逐块一致(J4/J5 底层 rot 180、C40/R40/R41 转 90° 都对) |
| 铜 | 678 段 / 275 孔 + 缝合 72(服务器算;NOSNAP=1 + 由缓存生成的导线快照,布线孔当零长度导线一起避让 —— stitch_points() 本身只避焊盘和导线) |
| 斜切 / 铺铜 | 4 轮到 0 直角;重载逐项相等;铺铜 25/25 |
board_check |
信号 56/56 全通 |
| DRC | 第一遍 10 = 缺口 4 + GND 6(U1.2/3 离散热盘 0.3 没接、U3.2、J4.12 的「斜线→桥线→孔」DRC 不认、J4.16 头顶被 USB_THERM 孔堵);补 6 段 + 1 孔(先进缓存、router_check 0 条再下板)⇒ 4 条,全是 PCIe 缺口 0.2 mm(§27.8) |
最终快照 _blade_board_rot180_final_0911.json。还欠用户:SIM 卡托 / 顶边导轨 / 排线实物走位这三条机械确认。
35.7 PCIe 缺口 1.9 → 1.6(用户拍板,§27.8 结案)
fp_edge.NOTCH_W = 1.6(CEM 值;1.9 是 KiCad 封装值)⇒ 口部断点 38.70 / 41.30,缺口边到 11/12 号指铜边 0.35(原 0.2)。
PCB 上元件的封装是工程库副本,不是个人库原件:J1 getState_Footprint() = a1ad3deadadbf758 @ 05a65c22…。
API 没有「更新封装」(IPCB_PrimitiveComponent 只有位号 / 位置 / uniqueId 这些 setter),但直接改工程库那份副本 + 重载 PCB,实例就跟着变:
fp_edge.py --notch 只删 / 重画两份封装的板框层 16 段(焊盘不碰)→ 重载后 J1 内部缺口读回 38.70~41.30、64 只焊盘网名全不变 →
pcb_blade --outline(板框折线里的缺口同源)→ 铺铜 25/25 → DRC 0 条(间距 0 / 连接性 0)。
⚠ lib_Footprint.search 在这台客户端上抛 o[r].match is not a function,所以 --notch 按 FP_COPIES 里的 uuid 直接开编辑器。
第五轮放大看才看清 U2.2 的真实卡法:对端顺序已经顺了,但 A* 一次只看一根 —— $1N164(p3) 出脚后斜到 x 79.0 往北走,压住 U2.2 头顶那一列;反过来让 EFUSE_PG 先布,它又在 U2.2 正北落孔,孔挡住 p3 那一列。 两只 0.5 节距的脚同时往西北出是走得通的(西边那只先拐、东边那只多直走半格再拐,两条 45° 平行线相距 0.707), 贪心 A* 找不到这种配合 ⇒ 和 D± 一样改成构造:p2/p3、p15/p14 各画「直走 1.0 / 1.5 + 45° 0.75」,端点在格点上、 落在禁换层圈外,A* 从端点起步。静态校核离相邻异网焊盘最近 0.275。
这几轮顺带抓出来、已经修掉的:
ctrl_hand的 I²C 上拉:位号写反(R41→SDA、R40→SCL,实际 R40 是 SDA 上拉)+ 排到 U4 南边时 +3V3 那只盘朝着芯片 ⇒ 改成按网名反查、pad1 朝 U4(南边 rot 270)。- U2 不在 0.25 格点上:刚体转之后 U2 中心 = U1_Y + 21.9,取 27.5 时西列 p17~p20 落在 x.15 / x.65,出线挤到 0.25 以下。 U1 两短边的 EN/PG/FB/COMP 和 U2 没法同时对格(相对距 21.9 不是 0.25 的倍数),旧版也一样,保 U2。
- U2 角上出不来的真因是摆位交叉:只按「离对端最近」排,EFUSE_PG(p2) 的上拉 R15 被 +3V3 的最近焊盘(U3.6)拽到东北,
而 $1N164(p3) 的分压 R16/R17 在西边 ⇒ 两根一出脚就交叉,先布的那根横在另一只脚头上。
⇒
target_point()对「还挂着别的信号网」的件不再按 +3V3 找去向;reassign()的代价加「芯片脚 → 外围件连线」交叉数 × 6 mm。
36. D16:底板电源入口改 USB-C PD 取电(2026-09-11 用户拍板「走方案 B」)
36.1 决定与理由
用户要求改成「用 Type-C 从 120W 氮化镓充电器取电,并兼容各手机厂商的充电器」。可行性结论(会话里给过用户):
- 各家 120W 标称都是私有协议(小米 / vivo 20V 6A、华为超级快充、OPPO SUPERVOOC),要手机端鉴权,取电芯片拿不到。 唯一的公约数是 USB PD:小米 120W / 华为 100W 的 C 口 PD 只到 65W(20V 3.25A),vivo 120W / Anker 这类 100W。 UFCS 互通只有 40~44W,而且 CH224A 不支持 UFCS。
- 单口上限 20V × 5A = 100W(5A 要 e-marker 线;普通 3A 线 60W)⇒ 降压后 12V 侧 约 95W / 7.9A, 低于 R1 §22.6 的最坏 9.99A(≈108W)。整板常态 10~25W,任何一档都够;最坏工况靠固件限功率(R1 §8.3 早就规划了「读输入侧 INA226 按优先级降载」)。
- 20V 不能直接进 12V 母线:U29 泄放 13.2V 导通(10Ω 上压 40W)、两块板的 SMBJ13A 14.4V 击穿、刀片 TPS54622 VIN 上限 17V。 ⇒ 板上加一级 20V → 12V 降压,12V 母线及以下(A1 的储能 / 检流 / 泄放、五片刀片)一个字不改。
- 顺带消掉决策 #20 的已知风险:DC-005 家族额定 2~5A 却要走 10A;USB-C 在 20V 下只走 5A。
36.2 电路(新页 A1B-PD,脚本 r2/a1b_pd.py)
J1 USB-C(TYPE-C-31-M-12,C165948,与 J23 同料,额定 5A/20V)→ F1 12A → VIN_FUSED(20V,≤5A)
→ D3 SMBJ22A + C21~C24 10µ/50V + C19/C20 100n/50V → U37 LM61495QRPHRQ1(C3188410,10A,3~36V)→ L4 → VIN_SW(12V)→ A1-INPUT 的 Rs6。
| 件 | 取值 | 依据 |
|---|---|---|
U36 CH224A(C42459160) |
单电阻 R7 120k ⇒ 只请求 20V |
各家 PD 都有 20V;12V 不是每家都有(小米没有);28V EPR 手机充电器不给 |
D3 |
SMBJ22A(C151920) | VRWM 22V > PD 20V 档上限 21V。⚠ 固件不许让 CH224 请求 28V(寄存器 0x0A=5) |
R8 RT |
22.1k ⇒ 720 kHz | RT = 16.4/fsw − 0.633;电感下限 L > Vout/(fsw·0.6·10A) = 2.8µH。400 kHz 要 ≥5µH,SRP1265A-6R8M 立创查不到料号,故提频率 |
L4 |
SRP1265A-4R7M(C780205) | Isat 28A / Irms 13.5A / 8.4mΩ;纹波 1.42A(14%) |
| FB | R10 110k / R11 10k |
VFB 1.0V ⇒ 12.0V |
| EN | R12 100k / R13 10k |
1.263V × 11 = 13.9V 才启动(12.8~15.0)⇒ PD 协商到 20V 之前(5V / 9V)不启动,母线大电容不会在 5V 下拽充电器;也挡住插错口(PC 只给 5V) |
| SPSP / SYNC / BIAS | VCC / GND / GND | 扩频开;轻载自动 PFM;BIAS 按手册「输出不低于 12V 就接地」(BIAS 绝对最大 16V) |
C14~C17 |
22µ/25V | 输出侧另有 A1 的 C2/C3 470µF + C4/C5 10µF |
| I²C | CFG2/CFG3 → TCA9548A 通道 5(SDA6/SCL6) |
寄存器 0x50 = 当前档位最大电流 ×50mA ⇒ 固件按它定整板功率上限(60 / 65 / 100W)。CH224A 自带 10k 上拉 |
删掉的(原 A1-INPUT):J1 DC-005、Q1 AO4407 反接保护、DZ1/R1/C1 栅极缓启动(USB-C 不会插反;缓启动由降压软启动 + EN 门限代替)。
F1 位号保留、搬到 A1B-PD。DP/DM、PG、RESET# 都不用;SBU / D± 不接(只取电)。
36.3 原理图改动
| 页 | 改动 |
|---|---|
| A1B-PD(新) | 25 件 / 90 段 / 21 旗 / 21 端口。U37 两侧 10 间距的脚挂不下旗,功能块间一律用端口(SW12 BST12 VCC12 RT12 EN12 FB12) |
| A1-INPUT | a1_input.py 加 D16_DROP / D16_SEGS:旧入口 6 件和挂在它们上的导线组整组删,VIN_SW 组只摘掉 Q1 漏极那五段;删完断言没有导线端点压在被删件的引脚上 |
| A3-CTRL | TCA9548A 脚 15/16(通道 5)引出 SDA6/SCL6(x 545,和 SDA5/SCL5 同列;名字只能 4 个字,右边 x≈620 起是 DAC 那一列的标签);A2 的地旗从 (585,270) 挪到 (530,290),让开新标签 |
改前两页的现状快照:r2/_a1_a3_pre_d16.json(A1 页上当时有 104 条文字,脚本只生成 16 条 —— 历次重画残留的)。
36.4 还没做的
- ⬜ 用户截图确认三页方向与排版(CLAUDE.md 规矩)。
- 🔶 PCB:导入 / 摆位 / 脚本已完成,布线进行中 —— 见 §36.5。
- ⬜ 固件:CH224A 驱动(TCA9548A 选通道 5,读 0x09 / 0x50)+ 整板功率上限按 0x50 取;禁止写 0x0A=5。
- ⬜ 丝印:J1 旁标「PWR 20V」,J23 标「USB」。两颗同料的 C 座插错不会坏(见 A1B-PD 页【C】),但要标。
36.5 PCB(2026-09-11 深夜 ~ 09-12)
导入
- 上次推三页时存了盘,但 A1-INPUT / A3-CTRL / A1B-PD 74 件的原理图 uniqueId 全是空的(存盘、重开工程都不给分配;A4-HUB 那次是给了的)。
空着导入 ⇒ 板上已摆好布好的 A1 / A3 49 件会被当成「移除 + 增加」。⇒ 原理图侧
setState_UniqueId()可用: 保留件写 PCB 现有的 ggeNNN,23 颗新件写d16_<位号>;存盘、重开工程读回 74/74。之后uid_sync_base0 / 141 不一致。 - 对话框是虚拟表格,按行读会超 30 s;改从表格的 React props 里直接取
rows(185 行 / 107 条明细): 移除 4(C1 DZ1 Q1 R1)/ 增加 23 / J1 换封装 / 改网络 29(U35.15/16 → SDA6/SCL6 + 11 组自动网名整组换号)/ 通道ID 50。 应用时取消「包含设计规则」「同时更新导线的网络」—— 换号那 11 组板上 51 段 / 10 孔照样被改了名(两个勾都没勾)。 - 验收:164 件位号 + 封装逐件对上;导入前后全板焊盘网名逐脚比对,差异 = 对话框清单,一条不多;铜一处未动(仅两段共线 VIN_SW 被并)。
快照:
_base_board_pre_d16_0911.json/_base_padnets_pre_d16.json(导入前)、_base_board_post_import_d16.json。
摆位(place_base.PD_HAND,27 件逐件手排,--only-pd 只下发这一窝) —— 图 M18(会话里给过用户 v4)
- J1 C 座底层 rot 180 口朝南 (12.5, 5.25);F1 在 J1 正北(两组 VBUS 在 F1 南合流);U36 CH224A 在 J1 东(CC 列朝西、I²C 列朝东进槽下走廊)。
- U37 底层 rot 270:SW 边朝西接横放的 L4(rot 180,SW 端朝东),信号边(FB/RT/VCC/EN)朝东。 这样转的理由:U37 两侧 VIN 要连通(见下),信号边朝东时 FB 采样线能沿东侧空带北上回 VIN_SW,不用跨 VIN; L4 的输出端正好落在西北角挨着 C2 / C5;L1 小岛变成南北向一长条,与 12V 电流方向平行。
- 两颗 100n(C19/C20)贴 U37 南北两侧 VIN/PGND(中心距 1.5);南侧大电容 C21/C22,北侧 C23/C24(经 L1 小岛); BOOT C18 在西北角落 L4.1 上沿;东侧一列 R8 / R11 / R10 / C13;EN 分压东南;输出电容 C14~C17 在 L4 北沿一行; RT602 改贴 U37 东侧测降压(用户选;原来测 DC-005 接触热)。
- 留空区
PD_FREE:J1 两组 VBUS 之间(CC 换层 + VIN_RAW 合流)/ BST 出路 / EN·SYNC·SPSP 出口 / SW 连接段。 - 读回:位姿逐件对上、朝向断言(J1/J23 口朝南、U37 SW 在西、L4 SW 端朝东)过。
⚠
verify()原来按焊盘块中心比,U37 这类多边形焊盘抓回来按板上水平条带拆,转 90° 后拆法不同 ⇒ 报了假的 0.375 mm; 改成逐脚比所有块合起来的外框(27 件最大差 0.002)。泄放链 Q3 漏极网名原来写死$1N114(导入后是$1N213)⇒ 改按 5 脚现取。
两处单层走不通 → 用户选的换层方案(pcb_base.PD_L1)
- CC 夹在两组 VBUS 之间(USB-C 脚序决定:GND VBUS CC2 … CC1 VBUS GND),VIN_RAW 一合流 CC 就被围住 ⇒ CC 在两组 VBUS 之间打孔上 L1,在 12V 大铜里各开一条窄走廊东去 U36 再下来(CC2 南、CC1 北,不交叉)。 ⛔ 没选「壳体底下走 L4」:20V / CC 压在接地金属壳下只隔一层阻焊。
- LM61495 两侧 VIN 连通(VIN1/VIN2 分两侧、中间夹 SW,TI 做法是 VIN 走另一层)⇒ U37 正上方 L1 挖一块 VIN_FUSED 小岛
(18.9
22.9, 13.429.2);L1 12V 主块在这一段还剩 18 mm。
- 实现:
route_base._build先把窗口从 12V 挡线图里扣掉、再按各自的网封(⚠ router_mark在别的网已占的格子上写会变 255,不能叠加);pour_base12V 大铜绕开小岛(外扩 0.5),小岛自己铺 VIN_FUSED。
脚本改动
pour_base:入口铜块不再按「本网焊盘外框」自动撑(新件东一颗西一颗,一撑就把 U37 包进去)⇒ 手画矩形PD_POUR(VIN_RAW 1 / VIN_FUSED L4 3 + L1 小岛 / SW12 / VIN_SW 3);Q1 栅极缺口删除。离线断面:J1→F1 6.60(要 3,不强制)/ L4→储能→Rs6 7.95(要 6.5)/ L1 12V 主块 13.20(要 8)。rules_base:加 SW12(PWR9A、铺铜全连接);_base_npth.json补 J1 两颗定位孔(按 J23 同料平移)。- 新脚本:
d16_route.py(服务器:固定构造 → 早段地孔 → 逐网补线 → 晚段地孔)、remote_d16.sh(上传 / 拉回,MODE=reach跑d16_reach.py泛洪诊断)、d16_check.py(本机四层精确净距 + L1 窗口 + 连通)、d16_push.py(下发 + 读回按几何逐条核)。
板上删旧铜:VIN_RAW / VIN_FUSED / GATE 整网 + 角内 VIN_SW / NTC2 + 压新件焊盘的 GND ⇒ 线 36 / 孔 2,按几何匹配删。
⚠ 删完线数只少 34:EasyEDA 删除过程中把残段合成了两条新线(新 ID、新几何,导入后的快照里没有),按几何再删一次才干净
(_base_board_post_del_d16.json,1787 段 / 580 孔)。⇒ 删铜后一律「期望 = 旧快照 − 删除清单」与读回逐条比。
服务器补线(d16_route.py,每轮 1525 s)
- 第一轮:SPSP(南侧)→ VCC(东北角)在 L4 上只能绕东侧,一根线把 FB / RT / EN 的出路全封了;0805 / 1206 的 GND 盘被当成散热盘打了盘中孔;
VIN_RAW 0.5 落不进 C 座 VBUS 0.3 宽的焊盘条;VIN_SW 报
C2.1#t出不来是通孔的 L1 障碍副本被当成了焊盘(假的)。 - ⇒ 固定构造(本机
d16_check四层精确净距 0 条后才上服务器): SW12 U37.16↔L4.1(1.0 宽,夹在两只 PGND 角脚之间)/ SPSP→VCC 走 U37 肚子底下(0.15 宽,从 SW 焊盘和东侧那排脚之间穿过, 离 FB 0.186、BIAS 0.165)/ U37 PGND×2、BIAS、SYNC、AGND 的「短线 + 孔」(AGND 从 R8 与 R11 中间往东引出)/ J1 两只贴片 GND 脚接旁边外壳通孔脚 / C18.SW → L4.1 / VCC 6 脚 → C13 / VIN_RAW 两组 VBUS 各一根竖线进 F1.1。盘中打孔阵只给 U36 散热盘。 - 第二轮:GND 地孔全打上;FB / RT / EN / VIN_FUSED / VIN_SW / NTC2 通;剩 BST12(被 SW12 的绕线封了)、VCC 6 脚、VIN_RAW ⇒ 上面最后三条固定线。
- 第四轮:除 SDA6/SCL6 外全通(197 段 / 49 孔,本机 0 条)⇒ 已下发存盘(
_base_board_post_push_d16.json)。 读回时两段同网 VIN_FUSED 被 EasyEDA 拼成一根(0.4 的短线挪了 0.05 mm),按实际坐标核过:铜覆盖原两段、离 C18 0.276。
I²C:CH224A 改挂主总线(用户 2026-09-12)
- SDA6 / SCL6(→ U35 通道 5)连着两轮「没布通」。
d16_reach.py在布线网格上泛洪:U35.15/16 能到的范围被整个圈在北半边 (y ≥ 46.9、x ≤ 72.6),南边 U36 能走遍全板但碰不上 —— 圈住它的是 J36 槽一带的原有布线(GND / +3V3 / L1 +12V、+5V / 风扇测速, 内层残留线挡孔),不是新入口造成的。A* 没有搜索上限,「没布通」= 真没有路。 - 用户选改挂主 I²C:0x22/0x23 与主总线上 U13 0x43 / U6 0x4A / U7 0x4B / U35 0x70 不冲突。
a1b_pd.pyU36.2/3 → SCL/SDA;a3_ctrl.pyU35.15/16 回 NC。推送、verify_sch 两页 PASS、xpage 0; uniqueId 同样被整页重画清空 → 再写回;导入 20 条改网(含 7 组自动网名换号:DAC 6 组 + CFG1$9N85 → $9N145),焊盘网名比对 0 意外。 ⚠ 导入后要place_base --dump重抓焊盘表,否则 route_nets 拿旧网名判「已连通」。 - SCL 能接(落在 U13.5 往东那根上),SDA 接不进:南边唯一的 SDA 是 U13.4,东边 INA_ALERT / SDA / SCL 0.5 mm 并排出束、
西边本体底下有一段 SCL 把 2、5 脚连起来 ⇒ 四面被围,这束一直夹着进北边,中间放不下一个孔(
d16_tap30 个落点全不通)。 - 用户选拆 U13 这一束重布(
d16_rip.py,只改数据不动板;拆除区 (15,38)~(40,58) 内三网外层铜,U13 本体底下的 2—5 脚 SCL 连线留着):- 12 组(先后 × 线宽 0.2/0.15)全都至少断 1 块 —— 南北之间能穿墙的路只有两条(那条走廊 + 经 L1 绕行的一条),却有三根线;
- 实验:候选落点 30 → 100,INA → SDA → SCL 三网都能回北边,但 U13 的 SCL 新路从南边兜过 U36,把 U36.3 和 SDA 隔开; INA_ALERT 不接回的话,U13 的 SCL 反而回不去(这条路不成立);
- ⇒ 逐步排序
--steps:INA:1 → SDA:1 → SDA:2 → SCL:1 → SCL:2(线宽 0.15、候选 100)0 块断开,本机净距 0 条。 代价:新 132 段 / 21 孔、303 mm(U13 的 SCL 从北侧 2 脚绕了 44 段 / 13 孔,INA_ALERT 36 段 / 5 孔)—— I²C 100400 kHz 下长线电容仍在允许范围内。 - 同批下发:C18 → L4.1 那段终点伸进焊盘(
board_check把 3.5×5 的 L4.1 读成 5×3.5,报 SW12 两块)。
37. 底板顶面件:C2 / C3 / J26 / J27 / J33(2026-09-12 用户要求)
用户:「将风扇座,C2,C11,J33 移到顶面」——追问时澄清 C11 是指 C3(C11 是 0402 的 3V3 去耦,
翻面等于把铜从 L4 挪到 L1、还要在 12V 大铜里挖窗,去耦电容又跑到芯片另一面,已排除)。
37.1 为什么这五件翻面是「零代价」,而别的件不是
名单在 pcb_base.TOP_EXTRA,side_of() 按它判层。判据只有一条:
焊盘全在封装 y = 0 那一排。place_base.pad_off() 翻面只把原生偏移的 y 取反,
所以 y=0 的脚翻面之后孔位、针序、铜一根都不变 —— 纯粹是装配面 + 丝印换面。
⛔ 焊盘不在一条线上的件(贴片、双排针)不成立:那种翻面会把铜整个挪到另一层,要重新布线。
37.2 顶面的限高不归 H_BOTTOM 管
插槽把刀片底边抬到板上约 11 mm(§6.6),刀片自己 y 0~11 又是金手指禁布区(两面无件) ⇒ 顶面件(12 mm 的电解、11.5 mm 的排针)高度不受限,只有横向约束:
| 约束 | 判据 |
|---|---|
| 刀片板面 | 竖在 y = 槽心 ±0.8(板厚 1.6),顶面件本体离它 ≥ CARD_CLR 0.5 |
| 槽体 | slot_body(i),x 28~70 |
| 背面 | 通孔件在背面只占焊盘(±4.61 × ±0.8),不是 5 mm 深的本体 —— 所以能塞进背面件的缝里 |
place_base.selfcheck 已加这一支。J27 原位 (13.5, 88.0) 的本体 y 85.5~90.5 正好穿过 J34 那片刀片
(89.64)⇒ 必须挪;而 x=13.5 往南焊盘先压 C738 再压 R754 ⇒ 只能往西,定在 (9.0, 85.5, rot180)。
rot180 是扫出来的:针序反转把 12V 脚换到靠 C738 那侧,未完成从 6 条降到 2 条。
37.3 ⛔ A6 西北角是「单层布线区」—— 这一轮最贵的一课
l1_12v_rects() 的 12V 主块是 x 0.527.8 / y 0.597.5 的一整块,把整个 A6 区的 L1 占死
⇒ 过孔上得去但走不动,那一带等于单层,而 L4 早被风扇驱动那一窝件占满。
于是「几何上放得下」≠「线接得上」:按用户先选的「两只座都南移进走廊」,
扫了 800 个候选落位(fan_scan.py,PyPy 上单轮补线 1.2 s)、压线宽、拆线重布、
修了通孔盘放大量,**始终有 34 条布不通**。
解法:给 FAN_PWM_L 在 pcb_base.PD_L1 里开一条 L1 走廊 (4.0, 86.0, 21.0, 89.0)。
它只挡导线图(route_base._build 先从 12V 里扣掉窗、再按窗的网名封),
铺铜那边不用开窗 —— L1 的 12V 铺铜本来就会绕开异网导线,D16 的 CC 两根走的就是这个路子。
- 断面账:主块宽 27.30,被一根 0.15 的线占掉约 0.5 ⇒ 仍 ≈26.8 mm ≫ §6.4 要的 8 mm。
- y 86~89 不碰任何一槽的 12V 指头(槽 5 南指 y≈83.04 / 北帽 y≈96.24)。
- 结果:四个风扇网全通,补 60 段 / 3 孔 / 87.5 mm,其中 PWM 借 L1 走 13.9 mm。
37.4 TH_GROW:通孔盘被统一放大 0.6,把排针的中间几只脚封死了
route_base.TH_GROW = 0.6 本是为 J1 / J23 的长槽孔加的(槽比焊盘大),却对所有通孔盘生效:
2.54 间距的风扇座(圆盘 1.6)在占用图里变成 2.2 × 2.2,相邻两脚之间只剩 0.34,
而出口要「半盘 1.10 + 线半宽 + 净距 = 1.33」才落得下第一格 ⇒ 中间那几只脚一根铜都出不来。
症状是布线器报「J26.3 没布通 / 一根铜都没有」,看着像没地方走,其实是被自己虚胖的邻盘封死;
压线宽、拆线重布、换落位全都救不回来。已改成按件区分(th_grow(),只有 TH_GROW_REFS 放大)。
37.5 两条方法论
- 能不动的件就别动。J26 原地翻面 = 零布线代价;它一旦挪窝,那三条线就得在单层区重布,
而布线器布不出来的路,不等于板上原来没有 —— 拆之前先备份几何,走不通就原样画回去
(
ripped_backup.json→restore_ripped.py,这一轮真用上了)。 - 搜索的判据缺一条,就会被精准地钻这个空子。
fan_scan起初没查「两只座本体不许重叠」, 扫出来的「最优」是两只座摞在一起(J26=(13.5,94.5) / J27=(12.0,94.5))—— 布线代价当然最低。
- ⬜ NTC2 绕了 108 mm / 12 孔(RT602 新位置 → 东边的老线),通,不好看。
收尾(修正 3)与最终状态
- DRC 第一遍:间距 3(全是「钻孔到钻孔」:服务器扇出的 VIN_FUSED / GND 孔紧挨着固定孔,0 / 0 / 8.5 mil)+ 物理 4(R10 采样线 0.2 < PWR9A 下限 0.3)
- 连接性 4(J36.1 / J36.4 / Q6.2 GND —— 新线切了铺铜 / 铺铜分块变了)。
⇒ 删 3 个服务器孔(留固定孔,C19/C20 的地仍经各自引出线接到固定孔)、采样线加宽 0.3、J36.4 / Q6.2 各补 GND 孔(
d16_gndfix.py, J36.1 找不到落孔点,靠与 J36.4 相连的那根 L1 GND 线)。d16_check补了同网钻孔间距(原来只查异网)。
- 连接性 4(J36.1 / J36.4 / Q6.2 GND —— 新线切了铺铜 / 铺铜分块变了)。
⇒ 删 3 个服务器孔(留固定孔,C19/C20 的地仍经各自引出线接到固定孔)、采样线加宽 0.3、J36.4 / Q6.2 各补 GND 孔(
- 最终:快照
_base_board_final_d16.json(2104 段 / 648 孔),图M18-d16-routed.png;重铺 147 块填 135(功率铜面全填); DRC 间距 0 / 连接性 0,只剩插槽封装自带 5 条(§27.8 起的老问题);board_check118 / 121(GND 6 只通孔 / 铺铜脚、XTAL1/2 圆弧 —— 老误报); 断面 L4→储能→Rs6 7.95 mm、L1 12V 主块 13.20 mm。 - ⚠
reload_base重载前会 save():一次d16_push … | tail && reload_base把读回差 1 段(被同网宽线整段覆盖的碎段)的版本存了进去, 无害;链条一律set -o pipefail。 - ⚠ 2026-09-12 复核板面(用户问「板上是不是最后那版」):与
_base_board_final_d16.json逐项比,少了 16 块铺铜、全是内层地 (GND-L2-07 / GND-L3-07,L2/L3 各 13 → 5;L1 55 / L4 66 一块没少),线 / 孔 / 弧 / 填充 / 164 件位姿全同 —— 也就是说内层地平面被删掉一多半,而 DRC / board_check 都不会直接指出来(一个不读铺铜,一个把它算成「靠铜面成网」)。 同时 USB2 差分对有 5 段直角改成了 45° 斜切(三个角),四层精确净距重算 0 条 ⇒ 改好不是改坏,保留。 ⇒ 只pour_base --push重建 147 块 / 填 135(L2、L3 各回 13),重铺前后线 0 变、孔 0 变、元件位姿 0 变; 恢复前存档_base_board_before_repour_0912.json,此后基准_base_board_d16_restored_0912.json。 教训:交接 / 收尾前按快照逐项比,铺铜要按「层 + 网 + 名字」逐块比,光看总块数看不出内层被删。
38. 底板风扇窗口按用户新布局重布 + L1 走廊重开(2026-09-12 用户要求)
用户:「将底板按照现在我的布局重新布线」→ 选「风扇窗口整体重布(拆掉自己手布的 43 段重来)」+「GND 回流孔一起补」。
38.1 ⛔ 走廊是跟着摆位走的,摆位一变走廊就作废
§37.3 给 FAN_PWM_L 开 L1 走廊解决了「A6 是单层布线区」,后来又按当时的摆位加了三条
(FAN_TACH_OUT 贴东缘竖带 / FAN_EN / FAN_PWM 短横带)。这一轮发现:
用户重摆之后,那四条走廊注释里写的坐标全是旧的 —— R748.1 从 (18.2,91.0) 跑到 (5.13,73.91)、
R757.2 从 (27.2,93.0) 跑到 (18.11,83.57)。走廊还在原地,等于没开
⇒ 四条长途网(FAN_EN / 两路 TACH / FAN_PWM_L)必然布不通,与布线器参数无关。
⇒ 走廊必须和摆位一起维护。为此把走廊做成可配置(_base_window.json 的 pd_l1_extra,
repair_window.py 运行时替换 B.PD_L1 里的 FAN_*),服务器单轮 1.5 s,试一组不用改源码;
定稿后再固化回 pcb_base.PD_L1。
38.2 走廊必须盖住焊盘正上方,不能只盖沿途
只盖沿途的话,那只脚得先在 L4 挪到走廊下方才打得了孔 —— 实测 J27.4 / Q10.3 就是这么卡住的:
| 版本 | 走廊 | 未完成 |
|---|---|---|
| 无走廊(旧的四条按旧摆位) | — | 4 |
| v1:只盖沿途 | 4 条 | 3(FAN_EN 0 段 → 11 段并布通) |
| v2:盖住焊盘(定稿) | 6 条 | 2 |
v3:把 FAN_TACH_IN 竖带再放大 |
6 条 | 2(换了人:TACH_IN 通了、FAN_EN 掉了) |
v4 = v3 + 把 FAN_EN 顶到 priority 最前 |
6 条 | 2(还是换人,总数不变) |
⇒ 再次印证「priority 是按下葫芦浮起瓢」(§36 同结论)。别再调。
38.3 定稿的六条走廊与断面账
FAN_EN (12.00, 76.10, 27.50, 77.10) R748.1 西段走 L4、东段借 L1 到窗缘
FAN_TACH_IN (16.00, 75.15, 27.50, 76.05) 主干端点 (26.00,75.62) 在窗缘
FAN_TACH_IN (13.70, 76.05, 16.20, 90.40) 竖带盖住 Q9.3 / R753.2
FAN_TACH_OUT (17.40, 80.70, 27.50, 81.70) 盖住 Q10.3
FAN_TACH_OUT (17.40, 81.70, 18.80, 84.10) 竖段接 R757.2
FAN_PWM_L (10.30, 83.90, 22.50, 87.30) 盖住 J27.4 与 Q6.3
- 判据(§6.4 ≥ 8.0 mm):主块宽 27.30,逐 y 水平断面上扣掉走廊的 x 跨度 ⇒ 新工具
l1_section.py。 纯几何算 11.80 mm;铺铜之后pour_base的实测断面(还要扣掉线和孔)9.82 mm,仍达标。 - 横带很贵、竖带几乎免费:横带按它的 x 跨度整段扣,竖带只扣 1~3 mm。
- 走廊 x 一律 ≤ 27.5,而槽指头在 x ≥ 27.5 ⇒ 不碰任何一槽的供电路径。
- 只挡导线图,铺铜不用开窗(同 §37.3)。
38.4 「布不通」这次不是拥塞
- L4 沿四条路径逐 x 扫过纵向空隙:没有一条彻底堵死(最窄 0.9 mm)。
- L1 上按 0.25 网格泛洪:
J27.4→ 已布 L1 段 686 个格点可达;R753.2→ 窗缘 757 个可达。 - 换层孔在
J27.4旁 0.25 mm 处就落得下。 ⇒ 三项都排除之后,FAN_PWM_L: J27.4仍 0 段,剩下的怀疑对象是 A* 自身(同 §36 的$6N64)。
38.5 板上结果
拆 43 段 → 补 139 段 / 7 孔 → GND 回流孔 10 个 → 缝合孔 25 个;
板上 外层 1960 / 内层 116(用户手布,一段没动)/ 过孔 669;铺铜 147 块建齐、填出 132(空的 15 块全是 GND 小瓦片)。
fan_check 对板上真实快照逐项净距达标(含「新孔 vs 内层线」);669 个孔 vs 新线异网净距 0 处不足。
遗留:① FAN_PWM_L: J27.4 没接上;② FAN_EN / FAN_TACH_IN / FAN_TACH_OUT 到 U20 的窗外段
(缺口 15.6 / 17.7 / 16.6 mm,中间是槽体 x 28~70 的手焊 1 mm 针排,按设计不许穿 —— 拆线前也没通);
③ DZ3.1(+12V) 被挪走后离开了原来的换层孔,最近同网铜 9.1 mm(L4 上那一带没有 12V 铜,要靠孔上 L1)
—— 拆线前就是这样,已在本轮顺手补一个 +12V 过孔(落点就在焊盘中心)。
⚠ 与拆线前逐网对比(同一套并查集判据):GND 未接 58 → 48、+3V3 未接 2 → 0、
两路 TACH 未接 2/1 → 0、+12V 一字不差、XTAL1/2 不变(老误报)
⇒ 本轮没有引入任何新的连通性问题。
38.6 两条操作上的坑
- EasyEDA 会合并线段:拆线点名 43 段、外层实际只少 42(
FAN_PWM主干被延长);下发 139 段、 板上净增 142,其中 8 段"按坐标找不到" —— 逐段核过全部被同网同层铜覆盖,真缺失 0。 ⇒ 拆 / 发之后要按「几何是否被覆盖」判,不能只按坐标比对。 - EasyEDA 的 PCB API 回的是 mil。抓板脚本漏了 ×0.0254 时,连通性判据会把每一只脚都报成"未接", 而数值上看着完全正常。
39. 底板位号丝印重排(2026-09-12 用户要求「按当前 EDA 中底板状态定版,优化丝印放置」)
板上布线以用户自己布好的那一版为准(定版,不再动铜);这一节只改丝印。
39.1 现状体检
板上 164 个位号(pcb_PrimitiveAttribute,key=='Designator'),字高统一 1.143 mm、
居中对齐、不镜像;顶层丝印(layer 3)10 个、底层(layer 4)153 个可见,C743 不可见。
板上没有任何元件外框丝印(丝印层 0 线 0 弧)—— 装配时只有位号可依。
| 判据 | 改前 | 改后 |
|---|---|---|
| 压同面焊盘 | 128 | 4 |
| 压过孔 | 48 | 8 |
| 越板框(留 0.5) | 8 | 3 |
| 位号互相重叠 | 34 对 | 0 |
重排 150 个(理想位 143 / 允许压过孔 4 / 允许压焊盘 3),白名单保留 13 个;
位号离本体中心平均 2.19 mm、最远 6.97 mm(L4,本体 15×12.5,位号贴在本体外 0.5 mm)。
39.2 ⛔ 三条判据上的坑
rotation字段是「度」且不归一化:900表示 180°、720表示 0°。 按 ×10 解读会得到「9° / 18° / 27°…」这种看着像真的却完全错误的朝向分布。读回一律% 360。- 不能用「本体 ≥ 5 mm」当保留白名单。第一版这么写,把
R9A(7.4×3.5) /D3(6.8×2.2) /U13(2.3×5.8) 这些该重排的中等件一起豁免了 —— 改后残留 25 个里 18 个是这么来的。 ⇒ 改成显式名单silk_base.KEEP:五个插槽(位号故意放槽体西侧 x=28,离本体 21 mm)、U20(让开天线净空)、顶面件J26/J27/J33/C2/C3、板边 USB-CJ1/J23。收紧后残留 25 → 12。 - 必须给「离本体」设硬上限(
MAXD = 2.2mm,量到本体外框)。 不设的话贪心会把位号甩到十几毫米外的空地上 —— 实测平均 3.28 / 最远 22.2 mm, 那样的位号对装配没有指向性。够不着就降级:理想位 → 允许压过孔 → 允许压焊盘 → 保留原位。
39.3 可行性先算过再动手
按现字高 1.143 mm 扫一遍:163 个可见位号里 161 个有解(无解只有 R13 / C745);
缩到 0.9 mm 则全部有解。⇒ 不用缩字号,保持 1.143 mm 可读性。
39.4 残留(都已定位,不是漏查)
- 白名单 5 个:
J23压过孔、J26/J33/U20越框、J1压U36.11—— 都是原本就如此的设计位。 - 重排后 7 个降级:
C731/C744/C749/R603压过孔,C745/R12/R13压焊盘 + 过孔 (都在最密的 0402 群里,周围 2.2 mm 内没有干净落点)。
工具:silk_base.py(--push 走 pcb_PrimitiveAttribute.modify(id, {x, y, rotation}),
下发后读回逐个核对),快照 _base_silk.json、方案 _base_silk_plan.json。