文件
phonerail/五路直供电源板设计.md
T
zhou yang和Claude Opus 5 2bfe308b30 初始导入:PhoneRail 五路手机直供电源板
原理图/PCB 已在 EasyEDA 里做到 12 页跨页 0 漏接,固件刚完成骨架包 A1。
这次是把已有的一切一次性纳入版本控制,没有改动任何设计内容。

纳入:
- 设计与需求文档、PROGRESS.md、小米8 参考原理图 PDF 与追脚脚本
- .claude/ 下的 EasyEDA 桥接工具链与几何/网表缓存(eda-parts.json、
  pcb-parts.json、pcb-pads.json、p2-ch1.json 等,是重画各页的唯一事实来源)
- 117 张验证截图(本项目所有方向问题都是靠人眼看截图发现的,属于证据不是垃圾)
- firmware/ 的 A1 骨架与 site/ 文档站源码

.gitignore 排除:构建产物(firmware/build、host/build、sdkconfig)、
site/node_modules、__pycache__、桥接日志 _bridge.log、脚本自标的 *.stale。

.gitattributes 默认 `* -text`:现有 .py/.json 大多是 CRLF,原样存,
不让 git 重写行尾。唯一例外是 *.sh 强制 LF —— 带 \r 的 shell 脚本 bash 跑不了。

Co-Authored-By: Claude Opus 5 <[email protected]>
Claude-Session: https://claude.ai/code/session_01QYuExfgyYa6DzRRcUso8M8
2026-09-06 18:18:14 +08:00

6984 行
428 KiB
Markdown
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# 五路手机直供电源板 设计文档
| 项 | 值 |
|---|---|
| 版本 | **v1.6(P1 补完输入侧检流;原理图只剩 P5 线束页)** |
| 日期 | 2026-09-03 |
| 输入 | DC 12V / 10A 适配器 |
| 输出 | 5 路独立,**3.52 ~ 4.01V** 可调,每路 4A |
| 负载 | 小米8(dipper)主板,经原装 BM3E 电池排线的 `P+` / `P−` 供电(§13.5) |
| 控制 | ESP32-S3,I²C 遥测 + 单路硬断电重启 + 开机键模拟 |
**v1.6 相对 v1.5**:P1 补上输入侧 INA226(U13 + Rs6 + C11,§19),地址 0x43。顺带修了 P1 上 `BLD_REF`/`BLD_A` 两个端口靠零长度导线“连着”的真错误。
**v1.5 相对 v1.4**:P2 复制成 P2B~P2E 四页,五路全画完(§16.5)。顺带修了母版上两个真错误:`K1_VUP` 端口靠零长度导线“连着”、两处标签压字。INA226 地址按布线难度重排(§8.2)。
**v1.4 相对 v1.3**:USB 子系统原理图画完(**§18** P4-USB)。五路负载开关的 `ON` 下拉 / `CT` 摆率 / `QOD` 泄放 / `CIN>COUT` 四条按 datasheet(SLVSD76C Rev C)定稿,元件补进 §9.1 BOM。
**v1.3 相对 v1.2**:控制部分原理图画完,拆成 **P3-CONTROL + P3B-EXPAND 两页**(§17)。
复核 **LMR51430**(Vref 0.6V、EN 可直接接 VIN、Y 后缀是 1.1MHz,§9.3)与
**DAC63204**(内部基准 **1.212V** 不是 1.25V → 满量程 2.424V;FBx/CAP/VREF 三条外围硬要求,§4.5)。
定稿 GPIO 分配(§8.1)与 I²C 地址表(§8.2)。调试口改用 **ESP32-S3 原生 USB-Serial-JTAG + USB-C**。
修正全板**位号撞车**:P1/P2 各有一套 R1~R9/C1~C10/Q1,现按页/通道分段(§16.0)。
**v1.2 相对 v1.1**:按 datasheet 复核纠正了四处错误 —— TPS54622 的 **Vref 是 0.6V 不是 0.8V**
(分压重算,§4.3)、eFuse 缓启动 **0.36 V/ms 不是 2 V/ms**(§5)、Buck 高侧限流最坏值
**14A 不是 8A**(§5)、TPS54622 的 **EN 绝对最大 6V**(要分压,§16.2)。
否决「五路 fsw 错开 2%」(§8.4)。**解决 OVP 容差窗口重叠**:R2 5.23k→5.49k、
Rinj 107k→150k,输出上限 4.22V→**4.01V**(§4.3 / §5)。P2-CHANNEL 单路原理图画完(§16)。
**v1.1 相对 v1.0**:**移除原厂电池保护板** —— 电源接到排线的 `P+`/`P−`(保护板输出侧),保护板自动退出通路。保护链四层→三层;eFuse OVP 4.45V→**4.35V**;输出上限 4.22V→**4.15V**,分压改 R2=12.7k / Rinj=192k。元件选型定稿(§9.3),Buck 改 TPS54622(外部补偿)。
**v1.0 相对 v0.3**:所有待选项已定稿(§0.1 决策清单);尾插改为**装原厂小板**;USB 三条对策全部落到硬件;侧键扩到 3 键 ×5 路并改用 74HC595 驱动;GPIO 重新预算;BOM 定稿。
**v0.3 相对 v0.2**:J600 / J601~604 / J1401 引脚定义已从原理图逐脚追踪确认(§13.2 / §13.3 / §13.4);**尾插的 USB 纳入范围**,新增 §13.5「USB 供电与电池直供冲突」及对应的三条对策;BOM 追加 12V 母线泄放器与 VBUS 负载开关。
**v0.2 相对 v0.1**:输出范围 3.6~6.0V → 3.5~4.2V;eFuse OVP 6.3V → 4.45V;适配器 12.5A → 10A;分压/注入电阻重算。
---
## 0. 设计前提与风险声明
**已确认**
- 负载是小米8 主板的电池端子。**保留原装电池排线的 BTB 公座 / NTC / ID,但旁路保护板** —— 电源接在排线的 `P+` / `P−`(保护板输出侧)焊点,电流不经过保护板的串联 MOS。
- 全部 1S 机型。
- **接尾插的 USB**(有线 adb / 刷机),其余功能不用。adb 日常走 WiFi。
- 当前无随机重启 / 信号异常现象。
**由此产生的两条硬约束**
1. **输出上限由 1S 锂电端子的绝对上限决定**(4.45V),而不再由保护板决定。规格定为 **3.52 ~ 4.01V**,上限压低是为了给 eFuse 的 4.36V OVP 留公差余量(§5,v1.2 由 4.15V 再降)。
附带好处:DAC 的所有失效态都落在正常电池电压上(§4.4)。
**代价**:去掉保护板 = 失去一层与本板独立的防线,详见 §5 的取舍说明。
2. **USB 供电会和电池直供打架。** 接上 VBUS 后手机充电器会往我们的 Buck 输出灌电,可能反灌抬高 12V 母线,或把 B+ 顶到保护板 OVP 导致手机掉电。**必须按 §13.5 的三条对策处理,一条都不能省。**
3. **天线馈点在尾插侧。** 既然要接 USB,建议直接装原厂尾插小板(§13.5 方案 A),顺带消除 §13.6 的 WiFi 风险。
### 0.1 决策清单(已定稿,不再讨论)
| # | 决策 | 依据 |
|---|---|---|
| 1 | 输入 12V / 10A 成品适配器 | §1 |
| 2 | 单级同步 Buck ×5,**480 kHz**(R103=100kΩ,CH1 位号),4.7 µH | §3 / §9.2 |
| 3 | 输出 **3.52 ~ 4.01V**,硬件上限 4.01V(最坏 4.12V) | §4 |
| 4 | 调压 = DAC 微调(非全范围),DAC63204 ×2,NVM 默认 3.90V | §4 |
| 5 | eFuse OVP **4.36V**(68.1k/20k)/ 限流 4.45A,每路一颗(**最后一道硬件防线**) | §5 |
| 6 | 电池侧接原厂排线的 **`P+`/`P−`**(保护板输出侧),**保护板旁路**,保留 BTB 座 / NTC / ID | §13.5 |
| 7 | 手机端 2200µF **铝电解**(靠 ESR 阻尼)+ 聚合物 + MLCC | §6.2 |
| 8 | 每路主动放电 MOS + 10Ω,与 eFuse EN 硬件反相联锁 | §7 |
| 9 | **侧键接 3 个**(PWR / VOL+ / VOL−)×5 台 = 15 路 MOS | §13.3 |
| 10 | **尾插装原厂小板**(不自制 BM24 转接板) | §13.5 方案 A |
| 11 | **USB 仅接电脑 / Hub(恒 5V),不接快充充电器** | §15.1 |
| 12 | USB 三条对策全做:软件关充电 + VBUS 负载开关 + 12V 母线泄放 | §15.2 |
| 13 | 15 路按键经 **74HC595 ×2** 驱动,EN / VBUS_EN 保持 GPIO 直连 | §8.1 |
**决策 10 的连带效果**:装了原厂尾插小板,§13.6 的 WiFi 天线风险自动消除(馈点、副麦克风、马达全部原样),该项从「打样前必做的阻塞项」降级为「装机后确认一次」。
**必须记录的失效模式**
- 直供电最致命的失效**不是固件写错电压值**,而是**反馈分压的下电阻开路 → FB = 0V → Buck 满占空比 → 输出直接跳到 12V**。软件对此完全无能为力。§5 第二层就是为它设计的。
- 无电池 = 失去了一个内阻只有几十 mΩ 的缓冲电容。瞬态阻抗设计(§6)比电压精度重要得多,是这类板子的主要故障来源。
---
## 1. 规格锁定
| 参数 | 值 | 说明 |
|---|---|---|
| 输入电压 | 12V ±10% | 成品适配器 |
| 输入电流 | ≤ 8A | 建议 12V / 10A(120W)适配器 |
| 输出路数 | 5,彼此独立 | 独立地线,不共地 |
| 输出电压 | **3.52 ~ 4.01V 连续可调** | 12 位 DAC,步进 ≈ 0.12 mV |
| 硬件电压上限 | **4.01V**(拓扑决定,最坏容差 4.12V) | 见 §4.4,软件越不过去 |
| 输出电流 | 4A / 路(峰值) | 手机常态每路 0.3 ~ 1A |
| 单路峰值功率 | 16.0W | 4.01V × 4A |
| 整板峰值 | 80W | 五路同时满载,实际不会发生 |
| 整板常态 | 10 ~ 25W | 手机挂机功耗 |
| 开关频率 | **480 kHz** | 五路统一,**不错相**(§8.4 已否决) |
| 输出纹波 | < 20 mVpp | 板端测试点 |
| 拓扑 | 单级同步 Buck ×5 | 12V→4.2V 占空比 0.35 |
---
## 2. 系统框图
```
DC12V 插座
│
├─ F1 保险丝 10A
├─ D1 TVS SMBJ13A
├─ Q1 P-MOS 反接保护(理想二极管,Rds < 5mΩ)
├─ C 2×470µF/25V + 4×10µF MLCC
│
└──> 12V 母线 ──┬──────────────── CH1 ────────────────────────┐
│ │
│ ┌────────────────────────────────────────┐ │
├──┤ U1 同步 Buck 480kHz │ │
│ │ L1 4.7µH / Isat 9A │ │
│ │ Cout 2×22µF X7R │ │
│ │ FB ← R1/R2 分压 ← Rinj ← DAC │ │
│ └──────────────┬─────────────────────────┘ │
│ │ │
│ Rs 5mΩ ───┴─── INA226 (I²C, V + I) │
│ │ │
│ eFuse ────┴─── 限流 4.5A / OVP 4.45V │
│ │ EN 通断 / 缓启动 │
│ ├─── Q_dis 放电 MOS + 10Ω │
│ │ (EN 反相硬件联锁) │
│ └──> 端子 ──> 手机1 电池排线 │
│ │
│ Q_key1~3 ──────> 手机1 侧键 PWR/VOL± │
│ (74HC595 驱动,栅极 100k 下拉) │
│ │
├── CH2 ... CH5 同上(布局复制,同频不错相) │
│
├── U_aux 小 Buck 12V→3.3V/500mA ──> ESP32-S3
│
├── U29 母线泄放 TL431+MOS+10Ω/5W(>13.2V 导通)
│ 防 USB 反灌 / 突卸能量抬高母线
│
└── INA226 #6(输入侧 V + I,整板功率预算)
USB 支路(每台一套,与电源支路完全分开走线):
电脑 / USB Hub ──> J12 USB-A ──┬── VBUS ──[U24 负载开关]──> J17.1 ──> 手机尾插小板
├── D− ────(差分对直通,90Ω)───> J17.2
├── D+ ────(差分对直通,90Ω)───> J17.3
└── GND ──────────────────────────> J17.4
↑ ESP32 VBUS_EN,默认断开
手机侧(每台一套,详见 §13):
电源板输出 ──> 原装 BM3E 排线的 B+ / B− 焊点(电芯已移除)
├── 排线自带 NTC / ID / 保护板
└── 原厂 BTB 插回主板电池座
C_damp 2200µF 铝电解 + C_fast + C_hf ← 放在排线端,不是电源板上
Q_key 2N7002 ×3 ──> 主板背面 J601/J602/J603 触点,公共地接 J604
USB 原厂尾插小板(USB-C 母座 + CC + 口温 NTC + 麦克风 + 天线馈点)
```
---
## 3. 单通道功率级计算
条件:Vin = 12V,Vout = 3.5 ~ 4.2V,Iout = 4A,fsw = **480 kHz**(R3 = 100 kΩ,见 §9.2)。
### 3.1 占空比
```
D = Vout / Vin
D_min = 3.5 / 12 = 0.29 → ton = 583 ns
D_max = 4.2 / 12 = 0.35 → ton = 700 ns
```
占空比范围很窄(0.29~0.35),环路增益变化小,补偿比 v0.1 好做。
### 3.2 电感
最坏纹波点在 Vout = 4.2V:
```
L = Vout·(1 − D) / (ΔIL · fsw) = 4.2 × 0.65 / (1.2 × 500k) = 4.55 µH
```
**取标准值 L = 4.7 µH**(与 v0.1 相同,BOM 不变):
```
ΔIL = 4.2 × 0.65 / (4.7µ × 500k) = 1.16 A (29% 纹波)
I_peak = 4 + 1.16/2 = 4.58 A
```
| 电感要求 | 值 |
|---|---|
| 感量 | 4.7 µH ±20% |
| 饱和电流 Isat | ≥ 7 A(含 eFuse 限流点 4.5A 的过冲裕量) |
| 额定电流 Irms | ≥ 5 A |
| DCR | ≤ 15 mΩ(4A 下损耗 240 mW) |
| 类型 | 一体成型屏蔽电感,0630 / 0650 封装 |
### 3.3 输出电容(板端)
板端电容只管纹波与环路,真正的储能在手机侧(§6)。
```
2 × 22µF / 10V X7R 1210 + 100nF 0402
```
X7R 在 4.2V 直流偏置下容量约剩 65%,有效 ≈ 28.6 µF:
```
ΔV = ΔIL / (8 · fsw · C) = 1.16 / (8 × 500k × 28.6µ) = 10 mV
```
加上 ESR 贡献约 3mV,总纹波 ≈ 13 mVpp。
> **环路注意**:手机侧挂着 2200 µF,通过线缆接在输出上。反馈**必须在板端本地取样(local sense),不要做手机端的远端取样(remote sense)**,否则线缆 LC 谐振进入环路,几乎无法补偿。见 §6.2。
### 3.4 输入电容
单路输入 RMS 纹波电流(D = 0.35):
```
Icin_rms = Iout · √(D(1 − D)) = 4 × √(0.35 × 0.65) = 1.91 A
```
| 位置 | 器件 |
|---|---|
| 每路 IC 引脚旁 | 2 × 10µF/25V X7R 1210 + 1µF 0603 + 100nF 0402 |
| 12V 母线共用 | 2 × 470µF/25V 低 ESR 电解 + 4 × 10µF MLCC |
### 3.5 损耗与热
每路满载(4.2V/4A = 16.8W,效率约 93%)损耗 ≈ 1.3W,五路 ≈ 6.5W,加前级约 8W。
- 实际常态(每路 3.9V/0.5A)整板损耗 < 1.5W,**自然对流足够,不需要风扇**。
- 老化测试跑满载时建议加一个 40mm 风扇。
---
## 4. 调压网络与本质安全设计
### 4.1 思路
不用 DAC 做「全范围调压」,而是做「**围绕固定中心点的微调**」:分压电阻把中心点算死在 **3.76V**,DAC 只提供 **±0.24V** 的偏移。这样即使 DAC 输出满摆到任何一端,输出也只能落在 **3.52 ~ 4.01V** 之间——**软件在物理上无法产生规格外的电压**。
### 4.2 电路与公式
```
Vout
│
R1
├────── FB (Vref) Rinj : DAC 注入电阻
R2 Vd : DAC 输出,0 ~ 2.424V
│ (内部 1.212V 基准 × 增益 2 = 2.424V)
GND
DAC ──[1k]──┬──[Rinj]── FB
10nF
│
GND
```
节点方程:
```
Vout = Vref · (1 + R1/R2 + R1/Rinj) − Vd · (R1/Rinj)
```
Vout 与 Vd **反向**:DAC 输出越高,输出电压越低。
### 4.3 电阻取值
**已按 datasheet 复核(SLVSA70F Rev F):TPS54622 的 Vref = 0.6 V ±1%(0.594 / 0.600 / 0.606),
不是 0.8 V。** 因此采用下面这一组:
**2026-09-03 定稿:采用「压低上限」的一组**(§5 第二层容差对策方案 2,用户已拍板)。
| 元件 | 值(1%,0402) | 立创 |
|---|---|---|
| R1 | 30.1 kΩ | C29402 |
| R2 | **5.49 kΩ** | **C407675** |
| Rinj | **150 kΩ** | **C25755** |
```
R1/R2 = 5.4827 R1/Rinj = 0.20067
Vout = 0.6 × (1 + 5.4827 + 0.20067) − 0.20067 · Vd
= 4.010 − 0.2007 · Vd (Vd: 0 ~ 2.424V,范围 3.524 ~ 4.010V)
Vd 的上限是 DAC63204 内部基准 1.212V × 增益 2 = 2.424V(不是 2.5V,见 §4.5)
```
> **为什么不是原来的 5.23k / 107k(上限 4.222V)**:那一组的最坏角落上限 4.34V
> 与 eFuse OVP 的跳闸下沿 4.21V **重叠**,会误跳。改这两个电阻后最坏上限降到
> **4.120V**,与 OVP 下沿让开 86 mV,见 §5 第二层。代价是手机看到的「满电」
> 只有 4.01V(约 85% 电量),对手机农场无影响。
> **Rinj 的实际值是 151 kΩ**:DAC 低通的 1 kΩ(R8)串在这条支路上。
> 折算后 Vout(Vd=0) = 4.009V、斜率 0.1993,与上式差 1 mV,工程上忽略。
> 早期版本写「TPS54622 是 0.8V、采用 49.9k/12.7k/192k」是错的,已作废。
> 首板实测后用 R2 的 E96 相邻值微调;**改 R2 会同时移动上下限,改完必须重算
> §5 第二层的容差窗口**。
### 4.4 失效态验算(本质安全的证明)
按 §4.3 的 Vref = 0.6V 一组,穷举 DAC 与 MCU 的所有失效状态:
| 状态 | Vd | 实际 Vout | 判定 |
|---|---|---|---|
| 正常,目标 3.90V | 0.548 V | 3.900 V | ✅ |
| 上电默认值(NVM 预置 0.548V) | 0.548 V | 3.900 V | ✅ |
| DAC 输出锁死在 0V | 0 V | **4.010 V** | ✅ 正常满电电压,手机继续跑 |
| DAC 输出锁死在满量程 | 2.424 V | **3.524 V** | ✅ 正常,相当于电量偏低 |
| DAC 未供电 / 输出 Hi-Z | — | **3.890 V** | ✅ Rinj 悬空退化成 R1/R2 分压,**正好落在目标值上** |
| I²C 总线挂死 | 保持上次值 | 上次值 | ✅ |
| ESP32 跑飞 / 复位 | 保持上次值 | 上次值 | ✅ |
**结论:DAC 与 MCU 的任何失效,输出都落在正常锂电池工作电压区间内,手机不会掉电,更不会损坏。**
最坏容差角落(Vref ±1% + 三个电阻 ±1% 取最不利组合):
| | 标称 | 最坏 |
|---|---|---|
| 上限(Vd = 0) | 4.010 V | **4.120 V** |
| 下限(Vd = 2.424V) | 3.524 V | **3.422 V** |
> 下限的最坏值 3.422V 已经贴近小米8 的关机门限(≈3.4V)。这只会出现在
> 「DAC 锁死满量程 + 全部容差取最坏」的复合失效下,属于安全侧失效(手机关机,
> 不损坏)。**固件里把 Vd 上限限制在 2.0V(→ 3.61V)即可完全避开**,
> 正常调节根本用不到 2.0V 以上。
>
> 上一版(5.23k/107k)需要固件禁止 Vd < 0.5V 来防 eFuse 误跳,**这条约束现在
> 不需要了** —— Vd=0 只有 4.010V,离 OVP 很远。
这一层防不了的是分压电阻本身失效,由 §5 第二层处理。
### 4.5 DAC 选型
- **TI DAC63204**(4 通道 12 位,I²C,带 NVM 上电默认值)× 2 片 = 8 通道,用 5 路。
- 关键特性是 **NVM 存上电默认值**:烧成 Vd = **0.548V**(对应 3.90V 输出),上电即安全工作,不依赖 ESP32 初始化成功。
即使 NVM 没烧成功(上电默认 0V),输出也只有 4.010V,仍然安全。
- **内部基准 1.212 V**(1.1979 / 1.212 / 1.224,±1%,TC 50 ppm/℃),增益 2× → 满量程 **2.424 V**。
早期文档写「1.25V × 2 = 2.5V」是错的,已按 SLASEX3A §6.8 更正。
- 分辨率:2.424V / 4096 × 0.2007 = **0.12 mV / LSB**(折算到输出)。
- **外围三条硬要求**(datasheet 表 5-1,接错了图上看不出来):
FBx 必须接回 OUTx;CAP 接 ≈1.5 µF(本设计 2.2 µF)到 AGND;
VREF 不用外部基准时要 100 nF 到地 **且**上拉到 VDD。GPIO 不用时也要外接电阻拉到 VDD 或 AGND。
实现见 §17.2。
- DAC 输出到 Rinj 之间加 **1 kΩ + 10 nF** 低通(截止 ≈16 kHz)滤更新毛刺。**这个 RC 必须放在 Rinj 的 DAC 侧,不能挂在 FB 节点上**,否则给环路引入额外极点。
---
## 5. 三层保护链
彼此独立,任何一层单独失效都不会导致手机损坏。
### 第一层:拓扑限幅(§4)
分压网络 + DAC 量程决定输出物理范围 **3.524 ~ 4.010V**(最坏容差 3.422 ~ 4.120V),
全部是正常锂电池电压。
- 防的是:固件 bug、I²C 误码、MCU 跑飞。
- 防不了:分压电阻本身失效。
### 第二层:eFuse 的独立过压断开 ⭐
**全板最关键的一个器件。** 每路输出串一颗带可调 OVP + 可调限流的 eFuse:
| 设定 | 值 | 作用 |
|---|---|---|
| OVP 阈值 | **4.36 V**(68.1k/20k) | 超过即断开负载,2µs。⚠️ 容差窗口很窄,见下 |
| 限流 | **4.45 A**(R_ILIM = 20kΩ) | 恒流限制,不依赖 MCU |
| 缓启动 dV/dt | **0.36 V/ms**(C_dVdT = 33nF) | 抑制 2200µF 的浪涌,涌流 0.80A |
| EN | ESP32 GPIO 直连 | 断电重启的开关 |
| FAULT | ESP32 GPIO 输入 | 上报故障 |
**它防的正是那个致命故障**:R2 开路 → FB = 0 → Buck 满占空比 → 输出冲向 12V → eFuse 在 4.35V 处切断。
**去掉原厂保护板之后,这一层是最后一道硬件防线**,所以要定量确认它来得及。
按 datasheet(SLVSA70F / SLVSCF3A)的**最坏值**而不是典型值:
```
故障电流受 TPS54622 高侧限流约束,datasheet 8 / 11 / 14 A(min/typ/max),取最坏 14 A
手机侧储能 2200 µF
dV/dt = 14 A / 2200 µF = 6.4 mV/µs
4.22V → 4.36V 需要 ≈ 22 µs
TPS25940 的 tOVP(dly) = 2 µs(datasheet 实测值) → 余量约 11 倍
```
**结论:余量仍然充裕,去掉保护板没有实质性提高过压风险。** 另外 eFuse 断开后 2200 µF 仍撑着,手机继续运行、不会掉电——比保护板断开(手机直接掉电)的表现还好。
> 早期版本按「限流 ≈ 8 A、余量 30 倍」估算,用的是 min 而不是 max,已修正为 11 倍。
#### OVP 阈值的容差窗口 —— 已解决(2026-09-03)
P2 画图时算出来的一个**真问题**。原始状况:
```
分压 R109/R110 = 68.1k / 20k(CH1 位号),V(OVPR) = 0.99V(typ) → 标称跳闸 4.361 V
V(OVPR) 范围 0.97 ~ 1.01 V(±2.0%),分压电阻 1% → 分压比 ±2.0%
→ 实际跳闸落在 4.206 ~ 4.519 V
而当时第一层允许的最高输出(Vd=0)标称 4.222 V,最坏 4.34 V
```
两个区间**重叠** → 坏角落下 DAC 失效到 0V 时 eFuse 会误跳。
根因是「最高输出 4.222V ~ 1S 上限 4.45V」只有 5.4% 的窗口,比器件容差还窄。
**对策:把第一层的上限压下去,而不是收紧 OVP。** 已改 §4.3 的两个电阻
(R2 5.23k→**5.49k**,Rinj 107k→**150k**),OVP 分压 68.1k/20k 保持不动:
| | 原(5.23k/107k) | 现(5.49k/150k) |
|---|---|---|
| 第一层最高输出(标称 / 最坏) | 4.222 / **4.34 V** | 4.010 / **4.120 V** |
| eFuse 跳闸区间 | 4.206 ~ 4.519 V | 4.206 ~ 4.519 V(未变) |
| 两者关系 | ❌ **重叠 0.13 V** | ✅ **让开 86 mV(2.1%)** |
另外两个被否掉的方案,留档备查:
- 分压电阻改 0.1%:窗口只收到 4.27 ~ 4.45 V,余量仍很小,且 0.1% 的 0402 全套凑不齐。
- 维持现状 + 固件禁止 Vd < 0.5V:把硬件问题推给固件,违背 §4 的本质安全原则。
**残留**:最坏角落下 eFuse 可能到 **4.519 V** 才跳,超过 1S 绝对上限 4.45 V 约 60 mV。
接受,理由是:输出要跑到 4.5V 必然意味着第一层已失效(R2 开路 → Buck 满占空比),
此时输出以 6.4 mV/µs 冲过这一段只需 ≈10 µs,4.45→4.52 V 的 70 mV 超调持续时间
远短于锂电池的过压损伤时间常数。
#### 其他已复核的 TPS25940A 参数
| 项 | 结论 |
|---|---|
| OVP 检测点 | **监视输入侧**(IN 到 GND 的分压)。本设计 eFuse 输入 = Buck 输出,正合适 |
| ILIM 公式 | `I_LIM(A) = 89 / R_ILIM(kΩ)`,**R_ILIM 合法范围 16.9 ~ 150 kΩ** |
| 限流取值 | R11 = 20 kΩ → 4.45 A(datasheet 表格 4.09/4.45/4.81 A) |
| dV/dt 公式 | `dV/dt = 12 × 1µA / C_dVdT`;总斜坡 `t = 8.3e4 × Vin × C` |
| **缓启动实际值** | C14 = 33 nF → **0.36 V/ms**,斜坡 11.5 ms,涌流 `2200µF × 0.36V/ms = 0.80 A` |
| Rds(on) | 42 mΩ typ(26~64 全温区)→ 4A 时压降 168 mV / 0.67 W |
| 反灌保护 | V(IN)−V(OUT) < −9.3 mV 断开;正向重新导通门限 +100 mV |
| 变体 | **TPS25940A = 热故障自动重试**(L 版是锁存),本设计用 A 版 |
| PGOOD | 开漏,PGTH 门限 0.99V。R16/R17 = 20k/10k → 检测 eFuse 输出 **2.97 V** 以上 |
> ⚠️ **早期版本写「缓启动 dV/dt ≈ 2 V/ms」是错的。** 2 V/ms 对 2200 µF 意味着
> `2200µF × 2V/ms = 4.4 A` 充电电流,直接顶到 4.45 A 限流点,上电会进限流而不是缓启动。
> 33 nF 给出的 0.36 V/ms 才是对的,`.claude/eda-parts.json` 里缓存的选型一直是对的。
> 同理 §7.4 写「EN ↑ 后约 3ms 稳定」也偏乐观:实际是
> `tON(dly) = 100 + 150×33 = 5.1 ms` 延迟 + 11.5 ms 斜坡 ≈ **17 ms**。
选型要求:Vin 覆盖 2.7 ~ 18V、连续电流 ≥ 4.5A、**OVP 行为是「断开」而不是「钳位」**、**OVP 阈值可设到 4.45V 这么低**、带 EN 与 FAULT。TPS25940A 全部满足。
### 第三层:ESP32 软件监控
INA226 读到电压偏离设定值超过 ±100 mV 且持续 50 ms → 拉低该路 EN 并上报。
去掉保护板之后这一层的价值上升了:它是唯一能发现「eFuse 本身失效」的手段。建议把巡检周期从 50 ms 收紧到 **20 ms**。
这一层是**记录与告警**用的,不承担实时保护职责。**不要把过流保护做进 MCU 循环。**
---
## 6. 手机侧储能与阻尼 —— 最容易翻车的地方
> ⚠️ **2026-09-03:这一节的数可能要整体重算。** 用户提出做一块**主板载板**
> (5 块主板固定其上,直接对插到本电源板),回路电感会从 20 cm 线缆的 300 nH
> 掉到板对板的约 50 nH 量级 —— 压降、f_res、Z0、Q 全变(都是往好的方向)。
> 电容组的位置也从「排线端」变成「载板上 P+/P− 焊盘旁」。
> 详见 `PROGRESS.md` 的「⭐⭐ 第二件事:主板载板」。**该方案卡在缺机械数据,尚未定稿。**
### 6.1 问题
锂电池内阻只有几十 mΩ 且贴在手机内部,天然吸收手机的全部瞬态电流。拿掉电芯后:
```
线缆电感(20cm 18AWG 双线)≈ 300 nH
射频发射突发 di/dt ≈ 2 A/µs
瞬时压降 V = L · di/dt = 300n × 2/1µ = 0.6 V
```
手机 VBAT 掉到 3.2V 以下 → 随机重启 / 信号异常 / 摄像头启动失败。**这类故障看起来像「手机自己有问题」,极难排查。**
### 6.2 线缆 LC 谐振(必须阻尼)
手机侧加大电容后,它和线缆电感构成谐振回路:
```
L = 300 nH , C = 2200 µF
f_res = 1 / (2π√(LC)) = 6.2 kHz
Z0 = √(L/C) = 11.7 mΩ
R_cable(18AWG,20cm,往返)≈ 2.6 mΩ
Q = Z0 / R = 11.7 / 2.6 = 4.5 ← 欠阻尼,会振铃
```
**解法:用铝电解的 ESR 做阻尼。** 把 2200 µF 选成**普通铝电解(ESR 40 ~ 100 mΩ)而不是聚合物电容**:
```
Q = 11.7 / (2.6 + 60) = 0.19 ← 过阻尼,干净
```
再并少量低 ESR 电容处理快速瞬态。**这里选错电容类型,板子会「莫名其妙地不稳」。**
### 6.3 手机侧电容组(每路一套,装在电池排线端)
**位号见 §20 的 P5-HARNESS 页**(CH1 为 C801~C806,CH2~CH5 为 C811~C846)。
这些器件**离板**:只画在原理图上,不进 BOM、不上 PCB。
| 位号(CH1) | 器件 | 立创 | 作用 |
|---|---|---|---|
| C801 | **2200µF / 6.3V 普通铝电解**,**SMD 10×10.5**(Rubycon 6.3TPV2200M10X10.5,ESR 60 mΩ@100kHz)| **C3828985** | 主储能 + **阻尼**。2026-09-06 换矮封装(原 C49256788 插件 10×16 作废);6.3V 对 4.2 V 轨够(第一层限幅 4.01 V,§4.3)|
| C802, C803 | 100µF / 6.3V X5R 1206 | C15008 | 中频瞬态 |
| C804, C805 | 22µF / 25V X5R 1206 | C12891 | 高频 |
| C806 | 100nF 0402 | C1525 | 甚高频,紧贴 `P+`/`P−` 焊点 |
> ⚠️ **C801 千万别买成聚合物。** 立创上同尺寸的 `C53446724`(PA10V2200M10X12)
> 是聚合物,ESR 只有 12 mΩ —— 装上去 Q 会从 0.19 回到 4.5,线缆 LC 在 6.2 kHz 上振铃
> (§6.2 的整个阻尼设计就是靠普通铝电解那几十 mΩ 的 ESR)。
> 选型时看描述里有没有「类型:聚合物」。
> **两处与原方案的偏离**(2026-09-03 画 P5 时定的,均待复核):
> ① C802/C803 原写「100µF/6.3V 聚合物」,立创基础库里没有这个规格,
> 改用 100µF/6.3V X5R 1206 MLCC。**3.9V 偏压下每颗只剩约 40 µF**,
> 中频段储能从 200 µF 掉到约 80 µF。要严格照原方案就换真聚合物。
> ② C804/C805 原写「22µF/10V 1210」,改用板上已有料 22µF/**25V** 1206(C12891)。
> 电压档更高 → 偏压衰减更小,等效容量反而更接近标称。
### 6.4 线缆与接地要求
1. **线长 ≤ 20 cm,18AWG 或更粗**,正负双绞或紧贴平行。
2. **每路独立回流地**,五路的地**绝对不要在手机端并成一根**——共地阻抗会让一台手机的射频突发窜到另外四台。
3. 板端出线用 Molex Micro-Fit 3.0(额定 8.5A)或 XT30,不要用杜邦线。
4. **大电容必须在排线端,不是电源板上。** 放在板上等于隔着 300 nH 线缆电感,基本无效。
---
## 7. 断电重启:必须做主动放电
### 7.1 为什么
只拉低 eFuse EN 是**关不掉手机的**:
```
手机侧 2200µF + 手机关机待机电流 ≈ 50 µA
自然放电到安全电压:t ≈ C·ΔV/I = 2200µ × 3.5 / 50µ ≈ 154 秒
```
「断电 10 秒再上电」根本不会触发重启。某些机型还要求 VBAT 掉到 2.5V 以下才算真正断电。
### 7.2 电路
在 eFuse 之后(手机侧)加:
```
Q_dis N-MOS(2N7002 / AO3400)
R_dis 10Ω / 1W / 2512
τ = 2200µF × 10Ω = 22 ms
放到 < 0.5V 约需 5τ ≈ 110 ms
峰值放电电流 = 4.2V / 10Ω = 0.42 A(瞬时 1.76W,占空比极低)
```
### 7.3 硬件联锁(重要)
如果固件同时打开 eFuse 和放电 MOS → 10Ω 上持续 1.76W → 电阻过热。
**用一级反相器把放电 MOS 的栅极接到 eFuse 的 EN 上**(一颗 2N7002 + 100 kΩ 上拉),令两者硬件互斥。好处:物理上不可能同时导通;**省掉 5 个 GPIO**;固件只需控制一根 EN 线。
### 7.4 重启的两级策略
有了开机键模拟(§13.3)之后,重启不必每次都断电:
```
一级(软):长按开机键 10s 强制重启
→ 不断电,闪存和文件系统友好,优先使用
二级(硬):EN ↓ → eFuse 断开,放电 MOS 自动导通
等待 3 ~ 5 s(放电到 <0.5V 只要 ~110ms,其余是等手机彻底断电)
EN ↑ → tON 延迟 5.1ms + 缓启动 0.36V/ms 斜坡 11.5ms ≈ 17ms 后稳定
→ 一级无效时才用
```
---
## 8. ESP32 接口设计
### 8.1 GPIO 分配
扩到 3 键 ×5 台后,直连方案需要 34 ~ 39 根 IO,**超出 ESP32-S3-WROOM-1 的可用数量**。按「安全关键直连、慢速信号扩展」拆分:
| 数量 | 信号 | 方向 | 接法 | 说明 |
|---|---|---|---|---|
| 5 | EFUSE_EN[1:5] | 输出 | **GPIO 直连** | 安全关键,任何情况下都要能关电 |
| 5 | VBUS_EN[1:5] | 输出 | **GPIO 直连** | 安全关键,反灌时要能立刻断 |
| 4 | KEY_SER / SRCLK / RCLK / OE# | 输出 | GPIO 直连 | 驱动 74HC595 ×2 → 15 路按键 |
| 2 | I²C SDA / SCL | 双向 | 4.7 kΩ 上拉 | INA226 ×6 + DAC63204 ×2 + PCA9555 ×1 |
| 1 | IOEXP_INT# | 输入 | GPIO 直连 | PCA9555 中断(汇总 5 路 EFUSE_FAULT) |
| 2 | NTC_ADC ×2 | 输入 | ADC | 电感区 / MOS 区各一 |
| — | UART / USB | — | — | 调试口 |
**合计 19 根**,余量充足(SYNC 若要做,还能再挤出 5 根)。
#### 实际引脚分配(**2026-09-06 按 PCB 几何重排,取代 09-03 那一版**,§26.18)
引脚号是从「板上要去哪儿」倒推的,不是逻辑顺序。除 `USB_DM/DP`(IO19/IO20 是 USB PHY
硬连线)与两路 NTC(要 ADC1 = IO1~IO10)外,全部信号走 **GPIO matrix**,落哪个脚都行。
| 模块脚 | GPIO | 出线方向 | 信号 | 去哪儿 |
|---|---|---|---|---|
| 6 | IO6 | 东 | `EFUSE_EN3` | CH3(东北)|
| 8 | IO15 | 东 | `SCL` | 全板 I²C |
| 9 | IO16 | 东 | `FAN_TACH` | R731/R732(x≈103)|
| 10 | IO17 | 东 | `VBUS_EN5` | J25.5(x≈109)|
| 11 | IO18 | 东 | `FAN_PWM` | R733(x≈98)|
| 12 | IO8 | 东 | `EFUSE_EN5` | CH5(东南)|
| 13 / 14 | IO19 / IO20 | 东 | `USB_DM` / `USB_DP` | J22 —— **硬连线,动不了** |
| 17 | IO9 | 北 | `KEY_RCLK` | U21/U22/U33 |
| 18 | IO10 | 北 | `VBUS_EN2` | J25.14 |
| 19 | IO11 | 北 | `VBUS_EN3` | J25.38 |
| 20 | IO12 | 北 | `KEY_SRCLK` | U21/U22/U33 |
| 21 | IO13 | 北 | `KEY_SER` | U21.14 |
| 22 | IO14 | 北 | `SDA` | 全板 I²C |
| 23 | IO21 | 北 | `KEY_OE#` | U21/U22/U33 + R609 |
| 24 | IO47 | 北 | `UP_VBUS_DET` | J24.25 |
| 25 | IO48 | 北 | `EFUSE_EN2` | CH2(西北)|
| **32** | **IO39** | 西 | `EFUSE_EN1` | CH1(西南)|
| **33** | **IO40** | 西 | `VBUS_EN1` | J24.20 |
| **34** | **IO41** | 西 | `EFUSE_EN4` | CH4 |
| **35** | **IO42** | 西 | `VBUS_EN4` | J24.19 |
| 31 | IO38 | 西 | `IOEXP_INT#` | U23(PCA9555)|
| 38 | IO2 | 西 | `NTC2` | ADC1_CH1,RT602 |
| 39 | IO1 | 西 | `NTC1` | ADC1_CH0,RT601 |
> **IO39~IO42 原来留给引脚 JTAG,2026-09-06 用户拍板改作 GPIO。**
> 调试口本来就走**原生 USB-Serial-JTAG**(IO19/IO20 → J22),出厂 eFuse 默认选的就是它,
> 板上也没有 JTAG 排针。⚠️ **永远别烧 `DIS_USB_JTAG`** —— 烧了引脚和 USB 两边都没有。
> 让出去的是兜底:固件把 IO19/20 改成普通 GPIO、或跑到 USB 外设起不来的地方挂死时,
> 引脚 JTAG 还能进去。IO39~IO42 在 S3 上**不是 strapping**(S3 只有 IO0/IO3/IO45/IO46 是),
> 复位期间高阻输入,配合目的地 100 kΩ 下拉,上电全关的行为一点没变。
**有意不接的引脚**(图上已用文字注明,验证脚本用 `.claude/p3-nets-nc.json` 放行):
| 引脚 | 为什么不用 |
|---|---|
| IO0 / IO3 / IO45 / IO46 | **strapping 脚**,挂负载会影响上电模式 |
| IO35 / IO36 / IO37 | WROOM-1 的 **R8 版(八线 PSRAM)占用**,留空以便换料 |
| **IO4 / IO5 / IO7(脚 4/5/7)** | **重排之后空出来的备用脚,三个都带 ADC1** |
| TXD0(IO43,脚 37)/ RXD0(IO44,脚 36)| 下载走原生 USB,不需要 UART;PCB 上引到测试点 |
**下载 / 调试口用 ESP32-S3 的原生 USB-Serial-JTAG**(IO19/IO20 直连 USB-C 的 D±),
不需要 USB 转串口芯片,也不需要 BOOT / RST 按键(esptool 通过 USB 直接复位进下载模式)。
**USB-C 的 VBUS 故意不接**:板子由 12V 供电,这样从物理上杜绝 USB 反灌到 3V3。
CC1/CC2 各 5.1 kΩ 下拉,对外表现为 UFP。
**按键为什么可以走移位寄存器**:按键是百毫秒级的慢速信号,串行移位的延迟(几十 µs)完全无影响;而 EN 必须在故障瞬间可控,不能依赖串行链路。
> **复位安全(三条都要做)**
> - `EFUSE_EN` / `VBUS_EN` 各加 **100 kΩ 下拉到 GND**:ESP32 复位期间 GPIO 高阻 → 五路输出全关、VBUS 全断。
> - `KEY_OE#` 加 **100 kΩ 上拉到 3.3V**:复位期间 74HC595 输出高阻。
> - 74HC595 每一路输出到按键 MOS 栅极之间加 **100 kΩ 下拉**:高阻时栅极被拉低 → 15 个按键全部不按。
>
> 缺任何一条,都可能在 ESP32 复位的瞬间误按五台手机的电源键。
### 8.2 I²C 设备表
| 器件 | 位号 | 用途 | **地址(2026-09-03 画五路时按布线难度重排)** |
|---|---|---|---|
| INA226 | U8 ~ U12 | CH1~CH5 输出 V + I(5mΩ 分流) | **0x40 / 0x41 / 0x44 / 0x45 / 0x42** |
| INA226 | U13 | 输入侧 V + I(整板功率预算) | **0x43**(A1=GND, A0=SCL) |
| DAC63204 | U6 | VDAC1 / VDAC2 / VDAC3 | **0x4A**(A0 接 SDA) |
| DAC63204 | U7 | VDAC4 / VDAC5 | **0x4B**(A0 接 SCL) |
| PCA9555 | U23 | 5×FLT + 5×PG + BUCK_PG + INA_ALERT | **0x20**(A0=A1=A2=GND) |
| **LM75BD** | **U34(载板)** | 载板温度,风扇闭环用它 | **0x48**(A0=A1=A2=GND)|
> **INA226 地址为什么不是 0x40~0x45 顺排(2026-09-03 改)**:
> INA226 的 A1/A0 各能接 GND / VS / SDA / SCL,但**只用 GND 和 VS 只能凑出 4 个地址**
> (0x40 / 0x41 / 0x44 / 0x45),而全板要 6 个,所以必然有两片得把地址脚搭到 I²C 线上。
> 顺排(0x40~0x44)会让 CH3 接 SDA、CH4 接 SCL,而 P2 上 A0 脚的上下两侧
> 正好夹着 Alert 和 SDA 两根横线,往 SCL 拉必然要跨线。
> 改成下面这样之后,**五个通道里只有 CH5 需要搭 SDA**(走 (690,470)→(690,450)→(700,450),
> 0 交叉),剩下那个 SCL 的落到 U13 头上——它画在 P1 的空白区,布线自由。
>
> | | CH1 | CH2 | CH3 | CH4 | CH5 | U13(输入侧) |
> |---|---|---|---|---|---|---|
> | A1 | GND | GND | **VS** | **VS** | GND | GND |
> | A0 | GND | **VS** | GND | **VS** | **SDA** | **SCL** |
> | 地址 | 0x40 | 0x41 | 0x44 | 0x45 | 0x42 | 0x43 |
>
> 六个地址仍然互不重复,也不与 DAC(0x4A/0x4B)、PCA9555(0x20)冲突。
> **代价:通道号不再等于地址低位,固件里要查表,不能算。**
> **DAC 的 A0 接 SDA/SCL 是 datasheet 明确允许的**(SLASEX3A §7.5.2.2.1:
> A0 可接 VDD / AGND / SDA / SCL,对应地址低三位 001 / 000 / 010 / 011)。
> 这里这么接是因为 A0 引脚夹在 SDA 和 SCL 中间,跳到相邻脚比拉到电源/地干净得多。
> 基址 `1001xxx` 与 INA226 的 `1000xxx`、PCA9555 的 `0100xxx` **不冲突**,已逐个核对。
分流电阻:**5 mΩ / 1% / 2512 / 1W**,Kelvin 四线焊盘。
4A 时压降 20 mV,芯片满量程 81.92 mV,分辨率 2.5 µV → **0.5 mA**。
### 8.3 固件功能(按价值排序)
1. **崩溃检测 + 自动重启(两级)**
`adb connect` 探活失败 N 次,或电流曲线卡死 → 先长按开机键 10s;再失败 → 断电 5s → 上电。
**这是整块板子最核心的价值。**
2. **过流 / 故障事件记录** —— 哪一路、什么时刻、多大电流。排查排线接触不良的唯一线索。
3. **单路电压微调** —— 跑不稳的手机从 3.9V 提到 4.1V,或反向降压降温。
4. **模拟电量曲线**(可选)—— 让手机以为电量在正常变化,避免系统因"电量永远 100%"触发异常逻辑。
5. **温度监控** —— NTC 超阈值先降流、再关路。
6. **整板功率预算** —— 读输入侧 INA226,超过适配器能力时按优先级降载。
**不要做的事**
- 不要让 ESP32 参与过流保护的实时环路(那是 eFuse 的活)。
- 不要提供任何能让输出超过 4.2V 的接口。
- 不要让任一路输出给 ESP32 供电(用独立的 12V→3.3V 小 Buck)。
### 8.4 错相同步 —— 已否决
原计划「五路 RT 电阻取不同值(480/490/500/510/520 kHz)避免拍频」。
**按 datasheet 复核后否决**:TPS54622 在 `Rrt = 100 kΩ` 下的 fsw 是 400 / 480 / 560 kHz(±17%),
器件本身的离散度远大于想刻意制造的 2% 错开,这个做法没有任何效果。
**五路统一 R3 = 100 kΩ(480 kHz)。** 详见 §9.2。
TPS54622 的 RT/CLK 支持外部时钟同步,若首板实测确实存在拍频问题,
再用 ESP32-S3 的 MCPWM 输出 5 路 72° 相移时钟(引脚已预留在 §8.1 的余量里)。
---
## 9. BOM 骨架
### 9.1 主板
| 位号 | 器件 | 数量 | 规格 / 要求 |
|---|---|---|---|
| J1 | DC 输入插座 | 1 | 12V / 10A,或 XT60 |
| F1 | 保险丝 | 1 | 10A 慢断 |
| D1 | TVS | 1 | SMBJ13A(立创 C163651) |
| Q1 | P-MOS 反接保护 | 1 | 30V,Rds(on) < 5 mΩ |
| C_in | 铝电解 | 2 | 470µF / 25V 低 ESR |
| **U1~U5** | **同步 Buck** | **5** | 见 §9.2 |
| L1~L5 | 电感 | 5 | 4.7µH,Isat ≥ 7A,DCR ≤ 15 mΩ |
| — | 输出 MLCC | 10 | 22µF / 10V X7R 1210 |
| — | 输入 MLCC | 10 | 10µF / 25V X7R 1210 |
| R1/R2/Rinj | 分压 + 注入 | 15 | 1% 0402,取值见 §4.3 |
| U6, U7 | DAC63204 | 2 | 4ch 12bit,NVM 默认值 |
| U8~U13 | INA226 | 6 | I²C 电压电流监测 |
| Rs1~Rs6 | 分流电阻 | 6 | 5 mΩ 1% 2512 1W(Rs6 在 P1 的 12V 母线上,量整板输入电流) |
| C11 | U13 的 VS+ 去耦 | 1 | 100 nF 0402(P1 上) |
| U14~U18 | eFuse | 5 | **OVP 可设 4.45V** / 限流 4.5A / EN / FAULT |
| Q_dis1~5 | 放电 N-MOS | 5 | 2N7002 或 AO3400 |
| R_dis1~5 | 放电电阻 | 5 | 10Ω 1W 2512 |
| Q_inv1~5 | 反相器 MOS | 5 | 2N7002(EN 联锁) |
| Q_key1~15 | 按键 MOS | 15 | 2N7002(3 键 × 5 台,§13.3) |
| R_kg1~15 | 栅极串阻 | 15 | 1 kΩ 0402 |
| R_kp1~15 | 栅极下拉 | 15 | 100 kΩ 0402 |
| U19 | 辅助 Buck | 1 | LMR51430**Y**DDCR,12V→3.315V / 500mA,**1.1 MHz**(§9.3) |
| U20 | ESP32-S3 模组 | 1 | WROOM-1 |
| **U21, U22** | **74HC595** | **2** | 串行驱动 15 路按键,`OE#` 上拉到 3.3V |
| **U23** | **PCA9555** | **1** | I²C 输入扩展,汇总 5 路 EFUSE_FAULT + 备用 |
| **U24~U28** | **VBUS 负载开关** | **5** | **TPS22918DBVR**(C131941),1~5.5V / 2A / Ron 52 mΩ(§18) |
| **U29** | **母线泄放** | **1** | TL431 + N-MOS(30V/5A) + 10Ω/5W,13.2V 导通(§15.2) |
| J2~J6 | 电源输出连接器 | 5 | Micro-Fit 3.0 双针,8.5A |
| J7~J11 | 按键连接器 | 5 | **4 针** 1.25mm(PWR / VOL+ / VOL− / GND) |
| ~~J12~J16~~ | ~~USB 上游口 ×5~~ | — | **2026-09-03 删除**:改板载 Hub 后外部只剩一根线(§15.1) |
| **U32** | **USB 2.0 7 口 Hub** | **1** | **USB2517I-JZX**(C478081,QFN-64)。配置见 **§21** |
| **Y1** | **晶振** | **1** | 24 MHz ±10ppm CL=9pF(C2762192)+ 2×12pF C0G(C1547) |
| **R708** | **RBIAS** | **1** | **12.0 kΩ ±1%**(C25752)→ GND,datasheet 硬性要求 |
| **J23** | **Hub 上游口** | **1** | TYPE-C-31-M-12(C165948,与 J22 同料),UFP;R717/R718 各 5.1kΩ 下拉 |
| **U30** | **第二路辅助 Buck** | **1** | LMR51430YDDCR(C5210749,与 U19 同料),12V→**4.98V**,见 §9.4 |
| **L3** | **5V 轨电感** | **1** | SPM6530T-4R7M(C76857,**与 L1~L5 同料**) |
| **R706 / R707** | **5V 反馈分压** | **2** | 100 kΩ(C25741)/ **13.7 kΩ**(C25854) |
| **U31** | **Hub 专用 LDO** | **1** | AMS1117-3.3(C6186,SOT-223),5V→3.3V,见 §9.5。**PCB 上要铺铜散热** |
| **J17~J21** | **USB 下游口** | **5** | **A1251WV-S-4P**(C225106,与 J7~J11 同料),VBUS / D− / D+ / GND |
| R701~R705 | VBUS_EN 下拉 | 5 | **100 kΩ 0402 → GND**,datasheet 明令 ON 脚不得悬空(§18.2) |
| C701~C705 | 负载开关 CIN | 5 | 2.2 µF / 50V 0805(C377773),**必须 > COUT**(§18.2) |
| C711~C715 | 负载开关 COUT | 5 | 100 nF 0402 |
| C721~C725 | 负载开关 CT | 5 | **100 pF C0G / 50V 0402**(C1546),设摆率 tR ≈ 425 µs |
| RT601, RT602 | 热敏电阻 | 2 | **10 kΩ B=3380**(NCP18XH103F03RB,C13564);原写 B=3950,改用立创基础库常备的 B3380,只是固件查表不同 |
| **J22** | **USB-C 母座** | **1** | TYPE-C-31-M-12(C165948),**只用于 ESP32 下载 / 调试,VBUS 不接** |
| R602, R603 | CC 下拉 | 2 | 5.1 kΩ 0402(C25905),USB-C 作 UFP 必需 |
| R601 | ESP32 EN 上拉 | 1 | 10 kΩ;配 C603 100nF 做上电复位 |
| R604, R605 | I²C 上拉 | 2 | 4.7 kΩ → +3V3 |
| R606, R607 | 开漏上拉 | 2 | 47 kΩ;BUCK_PG / INA_ALERT |
| R608 | 开漏上拉 | 1 | 10 kΩ;PCA9555 的 INT# |
| R609 | KEY_OE# 上拉 | 1 | **100 kΩ → +3V3**,ESP32 复位期间 15 路按键输出高阻 |
| R614, R616 | DAC VREF 上拉 | 2 | 10 kΩ → VDD(不用外部基准时 datasheet 要求) |
| R615, R617 | DAC GPIO 下拉 | 2 | 10 kΩ → AGND(GPIO 不用时 datasheet 要求外接电阻) |
| R618, R619 | NTC 分压 | 2 | 10 kΩ → +3V3 |
| C601 | ESP32 储能 | 1 | 22 µF 1206 |
| C608, C611 | DAC CAP 旁路 | 2 | **2.2 µF**(内部 LDO,datasheet 要 0.5~15 µF) |
| C609, C612 | DAC VREF 旁路 | 2 | 100 nF |
| C602~C607, C610, C613, C614 | 去耦 / 滤波 | 9 | 100 nF 0402 |
### 9.2 Buck 主控:TPS54622 已定稿并复核
选型已定:**TI TPS54622RHLR**(VQFN-14,4.5–17V 输入 / 6A)。
下面全部按 datasheet **SLVSA70F** 核过,不再是估值。
| 参数 | datasheet 值 | 本设计取值 |
|---|---|---|
| Vref | **0.6 V ±1%**(0.594/0.600/0.606) | 决定 §4.3 的 30.1k/5.49k/150k |
| 开关频率 | `Rrt(kΩ) = 48000 × fsw(kHz)^−0.997 − 2` | **R3 = 100 kΩ → 480 kHz**(datasheet 表格直接给出 400/480/560) |
| EN 绝对最大 | **6 V** ⚠️ 不能直接接 +12V | R4/R5 = 68.1k / 10k 分压 |
| EN 门限 | 上升 1.21V / 下降 1.17V,Ip 1.15µA / Ih 3.3µA | 起动 9.37 V,关断 8.84 V |
| 高侧限流 | **8 / 11 / 14 A** | §5 的故障 dV/dt 按 14A 算 |
| 误差放大器 gm | 1300 µS | 补偿计算用 |
| COMP→电流 gm | 16 A/V | 同上 |
| 慢启动 | Iss = 2.3 µA,`tss = Css·Vref/Iss` | C9 = 10 nF → 2.6 ms |
| PWRGD | 开漏,门限 ±(94~106)% Vref | 五路线或到一根 `BUCK_PG` |
| 补偿 | **外部补偿**(COMP 引脚,跨导型) | 见下 |
#### 环路补偿取值(Type II)
按 datasheet §8.2.2.10 的公式,取板端本地陶瓷电容(2×22µF,4.2V 直流偏置后 ≈ 28.6 µF):
```
fpmod = Iout/(2π·Vout·Cout) = 4/(2π×3.9×28.6µ) = 5.7 kHz
fco2 = √(fpmod × fsw/2) = 37 kHz ← 上限
选 fco = 18 kHz(刻意取低,见下)
R4comp = 2π·fco·Vout·Cout /(gm_ea·Vref·gm_ps) = 1.0 kΩ → R6 = 1 kΩ
C4comp = Vout·Cout/(Iout·R4comp) = 28 nF → C10 = 33 nF
C5hf → C11 = 100 pF(可选高频极点)
```
**为什么刻意把穿越频率取到 18 kHz 而不是 37 kHz**:这块板是在**模拟电池**。
手机侧挂着 2200 µF 铝电解(ESR 40~100 mΩ,§6.3),瞬态由它本地吸收,
环路只需要慢慢维持直流点。慢环路对线缆 LC 谐振(6.2 kHz,Q=0.19)也更宽容。
> **打样前仍然要做一次环路实测**:上面的推导假设「线缆电感把手机侧 2200 µF 在
> 几 kHz 以上隔离掉了」。这个假设成立与否只能靠实测。第一版三个补偿位置都留了焊盘。
#### §8.4 错相同步的结论:**不要做**
datasheet 给的 fsw 容差是 `Rrt = 100kΩ → 400 / 480 / 560 kHz`,即 **±17%**。
原计划「五路 RT 取 480/490/500/510/520 kHz 刻意错开 2%」被器件本身的离散度完全淹没,
毫无意义。**五路统一用 100 kΩ**,少一条 BOM 行。
### 9.3 辅助 Buck:LMR51430YDDCR 已复核(SLUSEF4A Rev A)
P1 页上原来标注「Vref / EN 耐压待复核」,2026-09-03 按 datasheet 查清,**结论是不用改**:
| 项 | datasheet | 对本设计的影响 |
|---|---|---|
| **Vref** | **0.6 V**(0.591 / 0.600 / 0.609,±1.5%) | P1 的 R2/R3 = **100k / 22.1k** → Vout = 0.6×(1+4.5249) = **3.315 V** ✅ |
| **EN 绝对最大** | **VIN + 0.3 V**(不是 6V!) | **EN 直接接 +12V 完全合法**,datasheet 引脚说明原文就写 "This pin can be tied to VIN" ✅ |
| EN 门限 | 上升 1.227V / 下降 1.08V(精密 EN) | 想加 UVLO 可以外接分压,本设计不需要 |
| VIN 范围 | 4.5 ~ 36 V(绝对最大 38V) | 12V 输入,余量充足 ✅ |
| VIN UVLO | 上升 3.89~4.5V / 下降 3.35~3.58V | 12V 母线跌到 4.5V 以下才关,不与 §5 的 13V 泄放门限打架 |
| 型号后缀 | **Y = 1.1 MHz**(X 是 500 kHz)、PFM 版 | ⚠️ 之前文档写「500 kHz」是错的,实际 **1.1 MHz** |
| 内部软启动 | 固定 4.0 ms(3.2/4.0/5.4) | 不用外部 SS 元件 |
| 高侧限流 | 3.67 / 4.76 / 6.68 A | 3A 器件带 0.5A 负载,余量巨大 |
| CB 电容 | 0.1 µF / ≥16V | P1 的 C8 = 100nF ✅ |
**电感复核**:L2 = SWPA4030S100MT(10 µH)。在 1.1 MHz / 12V→3.3V 下
`ΔIL = 3.3 × (1−0.275) / (10µH × 1.1MHz) = 0.218 A`,
0.5A 负载时纹波比 44%、峰值 0.61A,远低于 Isat ✅。
(TI 应用例用 6.8µH 是按 3A 满载算的,我们只用 0.5A,10µH 反而更省。)
> ⚠️ **唯一一处偏保守值**:C7(U19 的输入去耦)现在是 **2.2 µF / 50V 0805**,
> 而 datasheet §9.2.2.6 要求「高频去耦 ≥ 4.7 µF」,应用例用 2 × 4.7µF/50V。
> 2.2µF 的 X5R 在 12V 直流偏置下只剩约 1.2 µF。
> **建议改成 10 µF / 50V 0805(C440198,BOM 里已经有)**,或并一颗。
> 不改也能工作(12V 母线上有 2×470µF + 2×10µF 大电容兜底),但要在 PCB 上把
> C7 贴到 VIN/GND 引脚旁边——这条已写进 §10。
### 9.4 第二路辅助 Buck:12V → 5V(2026-09-03 随板载 Hub 新增)
板载 Hub 之后,下行 VBUS 不能再从上游线取(§15.1 边界 2),必须自己发 5V。
| 项 | 取值 | 说明 |
|---|---|---|
| U30 | **LMR51430YDDCR**(C5210749) | **和 U19 同料**,§9.3 的复核结论全部适用(Vref 0.6V、EN 可直接接 VIN、Y 后缀 = 1.1 MHz、内部软启动 4 ms) |
| R706 / R707 | **100 kΩ / 13.7 kΩ**(C25741 / **C25854**) | Vout = 0.6 × (1 + 100/13.7) = **4.98 V** |
| L3 | **SPM6530T-4R7M**(C76857) | **复用 L1~L5 那颗**,不新增 BOM 行 |
| C731, C732 | 10 µF / 50V 0805(C440198)×2 | 输入去耦。**直接按 §9.3 的教训取 ≥4.7 µF**,不重蹈 C7 只放 2.2 µF 的覆辙 |
| C733 | 100 nF(C1525) | CB 自举 |
| C734, C735 | 22 µF / 25V 1206(C12891)×2 | 输出 |
**电感复核**:12V→5V、D = 5/12 = 0.417、f = 1.1 MHz、L = 4.7 µH:
```
ΔIL = Vout × (1−D) / (L × f) = 5 × 0.583 / (4.7µ × 1.1M) = 0.564 A
2 A 负载时峰值 = 2.28 A ≪ Isat 6.2 A ✅ 余量巨大
纹波比 = 0.564 / 2 = 28% ✅ 正常区间
```
**负载预算**(正常态其实很轻):
| 负载 | 正常 | 最坏 |
|---|---|---|
| U31 LDO 输入(给 Hub 3.3V) | ~0.15 A | 0.42 A × 3.3/5 ≈ **0.28 A** |
| 5 路下行 VBUS | **≈ 0**(§15.2 对策 1 关掉充电后手机基本不从 VBUS 取电) | 5 × 0.5 A = **2.5 A**(关充电全部失效,且固件没来得及切) |
| 合计 | **< 0.5 A** | 2.8 A |
最坏工况只在「五路的 input_suspend 同时失效」时出现,而那正是 §15.2 对策 2
(TPS22918 + INA226 监控)要切断的场景。**按 2 A 连续设计,3 A 器件足够。**
### 9.5 Hub 专用 3.3V:U31 AMS1117-3.3
**不能挂 U19 那条 3.3V 轨。** USB2517 满配 5 口高速传输时,全部电源合计约 **420 mA**
(datasheet §8:1 口 230 mA / 4 口 330~420 mA / 7 口 420~460 mA),
而 U19 按 0.5 A 设计、上面已经挂着 ESP32-S3(WiFi 突发 ~350 mA)、两片 DAC、
两片 74HC595、PCA9555 和 6 片 INA226。
| 项 | 取值 | 说明 |
|---|---|---|
| U31 | **AMS1117-3.3**(C6186,SOT-223) | 5V → 3.3V,1 A 档;压差 1.7 V 远大于其 ~1.3 V 的 dropout |
| 耗散 | 0.42 A × 1.7 V ≈ **0.71 W**(最坏) | SOT-223 要铺铜散热,已写进 §10 |
| C736 / C737 | 10 µF 输入 / 22 µF 输出 | AMS1117 要求输出至少 10 µF 才稳 |
> **2026-09-04:U31 已随 Hub 搬到载板**,原理图上画在 **C1-CONN** 页
> (+5V 从排针进来就在那一页),不是 C2-HUB。上面那条「就近 Hub 供电」是
> **PCB 摆位约束**,和原理图分在哪一页无关 —— 布板时 U31 仍必须紧挨 U32。
> 它现在还多带两个负载:U34(LM75BD,约 0.3 mA)和五颗 EDL 模拟开关(µA 级),
> 相对 Hub 的 420 mA 可以忽略。
**顺带的好处**:Hub 的 3.3V 与 ESP32/DAC 那条控制轨**物理隔开**,
而且 U31 就放在 Hub 旁边(§10 的就近供电),480 Mbps 器件的回流不会串到
决定输出电压的 DAC 上去。
---
## 10. PCB 布局要点
### 10.1 叠层与铜厚
**4 层**,**外层 1 oz / 内层 0.5 oz**(嘉立创四层板的标准配置)。
| 层 | 用途 |
|---|---|
| L1 | 功率器件 + 信号(**D± 走这一层,以 L2 为参考面**)|
| L2 | **完整地平面(不许被割断)** |
| L3 | Inner2-PWR:12V 母线灌铜 + 五路输出灌铜 |
| L4 | 控制信号 + ESP32 |
> **2026-09-03 用户拍板:外层从 2 oz 改 1 oz。** 原来定 2 oz 是为了载流,
> 但后来加进来的两样东西和它打架:
> ① **U32 是 0.5 mm 间距的 QFN-64** —— 2 oz 外层最小线宽/间距 0.2 mm 起,扇出很吃力(1 oz 是 0.102 mm);
> ② **90 Ω 差分对的几何随铜厚变**(§15.3)—— 2 oz 下同样的 W/S 只有 83 Ω。
> 而 1 oz 载流本来就够(见下表),代价只是线要宽一点。
#### 载流(IPC-2221 外层,`A=(I/(0.048·ΔT^0.44))^(1/0.725)`,1 oz = 1.37 mil)
| 电流 | 哪里 | ΔT=20 °C 需要 | 本设计给的 | 实际温升 |
|---|---|---|---|---|
| 1.6 A | 每路的 +12V 支路(4 A×4.2 V÷12 V÷0.9)| 0.38 mm | 走灌铜 | — |
| 4 A | VOn / VOn_P 输出 | 1.34 mm | **1.5 mm**(规则 `PWR4A`)| 16.7 °C |
| 4 A | SW 铜箔(§10.2-2)| 1.34 mm | **2.0 mm** | 10.4 °C |
| 8 A | **12V 总干**(J1 → F1 → 体电容 → 五路)| **3.49 mm** | 见下 | — |
> ⚠️ **12V 总干那 8 A 不许当普通走线画。**
> 规则 `PWR12V` 给的默认 2.0 mm 是给**分支**用的 —— 8 A 走 2.0 mm 温升 **35 °C**,不能接受。
> 总干必须走**灌铜**:
> - Inner2-PWR(0.5 oz)上 8 A 要 **≥18 mm 宽**的铜面,或
> - 顶层灌铜 ≥3.5 mm 宽,或两者分流。
>
> 之所以不把 `PWR12V` 的最小值直接设成 3.5 mm:+12V 这个网络上还有一堆
> 进 0402 / SOT-23 焊盘的短支线,最小值卡 3.5 mm 会刷出几百条假 DRC 错误,
> 规则就没人看了。**载流靠灌铜保证,不靠 DRC。**
>
> **同一条道理再走一步(2026-09-03 扇出时):`PWR4A` / `PWR12V` 的最小值
> 从 1.0 mm 再降到 0.3 mm。** 规则是**按网络**生效的,而 `+12V` 上挂着 R104 那种
> 0402 分压抽头 —— 0402 焊盘只有 0.57 × 0.54 mm,**1.0 mm 的线比焊盘还宽**,
> 物理上引不出来。卡 1.0 的实测结果:29 个焊盘扇不出去,硬扇出去的又被判
> 「线宽 11.8 mil,应 ≥ 39.4 mil」。默认值仍是 1.5 / 2.0,交互布线画出来还是宽线。
### 10.2 每路 Buck 的关键回路
1. **热回路(Cin → 上管 → 下管 → GND)面积最小化。** 2 颗 10 µF MLCC 必须**同层紧贴** IC 的 VIN / GND 引脚。这是 EMI 的第一大来源。
2. **SW 节点铜箔面积压到刚好够载流**(约 2 mm 宽)。
3. **FB 走线尽量短,远离 SW 节点。** R1 / R2 紧贴 FB 引脚,Rinj 也放在附近;DAC 长线走 Rinj 另一侧。
4. **INA226 的分流电阻用 Kelvin 四线焊盘**,取样线并行走线,不跨越 SW 或电感。
### 10.2b 8 A 输入链必须挤在 J1 边上(2026-09-03 布线时重排)
`J1 → F1 → Q1 → C2/C3 → Rs6` 这一串**分叉之前全程 8 A**,所以它有多长,
就要多少宽的铜。第一版布局是自动摆的,摊成了 `J1(x5.8) … Rs6(x84.6~90.7)`,
**8 A 要横穿 85 mm**,其中 J1→F1 单独一段就 42 mm。
8 A 在 0.5 oz 内层要 ΔT=20 °C 得 **18 mm 宽**,band B 一共才 36 mm 高,
四条这样的铜面根本排不下。
重排到 J1 右手边的走廊(x 11.5~46 / y 49.5~68.5,栅极网络放 J1 上方的口袋)之后:
| | 之前 | 现在 |
|---|---|---|
| J1 → F1 | 42 mm | **6.9 mm** |
| 8 A 段横跨 | x 5.8 ~ 90.7 | x 12 ~ 40 |
| 分叉点 | x 90.7 | x ≈ 40 |
| 母线最大截面电流 | 全程 8 A | 顶带 ≤ 6.4 A |
**规律:8 A 那一段的长度是布局问题,不是布线问题。** 等到布线时再想办法加宽,
已经晚了 —— 板上没有那么多空间。
### 10.4 平面层的实际划分(2026-09-03 布线时定稿)
§10.1 那张表只写了"L3 = 12V 母线灌铜 + 五路输出灌铜"。真画下来有三处要补:
| 铜面 | 层 | 网络 | 范围(mm)|
|---|---|---|---|
| GND-L2 | L2 | `GND` | 整板,板框内缩 0.5,只挖 ESP32 天线区 |
| VIN-RAW-L3 | L3 | J1 → F1 | x 3~14 / y 45.5~55.5 |
| VIN-FUSED-L3 | L3 | F1 → Q1 | x 14.6~19 / y 49.5~56.5 |
| VIN-SW-L3 | L3 | Q1 → 体电容 → Rs6 上游 | L 形,x 14.4~35 / y 49~66.5 |
| 12V-L3 | L3 | `+12V` | 下带 x14.6~95 y33~48.3 + 中带 x38.5~95 + 顶带全板 y67.5~81.9 |
| VO1~5-L3 | L3 | `VOn` | 每路 30 mm 宽 / y 82.5~99.5 |
| **VO1~5_P-L4** | **L4** | `VOn_P` | 每路 30 mm 宽 / y 110~116.2 + 一条下伸臂到分流电阻 |
**三处补充说明**:
1. **`VOn_P` 铺在 L4 而不是 L3**,与 §10.1"L4 = 控制信号"有出入,是有意的。
L3 在 y>100 那一带已经被 `VOn` 与 eFuse 输出段占住,而且分流电阻 + INA226 +
放电联锁挤在一起,`VOn` / eFuse 输出 / `VOn_P` 三个网络的焊盘在 y 上互相咬合
(eFuse 输出 y95~107.5 与 `VOn_P` y103.9~116 重叠),L3 上切不出干净的分界。
连接器带(y110~116)在 L4 上恰好是空的,而且 L4 是 1 oz —— 4 A 只要 1.34 mm,
给了 30 mm。**控制信号避开这五块条带即可。**
2. **eFuse 输出段(`$2NxxxN` 一类的自动命名网)不铺铜**:它只有 9.5 mm
(U14 → Rs101),走顶层 `PWR4A` 规则的 1.5~2 mm 线就够。
3. **`+12V` 顶带做到 16.5 mm 高(y 67.5~81.9)而不是 18 mm**。18 mm 是 §10.1
算的 8 A 数值,但 8 A 只存在于**分叉点之前**。分叉点在 Rs6 下游 x≈40,
往左只喂 CH1(1.6 A)、往右喂 CH2~CH5(6.4 A),
6.4 A 在 16.5 mm 的 0.5 oz 内层上温升 **14 °C**,够了。
分叉点之前那段 8 A 走的是 band B 的 12V-L3 下带(15 mm 高)与
VIN-SW-L3(17.5 mm 高),且长度都在 10 mm 量级。
**分界线的位置由焊盘边决定,不是取整数**:`+12V` 顶边 81.9 卡在 C102 那排
1210 焊盘的上沿(y80.2~81.7);`VOn` 底边 82.5 是因为 C107 pin1 是 rot90 的 1210,
焊盘跨到 y83.07~84.55 —— 按"元件中心在 y85.4"去算,会把它漏在两块铜面之间的缝里。
**U8~U13 的 Kelvin 脚一律不进铜面。** INA226 是 MSOP-10、0.5 mm 间距,
U13.10 是 VIN+、U13.9 是 VIN−,两脚相距 0.5 mm,任何分界线都塞不进去。
它们走顶层细线,本来也不载流。所以 VIN-SW-L3 右边界停在 x35、
12V-L3 左边界从 x38.5 起,中间 3.5 mm 全让给这几个脚。
**过孔**:0.3 mm 孔 / 0.6 mm 焊盘,单孔约 1~1.5 A,所以**功率网络每个焊盘打 3 个**,
GND 靠地平面 + 散热盘阵列一个就够。出线宽度 1.0 mm ——
不是随手挑的,是 `PWR4A` / `PWR12V` 两条线宽规则的最小值,细过它 DRC 就报线宽违规。
### 10.3 整体
- 五路**完全相同的布局,同方向复制粘贴**。不要镜像或旋转。
- 输出连接器附近留**测试点**:Vout、GND、EN、FAULT。
- **五路输出地在连接器处分开**,只在板内地平面上单点汇合。
- 开机键的两根线(KPDPWR_N / GND)**必须和该路的电源地同源**,走线远离 SW 节点。
- 电感和 IC 下方铺大面积铜箔并打散热过孔阵列(0.3 mm 孔,1 mm 间距)。
- **板框 160 × 125 mm,四角 R5 圆角 + 四个 M3 金属化定位孔(孔 Φ3.2 / 焊盘 Φ6.0,接 GND)。**
定位孔的 Φ6.5 禁布区与顶边的五个 Micro-Fit 是打架的,解法见 `PROGRESS.md`。
- ESP32 模组天线区域下方**禁止铺铜、禁止走线**,模组放板边。
- **辅助 Buck(U19)的 C7 必须紧贴 VIN / GND 引脚**,回路面积最小化。它现在只有
2.2 µF(偏小,见 §9.3),布局补偿的余地更小;SW 走线尽量短、CB 电容贴着 CB/SW 引脚。
---
## 11. 首板上电调试顺序
**严禁第一次上电就接手机。** 按顺序做:
| 步 | 操作 | 通过标准 |
|---|---|---|
| 1 | 不装 U1~U5,只上 12V | 输入电流 < 50 mA,3.3V 正常,ESP32 能启动 |
| 2 | I²C 扫描 | 6 个 INA226 + 2 个 DAC 全部应答 |
| 3 | **断开 eFuse 输出侧**,装 CH1 的 Buck | 空载输出 3.90V ±60 mV(DAC 走 NVM 默认值) |
| 4 | 扫描 DAC 全量程 | 输出扫过 3.52 ~ 4.22V,与 §4.3 公式误差 < 1% |
| 5 | **人为断开 R2**(模拟致命故障) | eFuse 在 4.45V 断开,示波器确认输出侧不超过 4.7V 尖峰 |
| 6 | 电子负载 0→4A 阶跃(带 20 cm 线 + 电容组) | 压降 < 300 mV,**无 6 kHz 振铃**(阻尼验证,§6.2) |
| 7 | 满载 4A 跑 30 分钟 | 电感 / IC 温升 < 40 K |
| 8 | 断电重启时序 | 输出在 200 ms 内跌到 < 0.5V |
| 9 | 五路全装齐,重复 4 ~ 8 | — |
| 10 | **接第一台手机**,先设 3.80V | 正常开机,WiFi adb 可连 |
| 11 | 验证按键模拟(§13.3) | 短按唤醒 / 长按 10s 强制重启 / VOL−+PWR 进 Fastboot 均有效 |
| 12 | **ESP32 复位安全测试** | 手动复位 ESP32,示波器确认五路输出立即关断、15 路按键无一误触发 |
| 13 | **母线泄放测试**(§15.2) | 可调电源把 12V 母线升到 13.5V,泄放应导通并把电压拉回 13.2V 以下 |
| 14 | **USB 反灌测试**(§15.2,关键) | 接 USB 但**不**关充电 → 观察该路 INA226 电流转负、12V 母线上升;确认固件在 200 ms 内断开 VBUS |
| 15 | 关充电后复测 | `input_suspend=1` 后接 USB,该路电流应无反向分量,母线不上升 |
| 16 | 有线 adb / Fastboot | `adb devices` 可见;`fastboot devices` 可见 |
| 17 | 长稳 24h | 无重启、无告警 |
第 5、6 步是这块板子的两个核心验证项,**不要跳过**。
---
## 12. 待确认 / 后续
**已关闭**
- ~~WiFi 天线风险~~ → 决策 10 装原厂尾插小板,风险消除,装机后确认一次即可。
- ~~尾插要不要接~~ → 接,只用 USB(§15)。
- ~~按键接几个~~ → 接 3 个(§13.3)。
- ~~GPIO 够不够~~ → 74HC595 方案,19 根,余量充足(§8.1)。
**仍需在打样前完成(阻塞项)**
- [ ] **排线旁路验证**(§13.7)→ 确认焊在 `P+`/`P−` 而非 `B+`/`B−`,4.40V 不断开。
- [ ] **侧键触点定位**(§13.3)→ 万用表 5 分钟,拍照存档。
- [x] ~~TPS54622 的 Vref 按 datasheet 复核~~ → **已完成,Vref = 0.6V**(§4.3)。
- [x] ~~TPS25940 的 OVP 能否设到 4.35V~~ → **能**,OVP 基准 0.99V、监视输入侧、响应 2µs(§5 第二层)。
但引出了下面这条新的待决项。
- [x] ~~决定 OVP 容差对策~~ → **2026-09-03 用户拍板方案 ②**:R2 5.23k→5.49k、Rinj 107k→150k,
第一层上限压到 4.010V(最坏 4.120V),与 OVP 跳闸下沿 4.206V 让开 86 mV。
OVP 分压 68.1k/20k 不动。已改图(P2 页 R102/R107 换器件,六项验证复跑通过)与 §4.3 / §4.4 / §5。
- [ ] **环路补偿实测**(§9.2)→ 图上按 fco≈18kHz 放了 R106/C110/C111,三个位置都留了焊盘,首板要扫频确认。
- [ ] **量两个新连接器的高度**(§26.16-C,2026-09-06)→ `XT30PW-M`(C53373776) 和
`2510-3A 直针座`(C2803349)。`pcb1_place.H_FP` 里填的 **11.0 / 9.0 是按同系列常规取的
保守估计** —— 器件的 `3D Model Transform` 只给 XY 尺寸,**Z 读不出来**,
而这两个位置的 hmax 都是 12.0,余量只有 1~3 mm。**拿实物量,别信估计值。**
- [ ] **风扇线的装配顺序**(§26.16-C)→ 立式座插口朝上正对载板底面,座+胶壳约 11.5 mm,
13 mm 净空里插拔只剩 1.5 mm ⇒ 必须「先插好五根风扇线,再合上载板」。
外壳方案定下来时确认这个顺序做得到(否则退回弯针座,J26~J30 引脚位置一样,改回来很快)。
- [x] ~~4.7µH / Isat ≥ 7A 电感选型~~ → 用 SPM6530T-4R7M(Isat 6.2A),裕量分析见「已知遗留」。
**新增变更请求(2026-09-03)**
- [ ] **主板载板(第二块 PCB)**:按小米8 主板定位孔做一块载板,固定 5 块主板,
直接对插到本电源板。会改 §6.1~§6.4、§13.3、§15.4,并新增一节讲载板机械与板对板接口。
**头号阻塞项:本项目手上没有小米8 主板的任何机械数据**
(本 PDF 是电气原理图,不含外形 / 定位孔 / 接点坐标 / 元件高度),只能实测。
详见 `PROGRESS.md` 的「⭐⭐ 第二件事」。
- [x] ~~**板载 USB Hub** 的六个待定项~~ → **2026-09-03 全部定了**:
Hub = **USB2517I 单片 7 口**(用户拍板);自供电 5V 轨 = **U30 第二片 LMR51430**(§9.4);
Hub 的 3.3V = **U31 AMS1117-3.3 专供**(§9.5,不能挂 U19);上游口 = **USB-C UFP**(用户拍板);
TPS22918 ×5 **保留**(通断权留在 ESP32 手里);Hub 复位线走 **74HC595 的备用输出**(§21.7);
J17~J21 **仍在下边**(否则 D± 要纵穿功率区,§15.3)。
硬件配置逐条复核见 **§21**。
- [ ] **板载 USB Hub 的落地**:原理图 P4-USB 重画 + 新增 P4B-HUB 页;PCB【C】带重排。
**载板 v2(2026-09-06,元件全到底层 + 穿线槽)引出的**
- [x] ~~穿线槽尺寸实测~~ → **2026-09-06 用户实测:电池排线 8 宽 × 38 长,尾插排线 18 宽 × 55 长**。电池槽 10 × 3.0(接口边外侧);尾插槽 20 × 3.0 **在 J1401 正下方**,J7n 放主板下方远处 v 37,排线沿载板背面走(§25.16 v4,2026-09-06 用户拍板)。
- [ ] **两条排线路径要拿实物试装(v5)**:接口边朝板边,排线从板边翻下、穿槽、在背面往板中心走。尾插 2.86 + 5 + 2.7 + 1.6 + 37.7 ≈ 49.9 / 50(实长 55);电池 ≈ 31.6 / 35(实长 38)。
- [x] ~~电池排线改成直接焊载板~~ → **2026-09-06 已落地**(§13.5 末尾):J8n 直焊座在主板下方远处 v 15,R78n 10k / R79n 68k。还剩 **P+ 左右手性实测**(错了改 `BAND['j8']` 的 rot)和 **排线路径试装**(主板反面 3.0 mm 缝里钻过去)。
- [x] ~~J7n 手性按装法实测~~ → **2026-09-06 复核:不用再量。** 镜像位 2026-09-05 已实测(J1401 靠接口边那一排是奇数排,`fp_bm24.ODD_ROW_TOP=True` 与之一致),
加上 §25.16 补 3 的几何推导(只绕 u 轴弯 ⇒ J7n = J1401 绕 v 轴翻面),底层 rot 0 的回读(pin1/2 端在本体 −u、奇数排在 −v)正好等于「J1401 绕 v 轴翻面」。
装好后做一次两点通断复核:排线两头插好、手机不通电,J7n **pad 52**(本体 +u 端电源触点)对手机屏蔽罩通、**pad 51** 不通;**pad 8** 通(↔ J1401 pin 44 GND)、**pad 7** 不通(↔ pin 43)。
- [x] ~~J8n 的 P+ 在哪一侧~~ → **2026-09-06 用户实测:P+ 在左** ⇒ `BAND['j8']` rot 0 正确,什么都不用改。
- [x] ~~C8n1 卧倒~~ → **2026-09-06 用户拍板换矮封装**:Rubycon 6.3TPV2200M10X10.5(C3828985,SMD 10×10.5,ESR 60 mΩ)。下板在五块罐体投影下仍只能放 ≤1.5 mm 的件(`pcb2-bottom-heights.json`)。
- [ ] **J7n 镜像位实测要按底层装法重做**(§24.3 + §25.16)。
- [ ] `U34` 量的仍是走廊温度(§25.15 那条不变)。
**不阻塞打样,但要定**
- [ ] 主板机械固定方式(建议连中框,见 §13.6)。
- [ ] `input_suspend` 节点在目标 ROM 上的实际路径(§15.2 对策 1)。
---
## 13. 手机侧接口(小米8 / dipper)
### 13.1 连接器定位(已由原理图确认)
依据:`D:\DCDC\小米8原理图\Xiaomi_Mi_8_Schematic.pdf`(44 页,Rev E8,2018-03-23,SDM845 + PMI8998 + PM845 + SMB1355)。
| 接口 | 位号 | 型号 | 图纸页 | 本方案 |
|---|---|---|---|---|
| 电池 BTB | **J600** | Molex **505004-0810**,8 pin + 4 固定脚 | Sheet 25「PMI8998 CHARGE」 | 插原厂 BM3E 排线 |
| 侧键触点 ×4 | **J601~J604** | XM-217-XC-142-SP,各 2 pin | Sheet 28「PMI8998 HAPTICS&SIDEKEY」 | **要用**,见 §13.3 |
| 尾插 / 副板 BTB | **J1401** | Hirose **BM24-50DS/2-0.35V(51)**,50 pin | Sheet 40「LCD&BTB」 | 不接 |
| 屏幕 + 触摸 | J1102 | Hirose BM24-50DP/2-0.35V(51),50 pin | Sheet 40 | 不接 |
### 13.2 电池连接器 J600 引脚定义
**已从原理图逐脚追踪并逐条目视复核。**
| Pin | 网络 | 去向 / 附属元件 |
|---|---|---|
| 1 | **GND** | 直接接地 |
| 2 | **GND** | 接地;经 W606(0Ω)引出 `VBATT_CONN_VSENSE_M` |
| 3 | **BATT_ID** | → PMI8998 pin 119;TP615 测试点;CR605 / CR608 ESD5471Z |
| 4 | **BATT_THERM** | → PMI8998 pin 159;TP0.8mm 测试点;CR606 ESD5471Z;C684(NM) |
| 5 | **NC** | 未连接 |
| 6 | **NC** | 未连接 |
| 7 | **VBATT** | 电池正 |
| 8 | **VBATT** | 电池正;经 W607(0Ω)引出 `VBATT_CONN_VSENSE_P` |
| G1 (GND1) | **GND** | 固定脚,参与导流 |
| G2 (GND2) | **GND** | 固定脚,参与导流 |
| G3 (GND3) | ⚠️ **VBATT** | 固定脚,**不是地** |
| G4 (GND4) | ⚠️ **VBATT** | 固定脚,**不是地**;C691 10µF 去耦 |
> ### ⚠️ 陷阱:GND3 / GND4 这两个固定脚接的是 VBATT,不是地
>
> 原理图符号里它们叫 `GND3` / `GND4`,实际网络是 **VBATT**。按名字假设它们是地并短到地 = **直接短路电池**。
> 全连接器共 4 条正极通路(7、8、G3、G4)和 4 条负极通路(1、2、G1、G2)——0.4mm 间距 BTB 单 pin 载流有限,靠并联凑充电电流,固定脚也被算作载流路径。
> 任何时候在这个座子附近动手(探针、飞线、返修),先记住这条。
**电压采样是在座子处做开尔文取样**:`VBATT_CONN_VSENSE_P/M` 经 W606/W607 从 pin 8 / pin 2 引出,接 PMI8998 的 `VBATT_SNS_P`(147) / `VBATT_SNS_M`(134)。
含义:**手机读到的"电池电压"就是 J600 座子处的电压**,与我们板子到排线之间的线损无关,但**等于我们电源板输出减去线缆压降**。所以 §4 设定的 3.52~4.01V 就是手机看到的值,这也再次说明 §6 的线缆压降必须压住——线损会被手机当成"电池电量在掉"。
**对本方案的三条结论**
1. 直供只需要 VBATT 和 GND,但 **BATT_ID(3) 与 BATT_THERM(4) 是两根独立的实线**,缺任一条手机都可能拒绝开机或拒绝充电。这坐实了「保留原厂排线」是正确路线——排线上的 NTC 和 ID 直接落在这两个脚上。
2. VBATT 与 GND 各有 4 条通路,说明单 pin 载流很有限。**不要试图自制 BTB 转接板只焊一两个脚**。
3. BATT_ID / BATT_THERM 上有 ESD5471Z 保护,说明这两个脚对外暴露、对静电敏感——改造排线时注意防静电。
### 13.3 侧键 J601~J604 引脚定义与模拟电路
四个 2 pin 触点(XM-217-XC-142-SP),**每个连接器的两个 pin 在板内并联**,即每个是一个独立的弹片触点:
| 位号 | 串联电阻 | 网络 | 功能 | 去向 |
|---|---|---|---|---|
| **J601** | R610 1kΩ | `VOL_UP_N` | **音量 +** | PM845 GPIO |
| **J602** | R611 1kΩ | `PM_RESIN_N` | **音量 −** | PM845 `RESIN_N` (pin 129) |
| **J603** | R612 1kΩ | `PHONE_ON_N` | **电源键** | PMI8998 `KPD_PWR_N`(111) **和** PM845 `KPD_PWR_N`(128),两颗 PMIC 并联 |
| **J604** | — | `GND` | **三键公共地** | 直接接地 |
ESD 位:CR607 / CR608 / CR609(ESD5581MXT5G,**NM 未贴**),C686 / C687 100pF。
**按键 = 把 J60x 触点短接到 J604 触点。** 1kΩ 串阻已经在主板上(R610~R612),所以对地短接是安全且唯一正确的方式。
**驱动电路**(每台手机一套,接三个键就是三套):
```
J603 触点(电源键)───────── D
│ Q_key : 2N7002 N-MOS
ESP32 GPIO ──[1 kΩ]───────── G ┤
│ R_pd : 100 kΩ G→S 下拉
J604 触点(公共地)────────── S
```
- 电源板从 `B−` 给手机供地,两边同地,直接用 MOS 对地短接即可,不需要光耦。
- **绝对不要从外部往 J60x 灌电压。**
- 100 kΩ 下拉保证 ESP32 复位期间(GPIO 高阻)不会误按。
- **空闲电压需实测**:原理图上 `PHONE_ON_N` 没有外部上拉,电平由两颗 PMIC 的内部上拉决定。首板时记录实测值作为后续判据(读到稳定高电平即正常;读到 0V 说明认错了触点)。
**接三个键(而不是只接电源键)能换来远程救砖能力**:
| 组合 | 作用 | ESP32 实现 |
|---|---|---|
| J603 长按 ≈10s | 强制重启 | 单路 MOS |
| J603 长按 ≈2s | 开机 | 单路 MOS |
| J603 短按 ≈100ms | 唤醒 / 息屏 | 单路 MOS |
| J602 + J603 同时长按 | 进 Fastboot | 两路 MOS 同时导通 |
| J601 + J603 同时长按 | 进 Recovery | 两路 MOS 同时导通 |
对手机农场来说,**能远程进 Fastboot 意味着刷机失败不用跑到机架前**。每台多两颗 2N7002 和两个 GPIO,很划算。建议 §8.1 的 GPIO 从 5 路 `KEY_PWR` 扩到 15 路(5 台 × 3 键),ESP32-S3 的 IO 还够;不够就把三个键的 MOS 栅极经一片 74HC595 驱动(按键是慢速信号,串行移位完全够用)。
### 13.4 尾插连接器 J1401 引脚定义(Hirose BM24-50DS/2-0.35V,50 pin + 2 固定脚)
图纸 Sheet 40。**这块板上没有 USB-C 母座**——母座、CC、口温 NTC、ESD 全在尾插小板上,本 PDF 只覆盖主板。
#### ⚠️ 又一个同名陷阱:GND2 固定脚是 USB_VBUS
和 J600 的 GND3/GND4 一样,**J1401 符号里叫 `GND2` 的固定脚,实际网络是 `USB_VBUS`**(挂 C1415/C1416/C1417 去耦 + CR1402 ESDA13P70-1U1M TVS)。G1 才是真地。
**整个 USB 的供电就走这一个固定脚**——Hirose 的 holddown 接触面积远大于 0.35mm 信号脚,是刻意这么设计的。
#### 完整引脚表
| Pin | 网络 | | Pin | 网络 |
|---|---|---|---|---|
| 1 | MIC_BIAS1 ※ | | 2 | TUNER_C ※ |
| **3** | **GND** | | 4 | VREG_L19A_3P0 |
| 5 | CDC_MICIN | | 6 | VREG_S4A_1P8 |
| 7 | CDC_MICIP | | 8 | SAR_INT |
| **9** | **GND** | | 10 | SSC_I2C1_SCL |
| 11 | HEADSET_MIC_P_S_FL | | 12 | SSC_I2C1_SDA |
| **13** | **GND** | | 14 | VREG_L16A_2P7 |
| 15 | CDC_HPH_R | | 16 | GRFC8 |
| 17 | CDC_HPH_REF | | 18 | GRFC9 |
| 19 | CDC_HPH_L | | 20 | US_EURO_SEL |
| **21** | **GND** | | 22 | USB_AUDIO_EN1 |
| 23 | HAPTICS_OUT+ | | 24 | DEBUG_UART_TX |
| 25 | HAPTICS_OUT− | | 26 | MBHC |
| **27** | **GND** | | **28** | **GND** |
| 29 | DEBUG_UART_RX | | **30** | **USB_CC1** |
| **31** | **GND** | | **32** | **USB_CC2** |
| 33 | SPKR_OUT_N | | 34 | VREG_BOB |
| 35 | SPKR_OUT_N | | **36** | **GND** |
| 37 | SPKR_OUT_N | | 38 | USB_CONN_THERM |
| 39 | SPKR_SNS_N | | **40** | **GND** |
| 41 | SPKR_SNS_P | | 42 | SPKR_ID |
| 43 | SPKR_OUT_P | | **44** | **GND** |
| 45 | SPKR_OUT_P | | **46** | **USB3_HS_DP** |
| 47 | SPKR_OUT_P | | **48** | **USB3_HS_DM** |
| **49** | **GND** | | **50** | **GND** |
| **G1** | **GND** | | **G2** | ⚠️ **USB_VBUS** |
※ = 由局部连线推得,未逐脚目视复核,用前实测确认。其余为几何追踪 + 目视复核。
**这张表自校验通过**:D+ / D−(46/48)两侧正好是 GND(44、50)做屏蔽;CC1 / CC2(30/32)两侧也是 GND(28、36)。差分对被地包夹是必然的布线约束,能对上说明引脚映射正确。
#### ⚠️⚠️ 编号是「奇偶行」不是「DIP 绕圈」——立创的封装是错的(2026-09-04 画转接板时查清)
BM24 是 2 排 × 25 脚。两种编号方式差别巨大:
| 方式 | 排法 |
|---|---|
| **奇偶行(Hirose 真实编号)** | 1,3,5…49 一排;2,4,6…50 另一排。第 n 脚和第 n+1 脚跨排相邻 |
| DIP 绕圈 | 1…25 一排;26…50 反着排另一排 |
**小米8 图纸用的是奇偶行**,三条独立证据:
1. **符号本身**:J1401 左列画的是 1,3,5…49,右列 2,4,6…50。
2. **差分对被地包夹**:偶数排上 44/46/48/50 = GND / D+ / D− / GND 依次相邻,是教科书式的
USB 走法。按 DIP 绕圈读,D+(46) 两边会变成 45/47(都是 `SPKR_OUT_P`),说不通。
3. **两排分工干净**:奇数排全是音频(MIC / HEADSET / CDC_HPH / HAPTICS,中间夹 GND),
偶数排全是数字与电源(VREG / I²C / UART / CC / USB / GND)。而且 33/35/37 三脚并联
`SPKR_OUT_N`、43/45/47 三脚并联 `SPKR_OUT_P` —— 并联的大电流脚在同一排上连续,
按 DIP 绕圈读则中间会插进 34/36(`VREG_BOB` / GND),不可能。
**而立创的封装 `CONN-SMD_BM24-50DP-2-0.35V51` 用的是 DIP 绕圈**(实测把它放到 PCB 上读焊盘
坐标:1..25 在 y=+34.45 一排自左向右,26..50 在 y=−34.45 一排自右向左)。母座
`BM24-50DS`(C424561)也一样。**照搬它会把 50 个脚全接错。**
还有两处不一致,一并记下:
- 立创**符号**有 54 个脚(50 信号 + 51/52 + 53/54),而 LCSC 参数页写「总PIN数 52P」。
对照 Hirose 规格书的推荐 PCB 图:header(DP) 每端两个大焊盘、receptacle(DS) 每端一个,
所以 **51/52 是同一个电源触点的两个焊盘,53/54 是另一端那个**。DS 封装确实只有 51/52 两个。
- 立创**符号**把 51/52 画在 pin1 那一端,**封装**却把 53/54 放在 pad1 那一端 —— 符号和封装自相矛盾。
> 上面三条证据同时证明了**本节这张引脚表是对的** —— 三个独立角度互相印证。
>
> **封装已经自建完了**(2026-09-04 深夜,改走方案 D 之后):见 **§24**。
> 几何不是按上面那句「按 30/40 脚外推」做的 —— 后来拿到了 Hirose 官方样本,
> **50 芯的 A/B/C 表里就有**(A=12.25 / B=8.40 / C=12.55),不用外推。
> (那句外推公式里的 G/H/D/E 是 **Header(DP)** 那一侧的尺寸,和我们要的 DS 座对不上,已作废。)
>
> G1(GND) / G2(USB_VBUS) 落在哪一端仍然要**用万用表量**
> (量两个电源触点对主板地的电阻,~0 Ω 的那个是 G1)——
> 这一位错了转 180° 就能纠。真正致命的是**另一位**(哪一排是奇数排),见 §24.3。
#### 接 USB 需要的全部脚
| 信号 | 引脚 | 去向 |
|---|---|---|
| VBUS | **G2 固定脚** | → PMI8998 `USB_IN` / SMB1355 |
| D+ | **46** | → SDM845 HS PHY **和** PMI8998 `USB_DP`(163)(BC1.2 检测共用) |
| D− | **48** | → SDM845 HS PHY **和** PMI8998 `USB_DM`(176) |
| CC1 | **30** | → PMI8998 `CC1_ID`(151) |
| CC2 | **32** | → PMI8998 `CC2`(150) |
| 口温 NTC | 38 | → `USB_CONN_THERM`,快充过温保护 |
| GND | G1 + 3/9/13/21/27/31/49/28/36/40/44/50 | |
**Rd 下拉在 PMI8998 内部**(它自带 Type-C 端口控制器),所以自制小板上 CC1/CC2 直连座子即可,不需要外部 5.1k。
### 13.5 接 USB 的两个硬问题(结论已定稿,实现见 §15)
#### 问题一:0.35mm 间距,飞线是不可能的
BM24-50DS 是 0.35mm 间距 50 脚。**不要试图往单个 pin 上焊线**,做不到,也会毁掉座子。三个可行方案:
| 方案 | 做法 | 评价 |
|---|---|---|
| **A. 装原厂尾插小板**(推荐) | 整块装上,一根 FPC 插上 | USB-C 母座、CC、ESD、**口温 NTC**、麦克风、天线馈点全在上面,零风险 |
| B. 买"小米8 尾插排线"配件 | 只用它的 USB-C 母座那一段 | 便宜,但要自己确认排线上有没有 NTC |
| C. 自制小板 | 买 Hirose **BM24-50DP**(对插公座)焊到自制板,再引 USB-C | 唯一可靠的自制路线;**必须补一个 10kΩ NTC 到 pin 38**,否则手机可能报口温异常、拒绝快充 |
既然你已经决定不要尾插的其他功能,**方案 A 仍然是成本最低的**——那块小板本身就是块 FPC,占不了地方,还顺带把 §13.6 的 WiFi 天线风险一并消除了。
#### 方案演变(2026-09-04 一天之内改了三次,**最终是方案 D**)
| 时间 | 方案 | 为什么被推翻 |
|---|---|---|
| 白天 | **C** 自制 BM24 转接小板 | 要打样 0.35 mm + 钢网 + 回流;立创封装编号还是错的 |
| 当晚 | **A** 装原厂尾插小板 + USB-A转C 线改端子 | 体积大;USB 链路里多一层 USB-C 插拔 |
| 当晚更晚 | **D** ⭐ **原厂主板-尾插排线 + 载板上一颗同型号 BM24 座** | **定稿** |
#### ⭐ 方案 D(最终定稿):原厂排线直连载板
```
手机主板 J1401(BM24-50DS)
│
└── 原厂「主板→尾插」排线(两端 BM24 公头,用户实物见 2026-09-04 照片)
│
└── 载板上的 BM24-50DS 座(J71~J75,每台一颗)
│
└── 载板上就地做 Rp / 口温 / ESD / 去耦 → USB Hub
```
**为什么它比 A 和 C 都好**:
| | A 原厂尾插小板 | **D(定稿)** | C 自制转接板 |
|---|---|---|---|
| 自制 0.35 mm 板 | 否 | **否**(排线是原厂件)| 是 |
| 电路在哪 | 都在原厂件上 | **全在载板上,阻值随便改** | 在小板上,难返修 |
| 插拔点 | J1401 + USB-C | **J1401 + 载板座,各一次** | J1401 + 1.25mm |
| 体积 | 多一块小板 + 一根 USB 线 | **最紧凑** | 中 |
| 载板改动 | 无 | J17~J21 换成 BM24 座 + 每路 4 个件 | 无 |
**天线/麦克风怎么办**(2026-09-04 用户拍板):
> 「wifi 和蜂窝天线我直接买另外的插在主板上,麦克风振动马达不需要,只要能开机正常运行系统就行」
所以 **§13.6 那条「WiFi 馈点可能在尾插侧」的致命项不再成立** —— 用户自己配天线。
副麦克风、震动马达、扬声器一律不要。
#### ⚠️⚠️ 方案 D 的唯一硬前提:排线两端的引脚映射必须实测
我们只有主板图纸(§13.4 的 J1401 表),**没有尾插小板图纸**,
所以排线是 1:1 直通还是翻转的(pin n ↔ 51−n / 奇偶排对调)**不知道**。
好消息是这**只影响封装,不影响原理图**:
- **原理图按 §13.4 的 Hirose 编号画**(D+ = 46、D− = 48、CC1 = 30、口温 = 38、
地 = 3/9/13/21/27/28/31/36/40/44/49/50、两个电源触点 = G1(GND)/G2(VBUS))——
这一层无论排线怎么翻都是对的。
- **翻转与否被吸收进封装**:立创的 BM24 封装本来就是 DIP 绕圈编号、和 Hirose 对不上
(§13.4 末尾),所以**这颗座子无论如何都要自建封装**。
自建时把「焊盘号 = 经排线看过去的 Hirose 脚号」定死即可。
> ⚠️ **2026-09-04 深夜更正**:上一句原来写的是「两种候选正好差一个 180° 旋转,
> PCB 上转一下贴片方向就能切换」—— **这句是错的,候选有四个不是两个**。
> 四个候选 = 2(1 脚在左端还是右端)× 2(奇数脚在上排还是下排);
> 180° 旋转只在其中**两两之间**换,剩下那一位是**镜像**,转贴片方向换不掉,
> 错了就是重打载板。详见 **§24.3**。
#### ✅ 2026-09-04 已实测确认的三件事
用户拿到实物后确认:
| # | 结论 | 影响 |
|---|---|---|
| 1 | **主板上有两个对插的小圆孔(射频座)** | 天线可以直接插主板 → **§13.6 的致命项彻底解除** |
| 2 | **尾插小板上的 BTB 是母座** | 载板放 **`C424561` BM24-50DS** 是对的,不用改;也说明排线两端都是**公头**,和主板 J1401 是 DS 自洽 |
| 3 | **排线是 1:1 直通** —— 上方内侧↔下方内侧依次通、上方外侧↔下方外侧依次通 | 见下,**这条最值钱** |
##### 排线 1:1 直通意味着什么
**载板那颗座子就是 J1401 的电学克隆**(同型号 DS + 直通排线 + 两端同为公头)。所以:
> **原理图按 §13.4 的 Hirose 编号画就是对的,一行都不用改。**
翻转问题被降级成纯粹的**封装 / 贴片方向**问题:我们的座子在排线的另一端,
相对 J1401 天然转了 180°,引脚号会变成 **N ↔ 51−N**(两个电源触点也跟着对调)。
这个由自建封装的焊盘编号吸收,或者贴片时转 180° —— **网表不动**。
##### ⭐ 引脚映射已经推导完了(2026-09-04)
用户实测的原话:**「从左到右,上下内侧一一导通,上下外侧一一导通」**——
也就是排线在摊平的那个平面里是**恒等映射**(不换排、不倒序)。
照片又确认**两个公头在同一面、相差 180°**(各自的软板出线方向相对)。
于是在各自的本体坐标里:
```
公头A(某排, 第 m 个) ↔ 公头B(同一排, 第 26−m 个) ← 排不变、序号反过来
```
母座与插上去的公头引脚一一重合(pin1 对 pin1),这条关系原样传给两个母座:
> **J1401 的第 (排, m) 脚 ↔ 载板座子的第 (同排, 26−m) 脚**
再套 §13.4 已经证明的奇偶排编号(1,3,5…49 一排 / 2,4,6…50 另一排):
| J1401 脚号 | → 载板座子脚号 |
|---|---|
| **奇数 N** | **50 − N** |
| **偶数 N** | **52 − N** |
自检:1→49、2→50、49→1、50→2,**奇偶不变**(排没换)✔
**关键网络的落点**(已写进 `.claude/c5_j1401.py` 的 `map_pin()`):
| 网络 | J1401 | → 载板座子 |
|---|---|---|
| D+ | 46 | **6** |
| D− | 48 | **4** |
| CC1 | 30 | **22** |
| 口温 | 38 | **14** |
| CC2(必须悬空)| 32 | 20 |
| GND ×12 | 3,9,13,21,27,31,49 / 28,36,40,44,50 | **1,2,8,12,16,19,23,24,29,37,41,47** |
> ⭐ **这条推导不需要知道「哪一排是奇数排」** —— 两边都用 Hirose 脚号表达,
> 那个一直缺的绝对基准在等式两边自己抵消掉了。
**电源触点**:约定符号 `pin51` = Hirose pin1/2 那一端、`pin52` = pin49/50 那一端
(自建封装时按这个编号)。J1401 的 **G1(地) 在它的 pin1/2 端**,
经上面的反序落到我们这颗的 pin49/50 端 → **`52 = GND`、`51 = VBUS`**。
✅ **2026-09-05 实测印证**:用户量到 J1401 **右端的大触点对地导通 = G1**(顶视、接口边朝下),
即 1/2 脚端在右端 ⇒ 左端是 G2(`USB_VBUS`);折叠不翻长轴方向,落到载板这颗的 −X 端,
正是我们封装里 `pin51 = VBUS` 的位置。**两边独立得出同一结论。**(详见 §24.3)
⚠️ 首件仍要用万用表确认,**接反就是 5 V 对地短路**。
##### ⚠️ 同时带出来一条机械硬约束:排线只能走「台阶式下折」
两个公头在**同一面**,意味着装配时两个母座都得**朝上、大致共面**
(手机里主板和尾插小板就是这么摆的)。而我们这边 **J1401 朝天、载板座子也朝天、
载板在手机下面**,所以:
| 走法 | 净旋转 | 公头B 朝向 | 能不能用 |
|---|---|---|---|
| **台阶式下折**(下 90° 再上 90°)| 0° | 仍朝下 | ✅ |
| U 形回折(绕手机边沿兜一圈)| 180° | 翻成朝上 | ❌ 插不进去 |
> **→ 载板上那颗座子必须放在手机轮廓之外、J1401 出线的那一侧,
> 让排线顺着同一个方向下一个台阶。这条要在 PCB 摆位时就定死。**
> **⚠️ 2026-09-05 补:排线实长约 87 mm,而 `J7n` 只在手机板边外 3 mm ——
> 有 80 mm 以上的余量。** 用户拍板「排线长度不用管,我到时折叠一下」,
> 所以 `J7n` 不挪位、台阶式下折的结论不变。
> **但折叠的那一坨会占手机上方的高度,定压板高度(`h_up`,§22.3d)时必须把它算进去。**
##### 还要不要那块小板 —— **不用了**(2026-09-04 结论)
小板本来能给三样东西,现在只剩一样还悬着,而且风险很低:
| 小板本来能给 | 现在 |
|---|---|
| 引脚映射交叉验证 | ✅ 已从排线实测推出来(上面那张表)|
| 确认座子是公是母 | ✅ 用户目视确认是**母座** |
| 口温电阻真值 | ✅ **从主板图纸反推出来了**,见下 |
##### ⭐ 口温电阻:不用量小板,从主板图纸就能定(2026-09-04)
主板 Sheet 36(PDF 第 38 页)上,`USB_CONN_THERM` 接的是 **SMB1355**:
```
SMB1355 BIAS(pin1) ──[R640 20 kΩ ±1% 0201]──┬── TSKIN(pin7)
└── USB_CONN_THERM → J1401 pin38 → 小板 NTC → GND
```
也就是主板出偏置、串 20 kΩ 作上臂,**小板上的 NTC 是下臂**,分压点送进 SMB1355 的 TSKIN。
(另外那颗 C633 100 nF 是 VAACA 的去耦,和这条链路无关,别看串行了。)
**由此反推 NTC 规格**:分压灵敏度在 `R_ntc = R_bias = 20 kΩ` 时最高,
所以原厂 NTC 在关心的温度点上应该落在 20 kΩ 附近:
| 候选 | R = 20 kΩ 发生在 | |
|---|---|---|
| 10 kΩ NTC(B≈3435)| 约 **8 °C** | ❌ 过温传感器不会把灵敏区放在 8 度 |
| **100 kΩ NTC(B≈4250)** | 约 **63 °C** | ✅ **正好是接口过温的跳变区** |
而且 100 kΩ / B=4250(104EF、104FB 那一类)本来就是高通的标准热敏件 ——
内核里 `adcmap_100k_104ef_104fb` 那张查表就是为它做的。
> **→ 原厂是 100 kΩ NTC,不是本节早先猜的 10 kΩ。**
我们放的是**固定电阻**,所以:
| 放什么 | 手机读到 | |
|---|---|---|
| **100 kΩ**(定稿)| 约 **25 °C**(正好是 NTC 的标称点)| ✅ |
| 10 kΩ | **60 °C 以上** | ❌ 可能触发热限制 |
`R771~775` 已改成 **100 kΩ(`C25741`)**。
**风险仍然很低**:我们本来就用 `input_suspend` 关掉了充电,就算读数不准
也最多在内核里多一条告警。首台机上验一下即可:
```sh
for z in /sys/class/thermal/thermal_zone*; do
echo "$(cat $z/type) $(cat $z/temp)"
done | grep -iE 'conn|usb|skin'
```
读到接近室温 = 对了;读到荒唐值 = 换另一个阻值再试。
<details>
<summary>如果还是想在实物上量(备用)</summary>
拿一块裸的尾插小板:找 USB-C 附近那颗热敏电阻,量「BTB 座的 THERM 触点 → 小板 GND」
的总电阻(把整个网络都包进去,包括可能的串阻)。
**判别是不是 NTC**:量完用手指或热风捂一下再量 —— **NTC 阻值会明显下降,普通电阻几乎不变**。
</details>
##### ⚠️ 唯一的弱环:G1/G2 落在哪一端,用一次开机前的测量兜住
推导链里最弱的一环是「图纸符号上 **G1 画在 pin1 那头 = 物理上真在那一端**」。
这是读符号推的(虽然同一张符号的奇偶排排法已被三条独立证据验证),
而**接反的后果是 5 V 直接灌进手机的地 —— 一条短路,而且手机根本看不到 VBUS**
(§13.4:整个 USB 供电只走 G2 这一个固定脚,50 个信号脚里没有 VBUS)。
**兜法不用加任何硬件**:`VBUS` 负载开关(TPS22918)本来就默认关断
(`R701~705` 100 kΩ 下拉,§15.2 对策 2 / ESP32 复位期间全断)。首件流程:
1. 载板焊好,排线插上手机、插上载板,**先不使能 VBUS**;
2. 万用表量载板上 `VBUSn` 网络对 GND 的电阻;
3. 读到接近 0 Ω = **接反了**(此刻只有万用表在量,没有电流);读到高阻 = 对的;
4. 确认后再让 ESP32 拉高 `VBUS_ENn`。
一次测量、零成本、100% 抓得住。若真反了,把 `c5_j1401.py` 里的
`PWR = {'GND': 52, 'VBUS': 51}` 对调再重跑,封装也跟着改。
#### ⭐ 最省事的办法:**买一块原厂尾插小板当量具**(2026-09-04 想明白)
不用查图纸(查过了,公开渠道没有小板资料,见下),也不用在 0.35 mm 的排线插头上扎针。
**道理**:我们载板上那颗座子,**接的就是原厂小板上那颗座子的位置**——
同一根排线的同一端插进去。所以「物理位置 ↔ 网络」的对应关系,
**照抄原厂小板的就一定对**,根本不需要知道 Hirose 编号,也不需要知道排线翻没翻。
**做法**(拿一块裸的尾插小板,不装机):
1. 万用表打通断,从小板上 **USB-C 母座**的引脚出发(0.5 mm 间距,比排线插头好扎多了,
而且是裸板,走线扇出后有大片可扎的地方):
- D+ / D− / VBUS / CC1 / CC2 / GND 各自通到小板 BM24 座的**哪个位置**;
- 口温 NTC 的那一脚通到哪个位置。
2. 把结果按**物理位置**(哪一排、从哪一端数第几个)记下来,抄进我们自建的封装即可。
**顺带一次解决另外三个问题**:
| 顺带解决 | 怎么解决 |
|---|---|
| 座子是公头还是母座(`C424561` DS / `C424560` DP)| 看一眼小板上那颗是什么,照抄 |
| 口温电阻到底该用多大(10 k 还是 100 k NTC)| **直接量小板上那颗**,抄真值 |
| ESD 该用什么 | 看小板上有没有、是什么封装 |
一块尾插小板十几二十块钱,比任何图纸都便宜、也比图纸可靠(图纸还可能是别的版本)。
<details>
<summary>备用办法:直接量排线(更麻烦,只在拿不到小板时用)</summary>
1. 排线插上手机 J1401(手机不通电),万用表打通断,一表笔搭手机屏蔽罩(地);
2. 在排线自由端 50 个触点上走一遍(针尖表笔 + 放大镜),记下哪些响 = 地;
3. 对照 §13.4 的地脚分布 —— **奇数排的地在第 2,5,7,11,14,16,25 位,
偶数排的地在第 14,18,20,22,25 位**。这个图案旋转 180° 后完全不同,
所以量出来就唯一确定了映射方向。
4. 顺手确认两个大焊盘(电源触点)哪个通地 —— 那个是 G1,另一个才是 G2(VBUS)。
**接反就是 5 V 对地短路。**
</details>
> 不管走哪条路,都要目视确认这根排线**确实是尾插排线** ——
> 小米8 主板上有两个 50 脚 BM24:**J1401(尾插,母座)和 J1102(屏幕,公头)**,别拿错。
#### 📕 公开渠道没有小板资料(2026-09-04 查过,别再查了)
- 我们手上这份 `Xiaomi_Mi_8_Schematic.pdf`(Rev E8)**44 页全是主板**,
按关键字扫过一遍:`USB_CC1/CC2`、`USB_CONN_THERM`、`USB_VBUS` 只出现在
PMI8998 侧和 J1401 那一页,**没有任何一页画 USB-C 母座**。
- mobilerdx 的「Mi 8 完整包」里只有 Block Diagram / Schematics / Parts List /
Component finder 四份,就是我们这份的同一套,**没有小板原理图也没有 boardview**。
- vinafix 上 dipper 只有 **Mi 8 Lite / Mi 8X(Mi A3)**,都是别的板子(§22.3b 早查过一次)。
- 维修行业换小板是整块换,不需要它的原理图 —— 所以本来就不会有。
<details>
<summary>已作废的方案 A 记录(2026-09-04 晚),留档备查</summary>
**(当时的定稿)装原厂尾插小板(或买原厂尾插排线),载板侧不做任何 USB 相关电路。**
连接方式:
```
手机 J1401 ──原厂尾插排线── USB-C 母座
↑
USB-A 转 C 线(剪掉 A 头,压 1.25mm 4P 端子)
↓
载板 J17~J21(A1251WV-S-4P,一行都不用改)
```
**为什么改回来**(用户 2026-09-04 晚确认):一旦决定「用排线连接主板和载板」,
方案 C 相对方案 A 就没有任何优势了,而方案 A 把下面这些一次性全消掉:
| 方案 C 要解决的 | 方案 A 里怎么消失的 |
|---|---|
| CC1 上拉 56 kΩ Rp | **USB-A 转 C 线的 C 头里本来就有 56 kΩ**(Type-C 规范强制要求,Default USB 档)|
| pin38 口温电阻(阻值还是猜的)| 原厂尾插小板上就是**正确的那颗** |
| D± 的 ESD | 原厂尾插小板上本来就有 |
| CC2 悬空 | 线缆自己处理 |
| 自建 BM24-50DP 封装(立创那个编号是错的)| 不用做板了 |
| 0.35 mm 打样 + 钢网 + 回流 | 不用做板了 |
| §13.6 的天线馈点风险(**原本是致命项**)| 尾插小板装上了,馈点回来了 |
| 丢麦克风 / 扬声器 / 震动 | 全都回来了 |
代价只有一条:多一块原厂小板的体积和重量。对机架式手机农场无所谓。
> ⚠️ **买线注意**:必须是 **USB-A 转 C**,不能是 C 转 C 或不带 Rp 的 C 公头带线 ——
> Rp 就藏在 A 转 C 线的 C 头里。**到手先用万用表量一下 CC 对 VBUS 是不是 56 kΩ**
> (市面上确实有阻值给错的劣质线,会让手机误判成 1.5 A / 3.0 A 档)。
> 端子顺序按载板 J17:**1=VBUS 2=D− 3=D+ 4=GND**。
> ⚠️ **BM24 只有 10 次插拔寿命**(Hirose 规格书 Durability 一栏)。
> **这条在方案 D 下更要紧 —— 一根排线上有两个 BM24 插拔点。**
</details>
---
<details>
<summary>以下是已作废的方案 C 记录(2026-09-04 白天),留档备查</summary>
原话是「不接尾插小板,直接接到主板的尾插板接口」。这把上面的推荐推翻了,
**下面三条是方案 C 必须补的,缺一条手机就可能不认 USB 或报错**:
| 必补 | 为什么 |
|---|---|
| **CC1(pin 30)经 56 kΩ 上拉到 VBUS** | ⚠ 见下 |
| **pin 38 接一个 10 kΩ NTC(或先用固定 10 kΩ 电阻顶上)** | 口温检测,缺了可能报口温异常、拒绝快充 |
| CC2(pin 32)**悬空** | 只拉一边 CC,手机才能判出插入方向 |
⚠️ **CC 这一条是对 §13.4 结尾那句话的修正。** §13.4 写的是
「Rd 下拉在 PMI8998 内部,所以自制小板上 CC1/CC2 直连座子即可,不需要外部 5.1k」——
**那句话的前提是自制小板上还有一个 USB-C 母座**,Rp 由插进来的线缆/主机侧提供。
现在我们把 D± 直接硬接到板载 Hub 上、**整条链路里根本没有 USB-C 连接器了**,
就没人提供 Rp 了。手机的 PMI8998 是靠 CC 上看到 Rp 才判定「有 DFP 插入」
并把 USB PHY 切到 device 模式的;CC 两根都悬空,很可能**只充电不枚举**。
所以转接小板上必须自己放这颗 **56 kΩ(默认电流档)Rp**。
**物理形态**:J1401 在主板**正面朝上**(§22.3b),而载板在主板下面 ——
所以对插的 **BM24-50DP 不能直接焊在载板上**,只能做成一小块转接板/软板,
从上面插进 J1401,再引 4 根线(VBUS / D+ / D− / GND)下来。
载板那头就是现成的 **J17~J21(A1251WV-S-4P,1.25 mm 4P)**,
原理图完全不用改 —— 变的只是插上去的东西从「USB-A 转 C 短线」换成「J1401 转接板」。
**代价,先说清楚**:0.35 mm 间距 50 脚的 BM24-50DP 手工焊不了,
这块转接板得打样 + 钢网 + 回流;而且不装尾插小板就同时失去了**麦克风、扬声器、天线馈点**
(§13.6)。农场机走 WiFi、不用通话的话都不影响。
(↑ 就是这一段里的「天线馈点」把方案 C 拖垮的 —— §13.6 把它标成致命项,
而方案 A 一装上就不用做那个三步 RSSI 实测了。)
</details>
#### 问题二:USB 供电会和电池直供打架 ⚠️
这是接 USB 之后最容易炸的一条,必须在设计阶段处理。
**机理**:接上 VBUS 后,手机的充电器看到"电池"电压 3.9V,认为电量约 50%,于是按设定电流(最高 3A)往 `B+` 灌电。而 `B+` 是我们 Buck 的输出,被钳在 3.9V。结果:
- 我们的同步 Buck 被反灌,进入反向工作,把能量泵回 **12V 母线**;
- 12V 适配器不能吸收电流,母线电压被抬高 → 可能触发适配器 OVP 或损坏;
- 若 Buck 吸不动,`B+` 电压上冲 → **电池保护板 4.28V OVP 断开** → 手机瞬间失去 VBAT → 关机。
**三条对策,建议全做**
1. **软件关充电(最省事,首选)**
农场机本来就 root。写高通平台的抑制节点:
```
echo 1 > /sys/class/power_supply/battery/input_suspend
```
(节点名各 ROM 不同,也可能是 `charging_enabled` / `battery_charging_enabled`,首台机上确认一次即可。)
这样 USB 只做数据和自身供电,不给"电池"充电,直供完全不受干扰。
2. **VBUS 加 ESP32 可控负载开关(硬件兜底)**
VBUS 路径串一个负载开关,**默认断开**,只在需要有线 adb / 刷机时接通。
固件互锁:VBUS 接通期间监控该路 INA226 —— **INA226 是双向测量的**(±81.92mV 分流电压,有符号),出现负电流(反灌)或电压被顶高超过设定值 +100mV,立刻断 VBUS 并告警。
3. **12V 母线加泄放(几毛钱的保险,必须加)**
TL431 + N-MOS + 10Ω/5W 的分流泄放器,母线超过 **13.2V** 时导通。
防的就是"某一路被反灌 → 能量泵回母线 → 母线抬高 → 连累其他四台"。
这一条即使不接 USB 也建议加:Buck 在负载突卸时同样会有少量能量回灌。
> **对 §9.1 BOM 的追加**:TL431 ×1、N-MOS(30V/5A)×1、10Ω/5W 泄放电阻 ×1、VBUS 负载开关 ×5(TPS22918 一类,5V/2A,带 EN)。
#### 接 USB 之后的能力提升
| 能力 | 说明 |
|---|---|
| 有线 adb | WiFi adb 不通时的兜底通道,比断电重启温和 |
| Fastboot / EDL 刷机 | 配合 §13.3 的按键组合,远程救砖闭环 |
| `DEBUG_UART_TX/RX`(pin 24 / 29) | 如果自制小板,顺手把调试串口引出来——**内核 panic 时这是唯一能看到原因的通道**,对排查"随机重启"极其有用 |
### 13.5 电池排线改造
#### 排线的物理结构
```
BTB座 ──FPC走线── [P+ / P−] ──保护板 MOS── [B+ / B−] ──电芯焊点(已拆)
↑ ↑ ↑
主板 J600 **接这里** 原方案接这里
(保护板输出侧)
```
**关键事实**:保护板的两颗背靠背 MOS **串在负极**,位于 `P−` 与 `B−` 之间;正极 `B+`↔`P+` 是直通的。
所以接 `P+`/`P−` 时电流直接进 BTB 座,**根本不经过那两颗 MOS**;`B−` 悬空后,保护 IC 就算仍在上电工作、就算检测到过压去关 MOS,也影响不到这条通路。
**保护板自动退出,不用拆、不用飞线短接、不用改排线任何东西。** 而 BTB 公座、`BATT_ID`、`BATT_THERM`(NTC)全部原样保留——这两根信号缺了手机可能拒绝开机,自制转接板反而要重新解决。
#### ⚠️ 别焊错边
焊到 `B+`/`B−` 就等于又把保护板串了回去,而且**现象上完全正常**,只有在过压时才会暴露(保护板抢先动作,手机莫名掉电)。
**判别方法**(万用表电阻档,排线离机):
| 步 | 操作 | 判据 |
|---|---|---|
| 1 | 从 BTB 座 **pin 7 / 8**(VBATT)量到两个候选正极焊点 | 阻值≈0 的是 **`P+`** |
| 2 | 从 BTB 座 **pin 1 / 2**(GND)量到两个候选负极焊点 | 阻值≈0 的是 **`P−`**;另一个(读到二极管压降或开路)是 `B−` |
| 3 | 焊接后复测 | `P−` → BTB pin 1/2 必须是通路,且**与 `B−` 不通** |
> 第 2 步的原理:`B−` 与 `P−` 之间隔着未上电的 MOS,只有体二极管,正反测阻值不对称;`P−` 到 BTB 是纯铜箔,双向都接近 0Ω。
**做法**:电芯从 `B+`/`B−` 分离后,电源板输出焊到 `P+`/`P−`,§6.3 的电容组也装在这里,BTB 插回主板 J600。
**安全提示**:拆电芯时用绝缘工具,先剪正极再剪负极,不要同时接触两极。电芯单独存放,不要留在工位上。
#### 为什么不自制 BTB 转接板
查过立创库:只有 `5050040812`(C724121)——那还是**母座**,和主板上的 J600 同类,**没有对插的公座**(Molex 505003-08xx plug)。自制转接板需要自行采购 Molex 原厂件手贴,还要自己复制 `BATT_ID`(若是 1-wire 认证 IC 则无法复制)。用原厂排线是明显更优解。
#### ⭐ 2026-09-06 改法:在保护板焊点处剪断排线,4 个焊盘直接焊到载板(用户提出,实测中)
用户把排线从保护板上拆下来了。排线与保护板的接口是 **4 个焊盘一排**,用户在保护板上实测(从离 B+ 引线最近的那个数起):
| 序 | 焊盘 | 实测 |
|---|---|---|
| 1 | **P+** | 对 B+ 引线通断档 ≈0(B+↔P+ 直通铜箔)|
| 2 | **P−** | 对 B− 开路(隔着背靠背 MOS,符合预期)|
| 3 | **TEMP**(BATT_THERM)| 对 P− **10 kΩ** NTC |
| 4 | **ID**(BATT_ID)| 对 P− **≈68 kΩ** 固定电阻(不是认证 IC,可以复制)|
⚠️ NTC 和 ID 都是**对 P− 的**,对 B− 量是几十 MΩ 漂移(开路)。第一次按"对负极线"量会得出"三个都不通"的假结论。
**改法**:保护板整块不要。载板每站把 `TP8n1`/`TP8n2` 两个 Ø2.7 通孔焊盘换成一个 **4 焊盘 FPC 手焊封装**(底层,位置不变:主板投影下方贴接口边),
加两颗电阻:**TEMP → GND 10 kΩ**(固定电阻模拟 25 °C,手机不充电,只需要读数正常)、**ID → GND 68 kΩ**。原理图 C4-SITE1~5 各加两颗。
好处:不用再手焊两根线、保护板不再吊在排线上、§13.5「焊错 B+/B− 边」的风险消失、排线两头都固定。电池槽 10 × 3 不用动(只过 8 mm 宽的排线)。
**封装按保护板上的焊盘图案抄**(间距 / 焊盘尺寸 / 离排线进入边的距离用卡尺量保护板,比量排线好量):
排线是面朝下焊在保护板上的,载板上它同样面朝下焊,只要排线从同一侧进来,**载板底层焊盘的顺序 = 保护板焊盘面看到的顺序**,不用镜像。
排线焊盘面 = BTB 插头触点面(手机里两者都朝显示屏那一侧);按 §25.16 v4 的弯折推算,排线绕过接口边、穿槽、折回主板下方之后这一面正好朝载板背面,
所以焊盘留在现在 TP8n1/2 的位置就行。**装之前把排线摊平核一眼**:4 个焊盘和插头触点若不在同一面,焊盘要改到槽外侧(走廊那边,排线穿过去后不折回)。
✅ **已量并已落地(2026-09-06 晚)**:焊盘 1 × 2 mm、间距 2.0、排线尾巴伸出焊盘行 8 mm(装配时**剪到留 1 mm**,露出载板焊盘外伸的那一截给烙铁)。
| 落地项 | 内容 |
|---|---|
| 封装 | 个人库 `FPC-4P-P2.0_MI8-BAT`(`d0a99d3d…`,`fp_batfpc.py`):4 焊盘 1.1 × 4.0 上下对称(各多伸 1 mm),1 = P+ … 4 = ID 从 −X 到 +X;丝印画 8 mm 排线边 |
| 器件 | 个人库 `MI8-BAT-FPC-4P`(`22b0c3130f0b4ff6baab529761dab3e4`),符号借立创 PZ254V-11-04P 的 4 脚(副本 `bf0085b7…`),Convert to PCB = yes 已核 |
| 原理图 | C4-SITE1~5 重画:`J8n`(J81~J85) 换掉 TP8n1/2;`R78n` 10k TEMP→GND、`R79n` 68k ID→GND;母线西端 150→90 给四条竖走廊。六项验证 / 跨页 / port_audit 全过 |
| PCB | 导入 166 件(+5);`pcb2_place.py` v4b:**J8n 放到主板下方远处 (22.8, 15.0)**(用户拍板「35 mm 排线够得到的地方」:J600 4.6 + 绕边 5 + 到槽 2.7 + 穿板 1.6 + 背面 17.7 ≈ 31.6 ≤ 35,实长 38),电池排线车道 `BAT_LANE` u 18.8~27.8 / v −1.2~13 清空;电容组围着 J8n:C8n2 (13.5,15) C8n6 (17.5,15),C8n3/4/5 (13/18/23, 18.5),R78n/R79n (29.5/31.5, 18.5);C8n1 挪到 (34.3, 11.3) 让开车道与 H7 螺钉头 |
| 铺铜 | Inner1 主板下方那块岛 v −1~14 → **−1~20**(J8n 的 P+ 和电容组都在 v 13~19.4);五块岛重铺实测全过,最窄 7.05 |
| 手性 | `BAND['j8']` rot 0 = P+ 在本体 −u。**判法**:排线插在 J600 上,主板 J600 那一面朝上、接口边朝自己,排线摊平朝自己伸出(焊盘面朝桌子),把排线**末端向上翻折 180°**(折线平行于排线宽度方向,翻完焊盘面朝上、末端指回主板)——这样左右不变。用万用表找 P−(对主板屏蔽罩通断响的那个),紧挨 P− 的**排端焊盘**就是 P+。P+ 在**左** = rot 0 正确;在**右** = 改 rot 180(封装上下对称,只改这一个数)。**✅ 2026-09-06 用户实测:P+ 在左,rot 0 定稿。** |
⚠️ 顺带修的一个工具 bug:`pcb2_parts_dump.py` 抓底层元件包围盒时只反转不反镜像,J6n 这种上下不对称的封装会误报和 J7n 重叠(skill §9w 补)。
### 13.6 不接尾插的风险实测 —— ✅ **致命项已解除(2026-09-04)**
> **最终结论**:方案 D 不装尾插小板,但**用户确认主板上有两个对插的射频小圆孔,天线直接插主板**,
> 所以「WiFi 馈点可能在尾插侧」这条致命项不成立。副麦克风 / 扬声器 / 震动马达一律不要
> (用户原话:「只要能开机正常运行系统就行」)。下面这一节只剩第 3 步还要做。
<details>
<summary>原文(记录当时的判断过程)</summary>
副板上除 USB-C 外还有**天线馈点**、副麦克风、震动马达。小米8 天线主体在中框,主板只有馈点。
**方案 A 把尾插小板装回去了,所以第 2 步不用做了。**但第 3 步仍然要做:
| 步 | 配置 | 记录 | 还要不要做 |
|---|---|---|---|
| 1 | 整机原样(含中框、尾插) | `adb shell dumpsys wifi \| grep RSSI` 作基准 | ✅ 要(作基准)|
| 2 | 仅拔尾插排线 | RSSI 变化 | ❌ **不用了**,尾插装着 |
| 3 | 主板脱离中框,裸板 | RSSI 变化 | ✅ **要** |
**判据**:第 3 步掉得厉害 → 连中框一起固定到载板上(这会改动 §22.3 的机械方案,要早测)。
> 历史:这一节的第 2 步原本是方案 C 的头号风险(「WiFi 若受影响 = 致命项」),
> 也是 2026-09-04 晚一度放弃方案 C 的主要理由之一。用户自己配天线之后不再成立。
</details>
### 13.7 旁路验证(打样前必做,替代原「保护板 OVP 实测」)
原「保护板 OVP 实测」随 v1.1 移除保护板而作废。改做这三项:
| 步 | 操作 | 通过标准 |
|---|---|---|
| 1 | 按 §13.5 的判别表定位 `P+` / `P−`,焊线,拍照存档 | `P−`↔BTB pin1/2 通;`P−`↔`B−` 不通 |
| 2 | 可调电源 3.80V / **限流 100 mA** 接 `P+`/`P−`,量 BTB 座 pin 7/8 与 G3/G4 | 全部 3.80V,压降 < 5 mV(证明未串入保护板) |
| 3 | **升压验证保护板确已退出**:把电源升到 4.40V | BTB 座电压应**跟随到 4.40V 且不断开**。若在 4.3V 附近断开,说明焊到了 `B+`/`B−`,返工 |
| 4 | 插机开机 | 正常开机;`dumpsys battery` 温度读数正常(NTC 有效);无「非原装电池」告警或仅告警不影响使用 |
第 3 步是这套改造唯一的判定性测试,**不要跳过**——焊错边在常温常压下完全看不出来。
---
## 14. 实测记录表(首板前填写并存档)
**J600 复核**(引脚定义已由图纸确定,此处只做上机验证)
| 检查项 | 方法 | 预期 | 实测 |
|---|---|---|---|
| VBATT 脚 | 排线加 3.80V,量 BTB pin 7/8 与 G3/G4 | 3.80V | |
| GND 脚 | 同上量 pin 1/2 与 G1/G2 | 0V | |
| NTC 阻值 | 断电,量 pin 4 对 pin 1/2 | ≈10 kΩ @25°C,捂热应下降 | |
| BATT_ID 形式 | 量 pin 3 对地 | □ 电阻 ____ □ 1-wire IC □ 开路 | |
**侧键触点**(背面,与 SIM 卡托相对的长边;附近摄照片标出位置)
| 位号 | 功能 | 触点位置 | 空闲电压(对 J604) | 短接测试 |
|---|---|---|---|---|
| J601 | 音量 + | | | |
| J602 | 音量 − | | | |
| J603 | 电源 | | | 2s 开机 / 10s 强制重启 |
| J604 | 公共地 | | 0 V | — |
**保护板 OVP**(§13.7,测 3 块取最小值)
| 排线 # | OVP 阈值 |
|---|---|
| 1 | |
| 2 | |
| 3 | |
→ eFuse OVP 设定 = 最小值 − 100 mV = ______ V
---
## 15. USB 子系统实现
### 15.1 架构与边界(2026-09-03 改为**板载 Hub**)
对外只有**一根 USB 线**。五路下行由板上的 USB2517I 分,下行 VBUS 由板上自己的 5V 轨供,
不吃上游线的电流。
```
电脑 ──一根 USB 线──> J23 USB-C(UFP,上游)
│ D±
┌─────┴─────────────────────────┐
│ U32 USB2517I 7 口 Hub │ 自供电(§21)
│ Y1 24MHz / R708 RBIAS 12k │ 口 6/7 已禁用
└─────┬─────────────────────────┘
│ D± ×5
12V ──U30 LMR51430──> +5V ─┬─[U24~U28 TPS22918]──> VBUS ×5(ESP32 可控,默认断开)
└─U31 AMS1117-3.3──> +3V3_HUB(只给 U32)
│
J17~J21(4 针 1.25mm)── USB 线 ──> 手机原厂尾插小板 USB-C
```
**四条边界,定死不再改**
1. **上游只接电脑,VBUS 恒 5V。**
板上不做 PD/BC1.2 协商:J23 的 CC1/CC2 各串 5.1kΩ 下拉(R717/R718),
对外表现为纯 UFP。没有 PD 通信,充电器最多也只给 5V,
不会把 VBUS 抬到 9V/12V 去炸 TPS22918 的 5.5V 绝对最大值。
2. **Hub 是自供电(self-powered),不是总线供电。**
下行 VBUS 来自 U30 的 5V 轨,Hub 自身的 3.3V 来自 U31。
从上游只取 <1 mA。**这条不是省事,是必须的**:
若声明成总线供电,主机会按「每口 100 mA」做功率预算,
而手机的 USB 描述符通常申请 500 mA → **主机拒绝配置,手机根本枚举不上**。
实现方式见 §21.3(靠 CFG_SEL=000 走内部默认配置,寄存器 06h 默认 9Bh、bit7=1)。
3. **本板只切 VBUS,不碰数据线。** D± 从 Hub 出来直通到出线座,中间不串任何东西。
4. **不自制 USB-C 转接板。** 手机那一侧的口温 NTC(J1401 pin 38)、CC、ESD
全在原厂尾插小板上,自制必然漏项。
> ⚠️ **板上有两个长得一样的 USB-C**:J22 是 ESP32 调试口、J23 是 Hub 上游口。
> 插错了不烧,但现象是「adb 整排不见」,很难想到是插错口。
> **丝印必须写清楚**,建议再用不同颜色的座子或在外壳上做标记。
> (2026-09-03 用户在「USB-B 母座」与「USB-C」之间选了 USB-C,已知并接受这个风险。)
> **旧方案(已作废)**:5 个 USB-A 母座 J12~J16,各拉一根 A 公-A 公线到外置 Hub。
> 当时选 USB-A 母座的理由是「物理上插不了充电头」,现在由边界 1 的「不做 PD 协商」代替。
> J12~J16 从 BOM 里删除。
### 15.2 三条对策的具体实现
#### 对策 1:软件关充电(首选,零硬件成本)
```sh
# 高通平台常见节点,首台机上确认实际路径后写进固件的开机脚本
echo 1 > /sys/class/power_supply/battery/input_suspend
# 备选名:charging_enabled / battery_charging_enabled / usb/online
```
关掉后 USB 只做数据和自身供电,不给"电池"充电,直供完全不受干扰。
**这是常态运行的依赖项**,另外两条是它失效时的兜底。
#### 对策 2:VBUS 负载开关 + 反灌检测
**硬件**:每路 VBUS 串一颗 TPS22918 负载开关(1~5.5V / 2A,带 ON 与可调上升时间),`ON` 由 ESP32 GPIO **直连**并加 100 kΩ 下拉 → **默认断开**。电路画在 P4-USB,逐项计算见 **§18**。
> ⚠️ **2026-09-03 起 VBUS 的来源变了**:从「上游 USB 线缆」改成**板上 U30 的 5V 轨**(§9.4)。
> Hub 的端口电源控制脚(PRTPWR[7:1])**故意不接** —— 通断权必须在 ESP32 手里,
> 这是本对策成立的前提。Hub 自己以为端口一直上电,不影响这里的逻辑。
**固件逻辑**(每路独立):
```
接通 VBUS 前:确认该路 input_suspend 已生效(读 sysfs 或按上次状态)
接通后每 50 ms 读一次该路 INA226:
if I < −50 mA → 反灌,立即拉低 VBUS_EN,告警
or V > 设定值 + 100 mV → 被顶高,同上
不用时保持断开
```
> **INA226 是双向测量的**(分流电压 ±81.92 mV,有符号),所以「电流为负」这个判据可以直接读出来,不需要额外电路。这是选它而不是选单向电流计的原因之一。
#### 对策 3:12V 母线泄放(几毛钱的保险,必装)
```
12V 母线 ──┬── R上 ──┬── TL431 REF
│ R下
│ │
│ GND
│
└── Q_bleed(N-MOS 30V/5A) ── R_bleed 10Ω/5W ── GND
栅极由 TL431 阴极经一级驱动
阈值:13.2V 导通;泄放能力 (13.2−12)/10 ≈ 120 mA 起,母线越高吸得越多
```
防的是「某一路被反灌 → 同步 Buck 把能量泵回 12V 母线 → 母线抬高 → 连累其他四台,甚至触发适配器 OVP」。
**即使不接 USB 也建议保留**:Buck 在负载突卸时同样会有少量能量回灌。
### 15.3 D± 走线规则(板上唯一的高速信号)
USB 2.0 HS 是 480 Mbps,按差分对处理。
> **2026-09-03 改板载 Hub 之后,「目标 < 30 mm」这条作废。**
> 一颗 Hub 要喂五个分散在板边的出线座,短不了。把 U32 摆在板子正中央
> (x=79 / 板宽 160)之后,五路是 **64 / 32 / 0 / 32 / 64 mm**,上游 J23 到 U32 只有 16 mm。
> 最长 64 mm 对 USB 2.0 HS 完全够用(协议本身允许 5 m 线缆),
> **前提是受控阻抗** —— 长度不再是主要矛盾,阻抗和参考平面完整性才是。
> 顺带一提:五对之间**不需要**互相等长,它们是五个独立端口;
> 要等长的只有**对内**(DP 与 DM)。
- **差分阻抗 90 Ω ±10%**,4 层板用 L1 走线、L2 完整地平面做参考。
- **几何:W 0.28 mm / S 0.18 mm**(已写进 EasyEDA 的差分对规则)。
按嘉立创四层 1.6 mm 标准叠层 L1-L2 介质 h=0.2104 mm、εr≈4.3、
**1 oz 外层(§10.1 已定稿)**,用微带近似
`Z0 = 87/√(εr+1.41)·ln(5.98h/(0.8W+t))`、`Zdiff = 2·Z0·(1 − 0.48·e^(−0.96·S/h))`
得 Z0≈57.5 Ω、Zdiff≈90.5 Ω。
(若哪天回到 2 oz,同样几何只剩 83 Ω,W 要收到约 0.24 mm —— 铜厚 t 在分母的 0.8W+t 里。)
⚠️ 叠层、板厚、prepreg 型号一变这两个数就得重算 ——
**打样前用板厂的阻抗计算器复核,别信这里的近似公式。**
- 对内等长误差 < 1 mm(规则里设的是 0.5 mm,留一半余量)。
- **不跨越地平面分割**,不跨 SW 节点,不与任何 Buck 的电感 / SW 铜箔重叠。
- 五路 USB 走线集中在板子的一侧,与功率区物理分开。
- 每对旁边留地过孔缝合。
- **不要在 D± 上串电阻或加 ESD 之外的任何东西**——ESD 用低容(< 1 pF)的 USB 专用器件,或者干脆不加(原厂尾插小板上已有)。
### 15.4 每台手机的线束
> ⚠️ **2026-09-03:若「主板载板」方案落地,这张表基本作废** —— 三条线束会被
> **板对板连接器**取代(每台 2 电源 + 4 按键 + 4 USB,五台共 50 根,电源合计 20 A)。
> 详见 `PROGRESS.md` 的「⭐⭐ 第二件事:主板载板」。方案未定稿前,下表仍是有效方案。
| 线束 | 芯数 | 板端连接器 | 手机端 | 线规 / 要求 |
|---|---|---|---|---|
| 电源 | 2 | J2~J6 Micro-Fit 3.0 | BM3E 排线的 `B+` / `B−` 焊点 | **18 AWG,≤ 20 cm,双绞**;手机端挂 §6.3 电容组 |
| 侧键 | 4 | J7~J11 4 针 1.25 mm | J601 / J602 / J603 / J604 触点 | 细线即可,远离电源线 |
| USB | 4 | J17~J21 4 针 1.25 mm | 原厂尾插小板 USB-C | 用现成 USB 线改端子,D± 保持双绞 |
**接地约定**:三条线束的地在手机端是同一个地(都来自 `B−`),但在板上**必须分别回到该路的独立地**,只在板内地平面单点汇合。不要在手机端把三条地并成一根——那会把射频突发耦合进 USB 和按键线。
---
---
## 16. P2-CHANNEL 单路原理图(已画完,五路复制的母版)
EasyEDA 工程 `PhoneRail-5CH-PSU` 第 2 页。**先画完整一路、确认后再复制成五路**。
几何验证六项全过(`verify_sch.py`):0 悬空引脚、0 单引脚网络、0 无名旗端口、0 同网多名。
### 16.0 全板位号规则(2026-09-03 新增,**必须遵守**)
画 P2 时发现 P1 和 P2 的位号大面积撞车(两页各有一套 `R1~R9` / `C1~C10` / `Q1`),
而位号在**整张原理图里是全局唯一的**,不是每页独立。五路复制后会变成五倍。
已改成下面这套,P2 的 R/C/Q/L/Rs 全部加了 100:
| 页 / 单元 | R、C、Q、L、Rs | U(芯片) | J(连接器) |
|---|---|---|---|
| P1-INPUT(输入 + 辅助电源 + 泄放 + 输入侧检流) | **1 ~ 99**(含 Rs6 / C11) | U13 / U19 / U29 | J1 |
| **CH1**(P2) | **101 ~ 199** | U1 / U8 / U14 | J2 / J7 |
| CH2(P2B-CH2) | **201 ~ 299** | U2 / U9 / U15 | J3 / J8 |
| CH3(P2C-CH3) | **301 ~ 399** | U3 / U10 / U16 | J4 / J9 |
| CH4(P2D-CH4) | **401 ~ 499** | U4 / U11 / U17 | J5 / J10 |
| CH5(P2E-CH5) | **501 ~ 599** | U5 / U12 / U18 | J6 / J11 |
| P3-CONTROL | **601 ~ 619** | U20 | **J22**(USB-C 调试口) |
| P3B-EXPAND | **601 ~ 699**(同段续编) | U6 / U7 / U21 / U22 / U23 | — |
| P4-USB | **701 ~ 799** | U24 ~ U28 | J12 ~ J21 |
| **P5-HARNESS(离板)** | **801 ~ 899** | — | — |
- **通道号 = 位号的百位**,看位号就知道是哪一路,PCB 上排查故障时省事。
- U 和 J 沿用 §9.1 已经分配好的全局编号,不加百位(它们本来就不撞)。
- P1 保持原样不动(1~99 是「全板公共」段)。
- **8xx 段是离板件**(手机侧电容组),不进 BOM、不上 PCB,所以百位不表示通道;
通道写在**十位**上:CH1 = C801~C806,CH2 = C811~C816,…… CH5 = C841~C846。
### 16.1 页面分区
| 区 | 位置 | 内容 |
|---|---|---|
| Buck 功率级 | 左上 | U1 TPS54622 + 输入/输出电容 + L101 + RT / EN / SS / COMP |
| 反馈与调压 | 左下 | R101 / R102 / Rinj + DAC 的 1k+10nF 低通 |
| eFuse 与检流 | 右上 | U14 TPS25940A + 外围 + Rs101 + U8 INA226 + J2 |
| 放电联锁 | 右 | Q101 反相 + Q102 放电 MOS + R119 10Ω |
| 按键驱动 | 右下 | Q103/Q104/Q105 + 栅阻/下拉 + J7 |
### 16.2 单路位号与取值(复制五路时只改位号后缀)
| 位号 | 值 / 型号 | 作用 |
|---|---|---|
| U1 | TPS54622RHLR | 同步 Buck |
| C101, C102 | 10 µF / 50V 0805 | 输入 MLCC(紧贴 PVIN) |
| C103 | 2.2 µF / 50V 0805 | 输入中频 |
| C104 | 100 nF 0402 | 输入高频 |
| R103 | **100 kΩ** | RT/CLK → 480 kHz |
| R104 / R105 | **68.1 kΩ / 10 kΩ** | EN 输入 UVLO:起动 9.37V,关断 8.84V |
| C105 | 100 nF 0402 | BOOT |
| C109 | 10 nF 0402 | SS/TR → 2.6 ms 慢启动 |
| R106 / C110 / C111 | **1 kΩ / 33 nF / 100 pF** | COMP 补偿(fco ≈ 18 kHz,见 §9.2) |
| L101 | SPM6530T-4R7M | 4.7 µH |
| C106, C107 | 22 µF / 25V 1206 | 输出 MLCC |
| C108 | 100 nF 0402 | 输出高频 |
| R101 / R102 / R107 | **30.1k / 5.49k / 150k** | 分压 + 注入(§4.3,2026-09-03 由 5.23k/107k 改) |
| R108 / C112 | 1 kΩ / 10 nF | DAC 低通(必须在 Rinj 的 DAC 侧) |
| U14 | TPS25940ARVCR | eFuse |
| R109 / R110 | **68.1 kΩ / 20 kΩ** | OVP 分压 → 4.36V(容差窗口已由 §4.3 解决,见 §5) |
| R111 | **20 kΩ** | ILIM → 4.45 A |
| C114 | **33 nF** | dVdT → 0.36 V/ms,斜坡 11.5 ms,涌流 0.80 A |
| R112 | 10 kΩ | IMON 取样(本设计不用,仅作测试点) |
| R113 / R115 | 47 kΩ | FLT# / PGOOD 上拉到 +3V3(开漏) |
| R114 | 100 kΩ | EFUSE_EN 下拉(ESP32 复位期间输出全关) |
| R116 / R117 | **20 kΩ / 10 kΩ** | PGTH 分压 → 输出 2.97V 以上报 PGOOD |
| Rs101 | 5 mΩ 1% 2512 | 分流(Kelvin 焊盘) |
| U8 | INA226AIDGSR | A1=A0=GND → **地址 0x40**(CH2~CH5 见 §8.2 的地址表,不是顺排) |
| C113 | 100 nF 0402 | INA226 VS+ 去耦 |
| Q101 / R118 | 2N7002 / 100 kΩ | EN 反相器(硬件互锁) |
| Q102 / R119 | AO3400A / 10 Ω 1W 2512 | 放电 MOS + 泄放电阻 |
| Q103~Q105 | 2N7002 ×3 | 电源键 / 音量+ / 音量− |
| R120/R122/R124 | 1 kΩ ×3 | 栅极串阻 |
| R121/R123/R125 | 100 kΩ ×3 | 栅极下拉(复位期间不误按) |
| J2 | Micro-Fit 3.0 2P | 电源出线到电池座 |
| J7 | 1.25mm 4P | 按键出线(PWR / VOL+ / VOL− / GND) |
### 16.3 拓扑上的两个决定(与早期草案不同,已定稿)
**① 分流电阻放在 eFuse 之后(手机侧),不是之前。**
```
L101 → VO1(Cout、FB 取样、OVP 分压)→ U14 IN
U14 OUT → VO1_F(PGTH 分压、INA226 VIN+)→ Rs101 → VO1_P → J2
├── Q102/R119 放电
└── INA226 VIN− / VBUS
```
- 串联电流处处相同,所以放前放后测到的电流一样;
- 但 **VBUS 因此测的是手机侧电压**,这正是 §5 第三层「发现 eFuse 本身失效」所必需的
(放在 eFuse 之前只能看到 Buck 输出,eFuse 是否真的断开无从判断);
- 代价:读数含 eFuse 的 Rds(on) 压降。常态 0.5A 时只有 21 mV,远小于 ±100 mV 判据;
满载 4A 时 168 mV,固件按已知电流补偿即可。
**② OVP 分压取自 eFuse 输入(= Buck 输出),PGTH 分压取自 eFuse 输出。**
TPS25940 的 OVP 本来就是监视输入的,正好对应「Buck 失控 → 切断负载」这个要防的故障;
PGTH 则要看下游是否真的带上电了,所以取输出。两者刻意分开。
### 16.4 跨页网络(P3-CONTROL 侧要对上)
| 网络 | 方向 | 对端 |
|---|---|---|
| `+12V` / `+3V3` / `GND` | — | P1 |
| `VDAC1` | 入 | DAC63204 通道 |
| `EFUSE_EN1` | 入 | ESP32 GPIO 直连(安全关键) |
| `EFUSE_FLT1` / `EFUSE_PG1` | 出 | PCA9555 输入(每路 2 根,5 路共 10 根,余 6 根) |
| `BUCK_PG` | 出 | 五路**线或**到一根(都是开漏),只指示「有某一路不正常」 |
| `INA_ALERT` | 出 | 六片 INA226 线或到一根 |
| `SDA` / `SCL` | 双向 | I²C |
| `K1_PWR` / `K1_VUP` / `K1_VDN` | 入 | 74HC595 输出(慢速信号) |
| `VO1_P` | 出 | **P5-HARNESS 的手机侧电容组**(2026-09-03 新增,见下) |
> 复制成 5 路时要改的只有三样:
> 1. **位号百位**(1xx → 2xx/3xx/4xx/5xx),U / J 按 §16.0 的表换号;
> 2. **七个网络名**:`VDACn` / `EFUSE_ENn` / `EFUSE_FLTn` / `EFUSE_PGn` /
> `Kn_PWR` / `Kn_VUP` / `Kn_VDN`,以及输出网络 `VOn` / `VOn_F` / `VOn_P`;
> 3. **INA226 的 A0/A1 地址跳线**(地址表见 §8.2)。
>
> `BUCK_PG`、`INA_ALERT`、`SDA`、`SCL`、电源地网络五路共用,**不要加后缀**。
#### `VOn_P` 端口(2026-09-03 画 P5 时补的)
`VOn_P`(Rs*01 之后 → J*.1 / Q*02 漏极 / INA226 的 VIN− 与 VBUS)原来是页内一段
**没有名字**的网络。P5-HARNESS 的手机侧电容组要挂在这个节点上,跨页就必须有名字,
于是从 J2 那根横线(`y=695`)上引一段 50 长的支线,末端放 `VOn_P` 端口
(`(960,745)`,`dir='OUT'`,标签朝右)。五页同构,`p2gen.py` 的 `VOP_STUB` 统一生成。
> ⚠️ **`VO2_P`~`VO5_P` 在全工程里只有 1 个实例**,因为 P5 上的电容组只画了 CH1 一套
> 作代表。这不是漏接,`.claude/xpage.py` 的 `NAMING_ONLY` 集合已经把它们列为例外。
> 哪天把 CH2~CH5 的电容组也画上去,就把它们从那个集合里删掉。
### 16.5 五路复制(2026-09-03 做完)
`P2B-CH2` ~ `P2E-CH5` 四页用 `dmt_Schematic.copySchematicPage` 从 P2 复制出来,
然后由 `.claude/p2gen.py` + `.claude/p2push.py` 按通道号改写。五页各自几何验证六项全过,
跨页对账 **0 个"只有一个实例"的网络、0 个待补对端**(原来有 33 个)。
图页顺序:P1-INPUT / P2-CHANNEL / P2B-CH2 / P2C-CH3 / P2D-CH4 / P2E-CH5 /
P3-CONTROL / P3B-EXPAND / P4-USB / P5-HARNESS,共 10 页。
**复制时踩到的两件事,五页一起修了**:
1. **`K1_VUP` 的端口其实没连上。** 它的引脚坐标和 `R122.1` 完全重合,
靠一段**零长度导线**"连着"——几何验证在原来的 P2 上不报,是因为那段零长度线
恰好落在引脚上。真按这个网表打样,那一路音量+ 很可能是断的。
三个按键端口现在统一改走**向上 40 的短支线**,末端才放端口。
2. **两处标签压字**:`VDAC1` 和 `K1_PWR` 的标签面对面撞在一起(渲染成 `VDACK1_PWR`);
J7 的地旗文字压在 `Q105` 的位号上。前者靠把 VDAC1 也挪到支线末端解决,
后者把地旗再往下引 40。
> ⚠️ **端口的 `dir`(IN/OUT/BI)读不回来**——API 里没有对应的 `getState_`,
> 而 dir 决定标签画在引脚左边还是右边。所以 `p2gen.py` 里的 `PORTS` 是**显式声明**的,
> 不是从页面回读的。改端口位置时必须连 dir 一起想(见 `easyeda-sch-geometry` §8b)。
## 17. P3 控制部分原理图(2026-09-03 画完)
原计划一页,实际**拆成两页**:ESP32 的 WROOM-1 符号右侧一列就有 37 个引脚,
再加 2×595 + PCA9555 + 2×DAC 的 25 个跨页端口,标签在一张 A4 上必然互相压字。
| 页 | 内容 | 元件 |
|---|---|---|
| **P3-CONTROL**(第 3 页) | ESP32-S3 主控 + USB-C 调试口 + I²C/开漏上拉 + NTC 采样 | 19 |
| **P3B-EXPAND**(第 4 页) | 74HC595 ×2 + PCA9555 + DAC63204 ×2 | 19 |
两页各自跑完 `verify_sch.py` 六项检查(0 悬空、0 单引脚网络、0 无名端口、0 同网多名),
并做了一次**跨页网络对账**(`.claude/xpage.py`):全工程 0 个"只有一个实例"的网络,
33 个待 CH2~CH5 与 P4-USB 补对端。
### 17.1 P3-CONTROL
- 引脚分配见 §8.1;调试口方案与"有意不接的引脚"也在那一节。
- ESP32 的 3V3 来自 P1 的 U19,**不依赖任何一路输出**(§8.3 的硬约束)。
- `BUCK_PG` / `INA_ALERT` / `IOEXP_INT#` 三个开漏信号的上拉电阻放在这一页
(P2 上只有 eFuse 自己的 FLT#/PGOOD 上拉,Buck 的 PWRGD 和 INA226 的 ALERT 都没有)。
- NTC:`+3V3 → 10k → 节点 → NTC 10k → GND`,节点并 100nF 后进 ADC1。
### 17.2 P3B-EXPAND
**74HC595 级联**:U21 在前(DS 接 ESP32 的 KEY_SER),`U21.Q7S → U22.DS`。
先移入的位落到 **U22.Q7**。输出分配:
| | Q0 | Q1 | Q2 | Q3 | Q4 | Q5 | Q6 | Q7 |
|---|---|---|---|---|---|---|---|---|
| U21 | K1_PWR | K1_VUP | K1_VDN | K2_PWR | K2_VUP | K2_VDN | K3_PWR | K3_VUP |
| U22 | K3_VDN | K4_PWR | K4_VUP | K4_VDN | K5_PWR | K5_VUP | K5_VDN | 空 |
`MR#` 接 +3V3,`OE#` 走 KEY_OE# 并在本页用 **100 kΩ 上拉到 +3V3**——
ESP32 复位期间 GPIO 高阻,595 输出随之高阻,配合 P2 上每个栅极的 100 kΩ 下拉,
15 个按键都不会误按(§8.1 复位安全三条里的第 2、3 条)。
**PCA9555(0x20)**:
| 端口 | 用途 |
|---|---|
| IO0_0 ~ IO0_4 | EFUSE_FLT1 ~ 5 |
| IO0_5 / IO0_6 | **BUCK_PG / INA_ALERT**(原打算直连 ESP32,挪到扩展器省 2 根 GPIO) |
| IO0_7、IO1_5 ~ IO1_7 | 备用,**直接接地** |
| IO1_0 ~ IO1_4 | EFUSE_PG1 ~ 5 |
> ⚠️ 备用脚直接接地(不串电阻)依赖"PCA9555 上电默认全部为输入"这一点。
> **固件严禁把 Port0[7] / Port1[7:5] 配成输出**,否则输出高电平会直接对地短路。
> 这条已写在图纸上。
**DAC63204 ×2**:地址见 §8.2。三处 datasheet 强制要求,**图上看不出来、接错也不报错**:
1. **FBx 必须接回 OUTx** —— 电压输出模式下这是输出运放的闭环反馈路径
(SLASEX3A 表 5-1:*"In voltage-output mode, connect to OUTx for closed-loop amplifier output"*)。
不接的话输出是开环的。
2. **CAP 接 2.2 µF 到 AGND** —— 内部 LDO 的旁路,允许 0.5 ~ 15 µF,datasheet 建议 ≈1.5 µF。
100nF 太小。
3. **VREF 不用外部基准时,要 100 nF 到地 + 上拉电阻到 VDD**。
通道分配:U6 的 OUT0/OUT1/OUT2 = VDAC1/2/3,U7 的 OUT0/OUT1 = VDAC4/5;
U6.OUT3、U7.OUT2/OUT3 未用(FB 也不接,datasheet 说未用通道保持 FB 悬空)。
> **内部基准是 1.212 V(1.1979/1.212/1.224),不是 1.25 V。**
> 增益 2× → 满量程 **2.424 V**,不是 2.5 V。§4 的公式按 0~2.5V 推的,
> 实际 Vd 上限 2.424V,所以输出下限是 **3.524 V** 而不是 3.508 V(更安全,见 §4.4)。
### 17.3 这一页还欠什么
- ~~输入侧的 INA226(U13)+ 分流电阻 Rs6 还没画~~ ✅ 2026-09-03 已补到 P1 右侧空白区,见 **§19**。
- ~~`VBUS_EN1~5` 的 100 kΩ 下拉电阻放在 P4-USB~~ ✅ 已画(R701~R705,§18.2)。
---
## 18. P4-USB 原理图(2026-09-03 画完)
EasyEDA 工程第 5 页。五路完全相同,**一路一列**,信号自上而下:
`J12~J16(USB-A 上游)→ U24~U28(TPS22918)→ J17~J21(4P 出线座)`。
几何验证六项全过:0 悬空引脚、0 单引脚网络、0 无名旗端口、0 同网多名,
而且**全页 0 处导线交叉**——D+ / D− / GND 三条从上游座直下到出线座,
VBUS 单独绕到右边过开关再回来,谁也不跨谁。
### 18.1 每一路的连接
| 信号 | 走法 |
|---|---|
| `VBUS` | J1x.VCC → **U2x.VIN → VOUT** → J1y.1。**这是全页唯一被切断的信号** |
| `D−` / `D+` | J1x.2/3 → J1y.2/3,**板上直通**,中间不串任何东西(§15.3) |
| `GND` | J1x.4 → J1y.4;USB-A 的两个屏蔽脚、4P 座的两个固定脚也都接地 |
| `VBUS_ENn` | 端口 → U2x.ON,本页带 100 kΩ 下拉 R70n |
出线座引脚顺序 **1=VBUS / 2=D− / 3=D+ / 4=GND**,与 USB-A 座的引脚顺序一致,
所以三条直通线是三条笔直的竖线,做线束时也不容易接错。
### 18.2 TPS22918 的四个外围决定(SLVSD76C Rev C 复核)
**⚠️ 引脚号先说清楚**:datasheet 里**引脚图和 Pin Functions 表看起来是反的**——
图上标注被排版拆开后读作 `1 VOUT / 2 QOD / …`。按文字坐标还原后两处其实一致,
**以表为准:`1 VIN / 2 GND / 3 ON / 4 CT / 5 QOD / 6 VOUT`**,立创的符号也是这个。
这一条接反了图上完全看不出来。
1. **ON 脚必须有下拉(R701~R705,100 kΩ)**
datasheet 原文 *"This pin cannot be left floating and must be driven either high or low"*。
ESP32 复位期间 GPIO 高阻 → 没有下拉就是"VBUS 状态不确定",
这正是 §8.1「复位安全三条」里的第 1 条。
阈值 `VIH ≥ 1 V / VIL ≤ 0.5 V`,3.3 V GPIO 直驱,中间不需要电平转换。
2. **CT 接 100 pF C0G(C721~C725),不悬空**
摆率公式 `SR = 0.55 × CT(pF) + 30`(µs/V)→ 100 pF 时 85 µs/V,
5 V 下 **tR ≈ 425 µs**(10%~90%)。
涌流 `I = CL × dV/dt`,手机尾插小板那边按 10 µF 估:`10µF × 4V / 425µs ≈ 94 mA`。
CT 悬空的话 tR 只有 135 µs,同样负载涌流 ≈ 296 mA,接近 USB 口的软启动上限。
电容电压等级:datasheet 表 3 要求 VIN 4~5.5 V 时**至少 20 V**,选的是 50 V C0G,
没有电压系数问题。
3. **QOD 直接短接 VOUT**
用内部 `RPD ≈ 24 Ω`(5 V),关断后 VBUS 约 **200 µs** 归零(CL=10 µF)。
这正是反灌保护要的:一发现电流为负就拉低 `VBUS_EN`,VBUS 必须真的塌下去,
悬空的话电荷会挂在那儿。
**约束:直接短接时总容性负载不得超过 200 µF**,超了要串 REXT 限流,否则 RPD 过热。
本设计下游只有手机尾插小板,远低于这个数。
4. **CIN 2.2 µF 必须大于 COUT 100 nF**
datasheet 原文:*"a CIN greater than CL is highly recommended"*——
反过来的话掉电时 VOUT 会高于 VIN,电流从体二极管倒灌。
这里比值 22:1,比推荐的 10:1 还宽。
### 18.3 与手册其它部分的关系
- `VBUS_EN1~5` 五个端口与 P3-CONTROL 对上(跨页对账已确认,各 2 个实例)。
- 反灌检测读的是**该路输出的 INA226(U8~U12)**,不是 USB 侧——USB 这边没有电流计。
判据与固件逻辑见 §15.2 对策 2。
- **上游只接电脑或 USB Hub**,VBUS 恒 5 V。真接了快充头把 VBUS 抬到 9 V,
TPS22918 的绝对最大是 6 V,**会当场炸**。这条在 §15.1 已经定死,这里再记一次。
用的是 USB-A 母座,所以板到 Hub 之间是一根 **A 公 - A 公**线;
这不是标准 USB 用法,好处是物理上插不了充电头。
- CT / QOD / CIN>COUT 这三条**接错了图上都看不出来,也不报错**,
和 §17.2 里 DAC63204 的三条是同一类坑。
---
## 19. 输入侧检流(P1 的【D】区,2026-09-03 补画)
`U13 INA226 + Rs6 5mΩ + C11 100nF`,量 12V 母线的电流与电压,供 §8.3 的「整板功率预算」。
### 19.1 串在哪
```
J1 → F1 → Q1(反接保护) → ┬─ D1 TVS
├─ C2/C3 470µF + C4~C6 MLCC ← 体电容在**上游**
└─ Rs6 5mΩ ──→ +12V(五路 + 辅助 Buck + 泄放)
```
- **体电容在 Rs6 上游**,所以 Rs6 量到的是负载电流,不是适配器电流。
480 kHz 的开关纹波由各路自己的输入 MLCC 就近提供(阻抗 ~0.03Ω,
远低于回到体电容那条路的走线电感),所以真正流过 Rs6 的主要是直流 + 负载阶跃。
- 量程:满板约 8 A → **40 mV**,INA226 满量程 ±81.92 mV,余量一倍;
分辨率 2.5 µV / 5 mΩ = **0.5 mA**。2512 上耗散 0.32 W(3 W 额定)。
- **PCB 上 Rs6 要放在体电容与五路分叉点之间**,Kelvin 四线焊盘(和 Rs1~Rs5 一样)。
### 19.2 接法
| 引脚 | 接到 |
|---|---|
| VIN+ | Rs6 上游焊盘(Q1 漏极侧) |
| VIN− / VBUS | Rs6 下游焊盘 = `+12V` 网络(VBUS 因此量的是母线电压) |
| VS+ | `+3V3`,旁边 C11 100nF |
| A1 / A0 | **GND / SCL → 地址 0x43**(§8.2 的地址表,不是顺排) |
| Alert / SDA / SCL | `INA_ALERT` / `SDA` / `SCL` 三个跨页端口 |
INA226 的共模范围 0~36 V,12 V 母线在范围内;A0 接 SCL 是 datasheet 允许的 16 种地址组合之一。
### 19.3 顺手修的一个真错误
P1 上 `BLD_REF` / `BLD_A` 两个端口的**引脚坐标和 U29(TL431) 的 REF / 阴极完全重合**,
靠零长度导线"连着"——和 P2 上 `K1_VUP` 是同一个毛病(§16.5)。
两个端口已往左挪 40 并补了真导线。
> 这类错误**几何验证抓不到**(零长度段会让"引脚落在导线上"这一条通过),
> 只有重画那一页时才会暴露。规律已写进 `easyeda-sch-geometry` §8a。
### 19.4 U13 的 SCL 根本没接上(2026-09-03 布线时发现并修好)
§19.3 修的是**零长度导线**那一类。同一页上还藏着**近亲的第二类**,更隐蔽:
`SCL` 端口的引脚坐标 (920, 340) 压在导线 `[920,320 → 920,570]` 的**中段**,
而不是端点。EasyEDA 只在导线端点处认连接,所以
- 原理图上 A0 与 SCL 引脚连成了一个节点,但这个节点**没有名字**;
- 导进 PCB 后它叫 `$1N257`,只有 U13.2 与 U13.5 两个焊盘;
- **U13 的 SCL 不在 I²C 总线上 —— 输入侧检流整片芯片是死的**,
§19.2 说的地址 0x43 也无从谈起。
而同一页的 `SDA` 端口引脚 (910, 380) 恰好是导线 `[910,380 → 910,570]` 的端点,
所以 SDA 是好的。**两个端口在图上长得一模一样。**
DRC / ERC / `verify_sch --nets` / 跨页对账**四道检查全过**——
`verify_sch` 的判据是"引脚落在某条导线段上",中段搭接满足这一条。
已改成:A0 的跳线在 (920, 340) 收尾,再从 (920, 340) 单独引一段到 U13.5,
端口引脚成为两段导线的共同端点。PCB 侧走 **设计 → 从原理图导入变更** 应用,
对话框逐条列出 `U13:2 / U13:5 → SCL` 两条,别无其它变更。
> **新增检查工具 `.claude/port_audit.py`**:全工程 572 个旗/端口逐个判
> "引脚是不是某条导线段的端点"。全工程当时只有这一个不合格。
> 规律已写进 `easyeda-sch-geometry` **§8a-2**。
---
## 20. P5-HARNESS 线束页(2026-09-03 画完)
原理图第 10 页,也是最后一页。**这是一页文档页**——除了【B】区的手机侧电容组,
整页都是非电气图元(矩形 / 折线 / 文字),不参与网表。
它把散在 §6.3 / §13 / §15.4 里的「板子外面怎么接」收成一张图,
装机的人对着这一页就能把线束做出来,不用翻手册。
### 20.1 四个分区
| 区 | 内容 |
|---|---|
| **【A】** | 三条线束的连接图:板端连接器(左框)→ 缆线(中间,按信号着色)→ 手机端接点(右框) |
| **【B】** | 手机侧电容组的**真电路**(C801~C806 挂在 `VO1_P` 与 `GND` 之间) |
| **【C】** | 五路对照表:CH ↔ 板端 J ↔ 输出网络 ↔ INA226 地址 ↔ 电容组位号 |
| **【D】** | 动手前必读的五条红字警告(焊 `P+`/`P−`、J600 固定脚、电容位置、C801 选型、地不共用) |
### 20.2 【A】三条线束(每台手机一套)
| 线束 | 板端 | 缆线 | 手机端 |
|---|---|---|---|
| 电源 | J2 Micro-Fit 3.0 2P:`1 VO1_P` / `2 GND` | 18 AWG 双绞,≤ 20 cm,红=正 黑=负 | 电池排线 `P+`/`P−` 焊点 → J600 pin 7/8 + G3/G4(VBATT)与 pin 1/2 + G1/G2(GND) |
| 侧键 | J7 1.25 mm 4P:`K1_PWR` / `K1_VUP` / `K1_VDN` / `GND` | AWG 26~28 细线,远离电源线 | J603 电源键 / J601 音量+ / J602 音量− / J604 公共地 |
| USB | J17 1.25 mm 4P:`VBUS1` / `USB1_DM` / `USB1_DP` / `GND` | USB 线改端子,D± 保持双绞 | 原厂尾插小板 USB-C(CC / ESD / 口温 NTC 都在其上) |
电容组接在**电源线束的手机端**,也就是排线的 `P+`/`P−` 焊点处(§6.4:装在板上无效)。
### 20.3 【B】只画了 CH1 一套
CH2~CH5 的电容组与 CH1 完全相同,**没有画出来**,位号见【C】表。
代价是 `VO2_P`~`VO5_P` 在全工程里只有一个实例,已在 §16.4 说明并在
`.claude/xpage.py` 里列为 `NAMING_ONLY` 例外。
C801~C806 六颗都是 `addIntoBom=false / addIntoPcb=false` 放的,
读回 `getState_AddIntoBom()` / `getState_AddIntoPcb()` 确认过是 `false`。
**它们不会出现在贴片 BOM 里,也不会被拉进 PCB。**
### 20.4 画法上的两条新经验
1. **文档页不要用 `sch_PrimitiveWire` 画表格线和示意线** —— 导线会被判成网络,
`verify_sch.py` 会报一堆单引脚网络。用 `sch_PrimitiveRectangle` /
`sch_PrimitivePolygon` / `sch_PrimitiveText`(带颜色和粗体),三者都没有电气含义。
矩形的 `topLeftY` 在 Y 向上的坐标系里是**上边**,高度往 y 减小的方向长。
2. **文字宽度要在本地算出来查越界**:`宽度 ≈ 字号 × (CJK 数 + 0.5 × ASCII 数)`,
A4 可用区 `x 20~1145 / y 10~812`,标题栏占 `x>455 且 y<192`。
`.claude/p5_harness.py` 的 `selfcheck()` 已经把这两条做成自动检查。
细节都写进了 `easyeda-sch-geometry` skill 的 §12。
---
## 21. USB2517I 硬件配置(2026-09-03 按 datasheet 逐条复核)
### 21.1 用哪一份 datasheet ⚠️
**`2517.pdf` —— SMSC USB2517, Revision 2.8 (09-17-12), 50 页。**
> ⚠️ 从 Microchip 站上还能下到 `00001692C.pdf`,那是 **USB251x*B* 系列**
> (USB2517B,带电池充电支持)的手册,**另一个世代、引脚与寄存器都不同**。
> 我们的料是 `USB2517I-JZX`(C478081),**必须看 2517.pdf**。
### 21.2 引脚号:图和表打架,**表是对的** ⚠️
QFN-64 引脚图(Figure 2.1)和引脚表(Table 5.1)在几个脚上互相矛盾,
典型的是 `RBIAS`:图上读出来是 64、表里写的是 63。
**判别办法**(和 §18 的 TPS22918 完全同一个套路):把引脚图的文字**按坐标还原**——
`fitz` 的 `get_text("words")` 拿到每个词的 xy,再按「同一行/同一列」把引脚号和标签配对,
而不是按 PDF 的文本流顺序读。还原结果与 Table 5.1 **逐脚一致**:
```
VDDA33 = 5, 10, 52, 57 (图的文本流顺序会读成 1, 12 —— 错)
RBIAS = 63 VDD33PLL = 64 VDD18PLL = 62
VDD33 = 46 VDD33CR = 24 VDD18 = 25
```
结论:**图的文本流顺序不可信,Table 5.1 可信。** 本设计用的引脚号:
| 功能 | 脚号 |
|---|---|
| 上游 `USBUP_DP` / `USBUP_DM` | **59 / 58** |
| 下行 `USBDN[1..7]_DP` | **2, 4, 7, 9, 12, 54, 56** |
| 下行 `USBDN[1..7]_DM` | **1, 3, 6, 8, 11, 53, 55** |
| `VBUS_DET` | **44** |
| `RESET_N` | **43** |
| `RBIAS` | **63** |
| `XTAL1/CLKIN` / `XTAL2` | **61 / 60** |
| `CFG_SEL0`(=SCL) / `CFG_SEL1`(=HS_IND) / `CFG_SEL2` | **41 / 42 / 13** |
| `SUSP_IND/LOCAL_PWR/NON_REM0` | 45 |
| `SDA/SMBDATA/NON_REM1` | 40 |
| `LED_B3_N/GANG_EN` | 34 |
| `PRTPWR[1..7]` | 29, 26, 23, 20, 30, 39, 36 |
| `OCS[1..7]_N` | 28, 27, 22, 21, 35, 38, 37 |
| `TEST` | 19 |
| 电源 | `VDD33`=46、`VDD33CR`=24、`VDD33PLL`=64、`VDDA33`=5/10/52/57、`VDD18`=25、`VDD18PLL`=62 |
| 地 | **散热焊盘(Thermal Slug)必须接 VSS** |
### 21.3 配置方式:`CFG_SEL[2:0] = 000`
Table 5.2 的三个 CFG_SEL 脚在 `RESET_N` 上升沿被锁存,决定配置来源。
本设计取 **`000` = Internal Default Configuration + Strap Options are Enabled**:
不要 EEPROM、不要 SMBus,全靠内部默认值加几个跳线电阻。
**为什么这个组合是对的 —— 关键在寄存器 06h**:
```
Table 7.1:06h Config Data Byte 1 内部默认 ROM = 9Bh = 1001_1011b
bit7 = SELF_BUS_PWR = 1 = Self-Powered operation ✅
0Ch Max Power (Self) = 01h → 2 mA
0Eh Hub Controller Max Current = 01h → 2 mA
```
即**内部默认就是自供电**,正是 §15.1 边界 2 要的。不需要 EEPROM 去改。
实现:`CFG_SEL0`(41) / `CFG_SEL1`(42) / `CFG_SEL2`(13) 各 10 kΩ 下拉到地。
> ⚠️ 别选 `100` / `101`(Dynamic Power Switching):那两档虽然让 `LOCAL_PWR` 脚
> 决定自/总线供电,但**同时会把 Strap Options 关掉**,端口禁用跳线就失效了。
### 21.4 外围元件(逐条对 datasheet)
| 位号 | 值 | 接到哪 | datasheet 依据 |
|---|---|---|---|
| **R708** | **12.0 kΩ ±1%**(C25752) | `RBIAS`(63) → GND | Table 5.1:「A 12.0kΩ (+/-1%) resistor…to set the transceiver's internal bias」。**这个值不能动** |
| **Y1** | **24 MHz ±10ppm, CL=9pF**(C2762192) | `XTAL1`(61) / `XTAL2`(60) | §9.1:「Parallel Resonant, Fundamental Mode, **24 MHz ±350ppm**」。选 ±10ppm 余量很大 |
| **C740 / C741** | **12 pF C0G**(C1547)×2 | 晶振两端 → GND | 按 Figure 9.2:`CL = (C1+CS1)(C2+CS2)/(C1+CS1+C2+CS2)`,取杂散 ~3pF、CL=9pF → C1=C2≈12pF |
| **C742 / C743** | **1 µF 0402**(C52923)×2 | `VDD18`(25)、`VDD18PLL`(62) → GND | Table 5.1 两处都写「must have a **1.0µF (or greater) ±20% (ESR <0.1Ω)** capacitor to VSS」 |
| **R709 / R710** | 100 kΩ / 100 kΩ | 上游 VBUS → 分压 → `VBUS_DET`(44) | §7.1.2 + Table 5.1:「When designing a **detachable** hub, this pin must be connected to the VBUS power pin of the USB port that is upstream」。我们的上游是可插拔的 USB-C,**属于 detachable**,所以要真接、不能拉到 3.3V。该脚是 3.3V 逻辑,5V 必须分压 |
| **R711~R713** | 10 kΩ ×3 | `CFG_SEL[2:0]` → GND | §21.3 |
| **R714 / R715** | 10 kΩ ×2 | `USBDN6_DP`(54)、`USBDN7_DP`(56) → **+3V3_HUB** | Table 5.1:「To disable, **pull up with 10K resistor to 3.3V**」。见 §21.5 |
| **R716** | 10 kΩ | `RESET_N`(43) → +3V3_HUB | 上拉;同时由 74HC595 的备用输出驱动,见 §21.6 |
| 去耦 | 100 nF ×7 | `VDD33`(46)、`VDD33CR`(24)、`VDD33PLL`(64)、`VDDA33`(5/10/52/57) | 每个电源脚一颗,就近 |
| 储能 | 10 µF ×1 | +3V3_HUB | |
> **VBUS_DET 为什么必须真接上游 VBUS**:USB 2.0 §7.2.1 规定,
> 上游 VBUS 没上电时下行口不许给 D± 上拉。Hub 靠这个脚判断主机在不在;
> 上游断电后 10 秒内撤掉 D+ 上拉。**接成常高(拉到 3.3V)只在「主机永久连接」时才合法**,
> 我们是插拔式,必须分压引真 VBUS。
### 21.5 端口分配与两个用不上的口
| Hub 端口 | 去向 |
|---|---|
| 1 ~ 5 | CH1 ~ CH5 → J17~J21 → 手机原厂尾插小板 |
| 6, 7 | **禁用**:`USBDN6_DP`(54) / `USBDN7_DP`(56) 各 10 kΩ 上拉到 +3V3_HUB |
禁用而不是悬空,是为了 `lsusb` 上不出现两个永远空着的口。
跳线只在 `CFG_SEL=000`(Strap Options Enabled)下有效 —— 这是选 `000` 的另一个理由。
> 想把某个口放出来用(比如以后接个 USB 转串口),**拆掉对应那颗 10 kΩ 即可**,
> 焊盘留着。但目前板上没有把 6/7 口引到任何连接器,所以「备用」是指芯片有余量,
> 不是指有现成的口可插。
### 21.6 故意不接的脚
| 脚 | 处理 | 理由 |
|---|---|---|
| `PRTPWR[1..7]` | **不接** | 端口通断权在 ESP32 手里(§15.2 对策 2),不能交给 Hub |
| `OCS[1..7]_N` | **不接** | Table 5.3:`IPU`,内部上拉到 3.3V,悬空 = 无过流 ✅ |
| `LED_A*` / `LED_B*` | **不接** | 不做指示灯。⚠️ 但 `LED_B3_N`(34) 兼 `GANG_EN`、`LED_B[2:1]`(48/50) 兼 `BOOST[1:0]`、`LED_A*` 兼 `PRT_SWP*`,**这些脚都是 Strap,悬空取默认 '0'**:单独通断/单独过流检测、PHY 不加强、端口极性正常 —— 都符合本设计 |
| `SDA/NON_REM1`(40)、`SUSP_IND/LOCAL_PWR/NON_REM0`(45) | 各 10 kΩ 下拉 | 取 `NON_REM[1:0] = '00'` = 所有端口可移除。**注意 45 脚同时是 `LOCAL_PWR`**,但在 `CFG_SEL=000` 下自/总线供电由寄存器 06h 决定(§21.3),不看这个脚 |
| `TEST`(19) | 下拉到 GND | `IPD`,仅工厂测试用 |
### 21.7 复位
`RESET_N`(43):datasheet 说拉到 VDD33 即可用内部 POR、不需要外部复位电路。
本设计在此基础上**再引一根到 74HC595 的备用输出**(U21/U22 共 16 个输出,
15 路按键只用了 15 个,正好剩 1 个),让 ESP32 能远程复位 Hub——
Hub 偶尔枚举不出来时不用跑到机架前,符合本项目「远程救砖」的一贯思路。
R716 10 kΩ 上拉保证 ESP32 复位期间(`KEY_OE#` 被 R609 拉高 → 595 输出高阻)
`RESET_N` 仍是高电平,**Hub 不会跟着被复位**。
> ⚠️ PCA9555 的 4 个备用脚**不能**拿来做这件事——它们直接接了地(见 §9.1 的注),
> 固件严禁把它们配成输出。
---
*文档随设计推进更新。修改任何一节,请同步更新 §11 的验证项。*
---
## 22. 两板架构:电源底板 + 主板载板(2026-09-04 用户拍板)
### 22.1 为什么改,改了什么
原方案是**一块板 + 三条线束 × 5 台**(§15.4)。改成两块板对插:
```
┌──────────────────────────────────────────────────────────┐
│ 上板(载板) 5 块小米8 主板(反面朝下)+ USB Hub + VBUS 开关 │
│ 顶针顶侧键 / 1.25mm 座接 EDL / P+P− 焊盘 + 电容组 │
└───────────────────────────┬──────────────────────────────┘
2.54 排针(只走电源 + 低速控制,**没有 USB**)
┌───────────────────────────┴──────────────────────────────┐
│ 下板(电源板)12V 进 → 五路 4A → eFuse → 分流 → 排针座 │
│ ESP32-S3 + DAC + 六片 INA226 + 两片 595 + PCA9555 │
└──────────────────────────────────────────────────────────┘
```
**分工**
| 下板(纯电源 + 控制大脑) | 上板(载板) |
|---|---|
| J1 12V 进线 / F1 / Q1 反接 / TVS / 泄放 | 5 块主板定位孔 + 立柱 |
| 五路 Buck + DAC + eFuse + 分流电阻 + INA226 | **U32 USB2517I + Y1 + 全部 strap + U31 3V3 LDO** |
| U13 输入侧检流、U19 辅助 3V3、U30 12V→5V | **U24~U28 TPS22918 VBUS 负载开关** |
| ESP32-S3 + 74HC595 ×2 + PCA9555 | **J23 上游 USB-C** |
| **侧键驱动管 Q1x3~Q1x5** | 5 组侧键顶针、5 组 EDL(1.25mm 2P 座 + 模拟开关)|
| J22 调试 USB-C | 5 组 `P+`/`P−` 焊盘 + §6.3 电容组 |
**两处按工程判断定的**(用户没明说):
1. **侧键驱动管留在下板。** 移上去不省针数(每台仍是 3 根控制线),却要重画五路的按键部分。
留下等于只把 J7~J11 换成排针针位,原理图改动最小。
2. **EDL 开关放上板。** `FORCED_USB_BOOT` 是 1.8 V 逻辑脚、旁边挂着 ESD 管;
把 TP1204/TP1205 拉到下板再拉回来,等于在这个脚上挂一段长残桩。
开关就近放在 1.25mm 座旁边,穿排针的只剩 1 根控制线。
**跟着 Hub 一起上去的四样,少一样都白改**:U32 本体、U31(§9.5 要求就近供电)、
U24~U28(VBUS 开关隔着连接器等于把 VBUS 绕远)、**J23 上游 USB-C**
(留在下板的话上游那对 D± 还是要穿排针)。改完之后**一根高速差分都不穿连接器**。
### 22.2 排针接口定义(2026-09-04 定稿,原理图 P5-BTB 已画完)
**用两条 2×20(各 40 针,合计 80 针)**,分列板子两端。
不是 §22.2 初稿说的「一条 2×32 或两条 2×16」——
64 针按通道切怎么都不整齐(5 路 × 11 针 = 55,任何 32/32 的切法都会把某一路劈开),
用两条 2×20 反而干净:**J24 = CH1 + CH2 + 全局,J25 = CH3 + CH4 + CH5**,
多出来的 16 针**全部接地**,正好给 4A 回流加粗。
**下板装公头**(`C55020601` AZ-PZ2.54-V11-2\*20P,塑高 2.5 / 配合针长 6,直插镀金),
**载板装母座**(`C5307344` PC104-2×20,塑高 10.5,直插)。对插 = **13.0 mm**。
选型全过程见 **§22.3f**(2026-09-05 定稿,此前那两个占位料号已作废)。
**编号约定**(2026-09-05 两颗符号都在 EDA 里实测过,逐脚读回坐标):
**第 r 行 = 引脚 2r−1(左列)/ 2r(右列)**,第 1 行在符号中心上方 95 个单位。
两列 x 偏移 ±30,行距 10。
#### ✅ 公母同一套编号(旧的「两套编号」陷阱已随换件消失)
换件前是两套:下板公头 DIP 式(第 r 行 = r / 41−r)、载板母座 IDC 奇偶式
(第 r 行 = 2r−1 / 2r),查线只能按行号对。**换成 `C55020601` + `C5307344` 之后
两颗完全一致,都是 IDC 奇偶式**,`VO1_P` 在两块板上都是 1 / 3 / 5 脚。
原理图侧本来就不会错 —— `c1_conn.py` 直接 import `p5_btb.py` 里那两张按行组织的表
来生成载板页,两边共用同一个事实来源,没有任何手工转写。
⚠️ **但 PCB 上那条风险还在**:符号编号一致 ≠ 第 r 行真的对上第 r 行。
公头在下板顶层、母座在载板底层,**底层元件在顶视图里是镜像的**,
两个封装的焊盘编号 + 摆放镜像共同决定对位关系。
以 `pcb2-header-pads.json` 导出的 80 个焊盘坐标为准,**布板时必须实打实核对一次**。
#### ⚠️ 2026-09-05 重排:按**载板几何**分配,不再按通道号切
原来是 `J24 = CH1+CH2+全局 / J25 = CH3+CH4+CH5`,那是 09-04 定的、**当时载板 PCB 还不存在**。
载板画出来之后发现 09-04 那版有一条**硬冲突**:排母南排前 16 位全是 GND 焊盘,
Ø1.70 / 间距 2.54 ⇒ 相邻边距 0.84 mm,扣掉两边 0.2 净距,Inner1 上每个缝只剩 **0.44 mm 铜网**,
而 4 A 按 IPC-2221 内层 0.5 oz 要 **6.97 mm** —— **4 A 的电源面穿不过排母的地针行**。
偏偏 09-04 那版把 `VO4_P` / `VO5_P` 放在 J32 的**北**排,它们的站却在排母**南**边。
**新规矩:北排喂北边的站,南排喂南边的站,一路都不许跨行。** 依据是载板几何:
```
J31 焊盘 x 37.87~ 86.13 正对 site1(x 5~72,北) 和 site4(x 41~108,南)
J32 焊盘 x 133.87~182.13 正对 site3(x 148~215,北) 和 site5(x 112~179,南)
site2 (x 76.5~143.5,北) 夹在两颗中间 → VO2_P 取 J31 北排最右三针(x 81~86),
正好顶着 site2 最左边的负载 C811(x 86.0)
```
重排后五路 `VOn_P` **全部同侧**,Inner1 上最远曼哈顿距离从 **~120 mm**(VO4 原来要绕排母端头、
钻手机 2 底下再折回来)降到 **≤42 mm**。逐项见 **§25.10**。
两处随之改的针数(网络表一个都没变,只是落点变了):
| | 09-04 | 09-05 | 为什么 |
|---|---|---|---|
| `+5V` | 3 针(全在 J31 北排)| **10 针**,两颗排母 × 南北四处 | 不是为了电流(2.8 A/10 = 0.28 A/针),是为了**就近落地**,免得在 Inner1 上拉一条横贯全板的脊 |
| `GND` | 33 针 | **26 针** | 让位给 +5V;20 A 回流 = 0.77 A/针,仍宽裕 |
| 信号 | 47 | 54 | = 15 VO + 10 +5V + 25 站内 + 4 全局 |
**唯一事实来源是 `.claude/p5_btb.py` 里的 `J24` / `J25` 两张表**,
`c1_conn.py` 直接 import 它生成载板页,下面两张表是从同一份数据生成的。
#### J24(对插载板 J31)—— site1(北) + site4(南) + site2 电源 + 全局
| 行 | 北排(奇) 脚 / x mm | 网络 | 南排(偶) 脚 / x mm | 网络 |
|---|---|---|---|---|
| 1 | 1 / 37.87 | **`VO1_P`** | 2 / 37.87 | `GND` |
| 2 | 3 / 40.41 | **`VO1_P`** | 4 / 40.41 | `GND` |
| 3 | 5 / 42.95 | **`VO1_P`** | 6 / 42.95 | `GND` |
| 4 | 7 / 45.49 | **`+5V`** | 8 / 45.49 | `GND` |
| 5 | 9 / 48.03 | **`+5V`** | 10 / 48.03 | `GND` |
| 6 | 11 / 50.57 | `POGO1_PWR` | 12 / 50.57 | `POGO4_PWR` |
| 7 | 13 / 53.11 | `POGO1_VUP` | 14 / 53.11 | `POGO4_VUP` |
| 8 | 15 / 55.65 | `POGO1_VDN` | 16 / 55.65 | `POGO4_VDN` |
| 9 | 17 / 58.19 | `EDL_EN1` | 18 / 58.19 | `EDL_EN4` |
| 10 | 19 / 60.73 | `VBUS_EN1` | 20 / 60.73 | `VBUS_EN4` |
| 11 | 21 / 63.27 | `SDA` | 22 / 63.27 | **`+5V`** |
| 12 | 23 / 65.81 | `SCL` | 24 / 65.81 | **`+5V`** |
| 13 | 25 / 68.35 | `GND` | 26 / 68.35 | `UP_VBUS_DET` |
| 14 | 27 / 70.89 | `GND` | 28 / 70.89 | `GND` |
| 15 | 29 / 73.43 | `GND` | 30 / 73.43 | **`VO4_P`** |
| 16 | 31 / 75.97 | `GND` | 32 / 75.97 | **`VO4_P`** |
| 17 | 33 / 78.51 | `GND` | 34 / 78.51 | **`VO4_P`** |
| 18 | 35 / 81.05 | **`VO2_P`** | 36 / 81.05 | `GND` |
| 19 | 37 / 83.59 | **`VO2_P`** | 38 / 83.59 | `GND` |
| 20 | 39 / 86.13 | **`VO2_P`** | 40 / 86.13 | `GND` |
#### J25(对插载板 J32)—— site3(北) + site5(南) + site2 信号
| 行 | 北排(奇) 脚 / x mm | 网络 | 南排(偶) 脚 / x mm | 网络 |
|---|---|---|---|---|
| 1 | 1 / 133.87 | **`+5V`** | 2 / 133.87 | **`+5V`** |
| 2 | 3 / 136.41 | **`+5V`** | 4 / 136.41 | **`+5V`** |
| 3 | 5 / 138.95 | `POGO2_PWR` | 6 / 138.95 | `VBUS_EN5` |
| 4 | 7 / 141.49 | `POGO2_VUP` | 8 / 141.49 | `EDL_EN5` |
| 5 | 9 / 144.03 | `POGO2_VDN` | 10 / 144.03 | `GND` |
| 6 | 11 / 146.57 | `EDL_EN2` | 12 / 146.57 | `GND` |
| 7 | 13 / 149.11 | `VBUS_EN2` | 14 / 149.11 | `GND` |
| 8 | 15 / 151.65 | `HUB_RST` | 16 / 151.65 | `GND` |
| 9 | 17 / 154.19 | `GND` | 18 / 154.19 | **`VO5_P`** |
| 10 | 19 / 156.73 | `GND` | 20 / 156.73 | **`VO5_P`** |
| 11 | 21 / 159.27 | `GND` | 22 / 159.27 | **`VO5_P`** |
| 12 | 23 / 161.81 | `POGO3_PWR` | 24 / 161.81 | `POGO5_PWR` |
| 13 | 25 / 164.35 | `POGO3_VUP` | 26 / 164.35 | `POGO5_VUP` |
| 14 | 27 / 166.89 | `POGO3_VDN` | 28 / 166.89 | `POGO5_VDN` |
| 15 | 29 / 169.43 | **`VO3_P`** | 30 / 169.43 | `GND` |
| 16 | 31 / 171.97 | **`VO3_P`** | 32 / 171.97 | `GND` |
| 17 | 33 / 174.51 | **`VO3_P`** | 34 / 174.51 | `GND` |
| 18 | 35 / 177.05 | `EDL_EN3` | 36 / 177.05 | `GND` |
| 19 | 37 / 179.59 | `VBUS_EN3` | 38 / 179.59 | `GND` |
| 20 | 39 / 182.13 | **`+5V`** | 40 / 182.13 | **`+5V`** |
**合计 54 个信号 + 26 个地。** 五路 `VOn_P` 仍是 3 针并联(4 A / 3 = 1.33 A 每针,
母座额定 2.5 A 每针),**正对面 3 针 GND** 做本路回流(§15.4 各路独立回地不变)——
`p5_btb.py` 的 `plan()` 里有断言逐行核这一条。
#### 为什么侧键网络叫 `POGOn_*` 而不是 `KEYn_*`
驱动管留在下板(§22.1),所以**同一路按键有两个节点**:
栅极侧(ESP32 / 74HC595 来的)已经叫 `Kn_PWR`,漏极侧(穿排针去顶针的)如果叫
`KEYn_PWR`,两个名字只差一个字母 —— 这种命名迟早会接错。
改叫 **`POGOn_PWR` / `POGOn_VUP` / `POGOn_VDN`**,同时也点明了载板那头是顶针。
**侧键的公共地不占排针**:J604 是三键公共地(§13.3),在载板上直接接本路的电源返回地即可。
下板原来 J7~J11 上那三个专门的地针(每键一个)随连接器一起删掉了。
> **风扇不占排针**(2026-09-04 用户定:风扇装 3D 打印外壳上)。
> 风扇的 12V、PWM、TACH 全部从**下板**直接出线(J26~J30,见 §22.6)——
> 下板本来就有 12V 母线和 ESP32,绕到载板再绕回来毫无意义。
**电气复核**:三针并联的接触电阻约 5 mΩ,4 A 时压降 20 mV,可接受。
回路电感从线束的约 300 nH 掉到 **30~50 nH** 量级 —— §6.1 / §6.2 的谐振频率与
阻尼比要按这个重算,结论方向是**比原来更过阻尼**,C801 用普通铝电解做阻尼依然成立。
### 22.3 小米8 主板机械数据(从我们自己的 PDF 反推)
⚠️ **纠正一条旧结论**:`小米8原理图/Xiaomi_Mi_8_Schematic.pdf` 的**第 1、2 页是正反面位号图**
(含完整板框轮廓 + 全部位号),不是原理图。PROGRESS 里「PDF 不含任何机械尺寸、
必须实测」那条是错的,**头号阻塞项其实一直不存在**。
**比例尺标定方法**(可复现):原理图页上每个器件都标了封装(0201 / 0402 / …),
把「位号 → 封装」抽出来,再到位号图上量同名器件的矩形,反推 pt→mm:
| 封装 | 样本数 | 长边 pt/mm | 短边 pt/mm |
|---|---|---|---|
| 0201 | 464 | 16.80 | 17.20 |
| 0402 | 35 | 18.96 | 20.16 |
| 0603 | 9 | 18.45 | 20.25 |
取 **17.0 pt/mm**(0201 样本最多、长短边最一致;大封装偏大是因为画的是焊盘外框)。
**主板尺寸:卡尺实测 44.66 × 67.09 mm**(2026-09-04 用户实测,**以此为准**)。
反推比例尺 x 17.15 / y 16.93 pt/mm —— 与上表从 0201 推出的 17.0 只差 0.7%,图纸确认无误。
### 22.3a 七个定位孔(2026-09-04 从实测照片提取)
⚠️ **又一条旧结论被推翻**:先前从位号图上找同心圆,判定「主板没有定位孔、只能靠压板」,
**是错的**。实物照片上有 **7 个金属包边的定位孔**,沿板子周边分布。
错因是我在矢量图元里找「同心圆组」,抓到的全是测试点和圆焊盘;
而位号图上的孔要么没画成圆、要么被元件挡住 —— **没有实物对照就不该下这种结论**。
坐标从用户标注的照片提取(板体最大连通块定包围盒,按实测长宽标定),
**照片方向、板左下角为原点,单位 mm**:
| 孔 | X | Y | 位置描述 |
|---|---|---|---|
| H1 | 54.2 | 42.3 | 上边偏右 |
| H2 | 2.6 | 38.2 | 左边缘上 |
| H3 | 61.9 | 33.7 | 右边缘上(与 H4 成对)|
| H4 | 62.1 | 29.2 | 右边缘下 |
| H5 | 2.6 | 27.0 | 左边缘中 |
| H6 | 4.0 | 10.8 | 左下 |
| H7 | 42.6 | 3.7 | 下边偏右 |
**精度**:包围盒长宽比 1.533,实测 1.502,差 2%(拍摄轻微透视)→ 坐标误差约 **±0.5 mm**。
载板上的孔按 **Ø2.5 mm 沉孔或长圆槽**做,足以吸收这个误差;
装配时以 H2/H5(左边缘那两个,间距 11.2 mm)做主基准,其余给余量。
### 22.3b 统一坐标系(**后续所有机械工作以这张表为准**)
**顶视坐标系**:从上往下看装配体,板 **67.09 (X) × 44.66 (Y) mm**,左下角为原点。
就是用户那张标红框照片的方向 —— 主板「朝上那面」朝着你。
**三个变换关系(都已验证)**:
1. 照片朝向 = 位号图 page1 视图**逆时针转 90°**(用户 2026-09-04 目视确认)。
换算:`X = 67.09 − y_图`,`Y = x_图`。
2. 位号图 page2(反面)= page1 **上下翻转**(轮廓匹配:边界差 0.0194,
左右镜像是 0.057,差一倍多)。合成后 `x_view = 44.66 − x₂`,`y_view = y₂`。
3. **验证**:按 ① 预测 J600 / J1401 / TP1204 / TP1205 应落在照片的
(392,609) / (735,637) / (688,596) / (650,594) 像素处 —— 照片上那三处正好是
一个中等 BTB 座、底边那条长 BTB 座、以及紧挨着它的两个测试点。**三点独立吻合,映射成立。**
| 特征 | X | Y | 在哪一面 | 精度 |
|---|---|---|---|---|
| H1 定位孔 | 54.2 | 42.3 | 通孔 | ±0.5 |
| H2 | 2.6 | 38.2 | 通孔 | ±0.5 |
| H3 | 61.9 | 33.7 | 通孔 | ±0.5 |
| H4 | 62.1 | 29.2 | 通孔 | ±0.5 |
| H5 | 2.6 | 27.0 | 通孔 | ±0.5 |
| H6 | 4.0 | 10.8 | 通孔 | ±0.5 |
| H7 | 42.6 | 3.7 | 通孔 | ±0.5 |
| **TP1204 (EDL)** | **45.41** | **4.99** | 朝上 | **±0.3**,本体 0.73×0.74 |
| **TP1205 (EDL)** | **42.64** | **4.99** | 朝上 | **±0.3**,本体 0.73×0.74 |
| **J1401 尾插座** | **53.58** | **2.86** | 朝上 | **±0.3**,本体 2.27×12.25 |
| J600 电池座 | 23.8 | 4.6 | 朝上 | ±2(**位号文字位置**,本体没匹配上)|
| **J601 侧键** | **2.70** | **4.60** | 朝下(已折算顶视投影)| **±0.3**,本体 2.23×1.21 |
| **J602** | **5.41** | **6.52** | 朝下 | **±0.3**,本体 2.22×1.20 |
| **J603** | **3.11** | **6.91** | 朝下 | **±0.3**,本体 1.21×2.21 |
| **J604** | **2.12** | **2.46** | 朝下 | **±0.3**,本体 0.69×1.10 |
**触点坐标怎么来的**:先按位号文字位置估(±1~2 mm),后改成**匹配器件本体图元**,
到 ±0.3 mm。匹配规则:测试点找直径 0.75±0.25 mm 的圆、连接器找附近面积最大的矩形、
侧键找 0.4~3.5 mm 的焊盘,并且**一个图元只能被一个位号认领**(不去重会让
TP1204/TP1205 指向同一个圆)。
**三点自洽验证**:TP1204 与 TP1205 各自量出 **0.73 × 0.74 mm**(原理图标注 `TP0.75mm`)、
**Y 坐标完全相同**、间距 2.77 mm —— 比例尺、图元匹配、坐标变换三样同时对上才可能这样。
⚠️ 仍要注意:
- 7 个孔 ±0.5 mm(实测照片),触点 ±0.3 mm(矢量图元),**J600 是 ±2 mm**(本体没匹配上,用的还是位号文字位置)。
- **打样前顶针与 EDL 焊盘要拿实物复核**,或做成稍大的焊盘 / 可调顶针座。
机器可读版:`.claude/mi8_mech.json`(孔位与总体)、`.claude/mi8_contacts.json`(器件本体版触点)。
**关于「找精确机械图纸」**(2026-09-04 查过,结论:不用找了):
小米8(dipper) 的免费 boardview 在 vinafix 等站上**只有 Mi 8 Lite 与 Mi 8X(Mi A3)**,
都是别的板子;付费站(laptop-schematics / mobilerdx)声称有 BRD 但要账号积分,
而且给的是同一份数据的另一种封装。手机厂商不公开 DXF/STEP。
**我们手上这份位号图本来就是矢量的、精度等于原始 CAD**,卡尺又把比例尺锁到 0.7% ——
限制精度的从来不是图纸,是提取方法。
**关键触点**(看图方向,板左下角为原点):
| 触点 | 面 | 位置 mm | 用途 |
|---|---|---|---|
| J600 电池座 | 正面 | (4.7, 43.1) | BM3E 排线,接 `P+`/`P−`(§13.5:**必须保留原厂排线**)|
| J1401 尾插座 | 正面 | (2.5, 18.3) | 尾插小板 FPC → USB-C |
| **TP1204 / TP1205** | 正面 | (5.6, 21.6) / (5.8, 24.4) | EDL,间距 2.8 mm,**焊盘 0.75 mm** |
| J601~J604 侧键 | **反面** | 四个挤在约 2.7 × 2.6 mm 内 | 顶针 |
**由此定死主板朝向:反面朝下贴着载板。**(用户 2026-09-04 确认「主板装在上板的上表面」,
与此一致:载板在下、主板反面贴上去、正面朝天。)
- 侧键在反面 → 顶针顶得到 ✅(定位孔正好提供对位基准)
- J600 / J1401 在正面朝上 → 排线和尾插小板从上面插 ✅
- **EDL 两个测试点也在正面朝上 → 顶针够不着**,只能焊两根线到载板上的 1.25mm 2P 座。
反正 §13.5 已经要求把排线焊到载板的 `P+`/`P−` 焊盘,焊接本来就在装配流程里。
### 22.3c 侧键坐标的实测校核 + 公差链(2026-09-04)
⚠️ 这一节我连着读错两次:先把两个读数当成「主板厚度」,又把 **7.61** 读成 1.76
(卡尺屏是旋转的,数字看反了)。以用户口述为准:
| 实测 | 含义 |
|---|---|
| **7.61 mm** | 最上面那个侧键 → **下**边框 |
| **4.03 mm** | 最左边那个侧键 → **右**边框 |
拿它校核 §22.3b 从矢量图元提的侧键坐标(顶视,板 67.09 × 44.66,左下原点):
| 实测 | 对应推算 | 差 |
|---|---|---|
| 7.61 | J603 中心 Y=6.91、本体高 2.21 → 远边 **8.01** | **0.40** |
| 4.03 | J602 中心 X=5.41、本体宽 2.22 → 近边 **4.30** | **0.27** |
**两个独立测量都落在 0.3~0.4 mm 内**,而且差值正好是「实测量到触点边缘、
推算给的是触点中心」的半宽差 —— **坐标提取方法得到验证**。
#### ⚠️ 顶针的公差链(设计必须吃掉这个误差)
```
顶针实际落点误差 = 坐标提取 ±0.3 + 定位孔 ±0.5 + 装配间隙 ≈ ±1 mm
```
而手机侧键弹片触点本体才 **1.2 ~ 2.2 mm** —— ±1 mm 有可能顶偏。
原来写的三条对策里,**前两条 2026-09-04 选型时都被否掉了**:
| 原对策 | 结论 |
|---|---|
| ~~顶针选大冠径 Ø1.5~2~~ | ❌ **这个高度档没有大冠径的**。选定的 YTC1P-2510-01 柱塞只有 **Ø0.9 球头**(§22.3e) |
| ~~顶针孔做长圆槽装配后锁死~~ | ❌ 定的是 **SMD 贴片顶针**(Ø2.0 单焊盘),回流自对中,装完不能调 |
| **首件必验** | ✅ **现在是唯一的对策**,见下 |
**所以唯一的办法是首件实测校正**:第一块载板先用一块真主板试压,
四个触点逐个测通断;打偏的把实测偏移量填回 `mi8_contacts.json` 再出第二版。
减小误差本身也有一条路:**±1 mm 里 ±0.5 来自定位孔坐标是从照片提的**。
用卡尺把那 7 个定位孔重新量一遍,这一项能直接砍掉一半。
另外,四个触点的**风险不一样**:
| 触点 | 本体尺寸 | 打偏的后果 |
|---|---|---|
| J601 音量+ | 2.23 × 1.21 | 该键失效 |
| J602 音量− | 2.22 × 1.20 | 该键失效(还连着 Fastboot 组合键)|
| J603 电源键 | 1.21 × 2.21 | **最关键**,断电重启全靠它 |
| J604 公共地 | 0.69 × 1.10(最小)| **无所谓** —— P− 已经把地送到手机了,它只是冗余 |
### 22.3e 叠层高度与顶针选型(2026-09-04 实测)
| 实测 | 值 |
|---|---|
| 裸板厚 | **0.8 mm** |
| 侧键面(**朝下**)最高件 = 屏蔽罩,高出该面 | **1.4 mm** |
| 同一个屏蔽罩量到另一板面 | 2.2 mm |
**自洽校核**:0.8 + 1.4 = 2.2 ✔ —— 两个读数描述同一个屏蔽罩,数据可信。
#### 立柱与顶针(2026-09-04 选型定稿,**推翻了原来的 2.0 mm**)
侧键触点就在板面上(高度 0),而同一面的屏蔽罩高 1.4 mm,所以立柱只有**下限**
(>1.4 mm),没有上限 —— 立柱越高,屏蔽罩净空越大、板下风道越通。
⚠️ **原来先定「立柱 2.0 mm」再去找「工作高 2.0 mm」的顶针,方向反了,而且买不到。**
把立创上唯一成系列的单针 POGO(怡远 YTC1P-XXYY-01,规格书 `C5221293.pdf`)整族列出来:
| 型号 | 立创 | 自由高 A+B | 行程 D | **压到底 C** | 库存(2026-09-04) |
|---|---|---|---|---|---|
| YTC1P-1510-01 | — | 2.00 | 0.35 | 1.65 | |
| YTC1P-1807-01 | — | 2.50 | 0.55 | 1.95 | |
| YTC1P-2010-01 | C5221287 | 3.00 | 0.70 | 2.30 | 8570 |
| **YTC1P-2510-01** | **C5221288** | **3.50** | **0.80** | **2.70** | 3385 |
| YTC1P-3010-01 | C5221282 | 4.00 | 0.80 | 3.20 | 5355 |
| YTC1P-3015-01 | C5221293 | 4.50 | 1.00 | 3.50 | 330 |
| YTC1P-3515-01 | C5221292 | 5.00 | 1.30 | 3.70 | 3180 |
| YTC1P-4015-01 | C5221281 | 5.50 | 1.30 | 4.20 | 1720 |
规格书里 A/B/C/D 的含义(图纸实测,别按名字猜):**B = 露出的柱塞长度,A = 柱塞根部到
法兰底面,C = 压到底的总高,D = 最大行程**,且恒有 `A+B = C+D = 全高`。
型号里的 `XXYY`:`XX.X` ≈ A、`YY` = B×10(1510 那一行是规格书自己的笔误)。
**全族「压到底」都 ≥ 2.30 mm,所以 2.0 mm 的间隙一根都用不了** —— 顶到底就变成硬顶块,
20 根针 × 100 g ≈ 2 kg 会把主板从立柱上顶起来。正确顺序是**先选顶针,再由它定立柱高**。
> **定稿:立柱 3.0 mm + 顶针 YTC1P-2510-01(立创 C5221288,SMD Ø2.0 单焊盘)。**
> 自由高 3.5 → 压缩 **0.5 mm = 62% 行程**(约 62 g 接触力),压到底还差 0.3 mm;
> 屏蔽罩净空 3.0 − 1.4 = **1.6 mm**。额定 12 V / 1.5 A、接触电阻 ≤100 mΩ、寿命 1 万次。
⚠️ **立创参数页把 2510 的「工作高度」写成 2.3 mm,是错的**(那是 2010 那一行的值);
同族其它型号的参数页都和规格书一致。**以规格书图纸为准**。
⚠️ **冠径只有 Ø0.9 球头**(柱塞 Ø0.9 / 外管 Ø1.5 / 法兰 Ø2.0),
**这一族没有 §22.3c 想要的 Ø1.5~2 大冠径**。所以那 ±1 mm 公差链**不是靠针头吃掉的**,
只能靠首件实测校正(§22.3c 的对策 3)。四个触点里 J601/J602/J603 窄边约 1.2 mm,
是必须打准的;**J604 只是三键公共地,而 P− 已经把地送到手机了 —— J604 打偏不影响功能**,
它是冗余而不是关键路径。
#### 叠层累计(从载板顶面往上)
```
载板顶面 ─┬─ 3.0 立柱 ─┬─ 0.8 主板 ─┬─ h_up(正面元件高,**还没量**)
│ │ └─> 主板最高点 = 3.8 + h_up
└─ 顶针工作段 3.0(自由高 3.5,压缩 0.5)
```
🚧 **还缺 h_up**(正面 = 朝上那面最高元件高出板面多少)。
它决定压板高度和整机层高,但**不影响立柱与顶针选型**,可以后补。
📌 **有压板把主板压在立柱上,所以 Z 向是确定的**(只剩立柱长度公差 + 顶针焊高,
约 ±0.15 mm),不需要按 Z 向公差留大余量 —— 选型按**接触压力**定即可。
### 22.3d ⚠️ 排针叠高与下板高元件冲突
下板上现在最高的两个件:
| 器件 | 高度 |
|---|---|
| C2 / C3 470 µF 直插电解 | 约 **12 mm** |
| R9 泄放电阻(立式)| 约 9 mm |
(J23 USB-C 3.2 mm 已经随 Hub 搬到载板,不再是约束。)
→ **两板净空必须 ≥ 13 mm**,而**标准 2.54 排针 + 插座对插高度只有 8.5~11 mm,不够**。
三条出路,推荐第一条:
1. **用加高排针**(11.0 / 13.0 / 15.0 mm 都有现成料)。改动最小,顺带改善散热。
代价:针变长、回路电感略增 —— 13 mm 针约 10 nH,三针并联约 3 nH,
相对 §22.2 的 30~50 nH 预算可以忽略。
2. 把 C2/C3 换成贴片电解 / 固态电容(矮,但容量密度低、要多几颗)。
3. 在载板上对着 C2/C3 开孔让位(载板 200×150 完全盖住下板 160×125,所以要真的开孔)。
### 22.4 EDL(9008)控制口
原理图 Sheet 17(PDF 第 19 页):
```
VREG_S4A_1P8 ──[R1204 1.8kΩ ±5% 0201]── TP1204 ← 0.75 mm 测试点
FORCED_USB_BOOT ──┬── TP1205 ← 0.75 mm 测试点
└── CR1209 PESD3V3V1BCSF ── GND
```
短接 TP1204 ↔ TP1205 = 把 `FORCED_USB_BOOT` 拉到 1.8 V → SoC 进 9008。
**串了 1.8 kΩ,短路电流只有 1.8V/1.8kΩ = 1 mA** —— 所以不需要继电器、也不需要光耦,
一颗模拟开关(TS5A3157 / NLAS4599 一类,3.3 V 供电,1.8 V 信号在导通范围内,
Ron ~1 Ω)就够。**每台一颗,放在 1.25mm 2P 座旁边。**
⚠️ 别用普通 N-MOS 直接跨接两点:源极那侧导通后会被抬到 1.8 V,
3.3 V 栅压只剩 Vgs=1.5 V,落在阈值附近。要么用模拟开关,要么用 5 V 栅压驱动。
时序:**先短接、再插 USB**(等价于原厂短接法的「保持短接再连线」)。
固件里的顺序是 `EDL_EN=1` → `VBUS_EN=1` → 等枚举 → `EDL_EN=0`。
#### `EDL_EN1~5` 从哪来:第三片 74HC595(U33,2026-09-04 新增)
排针接口要 5 根 `EDL_EN`,但 §8.1 的 GPIO 已经排满,两片 74HC595 的 16 路输出
也全被占掉了(15 路侧键 + `HUB_RST`),PCA9555 只剩 4 个空脚 —— **差一路**。
所以在 U22 之后再级联一片 **74HC595(U33,位号见 P6-FAN-EDL 页)**:
```
U21 ──QH'(9)──> U22.SER(14) [SR_CAS]
U22 ──QH'(9)──> U33.SER(14) [SR_CAS2] ← 本轮新增,U22.9 原来是悬空的
U33: QA=EDL_EN1 QB=EDL_EN2 QC=EDL_EN3 QD=EDL_EN4 QE=EDL_EN5 QF/QG/QH 备用
```
`SRCLK` / `RCLK` / `OE#` 三根与前两片共用,不占新 GPIO。
**移位链从 16 位变成 24 位,先移入的那个字节落在 U33 上** —— 固件要跟着改。
#### 载板侧已画(2026-09-04,C4-SITE1~5 各一套)
| 位号 | 器件 | 接法 |
|---|---|---|
| `U41`~`U45` | **TS5A3157DBVR**(`C353034`,SOT-23-6) | `COM`(4) 与 `NO`(1) 分别接 1.25mm 座的两针;`NC`(3) 不接;`V+`(5) = `+3V3_HUB`;`IN`(6) = `EDL_ENn` |
| `J61`~`J65` | A1251WV-S-2P(`C225104`,1.25 mm 2P) | 两根线焊到主板正面的 TP1204 / TP1205;两个固定脚接地(与 C3-USB 上的 J17 一致)|
| `R741`~`R745` | 100 kΩ | `EDL_ENn` 下拉到地 |
| `C761`~`C765` | 100 nF | 开关去耦 |
⚠ **`EDL_EN` 的 100 kΩ 下拉不在下板,在载板上**,紧挨着那颗模拟开关。
理由和按键 MOS 栅极下拉一样(§8.1 复位安全三条):下拉要靠近被驱动的器件,
否则排针一断开、载板那头就浮空。ESP32 复位期间 595 输出高阻,
下拉保证五台手机不会被误拉进 9008。
### 22.6 散热:强制风冷(2026-09-04 用户拍板)
**先说被否掉的方案**:曾提议在侧键面屏蔽罩与载板之间那 0.6 mm 缝里塞导热垫,
把 SoC 的热导进载板铜箔。**用户否决,改用风扇。**
#### 风道(用户定)
```
┌──────── 顶部 1 个大风扇,向外排 ────────┐
│ ↑ ↑ ↑ ↑ ↑ │
→→ ┌─┴───────────────────────────────────┬─┐ ←←
侧面 │ 载板:5 块主板 │ │ 侧面
2 个 │ ─────────── 13 mm 缝(天然风道)──── │ │ 2 个
吸入 │ 下板:五路功率级 │ │ 吸入
→→ └─────────────────────────────────────┴─┘ ←←
```
**4 进 1 出 = 机箱正压** —— 灰尘从缝隙往外走而不是往里吸,长期运行更干净。
两板之间那 13 mm 缝正好是侧面进风的天然风道,顺带吹到下板的功率级。
#### 热负荷与风量
| 来源 | 估算 |
|---|---|
| 5 × SDM845 满载 | 10 ~ 15 W |
| 下板五路 Buck(92%)+ eFuse + 分流 | ≈ 9 W |
| **合计** | **≈ 25 W** |
`Q = P/(ρ·cp·ΔT)`,ρ·cp ≈ 1.2 kJ/m³K、ΔT = 15 K →
**Q = 1.4 L/s = 5 m³/h ≈ 2.9 CFM**。
4 个 40 mm 风扇随便超过 —— **风量不是瓶颈,风道和正压才是设计要点。**
#### 电气(全部在**下板**,不占排针)
| 项 | 选择 |
|---|---|
| 风扇 | 侧面 4 × 小(40 mm 级)+ 顶部 1 × 大,均 **12V** |
| 电流 | 4×0.10 + 1×0.30 ≈ **0.70 A @12V = 8.4 W** |
| 供电 | 下板 12V 母线,**风扇接插件放下板边缘** |
| 驱动 | **低边 N-MOS + PWM**,一路驱动全部 5 个风扇 |
| ⚠️ | 风扇是**感性负载**,MOS 漏极必须并**续流二极管** |
| PWM | **ESP32 IO47**(LEDC 硬件 PWM)—— §8.1 原标「备用」 |
| TACH | **ESP32 IO48** |
**TACH 的接法(一个脚监 5 个风扇)**:风扇 TACH 多为集电极开路,
**5 个并到同一个脚做线或**。全转时脉冲率约为单扇的 5 倍,
停一个频率就掉约 1/5 —— **能检出「有风扇停了」,虽然分不出是哪一个**。
要分辨到具体哪个,就得把进风与排风分成两组独立控制,得再找一组 PWM/TACH 脚。
(RXD0 已经在 2026-09-04 划给 `UP_VBUS_DET` 了,只剩 TXD0 一根,不够。)**当前不做。**
#### ⚠️ TACH 必须分压,直连 IO48 会打穿 ESP32(2026-09-04 画图时才想明白)
这一条初稿漏了,但它是**低边调速 + TACH 组合的必然后果**:
低边 MOS 关断时,风扇的「地」被抬到接近 **12 V**;而 TACH 是**以风扇自己的地为参考**的
集电极开路输出,于是 TACH 线也跟着浮到 12 V。直接接 3.3 V 的 IO48 就是往 GPIO 上灌 12 V。
**实际画法**(P6-FAN-EDL 页):
```
+12V ──[R730 10k]──┬── TACH_RAW ── J26~J30 的 pin3(5 个并联)
└──[R731 10k]──┬── FAN_TACH → IO48
└──[R732 3.3k]── GND
```
- IO48 上的最高电压 = 12 × 3.3 / 13.3 = **2.98 V**,在 3.3 V 以内,不需要钳位管。
- **代价:PWM 关断期间读到的是稳定高电平,测不到转速**;只有导通期间才有脉冲。
这是低边调速的固有限制,不是接线错 —— 固件要么在占空比 100% 的时候采转速,
要么按导通窗口去数脉冲。
- 想彻底解决就得换 **4 线 PWM 风扇**(风扇常供电、PWM 是独立输入脚,
TACH 直接以板地为参考)。风扇型号还没定,**如果最终选了 4 线风扇,
这一段的 MOS + 续流管 + 分压全都可以删掉**,改成 PWM 脚直驱 + TACH 上拉到 3V3。
#### 已画元件(P6-FAN-EDL 页,2026-09-04)
| 位号 | 器件 | 作用 |
|---|---|---|
| Q6 | AO3400A | 低边开关,切 5 个风扇的回流 |
| D2 | SS34 | 续流二极管,K 接 +12V、A 接风扇回流 |
| R733 / R734 | 1 kΩ / 100 kΩ | 栅极串阻 / 栅极下拉(复位期间风扇不转) |
| R730 / R731 / R732 | 10 k / 10 k / 3.3 k | TACH 上拉 + 分压 |
| C738 | 22 µF/25 V 1206 | 风扇 12 V 本地储能 |
| J26 ~ J30 | KF2510-3A(2.54 mm 3P) | 每个风扇一个:pin1 = +12V,pin2 = 风扇回流,pin3 = TACH |
#### 对 12V 输入预算的影响
原预算:五路 4A × 4.2V ÷ 0.92 ÷ 12V ≈ **7.6 A**;
加风扇 **+0.70 A** → 约 8.3 A,**10 A 适配器仍有余量**(§1 规格不用改)。
#### 测温仍然放载板
风扇是给**手机**降温的。板上已有的两路 NTC(IO1 电感区 / IO2 MOS 区)测的是
**下板功率级**,拿它做反馈等于测错地方。而 ESP32-S3 的 ADC1 只有 GPIO1~10,
IO4~IO10 已被 `EFUSE_EN`/`VBUS_EN` 占满,**没有多余 ADC 脚**。
所以把 **I²C 引到载板**(排针 +2 针),放一颗数字温度芯片。
现有 I²C 已挂 9 个器件,再加 1~2 个没压力。
#### 待定
- 风扇具体型号、外壳风道尺寸(等 3D 外壳方案)
- 顶部排风扇的风量要 ≥ 4 个进风扇之和的多少,才不会把机箱压得过头(一般不用管,
正压是有意为之;但外壳要留泄压缝)
### 22.5 推翻 / 需要重算的地方
| 位置 | 怎么改 | 状态 |
|---|---|---|
| §6.1 / §6.2 | 线缆电感 300 nH → 板对板 30~50 nH,压降与 Q 重算 | ⬜ 还没算 |
| §6.3 / §6.4 | 电容组从「装在排线端」改成「装在载板 `P+`/`P−` 焊盘旁」,条件自动满足 | ⬜ 电容组还没画到载板上 |
| §13.3 | 侧键从飞线改成**顶针** | ✅ 下板侧已改(`POGOn_*`)|
| §15.1 / §15.2 | Hub 与 VBUS 开关移到上板;**`J17~J21` 不是取消,是跟着搬到载板**(见下) | ✅ |
| §15.4 | 线束表作废,改成 §22.2 的排针接口表 | ✅ |
| §10 PCB 布局 | 下板接口区重排(连接器分边决策作废);上板是**第二块 PCB** | ⬜ 没动 |
| 原理图 P4 / P4B | Hub 页整页搬到上板工程 | ✅ 已复制到 Board2 并从下板删除 |
| 原理图 P5-HARNESS | 从线束页改成板对板接口页 | ✅ 已改名 P5-BTB 并重画 |
| 设计文档 **§8.1** | IO47 = `FAN_PWM`、IO48 = `FAN_TACH`,从「备用」改成已分配 | ✅ 另加 IO44 = `UP_VBUS_DET` |
| 设计文档 **§8.2** | I²C 设备表加载板上的温度芯片 | ⬜ 芯片型号还没选 |
⚠️ **修正初稿的一句话**:上面原来写「`J17~J21` 取消」。实际上 J17~J21 是
**A1251WV-S-4P(1.25 mm 4P)出线座**,不是 USB-A 母座(USB-A 母座是更早的 J12~J16,
Hub 改造那一轮就已经删了)。它们**从下板整体搬到载板**,位号和接法都不变 ——
变的只是插上去的东西(§13.5:从「USB-A 转 C 短线」换成「J1401 转接小板」)。
---
### 22.7 原理图落地结果(2026-09-04,两板拆分已完成)
EasyEDA 工程 `Zy1993/五路手机直供电源板` 里现在是**两个 Board**:
| Board | 原理图 | PCB | 内容 |
|---|---|---|---|
| **Board1** `phonerail-5ch-psu` | 11 页 | `PCB1`(160×125,已布线) | 下板:电源 + 控制 |
| **Board2** `phonerail-carrier` | 3 页 | `PCB2-CARRIER`(空) | 上板:载板 |
#### 下板 11 页(页序已排好)
| # | 页 | 本轮变化 |
|---|---|---|
| 1 | P1-INPUT | 无 |
| 2 | P1B-5V | **摘掉 U31 + C736 + C737**(Hub 专用 3V3 LDO 跟 Hub 一起上载板),现在是纯 12V→5V |
| 3~7 | P2-CHANNEL / P2B~P2E | **每页删 2 个连接器**:`J2~J6`(Micro-Fit 出线)+ `J7~J11`(6P 侧键出线);三路侧键漏极改挂 `POGOn_PWR/VUP/VDN` 端口 |
| 8 | P3-CONTROL | 新增 `FAN_PWM`(IO47) / `FAN_TACH`(IO48) / `UP_VBUS_DET`(IO44=RXD0) |
| 9 | P3B-EXPAND | U22 的 `QH'`(pin9) 原来悬空,现在引出 `SR_CAS2` 去级联 U33 |
| 10 | **P5-BTB**(原 P5-HARNESS) | 整页作废重画:J24 / J25 两条 2×20 排针,47 信号 + 33 地 |
| 11 | **P6-FAN-EDL**(新建) | 【A】U33 第三片 595 → `EDL_EN1~5`;【B】风扇低边驱动 + TACH 分压 + J26~J30 |
**从下板整页删掉的**:`P4-USB`、`P4B-HUB`(已先复制到 Board2 再删)。
#### 载板 11 页(2026-09-04 全部画完,方案 D 改造后)
> 2026-09-04 深夜方案 D 改造:**C3-USB 删掉 J17~J21 五个 1.25mm 出线座**,
> 新增 **C5-J1401A / C5-J1401B**(五颗 BM24-50DS 座)和 **C5-AUX**
> (每路的 ESD + CC 上拉 + 口温电阻)。USB 链路变成:
> `C2-HUB 的 U32 → C5-AUX 的 U5n → C5-J1401 的 J7n → 原厂尾插排线 → 手机 J1401`。
> D± 不再经过 C3-USB,那一页现在只负责切 VBUS。
> 生成脚本:`.claude/c5_j1401.py` / `.claude/c5_aux.py` / `.claude/c3_usb.py`。
| 新增位号 | 器件 | 在哪 |
|---|---|---|
| J71 ~ J75 | BM24-50DS/2-0.35V(51)(`C424561`)| C5-J1401A/B |
| U51 ~ U55 | USBLC6-2SC6(`C2687116`)D± ESD | C5-AUX |
| R761 ~ R765 | 56 kΩ(`C25796`)CC1 → VBUS 的 Rp | C5-AUX |
| R771 ~ R775 | **100 kΩ**(`C25741`)口温 → GND(阻值从主板 BIAS-20k-TSKIN 分压反推,见 §13.5)| C5-AUX |
已删:**J17 ~ J21**(A1251WV-S-4P 出线座)。
#### 载板原来的 8 页
| # | 页 | 内容 |
|---|---|---|
| 1 | **C1-CONN** | 排母 J31 / J32(对插 J24 / J25)+ **U31 AMS1117-3.3**(5V→3.3V,载板唯一 3.3V 源)+ **U34 LM75BD** 温度芯片(0x48)|
| 2 | C2-HUB | 从下板搬来的 Hub 页(U32 + Y1 + 全部 strap + J23),**新增 R721/R722 上游 VBUS 检测分压** |
| 3 | C3-USB | 从下板搬来的 VBUS 开关页(U24~U28 + J17~J21),一行没改 |
| 4~8 | **C4-SITE1~5** | 每台手机一页:`P+`/`P−` 焊盘 + §6.3 电容组 + 4 根侧键顶针 + EDL(1.25mm 座 + 模拟开关 + 下拉 + 去耦)|
**为什么手机位一台一页**:一套 16 个元件,五套 80 个塞一页会挤成一团 ——
和下板「一路一页」(P2 / P2B~P2E)保持同一个结构,而且五页由
`.claude/c4_site.py` 同一段代码生成,改一处五页一起变。
#### 载板位号分配
| 位号 | 器件 | 在哪 |
|---|---|---|
| J31 / J32 | 2×20 排母(`C5307344` PC104-2×20,直插,塑高 10.5)| C1-CONN |
| U31 / C736 / C737 | AMS1117-3.3 + 10µF + 22µF | C1-CONN |
| U34 / C760 | LM75BD + 100nF | C1-CONN |
| R721 / R722 | 10k / 20k,上游 VBUS 分压 | C2-HUB |
| TP801/802, TP811/812 … TP841/842 | `P+`(红) / `P−`(黑) 焊盘(`C9900007423` / `C9900007426`)| C4-SITE1~5 |
| C801~C806, C811~C816 … C841~C846 | §6.3 电容组(每套 6 颗)| C4-SITE1~5 |
| J41 ~ J60 | 侧键顶针,每台 4 根(PWR / VUP / VDN / J604 公共地)| C4-SITE1~5 |
| J61 ~ J65 | EDL 1.25mm 2P 座 | C4-SITE1~5 |
| U41 ~ U45 | TS5A3157DBVR 模拟开关 | C4-SITE1~5 |
| R741 ~ R745 / C761 ~ C765 | 100k 下拉 / 100nF 去耦 | C4-SITE1~5 |
#### 载板上的占位型号(打样前必须换)
1. ~~顶针 `C9900001338`~~ → ✅ **已换成 `C5221288` YTC1P-2510-01**(2026-09-04,见 §22.3e)。
`c4_site.py` 里 `P['POGO']` 已改,C4-SITE1~5 五页重生成并复验通过。
2. ~~排母 `C9900025309`~~ → ✅ **已换成 `C5307344` PC104-2×20**(2026-09-05,见 §22.3f)。
塑高 10.5 + 公头塑高 2.5 = **对插 13.0 mm**,是库里唯一够得到的一族;
同时从贴片变成**直插**,80 个通孔脚自带过孔。
`c1_conn.py` / `p5_btb.py` 已改并重生成两页,编号体系换件后公母统一(§22.2)。
#### 载板位号表 J41~J60(侧键顶针)的最新型号
| | |
|---|---|
| 型号 | YIYUAN YTC1P-2510-01 |
| 立创 | C5221288(Extended Part) |
| 封装 | `SMD-1_BD2.0-H3.6`,**单焊盘 Ø2.0 贴片** |
| 符号 | 只有 1 个引脚(引脚在符号中心左侧 15 单位;老那颗是 20,所以坐标必须读回不能推) |
| 图上名字 | 改短成 `POGO`(默认名 13 字会和相邻顶针叠字);`supplierId` 未动,BOM 照旧 |
#### 上游 VBUS 检测(C2-HUB 新增)
`UP_VBUS_DET` 在 §22.2 里占了一根排针,但载板上原来没有源头。
J23 的 VBUS 是 5 V,而排针那头是 ESP32 的 IO44(3.3 V 域),所以要分压:
```
VBUS_UP(5V) ──[R721 10k]──┬──[R722 20k]── GND
└── UP_VBUS_DET → 排针 → IO44
```
5×20/30 = **3.33 V**;USB 上限 5.25 V 时 3.5 V,仍在 ESP32 绝对最大值 3.6 V 以内,
且远高于 VIH(≈2.48 V)。主机没插时 VBUS = 0,读到 0 —— 这正是要的判据。
#### 本轮新增的位号
| 位号 | 器件 | 在哪 |
|---|---|---|
| J24 / J25 | 2×20 排针(`C55020601` AZ-PZ2.54-V11-2×20P,直插,塑高 2.5)| P5-BTB |
| U33 | 74HC595D(`C5947`) | P6-FAN-EDL |
| C739 | 100 nF | P6-FAN-EDL |
| Q6 | AO3400A | P6-FAN-EDL |
| D2 | SS34(`C8678`) | P6-FAN-EDL |
| C738 | 22 µF/25 V 1206 | P6-FAN-EDL |
| R730 / R731 | 10 kΩ | P6-FAN-EDL |
| R732 | 3.3 kΩ(`C25890`,新料) | P6-FAN-EDL |
| R733 | 1 kΩ | P6-FAN-EDL |
| R734 | 100 kΩ | P6-FAN-EDL |
| J26 ~ J30 | KF2510-3A 2.54 mm 3P(`C2940511`,新料) | P6-FAN-EDL |
R735~R739(`EDL_EN` 的 100 kΩ 下拉)**故意不在下板**,见 §22.4 末尾。
#### 验证结果
| | 下板 Board1 | 载板 Board2 |
|---|---|---|
| 页数 | 11 | 8 |
| 六项几何验证 | ✅ 全过 | ✅ 全过 |
| 跨页对账 | ✅ 0 漏接 / 0 待补 | ✅ 0 漏接(62 个网络)|
| `port_audit.py` | ✅ 513 个,可疑 0 | ✅ 260 个,可疑 0 |
| 存盘后重开复验 | ✅ | ✅ |
`port_audit.py` 现在带 `--board Board2` 就扫载板(页表在 `.claude/eda-parts.json`
的 `schematic_boards` 里)。
#### 画图时踩到的三条新坑(都已写回 skill)
1. **`create()` 的 rotation 参数和 `setState_Rotation()` 差 180°。**
同样传 270:`create` 得到 SS34 的 pin1(K) 在**下**,`setState_Rotation` 得到 pin1(K) 在**上**。
所以 §6 那张「rotation 90/270 → pin1 在哪」的表**只对 create 成立**。
2. **同样是 `create(270)`,不同型号的极性元件方向还不一样。**
P5 上 2200µF 电解(C49256788)`create(270)` 得到 pin1 在上;
C4-SITE 上同一颗料同样 `create(270)` 却得到 pin1 在**下**。
结论只有一条:**极性元件一律读回 `getAllPins()` 再断言**,不要相信任何一张方向表。
`c4_site.py` 里就断言「电解 pin1 必须比 pin2 的 y 大」,不过就直接终止。
3. **引脚跨距连同族都不统一。** 红色测试点的引脚在 `cx−20`,黑色测试点在 `cx−10`;
0402 是 ±20 而 1206 是 ±15。按名义值算线会画出斜线,而 `sch_PrimitiveWire.create()`
对斜线直接抛 `create failed!`(这次就是这么被拦下的)。
`c4_site.py` 现在统一「读回坐标 → 断言横平竖直且非零长度 → 才下发」。
三条合起来是同一件事:**这个 API 里任何几何量都必须读回来,不能推。**
---
## 23. ~~Board3:J1401 尾插转接小板~~(2026-09-04 画完,当晚作废)
**这块板已经从工程里删掉了**(Board3 / `phonerail-usbtap` / `PCB3-USBTAP` 全部删除,
生成脚本挪到 `.claude/obsolete/t1_usbtap.py`)。原因见 §13.5:改回方案 A,
装原厂尾插小板 + 一根改端子的 USB-A 转 C 线,本板要解决的问题全部消失。
留下这一节,是因为画它的过程中挖出来的**四条结论在别处仍然有效**。
### 23.1 ⚠️ 立创的 BM24 封装焊盘编号是错的(仍然有效,见 §13.4 末尾)
小米8 的 J1401 是**奇偶行**编号(1,3,5…49 一排 / 2,4,6…50 另一排),
而立创的 `CONN-SMD_BM24-50DP-2-0.35V51` 和 `BM24-50DS` 封装都是**DIP 绕圈**式。
**这一条同时也是 §13.4 那张引脚表的独立佐证** —— 三条证据(符号画法、
44/46/48/50 = GND/D+/D−/GND 的差分对包地、奇数排全音频偶数排全数字)互相印证,
说明 §13.4 的表是对的。将来若有人再想自制转接板,先读 §13.4 末尾。
### 23.2 BM24 只有 10 次插拔寿命
Hirose 规格书 Durability 一栏写的是 **10 mating cycles**。
**方案 A 下同样成立** —— 原厂尾插排线插上 J1401 之后就别反复拔,
调试期要拔的话记着次数,备件按每台手机 2 根排线备。
### 23.3 Rp / Rd 分压核算(解释了为什么 A 转 C 线就够)
手机侧 PMI8998 在 CC 上挂 **Rd = 5.1 kΩ ±20%**,A 转 C 线的 C 头里是 **Rp = 56 kΩ**:
```
V_CC = VBUS x Rd / (Rp + Rd)
标称:5.00 x 5.1/(56+5.1) = 0.417 V
最低:4.75 x 4.08/(56.56+4.08) = 0.320 V
最高:5.25 x 6.12/(55.44+6.12) = 0.522 V
```
UFP 侧 **vRd-USB = 0.25 ~ 0.61 V**(Default USB 档),三个角点全在窗口内,
离两端都有 ≥70 mV 余量。往上 0.70~1.16 V 是 1.5 A 档、1.31~2.04 V 是 3.0 A 档 ——
**所以买到阻值给错的线(22 k / 10 k)会让手机以为能取 1.5~3 A,而 TPS22918 给不了。
到手务必用万用表量一下 CC 对 VBUS 是不是 56 kΩ。**
### 23.4 为什么「把转接板直接做进载板」做不到(当时的分析,结论仍然成立)
两条各自独立的硬阻碍:
1. **面朝向**:§22.3b 定死「主板反面朝下贴着载板」(侧键在反面,顶针要往上顶),
而 J1401 在正面朝天,焊在载板上的 BM24 够不着。翻过来装也不行 ——
BM24 对插高度只有 0.8 mm,主板正面的屏蔽罩超过 0.8 mm,贴不下去。
2. **自对准范围只有 ±0.3 mm**(Hirose:*alignment range of 0.3 mm*),
而 §22.3c 的公差链是 **±1 mm**,差 3 倍。**BM24 必须装在能自由浮动、
由人手对准后插进去的东西上** —— 原厂尾插排线正好就是这个东西。
### 23.5 画图时的两条 API 经验(已写回 skill §8b / §8c)
1. **EasyEDA 的 `create()` 会在元件引脚处把导线截断**。想画一条穿过芯片本体的直通线做不到 ——
中间那段直接消失。所以 USBLC6 这种「1/6 内部短接」的直通器件,
D± 在网表里天然是两段,只能各起一个名字。
2. **`xpage.py` 对单页板会误报**:只出现一次的 netport 在多页工程里意味着漏接,
在单页板上只是「给这段线起个名字」。
---
## 24. BM24-50DS 自建封装(2026-09-04 定稿)
器件已建在**个人库**:`BM24-50DS/2-0.35V(51) HRS-PIN`
(device `771dbf002b714bb79cde47cf86aa0fb1`,lib `543725e8f0454017a5691e7e570aeef6`,
封装 `BM24-50DS_HIROSE-PIN` = `940f093c1578426aa81e91ebf0bfbd76`,符号是立创原符号的副本)。
`c5_j1401.py` 已改用它,C5-J1401A/B 重生成,三道验证全绿。
**BOM 仍指向立创 C424561**(`Supplier Part` / `Convert to PCB` / `Add into BOM` 都改回 yes 了 ——
`lib_Device.create()` 的 `property` 参数会被吞掉,必须紧跟一次 `lib_Device.modify()` 补,见 §24.5)。
生成脚本:`.claude/fp_bm24.py`(`--push` 重画,`--verify` 只读回校验)。
### 24.1 几何从哪来 —— 不是外推,是从官方样本的矢量图里反算的
来源:**Hirose BM24 系列官方样本** D47680_en(2021.12③ / Aug.1.2026),
"Receptacle → Recommended PCB layout"。样本只给了一张通用图 + 一张 A/B/C 尺寸表,
**图上标的尺寸不足以直接建封装**,剩下的是从 PDF 里把矢量段坐标提出来量的:
- 标定:图上 `P=0.35 mm` 占 6.706 pt、`B=3.15 mm` 占 60.355 pt → **19.1603 pt/mm**,两处自洽。
- 顺带确认那张图画的是 **20 芯**那一款(C=7.3 / B=3.15 都能对上表)。
| 量 | 值(50 芯) | 怎么得到的 |
|---|---|---|
| 信号焊盘 | **0.18 × 0.48 mm** | 宽 0.18 是标注的;**长 0.48 样本没标**,由外缘 2.6 与内缘 1.64 相减除 2 得出 |
| 同排间距 | **0.35 mm** | `P` |
| 每排 25 个,跨距 | **8.40 mm** | `B` = 24 × 0.35,**中心到中心** |
| 两排 y | **±1.06 mm** | (2.6+1.64)/2 = 2.12 的一半;和 Header 图上标的 1.06 对得上 |
| 电源焊盘 | **0.49 × 0.76 mm** | 0.49 是标注的(**它标的是电源焊盘的宽,不是信号焊盘的长** —— 尺寸线量的是 95.44→104.83 那一段,别看错);0.76 是标注的 |
| 电源焊盘中心 x | **±6.03 mm** | `C` = 12.55 是**两个电源焊盘的外缘到外缘** → (12.55−0.49)/2 |
| 禁布区 | **±5.785 × ±0.82 mm** | 两电源焊盘内缘之间 × 两排焊盘内缘之间(样本画成阴影,注 *pattern prohibited area*)|
| 本体 | **A = 12.25 × 2.3 mm**,高 0.8 | 装配层用 |
样本上那个 `0.14MAX` 是**中线上允许穿过禁布区的一条细缝**。
**我们不用它** —— G1 是地、G2 是 VBUS,这两个电源触点绝不能连起来。
封装里画了:52 个焊盘(顶层)、丝印外框 13.2 × 2.9(在所有焊盘之外,不压焊盘)+ 1 脚标记、
装配层本体框 12.25 × 2.3、**文档层的禁布区框**(布板时铺铜别灌进去)。
> **锡膏**:Hirose 推荐钢网 0.1 mm 厚、DS 侧开口率 80%(信号开口 0.39 × 0.18,比焊盘短)。
> 封装里用的是默认「锡膏 = 焊盘」,**打样时如果自己出钢网文件要按上面缩**;走嘉立创贴片则不用管。
### 24.2 焊盘编号约定(`fp_bm24.py` 的 `ODD_ROW_TOP`)
```
奇数脚 1,3,5 … 49 → +Y 那一排 1 脚在 −X 端(x = −4.20)
偶数脚 2,4,6 … 50 → −Y 那一排 49/50 在 +X 端
pin 51 = 1/2 脚那一端的电源触点 (x = −6.03)
pin 52 = 49/50 脚那一端的电源触点 (x = +6.03)
```
和 `c5_j1401.py` 里的 `PWR = {'GND': 52, 'VBUS': 51}` 是配套的。
### 24.3 ⚠️⚠️ 唯一没有实证的一位:**哪一排是奇数排**(镜像位)
> ⚠️ **2026-09-06 载板 v2 把 J7n 翻到了底层**(rot 0 时奇数排在南,§25.16)。下面的推理是按顶层装法写的,
> 实测时以底层装法为准 —— 层翻一次手性翻一次。
BM24 的 DS 座**完全对称**(样本注 2 原文 *This connector has no polarity*;
本体图两端一模一样、上下两排也一模一样,没有任何 1 脚标记),
所以「奇数脚在哪一排」不是这颗座子本身的属性,而是**小米8 那块板子的布局事实**,
图纸查不到 —— 我们只有原理图,没有小米8 的 PCB。
把编号往位置上贴,一共有 **4 种**候选:
| | 1 脚在 −X 端 | 1 脚在 +X 端 |
|---|---|---|
| **奇数在 +Y 排** | A(现在选的)| C |
| **奇数在 −Y 排** | B | D |
- **A ↔ D、B ↔ C** 差一个 **180° 旋转** —— 贴片时转个方向就能换,**不用重打板**。
- **A ↔ B、C ↔ D** 差一个**镜像** —— 相当于每个奇数脚和它的偶数搭档对调
(D+ 会落到 45 脚 `SPKR_OUT_P` 上)。**旋转换不掉,错了要重打载板。**
原来 §13.5 写的「两种候选差一个 180° 旋转」只覆盖了前一半,**已在上面更正**。
#### 打样前必做的那一次实测(两个探点,零成本、零风险)
拿手机主板(不通电)+ 万用表通断档,在 J1401 上量:
1. **先认哪一端是 1/2 脚端**:两个电源触点(焊盘大,0.49 × 0.76 mm,好戳)分别对主板地量电阻。
~0 Ω 的那个是 **G1**,G1 就在 **1/2 脚那一端**(§13.4)。
2. **再认哪一排是奇数排**:从 G1 那一端数,两排各自的**第 2 个信号触点**分别对地量。
- **奇数排的第 2 个 = pin 3 = GND** ✔
- 偶数排的第 2 个 = pin 4 = `VREG_L19A_3P0`,**不是地**
通的那一排就是奇数排。
这两点选得刻意:都紧挨着 G1 那一端,不用在 0.35 mm 间距里数到中间去;
而且判据是「通/不通」不是读数,探针滑一格也不会读错
(滑到 pin 1 = `MIC_BIAS1`、pin 5 = `CDC_MICIN`,都不是地)。
量完对照下表,落到哪个候选就把 `fp_bm24.py` 的 `ODD_ROW_TOP` 改一下重跑
(`--push` 一遍,1 秒的事);1 脚在哪一端那一位则留给贴片方向,封装不用动。
| 实测结果 | 要做的事 |
|---|---|
| 奇数排 = 载板上朝 +Y 的那一排 | 什么都不用改(当前就是 A)|
| 奇数排 = 朝 −Y 的那一排 | `ODD_ROW_TOP = False`,重跑 `fp_bm24.py --push` |
#### ✅✅ 2026-09-05 已实测:**A,什么都不用改**
用户拿主板 + 万用表量的,两条结论:
| 实测 | |
|---|---|
| **右端那个大触点是 G1**(对地导通)| ⇒ J1401 的 1/2 脚端在**右端**(顶视、接口边朝下)|
| **下面那一排(靠板边那一排)是奇数排** | ⇒ 镜像位定了 |
第二张照片确认了唯一那个几何前提:**排线从 J1401 直接朝板下边缘出去**
(软板一路下到尾插小板,板上印着 `MAIN` + 指向主板的箭头)。
所以「靠板边那一排」= **排线侧 = 内侧排**。
推导链(每一环都是已实测的事实,不是推测):
```
J1401 靠板边那一排(= 内侧排) ← 实测:奇数排
↕ 公头A 内侧排
↕ 排线 1:1 直通,内侧↔内侧 ← §13.5 用户实测
↕ 公头B 内侧排
载板 J7n 朝手机那一排(+Y) ⇒ 奇数排
```
载板这一侧为什么是「朝手机那一排」:排线出 J1401 → 越过手机板边 → **台阶式下折**
(折线平行于连接器长轴)→ 回头插进 v = −3.0 的 J7n,所以在 J7n 处**软板本体朝 +v 伸出**。
而 `to_board()` 对五个位都保证「封装本地 +Y = 朝手机主板」(CH1~3 rot 0、CH4/5 整位 180°)。
⇒ **`ODD_ROW_TOP = True` 就是对的,封装、原理图、摆位一个都不用动。**
**第二位(贴片方向)同时也自洽了**:折叠不翻长轴方向,所以 J1401 的左端(G2 = `USB_VBUS`)
对应载板座子的左端;我们的封装是 `pin51`(VBUS) 在 −X、`pin52`(GND) 在 +X、J7n 摆 rot 0,
⇒ VBUS 端落在 −X = 手机左端 ✔,和 §13.5 推出的「52 = GND、51 = VBUS」对上。
> ⚠️ 首件仍要按 §24.4 量一次 `VBUSn` 对 GND 的电阻 —— 那是**验证**,不是**决定**。
#### 可选的零成本复核(还没做,做了这一位就彻底钉死)
不需要地参考,两根表笔点相邻触点:奇数排上从 G1 端数,
**位置 17-18-19 互相导通**(`SPKR_OUT_N` 33/35/37)、**22-23-24 互相导通**(`SPKR_OUT_P` 43/45/47);
偶数排同样位置是 `VREG_BOB` / GND / 口温,不导通。
> ~~这一步必须在下单载板 PCB 之前做完~~ —— **2026-09-05 已做完,见上。**
> (当时写的退路:把 50 个焊盘全引到板边测试点、首件焊好再跳线 —— 用不上了。)
### 24.4 还有一个老的待实测项(§13.5 已记,这里只做交叉引用)
**G1/G2 落在我们这颗座子的哪一端**(即 51/52 谁是地)。
它属于上面表里「1 脚在哪一端」那一位,**贴片时转 180° 就能纠**,所以不致命。
首件上电前量一次 `VBUSn` 对 GND 的电阻即可(负载开关默认关断,零风险)。
### 24.5 建库时踩的两条 API 坑
1. **`lib_Footprint.copy()` 对系统库的封装静默失败**(返回 `undefined`,不抛错),
系统库封装也 `openInEditor()` 不了(返回 `false`)。
所以「复制立创封装再改编号」这条路走不通 —— 只能 `lib_Footprint.create()` 建空封装、
自己把 52 个焊盘画出来。反过来说这也是好事:几何直接按官方样本落,不继承立创的错。
2. **`lib_Device.create()` 的 `property` 参数会被吞掉**:建出来的器件
`Add into BOM` / `Convert to PCB` 都是 **no**(意味着**根本不会转到 PCB**),
供应商编号也全丢。必须紧跟一次 `lib_Device.modify(uuid, lib, u,u,u,u, {...})` 补上,
而且 `property` 要用 `{name, addIntoBom, addIntoPcb, otherProperty:{...}}` 这个嵌套结构。
---
## 25. 载板 PCB(PCB2-CARRIER,2026-09-04 从零布起)
生成脚本 `.claude/pcb2_place.py`(`--outline` 板框 / `--mech` 机械要素 / `--push` 摆件)。
截图 `PCB2-carrier-v1.png`、`PCB2-site1.png`、`PCB2-j23.png`。
### 25.1 板框与排布(用户拍板)
**220 × 135 mm,四角 R5**,五块主板 **3+2 双排面对面,第二排居中**:
| | X | Y | 旋转 |
|---|---|---|---|
| CH1 | 5.0 | 85.5 | 0(接口边朝下)|
| CH2 | 76.5 | 85.5 | 0 |
| CH3 | 148.0 | 85.5 | 0 |
| CH4 | 40.75 | 5.0 | **180**(接口边朝上)|
| CH5 | 112.25 | 5.0 | **180** |
(坐标是主板本体左下角,主板 67.09 × 44.66。)
**为什么能这么省地方**:小米8 主板的接口**全部**挤在同一条边上 ——
侧键 x 2~5.5 / J600 x≈23.8 / EDL x 42.6,45.4 / J1401 x 47.5~59.7,**y 全部 < 8 mm**。
所以每台手机只要一条 **18 mm 的服务带**贴着那条边,两排面对面就能共用中央通道:
```
y 130.16 ┬ CH1 CH2 CH3 (主板,正面朝天)
y 85.5 ┼ ─────── 接口边 ───────
│ 服务带 A:C8n1 / TP8n1,2 / C8n2~6 / J6n / U4n / J7n / U5n / U2n
y 67.5 ┼ ── 底层:J31 (62,67.5) · Hub (110,67) · J32 (158,67.5) ──
│ 服务带 B(同上,上下镜像)
y 49.66 ┼ ─────── 接口边 ───────
y 5.0 ┴ CH4 CH5 左右各空出 35.75 × 44.66 的口袋
```
左口袋放 J23 上游 USB-C + U31(3V3 LDO)+ U34(测温)+ R721/R722;右口袋暂空。
### 25.2 三条硬决定
1. **J31 / J32 排母在底层(layer 2)。** 下板公头朝上,载板母座必须朝下。
⚠️ 「第 r 行对第 r 行」不能靠脑补两边的引脚表 —— 底层元件在顶视图里是镜像的。
`pcb2_place.py --push` 会把载板侧 80 个焊盘的绝对坐标导出到
**`.claude/pcb2-header-pads.json`**;下板放 J24/J25 时按同一装配坐标系
把 pin k 摆到同一个 (x, y) 即可,**数值对上就一定插得上,不用推理**。
装配坐标系取载板坐标系,下板 160×125 居中 → 下板原点 = 载板 (30, 5),
所以下板侧目标坐标 = 导出值 − (30, 5)。
2. **USB Hub(U32 + Y1 + strap + 去耦,共 26 件)也在底层,压在通道正中 (110, 67)。**
顶层通道被两条服务带占满;而 Hub 若放进左右口袋,到最远那台的 D± 要走 200+ mm,
**超过 USB2517I 手册要求的 6 inch(152 mm)**。放中间后最长约 92 mm。
底层本来就要贴 J31/J32,不增加工序。
⚠️ 底层元件落在两板之间那 13 mm 缝里 —— **布下板时别让 C2/C3(12 mm 电解)撞上**。
3. **35 个手机定位孔做 NPTH(Φ2.5,不金属化),立柱必须用尼龙。**
主板那 7 个孔是金属化的、连着手机地。做成金属化孔 + 金属立柱 =
五台手机的地在载板上并成一根,4 A 回流会从专用的 `P−` 针里跑掉一部分,
直接违反 §6.4「每路独立回流」。
### 25.3 ⚠️ 顶针封装:立创的焊盘会让侧键短路(本轮抓到的真错误)
立创给 `C5221288`(YTC1P-2510-01)的封装 `SMD-1_BD2.0-H3.6` **焊盘是 Ø2.5**,
而顶针法兰只有 **Ø2.0**。单看没问题,按实测坐标密排就致命:
| 触点对 | 间距 mm |
|---|---|
| J603–J601 | 2.346 |
| J603–J602 | 2.333 |
| **J601–J604** | **2.217** ← 最近 |
`2.217 − 2.5 = −0.28 mm` → **两个焊盘直接叠在一起**,音量+ 会被永久按住。
**原理图侧完全看不出来**(网表是对的),只有 PCB 摆位的几何检查能抓到。
已自建封装 **`POGO-SMD1P_D1.9`**(个人库,器件 `YTC1P-2510-01 D1.9` =
`1c8e0ea1e66142a8860d6812b1dbe356`):单焊盘 **Ø1.9**,净间距 **0.317 mm**,
过 0.2 mm 规则;法兰 Ø2.0 只比焊盘大 0.05 mm/边,回流照样自对中。
`c4_site.py` 已改用它,C4-SITE1~5 重生成、三道验证全绿、PCB 已重新导入。
> 教训写进 skill §9f:**用实测坐标钉死位置的器件,摆位前先把焊盘直径和
> 实测最小间距对一遍**,别等 DRC。判据 = `最小间距 − 焊盘直径 ≥ 设计规则净间距`。
### 25.4 服务带的内容与排法(本体坐标,v<0 = 接口边外侧)
| 行 | v | 内容 |
|---|---|---|
| 1 | −3.2 | `TP8n1`(u21) `C8n6`(23.5) `TP8n2`(26) `C8n2`(31) `C8n3`(36.5) `J6n`(44) `J7n`(57.5) |
| 2 | −8.0 | `C8n4`(31) `C8n5`(36.5) `R74n`(41) `U4n`(45) `C76n`(49.5) `U5n`(57.5) `R76n`(61.5) `R77n`(64) |
| 3 | −11~−13 | `C8n1`(12, −11) `C70n`(39.5) `U2n`(45) `C71n`(49.5) `C72n`(52.5) `R70n`(55.5) |
排法的三条理由:① 要接排线 / 焊飞线的(P+P− 焊盘、EDL 座、BM24 座)全在行 1,
贴着手机边,飞线最短;② `J7n` 摆在 u≈57.5,正对主板 J1401(u 47.5~59.7);
③ `C8n1` 那颗 Ø10 电解摆到最左(u=12),那一段只有它,不跟任何东西抢地方。
`pcb2_place.py` 的本地检查有四项:位号齐全、不越框、**分层**重叠、
顶层元件不许压进主板投影。直插件(`C8n1` / `TP8n1,2`)**两层都算**,
且顶层按罐体 Ø12.5 留、底层只按引脚焊盘留 —— 用同一个框会把 J31 误判成撞上 C811。
### 25.5 这一版还欠什么
| # | 待办 | 说明 |
|---|---|---|
| 1 | ✅ **J23 方向定稿,位置已改**(见 §25.6)| 方向判据两条,都不是算出来的:① 这个封装的 12 个信号焊盘在**连接器背面**、4 个屏蔽固定孔靠近口,所以口朝板内是错的;② 前端面比最外侧铜还往外 2 mm,焊盘框算不出来,是从渲染图量的(板框紫线 + 信号焊盘列左沿两点标定),得出「中心离前端面 5.134 mm」。**位置 2026-09-04 深夜从左口袋改到右口袋**:`rot=90`、中心 `x=214.866`,前端面仍与板边齐平 |
| 2 | ✅ **Hub 26 件已逐脚对位手排** | 见 §25.6。原来是 3 mm 网格粗排 |
| 3 | ⬜ 设计规则 / 铺铜 / 布线 | 一根都还没布。⚠️ 载板已切 4 层(§25.6),`pcb_rules.py` 的差分几何可以照抄,但**规则配置还挂在两层板能力集上,要先换掉** |
| 4 | ✅ 右口袋已用掉 | J23 挪过去了(§25.6)。左口袋现在只剩 U34/C760 |
| 5 | ⬜ **主板 7 个定位孔的孔径没量** | 载板现在开 Φ2.5。立柱销径要配主板孔径,卡尺量一下就定了 |
| 6 | ⬜ C801 高 16 mm,是载板最高件 | 外壳内高按它留(§24 那次已拍板照装)|
### 25.6 布线前的四处返工(2026-09-04 深夜,用户拍板)
这一轮不是加东西,是**把上一版摆位里四个会咬人的地方修掉**。
四处全是「原理图侧完全看不出来、几何包围盒检查也过」的那一类。
#### ① 载板切到 4 层(2 层做不了)
转板过来默认两层。三条硬理由:
- **11 对 USB HS 差分要 90 Ω。** §10.1 的 W0.28 / S0.18 是按嘉立创四层 1.6 mm
叠层(L1-L2 介质 h=0.2104)算的。两层板的介质是整个 1.5 mm,
同样阻抗线宽要 2 mm 以上 —— 排不下,也没有参考面。
- **五路 4 A(合计 20 A)** 没有内层电源面就只能靠外层大面积铜,
而顶底两面都摆满了元件。
- **两面都是元件面**,地回流会被割得很碎。
叠层沿用下板,但**层的角色是镜像的**:
| | EasyEDA id | 下板(§10.1)| **载板** | 为什么不一样 |
|---|---|---|---|---|
| L1 | 1 | 信号(D± 走这层)| 信号:服务带、P+/P− 焊盘、U5n、U31 | |
| L2 | 15 | **完整地平面** | **电源面**(分割灌铜)| |
| L3 | 16 | 电源面 | **完整地平面** | |
| L4 | 2 | 控制信号 | 信号:J31/J32、**整个 Hub** | |
**为什么载板要把地平面放到 Inner2 而不是 Inner1**:载板的 `U32` 在**底层**,
所有长距离 D±(5 对下游 + 1 对上游)都从底层出发。底层的参考面是 Inner2 ——
Inner2 必须是完整地。反过来(Inner1 = 地)的话底层 D± 就以**分割的电源面**为参考,
直接违反 §10.1 那条「以完整地平面做参考」。
嘉立创四层 1.6 mm 标准叠层上下对称(L1-L2 与 L3-L4 都是 0.2104 mm 介质),
所以 **W0.28 / S0.18 这组几何照搬即可**,不用重算。
#### ② J23 从左口袋挪到右口袋 —— 上游 D± 原来只剩 8% 余量
§25.2 选「Hub 压在通道正中」时**只核了下游**(最远 92 mm),没核上游。
J23 在左口袋 x=5、Hub 在 x=110,上游曼哈顿 **140 mm**,
而 USB2517I 手册的上限是 **152 mm**。
挪到右口袋之后(实测读回的焊盘坐标):
| | 直线 | 曼哈顿 |
|---|---|---|
| **UP(J23 → U32)** | 103.6 | **104.4** |
| USB1 → U51 | 44.7 | 57.0 |
| USB2 → U52 | 32.5 | 43.3 |
| **USB3 → U53(最远下游)** | 101.7 | **113.3** |
| USB4 → U54 | 57.2 | 66.9 |
| USB5 → U55 | 19.6 | 27.6 |
两头都进到 115 mm 以内。用户对上游口从哪一边出没有偏好,按走线最优定。
几何:`rot=270 → 90`(口朝 +X),中心 `x = 220 − 5.134 = 214.866`,
`y = 62.0`(让信号焊盘列 x≈212.4 正对 Hub 的上游脚行 y≈62.55)。
壳体前端面仍与板边齐平 —— 这是把 §25.5 #1 那条标定几何镜像过去,不是重新量的。
顺带:`R717/R718`(CC1/CC2 的 5.1k 下拉)原来被 Hub 的网格排法捞走了,
摆在**底层**、离 J23 105 mm。CC 脚挂这么长的残桩没有意义。
现在贴着 A5/B5 焊盘、和 J23 同在顶层,实测 1.59 mm。
`R721/R722`(上游 VBUS 分压)原来在左口袋陪着老 J23 —— **方向是反的**。
分压要跟着**高阻端**走:`UP_VBUS_DET` 是高阻节点,要短;`VBUS_UP` 是低阻,
长跑无所谓。现在移到 J31 pin36 边上(底层,实测 3.27 mm)。
#### ③ U31 就近 Hub —— §22.7 写了但没落实
§22.7 白纸黑字:「§9.5 要求的『就近 Hub 供电』是 **PCB 摆位约束**,与分页无关」。
上一版 U31 在左口袋 (25, 42),离 Hub 90 mm。
现在 `U31 (105, 71)` / `C736 (98, 71)` / `C737 (112.5, 68.8)`,
顶层 y 67.5~72.5 那条横带原本是空的(J31/J32 在底层,服务带 A 从 y 72.5 起)。
实测 U31 的 3V3 输出脚到 U32.pin64 = **8.62 mm**。
#### ④ Hub 26 件从网格粗排改成逐脚对位手排
U32 是 QFN-64,脚距 0.5 mm,而 0402 件本体 0.54 mm 宽 ——
**一个脚一个件地排是排不下的**。所以每条边分两圈(A 圈 6.3 mm、B 圈 8.0 mm),
件按 1.2 mm 间距错开。手排相对网格排法真正多做的事是**让出三条通道**:
| 通道 | 位置(相对 Hub 中心)| 给谁 |
|---|---|---|
| 西侧扇出 | x < −4.45,y −3.8~+1.8 | 五对下游 D±(10 根),整条左边不放件 |
| 南侧竖井 | x −2.4~−0.2,y < −4.45 | XTAL1/2 下到 Y1 + UP_DP/DM 南下再西行 |
| 晶振窝 | (−4.2, −9.2) 一带 | Y1 + C740 / C741 |
A 圈 y=−6.3 上 `C743`(x−2.65) 与 `C745`(x+0.05) 之间那 **2.16 mm** 就是南侧竖井,
四根线(XTAL 用 0.2、UP 用 0.28)刚好过得去。
实测的对位距离(读回焊盘坐标算的,不是脚本里的意图值):
| 件 | 对哪个脚 | mm | |
|---|---|---|---|
| `R708` | 63 RBIAS | **1.43** | 精密偏置,全簇最近 |
| `C743` | 62 VDD18PLL | 1.43 | |
| `C742` | 25 VDD18 | 1.51 | |
| `C744/745/746/749/750` | 64/57/52/24/46 +3V3 | 1.46~2.30 | |
| `C747/C748` | 5/10 +3V3 | 3.55 / 3.10 | 夹在 D± 中间,只能放到扇出区之外 |
| `R712/R715/R714/R719/R709` | 42/56/54/40/44 | 1.42~1.86 | |
| `R711/R716/R720` | 41/43/45 | 3.1 | B 圈,纯配置下拉/上拉,够 |
| `Y1` | 61/60 XTAL | 4.95 / 5.76 | 见下 |
| `C740/C741` | Y1 的两个端子 | 1.48 / 1.83 | |
**晶振离芯片 5~5.8 mm 是通道的代价,不是疏忽。** `UP_DP/DM` 必须从南边出去再西行,
Y1(3.6 × 2.9)放不进它们的竖井,只能退到西南。24 MHz 下这个距离有充分余量,
真正要紧的「负载电容贴着晶振端子 + 地回路短」已经做到(1.5~1.8 mm)。
`C747/C748` 那 3.1~3.5 mm 同理:pin5 / pin10 夹在十根 D± 中间,
件放进去就堵死扇出。这两颗靠 **Inner2 的 +3V3 灌铜就近打孔**补偿,不靠这段走线。
#### ⑤ 载板自己的 M3 孔压在手机上(`pcb2_clear.py` 抓到的真错误)
四个 M3 孔 `(8,8)/(212,8)/(8,127)/(212,127)` 是在五个手机位拍板**之前**放的,
之后没复核。上面两个落在 **CH1 / CH3 的手机本体投影里**,
其中 `(8,127)` 的 Ø6 焊盘和 CH1 的定位孔 `P1H2` 直接重叠 **0.93 mm**。
这个错误 `pcb2_place.py` 的包围盒检查抓不到 —— 定位孔和 M3 孔都是**自由焊盘**,
不属于任何元件,根本不在它的检查范围里。
新写的 **`.claude/pcb2_clear.py`** 按焊盘真实形状两两算净间距,才把它翻出来。
板顶那条 `y 130.16~135` 的 4.84 mm 缝里塞不下 Ø6 焊盘,
三个手机横排也已经把 x 方向占满(5+67.09+4.41+67.09+4.5+67.09+4.91 = 220.09),
所以上面两个孔只能退进中央通道 / 右口袋:
MH = [(8, 8), (212, 8), (7, 60), (213, 45)]
`pcb2_place.py` 已加断言:M3 孔不许落进任何手机本体投影,
也不许离 35 个定位孔中的任何一个近于 `Ø6/2 + Ø2.5/2 + 0.2 = 4.45 mm`。
> ⚠️ **副作用,是外壳设计要回答的问题**:CH1~CH3 那一排(板子上半部分)
> 最近的安装点在 45 mm 之外,220 mm 跨距上没有支撑。
> 三条出路:外壳做侧边导轨托住上沿 / 在中央通道 `(127, 67)` 加一个中跨孔
> (实测那一块顶底两层都是空的)/ 缩板。**目前没做决定。**
#### 新写的检查脚本:`.claude/pcb2_clear.py`
/c/Python314/python .claude/pcb2_clear.py [--min 0.2] [--top 40]
按焊盘**真实形状**(RECT/OVAL 按轴对齐矩形、真圆按圆心距、POLYGON 按点表包围盒)
两两算净间距,分「同一封装内」(只报负间距)与「跨元件」(判据 0.2 mm)两类。
为什么不用 EasyEDA 自己的 DRC:没布线时它会刷出 1200+ 条「连接性错误」,
真正的间距错误埋在里面看不见(成因见 `drc_read.py` 的注释)。
写这个脚本踩到的**两个 API 陷阱**(已写进 skill §9g / §9h):
1. **焊盘归属哪个元件,只能靠 primitiveId 前缀。**
`pcb_PrimitivePad.getAll()` 回来的对象上**没有** `getState_ParentComponentPrimitiveId`
(TypeError: not a function);用 try/catch 包起来的话它会**静默地把所有焊盘
都当成自由焊盘**,看不出错。真正的判据是
「焊盘的 primitiveId 以父元件的 primitiveId 为前缀」——
元件 C701 = `356da09e850d14fa`,它 1 脚 = `356da09e850d14fae16`。
(坐标匹配也不行:有浮点尾巴,且 POLYGON 焊盘的 x/y 根本不是形心。)
2. ⚠️ **焊盘的 rotation 是弧度,元件的 rotation 是角度。**
`pcb_PrimitivePad.getState_Rotation()` 回来 `1.5707963267948963`(= π/2),
`pcb_PrimitiveComponent.getState_Rotation()` 回来 `90`。
按角度判 `rot % 180 == 90` 的话,**所有旋转过的矩形焊盘长短边都会被认反**。
实测后果:J23 那 12 个 0.30 × 1.30 的信号焊盘被误判成两两重叠 0.30 mm
(真实净间距 +0.20 mm),13 条假报。
这类错误最阴的地方是**只错一半** —— 不旋转的焊盘全对,
所以看上去像「某个封装有问题」,而不像「换算错了」。
#### 这一轮的验证结果
| 检查 | 结果 |
|---|---|
| `pcb2_place.py` 本地四项(位号齐全 / 不越框 / 分层重叠 / 顶层不压主板投影)| ✔ 161 个元件,顶层 133 / 底层 28 |
| M3 孔断言(不压手机投影 / 离定位孔 ≥ 4.45 mm)| ✔ |
| `pcb2_clear.py` 跨元件焊盘净间距 ≥ 0.2 mm | ✔ 814 个焊盘全过 |
| `pcb2_clear.py` 同封装内负间距 | ✔ 0 对 |
| 铜层数 | ✔ 2 → 4(id 1 / 15 / 16 / 2 启用) |
截图 `PCB2-carrier-v2.png`(全板)。
---
### 25.7 布线前置:设计规则、地平面、两个中跨孔(2026-09-05)
这一轮做的是「布线之前必须先有的东西」,**一根走线都还没画**(原因见末尾)。
#### ① 载板设计规则整套下发(`.claude/pcb2_rules.py`)
转板过来一直挂在 `JLCPCB Capability(Two Layers Board)` 上,而板子早就是四层了。
做法完全照抄下板的 `pcb_rules.py`(那边的文件头是唯一说明书,两个 config 形状的坑
和「别去 GUI 换配置下拉框」那条都适用),只有三处不同:
| | 下板 PCB1 | 载板 PCB2 |
|---|---|---|
| 差分对 | 7 对 | **11 对** |
| 功率线宽档 | 2 档(PWR4A / PWR12V)| **3 档**(PWR4A / PWR5V / PWR1A)|
| 线宽指派 | 12 个网络 | 12 个网络 |
**为什么是 11 对**:载板上每一路 D± 被 ESD 器件 `U5n` 切成两段 ——
`USBn_DP/DM`(U32 → U5n,长段,走底层)和 `USBn_DPJ/DMJ`(U5n → J7n,约 5 mm,走顶层)。
**两段都要建对**,否则短段会按普通信号布、在 ESD 器件那头留一截不受控阻抗。
5 长 + 5 短 + `UPSTREAM` = 11。载板没有 `DEBUG` 那一对(ESP32 在下板)。
**几何 W0.28 / S0.18 直接照搬不重算**:嘉立创四层 1.6 mm 标准叠层上下对称
(L1-L2 与 L3-L4 都是 0.2104 mm 介质),载板虽然层角色是镜像的,
底层 D± 以 Inner2(完整地)为参考,介质厚度与下板顶层 D± 以 Inner1(地)为参考完全相同。
⚠️ **顶层那 5 段 `*J` 的参考面是 Inner1,也就是分割的电源面**,不是完整地。
段长只有约 5 mm、又紧挨 ESD 器件,可以接受;但要保证每个 `U5n`↔`J7n`
下方的 Inner1 是**同一块铜**,别让分割缝横穿这 5 mm。
✅ **2026-09-05 Inner1 铺完后已实测**(`.claude/inner1_diffref.py`,把两根线的包围盒
外扩 1 mm 当窗口,逐窗口栅格化 Inner1 上所有铜面):五段窗口里**都只有 `GND-INNER1`
一块铜、一个连通域、覆盖 100%**(连反焊盘的洞都没有)。五块 `VOn_P` 岛离得最近的
是 VO4(右沿 x=100)对 CH1 的窗口(x 57.65~64.45),差着一整个服务带。
⇒ 这条约束是**满足的**,不是「可以接受」而已。改岛的边界或挪 `U5n`/`J7n` 之后要重跑这个脚本。
**三档功率线宽的依据**(IPC-2221 外层 1 oz,ΔT≈20 °C):
| 规则 | 默认 / 最小 | 挂哪些网络 | 依据 |
|---|---|---|---|
| `PWR4A` | 1.5 / 0.3 mm | `VO1_P`~`VO5_P` | 每路 4 A |
| `PWR5V` | 1.2 / 0.3 mm | `+5V` | §9.4 最坏 2.8 A(1.2 mm 可载 3.6 A)|
| `PWR1A` | 0.6 / 0.25 mm | `VBUS1`~`5`、`+3V3_HUB` | 下行每口 0.5 A;Hub 3V3 最坏 0.42 A |
最小值一律留到 0.25~0.3 mm,理由同 §10.1:规则是**按网络**生效的,
`+5V` / `VBUS` 上挂着 0402 去耦(焊盘才 0.57 mm 宽),卡大线宽会让几十个焊盘
扇不出去、刷出一屏假 DRC。**载流靠灌铜保证,不靠 DRC。**
`--check` 审计十一项全过:铜层数 4 / 四层板能力集(最小线宽 0.102、过孔 0.30-0.20、
含 0.5 oz 内层条目)/ 三条线宽规则存在 / 差分几何 W0.280 S0.180 /
非差分间距下限 0.2000 / 对内 `USBPAIR` 0.15 / 11 对差分 / 12 个线宽指派 / 11 条对内间距规则。
#### ② Inner2 整板地平面已铺好
一块 `GND-INNER2`,板框内缩 0.5 mm 的 R5 圆角矩形,`preserveSilos=false`,
重建后 **81 块填充**,已存盘。脚本是 `.claude/pcb2_pour.py`(`--push` 一气跑完:
清旧 → 建边框 → 重建 → 确认 → 存盘,中途不能停,理由见下面第 3 条)。这是载板上唯一**不依赖任何未决事项**的铜面 ——
Inner1 的分割电源面当时要等排母定了才能划 —— 排母 2026-09-05 定稿并落到 PCB 上(§22.3f / §25.9),
**Inner1 已于同日铺完,见 §25.11。**
#### ③ 两个中跨 M3 孔(用户拍板,§25.6 ⑤ 那条待办到此关闭)
孔位不是拍脑袋定的,是拿**真实焊盘 + 五个 Ø12.5 电解罐体**做网格搜索找出来的
(判据:孔中心到任何铜/罐体的净间距,NPTH Ø3.2 算):
| 候选窗口 | 位置 | 净间距 | |
|---|---|---|---|
| CH1\|CH2 缝下 | **(76.6, 80.1)** | **5.28 mm** | ← 选它 |
| CH2\|CH3 缝下 | **(148.1, 80.1)** | **5.28 mm** | ← 选它 |
| 走廊正中 | (127.9, 67.5) | 2.90 mm | 窄一半,且离要支撑的地方远 18 mm |
**选 y≈80 而不是走廊正中的两条理由**:
1. 要支撑的是 y 85.5~130 那一排手机,80.1 离它只有 5 mm,67.5 差了 18 mm。
插 BM24 原厂排线时的按压力正好作用在这个无支撑的上半部分。
2. 走廊正中被 `C811` / `C831` 两个 Ø12.5 电解罐夹着
(罐体分别占 y 68.25~80.75 和 y 54.41~66.91),只剩一条 6.9 mm 高的缝;
而三台手机之间那 4.41 mm 的 x 向空档一路通到 y 84,宽敞得多。
⚠️ y 再往上就被**顶针** `J48` / `J52`(y 87.96,CH2/CH3 的侧键触点)逼住:
y=83 时净间距掉到 2.41,y=84 只剩 1.41。**80.1 是这个窗口的最宽处。**
规格与原有四个一致:Ø3.2 孔 + Ø6 焊盘 + 接 GND(金属化,锁到外壳等于把载板地
接到机壳 —— 这和 §25.2 决定 3「手机定位孔必须 NPTH」不冲突,那一条防的是
**五台手机的地在载板上并成一根**,载板自己的地本来就是一个网络)。
`pcb2_clear.py` 重跑:**816 个焊盘**(原 814 + 2),跨元件净间距全过。
截图 `PCB2-carrier-v3.png`(全板)/ `PCB2-midspan-mh.png`(MH5 附近)。
#### ④ 查清一个必须记住的事实:**J31/J32 的占位封装是 SMD,排距 4.80 mm**
实测回读 J31 的 40 个焊盘:**20 列 × 2.54 mm 列距,2 行 × 4.80 mm 排距,
全部在 layer 2(底层)** —— 不是 layer 12,也就是说它是**贴片**焊盘,不是插装。
对照两边的封装名:
| | 器件 | 封装 |
|---|---|---|
| 下板公头 J24/J25 | `C9900001574` 2.54 双塑双排针 2\*20P L17MM | `HDR-**TH**_40P-P2.54-V-R2-C20-**S2.54**-1` |
| 载板母座 J31/J32 | `C9900025309` 双排**插装**排母 2\*20 40PIN 2.54 间距 | `HDR-**SMD**_40P-P2.54-V-F-R2-C20-**LS6.7**` |
> **本节写于换件之前,两颗都已作废**(2026-09-05 → `C55020601` + `C5307344`,见 §22.3f)。
> 下面这两条结论仍然有效,而且**正是换插装件的直接理由**,所以整节保留。
**4.80 mm 排距本身不是错**:贴片排母的触点在壳体内仍是 2.54 间距,
焊脚是鸥翼状往外掰的,`LS6.7` 就是两排焊脚外沿的跨距(4.80 + 焊盘长 ≈ 6.7)。
所以它和 2.54 的公头**能对插**。
**真正的问题有两个**:
1. **器件名写着「插装」,封装却是 SMD。** 立创的封装数据在这个工程里已经错过一次
(§23.1 的 BM24 焊盘编号)。选型时**以封装名和实际焊盘为准,别信器件名**。
2. **贴片排母承 5 路 × 4 A = 20 A、还要反复插拔**,焊脚的机械保持力和接触电阻
都不如插装件。§22.2 里「三针并联接触电阻约 5 mΩ」的估算是按插装件写的。
**换真件时优先选插装(TH)排母。**
⚠️ 换件之后 **80 个焊盘会整体移位**(排距从 4.80 变成插装件的 2.54,
壳体宽度和定位柱也会变),而它们正压在要铺电源面的走廊正中。
这就是这一轮**没有继续铺 Inner1、也没有开始布线**的原因(用户 2026-09-05 拍板:
先停下,等排母选定再动布线)。**2026-09-05 排母已定稿并实施完毕,见 §25.9。**
#### 这一轮暴露出来的四条 EasyEDA 坑(已写进 skill §9j~§9l)
1. **铺铜优先级是「数字小的先铺、占地盘」**,而不是反过来 ——
下板 `pcb_pour.py` 里 GND=1 / 电源岛=5 的写法是反的(那边铜面从不重叠所以没出事)。
2. **`create()` 的 `pourPriority` 参数不生效** —— 优先级是**按层、按创建顺序**从 1 编的。
⚠️ 别拿 `modify(id, {pourPriority})` 去补设:不生效,还会把客户端弄卡死(见下条)。
✅ **正确做法是靠创建顺序:电源岛先建(拿小数字、赢),GND 底填最后建。**
2026-09-05 在本板 Inner1 上做了对照实验:先建的 12×12 岛完整活着,
后建的 30×30 底填多出一个环(洞),几何相同但后建的那块被吃得一点不剩。
`pcb2_pour.py` 的 `plan()` 顺序就是优先级,`--push` 会回读断言。
3. **「重建所有」点了没反应 = 客户端卡在后台任务上**(窗口底部一条 0% 进度条;
健康时那个 DOM 扫描返回空数组,判据很干净)。`location.reload()` 之后一次就通;
⚠️ **重载会丢掉重载前建的铺铜边框,即使 save 过**,所以 `--push` 必须一气跑完。
⚠️ **而 `location.reload()` 会被「文档有未保存改动」静默挡掉** —— 调用返回成功、
标签栏和 `windowId` 都不变。可靠顺序是:关对话框 → 删掉刚建的边框 → `save()` →
`window.onbeforeunload = null` → `location.reload(true)` → **轮询 `windowId` 直到它变掉**。
4. **每个下发脚本必须自己 `openDocument`** —— 这一轮就因为上一条命令开了 PCB1,
把**下板**的 14 块铜面重铺并存了盘(无损失,但两边返回值都看着正常,
只有铜面名字能看出打错了对象)。
另外记一条不是坑的正常行为:`preserveSilos=false` 时,铺铜区域里没有本网络的
焊盘/过孔,整块会被当孤岛删光 —— 边框还在、`getAll()` 数得到,但填充是 0。
**所以扇出必须排在铺铜之前。**
---
### 25.8 载板 GND 扇出(2026-09-05)—— 顺带查出 BM24 的一个硬约束
Inner2 整板地平面铺好之后,**它其实只靠 20 个直插焊盘吊着**
(五路的 `C8n1` 负极 + `TP8n2`、`J23` 的四个屏蔽脚、6 个 M3),
另外 222 个贴片 GND 焊盘根本没连到平面上。所以铺完铜必须接着做扇出。
脚本 `.claude/pcb2_fanout.py` —— 复用下板 `pcb_fanout.py` 的规划器,只换板子常量。
#### 结果
| | |
|---|---|
| GND 贴片焊盘 | 222 个 |
| ~~**故意不扇**:J31/J32 的 GND 脚~~ | −33(当时排母未定)→ **2026-09-05 换成直插件后不再需要扇出**,通孔脚自己就是过孔(§25.9)|
| 实际目标 | **189 个** |
| 大焊盘走盘内过孔阵列 | 11 个焊盘 / **85 个过孔**(`U32` 的 4.8×4.8 散热盘一个就占 25 个)|
| 普通焊盘旁打过孔 | **125 个**(+125 条出线,中位 0.63 / 最长 1.77 mm)|
| **落盘合计** | **210 个过孔,全部 net=GND,Ø0.610 / 孔 Ø0.305** |
| ⬜ 打不下的 | **53 个**,见下 |
出线分布 **105 条顶层 + 21 条底层** —— 底层那 21 条是 Hub 簇和 `J31/J32` 之外的底层件。
> ⚠️ 这里改了 `pcb_fanout.py` 两处**只在载板上才会暴露**的写死前提(下板行为不变):
> ① `todo` 原来只收 `layer == L_TOP` 的焊盘 —— 下板 391 个元件全在顶层所以没事,
> 载板**两面都是元件面**,改成模块常量 `FANOUT_LAYERS`(载板覆盖成 `(1, 2)`);
> ② 下发 JS 里出线的层写死成 `1` —— 载板底层焊盘的出线会被画到顶层去、**悬空且看不出来**。
> 改成按焊盘自己的 `layer` 走。
#### ⚠️ 打不下的 53 个:51 个是五颗 BM24 的 GND 脚,这是几何上不可能,不是脚本的毛病
每颗 `J71`~`J75` 有 **13 个 GND 脚**,五颗共 65 个,只有 14 个(最外侧那些)打得下过孔。
算一下就知道为什么:
```
BM24 信号焊盘 0.1803 x 0.4801 mm,间距 0.35 mm(§24 自建封装,实测回读)
相邻焊盘边缘净距 = 0.35 − 0.18 = 0.17 mm
Ø0.6 过孔要离别的焊盘边缘 = 0.3 + 0.2(安全间距) = 0.50 mm ⇒ 塞不进去
```
**两排之间的中间通道倒是够**(两排 y = ±1.06,焊盘高 0.48 ⇒ 内边缘 ±0.82,
通道净高 1.64 mm > 2 × 0.5),但通道里过孔彼此要 0.6 + 0.2 = 0.8 mm 中心距,
而脚距只有 0.35 —— 三个脚才放得下一个过孔,且引线还要横穿别的脚。
**所以 0.35 mm 间距的连接器不能靠「旁边打过孔」扇出,只能逃逸布线**:
前排(y 81.44)一律往南出、后排(y 83.56)一律往北出
(同一排相邻焊盘之间只有 0.17 mm,连 0.102 的最小线宽都塞不下,
**横向穿不过去,每个脚只能直着离开连接器**),出了焊盘阵列再打过孔。
这属于布线阶段的活,等排母定了连同 D± 一起做。**打样前必须确认这 65 个 GND 脚
真的都接到地平面上了** —— USB 的回流路径全靠它们。
#### 顺带记一条工作顺序
`pcb_fanout.py` 文件头那条「**布局一动就要 `--clean` → 重新 dump → `--push``**,
三步不能省也不能并」对载板同样成立。换排母 = 布局变动(2026-09-05 已按这个顺序重来过一遍,§25.9),
这 210 个过孔届时要全部清掉重来 —— **脚本才是这一轮的产出,过孔是副产品。**
#### 扇出之后的 DRC 基线(2026-09-05,**下一轮照着这个数比对**)
`pcb_Drc.check()` 跑完,DRC 面板:
```
全部 (551)
同封装内间距错误 (115) 贴片焊盘 到 贴片焊盘 (115) ← 封装自带,永远修不掉,见下
连接性错误 (436) GND(107) +5V(15) VBUS1~5(各6) +3V3_HUB(33) ...
间距错误 —— **0 条** ← 210 个过孔 + 126 条出线一条没违规
```
**「间距错误」是 0**,说明这一轮落的铜是干净的。另外两支都是预期之内:
- **连接性错误 436 条 = 还没布线**。GND 那 107 条里,51 条是 BM24 的 GND 脚、
33 条是故意没扇的 J31/J32,剩下的是平面被分成的几个孤立块。
- **同封装内间距错误 115 条 = 封装自带的引脚间距,不是设计错误**,成因逐个核过:
| 位号 | 焊盘对 | 最小净间距 | 成因 |
|---|---|---|---|
| `J71`~`J75`(BM24-50DS)| 228 | **0.170 mm** | 0.35 间距 − 0.18 焊盘宽,见 §24 |
| `U32`(USB2517I QFN-64)| 4 | 0.125 mm | 0.5 mm 脚距 |
| `J23`(USB-C)| 3 | 0.200 mm | 正好卡在判据边界(浮点) |
安全间距规则全表抬到了 0.2 mm(§25.7 ①),比这几颗连接器**自己的脚距**还严,
所以必然报。三个数都在嘉立创四层工艺下限(0.1 mm)之上,可以打。
⚠️ **别去调低全局安全间距来「修」它们** —— 那等于把全板的保护一起放掉。
EasyEDA 已经把这一支单列成「同封装内间距错误」,和跨元件的「间距错误」是分开的。
**看 DRC 只看「间距错误」那一支;「同封装内」那一支确认成因之后就忽略。**
---
### 22.3f 板对板连接器定稿(2026-09-05,取代 §22.2 / §22.3d 里的两个占位)
用户 2026-09-05 授权「你来定选型」。**结论如下,§22.2 与 §22.3d 里凡是写 `C9900001574` /
`C9900025309` 的地方一律以本节为准。**
| | 型号 | 立创 | 关键参数 |
|---|---|---|---|
| **下板 J24/J25 公头** | **AZ-PZ2.54-V11-2\*20P**(宝讯 BXCONN)| **C55020601** | 2×20 / 2.54 / 直插;**塑高 2.5**、配合针长 6、端接针长 3;**3 A/针、触头镀金**;−40~+105 °C |
| **载板 J31/J32 母座** | **PC104-2\*20**(洲日 ZHOURI)| **C5307344** | 2×20 / 2.54 / **直插**;**塑高 10.5**;2.5 A/针;行距 **2.54**;−40~+105 °C |
**对插高度 = 2.5 + 10.5 = 13.0 mm**,由塑料对塑料定位。
配合针长 6 mm 插进 10.5 mm 的腔体,PC/104 母座是通孔式(针可以一路穿过去),
所以针不会先顶死、高度确实由塑料决定。
#### 为什么是这一对
1. **高度是唯一的硬约束,而这是库里唯一够的组合。** 把 EasyEDA 的立创库里
「间距 2.54、标了塑高」的排母全扫了一遍(`lib_Device.search`,十几个关键词):
| 塑高 | 料号 | |
|---|---|---|
| **10.5 mm** | `C5307344` PC104-2\*20 | ← 选它 |
| 10.5 mm | `C5307345` PC104-2\*40 | 尺寸不对(§22.2 已定两条 2×20)|
| 8.5 mm | `C55020541` / `C5124634` / `C9900025309`(贴片) | 对插只有 11 mm,**够不到** |
| 8.3 mm | `C35165` 2.54-2\*20P母长PC104 | 同上 |
8.5 mm 那一档配 2.5 mm 塑高的公头只有 11 mm,差 2 mm。没有「加高排针」能补 ——
库里 2.54 的双排排针塑高全是 2.5。
2. **从贴片改成插装**,这是比高度更重要的一处改善。三个好处:
- 20 A 总电流 + 反复插拔,靠的是插装脚的保持力;§22.2 里「三针并联接触电阻约 5 mΩ」
本来就是按插装件估的。
- **80 个通孔脚本身就是过孔**,直接把 `VOn_P` / `+5V` / 33 个 `GND` 连到 Inner1/Inner2。
§25.8 里被迫跳过的「J31/J32 那 33 个 GND 脚扇不出去」问题**自动消失**。
- 行距从占位件的 **4.80 mm**(贴片鸥翼脚外掰)回到规范的 **2.54 mm**。
3. **电流**:取两者较小值 **2.5 A/针**。
`VOn_P` 每路 3 针并 4 A = **1.33 A/针**(余量 47%);
`+5V` 3 针 2.8 A = 0.93 A/针;`GND` 33 针。都很宽裕。
4. **PC/104 本来就是板间堆叠总线连接器**,机械设计目标就是「两块板叠起来还要能反复拆装」,
和本项目的用法完全一致。
#### 这个决定带出来的三条硬约束
1. ⚠️ **`C2/C3` 的罐高必须 ≤ 11.5 mm**(13.0 − 1.5 mm 余量)。
现在的 `C22383480` 是立创的通用「470uF 25V」,**商城页面一个参数都没标,
§22.3d 那个「约 12 mm」是估的、不是查来的**。反正它要挪(见下),重选时把高度定死。
Ø8 × 11.5 是 470 µF/25 V 的标准罐,好买。
⚠️ **别顺手换成聚合物电容**(库里 `C48970541` Ø8×11 / ESR 20 mΩ 看着更好)——
输入体电容的 ESR 正是阻尼输入侧电缆 LC 的东西,和 §6.2 输出侧同一个道理,
换成低 ESR 会让输入滤波欠阻尼。§3.4 要的是「低 ESR **铝电解**」,不是聚合物。
2. ⚠️ **`C2`/`C3`/`C4`/`C5`/`C6` 必须挪 —— 它们压在 J24 要占的位置上。**
载板 J31 中心 (62, 67.5),下板坐标 = 载板 − (30, 5) ⇒ **J24 中心 (32, 62.5)**,
本体 53.34 × 5.08 mm ⇒ 占 x 5.33~59.96 / y 58.67~65.04。实测重叠:
| | 重叠 |
|---|---|
| `C2` (17, 63) Ø8 | **8.00 × 5.08 mm** |
| `C3` (26, 63) Ø8 | **8.00 × 5.08 mm** |
| `C4/C5/C6` (33, 60/63/65.5) | 3.20 × 1.29 / 2.50 / 0.79 mm |
J25 中心 (128, 62.5) 那一侧没有冲突。
3. ⚠️ **两板之间没有可用的立柱位。** 载板 6 个 M3 里只有两个中跨孔映射进下板内
(下板 (46.6, 75.1) / (118.1, 75.1)),而实测那两处在下板上是占着的
(前者甚至和焊盘重叠 0.27、和过孔重叠 1.03 mm)。
**所以两板间距只能由连接器的塑料对塑料保证,没有机械兜底。**
下板重排接口区时若能顺手让出这两个位置,就能加两根 13 mm 立柱把间距定死 —— 值得做。
#### 到货必须核的两件事
1. **触头镀层**:`C5307344` 商城没标镀层(只写了「触头材质:黄铜」)。
PC/104 一般是镀金的,但没写就得实物确认 —— 20 A、反复插拔,镀锡会随插拔次数劣化。
2. **母座腔体深度 / 配合针长**:确认 6 mm 的针插到底时**两个塑料真的贴合**
(而不是针先顶到腔体底)。量一次对插后的板间距,应为 13.0 mm。
#### 换件要改的地方(实施清单)
| 文件 | 改什么 |
|---|---|
| `.claude/eda-parts.json` | ✅ 已加 `C55020601` / `C5307344`,旧两颗标了「已作废」 |
| `.claude/p5_btb.py` | ✅ 公头器件换 `C55020601`;引脚公式 `r / 41−r` → `2r−1 / 2r`;**`ROW0` 100 → 95** |
| `.claude/c1_conn.py` | ✅ 母座器件换 `C5307344`;引脚公式与 `ROW0`(95)都不用动 |
| P5-BTB / C1-CONN 两页 | ✅ 已重新生成:`verify_sch` 两页 PASS(C1-CONN 带 `--nc c1-nets-nc.json`)、`xpage` 0 漏接、`port_audit` 下板 513 / 载板 330 全部可疑 0 |
| §22.2 逐针表 | ✅ 已按新编号重写(1/3/5 而不是 1/2/3),两块板共用一张表 |
| `.claude/pcb2_place.py` | ⬜ `HDR` 摆位不变(中心 (62,67.5)/(158,67.5)),但焊盘从**贴片 4.80 行距**变成**通孔 2.54 行距** |
| 载板 PCB | ✅ 已走完:`clean2()` 清过孔 → `pcb2_place.py --push` → `pcb2_parts_dump.py` + `dump_pads.py` → `pcb2_fanout.py --push`(`SKIP_HDR=False`)→ `pcb2_pour.py --push`。逐项见 **§25.9** |
#### 实测到的符号几何(2026-09-05,两颗一起量的)
```
公头 C55020601 / 母座 C5307344 —— 两颗完全一样
20 行,行距 10,左列 x = cx−30,右列 x = cx+30
第 1 行 y = cy + 95(不是公头原来那颗的 +100 ⇒ p5_btb.py 的 ROW0 要改)
第 r 行 = 引脚 2r−1(左)/ 2r(右)
```
量法:在 C1-CONN 上临时各放一颗、`getAllPins()` 读回 40 个引脚号与相对坐标,
**同一次调用的 `finally` 里删掉**(前后元件总数都是 69,无残留)。
#### ✅ 编号体系已实测:**§22.2 那个编号陷阱换件之后消失了**
两个新符号各在 C1-CONN 上临时放了一次、把引脚号与坐标读回来(读完同一次调用里删掉,
`verify_sch` + `xpage` 复核过页面无残留)。结果**两颗完全一致**:
```
20 行 x 左右两列,列 x 偏移 ±30,行距 10
第 1 行: 引脚 1(左) / 2(右) 第 2 行: 3 / 4 ... 第 20 行: 39 / 40
```
即**两颗都是 IDC 奇偶式:第 r 行 = 引脚 2r−1(左)/ 2r(右)**。
而旧的一对是**两套不同的编号**(下板 DIP 式 第 r 行 = r / 41−r,
载板 IDC 奇偶式 第 r 行 = 2r−1 / 2r),§22.2 专门为此写了一节警告
「只能按行对,不能按引脚号对」。**换件之后两块板从此同一套编号,这条陷阱自动消失。**
⇒ `p5_btb.py` 的引脚公式要从 `r / 41−r` **改成 `2r−1 / 2r`**;
`c1_conn.py` 的公式**不用动**(本来就是 `2r−1 / 2r`)。
两边仍然共用 `p5_btb.py` 那张按行组织的表,事实来源不变。
⚠️ **但 PCB 上那一条还在**:符号编号一致 ≠ 第 r 行真的对上第 r 行。
公头在下板顶层、母座在载板底层,**底层元件在顶视图里是镜像的** ——
`pcb2_place.py --push` 导出的 `pcb2-header-pads.json` 仍然是唯一靠得住的对位依据,
下板照那 80 个坐标摆,布板时实打实核一次。
---
### 25.9 换件落到载板 PCB 上(2026-09-05 夜)
§22.3f 定的 `C55020601` + `C5307344` 在这一轮走完了从原理图到 PCB 的整条流程。
**结论:能换,而且换完 DRC 和换件前的基线一模一样**(间距错误那一支 115 条,
全是 `J71~J75`/`U32`/`J23` 封装自带的引脚间距,见 §25.8 末尾)。
#### 导入变更只有 14 条
C1-CONN 整页是脚本重画的,7 个元件的 UUID 全新 ⇒ 每个一条「移除元件 + 增加元件」。
**没有网络层面的变更**,说明两页的网表在换件前后完全等价(这正是想要的:
换的是封装和引脚编号,不是电路)。
⚠️ 对话框里的 **「包含设计规则」必须保持不勾** —— 勾上会拿原理图侧的规则覆盖
`pcb2_rules.py` 下发的那 11 条。这次核过了是不勾的。
#### 换成通孔件逼出来的连锁改动:五个 Ø10 电解整体上移 2.5 mm
这是**换件真正的代价**,而且原理图侧完全看不出来:
> 贴片排母只占底层,所以 J31/J32 从来没和顶层的东西打过架。
> 换成直插之后**顶层也占位**(40 个通孔脚的焊盘区 50 × 4.24 mm),
> 而中央走廊在那两条带上正好被两排电解夹住:
> 上排三站的罐底 y = 68.25、下排两站的罐顶 y = 66.95,**中间只剩 1.30 mm**。
三条出路里只有一条走得通:
| 方案 | 结论 |
|---|---|
| J31/J32 往下挪 | ✗ 下面 3 mm 处是下排各站的行 3(`U27`/`C704` 等,y ≤ 63.91),窗口 0.7 mm 不够 |
| J31/J32 往左右挪躲开罐子 | ✗ J31 可以(左移 5 mm 就避开 `C811`),**J32 不行** —— 左移会撞底层的 Hub 簇,右移出板 |
| **把五个罐子往手机那侧收** | ✅ 罐体在服务带里 `u 5.75~18.25` 这一段是独占的(行 1/2/3 的件都从 u=21 起),v 可以一直收到「不进手机投影」为止(v ≤ −6.25)|
`BAND['c1']` 的 v 从 **−11.0 改成 −8.0**(和行 2 齐平):
| | |
|---|---|
| 罐体边 → 手机板边 | **3.00 mm**(keep-out 边 1.75 mm)|
| keep-out 边 → J31/J32 焊盘 | **1.63**(上排)/ **1.43**(下排)mm |
| 实测可行区间 | v ∈ [−9.0, −6.75] 本地四项检查全过 |
顺带的好处:罐子离手机的 `P+/P−` 焊盘(v = −3.2)更近了 2.5 mm,
§6.3 那一组电容的回路更短。
#### 通孔脚自己就是过孔,§25.8 的一条待办直接消失
`pcb_fanout.one_net()` 的 `todo` 本来就写着 `not p['hole']` —— 通孔焊盘一律不进扇出清单。
所以 J31/J32 那 33 个 GND 脚**不需要**扇出,`SKIP_HDR` 关掉即可,
§25.8 里「排母的 33 个 GND 脚扇不出去」这条待办随换件一起关闭。
换件后重跑的结果和换件前**完全一致**:210 个过孔、失败 53 个(BM24 那 51 个 + `C749` + 1)。
#### Inner2 地平面:81 段 → 213 段
重铺之后填充段数从 81 涨到 213,包围盒仍是整板 (0.6, 0.6)~(219.4, 134.4)。
涨的原因是那 80 个 2.54 间距的通孔在内层开了两条反焊盘带
(Ø1.7 焊盘 + 0.2 净距 ⇒ 相邻反焊盘之间只剩 **0.44 mm** 的铜网)。
**平面没有被切断**(网还在),但**Inner1 的电源岛不要指望从排母底下横穿**,
颈宽要绕着这两条带走。
#### 这一轮踩到的三个坑
1. **`pcb2-parts.json` 不能在元件摆好之后随便重抓** —— 焊盘的 `x/y` 跟着元件转,
但 `pad` 数组里的 **w/h 不转**(方向记在 `pad.rotation` 上)。摆好之后直接抓,
得到的是「位置转了、尺寸没转」的四不像包围盒,`pcb2_place.box()` 再按 rot 翻一次
⇒ 凭空报出 **12 条**假问题(手排的 0402 互相重叠、J23 越框)。
新脚本 `.claude/pcb2_parts_dump.py` 把焊盘位置**反转回元件本地系**再存,
和「刚导入、全是 rot=0」时抓的那份等价。
2. **`pcb_fanout.clean()` 在载板上是破坏性的** —— 它删「layer !== 11 的所有导线」。
下板除板框外没有别的线所以没事;载板上有 **丝印 50 + 装配 100 + 文档 20 = 170 条**
会被一起删光,DRC 和几何检查一条都不报。
⇒ `pcb2_fanout.py` 里另写了 `clean2()`,只删过孔和信号层 (1/2/15/16) 的导线,
并回读断言 3/9/13 三层还在。
3. ⚠️ **板框是 layer 11 上的 `pcb_PrimitivePolyline`,不是 `Line`。**
「剩余导线里还有没有 layer 11」不能当板框还在的证据 —— 第一版断言就是这么写错的,
清理明明是对的却报「板框被清光了」。要查板框得查 `pcb_PrimitivePolyline`。
#### 本轮验证结果(全过)
verify_sch.py P5-BTB ✔ PASS
verify_sch.py C1-CONN --nc c1-nets-nc.json ✔ PASS(U34.3 OS 有意悬空)
xpage.py 全工程 ✔ 真正漏接 0
port_audit.py 下板 513 / 载板 330 ✔ 可疑 0
pcb2_place.py 本地四项 + M3 断言 ✔ 161 元件(顶 133 / 底 28)
pcb2_clear.py 跨元件净间距 >= 0.2 mm ✔ 816 个焊盘
DRC 511 = 同封装内 115 + 连接性 396 + 其它 0(与基线一致)
截图 `PCB2-carrier-v4.png` / `P5-BTB.png` / `C1-CONN.png`。
---
### 25.10 排母逐针分配按几何重排(2026-09-05 夜,取代 §22.2 的 09-04 版)
铺 Inner1 之前先摸底,摸出 §22.2 那张「定稿」表和载板几何对不上。**这是布线开始前
最后一次能免费改接口的机会**(下板 PCB 还没布),所以先改表再铺铜。
#### 硬冲突:4 A 的电源面穿不过排母的地针行
排母南排(y = 66.23)在两颗的前 16 位全是 GND 焊盘。焊盘 **Ø1.6993**、间距 **2.54**
⇒ 相邻焊盘边距 0.84 mm,扣掉两边各 0.2 mm 净距,Inner1 上每个缝只剩 **0.44 mm 铜网**。
`VOn_P` 是 4 A,按 IPC-2221 内层 0.5 oz、ΔT 20 °C 要 **6.97 mm** —— 把一路三针周围
所有的缝加起来也只有约 1.8 mm。**结论是硬的:跨行走不通,不是难看的问题。**
#### 09-04 那版为什么会跨行
它是按**通道号**切的(J24 = CH1+CH2+全局 / J25 = CH3+CH4+CH5),当时载板 PCB 还不存在。
载板画出来之后,五路的落点是:
| 网络 | 09-04 排母引脚 | 本站负载 | 负载在排母哪一侧 |
|---|---|---|---|
| `VO1_P` | J31 北 x 37.9~43.0 | x 14.5~43.1 | 北 ✔ |
| `VO2_P` | J31 北 x 45.5~50.6 | x 86.0~114.6 | 北(但要东行 55 mm)|
| `VO3_P` | J32 北 x 133.9~139.0 | x 157.5~186.1 | 北(东行 35 mm)|
| **`VO4_P`** | **J32 北 x 141.5~146.6** | x 69.8~98.3 | **南 ✘ 跨行** |
| **`VO5_P`** | **J32 北 x 149.1~154.2** | x 141.3~169.8 | **南 ✘ 跨行** |
| `+5V` | J31 北 ×3 | x 45.5~194.4,**南北都有** | 两侧,要横贯全板 |
跨行的唯一出路是绕排母端头(三个通道:x<132.8 / 87.2~132.8 / >183.2)。
`VO4_P` 会变成一条约 120 mm 的蛇形岛(西行 → 钻手机 2 底下 → 南下 → 再西行 50 mm),
`VO5_P` 的站就在 J32 正下方却要绕 40 mm 再折回来。
#### 新规矩:北排喂北边的站,南排喂南边的站
依据是载板几何 —— **每颗排母正上方一个站、正下方一个站**:
```
J31 焊盘 x 37.87~ 86.13 正对 site1(x 5~72,北) 和 site4(x 41~108,南)
J32 焊盘 x 133.87~182.13 正对 site3(x 148~215,北) 和 site5(x 112~179,南)
site2 (x 76.5~143.5,北) 夹在两颗中间 → 取 J31 北排最右三针(x 81.05~86.13),
正好顶着 site2 最左的负载 C811(x 86.0)
```
重排后(逐针表见 §22.2,事实来源是 `.claude/p5_btb.py` 的 `J24`/`J25`):
| 网络 | 引脚 x / 行 | 最远负载曼哈顿 | 同侧 |
|---|---|---|---|
| `VO1_P` | 37.9 / 40.4 / 42.9 北 | 32.1 mm | ✔ |
| `VO2_P` | 81.0 / 83.6 / 86.1 北 | 42.0 mm | ✔ |
| `VO3_P` | 169.4 / 172.0 / 174.5 北 | 25.1 mm | ✔ |
| `VO4_P` | 73.4 / 76.0 / 78.5 **南** | 28.4 mm | ✔ |
| `VO5_P` | 154.2 / 156.7 / 159.3 **南** | 26.3 mm | ✔ |
| `+5V` | 10 针,两颗 × 南北四处 | 37.1 mm(到 Hub 的 C736)| —— |
**最远行程从 ~120 mm 降到 ≤42 mm,五路全部同侧、一路都不跨行。**
#### 顺带把 +5V 的「横贯全板脊」也消掉了
09-04 版 `+5V` 只有 3 针、全在 J31 北排,而它的 12 个负载散在 x 45.5~194.4、
南北都有 ⇒ Inner1 上必须拉一条 150 mm 长、≥4.3 mm 宽的脊,横穿五路 `VOn_P` 的地盘。
改成 **10 针分散取电**(J31 北 4~5 / J31 南 11~12 / J32 南北 1~2 / J32 南北 20)之后,
每个入口只喂本站的 `U2n` + `C70n`,段电流 ≤0.6 A ⇒ **顶层 0.5~0.8 mm 走线就够,
Inner1 上不用给 +5V 留任何东西**。同理 `+3V3_HUB`(420 mA,局部)也不做岛。
⇒ **Inner1 的最终规划简化成:5 块 `VOn_P` 岛 + GND 底填**(原来是 5 + `+5V` + `+3V3_HUB` + 底填)。
#### 针数变化(网络表一个都没变,只是落点变了)
| | 09-04 | 09-05 |
|---|---|---|
| 信号 | 47 | **54** = 15 `VOn_P` + 10 `+5V` + 25 站内 + 4 全局 |
| GND | 33 | **26**(20 A 回流 = 0.77 A/针)|
五路 `VOn_P` 的「正对面 3 针 GND」(§15.4 各路独立回地)**一条不少**,
`p5_btb.py` 的 `plan()` 里逐行断言。
#### 原理图画法跟着改了一处:GND 也走 netport
重排之后 GND 不再是「右列从第 1 行起的连续块」,而是散在两列的若干段
(J24 北 13~17 / 南 1~5,14,18~20;J25 北 9~11,20 / 南 5~8,15~19)。
给每一段配母线 + 地旗的话,**旗会掉进相邻行的端口里**(行距只有 10,而旗高 15~20,skill §7)。
所以两页统一改成**每个引脚一个 netport(含 GND)**。
实测 `verify_sch --nets` 回读到 `GND 26 个引脚`,netport 命名的 GND 与地旗合并到同一个网络,
40 个端口叠在 10 的行距上渲染也没打架(截图确认过)。
#### 本轮验证结果(全过)
verify_sch.py P5-BTB ✔ PASS(导线 80 / 端口 80)
verify_sch.py C1-CONN --nc c1-nets-nc.json ✔ PASS
xpage.py 全工程 ✔ 真正漏接 0
port_audit.py 下板 544 / 载板 361 ✔ 可疑 0
载板 PCB 导入变更 ✔ 65 条,全部是 J31/J32 的「修改网络」,无元件增删
PCB 上 80 个焊盘的网络 vs 逐针表 ✔ 全部一致(脚本逐行比对)
pcb2_place.py / pcb2_clear.py ✔ 161 元件 / 816 焊盘
重扇 210 孔 + Inner2 重铺 185 段 ✔
DRC ✔ 518 = 同封装内 115(与基线一致)+ 连接性 403 + 其它 0
截图 `P5-BTB.png` / `C1-CONN.png`。
---
### 25.11 载板 Inner1 分割电源面(2026-09-05 夜)—— 五块 `VOn_P` 岛 + GND 底填
**事实来源 `.claude/pcb2_pour.py` 的 `ISLANDS`**,改铜面改那里再 `--push`。
两个校核脚本都必须过(见本节末)。
#### 落地的形状
Inner1 只有两类铜:五块 `VOn_P` 岛(优先级在前,先占地盘)+ GND 底填(优先级最后)。
`+5V` / `+3V3_HUB` 不开岛 —— §25.10 把 `+5V` 重排成 10 针分散取电之后,
每个入口只喂本站的 `U2n` + `C70n`、段电流 ≤0.6 A,顶层 0.5~0.8 mm 走线就够。
| 岛 | 网络 | 主体矩形(mm)| 颈(x0~x1 → y)| 面积 |
|---|---|---|---|---|
| VO1 | `VO1_P` | 12.5, 67.6 ~ 44.3, 84.0 | 不用开颈 | 491 mm² |
| VO2 | `VO2_P` | 80.0, 67.6 ~ 116.0, 84.0 | 不用开颈 | 541 mm² |
| VO3 | `VO3_P` | 152.0, 70.5 ~ 188.0, 84.0 | 168.5~175.9 → 67.6(朝下)| 475 mm² |
| VO4 | `VO4_P` | 68.0, 50.8 ~ 100.0, 63.5 | 71.5~79.9 → 67.4(朝上)| 406 mm² |
| VO5 | `VO5_P` | 139.5, 50.8 ~ 172.0, 63.5 | 152.8~160.6 → 67.4(朝上)| 411 mm² |
**上排的 VO1 / VO2 不用单独开颈**:它们左右都没有别的排母针挡路,
整块矩形直接压到 y=67.6(南排针 y=66.23 的反焊盘上沿 67.28 之上 0.32 mm)。
VO3 不行 —— 它左边就是 J32 的 POGO3 三针,只能从针缝里开一条 7.4 mm 的颈下去。
#### 每一条边界都是被具体的焊盘顶住的
排母针 Ø1.699 + 0.2 安全间距 ⇒ 反焊盘半径 **1.05 mm**。逐条:
| 边界 | 顶住它的焊盘 | 反焊盘沿 |
|---|---|---|
| VO1 右 44.30 | `J31.7` `+5V` (45.489) | 44.439 |
| VO2 左 80.00 | `J31.33` GND (78.509) → 79.559;兼顾 `MH5` Ø6 (76.6, 80.1) → 79.6 | 79.6 |
| VO3 主体左 152.00 | `MH6` Ø6 GND (148.1, 80.1) | 151.30 |
| VO3 颈左 168.50 | `J32.27` `POGO3_VDN` (166.889) | 167.939 |
| **VO3 颈右 175.90** | `J32.35` `EDL_EN3` (177.049) | 175.999 ← **全板最窄的颈 7.40 mm** |
| VO4 颈左 71.50 | `J31.28` GND (70.889) | 71.939(吃掉 0.44,实测仍够)|
| VO4 颈右 79.90 | `J31.36` GND (81.049) | 80.199 |
| VO5 颈左 152.80 | `J32.16` GND (151.649) | 152.699 |
| VO5 颈右 160.60 | `J32.24` `POGO5_PWR` (161.809) | 160.759 |
颈宽下限 **7.0 mm** 的来历(IPC-2221 **内层** 0.5 oz,不是外层):
`A = (I/(0.024·ΔT^0.44))^(1/0.725)`,ΔT=20 °C ⇒ 4 A 需 188 mil² / 0.685 mil = **6.97 mm**。
#### ⚠️ 一条本轮才踩到的坑:铺铜的焊盘连接方式
默认规则 `copperRegion` 是**十字花**(`connectMode: 0`,辐条 0.254 mm)。
十字花下铜面多边形**把自己的焊盘也挖空**,只留 4 条描边辐条 ——
于是几何校核量到的最窄断面是 **0.3 mm**,看着像断路,其实是**度量假象**。
但假象和真断路在数据上分不出来,所以给五路 `VOn_P` 单独挂了 `PLANE-DIRECT`
(`.claude/pcb2_rules.py` 的 `PLANE_RULE`,`connectMode: 1` = 全连接),
铜面就是一整块,怎么量都不含糊。**GND 留默认十字花** —— 它有 ~200 个通孔焊盘
(光两颗排母就 160 针)要手焊,而回流被 26 根排母针分掉。
📐 **「0.254 mm 辐条扛不住 4 A」是个看着对但错的直觉**:IPC 的线宽表是给长导体的,
辐条只有 0.254 mm 长、两端都焊在大铜面上。单条 R ≈ 0.99 mΩ,4 条并联 0.25 mΩ,
4 A 上压降 1 mV / 发热 16 mW,ΔT ≈ PL/(8kA) ≈ **0.02 K**。
所以改全连接是为了**几何可验证**,不是因为十字花会烧。
#### 两个必须都过的校核(**都不看 EDA 报的「段数」**)
`getState_PourFills()` 把一块铜面吐成十几个 fill,那多半是切块不是断开(相邻块共边),
**段数分辨不出「碎成孤岛」和「切块」**。唯一靠得住的判据是把所有环画进同一张栅格再做连通域。
/c/Python314/python .claude/inner1_check.py # 下发前:按 ISLANDS 多边形 + 反焊盘预测
/c/Python314/python .claude/inner1_verify.py # 下发后:按 EDA 实际吐出来的铜实测
/c/Python314/python .claude/inner1_diffref.py # §10.1:顶层 5 段 *J 差分下方是不是一整块
实测(2026-09-05,栅格 0.05 mm):
| 岛 | 连通域 | 本网通孔焊盘 | 最窄横断面 | 最窄纵断面 |
|---|---|---|---|---|
| VO1 | 1 | 5/5 在主域 | 25.20 @ y=82.63 | 12.90 @ x=30.68 |
| VO2 | 1 | 5/5 | 29.20 @ y=69.08 | 11.70 @ x=107.73 |
| VO3 | 1 | 5/5 | **7.20** @ y=67.73 | 10.60 @ x=187.88 |
| VO4 | 1 | 5/5 | **7.70** @ y=66.03 | 8.40 @ x=80.38 |
| VO5 | 1 | 5/5 | **7.60** @ y=63.48 | 9.25 @ x=152.83 |
VO4 那条 8.40 mm 的纵断面在 x=80.38 —— 挡路的是 `TP832`(P− 的 Ø2.7 焊盘,
反焊盘半径 1.55)加三个 GND 扇出过孔,是预期之内的。
DRC:**499 = 同封装内间距 115(与基线一模一样)+ 连接性 384 + 间距错误 0**。
连接性从铺岛前的 396 掉到 384,正是五块岛接上的那 12 处。
截图 `PCB2-inner1.png`(整板)/ `PCB2-inner1-left.png` / `PCB2-inner1-right.png`(走廊两半)。
截图脚本 `.claude/shot_pcb_layers.py <out.png> 15,12 <uuid> [x0 y0 x1 y1]` ——
只显示指定铜层,截完自动恢复图层可见性。
---
### 25.12 差分对布线(2026-09-06)—— 连接器侧 5 对已完成,长距离 6 对待做
**事实来源 `.claude/pcb2_route_dp.py` 的 `SITE_J` / `PATHS`**,配套本地校核在同一个文件里。
#### ⚠️ 先纠一个摆位错误:U5n 装反了(已改)
`USBLC6-2SC6` 是**直通**器件:pin1/6 = I/O1、pin3/4 = I/O2,一排朝连接器、一排朝主机。
`BAND['u5']` 的 rot 从来没设过(默认 0),结果**朝连接器那一排背对着 J7n**,
两条网络都得绕过封装走。已改成 **rot 180**。
SOT-23-6 是对称封装,转 180° 之后 **6 个焊盘落在完全相同的 6 个位置**,只是引脚编号对调
⇒ 没有任何新的间距冲突(`pcb2_clear.py` 816 焊盘复核过),但必须跑完整的
「重摆 → GND 扇出 clean/dump/push → 重铺铜 → 重验」流程(扇出 210 孔、
Inner1 五块岛最窄颈 7.20 mm、`inner1_diffref` 五段全过,全部与改之前一致)。
**顺带的收益**:`VBUS1`(pin5) 也跟着换到朝 U2n 那一侧;长差分对的换层点从
「U5n 与 BM24 焊盘之间那条 2.0 mm 窄缝」挪到了开阔走廊。
#### 自动布线器在载板上不可用(结论,别再试)
按下板那一轮的做法配好并跑过(`pcb2_route_diff.py` 里 `--snap/--config/--run/--watch/--finish/--rollback`
一整套都留着,配置项逐条回读断言):**22 个网络里只画出 J23 自己那两条 A6↔B6 / A7↔B7 的
短接线,全板 0 个过孔**,30 秒内就"跑完",console 只有一句
`ProgressManager: can not remove progressGroup[win_progress_0] not exist`。
板框是合规的单条闭合多段线、四层、规则齐全、22 个网络也确实选中了(46 个焊盘)——
它就是没在找路。**改成手工逐段算坐标 + 本地校核。**
#### ✅ 已完成:5 对 `USBn_DPJ/DMJ`(U5n ↔ J7n)
五个服务带同构,所以只写一遍**站内坐标 (u, v)**,`to_board()` 映射到五个位置。
- `DPJ` 全程顶层:出 J7n.6 → 外移到 v=-5.20 → 东行 → 进 U5n.3。**5.05 mm**
- `DMJ` 两端 u 次序与 DP 相反(J7n 上偏西、U5n 上偏东)⇒ **必须交叉**,
用两个过孔沉到底层从 DP 底下穿过去再上来。**9.19 mm**,偏斜 **4.14 mm**(容差 5)。
底层那一段的参考面是 Inner2 整板地,比顶层还干净。
**出线宽度是算出来的,不是拍的**:BM24 焊盘 0.1803 宽 / 间距 0.35 ⇒
`0.35 − 0.09015(焊盘半宽) − 0.20(安全间距) = 0.05985` 半宽 ⇒ 线宽上限 **0.1197 mm**。
取 **0.11**(净距 0.205);0.12 会差 0.00015 mm 卡在判据线上,实测报错。
出了焊盘阵列、两根线还只隔 0.35 时用 **0.20**(0.35−0.10−0.10 = 0.15 = 对内间距),
分开之后才放宽到 0.28。
⇒ `pcb2_rules.py` 的 `DIFF['strokeWidthMin']` 随之从 0.20 降到 **0.10**
(同 §10.1 里 PWR4A 把最小值降到 0.3 的道理:规则按网络生效,
一个网络上既有 0.28 的主干也有进细间距焊盘的颈)。
验证:本地净距校核(线-焊盘 / 线-过孔 / 线-线 / 过孔-×4,一般 0.20、对内 0.15)**全过**;
下发 60 段导线 + 10 个过孔;**重铺铜之后** DRC 回到
**479 = 同封装内 115(与基线一致)+ 连接性 364 + 间距错误 0**。
> ⚠️ **加完线和过孔一定要重铺铜再看 DRC。** 不重铺时刷出 **40 条间距错误**
> (「到过孔」20 +「到钻孔」20)—— 那是铺铜还不知道新过孔的存在、没让开它们。
> 重铺之后 GND-INNER1 的环数 217→227、INNER2 330→340,正好是 10 个新过孔的反焊盘。
#### ✅ 已完成:6 对长差分(`USBn_DP/DM` ×5 + `UPSTREAM`)—— 详见 §25.13
(下面这段走廊表是当时的踏勘结果,留作背景;实际怎么走看 §25.13。)
#### 当时的踏勘:底层走廊
**底层走廊已经扫出来了**(`pcb2_route_dp.py --corridors` 可复现),照着走别再猜:
| 用途 | 纬线 | 底层通的区间 |
|---|---|---|
| 南高速 | **y = 56.0** | x 40~215 **整段通** |
| 南高速(西行)| **y = 60.5 / 61.0** | x 40~104 整段通 |
| 北高速 | **y = 75.0 / 76.0** | x 40~112、115~215(112~115 被 Hub 北侧卫星挡)|
| 北高速(绕开 Hub)| **y = 84.0** | 58.7~129.1、130.2~200.6、201.7~215 |
| 竖向(Hub 西侧)| **x = 100.0 / 101.0** | y 55~78 整段通 |
⚠️ **每一对都至少要换一次层**,两条独立的原因:
1. **U32 的引脚次序和目的地次序对不上**:西边缘从南到北是 port1..5,
而 port1/2/3 去北排三站、port4/5 去南排两站 —— 正好反过来。
十根线在一层上无论怎么绕都要交叉 6 处。
2. **奇偶性**:一根线"西行→北行→西行"(右转再左转)之后左右关系**回到原样**,
所以就算次序对得上,到 U5n 那一端 DP/DM 谁在东谁在西也未必对。
**交叉要挑 Inner1 是 GND 的窗口做**:`x 100~139 / y 50~67.5` 是一大片 GND
(VO4 岛止于 x=100、VO2 岛止于 y=67.6、VO5 岛从 x=139.5 起),Hub 西侧的换层就放这里。
换完层之后 `inner1_diffref.py` 要扩展成"沿实际走线逐段查参考面"再跑一遍。
### 25.13 六对长差分布线(2026-09-06 第三轮)—— 载板差分对全部布完
事实来源是 **`.claude/pcb2_dp_long.py`**(坐标 + 每一条的理由),
校核 / 下发仍走 `.claude/pcb2_route_dp.py`。
/c/Python314/python .claude/pcb2_route_dp.py --dump # 改了布局/铜就重抓障碍表
/c/Python314/python .claude/pcb2_route_dp.py # 只算 + 本地净距校核
/c/Python314/python .claude/pcb2_route_dp.py --push # 下发(先删本网 1/2 层旧线)
/c/Python314/python .claude/pcb2_net_conn.py # 按实际铜算 22 个网络的连通域
/c/Python314/python .claude/inner1_diffref.py --routes # §10.1:沿实际走线查参考面
#### 决定全局走法的那道隘口:x 112~116
Hub 北边的 `C751`(10 µF 1206,**底层**,(113.0, 74.0))加上 `C815` 的 GND 扇出孔
(113.047, 77.5),把北高速在 x=113 处掐成两个窗口(线心可用范围):
| 窗口 | 线心 | 能塞几对 |
|---|---|---|
| 底层·低窗 | 76.185 ~ 76.72(0.535 mm)| **1 对** |
| 底层·高窗 | 78.28 ~ 81.52 | 够,但东边 (117.067, 78.392) 那个孔把 x=117 的天花板压到 77.75,出隘口必须马上降下来 |
| **顶层**同一段 | 75.58 ~ 76.16 | **1 对**(`C751` 在底层,顶层是通的)|
南边过不去:Hub 南侧 A 圈那排 0402 占了 y 60.28~61.12、x 105~114,
上下都只剩 0.05 mm,**只有 y≈56 一条缝**,塞不下三对。
所以三对东行的(pair2/3/5)只能一对一个窗口,**南北次序被 U32 的引脚次序锁死**:
爬升后由西到东是 1,2,3,5,转东后由北到南就是 2,3,5 ——
正好对上「pair2 在 x=133 北拐、pair3 继续东行、pair5 在 x=121 南下」的需求,不用额外交叉。
#### 六对各自怎么走
| 对 | 走法 | 长度 |
|---|---|---|
| 1 | 底层西行 → x 98.3/98.8 爬升 → 西行 74.70/75.55 → site1 | 54.5 / 55.9 |
| 2 | 底层西行 → 爬升 → **高窗** 78.29/78.83 → 降到 77.16/77.70 → 缓降到 75.05/75.70 → site2 | 56.8 / 53.6 |
| 3 | 底层西行 → 爬升 → **低窗** 76.20/76.63 → 降到 73.85/74.35 → 抬回 75.00/75.70 → site3 | 123.1 / 119.9 |
| 4 | **一出焊盘就上顶层**南下(全板唯一要横穿其它对的一对)→ 底层西行 60.30/61.00 → site4 | 63.9 / 62.6 |
| 5 | 底层爬升 → 顶层过隘口 75.68/76.14 → 底层南下 → site5 | 47.4 / 46.1 |
| UP | U32 南边一出焊盘上顶层(竖井底层被扇出孔堵死)→ 顶层东行 61.10/61.70 → x=128 沉底层 → 60.00/60.75 → J23 | 108.0 / 106.0 |
最长的 pair3 是 **123 mm**,加上 `*J` 那 9 mm 一共 132 mm,
在 USB2517I 手册的 152 mm(6 inch)以内。对内偏斜最大 3.3 mm(容差 5)。
#### 这一轮改的两件事(不是布线本身)
1. **`VO2_P` 岛东边界 116 → 119**(`pcb2_pour.py` 的 `ISLANDS`)。
pair5 过隘口那一段在顶层,参考面就是这块岛;边界停在 116 的话,
下沉的两个过孔(x=118)会落到 GND 底填上,那一小段要跨分割缝(违反 §10.1)。
放到 119 之后 `inner1_check` / `inner1_verify` 仍全过(VO2 一个连通域、
最窄横断面 29.30 / 纵断面 9.80,下限 7.0)。
2. **J23 的 `A6↔B6` / `A7↔B7` 短接线要自己画**。原来那两条是自动布线器留下的,
被 `--push` 的「先删本网所有 1/2 层导线」连坐删掉了 —— 少了它们,
USB-C 反插方向就没有 D±。四个焊盘在同一列上(B7 61.25 / A6 61.75 / A7 62.25 / B6 62.75),
两两要短接的中间都隔着对方的脚,只能**绕到连接器东侧 x>213.5 沉底层**跨过去。
为此给 `pcb2_route_dp.py` 加了 `NET#2` 这种「同网络第二条支路」的 key(`netof()`)。
#### ⚠️ 三个这一轮才踩到的坑
1. **`drc_read.py` 不加 `--pcb2` 跑的是下板**(默认 UUID 是下板的)。
第一次读到 649 条、里面全是 `KEY_OE#` / `SDA` 这些下板网络,白查了半天。
2. **DRC 的「连接性」结果在程序化建线之后是陈旧的,要 `location.reload()` 才刷新。**
刚下发完跑出来是 403(我的网络每个还报 2~7 条「与其他相同网络的对象断开了连接」),
而 `pcb2_net_conn.py` 按实际铜算是 22/22 全连通、`pcb_Net.getNetLength()` 也等于算出来的长度。
重载客户端之后立刻变成 **338**(比布线前的 364 少 26 = 12 个网络 ×2 + J23 的 B6/B7)。
⇒ **别信刚下发后的连接性数字**;间距错误那一支倒是即时更新的。
3. **45° 切角的半径会把线甩进旁边焊盘的净距圈**。`chamfer()` 默认 r 从 0.6 降到 **0.35**,
而且在焊盘阵列附近还要**多插一个共线点**把切角压到 0.15~0.2 ——
`USB1_DM` 的让位拐角、J23 那四条出线都是这么救回来的(差 0.04~0.18 mm)。
#### 收工时的数字
| 项 | 值 |
|---|---|
| 导线 / 过孔 | 270 段 / 38 个(含 `*J` 那 5 对) |
| 本地净距校核 | 全过(一般 0.20 / 对内 0.15) |
| `pcb2_net_conn.py` | 22 / 22 个差分网络各 1 个连通域 |
| `inner1_diffref.py --routes` | 每条顶层走线只压在一块铜上(pair5 那段是 `VO2_P`,其余 GND)|
| `inner1_check` / `inner1_verify` | 五块岛全过 |
| **DRC(载板)** | **453 = 同封装内 115(与基线一致)+ 连接性 338 + 间距错误 0** |
---
### 25.14 载板电源与杂散信号布线(2026-09-06 第四轮)—— 栅格迷宫布线器
差分对收工之后还剩 **77 个网络、三百多个端点**:五路的 `VBUSn`、`+5V` / `+3V3_HUB`、
十五根 `POGO*`、`EDL_ENn` / `VBUS_ENn`、`CC1_n` / `THERM_n`、Hub 的十几根配置线、
`SCL/SDA`,外加 §25.8 欠着的 **BM24 那 65 个 GND 脚的逃逸布线**。
这一批和差分对是两类活:差分对要管耦合 / 参考面 / 偏斜 / 换层窗口,是几何设计,
所以写死坐标才说得清理由;这一批绝大多数是「从 A 走到 B、别撞上东西」。
所以新写了 **`.claude/pcb2_route_sig.py`**:一个栅格迷宫布线器,
**产出照样过 `pcb2_route_dp.check()`**(和差分对同一份净距判据),路径怎么来的不重要。
/c/Python314/python .claude/pcb2_route_sig.py # 算 + 本地校核,不下发
/c/Python314/python .claude/pcb2_route_sig.py --push # 下发(没布通的网络要加 --force)
#### 收工时的数字
| 项 | 值 |
|---|---|
| 网络 / 路径 / 导线 / 过孔 | 77 / 431 / **991 段** / **160 个** |
| 净距校核(`check()`,一般 0.20)| **全部通过** |
| `pcb2_net_conn.py`(按实际回读的铜算连通域)| 72 / 75 通 |
| `inner1_verify` / `inner1_diffref --routes` | 五块岛仍各 1 个连通域、最窄颈 7.20 mm;顶层差分下方仍只压一块铜 |
| **DRC(载板)** | **166 = 同封装内 115(与 §25.8 基线一模一样)+ 连接性 51 + 间距错误 0 + 物理错误 0** |
连接性 51 的构成(**全部是已知的、还没做的活**,不是错误):
`VO1~VO5_P` 各 6~7 条 = **31**(五路的贴片电容还没打孔接到 Inner1 岛,见下面「下一步」)、
`+3V3_HUB` 4 + `VBUS_UP` 2 + `SCL` 2 + `POGO5_VDN` 2 = **10**(四个网络各差一两段,见下)、
`GND` **10**(J23 的两个屏蔽脚 + Hub 簇 4 个 0402 的地脚 + 1 个过孔,§25.8 遗留)。
对比布线前:**499 → 166**,连接性 384 → 51。
#### 布线器的三条判据(都不是"看着差不多",是算出来的)
1. **栅格 0.1 mm,障碍先胀 `QERR = g·√2/2` 再栅格化。**
只标"格心落在铜里"的格时,铜边界到最近的被标记格心可以差到将近一整格
(实测一个 Ø0.61 过孔的边在 x=52.781、最近格心在 52.7,差 **0.081** > 0.0708),
于是距离场会**高估** 0.08 mm,净距校核在下发前一刻才炸。
先胀再栅格化之后 `真实净距 >= edt − QERR` 才严格成立。
2. **窗口先小后大、栅格先粗后细(0.1 → 0.05 → 0.025)。**
排母 2.54 间距 / Ø1.699 焊盘 ⇒ 缝宽 0.841 mm,0.25 的线要 0.65,明明过得去,
但 0.1 mm 栅格上离缝心最近的格心可能偏 0.04,加上 QERR 就差那么一点点 ——
于是"从排母针缝里穿过去"在粗栅格上**整片不可达**。
3. **线宽阶梯**:正常宽度过不去就收窄再试(信号到 0.15,功率按 `TRACK_RULES` 的 min)。
Hub 卫星圈是 1.2 mm 网格上的 0402,缝只有 **0.659 mm**,
0.25 的线要 0.65 —— 量化余量一进去就过不去,0.20 才通。
⇒ `W_SIG` 定 **0.20**(不是 0.25)。
#### ⚠️⚠️ 这一轮抓到的最阴的一个 bug:`expand()` 会静默丢掉**路径末端的过孔**
`pcb2_route_dp.expand()` 的语义是「第 i 点的层 = 从这一点走到下一点那一段的层」,
换层的过孔打在第 i+1 点上 —— **但它显式跳过最后一个点**(`i + 1 < n - 1`),
最后一点的层被当成占位符。于是「走到目标焊盘正上方再换层落下去」这种路径,
**过孔被静默丢掉**:两层的铜各画各的,中间断开。
三道校核**全都抓不到**:
净距校核只看撞没撞(断开当然不撞)、`inner1_verify` 只看铜面、
DRC 的连接性又要 `location.reload()` 才刷新。
踩到两次,第二次更贵:
- 布线器自己的路径:`$25N40` / `SDA` / `VBUS_DET` / `XTAL2` / `VBUS_EN3` 五个网络断开;
- **手写的 `bm24_pre()`**:五个站 **50 个 GND 过孔全部丢掉**,
两条梳子 + pin52 的连线整个悬空,DRC 报出 J7n 的 pin 1/2/8/12/47/52 断开(GND 55 条)。
补上之后 GND 从 55 掉到 **10**。
⇒ `pcb2_route_sig._end_via()`:末点上有换层就补一个重复点。**所有**路径(含手写的)都要过这一道。
#### BM24 周围的车道分配(§25.8 那条待办的落地方案)
§25.8 判定"51 个 GND 脚旁边打不下过孔、只能逃逸布线"是对的,
但它写的"前排一律往南、后排一律往北"**没用上两排之间的中央通道**。实际只有三块地方能走线:
```
┌ 后排北侧 v > -1.70,到手机投影边 v=0 ── 后排 7 个 GND 脚的梳子(v=-1.10,5 个过孔)
│ 中央通道 v ∈ [-3.82, -1.70],净高 1.64 ── THERM / CC1 两条东行车道 + pin2/pin8 的过孔
└ 前排南侧 v ∈ [-4.30, -5.06],净高 0.76 ── 前排 pin 12/16/24 的梳子(v=-4.68,宽 0.20)
```
三条算式(每一条都卡在 0.2 mm 上,改动前先重算):
| | 算式 | 结果 |
|---|---|---|
| 前排梳子 v=-4.68 | 到焊盘南沿 0.38 − 0.10;到 `*_DPJ` 东行段上沿 0.38 − 0.10 | 两边都 **0.28** ✔ |
| pin 2 / pin 8 上不了这条梳子 | `*_DPJ` 过了 v=-4.65 放宽到 0.20,u=54.35 处只剩 0.35 − 0.055 − 0.10 | **0.195**(差 5 µm)✘ |
| 中央通道里 GND 与 THERM/CC1 不能共存 | 前排的脚往北出必须**竖着穿过通道**,会切断任何东行车道;想换层绕过去,通道里过孔离相邻竖线只有 0.35 − 0.305 − 0.055 | **< 0** ✘ |
所以:通道判给 THERM/CC1(它们没有别的出路,`R76n`/`R77n` 在东南),
pin 2 / pin 8 在通道最西端就地打孔,其余前排 GND 走南缝。
南梳子上打不下过孔(南北各只有 0.38,要 0.505),所以**往东伸到 u=60.5** 再打两个。
⚠️ **`pin 52` 的扇出在 site1~3 朝东(u=64.48)、site4/5 朝西(u=62.58)** ——
西边那两个正好堵在 THERM/CC1 的车道出口上。本脚本把五个站统一成朝东,
删除框放到 `u <= 65.2` 把旧的收进去。
#### 顺带修掉的两个方向错误(原理图看不出来、几何检查也过的那一类)
1. **`R76n` 装反**(`pcb2_place.BAND['r76']` rot 0 → **180**):
pin1=CC1 要朝**东**(CC1 从中央通道的车道出口 u=62.3 过来)、pin2=VBUS 要朝**西**
(VBUS 从 U5n 的 u=57.5 过来)。rot 0 时两根线各自绕过整颗电阻、当场交叉,
**五个站的 `VBUSn` 全部布不通**。这和 §25.3 的顶针、§25.12 的 U5n 是同一类错误。
2. **`+5V` 从 0.80 收到 0.60**:§25.10 重排逐针分配之后它是 10 针分散取电、
段电流 ≤0.6 A,0.60 mm 外层 1 oz 可载 ~2 A。0.80 在排母到服务带那条
已经站满 EN/POGO 线的走廊里挤不过去(实测五处布不通)。
#### 布线器上必须记住的四条工程约定
1. **先给所有网络的所有焊盘留好出线段,再开始布线**(escape routing 先行)。
不这么做的话先布的网络会把后布的网络**出焊盘的那 0.6 mm** 占掉:
实测 `VBUS2` 斜穿 U25 东侧让 `+5V` 出 U25.1 只剩 −0.02 mm,
`+3V3_HUB` 竖着切进 U42.5 让隔壁 0.95 mm 外的 `EDL_EN2` 出不来。
2. **出线段的方向 = 焊盘长轴(长短边 ≥1.3 时)背离元件形心**;接近方的焊盘(0402、晶振)
才按"背离形心的那根轴"。只用后者会把 `J23.A5` 判成往南出、**正好压在 B8 焊盘上**。
3. **生成树用 Prim,不是最近邻链**。`+3V3_HUB` 有 33 个焊盘,
最近邻链会串成一条长蛇,好几段被逼着绕过整个 Hub 卫星圈。
4. **障碍表要摘掉"下发时会被删掉的铜"**:本脚本负责的网络(整网重画)+
五个 BM24 框里的旧 GND 扇出。不摘的话第二次跑会把自己上一轮的线当障碍,
既不幂等,还会刷出「和马上要删掉的那条线撞了」的假冲突。
#### ⚠️ 铺铜必须重来一遍,而且客户端要**真的**重载
布完线之后 DRC 是 **696**,其中 445 条是「铺铜区域(填充) 到 过孔 / 钻孔」——
新打的一百多个过孔在旧的铜面里没有反焊盘。**布线之后必跑 `pcb2_pour.py --push`。**
跑的时候踩到一个坑:`location.reload()` 会弹出浏览器的「离开该页面 / 留在该页面」确认框
(文档有未保存改动),点了「留在该页面」**页面根本没重载**,
客户端仍卡在后台任务上 —— 表现就是 `工具 → 铺铜管理器…` 点了没反应、
`重建所有` 按钮找不到,`getState_PourFills()` 一直是 0 段。
⇒ **重载前先 `eda.pcb_Document.save()`**,否则等于没重载。
#### 还剩的四个网络(都差一两段,成因已定位)
| 网络 | 差的那一段 | 成因 |
|---|---|---|
| `+3V3_HUB` | U32.46 / R716.2 各一段 | Hub 卫星圈 A 圈(6.3 mm)+B 圈(8.0 mm) 把 QFN 围死,缝只有 0.659 mm,几根线抢同一条缝 |
| `VBUS_UP` | 到 `R709.1` | 同上:R709 在 A 圈东侧,出口被 B 圈的 R716/R720 夹住 |
| `SCL` | J31.23 → U34.2(~70 mm)| 和 `SDA` 抢同一条通道;`SDA` 先布,占掉了唯一那条 |
| `POGO5_VDN` | J32 → J59 | 走廊被十五根 POGO 线切碎之后没缝了 |
**这四个不是布线器的毛病,是 Hub 卫星圈的摆位太挤 + 左下角只有一条通道。**
真要收干净,两个方向(都要用户拍板,因为会动已经验过的东西):
① 把 Hub 的 B 圈(R711/R716/R720,纯配置电阻)从半径 8.0 挪到 9.5,
A/B 圈之间就从 0.7 mm 变成 2.2 mm —— 代价是这三颗的 GND 扇出过孔要重做;
② `SCL/SDA` 改成从 J31 的**东**端绕,或者把 `U34`(测温) 从左口袋挪到离 J31 近的地方。
#### 45° 走线(2026-09-06 用户拍板:**全板不许有直角走线**)
在 `pcb2_route_dp.py` 里加了三个工具,两个脚本共用:
| 函数 | 干什么 |
|---|---|
| `sharp_corners()` | 列出所有转向角 > 45° 的拐点(**换层点不算** —— 那是过孔,不是拐角)|
| `chamfer45()` | 逐个拐点把 45° 斜切的半径**试出来**:`0.50 → 0.06` 依次退让,取第一个过净距的 |
| `smooth_micro()` | 先抹掉微台阶(偏离前后连线 < 0.15 mm 的中间点),再切 |
结果:**差分对 10 → 0,信号线 72 → 0,全板一个直角拐点都没有**,
净距校核、`pcb2_net_conn`、`inner1_verify`、`inner1_diffref` 全部保持通过,
**DRC 仍是 166**(和 45° 化之前一模一样)。
四条实现上的判据(每一条都是踩出来的):
1. **只切转向角 > 45° 的拐点。** 已经是「正 + 斜」的 45° 拐是标准形态,
再切一刀会变成两个 22.5°,反而更糟。
2. **切完只校核斜切段本身。** 被缩短的那两段是原来那两段的子集,净距只增不减。
3. **净距余量必须按 `need()` 算,不能只算净距再拿 `CLR` 比。**
对内间距是 0.15,`*_DPJ`/`*_DMJ` 就是贴着这个数并排走的 ——
一律按 0.20 判的话,这五对的拐角全都"切不动"(第一版就是这么卡住的,10 → 5)。
4. **`smooth_micro` 只给布线器的产出用,差分对不抹。**
而且**绝不能删线宽换挡点** —— BM24 出线靠 0.11 / 0.20 / 0.28 三档才合法,
把换挡点当"共线冗余点"删掉,整条就按最宽的那一档画,当场违规(实测 275 → 211 段,两处炸)。
顺带:抹平**不是**保守操作(斜切才是),所以校核里必须连**本轮新打的过孔**一起查 ——
只查线的话会把线挪进别人的孔里(实测 `USB5_DM` 撞 `USB3_DP` 的孔)。
⚠️ **T 形接头不算拐角,保持直角。** BM24 那两条 GND 梳子上,
中间几根出线段是「梳子 + 支线」的 T 形接头 —— 线本身没有拐弯,只是两条线相交。
最西那一根已经和梳子写成同一条路径,所以它那个 90° 切成了 45°;
其余的按 T 形保留。前排梳子所在的通道只有 0.76 mm,
就算全部改成 45° 分支,斜切半径也只能到 **0.10 mm**(算式:0.3093 − r ≥ 0.20),肉眼看不出区别。
### 25.15 载板收尾:五路 `VOn_P` 电容打孔 + §25.8 遗留的悬空 GND(2026-09-06 第五轮)
**DRC 从 166 掉到 125 = 同封装内间距 115(基线)+ 连接性 10 + 间距错误 0 + 物理错误 0。**
连接性剩下的 10 条全是 §25.14 末尾那四个网络(`+3V3_HUB` 4 / `VBUS_UP` 2 / `SCL` 2 /
`POGO5_VDN` 2),要用户拍板才能动。**这一轮之后,载板上不需要拍板的活全部做完。**
| 脚本 | 干什么 | 产出 |
|---|---|---|
| `.claude/pcb2_vo_vias.py` | 25 个贴片电容焊盘各打一个过孔下到 Inner1 的岛上 | 25 线 / 25 孔 |
| `.claude/pcb2_gnd_patch.py` | 自己找出悬空的 GND 连通域再补孔 | 5 个域 → 6 线 / 5 孔 |
| `.claude/pcb2_npth.py` | 从铺铜反焊盘里**反解封装自带的非金属化孔** | 见下 |
#### 一、五路 `VOn_P` 的电容(连接性 51 里的 31 条)
每个 `VOn_P` 网络 10 个焊盘:**5 个通孔**(`C8n1.1` 电解正极 / `TP8n1` / 排母 3 针)
本来就落在 Inner1 的岛上;剩下 **5 个贴片焊盘**(`C8n2/3` 100µF、`C8n4/5` 22µF、
`C8n6` 100nF)只有顶层铜,和岛之间没有任何通路。⇒ 每个旁边打一个过孔。
选点判据(`pcb2_vo_vias.place()`,`pcb2_gnd_patch` 共用同一套):
| | |
|---|---|
| 方向 | 只取 8 个方向(0/45/90…);一段直线不行才拐**一个 45°**,不许直角 |
| 起步距离 | 过孔铜边到本焊盘 ≥ 0.15(同网,不是 DRC 约束,是不想做 via-in-pad)|
| 净距 | 借 `pcb2_route_dp.check()` 同一份判据,异网 ≥ 0.20 |
| 岛内余量 | 过孔中心离岛边界 ≥ 0.61/2 + 0.30 = 0.605 |
| 线宽 | `PWR4A` 最小 0.30;从 1.00 起往下退让,25 个里 20 个用到 1.00、5 个 0402 用 0.60 |
25 个全部一段直线搞定。铺完铜 `inner1_verify` 五块岛仍各 1 个连通域、
**5 焊盘 + 5 过孔全在主域**、最窄断面 7.20/9.10/10.15/7.35/7.60 mm(下限 7.0)。
> `inner1_verify.py` 这一轮加了**过孔**的校核。原来只查本网通孔焊盘 ——
> 贴片电容全靠这一个孔接岛,孔要是掉进边角碎片里,原来那版一个字都不会说。
#### 二、§25.8 遗留的悬空 GND(连接性 51 里的 10 条)
`pcb2_gnd_patch.py` **不抄 DRC,自己算**:把 GND 的焊盘/过孔/导线当图,
一个连通域里只要有一个过孔或一个通孔焊盘就算落到平面上,
**一个都没有的域就是悬空的**。算出来 5 个:
`C749.2` / `R710.2` / `U32.19` / `J23.A1B12` / `J23.B1A12`。补完再跑,0 个。
⚠️ **下发不能用 `pcb2_route_dp.push()`** —— 它整网重画,对 GND 就是把 210 个扇出孔
连同 BM24 的梳子一起删光。改成只动自己那几个对象,靠 `_pcb2_gnd_patch.json`
记账(上一轮画在哪),下次 `--push` 先按坐标删掉再重画。
**不记账实测踩过**:改完选点逻辑直接再推,板上多出一对旧坐标的过孔(425 而不是 423),
而且新画的细线被 EasyEDA 并进了旧的粗线里 —— 现象是"改了没生效"。
#### ⚠️⚠️ 这一轮最值得记住的:**封装自带的孔,API 一个都读不出来**
J23(USB-C 母座)的封装里有**两个 Ø0.60 的非金属化定位孔**,
在 `A1B12` / `B1A12` 两个 GND 焊盘的外侧角上:**(213.660, 59.100)** 和 **(213.660, 64.900)**。
它们不在 `pcb_PrimitivePad.getAll()` 里;`pcb_PrimitiveRegion` / `pcb_PrimitiveFill` 是空的;
`pcb_Primitive.getPrimitiveByPrimitiveId('e55')` 返回空;
`pcb_Document.getPrimitiveAtPoint()` 只回最上面那条线。
**能看见它们的只有两处:DRC(「挖槽区域 到 导线」)和内层铺铜给它们让出来的反焊盘。**
⇒ `pcb2_npth.py`:把 Inner1/Inner2 的铺铜环读回来,拟合出里面所有的**圆弧**,
用「已知过孔的反焊盘半径 − 过孔半径」标定铺铜净距(实测 **0.3583 mm**,234 个样本,
离散度 0.005),再反推每个圆的真实孔径;圆心对不上任何焊盘/过孔的就是封装自带的孔。
全板扫出 423 段弧,滤掉铺铜自己的圆角(孔径 ≈ 0)和板框 R5(≈ Ø8.08),**只剩这两个**。
/c/Python314/python .claude/pcb2_npth.py --write # 写 _pcb2_npth.json,布线脚本读它
**两类孔的待遇完全不同**(一条条用 DRC 试出来的,写在 `pcb2_vo_vias.holes()` 里):
| | 线能不能压上去 | 过孔能不能靠近 |
|---|---|---|
| 焊盘自己的孔(`SLOT` / `ROUND`,金属化)| **能** —— 它就是焊盘的一部分 | 不能,钻孔间距 ≥ 0.30 |
| 封装自带的非金属化孔 | **不能**,DRC 报「挖槽区域 到 导线 距离 0mil」| 不能 |
一开始把两类混在一起判,结果是「谁都连不上 J23 的屏蔽脚」——
`J23.1`/`J23.4` 是 `SLOT 0.80×1.50` 的槽孔焊盘,**焊盘上任何一点离自己的槽都不足 0.80 mm**,
按那个判据连焊盘本身都碰不得。
#### 这一轮踩到的另外两条
1. **净距校核只看铜,钻孔是另一条规则。** 第一版给 `J23.A1B12` 打的孔正落在
`J23_4` 的**焊盘里**(同网,铜的判据直接跳过)—— 校核全过,DRC 报
「钻孔 到 钻孔 距离 0mil,应该 >= 11.8mil」。⇒ `fits()` 里同网的**通孔**焊盘
和同网的**过孔**都要按 `DRILL = 0.33` 再判一遍(规则要求 0.2997,留 30 µm 余量)。
2. **线的起点默认在焊盘中心,但要能往外退。** `place()` 的 `starts()` 沿出线方向
从中心一路退到焊盘边内 0.02 mm,取第一个过的 —— 焊盘正中有孔时(J23 那两个)
只有退到边上才过得去。25 个电容一个都没用上这一条(全部从中心起步)。
#### 追加(2026-09-06 第五轮后半):`U34` 挪到 J31 旁边,四个网络收掉两个
用户拍板「直接把 U34 挪到 J31 附近」。之前按「只动布线」试了一轮(见下),
`SCL` / `POGO5_VDN` 其实已经布通了,但 SCL/SDA 仍是 70 mm 的长跑;挪件之后 **~4 mm**。
| | 原来 | 现在 |
|---|---|---|
| `U34`(LM75BD)/ `C760` | 左口袋 (36, 12) / (36, 6.5),**顶层**,贴着 CH4 量进风侧空气 | **(68.0, 72.1, rot 90) / (72.6, 72.1, rot 90),底层**,J31 北排 pin 21/23 正上方 |
| `SCL` / `SDA` | J31.21/23 → 左下角,~70 mm,两根抢左下角唯一那条通道 | ~4 mm,底层直连 |
| DRC | 125 | **121** = 同封装内 115 + 连接性 6(`+3V3_HUB` 4 / `VBUS_UP` 2)|
⚠️ **它量的东西变了**:原来是进风侧空气温度,现在是两排手机之间**排母走廊**的温度。
风扇闭环(§22.6)的阈值要按新位置重新定 —— 这是挪件的代价,不是 bug。
位置是被三样东西夹出来的(`pcb2_place.BOT_GLOBAL` 里有注释):
顶层塞不下(J31 焊盘顶 69.62 到 U24 底 71.25 只有 1.6 mm);底层这条带子上沿是
`USB1_DM` 那对长差分(手写几何,y≈74.7,不能动),竖放时北排焊盘压在上面(实测 −0.14);
横放后 4.38 mm 高的焊盘只能落在 y 72.01~72.17 之间,再往左 `U34.4` 撞
`USB1_DM` 在 (63.45, 74.70) 的换层过孔。旧位置的 5 个 GND 扇出孔按框删掉。
**只动布线那一轮的结论**(`pcb2_route_sig.py` 里两处改动,都保留了):
1. **出线方向要有备选**。`entry_stub()` 现在返回全部合法方向,`route_net()` 在首选方向
布不通时换一个再试。`R709.1`(VBUS_UP)原来「背离形心」= 朝东扎进 A/B 圈之间 0.268 mm 的
死胡同,`U34.2` 原来朝南顶着板边 —— 两个都是**只布这一个网络、整板空着也布不通**,
不是拥挤,是方向选错。换方向之后 `SCL` 通了。
2. **POGO 按两端直线距离从短到长排**。site4/5 的 `VDN` 源在最东、靶在最西,
后布就被另外两根夹死;提前之后 `POGO5_VDN` 通了。
3. **试过把 `+3V3_HUB` 提到卫星圈配置线之前,更糟**:它 33 个焊盘先铺满 Hub 周围,
`XTAL1`/`CFGSEL0`/`PRTDIS6`/`PRTDIS7`/`HUB_RST` 五根全布不通(4 → 7)。已回退。
大网络必须排在点对点的小网络之后。
⇒ 剩下 `+3V3_HUB`(`U32.46` / `R716.2`)和 `VBUS_UP`(`R709.1`)三段,
全在 Hub 卫星圈 A/B 两圈之间,只动布线穷尽了:**要收干净只剩方案 ①(B 圈半径 8.0 → 9.5)**。
顺带一条 `pcb2_vo_vias.fits()` 的 bug:本轮新打的**同网**过孔之间没判钻孔间距,
U34 相邻三个 GND 脚的孔排成一列、中心只隔 0.23 mm。已按 `DRILL` 补上。
### 25.16 载板 v2:元件全部到底层,排线穿槽(2026-09-06 用户拍板)
**用户两条指令**:① 把载板正面的器件全部放到背面,在背面重新布局;② 排线通过板内开的细长槽
穿过去接到载板。补充:**器件可以放到主板投影下方(底层),方便布线。**
脚本 `.claude/pcb2_place.py`(v2,文件头有完整说明);v1 存档 `obsolete/pcb2_place_topside_2026-09-06.py`,
v1 的全部铜/元件状态在 `.claude/_pcb2_snap_topside.json`(`pcb2_snapshot.py` 抓的,1586 线 / 416 孔 / 7 铺铜)。
截图 `PCB2-v2-all.png` / `PCB2-v2-bottom.png` / `PCB2-v2-ch1.png`。
#### 落地结果
| | v1 | **v2** |
|---|---|---|
| 顶层元件 | 131(服务带 105 + 顶针 20 + J23/U31 组 6)| **20(只有顶针)** |
| 底层元件 | 30 | **141** |
| 穿线槽 | 无 | **10 条**(每站 2 条,3.0 mm 宽,跑道形,layer 12 挖槽区域)|
| C8n1 Ø10×16 电解 | 顶层立装(载板最高件 16 mm)| **底层卧倒**(占高 10 mm)|
| Hub 簇中心 | (110, 67) | **(100, 68)** |
| 铜 | 全部布完 | **全部清空**(1416 线 + 16 条漏网的 + 416 孔 + 7 铺铜),要重来 |
本地检查(无重叠 / 无越框 / 无人压槽 / 顶层只有顶针 / 底层件离螺钉头 ≥ 2.8/3.5)
与 `pcb2_clear.py` 焊盘级净距(跨元件 ≥ 0.20)全过;`--verify` 回读焊盘坐标核了镜像语义
(J23 口朝 +X、R717/R718 对上 A5/B5、J71/U51/U24 都在 layer 2)。
#### 槽的几何(本体坐标,v<0 = 接口边外侧)
| 槽 | u | v | 尺寸 | 给谁 |
|---|---|---|---|---|
| 电池槽 | 5 ~ 43 | −4.2 ~ −1.2 | 38 × 3.0 | BM3E 排线 + 保护板整体穿过(J600 在 u≈23.8)|
| 尾插槽 | 47 ~ 64 | −4.2 ~ −1.2 | 17 × 3.0 | 尾插排线 + BM24 插头(J1401 在 u 47.5~59.7)|
两槽之间 4 mm 筋;槽东端到本体边 3.09 mm,再到邻站 4.41 mm。EDL 两根飞线(TP1204/1205,u 42.6/45.4)
走电池槽东端或尾插槽西端。**排线从主板正面(z = 3.8)越过接口边、向下穿槽、在底面继续往 −v 走**,
不用折返,所以 TP8n1/2 与 J7n 都排在槽外侧(走廊)的行 A。
⚠️ **槽长按经验估,打样前必须拿实物量**:BM3E 保护板长度(决定电池槽 38 够不够)、
尾插排线 / BM24 插头宽度(决定尾插槽 17 够不够)。改 `SLOTS` 一行重跑 `--outline` 即可。
#### 底层排法(本体坐标)
v −1.2~−4.2 ═══ 电池槽 ═══ 筋 ═══ 尾插槽 ═══
v −7.5 行 A TP8n1(21) C8n6(23.5) TP8n2(26) C8n2(31) C8n3(36.5) J6n(43.5, v −8.5) J7n(56)
v −12 行 B (西半边空着:差分对 / 电源线的高速路) U5n(56) R76n(60) R77n(62.5)
v +3 行 C C8n4(20.5) C8n5(26) R74n(31) U4n(35) C76n(38.5) · C70n(49.5) U2n(54) C71n(58) C72n(60.5) R70n(63)
v +8 C8n1 引脚 (23.5, 8),罐体往 +v 躺到 v≈27.5(keep-out 12.5 × 17)
行 C 全在主板投影下方,紧贴槽的内侧。**跨槽的网络**(+5V / VBUSn / EN 进 VBUS 组,EDL 两根进 U4n,
VOn_P 岛接 C8n4/5 与 C8n1)都得从槽端绕:4 mm 筋(u 43~47)或槽东端(u > 64,到邻站电池槽之间有 12.5 mm)。
4 A 主路径(排母 → TP8n1)不跨槽,仍在走廊里。
全局件(板坐标,全部底层):J31 (62, 67.5) / J32 (158, 67.5) 没动;Hub 簇 (100, 68),C751 挪到西北角 (96, 74.3) 横放;
U31 (87, 73) / C736 (84.5, 77.5) / C737 (92.5, 77.2);U34 (78, 72.6, rot 90) / C760 (78, 76);
R721/R722 (83/81, 62.2);J23 (214.866, 62, **rot 270**) / R717 (210.37, 63.25) / R718 (210.37, 60.75)。
#### 底层镜像语义(实测,写进 skill §9w)
底层 = 封装先在本地系沿 x 轴翻(ly → −ly),再按 rot 逆时针转。两脚件 pin1 方向和顶层一样;
rot 0 的 SOT23-6 / BM24 南北两排对调;rot 90 时东西对调。所以 J23 在底层用 rot 270 才口朝 +X,
R717/R718 的 y 对调。**J7n 在底层 rot 0 时奇数排在南** —— 这改变了插头的物理手性,
§24.3 那个「哪一排是奇数排」的镜像位实测**必须按底层装法重做**。
#### 三条代价(都是决定,写进 §12)
1. **C8n1 卧倒占高 10 mm**,两板净空 13 mm ⇒ **下板在五块罐体投影(`pcb2-bottom-heights.json` 里 h=10 的五块)下只能放 ≤ 2 mm 的件**。
排母 J31/J32 本体 8.5、J6n 3.6、J23 3.2 同理。下板布局前先读这个文件。
2. **顶层变成空的**(只剩顶针焊盘)⇒ 顶层是一整层自由布线层,比 v1 多出一层;但每站 U4n/U2n 组的
信号都要跨槽,走线比 v1 长 10~30 mm。
3. **v1 的全部布线作废**:11 对差分(`pcb2_route_dp.py` / `pcb2_dp_long.py` 的手写几何)、
`pcb2_pour.py` 的 `ISLANDS`(五块 VOn_P 岛要重划,且要跨槽)、`pcb2_route_sig.py` 的 77 个网络、
扇出、`pcb2_vo_vias.py`、`pcb2_gnd_patch.py` —— 侧车文件(`_pcb2_sig_routes.json` /
`_pcb2_gnd_patch.json` / `_pcb2_vias.json` / `pcb2-copper.json` / `_pcb2_route_geom.json`)全部过期。
重布顺序:`pcb2_rules.py --check`(规则没动)→ 重划 `ISLANDS` → `pcb2_pour.py --push` →
`pcb2_route_dp.py --dump` → 重写 `SITE_J`(站内坐标,底层版)和 6 对长差分 → 扇出 → 迷宫布线 → vo_vias → gnd_patch。
#### 2026-09-06 补:槽改到远端边(v3)+ C8n1 换矮封装
- **用户第二次调整**:槽挪到**主板投影外侧、靠板边**那一条(本体坐标 v 45.5~48.5),排线按 6 cm 跨过主板正面到远端边、
下穿、折回底面;上排下移 / 下排上移各 2.5 mm(`SITES` y 83.0 / 7.5),板边留 3.5 mm 筋;中跨 M3 孔随之到 y 79.5。
每站器件**全部收进主板投影下方**(v 21~42 五行,`pcb2_place.BAND`),走廊只剩 J31/J32、Hub 簇、U31 组、U34、R721/722、J23。
尾插排线全程约 57 mm(J1401 v 2.86 → 远端边 → 槽 → J7n v 36),电池排线约 52 mm。
- **C8n1 换矮封装**:Rubycon 6.3TPV2200M10X10.5(C3828985,SMD D10×L10.5,液态铝电解 ESR 60 mΩ、纹波 1.19 A,库存 500)。
立创库里这颗器件挂的是**直插**封装,所以在个人库建了「6.3TPV2200M10X10.5 SMD」(符号复制自立创;封装为
`CAP-SMD_BD10.0-L10.3-W10.3-LS11.2-FD_H10.5` 的副本,渲染图核过**焊盘 1 = +**)。`c4_site.py` 的 `P['C2200U']` 已换,
五页重画 + 六项验证 / 跨页 / port_audit 全过,PCB 导入变更 80 移除 + 80 增加(整页重画的正常现象),
`pcb2_place.py` 不再卧倒(`CAN_BODY` 10.3 见方),截图 `PCB2-v3-c801.png` 核过极性丝印。
- Inner1 五块岛改成「走廊主体 + 主板下方整条带」(`pcb2_pour.ISLANDS` v3),最窄断面 7.05~30 mm,全过。
为差分让位:VO2 主体收到 x 87.3、VO4 收到 x 89 / 89.5(Hub 西侧 x>87.7 顶层差分参考 GND)。
- 为布线做的摆位微调:Hub 西侧 C747/C748 挪到 (88.2, 66.6)/(88.5, 69.625)(十条 D± 车道从 U32 西缘扇开到 0.75 间距、
x 87.7~93.3 放换层过孔);U31 组到 J31 东端南侧 (87.5, 59.5);U34/C760 到 J31 南侧 (58/62.5, 60);
R721/R722 (80/78, 61.5);R717/R718 (209, 64.5/59.5)。差分几何本身还没写(下一步)。
#### 2026-09-06 补 2:按实测排线尺寸定槽(v3b)
用户实测:**电池排线 8 宽 × 38 长,尾插排线 18 宽 × 55 长**。
| | 走向 | 槽(本体坐标)| 长度核算 |
|---|---|---|---|
| 电池排线 | J600 (v 4.6) 越过**接口边**下穿,折回主板下方的 P+/P− | u 18.8~28.8,v −4.2~−1.2(10 × 3)| 4.6 + 3.8 + 1.6 + ~6 ≈ 16 ≪ 38 ✔ |
| 尾插排线 | J1401 (v 2.86) 跨过主板正面到**远端边**下穿,折回 J7n | u 37~57,v 45.5~48.5(20 × 3)| 41.8 + 4.2(斜下)+ 1.6 + ~3.5 ≈ **51**,余 4 ✔ |
38 mm 的电池排线够不到远端边(光跨主板就要 40),所以电池侧回到接口边;尾插侧 55 mm 走远端边的前提是
**J7n 贴着槽放(v 42.5,东端 ≤ 50.8 让开 H1 螺钉头)**。每站器件仍全部在主板投影下方
(`pcb2_place.BAND` v3b:行 A v 3.5 TP+/C8n6/TP−/C8n2/C8n3,行 B v 8.5 C8n4/C8n5 + C8n1 (33, 11),
行 C v 21 EDL 组,行 D v 26 VBUS 组,行 E v 38 R77n/R76n/U5n,行 F v 42.5 J7n,J6n (61.5, 40.5))。
Inner1 主板下方那块收到 v −1~14;电池槽落在走廊主体里,铺铜自己让开,最窄断面 7.05~30 mm,五块实测全过。
U31 组为让开 CH4 的电池槽挪到 (87.5, 60.5) / C736 (80.5, 58.5) / C737 (93, 54),**USB1 那对的底层车道改走 y 64.0/64.46**。
截图 `PCB2-v3b-bottom.png` / `PCB2-v3b-ch1.png`。
#### 2026-09-06 补 3:尾插槽回到 J1401 正下方,J7n 放到主板下方远处(v4,用户拍板)
用户指令:**尾插槽放在主板尾插接口(J1401)正下方;载板尾插座放在主板下方远处、50 mm 排线够得到的地方;
连接时尾插排线走载板背面。** 事实来源 `pcb2_place.py`(`SLOTS['tail']` / `TAIL_LANE` / `BAND` 行 D~F)。
| | v3b | **v4** |
|---|---|---|
| 尾插槽(本体坐标)| u 37~57,v 45.5~48.5(远端边外侧)| **u 45~65,v 1.4~4.4(J1401 本体 u 47.5~59.7 / v 1.7~4.0 正下方)** |
| 排线路径 | J1401 → 跨过主板正面 → 远端边下穿 → 折回 3.5 | J1401 出线朝接口边 2.9 → 绕过接口边下落 ~5(插头 1 + 主板 1 + 立柱 3)→ 折回主板下方到槽心 2.9 → 穿板 1.6 → **背面往 +v 走 34.1** |
| 长度核算 | ≈ 51 / 55 | **≈ 46.5 / 50**(用户给的可达长度),实长 55 再余 5 |
| J7n | (44.5, 42.5) rot 180 | **(53.5, 37.0) rot 0**,框 u 47.2~59.8 / v 35.7~38.3,离 H1 4.0、H3 2.9 |
| U5n / R76n / R77n | J7n 南边行 E v 38 | **J7n 北边**(插头背后):U5n (49.8, 41.5, rot 180),R76n (52.8, 39.15),R77n (55.8, 39.15) |
| J6n | (61.5, 40.5) | (62.5, 41.0),EDL 飞线随排线走背面 ~40 mm |
| 行 D(VBUS 组)| u 34.5~48 | **整体西移 4.5 → u 30~43.5**,让开排线车道 |
| 排线车道 | — | **`TAIL_LANE` u 44.6~62.6 / v 4.4~38.3 不放任何底层元件**(`check()` 新增一条),排线要平贴到插头 |
**手性的几何推导(决定 J7n 用 rot 0,而不是 v3b 的 rot 180)**:
1. 排线是 1:1 直通(§24.3 用户实测:摊平后同排同序号导通);两个公头同面、相差 180°。
2. v4 路径里排线只绕 **u 轴**弯折(接口边一个 U 形回折 + 槽里一个台阶),**不在面内转、不横向翻**,
所以排线上任何一点的 u 坐标从头到尾不变。公头 A 的「内排」(沿排线更靠近 B 的那一排)是 J1401 的 −v 排;
排线到 J7n 时是朝 +v 方向来的,公头 B 的内排也是 −v 排。内排对内排、同 u ⇒ **J7n 的触点图案就是 J1401 触点图案的平移**
(v3b 那条路径同理,也是平移;§24.3 讲的「台阶式 / 朝上座子」那套是母座朝上时的情形,J7n 朝下后不适用)。
3. 翻面次数:U 形回折翻一次,台阶不翻 ⇒ 公头 B 朝 +z(朝载板背面),正好插进朝 −z 的 J7n ✔。
4. J1401 的 pin1/2 端(G1)在 +u(用户实测右端触点对地导通,顶视接口边朝下)⇒ 平移后 J7n 的 pin1/2 端要在 **−u**;
自建封装 `pin51`(pin1/2 端)在本地 −X,底层翻层是「本地 y 翻再转 rot」不改 x ⇒ **底层 rot 0**。
rot 180 会把 pin1/2 端(VBUS)放到东边,与 §24.3「VBUS 落到载板这颗的 −X 端」自相矛盾(v3b 没发现,当时把它推给了"事后改焊盘编号")。
5. `--verify` 回读(CH1,J71 中心 (58.5, 120)):pin1 (54.3, 118.94) / pin2 (54.3, 121.06) / pin51 (52.47, 120) / pin52 (64.53, 120),
pin4 (54.65, 121.06) / pin6 (55.0, 121.06) ⇒ **奇数排南、偶数排北,D± 在北排西端,VBUS 西端** ✔。
仍然悬而未决的只有「封装的奇/偶排分配对不对」(§24.3 镜像位)—— 错了 D± 换到南排西端,U5n 绕西端多走 2.5 mm,只改焊盘编号。
**站内 D± 短差分(下一步重写 `SITE_J`)**:J7n.4=DMJ (49.65, 38.06) / .6=DPJ (50.0, 38.06) 往北 1.6 mm 进 U5n 南排 .3=DPJ (48.85, 40.35) / .1=DMJ (50.75, 40.35)。
两端次序相反,仍然要交叉一次(v3b 结论不变):DPJ 底层直走,DMJ 上顶层从 DPJ 底下穿过去(顶层空的,Inner1 在这里是 GND 底填,参考面干净)。
代价 / 风险:① 排线要从主板反面钻过(立柱只有 3.0 mm),主板反面 u 44~63 / v 0~4 有没有高元件挡道**图纸上看不出来,只能试装**(§12);
② 排线 18 宽比 BM24 插头宽 6 mm,超出插头的那 3 mm 会搭在 H3 (61.9, 33.7) 螺钉头边上(头 Ø4.5,西沿 59.65;插头东端 59.6),不碰插头本身;
③ H7 (42.6, 3.7) 立柱西沿 44.85 与排线西沿 44.6 差 0.25,排线往东挪半毫米即可。
#### 2026-09-06 补 4:尾插槽挪到与电池槽同一条线(v4c,用户拍板)+ 电池排线直焊座(v4b)
用户指令:**尾插槽移到与电池槽同一水平线**。⇒ 两条槽都在接口边外侧 v −4.2~−1.2:电池槽 u 18.8~28.8、尾插槽 u 45~65。
排线翻过接口边直接下穿,**不再从主板反面 3.0 mm 的缝里钻**(补 3 的那条试装风险消失)。背面到 J7n 长了 5.6,
J7n 从 v 37 收到 **v 35**、中心 u 52.5(让开 H3 螺钉头 3.1):2.86 + 5 + 2.7 + 1.6 + 37.7 ≈ 49.9 ≤ 50,实长 55 余 5。
U5n (48.8, 39.5, rot 180) / R76n (51.8, 37.15) / R77n (54.8, 37.15) 跟着下移 2;`TAIL_LANE` v −1.2~36.3。手性推导(补 3)不变:只绕 u 轴弯,J7n 仍 rot 0。
同一晚的 **v4b 电池侧**(§13.5 末尾):J8n 排线直焊座 (22.8, 15.0),电池排线车道 u 18.8~27.8 / v −1.2~13,电容组围着 J8n,
C8n1 (34.3, 11.3),Inner1 主板下方那块岛扩到 v 20。
实测:摆位本地检查 / `pcb2_clear` 846 焊盘 / `inner1_check` / `inner1_verify` 五块岛全过,最窄横断面 7.05~20.85;
**VO3 的纵断面从 12.3 掉到 8.6**(x 194.18,CH3 尾插槽 x 193~213 在 VO3 走廊主体东端切了个口),仍 ≥ 7.0。
截图 `PCB2-v4c-ch1.png` / `PCB2-v4c-bottom.png`。
⚠️ **对长差分方案的影响**:补 2 里"USB2/3 上顶层北上 → y 79/80.5 东行"那两条车道会**横穿 CH2 的尾插槽(x 121.5~141.5, y 78.8~81.8)**,
CH1 的槽(x 50~70)也压在 USB1 "y 98 东行"的西侧回路之外但 x 36 北上那一段要避开 CH1 电池槽(x 23.8~33.8)—— 写 `pcb2_dp_long.py` 时把 10 条槽当障碍。
#### 2026-09-06 补 5:五块主板连槽整体转 180°,接口边一律朝板边(v5,用户拍板)
用户指令:**整体旋转主板和槽,两行的槽都靠近板边**。⇒ `pcb2_place.SITES` 的站向翻转(上排 rot 180、下排 rot 0,位置矩形不动):
| | v4c | **v5** |
|---|---|---|
| 上排(CH1~3)接口边 | y 83(朝走廊)| **y 127.66(朝板边)**,槽 y 128.86~131.86,离板边 3.14 |
| 下排(CH4/5)接口边 | y 52.16(朝走廊)| **y 7.5(朝板边)**,槽 y 3.3~6.3 |
| 排线 | 从走廊一侧翻下 | **从板边翻下**,在背面往板中心走;走廊 y 52.16~83 完全空出来(只剩 J31/J32 / Hub / U31 组 / U34 / J23)|
| 顶针(侧键,v 2.5~7)| 走廊一侧 | 板边一侧 |
| 每站底层件 | 电容组 / J8n 在走廊一侧,J7n/U5n 在远端 | 反过来:**J7n/U5n 靠走廊**(上排 y 88~95,下排 y 40~48),电容组 / J8n / C8n1 靠板边 |
| Inner1 岛 | 走廊主体 + 主板下方 v −1~20 的窄带 | 走廊主体 + **整条竖带 u 8~44 × v −1~47**(板边贯通到走廊);VO2 加 **Hub 北横带 (87, 75.5, 100.5, 83)**,高 7.5 |
站内摆位(`BAND`)、槽(`SLOTS`)、车道(`LANES`)、手性推导全部不用改 —— 都是本体坐标,随站一起转。
`--verify` 里"pin51 在西"改成按本体 −u 判。
实测:本地检查 / `pcb2_clear` 846 焊盘 / 五块岛全过,最窄横断面 7.05~31.55,**VO2 纵断面 7.30**(x 87.28,就是那条 Hub 北横带)。
截图 `PCB2-v5-bottom.png` / `PCB2-v5-ch1.png`。
⚠️ **对布线的影响**:① 走廊北带 y 75.5~83、x 87~100.5 现在是 VO2_P 平面,差分在那里只能走**底层**(参考 Inner2);
② 五站 U5n 都贴着走廊(离 Hub 近多了,长差分缩短 30~40 mm);③ 10 条槽全在板边,不再挡走廊里的任何车道;
④ 排线从板边翻下来,下板(在载板下面)的边缘 y < 6.3 / y > 128.9 那两条带要给排线让开。
#### 2026-09-06 补 6:v5 差分布线定稿 —— 11 对差分 + Hub 西缘两条 +3V3 车道(已下发,DRC 无新增间距错误)
事实来源:`.claude/pcb2_dp_long.py`(六对长差分 + +3V3 三条)与 `.claude/pcb2_route_dp.py` 的 `SITE_J`(五对短差分,站内坐标)。
v3 版长差分存档在 `.claude/obsolete/pcb2_dp_long_v3_2026-09-06.py`,只作历史。
**出发点的困难**:U32(QFN-64,底层)十根 D± 全在西缘 x 95.55、0.5 脚距,中间还夹着 pin5 / pin10 两个 +3V3,
而五个目的地是四面八方(1 西北远处、2 正北、3 东北、4 西南、5 东南)。0.5 脚距的车道之间**打不了孔**
(孔要离两边车道各 0.645),所以只能像剥洋葱:最北的先拐走,邻居走了才能打孔 —— pair 5 → pin10 → pair 4 打孔上顶层 → pair 3 → pin5 → pair 2。
| 车道 | 层 | 走法 | 备注 |
|---|---|---|---|
| pair 1 | 底 | y 64.25/64.75 直着西行到 x 22.34/22.82,北上进 U51 | 从 J31 底排焊盘(底 65.38)与 U31 pin1(顶 63.35)之间穿过 |
| pair 2 | 底 | 西行到 89.27/89.75 北上,y 80 起 45° 斜到 93.84/95.74 进 U52 | 斜段必须在 pair 3/5 东行车道(y ≤ 77.1)之上;绕开 site2 H1 (89.39, 85.36) |
| pin5 +3V3 | 底→顶→底 | 西行到 90.4 跟 pair 3 北上,(90.4, 70.5) 翻顶层西去 (88.2, 70.5) 下来进 C747 | C747 挪到 (88.2, 71.5) rot 90,夹在 J31 最东列与 pair 2 之间 |
| pair 3 | 底 | 西行到 91.05/91.53 北上,y 76.50/76.98 东行,x 112 压到 75.40/75.88,x 165 北上进 U53 | 压低是为了从 MH (148.1, 79.5) 的 Ø6 焊盘(底 76.5)下面过 |
| pair 4 | **顶** | x 92.2 打孔上顶层(DM 67.95 / DP 68.85),沿 91.5/91.98 南下到 y 52,斜到 (89.6/90.5, 50.3) 下来进 U54 | 全板唯一整段走顶层的一对;底下 Inner1 全是 GND |
| pin10 +3V3 | 底 | 西行到 92.95 跟 pair 5 北上,斜到 (92.5, 70.0) 进 C748 | C748 挪到 (92.5, 71.2) rot 90,夹在 pair 3 与 pair 5 的北上车道之间 |
| pair 5 | 底 | 西行到 93.47/93.95 北上,y 75.50/75.98 东行到 110.30/110.78 南下,**y 59.2~61.6 翻顶层跨 UP**,y 52.5/52.98 东行,x 160.1/162 南下进 U55 | DP 东沿离 C751 焊盘 0.205;pin13 GND 的孔位留在 (94.6, 71.4) |
| UP | 底 | pin58/59 从 C743/C745 之间的竖井下到 60.12/60.60,一路东行,x 205 抬到 61.25/61.75 平着进 J23 B6/A7 | 不能压在 60.2 —— 会把 B5 (CC2, 60.25) 的走线堵死 |
| J23 短接 | 底+顶 | A6↔B6 / A7↔B7 两个小环,几何照抄 v3,网络对调、跨越段翻到顶层 | 同一对的两根按对内 0.15 判(横线离孔 0.165)|
| +3V3 干线 | 顶 | U31 pin2 旁 (90.3, 61.65) 打孔上顶层,沿 x 90.3 北上到 (90.4, 70.5) 与 pin5 汇合,东去 (92.5, 70.0) 下来进 C748 | 后面信号布线器把这三条 +3V3 当**已有障碍**,别删 |
| 五对短差分 | 底 + 一段顶 | DMJ 全程底层 45° 斜进 U5n.1;**DPJ 翻顶层**:出焊盘 0.54 浅斜到 (50.0, 37.0) 打孔,顶层西去 (47.2, 37.4) 下来 45° 进 U5n.3 | 站内坐标,五站同构;两排之间只有 1.515 mm,孔只能落在 y 36.805~37.31 或两侧 |
**顶层参考面**:所有顶层段都核过「要么全在 GND 上、要么全在同一块岛里」(`topref` 检查 0 处跨界)。
为此 **VO4 岛主体东界从 89 收到 87**(`pcb2_pour.ISLANDS`)—— site4 的短差分顶层段在 x 87.8~90.9、pair 4 在 x 89.6~92.2、+3V3 干线在 x 90.3,
原来的 89 正好从中间劈过去。site5 的短差分顶层段整段落在 VO5 岛内部(一整块铜,不跨界)。重铺后 `inner1_verify` 五块岛各 1 连通域,
最窄 7.05 / 7.20 / 7.70 / 7.60 / 31.55(下限 7.0)。
**成对 45° 斜段的规矩**:两根线各自的拐点不能同 x / 同 y,第一拐**内侧**那根早拐 0.2(= 0.48·(√2−1)),
否则斜段上的垂直间距只剩 0.34 < 0.43。转弯时左右次序的判法:向右拐,左边那根变外侧;连拐两次回到原样 ——
五对到站都不用交叉,全靠这条把车道次序排对。
**校核**:`pcb2_route_dp.py` 本地净距全过(一般 0.20 / 对内 0.15)、端点全落在本网焊盘、对内偏斜最大 4.75 mm(USB5,容差 5)。
下发 182 线 / 26 孔(回读 178 线,4 条同宽共线段被 EDA 合并,无害)。DRC 634 = 同封装内间距 115(基线)+ 连接性 519(未布线,预期)。
截图 `PCB2-v5-dp-hub.png` / `PCB2-v5-dp-all.png` / `PCB2-v5-dp-site4.png`。
⚠️ 一条工具坑:`pcb2_dp_long.chamfer()` 原来对**每个**拐点都切 0.35,包括已经是 45° 的拐(正 + 斜),
切出来的 22.5° 小段会向内挪 0.1 mm —— 实测把 DP4 的抬升段切进了 pin10 车道的净距圈(0.125)。现在转向角 ≤ 46° 不切。
#### 2026-09-06 补 7:v5 载板布线全部完成(扇出 / VOn_P 进岛 / 77 个信号网络)
**结论先写:载板 PCB2 布完了。** DRC **115 条,全部是封装自带的「贴片焊盘到贴片焊盘」基线**——
间距 0 新增、连接性 0、悬空 GND 连通域 0、五块 Inner1 岛各 1 主域(最窄 7.05)、11 对差分偏斜全过。
铜量:**1030 条导线 / 537 个过孔**。截图 `PCB2-v6-routed-all.png` / `PCB2-v6-hub.png` / `PCB2-v6-site4.png`。
##### ① GND 扇出(247 孔 / 122 短线)
`pcb2_fanout.py` 按 v5 重跑。三条和 §25.8 不一样的地方:
- **J7n 的 65 个 GND 脚整批不扇**(`SKIP_PAD`)。它们归 `bm24_pre()` 的两条梳子管;
让自动扇出去碰的后果实测是「十个必然失败 + pin 1/2/52 三个『成功』的孔正好落在梳子和车道上」。
- **U32 的 pin13 / pin19 往 QFN 肚子里打孔**((96.50, 70.25) / (97.25, 71.50))。
西边走廊虽然放得下孔(x ∈ [94.59, 94.625]),但**引线出不去**:pin13 与 pin14 之间只有 0.20 mm。
引脚环东沿 95.975 到散热盘西沿 97.600 有 1.625 mm 净宽,是这一带最宽敞的地方。
- **C745 往南挪 2.7 mm**(用户拍板)。原位 (100.05, 61.70) 的 GND 脚四面被堵死:
南 `UP_DM` 东行段 y=60.60(孔要 0.64,只有 0.41)、北是 U32 南排焊盘之间 0.73 的死带(孔要 1.0)、
东 R715(缝 0.667)、西被 `UP_DP`/`UP_DM` 两条竖段夹住(相距 0.5,塞不下 Ø0.6)。
新位 GND 脚 (100.0, 58.60) / +3V3 脚 (100.0, 59.44),孔打在正东 (100.87, 58.60)。
##### ② `VOn_P` 进岛(55 孔):`C8n1.1` 和 `J8n.1` 也是贴片
换成 Rubycon 6.3TPV2200M10X10.5(V-chip)+ 电池排线直焊座之后,
**每一路 `VOn_P` 只剩排母那 3 针是通孔**,其余 7 个焊盘(`C8n1.1`、`C8n2`~`C8n6`、`J8n.1`)都要打孔下岛。
个数按 §10.3「功率网络每个焊盘 3 个孔」:`J8n.1`(这一路 4 A 的唯一去路)和 `C8n1.1`(2200 µF 主储能)各 3 个。
⚠️ **`C8n2`~`C8n6` 仍是各 1 个 —— 这是对 §10.3 的一处有意偏离**:
全按 3 个来会往五块岛里再钻 50 个反焊盘,最窄断面(下限 7.0)扛不住;这五颗只承担高频纹波,单孔 1~1.5 A 够用。
##### ③ v5 的 BM24 逃逸:和 v4 **反过来**
v5 把 J7n 从 rot 180 改成 rot 0 又挪了位置,站内坐标整体差一个仿射映射
**`u′ = u − 5.00` / `v′ = 32.00 − v`(v 轴是镜像的)**。但**照抄映射也不对** ——
v 一镜像,v4 那条「前排外侧 0.76 mm 的缝」换到了另一边,而那一边站着 R76n/R77n。
v5 的实测站内几何:后排(奇数脚,**全是 GND**)v=33.940;中间大脚 v=35.000(pin51 VBUS u 46.47 / pin52 GND u 58.53);
前排(偶数脚)v=36.060;两排 u 都是 48.30~56.70。
| | v4 | **v5** |
|---|---|---|
| 中央通道(1.64 mm)| THERM / CC1 两条东行车道 | **前排 5 个 GND 的梳子**(v=35.00,4 个孔)|
| 后排外侧 | 后排 7 个 GND 的梳子 | 同上(v=33.10,5 个孔)—— 但这一侧现在一路空到 v 26,最宽敞 |
| 前排外侧 | 前排 4 个 GND 的梳子 | **只给 THERM / CC1**(R76n/R77n 就在正北)|
反过来的理由:**v5 后排 25 个脚全是 GND**,没有信号脚要往外挤;而 THERM(pin14)/CC1(pin22) 和它们的靶子
R77n/R76n 都在前排外侧。让它们各走各的最短路,中央通道就整条空出来,
不再有 v4 那个「东行车道被竖着穿过通道的 GND 线切断」的死结。
**为此挪了 R76n / R77n:v 37.15 → 38.0,R76n 的 u → 52.233。**
原来前排逃逸带只剩 0.58 mm(J7n 前排焊盘外沿 36.30 ←→ R76n/R77n 焊盘下沿 36.88),
而 THERM 要往东、CC1 要往北,**在 u≈51.8 必然交叉**,同层无解;想让 THERM 翻顶层又打不下孔
(要离前排 0.5 ⇒ v ≥ 36.80,又要离 R76n 0.5 ⇒ v ≤ 36.38)。挪完带宽 1.43 mm:
CC1 一根直线上去(52.233 是算出来的,好让 pin1 正落在 u 51.800 = J7n.22 正北),
THERM 在 (50.95, 37.20)/(54.37, 37.20) 打两个孔走顶层跨过去。
⚠️ **THERM 出阵列后第一次拐弯的 v 只有 0.053 mm 的窗口**(下受前排焊盘、上受 `*_DPJ` 的换层孔),
取窗口正中 36.58,而且那两段必须一直保持 0.11 —— 换成 0.15 窗口只剩 0.005,0.20 直接无解。
##### ④ 77 个信号网络:四段必须手写
栅格布线器(0.1 mm 栅格,判据 `edt ≥ 净距 + 半线宽 + 0.0708`)**进不去**这几个地方,只能手写坐标:
| 网络 | 卡在哪 |
|---|---|
| `THERM_n` | 上面那 0.053 mm 的窗口 |
| `+3V3_HUB` U32.52→U32.46 | pin46 在东排被 VBUS_DET/NONREM0 围死,唯一出路是往 QFN **肚子里**走(南排焊盘上沿 63.975 与散热盘南沿 65.60 之间那条 1.6 mm 死带)|
| `+3V3_HUB` C750.1→R716.2 | R716.2 是最东那颗 +3V3 焊盘,南北被 R711.2 / R720.2 两个 GND 脚夹住(各 1.2 mm),只能翻顶层斜拉 |
| `HUB_RST` / `VBUS_DET` | R709(y 65.85) 与 R712(y 67.05) 之间只有 **0.66 mm**。0.15 的线走得过去(上下各 0.23),但栅格判据要 0.371 而半缝只有 0.33 |
##### ⑤ 布线器本身修掉的四个真 bug(写在这里是因为它们都属于「校核过了但其实是错的」那一类)
1. **搜索窗口边上没有墙**。障碍裁到窗口里再栅格化,**完全落在窗外的铜一格都不标** ——
贴着窗口边走的线看不见它。实测 `SCL` 的窗口从 x=44.02 起,J31.6 的焊盘框(42.10~43.80)整个在窗外,
布线器就在 (44.10, 67.40) 打了个孔,离那焊盘只有 0.134。改法:数组往外扩 1.2 mm 标障碍,
**再把外面这一圈整体标成占用**。
2. **钻孔间距不分网络,`viafree` 却只看异网铜**。于是紧挨着 `pcb2_dp_long` 已有的孔又打一个
(中心距 0.510,规则要 0.605)。新增 `holefree` 距离场。
3. **手写前置段没有一开始就进障碍表**,排在前面的网络照样从上面碾过去。
4. **`+3V3_HUB` 上 `pcb2_dp_long` 画的三条会被 `push_sig()` 静默删掉**(它按网络整删)。
改成从同一个事实来源取回来当前置段。
⚠️ **由此产生一个口子**:`+3V3_HUB` 现在由 `pcb2_route_sig.py` 下发,
**再单独跑 `pcb2_dp_long.py --push` 会把整个 +3V3_HUB 删掉重画**。
要改差分的顺序是 `dp_long --push` → `route_sig --push`,不能只跑前一半。
另外扇出规划器补了三处:**板上已有的走线也当障碍**(线对线分层比、过孔对线不分层)、
第三遍「并到旁边同网焊盘」加了 3.0 mm 上限并要求目标同层(原来把 C745.2 一路并到 9.78 mm 外**另一层**的 J64.3),
以及 `dump_pads.py` 的位号认领改成最近邻匹配(原来两边各自 `Math.round` 到 0.01,
落在 `.xx5` 上的 88 个焊盘认不到主人 —— J75 pin15/16 就在其中,害得「J7n 的 GND 脚整批跳过」漏掉两个)。
---
## 26. 下板 PCB1 v6(2026-09-06,两板拆分之后从头重排)
载板 PCB2 布完之后,剩下的就是**下板**。板上原有的东西是**单板时代**的产物:
391 个元件、5813 条自动布线、1208 个过孔,网络表和布局都已经过期。这一轮做的是
「导入变更 → 重建约束模型 → 重排摆位」。
事实来源:`.claude/pcb1_place.py`(摆位)、`.claude/pcb1_env.py`(环境约束)、
`.claude/pcb1-env.json`(生成物)、`.claude/pcb1-parts.json`(真实焊盘框)。
### 26.1 从原理图导入变更:391 → 338
| | 数 |
|---|---|
| 删 | **70** 个(J2~J11 / J17~J21 / J23 / U24~U28 / U31 / U32 / Y1 / 29 个 7xx 电容 / 15 个 7xx 电阻)|
| 加 | **17** 个(J24 J25 排针;U33 第三片 595;Q6 D2 风扇低边 + 续流;R730~R734;C738 C739;J26~J30 风扇座)|
| 结果 | **338 个元件,位号与封装逐条对上原理图 11 页**(`pcb1_import.py --verify`)|
⚠️ **导入对话框的变更列表会骗人**。它把「将被删掉的元件」复用成「新增的元件」,
显示成一堆 `修改封装 C0805 → HDR-TH_40P-...`,看上去像是要把一颗 0805 电容变成 40 针排针。
实际结果是对的(位号跟着改),但**列表本身读不出这一点**,而且虚拟滚动逐屏抓下来还会漏行。
⇒ 判据只有一个:**导入之后拿 PCB 的元件表和原理图 BOM 逐条对账**(`--verify`)。
### 26.2 ⭐ 载板底面 → 下板的高度预算图(`pcb1-env.json`)
两板净空 **13.0 mm**(公头塑高 2.5 + 母座塑高 10.5,§22.3f)。
下板坐标 = 载板坐标 − (30, 5)(下板 160×125 居中在载板 220×135 下方)。
`pcb1_env.py` 把载板 146 个底层件 + 10 条排线车道 + 10 条穿线槽全部折算过来,
每块给一个 `hmax = 13 − h(载板件) − 1(装配余量)`:
| 下板上的位置 | 来自 | hmax |
|---|---|---|
| (1.3~14.2, 106~116.8) / (72.8~85.7, 106~116.8) / (144.3~157.2, 106~116.8) | C801 / C811 / C821 Ø10 罐 | **1.5** |
| (38.6~51.5, 8.4~19.2) / (110.1~123, 8.4~19.2) | C831 / C841 | **1.5** |
| (7.0~57.0, 60.4~64.6) / (103.0~153.0, 60.4~64.6) | J31 / J32 排母本体 | 3.5(就是排针自己占的地方)|
| J62~J65 四个 1.25 mm EDL 座 | | 8.4 |
| 9 条排线车道 | 排线平贴载板背面 | 11.0 |
| 10 条穿线槽的投影(板边 y<1.3 / y>123.9)| 排线从这里下穿 | 3.0(本模型自己定的)|
| 其余 | 载板那边是 1206 / 0402 / 光板 | 10.3 ~ 12.0 |
⇒ **五块 12.9 × 10.8 的 1.5 mm 禁区是这一版布局最硬的约束**:
电感(SPM6530T,3.0)、直插电解(12)、接线端子(10)、风扇座(9)一个都进不去。
`pcb1_place.check()` 里逐件核算,这一条**几何检查以前完全看不见**。
### 26.3 五路怎么分到南北两块 —— 只有一种解
`VOn_P` 每路 3 针,x 位置由载板几何定死(§25.10):
`VO1 10.4 / VO4 46.0 / VO2 53.6 / VO5 126.7 / VO3 142.0`。
母版(`CH1` 表)的输出端在**局部 (6, 40.5)**,也就是左上角。所以
* 放**南**边(rot 0,原样):输出朝上正对排针 ⇒ 通道占 `bx+2.3 ~ bx+29.5`,输出 x = bx+6
* 放**北**边(**整路 rot 180**):输出转到右下正对排针 ⇒ 输出 x = bx−6
`VO1` 太靠左板边(rot 180 要求通道体在 x −14 起)、`VO3` 太靠右板边(rot 0 要求到 x 166)
⇒ **CH1 只能在南、CH3 只能在北**;剩下三路按互不重叠排下来只有
> **南 = CH1 (10.6~37.8) / CH4 (42.3~69.5) / CH5 (121.8~149.0),
> 北 = CH2 (30.1~57.3) / CH3 (118.5~145.7)**,南北都是 y 18.2~59.2 / 66.3~107.3。
⚠️ **不做 y 镜像** —— 镜像要把元件翻到底层。转 180° 是纯旋转,
母版里 §10.2 那四条手调出来的关键回路(Cin 热回路 / SW 铜箔 / FB / Kelvin)原样保留。
代价:**CH2 的 `POGO2_*` 三根在 J25 上(x 109~114),而 CH2 的体在 x 30~57**,
要横穿 60 mm。这是载板那边「site2 电源走 J31、信号走 J32」带来的,不是布局失误。
### 26.4 其余四块
| 块 | 范围 | 内容 |
|---|---|---|
| N-L | x 1~30 / y 66~124.5 | P1-INPUT:J1 12V 端子(左板边)→ F1 → Q1 → D1 → C2/C3 罐 → Rs6+U13 → R9;U19 辅助 3V3 组压在 x>14.3(C801 禁区)|
| N-M | x 58~118 / y 66~124.5 | P1B(U30 12V→5V + L3)、P6(U33 第三片 595 + Q6/D2 风扇驱动 + TACH 分压)|
| S-M | x 70~118 / y 0.5~59 | P3/P3B 控制块:U20 ESP32(天线端转到 −Y 朝下板边)、U6/U7 DAC、U21/U22 595、U23 PCA9555 |
| 板边 | — | J26/J27 左板边、J29/J30 右板边、J28 顶板边(4 进 1 出,§22.6);J22 调试 USB-C 转到**右板边**(下板边被 C841 的 1.5 mm 禁区压掉了)|
### 26.5 ⚠️⚠️ J24 / J25 对插针号错位 —— 必须先拍板再布线
`pcb1_place.py` 的对位核算(拿载板 J31/J32 的**实际焊盘坐标**反推)结论:
> **80 个焊盘全部落在载板针的正下方(误差 0.001 mm),但每一个都压在「同一行对里的另一根针」上。**
> 下板 pin1 ↔ 载板 pin2,pin2 ↔ pin1,pin3 ↔ pin4 …… **奇偶整体互换。**
也就是说照现在的原理图做出来,**下板的 `VO1_P` 会顶在载板的 `GND` 上** —— 4 A 直接对地。
**成因**(几何,已复核):两颗封装的焊盘编号**同手性**(本地 pin1 都在「西南」角),
而母座装在载板**底层**、公头装在下板**顶层**。底层件在顶视图里镜像一次(skill §9w),
于是载板的奇数排跑到 y 68.77(北),下板的奇数排在 y 61.23(南)。
公头 / 母座都是**无防呆的 2×20**,物理上完全对称,所以「pin1 在哪一排」纯粹是封装画法约定 ——
不存在「哪个封装画错了」,只存在「两边约定不一致」。
§22.2 当时写的「换件之后两块板同一套编号,陷阱消失了」说的是**符号**;
同一节末尾那句「⚠️ 但 PCB 上那条风险还在」说的就是这一条,现在被实测坐标钉死了。
**两条修法(等用户拍板)**:
| | 改什么 | 好处 | 代价 |
|---|---|---|---|
| **A** | 下板原理图 P5-BTB 里 J24/J25 的网络**奇偶对调**(`p5_btb.py` 只改下板那一半,`c1_conn.py` 用的表不动)| 不碰器件库;载板一个字都不改 | 两块板的逐针表从此不一样,§22.2 要加一张对照表 |
| **B** | 建一个焊盘编号奇偶互换的**自制封装**给 J24/J25 | 两块板逐针表保持一致,看图不用换脑子 | 要建库 + 换器件 + 重新导入 PCB |
### ✅ 2026-09-06 用户拍板:选 A,已实施
`p5_btb.py` 新增 **`MATE_SWAP = True`** 与 `board_rows()`:两张逐针表仍按**载板**几何写
(`c1_conn.py` 生成载板 C1-CONN 时直接用原始表,一个字没动),
生成**下板** P5-BTB 时把每一行的 (北, 南) 翻成 (奇数脚, 偶数脚)。
P5-BTB 重画 → `verify_sch` PASS / `xpage` 漏接 0 → PCB1 重新导入 → 摆位重推。
**从此这颗排针的判据是「网络」不是「针号」**:下板 pin(2r−1) 正对载板 pin(2r)。
`pcb1_place.py` 的 `mate_map()` / `--verify` 都改成按网络比,
锚点表 `pcb1-env.json` 的 `anchors` 里也一起存了载板侧的网络名
(`pcb1_env.header_anchors()` 当场从载板 PCB 读回来)。
回读复核:**J24 / J25 各 40 个焊盘逐个网络对上载板。**
⚠️ 以后谁再看这两页,会觉得「两块板的逐针表对不上」—— 那是对的,就是这一条。
### 26.6 这一轮踩到的两条
1. **`CONN-TH_KF2510-3A-1` 是弯针座,塑壳整个往 +Y 伸 11.7 mm。**
按 ±4.5 猜的占位框让 J28 整个探出板框、J30 压住 J22,**本地检查一条都不报**。
API 取不到封装本体(`lib_Footprint.get()` 只回元数据,没有图元;组件的丝印也不外露),
最后是用**带标尺的放大截图 + 拿它自己的三个焊盘做标定**量出来的:
本体 7.8 × 11.9,局部框 `(-3.90, -0.20, 3.90, 11.70)`。
⇒ 板边连接器的本体框,**除了实测没有别的来源**;这是本项目第三次栽在同一件事上(USB-A / Molex / 现在 KF2510)。
2. **低分辨率整板截图不能用来判「有没有出框」。** 5.7 px/mm 下 J28 和 U20 都「看着」探出板边,
放大到 30 px/mm 再量,两个都在框内。要判出框就截**带板边的局部图**。
### 26.7 下板设计规则(2026-09-06 第十五轮,`pcb1_rules.py --check` 十七项全过)
单板时代那份 `pcb_rules.py` 已经不能用了(它建 7 对差分、给 `+5V` 挂 `PWR12V`,
拆板之后两条都不对),新写 **`.claude/pcb1_rules.py`** 取代它。做法照抄载板
`pcb2_rules.py`,两个 API 坑和两条陷阱一字不改(见那两份文件头)。
#### 线宽分五档
| 规则 | 默认 | 最小 | 最大 | 挂给谁 | 依据 |
|---|---|---|---|---|---|
| `PWR12V` | 2.0 | 0.3 | 10.0 | `+12V` + 8 A 输入链三段 | §10.1:8 A 走 2.0 mm 温升 35 °C ⇒ **总干必须灌铜**,2.0 只给分支 |
| `SWNODE` | 2.0 | 0.3 | **4.0** | 五路 Buck 的 SW 节点 | §10.1 表:4 A 的 SW 铜箔 2.0 mm(ΔT 10.4 °C)|
| `PWR4A` | 1.5 | 0.3 | 6.0 | `VOn` / `VOn_F` / `VOn_P` | 每路 4 A(IPC-2221 外层 1 oz,ΔT 16.7 °C)|
| `PWR5V` | 1.2 | 0.3 | 6.0 | `+5V` + U30 的 SW | §9.4 最坏 2.8 A(1.2 mm 可载 3.6 A)|
| `PWR1A` | 0.6 | 0.15 | 3.0 | `+3V3`、`SW3V3` | §9.3 辅助 Buck 按 0.5 A 设计 |
**`SWNODE` 为什么要和 `PWR4A` 分开、而且 max 卡在 4.0**:SW 是开关节点,
铜越宽 I²R 越小、但 dV/dt 的辐射面积越大(§10.2-2「压到刚好够载流」)。
`PWR4A` 的 max 6.0 是留给灌铜出线的,SW 不该享受那个上限 —— 分成两条规则,
DRC 才拦得住「顺手把 SW 拉成一大片铜」。
差分对只剩 **1 对 `DEBUG`**(`USB_DP`/`USB_DM`,J22 → U20)。
五路下行 D±、`UP_*` 和五段 `*J` 在 2026-09-04 拆板时整体搬去载板,
下板上这些网络已经不存在 —— 建不上不是失败,是本来就不该有。
`strokeWidthMin` 保持 **0.20**(不像载板降到 0.10):这一对路上没有 0.35 mm 间距的连接器要钻。
#### ⭐ 四类干路是自动命名网,**按「位号 + 引脚」当场反查,不写死网名**
拆板那次导入变更之后,同一个节点的自动网名从 `$2N687` 变成了 `$2N699`。
写死网名的后果是**静默失效**:`overwriteNetRules` 只改它认得的行,
认不出的名字**既不报错也不留痕**,DRC 照样干干净净,
而板上那条 4 A 干路的线宽规则已经悬空了。
⇒ 事实来源是 `pcb1-parts.json` 里每个焊盘自带的 `net`,`resolve_auto()`
拿 (位号, 引脚号) 反查,并逐条断言「是 `$` 开头 / 互不重复 / 链路另一端查到同一个网」,
**对不上就直接退出,一个字都不下发**。本轮实际查出来的 14 个:
| 逻辑名 | 网名 | 规则 | 探针 / 校核端 |
|---|---|---|---|
| `SW1`~`SW5` | `$2N665` `$8N665` `$10N665` `$12N844` `$14N665` | `SWNODE` | `Ln01.1` / `Un.11` |
| `VO1_F`~`VO5_F` | `$2N699` `$8N699` `$10N699` `$12N878` `$14N699` | `PWR4A` | `Rsn01.2` / `U(13+n).5` |
| `VIN_RAW` / `VIN_FUSED` / `VIN_SW` | `$1N223` `$1N227` `$1N236` | `PWR12V` | `J1.2`/`F1.1`、`F1.2`/`Q1.1`、`Rs6.1`/`C2.1` |
| `SW5V` | `$16N18` | `PWR5V` | `L3.1` / `U30.2` |
⚠️ 顺序从此是 **`pcb1_import --apply` → `pcb1_parts_dump` → `pcb1_rules --push`**。
少跑中间那一步,反查用的就是旧网名,28 个指派里有 14 个会静默落空。
#### 铺铜全连接(`PLANE-DIRECT`,`connectMode = 1`)挂 9 个网络
`VO1_P`~`VO5_P`、`+5V`、`$1N223`/`$1N227`/`$1N236`。理由和载板 §25.11 同一条:
不是怕十字花烧(辐条只有 0.254 mm 长、两端焊在大铜面上,8 A 下 ΔT ≈ 0.3 K,
实算见 `pcb2_rules.py`),而是**铺完之后铜面几何要量得准** ——
十字花时铜面多边形把自己的焊盘挖空,断面测量会读到一个 0.3 mm 的假瓶颈,
真瓶颈和度量假象在数据上分不出来。
**内层铺铜的全连接没有手焊代价**(焊接热走的是外层),所以下板比载板放得开:
8 A 输入链的三段上挂着 J1 端子和 C2/C3 两颗直插电解 —— 那是全板电流最大的通孔焊盘。
不进来的两个不是忘了:`GND` 有 47 个通孔焊盘、同时贴 Inner1 与 Inner2,留十字花;
`+3V3` / `VOn` **一个通孔焊盘都没有**(全是贴片),connectMode 对它们是空操作。
#### 顺手清掉的板框陈迹
layer 11 上原来是「1 条闭合多段线 + 4 条早年的直线」。四条直线和多段线的四条直边
**完全重合**(都是 0/196.85 → 6299.216/4921.26 mil 那一圈),删掉之后
layer 11 只剩 1 条闭合多段线 —— 这是自动布线器取板框的硬要求(PROGRESS「三条最贵的教训」第 1 条)。
### 26.8 下板 Inner2 怎么分 —— 算出来是**三块**,不是草案里的八块
事实来源 **`.claude/pcb1_pour.py`**(`REGIONS` 是唯一的定义,跑一次全部校核 + ASCII 分块图)。
上一轮 PROGRESS 写的「+12V / +5V / +3V3 / VO1~VO5 八块」是草案。逐条算下来只剩
**+12V 一大块 + +3V3 南部两块**,其余全部退回走线。
#### 判据:内层 0.5 oz 和外层 1 oz 差了约 4 倍
IPC-2221 `A=(I/(k·ΔT^0.44))^(1/0.725)` mil²,**内层 k=0.024 / t=0.685 mil,
外层 k=0.048 / t=1.37 mil** —— 两个系数都翻倍,所以同样电流外层只要内层约 **1/4** 的宽度:
| 电流 | 内层 0.5 oz | 外层 1 oz |
|---|---|---|
| 8 A | **18.2 mm** | 3.49 mm |
| 4 A | 6.99 mm | 1.34 mm |
| 2.8 A | 4.27 mm | 0.82 mm |
| 2.0 A | 2.69 mm | 0.55 mm |
| 0.5 A | 0.40 mm | 0.08 mm |
⇒ **「要不要占内层」的门槛比直觉高得多。** 这块板 338 个元件全在顶层、
**底层整层是空的**,一条 1.2 mm 的底层线就能带 4 A —— 短距离大电流根本不该上内层。
#### 逐个网络的结论
| 网络 | 实际跑多远 / 多大 | 结论 |
|---|---|---|
| `+12V` | 源 Rs6.2 (9.6, 91) 在北左,负载散布南北五路 + 五个风扇,南边要 5.6 A | ✅ **Inner2 主平面(3 块)** |
| `+3V3` | 源 L2 (25.5, 104),**64 个焊盘遍布全板**,但只有 0.5 A | ✅ **Inner2 南部 2 块** —— 要的不是载流,是「64 个焊盘各打一个孔就完事」|
| `+5V` | 源 L3.2 (73.3, 78),去处**全是排针上那 10 个通孔针**,最坏 2.8 A | ❌ 底层 1.2 mm 干线(`PWR5V`)。外层 0.82 mm 就够 |
| `VO1`~`VO5` | Buck 输出 → eFuse,**通道体内约 12 mm** | ❌ 顶层 1.5~2.0 mm(`PWR4A`)。§10.2 本来就要求这段回路面积最小 |
| `VO1_P`~`VO5_P` | 分流电阻 → 排针,**只有约 9 mm** | ❌ **底层五块小岛**(排针那 3 根针是通孔,一铺就自动连上,省掉三条 4 A 走线)|
| 8 A 输入链三段 | J1→F1→Q1→C2/C3→Rs6,**全长只剩 25 mm** | ❌ **顶层宽铜 ≥3.5 mm**(见下)|
#### ⚠️ 8 A 输入链改走顶层 —— 和 §10.4 不一样,是有意的
§10.4 是给 v5(单板时代)写的,那时这条链被摊开到 85 mm。v6 已按 §10.2b 收进北左角
(x 3~28, y 69~91)、全长 25 mm,于是两个新事实起了作用:
1. **内层扛不动。** 8 A 在 0.5 oz 内层要 **18.2 mm 宽**,那个角落总共才 22 mm 高,三段排不下。
2. **过孔才是真瓶颈。** F1 / Q1 / D1 / C4~C6 全是贴片,下内层只能靠过孔;
Ø0.3 过孔单孔 1~1.5 A、扇出每个焊盘给 3 个 ⇒ 一个转换点最多 3~4.5 A ≪ 8 A。
顶层是**零过孔的最短路径**(这条链上每个元件都在顶层),1 oz 外层 8 A 只要 3.49 mm,
而那个角落横向有 25 mm 可用。这正是 §10.1 原文三个选项里的「顶层灌铜 ≥3.5 mm 宽」。
Inner2 那一片留给 GND 底填,**顺带给这条大电流回路铺了一整块贴身地平面,比原方案还好**。
#### 排针把 Inner2 劈成南北两半 —— 只有三条通道
J24 焊盘 x 6.97~57.03、J25 x 102.97~153.03,两排 y 61.2 / 63.8。Ø1.8 焊盘 + 0.2 净距
⇒ 同排相邻反焊盘之间只剩 **0.34 mm**、两排之间 **0.4 mm** 的铜网 —— 数值上没断,电气上当断路看。
| 通道 | x | 净宽 | 内层能带 | 用途 |
|---|---|---|---|---|
| 左 | 0.5 ~ 6.7 | 6.2 mm | 3.7 A | **不用**(北端被 J1 (6,74) 和 C2.1 (4.8,82) 两个通孔掐到 2.8 mm、只剩 2.06 A)|
| **中** | 57.3 ~ 102.7 | **45.4 mm** | — | +12V 中桥 (x 61.5~72) + +3V3 北臂 (x 73~96) |
| 右 | 153.3 ~ 159.5 | 6.2 mm | 3.7 A | +12V 右通道 (x 153.5~159.5) |
**南边要 5.6 A**(CH1 + CH4 + CH5 各 1.6 A + 左右四个风扇各约 0.4 A)。
分法:**中桥喂 CH1 + CH4 + 左风扇 = 3.6 A(实测断面 10.5 mm → 5.4 A),
右通道喂 CH5 + 右风扇 = 2.0 A(6.0 mm → 3.6 A)**。
#### ⚠️⚠️ 一条拓扑上绕不过去的结论:`+3V3` 南部必然被 `+12V` 中桥切成两半
中桥必须从北 (y≥88) 穿到南 (y≤34),也就是**纵向穿过 y 41~58.5 这条带**;
而 `+3V3` 的南部焊盘(CH1/CH4 的 INA226 与上拉、控制块、CH5 那一组)
正好**横向铺满同一条带**。同一层上,两个都要连通的 2-D 区域,交叉是避不开的。
⇒ 让电流小的那个换层:`+3V3` 只有 0.5 A,
**南西块与南东块各自从北边的源单独引一条底层干线**(0.6 mm 足够,底层是空的),
不在 Inner2 上强行连通。**`+3V3` 有 2 个连通域是设计意图,不是漏接** ——
`pcb1_pour.py` 里那一条校核写死的就是「等于 2」。
这和载板 §25.10 取消 `+5V` / `+3V3_HUB` 两块岛是同一类判断。
#### 落地成这样(`REGIONS` 的顺序 = 铺铜优先级,GND 底填必须最后)
| 层 | 网络 | 名称 | 形状 |
|---|---|---|---|
| Inner2 | `+12V` | `12V-N` | 北带 y 88~124.5 通板 **+ 风扇指下伸到 y 66.5**(x 96.5~112),挖掉 U13 那一角 |
| Inner2 | `+12V` | `12V-SW+BR` | 南西块 (0.5~72, 9~34) **+ 中桥** (61.5~72, 34~88),⌐ 形 |
| Inner2 | `+12V` | `12V-SE+RC` | 南东块 (116~159.5, 9~34) **+ 右通道** (153.5~159.5, 34~88),L 形 |
| Inner2 | `+3V3` | `3V3-SW` | (0.8, 41)–(58.5, 58.5) |
| Inner2 | `+3V3` | `3V3-SE` | 控制块 (73~115, 9~58.5) + 南东臂 (115~148, 41~58.5) + 北臂 (73~96, 58.5~86.5) |
| Inner2 | `GND` | `GND-FILL-L3` | 剩余全部(含北左角那一片,垫在 8 A 顶层大铜下面)|
| Bottom | `VOn_P` | 五块小岛 | 各约 18 × 13 mm,框住 `Rs*01.1` + INA226 两脚 + `R*19` + 排针 3 针 |
| Inner1 | `GND` | `GND-L2` | 整板,只挖 ESP32 天线区 |
#### ⭐ 校核当场抓出来的一个错:**孤岛判定是按铺铜对象算的,不是按网络**
第一版按几何写成六个矩形(北带 / 中桥 / 风扇指 / 南西 / 南东 / 右通道)。
栅格连通性说「+12V 是 1 个连通域」—— 看着完全正常。但新加的**孤岛规则校核**报出来:
`12V-RC`(右通道,x 153.5~159.5 / y 34~88)**里一个 `+12V` 焊盘都没有**。
载板 `pcb2_pour.py` 文件头第 4 条那句「区域内没有本网焊盘/过孔 = 整块被当孤岛删光」,
判定粒度是**每个铺铜对象各算各的** —— 哪怕它和北带紧挨着、铺出来是连续铜,
它自己那一块里没有本网焊盘/过孔,照样会被删掉(边框还在、`nPoured` 是 0)。
⇒ 把中桥并进南西、右通道并进南东、风扇指并进北带,凑成**三个 L / ⌐ 形多边形**,
每块各自含 `J28.1` / `J26.1 + J27.1` / `J29.1 + J30.1`,**不依赖扇出就活得下来**。
`+3V3` 那两块则是 0 个通孔焊盘、全靠扇出过孔活着 —— 这就是「**扇出必须排在铺铜之前**」的原因。
#### 还有两条校核经验
- **只有通孔焊盘在内层挖反焊盘,贴片焊盘对内层完全透明。** 按「所有焊盘都挡内层」去算,
这块板 1200 多个贴片焊盘会把 Inner2 算成一张网,结论全错。板上实测 122 个通孔焊盘。
- **区域间净距不能用包围盒估。** `3V3-SE` 是个 L 形,它的包围盒 (73,9)-(148,86.5)
把 `12V-FAN` (96.5,66.5)-(112,88) 整个罩进去,按包围盒算出来是 0.00 mm、像一条严重违规,
实际两块相距 0.50 mm。改成逐边线段距离才对。
#### 明知故犯:21 个焊盘不进平面,靠布线
`+12V` 2 个 + `+3V3` 19 个,全部有名有姓地写在 `pcb1_pour.py` 的 `ROUTED_PADS` /
`ROUTED_BLOCKS` 里,校核时单独列出来而不算「漏掉」:
| 焊盘 | 为什么 |
|---|---|
| `U13.8` / `U13.9`(+12V)、`U13.6` / `C11.1`(+3V3)| **Kelvin 脚**。§10.4:U8~U13 的取样脚一律不进铜面,5 mΩ 分流器满量程才 20 mV |
| CH2 / CH3 的 10 个 `+3V3` | 在北边、各 50 mA;沿 y≈84 那条空带走顶层线到 `3V3-SE` 北臂 |
| 北左辅助 Buck 那一窝(`L2.2` `R2.2` `C9.2` `C10.2`)| U19 / L2 / C7~C10 / R2~R6 / Q3 把 12V 与 3V3 挤在 16×24 mm 里交错,整窝走顶层 |
| `C739.1`(+3V3)| 一颗去耦电容孤零零落在风扇指里,走 11 mm 顶层线到 `U33.10` |
### 26.9 下板扇出(2026-09-06 第十六轮)—— 438 个过孔 + 441 条短线,DRC 间距 0
做的是 §26.8 定的第 3 步「扇出」。真正花时间的不是扇出本身,而是**扇出把三个
早就在、但一直没被任何检查碰到的错顶了出来**。三个都属于同一类:
**几何检查全绿,板子是错的。**
#### ⭐⭐ 错一:控制块的去耦电容全都离本尊很远,ESP32 那对在 48 mm 外
追「U6.15 为什么扇不出去」时发现的:那个脚周围 6 mm 内没有任何同网焊盘可以并过去。
往外查了一圈,全板 20 个 IC 的 `+3V3` 电源脚里,**只有 1 个的去耦在 3 mm 以内**。
| 电容 | 是谁的 | 原来的距离 |
|---|---|---|
| **C601 22 µF「ESP32 储能」** | U20.2 | **48.2 mm** |
| **C602 100 nF**(同为 P3 页 ESP32 的)| U20.2 | **45 mm**(碰巧贴在 U22 旁边)|
| C607 / C610 | U6.15 / U7.15 DAC VDD | 10.5 / 11.0 mm |
| C604 / C605 / C606 | U21.10 / U22.10 / U23.24 | 8.2 / 8.8 / 9.2 mm |
U20 的电源脚周围 **12 mm 内一个元件都没有**。ESP32-S3 发射时是几百 mA 的突发电流,
48 mm 外的储能电容等于没有。
**根因很具体**:`pcb1_place.py` 里控制块是
`affine(['P3-CONTROL','P3B-EXPAND'], 73, 34, 42, 22)` —— 把两页原理图坐标整体**仿射映射**
进一个矩形。它保的是「原理图上挨着的板上也挨着」,**保不住「去耦贴着电源脚」**;
而 U20 / J22 / RT60x 是上面手工单独摆的 —— **芯片被拎出了仿射集合,去耦却留在了原地**。
⇒ 新增 `DECAP` 表 + `place_decaps()`:表里的电容不参与仿射,等芯片摆完之后
绕着本尊的电源脚一圈圈往外找第一个放得下的位置。两条经验:
- **表的顺序 = 抢位置的顺序,小的高频那颗必须排在大的储能之前。** 反过来实测过:
C601(1206,本体 4.7 × 1.7)先占掉贴身那一圈,C602 只能落到 3.52 mm 外 ——
而两颗里真正要贴身的恰恰是 100 nF 那颗。
- **上限是每颗一个数,不是全表一个数**(`DECAP` 第四列)。100 nF 靠的是自身低 ESL,
只有贴身才有意义;22 µF 管的是毫秒级电流坑,几毫米走线电感对它无所谓。
给储能 8 mm,它自然会让开贴身那一圈。
改完的结果:C602 → U20.2 **1.46 mm**,C601 → 3.31 mm,其余五颗 0.76 ~ 2.24 mm。
全板只动了 34 个元件,全部在控制块内(外加那两颗跨半块板搬过去的)。
#### ⭐⭐ 错二:`pcb1-parts.json` 的包围盒**漏了焊盘自身的旋转**
改完摆位,本地六项检查全过,DRC 却报出 **4 条间距错误** ——
`C607_2` 到 `U6_13` 只有 **3.8 mil(0.096 mm)**,规则要 7.9 mil。
`pcb1_parts_dump.py` 里 `w = p.pad[1]; h = p.pad[2]`,**没有用 `p.rotation`**。
QFN / SOIC 的侧边引脚就是同一个长条焊盘转 90° 用的:U6(WQFN-16)北排脚是
`RECT 0.80 × 0.28` 转 −90°,真实是 0.28 宽 × 0.80 高。不转的话
**U6 的 bb 在 y 上短 0.26 mm**,而摆位检查、铺铜反焊盘全都吃这个 bb。
> ⚠️ 这一套 API 里 `getAllPinsByPrimitiveId` 给的 rotation 是**度**,
> 而 `pcb_PrimitivePad.getAll()` 给的是**弧度**(见 `pcb_fanout.py` 文件头坑 1)。
影响面实测只有 **8 个元件**(U1~U5 的 VQFN-14、U6/U7 的 WQFN-16、U20 的模组),
但正好都是这块板上最贵的几颗。修完 bb 各长 0.26 ~ 0.30 mm。
#### 由错二引出的新检查:**焊盘到焊盘净距**(`pad_clearance_errs()`)
原来 `check()` 只查「元件包围盒重不重叠」。**不重叠不等于够净距** ——
C607 那次包围盒还差 0.358 mm 不碰,焊盘之间只剩 0.096 mm。
新的检查直接照着 DRC 那条规则算(0.2 mm / 7.9 mil),量的是**焊盘**不是包围盒,
跨元件、跨网络才查(同元件内部是封装厂商定的,同网铜可以贴在一起)。
全板 1171 个焊盘跑下来 **一条不报**,和布线前 DRC 间距基线 0 对得上 —— 互为交叉验证。
#### ⭐ 错三:`pcb_fanout.py` 有两处还指着**上一版**的事实来源
两处都是**静默失效**:不报错、不留痕、DRC 干干净净。
1. **`TARGET` 还停在 §26.8 之前**,里面有 `VO1`~`VO5`、`+5V`、以及 8 A 输入链三段。
§26.8 已判定这三类都不上 Inner2 ⇒ 照原样跑会给它们打一堆**接不到任何铜面的悬空过孔**。
⚠️ 第十五轮刚把 8 A 那三段的写死网名改成 `resolve_auto()` 反查,**那个改动本身是对的**,
只是 §26.8 随后判定它们根本不该下到 Inner2。**别再把它们加回 `TARGET`。**
2. **`_pour_filter()` 指着 `pcb_pour.py`** —— 单板时代 v5 的铜面几何。
现在改指 `pcb1_pour.REGIONS`,并且**每个网络都要过这一关**,不再分
「完整覆盖 / 只盖一部分」:Inner2 是分割电源面,连 `+12V` 都只盖三块 L/⌐ 形。
实测这一条在干活:`+3V3` 的 61 个贴片焊盘里 **17 个落在铜面外**,
不滤掉就是 20 多个悬空过孔。
判据是**过孔中心**在不在多边形里,不要求整个过孔都在 ——
铜面内缩 0.5、过孔离板边 0.6,板边那一圈 GND 过孔的铜环本来就探出去 0.3。
#### 扇出规划器这一轮补的四条(都是被真实焊盘逼出来的)
- **`FANOUT_WHY=U6.15` 调试开关**:把这个焊盘所有候选孔位**卡在哪一道校核上**按次数打出来。
「周围太挤」四个字查不出任何东西,而每次卡住的原因都不一样。
- **第三类并线锚点:这一轮已经扇出成功、身上已经有过孔的同网焊盘。**
原来只认「通孔 / 散热盘」。0.5 mm 间距 QFN 的中间脚一旦被邻脚的过孔堵住正北那条
唯一出路就只能报失败 —— 哪怕 0.8 mm 外就趴着一颗自己的去耦电容。
- **起止两个焊盘自己的孔不算障碍。** 并线的终点本来就落在锚点上,而锚点常常正是一个
自带钻孔的焊盘(QFN 散热盘里那个 Ø1.02 热过孔)。把它当障碍 =
「这条线不许接到它要接的那个焊盘上」。U6.14 唯一的出路就是被 U6.17 自己的孔挡掉的。
- **`PREFER_LINK`:宁可并线也不要自己那个过孔。**
U6 北排四个脚里 pin14 是 GND、pin15 是 +3V3。GND 那一遍先跑,pin14 顺利在正北打了个孔,
**那个孔的铜箔正好卡在 pin15 唯一的出线走廊上** —— 于是 pin15 既打不了孔也并不过去。
而 pin14 南边 0.25 mm 就是自己的散热盘(自带热过孔,本来就通全层),并过去 0.45 mm 完事,
比它自己占一个过孔还短。**这是「谁更没得选谁先占」,不是特例补丁。**
- **并线也能退到窄线宽(0.3 → 0.2 → 0.15)。** U6.15 并到 C607.1 时,线心到 C607.2
有 0.346 mm,0.3 的线要 0.35 —— **差 0.004 mm** 整个脚就断在那里。
并线走的是 mA 级的地 / 3V3,规则里最小线宽 0.102。
#### 结果
| 网络 | 目标层 | 贴片焊盘 | 过孔 | 并线 |
|---|---|---|---|---|
| `GND` | Inner1 (15) | 250 | 256(含 6 个散热盘的盘内阵列共 14 个)| 2 |
| `+12V` | Inner2 (16) | 56(跳过 U13 两个 Kelvin 脚)| 98 | — |
| `+3V3` | Inner2 (16) | 44 在铜面内 / 17 靠走线 | 44 | 2 |
| `VO1_P`~`VO5_P` | Bottom (2) | 各 4 | 各 8 | — |
板上 **438 个过孔 + 441 条短线**,全部网络**失败 0 个**。
DRC:**间距错误 0** / 连接性 1336(还没铺铜,预期之内)。
⚠️ **扇出之后连接性数字会先涨再跌**:布线前基线是 1145,扇出完是 1336 ——
过孔本身是新对象,在铺铜之前每一个都是自己网络里的孤岛。铺完 Inner1/Inner2 才会掉下去。
### 26.10 下板铺铜下发(2026-09-06 第十六轮,`pcb1_pour.py --push` / `--verify`)
§26.8 定的第 4 步。`--push` 整套流程照抄载板 `pcb2_pour.py`(那边跑通过两轮),
三条硬约定原样保留,不重复写了:**顺序即优先级** / **`create()` 成功了也会抛** /
**点列末尾要把首点再写一遍**(见 `pcb1_pour.py` 的「下发」段注释与 skill §9j、§9k)。
#### ⭐ 这一轮真正新加的是「下发后按**实测铜**再校核一遍」,而且和下发前**共用同一段代码**
`grid_checks(G_, pads, chk)` —— 连通域 / 断面 / 焊盘覆盖三条。
下发前的 `G_` 由 `REGIONS` 栅格化而来,下发后的 `G_` 由
`getState_PourFills()` 回读的真实多边形栅格化而来,**跑的是同一个函数**。
> 分成两套写,「预测过了、实测也过了」就只证明两套代码各自自洽,
> 证明不了板上那块铜真的是计划里那块铜。
回读那一段的两个坑:
- **环是 `x1 y1 'L' x2 y2 ... 'ARC' 角度 ex ey ...`** —— `'ARC'` 后面第一个数是**角度不是坐标**,
按奇偶分 x/y 会整体错位(载板那边把包围盒算成过 −22.9 ~ 219.4)。
这块板实测有 **1485 段圆弧**(反焊盘),这里按**弦**处理,反焊盘会算大一丁点 —— 偏保守。
- **不能逐格做 point-in-polygon**。一整层地平面二百多个环 × 32 万格,Python 里要跑几分钟。
改成**扫描线 + 奇偶规则**(环套环就是洞),秒级完成。
#### ⭐⭐ 新校核:**每一块碎片都要有本网的过孔 / 通孔落脚**,否则是浮铜
铺铜自己的孤岛判定只在「重建」那一刻生效,而且它认的是**铺铜对象**;
一个对象铺出好几块的时候(Inner2 的 GND 底填被三块电源面切成 3 段),
**单独某一段有没有落脚点它是不管的**。
浮铜在 DRC 里只会变成几条连接性错误,混在几百条「还没布线」里根本挑不出来。
实测:9 组 (网络, 层) 的全部 12 块碎片**都有本网过孔/通孔落脚**。
#### 实测结果(`--verify`,24 项全 OK)
| 层 | 网络 | 铺出来的面积 | 连通域 | 计划 |
|---|---|---|---|---|
| Inner1 | `GND` | 19610 mm² | **1** | 1 ✅ |
| Inner2 | `+12V` | 9778 mm² | **1** | 1 ✅ |
| Inner2 | `+3V3` | 4286 mm² | **2** | 2(南西/南东,§26.8 拓扑上避不开)✅ |
| Inner2 | `GND` 底填 | 5290 + 2191 + 94 mm² | 3 | 被三块电源面切开,预期之内 |
| Bottom | `VO1_P`~`VO5_P` | 194~307 mm² | 各 **1** | 各 1 ✅ |
13 条断面**全部达标**,而且实测普遍**比计划宽**(如「北大块 @Rs6 东出」计划 28.75 mm、
实测 36.50 mm)—— 计划里的反焊盘按 `焊盘半宽 + 0.2` 一刀切,比真实反焊盘保守。
方向是对的:实测 ≥ 计划。
`+12V` 61 / 63、`+3V3` 45 / 64 个焊盘落在自己的平面上,其余 21 个是
§26.8 那张「明知故犯」表里有名有姓的,一个不多一个不少。
#### DRC
| 阶段 | 间距错误 | 连接性错误 |
|---|---|---|
| 布线前基线(板上一根铜都没有)| 0 | 1145 |
| 扇出下发之后 | 0 | **1336** |
| 铺铜下发之后 | **0** | **733** |
⚠️ **扇出之后连接性会先涨**(1145 → 1336):过孔本身是新对象,铺铜之前每一个都是
自己网络里的孤岛。铺完 Inner1 / Inner2 才一次性掉到 733。
**只看扇出完那一步会以为扇出把事情弄坏了。**
### 26.11 8 A 输入链的顶层宽铜(2026-09-06 第十七轮,已下发并回读复核)
做的是 §26.8 定的第 5 步,也是全板**唯一一条 8 A 的路**。三段一律顶层灌铜,
定义在 `.claude/pcb1_pour.py` 的 `REGIONS` 里,和 Inner2 / Inner1 / Bottom 那 12 块
走同一套 `--push` / `--verify`。
| 铺铜 | 网络(当场反查)| 面积(实测)| 覆盖 |
|---|---|---|---|
| `VINRAW-TOP` | `$1N223` | 46 mm² | J1.2(端子) → F1.1 |
| `VINFUSED-TOP` | `$1N227` | 19 mm² | F1.2 → Q1.1~3(SOP-8 源极三脚)|
| `VINSW-TOP` | `$1N236` | 284 mm² | Q1.5~8(漏极) → D1 → C4/C5/C6 → C2/C3 → Rs6.1 |
实测断面(顶层 1 oz,ΔT=20 °C,**都是回读实测铜量的,不是按计划算的**):
| 位置 | 连续铜宽 | 能带 | 要 |
|---|---|---|---|
| RAW J1→F1(x=10)| 5.00 mm | 10.4 A | 8 A |
| FUSED F1→Q1(x=17)| 5.00 mm | 10.4 A | 8 A |
| SW Q1 漏极西出(x=21)| 12.00 mm | 19.6 A | 8 A |
| SW C4 旁缩腰(x=24)| 8.75 mm | 15.6 A | 8 A |
| **SW 干道(x=12)** | **4.75 mm** | **10.0 A** | 8 A |
| SW 干道拐北(y=79)| 21.50 mm | 29.9 A | 8 A |
| SW 北柱 @C2 上方(y=86)| 7.00 mm | 13.2 A | 8 A |
| **SW 北柱 @Rs6.1(y=92)** | **5.00 mm** | **10.4 A** | 8 A |
最窄的两处是 4.75 / 5.00 mm,8 A 下 ΔT 分别约 12 / 11 °C。
#### 走法:一条 ⌐ 形干道,全程零过孔
```
y 93 ┌──┐ Rs6.1(分流器西脚),北柱到此为止
│北│ —— 再往北是 U13 的 Kelvin 脚,不铺
y 86 │柱│ ┌─┐ 右边那条竖的是 C4/C5/C6 去耦指
y 83 ├──┤C3│ │
y 81 │ └┬─┘ │ C2/C3 两颗体电容各开一个口袋
y 76 └───┴────┴──────────────┐ ← 8 A 干道 y 76~80.95(净 4.95 mm)
y 70 Q1 漏极 + D1 │
y 68.6 └
x1.5 x12 x19.6 x28.9
```
`VIN_SW` 是**一个**铺铜对象、24 个点的直角多边形,不是几块拼的 —— 理由见下面第 3 条。
#### ⭐ 三件这一轮才想清楚的事
**1. 顶层和内层挡路的东西根本不是同一批。**
| | 通孔焊盘 | 贴片焊盘 | 过孔 | 走线 |
|---|---|---|---|---|
| 内层 Inner1/2 | 挡 | **不挡**(对内层完全透明)| 挡 | 挡本层的 |
| 外层 Top/Bottom | 挡 | **挡** | 挡 | 挡本层的 |
`Grid` 原来只会挖「异网通孔焊盘」—— 那是给内层写的。照搬到顶层,
这块角落里 D1.2 / C4.1 / C5.1 / C6.1 / R1.1 的 GND 贴片焊盘、
扇出给它们打的 9 个过孔、以及 Rs6.2 那两条 1 mm 宽的 +12V 出线,**一样都不会被算进去**,
铺出来的 8 A 铜会比算的窄一大截,而所有断面数字都还是绿的。
⇒ `Grid.__init__` 加了 `outer` 分支 + `obstacles()`(过孔全层挡、走线只挡本层),
`snapshot()` 发现缓存里没有 `via`/`line` 就**强制重抓**。
**2. ⭐⭐ 0.25 mm 的栅格漏掉了一处 0.101 mm 的侵入。**
`check_top_clearance()` 是这一轮新加的**不过格子**的校核:顶层三块铜的多边形,
到每一个异网铜(焊盘框 / 过孔 / 走线,含线宽)的**真实几何距离**必须 ≥ 0.2 mm。
它当场抓出两处,栅格只抓到其中一处:
| 侵入 | 栅格看得见吗 | 成因 |
|---|---|---|
| 干道东端 ↔ `C4.1` 的 GND 脚,**0.096 mm** | 看得见(挖掉 7 格)| 边界写在 23.2,C4.1 西缘在 23.296 |
| 北柱东缘 ↔ Rs6.2 的 +12V 出线,**0.101 mm** | **看不见** | 那条线 1.0 mm 宽、**圆头端帽往外多探 0.5 mm**,实际铜到 x 6.901,而边界写在 6.8 |
第二条是这一类错的标本:**线的端点不是铜的端点**,端帽要按半线宽外扩;
0.101 mm 的侵入在 0.25 mm 栅格上一个格心都落不进去 ⇒ 栅格全绿。
真下发下去,EDA 自己会往回缩一点点铜 —— 板子不会有 DRC 错,
但**板上那块铜和这里写的那块铜就不是同一块了,后面所有断面数字全部作废**。
⇒ 边界改成 23.05 / 6.65,并顺手把北柱西缘从 2.6 挪到 1.5(离板边仍有 1.5 mm),
`@Rs6.1` 那道最窄断面从 4.25 涨到 5.00 mm。
**3. `VIN_SW` 必须是一个铺铜对象,不能拆成几块靠重叠连起来。**
第一版按几何拆成四块(干道 / 漏极块 / 电容指 / C3 口袋),各自都含本网焊盘、
孤岛规则也过。但**同层同网两块铜重叠时,低优先级那块会被高优先级那块裁掉,
裁的时候留不留 0.2 mm 净距,API 文档没说**。留了的话,干道和漏极块之间就是一条
看不见的缝 —— 而且**连接性 DRC 也报不出来**,因为两边各自都还连在自己的焊盘上。
⇒ 合成一个 24 点的直角多边形。
手写 24 个点的代价是「写错一个坐标什么检查都发现不了」(断面照样够宽、
连通域照样是 1、净距照样过,错的地方正好没被任何一条断面线量到)。
⇒ 区域里多带一个 `rects=[...]`(这 24 个点该等于的 8 个矩形),
`poly_vs_rects()` 用 0.05 mm 的细格逐格对照。写错一个点当场报。
#### 不进宽铜的三个焊盘(都是有意的,写在 `ROUTED_PADS` 里)
| 焊盘 | 为什么 |
|---|---|
| `U13.10`(`$1N236`)| **Kelvin(VIN+)**。Rs6 满量程才 40 mV,取样脚要单独引细线到 Rs6.1,不能从大铜面上随便找个点接。北柱顶端 y 93.0 那一小截是死头、不过电流,正好当取样点 |
| `DZ1.1` / `C1.1`(`$1N227`)| Q1 栅极钳位与 RC 的上端,µA 级;夹在 F1.1 与 Q1.4 之间只有 3.1 mm,走细线 |
#### DRC
| 阶段 | 间距错误 | 连接性错误 |
|---|---|---|
| 铺完 Inner1/Inner2/Bottom(§26.10)| 0 | 733 |
| **加上顶层 8 A 宽铜** | **0** | **719** |
#### ⚠️ 顺带看出来的一件事:F1 的封装是 1206,但 BOM 写的是 10 A
`F1` 板上用的是 `FUSE-SMD_L3.2-W1.6-1`(1206),而 §7 的 BOM 写「保险丝 10A 慢断」。
**1206 的贴片保险丝一般做到 5 A 左右就到顶了**,10 A 通常要 2410 / Nano2 那一类。
铜宽本身没问题(这条链按 8 A 铺的),但**器件选型和封装对不上**,得单独定一次。
换更大的封装会动 J1→F1 那一段的摆位(`pcb1_place`)⇒ 要重推摆位 + 重扇出 + 重铺铜。
### 26.12 F1 换 12 A / R9 换 5 × 2Ω 2512(2026-09-06 第十八轮,用户拍板)
两件都是**元件选型**改动,走的是完整链路:改原理图 → 导入变更 → 重推摆位 →
重扇出 → 重铺铜 → DRC。
#### ⚠️ 先纠一条上一轮写错的判断
§26.11 末尾写「F1 的封装是 1206 但 BOM 写 10 A,1206 做不到 10 A」——**这条是错的**。
`F1206HC10A0TM`(C310989)本来就是 **1206 封装、额定 10 A**(35 V,分断 150 A,I²t 15 A²s),
BOM 和封装从来没有对不上。教训很直白:**「这个封装做不到那个规格」属于记忆,不是证据**,
库里 `lib_Device.search()` 一查就有 `Current Rating` 字段。
不过顺着查下去发现了一条**真的**:
| | 值 | 判据 |
|---|---|---|
| 连续电流 / 额定 | 8 / 10 = **80%** | 保险丝常规降额线是 **75%**,超了 |
| I²t | **15 A²s** | C2/C3 两颗 470 µF 上电浪涌,误熔断风险 |
⇒ 换同族 **`F1206HC12A0TM`(C310990,12 A / I²t 20 A²s)**:8/12 = 67% 落在降额线内,
而且**封装还是 1206,摆位一格都不用动**。
⚠️ 但**封装对象换了**:`FUSE-SMD_L3.2-W1.6-1` → `F1206`。实测焊盘几乎一样
(1.191 × 1.727 @ ±1.444,原来是 ±1.52),顶层那两块宽铜的边界照旧够用 ——
**这是 `check_top_clearance()` 复核出来的,不是看着差不多就放过的**。
#### ⭐⭐ R9:高度检查在一个错的数上放行了整整一轮
`R9`(10 Ω/5 W 母线泄放)用的是 `5W水泥电阻 5W10RJ`(C9900012720),
封装 `RES-TH_L13.5-W9.5-P5.80-D0.7`,而 `pcb1_place.H_FP` 给它填的高度是 **9.5** ——
照封装名里的 `W9.5` 抄的。
**`P5.80` 的脚距才是判据:本体 13.5 长、脚距只有 5.80,说明它是立式的。**
同族的 C9900012721(`RES-TH_L13.0-W9.5-P4.50-D1.0`)3D 模型名直接写着 **`H52.0`**。
那一片 hmax 只有 **12.0**(载板底面压下来),所以「高度预算全过」这句话在它身上一直是假的。
> ⇒ 往 `H_FP` 里加直插件的判据:**脚距和本体长度对不上就是立式**,
> 高度不是封装名里的 W,是那个对不上的方向。
卧式的 5 W 水泥电阻库里有(`C9900015499`,`RES-TH_BD9.5-L22.0-P26.00-D0.8`,高 9.5),
但**脚距 26 mm、占位 28 × 11 mm,北左角塞不下** —— 可行位置只剩 x 83~101 / y 88~92
那块北中空地,离 Q3 (25.5, 119) 有 70 mm。
⇒ 用户选了**第三条路:5 × 2 Ω 2512 串联**(`RHC2512FT2R00` C2570006,2 Ω/2 W)
= **10 Ω / 10 W,高 0.8 mm**。功率余量还翻了一倍。
| | 原 R9 | R9A~R9E |
|---|---|---|
| 高度 | ≥ 22 mm(模型里写的 9.5 是错的)| **0.8 mm** |
| 功率 | 5 W | **10 W** |
| 占位 | 13.5 × 9.5 | 15.5 × 12(1+2+2 蛇形)|
摆位:可用空地是 **x 14.5~30.0 / y 86.5~101.8**(西 U29 到 14.0 / 东 R220 从 30.87 /
北 L2、U19 从 102.25 / 南 C6)。一颗 2512 占 7.42 × 3.46,**一行放不下五颗**(要 39.4 mm),
排成 1 + 2 + 2 的蛇形,串联顺序跟着几何走 —— Q3 在正北,所以 R9A 放最上面、R9E 收在最下面接地:
```
y 98.5 R9A (18.0) ← $1N244 从 Q3 漏极下来
y 94.0 R9B (18.5) R9C (26.5)
y 89.5 R9E (18.5) R9D (26.5)
↑ R9E.2 = GND
```
四个串联节点是自动命名网(`$1N263`~`$1N266`),13.3 V 全压在 10 Ω 上是 **1.33 A**,
`pcb1_rules.AUTO_TRACK` 里加了 `BLEED0`~`BLEED4` 五条按位号反查的指派,挂 `PWR1A`(0.6 mm,
外层 1 oz 可带 2.16 A)。
#### 这一轮踩到的四条(都写进了对应脚本的防呆)
1. ⭐⭐ **`pcb_fanout.py --net all --push` 不幂等,我连推了两遍。**
板上变成 **888 个过孔**,每个都有一个同坐标同网的副本;
而**短线数没变**(444)—— EasyEDA 把共线重叠的新线并进了旧线(skill §9v)。
**连接性 DRC 也不报**,因为副本和焊盘同网,电气上「没错」。
唯一看得出来的判据是回读过孔数。⇒ `guard_not_pushed_twice()`:
板上已有过孔就拒绝 `--push`,并把 `--clean → dump_pads → --push` 的顺序打出来。
(`--only` 那种「补一两个漏网的」不设闸。)
2. **`_p1_sch_bom.json` 在仓库里根本没有生产者。** `--verify` 拿它当对账基准,
而它只能靠手工维护 ⇒ 改过原理图之后 `--verify` 是拿新 PCB 和旧原理图对账。
⇒ `pcb1_import.py` 加 `--bom`:逐页重抓。**一页一个请求** ——
`eda.py` 把返回值截到 20000 字符,整本 BOM 装不下,截断之后 `json.load` 炸在中间。
3. **`JS_DUMP` 没有 `openDocument`**(skill §9l)。跟在 `--bom` 后面跑 `--verify`,
当前文档停在原理图上,`pcb_PrimitiveComponent.getAll()` 直接抛
`Cannot read properties of null (reading 'map')` —— 报错信息完全指不到根因。
4. **`p1_add.py` 这类「整页重画」的脚本改完就变成地雷。** 它的底稿 `p1-base.json`
停在 2026-09-04,再推一次会把 R9A~R9E 之间那 6 段新导线**静默回退**
(BASE 里没有它们,却有旧的 GND 引线)。⇒ 加了硬闸门,要跑必须显式带
`--i-know-it-is-stale`。**改一页就要问一遍:还有哪个脚本会重画这一页。**
#### 顺带清掉的:P1-INPUT 的文字叠了两代
截图才看出来(三道几何检查都不看文字):**66 个文字图元里只有 30 条是唯一的**,
多出来 36 个是同坐标同内容的副本(`p1_add.py` 推过好几次,它的清空没清干净);
另外还压着**更早一整代**的说明 —— 旧【C】压在【A】上、旧【B】压在【C】上、
旧【A2】**直接印在标题栏里**。判据是 `p1-base.json` 只有 9 条 + `ADD_TEXT` 5 条 = 14 条,
其余全是残留。收拾完 66 → 14,并逐条对账(多一条少一条都报)。
⚠️ `p1_text_fix.py` 第一版**不幂等**:去重跑在新增之前,第二次跑会再叠一层
(27 → 18 而不是 14,而且因为坐标在名单内,对账还报了 OK)。
⇒ 把新增块的坐标也放进删除名单,改成「先删再建」,并断言最终条数。
#### 结果
| | 值 |
|---|---|
| 元件 | 338 → **342**(R9 去 1、R9A~R9E 来 5)|
| 导入对账 | PCB 342 / 原理图 342,缺 0 / 多 0 / 封装对不上 0 |
| 扇出 | 444 过孔 + 444 短线,失败 0,**重复 0** |
| 铺铜 | 15 块全部铺出,顶层三段各 1 个连通域,实测断面与 §26.11 一致 |
| DRC | **间距 0** / 连接性 725(多出来的 6 条是泄放链还没布线)|
### 26.13 五路功率级精调(2026-09-06 第十九轮)—— §10.2 的四条关键回路
这一轮做完 PROGRESS 里排的第 6 步。**四条回路里有三条的根因是器件朝向,不是布线技巧**,
所以先改摆位再布线;改摆位这一步用户拍板过(选「转三个 + 挪三颗」)。
#### ⭐⭐ 先说一个真错误:五路 Buck 的散热盘一个过孔都没有
TPS54622 的 PowerPAD(`U1~U5` 的 pin 15)既是 **PGND**,也是这颗 4 A Buck
**唯一的散热通道**。§10.3 早就写了「电感和 IC 下方铺大面积铜箔并打散热过孔阵列
(0.3 mm 孔,1 mm 间距)」—— 而板上这五个盘是**光的**。同样漏掉的还有 U6/U7 的 EP。
根因在 `pcb_fanout.one_net()` 的一行:
```python
todo = [p for p in pads if p['net'] == net_filter and not p['hole'] and ...]
```
`not p['hole']` 想表达的是「这是贴片盘,通孔盘不用扇出」。但是——
> **EasyEDA 给每一个 POLYGON 焊盘都塞了一个假的 `hole`。**
> 板上 11 个 POLYGON 盘(U1~U5.15、U6/U7.17、J22 的四个壳体盘)
> **无一例外**满足 `hole = 0.600 x min(w, h)`:U1 的盘 2.032 x 4.320 -> 1.2192,
> U6 的 1.70 x 1.70 -> 1.02,J22 的 1.30 x 0.60 -> 0.36。
> 这是个派生出来的占位值,EasyEDA 自己渲染出来那几个盘是**实心的**。
于是这 7 个散热盘被整批滤掉。判据本来就该是**层号**:`layer == 12` 是多层(真通孔),
`1 / 2` 是单铜层。三处已改:
| 文件 | 改了什么 |
|---|---|
| `dump_pads.py` | 落盘前把**单铜层焊盘的 `hole` 一律清成 None**,并断言被清掉的确实符合 0.6 倍关系;不符合的打印出来要人看 |
| `pcb_fanout.py` | `todo` 只按层号过滤;顺带加了 `stale` 提醒(`pcb-copper.json` 是旧的会报出来)|
| `pcb1_parts_dump.py` | POLYGON 盘的尺寸原来取自 `+s[1]`(那是**点数组**,得到 NaN->0),再退回到 hole 那一位 —— U1 的散热盘因此被记成一个 **0.12 mm 的点**。现在按点数组算真实 AABB |
⚠️ **这一类失效是静默的**:连接性 DRC 只会含糊地多出几条,
没人会把它和「footprint 里一个用不上的字段」联系起来。
#### 盘内阵列也重写了:**散热盘不是它的包围盒**
`U1~U5` 的 EP 是个**十字**:中间 2.03 x 2.03 的方块,上下各伸出两根 0.24 mm 宽的
指头到 ±2.16。按包围盒(2.03 x 4.32)撒 1 mm 栅格,y 方向两头那两个孔会落到**铜外面**,
而净距校核和连接性 DRC 都不会响(那儿本来就没别人)。
⇒ 新增 `pad_poly()` / `disc_in_poly()`:候选孔位要求**整个 Ø0.7 的圆都在多边形里**。
顺带把阵列改成「先按 1.0 mm 排,太小就退到 0.65 mm 再排一次,取孔多的那一版」,
并在偶数栅格中心补一个孔(散热盘最该打孔的就是正中间)。结果:
| | 之前 | 现在 |
|---|---|---|
| `U1~U5.15` Buck 散热盘 | **0** | 5(2x2 @1.0 + 中心)|
| `U6/U7.17` DAC 散热盘 | 0(走了一条 2.74 mm 的 0.2 引线到盘外)| 4(2x2 @0.65)|
| `U14~U18.21` eFuse 散热盘 | 2 | 6(3x2 @0.65)|
`U6/U7` 的 EP 是 1.70 x 1.70 = 2.89 mm²,卡在面积阈值 `THERMAL_AREA=4.0` 之下、
又在 `U31` 的 2.75 之上 —— 把阈值降到 2.8 等于拿 0.05 mm² 的余量去赌。
新增 `THERMAL_PADS` 点名表,两颗直接写进去。
#### 摆位:转三个 + 挪四颗(用户拍板)
| 器件 | 改法 | 为什么 |
|---|---|---|
| `L*01` | rot 180 **+ 东移到 (10.7, 18.0)** | footprint 的 pin1(SW) 在西,rot 0 时正好**背对** U 的 SW 脚,SW 要绕过整个电感 13.1 mm |
| `U*14` | rot 180,北移 0.8 到 y 30.3 | rot 0 时输入脚在北、输出脚在南,而源在南、去处在北,两条 4 A **各横穿一次封装**;北移是为了给输出电容腾出 4.6 mm 的空袋 |
| `Rs*01` | rot 180 | rot 0 是「西 = VO_P / 东 = $2N699」,而 INA226 的 IN+ 是 p10(西)、IN− 是 p9,**两条取样线必然交叉** |
| `C*05` | (11.5,16.2,90) -> (12.4,13.0,0) | 原位置正卡在 SW 立管唯一能走的缝上(U.13 东缘 10.624 到它西缘 11.229 只有 **0.605 mm**,0.28 的线要 0.68)|
| `C*06/07/08` | 从 x 14~17.5 挪进 L*01 与 U*14 之间的空袋 | 输出电容跟着电感转过来的 VO 脚走;三颗的 VO 脚排成一列 x = 5.200,正对 U*14 转过来的输入脚 |
⚠️ **1206 的焊盘 rot 0 时是 1.49 宽 x 1.73 高**(不是反过来)。按 1.49 高算的话
两颗摞起来「差 0.37 mm 能塞下」,实际差 0.37 的另一头 —— 本地检查当场报了 0.166 / 0.188。
⚠️ **L*01 不能往南挪**:C*02 的 0805 罐压在它北边 1 mm 内,挪 1.3 mm 就重叠。
空袋是靠 U*14 北移 0.8 mm 腾出来的。
母版的局部包围盒**一格没变**(x 2.28~29.50 / y 2.73~43.71),
所以五路的分区(§26.3)和 `VO_X` 对位一个字没动。
#### 布线:`pcb1_route_pwr.py`(新)
四条关键回路**不能交给栅格布线器**:它优化的是长度和过孔数,
而这四条的判据都不是「连通」—— 一个完全连通的解可以四条全不满足。
⇒ 路径写在 **CH1 母版的局部坐标**里,按 `CH_PLACE` 仿射到五路(rot 180 是纯旋转),
改一处等于五路一起改。27 条母版路径 x 5 = 135 条 / 210 段。
| 回路 | 做法 | 结果 |
|---|---|---|
| ① 热回路 | `C*01.1` 顶层 1.0 mm 直上 U 的 PVIN;`C*02/C*03` 从**西侧** 0.8 mm 母线并过来 | 地不另画顶层线 —— Inner1 就在顶层下 0.2104 mm,回流是镜像电流,回路面积 = 走线长 x 0.21。让 +12V 下到 Inner2 再回来的话回路高度变成 L2-L3 的 1.13 mm,**差 5 倍** |
| ② SW | 0.30 窄线出脚 -> 1.0 -> 1.5 立管直上电感 | **13.1 -> 9.7 mm,铜面积 11.2 mm²** |
| ③ FB | `U.7` 往南出,贴散热盘南爪西边 0.224 下来,走 R*08 **东边**再往西折 | 全程在 SW 的反面,最近处 3.5 mm |
| ④ Kelvin | 两条取样线**并排往北 1.7 mm 再分开**;IN− 从**电阻本体下面**(两焊盘之间)横过去 | 不交叉,取样点在焊盘上 |
⚠️ **`U*8.9`(IN−)不许有下到 `VO*_P` 小岛的过孔**,已写进 `pcb1_pour.ROUTED_PADS`。
让它走岛的话,取样点在岛上而不是分流电阻的焊盘上,中间隔着 `Rs*01` 那三个扇出孔
(并联约 0.5 mΩ)。Rs 只有 5 mΩ、满载 20 mV,**0.5 mΩ x 4 A = 2 mV = 10% 的读数误差**,
而 DRC 和连通性检查都看不出来(IN− 和 `VO*_P` 本来就是同一个网,连上了就算过)。
pin 8 是 VBUS(测输出电压),照旧进岛 —— 它要的就是负载端的电位。
#### ⭐⭐ 这一轮踩到的四条
**1. 五路的扇出结果并不相同。**
摆位是一模一样的(CH2/CH3 整路转 180°),但扇出规划器的候选角度是按**板坐标**排的,
同一个焊盘在 CH1 往东扇、在 CH2 就往西扇。于是母版里算好的走廊在 CH2/CH3 上被堵死,
校核报出来的却是「CH2 的 F-trunk 撞到一个 GND 过孔」—— 看上去像布线画错了,
**错的是上游的扇出不对称**。⇒ `pcb_fanout._CH_FORCE_LOCAL`:
把和手工走廊相关的 5 个焊盘(`C*01.2` / `C*02.2` / `C*03.1` / `U*8.1` / `R*02.2`)
按 CH1 的解钉死,展开到五路 25 个 `FORCE_VIA`。钉死之后照样走全套净距校核。
**2. DRC 的「物理错误」那一支平时是空的,容易漏看。**
第一版按 0.28(SW 出脚)/ 0.25(Kelvin)下发,**间距错误 0、连接性还降了 125 条**,
看那两支会以为全过 —— 而 `物理错误·导线` 里躺着 **50 条**
「线宽 11mil,应该在 11.8mil ~ 157.5mil」:`pcb1_rules.TRACK_RULES` 里
`SWNODE` / `PWR4A` 的 `strokeWidthMin` 都是 0.30。加宽到 0.30 之后清零。
(0.30 的线从 0.28 高的 QFN 焊盘出来,上下各留 0.21,正好还够。)
**3. 回读走线不能按端点比 —— EasyEDA 会在 T 形接点上把已有的线劈成两条。**
西侧那条 +12V 母线 `(2.550, 8.701)->(2.550, 13.949)` 下发之后,板上是两条,
因为 `C*01` 那条支线正好接在中间。按端点比会报「210 段里 40 段对不上」,
而板上的铜一点没少。⇒ `verify()` 改成**覆盖判据**:沿计划路径每 0.2 mm 取一个点,
要求都被某条同网同层同线宽的实测线盖住。
**4. IPC-2221 不能套在短桩上。**
0.5 mm 间距的 QFN 只能用 0.30 的窄线出 1 mm,套公式算出来是 49 °C;
再窄一点(0.28)直接 265 °C。那条式子假定的是**长而均匀**的导体,
而这种短桩两端都焊在大铜上。⇒ 短于 2 mm 的段只打印不报错。
#### 这一轮的数
| | 值 |
|---|---|
| 元件 / 过孔 / 走线 / 铜面 | 342 / **495** / **691** / 15 |
| DRC | 间距 **0** / 物理 **0** / 连接性 **594**(这一轮开始时 725)|
| 一路功率级走线 | 74.8 mm,其中 SW 9.7 mm |
| 校核 | 本网落脚 + 组内连通 + 逐段净距 + 拐角 + 载流,下发前后同一段代码 |
#### 还欠的(都不影响下一步)
- **`R*01` / `R*02`(FB 分压)离 U 的 FB 脚 7 mm**,§10.2-3 的「紧贴 FB 引脚」没做到。
现在那条 FB 走线 8.6 mm,全程在 SW 的反面、最近 3.5 mm,能用;
真要做的话得把 `R*01/R*02/R*07/R*08/C*12` 整组挪到 U 的正南(局部 x 7~12 / y 5.5~9),
那是又一轮摆位 + 扇出 + 铺铜。
- **`C*08` 离电感的 VO 脚 4.5 mm**(在袋子东头)。它是输出侧的高频去耦,
真正管环路的是 `C*06/C*07` 两颗 1206,那两颗贴着。
---
### 26.14 下板信号布线(2026-09-06 第二十轮)—— 379 条布通 284 条,⛔ 未下发
这一轮建好了下板的信号布线工具链,并**把「布不通」拆成了两类**:
**几何上没有出路**(22 个引脚)和**拥挤**(95 条连接)。前者换任何布线策略都无解。
**板上一个对象都没动。**
#### 26.14a 三件新工具
| 文件 | 干什么 | 为什么要单独有它 |
|---|---|---|
| `pcb1_netlist.py` | 按**实测铜**算每个网络还欠几条 | DRC 的「连接性错误」是按对象列的、还要 reload 才准,594 这个数说明不了「还剩几条线要拉」。这里把焊盘 / 过孔 / 走线 / **回读的铺铜**当图的节点,`k` 个连通域就是还差 `k−1` 条 |
| `pcb1_route_sig.py` | 下板信号布线器 | 载板那个是「本脚本负责的网络整网删掉重画」;下板已经有 691 条线(§26.13 的功率级 + 扇出),照抄会把它们抹掉。这一版**只加不拆**,任务表来自 `pcb1_netlist` |
| `pcb1_escape_audit.py` | 逐焊盘算「能不能走出 4 mm」 | 「布不通」看不出根因是**这一头出不来**还是**中间那段挤**,而两者的处理办法完全不同 |
#### 26.14b 四个真 bug(都属于「检查全绿而结果是错的」那一类)
**1. POLYGON 焊盘的包围盒不是它的形状。**
§26.13 抓的是它的 `hole` 是假的;这次是 `pad[1], pad[2]` 那对宽高。
TPS54622 的散热盘是**带四个缺口的多边形**(缺口正是让给 pin 1/7/8/14 的),
按 2.032 × 4.320 的包围盒当障碍,这四个脚整个泡在 GND 铜里,一个出线方向都找不到。
⇒ **POLYGON 焊盘的任何标量属性都不能直接当几何用**;只能读 `pad[1]` 那串点,
再按真实轮廓光栅化。板上一共 11 个这样的盘(5 个 Buck EP + U6/U7 EP + J22 的 4 个屏蔽脚)。
**2. 网名里带 `#` 会被 `netof()` 拆坏。** 下板有 `KEY_OE#` 和 `IOEXP_INT#`,
而引擎用 `key.split('#')[0]` 还原网名 ⇒ 校核时它和自己的焊盘被当成异网,
报「净距 −0.100」。分隔符改成 `chr(0)`。
**3. 45° 切角会切进铺铜。** 切角是往拐角**内侧**补铜(不是只拿掉铜),
而 `seg_slack()` 只认焊盘 / 过孔 / 走线三样。⇒ 把铺铜矩形条包装成「假焊盘」一起喂进去。
**4. 「放得下」不等于「栅格上走得通」。** 见下一节。
#### 26.14c 细栅格逃逸:0.5 脚距的脚要单独走出来
`U8.3`(INA226 的 ALERT)西边 1.00 mm 是 GND 扇出孔,东边 1.00 mm 是邻脚的出线段:
| 线宽 | 需要的净宽 | 0.1 mm 栅格上需要(各加一个 QERR 0.0707)|
|---|---|---|
| 0.20 | 1.005 mm(**差 5 µm**)| 1.096 mm |
| 0.15 | 0.955 mm(**放得下**)| 1.096 mm(仍然过不去)|
0.025 mm 栅格的 QERR 只有 0.0177,同一条缝就通了。
⇒ 凡是在 0.1 栅格上出不来的脚,先在 4 mm 内用 **0.025 mm 栅格**单独走出去,
再把这一小段当本网已有的铜交给主布线器。实测 47 个脚里救回 **25 个**。
⚠️ 逃逸环半径 **4.0 mm**,不是 2.5:INA226 两排脚之间就有 2.6 mm,
走到 2.5 还在芯片肚子里,主布线器接手照样出不去。
#### 26.14d ⛔ 22 个引脚几何上没有出路 —— 要动板子
| 组 | 焊盘 | 卡在哪 | 缺多少 | 解 |
|---|---|---|---|---|
| **A** | `U1.10`~`U5.10`(Buck 的 `EN`)| §10.2 的 **SW-run 1.5 mm 铜**,圆头端帽从 (20.05, 27.10) 往西探到 x 19.30 | 脚东边净空 0.376,一根 0.2 的线要 0.6 | EN 进 §10.2 母版;`SW-run` 起点东移 ~0.35 mm,或前 2 mm 收窄到 1.2(**收窄反而符合 §10.2-2**)|
| **B** | eFuse 北排 14 个脚(`U14.2/3` `U15.2/3/14/15` `U16.2/3/14/15` `U17.2/3` `U18.2/3`)| 上面 INA226 的焊盘边只隔 **0.33 mm**,下面自己的散热盘 **0.25 mm** | 要 ≥ 0.6,缺 ~0.7 mm | `U8 + Rs101` 在母版里北移 0.7~0.8 mm(唯一的余量在 Rs101 顶 57.73 到通道北界 59 之间的 1.27 mm)|
| **C** | `U10.3`(ALERT) `U13.4`(SDA) `U13.5`(SCL) | 隔壁 GND 扇出孔正对着出线走廊 | **5 µm** | 在 `pcb_fanout._CH_FORCE_LOCAL` 里给那几个孔钉一个偏 0.1~0.2 mm 的位置 |
CH1 那一列从下往上:`C106`(顶 43.46) → `U14`(43.85~47.75) → `U8`(48.08~53.92) → `Rs101`(54.27~57.73),
缝一律 **0.33~0.39 mm**,一点余量都没有。这不是布线问题,是**摆位把走线通道挤没了**。
⚠️ B 组一改就作废**扇出 + 铺铜 + 五路功率级布线**(`U*.9 → Rs*01.1` 的 Kelvin 线也在母版里),
所以**先拍板再动**,别先下发信号布线。
#### 26.14e 剩下 95 条是拥挤 —— 要拆线重布
失败集中在**控制块(U21~U23,x 75~107 / y 43~58)**和 **J24/J25 排针**周边。
现在这个布线器是**一遍过、只加不拆**(这是有意的:板上已有的 691 条线不能被抹掉),
于是先布的网络把后布的堵死。这正是商业布线器用 **rip-up & reroute**(协商式拥塞)解决的那一类。
顺带两条:`POGO2_VUP` / `POGO2_VDN` 离 SW 节点只有 **0.54 / 0.64 mm**(§10.3 要求「远离」,已有校核在报);
8 个 45° 切不动的拐角(转向 89~90°),都在细缝里。
#### 26.14f USB 差分对:一整束布线,再平行偏移
`U20`(ESP32-S3 原生 USB)到调试口 `J22` 有 55 mm。布线器一次只认一根线,
两根各走各的最短路就不再是一对。做法是:按**一整束**的宽度 `2W + S = 0.74` 布一条中心线
(它占的地方和两根并排一模一样),再往两侧各偏移 `(W + S)/2 = 0.23`。
三条要点:
1. **接哪两个脚是算出来的。** Type-C 的 A/B 两面各有一对 D±,J22 南→北是
`B7(DM) 51.250 / A6(DP) 51.750 / A7(DM) 52.250 / B6(DP) 52.751`。
偏移出来的两根线左右关系沿整条路不变,而 `U20` 那边 DP 在 DM 北边
⇒ 只有 **B6/B7** 满足;接 A6/A7 得中途交叉一次。A↔B 两面的短接交给通用布线器。
2. **两端各硬接一段水平引出线。** 不然束的第一段是布线器自己挑的(实测 45° 斜着往东北),
偏移出来的两个端点在 y 上只差 0.32 而不是 0.46,扇入段一走平就压到 0.045。
3. **翻层的两个过孔必须错开 ≥ 1.5 mm。** 0.46 的对内间距下并排打不下
(钻孔到钻孔要中心距 ≥ 0.605,铜到铜 ≥ 0.81)。
结果:束长 58.1 mm,全程底层,**对内偏斜 0.00 mm**(容差 5.0 mm)。
---
### 26.15 五路母版的三处几何整改(2026-09-06 第二十一轮,用户拍板 A+B+C)
§26.14 抓出的 22 个「几何上没有出路」的引脚,在这一轮全部动手改掉。
**三处都改在母版里 = 五路一起改**,改完整条链重跑(摆位 → 扇出 → 铺铜 → 功率级 → 信号)。
#### A. SW 不再往南潜 —— 把 `EN` / `COMP` 的走廊还回来
TPS54622 东侧一列从南到北是 `p9(COMP) 11.001 / p10(EN) 11.501 / p11,p12(SW) 12.001,12.501`
(局部坐标,0.5 脚距)。老版本的 SW 是「先往南潜到 y 11.6,再东行,再 45° 抬回立管」,
为的是从 `C%05.1`(BOOT 焊盘,底 12.732) **下面**绕过去 —— 那里只有 0.581 mm 的缝。
那一潜的 1.5 mm 圆头端帽在 y = 11.5 那一行往西探到 **x 11.007**,
而 COMP 与 EN 两条 0.2 的线要并排出来至少得到 x 11.62 ⇒ **两个脚只能活一个**。
实测就是 COMP 抢到走廊、`EN` 五路全布不通。
解法不是继续挪那 0.1 mm(试过两次,都卡在 5~20 µm 上),而是**换拓扑**:
| | 老版本 | 新版本 |
|---|---|---|
| `C%05`(自举电容)| 局部 (12.4, 13.0) | **(12.4, 13.6)** —— 北移 0.6 |
| SW 东行 | `SW-down` 潜到 y 11.6 → `SW-run` → 45° 抬回 | **`SW-run` 平着走 y 12.500,1.2 mm 宽** |
| SW 到 BOOT 电容 | 45° + 立管顺路盖住 | 立管(x 13.5,1.5 宽 ⇒ 铜跨 12.75~14.25)**顺路盖住 `C%05.2`**,不用单画 |
| `BOOT` | 三段,末段往南扎进焊盘 | 两段,终点直接落在焊盘正中 |
| SW 节点 | 9.6 mm / 10.9 mm² | **8.9 mm / 9.4 mm²**(§10.2-2 要它小,所以这是**改好了**)|
`C%05` 北移之后 BOOT 焊盘底 13.332,SW 那条 1.2 宽的线顶 13.10 ⇒ 净距 0.232。
`y < 11.9` 整片空出来:COMP 走 y 11.001、EN 走 y 11.501,各走自己那一行。
⚠️ 途中踩到的一条:`SW-run` 起点原本放 11.200,它 1.2 mm 宽的**西端圆头端帽**
(半径 0.6)离 `U%1.13`(BOOT 引脚) 焊盘只有 **0.080**。把 `SW-p12` 的短桩往东多走 0.3、
起点改 11.500 之后是 0.347。**「端帽比端点往外探半个线宽」这一条本轮又踩了两次**(§26.11)。
#### B. `U%8`(INA226) + `Rs%01` + `C%13` 整体北移 0.8 mm
eFuse 北排焊盘顶 47.75 到 INA226 南排焊盘底 48.08 **只隔 0.33 mm**,
一根 0.2 的线要 0.6 ⇒ `U14`~`U18` 北排 14 个脚一个都出不来。
这一列从下往上是 `C%06`(顶 43.46) → `U%14`(43.85~47.75) → `U%8`(48.08~53.92)
→ `Rs%01`(54.27~57.73),缝一律 **0.33~0.39 mm**;唯一的余量是 `Rs%01` 顶到
J24 焊盘底(60.33)之间的 **2.60 mm**(CH2/CH3 那一侧是 3.10 mm)。
北移 0.8 之后 eFuse 那条缝 **0.33 → 1.13 mm**,`Rs%01` 到 J24 还剩 1.80 mm。
⚠️ 跟着一起改的三处(漏一处就是静默失效):
- `pcb_fanout._CH_FORCE_LOCAL[('U%__8','1')]`:33.896 → **34.696**
- `pcb1_route_pwr` 的 `F-trunk` 北端:39.300 → **40.100**
- `pcb1_route_pwr` 的 `K-IN+` / `K-IN−`(Kelvin 四线):整体 **+0.8**
#### C. 效果
`pcb1_escape_audit.py` 实测「几何上出不去」的焊盘:**22 → 8**。
剩下 8 个(`U13.2` 与 CH2/CH3/CH5 的几个 eFuse 脚)是**和邻脚预留出线段抢地方**,
不是硬几何 —— 单独布它们都能通,布线器换出线方向重试还有机会。
#### D. 顺带修好的一个**校核假阳性**
`pcb1_route_pwr.verify()` 原来要求「被**同宽**的实测线盖住」。
一段窄线整个落在一条宽线的圆头端帽里时,EasyEDA 会把它**直接吞掉** ——
铜一点没少,回读却报 5 条对不上。判据改成「实测线不窄于计划线,且中心距 ≤ (o_w − p_w)/2」。
#### E. 整改之后的两处**铺铜**连带修改(信号布线把电源面啃窄了)
信号布线下发之后重铺,`pcb1_pour.py` 当场拦下两条 —— 都不是铺铜算错,是**布线动了平面**:
1. **Inner2 中桥 @南出口 y=35 被啃到 5.00 mm**(要 6.04 mm / 3.6 A)。
三个异网信号过孔的反焊盘把这一行切成 1.50 / 0.75 / 5.00 三段。
⇒ 把 `12V-SW+BR` 的南出口在 **y 34~40.7 加宽到 x 54**(再往上 y 41 起是 `3V3-SW`,要留 0.2)。
实测这一行变成连续 **18.25 mm**。
⚠️ 原来那个 61.5 的西边界注释写着「躲开 R706/R707 的 0402 焊盘」——
**贴片焊盘对内层是透明的**,那条约束本来就不存在。
2. **Inner2 上一块 0.3 × 14.5 mm 的浮铜**(7.3 mm²,y 65.5~80)。
它是 GND 底填卡在 `12V-SW+BR`(东界 72.0)和 `3V3-SE`(西界 73.0)之间那 1.0 mm 里,
两边各让 0.2 之后剩 0.6,填出来 0.3 宽、**里面一个 GND 落脚点都没有**。
⇒ 把 +12V 的东界推到 **72.6**,缝就没了(离 3V3-SE 还有 0.4)。
#### F. 又一个「包围盒当几何用」的假阳性
`pcb1_pour.obstacles()` 为了省事把每条走线折成**轴对齐包围盒**——
板上只有扇出的正交短线时无所谓,信号布线一上来有两千多条 45° 斜线,
**一条长斜线的包围盒必定罩住半块顶层铜** ⇒ `check_top_clearance` 报
「VINRAW-TOP 侵入 0.000 mm」「VINSW-TOP 侵入 0.000 mm」,真实净距其实好几毫米,
而且它**拦下了整次重铺**。
⇒ 新增 `poly_seg_gap()`,走线一律按**真实胶囊**算;过孔仍用包围盒(对圆形够准)。
这已经是本项目第三次栽在「拿包围盒当几何」上(前两次:POLYGON 焊盘的 `hole`、POLYGON 焊盘的 w/h)。
#### G. 最终状态(全部已下发并按实测铜回读)
| | 会话开始 | 现在 |
|---|---|---|
| 板上 | 342 件 / 495 孔 / 691 线 / 15 铜面 | 342 件 / **942 孔** / **2951 线** / 15 铜面 |
| 还欠的连接(按实测铜自算)| 384 | **91**(147 个网络全通 / 75 个还碎)|
| DRC | 间距 0 / 连接性 594 | **间距 0 / 物理 0** / 连接性 **182** |
| 几何上出不去的引脚 | 22 | **11** |
| 五路 SW 节点 | 9.6 mm / 10.9 mm² | **8.9 mm / 9.4 mm²** |
信号布线本轮下发 **2305 段线 + 444 个过孔**,总长 6617 mm;
Kelvin 3 条、USB 差分对 1 对(对内偏斜 0.00 mm)。
**已知偏差(写在这里,不是遗漏)**:
- **19 个切不动的 90° 拐角**,全在 0.5 脚距的逃逸段里。`chamfer45` 半径试到 0.05
仍撞邻脚 —— 属于「这一处通道宽度物理上不允许」,不是没切。
- `POGO2_VUP` / `POGO2_VDN` 离 SW 节点 0.54 / 0.74 mm(§10.3 要「远离」)。
`pcb1_route_sig.sw_keepaway()` 会一直报,当提示不当错误。
- 剩下 91 条连接是**拥挤**(控制块 U21~U23 与 J24/J25 排针周边),不是没路。
这个布线器一遍过、只加不拆,先布的把后布的堵死;再往前要 **rip-up & reroute**。
---
### 26.16 拆线重布 + 两处换件 + 控制块按几何重排(2026-09-06 第二十二轮)
这一轮做了四件事,**结尾把板上的铜全清了**,摆位重来一遍。
#### A. 信号布线器加了拆线重布(`pcb1_route_sig.py --ripup`)
§26.14 剩下的 91 条布不通几乎全是「拥挤」而不是「没路」—— 单独布每一条都通。
做法:一条连接在「换出线方向」和「放回队尾再等一轮」都失败之后,才去拆挡路的
**本脚本自己下发过的**铜,重算,再把被拆的按原端点布回去;任何一步失败整个回滚。
扇出 / 功率级 / 铺铜 / 焊盘一律不动;Kelvin 三条和 USB 差分对按**几何**钉死不许拆
(`rip_pool()`:路径上有点落在 `FORCE` 表点名的焊盘里就不许拆 —— 光看键名不行,
从下发记录反推出来的键是 `netpN`,`FORCE:` / `usb` 前缀一个都不剩)。
单网验证过:`EDL_EN2` 原来布不通,拆 9 条子链 + 重布之后通了,净距/钻孔/铺铜全 0。
**全量那一跑没跑完就被这一轮的摆位重排作废了**,代码留着,重布线时直接用。
##### ⭐⭐ 建它的过程里抓到三条,每一条都真的把一次尝试搞砸过
**1. `clean()` 一直只删得掉自己 59% 的铜。**
它按「网络|层|两端点|线宽」精确比对认自己画的线,而 EasyEDA 会把共线相接的**并成一条**、
在 T 形接点上把线**劈成两条**(§26.13 第 4 条踩过一次)。实测 2305 段计划里只有
**1351 段**能在板上找到坐标完全一样的线 —— 按精确比对删,41% 的铜留在板上而记录里
已经没有它,**从此没人认领**。
⇒ 判据改成**覆盖**:板上这条线的中心线整条贴在同网同层同宽的计划线上(≤0.02 mm)。
实测 2951 条里 2277 条整条落在计划里、**0 条只落一半**,过孔 444 个全部对上。
`clean()` 同时加了 `--force-clean` 闸:这个布线器是增量的,一刀全删会把已布通的几百条抹掉。
**2. 一条 `--net EDL_EN2` 的空跑,把 700 条路径的计划缓存清成了 `{}`。**
`_pcb1_sig_plan.json` 是**无条件**写的,`--net` / `--limit` 的试水也照写不误。
⇒ 归属表改成从 `_pcb1_sig_routes.json`(**只在 `--push` 时写**,是板上那些铜唯一可靠的账本)
按铜的连通图**反推**路径:端点建图、过孔是连上下两层的一条边、度 ≠ 2 的点断开,
拆成一条条极大链,**再逐条回验**「重新 `expand()` 之后和账本一模一样」。
同时给 `--net` / `--limit` 加了闸,不许覆盖缓存。
(反推顺带踩到:账本里有 2 条 **0.1 µm** 长的线段,是 `_snap_end` 把端点拽向焊盘中心
留下的数值毛刺;1 µm 的节点栅格上它们是自环,对账时要按长度剔掉。)
**3. ⭐「两个端点钉死 ⇒ 连通性不变」这条不变量是破的。**
`KEY_RCLK` 三条链里,两条的起点 (83.70,52.30) / (84.70,61.00) 正落在第三条链
**某一段的中间** —— 当初布线器就是奔着「已有的那坨铜」去的,终点落在它的**铜里**
而不是它的端点上。按端点重布,那两条当场挂空。
⇒ 先按**搭接点**把链切开(别的链的端点、同网焊盘、非本脚本的线端/过孔,投影到链上切一刀),
切完每一处搭接都是某条子链的端点。实测 409 条链切成 **797 条(388 刀)**,铜一点没动。
另外拆完必须用 `pcb1_netlist.analyze()` 按实测铜重算受影响网络的碎片数,**不许变多** ——
上面这个坑,栅格 / 净距 / DRC **三样都看不出来**,就是靠这一步抓到的。
还有两条一起做的:**共享铜要连坐**(2277 条属于本脚本的线里 401 条同时落在相邻两条路径上,
只拆一条会「归属没落全 ⇒ 删不掉」,而它已经不在计划里 ⇒ 下一轮算成「不是我画的」,
永远拆不动也删不掉);**一轮里同一条只拆一次**(没有拥塞代价函数,反复拆会来回震荡)。
#### B. ⭐⭐ 本体框有第二个来源了 —— §26.6 那句话是错的
§26.6 写着「板边连接器的本体框,除了实测没有别的来源」。**这条是错的**,只是当时没找到路子。
`lib_Device.search()` 回来的 `otherProperty['3D Model Transform']` 是一串逗号分隔的数:
v[0], v[1] = 3D 本体的 X / Y 尺寸(mil)
v[6], v[7] = 本体中心相对**封装原点**的偏移(mil)
拿六个当年用放大截图量过的封装交叉验证,**全部对上,误差 ≤0.31 mm**(就是截图标定的精度):
| 封装 | 3D 算出的 y 向框 | 当年截图实测 |
|---|---|---|
| `CONN-TH_KF2510-3A-1` | −0.31 .. +11.70 | −0.20 .. +11.70 |
| `CONN-TH_P5.08_KF128-5.08-2P` | −5.31 .. +5.38 | −5.20 .. +5.20 |
| `USB-C_SMD-TYPE-C-31-M-12_1` | −5.05 .. +2.85 | −5.20 .. +3.12 |
| `WIRELM-SMD_ESP32-S3-WROOM-1` | −9.10 .. +16.40 | −9.35 .. +16.75 |
| `IND-SMD_L7.1-W6.5` | −3.25 .. +3.25 | −3.35 .. +3.35 |
| `CAP-TH_BD8.0-P3.50-D0.6-FD` | −4.00 .. +4.00 | −4.10 .. +4.10 |
已固化成 **`.claude/fp_body.py`**(`--scan <关键词>` 选型 / `--check` 对账整张 `FP_BODY`)。
⚠️ 它只给 XY,**Z(高度)读不出来**,高度仍然只能查规格书或量实物。
⚠️ 没有 3D 模型的器件读不出来,那种还是得截图。
**立式 / 弯针一眼分得出**:同一个 3P 2.54 端子座,立式本体 ≈ 7.6 × 6 且偏移 ≈ 0;
弯针 ≈ 7.6 × 12 且偏移 ≈ ±5.7。**名字完全不可靠** —— `KF2510-3A`(C2940511) 名字像直针,
数说它是弯针(+5.69);`KF2510-3AW`(C457341) 也是弯针,只是甩向 −Y。
#### C. 两处接口换件(用户拍板)
| | 旧 | 新 | 立创 | 本体 |
|---|---|---|---|---|
| J1 12V 输入 | `KF128-5.08-2P` 螺钉端子 | **`XT30PW-M`** | C53373776 | 13.30 × 13.95,框 (−6.65,−7.98,6.65,5.97) |
| J26~J30 风扇 | `KF2510-3A`(弯针)| **`2510-3A(直针)`** | C2803349 | 7.62 × 5.81,框 (−3.81,−2.88,3.81,2.93) |
⚠️ **用户原话是「3.5 mm DC 接口」,那个规格接不了这块板。** 12V 输入是 **8 A**
(五路 4A × 4.2V ÷ 0.92 ÷ 12V ≈ 7.6 A,加风扇 0.7 A),而 DC-002 一类(外径 3.5 / 内径 1.35)
**额定只有 0.5~1 A**,差了近一个数量级 —— 接上去会烧插座。用户改选 XT30(主脚额定 20 A)。
选 **2 脚版**而不是 (2+2):多出来那两脚是 **1 A 信号脚**,用不上,而且库里读不出 pin 语义;
2 脚版符号的引脚名**直接写着 `+` / `−`**。导入后实测焊盘证实:p1/p2 是 **2.5 mm** 大焊盘、
针距 **4.999 mm**(XT30 标准 5.0),p3/p4 只有 1.8 mm,确实是机械固定脚(**不接网络**,
已进 `.claude/p1-nets-nc.json`)。
两处换件都做到了**一根导线不动**:J1 原位 (120,705) rot 180 时新符号 p1/p2 与旧件完全重合;
风扇座元件东移 5 到 x=1085,抵消引脚偏移(−20 vs −15),引脚绝对坐标不变。
脚本 `.claude/p1p6_conn.py`(试跑会自己把试建的新件删回去 —— 「先 create 后 delete」
意味着断言那一步已经把件建到页上了,不收尾就会留下一堆重叠件)。
##### ⚠️ 立式风扇座的代价:装配顺序被锁死(2026-09-06 用户拍板接受)
弯针座是从**板边水平**插拔,13 mm 两板净空完全不碍事;立式插口朝上,正对载板底面。
座子 + 胶壳总高约 11.5 mm,**装得下**,但插拔只剩 1.5 mm 余量,手伸不进去
⇒ **装配顺序必须是「先插好五根风扇线,再合上载板」**,以后换风扇线要拆载板。
换来的是每个座省 **6.2 mm** 进深(12.01 → 5.81)。
⚠️ `H_FP` 里这两个高度(XT30 11.0 / 直针座 9.0)是按同系列常规取的**保守估计**,
`3D Model Transform` 给不出 Z —— **打样前必须拿实物量**(§12)。
#### D. 控制块从「按原理图仿射」改成「按连接几何」
`affine(['P3-CONTROL','P3B-EXPAND'], 73, 34, 42, 22)` 是把两页的**原理图坐标**线性映射到
板上一块 42 × 22 —— 保的是「原理图上挨着的板上也挨着」,和「谁连谁」没有半点关系。三条后果:
1. 焊盘框总面积只有 253 mm²,却全挤在 924 mm² 里(**填充率 27%**),而 S-M 块可用 50 × 58 ——
`y 0.5~32` 大片空着,而 §26.14 那 91 条布不通正好集中在 U21~U23 周边。
2. **U22 和 U23 放反了**:U22 只服务 CH3/CH4/CH5(理想 x≈105)却待在 79.6,
U23 服务五路全部(理想 x≈78)却待在 103.7。
3. U21(79.61,56.00) 与 U22(79.61,47.96) 中心只隔 **8.04 mm**,两个 SOIC-16 的焊盘框
(7.44 高)之间只剩 **0.6 mm** —— 一根线都插不进去。
⇒ 新增 **`.claude/pcb1_ctrl_place.py`**:五颗芯片退火求位置,目标 HPWL,
**预留框故意开得比「本尊 + 附属件」还大,多出来那一圈就是走线通道**
(只按占地摆的话,退火会把它们贴在一起去换那几毫米线长)。结果钉进 `pcb1_place.CTRL`:
U21 (92.25, 52.37) U22 (92.84, 38.01) U23 (76.50, 49.63)
U6 (79.58, 38.01) U7 (109.57, 34.71)
最近的两颗现在隔 14.4 mm。**不再 relax** —— relax 只管不重叠、不管通道,会把它们重新推回一起。
##### ⭐ 顺带抓到的真错:USB-C 的 CC 下拉电阻在 77 mm 外
22 个附属 R/C 改成逐个贴到**真正的对端引脚**(`pcb1_place.SAT` 表,每颗带上限,`check()` 硬校核)。
其中最要紧的一条:**`R602` / `R603` 是 Type-C 的 CC1/CC2 下拉 5.1k**,按 affine 摆在
(77.2,33.2)/(76.4,36.8),而 J22 在 (154.4,52) —— **离了 77 mm**
(`$3N203` / `$3N204` 那两条 77 mm 的网络就是它们)。CC 是角色检测线,下拉必须贴着座子。
现在 **1.3 mm**。这和 §26.16-A 那颗「ESP32 储能电容在 48 mm 外」是同一类:
不重叠、不越框、高度也够,**几何检查一条都报不出来**,纯粹是电学上错了。
全板 HPWL **9416 → 8935 mm**。⚠️ 控制块**位置**本身只贡献 4% ——
U23 单颗管五路,往西省 CH1/CH4 就在 CH3/CH5 上赔回来,是**零和**的;
真正的收益来自这些「贴身」修正。(想再进一步得改**通道分配**:U6 现在管 CH1/CH2/CH3,
而 CH1 在 x 17、CH3 在 x 139,`VDAC3` 因此拉了 93.8 mm;按几何应该是「U6 管左边、U7 管右边」,
595 的按键位同理,估计再省 ~300 mm。**这要改原理图,还没做。**)
#### E. J1 换 XT30 之后 N-L 块重排
`CONN-TH_XT30PW-M` 插口在 −Y 端 ⇒ 要它朝左板边就得 **rot 270**,转过来往 −X 伸 7.98。
放在 x=8.5 时框 (0.52,64.85)-(14.47,78.15),**原来 F1 的位置 (14.5,71.5) 正好被吃掉**;
而东边的墙是硬的:北排 CH2 从 **x 29.6** 起,D1(SMB) 再往东就撞上去。
J1 东边只剩 15 mm 要放 F1/Q1/D1/DZ1/C1/R1 六件,一行排不下 ⇒ 改**两行**,
C2/C3 罐与 R9A~R9E 整列北让(J24 排针顶到 y 65.04、C2/C3 原来从 77.9 起,
中间只有 12.8 mm 而 J1 要 13.3)。
摆位已下发:**342 件**,本地检查全过,J24/J25 各 40 个焊盘逐个网络对上载板。
截图 **`PCB1-v11-place.png`**(只开通孔焊盘 + 丝印)。
#### F. 板上的铜全清了
摆位大改之后,2951 条走线 + 942 过孔 + 15 块铺铜全部按旧坐标算的,元件挪走了它们
**不会跟着动** —— 已经是废铜,而 DRC 只会报「连接性错误」,看不出「这些铜已经作废」。
`.claude/pcb1_wipe.py --push` 清空:删 **layer 1/2/15/16** 四个铜层的线 + 全部过孔 + 全部铺铜,
元件/板框/丝印不动,删完核对元件数不变(342 → 342)。
⚠️ **顺带查实:板框根本不是 `pcb_PrimitiveLine`。** 板上 2951 条线**全部在 layer 1(2298) / 2(653)**,
layer 11 一条都没有(API 的 Line / Arc / Region 里都找不到板框)。
所以 `pcb1_pour.py` 里那句 `if (l.layer === 11) continue; // 11 = 板框` 是**死代码**;
`pcb1_wipe.py` 没沿用它,判据改成**铜层白名单**。
清空时把 13 个旧账本改名成 `.stale`(`_pcb1_sig_routes.json` / `_pcb1_sig_plan*.json` /
`_pcb1_poured.json` / `_pcb1_todo.json` / 五个 `_fanout_plan_*.json` …)——
留着的话下一轮的归属表会拿旧账本去认板上的新铜。
---
### 26.17 ⚠️ v11 的两行排法把 8 A 输入链卡死了(2026-09-06 第二十三轮,已修)
§26.16-E 把 J1 换成 XT30 之后,N-L 块改成了两行。摆位的本地检查(不重叠 / 不越框 /
不压定位孔 / 高度预算)**六项全过**,可是回到 §26.11 去重算顶层宽铜的多边形时,
第一刀就下不去 —— **`VIN_RAW` 从 J1 出来根本没有 3.49 mm 的路**。
#### 为什么卡死:XT30 rot 270 之后 GND 在北、VIN 在南
| 焊盘 | v11 坐标 | 说明 |
|---|---|---|
| `J1.1` GND | (13.5, 74.5) Ø2.5 通孔 | 北针 |
| `J1.2` `$1N223` | (13.5, 69.5) Ø2.5 通孔 | **南针 = 8 A 入口** |
| `F1.1` | (16.06, 74.5) | F1 卧着放,和 **GND 针同一行** |
| `D1.1/D1.2` | (17.5, 71.86 / 67.14) | 正堵在 J1.2 与 F1.1 之间 |
于是 8 A 要从南针绕到 GND 通孔**东侧**再往北爬。实测通道宽度:
GND 焊盘(圆心 (13.5,74.5) r 1.25)到 D1.1 西北角 (16.404, 72.884) 的距离
√(2.904² + 1.616²) = 3.324,减掉 r 1.25 = **2.074 mm**,两边各让 0.2 之后
只剩 **1.674 mm** —— 1 oz 外层 ΔT=20 °C 下约 **4.5 A**,而这里要 8 A。
> **这一类错误几何检查一条都报不出来**:元件不重叠、不越框、高度也够。
> 抓到它的是「照着新坐标重画 §26.11 的多边形」这个动作本身。
> ⇒ **摆位改完不能只看本地检查,必须把顶层宽铜的多边形重推一遍**,
> 推不出 3.49 mm 就是摆位错了,不是铜画错了。
#### 三处改动(都在 `pcb1_place.py` 的 N-L 表里)
| # | 改动 | 拿回了什么 |
|---|---|---|
| ① | **`F1` 卧 → 竖**(rot 0 → **90**),(17.5, 74.5) 不动 | `F1.1` 落到 (17.5, **73.06**),正对 J1.2 那一片空地;`F1.2` 到 (17.5, 75.95) 朝北接 Q1 |
| ② | **`D1` (17.5,69.5) → (31.0, 74.5)** rot 270 | 通道里最后一个障碍搬走;TVS 贴到漏极铜的东缘,离 Q1 漏极 2.1 mm |
| ③ | **`C4/C5/C6` x 25 → 30.5,rot 0 → 180** | 让出 y 78.85~83.5 那条 **4.64 mm** 的西行干道;rot 180 让 `$1N236` 脚朝西迎着漏极铜、GND 脚朝东好打孔 |
⚠️ ①的关键在于**换了个方向就不用绕了**:F1 竖过来之后,`VIN_RAW` 从 J1.2 出来
一路向北偏东,GND 通孔只需要一个台阶就躲开,颈部净宽 **3.50 mm**(要 3.49)。
"挪 0.1 mm 解决不了拓扑问题"(§26.15 那一条)反过来也成立:
**转 90° 常常比挪 5 mm 更有用**。
⚠️ ③还有一层:v10 的干道走 y 76~80.95,而 XT30 的**机械固定脚 `J1.4` 在 (3.5, 77.5)**,
Ø1.8 无网络通孔,占到 y 78.4。干道被迫整体北提 2.8 mm 到 **y 78.85~83.49**,
上边界又被 C2/C3 两颗罐的通孔(底 83.7)压住 ⇒ 净宽从 4.95 掉到 **4.64 mm**(能带 10.0 A)。
#### 顶层三块宽铜重画后的实测断面(1 oz,ΔT=20 °C)
| 位置 | 连续铜宽 | 能带 | 要 |
|---|---|---|---|
| **RAW J1→F1 颈(y=73.4)** | **3.50 mm** | **8.0 A** | 8 A |
| RAW J1.2 东出(x=15.5)| 8.25 mm | 14.9 A | 8 A |
| FUSED F1.2→Q1 源极(x=19.5)| 5.25 mm | 10.8 A | 8 A |
| SW Q1 漏极北出(y=77.5)| 6.75 mm | 12.9 A | 8 A |
| **SW 干道(x=12 / x=24)** | **4.75 mm** | **10.0 A** | 8 A |
| SW 干道拐北(y=84)| 5.25 mm | 10.8 A | 8 A |
| **SW 北柱 @Rs6.1(y=92)** | **5.25 mm** | **10.8 A** | 8 A |
面积 59 / 30 / 263 mm²,各自 **1 个连通域**,`check_top_clearance()` 零侵入。
```
y 95.4 ┌───┐ 北柱到 Rs6.1 为止(再往北是 U13 的 Kelvin 脚)
│北 │
y 86.5 │柱 │ ┌─┐ 右边那条是 C4/C5/C6 去耦指(x 28.6~30.47)
y 85.5 ├───┤ ┌──┐ │ │ C3 口袋
y 83.5 │ └─┤C3│───┴─┴──┐
y 78.85└─────┴──┴────────┤ ← 8 A 西行干道 y 78.85~83.49(净 4.64 mm)
┌────┴──┐ Q1 漏极块 + D1(TVS)
y 73.45 ┌──┐ │ │
y 73.0 ┌────┤F1├───┤ │ ← FUSED 在 F1 与 Q1 源极之间
y 65.4 └────┴──┴───┘ └
x1.5 x15 x19.6 x25.6 x32.3
```
#### 顺带抓到的一个**静默失效**:Rs6.2 一个过孔都没打
`12V-N` 那块 Inner2 平面为了让开 U13 的 Kelvin 脚,在西边咬了一个缺口
`(0.5,93.0)-(12.5,101.5)`。而 **`Rs6.2` 的焊盘是 (8.93~10.21, 91.77~95.23)**,
中心 (9.57, 93.50) **正落在缺口里** ⇒ 扇出判定「这颗不在铜面上」,
于是**全板唯一的 8 A 源不接电源平面**,96 个 +12V 过孔里一个都不在它旁边。
- 失效是静默的:`--push` 报「放下 95 个过孔,失败 0 个」,一切正常;
- 连接性 DRC 也不会响 —— +12V 平面靠别的 55 个焊盘照样连通,
只有 Rs6.2 这一端是断的,而它恰好是**源**。
缺口收成 `(0.5,95.6)-(12.5,102.4)`,只罩住 U13 的十个脚(96.08~101.92)与 C11。
重跑扇出:+12V 焊盘 55 → **56**、过孔 95 → **98**,Rs6.2 拿到 3 个孔。
⚠️ 这三个孔的引线是 **1 mm 宽**、朝**西**甩出去的,
`(8.975,94.397)-(7.401,94.397)` 带圆端帽往西探到 x **6.901**
(端帽 = 端点 ± w/2,§26.11 那一条第三次踩到)。
`VINSW-TOP` 的北柱东边界因此从 7.22 让到 **6.65**(净宽仍有 5.15 mm)。
#### `C606.1` / `R608.1`:不是漏掉,是两块内层平面都够不着
v11 控制块退火重排之后,这两颗落到 x 71.87~72.41 ——
正好是 `12V-SW+BR`(东界 72.6)与 `3V3-SE`(西界 73.0)中间那 0.4 mm 的缝里。
**贴片焊盘对内层是透明的,所以这不是错误**;已写进 `ROUTED_PADS`:
`C606.1` 紧贴 `U23.24`(0.3 mm,去耦回路本来就该这么短),
`R608.1` 沿 U23 西缘走 6 mm 顶层线搭到 `C606.1`。
#### ⚠️ `pcb1_route_pwr.py --push --verify` 是**只 verify**
`main()` 里 `--verify` 在 `--push` 之前 `return`。PROGRESS 上一轮写的那条命令
(`--push --verify`)实际上一根线都没下发,而它照样打 `✅ 全部校核通过`,
只在最后一行的回读里露馅:「195 段里没被实测铜盖住的 **195** 条」。
**要下发就只写 `--push`**(它自己会回读)。
---
### 26.18 ⭐ 按 PCB 几何重排三组引脚(2026-09-06 第二十三轮,用户拍板)
**「哪个信号落在哪个物理脚」在这块板上有三处是自由的**,而这三处原来全是按
**逻辑顺序**排的(EFUSE_EN1→IO4、EN2→IO5……VDAC1→U6 通道 0、K1→U21 的头三位),
和它们在板上要去哪儿**一点关系都没有**。
| 组 | 为什么可以随便换 | 换脚要改什么 |
|---|---|---|
| **ESP32-S3(U20)22 个信号** | 除 `USB_DM/DP`(IO19/IO20 是 USB PHY 硬连线)与两路 NTC(要 ADC1 = IO1~IO10)外,**全部走 GPIO matrix** —— I²C、LEDC(FAN_PWM)、PCNT(FAN_TACH)、普通 GPIO 都不挑脚。IOMUX 直连只在 >40 MHz 的 SPI/LCD 上才必须,这块板一根都没有 | 原理图上的网络标签 + 固件里的引脚号 |
| **DAC63204 ×2 的 5 个通道** | 四个通道完全对等 | 标签 + 固件通道号 |
| **74HC595 ×3 的 21 个位** | 三片串成一条 24 位链,谁在哪一位只是移位的字节序 | 标签 + 固件位序 |
#### 目标函数:绕开芯片本体的直角最短路,不是 HPWL
`.claude/pinmap.py` / `reassign.py`:代价 = 从**出线点**(焊盘往芯片外挪 1.7 mm)
到本网最近焊盘的**绕障直角最短路**,再跑匈牙利算法求最小总和。
**HPWL 量不出「东边的脚要去西边」有多贵** —— 那根线得先往北爬出模块、
再横穿 17.5 mm 的封装宽度,而且同向的几根会一起挤在同一个拐角上。
实测两个指标的差别:同一批改动 HPWL 只说省 7%,绕障路长说省 15%。
#### A. ESP32-S3:放开 IO39~IO42,西边从 4 个坑变 8 个
原来 22 个信号**正好塞满** 22 个可用脚(东 9 / 北 9 / 西 4),一点腾挪余地都没有,
而 `EFUSE_EN1`(去 CH1, x 21)、`EFUSE_EN2`(x 47)、`EFUSE_EN4`(x 53) 三条去西半板的线
偏偏都在**东边**,得整条绕过模块。
瓶颈是西边只有 IO38 / IO44 / IO2 / IO1 四个脚,而 **IO39~IO42 被 §8.1 留给了引脚 JTAG**。
用户 2026-09-06 拍板放开:
> 调试口本来就走 **ESP32-S3 原生 USB-Serial-JTAG**(IO19/IO20 → J22),出厂 eFuse
> 默认选的就是它;板上没有 JTAG 排针,也没打算烧 `JTAG_SEL_ENABLE` / `DIS_USB_JTAG`
> 把 JTAG 切到引脚上。留着这 4 个脚 = 在**最缺位置的西边**空放 4 个坑。
>
> ⚠️ 让出去的是**兜底**:固件把 IO19/20 改成普通 GPIO、或跑到 USB 外设起不来的地方挂死时,
> 引脚 JTAG 还能进去,USB JTAG 进不去。另外**永远别烧 `DIS_USB_JTAG`**,烧了两边都没有。
> IO39~IO42 在 S3 上**不是 strapping**(S3 的 strapping 只有 IO0/IO3/IO45/IO46),
> 复位期间是高阻输入,配合目的地那边的 100 kΩ 下拉,上电全关的行为一点没变。
**结果:绕障路长 1195 → 1020 mm(−15%),挪 12 个脚,绕模块的线 3 根 → 0 根。**
| 模块脚 | GPIO | 边 | 信号(新)| 原来是 | 路长 |
|---|---|---|---|---|---|
| 6 | IO6 | 东 | `EFUSE_EN3` | 同 | 94 |
| 8 | IO15 | 东 | `SCL` | 同 | 1 |
| 9 | IO16 | 东 | **`FAN_TACH`** | KEY_SER | 68→61 |
| 10 | IO17 | 东 | **`VBUS_EN5`** | KEY_SRCLK | 54→51 |
| 11 | IO18 | 东 | **`FAN_PWM`** | KEY_RCLK | 66→60 |
| 12 | IO8 | 东 | `EFUSE_EN5` | 同 | 48 |
| 13/14 | IO19/IO20 | 东 | `USB_DM`/`USB_DP` | 同(**硬连线,动不了**)| — |
| 17 | IO9 | 北 | **`KEY_RCLK`** | VBUS_EN1 | 24→13 |
| 18 | IO10 | 北 | `VBUS_EN2` | 同 | 63 |
| 19 | IO11 | 北 | `VBUS_EN3` | 同 | 95 |
| 20 | IO12 | 北 | **`KEY_SRCLK`** | VBUS_EN4 | 24→18 |
| 21 | IO13 | 北 | **`KEY_SER`** | VBUS_EN5 | 44→29 |
| 22 | IO14 | 北 | `SDA` | 同 | 1 |
| 23 | IO21 | 北 | `KEY_OE#` | 同 | 19 |
| 24 | IO47 | 北 | **`UP_VBUS_DET`** | FAN_PWM | 86→78 |
| 25 | IO48 | 北 | **`EFUSE_EN2`** | FAN_TACH | 112→81 |
| 31 | IO38 | 西 | `IOEXP_INT#` | 同 | 30 |
| **32** | **IO39** | 西 | **`EFUSE_EN1`** | 原 JTAG MTCK | 107→**72** |
| **33** | **IO40** | 西 | **`VBUS_EN1`** | 原 JTAG MTDO | 97→**83** |
| **34** | **IO41** | 西 | **`EFUSE_EN4`** | 原 JTAG MTDI | 72→**40** |
| **35** | **IO42** | 西 | **`VBUS_EN4`** | 原 JTAG MTMS | 90→**81** |
| 38 | IO2 | 西 | `NTC2`(ADC1_CH1)| 同 | 1 |
| 39 | IO1 | 西 | `NTC1`(ADC1_CH0)| 同 | 1 |
**空出来的脚**:IO4 / IO5 / IO7(脚 4/5/7,**三个都带 ADC1**)与 RXD0/IO44(脚 36)。
比原来的「一个不剩」宽裕多了。
> ⚠️ 这一版把 `EFUSE_EN2` 放到了 **IO48**。WROOM-1 模组上 IO48 是普通 GPIO
> (板载 RGB 灯是 DevKitC 的事,模组上没有),复位高阻 + 目的地 100 kΩ 下拉,安全。
#### B. DAC63204:纯置换,一根线都不用新画
`VDAC3` 原来挂在 **U6 的 OUT2(西侧脚)**,而 CH3 在板子的**东北角 (141,105)** ——
131.9 mm,是全组最长的一条。按几何重排:
| 通道 | 新 | 原 | 路长 |
|---|---|---|---|
| U6.OUT2(**西**侧)| `VDAC1` → CH1 (15,21) | VDAC3 | 85→78 |
| U6.OUT0(东)| `VDAC2` → CH2 (53,105) | VDAC1 | 97→96 |
| U6.OUT1(东)| `VDAC4` → CH4 (47,21) | VDAC2 | 80→**53** |
| U7.OUT0(东)| `VDAC3` → CH3 (141,105) | VDAC4 | 132→**98** |
| U7.OUT1(东)| `VDAC5` → CH5 (126,21) | 同 | 27 |
**422 → 352 mm(−17%)。** 特意只在**已经画好线的那 5 个通道**里置换 ——
动用 U6.OUT3 / U7.OUT2 / U7.OUT3 还能再省 6 mm,但要新画 OUT/FB 两根线,不值。
⇒ U6 = 0x4A 管 VDAC1/2/4(都去西半板),U7 = 0x4B 管 VDAC3/5(都去东半板)。
#### C. 74HC595:每路三键必须成束
原来 U21 管 CH1/CH2/CH3 的头 8 位、U22 管 CH3 尾 + CH4/CH5 + HUB_RST、U33 管 5 路 EDL。
问题是 **U21 在 y≈50 却要去够 y 87~94 的 CH2/CH3**,而 **U33 就在 y≈70**、正对它们。
约束加了一条:**每一路的 3 个按键必须落在同一片的连续三个南脚上**(`QB~QH` 的滑动窗口),
这样三根线出芯片就是一束,不各走各的。代价是比自由指派多 40 mm,换来的是布线可读。
| 芯片 | 位置 | 新的位分配 |
|---|---|---|
| **U21**(y≈50)| 中 | `QA`=EDL_EN4 / `QB QC QD`=**K1** / `QE` 空 / `QF`=EDL_EN5 / `QG`=EDL_EN3 / `QH`=EDL_EN2 |
| **U22**(y≈35)| 南 | `QA` 空 / `QB QC QD`=**K4** / `QE` 空 / `QF QG QH`=**K5**(VDN/VUP/PWR)|
| **U33**(y≈70,在 P6 那一页)| 北 | `QA`=EDL_EN1 / `QB QC QD`=**K2** / `QE QF QG`=**K3** / `QH`=HUB_RST |
**1286 → 1141 mm(−11%)。** 单条改善最大的几个:
`HUB_RST` 56→29、`K3_VDN` 76→50、`K2_VUP/VDN` 各 −23、`K3_PWR` 72→54。
> U33 从「EDL 专用片」变成「北边那一片」,页面语义确实乱了一点
> (CH2/CH3 的按键网络现在出现在 `P6-FAN-EDL` 上),但三片本来就是一条链,
> 功能上没有区别,而几何上 U33 就是离 CH2/CH3 最近的那一片。
#### 落地:端口只能删掉重建,不能改名
三张映射一共 **44 处「修改网络」**(导入对话框里逐条核对过,**没有一条是增删元件**)。
落地脚本 `.claude/pinmap.py`:
⚠️⚠️ **`setState_Net` 对 netport 是坏的** —— 调用之后网络名变成**空字符串**,
标签也一起没了(和 skill §3b 的 `setState_X/Y` 同一个毛病,这一轮实测栽了一次)。
⇒ 端口只能 `delete` + `createNetPort` 重建。
✅ 但 skill §8b 那句「端口的 dir(IN/OUT/BI)读不回来」是**错的**:
**`getState_Component().name` 就是 `Netport-BI` / `Netport-IN` / `Netport-OUT`。**
重建前读它、原样传回去即可,不用像 `p1_add.py` 那样「端口只增不重建」。
改动量:P3 改名 8 / 删 4 / 新建 4;P3B 改名 14 / 删 3;P6 改名 4 / 新建 3。
三页 `verify_sch --nets --nc`、`xpage.py`(0 漏接)、`port_audit.py`(544 个旗/端口 0 可疑)全过。
NC 清单跟着改:`p3-nets-nc.json` 去掉 32~35、加上 4/5/7/36;
`p3b-nets-nc.json` 加 `U21:[4]` / `U22:[4,15]`;`p6-nets-nc.json` 的 U33 只剩 `[9]`(链尾的 Q7S)。
#### 顺手治了一处烂了很久的东西:图面文字叠了好几代
读回来发现 P3 有 **44** 条 `sch_PrimitiveText`、P3B **64** 条、P6 **76** 条,
其中大量是**同坐标同内容的完全重复**(历代脚本只 `create` 不 `delete`),
还有互相矛盾的旧说明叠在一起,渲染出来就是一坨看不清的黑块。
**`verify_sch` / `xpage` / `port_audit` / DRC 四道验证一条都不管文字**,所以它烂了很久也没人发现。
`.claude/sch_text.py` 整页重写:P3 44→13、P3B 64→14、P6 76→16,
顺带把换脚之后**变成假话**的几条改掉(`IO39~IO42 留给 JTAG`、`IO47/IO48 备用`、
`U22.Q7 = HUB_RST`、`QA~QE = EDL_EN1~5;QF/QG/QH 备用不接`、`风扇座 KF2510-3A`)。
> 判据:`sch_PrimitiveText` 只有图面注释,**标题栏不是它**(图框自己的字段,
> `getAll()` 里根本不出现),所以整页删干净是安全的。
---
### 26.19 ⚠️ 8 A 的源只有 3 个过孔 —— 四道验证一条都不管(2026-09-06 第二十三轮)
第一次跑信号布线跑到 35/196 个网络时中止,原因不是布线器,是它**报出来的失败**
把两个上游问题照了出来。
#### A. `Rs6.2` → +12V 平面:3 个 Ø0.3 过孔扛不住 8 A
`Rs6` 是输入检流电阻,**`Rs6.2` 是全板 `+12V` 平面唯一的源** ——
12V 进线 8 A 全部由这一个贴片焊盘下到 Inner2。而扇出规划器按
`pad_n_via()` 给了它 **3 个孔**:Ø0.3 过孔单孔算 1~1.5 A ⇒ **3~4.5 A**,缺一半。
**这一条为什么四道验证一条都抓不到**:
| 验证 | 它在看什么 | 为什么漏 |
|---|---|---|
| `pcb1_pour` 断面校核 | 平面**本身**的连续铜宽(`北大块 @Rs6 东出 x=20 → 11.1 A`)| 它量的是平面,不是**焊盘怎么下到平面** |
| `pcb_fanout` | 「孔放下了没有」 | 放下 3 个就报「失败 0 个」,它不知道要几个 |
| 连接性 DRC | 「连上没有」 | 连上了,只是细 |
| `pcb1_escape_audit` | 「出得去吗」 | 出得去 |
⇒ `pcb_fanout.py` 新增 **`FORCE_ARRAY[(位号, 引脚号)] = [(x, y), ...]`**:
整片阵列钉死,逐个仍走全套净距校核。`Rs6.2` 钉了 **12 个孔(≈12 A)**,
摆在焊盘**正南**那片空地(实测 x 5.2~14.0 / y 85.5~91.5 什么都没有)。
> **规矩:凡是 >4 A 的「焊盘 → 平面」转换点,过孔数必须手写,不能交给 `pad_n_via()`。**
> 这块板上只有 `Rs6.2` 一处(五路的 `VOn_P` 走底层小岛、排针针脚是通孔,不经过这一步)。
#### B. 同一处改动顺带把 U13 的 I²C 放了出来
原来那 3 个孔里有两个被规划器甩到**西边** (7.40,94.40) / (7.91,95.16),
两根 1 mm 宽的引线(圆端帽还要再往西探 0.5)正压在 **U13 南排五个脚唯一的出线通道**上。
`pcb1_escape_audit` 报 `U13.2 被围死:最好的一个方向两层加起来只能走 0.47 mm²`,
挡它的是 **`$1N236` 铺铜,只差 0.379 mm** —— 也就是 §26.17 刚画的 `VINSW-TOP` 北柱。
两边一起让:
* 12 个孔改朝**南** ⇒ 西边那两根 1 mm 引线消失;
* `VINSW-TOP` 北柱在 **y > 87 收窄到 x 1.5~5.3**(3.8 mm,断面 8.4 A ≥ 8 A),
y < 87 的 C2.1 口袋仍是 x 1.5~6.65。
U13 南边于是变成一整片 **x 5.5~14 / y 91.6~96** 的空地,`U13.2` 从「被围死」名单上消失。
#### C. 扇出不对称的教科书样本:`C%06.2`
`U15.14/15`、`U16.14/15`(CH2 / CH3 的 eFuse)报「被围死」,而 **CH1 / CH4 / CH5
的同一个脚完全正常** —— 五路摆位一模一样(实测五路的局部包围盒逐件相同),
所以错的一定在上游。
把五路的过孔全部换算回母版局部坐标一比就出来了:
| 通道 | `C%06.2` 的 GND 孔(母版局部)|
|---|---|
| CH1 / CH4 / CH5(rot 0)| **(10.02, 27.10)** 往东 |
| CH2 / CH3(rot 180)| **(6.75, 27.10)** 往西 ⇒ 正压在 `U%8` 脚 14/15(局部 (6.25/6.75, 28.80))唯一的南向出线口上 |
这就是 §26.13 那一条(「扇出规划器的候选角度按**板坐标**排,整路转 180° 之后同一个焊盘
在 CH1 往东扇、在 CH2 就往西扇」)的又一次发作。加进 `_CH_FORCE_LOCAL`:
`('C%06', '2'): (10.020, 27.100)`。
#### D. 剩下 10 个「被围死」不是板上的铜
改完再审,还剩 `U6.6/16`、`U7.16`、`U15.3/14/15`、`U16.3/14/15`、`U18.3` 十个。
逐个查挡路物,发现报出来的 `GND 过孔 (52.84,82.90)` **板上根本不存在**
(那一点 2 mm 内一个过孔都没有)——它是**审计自己给邻脚预留的出线段**。
⇒ 这十个是「**和邻脚抢预留位**」,不是硬几何。判据很简单:
**`--why` 列出来的挡路物,去 `pcb-copper.json` 里查一遍,查不到的就是预留段。**
这一类布线器的细栅格逃逸自己能救回一部分(上一轮 52 个里救回 38 个),
真救不回来的才需要动摆位。
#### 顺带记一条:`route_sig` 是跑完才一次性下发
中途 `TaskStop` 掉,板上一根铜都不会变(回读 665/491/15 与开跑前一致)。
代价只是算力。**所以「先跑着看看」是安全的**,发现上游有问题随时可以停。
反过来也意味着:**跑到 90% 被打断 = 全白跑**,长跑要放后台并挂 monitor 盯
`… k/196 个网络` 那一行。
实测速率(第一次跑):前 2 个网络(`SDA`/`SCL`,各挂 14 个焊盘横跨整板)吃掉 **1516 s**,
之后 5 个网络只要 **68 s**。⇒ **别拿头几个网络外推总时长**。
---
### 26.20 ⭐ I²C 干线改走 Inner2(2026-09-06 第二十四轮,用户拍板)
`SDA` / `SCL` 是全板最长的两个网络(各挂 14 个焊盘,横跨整块板),
布线器在它们身上花掉 1516 s,还把外层最好的通道占了。
用户拍板:**走内层,只挪跨板长干线**(器件脚下的短引出仍在外层)。
工具是新写的 **`.claude/pcb1_i2c_l3.py`**(三层迷宫布线:Top / Bottom / Inner2)。
#### 结论:中桥那 13 mm 是唯一不能进内层的一段
Inner2 上东西两半之间**只有一条隔断不能割** —— `12V-SW+BR` 的中桥
(x 61.5~72.6,11.1 mm,喂南西块 3.6 A,`pcb1_pour.CUTS` 里三条断面都盯着它)。
横着割一刀就是南西块断电,而 I²C 要过去就必须横着割。
⇒ **中桥只能外层跳过去**(现在是 x 61 ↔ 73 的底层 13 mm + 两个孔)。
巧的是上一轮 `pcb1_route_sig` 自己也撞出了同一个结论 —— 它给 `SDA` 布的就是这个跳法。
除此之外内层随便走:`+3V3` 两大块只有 0.5 A(内层 0.5 oz 下 0.40 mm 就够),
`GND-FILL-L3` 只是底填(L2 才是「不许割断」的那张完整地平面)。
`+12V` 三块一律硬障碍,一格都不进。
| | 改之前 | 改之后 |
|---|---|---|
| I²C 总铜长 | 596 mm,**内层 0** | 609 mm |
| Inner2 | — | **302 mm** |
| 顶层 / 底层 | 596 mm | 157 / 150 mm |
| 换层孔 | 18 | 35 |
| 连通性 | SCL 3 片 / SDA 4 片 | **一模一样**(欠的那几条是上一轮就欠着的)|
#### ⚠️ 教训一:`PEN_3V3` 这个代价决定的不是长度,是平面会不会被切出孤岛
第一版给「L3 上穿 +3V3」定的代价是 **1.8**,于是 `SCL` 沿 y=50 在 `3V3-SW` 里
横跑了 12.7 mm、`SDA` 又从东边界斜插进来 —— 两根线加平面东边界围出一块
**7.2 mm² 的孤岛,里面正好有 `R415.2` 的 +3V3 焊盘和它的过孔**。
> 这一条**三道检查全都看不见**:
> · 铺铜的「浮铜」检查不响 —— 那块铜有本网落脚点;
> · 「焊盘覆盖」检查不响 —— 焊盘确实落在本网铜上;
> · 连接性 DRC 不响 —— 过孔把它接到顶层去了。
> **只有数连通域看得见。**
**堵住孤岛重绕是不收敛的**(实测四轮,越堵越大:7.2 → 25.4 → 26.8 → 32.5 mm²)。
真正的修法是改代价:**`PEN_3V3 = 4.0`** 之后干线改走北边的 GND 底填,
只在器件附近**扎一个盲端**进平面 —— 盲端不切平面,连通域数不变。
代价是 Inner2 占比从 82% 掉到 70%(多出来的都是器件脚下的短引出,本来就说好留在外层)。
⇒ 规矩:**内层干线穿电源面只许扎盲端,不许从一边穿到另一边**。
`pcb1_i2c_l3.plane_report()` 在**规划阶段**就数连通域(+12V 要 1 块、+3V3 要 2 块),
和 `pcb1_pour.grid_checks` 用同一套 `PO.Grid`。
#### ⚠️ 教训二:`expand()` 会静默丢掉最后一点上的过孔(引擎早写着,我又踩了一遍)
路径写成「L3 上走到焊盘正上方 → 换层落下去」时,`expand()` 的
`i + 1 < n - 1` 把最后一个换层点跳过了 ⇒ **末段画在 L3 上、过孔根本没生成**。
现象是净距校核全过、DRC 也不响,只有数碎片才看得出来
(实测「U8.4 还是单独一片」)。修法是引擎里现成的 `E._end_via(path)`。
#### ⚠️ 教训三:`own`(本网铜放行)不能按「格心落在本网铜里」判
`free = edt >= need | own` 会让 0.2 mm 的线贴着自家焊盘的**边**走 ——
INA226 的焊盘只有 0.28 宽,线心压在西边缘就往外探出 0.1,离邻脚只剩 0.06;
Φ0.61 的过孔更离谱(实测 −0.145,一口气 30 条)。
· 走线:`own` 要**按半线宽内缩之后**再标(真正的判据是「本网铜完全盖住这根线」);
· 过孔:**根本不吃这条放行** —— `edt` 里本来就不含本网铜,直接按真净距判。
#### 顺带修掉的一块浮铜(**不是这次改动造成的**)
铺铜回读报「Inner2 GND 有 1 块浮铜 1312.8 mm²」。查下来是**板子南沿 y 0.5~9
那一整条 GND 底填**:南边是板框,北边被三块电源面封死,原本只剩
x 72.6~73(0.4 mm,本来就走不了)和 x 115~116(1.0 mm)两条缝,
而后者被 `K5_VUP(114.80,28.70)` / `VDAC5(116.70,29.50)` / `EFUSE_EN3(115.00,32.40)`
三个**信号布线打的过孔**的反焊盘掐断了 —— 那一条里一个过孔、一个通孔焊盘都没有。
它正贴着 ESP32 天线禁铺区,160 mm 的悬空铜条不能留。
⇒ 新脚本 **`.claude/pcb1_gnd_stitch.py`**,南沿补 6 个 GND 缝合孔
(过孔是通孔,一个孔就把 Inner2 这块铜接到 Inner1 的完整地平面上)。
> **它同样是静默的**:`pcb1_pour.py` 下发前的 `report()` 看不见 ——
> 它的栅格**不含别的铺铜**,算出来 GND 是一整块;
> 只有下发后 `verify()` 回读实测铜才量得出来。
#### 验收(2026-09-06)
| 项 | 结果 |
|---|---|
| `pcb1_i2c_l3.py` 净距 / 拐角 / 孔距 | ✅ 全过 |
| 平面完整性(规划阶段) | ✅ Inner2 +12V 1 块 / +3V3 2 块 |
| `pcb1_pour.py --push --verify` | ✅ 实测铺铜和计划对得上 |
| `pcb1_netlist.py` | SCL 3 片 / SDA 4 片,**和改动前一模一样** |
| `drc_read.py` | 72 条间距错误里**没有一条**牵涉 SDA/SCL(全是上一轮 route_sig 的 VDAC/EFUSE/K*/FAN)|
#### 26.20b 挪进内层是为了**腾外层给布不通的线** —— 效果实测
用户点明了目的:I²C 挪内层不是为了 I²C 自己,是为了把外层通道让给那 87 条布不通的线。
挪完立刻跑第三遍信号布线(`pcb1_route_sig.py --refresh --ripup --push`)验证:
| | 挪之前 | 挪之后 + 第三遍布线 |
|---|---|---|
| 已连通网络 | 148 | **163** |
| 还欠连接 | 87 条 / 74 网络 | **68 条 / 59 网络** |
| DRC 连接性错误 | 1044 | **855** |
| `INA_ALERT` | 5 碎片 | **3 碎片** |
| 板上铜 | 3196 线 / 1000 孔 | 3516 线 / 1084 孔 |
**内层干线一段没丢**:`--ripup` 拆了 191 线 / 46 孔,55 段 L3 走线(302 mm)、
6 个南沿缝合孔全在;I²C 过孔 35 → 39(布线器补的)。
#### ⚠️ 26.20c 引擎的层数写死是 2 —— 板上一有内层走线就崩
`pcb2_route_sig.Field.__init__` 里 `occ = {L: ... for L in (L_TOP, L_BOT)}`,
`mask_of` / `_mask` 也是同一句。板上一出现 layer 16 的走线,障碍表里就带 16 ⇒
**`KeyError: 16` 当场崩**(实测 `pcb1_route_sig.py --limit 6` 就崩在 `_mask`)。
更阴的是「滤掉 16 层就好了」这个想法是**错的**:
`viafree = np.minimum(edt[L_TOP], edt[L_BOT])` —— 过孔是通孔,
只看外层两层的话,**新过孔会直接打在内层干线上,而净距校核一声不吭**。
⇒ 改成:`self.lays` = 障碍表里真正出现过的层(并上 1/2),
`occ` / `edt` / `mask_of` / `_mask` 全按 `self.lays` 建,
`viafree = np.minimum.reduce([edt[L] for L in self.lays])`。
只有 1/2 层时行为和以前**逐格一致**。
顺带把 `pcb1_route_sig._layers()` 里「过孔只算 (L_TOP, L_BOT)」改成四层 ——
否则碎片分析会把「内层线 + 两端的孔」数成两片。
#### ⚠️ 26.20d 顺带查出来的:21 处**真实铜重叠**(在 Buck 控制器的 GND 脚上)
DRC 报 74 条间距错误。按板上真实几何逐对算下来,**21 处净距 < 0**,
全部是 `U1.15` ~ `U5.15`(五个 Buck 控制器的 **GND 脚**)被功率级走线压进去
**0.10 ~ 0.125 mm**,**五路完全对称** ⇒ 是 `pcb1_route_pwr.py` 的几何有系统性问题,
不是布线器随机撞的。**做板之前必须清掉。**
> 为什么一路绿到现在:`pcb1_route_sig` 的 `check()` **只核本轮新画的铜**
> (`mine` 那张表),板上早就存在的线-焊盘重叠它一次都没看过。
> 同理 `pcb1_route_pwr.py --verify` 核的是「195 段有没有被实测铜盖住」,
> 也不是「有没有压到别人的焊盘上」。
---
### 26.21 ⛔ 漏跑 `pcb1_parts_dump.py` = 后面两轮布线全照着过期引脚映射画(2026-09-06 第二十五轮)
§26.18 按几何重排了三组引脚(U20 / U6+U7 / U21+U22+U33,共 **44 个焊盘**),
改动**导进 PCB 了**,但 **`pcb1_parts_dump.py` 漏跑了** ——
它的文件头就写着「**从原理图导入变更之后必须跑一次**」。
于是 `pcb1-parts.json` 停在重排**之前**。而**本项目所有脚本的焊盘网络都来自这个缓存**
(`pcb1_pour.load_pads` → `pcb1_netlist.geom` → `pcb1_route_sig`),
只有 **EasyEDA 自己的 DRC** 用的是 PCB 文档里的真实焊盘网络。
⇒ **后面两轮信号布线(共 ~1000 段)里,这 33 个网络的铜连的是错信号。**
板上表现是 **74 条「贴片焊盘 到 导线 距离 0 mil」** —— 走线**正正好落在**某个焊盘上,
因为按缓存那是它自己的焊盘,按板子那是别人的。
| 判据 | 结果 |
|---|---|
| 用**旧缓存**的网络算净距 | **0 对**违规(所以脚本一路全绿)|
| 用**板上真实**网络算净距 | **44 对**,头几条正是 DRC 报的那几条 |
| 刷新缓存后再算 | 53 对 < 0.20,其中 **45 对真重叠** |
**善后**:`pcb1_parts_dump.py` 重抓(旧的备份成 `pcb1-parts.json.before-remap-refresh`)→
焊盘网络 0 处不一致 → 拆掉这 33 个网络的全部铜(**530 段 / 2482 mm / 138 孔**,
占全板 3512 段的 15%)→ 按正确映射重布。
I²C 不受影响(`SDA` / `SCL` / `INA_ALERT` 都不在重排名单里)。
> **规矩**:`pcb1_import.py --apply` 之后**下一条命令就是 `pcb1_parts_dump.py`**。
> 中间插任何别的操作,后面所有几何和布线都建在沙子上,而且**六道自检一条都不会响** ——
> 它们全都读同一份缓存,自洽得很。
#### 顺带记两条「怎么查才算数」
1. **多边形焊盘不许按包围盒判。** QFN 的散热盘(`U1.15`~`U5.15`,21 个点的十字形)
包围盒是 2.03 × 4.32 mm,把 1/7/8/14 脚整个套进去 ⇒ 临时写的检查会凭空报出
**21 处「重叠」**,全是假的(按真实轮廓算净距全 ≥ 0.20)。
`pcb1_route_sig.expand_pads()` 存在就是为了这件事,临时检查别绕过它。
2. **DRC 的「连接性」和「间距」新鲜度不一样。** 程序化建线之后连接性那一支是陈旧的
(实测 `location.reload()` 之后 855 → 198),**但间距那一支是即时的** ——
重载前后都是 74 条、内容逐字相同 ⇒ 间距报出来的东西**不能当成陈旧数据糊弄过去**。