文件
phonerail/刀片式方案规划-R2.md
T

288 KiB
原始文件 Blame 文件历史

PhoneRail R2 · 刀片式 方案规划

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

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


0. 决策与前提

0.1 已拍板(不再讨论)

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

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

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

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

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

1. 架构

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

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

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


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

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

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

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

2.1 顺手解掉的六个 R1 约束

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

3. 机械与热

3.1 尺寸

值
刀片板框 98 × 76 ⇒ 90 × 68 mm(2026-09-11,§34;硬上限 98×98,见 D14),1.6 mm 厚(金手指要求),四角 R2。下面分区图是 98×76 版,新数见 §34.1
底板板框 110 × 125 mm ⇒ ≤ 98 × 98 mm、4 层(D15,2026-09-10),1.6 mm 厚(插槽保持力),四角 R5
槽距 20.32 mm(A4),5 槽跨度 81.28 mm
插槽 PCI-E x4 直插,槽体 39 mm(A1)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

3.3 风道

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

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

✅✅ 外壳改两件式(2026-09-13 用户拍板:顶盖一体打印 + 底盖一整块 + 螺丝固定)—— 现行方案

件 文件 内容
一体顶盖 TopShell_v1.SLDPRT 顶板 + 南北侧墙 + 两端墙 + 4 根内角立柱,底部敞开,外形 174.8 × 110.8 × 84.4(z −10~74.4)。沿用:15 mm 分风腔、顶内表面 z=72(离刀片顶 0.66,兼导轨)、11 条泄压缝、两端 Ø60 风口 + 4ר3.4 风扇孔、南墙 2 个 13×9 Type-C 窗、北墙 J33 窗 + 风扇出线窗
一整块底盖 BottomPlate_v1.SLDPRT 174.8 × 110.8 × 2.4 平板(z −12.4~−10,与顶盖外形齐平)+ 底板 PCB 的 4 根 Ø8×10 立柱(柱顶 Ø4.2 螺母孔,盲孔深 10)+ 四角 4 个 Ø3.4 过孔

固定:4 颗 M3,从底盖下方往上拧,穿过底盖四角过孔进顶盖角柱底部的 Ø4.2 热熔螺母 (角柱 10×10、在分风腔四角 x −36~−26 / 124~134;柱孔从底面进、深 82 的盲孔,顶面看不到)。 六件式的 A 组 8 颗 + C 组 4 颗 + 端板脚锁孔 4 个全部随拆件取消。

总装复验(place_twopiece.py):两件包围盒 ✅;分风腔西 15.01 / 东 15.51 ✅;干涉 360 = 基线 ✅; 顶盖墙底落在底盖板面 z=−10 ✅;底盖过孔 ↔ 顶盖螺母孔同轴 4/4 ✅; 端墙风扇孔 ↔ 风扇安装孔(R2.15)同轴 8/8 ✅(六件式时代没核过的一项)。总装顶层件 14 → 10。

装配顺序与代价(按包围盒推的,未做运动仿真):

  • 顶盖内腔 xy 覆盖了全部内部件,角柱那四列下方没有任何件 ⇒ 顶盖可以竖直往下扣到底。
  • 风扇先从外侧用螺丝固定在顶盖端墙上,扣盖时把两根风扇线插到 J26/J27;东端风扇线要跨过整机长度到西北角。
  • 拆盖要把机器侧过来拧底部 4 颗螺丝 —— 手机农场日常换机时要考虑这个。
  • 打印尺寸:顶盖倒扣打印 175 × 111 × 84.4 —— ✅ 拓竹 A1(256³)放得下(加滤网导轨后见下节)。
  • ⚠ 南墙 Type-C 窗下沿(z −5.7)离墙底只有 4.3 mm,是一条细梁,打印/拆装注意别掰断。

✅✅ Type-C 外侧沉槽(2026-09-30,现行外壳:TopShell_v11 + BottomPlate_v6)

起因:v4 起记下的已知风险兑现 —— 用户实测两个 Type-C 口墙太厚,线插不到底(母座口面缩在墙外表面里 4.26,开口只有口那么大)。 改法(用户:不要完全掏空,留 1 mm 薄壁):贯穿孔仍 = 母座口内侧轮廓 8.34×2.60 R0.7;南墙外侧加 13.4 × 7.4、R3.2 沉槽,深 1.4,槽底留 1.0, 护套能伸进墙 1.4 ⇒ 护套前端到口面 4.26 → 2.86,要求金属壳 ≳ 2.86 + 4.05 ≈ 6.9(原 8.3)。标识(闪电 / 箭头)右移到口中心 +10.5(离沉槽边还剩 1.6)。 回读:槽底薄壁面积 138.213 = 2×(90.370−21.263) 精确相等;圆柱面 R0.7 ×8 + R3.2 ×8 在位。复验(place_v11.py):干涉 360 = 基线、嵌入间隙四边 0.300、螺丝孔 4/4、风扇孔 8/8。 STL:新建文件夹\5blades\print\PhoneRail_TopShell_v11.stl(封闭、体积差 0.002%)。 ⚠ 仍需实插验证:6.9 仍比常见金属壳(约 6.5,未核规格书)略长;插不到底就把 make_v11.py 的 PK_LEFT 调小(0.6 ⇒ 要求 6.5)或改回贯穿。

✅ 螺丝选型与建模(2026-09-30,screws_v1.py,取代下文「M3 × 6 左右」)

用户实测原配螺丝太短。三种螺丝已建模并装进总装:底盖 → 顶盖 M3×10 薄头内六角 DIN 7984 ×4(头 Ø5.5×2.0 刚好埋进沉孔、与底面齐平,进角柱 8.4)、 PCB → 立柱 M3×8 同款 ×4(PCB 模型实测厚 1.67,进立柱 6.3、孔深 10)、风扇 5×12 自攻 ×8(穿 2.4 墙后进风扇 9.6,不伸进分风腔)。 复验:干涉 368 = 基线 360 + 8 处风扇螺丝咬风扇孔(预期),其它 0。⚠ 热熔螺母长度按 ≤ 6 考虑;风扇螺丝螺纹外径须 ≤ 5.1(墙孔 Ø5.2)。

✅ 底盖改嵌入式(2026-09-13,TopShell_v10 + BottomPlate_v6,顶盖已被上面 v11 取代,底盖沿用)

用户要求:底盖螺丝拧紧后嵌入顶盖、被顶盖包裹。

项 v9 v10
顶盖四面墙 墙底 z −10 向下延长 3.6(= 底盖厚),墙底 z −13.6,包住底盖侧边
角柱 底面 z −10 不变,当底盖顶面的限位
底盖外形 顶盖外沿内缩 0.5(阴影缝) = 顶盖内腔四边各让 0.3:x −15.7113.2、y −1.355104.045;四角 R1(让开打印出来带圆角的墙内角)
拧紧后 底盖挂在墙底下面 底盖顶面顶住 4 根角柱,底面与墙底齐平,侧面看不到底盖

整机外形不变 134.3 × 110.8 × 88.0;沉头、脚垫窝、PCB 立柱、四角过孔位置都不变(沉头离底盖边 ≈1.45)。 放置时脚垫着地(窝深 1.0、脚垫厚 1.5 ⇒ 凸出 0.5),墙沿不碰桌面。原「阴影缝」取消,底面只剩一圈 0.3 缝。

复验(place_v10.py):墙底 −13.600 = 底盖底面 −13.600;底盖离墙内侧间隙 西/南/东/北 0.300 / 0.300 / 0.300 / 0.300; 干涉 360 = 基线;底盖过孔 ↔ 顶盖螺母孔 4/4、风扇孔 8/8。顶盖格栅等其余特征回读与 v9 逐项相同。 ⚠ 间隙 0.3 按 A1 精度定;首件太紧改 make_v10.py 的 CLR 为 0.4,太松改 0.2。

✅ 风扇格栅改可打印(2026-09-13,TopShell_v9 + BottomPlate_v5,已被上面 v10 取代,格栅参数沿用)

问题:v7 的竖槽格栅打不出来。顶盖倒扣打印时端墙竖着长高,竖槽之间的筋 1.2 宽 × 2.4 厚 × 最长 64 高(长细比 > 50), 只有下端连着墙往上悬空长 ⇒ 晃、拉丝、断。槽头 R2.25 半圆只是 4.5 的小桥接,不是问题。

改法(用户选:加横筋 + 加厚纵横筋 ⇒ 方案 ③):

  • 槽宽 4.5 → 6.0;竖筋 1.2 → 2.0(约 5 道线);新增水平横筋 2.0、中心距 12 ⇒ 最长悬空槽段 10(原 64)。
  • 7 条竖槽被切成 34 段;只有真正的槽头保留半圆,横筋处为平边;放不下「端头 + 0.8」的碎段做成实心。
  • 开孔 1705 mm² = 原 Ø60 的 60.3%(v7 为 81.2%、v8 三横撑 75.6%)⇒ ⚠ 两端风阻明显增加, 叠加薄风扇 + 分风腔 10,首件必须实测刀片温度;不够就退回 ①(槽宽 6 / 筋 1.6 / 段长 12,开孔 65.2%)。
  • 离风扇螺丝孔最近 3.85。横筋处桥接 6 mm,A1 无需支撑。

