From ab37f9dc4960bdb9c6934186fe855cd99fcb5122 Mon Sep 17 00:00:00 2001 From: zhou yang Date: Sun, 6 Sep 2026 19:33:51 +0800 Subject: [PATCH] =?UTF-8?q?A5=EF=BC=9A74HC595=2024=20=E4=BD=8D=E9=93=BE=20?= =?UTF-8?q?+=20=E5=BD=B1=E5=AD=90=E5=AF=84=E5=AD=98=E5=99=A8=E5=8D=95?= =?UTF-8?q?=E4=B8=80=E5=86=99=E5=85=A5=E7=82=B9?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit 15 路侧键 + 5 路 EDL_EN + HUB_RST 在一条 24 位链上,内存里只有一份影子, 唯一写入点是 sr595_flush()。发送顺序 U33 → U22 → U21,每字节 QH 先发。 位表是从 .claude/pcb1-parts.json 的真实焊盘网络逐脚核回来的,不是照文档抄 —— 设计文档 §17.2 那张是 09-04 的两片版,§26.18 重排后 15 路里有 12 路对不上。 顺手把 §17.2 与 §8.2 里过期的两张表都改了。 sim 侧新增按 datasheet 建模的假移位链(SRCLK 上升沿移一格、RCLK 上升沿锁存), 只看线上真实发生的边 —— 对着驱动自己的影子变量断言等于自己证明自己。 四个注错进去的 bug(字节序反、OE# 先使能、安全影子写 0、位表写成算式)全被拦住。 上电顺序按「先锁存安全值、再使能 OE#」写死:三片 MR# 接死在 +3V3, 上电时移位寄存器内容不确定,先拉低 OE# 就是把随机值放到 15 个栅极上。 Co-Authored-By: Claude Opus 5 Claude-Session: https://claude.ai/code/session_01QYuExfgyYa6DzRRcUso8M8 --- firmware/HANDOFF.md | 101 +- firmware/components/drv/CMakeLists.txt | 1 + firmware/components/drv/include/sr595.h | 133 + firmware/components/drv/sr595.c | 226 + .../phonerail_hal/sim/hal_gpio_sim.c | 12 + .../components/phonerail_hal/sim/sim_hal.c | 2 + .../components/phonerail_hal/sim/sim_hal.h | 25 + .../components/phonerail_hal/sim/sim_sr595.c | 98 + firmware/host/CMakeLists.txt | 2 + firmware/main/phonerail.h | 2 +- firmware/test/test_sr595.c | 372 + 五路直供电源板设计.md | 13774 ++++++++-------- 需求文档.md | 16 + 13 files changed, 7895 insertions(+), 6869 deletions(-) create mode 100644 firmware/components/drv/include/sr595.h create mode 100644 firmware/components/drv/sr595.c create mode 100644 firmware/components/phonerail_hal/sim/sim_sr595.c create mode 100644 firmware/test/test_sr595.c diff --git a/firmware/HANDOFF.md b/firmware/HANDOFF.md index 953b546..f5082c2 100644 --- a/firmware/HANDOFF.md +++ b/firmware/HANDOFF.md @@ -1,63 +1,76 @@ # 交接 -更新:2026-09-06 完成任务包 **A4**(DAC63204 驱动 + `rail_set_mv()`) +更新:2026-09-06 完成任务包 **A5**(74HC595 24 位链 + 影子寄存器单一写入点) ## 一句话现状 -五路输出电压能设了:`rail_set_mv(rail, mv)` 是唯一入口(rail 是 **1~5**), -内部走 mV → Vd → 12 位码,**码越大电压越低**;4010 mV 以上、3524 mV 以下一律拒。 -两片 DAC 认件(DEVICE-ID=01h)、开内部基准、增益 2×、只给用到的通道上电, -上电即 3.90 V。6 条 ctest(46 个用例)全绿,`idf.py build` 通过。 +15 路侧键 + 5 路 `EDL_EN` + `HUB_RST` 全在一条 24 位链上,内存里只有一份影子, +唯一写入点是 `sr595_flush()`。位表**从 PCB 的真实焊盘网络逐脚核回来**(不是照文档抄), +上电顺序按「先锁存安全值、再使能 `OE#`」写死。7 条 ctest(61 个用例)全绿, +`idf.py build` 通过。 ## 下一步 -**A5**:74HC595 24 位链 + 影子寄存器单一写入点(需求 §10.6「影子寄存器」那段 + -设计文档 §17.2 的位表)。两条断言:①改 CH1 按键不动 CH2~5 的位 ②字节顺序 U33→U22→U21。 -⚠️ 位表也被 §26.18 重排过(`.claude/pinmap.py` 的 `P3B` / `P6` 两节是真表), -和这次的 DAC 通道一样,**别照 §17.2 的旧表写**。 +**A6**:PCA9555 驱动(需求 §10.4 末段)。验收断言:**方向寄存器永远不会把 +Port0[7] / Port1[7:5] 配成输出**(配错直接 abort)—— 那 4 个备用脚在板上**直接接地** +(设计文档 §17.2 的注),配成输出并输出高就是对地短路。 +A3/A4/A5/A6 四个驱动包彼此独立,做完 A6 就能进 A7(通道配置表)。 ## 本次新增/修改的文件 -- `components/drv/include/dac63204.h` — 寄存器、位域、五路→(片,通道)映射(唯一对外契约) -- `components/drv/dac63204.c` — 驱动本体(≈180 行,只经 `hal_i2c_*`) -- `main/rail.h` / `main/rail.c` — mV ↔ 码的**唯一**换算与 `rail_set_mv()` / `rail_get_mv()` -- `test/test_dac63204.c`(21 个用例)/ `test/test_rail.c`(12 个用例) -- 三处 CMakeLists + `main/phonerail.h`(版本 `0.1.0-a4`) -- `../需求文档.md` §10.5、`../五路直供电源板设计.md` §17.2 — 记落地 + **修掉过期的通道分配表** +- `components/drv/include/sr595.h` — 24 位链的位表、引脚、影子契约(唯一对外契约) +- `components/drv/sr595.c` — 驱动本体(≈200 行,只经 `hal_gpio_*`) +- `components/phonerail_hal/sim/sim_sr595.c` — **按 datasheet 建模的假移位链** + (SRCLK 上升沿移一格、RCLK 上升沿锁存),加上 `sim_hal.h` 的一节声明 +- `components/phonerail_hal/sim/hal_gpio_sim.c` — 加了一个窃听钩子给上面那个模型; + `hal_gpio_config(OUTPUT)` 也会触发(真芯片配成输出就开始驱动,`OE#` 靠这一条) +- `test/test_sr595.c`(15 个用例) +- 三处 CMakeLists + `main/phonerail.h`(版本 `0.1.0-a5`) +- `../需求文档.md` §10.6、`../五路直供电源板设计.md` §17.2 — 记落地 + **修掉过期的位表** + (§8.2 那行过期的 DAC 通道分配也顺手改了) ## 验收命令与结果 ``` $ bash host/test.sh -100% tests passed, 0 tests failed out of 6 # +test_dac63204(21) +test_rail(12) +100% tests passed, 0 tests failed out of 7 # +test_sr595(15) $ .\build_idf.ps1 # PowerShell phonerail.bin binary size 0x32550 bytes. ... 0xcdab0 bytes (80%) free. -Project build complete. # dac63204.c.obj 与 rail.c.obj 都在;bin 与 A3 同样大是正常的 - #(还没人调它们,链接器把符号丢了) +Project build complete. # sr595.c.obj 在;bin 与 A4 同样大是正常的(还没人调它) -# 三个「一定会被写出来的错」逐个改进去跑过,确认测试拦得住: -# 反向关系写反 -> test_rail 红;忘了左对齐 / 通道按 rail-1 算 -> test_dac63204 红 +# 四个「一定会被写出来的错」逐个改进去跑过,确认测试拦得住: +# 字节顺序发反(U21 先发) -> test_byte_order 红 +# 先使能 OE# 再锁存安全值 -> test_outputs_are_enabled_only_after_a_safe_latch 红 +# 安全影子写成 0(HUB_RST 摁死) -> 三条红,其中一条直接说「上电后 Hub 不能被摁在复位里」 +# 位表改成 3(rail−1)+key 的算式 -> sr595_modify 的 assert 当场 abort(碰到空脚 bit4) ``` ## 踩到的坑(只写会再犯的) -- **12 位码在 `DAC-X-DATA` 里左对齐**(bit15-4,低 4 位 don't care)。忘了 `<< 4` - 不报错,只让输出变成 1/16 —— 而在本板上那是「五路都 4.010 V 满电」,看不出异常。 -- **两种步长**:`DAC-X-VOUT-CMP-CONFIG` 每通道跨 6(03/09/0F/15),`DAC-X-DATA` 连续(19~1C)。 -- **上电顺序**:`EN-INT-REF` 要先写(datasheet 明说增益设定之前必须已置位), - 安全码要在通道上电之前写(复位码 0 = Vd 0 V = 输出上限 4.010 V)。 - 所以 `COMMON-CONFIG` 写两次。sim 只留寄存器终值看不到中间态, - 顺序是靠「`CC_REF_ONLY` 里四路输出全按住」+「`n_read` 计数」两条间接钉的。 -- **未用通道不许上电**:FBx 悬空时电压输出是开环运放(datasheet 表 5-1)。 - U6 用 OUT0/1/2、U7 只用 OUT0/1,所以 `COMMON-CONFIG` 是每片一个值,不是常量。 -- **cygwin 的偶发 `Subprocess aborted` 不止发生在链接**:这次 ctest 跑测试时 - `test_hal_sim` / `test_ina226` 同时挂了一次,重跑就全绿。**别去查代码。** +- **位表不能照 §17.2 抄** —— 那张表是 09-04 的两片版,§26.18 重排之后 15 路里 + **12 路对不上**。这次是从 `.claude/pcb1-parts.json` 的真实焊盘网络逐脚核出来的 + (顺手把 §17.2 和 §8.2 里过期的两张表都改了)。和 A4 的 DAC 通道分配同一类坑。 +- ⚠️ **CH4 的三个键碰巧就是 bit 9/10/11**,和「顺排公式 `3(rail−1)+key`」一模一样。 + 所以「断言位表不是公式」只能**整体**断言(15 位里只有 3 位重合), + 逐路写 `NOT_EQUAL` 到 CH4 就自己红了 —— 第一版正是这么写的。 +- **`HUB_RST` 是低有效**(USB2517I 的 `RESET_N`,§21.7)。全 0 的上电影子会把 Hub + 一直摁在复位里,而五路手机的电压电流全都正常 —— 看起来跟固件一点关系都没有。 +- **上电顺序不能换**:三片 `MR#` 接死在 +3V3,没有复位线 ⇒ 上电时移位寄存器内容 + 不确定。所以 `KEY_OE#` 在安全值锁存完之前**根本不配成输出**(ESP-IDF 一配成输出 + 就开始驱动,输出寄存器复位值 0,等于当场使能)。板上 R609 100 kΩ 上拉扛着这一段。 +- **假移位链值得写**:A5 的两条验收断言如果只对着驱动自己的影子变量断言,那是自己 + 证明自己 —— 字节顺序发反、每帧多打一个时钟、RCLK 打早了,影子变量一律看不出来。 + `sim_sr595_*` 按 datasheet 建模,attach 时把移位寄存器塞成 `0xA5A5A5`(真板子上电 + 就是不确定值),四个注错进去的 bug 全被它照出来了。 +- **cygwin 的偶发 `Subprocess aborted` 又来了一次**:这次是三条测试同时在 0.03 s 里挂, + 其中两条根本不碰 595。重跑就正常。**别去查代码。** -## 这个驱动 / 这一层的几条约定(写 A7 / A10 / A12 之前看一眼) -- **除 `rail.c` 外,任何地方都不许调 `dac63204_write_code()`。** 反向关系只在 - `rail_mv_to_code()` 里出现一次(那个减法),多一处就多一处写反的机会。 -- **查表不要算**:`dac63204_rail_addr()` / `dac63204_rail_ch()`,rail 是 1~5,越界 abort。 - CH1→U6.OUT2 / CH2→U6.OUT0 / CH3→**U7**.OUT0 / CH4→U6.OUT1 / CH5→U7.OUT1(§26.18)。 - 四通道电气对等 ⇒ **接错了板子照样正常工作,只是调错了路**,功能测试测不出来。 -- **单位**:`rail_set_mv/rail_get_mv` 用 mV,`rail_code_to_vd_uv()` 用 µV。一个码在输出端 - 只值 **0.119 mV**,往返误差 ≤ 1 mV 正常。`rail_get_mv()` 读的是**设定值不是实测**(实测走 INA226)。 -- **不要用 `rail_set_mv()` 做保护**(需求 §10.5 规矩 2):异常处理是 `EFUSE_EN` 的活。 -- **越界请求现在只返回 `HAL_ERR_ARG`,还没记事件** —— SR-13 要求记,`rail.c` 里 - 留了 `TODO(A11)`,事件环形缓冲做完要回来补。 -- **标定还没做**(需求 §10.5 规矩 3):现在走理论公式,误差约 ±40 mV。 - 将来两点标定要顶替的是 `RAIL_VOUT0_UV`(4010018) 与 `RAIL_DAC_SPAN_UV`(486416) 这两个常量。 +## 这个驱动 / 这一层的几条约定(写 A9 / A12 之前看一眼) +- **除 `sr595.c` 外,任何地方都不许自己去打 SER/SRCLK/RCLK。** 改按键或 EDL 一律是 + 「`sr595_modify()` 改影子 → `sr595_flush()`」。多处直接操作移位链的症状是 + **另一台手机的按键被顺手清掉**,而且要两个动作正好撞在一起才复现。 +- **组合键必须 `sr595_write(mask, value)` 一次给两位**(VOL− + PWR 落在同一帧)。 + 分两次写会先单按一个键。`RCLK` 之前输出不变,所以整帧是原子的。 +- **不许拿 `OE#` 当「临时全松开」用**(需求 §10.6):那是复位路径不是控制路径, + 所以 `sr595.h` 根本没提供抬 `OE#` 的接口。 +- **rail 是 1~5**,`sr595_key_bit()` / `sr595_edl_bit()` 越界 abort; + `sr595_modify()` 的 mask 碰到三个空脚(bit 4/8/12)也 abort —— + 悄悄忽略的话那一位永远是 0,而「按键没反应」要到接上真手机才发现。 +- **`sr595_map_ok()` 还没人调**:A7 的启动自检要把它和 `dac63204_map_ok()` 一起调上。 +- **按键的保持时长(100 ms / 2 s / 10 s)与序列互斥还没做**,那是 A9 的活。 + A5 只保证「写下去的那一帧是对的」。 diff --git a/firmware/components/drv/CMakeLists.txt b/firmware/components/drv/CMakeLists.txt index 4e46819..5afed1c 100644 --- a/firmware/components/drv/CMakeLists.txt +++ b/firmware/components/drv/CMakeLists.txt @@ -5,5 +5,6 @@ idf_component_register( SRCS "ina226.c" "dac63204.c" + "sr595.c" INCLUDE_DIRS "include" REQUIRES phonerail_hal) diff --git a/firmware/components/drv/include/sr595.h b/firmware/components/drv/include/sr595.h new file mode 100644 index 0000000..79c9a43 --- /dev/null +++ b/firmware/components/drv/include/sr595.h @@ -0,0 +1,133 @@ +/* 74HC595 ×3 —— 一条 24 位移位链,带全固件唯一的影子寄存器(需求 §10.6)。 + + 链上挂着 **15 路侧键 + 5 路 EDL_EN + HUB_RST**,共 21 位有效、3 位空脚。 + 写任何一位都要把整条链重发一遍,所以: + + ⚠️ **内存里只有一份 24 位影子值,只有本文件的 `sr595_flush()` 会碰移位链。** + 任何任务改按键 / EDL 都是「`sr595_modify()` 改影子 → `sr595_flush()` 请求刷新」。 + 多处直接操作移位链的症状是**另一台手机的按键被顺手清掉**,而且要两个动作 + 正好撞在一起才复现 —— 属于会拖很久的那类 bug。 + + `RCLK` 打点之前输出不变 ⇒ 整帧刷新是原子的,组合键(VOL− + PWR)必须 + **一次 `sr595_write()` 两位一起给**,不能先后两次。 + + ⚠️ **不许用拉高 `OE#` 的方式「临时全松开」**(需求 §10.6):那会让 15 个栅极 + 同时进高阻,靠的是每个栅极自己的 100 kΩ 下拉 —— 那是**复位路径**,不是正常 + 控制路径。所以本头文件根本不提供「抬 OE#」的接口。 + + 本驱动只经 hal_gpio_*,宿主机上由 sim 的移位链观测器(`sim_sr595_*`)全部测完。 */ +#ifndef SR595_H +#define SR595_H + +#include +#include + +#include "hal_err.h" + +#ifdef __cplusplus +extern "C" { +#endif + +/* ---- 四根线(ESP32-S3 引脚,设计文档 §8.1 的表,§26.18 重排后) --------- */ + +#define SR595_PIN_SER 13 /* IO13 模组脚 21 → U21.DS(14) */ +#define SR595_PIN_SRCLK 12 /* IO12 模组脚 20 → 三片的 SRCLK(11) */ +#define SR595_PIN_RCLK 9 /* IO9 模组脚 17 → 三片的 RCLK(12) */ +#define SR595_PIN_OE_N 21 /* IO21 模组脚 23 → 三片的 OE#(13),板上另有 R609 100 kΩ 上拉 */ + +/* `MR#`(10) 三片都直接接 +3V3 —— 没有复位线,上电后移位寄存器内容是**不确定**的。 + 所以 `sr595_init()` 必须先把安全影子锁存进去、**再**驱动 `OE#`。 */ + +/* ---- 24 位的编号 --------------------------------------------------------- */ + +/* 位号 = **链上的物理位置**:0 = U21.QA(离 ESP32 最近的第一级),23 = U33.QH(链尾)。 + 一次移位 = 每一级往编号大的方向走一格,所以**先移入的位停在编号最大处**。 */ +#define SR595_CHIP_COUNT 3 +#define SR595_BITS 24 +#define SR595_MASK_ALL ((uint32_t)0x00FFFFFFu) + +#define SR595_CHIP_U21 0 /* 影子的 bit0~7 ;P3B 页,板上 y≈50(中)*/ +#define SR595_CHIP_U22 1 /* 影子的 bit8~15 ;P3B 页,板上 y≈35(南)*/ +#define SR595_CHIP_U33 2 /* 影子的 bit16~23;**P6 页**,板上 y≈70(北)*/ + +/* 位分配(**2026-09-06 按 PCB 几何重排**,设计文档 §26.18 C; + 此处的值是从 `.claude/pcb1-parts.json` 的真实焊盘网络逐脚核对出来的): + + U21 QA=EDL_EN4 QB=K1_PWR QC=K1_VUP QD=K1_VDN QE=空 QF=EDL_EN5 QG=EDL_EN3 QH=EDL_EN2 + U22 QA=空 QB=K4_PWR QC=K4_VUP QD=K4_VDN QE=空 QF=K5_VDN QG=K5_VUP QH=K5_PWR + U33 QA=EDL_EN1 QB=K2_VUP QC=K2_VDN QD=K2_PWR QE=K3_VDN QF=K3_VUP QG=K3_PWR QH=HUB_RST + + ⚠️ **「K1/K2/K3 顺排在 U21、U33 是 EDL 专用片」是旧版**(设计文档 §17.2 的 + 09-04 那张表),15 路里有 12 路对不上。三片本来就是一条链,谁在哪一位只是移位 + 的字节序 ⇒ **搞错了板子照样正常工作,只是按 CH1 的电源键按到了 CH4 的音量键**, + 功能测试完全测不出来。查表,不要算。 */ +#define SR595_BIT_HUB_RST 23 + +/* 空脚(U21.QE / U22.QA / U22.QE)。写它们没有意义,`sr595_modify()` 直接 abort。 */ +#define SR595_MASK_UNUSED (((uint32_t)1u << 4) | ((uint32_t)1u << 8) | ((uint32_t)1u << 12)) +#define SR595_MASK_VALID (SR595_MASK_ALL & ~SR595_MASK_UNUSED) + +typedef enum { + SR595_KEY_PWR = 0, + SR595_KEY_VUP, + SR595_KEY_VDN, + SR595_KEY_COUNT, +} sr595_key_t; + +/* rail 是 **1~5**,key 越界或 rail 越界一律 abort(那是调用方算错了位号)。 */ +int sr595_key_bit(int rail, sr595_key_t key); +uint32_t sr595_key_mask(int rail); /* 该路三键的掩码,「一路全松开」用得上 */ +int sr595_edl_bit(int rail); + +/* 15 路侧键的总掩码。安全巡检与「全松开」用。 */ +uint32_t sr595_all_keys_mask(void); + +/* 21 个有效位互不重复、都落在 SR595_MASK_VALID 里、空脚一个都没被占。 + 启动自检调一次(A7);返回 false = 位表被改坏了。 */ +bool sr595_map_ok(void); + +/* ---- 上电安全影子 -------------------------------------------------------- */ + +/* ⚠️ **`HUB_RST` 是低有效**(USB2517I 的 `RESET_N`(43),设计文档 §21.7, + 板上 R716 10 kΩ 上拉)。影子位 = 1 才是「Hub 正常跑」,= 0 是**按住复位**。 + 全 0 的影子会把 Hub 一直摁在复位里 —— 现象是「插上枚举不出来」, + 而五路手机的电压电流全都正常,看起来一点毛病没有。 + 所以上电安全值不是 0,是这个: */ +#define SR595_SHADOW_SAFE ((uint32_t)1u << SR595_BIT_HUB_RST) + +/* 复位是低有效,反相只在 `sr595_set_hub_reset()` 里出现这一次 + (和 `rail_mv_to_code()` 里那个减法同一个道理:多一处就多一处写反的机会)。 */ +void sr595_set_hub_reset(bool in_reset); + +/* ---- 器件操作 ------------------------------------------------------------ */ + +/* 三步,顺序不能换(上电时移位寄存器内容不确定,`MR#` 又接死在 +3V3): + ① SER / SRCLK / RCLK 配成输出并置低;**`OE#` 这时还是输入**, + 靠板上 R609 上拉着 ⇒ 三片输出保持高阻,15 个栅极被各自的 100 kΩ 拉低 + ② 把 `SR595_SHADOW_SAFE` 移进去并锁存 + ③ 这才把 `OE#` 配成输出并拉低,输出使能 + ②③ 换个个儿 = 上电瞬间把移位寄存器里的随机值放到 15 个栅极上, + 也就是**五台手机的电源键可能一起被按下去**。 */ +hal_err_t sr595_init(void); + +uint32_t sr595_shadow(void); /* 当前影子(未必已经刷下去,看 sr595_dirty()) */ +bool sr595_dirty(void); /* 影子和链上的值不一致 */ + +/* 影子 = (影子 & ~mask) | (value & mask),并置脏。**不碰总线**。 + mask 越出 SR595_MASK_VALID(含碰到空脚)直接 abort。 */ +void sr595_modify(uint32_t mask, uint32_t value); + +/* 把影子整帧发下去:U33 字节 → U22 字节 → U21 字节,每个字节 QH 先发, + 最后一个 RCLK 上升沿统一生效。不脏就直接返回 HAL_OK(不空发一帧)。 + 没 init 过 → HAL_ERR_STATE。 */ +hal_err_t sr595_flush(void); + +/* `sr595_modify()` + `sr595_flush()`。**组合键必须走它**—— + VOL− + PWR 要落在同一帧里,分两次写会先单按一个键。 */ +hal_err_t sr595_write(uint32_t mask, uint32_t value); + +#ifdef __cplusplus +} +#endif + +#endif /* SR595_H */ diff --git a/firmware/components/drv/sr595.c b/firmware/components/drv/sr595.c new file mode 100644 index 0000000..ff48ed2 --- /dev/null +++ b/firmware/components/drv/sr595.c @@ -0,0 +1,226 @@ +/* 74HC595 ×3 的 24 位链 + 影子寄存器。契约见 sr595.h。 */ +#include "sr595.h" + +#include + +#include "hal_gpio.h" + +/* ---- 位表 ---------------------------------------------------------------- */ + +/* 从 `.claude/pcb1-parts.json` 的真实焊盘网络逐脚抄出来的(设计文档 §26.18 C)。 + 位号 = 链上物理位置:0 = U21.QA … 23 = U33.QH。 + 排布规矩:**每一路的三个键必须落在同一片的连续三脚上**(出芯片是一束线), + 所以三个键的位号在表里挨着,但**顺序每一路都不一样**(U22 上的 CH5 是倒着的)。 */ +static const int8_t k_key_bit[5][SR595_KEY_COUNT] = { + /* PWR VUP VDN */ + /* CH1 */ { 1, 2, 3 }, /* U21.QB QC QD */ + /* CH2 */ { 19, 17, 18 }, /* U33.QD QB QC */ + /* CH3 */ { 22, 21, 20 }, /* U33.QG QF QE */ + /* CH4 */ { 9, 10, 11 }, /* U22.QB QC QD */ + /* CH5 */ { 15, 14, 13 }, /* U22.QH QG QF */ +}; + +/* EDL_EN1~5。⚠️ 只有 EDL_EN1 还在 U33(QA),其余四路搬到了 U21 上, + 而且**不是顺序的**:QA=EDL_EN4、QF=EDL_EN5、QG=EDL_EN3、QH=EDL_EN2。 */ +static const int8_t k_edl_bit[5] = { + 16, /* CH1 → U33.QA */ + 7, /* CH2 → U21.QH */ + 6, /* CH3 → U21.QG */ + 0, /* CH4 → U21.QA */ + 5, /* CH5 → U21.QF */ +}; + +int sr595_key_bit(int rail, sr595_key_t key) +{ + assert(rail >= 1 && rail <= 5); + assert((unsigned)key < (unsigned)SR595_KEY_COUNT); /* 枚举可能是无符号,别写 key >= 0 */ + return k_key_bit[rail - 1][key]; +} + +uint32_t sr595_key_mask(int rail) +{ + uint32_t m = 0; + for (int k = 0; k < SR595_KEY_COUNT; k++) { + m |= (uint32_t)1u << sr595_key_bit(rail, (sr595_key_t)k); + } + return m; +} + +int sr595_edl_bit(int rail) +{ + assert(rail >= 1 && rail <= 5); + return k_edl_bit[rail - 1]; +} + +uint32_t sr595_all_keys_mask(void) +{ + uint32_t m = 0; + for (int rail = 1; rail <= 5; rail++) { + m |= sr595_key_mask(rail); + } + return m; +} + +bool sr595_map_ok(void) +{ + uint32_t seen = 0; + int n = 0; + + for (int rail = 1; rail <= 5; rail++) { + for (int k = 0; k < SR595_KEY_COUNT; k++) { + uint32_t b = (uint32_t)1u << k_key_bit[rail - 1][k]; + if ((b & SR595_MASK_VALID) == 0 || (seen & b) != 0) { + return false; /* 落到空脚上,或者两个信号抢同一位 */ + } + seen |= b; + n++; + } + uint32_t e = (uint32_t)1u << k_edl_bit[rail - 1]; + if ((e & SR595_MASK_VALID) == 0 || (seen & e) != 0) { + return false; + } + seen |= e; + n++; + } + + uint32_t h = (uint32_t)1u << SR595_BIT_HUB_RST; + if ((h & SR595_MASK_VALID) == 0 || (seen & h) != 0) { + return false; + } + seen |= h; + n++; + + /* 21 个信号占满 21 个有效位,一位不多一位不少。 */ + return n == 21 && seen == SR595_MASK_VALID; +} + +/* ---- 影子 ---------------------------------------------------------------- */ + +static uint32_t s_shadow; +static bool s_dirty; +static bool s_inited; + +uint32_t sr595_shadow(void) { return s_shadow; } +bool sr595_dirty(void) { return s_dirty; } + +void sr595_modify(uint32_t mask, uint32_t value) +{ + /* 越出有效位 = 位号算错了(多半是把 rail 当下标又减了一次 1)。 + 悄悄忽略的话,那一位会一直是 0,而「按键没反应」要到接上真手机才发现。 */ + assert((mask & ~SR595_MASK_VALID) == 0); + + uint32_t next = (s_shadow & ~mask) | (value & mask); + if (next != s_shadow) { + s_shadow = next; + s_dirty = true; + } +} + +void sr595_set_hub_reset(bool in_reset) +{ + /* 低有效:按住复位 = 输出 0。整个固件里这个取反只出现这一次。 */ + uint32_t bit = (uint32_t)1u << SR595_BIT_HUB_RST; + sr595_modify(bit, in_reset ? 0u : bit); +} + +/* ---- 移位链 -------------------------------------------------------------- */ + +/* 先出错的那个错误码留住,后面照样把该发的边发完 —— 半帧数据留在链上比整帧发完更糟。 */ +static void keep(hal_err_t *first, hal_err_t e) +{ + if (*first == HAL_OK) { + *first = e; + } +} + +static void clock_bit(hal_err_t *err, int bit) +{ + keep(err, hal_gpio_write(SR595_PIN_SER, bit)); + keep(err, hal_gpio_write(SR595_PIN_SRCLK, 1)); /* 上升沿采样 SER */ + keep(err, hal_gpio_write(SR595_PIN_SRCLK, 0)); +} + +/* 先移入的字节走到链尾 ⇒ 发送顺序 **U33 → U22 → U21**; + 每个字节里 QH(bit7)先发,同样因为先移入的位走得最远。 */ +static const uint8_t k_send_order[SR595_CHIP_COUNT] = { + SR595_CHIP_U33, + SR595_CHIP_U22, + SR595_CHIP_U21, +}; + +static hal_err_t shift_and_latch(uint32_t value) +{ + hal_err_t err = HAL_OK; + + for (int i = 0; i < SR595_CHIP_COUNT; i++) { + uint8_t byte = (uint8_t)((value >> (8 * k_send_order[i])) & 0xFFu); + for (int b = 7; b >= 0; b--) { + clock_bit(&err, (byte >> b) & 1); + } + } + + /* RCLK 上升沿之前输出一点不变 ⇒ 整帧是原子的。 */ + keep(&err, hal_gpio_write(SR595_PIN_RCLK, 1)); + keep(&err, hal_gpio_write(SR595_PIN_RCLK, 0)); + return err; +} + +hal_err_t sr595_init(void) +{ + hal_err_t err = HAL_OK; + + s_inited = false; + + /* ① 三根数据线配成输出并置低。`OE#` **故意还不碰** —— 板上 R609 把它拉在高位, + 三片输出保持高阻,15 个栅极被各自的 100 kΩ 拉低。 */ + keep(&err, hal_gpio_config(SR595_PIN_SER, HAL_GPIO_OUTPUT)); + keep(&err, hal_gpio_config(SR595_PIN_SRCLK, HAL_GPIO_OUTPUT)); + keep(&err, hal_gpio_config(SR595_PIN_RCLK, HAL_GPIO_OUTPUT)); + keep(&err, hal_gpio_write(SR595_PIN_SER, 0)); + keep(&err, hal_gpio_write(SR595_PIN_SRCLK, 0)); + keep(&err, hal_gpio_write(SR595_PIN_RCLK, 0)); + if (err != HAL_OK) { + return err; + } + + /* ② 安全影子先锁存进去(上电后移位寄存器内容不确定,`MR#` 接死在 +3V3, + 没有别的办法把它清干净)。 */ + s_shadow = SR595_SHADOW_SAFE; + s_dirty = false; + err = shift_and_latch(s_shadow); + if (err != HAL_OK) { + return err; + } + + /* ③ 这才使能输出。②③ 换个个儿 = 上电瞬间把随机值放到 15 个栅极上。 */ + keep(&err, hal_gpio_config(SR595_PIN_OE_N, HAL_GPIO_OUTPUT)); + keep(&err, hal_gpio_write(SR595_PIN_OE_N, 0)); + if (err != HAL_OK) { + return err; + } + + s_inited = true; + return HAL_OK; +} + +hal_err_t sr595_flush(void) +{ + if (!s_inited) { + return HAL_ERR_STATE; + } + if (!s_dirty) { + return HAL_OK; /* 不空发一帧:链上已经是这个值了 */ + } + + hal_err_t err = shift_and_latch(s_shadow); + if (err == HAL_OK) { + s_dirty = false; /* 发失败就留着脏,下一次 flush 会重发整帧 */ + } + return err; +} + +hal_err_t sr595_write(uint32_t mask, uint32_t value) +{ + sr595_modify(mask, value); + return sr595_flush(); +} diff --git a/firmware/components/phonerail_hal/sim/hal_gpio_sim.c b/firmware/components/phonerail_hal/sim/hal_gpio_sim.c index 17404b9..0ac5c72 100644 --- a/firmware/components/phonerail_hal/sim/hal_gpio_sim.c +++ b/firmware/components/phonerail_hal/sim/hal_gpio_sim.c @@ -15,6 +15,11 @@ static pin_t s_pin[SIM_GPIO_PINS]; void sim_gpio_reset_internal(void); /* 只给 sim_hal_reset() 用 */ +/* 假 74HC595 链的窃听口(sim_sr595.c)。没 attach 过就是个空动作。 + 放在这里而不是让测试自己数边:移位链要看的是**电平的跳变**, + 而 hal_gpio_write() 写同一个值也会计一次 writes。 */ +void sim_sr595_gpio_hook(int pin, int level); + void sim_gpio_reset_internal(void) { memset(s_pin, 0, sizeof(s_pin)); } static bool valid(int pin) { return pin >= 0 && pin < SIM_GPIO_PINS; } @@ -30,6 +35,12 @@ hal_err_t hal_gpio_config(int pin, hal_gpio_mode_t mode) /* 上拉输入没人驱动时读回高电平 —— 五路 FLT/PG 都是开漏 + 上拉, 「没有故障」在假板子上也必须是 1,不然测试会把默认 0 当成一直有故障。 */ p->level = (mode == HAL_GPIO_INPUT_PULLUP) ? 1 : 0; + /* 配成输出的那一刻引脚就开始驱动了(ESP-IDF 的 gpio_config 也是这个行为, + 输出寄存器复位值 0)。`KEY_OE#` 正是靠这一条:配成输出 = 输出立刻使能, + 所以 sr595_init() 必须等安全值锁存完了再配它。 */ + if (mode == HAL_GPIO_OUTPUT) { + sim_sr595_gpio_hook(pin, p->level); + } return HAL_OK; } @@ -40,6 +51,7 @@ hal_err_t hal_gpio_write(int pin, int level) } s_pin[pin].level = level ? 1 : 0; s_pin[pin].writes++; + sim_sr595_gpio_hook(pin, s_pin[pin].level); return HAL_OK; } diff --git a/firmware/components/phonerail_hal/sim/sim_hal.c b/firmware/components/phonerail_hal/sim/sim_hal.c index 3a3347f..19c3c5b 100644 --- a/firmware/components/phonerail_hal/sim/sim_hal.c +++ b/firmware/components/phonerail_hal/sim/sim_hal.c @@ -4,6 +4,7 @@ void sim_i2c_reset_internal(void); void sim_gpio_reset_internal(void); +void sim_sr595_reset_internal(void); void sim_pwm_reset_internal(void); void sim_time_reset_internal(void); @@ -11,6 +12,7 @@ void sim_hal_reset(void) { sim_i2c_reset_internal(); sim_gpio_reset_internal(); + sim_sr595_reset_internal(); sim_pwm_reset_internal(); sim_time_reset_internal(); } diff --git a/firmware/components/phonerail_hal/sim/sim_hal.h b/firmware/components/phonerail_hal/sim/sim_hal.h index 8560559..daf2c25 100644 --- a/firmware/components/phonerail_hal/sim/sim_hal.h +++ b/firmware/components/phonerail_hal/sim/sim_hal.h @@ -66,6 +66,31 @@ int sim_gpio_level(int pin); /* 被 hal_gpio_write() 写成功过几次。断言「改 CH1 没动 CH2~5」用得上(A5)。 */ uint32_t sim_gpio_writes(int pin); +/* ---------------- 74HC595 ×3 的 24 位链 ---------------- */ + +/* 按 datasheet 建模的假移位链,**只看线上真实发生的边**(SRCLK / RCLK 上升沿)。 + 对着驱动自己的影子变量断言等于自己证明自己 —— 字节顺序发反、每帧多打一个时钟、 + RCLK 打早了,影子变量一律看不出来。位号与 sr595.h 一致:0 = U21.QA,23 = U33.QH。 + + attach 之后移位寄存器与输出锁存器被塞成 0xA5A5A5:真板子上电时它们的内容 + **不确定**(`MR#` 接死在 +3V3,没有复位线),驱动必须先锁存安全值再使能 OE#。 */ +void sim_sr595_attach(int ser_pin, int srclk_pin, int rclk_pin, int oe_pin); + +uint32_t sim_sr595_outputs(void); /* 输出锁存器(不管 OE# 是高是低) */ +uint32_t sim_sr595_shift(void); /* 移位寄存器当前内容(还没锁存的那一份) */ +uint32_t sim_sr595_clocks(void); /* SRCLK 上升沿总数:一帧应当正好 +24 */ +uint32_t sim_sr595_latches(void); /* RCLK 上升沿总数:一帧应当正好 +1 */ +int sim_sr595_oe(void); /* OE# 当前电平。初值 1 —— 板上 R609 拉着 */ + +/* OE# 第一次被拉低那一刻的现场。断言「输出使能之前已经锁存过安全值」用: + 驱动要是把顺序换了,enable_latches 会是 0、enable_outputs 会是那坨 0xA5A5A5。 */ +bool sim_sr595_enabled(void); +uint32_t sim_sr595_enable_latches(void); +uint32_t sim_sr595_enable_outputs(void); + +/* 某一位在栅极上的实际电平;OE# 为高时返回 -1(高阻,不是 0)。 */ +int sim_sr595_pin(int bit); + /* ---------------- PWM ---------------- */ int sim_pwm_pin(int ch); /* 未配置返回 -1 */ diff --git a/firmware/components/phonerail_hal/sim/sim_sr595.c b/firmware/components/phonerail_hal/sim/sim_sr595.c new file mode 100644 index 0000000..2b66e8d --- /dev/null +++ b/firmware/components/phonerail_hal/sim/sim_sr595.c @@ -0,0 +1,98 @@ +/* 假的 74HC595 ×3 移位链 —— 挂在 GPIO sim 上,只看**线上真实发生的边**。 + + 为什么要这么一个东西:A5 的两条验收断言(改一路不动别路、字节顺序 U33→U22→U21) + 如果只对着驱动自己的影子变量断言,那是**自己证明自己** —— 字节顺序发反了、 + 每帧多打一个时钟、RCLK 在数据发完之前就打了,影子变量一律看不出来。 + 所以这里按 datasheet 建模:SRCLK 上升沿移一格,RCLK 上升沿把移位寄存器抄进输出锁存器。 + + 24 级的编号与 sr595.h 一致:0 = U21.QA(DS 进来的第一级),23 = U33.QH(链尾)。 */ +#include +#include + +#include "sim_hal.h" + +typedef struct { + bool attached; + int ser_pin, srclk_pin, rclk_pin, oe_pin; + int ser, srclk, rclk, oe; /* 当前电平;oe 初值 1 = 板上 R609 拉着 */ + uint32_t shift; /* 移位寄存器(未锁存) */ + uint32_t out; /* 输出锁存器 */ + uint32_t clocks; /* SRCLK 上升沿总数 */ + uint32_t latches; /* RCLK 上升沿总数 */ + bool enabled_once; + uint32_t enable_latches; /* OE# 第一次被拉低时,已经锁存过几次 */ + uint32_t enable_out; /* OE# 第一次被拉低那一刻,输出锁存器里是什么 */ +} chain_t; + +static chain_t s_ch; + +void sim_sr595_reset_internal(void); /* 只给 sim_hal_reset() 用 */ +void sim_sr595_gpio_hook(int pin, int level); + +void sim_sr595_reset_internal(void) { memset(&s_ch, 0, sizeof(s_ch)); } + +void sim_sr595_attach(int ser_pin, int srclk_pin, int rclk_pin, int oe_pin) +{ + memset(&s_ch, 0, sizeof(s_ch)); + s_ch.attached = true; + s_ch.ser_pin = ser_pin; + s_ch.srclk_pin = srclk_pin; + s_ch.rclk_pin = rclk_pin; + s_ch.oe_pin = oe_pin; + /* `OE#` 上电就被 R609 拉高 —— 高阻,不是 0。 */ + s_ch.oe = 1; + /* 上电后移位寄存器与输出锁存器的内容**不确定**(`MR#` 接死在 +3V3,没有复位线)。 + 这里塞一个显眼的非零值:驱动要是先使能 OE# 再锁存安全值, + `sim_sr595_enable_outputs()` 就会把这坨脏东西原样报出来。 */ + s_ch.shift = 0x00A5A5A5u & 0x00FFFFFFu; + s_ch.out = s_ch.shift; +} + +void sim_sr595_gpio_hook(int pin, int level) +{ + if (!s_ch.attached) { + return; + } + level = level ? 1 : 0; + + if (pin == s_ch.ser_pin) { + s_ch.ser = level; + } else if (pin == s_ch.srclk_pin) { + if (level == 1 && s_ch.srclk == 0) { /* 上升沿:整条链往编号大的方向挪一格 */ + s_ch.shift = ((s_ch.shift << 1) | (uint32_t)s_ch.ser) & 0x00FFFFFFu; + s_ch.clocks++; + } + s_ch.srclk = level; + } else if (pin == s_ch.rclk_pin) { + if (level == 1 && s_ch.rclk == 0) { + s_ch.out = s_ch.shift; + s_ch.latches++; + } + s_ch.rclk = level; + } else if (pin == s_ch.oe_pin) { + if (level == 0 && s_ch.oe != 0 && !s_ch.enabled_once) { + s_ch.enabled_once = true; + s_ch.enable_latches = s_ch.latches; + s_ch.enable_out = s_ch.out; + } + s_ch.oe = level; + } +} + +uint32_t sim_sr595_outputs(void) { return s_ch.out; } +uint32_t sim_sr595_shift(void) { return s_ch.shift; } +uint32_t sim_sr595_clocks(void) { return s_ch.clocks; } +uint32_t sim_sr595_latches(void) { return s_ch.latches; } +int sim_sr595_oe(void) { return s_ch.oe; } +bool sim_sr595_enabled(void) { return s_ch.enabled_once; } +uint32_t sim_sr595_enable_latches(void) { return s_ch.enable_latches; } +uint32_t sim_sr595_enable_outputs(void) { return s_ch.enable_out; } + +int sim_sr595_pin(int bit) +{ + assert(bit >= 0 && bit < 24); + if (s_ch.oe) { + return -1; /* 高阻。栅极侧靠自己的 100 kΩ 下拉,HUB_RST 侧靠 R716 上拉 */ + } + return (int)((s_ch.out >> bit) & 1u); +} diff --git a/firmware/host/CMakeLists.txt b/firmware/host/CMakeLists.txt index 4da1f19..3ba020c 100644 --- a/firmware/host/CMakeLists.txt +++ b/firmware/host/CMakeLists.txt @@ -32,6 +32,7 @@ set(PHONERAIL_HAL_SIM_SRCS ${PHONERAIL_HAL_DIR}/sim/sim_hal.c ${PHONERAIL_HAL_DIR}/sim/hal_i2c_sim.c ${PHONERAIL_HAL_DIR}/sim/hal_gpio_sim.c + ${PHONERAIL_HAL_DIR}/sim/sim_sr595.c ${PHONERAIL_HAL_DIR}/sim/hal_pwm_sim.c ${PHONERAIL_HAL_DIR}/sim/hal_time_sim.c ) @@ -41,6 +42,7 @@ set(PHONERAIL_DRV_DIR ${FW_ROOT}/components/drv) set(PHONERAIL_DRV_SRCS ${PHONERAIL_DRV_DIR}/ina226.c ${PHONERAIL_DRV_DIR}/dac63204.c + ${PHONERAIL_DRV_DIR}/sr595.c ) add_library(phonerail_core STATIC diff --git a/firmware/main/phonerail.h b/firmware/main/phonerail.h index f29ad38..82bb068 100644 --- a/firmware/main/phonerail.h +++ b/firmware/main/phonerail.h @@ -3,7 +3,7 @@ #define PHONERAIL_H /* 固件版本。规则:<主>.<次>.<修订>-<最后完成的任务包> */ -#define PHONERAIL_FW_VERSION "0.1.0-a4" +#define PHONERAIL_FW_VERSION "0.1.0-a5" /* 通道数。五路直供,见设计文档 §2。 */ #define PHONERAIL_RAIL_COUNT 5 diff --git a/firmware/test/test_sr595.c b/firmware/test/test_sr595.c new file mode 100644 index 0000000..cb60df4 --- /dev/null +++ b/firmware/test/test_sr595.c @@ -0,0 +1,372 @@ +/* A5:74HC595 24 位链 + 影子寄存器单一写入点。 + 两条验收断言(固件开发计划 §5 A5 那一行)都打了 ⭐: + ① 改 CH1 的按键**不动** CH2~5 的位 + ② 字节顺序 **U33 → U22 → U21** + + 全部断言都对着 `sim_sr595_*`(按 datasheet 建模的假移位链,只看线上真实发生的 + 边),不对着驱动自己的影子变量 —— 后者是自己证明自己。 */ +#include "hal_gpio.h" +#include "phonerail.h" +#include "sim_hal.h" +#include "sr595.h" +#include "unity.h" + +void setUp(void) { sim_hal_reset(); } +void tearDown(void) {} + +static void attach(void) +{ + sim_sr595_attach(SR595_PIN_SER, SR595_PIN_SRCLK, SR595_PIN_RCLK, SR595_PIN_OE_N); +} + +static void up(void) +{ + attach(); + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_init()); +} + +/* 链上某一位现在是什么(输出锁存器,不是影子)。 */ +static int out_bit(int bit) { return (int)((sim_sr595_outputs() >> bit) & 1u); } + +/* ---- 位表:只能查,不能算 ------------------------------------------------- */ + +/* 位表逐条对着 `.claude/pcb1-parts.json` 里的真实焊盘网络(设计文档 §26.18 C)。 + 这张表**不是任何公式**:CH2/CH3 在链尾那片 U33 上,CH5 的三个键还是倒着排的。 */ +static void test_bit_table_matches_the_board(void) +{ + /* CH1 -> U21.QB QC QD */ + TEST_ASSERT_EQUAL_INT(1, sr595_key_bit(1, SR595_KEY_PWR)); + TEST_ASSERT_EQUAL_INT(2, sr595_key_bit(1, SR595_KEY_VUP)); + TEST_ASSERT_EQUAL_INT(3, sr595_key_bit(1, SR595_KEY_VDN)); + /* CH2 -> U33.QD QB QC */ + TEST_ASSERT_EQUAL_INT(19, sr595_key_bit(2, SR595_KEY_PWR)); + TEST_ASSERT_EQUAL_INT(17, sr595_key_bit(2, SR595_KEY_VUP)); + TEST_ASSERT_EQUAL_INT(18, sr595_key_bit(2, SR595_KEY_VDN)); + /* CH3 -> U33.QG QF QE */ + TEST_ASSERT_EQUAL_INT(22, sr595_key_bit(3, SR595_KEY_PWR)); + TEST_ASSERT_EQUAL_INT(21, sr595_key_bit(3, SR595_KEY_VUP)); + TEST_ASSERT_EQUAL_INT(20, sr595_key_bit(3, SR595_KEY_VDN)); + /* CH4 -> U22.QB QC QD */ + TEST_ASSERT_EQUAL_INT(9, sr595_key_bit(4, SR595_KEY_PWR)); + TEST_ASSERT_EQUAL_INT(10, sr595_key_bit(4, SR595_KEY_VUP)); + TEST_ASSERT_EQUAL_INT(11, sr595_key_bit(4, SR595_KEY_VDN)); + /* CH5 -> U22.QH QG QF —— 倒着的 */ + TEST_ASSERT_EQUAL_INT(15, sr595_key_bit(5, SR595_KEY_PWR)); + TEST_ASSERT_EQUAL_INT(14, sr595_key_bit(5, SR595_KEY_VUP)); + TEST_ASSERT_EQUAL_INT(13, sr595_key_bit(5, SR595_KEY_VDN)); + + TEST_ASSERT_EQUAL_INT(16, sr595_edl_bit(1)); /* U33.QA —— 只剩这一路还在 U33 */ + TEST_ASSERT_EQUAL_INT(7, sr595_edl_bit(2)); /* U21.QH */ + TEST_ASSERT_EQUAL_INT(6, sr595_edl_bit(3)); /* U21.QG */ + TEST_ASSERT_EQUAL_INT(0, sr595_edl_bit(4)); /* U21.QA */ + TEST_ASSERT_EQUAL_INT(5, sr595_edl_bit(5)); /* U21.QF */ +} + +/* 把「一定会被写出来的那个算式」按死:三键顺排 `bit = 3(rail−1) + key`。 + ⚠️ CH4 **碰巧**就是 9/10/11,和公式一模一样 —— 所以这里只能整体断言 + 「15 位里只有 CH4 那三位对得上」,不能逐路断言「都不等于公式」。 + 写成算式的症状是**按 CH1 的电源键按到了别路的音量键**:板子照样正常工作, + 功能测试测不出来(§26.18)。 */ +static void test_bit_table_is_not_a_formula(void) +{ + int naive_hits = 0; + for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) { + for (int k = 0; k < SR595_KEY_COUNT; k++) { + if (sr595_key_bit(rail, (sr595_key_t)k) == 3 * (rail - 1) + k) { + naive_hits++; + } + } + } + TEST_ASSERT_EQUAL_INT_MESSAGE(3, naive_hits, + "15 位里只有 CH4 的三位碰巧和顺排公式重合"); + + for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) { + /* 每一路的三个键在表里**未必**是 PWR + sr595_key_bit(rail, SR595_KEY_VDN)); + } + /* 「U33 是 EDL 专用片、EDL_ENn 在它的第 n−1 位」—— 只剩 EDL_EN1 还对 */ + if (rail >= 2) { + TEST_ASSERT_NOT_EQUAL_INT(16 + (rail - 1), sr595_edl_bit(rail)); + } + } + + /* CH2 / CH3 的六个键位全在链尾那片 U33(bit16~23)上,一个都不在 U21 */ + for (int k = 0; k < SR595_KEY_COUNT; k++) { + TEST_ASSERT_TRUE(sr595_key_bit(2, (sr595_key_t)k) >= 16); + TEST_ASSERT_TRUE(sr595_key_bit(3, (sr595_key_t)k) >= 16); + } +} + +/* 21 个信号占满 21 个有效位,一位不多一位不少,空脚一个都没被占。启动自检用。 */ +static void test_map_ok(void) +{ + TEST_ASSERT_TRUE(sr595_map_ok()); + TEST_ASSERT_EQUAL_HEX32(0x00FFEEEFu, SR595_MASK_VALID); /* 去掉 bit4/8/12 */ + + uint32_t keys = sr595_all_keys_mask(); + int n = 0; + for (int b = 0; b < SR595_BITS; b++) { + n += (int)((keys >> b) & 1u); + } + TEST_ASSERT_EQUAL_INT_MESSAGE(15, n, "15 路侧键"); + /* 按键掩码里不许混进 EDL 与 HUB_RST */ + TEST_ASSERT_EQUAL_HEX32(0, keys & ((uint32_t)1u << SR595_BIT_HUB_RST)); + for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) { + TEST_ASSERT_EQUAL_HEX32(0, keys & ((uint32_t)1u << sr595_edl_bit(rail))); + } +} + +/* ---- ② 字节顺序 ---------------------------------------------------------- */ + +/* ⭐ 验收主项二:一帧的字节顺序是 **U33 → U22 → U21**。 + 先移入的位走得最远,所以链尾那片的字节要先发。发反了 U21 的字节会停在 U33 上 + —— 现象是「按 CH1 的电源键,CH3 的手机弹出了 EDL」。 + 这里靠的是假移位链自己按 datasheet 移的结果,不是驱动的影子变量。 */ +static void test_byte_order_is_u33_u22_u21(void) +{ + up(); + + /* 三片各给一个只有该片认得的图案,这样字节走错片一眼就看出来。 */ + const uint32_t pattern = 0x00A1B2C3u & SR595_MASK_VALID; + sr595_modify(SR595_MASK_VALID, pattern); + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_flush()); + + TEST_ASSERT_EQUAL_HEX32(pattern, sim_sr595_outputs()); + TEST_ASSERT_EQUAL_HEX32_MESSAGE(pattern & 0xFFu, sim_sr595_outputs() & 0xFFu, + "U21 = 影子的 bit0~7"); + TEST_ASSERT_EQUAL_HEX32_MESSAGE((pattern >> 8) & 0xFFu, (sim_sr595_outputs() >> 8) & 0xFFu, + "U22 = 影子的 bit8~15"); + TEST_ASSERT_EQUAL_HEX32_MESSAGE((pattern >> 16) & 0xFFu, (sim_sr595_outputs() >> 16) & 0xFFu, + "U33 = 影子的 bit16~23(链尾,字节要先发)"); + + /* 字节顺序反过来发的话,输出会变成字节序倒过来的那个值 —— 图案不对称,认得出来。 */ + uint32_t reversed = ((pattern & 0xFFu) << 16) | (pattern & 0xFF00u) | ((pattern >> 16) & 0xFFu); + TEST_ASSERT_NOT_EQUAL_HEX32(reversed, sim_sr595_outputs()); +} + +/* 一帧正好 24 个 SRCLK 上升沿 + 1 个 RCLK 上升沿。 + 多打一个时钟整条链就转一格(**每一位都错开一位**,症状是十五个按键全乱套), + 而只看最终电压电流是完全正常的。 */ +static void test_one_frame_is_24_clocks_and_1_latch(void) +{ + up(); + uint32_t c0 = sim_sr595_clocks(), l0 = sim_sr595_latches(); + + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_write(sr595_key_mask(2), sr595_key_mask(2))); + TEST_ASSERT_EQUAL_UINT32(c0 + 24, sim_sr595_clocks()); + TEST_ASSERT_EQUAL_UINT32(l0 + 1, sim_sr595_latches()); +} + +/* RCLK 打点之前输出一点不变 ⇒ 整帧是原子的,组合键不会先单按一个。 + 假移位链把「移位寄存器」和「输出锁存器」分开建模,正是为了能断言这一条。 */ +static void test_frame_is_atomic(void) +{ + up(); + uint32_t before = sim_sr595_outputs(); + + /* 手动把一帧发一半:只移 8 位,不打 RCLK。 */ + for (int i = 0; i < 8; i++) { + TEST_ASSERT_EQUAL_INT(HAL_OK, hal_gpio_write(SR595_PIN_SER, 1)); + TEST_ASSERT_EQUAL_INT(HAL_OK, hal_gpio_write(SR595_PIN_SRCLK, 1)); + TEST_ASSERT_EQUAL_INT(HAL_OK, hal_gpio_write(SR595_PIN_SRCLK, 0)); + } + TEST_ASSERT_NOT_EQUAL_HEX32(before, sim_sr595_shift()); /* 移位寄存器动了 */ + TEST_ASSERT_EQUAL_HEX32(before, sim_sr595_outputs()); /* 输出一点没动 */ +} + +/* ---- ① 改一路不动别路 ---------------------------------------------------- */ + +/* ⭐ 验收主项一:改 CH1 的按键,CH2~5 的 12 位一位都不许动。 + 这是「全固件只有一个函数能写 595」的核心理由 —— 多处直接操作移位链的症状是 + **另一台手机的按键被顺手清掉**,要两个动作正好撞在一起才复现。 */ +static void test_changing_ch1_leaves_ch2_to_ch5_alone(void) +{ + up(); + + /* 先让 CH2~5 各按住一个不同的键,作为「别人的现场」。 */ + uint32_t others = 0; + others |= (uint32_t)1u << sr595_key_bit(2, SR595_KEY_PWR); + others |= (uint32_t)1u << sr595_key_bit(3, SR595_KEY_VUP); + others |= (uint32_t)1u << sr595_key_bit(4, SR595_KEY_VDN); + others |= (uint32_t)1u << sr595_key_bit(5, SR595_KEY_PWR); + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_write(others, others)); + TEST_ASSERT_EQUAL_HEX32(others, sim_sr595_outputs() & sr595_all_keys_mask()); + + /* CH1 按下电源键 -> 松开。两次之后,别路的四位必须原封不动。 */ + uint32_t k1_pwr = (uint32_t)1u << sr595_key_bit(1, SR595_KEY_PWR); + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_write(k1_pwr, k1_pwr)); + TEST_ASSERT_EQUAL_HEX32_MESSAGE(others, sim_sr595_outputs() & ~sr595_key_mask(1) & sr595_all_keys_mask(), + "按下 CH1 动了别路的位"); + TEST_ASSERT_EQUAL_INT(1, out_bit(sr595_key_bit(1, SR595_KEY_PWR))); + + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_write(k1_pwr, 0)); + TEST_ASSERT_EQUAL_HEX32_MESSAGE(others, sim_sr595_outputs() & ~sr595_key_mask(1) & sr595_all_keys_mask(), + "松开 CH1 动了别路的位"); + TEST_ASSERT_EQUAL_INT(0, out_bit(sr595_key_bit(1, SR595_KEY_PWR))); + + /* 顺带:HUB_RST 从头到尾没被别人顺手清掉。 */ + TEST_ASSERT_EQUAL_INT(1, out_bit(SR595_BIT_HUB_RST)); +} + +/* 「一路全松开」用 sr595_key_mask(),同样不许碰别路,也不许碰本路的 EDL_EN。 */ +static void test_releasing_one_rail_keeps_edl_and_others(void) +{ + up(); + + uint32_t all_keys = sr595_all_keys_mask(); + uint32_t edl3 = (uint32_t)1u << sr595_edl_bit(3); + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_write(all_keys | edl3, all_keys | edl3)); + + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_write(sr595_key_mask(3), 0)); + TEST_ASSERT_EQUAL_HEX32(0, sim_sr595_outputs() & sr595_key_mask(3)); + TEST_ASSERT_EQUAL_HEX32(all_keys & ~sr595_key_mask(3), sim_sr595_outputs() & all_keys); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, out_bit(sr595_edl_bit(3)), "松开按键不该碰 EDL_EN3"); +} + +/* 组合键(VOL− + PWR)必须落在**同一帧**里:一次 sr595_write() 两位一起给。 + 分两次写会先单按一个键 —— EDL 的组合键对顺序是敏感的(需求 §10.6)。 */ +static void test_combo_lands_in_one_frame(void) +{ + up(); + uint32_t l0 = sim_sr595_latches(); + + uint32_t combo = ((uint32_t)1u << sr595_key_bit(4, SR595_KEY_PWR)) | + ((uint32_t)1u << sr595_key_bit(4, SR595_KEY_VDN)); + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_write(combo, combo)); + + TEST_ASSERT_EQUAL_UINT32_MESSAGE(l0 + 1, sim_sr595_latches(), "组合键必须一帧发完"); + TEST_ASSERT_EQUAL_HEX32(combo, sim_sr595_outputs() & sr595_key_mask(4)); +} + +/* ---- 上电顺序与 HUB_RST -------------------------------------------------- */ + +/* `HUB_RST` 是**低有效**(USB2517I 的 RESET_N,设计文档 §21.7)。 + 影子全 0 会把 Hub 一直摁在复位里 —— 现象是「插上枚举不出来」, + 而五路手机的电压电流全都正常。所以上电安全值不是 0。 */ +static void test_hub_rst_is_active_low_and_released_after_init(void) +{ + up(); + TEST_ASSERT_EQUAL_HEX32(SR595_SHADOW_SAFE, sr595_shadow()); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, out_bit(SR595_BIT_HUB_RST), "上电后 Hub 不能被摁在复位里"); + + sr595_set_hub_reset(true); + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_flush()); + TEST_ASSERT_EQUAL_INT(0, out_bit(SR595_BIT_HUB_RST)); + + sr595_set_hub_reset(false); + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_flush()); + TEST_ASSERT_EQUAL_INT(1, out_bit(SR595_BIT_HUB_RST)); + + /* 复位 Hub 期间 15 个按键一个都不许被按下去。 */ + sr595_set_hub_reset(true); + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_flush()); + TEST_ASSERT_EQUAL_HEX32(0, sim_sr595_outputs() & sr595_all_keys_mask()); +} + +/* 上电顺序:先锁存安全值,**再**使能 OE#。 + 换个个儿 = 把移位寄存器里的随机值放到 15 个栅极上,也就是五台手机的电源键 + 可能一起被按下去(设计文档 §8.1「复位安全三条」)。 + 假移位链 attach 时被塞了 0xA5A5A5,正是用来照出这个错的。 */ +static void test_outputs_are_enabled_only_after_a_safe_latch(void) +{ + attach(); + TEST_ASSERT_EQUAL_INT_MESSAGE(1, sim_sr595_oe(), "上电时 OE# 由 R609 拉高"); + TEST_ASSERT_FALSE(sim_sr595_enabled()); + + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_init()); + + TEST_ASSERT_TRUE_MESSAGE(sim_sr595_enabled(), "init 之后 OE# 必须被拉低"); + TEST_ASSERT_EQUAL_INT(0, sim_sr595_oe()); + TEST_ASSERT_TRUE_MESSAGE(sim_sr595_enable_latches() >= 1, + "OE# 拉低之前一帧都还没锁存过 —— 15 个栅极上是随机值"); + TEST_ASSERT_EQUAL_HEX32_MESSAGE(SR595_SHADOW_SAFE, sim_sr595_enable_outputs(), + "使能那一刻链上不是安全值"); + TEST_ASSERT_EQUAL_HEX32(0, sim_sr595_outputs() & sr595_all_keys_mask()); +} + +/* ---- 影子与刷新 ---------------------------------------------------------- */ + +/* 「改影子 -> 请求刷新」是两步:`sr595_modify()` 一个字节都不许发出去。 */ +static void test_modify_does_not_touch_the_chain(void) +{ + up(); + uint32_t c0 = sim_sr595_clocks(), out0 = sim_sr595_outputs(); + + sr595_modify(sr595_key_mask(5), sr595_key_mask(5)); + TEST_ASSERT_TRUE(sr595_dirty()); + TEST_ASSERT_EQUAL_UINT32_MESSAGE(c0, sim_sr595_clocks(), "modify 不许碰总线"); + TEST_ASSERT_EQUAL_HEX32(out0, sim_sr595_outputs()); + + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_flush()); + TEST_ASSERT_FALSE(sr595_dirty()); + TEST_ASSERT_EQUAL_HEX32(sr595_shadow(), sim_sr595_outputs()); +} + +/* 不脏就不空发一帧:24 个时钟 + 一次锁存不是免费的,而且真板子上每发一帧 + 都要占住那三根线。写一个和现在一样的值同样不算脏。 */ +static void test_flush_is_a_noop_when_clean(void) +{ + up(); + uint32_t c0 = sim_sr595_clocks(), l0 = sim_sr595_latches(); + + TEST_ASSERT_FALSE(sr595_dirty()); + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_flush()); + TEST_ASSERT_EQUAL_UINT32(c0, sim_sr595_clocks()); + TEST_ASSERT_EQUAL_UINT32(l0, sim_sr595_latches()); + + sr595_set_hub_reset(false); /* 已经是这个值了 */ + TEST_ASSERT_FALSE(sr595_dirty()); + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_flush()); + TEST_ASSERT_EQUAL_UINT32(l0, sim_sr595_latches()); +} + +/* value 里 mask 以外的位不许漏进影子(`sr595_write(bit, 0xFFFFFFFF)` 这种写法)。 */ +static void test_modify_only_touches_the_masked_bits(void) +{ + up(); + uint32_t k2 = (uint32_t)1u << sr595_key_bit(2, SR595_KEY_VUP); + + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_write(k2, 0xFFFFFFFFu)); + TEST_ASSERT_EQUAL_HEX32(SR595_SHADOW_SAFE | k2, sim_sr595_outputs()); +} + +/* 发送失败(把 SER 那根脚踢回输入,模拟「没配成输出就用」)要留着脏, + 下一次 flush 重发**整帧**。丢了脏标志 = 链上和影子永久对不上, + 而后面每一次 flush 都会「成功」。 */ +static void test_failed_flush_stays_dirty(void) +{ + up(); + uint32_t k1 = (uint32_t)1u << sr595_key_bit(1, SR595_KEY_VDN); + + TEST_ASSERT_EQUAL_INT(HAL_OK, hal_gpio_config(SR595_PIN_SER, HAL_GPIO_INPUT)); + sr595_modify(k1, k1); + TEST_ASSERT_EQUAL_INT(HAL_ERR_ARG, sr595_flush()); + TEST_ASSERT_TRUE_MESSAGE(sr595_dirty(), "发失败必须留着脏"); + + TEST_ASSERT_EQUAL_INT(HAL_OK, hal_gpio_config(SR595_PIN_SER, HAL_GPIO_OUTPUT)); + TEST_ASSERT_EQUAL_INT(HAL_OK, sr595_flush()); + TEST_ASSERT_EQUAL_HEX32(SR595_SHADOW_SAFE | k1, sim_sr595_outputs()); +} + +int main(void) +{ + UNITY_BEGIN(); + RUN_TEST(test_bit_table_matches_the_board); + RUN_TEST(test_bit_table_is_not_a_formula); + RUN_TEST(test_map_ok); + RUN_TEST(test_byte_order_is_u33_u22_u21); + RUN_TEST(test_one_frame_is_24_clocks_and_1_latch); + RUN_TEST(test_frame_is_atomic); + RUN_TEST(test_changing_ch1_leaves_ch2_to_ch5_alone); + RUN_TEST(test_releasing_one_rail_keeps_edl_and_others); + RUN_TEST(test_combo_lands_in_one_frame); + RUN_TEST(test_hub_rst_is_active_low_and_released_after_init); + RUN_TEST(test_outputs_are_enabled_only_after_a_safe_latch); + RUN_TEST(test_modify_does_not_touch_the_chain); + RUN_TEST(test_flush_is_a_noop_when_clean); + RUN_TEST(test_modify_only_touches_the_masked_bits); + RUN_TEST(test_failed_flush_stays_dirty); + return UNITY_END(); +} diff --git a/五路直供电源板设计.md b/五路直供电源板设计.md index c562255..38e7825 100644 --- a/五路直供电源板设计.md +++ b/五路直供电源板设计.md @@ -1,6827 +1,6854 @@ -# 五路手机直供电源板 设计文档 - -| 项 | 值 | -|---|---| -| 版本 | **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' -``` - -读到接近室温 = 对了;读到荒唐值 = 换另一个阻值再试。 - -
-如果还是想在实物上量(备用) - -拿一块裸的尾插小板:找 USB-C 附近那颗热敏电阻,量「BTB 座的 THERM 触点 → 小板 GND」 -的总电阻(把整个网络都包进去,包括可能的串阻)。 -**判别是不是 NTC**:量完用手指或热风捂一下再量 —— **NTC 阻值会明显下降,普通电阻几乎不变**。 - -
- -##### ⚠️ 唯一的弱环: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 该用什么 | 看小板上有没有、是什么封装 | - -一块尾插小板十几二十块钱,比任何图纸都便宜、也比图纸可靠(图纸还可能是别的版本)。 - -
-备用办法:直接量排线(更麻烦,只在拿不到小板时用) - -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 对地短路。** - -
- -> 不管走哪条路,都要目视确认这根排线**确实是尾插排线** —— -> 小米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 早查过一次)。 -- 维修行业换小板是整块换,不需要它的原理图 —— 所以本来就不会有。 - -
-已作废的方案 A 记录(2026-09-04 晚),留档备查 - -**(当时的定稿)装原厂尾插小板(或买原厂尾插排线),载板侧不做任何 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 插拔点。** - -
- ---- - -
-以下是已作废的方案 C 记录(2026-09-04 白天),留档备查 - -原话是「不接尾插小板,直接接到主板的尾插板接口」。这把上面的推荐推翻了, -**下面三条是方案 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 实测了。) - -
- -#### 问题二: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 步还要做。 - -
-原文(记录当时的判断过程) - - -副板上除 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 的主要理由之一。用户自己配天线之后不再成立。 - -
- -### 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**。 - -通道分配(**2026-09-06 按 PCB 几何重排,取代 09-03 那一版**,§26.18): - -| 路 | 片 | 通道 | -|---|---|---| -| `VDAC1` | U6(0x4A) | **OUT2** | -| `VDAC2` | U6 | **OUT0** | -| `VDAC3` | **U7(0x4B)** | OUT0 | -| `VDAC4` | U6 | **OUT1** | -| `VDAC5` | U7 | OUT1 | - -U6.OUT3、U7.OUT2/OUT3 未用(FB 也不接,datasheet 说未用通道保持 FB 悬空)。 - -> ⚠️ **「前三路在 U6、通道号 = rail−1」是旧版**,五路里有四路对不上。 -> 四个通道电气上完全对等,所以接错了**板子照样正常工作,只是调 CH1 的命令去调了 CH2**, -> 功能测试完全测不出来。固件里查表不要算:`dac63204_rail_addr()` / `dac63204_rail_ch()` -> (A4 已落地,`test_rail_map_is_not_the_naive_formula` 专门拦这一手)。 -> -> ⚠️ **未用通道不许上电**:FBx 悬空时电压输出模式是开环运放。 -> `COMMON-CONFIG` 里 U6 = `0x1E49`(OUT3 保持 Hi-Z)、U7 = `0x1FC9`(OUT2/OUT3 保持 Hi-Z)。 - -> **内部基准是 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 15,12 [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**。⇒ **别拿头几个网络外推总时长**。 +# 五路手机直供电源板 设计文档 + +| 项 | 值 | +|---|---| +| 版本 | **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 / VDAC4**(§26.18 重排过,不是 1/2/3)| **0x4A**(A0 接 SDA) | +| DAC63204 | U7 | **VDAC3 / 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' +``` + +读到接近室温 = 对了;读到荒唐值 = 换另一个阻值再试。 + +
+如果还是想在实物上量(备用) + +拿一块裸的尾插小板:找 USB-C 附近那颗热敏电阻,量「BTB 座的 THERM 触点 → 小板 GND」 +的总电阻(把整个网络都包进去,包括可能的串阻)。 +**判别是不是 NTC**:量完用手指或热风捂一下再量 —— **NTC 阻值会明显下降,普通电阻几乎不变**。 + +
+ +##### ⚠️ 唯一的弱环: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 该用什么 | 看小板上有没有、是什么封装 | + +一块尾插小板十几二十块钱,比任何图纸都便宜、也比图纸可靠(图纸还可能是别的版本)。 + +
+备用办法:直接量排线(更麻烦,只在拿不到小板时用) + +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 对地短路。** + +
+ +> 不管走哪条路,都要目视确认这根排线**确实是尾插排线** —— +> 小米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 早查过一次)。 +- 维修行业换小板是整块换,不需要它的原理图 —— 所以本来就不会有。 + +
+已作废的方案 A 记录(2026-09-04 晚),留档备查 + +**(当时的定稿)装原厂尾插小板(或买原厂尾插排线),载板侧不做任何 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 插拔点。** + +
+ +--- + +
+以下是已作废的方案 C 记录(2026-09-04 白天),留档备查 + +原话是「不接尾插小板,直接接到主板的尾插板接口」。这把上面的推荐推翻了, +**下面三条是方案 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 实测了。) + +
+ +#### 问题二: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 步还要做。 + +
+原文(记录当时的判断过程) + + +副板上除 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 的主要理由之一。用户自己配天线之后不再成立。 + +
+ +### 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 级联**(三片一条 24 位链,U33 在 P6 那一页,见 §22.4): + +``` +ESP32.KEY_SER → U21.DS(14) U21.Q7S(9) ──SR_CAS──> U22.DS U22.Q7S(9) ──SR_CAS2──> U33.DS + U33.Q7S(9) 不接(链尾) +``` + +先移入的位走得最远 ⇒ 落到 **U33.QH**。所以固件发送顺序是 +**U33 字节 → U22 字节 → U21 字节**,每个字节 **QH 先发**,最后一个 RCLK 上升沿统一生效。 + +输出分配(**2026-09-06 按 PCB 几何重排,取代 09-04 那一版**,§26.18 C。 +下表是 2026-09-06 从 `.claude/pcb1-parts.json` 的**真实焊盘网络**逐脚核回来的): + +| 影子位 | | QA(15) | QB(1) | QC(2) | QD(3) | QE(4) | QF(5) | QG(6) | QH(7) | +|---|---|---|---|---|---|---|---|---|---| +| 0~7 | **U21** | EDL_EN4 | K1_PWR | K1_VUP | K1_VDN | 空 | EDL_EN5 | EDL_EN3 | EDL_EN2 | +| 8~15 | **U22** | 空 | K4_PWR | K4_VUP | K4_VDN | 空 | K5_VDN | K5_VUP | K5_PWR | +| 16~23 | **U33** | EDL_EN1 | K2_VUP | K2_VDN | K2_PWR | K3_VDN | K3_VUP | K3_PWR | HUB_RST | + +约束是**每一路的三个键必须落在同一片的连续三脚上**(出芯片是一束线), +所以三个键的位号挨着,但**顺序每一路都不一样** —— CH3 / CH5 是倒着的。 + +> ⚠️ **「K1/K2/K3 顺排在 U21、U33 是 EDL 专用片」是旧版**(09-04 那张表), +> 15 路里有 12 路对不上。三片本来就是一条链,谁在哪一位只是移位的字节序 ⇒ +> **搞错了板子照样正常工作,只是按 CH1 的电源键按到了 CH4 的音量键**, +> 功能测试完全测不出来。和 DAC63204 的通道分配是同一类坑。 +> 固件里查表不要算:`sr595_key_bit()` / `sr595_edl_bit()`(A5 已落地, +> `test_bit_table_is_not_a_formula` 专门拦这一手 —— ⚠️ **CH4 碰巧就是 9/10/11**, +> 和顺排公式一模一样,所以那条测试只能整体断言「15 位里只有三位重合」)。 +> +> ⚠️ **`HUB_RST` 是低有效**(USB2517I 的 `RESET_N`,§21.7,R716 10 kΩ 上拉): +> 影子位 = 1 才是「Hub 正常跑」。全 0 的上电影子会把 Hub 一直摁在复位里 —— +> 现象是「插上枚举不出来」,而五路手机的电压电流全都正常。 +> 所以固件的上电安全影子是 `1 << 23`,不是 0。 + +`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**。 + +通道分配(**2026-09-06 按 PCB 几何重排,取代 09-03 那一版**,§26.18): + +| 路 | 片 | 通道 | +|---|---|---| +| `VDAC1` | U6(0x4A) | **OUT2** | +| `VDAC2` | U6 | **OUT0** | +| `VDAC3` | **U7(0x4B)** | OUT0 | +| `VDAC4` | U6 | **OUT1** | +| `VDAC5` | U7 | OUT1 | + +U6.OUT3、U7.OUT2/OUT3 未用(FB 也不接,datasheet 说未用通道保持 FB 悬空)。 + +> ⚠️ **「前三路在 U6、通道号 = rail−1」是旧版**,五路里有四路对不上。 +> 四个通道电气上完全对等,所以接错了**板子照样正常工作,只是调 CH1 的命令去调了 CH2**, +> 功能测试完全测不出来。固件里查表不要算:`dac63204_rail_addr()` / `dac63204_rail_ch()` +> (A4 已落地,`test_rail_map_is_not_the_naive_formula` 专门拦这一手)。 +> +> ⚠️ **未用通道不许上电**:FBx 悬空时电压输出模式是开环运放。 +> `COMMON-CONFIG` 里 U6 = `0x1E49`(OUT3 保持 Hi-Z)、U7 = `0x1FC9`(OUT2/OUT3 保持 Hi-Z)。 + +> **内部基准是 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 15,12 [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**。⇒ **别拿头几个网络外推总时长**。 --- @@ -6998,3 +7025,102 @@ I²C 不受影响(`SDA` / `SCL` / `INA_ALERT` 都不在重排名单里)。 2. **DRC 的「连接性」和「间距」新鲜度不一样。** 程序化建线之后连接性那一支是陈旧的 (实测 `location.reload()` 之后 855 → 198),**但间距那一支是即时的** —— 重载前后都是 74 条、内容逐字相同 ⇒ 间距报出来的东西**不能当成陈旧数据糊弄过去**。 + +#### 26.21b 善后跑下来的三条(都值一条规矩) + +1. **`--ripup` 能把一个碎片的铜拆到一根不剩** ⇒ `Comp.shapes` 空表 ⇒ + `E._bbox()` 里 `min([])` 抛 `ValueError`。而 `pcb1_route_sig` 是**跑完才一次性下发**的, + 一崩整轮白跑 —— 实测那次板上正停在「530 段拆了没补」。 + ⇒ `connect()` 开头加防护:**空碎片当成"这一条布不通",不许掀桌子**。 +2. **铺铜边界不要卡在净距的整数上。** `VINSW-TOP` 东边界 30.47 是贴着 `C6.1` 西边缘 + 30.670 留**整 0.200** 定的。`pcb1_parts_dump.py` 重抓之后(§26.17 挪过 C6 的位置 + 转了 180°) + 本地焊盘偏移差了 **0.04 mil ≈ 1 µm**,实测就变成 **0.199**,`--push` 当场不下发。 + ⇒ 改 **30.46**,留 0.01 的余量。 +3. **浮铜检查加了下限 `MIN_FLOAT_AREA = 1.0 mm²`**(`pcb1_pour.py`)。 + 布线一多,过孔反焊盘之间必然夹出 0.25×0.25(**正好一个栅格**)这种碎屑; + 实测两粒 0.06 / 0.19 mm²,比一个过孔盘还小。 + 门槛之上的两条真问题(南沿 **1312.8 mm²**、`3V3-SW` 里 **7.2 mm²**)一条都不会漏。 + 小于门槛的照样打印,只是不判红。 + +#### 26.21c 验收(2026-09-06 第二十五轮) + +| 项 | 修之前 | 修之后 | +|---|---|---| +| **DRC 间距错误** | **74** | **0** | +| DRC 连接性错误 | 855 | 113 | +| 已连通网络 | 148 | **176** | +| 还欠连接 | 87 条 / 74 网络 | **56 条 / 46 网络** | +| 真实几何全板复核(线-焊盘 / 孔-焊盘 / 线-线) | 45 处真重叠 | **0** | +| 焊盘网络 板上 vs 缓存 | 44 处不一致 | **0** | +| 铺铜 `--verify` | ❌ | ✅ 实测和计划对得上 | +| Inner2 I²C 干线 | — | 55 段 / 302 mm,两轮 `--ripup` 一段没丢 | + +--- + +### 26.22 剩余布不通的分类处理(2026-09-06 第二十六轮,用户拍板 A-1 + A-2) + +56 条布不通按**失败原因**分五类,处理办法完全不同: + +| 类 | 条数 | 症状 | 处理 | +|---|---:|---|---| +| **A 焊盘几何上出不去** | ~5 | 出线道 0.31~0.38 mm(要 0.60)| **挪件**(A-1)/ 改走内层(A-2)| +| **B USB 差分对** | 4 | 整束 0.7 mm 找不到走廊,布线器主动跳过 | 未做 | +| **C 五路母版系统性缺口** | ~14 | `$*N676/680/698/727`,**2.4~5.7 mm 的短跳**在多个通道同时失败 | 未做 | +| **D I²C / INA_ALERT 末端** | ~7 | 器件脚下顶层口袋里没有合法孔位 | 未做 | +| **E 单发拥堵** | ~26 | 被自己先布的线堵死 | 多跑几轮(`RIP_LIMIT=1` 是有意的,见源码注释)| + +#### ⭐ A-1「够净距」≠「出得去线」——检查体系里缺的一条 + +`pcb1_place.pad_clearance_errs()` 判的是**焊盘净距 ≥ 0.20**, +而一根 0.2 mm 的线要从两个焊盘中间出去需要 **0.20 + 0.20 + 0.20 = 0.60**。 + +`U6` / `U7`(DAC63204,WQFN-16 3×3,**四边出脚**)周围的卫星件正好卡在 **0.31~0.38**: + +| 堵点 | 挡住哪一排 | 道宽 → 挪 0.30 后 | +|---|---|---| +| `R615` / `R617` | U6/U7 **南排**(含 `U6.6` = SCL)| 0.312 → 0.612 | +| `C607` / `C610` | **北排**(含 `U6.16` / `U7.16`)| 0.315 → 0.615 | +| `C608` / `C611` | **东列**(VDAC2/3/4/5)| 0.376 → 0.676 | + +**本地六项全过、DRC 也零间距错误**,只有 `pcb1_escape_audit` 报「被围死」、 +布线器报「几何上就出不去」。实测 14 个脚的出线道 < 0.60,挪完**全部 ≥ 0.60**。 + +⇒ `pcb1_place.py` 新增 **`ESCAPE_NUDGE`** 表(在 `POS` 定稿后统一施加), +这样以后重跑摆位器不会把这一手抹掉。 +⚠️ **不能跑 `pcb1_place.py --push`** —— 它会把全部 342 个元件重新下发、 +把所有布线作废。只对这 6 颗做定点移动。 + +**挪完的善后**(一步都不能省): +挪动留下 20 处净距违规 + 2 个 GND 焊盘丢了扇出短线 ⇒ +① 删掉六颗周围 6 mm 内被压到的铜(**44 段 / 106.6 mm / 6 孔**,7 个网络); +② 给 `R615.1` / `R617.1` 补「短线 + 过孔」(要求孔心离焊盘 ≥ 0.45,别做成 0402 的盘内孔); +③ 重跑 `pcb1_i2c_l3.py`(`C607` / `R617` 的新位置会压到 `SDA` / `SCL` 的换层孔, + 那两个孔是它每轮重算的,自己会让开);④ 再 `route_sig --ripup --push`。 +⚠️ **绝不能用 `pcb_fanout.py --clean`** 善后 —— 它会把全板走线删光。 + +#### ⭐ A-2 `J25.24` 根本不用换针位 + +`pcb1_escape_audit` 报它「被围死」,第一反应是排针内圈针要换针位 —— +**查下来是错的**:`J25` 是双排 40 针,**24 号在外排(y=63.77),北边根本没有针**。 +真正堵住它的是 **`+5V` 那条 0.84 mm 的顶层干线**(L1,y=65.40,横贯 x 107.6~150.9), +离焊盘上沿只剩 **0.31 mm**;而底层那一片整个压在 `VO3_P` 小岛下。 + +**那条干线在 L1,挡不着内层。** 而排针针是通孔、L3 上本来就有铜 ⇒ +`POGO*` 从 Inner2 出去,**那一端连过孔都不用打**, +不用换针位、**不用动载板 PCB2 的对接定义**。 + +⇒ `pcb1_i2c_l3.NETS` 加进 5 条侧键线(`POGO3_PWR` / `POGO3_VDN` / `POGO4_VDN` / +`POGO5_PWR` / `POGO5_VUP`,全是 µA 级)。实测**五条全部一次布通**(各 2 片 → 1 片)。 + +#### `BUCK_PG` 试过,挪不动 —— 于是候选表改成「自动踢」 + +`BUCK_PG` 顶层占 234 mm、跨 121 mm,看着是最该进内层的。实测**五个分支一条都布不通**: +它们要去板子四角,而 L3 上 `y < 34` 往东只剩 `x 115~116` 那条 **1.0 mm** 的缝 +(净距后 0.6,刚好一根线),`+12V` 把别的通道全占了。 + +⇒ `pcb1_i2c_l3.py` 的连通性保险从「有一个变差就毙掉整轮」改成 +**「把变差的踢出候选表、重算一轮、剩下的照常下发」**。 +⚠️ 改这一段时踩到一个真 bug:第一版只换了 `run_plan` 的网络表, +**`drop_l/drop_v` 还是按完整候选表算的** ⇒ `--push` 会把被踢掉那个网络的铜 +删掉、又不给它重布,板子直接变差**而净距校核照样全绿**。 +踢网络时**拆除清单必须跟着重算**。 diff --git a/需求文档.md b/需求文档.md index c1870cb..911de50 100644 --- a/需求文档.md +++ b/需求文档.md @@ -475,6 +475,22 @@ ESP32.KEY_SER → U21 → U22 → U33 (先移入的字节落在链尾 U > 的方式「临时全松开」——那会让 15 个栅极同时进高阻,靠的是每个栅极自己的 100 kΩ 下拉, > 是复位路径,不是正常控制路径。 +> **2026-09-06 A5 落地**:`components/drv/sr595.{h,c}`。影子是一个 24 位整数 +> (bit0 = U21.QA 链首 … bit23 = U33.QH 链尾),唯一写入点是 `sr595_flush()`; +> 别处只准 `sr595_modify()` 改影子,组合键走 `sr595_write(mask, value)` 一帧发完。 +> 位表见设计文档 §17.2(§26.18 重排后的那张,**不是 09-04 那张**)。 +> +> 同处记下三条这一层的实现约定: +> - **上电顺序是「先锁存安全值,再使能 `OE#`」,不能换。** 三片的 `MR#` 接死在 +3V3, +> 没有复位线 ⇒ 上电时移位寄存器内容**不确定**。先拉低 `OE#` 就是把那坨随机值 +> 放到 15 个栅极上 —— 五台手机的电源键可能一起被按下去。所以 `sr595_init()` 里 +> `KEY_OE#` 在安全值锁存完之前**根本不配成输出**,靠板上 R609 上拉着。 +> (ESP-IDF 的 `gpio_config()` 一配成输出就开始驱动,输出寄存器复位值是 0。) +> - **`HUB_RST` 低有效**,所以上电安全影子是 `1 << 23` 而不是 0。写成 0 的现象是 +> 「Hub 插上枚举不出来」,而五路电压电流全都正常,看不出跟固件有关。 +> - **发送失败要留着脏**(`sr595_flush()` 失败不清 dirty,下次重发整帧)。 +> 丢了脏标志 = 链上和影子永久对不上,而后面每一次 flush 都会「成功」。 + ### 10.7 事件记录与存储 事件是 SW-3 的交付物,也是排查排线接触不良的唯一线索,所以**记录路径不能依赖上位机在线**。