# 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(私有 100~120W 协议要手机鉴权);单口 20V×5A = 100W ⇒ 12V 侧约 95W,常态 10~25W 够、最坏 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 铜柱,外壳跟着改 | ### 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.7~13.7 mm ⇒ 余 1.2~3.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 88~98), FB 分压、DAC、INA226、PCA9555 靠内(x 72~84);L2 完整地平面必须一路铺到板边。 见风险 R-12。 刀片 98 mm 宽、插槽只有 39 mm 长 ⇒ **上端必须加 3D 打印导轨**(PC 机箱卡导轨那种), 否则悬臂 29.5 mm 会晃。若不想做导轨,可把 A1 换成 **x8(56 mm)或 x16(89 mm)**槽体—— 多出来的针全部接地,代价是金手指面积变大(T3 的工艺费按面积算)。 ### 3.2 高度预算 ✅ T1 已定:槽距 20.32 mm ⚠️ **这一节 2026-09-08 重算过。原来的版本用错了安装方式** —— 它写「立柱 3」, 那是 R1 已经作废的顶针方案;现行是 R1 §22.3e 定稿的**中框式焊盘、螺柱间隙 1.0 mm** (螺丝把主板压在刀片上,主板自己的弹片直接压裸铜盘)。差这 2 mm 就是 T1 一直卡着的原因。 ``` 槽距 P = 刀片 PCB 1.6 + A 面(螺柱间隙 1.0 + 手机主板含屏蔽罩 h_phone) + B 面元件 h_B + 空气 g ``` `h_B = 3.0`(B 面最高件 = `L1` SPM6530T-4R7M),`P = 20.32` ⇒ **`h_phone + g = 14.72`**。 | `h_phone` 取值 | 来源 | 剩余空气 `g` | |---|---|---:| | 3.2 mm | 0.8 裸板 + 1.4 侧键面屏蔽罩(**实测**)+ 正面按 1.0 估 | 11.5 | | 5.0 mm | 常见手机主板总厚 | 9.7 | | 6.3 mm | 旧版本写的「超过就要放到 22 mm」告警阈值 | 8.4 | | **7.6 mm** | **小米8 整机厚度 —— 主板是它的子集,这是物理上限** | **7.1** | ⇒ **结论对 `h_phone` 完全不敏感**:连物理上限都富余 7 mm。 **槽距定 20.32 mm(PCIe / PC 机箱标准,导轨和插槽都是现成的),T1 不再是开画前提。** > ⚠️ **2026-09-09 更正(§26)**:下表「B 面 ≤ 3.0」是把 `L1` 的高度当预算写的,不是净空。 > 真正的净空分两段:**手机投影下 20.32 − 1.6 − 1.0 − 7.6 = 10.1**(h_phone 取物理上限), > **服务带 20.32 − 1.6 = 18.7**(A 面服务带清空之后对面是空的)。`C60`(10.5) 因此能下到 B 面服务带。 | 面 | 可用高度(按 g 留 2~4 mm) | 落地 | |---|---:|---| | B 面(背面,全板) | ~~≤ 3.0 已用满~~ → 手机投影下 **10.1** / 服务带 **18.7**(§26) | `L1` SPM6530T 3.0;`C60`/`J2`/`J3` 在服务带 | | A 面 手机区 | 1.0 + h_phone | 螺柱间隙 + 主板,见上表 | | A 面 服务带 + 功率列(没有手机压着)| **11.7 ~ 13.7** | **`C60` 2200 µF 只能放这两处**(T2 = 10.5,余 1.2~3.2)| ⚠️ **仍要在装配首件确认的一个数**(但它不影响槽距,只影响压板): R1 §22.3e 里有一处**自相矛盾**——「侧键面(贴合面)最高件 = 屏蔽罩 **1.4 mm**」 与两天后写的「贴合面上元件**全都低于 1 mm**」对不上,而螺柱间隙就是按 1.0 定的。 1.4 那个读数若指的是贴合面,1.0 mm 间隙会顶到屏蔽罩。**首件用塞尺量一次**, 真顶到就把间隙垫片从 1.0 换 1.5(槽距这边有 7 mm 富余,随便加)。 ### 3.3 风道 竖插的天然优势:5 条 20.32 mm 的平行通道,风墙放槽阵一端,沿通道直吹。 风扇电路沿用 R1 §22.6(两路 4 线 PWM + TACH,`FAN_12V_SW` 0.8 mm 线宽), **位置从「3D 打印外壳上」改为「底板槽阵一端」**,首板只装一只(A3)。 外壳要重画:R1 的平铺外壳完全不能用。 --- ## 4. 电气分界(BOM 归属) | 归属 | 器件 | 数量 | 来源 | |---|---|---:|---| | **底板** | J1 DC-005 座 / F1 10A / D1 TVS / Q1 反接 P-MOS / C_in 2×470 µF | 1 套 | R1 §9.1 原样 | | 底板 | U19 LMR51430Y(3V3)/ U30 LMR51430Y(5V)/ L3 / 分压 | 1 套 | R1 §9.3 / §9.4 | | 底板 | U29 母线泄放 TL431 + MOS + 10 Ω/5 W | 1 | R1 §15.2 | | 底板 | U20 ESP32-S3-WROOM-1 | 1 | R1 §9.1;**J22 调试 USB-C 删除**(D13) | | 底板 | **J33 调试应急口 5P 1.25 mm**(GND / TXD0 / RXD0 / EN / IO0) | 1 | **R2 新增(D13 的退路)** | | 底板 | **U35 TCA9548A** I²C 八路多路器 | 1 | **R2 新增(D8)** | | 底板 | U13 INA226(输入侧)+ Rs6 5 mΩ | 1 | R1 §19 | | 底板 | U32 USB2517I + Y1 24 MHz + R708 12k + U31 AMS1117-3.3 + J23 上游 USB-C | 1 套 | R1 §21,~~`CFG_SEL[2:0]=110` 不变~~ → **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.05~0.1 µm 且底下是镍磷层, **是为焊接设计的,不是为插拔设计的** —— 金手指反复摩擦会很快磨穿见镍。 真正的金手指工艺是**电镀硬金**(1~1.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 44~58.2 / y 30.2~34、J36 南排投影 x 44~58 / y 43.4~46.4)。走廊 2 净高 11.12 而 U32 占 9.75, > 按检查清单「VDDA33 / VDD33 每脚 0.1 µF 紧贴」,南排 46 脚和北排 5 / 10 脚的去耦只有放进这两条才能 ≈1.3 mm > (不放开是 7~8 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 ⚠️ 刀片投影规则(竖插 + 降高度带来的新约束) 插槽把刀片底边抬到底板上方约 **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` 在固件里**只在启动自检时脉冲一次**,运行期不许再动;③ 该脚外部上拉,ESP32 复位期间 Hub 保持工作 | | 3 | 板子是**自供电 Hub**(12V→5V→3V3),不是总线供电 | 上游只取 D±,VBUS 只用于「电脑在不在」检测(沿用 R1 的 `UP_VBUS_DET`) | | 4 | 上游 480 Mbps 由 6 个设备共享 | 挂机农场的 adb 流量很小;大文件传输会互相分带宽,可接受 | | 5 | 底板多一对 D± 要走(§6.3 第 6 对,≈25 mm) | 同样受 §6.2 第 1 条约束 | | 6 | T6:`CFG_SEL=110` 下 7 个口是否默认全开 | 开画前对 datasheet 核一遍;若需要禁用多余口,改的是 strap 而不是电路 | **净收益**:桌面上从「一根 USB 到 Hub 上游 + 一根 USB 到 ESP32 调试口」变成**一根线**, 且省掉一个 USB-C 座。 --- ## 9. 从 R1 复用什么 | R1 页 / 产物 | R2 去向 | |---|---| | `P2-CHANNEL`(单路母版) | → **刀片**,几乎原样,去掉五路复制 | | `C4-SITEn`(顶针 / EDL / P+P− / 电容组 / VBUS 开关) | → **刀片**,与上面那页合并成一页 | | `P1-INPUT` / `P1B-5V` | → **底板**,原样 | | `P6-FAN-EDL` | → **底板**,风扇部分原样;EDL 部分挪去刀片 | | `P3-CONTROL` / `P3B-EXPAND` | → **底板**,删掉挪到刀片上的部分,加 TCA9548A;**J22 删除、加 J33**(D13) | | `P4B-HUB`(USB2517I + strap + Y1) | → **底板**,**几乎原样**;只多接一个下行口给 ESP32(D13) | | `P4-USB` / `P5-HARNESS` | 拆进刀片 | | `P5-BTB`(80 针排针表) | ⛔ **作废**,换成金手指表(§5.2) | | 自建封装 BM24-50DS / fp_body / 顶针封装 | **全部复用** | | `pcb1_pour.py` 的断面校核机制 | 复用到底板 12V 链 | | `pcb1_netlist.py` / `verify_sch.py` / `xpage.py` | 复用 | | 固件 A1~A11 | 见 §8.1 | **原理图工作量估计:约六成是搬运**,新画的只有金手指符号、5 个插槽、TCA9548A、刀片拼页。 --- ## 10. 风险登记 | # | 风险 | 缓解 | |---|---|---| | R-1 | **底板 D± 不控阻抗**,五片手机枚举不稳 | 长度压 ≤45 mm;L2 走廊不割;**D12 的 1.25 mm 座退路**(割断改飞线,¥2) | | R-2 | 金手指工艺费吃掉板费 | §5.4 退回 1.27 mm 排针(失去盲插与机械保持) | | R-3 | **TCA9548A 是单点**:它挂了五路全瞎 | 复位脚接 ESP32;A10 加判据「mux 失联 ⇒ 全部断电」 | | R-4 | **槽距不够**(T1 实测 h_phone > 6.3 mm) | 槽距放 22 mm,底板 +8 mm 宽 | | R-5 | C801 高度与竖插冲突(T2) | 只放没有手机压着的空白列 / 服务带;或改低高度聚合物电容 | | R-6 | 竖插外壳要重画,R1 的平铺外壳全废 | 归入 M7 | | R-7 | R1 §24.3 BM24 镜像位仍无实证 | 老账;好消息是现在只影响 80 cm² 的一块板 | | R-8 | 手机主板 7 孔 ±0.5 mm 公差搬到刀片 | 孔做 Ø2.5 沉孔或长圆槽;以 H2/H5 做主基准(R1 §22.3a) | | R-9 | 误插真 PCI-E 卡 / 刀片误插进 PC | §5.2 电源针位对齐真 PCIe 语义 + 插槽旁丝印警告 | | R-10 | 刀片 30.5 mm 悬臂晃动 | 上端 3D 打印导轨;或 A1 换 x8 / x16 槽体(§3.1) | | **R-12** | **功率级与手机主板共面、只隔 2 mm**(降高度 + 收窄到 98 的代价):480 kHz 开关噪声离手机天线更近 | SW/电感/Cin 排在功率列最外边(x 88~98);L2 完整地平面铺到板边;必要时功率列加屏蔽罩 | | **R-11** | **D13 的自锁**:固件复位 Hub = 自断控制台与烧录口 | J33 UART 应急口 + `HUB_RST` 只在自检脉冲一次 + 外部上拉(§8.2 第 2 条) | --- ## 11. 执行计划 | 里程碑 | 内容 | 验收判据 | |---|---|---| | **M0** | 核 T1(主板厚度)/ T2(C801 高度)/ T3(金手指报价)/ T4(CEM 引脚表)/ T6(Hub 口使能) | 五项都有数,槽距与针位表定稿 | | **M1** | 新建 EasyEDA 工程 `PhoneRail-R2`,建两块板的文档骨架 | ✅ **已完成 2026-09-08**,见 §13 | | **M2** | ✅ **刀片原理图** ~~4~~ **5** 页全部画完(2026-09-08)| `verify_sch --nets` 六项全过;`port_audit` 146 个可疑 0;`xpage` 漏接 0 | | M2a | ✅ **`B1-POWER`**(2026-09-08) | 42 件 / 218 段 / 31 旗 / 13 端口,六项全过、可疑 0,见 §14 | | M2b | ✅ **`B2-CTRL`**(2026-09-08)| 13 件 / 55 段 / 13 旗 / 20 端口,六项全过、可疑 0,见 §15 | | M2c | ✅ **`B3-PHONE` + `B3B-USB`**(2026-09-08,**拆成两页**)| 17 件 + 9 件,六项全过、可疑 0,见 §16 | | M2d | ✅ **`B4-EDGE`**(2026-09-08)| 2 件 / 85 段 / 7 旗 / 15 端口,六项全过、可疑 0、交叉 0,见 §17。**M2 至此收口** | | **M3** | **底板原理图** 6 页(P1 + P1B + P3 + P4B + P6 + mux + 5 槽 + D13 的第 6 个 Hub 口) | 同上 | | M3a | ✅ **`A1-INPUT`**(2026-09-08)| 25 件 / 101 段 / 18 旗 / 10 端口,六项全过、可疑 0、交叉 0,见 §18 | | M3b | ✅ **`A2-AUX`**(2026-09-08)| 17 件 / 56 段 / 15 旗 / 8 端口,六项全过、可疑 0,见 §19 | | **M4** | **刀片 PCB**(4 层,98×76) | **板框 ≤98×98(D14)**;关键回路按 §7.2 复核;功率列按「离手机越远越吵」排;DRC 0 | | **M5** | **底板 PCB**(~~2 层,110×125~~ ⇒ **4 层,≤98×98,器件全在背面**,D15) | 12V 断面 ≥ §6.4;六对 D± ≤45 mm、参考层 L3 无开口;插槽面只有插槽 | | **M6** | **先只打刀片**,用实验室电源直接喂 12V 验证单路 | R1 §11 的上电顺序照跑;不用等底板 | | **M7** | 打底板 + 外壳 + 联调 | R1 §14 实测记录表;**验收一条:只插一根 USB-C,电脑同时看到 5 台 adb 设备 + ESP32 串口** | > **M6 是这个架构白送的**:刀片只需要 12V 就能独立验证, > 可以在底板还没画完的时候先打样、先调通、先把 R1 §13.5 / §24.3 那些手机侧的老账清掉。 > 一次刀片打样的钱远小于一次整板打样。 --- ## 12. 与 R1 的关系 - R1 的工程、原理图、PCB、文档**全部保留**,不删不改。 - R1 文档 `五路直供电源板设计.md` 仍是**所有未变更计算的事实来源**。 - R2 若最终落地,R1 转为「历史方案」,但在那之前**两条线互不干扰**。 - 固件仓库共用一套,按 §8.1 的表做增量改动;A5 那一包会被架空,代码保留。 --- ## 13. M1 落地记录(2026-09-08) 工程已建好并逐项回读验证。**R1 工程(`1e5745f4caff4b15a921694d2fd912e4` 五路手机直供电源板)一个字节没动。** ### 13.1 UUID(唯一事实来源是 `.claude/r2/r2-uuids.json`) | | 名称 | UUID | |---|---|---| | 工程 | `PhoneRail-R2` | `05a65c22f14846b8b95360ef8d3c1e2e` | | 板 1 | `BLADE`(刀片 98×76 四层) | — | | ├ 原理图 | `r2-blade` | `ec5f3ca5108b618d` | | ├ PCB | `BLADE-PCB` | `3b9c4e39c8d164db` | | ├ 页 | `B1-POWER` | `5338949298dcff35` | | ├ 页 | `B2-CTRL` | `4f458d678c50f7a4` | | ├ 页 | `B3-PHONE` | `cf32a688430fc2d1` | | ├ 页 | **`B3B-USB`**(2026-09-08 新增)| `4ce5bfe35e90e560` | | └ 页 | `B4-EDGE` | `c8f10dbd1286853b` | | 板 2 | `BASE`(底板 110×125 双面) | — | | ├ 原理图 | `r2-base` | `372e2399adb7a6db` | | ├ PCB | `BASE-PCB` | `7b9524b6aaf6f235` | | ├ 页 | `A1-INPUT` | `9d86e72abb1a6571` | | ├ 页 | `A2-AUX` | `3361444ab04474c5` | | ├ 页 | `A3-CTRL` | `38327f806bc13133` | | ├ 页 | `A4-HUB` | `09d583ff95cd35d9` | | ├ 页 | `A5-SLOTS` | `2c73c5bf77f34053` | | └ 页 | `A6-FAN` | `68c9ffaa578572d3` | 各页内容分工见 `r2-uuids.json` 的 `page_contents` 字段。 回读工程树:`/c/Python314/python .claude/eda.py .claude/r2/tree.js` ### 13.2 建工程时踩到的三条 API 经验 1. **`dmt_Project.createProject()` 传 `teamUuid` + `description` 会静默失败**: 返回 `undefined`,工程列表里查无此项,**不抛异常**。 只传 `friendlyName`(可再带 `projectName`)就成功。 ⇒ **判据是「回列表里查得到」,不是「调用没报错」。** 2. **`dmt_Schematic.createSchematic(boardName)` / `dmt_Pcb.createPcb(boardName)` 建不出新板**: 传一个不存在的板名时两者都返回 `undefined`、什么也不建。 正解是 **先 `dmt_Board.createBoard()`(无参)**——它会连原理图带 PCB 一起建好、 自动命名 `Board1`,再用 `modifyBoardName` / `modifySchematicName` / `modifyPcbName` 改名。 3. **`modifySchematicName()` 会把名字转成小写**(`R2-BLADE` → `r2-blade`),板名和 PCB 名不会。 不影响使用,但按名字查原理图时要注意大小写。 > ⚠️ **API 没有删除工程的接口**。试参数时误建的空工程 `PhoneRail-R2b` > (`ab94ce71a50b48348f845017fb57d557`)**要在工程树里右键手动删除**。 ### 13.3 下一步(M2 之前) M0 的五项实测/核对(§0.3 的 T1~T6)没有做完,其中 **T1(主板含屏蔽罩厚度)** 直接决定槽距 20.32 够不够,**T4(PCIe CEM 引脚表)**决定 `B4-EDGE` 那一页能不能开画。 建议先补这两项,`B1-POWER` / `A1-INPUT` 这些不依赖它们的页可以并行开工。 --- ## 14. M2a 落地记录:`B1-POWER`(2026-09-08) ### 14.1 做法:**搬 R1 的版图,不重排** `P2-CHANNEL` 在 R1 上已经过六项几何验证 + 人眼确认,是全工程最成熟的一页。 `.claude/r2/dump_page.py` 把它整页读回(40 元件 / 213 段导线 / 29 旗 / 12 端口, **含每个引脚的坐标**),`.claude/r2/b1_power.py` 做三件事再重放: | | 内容 | |---|---| | 位号映射 | `C1xx→Cx` / `R1xx→Rx` / `Rs101→Rs1` / `L101→L1` / `Q101→Q1` / `Q102→Q2`;
芯片按刀片编号:`U1` Buck、**`U8→U3`** INA226、**`U14→U2`** eFuse | | 网络去后缀 | `VO1→VO`、`VO1_P→VO_P`、`VDAC1→VDAC`、`EFUSE_*1→EFUSE_*`;
`+12V→+12V_F`(Buck 吃的是保险丝之后那一段)| | 新增 | **12V 入口保护**:`+12V`(金手指) → `F1` → `+12V_F`,`D1` TVS 钳到地(D10)| 结果:**42 件 / 218 段导线 / 31 旗 / 13 端口 / 8 条文字**。 `verify_sch --nets` 六项全过(悬空 0 / 单引脚网络 0 / 无名旗端口 0 / 一网多名 0), `port_audit` 44 个旗端口**可疑 0**。 ### 14.2 跨页网络(B2 / B3 / B4 要对上) | 网络 | 方向 | 对端 | |---|---|---| | `+12V` | 入 | B4-EDGE 金手指 | | `+3V3` / `GND` | — | B4-EDGE | | `VDAC` | 入 | B2-CTRL 的 DAC63204 CH0 | | **`EFUSE_EN`** | 入 | **B4-EDGE(直连底板 ESP32,不经 PCA9555)** | | `EFUSE_FLT` / `EFUSE_PG` / `BUCK_PG` / `INA_ALERT` | 出 | B2-CTRL 的 PCA9555 输入 | | `SDA` / `SCL` | 双向 | B4-EDGE | | `VO_P` | 出 | B3-PHONE(`P+`/`P−` 焊盘 + C801 阻尼组)| > `+12V_F` 是刀片内部轨,只在本页出现(电源旗 10 个引脚),不跨页。 ### 14.3 ⚠️ 跨工程搬版图踩到的三条(已并入 skill §3c / §3e / §6f) 1. **`create()` 会把元件坐标吸附到 5 的倍数** —— R1 页上 679/639/654/589 那些位置 放下去会差 1~2 个单位,「按坐标精确认领位号」42 件只认到 28 件。 ⇒ 就近认领(容差 3)+ 认完 `setState_X/Y` 拉回精确坐标。 2. **42 件里有 27 件的 `create(rot=270)` 语义与 R1 相反。** 25 件是两脚对称件(只有编号互换,无害),但 **C10 / C14 两颗 33nF 是 +20/−15 的 不对称跨距,翻过来坐标真的差 5**,照 R1 的坐标画线会断在这两颗上。 ⇒ 脚本里做了「对不上就翻 180 再回读」的自动修正循环。 ⚠️ 第一轮**看起来没生效**:`create(270)` 与 `setState_Rotation(270)` 差 180°, 要翻两次才落位(日志里同一批 27 件连打两行「翻转…重试」是正常的)。 3. **`rot=180` 的旗/端口读回来带浮点尾巴**(`789.9999999999999`), 不取整的话「坐标必须是 5 的倍数」「必须落在导线端点」两道自检全部误报。 ### 14.4 还欠的 - ~~T7~~:✅ 已结(2026-09-08),`F1` = `F1206SB2000V063TM`(`C310998`)。见 §20.7。 - `port_audit.py` 的页面清单是 R1 硬编码的,在 R2 工程里它会对着当前页跑 11 遍 (数字仍然可信,但要写一个 R2 版)。 - 人眼截图确认:`.claude/r2/B1-POWER.png`。 --- ## 15. M2b 落地记录:`B2-CTRL`(2026-09-08) 脚本 `.claude/r2/b2_ctrl.py`(幂等,`--push` 清页重画)。 **13 件 / 55 段导线 / 13 旗 / 20 端口 / 9 条文字**, `verify_sch --nets` 六项全过(悬空 0 / 单引脚 0 / 无名旗端口 0 / 一网多名 0), `port_audit --r2 BLADE` 44+33 个旗端口**可疑 0**,本地交叉点 0。 截图 `.claude/r2/B2-CTRL.png`。 ### 15.1 页面内容 | 位号 | 器件 | 说明 | |---|---|---| | `U4` | PCA9555PW,0x20(A0/A1/A2 接地)| P0.0~P0.2 三个侧键 / P0.3 `EDL_EN` / P0.4 `VBUS_EN` 输出;P1.0~P1.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**(A1~A18 / B1~B18)| ❌ 其实是 **x1** | | `10061913-103TLF`(Amphenol,贴片)| `C4697499` | **38**(A1~A18/B1~B18 + 2 屏蔽)| ❌ 其实是 **x1** | | `X3091WR-64B-9TV15`(XKB)| `C30167381` | — | ❌ **弯插**(卡平躺),与 D4「刀片竖插」冲突 | | `91613-110141D` / `91619-110141D`(友贸)| `C1509727` / `C5210922` | — | ❌ **夹板式**(跨板边),是延长线/转接用的 | ⇒ **描述不可信,判据是把符号放到空页上读回引脚数**。 #### 换料对图纸的影响:只有脚号,版图一个字没动 | | 刀片 `PCIE-X4-EDGE-64P`(金手指)| 底板 `PCIE-64P11L`(插槽)| |---|---|---| | **脚号** | `A1`~`A32` / `B1`~`B32` | **`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` 放槽 1~3,新开 **`A5B-SLOTS`(`e493f8bce3a51aae`)** 放槽 4~5 + 全部 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 没定**:本页按可能上 R8 保守处理,`IO35/36/37` 全部不接。 若确定 N8,这三脚可放出来当 GPIO。~~现在全板只剩 `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 条,够不着立创全库」。 **实际上它的完整签名是** ```js 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.05~0.1 µm、底下是镍磷层,**是为焊接设计的,不是为插拔设计的**, 金手指反复摩擦会很快磨穿见镍。金手指要的是**电镀硬金**(1~1.5 µm + 钴/镍硬化)—— 嘉立创的「金手指」选项本身就是这个工艺,勾了就有。 **对 M4 的两条约束**(`B4-EDGE` 的金手指封装现在可以开画了): - ~~斜边会吃掉手指前端约 1.0 mm 的镀层~~ ⇒ **M4a 实测这条不成立,但结论不变**: CEM 的金手指本来就**离板边留 1.3 mm 裸边**(指尖不到板边),斜边啃的是那 1.3 mm 的裸 FR4, 一点镀层都吃不到。金手指长度仍然照 CEM 画(4.3 mm),别自己缩短。 - 板厚必须是 **1.6 mm**(插槽的夹持力按这个设计),下单时不能被「1.2 更便宜」换掉。 > **唯一会推翻这个决定的**:金手指工艺费报价离谱到吃掉板费。那时走 §5.4 的退路 > (1.27 mm 排针)—— 而且现在这条退路的代价比原来小:底板插槽已经换成贴片立式 > (§20.3),机械固定件本来就要加。 --- ## 22. M4a 落地记录:金手指封装(2026-09-08) `PCIE-X4-EDGE-64P` 从「只有符号」变成「符号 + 封装」,**M4 的最后一个前置条件清空**。 | | | |---|---| | 封装名 | **`EDGE-64P-P1.00_PCIE-X4-GF`** | | UUID | `569096fb8fed4743b85c69f4b6581ead`(个人库;已写进 `.claude/r2/r2-uuids.json`) | | 脚本 | **`.claude/r2/fp_edge.py`** —— 几何的唯一事实来源,`--push` 幂等重画 + 读回校验 | | 判据 | 64 焊盘逐脚对坐标/层/尺寸、板框缺口 16 段折线闭合且两端点落在板边、丝印零侵入指区 | ### 22.1 几何不是凭记忆写的 M2d 那两处「凭记忆写错针位」的教训之后,这一版的每个数都有出处:主源是 **KiCad 官方 `Connector_PCBEdge.pretty/BUS_PCIexpress_x4.kicad_mod`**(其 `descr` 注明摘自 PCI-E CEM 的 add-in card edge-finger 图),再拿三处独立资料交叉核对。 | 项 | 取值 | 交叉核对 | |---|---:|---| | 间距 | 1.00 mm | CEM / 立创资料 / KiCad 三处一致 | | 手指宽 | 0.70 mm(净距 0.30) | 同上 | | 手指长 | 4.30 mm | 中文资料常写 4.0,同量级 | | **指尖到板边** | **1.30 mm** | multi-cb 给 PCIe 荐值 1.4,另一处给 0.6~1.5 窗口 ⇒ 1.3 在窗口内 | | 缺口 | 11/12 号针之间,宽 1.9、深 7.45,口部两个 0.5×45° 导入角 | KiCad 的 x1 与 x4 两个封装完全一致 | | 缺口到 11/12 号指 | 铜边距 **0.20 mm** | 直段两侧对称,`selfcheck` 里断言死 | | A 排 / B 排 | A = 底层,B = 顶层 | 同 KiCad | **`A1` / `B31` 是短指(3.2,指尖再退 1.10)**,远端与长指齐平。这不是装饰:本方案的在位检测 就是这两根(底板 `A1=GND` / `B31=PRSNT{n}#`,刀片上短接)。做成等长指,**刀片插一半就报 「已插入」**,而这一类错误功能测试测不出来 —— 与 §20.1 是同一个坑的两面。 ### 22.2 ⛔ 两条与既有文档冲突的,已经改掉文档 1. **T3 的「20° 斜边」在嘉立创下不了单。** 嘉立创《金手指斜边设计注意事项》写明 **只有 30° 和 45°,并建议优先 30°**。⇒ §5.3 / §21.3 已改成 **30°**。 2. **「斜边吃掉 1.0 mm 镀层」不成立。** CEM 的金手指本来就离板边留 1.3 mm 裸边, 斜边啃的是那段裸 FR4。结论不变(照 CEM 画、别缩短),但理由换了 —— 那 1.3 mm 的用途就是给斜边的。 嘉立创另外三条已核:金手指处**必须开通窗**(焊盘自带,且本封装不在指区放任何丝印); 斜边板单片长宽 **≥ 50 mm**(刀片 98×76,过);板厚 ≥ 0.4(1.6,过)。 ### 22.3 板框:缺口跟着封装走,外框归 PCB 封装在 **板框层(11)** 只画**缺口那一段**(两个导入角 + 两条竖线 + 12 段折线近似的顶部半圆)。 刀片 98×76 的外框在 PCB 文档里画,**底边必须在 `x = -6.45` 和 `x = -3.55`(相对封装原点) 断开**,两段拼成一个闭合外框。坐标从 `fp_edge.notch_mouth()` 取,不要手抄。 ⇒ **缺口忘不掉**(跟着封装走),而外框尺寸仍归 PCB;拼不上时 DRC 会报开口外框。 ### 22.4 这一轮踩到的四条 API 坑(都已写进脚本注释) | 坑 | 现象 | 做法 | |---|---|---| | **`pcb_PrimitiveArc` 只写不读** | `create()` 返回成功、画面上也确实画出来了,但 `getAll()` / `getAllPrimitiveId()` 一律返回空 ⇒ **既校验不了也删不掉**,重画一次多一批 | 半圆改用 12 段折线(弦高误差 < 0.01 mm)。发现时已经堆了 5 个删不掉的弧,**整个封装删掉重建** | | **`lib_Device.modify` 的 `association` 在第 5 位** | `dev_edge.py` 当初把它写到第 6 位(`description`),所以一直「关联改不动」 | 位序是 `(uuid, lib, name, classification, association, description, property)` | | **`addIntoBom` 是 boolean 不是字符串** | `dev_edge.py` 传的是 `'no'`,于是「API 改不动、只能去客户端手工改」 | 传 `false` 就改掉了 —— **`eda-parts.json` 里 `MI8-KEY-PAD` 那条同样的结论要一起翻案** | | **助焊(锡膏)扩展关不死** | 给 `-0.35 mm`,客户端夹到 **-0.035 mm** | 「金手指区钢网不开口」只能**下单时另外说明**(同 `fp_keypad.py` 那颗接触盘) | 另两条无害但费时间的:系统库封装**不能** `openInEditor`(返回 `false`),`lib_Footprint.copy` 从系统库复制到个人库也静默失败 ⇒ 想读系统库封装的几何,只能放到空 PCB 里读回。 ### 22.5 坐标系:PCB 里 **y 向上为正** 封装原点 = **金手指阵列的 X 中心 × 卡的底边**,手指朝 **+Y**(板内)。 第一版画反了(手指长到板外),**四道几何校验全过,是截图看出来的** —— 又一次 「几何验证证明不了看着对」。判据留在脚本注释里:板边基准线画在文档层 y=0, 截图上它必须在手指**下方**。 --- ## 23. M4b 落地记录:刀片板框 + 导入(2026-09-08) | 步 | 结果 | |---|---| | 板框 | **98 × 76,四角 R2**,画在 `BLADE-PCB`(`3b9c4e39c8d164db`)。脚本 `.claude/r2/pcb_blade.py` | | 金手指 | `J1` 摆在 **(49.00, 0)**,rot 0,layer 1。64 个焊盘的网络逐脚读回正确 | | 导入 | **83 件全部导入**(`--probe` 报 83 增 / 0 删 / 0 改),`--verify` 位号+封装逐件对上 | 坐标系:**板左下角 (0,0),x 右 y 上**,就是 §3.1 那张分区图的坐标。 ### 23.1 金手指为什么摆在 x=49(板宽正中) 刀片 98 宽、插槽体只有 39 ⇒ 两侧各悬出 29.5。**居中**让左边(手机主板)和右边 (功率列,压着 2200 µF 和电感)的悬臂等长 —— 插槽是**贴片立式、保持力只靠焊盘剪切** (§20.3),不该让任何一边偏重。代价:`+12V` 在 `B1/B2/B3`(阵列**左**端), 到功率列要横穿 ~40 mm;这一段走 L3 的 12V 灌铜,不是走线,无所谓。 ⛔ **底板的 5 个插槽必须按同一个数摆**:槽中心 = 刀片中心。这是两块板之间唯一的 硬对位关系,M5 画底板时从 `pcb_blade.J1_X` 取。 ### 23.2 板框底边**是断开的**,这是设计不是错误 缺口(防呆键)画在封装的板框层里,PCB 这边的底边在 **x = 42.55 / 45.45** 断开, 两段拼成闭合外框。`pcb_blade.py --verify` 的判据就是「板框上有且只有两个自由端点, 且正好落在缺口口部」—— 拼错一格会当场报出来。 ### 23.3 两个坑 1. **`pcb_Document.importChanges()` 在本机一律返回 `false`、对话框都不弹** (带/不带 schematic uuid 都试过)⇒ 导入只能沿用 R1 那套**驱动 GUI** 的做法, 新脚本 `.claude/r2/pcb_import.py`(刀片/底板通用,`--base` 切板)。 2. **原理图里已经放下的元件会把「器件没有封装」这个状态缓存住。** `J1` 在 M2d 放下时器件还没封装,M4a 建好封装并挂上去之后, `B4-EDGE` 页上的 `J1` 读回来仍然是 `footprint.uuid = ""`, BOM 里显示成 `[object Object]`,**导入 PCB 会缺件**。 解法:**重跑 `b4_edge.py --push` 整页重画**(幂等),J1 才会带上新封装。 ⇒ 以后凡是「先放件、后补封装」的器件,都要回去重画那一页。 ### 23.4 M4 接下来的顺序 1. **设计规则**(照 `pcb1_rules.py` 改:刀片只有一路,`PWR12V` / `SWNODE` / `PWR4A` / `PWR1A` 四档 + `USB_DP/DM` 一对差分) 2. **摆位**:先钉死三颗 —— `J1`(已定)、`C60`(Ø10×10.5,只能放服务带/功率列,§21.2)、 `J4` BM24 尾插(接口边);再按 §3.1 的分区放其余 80 件, 功率列内部按「离手机越远越吵」排(SW/L/Cin 靠 x=98 那一边) 3. **布线**:L1 信号+功率、L2 完整地平面(不许割断)、L3 12V/VO 灌铜、L4 控制信号; D± 走 L1 以 L2 为参考 4. **灌铜 + DRC 清零**,再截图人眼确认 --- ## 24. M4c 落地记录:规则 / 摆位 / 铺铜(2026-09-08) ### 24.1 ⛔ 刀片 PCB 建出来是 **2 层**,不是 4 层 M1 建文档骨架时没设铜层数,`BLADE-PCB` 一直是 2 层。 表面上看不出来 —— `pcb_Layer.getAllLayers()` 照样列出 `Inner1` / `Inner2`(那是**层定义**, 不是启用的铜层),设计规则也照建不误。**唯一露馅的地方**是规则审计里那句 `getTheNumberOfCopperLayers() = 2`,以及规则配置的基准集叫 「JLCPCB Capability(**Two** Layers Board)」。 ⇒ `setTheNumberOfCopperLayers(4)` 改掉,然后**规则要重下一遍**(换层数会换基准能力集)。 ⚠ 底板 `BASE-PCB` 是 2 层(§6.1),那一块**不要**改。 ### 24.2 设计规则(`.claude/r2/pcb_rules.py`) 照搬 R1 `pcb1_rules.py` 的那一套,四个坑一个没变。和 R1 不同的四处写在脚本头上, 其中两处值得在这里重复: - **`PWR12V` 从 2.0 降到 0.8**:刀片 12V 满载只有 **1.45 A**(§20.7 那颗 2 A 保险就是按它选的)。 R1 的 2.0 mm 是给整机 8~10 A 干路的,照抄过来只会把 12 mm 宽的功率列挤死。 - **两对差分,不是一对**:`USB_DP/DM`(金手指 → U7)和 `USB_DPJ/DMJ`(U7 → J4) 被 ESD 管隔成两段,各自成对。只建一对,另一段就退回默认间距规则。 **⛔ 安全间距是 0.15,不是 R1 的 0.2。** 抬到 0.2 会刷出 23 条「贴片焊盘到贴片焊盘」, **全部在 `J4` BM24-50DS 内部** —— 0.4 mm 间距的尾插座,相邻焊盘净距 0.168~0.171, 是买来的封装本身的几何,改摆位修不掉。0.15 仍远高于嘉立创四层 0.09 的能力线。 ⚠ 顺带发现 R1 那份的间距循环**只抬不降**,所以把下限改小是改不动的 —— 这里改成了「≤0.2 的格子一律赋成下限,0.254/0.3 那几格(孔/板边相关)不动」。 ### 24.3 摆位(`.claude/r2/pcb_place.py`):三类件三种定位 1. **机械锚定**(位置由小米8 主板决定):`K1~K4` 侧键触点盘、`J5` 电池排线焊盘、 `J4` 尾插座 —— 坐标从 `.claude/mi8_mech.json` 换算,不手抄。 手机落点 `PHONE_ORG = (3, 29)`,接口边(`v=0`,J600/J1401/侧键都在上面)朝下。 2. **手工钉死**:`J1`(49,0) / `C60`(37.5,19) / `J2`(62,15) / `J3`(66.5,25)。 3. **其余 70 件**:按功能分组、按电流流向排序,货架式排布器塞进四个区。 **顺序是设计意图,坐标不是** —— 要改布局改 `GROUPS`,别去改坐标。 三条落地时改掉的: - **功率列自下而上 = 输出端 → 输入端**(和电流方向相反)。`VO_P` 是 4 A, 出口必须离服务带的 `C60`/`J5` 近;`+12V` 只有 1.45 A 又走灌铜,爬到板子上半段无所谓。 - **`U3` INA226 挪进 `POWER_OUT` 并紧挨 `Rs1`**。原来它在内条,隔着一整列 —— §7.2 第四条「取样脚落在 Rs 的 Kelvin 焊盘上」就做不到了。 - **每个组占一条完整横带**(区里放一个 y 游标)。不这么做小件会回填进前一组的空隙, 功能级在 y 上互相咬,L3 的 12V / VO 岛就切不出来。 **B 面留空**:§3.2 把 `L1` 电感算成「B 面最高件 3.0」,但同一张表里 A 面功率列可用 11.7~13.7 —— 3.0 的电感放 A 面绰绰有余,还能贴着 `U1` 摆、SW 节点不打过孔。 83 件全在 A 面,`h_B` 从 3.0 变 0,槽距只会更宽裕。 ### 24.4 ⛔ 全贴片的板子:不打缝合过孔,四层里有三层的铜面会被整块删掉 六块铜面(`GND-TOP/L2/L3/BOT` + `VO-L3` + `V12-L3`)下发后,**只有 `GND-TOP` 填出来** (213 块),另外五块一块铜都没有。根因:**这块板一个通孔焊盘都没有**(全贴片), 内层铜面因此一个连接点都没有,「移除孤岛」把整块删了。 **三个地方都不报错**:`rebuildCopperRegion()` 返回成功、铺铜管理器显示「0/0」、 DRC 的间距那一支干干净净。只有把内层截一张图才看得出来是空的。 ⇒ 顺序必须是 **摆位 → GND 缝合过孔 → 布线 → 铺铜**。 `pcb_route.py --stitch` 按 5 mm 网格、避开所有焊盘 0.6 mm 打 196 个 GND 过孔。 同理 `VO_P` / `+12V` 也**不能**只靠灌铜:让自动布线器拉线,它换层打的过孔 正好把 L3 的两个岛接上。 ### 24.5 铺铜结果:6 块里 4 块填出来了,2 块等布线 打完 196 个 GND 缝合过孔再重铺,`GND-TOP` / `GND-L2` / `GND-L3` / `GND-BOT` 四块全部填上, **L2 是一整块没有割断的地平面**(§7.1 的硬要求,截图 `.claude/r2/M4c-blade-L2-gnd.png` 为证)。 剩下 `VO-L3` / `V12-L3` 两块仍是空的 —— **这是对的**:`VO_P` 和 `+12V` 现在一根线都没布, L3 上那两个岛还没有任何过孔可接。布完线(换层过孔会穿过 L3)它们自然就填上了。 DRC:**间距错误 0**,连接性错误 252(= 还没布线)。 ### 24.6 ⛔ 自动布线在这台客户端上**跑不出一根铜** 两条路都试过,都不行: | 路子 | 结果 | |---|---| | `pcb_Document.autoRouting(...)` | **这个 API 在本机客户端上不存在**:`autoRouting is not a function`(文档里有,实现里没有)| | GUI:`布线 → 自动布线...` | 对话框能开、图层能勾(已取消内层,只留顶/底层)、`运行` 点得下去,**对话框立刻关闭,铜线数量 0**,不报错、不弹进度、不弹失败 | ⇒ **布线这一步没有自动化的路可走**,只剩两条: ① 我按脚本逐网络布(要自己写一个够用的布线器:约 55 个网络 / 361 个焊盘); ② 用户在客户端里手动跑一次自动布线(可能要登录 / 要额度),或直接手工布关键几条。 ⚠ 无论走哪条,**内层不许布线**这一条不能破(L2 是地平面、L3 是电源岛), 而且 §7.2 那四条关键回路(Buck 输入环路 / SW 面积 / FB 远离 SW / **Kelvin 取样**) 自动布线器一条都不认识,跑完必须逐条复核。 --- ## 25. M5 落地记录:器件翻到 B 面 + 功率级手排(2026-09-08) **用户要求**:卡片(刀片)上的器件放到**手机主板的另一面**;优化器件布局; 尾插排线座与电池排线焊盘**按之前的处理**放置。 ### 25.1 分面:A 面只留 10 件 小米8 主板压在 A 面,`J600` 的电池排线和 `J1401` 的尾插排线**贴着 A 面**折下来 落到服务带。所以 A 面只留下面这些,其余 **73 件全部搬到 B 面**: | A 面留守 | 为什么非在 A 面不可 | |---|---| | `K1~K4` 侧键触点盘 | 主板弹片直接压在裸铜盘上(R1 §22.3e)| | `J5` 电池排线焊盘 / `J4` BM24 尾插座 | 排线折下来焊在 A 面。**坐标和层一个数没改**(用户指定)| | `C60` 2200 µF | 高 10.5 mm,B 面预算只有 3.0(§3.2)| | `J2` D± 退路座 / `J3` EDL 座 | 线座约 5 mm 高,同样超 B 面预算;且要能插拔 | | `J1` 金手指 | 板边卡,两面都是指 | **换面赚到的三件事**(这才是「优化」的实质,不是重排坐标): 1. **两条排线底下彻底空了**。原来服务带塞着 30 多个小件,排线是贴着板面躺过去的。 2. **侧键 MOS 挪到 `K1~K4` 正背面**。漏极是手机侧键线(机内 100 k 上拉、高阻、最怕拾噪), 从 ~20 mm 缩到 3.9~6.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.77~32.77 × y 24.80~27.80(12×3,中心对 J600 u 23.77;§22.3b 标 ±2 所以比 R1 的 10 宽 2)| | 尾插槽 `TAIL` | x 46.58~66.58 × y 24.80~27.80(20×3,中心对 J1401 **本体中心 u 53.58**)| | 槽的实现 | **layer 12 (MULTI) 填充 = 挖槽区域**(`pcb_PrimitiveFill`,R1 同),不是板框内环;DRC 认「挖槽区域到导线」| | 排线车道(B 面,一件不放)| BAT x 22.27~31.27 / TAIL x 47.08~66.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: ```
… ``` `data-value=11` 没错(板框层),但**显示文字是空的**,而且属性面板给这个对象的标题是 **「导线」**,还带 `网络` / `网络长度` 两个字段。 ⇒ **`pcb_PrimitiveLine` 在嘉立创里是「导线」(铜),不是图形线。** 把它建在层 11 上,客户端照样渲染成品红、DRC 也不报(M4b 起四道几何校验全过), 但**板框识别只认图形图元**,所以它一路认为「没有板框」。 `图层` 下拉里只有铜层,板框层不在选项里 —— 这就是那一格空白的由来, 也是**几何验证永远抓不到这一类错**的原因:坐标、闭合、外接矩形全对,对象类型错了。 **改法**(`pcb_blade.py`):板框改成**一条闭合折线** `pcb_PrimitivePolyline`, 缺口不再靠封装拼,而是用 `outline_polygon()` 把 `fp_edge` 的缺口点列**插进底边中间** (几何仍然只有 `fp_edge` 一个出处,这里只做平移 + 顺序调整):54 个点,首尾重合。 判据从「37 段线两两端点相接」换成 **「层 11 上有且只有 1 条折线 + 首尾重合 + 外接矩形 0~98 × 0~76」**,另外允许层 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`: ```python 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`(63~91 × 0.8~16.0) + `SPINE`(2~91 × 15.8~20.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.0~8.5,其中 x 7.5~8.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.9~43.5)里是横着跑的, `USB5`(去最西槽)和 `USB1`(去最东槽)共用 y=41.4 那条道,两段拼起来 **x 24.5 一直到 105.1,横贯整块板**。而 12V 入口在南(y<16)、槽针在北(y 48~50), 中间只有两处竖井能穿:西 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.5~107.5 套着天线净空 86~106),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_EN3~5、PRSNT…)断在同一道横贯全板、两层都封死的墙上。 查墙上各网的两端(PROGRESS「U20 一簇诊断」):**NTC1/NTC2 在北排东头(IO1/IO2)却要去南边的热敏电阻**(RT601 (85,26) / RT602 (19,8)), **风扇那组在南排(IO4~IO7)却要去西北角风扇电路** —— 两组方向全反,风扇线横穿全板就是那道墙。布线器层面四轮 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 引脚。 结果:明确的 67~77 mm Buck 去耦跨板问题清零;审计剩下的电容距离提示中, 4 条是 3.0~3.2 mm,另 1 条是两风扇座共用的 `C738`(6.3 mm,位于两座中间)。 北边保留相邻的 `J27@x70 / J26@x83`。J33 是 ESP32 的 GND/TXD0/RXD0/EN/IO0 应急口,用户在客户端定稿为 **`(107.06,76.83,270°)`**:位于 U20 下方的右板边,从侧边接插,不再占用北侧风扇模块。 J33 的本体横向范围约 `x=105.8~108.3`,而刀片投影只到 `x=95.5`,所以虽然 y 落在槽阵带, 11.5 mm 插座高度仍无机械干涉。布局检查器的限高判据已从“只看 y”改为“同时落入 x/y 投影”。 ### 32.2 NTC 改为直接监测两个最高热密度点 `RT601` 放在 U31 右侧 `(92.0,24.5,270°)`。U31 在 Hub 最坏 0.42 A 时耗散 `0.42×(5-3.3)=0.71 W`,是持续热点。`RT602` 放在 J1/DC-005 右侧 `(72.5,10.0,180°)`:整机最坏 9.99 A,插座家族额定只有 2~5 A,接触弹片是优先安全热点, 邻近 Q1 在 10 A / 5 mΩ 上限下另有约 0.5 W 导通损耗。 NTC1/NTC2 的滤波电容 `C736/C739` 继续贴 U20 ADC1 脚,将远端传感线的噪声在 MCU 端滤除。 读回确认 RT601.1=`NTC1@(92.00,25.25)`,RT602.1=`NTC2@(73.25,10.00)`。 ### 32.3 Q6 / Q10 / U13 定点优化 - `U13=(19.0,5.5,0°)`,位于 Rs6 正下方。读回 8/9/10 脚在 `y=7.61`、朝上对着 `Rs6 y=11`,避免了原先在东侧控制列的跨板 Kelvin 线,也修掉了“位置回来但采样脚朝外”的 180° 方向错。 - `Q6=(72.5,113.5,180°)` 和 `R733/R734` 归到 J27 下方的 PWM 整形块; Q6.3/FAN_PWM_L 朝接口。 - `Q10=(98.0,114.5,90°)` 和 `R754~R757` 归到 U20 上方的 TACH_OUT 整形块; Q10.3/FAN_TACH_OUT 朝南对着 U20。 - D2/R747/R748/R753 为新的两个小信号块让位,R660/R661 移到 U20 ADC 附近。 ### 32.4 电源输入链按用户截图定稿 本节覆盖 §32.2 里 RT602 的旧坐标,也覆盖 §32.3 里 U13 的旧坐标。 客户端实测布局按 16 件整组固化: `J1/F1/Q1/D1/C1/R1/DZ1/C4/C5/C6/C2/C3/Rs6/U13/RT602/C11`。 主电流按左→右排成 `J1 → F1 → Q1 → D1/C2/C3 → Rs6`,U13 在 Rs6 上方。 | 器件 | 定稿坐标 / 角度 | |---|---| | J1 / F1 / Q1 | `(20.83,10.79,90)` / `(31.08,3.63,0)` / `(37.08,6.63,0)` | | C2 / C3 | `(68.12,4.30,270)` / `(68.12,13.19,90)` | | Rs6 / U13 | `(75.99,8.74,90)` / `(76.71,16.89,180)` | | RT602 | `(32.07,9.16,0)`,位于 F1/Q1 热点中间 | U13 的 8/9/10 脚在 `y=14.78`,与 Rs6 的 `y=5.68/11.81` 两端实行独立 Kelvin 引线。 U13 本体向北越过 D± 预留通道的南界约 0.8 mm,必须在新路由器中作为固定障碍, 不得继续把该处当成全宽空通道。 ### 32.5 LIVE 布局快照成为当前唯一位置基线 `place_base.py --adopt-live --verify` 已从 EasyEDA 读取当前 `BASE-PCB` 的全部 138 件, 将 x/y/角度/层写入 `.claude/r2/_base_place_live.json`。只要该文件存在, `place_base.plan()` 就以它为最高优先级,跳过旧的镜像排布、0.25 mm 吸附和自动翻转。 验收为 138 件逐件读回一致,全部布局几何检查通过。 D2 及 R748/R753/R755/R757 随接口重排让位,不再夹在 J33 与 U20 之间。 --- ## 33. M12:底板布线逻辑迁移与预检(2026-09-10) M10 旋转插槽后,旧路由器不是单纯左右镜像:D± 从插槽北排换到南排, 物理槽位也从南→北 `USB1~5` 变为 `USB5~1`。新逻辑因此将「USB 编号」和 「物理槽位」拆成两个概念:`USB1~5 -> J34~J38`,分别使用对应插槽的南侧走廊。 五对下行 D± 不再交给 A* 自由蜕行,而是 U32 西排细线扇出、东侧三条专属车道、 槽端向南逃逸的构造路径。较短线在自己的竖向车道内向外加 45° 微蛇形; 离线结果为五对净距 0 错,对内长差均 0.25 mm,满足 ≤1 mm 规则。 电源面也改为按实测针排分段:12V 使用 14 mm 西侧干道和每槽四块「宽帽 + 窄指」, 覆盖 25/25 只槽电源脚且不压 GND/外壳盘;3V3 修正上下排的 NC 边界,覆盖 15/15。 `VIN_SW` 铜面不再把 U13.10 Kelvin 监测脚当主电流脚;强制断面为 `VIN_SW 12.17 mm` / `+12V 14.00 mm`,均过线。 路由缓存增加 schema + 插槽方向 + USB 映射校验,任一条不同即重算; 只要仍有未布通记录,`--push` 就拒绝写板。 ⚠️ **当前仍未完成全板路由**:完整试算两轮为 105 / 104 个未完成连接, 优先级重排几乎无改善,证明是东侧密脚区的出线容量问题。`R610` / `R722` 恰好堵住 U32→U20 的 USB6 通道,已规划移到 `(78,109.5)` / `(78,111)` 并通过布局自检; 但 EasyEDA 窗口断开导致定点下发 HTTP 500,板端尚未移动。重连后要先下发这两件、 重抓 `_base_pads.json`,再重跑完整路由 / 连通性 / DRC。 --- ## 34. 刀片压到 90 × 68(2026-09-11 用户拍板) **用户要求**:刀片 98×76 → **90×68**。先做可行性核账(几何两个方向都放得下, 真正要取舍的只有 C60 和功率列宽度),两处交用户拍板: **手机上移、C60 留在两槽之间**;**删掉 J2**。 ### 34.1 几何(事实来源 `pcb_blade.py`,与手机绑定的一律从 `PHONE_ORG` 推) | 项 | 旧(M7) | 新 | |---|---|---| | 板框 | 98 × 76 | **90 × 68**,四角 R2,一条闭合折线(读回 54 点、外接 0~90 × 0~68)| | 手机原点 | (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.8~76 × y 20.7~40);`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.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 44~45.4,y 4~35.7)并排只剩 ~1 mm, ⇒ **y 13~35.7 东西向两层都过不去**,左下角 U4 去东边的网只能爬到手机底下横过去。服务器定点补线(`MODE=repair`)也接不上。 **铺铜够不着的 27 个 GND 焊盘**(DRC 连接性原文):J4(BM24 0.35 节距)1/2/8/12/16/19/23/24/29/37/41/47 + 大地盘; U2 1/16/21(EP);U3 1/2/7;U1 2/3;U4 20/21;Q4.2、K4.1、C13.2;一个 GND 孔。 刀片布线器一直 `SKIP = ('GND',)` 靠铺铜,而 0.35 / 0.5 节距的盘之间铺铜进不去 —— 要给这些盘各打**引出线 + 过孔下 L2** (U2 的 EP 用盘中孔),流程里还没有这一步(底板 route_base 有「GND 打孔」)。M7 大概率同样存在,只是当时没数连接性。 **收尾时又抓到两个工具毛病**(都已修): - `pcb_route.stitch()` 下发前「删掉板上所有 GND 孔」—— 会连布线器的 23 个地指母线孔一起删(地指下到 L2 的唯一通路)。改成只删不在布线缓存里的。 另:它第一次重写时字符串拼接和 `%` 格式化的优先级写错,下发直接抛异常 —— 而收尾链用 `| tail` 接管道,**退出码被 tail 吃掉,链子没停**, 一路跑到了斜切 / 重载。以后链子一律 `set -o pipefail`。 - `miter.py` 的「只去铜不加铜」只对拐角外侧成立,斜边凹侧会加铜(见其模块头更正):1.19 宽的 +12V 拐角斜切后压上凹侧一个 `$3N30` 孔 (DRC 导线 / 钻孔到过孔 0 mil)。板上那个角已恢复成直角(DRC 间距 7 → 4);脚本加了新斜边的精确净距校核。 ## 35. 主板转 180°、两条排线槽到顶部、U4 到右侧(2026-09-11 晚 用户拍板) **用户**:「重新优化刀片板布局」→「将排线插槽和排线移到顶部,主板不旋转」。核账:**电池排线 38 mm 够不到顶边** (J600 在 v 4.6,光跨主板就要 40.05 —— R1 §25.16 v3b 早核过同一件事),尾插 55 mm 余约 4 mm。 摆给用户三条路之后,用户改为 **「都挪,主板跟着旋转」**,随后又补一条 **「U4 移到右侧」**。板框仍是 90 × 68。 ### 35.1 几何(事实来源 `pcb_blade.py`:`PHONE_ROT = 180` + `phone_xy(u, v)` 唯一实现旋转) | 项 | §34(90×68 第一版)| 新 | |---|---|---| | 主板 | 接口边朝下,原点 (1.5, 22.34) | **转 180°,接口边朝上**;投影 x 1.5~68.59 / **y 11.0~55.66**(远端边贴金手指区上沿)| | 服务带 | 底部 11.34(金手指区之上)| **顶部 12.34**(接口边 55.66 → 板顶 68)| | 两条槽 | y 18.14~21.14 | **y 56.86~59.86**;尾插槽 x 5.01~25.01(左)、电池槽 x 38.82~50.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 | 左下 | **右上** (64~67, 49~52),紧挨功率列 | ⚠ 机械上要确认: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 26~89.5 / y 38~56.3,加两个上叶夹着电池槽(C60 / Rs1·U3),U 形单环。 - `+12V` 岛:**x 27~84 / y 9~20**,金手指 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.9~22.9, 13.4~29.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`,每轮 ~15~25 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 100~400 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.5~27.8 / y 0.5~97.5 的一整块**,把整个 A6 区的 L1 占死 ⇒ 过孔上得去但走不动,那一带等于**单层**,而 L4 早被风扇驱动那一窝件占满。 于是「几何上放得下」≠「线接得上」:按用户先选的「两只座都南移进走廊」, **扫了 800 个候选落位**(`fan_scan.py`,PyPy 上单轮补线 ~1.2 s)、压线宽、拆线重布、 修了通孔盘放大量,**始终有 3~4 条布不通**。 **解法**:给 `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-0~7 / GND-L3-0~7,L2/L3 各 13 → 5;L1 55 / L4 66 一块没少),线 / 孔 / 弧 / 填充 / 164 件位姿全同 —— 也就是说**内层地平面被删掉一多半,而 DRC / board_check 都不会直接指出来**(一个不读铺铜,一个把它算成「靠铜面成网」)。 同时 USB2 差分对有 5 段直角改成了 45° 斜切(三个角),四层精确净距重算 0 条 ⇒ 改好不是改坏,**保留**。 ⇒ 只 `pour_base --push` 重建 147 块 / 填 135(L2、L3 各回 13),重铺前后线 0 变、孔 0 变、元件位姿 0 变; 恢复前存档 `_base_board_before_repour_0912.json`,此后基准 `_base_board_d16_restored_0912.json`。 **教训:交接 / 收尾前按快照逐项比,铺铜要按「层 + 网 + 名字」逐块比,光看总块数看不出内层被删。** ## 38. 底板风扇窗口按用户新布局重布 + L1 走廊重开(2026-09-12 用户要求) 用户:「将底板按照现在我的布局重新布线」→ 选「**风扇窗口整体重布**(拆掉自己手布的 43 段重来)」+「GND 回流孔一起补」。 ### 38.1 ⛔ 走廊是跟着**摆位**走的,摆位一变走廊就作废 §37.3 给 `FAN_PWM_L` 开 L1 走廊解决了「A6 是单层布线区」,后来又按当时的摆位加了三条 (`FAN_TACH_OUT` 贴东缘竖带 / `FAN_EN` / `FAN_PWM` 短横带)。这一轮发现: **用户重摆之后,那四条走廊注释里写的坐标全是旧的** —— `R748.1` 从 (18.2,91.0) 跑到 **(5.13,73.91)**、 `R757.2` 从 (27.2,93.0) 跑到 **(18.11,83.57)**。走廊还在原地,等于没开 ⇒ 四条长途网(`FAN_EN` / 两路 `TACH` / `FAN_PWM_L`)必然布不通,**与布线器参数无关**。 ⇒ 走廊必须**和摆位一起维护**。为此把走廊做成可配置(`_base_window.json` 的 `pd_l1_extra`, `repair_window.py` 运行时替换 `B.PD_L1` 里的 `FAN_*`),服务器单轮 1.5 s,试一组不用改源码; 定稿后再固化回 `pcb_base.PD_L1`。 ### 38.2 走廊必须**盖住焊盘正上方**,不能只盖沿途 只盖沿途的话,那只脚得先在 L4 挪到走廊下方才打得了孔 —— 实测 `J27.4` / `Q10.3` 就是这么卡住的: | 版本 | 走廊 | 未完成 | |---|---|---| | 无走廊(旧的四条按旧摆位) | — | 4 | | v1:只盖沿途 | 4 条 | 3(`FAN_EN` 0 段 → 11 段并布通) | | **v2:盖住焊盘(定稿)** | **6 条** | **2** | | v3:把 `FAN_TACH_IN` 竖带再放大 | 6 条 | 2(**换了人**:TACH_IN 通了、`FAN_EN` 掉了) | | v4 = v3 + 把 `FAN_EN` 顶到 priority 最前 | 6 条 | 2(还是换人,总数不变) | ⇒ 再次印证「priority 是按下葫芦浮起瓢」(§36 同结论)。**别再调**。 ### 38.3 定稿的六条走廊与断面账 ``` FAN_EN (12.00, 76.10, 27.50, 77.10) R748.1 西段走 L4、东段借 L1 到窗缘 FAN_TACH_IN (16.00, 75.15, 27.50, 76.05) 主干端点 (26.00,75.62) 在窗缘 FAN_TACH_IN (13.70, 76.05, 16.20, 90.40) 竖带盖住 Q9.3 / R753.2 FAN_TACH_OUT (17.40, 80.70, 27.50, 81.70) 盖住 Q10.3 FAN_TACH_OUT (17.40, 81.70, 18.80, 84.10) 竖段接 R757.2 FAN_PWM_L (10.30, 83.90, 22.50, 87.30) 盖住 J27.4 与 Q6.3 ``` - 判据(§6.4 ≥ 8.0 mm):主块宽 27.30,**逐 y 水平断面**上扣掉走廊的 x 跨度 ⇒ 新工具 `l1_section.py`。 纯几何算 **11.80 mm**;铺铜之后 `pour_base` 的实测断面(还要扣掉线和孔)**9.82 mm**,仍达标。 - **横带很贵、竖带几乎免费**:横带按它的 x 跨度整段扣,竖带只扣 1~3 mm。 - 走廊 x 一律 ≤ 27.5,而槽指头在 x ≥ 27.5 ⇒ **不碰任何一槽的供电路径**。 - 只挡**导线图**,铺铜不用开窗(同 §37.3)。 ### 38.4 「布不通」这次不是拥塞 - L4 沿四条路径**逐 x 扫过纵向空隙:没有一条彻底堵死**(最窄 0.9 mm)。 - L1 上按 0.25 网格泛洪:`J27.4` → 已布 L1 段 **686 个格点可达**;`R753.2` → 窗缘 **757 个可达**。 - 换层孔在 `J27.4` 旁 **0.25 mm** 处就落得下。 ⇒ 三项都排除之后,`FAN_PWM_L: J27.4` 仍 0 段,**剩下的怀疑对象是 A\* 自身**(同 §36 的 `$6N64`)。 ### 38.5 板上结果 拆 43 段 → 补 **139 段 / 7 孔** → GND 回流孔 **10 个** → 缝合孔 **25 个**; 板上 外层 1960 / 内层 116(用户手布,一段没动)/ 过孔 669;铺铜 147 块建齐、填出 132(空的 15 块全是 GND 小瓦片)。 `fan_check` 对**板上真实快照**逐项净距达标(含「新孔 vs 内层线」);669 个孔 vs 新线异网净距 0 处不足。 **遗留**:① `FAN_PWM_L: J27.4` 没接上;② `FAN_EN` / `FAN_TACH_IN` / `FAN_TACH_OUT` 到 U20 的**窗外段** (缺口 15.6 / 17.7 / 16.6 mm,中间是槽体 x 28~70 的手焊 1 mm 针排,按设计不许穿 —— **拆线前也没通**); ③ `DZ3.1`(+12V) 被挪走后离开了原来的换层孔,最近同网铜 9.1 mm(L4 上那一带没有 12V 铜,要靠孔上 L1) —— **拆线前就是这样**,已在本轮顺手补一个 +12V 过孔(落点就在焊盘中心)。 ⚠ 与拆线前逐网对比(同一套并查集判据):`GND` 未接 58 → **48**、`+3V3` 未接 2 → **0**、 两路 `TACH` 未接 2/1 → **0**、`+12V` **一字不差**、`XTAL1/2` 不变(老误报) ⇒ 本轮**没有引入任何新的连通性问题**。 ### 38.6 两条操作上的坑 - **EasyEDA 会合并线段**:拆线点名 43 段、外层实际只少 42(`FAN_PWM` 主干被延长);下发 139 段、 板上净增 142,其中 8 段"按坐标找不到" —— 逐段核过**全部被同网同层铜覆盖,真缺失 0**。 ⇒ 拆 / 发之后要按「几何是否被覆盖」判,不能只按坐标比对。 - **EasyEDA 的 PCB API 回的是 mil**。抓板脚本漏了 ×0.0254 时,连通性判据会把**每一只脚**都报成"未接", 而数值上看着完全正常。 ## 39. 底板位号丝印重排(2026-09-12 用户要求「按当前 EDA 中底板状态定版,优化丝印放置」) 板上布线以**用户自己布好的那一版为准**(定版,不再动铜);这一节只改丝印。 ### 39.1 现状体检 板上 **164 个位号**(`pcb_PrimitiveAttribute`,`key=='Designator'`),字高统一 1.143 mm、 居中对齐、不镜像;顶层丝印(layer 3)10 个、底层(layer 4)153 个可见,`C743` 不可见。 **板上没有任何元件外框丝印**(丝印层 0 线 0 弧)—— 装配时只有位号可依。 | 判据 | 改前 | 改后 | |---|---|---| | 压同面焊盘 | **128** | **4** | | 压过孔 | 48 | 8 | | 越板框(留 0.5) | 8 | 3 | | 位号互相重叠 | 34 对 | **0** | 重排 150 个(理想位 143 / 允许压过孔 4 / 允许压焊盘 3),白名单保留 13 个; 位号离本体中心平均 2.19 mm、最远 6.97 mm(`L4`,本体 15×12.5,位号贴在本体外 0.5 mm)。 ### 39.2 ⛔ 三条判据上的坑 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 mm**(x 27.00~63.00)| 金手指本身跨 33.70(x 28.15~61.85),两侧各余 1.15 | | 台阶高 | **12.0 mm** | 槽体 ~9,余 3 | | 内凹角 | **R1.0** | 外形铣刀下不去直角(嘉立创外形最小 R0.5) | | 切掉 | **648 mm²**(占 10.6%)| 左 27.0×12.0 + 右 27.0×12.0 | 常量在 `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.00、右 x 63.00~68.59,合计 31.09 mm²)。 主板是 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.74~27.16 —— 左半截落在被切掉的板材上(交叠 1.44 mm²)。 已挪到 **(28.50, 8.378)**,`alignMode=3`(LEFT_BOTTOM)下框 x 28.50~29.92, 按「居中」口径算也在舌头内,两种口径都干净。丝印层的**线** 0 段越界。 ⚠ 封装自带的那条 `NOT PCIe - PhoneRail blade`(`fp_edge` 画在金手指封装里, 锚点板坐标 x=28.50 / y=7.20)**读不回来** —— `pcb_PrimitiveString.getAll()` 在 PCB 文档里 不列封装内部图元。按 `alignMode` 默认 3(左下)推算 x 28.50~44.62 落在舌头内; 若是居中则 20.44~36.56 会越界。已用截图实测佐证。 ⇒ **以后改板框(尤其是切掉板材)时,检查清单必须包含丝印与位号**,不能只查铜层。 ### 40.6 顺带补齐:刀片外层铺铜原本整层缺失 抓板发现刀片上只有 **11 块铺铜**(L2 九块 GND + L3 两个岛),而 `plan()` 计划 25 块 —— **L1 七块 + L4 七块 GND 底填全都不在板上**(交接记录写的"铺铜 25/25"与板上不符)。 已重建。台阶改动后每层 GND 由 7 → 9 块。