回读判据:每面墙外表面面积减少 1790.04 = 理论(34 段槽 1705.09 + 4 个螺丝孔 84.95)精确相等; 槽头半圆柱 +10、横筋平端面 +58,与生成器预期逐个相等;风扇孔在位。 复验:干涉 360 = 基线(首次报 288,是中间刀片板体被人在 GUI 里隐藏、而复验设了忽略隐藏实体 —— 已改为不忽略,见 NOTES §39); 螺丝孔 4/4、风扇孔 8/8。整机尺寸不变 134.3 × 110.8 × 88.0。

✅ 外观美化 + 去掉滤网(2026-09-13,格栅已被上面 v9 取代,其余美化项沿用)

整机 134.3 × 110.8 × 88.0(x −18.4115.9 / y −4.055106.745 / z −13.6~74.4)。

用户选的美化项与之后的两次修改:

项 做法 回读判据
顶面圆角 顶面外轮廓 8 条边(4 直 + 4 段 R3 弧)一次倒 R1.5 R1.5 圆柱面 4 个
圆头泄压槽 11 条 1.5×60 直角缝 → 1.5×60.32 圆头槽(面积仍 90/条) R0.75 半圆柱 22 个、直边长 58.82
两端风扇格栅 两端墙 Ø60 圆孔 → 11 条竖向圆头槽(外包 R32、槽宽 4.5、筋 1.2),开孔 2295 mm² = 原 Ø60 的 81.2%,离风扇螺丝孔最近 2.59 每面外表面面积减少 2379.94 = 理论(槽 + 4 个 Ø5.2 螺丝孔)精确相等;槽端半圆柱 y 跨槽宽、z 跨半径 ⇒ 竖槽
Type-C 标识 J1 右侧 9 mm 凹刻 闪电(PWR 20V)、J23 右侧凹刻 箭头 + 圆点(USB),深 0.6 凹槽底面积 17.361 = 理论;「点在面内」判据确认无镜像、无翻转
阴影缝 底盖四边比顶盖内缩 0.5,四角 R2.5(与顶盖 R3 同心) 包围盒
底部沉头 + 脚垫 底盖加厚 2.4 → 3.6(向下);四角 沉头 Ø6.5 深 2(头下留 1.6);4 个 Ø10 深 1 脚垫窝(螺丝内侧,不盖螺丝) 各 R 圆柱面 4 个、z 深度与圆心逐个在位
去掉滤网设计(用户 2026-09-13) 删滤网框与西端导轨;西端改成与东端相同的格栅;底盖西沿回到 −17.9 总装顶层件 10;干涉 360

⚠ 推翻了一条旧决定:之前定的「进风口加滤网 + 顶盖泄压缝维持轻微正压」不再成立 —— 没有滤网,灰尘会直接进机箱(手机主板、刀片、风扇),要靠定期清灰;泄压缝仍保留作出风/散热用。 整机长 140.7 → 134.3(少了滤网导轨 6.4)。

复验(place_v7.py):干涉 360 = 基线;底盖沉头过孔 ↔ 顶盖角柱螺母孔 4/4;两端风扇孔 ↔ 风扇模型腰孔 8/8(偏 0.1 = 模型 50.0 vs 实物 50.2); 分风腔按实物 10.01(模型回读 9.27,因模型厚 10.75)。 打印(拓竹 A1、PETG):顶盖倒扣打,圆头槽与圆角都在热床面,干净;格栅竖槽在竖墙上桥接 4.5,无需支撑;顶面 R1.5 圆角贴床那一圈首层可能略毛,介意就在切片里给一圈 0.4 的边缘处理。 螺丝:M3 × 6 左右(沉头下 1.6 + 螺母深 6,按热熔螺母实际长度取);脚垫买 Ø10 × ≥1.5 自粘硅胶垫。

✅ 开口精简(2026-09-13,TopShell_v4,已被上面 v7 取代,开口规格仍有效)

用户要求两项:

  1. 北墙去掉 J33 调试插针窗口、J26/J27 风扇插座出线窗口 ⇒ 北墙整块无开口。 ⚠ 连带:J33 是 D13「删 J22 调试 USB-C」之后的应急调试口,现在要开盖才能接;风扇线在机内插 J26/J27,不外露。
  2. 南墙两个 Type-C 开口 = 母座口内侧轮廓(用户拍板,不外扩): STEP 实测母座 USB-C_SMD-TYPE-C-31-M-12 口内侧 8.34 × 2.60、四角 R0.70(外壳外侧 8.94 × 3.20,口内腔深 4.05), 开口中心 J1 (12.50, −1.65) / J23 (84.00, −1.65)。 ⚠ 顺带修正:旧窗口中心 z=−1.20 是按连接器整体包围盒(含焊脚)定的,比真实口中心偏 0.45。

⚠⚠ 已知风险(用户知情选择):插头可能插不到底。 母座口面在 y=0.20,墙外表面 y=−4.055 ⇒ 口缩进墙内 4.26; 开口只有口那么大 ⇒ 插头塑料护套进不了墙,只能靠金属壳伸进去,需要金属壳长 ≳ 4.26 + 4.05 ≈ 8.3。 常见 USB-C 插头金属壳约 6.5(规格书值未核)⇒ 普通线大概率差约 2 mm 插不到位。 退路(参数化,改一个数重生成):开口以母座口轮廓等距外扩 2.1 → 12.54 × 6.80、R2.8(常见 12×6.5 护套可进)。 首件务必拿常用的几根线实插验证。

复验(place_v4.py):干涉 360;螺丝孔 4/4、风扇孔 8/8;滤网间隙全等设计值; 南墙外表面面积 10785.99 = 无开口 10828.52 − 2 × 母座口轮廓面积(精确相等)、北墙外表面 10828.52 = 无开口(精确相等)。 圆柱面 {R0.7 ×8、Ø4.2 ×4、Ø5.2 ×8、R3 ×4、Ø60 ×2}。

✅✅ 短机版(2026-09-13 用户要求缩短整机)—— 零件除顶盖已升 v4 外以这一节为准

用户拍板两项:分风腔两端 15 → 10、风扇 60×60×25 → 60×60×10(用户指定:广诚散热科技薄风扇,孔距 50.2、配机箱自攻螺丝、小 4PIN)。

段(沿 x) 原 现
风扇 ×2 25 10
分风腔 ×2 15.01 / 15.51 10.01 / 10.01
滤网导轨 5.4 6.4(滤网框加厚 1,让开自攻螺丝头)
整机长 180.2 140.7(−39.5)

现行件:TopShell_v3(内腔 x −16113.5、外 −18.4115.9、唇边 −24.8;角柱 x −16~−6 / 103.5113.5;端墙风扇孔 Ø5.2、孔距 50.2)、 BottomPlate_v3(x −24.8115.9,四角过孔 x −11 / 108.5)、FilterFrame_v2(70×90×4,贴墙层 3)。风扇模型 Orion OD6010(仅查干涉)。

复验(place_v3.py):干涉 360 = 基线(模型厚 10.75 比实物厚仍不撞);底盖↔顶盖螺丝孔 4/4 同轴; 滤网间隙 贴墙 0 / 唇边侧 0.40 / 南北 0.30 / 底 0;端墙风扇孔 ↔ 模型腰孔中心偏 0.100(= 模型孔距 50.0 与实物 50.2 之差,按实物开孔)。 分风腔:模型回读 9.27(模型厚 10.75),按实物 10 mm 为 10.01。

⚠ 散热代价(用户已知情拍板):

  • 分风腔 10 的横向/通道阻力比 1.26(> 1) ⇒ 边缘通道(1 号手机 9.18 缝、C1、C4)会重新偏缺风;
  • 薄风扇风量 / 静压低于原 25 mm 款,还要推过滤网 + 刀片堆叠;这款风扇没有拿到任何风量 / 静压 / 电流数据。 ⇒ 首件必须实测各刀片温度(尤其 1 号、2 号、5 号);不行的退路按代价从小到大:分风腔回 12(+4)、换高静压 6010、风扇回 25 mm。

⚠ 要实物核的两个数:机箱自攻螺丝螺纹外径(墙孔 Ø5.2 是按常见机箱风扇螺丝估的)、螺丝头高(滤网贴墙层 3 mm 按 ≤ 2.8 让位)。改一个参数即可重生成。 ✅ 电气接口:小 4PIN 针序 1 GND / 2 +12V / 3 TACH / 4 PWM 与 a6_fan.py 里 J26/J27 一致;板上 PWM 为开漏、靠风扇内部上拉,符合 PC 4 线规范(通用风扇是否真按规范,要实物验证)。

打印(拓竹 A1):顶盖 140.7 × 110.8 × 84.4、底盖 140.7 × 110.8 × 12.4,余量更大;打印要点同下节。

✅ 西端插拔式滤网(2026-09-13,两件式的补充;零件升到 TopShell_v2 / BottomPlate_v2 + 新增 FilterFrame_v1)

件 改动
TopShell_v2 西端墙外侧加两条通高 L 形导轨:滑槽 x −41.8~−38.4(3.4)、y 16.04586.645(70.6);唇边 x −43.8−41.8、各压滤网边 3.0,两唇之间开口 64.6 ≥ Ø60 风口
BottomPlate_v2 向西加长 5.4 到 x −43.8,托住导轨下端和滤网底边
FilterFrame_v1(新) 70 × 90 × 3,62×62 窗口 + 1 mm 的 6×6 格栅托滤材(滤网纱/滤网棉外购,粘在格栅上);从上方插入,底边落在底盖上,顶部露出顶盖 5.6 mm 当把手

为什么选插拔:手机农场要定期清灰,插拔不用工具。否掉的两种:用风扇螺丝压滤网(拆滤网 = 松开风扇,风扇在封闭顶盖里会掉);磁吸(多零件、多建模步骤)。

为什么不漏风:4 颗风扇螺丝头(Ø5.6 × 1.8)都落在 62×62 窗口里、低于框厚 3 ⇒ 框体能平贴墙面; 进风时外侧气压高,吸力把框压在墙上 ⇒ 基本自密封。

复验(place_filter.py):滤网框间隙实测 贴墙 0 / 唇边侧 0.40 / 南北各 0.30 / 底边落在底盖上 0 / 露出顶盖 5.60; 干涉 360 = 基线;底盖过孔↔顶盖螺母孔 4/4、风扇孔 8/8 同轴;分风腔 15.01 / 15.51 不变。

整机长 174.8 → 180.2。✅ 打印机定为拓竹 A1(256 × 256 × 256),全部件放得下,不必为打印改尺寸(⚠ A1 mini 是 180³,放不下)。

打印要点(拓竹 A1,开放式无腔体)

件 朝向 支撑 / 注意
一体顶盖 180.2×110.8×84.4 倒扣(顶板贴热床) 泄压缝只是底层镂空;角柱螺母孔竖直、孔口朝上,直接压热熔螺母;导轨竖向无悬垂;墙上矩形窗桥接 13 / 15.7 / 18.5,无需支撑。两端 Ø60 风口顶部约 42 mm 弦长那段悬垂 >45°,不支撑会轻微下垂(只过风、不影响功能),要好看就给这两个孔开「仅热床支撑」
底盖 180.2×110.8×12.4 平放、立柱朝上 无
滤网框 70×90×3 平放、格栅层贴热床 无
  • 材料 PETG:机箱内 40~50 ℃,PLA 约 55 ℃ 软化、热熔螺母会松;A1 无腔体,ABS/ASA 大件翘边。
  • 滤网滑槽单边间隙 0.3 / 0.4,按 A1 精度 ±0.1~0.2 够用;首件太紧就把 topshell_v2 里的 CLR 放到 0.4。

⛔ 已被上面两件式取代:竖插外壳第一版(2026-09-13,封闭盒子 / 分件打印)

5 个 3D 打印件(都在 新建文件夹\5blades\,SolidWorks 原生特征、可直接改尺寸):

件 文件 装配位置 / 要点
底板托盘 Tray_v9 106×106×2.4;y −1.655~104.345(与侧板内表面齐平,否则侧板悬空);四角 Ø8 立柱高 10(原 15,因 C2/C3 已挪顶面、背面最低只 −6.30);柱顶 Ø4.2 热熔螺母孔;南边两个 USB-C 缺口(J1/J23 朝南埋在板底,不开就插不进)。15 mm 分风腔那轮托盘没动
端板 ×2 EndPlate_v10 西 x −38.40 / 东 x 98136.4;Ø60 风口 + 4× Ø3.4 风扇孔(50×50);L 脚长 36(原 25,端板外移 11 后要够回托盘原有锁孔 x −1.9/99.9);4 根角柱(截面 8(y)×10(x)、通高 z 0~72)
南板 / 北板 SouthPanel_v4 / NorthPanel_v3 各一整块 175×82×2.4(原 153,跟分风腔加长);南开 2 个 13×9 Type-C 口,北开 J33 口 + J26/J27 风扇出线口;各 7 个 Ø3.4 过孔
顶盖 TopPanel_v4 x −38.4136.4、**y −4.055106.745**(v3 只到 102,与北板内表面差 2.345 ⇒ 沿全长开着一条缝,回读比对才发现);内表面 z=72,离刀片顶 71.34 仅 0.66 ⇒ 兼做上端导轨(咬边 ≤1 ✅);11 条 1.5×60 泄压缝 + 4 个 Ø3.4 过孔

风道:进风口加滤网 + 顶盖开泄压细缝(用户拍板)。R2 改「一进一出」后 R1 的 「4 进 1 出正压」不再成立,靠这条恢复轻微正压、灰尘往外走,也给风扇覆盖不到的 边缘通道(槽1/槽5,覆盖率仅 61%)一条出路。

全部外壳件外轮廓倒 R3 圆角,每件都用圆柱面半径直方图验过 4/4 条。

⛔ 两条一次就踩中的几何约束(都是回读实测出来的,不是推出来的):

  • 端板必须以风口中心 51.345 做 y 对称(−1.655104.345)。按托盘边缘取 −4102 时 板几何中心 49 ≠ 风口中心 51.345,东端板绕 z 翻转后偏 4.69、撞穿北板 616 mm³。
  • 南北板贴的是端板外侧、不是托盘边缘:端板比托盘宽,按托盘摆会重叠 2.345。

✅ 螺丝孔已全部用脚本做完(2026-09-13,EndPlate_v13),不再需要 GUI 补: A 组 8 × Ø4.2 深 6(沿 y,角柱南/北外侧面,z=10/60)、C 组 4 × Ø4.2 深 6(沿 z,角柱顶面)、 L 脚锁孔 4 × Ø3.4(沿 z,装配 x −1.9/99.9)。 装配内同轴核对:12/12 螺母孔对上相邻板的 Ø3.4 过孔、4/4 脚锁孔对上托盘锁孔,横偏全 0;干涉 360 = 基线。 ⚠ 仍待补:西端进风口滤网槽。

风墙的 3D 定位与覆盖率(2026-09-13 在装配体里实测)

布置:两只,西端进风(x −250)+ 东端排风(x 98123),厚度方向沿 x(= 通道方向), 按刀片堆叠中心对中。两只风扇与刀片/底板零干涉。

⚠ 一只 60×60 盖不住迎风面(这是实测出来的新约束): 堆叠迎风截面 y 87.6 × z 67.0 = 5869 mm²,60×60 正面只有 3600 ⇒ 覆盖 61%, 按中心摆时通道 4(槽 4–5,中心 y=81.83)落在风扇正面之外。 2026-09-13 用户先取方案 ③:接受边缘通道,靠外壳导流罩分风 (另两个被否的选项:每端并排两只 60、或换 80×80×25)。

⛔ 但「导流罩」这条路当天就被几何否掉了 —— 改成 15 mm 分风腔

画之前先量了一遍,三个数把方案 ③ 直接判死(全部回读自活装配,不是推的):

  1. 没有空间。西端风扇出口 x=0、刀片前缘 x=4.01 ⇒ 分风腔只有 4.01 mm(东端 4.51)。 把 Ø61 摊成 87.6×67 的无叶扩散段,按 7°/10°/15° 半角分别要 183 / 128 / 84 mm。

  2. 缺风比「61%」严重得多。61% 是整面积口径;逐通道算(迎风面 = 通道宽 × 67):

    通道 edge-S C1(刀片1-2) C2 C3 C4(刀片4-5) edge-N
    落在 Ø61 内 0% 19.9% 84.9% 84.9% 19.9% 0%
  3. 决定性的一条:4 mm 腔里「从风口中心横向喂到最远通道」的阻力是通道本身的 18 倍 (等流量 Dh 口径)。⇒ 边缘通道被饿死与有没有导流叶片无关,只跟腔深有关:

    腔深 4.01(原) 8 10 12 15 20
    横向/通道 阻力比 18.1 2.4 1.3 0.75 0.40 0.18

⇒ 2026-09-13 用户拍板:两端各外移 11 mm,做 15 mm 分风腔(已实测落地:西 15.01 / 东 15.51)。 代价是整机 152.8 → 174.8(y 110.8 / z 86.8 不变)。导流叶片不做 —— 15 mm 腔本身就是分风器。

⚠ 顺带纠正一条记反了的:南边那条窄缝不是旁通,是 1 号刀片的手机通道

刀片 B 面器件全部从 y=9.20 起、板体 7.539.20 ⇒ 手机在每片刀片的 −y 侧。 于是:南侧 9.18 mm 缝里装的是1 号刀片的手机(比别的通道的 13.95 窄,首件要量), 北侧 9.17 mm 才是唯一的纯旁通。旁通总面积 1762 mm²,占迎风流通面积 32% (其中南条 661 要划掉)。⇒ 真要再加挡风板,只该挡北侧,且只能占 y 98.0104.345 (再往南就压到底板 PCB:J26 到 y 97.30、J33 到 96.77)。本轮没做,留作后续可选项。

建模用的风扇模型:山洋 9G0612P4S001 的 STEP 要填表才能下(脚本拿不到), 改用 Orion Fans OD6025(https://orionfans.com/3d/OD6025_m0_frame.stp,无登录直链)—— 同规格 60×60×25 DC 轴流,数据手册第 2 页确认该系列有「4 线 PWM + Tach」版本。 ⚠ 这份模型只对"安装接口"可信:实测安装孔 50.00 × 50.00 / Ø4.30 贯穿 ✅ 标准, 但框体外缘量得 62.95 见方、风道 Ø61,比 60 标称每边大 1.5。 ⇒ 外壳开孔按标称 60×60 留间隙、螺孔按 50×50,不要照抄模型外缘。


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 不变 → 2026-09-10 改 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 正南 / 正北各开一条窄带的口子(place_base.HUB_STRIPS: J37 北排投影 x 4458.2 / y 30.234、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 成立的前提,不是收尾检查项。布线时它们优先于一切其它考虑。

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

6.3 D± 的账

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

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

USB 2.0 不要求 pair-to-pair 等长,只管 intra-pair skew(≤ 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 ⚠️ 刀片投影规则(竖插 + 降高度带来的新约束)

⛔⛔ 2026-09-12 晚更正:这个 11 mm 是错的,真值只有 3.21 mm。 11.56 是插槽塑料体自己的高度,被当成了刀片底边的离板高度。SolidWorks 实测: 塑料体顶面在底板局部 z=12.33、板面 z=1.67 ⇒ 完全不插入时也只有 10.66; 再减去插入深度 d ⇒ 刀片底边离板面 = 2.66 mm(2026-09-12 晚加深缺口后的现值)。

⇒ d 由什么决定,取决于缺口深 NOTCH_D 和防呆键筋全高 8.00 谁大: 键筋是通到槽底的全高 8.00(竖壁 z 2.000~9.500 + 顶上 0.5 的 45° 导入角)。

NOTCH_D 谁先顶住 卡底停在 d 离板面
7.45(旧) 缺口封闭端顶在键筋顶上 z=2.55 7.45 3.21
8.3(现行) 缺口让开键筋,卡坐到槽底 z=2.000 8.00 2.66

⛔ 2026-09-12 晚用户拍板把 NOTCH_D 由 7.45 加深到 8.3,正是为了消掉上面那 0.55: 7.45 时卡是坐在一条塑料防呆筋上而不是坐在槽底,受力点从一个面变成一条筋。 电气上本来就无碍(触点 z 6.18~7.12 被卡完全盖住),纯粹是受力点的选择。 8.3 = 模型槽底 8.00 再留 0.3 余量,防实测键筋高于标称。 ⚠ 8.00 / 2.000 都是厂商 STEP 的标称值、不含公差,卡尺实测仍是权威口径。 (早先写过的区间 7.45~8.00 / 2.66~3.21 曾被判"下限永远达不到",加深之后达到的正是下限那一端。)

✅ 这张表已作废(2026-09-12 晚逐件核过,无碰撞)

下面那张「刀片投影内 ≤8 mm」的表是从错的 11 mm 推出来的,但**重新核算的结论是: 这条约束本来就不该按高度判,而且现状一处都不撞。**正确判据在 place_base.py:

顶面件(pcb_base.TOP_EXTRA)避让刀片只管横向:刀片板面占槽心 ±CARD_HALF, 净距 CARD_CLR = 0.5 ⇒ 顶面件本体必须避开 槽心 ±1.300 (place_base.py:984 判的就是 CARD_HALF + CARD_CLR = 0.8 + 0.5)。

⚠ CARD_HALF = 0.8 取的是标称板厚 1.6 的一半;STEP 实测板体是 1.67(半厚 0.835)。 下表两种口径都给,结论不受影响。

逐件实测(底板局部坐标,STEP 量得):

位号 封装 z 顶 y 范围 所属槽 净距(标称 ±1.300) 净距(实测 ±1.335)
J26 2510 4P 立式 13.17 91.50~97.30 5 (89.64) 0.56 0.525
J27 2510 4P 立式 13.17 81.65~87.45 5 0.89 0.855
J33 2.54 排针立式 10.21 94.23~96.77 5 3.29 3.26
C2 / C3 Φ8 直立电解 9.67 31.00~39.01 2 (28.68) 1.02 / 1.01 0.985 / 0.975

两种口径下全部 ≥ 0.5 ⇒ 无碰撞 (J26 只富余 0.06,说明当初就是照这条规则卡着摆的 —— 这一件以后别再动)。

为什么高度不构成问题:这几件最高 13.17,而刀片底边在 z = 12.33 − d = 4.88 ⇒ 它们只够到刀片局部 y ≤ 8.29,整段落在 ZONES['finger'](y 0~12)这个 两面禁布区里 —— 刀片在那一段只有 1.67 mm 裸板,没有器件可撞。 (逐件核过:刀片本体下沿最低的是 U4,y=11.75,换算到底板 z 16.63, 比 13.17 还高 3.46;J1 的 y=−2.15 是金手指封装本身,平铜无高度。)

⇒ 派生上限(以前没有的数):底板顶面件一旦高过 z = 16.88(板面以上 15.21 mm) 就会够到刀片的器件带,届时横向要按 槽心 −0.835 ~ +5.535(器件面朝 +y)判,而不是 ±1.335。 现状最高 13.17,余量 3.71 mm。

器件面朝向(这条以前没写明,但决定横向判据是否对称): fp_edge.LAYER = {'A':2,'B':1} ⇒ A 排 = 刀片层 2(底面); a5_slots.slot_pin 把 A(n) 映到插槽脚号 132,而 pcb_base 的 N 北排正是焊盘 132 (y = 槽心 +3.6)⇒ A 排贴北排。刀片 77 个器件里 77−5 全在层 2(层 1 只有 J1/K1~K4) ⇒ 器件面与 A 排同侧,朝 +y(北)。

(以下为作废内容)插槽把刀片底边抬到底板上方约 11 mm,所以:

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

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

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

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


7. 刀片设计(4 层)

7.1 叠层

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

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

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

7.2 关键回路

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

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

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

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

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

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

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

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

PCA9555 位分配:

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

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

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

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

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

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

8.1 固件改动

任务包 影响
A2 HAL 无
A3 INA226 驱动 地址表从「六片不同地址」变成「五片同地址 + 一片输入侧」。⚠ 底板输入侧 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 在固件里只在启动自检时脉冲一次,运行期不许再动 ⇒ 2026-09-29 用户拍板改为按需启停(固件 0.1.14 hubctl,见下方 8.2a);③ 该脚外部上拉,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 座。

8.2a Hub 按需启停(2026-09-29 用户拍板,固件 0.1.14,推翻上表第 2 条②)

起因:五路 VBUS 平时全关,但上行插着电脑时 Hub 一直是活动态 —— 第 6 口的 ESP32 USB-Serial-JTAG 让电脑永远不挂起它。连着电脑时 Hub 空转,2026-09-29 板 B 实测 1.03 W(Hub 开 1.77 W / 关 0.69~0.80 W 底板损耗,12 V 输入电流差约 88 mA;原始数据 10.5.5.13:/root/phonerail-src/bench-hub-20260929.jsonl)。WiFi / MQTT / OTA 上线之后, USB 控制台已经不是唯一的进路,「运行期不许动 HUB_RST」的代价不再值得。

做法:不改硬件。ESP32 在没人用 USB 时把 HUB_RST#(GPIO8 → U32.43)拉低按住复位; 要用时放成输入,靠 R716 拉高(固件从不主动驱高)。判定全在板上(firmware/main/hubctl.{h,c}):

开的理由 条件
mode 模式 = 常开(hub 命令,存 NVS;默认 auto)
vbus 任一路 VBUS 通着
flash 任一路刷机模式窗口内
act 任一路执行器序列在跑(EDL 要枚举 9008)
hold hub 命令给的保持窗口(1~240 分钟)
link MQTT 连续 60 s 没连上(含从没配过网)
idle 以上都不成立,但离最后一次「需要」不到 10 分钟

「最后一次需要」还会被启动、上行电脑插上(UP_VBUS_DET 上升沿)、USB 链路上来一条命令刷新。 全不成立 ⇒ 按住复位。

退路(推翻 R-11 的前提):① 网断 1 分钟 Hub 自己回来;② ESP32 任何一次复位(上电 / 看门狗 / esp_restart / esptool / J33 EN)引脚都回高阻,R716 拉出复位,且启动后至少 10 分钟不关;③ 板子断电重上 = ②;④ J33 UART 不经 Hub。

代价:Hub 关着时电脑那边看不到 ESP32 的 COM 口,也不能 USB 烧录 —— 先发 {"cmd":"hub","min":30} (经 MQTT)或 {"cmd":"hub","mode":"on"};手机 VBUS 一开 Hub 就自动回来,重新枚举约 1~2 s。


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 只在自检脉冲一次 ⇒ 2026-09-29 起按需启停,靠 §8.2a 的四条退路(断网自动放开 / 任何复位即放开 / 断电 / J33)

11. 执行计划

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

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


12. 与 R1 的关系

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

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

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

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

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

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

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

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

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

13.3 下一步(M2 之前)

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


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

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

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

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

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

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

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

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

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

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

14.4 还欠的

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

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

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

15.1 页面内容

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

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

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

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

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

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

15.4 给 B3 / B4 / A3 留的接口

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

15.5 顺带做掉的两件小事

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

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

16.1 ⚠️ 为什么拆成两页

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

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

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

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

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

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

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

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

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

⇒ 两条规矩:

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

16.4 三样故意分开放的东西

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

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

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

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


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

17.1 器件

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

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

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

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

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

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

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

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

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

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

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


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

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

18.1 三条改动

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

19.1 一处改名:BST → BST3V3

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

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

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

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

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

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

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

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

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

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

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

19.4 本页不含的两件事

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

  • NTC1 / NTC2 —— 必须 ADC1(ADC2 与 WiFi 冲突),脚本里有断言。 NTC1 = IO1 / NTC2 = IO2 ⇒ 2026-09-11 方案 B 改为 NTC1 = IO4 / NTC2 = IO5(仍是 ADC1,见 §29.6)。
  • USB6_DM = IO19 / USB6_DP = IO20 —— 原生 USB 硬定死,脚名脚号从 _p3_live.json 查的。
  • ⚠️ 模组是 R8(八线 PSRAM)还是 N8 没定 ⇒ ✅ 2026-09-13 用户定为 ESP32-S3-WROOM-1-N16R8 (16 MB 四线 Flash @3.3 V + 8 MB 八线 PSRAM;立创 C2913202)。原本按 R8 保守处理、IO35/36/37 全部不接,现在这个做法正好对得上。 已从底板 PCB 读回 U20 焊盘网络核对(与原理图符号脚名逐脚对上): IO35/36/37(脚 28/29/30)无网络 ✓;Flash 用的 IO26~32 模组没引出 ✓; IO45(脚 26,决定 VDD_SPI 电压)悬空,靠内部下拉 = 3.3 V,与 N16R8 的 3.3 V Flash 匹配 ✓(绝不能上拉,上拉就变成 1.8 V,Flash 起不来); IO3/IO46 悬空 ✓;IO0 只接 J33 下载脚,悬空为高 = 正常启动 ✓。 ✅ U20 料号已换成 C2913202(2026-09-13):两颗库器件的封装 / 3D 模型 UUID 完全相同,只是符号 UUID 不同。所以没有删掉重放, 而是在原理图和 BASE-PCB 上直接改 U20 的属性(manufacturer / manufacturerId / supplierId / otherProperty),两边都已存盘。 改后读回:PCB 上 U20 的坐标、旋转和 41 个焊盘网络与改前逐项一致;A3-CTRL 的 verify_sch 只报 a3-ctrl-nc.json 登记的 20 个有意不接脚;xpage 漏接 0。现在全板只剩 IO47/IO48 两个备用脚 ⇒ 方案 B 之后 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。

决定:做。 三条理由:

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

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

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

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

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


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

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

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

22.1 几何不是凭记忆写的

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

项 取值 交叉核对
间距 1.00 mm CEM / 立创资料 / KiCad 三处一致
手指宽 0.70 mm(净距 0.30) 同上
手指长 4.30 mm 中文资料常写 4.0,同量级
指尖到板边 1.30 mm multi-cb 给 PCIe 荐值 1.4,另一处给 0.6~1.5 窗口 ⇒ 1.3 在窗口内
缺口 11/12 号针之间,宽 1.6、深 8.3,口部两个 0.5×45° 导入角 宽取 CEM 值(KiCad 的 x1/x4 封装都是 1.9,到 11/12 号指只剩 0.2 ⇒ DRC 报「板框到焊盘 <0.3」,2026-09-11 改 1.6);深 2026-09-12 晚由 7.45 加深,见 §6.6
缺口到 11/12 号指 铜边距 0.35 mm 直段两侧对称,selfcheck 里断言 ≥0.3;板上实测 0.350
A 排 / B 排 A = 底层,B = 顶层 同 KiCad

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

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

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

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

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

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

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

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

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

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

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

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


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

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

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

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

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

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

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

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

23.3 两个坑

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

23.4 M4 接下来的顺序

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

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

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

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

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

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

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

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

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

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

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

三条落地时改掉的:

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

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

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

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

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

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

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

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

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

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

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

两条路都试过,都不行:

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

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

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


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

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

25.1 分面:A 面只留 10 件

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

25.5 当前状态与没做完的

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

25.11 布线现状(诚实版)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

26.1 为什么三条是一件事

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

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

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

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

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

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

26.4 摆位 / 校验

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

26.5 布线 / 铺铜 / DRC 结果

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

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

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

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

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

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

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

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

⚠ 三条经验:

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

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

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

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

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

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

请先绘制板框!查看更多

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

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

⇒ 判据与做法:

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

判据交了两次学费:

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

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

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

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

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

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

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

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

27.8 M7 结果

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

那 4 条缺口间距是 PCIe 几何本身定死的:1.0 mm 间距 / 0.7 mm 指宽 / 1.9 mm 缺口宽 ⇒ 缺口边到 11、12 号指的铜边只有 (3.0−1.9)/2 − 0.35 = 0.2 mm,任何 PCIe 卡都是这个数。 ⚠ 它以前不报,是因为板框那时候是「导线」(§27.3),DRC 根本没把它当板框。 ⇒ 要么下单时和嘉立创确认「金手指缺口处铜到板边 0.2 mm 可做」,要么把缺口收窄到 CEM 的 1.6 mm(clearance 变 0.35,但防呆筋的配合余量少 0.15)。这一条需要用户拍板。 ⇒ ✅ 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(6391 × 0.816.0) + SPINE(291 × 15.820.8),五条支路交给布线器画 1.5 mm 支路只有 1.5 A,1 oz 外层 1.5 mm 带 3.2 A;脊上最大 ~6 A(进料在东段,往西只带 3 个槽 + 两颗 Buck),5 mm 够

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

28.13 每对 D± 一条专属车道

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

代价(已知、可接受)

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

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()(拿实测焊盘表比,三条缺一不可):

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

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


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

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

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

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

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

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


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

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

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

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

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

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

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

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

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

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

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

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

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

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

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

32.3 Q6 / Q10 / U13 定点优化

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

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

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

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

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

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

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

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


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

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

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

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

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

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


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 点、外接 090 × 068)
手机原点 (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 整页重画,截图已自查)

  1. 删 J2(D± 退路座):底板 J39~J43 在 §28.11 已删,刀片这头没了对端,D12 实质作废; 旧版 D± 往东绕到 x≈60 就是为了它。
  2. 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 内部直通,电气等价。
  3. J1 改为不进 BOM(§17 遗留)。
  4. 验证:两页 verify_sch --nets PASS、xpage 漏接 0、port_audit --r2 BLADE 142 个可疑 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 那一簇(C68 CT 9 mm、C67 VBUS 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 是全通),按根因分三类:

  1. +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 最前。
  2. 我自己引入的摆位退化:EFUSE_AUX 西边少 4.3 mm($1N165: R16.1)、U6 被挤到离 J3 20 mm($3N45)、 C68 离 U5 7.9 mm($5N71)⇒ 分区第二版(§34.3)。
  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.568.59 / **y 11.055.66**(远端边贴金手指区上沿)
服务带 底部 11.34(金手指区之上) 顶部 12.34(接口边 55.66 → 板顶 68)
两条槽 y 18.14~21.14 y 56.86~59.86;尾插槽 x 5.0125.01(左)、电池槽 x 38.8250.82(中)
排线在 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 左下 右上 (6467, 4952),紧挨功率列

⚠ 机械上要确认: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_base 0 / 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)

  1. CC 夹在两组 VBUS 之间(USB-C 脚序决定:GND VBUS CC2 … CC1 VBUS GND),VIN_RAW 一合流 CC 就被围住 ⇒ CC 在两组 VBUS 之间打孔上 L1,在 12V 大铜里各开一条窄走廊东去 U36 再下来(CC2 南、CC1 北,不交叉)。 ⛔ 没选「壳体底下走 L4」:20V / CC 压在接地金属壳下只隔一层阻焊。
  2. LM61495 两侧 VIN 连通(VIN1/VIN2 分两侧、中间夹 SW,TI 做法是 VIN 走另一层)⇒ U37 正上方 L1 挖一块 VIN_FUSED 小岛 (18.922.9, 13.429.2);L1 12V 主块在这一段还剩 18 mm。
  • 实现:route_base._build 先把窗口从 12V 挡线图里扣掉、再按各自的网封(⚠ router _mark 在别的网已占的格子上写会变 255,不能叠加); pour_base 12V 大铜绕开小岛(外扩 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.py U36.2/3 → SCL/SDA;a3_ctrl.py U35.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_tap 30 个落点全不通)。
  • 用户选拆 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 两条方法论

  1. 能不动的件就别动。J26 原地翻面 = 零布线代价;它一旦挪窝,那三条线就得在单层区重布, 而布线器布不出来的路,不等于板上原来没有 —— 拆之前先备份几何,走不通就原样画回去 (ripped_backup.json → restore_ripped.py,这一轮真用上了)。
  2. 搜索的判据缺一条,就会被精准地钻这个空子。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 补了同网钻孔间距(原来只查异网)。
  • 最终:快照 _base_board_final_d16.json(2104 段 / 648 孔),图 M18-d16-routed.png;重铺 147 块填 135(功率铜面全填); DRC 间距 0 / 连接性 0,只剩插槽封装自带 5 条(§27.8 起的老问题);board_check 118 / 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。 教训:交接 / 收尾前按快照逐项比,铺铜要按「层 + 网 + 名字」逐块比,光看总块数看不出内层被删。
  • ⛔ 2026-09-13 第二次:同样这 16 块(GND-L2-07 / GND-L3-07)又没了,DRC 报 GND 连接性 65 条。只按 pour_base.plan() 补建这 16 块,然后「重建所有」⇒ 147 填 135、DRC 连接性 0。触发原因仍未查明,详见 PROGRESS 顶部「底板内层 GND 平面第二次整块消失」。

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 ⛔ 三条判据上的坑

  1. rotation 字段是「度」且不归一化:900 表示 180°、720 表示 0°。 按 ×10 解读会得到「9° / 18° / 27°…」这种看着像真的却完全错误的朝向分布。读回一律 % 360。
  2. 不能用「本体 ≥ 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-C J1/J23。收紧后残留 25 → 12。
  3. 必须给「离本体」设硬上限(MAXD = 2.2 mm,量到本体外框)。 不设的话贪心会把位号甩到十几毫米外的空地上 —— 实测平均 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。

39.5 自由丝印(silk_str.py,2026-09-12 补)

板上原本 pcb_PrimitiveString 是 0 条 —— 方案 §5.2 要求的插槽警告、以及 J1/J23 的接口标注 一直只写在原理图的说明文字里,没有落到 PCB。已补 6 条:

文案 层 坐标 为什么
PWR 20V 4 (12.500, 1.800) J1 与 J23 同一颗 USB-C 座,插错要能看出来
USB 4 (84.250, 1.800) J23 是 Hub 上行口
NOT PCIe - PhoneRail blade only 3 (49.000, 79.480) 槽是 PCI-E x4 座但针位自定义,插真卡会烧
NOT PCIe ×3 3 (36.000, 18.520) / (62.000, 38.840) / (45.000, 59.160) 完整句只放得下一条,其余槽间放短标 ⇒ 五个槽每个都邻着一条

字高 1.2 / 线宽 0.15(嘉立创丝印下限 0.8 / 0.15)。J1/J23 在底面 ⇒ 走底层丝印 layer 4; 插槽在顶面 ⇒ layer 3。

两条判据上的坑:

  1. ⛔ 丝印压铜不算冲突 —— 铜上有阻焊,油墨正常印在阻焊上。第一版把「压铜」也当冲突, 于是六个候选位全军覆没,看着像「板上没地方放字」。真正要避的只有 焊盘 / 过孔 / 位号 / 安装孔 / 板框外。
  2. ⚠ alignMode 必须显式传 5(CENTER)。不传的话默认不是居中,坐标含义和按中心算的 文字框对不上,字会整体偏出去。位号 Attribute 用的 3 是另一套口径,别照抄。

silk_str.py 自带落点搜索(0.25 mm 步长、限定偏移上限)+ 幂等下发(先删同文案再建)+ 读回核对, 落点存 _base_silk_str.json。

40. 刀片金手指两侧开台阶(2026-09-12 用户指出「插不进插槽」)+ 铺铜补齐

用户:「解决刀片板与插槽干涉的问题,完善刀片板铺铜」→「金手指两侧没有开槽,应该会插不进插槽」。

40.1 ⛔ 根因:刀片底边是一条直线,而 PCI-E 卡在这一段必须是「凸」字形

outline_pts() 原来第一段就是 (r, 0) → (BW-r, 0) —— 整块 90 mm 宽的板材一直到 y=0。 而插槽塑料体只有 39 mm 长且两端封闭(PCIE-64P11L,焊盘外框 42.0 × 9.2), 高度约 9 mm。卡插下去时,x < 29.5 / x > 68.5 的板材会压在塑料体两端壁上,插不到底。

⚠ 这一条 §3.1 的分区图里其实写着「金手指区 11 mm(槽体高度 ~9 mm 要让开)」, 但那只写进了 ZONES['finger'](禁布区),板框没有跟着开台阶 —— 禁布区管的是"别放件", 不等于"这里没有板材"。两者是两回事,这次才暴露。

40.2 定稿尺寸(用户拍板)

项 值 说明
舌头宽 36.0(x 27.00~63.00) ⇒ 34.5 mm(x 27.75~62.25) 金手指跨 33.70(x 28.15~61.85),两侧各余 1.15 0.40(> DRC 板边 0.3,可做)
台阶高 12.0 mm ~槽体 9,余 3 ⇒ 见下方更正
内凹角 R1.0 外形铣刀下不去直角(嘉立创外形最小 R0.5)
切掉 666 mm²(占 10.9%) 左 27.75×12.0 + 右 27.75×12.0

⛔ 2026-09-12 晚:36.0 收到 34.5 —— 因为 36.0 根本插不进去。 SolidWorks 量厂商 STEP 里 PCIE-64P11L 的顶面内环(= 卡槽开口)得 35.08 mm (x ±17.540,中间 0.78 是防呆键筋),36.0 比它宽 0.92,舌头两端会压在腔的端壁上。 收到 34.5 后对开口留 0.29/侧。⚠ 35.08 是厂商标称值、不含公差,待卡尺复核。

✅ 2026-09-12 深夜 3D 复核通过(重导两份 STEP 后在 SolidWorks 里实测, 详见 solidworks-assembly skill 的 NOTES §29): 舌头实测 34.474、台阶 9.900、防呆缺口 1.926 × 8.3 —— 板上轮廓与设计一致; 刀片坐到腔底,插入深度 d = 8.00 达成,刀片底边离底板板面 2.66,与 §6.6 的预测吻合。 ⚠ 扫描里「首次接触」发生在插入 3.03 处,那是 64 根簧片触点(模型把簧片建成刚性、 通道 1.568 < 板厚 1.67),不是机械止点 —— 判据要看干涉体积随深度的斜率并做阳性对照: 坐到腔底时总干涉仅 1.49 mm³,再压 0.53 就暴涨到 28.2 mm³。 5 块刀片同时插上时刀片↔刀片 0 处干涉,相邻净距 13.95 mm(B 面口径)。

⛔ 顺带更正「台阶高 12.0 = 槽体 ~9,余 3」的前提:槽体实测高 11.56(不是 ~9)。 但要比的本来就不是槽体高度,而是插入深度:d = 8.00 (2026-09-12 晚 NOTCH_D 加深到 8.3 之后,卡坐到槽底,d 改由槽底决定;见 §6.6) ⇒ 台阶肩部离塑料体顶面还有 12.0 − 8.00 = 4.00 mm,结论仍然安全(且偏宽裕)。

常量在 pcb_blade.TONGUE_X0/TONGUE_X1/STEP_H/STEP_R;outline_pts() 改成凸字形, 第一段仍是舌头底边(segments() 与 outline_polygon() 都按这个前提把防呆缺口插进去)。

40.3 放行前逐项核过(两种口径交叉验证)

被切区(x<27 或 x>63 且 y<12)里:铜 0 段 / 过孔 0 / 焊盘 0 / 器件本体框 0 (板上读回 + _blade_pads.json 缓存两种口径一致)。 7 个定位孔最南 H5 在 y=14.46,全在板材上;两条铣穿槽在 y 56.86 起,都不受影响。

⚠ 唯一代价:手机主板投影底边在舌头两侧悬空 1.0 mm (PHONE_ORG.y = 11.0 < 台阶 12.0;左 x 1.50~27.75、右 62.25~68.59, 合计 32.59 mm²;2026-09-12 晚舌头由 36.0 收到 34.5 后由 31.09 增加)。 主板是 7 个 M1.6 尼龙立柱压住的(§3.2 中框式焊盘,螺柱间隙 1.0),不靠边缘托 ⇒ 无害。 selfcheck 里改成判「悬空量 ≤ 1.5」+「定位孔不许落进台阶区」,不再用原来那条 phone.y0 >= finger.y1(台阶之后 finger 区只剩舌头,那条断言已经没有意义)。

40.4 铺铜跟着台阶改

  • 新常量 pcb_pour.STEP_POUR_Y = STEP_H + INSET = 12.5:舌头两侧的铜下沿。 舌头那一段仍按 TOP_POUR_Y(外层 11.5) / INSET(内层 0.5) 走。
  • gnd_tiles() 的竖条切分点加入舌头两端,舌头外的条 y_lo 抬到 12.5 ⇒ 外层 L1/L4 每层 7 → 9 块,内层 L2 由 9 → 11 块(内层下沿是 0.5,被舌头切得更细)。 板上铺铜合计 25 → 31 块(L2 11 + L1 9 + L4 9 + L3 两岛)。
  • +12V 岛(L3)改成阶梯形单环:舌头段仍下探到 y=9.0 去接 12V 三指的 launch 孔 (x 28.5~30.5 / y 11.75,全在舌头内;下沿 9.0 是为了避开地母线的孔 y 7.0/8.2), 舌头以东抬到 12.5。断面由 11.0 收到 7.5 mm(1 oz 内层 ≈ 5.1 A,需求 1.5 A 峰值)。

⚠ inner_poly() / outer_poly() 是死函数 —— plan() 只用 gnd_tiles()。改铺铜边界时 别去改那两个(改了不生效,看着像"改了没用")。

40.5 一条判据上的坑:阶梯形多边形不能按包围盒判

给 selfcheck 加「铜不许伸进台阶切掉的区域」时,第一版按整个环的包围盒判: +12V 岛 min(y)=9.0 且 max(x)=84 ⇒ 直接误报,而它 y=9.0 的那一段其实只在舌头内。 ⇒ 改成逐边采样(0.25 mm 步长)判每个点。阶梯形/L 形铜面都要这么判。

40.7 ⚠ 台阶的连带影响:丝印也要一起查

开台阶时只查了铜 / 过孔 / 焊盘 / 器件,漏了丝印。事后补查(pcb_PrimitiveString + key=='Designator' 的 pcb_PrimitiveAttribute,82 条)发现 金手指 J1 的位号 锚在 (26.45, 8.38),文字框 x 25.7427.16 —— 左半截落在被切掉的板材上(交叠 1.44 mm²)。 已挪到 (28.50, 8.378),alignMode=3(LEFT_BOTTOM)下框 x 28.5029.92, 按「居中」口径算也在舌头内,两种口径都干净。丝印层的线 0 段越界。

⚠ 封装自带的那条 NOT PCIe - PhoneRail blade(fp_edge 画在金手指封装里, 锚点板坐标 x=28.50 / y=7.20)读不回来 —— pcb_PrimitiveString.getAll() 在 PCB 文档里 不列封装内部图元。按 alignMode 默认 3(左下)推算 x 28.5044.62 落在舌头内; 若是居中则 20.4436.56 会越界。已用截图实测佐证。

⇒ 以后改板框(尤其是切掉板材)时,检查清单必须包含丝印与位号,不能只查铜层。

40.6 顺带补齐:刀片外层铺铜原本整层缺失

抓板发现刀片上只有 11 块铺铜(L2 九块 GND + L3 两个岛),而 plan() 计划 25 块 —— L1 七块 + L4 七块 GND 底填全都不在板上(交接记录写的"铺铜 25/25"与板上不符)。 已重建。台阶改动后每层 GND 由 7 → 9 块。

40.6 ⛔ 台阶内凹角的半径 bug(2026-09-12 晚,收窄舌头时才显形)

pcb_blade.corner(cx, cy, a0, a1) 原本写死 CORNER_R(2.0),而两个台阶内凹角 调用它时只把 STEP_R(1.0)用在了弧心偏移上:

pts += corner(TONGUE_X0 - ri, hs - ri, 90, 0)    # 弧心 (26.75, 11.0),但半径仍是 2.0

弧心 (TONGUE_X0−1.0, 11.0) 配半径 2.0 ⇒ 弧终点落在 x = 26.75 + 2.0 = 28.75, 而不是应有的 27.75。于是舌头侧边成了一条 (28.75, 11.0) → (27.75, 0.0) 的斜线:

尖端(y=0) y=11 处
设计意图 34.5 34.5
实际画出来 34.5 32.5(两侧各内收 1.0)

为什么一直没发现:36.0 时斜边最大只到 x=28.00,够不着 x=28.50 的线, DRC 与几何校验都不报;把舌头收到 34.5 之后斜边推进到 28.75, 才把 +12V / PRSNT#(x=28.50)在 y>8.25 的部分切到板外 —— DRC 一次报出来。

修法:corner() 加半径参数(省略时仍用 CORNER_R),两个内凹角调用处传 ri。 修正后侧边变成真正竖直的 x=27.75 / 62.25,+12V/PRSNT# 的净距由负值变成 0.575 / 0.650,四条违规不用改线即消失。

⇒ 教训:参数传进去了 ≠ 用上了。 STEP_R 只影响弧心、不影响半径, 而画出来的形状仍然“看着像个圆角”,人眼截图也看不出来 —— 这类错误只能靠 「按实际点列量关键尺寸」发现,不能靠看图。

40.7 +5V 靠板边那一段:x 61.72 → 61.70,线宽 0.60 → 0.46(2026-09-12 晚)

舌头收到 34.5 后,x≈61.7 的三段共节点 +5V 线((60.10,13.75)→(61.72,12.13)→ (61.72,6.67)→(61.50,6.46))到板框只剩 0.235,不满足板边规则 0.3。

纯平移无解(这是个几何死结,别再试):

到板边(需 ≥0.3) 到 GND 过孔 (60.83, 6.99)
原位 61.72 / 0.60 0.235 ✗ 0.28
平移到 61.60 / 0.60 0.35 ✓ 0.162 ✗
定稿 61.70 / 0.46 0.32 ✓ 0.33 ✓

板边要求 x ≤ 61.65,过孔要求 x ≥ ~61.71 ⇒ 窗口为空,必须同时收线宽。

载流核算(按 §6.4 的 IPC-2221 / 1 oz 外层 / ΔT 20 ℃ 口径): +5V(VBUS)需求 ≤ 0.5 A(§5.2 针位表);以本文档自有锚点 「1.5 A → ≥1.2 mm」「0.30 mm → 0.65 A」换算,0.46 mm ≈ 0.88 A,余量 1.8 倍。 ⇒ 收窄无电气代价。改动后刀片 DRC 间距错误 0 条。

41. 刀片压到 89.5 × 67(2026-09-12 深夜 用户拍板)

用户要求:「缩短卡片板宽度,从金手指让出来的尺寸那里裁剪」,后补「68 那一边也裁」。

41.1 ⛔ 先证伪一个前提:「金手指让出来的那片」不是空板材

金手指铜只占 x 28.15~61.85(33.70 宽),舌头 34.50,两侧各"让出"约 27.75 —— 但那片地方 在 y>12 处早就被走线、过孔和功率列器件占满。按铜 + 孔 + 焊盘(不能只看焊盘)实测:

占用带 两侧/两端空白
x 2.195 ~ 89.140 西 2.195 / 东 0.860
y 3.201 ~ 66.400 南 3.201(但那是金手指区)/ 北 1.600

而"金手指让出来的量"只有:舌头比金手指铜每侧富余 0.40;舌头 36.0→34.5 那次每侧让出 0.75。 都是 1 mm 以内,撑不起一次板宽裁剪。 另外台阶那 666 mm²(§40)已经切过了。

⚠ 南边永远不能裁:y=0 就是金手指所在的板边(指尖在 y=1.30),从南裁等于切金手指。

41.2 定稿:只裁东 0.5 + 北 1.0,器件一律不动

项 旧 新
板框 90 × 68 89.5 × 67,四角 R2,读回折线 74 点、外接 089.5 × 067
J1_X BW / 2.0 常数 45.0(解耦)
金手指居中 严格居中 偏心 0.25(板宽的 0.3%)
服务带 12.34 11.34 = §34 的下限「C60 本体 11 + 0.34」
面积 61.20 cm² 59.97 cm²(省 2.0%)

⛔ J1_X 必须解耦:它原是 BW/2,板宽一改就会算出 44.75,金手指连同舌头整体平移、 全板器件与 64 根线立刻对不上。解耦成 45.0 后金手指绝对位置一点没变。 ⚠ 代价是以后再改 BW,J1_X 不会自动跟着走。

为什么不两侧对称裁:保持居中就得全板西移(899 段铜 + 346 孔 + 164 件),无现成工具、 还会作废一批 _blade_*.json 缓存。用户拍板接受偏心。

41.3 ⛔ 东侧为什么只能裁 0.5 —— 又一个「几何死结」

卡点是 VO_P(4 A 主通道,宽 1.283)那条铜的东沿到 88.391。

板宽 铜面界 INA_ALERT 贴边竖线
89.0 88.5 88.391 + 0.15 = 88.541 > 88.5 ⇒ y≈54.1~54.25 处无解,0.279/0.20/0.15 全试过,收线宽也救不了
89.5 89.0 窗口 [88.68, 88.86] 宽 0.18 ⇒ 外层可行,线宽都不用改

裁到 89.0 的唯一出路是把那段 12.4 mm 挪进 L15 内层(内层扫描确认全程可行,最东中心 88.361), 代价是多 2 个换层孔 + 在 GND 内层切一道 12.4 mm 的缝,而只多省 0.6% 面积 ⇒ 用户拍板不拿地平面完整性换。

⚠ 判据教训:第一版算东侧窗口时只看过孔(用 VO_P 过孔东沿 88.055),得出「裁 1.0 可行」; 按线段实际占用逐 y 重扫才发现无解。宽铜线的东沿比它的过孔远 0.34。

41.4 INA_ALERT 西移(唯一要动的网)

它原本贴着旧板边 x=89.000 走了 12.4 mm(y 52.625~65.000)。新几何: 竖线 x=88.800(东沿 88.939,到界余 0.061)、过孔 x=88.600(东沿 88.905,余 0.095), 6 段 + 2 孔,线宽 0.279 不变。两端 U3.3 / U4.15 并查集核到仍是同一块铜。

⛔ 两条踩坑记录:

  1. primitiveId 必须整串传(16 个十六进制字符)。第一次把诊断脚本里 pid[:14] 截断显示的 id 复制进删除清单,delete() 收到不存在的 id 不报错、静默忽略 ⇒ 「删 6 线 / 2 孔」照常打印成功、err 为空,实际一个都没删,板上变成新旧并联(16→21 段), EasyEDA 还把重叠处打断重组成三段、原 id 当场失效。已写进 router.py 的 clear_mine() 前。
  2. 长条焊盘不能用 max(w,h)/2 当各向同性半径。Rs1.1 是 1.283 × 3.457 的竖长条, 圆近似假报「新线距它 −0.210」,按矩形判据算真实间距是 0.877。 (fan_check 原版就是这个圆近似 —— 它偏保守、只误报不漏报,卡新线下发是安全的, 但会挡住合法改动;同一个错今天已犯两次,另一次见 §38 的插槽针排假警报。)

41.5 北侧裁 1.0 是零代价的

北侧最高的 J3.4 焊盘顶在 66.400,新铜面边界 66.5 刚好让过(余 0.10) ⇒ 越界 0 项。 再往 66.5 走就开始撞 J3 / R63 / EDL_EN(1.5 时 6 项、2.0 时 10 项、3.0 时 25 项并吃到 U3)。

⚠ IF_Y 跟手机走(PHONE_ORG[1]+PHONE_WH[1] = 55.66)、不跟 BH ⇒ 改 BH 只压服务带, 手机投影与两条排线槽都不受影响。再压就放不下 C60。

41.6 验收

板框折线 74 点 / 外接 089.5 × 067 / 挖槽 2 个;重铺 31 块填 31/31; DRC 0 条;board_check 900 段铜 / 346 孔、56/57 连通 (GND 那 49 只脚是 covered() 在刀片下的固有假阳性,见 board_check.py 文件头)。

41.7 下游回归:位号丝印跟着板框修

板框缩小会让北侧几个位号越框 —— 这是改板框最容易漏掉的下游影响, silk_blade 的改前体检「越框/入禁区」从 §40 定版时的 1 涨到 3。

只动了 3 个位号,其余 78 个原位不变(上一轮的人眼确认基本保住):

位号 原位 新位 移动 新位离自己器件焊盘框
J3 (20.12, 66.77) (25.16, 63.45) 6.031 0.857
R63 (13.24, 66.00) (9.78, 64.46) 3.795 1.513
C69 (7.83, 63.52) (7.83, 61.48) 2.043 0.751

modify 81/81、读回 81 个全部对上;改后体检回到 1(J1 白名单例外)、压焊盘 0 / 重叠 0; 三个新位都在 MAXD 2.2 内,位号不会离器件太远。丝印非铜,DRC 仍 0 条。

⚠ 越框有两套口径,别混用:按板框多边形判,真正跑到板外的只有 J3(2 个角在外); silk_blade 报 3 个是因为它更严 —— 越框要求「四角在框内且到轮廓 ≥ EDGE 0.5」, 并且把「入金手指禁区 y<12」并进同一项计数。R63 / C69 属于「离新板边不足 0.5」,不是真越框。

⚠ 验证脚本的一个坑:silk_blade --push 过程中会重新抓板并覆盖 _blade_silk.json。 拿它当「改前快照」去和 plan 比对时,若与 --push 并行跑,读到的已经是下发后的状态, 于是「原位」「新位」算出同一个数。要比对改动量,必须在 --push 之前把快照另存一份。

42. 舌头变短 + 缺口回标准值(2026-09-12 深夜 用户拍板,两项合并下发)

用户:「让舌头变短,并且解决缺口的问题」。两项都改板框层,合并成一次重画 + 一次重铺。

42.1 缺口 1.6 → 1.9:1.6 那版根本插不进插槽

厂商 STEP(SOFNG PCIE-64P11L)量出防呆键筋根部宽 1.78(竖壁 x −5.890/−4.110, 中心 −5.000 与 NOTCH_CX 独立吻合)。顶上 0.5 是 45° 导入角 ⇒ 顶端 1.78 − 1.0 = 0.78, 与文档另一处记的「顶端 0.78」正好对上 —— 锥形这个前提由两个独立数据互证。

⇒ 缺口 1.6 < 键筋 1.78:卡只能套住键筋顶端,往下插到 z = 9.59 就被撑住, 离槽底 2.000 差 7.59 mm。不是勉强,是根本插不进。

缺口 1.6(旧) 缺口 1.9(现行)
键筋配合间隙/侧 −0.090(过盈) +0.060 ✓
到 11/12 号指铜边距 0.350 0.200

⛔ 2026-09-11 那次 1.9 → 1.6 是基于错误信息的决定,两处都错: ① 当时写作「CEM 的 1.6」——CEM 标准缺口就是 1.9(KiCad 官方 x1/x4 封装均为 1.9); ② 代价只估成「防呆筋配合余量少 0.15」,没意识到会导致插不进。

0.2 不是本项目的妥协,是 PCIe 几何定死的:1.0 间距 / 0.7 指宽 / 1.9 缺口 ⇒ (3.0 − 1.9)/2 − 0.35 = 0.2,任何 PCIe 卡都是这个数(§27.8 原话)。 ⇒ fp_edge.selfcheck 的门槛已由 0.3 放回 0.2;按 0.3 反推缺口只能 ≤1.70,装不下 1.78,窗口为空。

⚠ 另一条没走的路:把 A11/A12/B11/B12 四根指改窄到 0.50 可换回 DRC 0 条 (那四根是 EFUSE_EN / INT# / GND×2,都不走电流,载流零代价), 但会偏离 CEM 标准指宽、与簧片接触面积少 29%。用户选了保标准指宽、接受 DRC。

42.2 台阶 12.0 → 9.9:⚠ 这一刀让板材变多

STEP_H 是台阶切掉的高度:y ≤ STEP_H 只有舌头(x 27.75~62.25)有板材,y > STEP_H 是全宽主体。 ⇒ 降低它 = 舌头变短、两侧原本被切掉的部分恢复成板材:

STEP_H 两侧切掉 实际板材
12.0(旧) 660.0 5336.5
9.9 544.5 5452.0(+115.5)

外接 89.5 × 67 = 5996.5 不随 STEP_H 变(嘉立创按外接矩形计价)⇒ 想减面积的话方向是反的。

9.9 是下限,三条约束同时卡住:

约束 值 说明
桥宽 = STEP_H − NOTCH_D 1.60 缺口顶到肩部这段是舌头左右两半唯一的连接
肩部余量 = STEP_H − 8.00 1.90 零件本地坐标(塑料体顶面 10.000 / 槽底 2.000)
丝印带上沿 9.40 离肩部 0.50 = silk_blade.EDGE

⛔ 定档时踩的坑:先给过一档 8.31(「只保缺口不被切开」),但那只保证缺口不被切开、 没保证缺口上方还有板材 —— 8.31 时桥宽只剩 0.01 mm,等于把舌头从中间切断; 肩部余量也只剩 0.31。⇒ 凡是「挖槽 + 外轮廓」同时收紧的地方,必须单独校核两者之间的剩余板材。

⚠ 另一处差点栽的:一度用底板坐标 z=12.33 算肩部余量,得出「肩部会陷进塑料体」。 那是两套坐标系搞混(零件本地 vs 底板局部,差 2.33)。肩部余量恒等于 STEP_H − 插入深度。

丝印与 J1 位号都不会被铣掉(用实际折线多边形含 R1.0 圆角复判四角): 丝印 8.409.40 完全在舌头内、离轮廓 0.750;J1 位号 9.5610.70 跨过肩部线, 但下半在舌头上、上半在全宽主体上,最近角离轮廓 1.695。 ⇒ silk_blade 体检改前 1 / 改后 1,没有引入任何新的位号越框。

42.3 验收:DRC 5 条(预期 4 + 漏算 1),其余全过

板框折线 74 点 / 外接 089.5 × 067;缺口区读回 y 顶 8.300、断点 38.55~41.45; 舌头侧边 y 值 [0, 8.90] 配肩部序列 8.9→9.1→…→9.9→10.05(R1.0 内凹圆角)⇒ 肩部落在 9.90 ✓; 舌头宽仍 34.50;重铺 31 块填 31/31;board_check 900 段铜 / 346 孔、56/57 连通。

DRC 条数 内容
板框 到 贴片焊盘 4 J1_A11(EFUSE_EN) / A12(GND) / B11(INT#) / B12(GND),均 0.2,PCIe 固有
板框 到 过孔 1 GND 孔 (41.500, 7.000),0.245

⛔ 那 1 条过孔是我立 DRC 基线时漏算的:基线只扫了焊盘,没扫过孔。 成因也不是台阶下移,而是缺口变宽 —— 右壁由 40.800 移到 40.950(+0.15), 该孔净距从上一轮核过的 0.395 掉到 0.245。 ⇒ 教训与 §41.3「只看过孔漏了宽铜线」是同一个:净距校核必须覆盖线 / 孔 / 焊盘三类,缺一类就会漏报。

⇒ 5 条性质相同(板框到铜),且 0.245 比 0.2 更宽松。 下单时统一向嘉立创确认「金手指缺口处铜到板边 0.2 mm 可做」即可覆盖全部 5 条。