- 规则:铜层 2→4,差分 0.28/0.18,间距 0.15,过孔 0.3/0.2(rules_base) - 几何:98×98 板框 + 4×M3,槽阵居中,L1 12V 大铜 + 指头(pcb_base) - 摆位:五插槽留 L1,其余 133 件翻到 L4;背面镜像规则实测;Hub 放走廊 2、 东移 2.5 mm;扇出圈 / 小件间距 1.5(去耦例外)/ 9 A 过孔阵禁区(place_base) - 叠层按用户决定改为 L1 槽面 / L2 整层 +3V3 / L3 整层 GND / L4 器件面 - 布线:D± 七对按构造布通(USB3 掉头、USB1/2 北去掉头、USB4/5 东绕、 J23 桥),+3V3 / GND / +12V 平面网每脚一孔,0.125 网格 + PathFinder 开关(route_base、remote_route.ps1);剩 37 个网待手工补 - 铺铜:4 层重写,入口链自南向北切段 + 断面校核(pour_base); 已下发布线 / 缝合孔 / 铜面轮廓,填铜未成功(待查) - 工具:plot_base / plot_routes / shot_base,board_check 通孔两层都算 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_0168Bu6SEx3cXXCJLkdnE6zB
4566 行
325 KiB
Markdown
4566 行
325 KiB
Markdown
# 进度与交接
|
||
|
||
## 固定执行约束(2026-09-10 用户明确要求)
|
||
|
||
- **以后所有 PCB 布线运算都用 `10.5.5.13` 服务器跑。** 本机仅做快照、结果校验、
|
||
EasyEDA 下发与 DRC,不再做完整重算或局部 D± 试算。
|
||
- 底板入口为 `.claude/r2/remote_route.ps1`;`route_base.py` 已加本机硬阻断,避免新会话误跑。
|
||
|
||
## ⭐⭐ 新会话从这里开始:底板 4 层重做(D15,2026-09-10 用户已确认分区)
|
||
|
||
**分区草图(用户已确认)**:`.claude/r2/M14-4L-floorplan.png`(左 = 正面 L1,右 = 背面 L4,同一套坐标、从上往下看)。
|
||
**决定**:4 层、98 × 98、**正面只放 J34~J38 五个插槽**、其余 133 件全在背面、叠层 **L1 槽面 / L2 GND / L3 GND / L4 器件面**、
|
||
插槽手焊(工厂只贴背面)。方案文档 D15(`刀片式方案规划-R2.md` §0.1),§6 已标 2 层版作废。
|
||
|
||
### 进度(2026-09-10 晚)
|
||
|
||
- ✅ **第 1 步 规则**:`rules_base.py --push` 已跑,铜层 2 → 4,补了 0.5 oz 线宽 / 内层间距,
|
||
过孔 0.3/0.2,差分 **W 0.28 / S 0.18**(intra-pair skew 仍 1 mm),安全间距 0.2 → **0.15**(同刀片),
|
||
`USBPAIR` 0.15;`--audit` 七项全过。
|
||
- ✅ **第 2 步 几何**:`pcb_base.py` 已重写(2 层版的 `BUS_W`/`rib_rects`/`wall3v3_*`/`DP_CHAN`/`USB6_CHAN`/
|
||
`DP_N_LANE`/`THROAT`/`HUB_ESC`/`PROJ`/`MID`/`EAST` 全删,下游引用会 AttributeError —— `place_base` /
|
||
`route_base` / `pour_base` 都要重写)。板框 98×98 折线 + 4 个 M3 已下发,`--verify` 全过。
|
||
新增:`TOP/BOTTOM`、`side_of(ref)`、`PIN_ROWS`(两排 32 针实测表)、`pad_rect()`、`shell_rects()`、
|
||
`via_bands()`、`ZONES`(A1/A2/A3/A5/A6/A4H/A4M)、`zone_of(x, y)`、`height_ok(h)`(背面限高 14)、
|
||
`l1_12v_rects()`(L1 12V 主块 + 15 块指头,自检:每只 12V 针被盖到、离异网针/外壳盘 ≥ 0.2)。
|
||
- ⚠ **更正上表**:12V 指头东界是 **x 34.95**,不是 35.1 —— 两排 12V 东边紧挨的 x 35.5 是 **GND**;
|
||
北排 12V 西边 x 32.5 也是 GND,所以北排指头是「排外横帽 + 东侧一颗牙」的 L 形。
|
||
- ⭐ **背面镜像规则(实测,U13 翻面读焊盘)**:封装原生偏移 `(dx, dy)` 在底层变成 **`R(rot)·(dx, −dy)`**
|
||
—— 先关于 x 轴翻(y 取反),再按和顶层一样的 CCW 转 rot。`modify(id, {layer: 2, rotation: …})` 一步到位,
|
||
rotation 0 要传 360。推论:顶层 rot 0 的「朝西、1 脚在北」在底层**做不出来**(底层 rot 0 = 朝西 1 脚在南,
|
||
rot 180 = 朝东 1 脚在北)。U13 现在已在底层 rot 0(原位,第 3 步会重摆)。
|
||
- 🟡 **第 3 步 摆位**:`place_base.py` 已重写(手排 36 件 + 按「翻面后真实脚位」瞄准的卫星排布器 102 件),
|
||
离线自检全过,**尚未下发**。对比图 `.claude/r2/M15-4L-place-hub3-vs-hub2.png`(`plot_base.py` 画)。
|
||
- U32 **底层 rot 270**(口朝北、USB1 在西)是唯一不交叉的朝向:USB1/2 直上,南去的几对从北沿出来绕 U32 东侧
|
||
(那一边几乎全是 NC);上行 / USB6 在西侧打孔走 L1 过去。U20 底层 rot 90 天线朝东;J1 rot 90、J23 rot 180 口朝南;Q1 rot 180。
|
||
- ✅ **用户拍板:Hub 在走廊 2、mux/DAC 在走廊 3**(与分区草图对调;`pcb_base.ZONES` 已改、R2 文档 §6 已记)。
|
||
D± 估算 45/23/3/40/58 mm(草图原样是最远 80,`--hub3` 可复现对比)。M5 验收线 45 只有 U32 坐进中间槽正下方的过孔带才做得到,没选。
|
||
- ✅ **已下发**(`place_base.py --push`):138 件位姿 / 层逐件读回对上,**离线镜像模型与板上 822 个焊盘最大差 0.003 mm**,
|
||
朝向断言全过(U32 口朝北 USB1 在西、插槽 12V 在西 D± 在南排、U20 天线朝东入缺口、J1/J23/Q1)。
|
||
`--native` 已按新板重建 `_base_native_pads.json`。截图:板上 `M15-4L-place-live.png`,离线 `M15-4L-place-final.png`。
|
||
⚠ verify 的脚号会重复(插槽外壳盘两个都叫 65、J23 的 A1B12/A4B9 多块),逐脚对账按「同号取最近」。
|
||
- ⬜ **等用户看截图确认方向与排版**(CLAUDE.md 规矩)。截图里 J23 / U20 角上有几个黄色 × 标记,还没查是什么。
|
||
- 🟡 **第 4 步 布线**(2026-09-10 晚,进行中):`route_base.py` 已按 4 层重写(2 层版在 `archive_base2L/`),
|
||
服务器入口不变(`remote_route.ps1`,schema 升到 **8**,旧 v7 缓存改名为 `_base_routes.2L-v7.json`)。
|
||
⚠ 在 Windows PowerShell 5.1 里调 `remote_route.ps1` **别加 `2>&1`**:远端 `time` 打到 stderr,会被当错误抛出,结果下载不回来。
|
||
- 主流程:Kelvin(U13↔Rs6 专线)→ Rs6.2 西侧 L4 +12V 铜块 + 15 孔上 L1 → J23 同名 D± 脚两座桥(DP 南绕 / DM 北绕)→
|
||
USB3 U 形掉头(构造)→ 其余六对 D±(DP 先 A*,DM 按「贴 DP」过路费)→ +12V / 散热盘孔 → **输入链 → 信号 → 电源**三段 A* →
|
||
GND 每脚一孔(最后做)→ 打不上的直连到邻近已接地焊盘。
|
||
- ⭐ **北去三对 D± 极性是反的**(U32 北沿 DM 在西、槽上 D+ 在西):换位靠一次 U 形掉头(左右自然对调,不交叉)。
|
||
为此 U32 **东移 2.5 mm**(`place_base.HUB_CX` 49.0 → 51.5),USB3 从 J36 南排底下北上、两排之间向西掉头、打孔回焊盘。
|
||
- 服务器实测:首轮 212 → 第二轮 195 条未完成。失败原因与对策:GND 孔先打会封死 1 mm 针排里的信号脚(→ 挪到最后);
|
||
宽的电源先布会把芯片围死(→ 三段);UP/USB6 从 U32 西南绕出去堵 strap 脚(→ L4 收过路费逼上 L1)。
|
||
- 看图:`plot_routes.py <png> [--zoom x0 y0 x1 y1]`(L4/L1 并排,失败脚红叉)。
|
||
- 第三轮(U32 东移 + 三段 + GND 救援之后)198 条(`remote_route.ps1 -AcceptAny`:摆位改过后旧缓存没有可比性;
|
||
东移前那份存为 `_base_routes.pre-shift.json`)。**诊断**:板上大部分是空的,失败几乎全是「芯片脚出不去」——
|
||
U32 ~36 / U20 27 / U35 17 / U6·U7 16 / J23 9 + 风扇角 + 部分槽 GND 脚。器件全在一面,脚、去耦、strap、GND 孔
|
||
挤在 L4 同一圈里;芯片正上方的 L1 是空的,但只有脚边落得下过孔才上得去。U32 另有三难:口排里夹 3V3(5/10/13)、
|
||
北去三对要换位、南沿到 J37 只剩 0.4 mm。
|
||
- 用户选「扇出上 L1 + U32 按构造画」:已做扇出圈(`place_base.FAN_RING`)、U32 北沿 3V3_HUB 构造(`u32_north`)、
|
||
U35/U6/U7/U20 扇出(`fanout`,62 只脚打孔)→ 第四轮 205 条;接进 PathFinder(`--pf --pf-iters 20`)→ **188 条**(当前缓存)。
|
||
PF 冲突格点 5342 → ~2700 就平了。
|
||
- **量化**:需布线 105 个网;横穿槽体的需求 J36 26 / J35 21 / J37 15 / J34 5 / J38 0 条,而槽体下 x 35~70 按 0.5 mm 一道约 60 道
|
||
⇒ **不是全局容量不够**。188 条按区域:Hub 区 48、J36 槽下 33、U20 区 29、mux 区 17,其余零散 ⇒ 是 U32→J36 那一小块的
|
||
局部几何(D± 拓扑 + 3V3 + strap + I²C 全挤在 J36 西段)和 U20 扇出孔排成墙。
|
||
- 用户选「构造 D± + 划横穿车道」:USB1~5 全部按构造画(`dp_construct` + `usb3_uturn`;北去在目标槽两排之间向东掉头,
|
||
南去东绕,USB4 用它本来就要的 L1 跳线越过 USB5),上行 / USB6 在 U32 西侧打孔从 L1 起步 → ✅ **七对 D± 全通**。
|
||
- 当前最好:`_base_routes.json` = `_base_routes.r6-pf192.json`(PF,192 条 = **信号网 37 个** + GND 打孔失败 97 + 连通性重复)。
|
||
37 个信号网成簇:U20 北沿那排上拉 / NTC 阻容 21、U32 西 / 南(晶振、RBIAS、VDD18PLL、strap)10、mux 区 7、零散若干。
|
||
GND 打不上孔的交给铺铜 + 缝合,铺完用 `board_check` 读回铜皮连通性再判。
|
||
- 试过无效:给 A3/A4M/A5 所有小件扇出(第七轮 43 个信号网,存 `_base_routes.r7-fanzone220.json`,已关)。
|
||
根子在摆位:排布器按 0.6 mm 装配间距把卫星件排成一排贴芯片,没给布线留余量。
|
||
- 用户选「加大小件间距重排」:`place_base.SAT_GAP = 1.5`(去耦例外仍 0.6、且先摆,去耦离脚平均 3.8 mm),
|
||
9 A 过孔阵加进摆位禁区(`LANES['V12_VIAS']`);U32 本地网先布(`u32_local`)。重排已下发、读回全过。
|
||
→ PF 199 条 / 信号网 38(mux 区变差、A3/A4H 变好,失败换地方,总量不降)。
|
||
- `--grid 0.125`(线距可以按 0.3 排,不再被 0.25 网格卡成 0.5)+ `--zone-pen` → **183 条(当前缓存,历来最好)**,
|
||
GND 打孔失败 100 → 69,但**信号网仍 38**;大头变成电源:+5V 到槽 7 处、+3V3 到槽 / U20 上拉 / mux 去耦二十来处。
|
||
细网格顺序布线服务器 ~4 分钟,可接受。`--zone-pen`(12V 大铜区对过路网收费)实测无效果(与不加时逐项相同)。
|
||
历次缓存:`_base_routes.r6-pf192.json`(信号网 37)、`r7-fanzone220`、`r9-pf199`。
|
||
- **结论**:换算法 / 顺序 / 间距 / 网格,信号网都卡在 37~38;剩下的四成是 +3V3 / +5V 这种几十只脚的电源树。
|
||
- ⭐ **用户拍板(2026-09-10):叠层改为 L1 槽面 / L2 整层 +3V3 / L3 整层地 / L4 器件面**(D15 已改,R2 文档 §0.1)。
|
||
+3V3 并入平面网(`route_base.PLANE_NETS`),每脚一孔;+5V / +3V3_HUB 仍布线。`pour_base` 要在 L2(id 15)铺 +3V3、L3(16)铺 GND。
|
||
- +3V3 改平面网后细网格 183 条 = 信号网 40 + 平面网打孔失败(GND 75 / +3V3 11 / +12V 1);**+5V 整棵落空**(10 只槽针)
|
||
→ +5V 干线 0.6 → 0.4、挪进信号段(`POWER_LATE` 只剩 +3V3_HUB / FAN_12V_SW)→ **191 条(当前缓存)**:
|
||
+5V 基本接上(10 只槽针只剩 J37.32),平面网打孔失败 GND 85 / +3V3 9 / +12V 1,**信号网 42**,D± 全通。
|
||
失败的脚几乎都是一两毫米的本地连接:U20 西排 / 扇出点 17、U32 南 strap + 3V3_HUB 11、风扇区 9、mux I²C 6、
|
||
Buck 自举 / 反馈 4、J23 VBUS 等 8。十几轮换算法 / 顺序 / 间距 / 网格 / 电源平面,信号网始终 37~42 ⇒ 调参数到头了。
|
||
- 🟡 **2026-09-10 夜:已下发到板上(用户选「先下发、剩下手工补」)**
|
||
- `route_base --push --force`:当前最好的布线(缓存 191 条那版)。板上读回 L1 856 + L4 1357 段(缓存 2288,
|
||
差数是 EasyEDA 建线时合并同向首尾相接的段),过孔 616(GND 229 / +3V3 37 / +12V 31)一个不差。
|
||
- `pour_base --stitch`:GND 缝合孔 122 个(修过:删旧孔时跳过布线缓存里的 GND 孔 —— 有 2 个恰好落在缝合网格上)。
|
||
- `pour_base --push`:83 块铜面按层建好(L1 33 / L2 13 / L3 13 / L4 24),**但「重建所有」没填出铜(poured = 0)**。
|
||
GUI 点击返回 fired: true,等 4 分钟仍 0;这套流程从 2 层版继承,底板上从没验证过 ⇒ 待查,或在客户端手动「铺铜管理器 → 重建所有」。
|
||
- `board_check --base`(已修:通孔焊盘两层都算):**37 个网没连通**,清单即手工补线清单(见会话 / 重跑该命令)。
|
||
- `drc_read --base`:间距错误 46 条 ——「挖槽区域」26 条(对象 e149/e150/e55/e56,板上图元里查不到,疑为封装内部
|
||
长槽孔 / 开槽,**要在客户端点 DRC 条目定位**;若是插槽键位真铣穿的槽,从下面穿过的 USB1/USB2 会被切断)、
|
||
J1 通孔地脚里误打的孔 4 条(代码已修 `TH_KEYS`,板上 4 个孔待删)、U20 地脚 1/40 离天线缺口 0.155 mm
|
||
(缺口东移 0.3 即可)、+5V 线离信号孔 0.124 mm 6 条 + UP 对内线到孔 0.185 mm 5 条(细网格量化)、板边 / 线线 2 条。
|
||
「连接性错误」557 那一支没意义(要重载客户端才准,且铜没填)。
|
||
- 板上截图:`.claude/r2/R12-board-routed-poured.png`。
|
||
- 🟡 **`pour_base.py` 已按 4 层重写**:L1 12V(主块按 M3 孔切瓦片 + 15 指)+ GND 底填 / L2 整层 +3V3 / L3 整层 GND /
|
||
L4 入口链三段(自南向北,按焊盘空隙在 F1、Q1 处切开,挖栅极缺口)+ Rs6 西侧 12V 铜块(读布线缓存 `v12_patch`)+ GND 底填。
|
||
离线自检全过;**断面**:VIN_SW 7.41(要 6.5)✅、L1 12V 主块 13.20(要 8)✅;VIN_RAW 6.77 / VIN_FUSED 4.35 不强制(瓶颈在 DC 座与保险,已接受)。
|
||
判据修过三处:`tiles()` 对 y 方向不相交的禁区会切出越界瓦片(已修);同网相邻瓦片先合并再量;
|
||
焊盘 / 过孔 / 平面网的短引出脚按「洞」扣(铜从四周绕过去),只有信号线算切断。
|
||
缝合孔 `--stitch` 读布线缓存算点(避开硬功率铜);下发顺序:`route_base --push` → `--stitch` → `--push` → DRC + `board_check`。
|
||
- `pour_base.py` 还没改(仍引用 2 层名字):内层 id **L2 = 15、L3 = 16**;入口链电流现在自南向北 ⇒ 断面沿 y 轴、查 L4 的线。
|
||
车道意图已固化在 `place_base.LANES`:DP_H(U32 东侧 x 55.5~59.5,USB4/5 南下)、DP_M(走廊 3 x 44~49,USB1/2 北上)、
|
||
I2C_H/I2C_M(x 28.5~31.5)、U32_WVIA(上行 / USB6 上 L1 的过孔带)。
|
||
|
||
### 起点状态(本段以前)
|
||
|
||
- EasyEDA `BASE-PCB`(`7b9524b6aaf6f235`)**仍是 2 层、110×125 板框、138 件在 2 层版位置、0 导线 / 0 过孔 / 0 铺铜**。
|
||
- `_base_routes.json` 是 2 层版最好结果(63 条未完成),**已作废**;2 层版脚本 + 缓存原样存档在 `.claude/r2/archive_base2L/`。
|
||
- `place_base.ROUTE_FIX`(DZ1/C1/R1 翻转等)和 `USER_INPUT` 都是 2 层版坐标,新摆位落地后要清空。
|
||
- 服务器没有在跑的任务;`/root/pypy` 已装好(见下)。git 工作区大量未提交改动(本会话没提交)。
|
||
|
||
### 新几何(全部 mm;x = 槽长方向,y = 槽堆叠方向;左下角原点)
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| 板框 | 98 × 98,四角 R5,**折线**(不是导线,§27.3 老坑)|
|
||
| 安装孔 | M3 NPTH Φ3.2:(4,4) (94,4) (4,94) (94,94) |
|
||
| 槽阵 | `SLOT_CX=49`、`ARRAY_CY=49`、槽距 20.32;槽心 y = **8.36 / 28.68 / 49.00 / 69.32 / 89.64**(J38 最南 … J34 最北,`USB_SLOT_REF` 1→J34 不变)|
|
||
| 槽体 | 42 × 9.2(x 28~70),rot 0,两排焊盘 y = 槽心 ±3.6,`PIN_U` 针位表沿用 `pcb_base.py`(12V 在 x 32.5~34.5,I²C 36.5/37.5,3V3 39.5~41.5,EN 42.5,D± 47.5/48.5,VDAC 49.5,5V 52.5/65.5,PRSNT 64.5)|
|
||
| 外壳 GND 盘 | 每槽两端 3×5,x = 29.5 / 68.5 |
|
||
| 槽间走廊 | y 12.96~24.08 / 33.28~44.40 / 53.60~64.72 / 73.92~85.04 |
|
||
| 天线缺口 | (90.5, 58) ~ (98, 80),东板边(暂定,U20 摆位后按天线实际位置调)|
|
||
| **正面 L1** | +12V 大铺铜 x 0.5~31.5 全高 + 每排 12V 脚伸一指到 x 35.1;槽的 GND 脚打孔到 L2/L3;信号脚打孔下 L4 |
|
||
| **背面 L4 分区** | A1 输入链 (0.5,0.5)-(27.5,56);A2 降压 (0.5,57.5)-(27.5,74);A6 风扇 (0.5,75.5)-(27.5,97.5);A3 控制(U20/J33…)(70.5,40)-(97.5,97.5);J23+U31 (70.5,0.5)-(97.5,38.5);**Hub U32 在走廊 53.60~64.72**(x 28.5~69.5);**U35/U6/U7 在走廊 33.28~44.40**;每槽焊盘正下方 x 31~67、y 槽心 ±4.6 是过孔带(不放件)|
|
||
| D± / I²C | D± 在 L4 沿 x≈48 竖向成束(参考 L3),最远 ~41 mm;I²C/VDAC 沿 x≈37 |
|
||
|
||
面积核账:133 件本体 1640 mm²(A1 540 / A3 516 / A4 262 / A6 186 / A2 136),背面可用约 9300 mm²。
|
||
背面最高 12 mm(C2/C3),底板下要 ≥ 15 mm 铜柱,外壳跟着改。
|
||
|
||
### 下一步(按顺序,每步的坑写在后面)
|
||
|
||
1. **`rules_base.py` 改 4 层**:`LAYERS = 4`;下发前先 `eda.pcb_Layer.setTheNumberOfCopperLayers(4)`(换层数会换能力集,§24.1);
|
||
把刀片 `pcb_rules.py` 第 192~210 行那段「补 `copperThickness0.5oz` 线宽 + `copperThicknessInner0.5oz` 间距」搬过来
|
||
(内层表从 `multi` 能力集拷,看该文件里 `multi` 怎么取的);过孔下限 0.3/0.2;差分改刀片那组 **W 0.28 / S 0.18**
|
||
(两层版 1.2/0.2 在 4 层薄介质上阻抗严重偏低);`--push` 后跑 `--audit`。⚠ 别在 GUI 换「配置」下拉框(整套重置)。
|
||
2. **`pcb_base.py` 换新几何**:上表的数;删掉 2 层专有的 `BUS_W`/`rib_rects`/`wall3v3_*`/`DP_CHAN`/`USB6_CHAN`/`DP_N_LANE`/`THROAT`/`HUB_ESC`
|
||
和刀片投影限高(背面没有刀片);`--outline` / `--holes` / `--verify`。
|
||
3. **`place_base.py` 重排**:五槽留正面到新位置,**其余全部翻到背面**,按上面分区。⚠ 翻面 API 还没查 ——
|
||
先看 `easyeda-api` skill 里 `pcb_PrimitiveComponent` 的 layer/翻转写法;翻完**必须** `--dump` 重抓焊盘、`--bbox` 重抓外框,
|
||
并像本会话核 rot90/270 那样,用实测焊盘确认背面镜像后 1 脚落在哪一侧(正面实测:rot90 → 1 脚朝南、rot270 → 朝北、焊盘长宽互换)。
|
||
摆完截图给用户确认(CLAUDE.md 规矩)。然后清空 `ROUTE_FIX` / `USER_INPUT`。
|
||
4. **布线 / 铺铜脚本改 4 层**:`router.py` 仍是两层 A*(`LAY=(1,2)`)⇒ 1 = L1 正面、2 = L4 背面,内层只做 GND 平面不布线。
|
||
`route_base.py` 删掉 `BOT_PEN`/`DIFF_KEEP`/`TOP_ONLY`/12V 干道/铜墙/车道那一整套;D± 从 U32 到槽 D± 脚按构造画(L1 焊盘 → 过孔 → L4)。
|
||
**每只 GND 焊盘都要一个到内层的过孔**(新增扇出步骤,GND 仍不布线);12V:Rs6 输出打过孔阵上 L1 铺铜,槽 12V 脚直接在铺铜里。
|
||
`pour_base.py` 本会话的改动可复用:焊盘空隙定刀口(`clip_chain`)、GATE 缺口、`GND_PAD_VIAS` 地岛专用孔、漏极铜、缝合孔不进硬铜面。
|
||
`CACHE_SCHEMA` 升到 8(旧 2 层缓存必须被拒)。
|
||
5. **服务器布线**:`remote_route.ps1 -Interp /root/pypy/bin/pypy3 -Variants @(...)`(PyPy 单轮 47 s vs CPython 222 s;
|
||
PyPy 输出是确定的,扫 `--hash-seed` 对它无用);结果只在「未完成不增加」时接受。
|
||
|
||
## ⭐ 2026-09-10:底板改 4 层(D15)—— 2 层版停止
|
||
|
||
- **用户拍板**:底板 **4 层、≤ 98 × 98**;**插槽面(顶层)只放 J34~J38 五个插槽**,其余 133 件全部放**背面**;
|
||
叠层 **L1 插槽面(槽焊盘 + 12V 大铺铜 + 少量线)/ L2 GND / L3 GND / L4 器件面(全部器件 + 信号 + D± + 3V3/5V 局部铜)**;
|
||
**插槽手焊**,工厂只贴背面。方案文档 D15(取代 D5),§6 开头已标作废。
|
||
- **为什么改**:2 层版卡在 63 条,其中 30 条是 D± 墙(19 个网要从 U20 一侧跨到槽侧,0 条通过:
|
||
顶层是连续差分线、底层 D± 下方禁开口)、6 条是西侧 12V 干道(顶层硬铜,只能底层跳);局部逃逸只能救约 20 条。
|
||
- **可行性核账**:除插槽外 133 件本体面积 1640 mm²,98×98 背面扣天线 / 安装孔约 9300 mm²(5.7 倍);
|
||
五槽外包 42 × 90.5(槽距 20.32、槽体 9.2),98 方向两边各剩约 3.75 mm。插槽是贴片立式(PCIE-64P11L,
|
||
64 贴片脚 + 2 个 3×5 固定盘,全在顶层),背面不被插针占。背面最高 12 mm(C2/C3),底板下要 ≥ 15 mm 铜柱。
|
||
- **EasyEDA 改层数**:`setTheNumberOfCopperLayers(4)`,然后规则重下一遍(R2 文档 §24.1,刀片踩过)。
|
||
- 2 层版脚本 / 缓存存档在 `.claude/r2/archive_base2L/`;服务器上 2 层版的拆线重布已停。
|
||
- **下一步**:① 新几何(`pcb_base`:98×98 板框、槽位、天线缺口、安装孔、板边接口)→ ② EasyEDA 改 4 层 + 规则 →
|
||
③ 133 件翻到背面重新摆位(U32 在中间槽正下方)→ ④ 路由 / 铺铜脚本改 4 层(去掉 2 层专有的底层过路费、
|
||
D± 走廊封底层、12V 西干道)→ ⑤ 服务器布线。
|
||
|
||
## 2026-09-10:Q1 栅极网络挖缺口 + 服务器并行变体(进行中,未下发)
|
||
|
||
- **根因**:`GATE: Q1.4 出不来` 不是拥塞 —— Q1.4 北/西/南三面是 VIN_FUSED 硬铜面、东面是
|
||
VIN_SW,中间只剩 0.25 mm 缝;DZ1/C1/R1 也都落在这两块铜面里。挪栅极件救不了,必须改铜面。
|
||
- **潜伏 bug(已修)**:`pour_base` 读实测焊盘、`route_base` 读 ROUTE_FIX 后的焊盘,两边不一致;
|
||
而 `clip_chain()` 按「重叠区中点」竖切,在 Q1(南排源极 / 北排漏极)处会切进 Q1 里面。
|
||
以前没出事只因 DZ1 旧位置(x=38.6)把 VIN_FUSED 撑到 x=40;DZ1 一挪,分界退到 30.5,
|
||
VIN_SW 盖住 Q1.3。现改为:换算函数挪到 `place_base.route_fixed_pads()` 两边共用;
|
||
刀口按「两网相邻焊盘的空隙中点」定(VIN_FUSED/VIN_SW 仍在 x≈33.0);栅极件不撑大外框。
|
||
- **GATE 缺口**:`pour_base.gate_notch()` = 主块 x 31.90–37.52 / y 0–3.57 + Q1.4 竖条,
|
||
从 VIN_FUSED、VIN_SW 两块里用 `tiles()` 挖掉(多块同名前缀,`check_cuts` 已支持)。
|
||
断面:VIN_SW 最窄 13.40 → **11.31 mm**(要 6.5,OK);12V 9.15 不变;`selfcheck` 全过。
|
||
- **摆位(ROUTE_FIX,未下发)**:DZ1 (31.0,1.65) 翻 180° 使 GATE 脚正对 Q1.4;
|
||
C1 (34.5,1.2)、R1 (36.5,1.2) **R1 翻 180°**(GATE 朝西与 C1.2 相邻)。
|
||
C1/R1 原计划 34.0/36.0 时 C1 离 DZ1 仅 0.22 mm,已东移 0.5;摆位自检无新增冲突。
|
||
离线模型支持平移与 180° 翻转;90°/270° 实测约定为 rot90 → 1 脚朝南、rot270 → 1 脚朝北、焊盘长宽互换,尚未接入。
|
||
- **C1.1 固定细线**:`route_base.gate_tap()` 画 0.30 mm(PWR9A 下限)C1.1 → 板边 y=0.70 → DZ1.1,
|
||
不走 A*(2.0 mm 网在 0402 上起不了步;板边那条缝在 0.25 网格上也表示不出来)。
|
||
- **`--repair`**(`route_base.rip_repair`):底板以前从没用过 `router.repair()`;现只对普通信号启用,
|
||
D± 与铜面网不参与。旧模型实测 v1 第一轮 **71 → 71**,无改善 —— 剩余失败主要是通道容量,不是顺序。
|
||
- **`remote_route.ps1 -Variants`**:服务器并行跑多组参数(脱离 ssh,`setsid nohup`),取未完成最少者
|
||
走原有校验 / 接受逻辑。`pour_base --push/--stitch` 在 ROUTE_FIX 未下发时会硬拒绝。
|
||
- 已确认 EasyEDA 底板当前 **138 件 / 0 过孔 / 0 导线**(旧文里的 162 个过孔已不存在)。
|
||
- 中间模型(只有 GATE 缺口)服务器实测:单轮 **70 → 64**;拆线重布变体首轮 64~70。
|
||
- **Q1 漏极排接入 VIN_SW**:`pour_base.drain_piece()` 补 `PWR-VIN_SW-Q1`(x 28.29–34.12 / y 7.05–11.49),
|
||
东头与 VIN_SW 搭接、南沿让开 VIN_FUSED。以前 9 A 只靠 A* 的 2 mm 线从四只漏极脚爬进铜面。
|
||
- **GND 贴片脚专用过孔**(`GND_PAD_VIAS`):D1.2(TVS)挖朝南地岛 + 3 孔、C5.1 挖朝北地岛 + 2 孔、
|
||
R1.1(在 GATE 缺口里)1 孔。`route_base` 把它们当固定 GND 过孔进占用图,`stitch_points` 永远保留。
|
||
C2.2/C3.2/J1 是通孔地脚,本来就穿到底层地平面,不用处理。
|
||
- **缝合孔不再打进硬功率铜面**(`PWR-*`):以前 4 mm 网格照打,在 VIN_SW / 12V 上掏洞,断面校核看不到。
|
||
离线核对:492 个缝合点、硬铜面内 0 个。
|
||
- 断面校核仍全过:VIN_SW 最窄 11.31 mm(要 6.5)、12V 9.15 mm(要 8.0)。
|
||
- **完整新模型服务器实测(单轮四变体)**:默认 64 / `--priority-cache` **63** / `--bot-pen-w 1` 70 /
|
||
两者叠加 64。已接受 v1:**1490 段 / 316 过孔 / 63 条未完成**(上一版 70,且是旧模型)。
|
||
输入链(GATE / VIN_FUSED / VIN_SW)**全部布通**;6 个专用 GND 过孔已在缓存里。
|
||
底层跳线降价(`--bot-pen-w 1`)两次都最差,不再试。
|
||
- 剩余 63 条集中在:U20 12、U35 6、U6/U7 8、U32 3、J23 3;U35/U6/U7 那一窝 SDA/SCL/VDAC
|
||
随顺序此消彼长 —— 是 I²C/DAC 西侧簇的通道容量问题,下一步仍是这几颗的局部逃逸。
|
||
- **服务器装了 PyPy**(免安装包,`/root/pypy` → `/root/pypy3.11-v7.3.23-linux64`,不动系统 Python)。
|
||
`remote_route.ps1 -Interp /root/pypy/bin/pypy3` 切换解释器。
|
||
实测同模型单轮:默认 **222 → 47 s**、`--priority-cache` **314 → 69 s**(4.6~4.7×),内存 95 → 290 MB。
|
||
未完成 68 vs CPython 63/64 —— **不是算错**:两份输出异网同层线距违规都是 0;失败 47 条相同,
|
||
其余差异都在 U32/U7/U35/U6 与风扇那几窝。原因是集合遍历顺序不同(PyPy 一律按插入序,
|
||
CPython 按哈希序),A* 起点 / 直连的平局先后因此不同。
|
||
⚠ **PyPy 是完全确定的**:`--hash-seed 1~8` 八个输出逐字节相同(68 条 / 1480 段 / 307 孔),
|
||
扫种子对它没用。`--hash-seed` 只对 CPython 有用(可复现;CPython 各种子是否真有差异尚未实测)。
|
||
⚠ 8 个 PyPy 并行时单个从 47 s 涨到 ~97 s(24 线程多半是 12 物理核 + 超线程),并行别开太满。
|
||
⇒ 用法:改模型后的快速验证用 PyPy;最终取最好结果仍按条数选,哪个解释器都行。
|
||
服务器下载站只有 ~76 KB/s,官方包 35 MB,直接 curl 会超时,要 `curl -C -` 续传。
|
||
- `remote_route.ps1`:临时文件带 PID,可同时起两批;收尾 `pkill` 改用 `[p]ython3 <目录>/`,
|
||
以前模式串也命中执行它的远程 shell,ssh 返回 255、目录没删掉。
|
||
|
||
## 2026-09-10:M13 底板差分与功率拓扑打通(普通信号仍未完成)
|
||
|
||
- 所有试算均在 `10.5.5.13` 完成;远程入口新增 `-DpOnly`,并修复上传包文件名不一致。
|
||
结果缓存现在只接受“未完成数不增加”的方案,更差结果保存为 `_base_routes.rejected.json`。
|
||
- 五槽保持 20.32 mm 间距,整体北移 3 mm。同步重排 `C7/C731/C10/R610/R722/C737`
|
||
和 `R9C~R9E`;新增摆位冲突 0,原有几何告警从 9 条降为 8 条。
|
||
- 七对 D± 全部改为确定性构造:USB1~5 与 USB6 全顶层;上行 USB 只在 U32 北侧用
|
||
两段短底层跨越完成局部换序(4 个信号过孔),随后立即回顶层。
|
||
服务器精确检查:异网净距 0 错、未连通 0;对内长度差
|
||
`0.9/0.3/0.3/0.2/0.3/0.3/1.0 mm`,均满足 `<=1 mm`。
|
||
- `Rs6` 从 90° 改为 0°,焊盘沿输入电流方向排列;`U13` 从板西侧移到 `Rs6` 上方,
|
||
`U29` 让位到旁边。`VIN_SW` 不再用 2 mm 粗线横切 12V 主干。
|
||
- 功率计划校核通过:`VIN_SW` 最窄 **13.40 mm**(要求 6.5),12V 西侧主干
|
||
**9.10 mm**(要求 8.0);12V/3V3 槽脚覆盖完整,异网侵入 0。
|
||
- 当前最佳全板缓存:**1539 段 / 312 过孔 / 75 个网络 / 70 条未完成连接**。
|
||
与本轮开始的 81 条相比减少 11 条,但仍禁止 `--push`,EasyEDA 板端仍是纯布局。
|
||
- 已证伪:继续随机优先重排在 70~73 间振荡;对全部密脚或只对 U20 做同层预扇出,
|
||
分别退化到 73 / 77 条。下一步应针对 `U20/U32/U35/U6/U7` 做局部通道与端点逃逸,
|
||
不再重复上述两类服务器试算。
|
||
|
||
## 2026-09-10:底板布线迁移到 10.5.5.13 服务器计算
|
||
|
||
- `route_base.py` 新增 `--snapshot-vias` / `--offline`:本机只负责从 EasyEDA 刷新
|
||
162 个既有过孔到 `_base_board_vias.json`,服务器离线计算时缺快照会硬失败。
|
||
- 新增 `.claude/r2/remote_route.ps1`,自动创建服务器 `/tmp/dcdc-route.*` 隔离目录、
|
||
打包上传、远程计时计算、校验 schema/插槽方向/USB 映射、备份并替换本地缓存。
|
||
使用:`powershell -ExecutionPolicy Bypass -File .claude/r2/remote_route.ps1 -PriorityCache`。
|
||
- `10.5.5.13`(Ubuntu 20.04 / Python 3.8.10)首轮实跑 **292.93 s**,CPU 99%,
|
||
峰值内存 93,876 KiB;本机同类单轮约 7 分钟。结果已拉回 `_base_routes.json`:
|
||
schema 7,1640 段 / 351 过孔 / 73 个网络,仍有 **81 条未完成连接**,未下发 EasyEDA。
|
||
- 同轮修正:五对槽 USB 不再因固定 y 阈值让 USB3 自交叉,长度差为
|
||
`0.918/0.250/0.250/0.250/0.250 mm`;`+3V3_HUB` 两块软铜覆盖从 1/21 修正为
|
||
21/21,并用一条固定桥连接;12V 主干覆盖 25/25 个槽电源脚、异网侵入 0,
|
||
含实际路由切口后的最窄断面 8.50 mm(要求 8.00 mm)。
|
||
- ⛔ 仍不可下发:USB6/上行 D± 尚未成对布通,且 `USB5_DP` 在当前布局下切过
|
||
`VIN_SW` 铜面,使其有效断面仅 3.31 mm(要求 6.50 mm)。`--push` 继续由
|
||
“存在未布通记录”硬阻断;下一步需调整南侧输入链或 USB5 走廊拓扑。
|
||
|
||
## 2026-09-10:M12 底板采用 EasyEDA 当前布局
|
||
|
||
- 以 EasyEDA 当前画布为唯一摆位基准,138 件已重新读回到
|
||
`.claude/r2/_base_place_live.json`;`place_base.py` 不再叠加 `ROUTE_FIX` 强制坐标。
|
||
- 用户在画布上完成了新一轮功能重排:`U35/U6/U7` 及配套件已在西侧,
|
||
`U32=(89.111,52.903)`,`U20=(93,97)`。旧的一次性 I2C 搬件脚本已删除,
|
||
不得再用旧坐标覆盖当前布局。
|
||
- 已重抓 822 只焊盘、138 件封装外框和旋转数据。五路 USB 曼哈顿估算长度
|
||
变为约 `87/67/46/53/73 mm`。当前整板截图 `.claude/r2/M12-current-layout.png`。
|
||
- 当前画布有 12 条几何告警:`C11/C607/R614`、`C609/R614`、
|
||
`C610/C612/R616`、`C7/C731`、`C8/R749/U19`、`RT601/U31` 过近;
|
||
`C737/R9D/R9E` 进入旧 D± 通道。这些位置按用户当前布局原样保留。
|
||
- 板端仍是 `0 导线 / 0 过孔 / 0 铜面`。I2C 已占用旧顶层 12V 母线区,
|
||
`U32` 也已离开 M12 旧逃逸框;下一步必须按这版布局重做 12V 干道和 D± 路由,
|
||
不得下发 M11/M12 旧缓存。
|
||
|
||
## ⚠️ 2026-09-10:M12 底板布线逻辑迁移(未下发)
|
||
|
||
- `route_base.py` 已从旧的「D± 西通道 / 12V 东母线」迁移到 M11:
|
||
USB1~5 明确映射到 `J34~J38`,槽端改从南排逃逸,东侧三条车道构造路由。
|
||
- 五对下行 D± 为 84 段 0.15 mm 逃逸 + 81 段主干/等长段;
|
||
离线净距 0 错,每对长差均为 0.25 mm(规则 ≤1 mm)。
|
||
- 12V 改为西侧 14 mm 干道 + 逐排分段铜墙,覆盖 25/25 只槽电源脚;
|
||
3V3 铜墙修正 NC 边界后覆盖 15/15,两者均为 0 异网侵入。
|
||
- 功率铜面离线断面:`VIN_SW=12.17 mm`、`+12V=14.00 mm`,强制项全过。
|
||
`U13.10` 是 Kelvin 监测脚,已从 9 A 铜面包围盒排除。
|
||
- 旧 `rot=180` 路由缓存现在会被 schema 拒绝;有任何未布通记录时 `--push`
|
||
也会拒绝下发,不再把部分路由写入板端。
|
||
- 完整 A* 试算两轮为 105 / 104 个未完成连接,排序重试几乎无改善;
|
||
其中 `R610` / `R722` 横断 U32→U20 的 USB6 专用通道。
|
||
- 两件的新位置规划为 `R610=(78,109.5)` / `R722=(78,111)`,布局自检通过;
|
||
但 EasyEDA 窗口已断开,定点下发返回 HTTP 500,**板端尚未移动**。
|
||
当前底板仍是 `0/0/0` 的纯布局状态,不可投板。
|
||
|
||
## ⚠️ 2026-09-10:底板 PCIe 插槽再旋转 180°
|
||
|
||
- 用户要求将 `BASE-PCB` 的 `J34~J38` 在 M9 方向上再旋转 180°:
|
||
五个插槽已定点下发并读回为 **`rot=0`**,其他 133 件未动。
|
||
- 这不是纯机械改动:`+12V` 脚从东侧换到西侧(约 `x=47`),
|
||
`+5V` / `PRSNT#` 换到东侧(约 `x=79~80`)。M9 的“12V 东侧铜墙 / 控制西侧”拓扑因此失效。
|
||
- 旧铜已清空:导线 **0** / 过孔 **0** / 铜面 **0**,避免旋转后焙盘压到异网旧铜。
|
||
`route_base.py` / `pour_base.py` 已加新方向硬阻断,旧拓扑不能误下发。
|
||
- 当前底板是**布局状态,不是可投板状态**。下一步必须按新针位重做东西分区、电源铜墙和全板布线。
|
||
- 截图:`.claude/r2/M10-slots-rot180.png`。
|
||
|
||
### ✅ M11:按原理图功能模块重排底板器件
|
||
|
||
- 槽阵整体西移:中心 `x=46.5`,槽体 `x=25.5~67.5`;南→北为 `J38/J37/J36/J35/J34`,
|
||
与 U32 旋转后 USB5→USB1 的引脚顺序同向,五对 D± 不交叉。
|
||
- 西侧 = 12V 功率区:`x=0.5~10.5` 主干 + `x=10.5~32.5` 槽支路;
|
||
南侧输入链 `J1/F1/Q1/D1/C2/C3/Rs6/U13` 按电流方向聚类,`C1/R1/DZ1` 贴 Q1。
|
||
- 东侧 = 数字/高速区:`x=67.5~81` 为 D± 专用通道,`x=81~110` 放
|
||
`U32` Hub、`U20` ESP32、`U35` I²C mux、`U6/U7` DAC 及就近 RC。
|
||
- `U20` 改为天线朝东,板框缺口同步移到东边 `x=102.5~110 / y=86~108`;
|
||
EN/NTC 滤波、Hub VDD18/VDD18PLL 去耦、DAC 参考 RC 均按读回脚位重新钉位。
|
||
- 北带 = 两路辅助 Buck + 风扇/应急口;南带 = 输入功率 + 上行 USB-C。
|
||
- 验收:138 件逐件读回一致;板框 1 条 / 49 点闭合;安装孔 4 个;
|
||
重叠 / 越框 / 限高 / 槽带侵入 / 天线净空均为 0。截图 `.claude/r2/M11-functional-layout.png`。
|
||
- 仍是纯布局稿:导线 / 过孔 / 铜面 = `0/0/0`;布线器要按新的东侧 D± 通道重写后才能下发。
|
||
|
||
### ✅ M11b:相关电阻电容按引脚收紧
|
||
|
||
- `A2-AUX`:`C7/C731/C732` 从东侧控制列收回 U19/U30 的 12V 输入脚,
|
||
`C9/C10` 收回 L2 的 3V3 输出;原先 67~77 mm 的跨板距离消失。
|
||
- `A3-CTRL`:`C601/C602/R601/C603` 围绕 U20 的 3V3/EN,`R606~R610` 按
|
||
PRSNT1#~5# 的实际 GPIO 脚排列;`C604/R602/R603` 收回 U35;
|
||
U6/U7 的 `C607~C612/R614~R617` 按脚侧重排,`C608/C611` 另外旋转 180°让信号端朝芯片。
|
||
- `A4-HUB`:`C744~C751` 在 U32 右侧组成紧凑去耦阵列,
|
||
`R710/R711/R712/R720/R716` 组成 strap/reset 电阻列,与去耦阵列分开;
|
||
`C737/C752/C753` 贴 U31。
|
||
- `A1-INPUT`:`C1/R1/DZ1` 收回 Q1 GATE/VIN_FUSED 引脚周围。
|
||
- 读回审计的“去耦离引脚 >3 mm”只剩 5 条:四条为 3.0~3.2 mm;
|
||
`C738` 为两只风扇座共用储能,放在两座之间,距单侧 6.3 mm 是对称折中。
|
||
- 用户指出 J33 位置不合理并在客户端调整:定稿为
|
||
**`J33=(107.06,76.83,270°)`**,位于 U20 下方的右板边,从侧边接插;
|
||
其本体 `x≈105.8~108.3` 在刀片横向投影 `x=-2.5~95.5` 之外,11.5 mm 高度不干涉。
|
||
北边只保留相邻的 `J27(70) / J26(83)` 风扇座。D2/R748/R753/R755/R757 同步让位。
|
||
|
||
### ✅ M11c:两颗 NTC 改到最高热密度点
|
||
|
||
- `RT601=(92.0,24.5,270°)`:贴 U31 右侧,监测 Hub LDO。U31 最坏耗散
|
||
`0.42 A × (5-3.3) V ≈ 0.71 W`,是底板最明确的持续热点;NTC1 信号端朝北。
|
||
- `RT602=(72.5,10.0,180°)`:贴 J1/DC-005 右侧,监测 9.99 A 输入接触热。
|
||
DC-005 家族额定仅 2~5 A,此处是已知的安全热点;邻近 Q1 最坏约 `I²R ≈ 0.5 W`。
|
||
- `C736/C739` 仍贴在 U20 ADC1 脚旁做 MCU 端滤波,不跟 NTC 跨板移动。
|
||
- 读回脚位:RT601.1/NTC1=`(92.00,25.25)`,RT602.1/NTC2=`(73.25,10.00)`;
|
||
布局碰撞、越框和刀片投影检查通过。
|
||
|
||
### ✅ M11d:Q6 / Q10 / U13 按信号流重排
|
||
|
||
- `U13=(19.0,5.5,0°)`:回到 `Rs6=(19,11)` 正下方,并原地转到 0°;
|
||
读回 8/9/10 脚(`+12V/+12V/VIN_SW`)在 `y=7.61`,朝上正对 Rs6,保留 Kelvin 最短路径。
|
||
- `Q6=(72.5,113.5,180°)`:放在 J27 下方,`R733/R734` 围绕其输入网;
|
||
Q6.3 `FAN_PWM_L=(73.5,113.5)` 朝风扇接口。
|
||
- `Q10=(98.0,114.5,90°)`:放到 U20 上方的空区,`R754~R757` 收成一组;
|
||
Q10.3 `FAN_TACH_OUT=(98.0,113.5)` 朝南对着 U20。
|
||
- D2/R747/R748/R753 同步让位,R660/R661 回到 U20 ADC 滤波组。
|
||
本轮使用 `push_subset.py` 只下发 15 个相关器件,没有覆盖用户正在客户端调整的其他位置。
|
||
|
||
### ✅ M11e:用户定稿新的电源输入链布局
|
||
|
||
- 以客户截图和板上读回坐标为准,16 件已写入 `USER_INPUT` 机械锚点:
|
||
`J1/F1/Q1/D1/C1/R1/DZ1/C4/C5/C6/C2/C3/Rs6/U13/RT602/C11`,不再做 0.25 mm 吸附。
|
||
- 功率流从左到右:`J1(20.83,10.79)` → `F1(31.08,3.63)` →
|
||
`Q1(37.08,6.63)` → `D1/C2/C3` → `Rs6(75.99,8.74)`。
|
||
- `U13=(76.71,16.89,180°)` 位于 Rs6 上方;8/9/10 采样脚读回为
|
||
`(76.71,14.78)/(77.21,14.78)/(77.71,14.78)`,可从 Rs6 两端单独引 Kelvin 线。
|
||
- `RT602=(32.07,9.16,0°)` 移到 F1/Q1 输入热点中间,代替 M11c 的 J1 右侧位置。
|
||
- 检查器同步修正两个模型:器件间距改用带偏移的真实本体框;
|
||
用户贴边锚点按 0.25 mm 板内余量判定。U13 顶部进入 D± 通道南端约 0.8 mm,
|
||
已登记为后续路由的局部固定障碍。
|
||
- 16 件已定点下发并全部读回一致。
|
||
|
||
### ✅ M11f:采用 EasyEDA 当前整板布局
|
||
|
||
- 用户要求“按我现在的布局修改”;已通过
|
||
`place_base.py --adopt-live --verify` 读取 `BASE-PCB` 当前全部 **138 件**。
|
||
- 快照 `.claude/r2/_base_place_live.json` 保存每件的 x/y/角度/层。
|
||
`place_base.plan()` 现在优先使用该快照,并跳过自动吸附和自动翻转;
|
||
以后普通 `--push` 不会把当前手工布局拉回旧位置。
|
||
- 验收:138 件坐标/角度逐件一致;重叠、越框、限高、螺钉头、槽带侵入、天线净空均为 0。
|
||
|
||
## ⚠️ 2026-09-08:架构分叉,先看这里
|
||
|
||
用户拍板**重做方案以节约打样成本**:改成「**底板 + 5 片相同刀片(PCIe 竖插)**」,
|
||
新方案规划写在 **`刀片式方案规划-R2.md`**(架构、成本模型、引脚表、风险、里程碑都在里面)。
|
||
|
||
- **R1(下面这一整份进度)全部保留,不删不改**,工程 / 原理图 / PCB 一个字节没动。
|
||
- R1 停在「下板欠 50 个网络 / 97 条连接 + 5 条 DRC 间距错误」,`pcb1_route_sig` 那一步**未下发**。
|
||
- ✅ **M1 已完成**:工程 `PhoneRail-R2` = `05a65c22f14846b8b95360ef8d3c1e2e`,
|
||
两块板 `BLADE`(后来变 5 页)/ `BASE`(6 页)骨架建好,UUID 全在 `.claude/r2/r2-uuids.json`。
|
||
- ✅ **M2 已完成(刀片原理图 5 页全画完,2026-09-08)**:
|
||
`B1-POWER`(42 件) / `B2-CTRL`(13) / `B3-PHONE`(17) / `B3B-USB`(9) / **`B4-EDGE`(2)**。
|
||
五页 `verify_sch --nets` 六项全过、`port_audit --r2 BLADE` **146 个旗端口可疑 0**、
|
||
本地交叉点 0、**`xpage` 真正漏接 0**。
|
||
- ✅ **T4 也在同一轮做掉了**(`B4-EDGE` 的前置条件):PCI-E CEM 引脚表逐脚核对,
|
||
**揪出方案文档 §5.2 两处凭记忆写错的针位**,其中一处会烧板 ——
|
||
**`B3` 是 +12V 不是 RSVD**,原方案要把 `+5V` 放上去,刀片误插进真 PC 槽时
|
||
主板会把 12 V 灌进刀片的 +5V 轨(`U5` TPS22918 abs max 6 V)。
|
||
`+5V` 已改挂 **A19 / A32**(每一版 CEM 里都是 RSVD,两个方向都安全)。
|
||
另一处:`B12` 从 CEM 2.0 起是 CLKREQ#,不能当自由针 ⇒ 改接地。定稿针位表见方案文档 §5.2 / §17。
|
||
- ⚠️ 本轮又踩到两处 skill §6c「rot 语义与源页相反」:`C60` 2200µF **电解极性接反**
|
||
(四道校核全过,只有网表明细看得出来)、`U5` TPS22918 的两排引脚**镜像**
|
||
(不是 180°,自动翻转循环修不了)。做法与判据写在方案文档 §16.3。
|
||
- ⚠️ **2026-09-08 改判 D11b:DAC63204 挪到底板**(2 颗喂 5 路 = R1 的 U6/U7 原样搬),
|
||
刀片上不再有 DAC,位号顺移(PCA9555 `U5→U4`,B3 的 TPS22918/TS5A3157 → `U5`/`U6`)。
|
||
依据是设计文档 §4.4 的失效表:`VDAC` 断线 = 3.890 V、对地短路 = 4.010 V,注入增益 0.2007。
|
||
详见方案文档 **§15**。
|
||
- ✅ **金手指封装已建(2026-09-08,M4a)**:`EDGE-64P-P1.00_PCIE-X4-GF`
|
||
= `569096fb8fed4743b85c69f4b6581ead`,脚本 **`.claude/r2/fp_edge.py`**(几何唯一事实来源,
|
||
`--push` 幂等重画 + 读回校验:64 焊盘逐脚对上、板框缺口 16 段折线闭合、丝印零侵入指区)。
|
||
已挂到器件 `PCIE-X4-EDGE-64P` 上,`Add into BOM` 也一并改成了 no。落地记录见方案 **§22**。
|
||
⚠️ 它顺手推翻了文档里两条:**斜边角度 20° 在嘉立创下不了单**(只有 30/45,已改 30),
|
||
**「斜边吃掉 1 mm 镀层」不成立**(CEM 本来就留 1.3 mm 裸边,斜边啃的就是它)。
|
||
⚠️ 第一版把手指画在了板外(y 反了),**四道几何校验全过,靠截图才看出来**。
|
||
- ✅ **M3 已完成(底板原理图 7 页全画完,2026-09-08)**:
|
||
`A1-INPUT`(25 件) / `A2-AUX`(17) / `A3-CTRL`(30) / `A4-HUB`(31) /
|
||
`A5-SLOTS`(3,槽 1~3) / **`A5B-SLOTS`(7,槽 4~5 + 5 个 D± 退路座)** / `A6-FAN`(30)。
|
||
七页 `verify_sch --nets` 六项全过、**`xpage` 真正漏接 0**、
|
||
**`port_audit --r2 BASE` 372 个旗/端口可疑 0**。落地记录见方案文档 **§18/§19/§20**。
|
||
后四页是**四个子代理并行设计 + 主代理串行下发**:全机只有一个 EDA 客户端、
|
||
`openDocument` 是全局状态,同时推会把图元放进别人的页,**而且六项验证照样全过**。
|
||
- ⛔ **底板从 6 页变成 7 页**:5 个 64 针插槽一页放不下(每槽净宽 355 × 5 = 1815 ≫ 可用 1125),
|
||
新开 `A5B-SLOTS` = `e493f8bce3a51aae`,已写进 `.claude/r2/r2-uuids.json`。
|
||
- ⛔ **差点烧进去的一条(子代理揪出来的):`PRSNT#` 在底板上不能镜像刀片。**
|
||
底板是**主板侧** ⇒ `A1 = GND`、`B31 = PRSNT{n}#`;短接 A1↔B31 的是刀片。
|
||
若照字面镜像并成一个网,回路里一个对地通路都没有 ⇒ **插不插刀片都读「未插入」,
|
||
而 DRC / ERC / 几何验证 / 跨页对账四道全过**。见方案 §20.1。
|
||
- ✅ **T6 结了,结论与方案 §8.2 的问法相反**:DS00001598C Table 7-1 的 `0Ah/0Bh` 默认 `00h`
|
||
⇒ `CFG_SEL=110` 下七个下行口全开,第 6 口**不用改 strap,只要连线**。见 §20.2。
|
||
- ✅ **T8 已结(2026-09-08)**:`J34~J38` 换成 **SOFNG `PCIE-64P11L`(`C19188869`)**,
|
||
PC 标准 x4 64PIN。**根因也修掉了**:`lib_Device.search` 不是只能回 38 条 ——
|
||
带上 `itemsOfPage` / `page` 就能翻页(`search(key, libraryUuid, classification,
|
||
symbolType, itemsOfPage, page)`)。
|
||
- ✅ **T7 也一起结了**:刀片 `F1` = **`F1206SB2000V063TM`(`C310998`)** 2A 慢断 1206/63V,
|
||
取代同封装的 10A 占位件 `C310989`。AEM `F1206` 的系列码:`SB`=慢断 / `HI`=耐涌 /
|
||
`FA`=快断 / `HC`=大电流。B1-POWER 已重画并验证(六项全过、`xpage` 漏接 0、
|
||
`port_audit --r2 BLADE` 146 个可疑 0)。
|
||
⚠ **裕量只有一档**:刀片满载 1.45 A = 额定的 73%,压在「连续 ≤75%」的降额线上;
|
||
真无故熔断就换 `F1206SB2500V032TM`(`C310999`),同封装,改一个常量。见 §20.7。
|
||
⚠ 立创描述写「PCI-E 4X」的有两颗其实是 x1(实测 36/38 脚),判据只能是放到空页读回引脚数。
|
||
⚠ 脚号体系不同:插槽是 `1`~`64`(脚名才是 A1~B32)+ 一根 `65` 屏蔽脚,
|
||
引脚相对坐标与金手指完全一致 ⇒ 版图一个字没改,只加了一层 `slot_pin()` 换算。
|
||
⛔ **新风险:贴片立式**,保持力只靠焊盘剪切 —— M4 布板必须给刀片另加固定件。见 §20.3。
|
||
- ⚠️ 本轮又交了**五次「几何验证抓不到」的学费**,全靠放大截图发现(§20.5):
|
||
R1 搬来的图元整块落进标题栏、钽电容 `C737` 的 rot 语义与跨距都与假设相反、
|
||
三处文字被旗标签 / 元件值标签压穿。建议给检查器补两个盒子模型
|
||
(旗的「符号+标签」矩形、元件位号/值文字的矩形)。
|
||
- ✅ **T1 / T2 / T3 已全部定稿(2026-09-08)**,`§0.3` 那张表现在一条待办都不剩。见方案文档 **§21**:
|
||
- **T1 = 槽距 20.32 mm,不必实测。** 根因是 §3.2 的公式里写着「立柱 3.0」——
|
||
那是 2026-09-06 就被中框式焊盘(间隙 **1.0 mm**,R1 §22.3e)取代的顶针方案。
|
||
改正后 `h_phone + g = 14.72`,**即使把 h_phone 取成小米8 整机厚度 7.6 mm(物理上限)仍余 7.1 mm** ⇒ 对这个数不敏感。
|
||
- **T2 = 10.5 mm**(`C3828985` `6.3TPV2200M10X10.5` SMD)。这个数 2026-09-06 换矮封装时就有了,只是没回填。
|
||
⛔ 只能放 A 面没有手机压着的服务带/功率列(可用 11.7~13.7,余 1.2~3.2);B 面只有 3.0 mm 放不下。
|
||
- **T3 = 做斜边**(`20°/1.0 mm`)。加价压在**已经要付的金手指工艺费之上**,
|
||
而它挡掉的是「刮伤已焊死的插槽簧片 → 偶发掉线,功能测试测不出来」。
|
||
⚠ 顺带纠正 §5.3 一个错:**金手指区要电镀硬金,不是 ENIG**(ENIG 只有 0.05~0.1 µm,是为焊接设计的,插拔会磨穿见镍)。
|
||
- ⇒ **M4(刀片 PCB)已开工**:M4a = 金手指封装(见上);
|
||
✅ **M4b 也做完了**:板框 98×76 / R2 已画并校验闭合,`J1` 摆在 (49, 0),
|
||
**83 件全部导入 PCB**(位号 + 封装逐件对上)。脚本 `.claude/r2/pcb_blade.py` /
|
||
`.claude/r2/pcb_import.py`。落地记录见方案 **§23**。
|
||
✅ **M4c 前三步也做完了**(见方案 **§24**):
|
||
设计规则已下发并审计全过(⛔ 发现 `BLADE-PCB` 建出来是 **2 层**,已改 4 层;
|
||
安全间距只能给 **0.15** —— 0.2 会刷出 23 条全在 `J4` BM24 封装内部的假错);
|
||
**83 件摆位已下发并读回校验**(机械锚定件从 `mi8_mech.json` 换算,
|
||
功率列自下而上 = 输出端→输入端,`U3` 已挪到 `Rs1` 边上保 Kelvin,B 面留空);
|
||
**DRC 间距错误 0**,剩下的 320 条全是「还没布线」。
|
||
⛔ 铺铜踩到一条大的:**全贴片的板子不打缝合过孔,四层里有三层的铜面会被当孤岛整块删掉**,
|
||
而 `rebuildCopperRegion()`、铺铜管理器、DRC **三个地方都不报错**。已按 5 mm 网格
|
||
打了 196 个 GND 过孔。⇒ 正确顺序是 **摆位 → 缝合过孔 → 布线 → 铺铜**。
|
||
✅ **铺铜也做完了**:6 块铜面里 4 块已填,**L2 是一整块没割断的地平面**
|
||
(截图 `.claude/r2/M4c-blade-L2-gnd.png`);`VO-L3`/`V12-L3` 两块等布线打了过孔才会填。
|
||
**DRC 间距错误 0**,连接性错误 252(= 还没布线)。
|
||
⛔ **卡在布线**:自动布线两条路都跑不出一根铜 —— `pcb_Document.autoRouting` 这个 API
|
||
在本机客户端上**根本不存在**;GUI 的「布线 → 自动布线...」对话框能开、能配、`运行`
|
||
点得下去,但**立刻关闭且铜线数 0**,不报错不弹进度。见方案 **§24.6**。
|
||
⇒ 要么我自己写一个够用的布线器(~55 网络 / 361 焊盘),要么用户在客户端里手跑一次。
|
||
⚠ 刀片外框的**底边必须在缺口口部断开**(相对封装原点 x = -6.45 / -3.55),
|
||
坐标从 `fp_edge.notch_mouth()` 取,别手抄;拼不上会得到一个开口板框。
|
||
唯一还悬着的是 **ESP32-S3-WROOM-1 是 R8 还是 N8**:现在按 R8 保守留空 `IO35/36/37`,
|
||
全板只剩 `IO47/IO48` 两个备用脚(§20.6)。定了 N8 就能多放三个脚出来。
|
||
- ✅ **M6(2026-09-09,用户拍板):屏蔽窗去掉、器件全到 B 面、加两条排线穿板槽**。
|
||
A 面只剩 `K1~K4` + `J1`,78 件在 B 面;`C60`/`J2`/`J3` 能下去是因为**B 面服务带净空
|
||
18.7**(对面 A 面清空了),「B 面只有 3.0」是把 `L1` 高度当预算写的,§3.2 已更正。
|
||
排线槽照搬 R1(layer 12 填充 = 挖槽区域):BAT x 20.8~32.8 / TAIL x 46.6~66.6,y 24.8~27.8;
|
||
排线穿槽 U 形折回 B 面,`J5`(26.8,32) / `J4`(56.6,33) 在槽北边、**底层 rot 0**(推导 + 读回,
|
||
见方案 **§26.3**,首件仍要通断复核)。⚠ `J1401` 的锚从 48.76 改成本体中心 **53.58**(§22.3b),
|
||
差 4.8 mm,按旧值尾插车道会压在 H4 螺钉头上。旧布线全部作废,缝合过孔重打 182 个;重布 **714 段 / 289 过孔**、铺铜 24 块全填、
|
||
**DRC 间距 0 / 物理 0**,没接完 **16 处 / 10 个网**(功率列 `U2`/`U4` 那一窝老拥塞,见方案 §26.5)。
|
||
⚠ `VO_P` 岛改成 L 形跟着 `J5` 北伸(`pcb_pour.VO_LOBE`);USB_DP 收尾压 DM 扇出孔那一处是手改的,
|
||
不在路由缓存里。
|
||
⛔ **「继续布完」试了四种办法都到不了**(换顺序 / PathFinder / 只补线 / 过孔扇出,方案 §26.6 有表),
|
||
板上实际只欠 **5 只脚**(`U2.15` `U2.17`+`R11.1` `U2.2` `R16.1` `R8.2`),全是出口被自家邻脚封死。
|
||
**作业单 `.claude/r2/HANDROUTE-M6.md`,在客户端交互式布。** 好的路由缓存备份 `_blade_routes_m6_good.json`。截图 `.claude/r2/M6-place-bot.png` / `M6-place-top.png`。
|
||
- ✅ **M7(2026-09-09):板框改折线 → B 面重排 → 自己布线,714 段全通**
|
||
① ⛔ **板框根因**:`pcb_PrimitiveLine` 在嘉立创里是**导线(铜)**,不是图形线。
|
||
M4b 起板框一直是用它画在层 11 上的 —— 渲染成品红、DRC 干净、四道几何校验全过,
|
||
但客户端**不认它是板框**(属性面板 `图层` 那一格 `data-value=11` 却显示空白)。
|
||
是**用户看属性面板发现的**。改成一条 54 点的闭合 `pcb_PrimitivePolyline`
|
||
(缺口用 `outline_polygon()` 插进底边)之后,自动布线才第一次跑起来。见方案 §27.2/§27.3。
|
||
② ⛔ **官方自动布线放弃**:板框修好后它能跑到 100%,但**收尾时把自己布的铜全丢掉**
|
||
(大跑小跑都一样,最后只剩运行前就有的那几段),toast 却报「自动布线已完成!」。
|
||
探针全装(console/onerror/fetch/XHR/Worker)一条都抓不到。⇒ 用 `router.py`。
|
||
③ **B 面重排**(用户拍板):排布器从「按面积自下而上塞」改成**「挑离目标最近的空位」**,
|
||
目标点精确到**对端焊盘**、有芯片对端时只认芯片。`U4` PCA9555 按用户要求挪到**左下角**
|
||
(12.5,15.6)(⚠ 用户拖的 y=10.67 会压进金手指区,已抬到禁布区上沿);
|
||
`U2` 东边四只脚的外围件拆出 `EFUSE_E` 区,一列按 p17→p20 排;
|
||
`R3`(U1 的 EN 分压)从东边挪到 U1 西边的口袋。
|
||
④ **新判据**:`place_audit.py`(摆错边 / 被挡 / 去耦太远,判「侧」不判「穿本体」)、
|
||
`board_check.py`(**从板上读回铜**做并查集,缓存/`getNetLength`/DRC 三个都不可信)、
|
||
`grid_snap.py`(把件微调到 0.25 布线网格,对齐焊盘 8 → 83)。
|
||
⑤ **结果**:铜 **714 段 / 2563 mm**,过孔 316 + GND 缝合 131,铺铜 24 块全填,
|
||
**L2 一整块地平面**;`board_check` **57 个网 56 个全连通**(GND 靠铜面);
|
||
**DRC 间距错误 4 条,全是 PCIe 缺口到 11/12 号指的 0.2 mm**(几何定死的,见下)。
|
||
截图 `.claude/r2/M7-routed-top.png` / `M7-routed-bot.png` / `M7-L2-gnd.png` / `M7-u2-area.png`。
|
||
⛔ **要用户拍板的一条**:缺口到 11/12 号指铜边距 **0.2 mm**,嘉立创规则要 0.3。
|
||
这是 CEM 几何定死的(1.0 间距 / 0.7 指宽 / 1.9 缺口宽),任何 PCIe 卡都一样;
|
||
以前不报是因为板框那时是「导线」。⇒ 下单前问嘉立创能不能做,或把缺口收窄到 1.6。
|
||
⑥ **直角走线全部改 45° 斜切**(`miter.py`,自动跑到收敛,3 轮共切 **227 个**):
|
||
只去铜不加铜 ⇒ 净距只会变好,DRC 前后都是 4 条。剩下的 90° 全是结构性的
|
||
(焊盘/过孔上 11、T 型分支、腿太短 45),见方案 §27.10。
|
||
⛔ 第一版把端点归并写成「坐标除以容差取整」的**固定分桶**,相差 0.011 的两点掉进
|
||
两个桶 ⇒ 同一个角切两次、原直角腿留在板上,**板上留下 31 处悬空小碎块**
|
||
(用户放大 `KPAD_VUP` 那一带一眼看到,而 DRC / `board_check` / `router_check`
|
||
三道判据全过)。改成空间哈希就近归并 + 新增「断头铜」判据,现在 7 处,
|
||
全是布线器本来就有的(地母线故意外伸 1 mm / 引出脚余量)。见方案 §27.11。
|
||
⚠ 顺序:布线 → 下发 → 缝合过孔 → **斜切** → 铺铜;重跑布线器要重跑这一步。
|
||
⚠ 还欠一件:**D12 的割断位**(金手指到 `J2` 之间要留一段带丝印的割断位,方案 §17.4)。
|
||
- 🔧 **M8(2026-09-09,进行中):底板 PCB `BASE-PCB` 从空文档做到摆位定稿**
|
||
① **板框**:建工程时留的 4 条 `pcb_PrimitiveLine`(110×125 默认框)就是 M7 §27.3 那个坑 ——
|
||
**导线不是板框**。已删掉,改成一条 45 点闭合 `pcb_PrimitivePolyline`(四角 R5)。
|
||
② **安装孔 4×M3**(Φ3.2 NPTH,离板边 4 mm,四角)。用户拍板去掉原来东西两侧中点那两个 ⇒
|
||
**5 片刀片一起插拔时板中部无支撑,装配要从槽阵下方托住再插**。
|
||
③ **143 件全部导入**(`pcb_import.py --base`),位号 + 封装逐件对上。
|
||
④ **设计规则**(`rules_base.py`,2 层 `JLCPCB Capability(Two Layers Board)`):
|
||
5 条线宽(`PWR9A`/`PWR12V`/`FAN12V`/`PWR5V`/`PWR3V3`)+ **七对差分**
|
||
(5 槽 + ESP32 原生 USB + 上行 USB-C)+ 安全间距 **0.20**,审计六项全过。
|
||
⑤ **摆位 143 件下发并读回校验**(`place_base.py`)。五条带:
|
||
input 0~15.5 / hub 15.5~43.5 / **slots 43.5~85.5(只有 5 个插槽,走廊留给布线)** /
|
||
ctrl 85.5~113.5 / fan 113.5~125。投影带内限高 8 mm 是硬碰撞判据。
|
||
⛔ **三条「几何验证抓不到、错了就报废」的朝向,已做成读回断言**:
|
||
· `U32` **rot=270**(下行口原生朝西,转 270 才朝北正对槽阵);
|
||
· **插槽物理顺序是反的:西→东 = `J38 J37 J36 J35 J34`** —— `U32` 北排的 x 顺序是
|
||
USB1 在东、USB5 在西,按位号自然顺序摆会让五对 D± **互相交叉**,
|
||
两层板上交叉 = 打过孔换到 L2 = 在 D± 走廊正下方割地平面(方案 §6.2 第 1 条明令禁止);
|
||
· 插槽 **rot=90** ⇒ `+12V`(A2/A3/B1~B3) 落在南边 y48~50 正对入口链,`D±`(B14/B15) 在东列。
|
||
⛔ **`U32` 只能放 y=30,不能放 37**:hub 带一共 28 mm,要塞下「12V 横脊 5 + 南边逃逸 4.3 +
|
||
本体 9.75 + 北边 D± 扇出 8.6」。放 37 时北沿离插槽焊盘只剩 **1.6 mm**,
|
||
布线器实测 `USB2` 直接布 0 段。
|
||
⛔ **9 A 的 12V 分配走了两次弯路,最后是「输入带母线 + 一条横脊」**:
|
||
· 第一版让排布器摆入口链 ⇒ `F1`/`Q1`/`D1` 被摊到整条 110 mm 上,`VIN_FUSED` 一个网的
|
||
焊盘外框 42 mm 宽、四段铜面互相重叠。⇒ **入口链整条手排**(J1→F1→Q1→D1→C2/C3→Rs6→U13)。
|
||
· 第二版在槽阵南沿画了一条横杠 ⇒ 五对 D± 要竖着穿过它,**两层板上一根竖线就把横杠整个切断**,
|
||
而铺铜管理器 / DRC / 断面校核三个都只说「有铜」。⇒ 改成脊 + 布线器画的 1.5 A 支路。
|
||
· 第三版想给每槽加一根铺铜「齿」走两列焊盘之间那条 5.2 mm 无盘带 ⇒
|
||
**槽的第 65 脚(屏蔽脚 3.0×5.0,接 GND)正坐在那条带的正中**,断面量出来 0.00 mm。
|
||
定稿:`BUS_IN`(63~91 × 0.8~16.0,15.2 mm) + `SPINE`(2~91 × 15.8~20.8,5 mm),
|
||
断面校核(`pour_base.py`,逐刀竖切取最窄、跳过串联元件本身)全过。
|
||
⚠ `VIN_RAW` 1.70 / `VIN_FUSED` 6.35 **不强制**:瓶颈是 DC-005 三只脚和 1206 保险本身,
|
||
板上加铜救不了 —— 与「插座超额定」是同一条已知风险(设计文档 §22.6)。
|
||
⛔ **布线器要知道铺铜的存在**:顶层电源铜面按各自的网标进占用图,
|
||
否则别的网会大大方方从 12V 母线中间穿过去,铺铜时把母线整段切断。
|
||
📌 **用户拍板(2026-09-09)**:最远一路 D± **接受 ~70 mm**(方案 §6.3 预估 41 mm 的前提是
|
||
「D± 排在靠 Hub 那一端的针位」,而 M2d 定稿把它放在 B14/B15 = 42 mm 长插槽的正中)。
|
||
仍远短于 R1 载板的 92 mm,且 `J39~J43` 五个 D± 退路座本就是为这一条留的。
|
||
⇒ **M5 的验收判据「六对 D± ≤45 mm」改写成 ≤75 mm**。
|
||
新脚本:`pcb_base.py`(板框/分区/槽阵/母线,唯一事实来源)、`rules_base.py`、
|
||
`place_base.py`、`route_base.py`、`pour_base.py`;`miter.py` / `board_check.py` 加了 `--base`。
|
||
截图 `.claude/r2/M8-place-all.png`。
|
||
- 要继续 R1 的布线,从下面「⭐ 新会话从这里开始」往下读;
|
||
要做 R2,读 `刀片式方案规划-R2.md`:§0.3 的 T1~T8 **现在全部已结**,§13 是 M1 落地记录、§21 是三项收口。
|
||
- ⛔ 手工活只剩一件:工程树里删掉误建的空工程 `PhoneRail-R2b`。
|
||
(原来的「Add into BOM 要在客户端手改」已作废:`addIntoBom` 是 **boolean**,
|
||
当初传的是字符串 `'no'` 才改不动。`MI8-KEY-PAD` 那条同样的结论也应该重试。)
|
||
(原来第二件「量主板厚度」已由 §21.1 的上下界论证取代;**装配首件**仍要用塞尺确认一次
|
||
R1 §22.3e 那处自相矛盾 ——「贴合面屏蔽罩 1.4 mm」vs「贴合面元件全低于 1 mm」,
|
||
螺柱间隙就是按 1.0 定的。真顶到就把垫片换 1.5,槽距那边有 7 mm 富余。)
|
||
|
||
---
|
||
|
||
|
||
更新:2026-09-08 **第三十四轮**。✅ **12V 输入换成圆形 DC 电源座**(`DC-005-5.5*2.5`,
|
||
用户拍板不降载、接受插座超额定)——原理图与 PCB 两侧都已落地并逐项回查通过;
|
||
摆位 301 件已下发,悬空铜清零,扇出补口完成。⛔ 两条要紧的:
|
||
**① ~~「从原理图导入变更」对下板已不能用~~ → 已修好**:根因是 20 个元件的 `uniqueId`
|
||
与原理图错位一格,`pcb1_uid_sync.py` 对齐之后变更清单归零(见交接二);
|
||
**② ~~8 A 输入链的三块顶层铺铜要重画~~ → 已重画并下发**,断面全过(见交接三)。
|
||
布线只欠 50 个网络 / **97 条连接**,**不是整板重布**;DRC 间距错误 **5 条**,全在 U6/U7 那一窝。
|
||
|
||
---
|
||
|
||
更新:2026-09-08 **第三十三轮**。✅ **载板已完全恢复**:原 `PCB2-CARRIER` 在一次桥接失同步
|
||
事故中损坏,靠工程历史还原将其移除,新建 **`PCB2`(`942ed1560d81c1e7`)** 按快照重建,
|
||
**DRC 已回到 115 条基线、连接性 0**。下板 PCB1 全程未受影响。细节见「交接(一)」。
|
||
|
||
本轮已定稿的设计决策:**U32 改 `CFG_SEL[2:0]=110`(strap 禁用)**,取代上一轮的
|
||
「`PRT_SWP1~5` 各 100k 下拉」——那五颗里有三颗(CH1/CH2/CH3)在载板上**布不出线**。
|
||
**原理图侧已经改完并验证通过、已存盘,不受载板事故影响。** BOM 净 −7 颗。
|
||
|
||
---
|
||
|
||
## ⭐ 新会话从这里开始
|
||
|
||
### 第三十四轮交接(一):✅ 12V 输入换成**圆形 DC 电源座**,两侧都已落地
|
||
|
||
用户 2026-09-08 拍板:**`J1` XT30PW-M → `DC-005-5.5*2.5`(立创 C9900017043),且不降载。**
|
||
|
||
#### ⚠️ 这是全板唯一一处「明知超额定还要装」
|
||
|
||
整机 12V 最坏工况 **9.99 A**(§22.6),而 DC-005 家族额定 **2~5 A**
|
||
(同族 XKB `DC-005-2.5A-2.5` = C319098 官方标 2.5 A)。
|
||
发热点在**插头内芯与插座弹片的接触面**,板上加铜救不了那一处。
|
||
⇒ 这不是「算过没问题」,是**已知风险、用户明确接受**。设计文档 §1 / §22.6 要写明。
|
||
|
||
板端唯一能做的缓解已经做了:**pin2 / pin3 两个负极触点都接地并联**,接触电阻减半。
|
||
|
||
#### 引脚定义(查过三处,两处互相印证;装配前仍要用万用表核一次)
|
||
|
||
| 脚 | 含义 | 接法 |
|
||
|---|---|---|
|
||
| 1 | 中心极,**正** | `VIN_RAW`(`$1N223`)→ F1.1 |
|
||
| 2 | 负极**静触点**(无插头时与 3 短接)| GND |
|
||
| 3 | 负极**动触点**(插头外壳压这一片)| GND |
|
||
|
||
> 万用表判据:无插头时 2-3 导通、1 对 2/3 断开。
|
||
|
||
#### 做了什么
|
||
|
||
| 步骤 | 脚本 | 结果 |
|
||
|---|---|---|
|
||
| 原理图换件 | **`p1_dcjack.py`** | `verify_sch --nets` 悬空 0 / 单引脚 0 / 一网多名 0;`port_audit` 458 个可疑 0;`xpage` 漏接 0 |
|
||
| PCB 换件 | **`pcb1_dcjack.py`** | 封装 / 三个引脚网络 / 元件数 全部回查通过 |
|
||
| 摆位 | `pcb1_place.py --push` | 301 件,本地六项全过;`edge_access` J1 离西板边 **0.5 mm**、桶口朝外(已截图确认)|
|
||
| 悬空铜 | **`pcb1_orphan_cu.py`** | 25 段线 + 2 孔清掉,回查碎片 **0** |
|
||
| 扇出补口 | `pcb_fanout.py --only <31 件>` | +13 孔,GND 缺口 26 → 23 |
|
||
|
||
板上现在:**301 件 / 铜层 2878 线(顶 2174 / 底 704)/ 955 孔 / 1046 焊盘 / 15 铺铜**。
|
||
|
||
---
|
||
|
||
### 第三十四轮交接(二):✅ 「从原理图导入变更」已修好(根因是 uniqueId 错位)
|
||
|
||
换 J1 时撞上的,**这条比 J1 本身重要**。
|
||
|
||
对话框提出的是一大串风扇块重映射:`J27→J26`、`Q10→Q9`、`R753→R752`、
|
||
`Q7` 换成 4 脚座封装、`R747` 换成 DC 座封装……而下板和原理图**按四项逐个对过、全部一致**:
|
||
|
||
| 对账项 | 结果 |
|
||
|---|---|
|
||
| 位号(301 个)| 全对 |
|
||
| 封装名 | 只有 J1 一处不同(就是要改的那处)|
|
||
| 器件值(风扇块 23 件)| 全对 |
|
||
| **焊盘网络**(风扇块)| 全对,且自洽(J26→`FAN_IN_TACH_RAW`→R750/751/752→Q9→`FAN_TACH_IN`)|
|
||
|
||
根因是 skill §9o:**P6-FAN-EDL 页整页重画过,通道 ID 全变了**,
|
||
EasyEDA 按内部 ID 重新配对、配错一格。**应用下去会把一个本来正确的风扇块打乱。**
|
||
|
||
#### ✅ 已修(同日)
|
||
|
||
`getState_UniqueId()` 一查就清楚了:**原理图的 ID 比 PCB 的整整大 1**,
|
||
全板 301 件里错 20 个、全在 P6-FAN-EDL 那一页。
|
||
|
||
位号 PCB 原理图
|
||
J26 gge418 gge419
|
||
J27 gge419 gge420 ← 板上 J27 拿着原理图 J26 的 ID
|
||
Q9 gge423 gge424
|
||
|
||
**`pcb1_uid_sync.py`**:按位号对账 → **两阶段**写回(先临时 ID 再目标 ID,
|
||
因为这是个排列,直接写会中途重号)→ 回查逐个一致且无重号。
|
||
|
||
结果:变更清单从一大串塌成**一行**(`J1:通道ID (空) → $1I219` ——
|
||
API 新建的元件本来就没有通道ID)。应用它,再开对话框 **0 条变更**。
|
||
应用前后风扇块 20 件的焊盘网络**逐条未变**,元件 301 / 铜 2878 / 孔 955 / 铺铜 15 也没动。
|
||
|
||
⇒ **导入对话框现在可以正常使用了。**
|
||
|
||
> ⚠️ 改的是元件身份,`DRC / 几何检查 / 连通性一条都不会报` ——
|
||
> 唯一验收是「重开对话框看还剩几条」。写之前存了快照 `_pcb1_snap_pre_uidsync_20260908.json`。
|
||
|
||
> 💡 教训已并入 skill **§9o-2 / §9o-3**:
|
||
> 判据是「位号 / 封装 / 器件值 / **焊盘网络** 四项对账」,**不是对话框**;
|
||
> 其中只有焊盘网络那一项有判别力(同封装、同型号之间的错位前三项都看不见)。
|
||
|
||
> 💡 读那个对话框时**不要用 `pcb1_import.py --probe`**:它读滚动容器的 `innerText`,
|
||
> 而那张表是**多列分开渲染**的,`offsetTop` 在列之间碰撞 ——
|
||
> 表头(位号)和明细行会被拼错,读出来的清单似是而非。
|
||
> 新写的 **`p1_import_rows2.py`** 逐 `<tr>` 读、每行自带单元格。
|
||
> **但结论仍要以「PCB vs 原理图四项对账」为准,不要以对话框为准。**
|
||
|
||
---
|
||
|
||
### 第三十四轮交接(三):布线只欠 116 条,**不是整板重布**
|
||
|
||
PROGRESS 之前写「下发摆位 = 作废 2951 段铜、整板重布」。**实测不是。**
|
||
31 件挪位之后,270 个没动的元件的铜完好,欠的是 **52 个网络 / 116 条连接**。
|
||
⇒ **不要跑 `pcb_fanout.py --clean`**(那条会把 955 孔 + 2935 线全删),走增量补线。
|
||
|
||
#### ✅ 8 A 输入链的铺铜已重画并下发(2026-09-08 收尾)
|
||
|
||
新链路是**单向**的,比旧版顺:`J1(−18.8) → F1(−12.5) → Q1(−6) → D1(1) → 东北去 C2/C3/Rs6`。
|
||
旧版是 J1 一路向东到 Q1、再折回西边找 Rs6。**C2/C3/C4/C5/C6/Rs6 一颗没动**,
|
||
所以旧的干道 / 两个电容口袋 / 北柱原样保留,只重画了西端进料三块 + 干道西延。
|
||
|
||
| 断面 | 实测 | 需要 |
|
||
|---|---:|---:|
|
||
| RAW J1.1→F1.1 (x=−14.2) | 5.75 mm = **11.5 A** | 8 A |
|
||
| FUSED F1.2→Q1 源极 (x=−10.7) | 4.50 mm = **9.6 A** | 8 A |
|
||
| SW Q1 漏极东出 (x=−1.5) | 9.25 mm = **16.2 A** | 8 A |
|
||
| SW 过 D1 北上 (x=2.0) | 12.75 mm = **20.5 A** | 8 A |
|
||
| SW 干道 / 北柱到 Rs6.1 | 4.75 / 3.75 mm = **10.0 / 8.4 A** | 8 A |
|
||
|
||
回读实测:`$1N223` 25 mm² / `$1N227` 23 mm² / `$1N236` 256 mm²,**各自一个连通域**;
|
||
15 块铺铜全部填充;异网最近距 0.25 mm(下限 0.20)。
|
||
|
||
#### ⚠️⚠️ 顺带修掉一个藏了很久的东西:`pcb1_pour.py` 也在用**假板框**
|
||
|
||
它的栅格一直是 `160×125 @(0,0)`(`pcb1_place.py` 第三十轮就改成真板框了,这个文件没跟)。
|
||
平时看不出来 —— 所有铜都在第一象限;一把元件挪到 x<0,三块顶层铜当场报
|
||
「碎成 0 块 / 断面 0.00 mm」,而**板上的铜其实没问题**(多边形是原样下发的)。
|
||
已把毫米↔栅格收进 `gi/gj/gx/gy` 四个函数,板框改成 `220×135 @(−30,−5)`。
|
||
副作用是**地平面现在真的覆盖整块板**(Inner1 从 28351 → 29099 mm²)。
|
||
|
||
⛔ **但改共享常量震到了 `pcb1_netlist.py`**:它 `G = PO.G` 却自己写 `int(x / G)`,
|
||
于是坐标偏了 30 mm,报出「+12V 从 4 个碎片炸成 23 个」的假象,
|
||
`pcb1_orphan_cu.py` 据此误删 12 个过孔(所幸那些碎片本来就不含焊盘,电气无损)。
|
||
已修,教训写进 skill **§9ah / §9ah-2**:
|
||
**「连通性突然大面积变差」+「实测回读健康」= 先怀疑度量,别改板子。**
|
||
|
||
#### 还剩的 5 条 DRC 间距错误(都在 U6/U7 那一窝)
|
||
|
||
`SAT_FLIP` 把 C609/C612 转了 180°,两个脚南北互换,旧铜接到了对方脚上 ——
|
||
**那是真短路不是 DRC 挑剔**(端点落在对方焊盘轮廓里)。
|
||
`pcb1_satflip_fix.py` 删掉了那 4 段(9 → 5 条)。剩下 5 条是
|
||
`$6N532`/`$6N547`/`SDA`/`VDAC4` 与挪位后的卫星件抢地方,**交给 `--ripup` 布线**。
|
||
C609.1/C612.1 的地扇出补不进去(那一窝太挤),同样交给布线。
|
||
|
||
#### 下一步的第一件事:整块重布
|
||
|
||
**`pcb1_pour.py` 里 `VINRAW-TOP` / `VINFUSED-TOP` / `VINSW-TOP` 三块的多边形坐标
|
||
是按旧摆位手写的**(J1@8.5、F1@17.5、Q1@24、D1@31),而输入首级整体**西移了 30 mm**
|
||
(J1→−18.8、F1→−12.5、Q1→−6、D1→1)。现在那些多边形和 §「8 A 输入链」那一排
|
||
断面校核线**量到的都是空气**。文件里已有一条同样的教训注释(第二十三轮那次)。
|
||
|
||
这是全板电流最大的一段(8 A,顶层 1 oz),**要按新几何重画,不能顺手拖一下**。
|
||
|
||
#### 剩下的链(按顺序)
|
||
|
||
```bash
|
||
# 0. ⛔ 先重画输入链三块顶层铺铜 + 断面校核线(pcb1_pour.py,见上)
|
||
/c/Python314/python .claude/pcb1_i2c_l3.py # 挪件之后换层孔要重算
|
||
/c/Python314/python .claude/pcb1_route_sig.py --refresh --ripup --push
|
||
/c/Python314/python .claude/pcb1_route_usb.py # J22 东移了 30 mm
|
||
/c/Python314/python .claude/pcb1_pour.py --push
|
||
/c/Python314/python .claude/drc_read.py
|
||
```
|
||
|
||
⚠️ `FAN_12V_SW` 的 0.8 mm 线宽**已经落实**:`pcb1_rules.py` 新增 `FAN12V` 类
|
||
(0.8 / min 0.3 / max 3.0)并指派给该网络,34 个网络指派全部下发成功。
|
||
依据(Q7 居中、东西各 0.67 A、51/39 mV,而 0.20 mm 下是 204/155 mV)写在文件里。
|
||
|
||
⚠️ **J1 换件之后 `AUTO_TRACK['VIN_RAW']` 的探针从 `J1.2` 改成了 `J1.1`**
|
||
(XT30 是 1=`−`/2=`+`,DC-005 是 1=中心正极)。探针写错时 `pcb1_rules.py` 是硬失败、
|
||
不会静默放过 —— 这次就是它拦下来的。
|
||
|
||
#### 本轮新增的常驻工具
|
||
|
||
| 文件 | 用途 |
|
||
|---|---|
|
||
| `p1_dcjack.py` | 原理图侧 J1 换 DC 座(幂等,自带线段集合比对的回查)|
|
||
| `pcb1_dcjack.py` | PCB 侧定点换件,**绕开导入对话框**;记着 `create()` 的签名是 `(器件, layer, x, y, rot, ?)` |
|
||
| `pcb1_orphan_cu.py` | 找/删**悬空铜**:判据是「碎片里既无焊盘也无铺铜」。删除按坐标带容差匹配,且线/孔分开走各自 API |
|
||
| `p1_import_rows2.py` | 逐 `<tr>` 读导入对话框(替代 `--probe` 的 innerText 拼接)|
|
||
| `pcb1_uid_sync.py` | **把 PCB 元件的 `uniqueId` 与原理图对齐**(两阶段写,避免中途重号)—— 导入对话框失灵时的正解 |
|
||
| `pcb1_satflip_fix.py` | 删 C609/C612 转 180° 之后接错脚的旧铜(真短路)|
|
||
|
||
---
|
||
|
||
|
||
### 第三十三轮交接(一):⛔ 载板 PCB 文档损坏 → 换文档重建
|
||
|
||
#### 事故链(责任在流程漏了一道判据,防呆已补)
|
||
|
||
```
|
||
pcb2_cfgsel.py --push 建 6 线 2 孔 + save() ← 正常
|
||
pcb2_reload.py 删铺铜边框 → save() → location.reload()
|
||
↑ 重载回来载板已经进入「Load Empty」状态、铜层读回全 0,
|
||
而当时判断「重载成功」只看 windowId 变没变,**没有数图元**
|
||
pcb2_pour.py --push 建 7 块边框 → 填充一直 0/7 → 中途 save() ← 这一下把「空」写回文档
|
||
```
|
||
|
||
**根因是 skill §9ae 的失同步,而真正毁数据的是失同步之后那次 `save()`。**
|
||
`location.reload()` 本身不删数据。
|
||
|
||
#### 防呆(已落地)
|
||
|
||
- **`pcb2_reload.py` 新增 `assert_alive()`**:重载后强制数元件/导线/焊盘,
|
||
任何一项为 0 就 `sys.exit`,并写明「不要 save()、不要跑 pcb2_pour.py」。
|
||
⇒「重载成功」的判据从此是**图元数不为零**,不是 windowId 变了。
|
||
**这条防呆当天就救了一次**:重建完成后再跑 `pcb2_reload.py`,同样的失同步**又发生了**,
|
||
脚本在 `save()` 之前停住,一个字节都没写。
|
||
- skill 新增 **§9ae-2**,记了整条失败链、迷惑性现象和三条规矩。
|
||
|
||
#### ⛔ 结论:`PCB2-CARRIER` 这个文档修不好,必须换
|
||
|
||
三条互相印证的判据:
|
||
|
||
1. 重开之后电气对象(元件/焊盘/导线/过孔/铺铜)**一律读回 0**,
|
||
而**同一次会话里** PCB1 读回 301 件 / 2951 线 / 944 孔完全正常
|
||
——「换一块板对照」是区分「客户端坏了」和「这个文档坏了」最快的办法。
|
||
2. `getCurrentRenderedAreaImage()` / `zoomToAllPrimitives()` **只在这个文档上挂到超时**
|
||
(不是 §9t 那种 88 字节空 PNG),PCB1 上正常。
|
||
3. 决定性的一条:上一轮把孤儿图形删干净(1546 → 40)**并存盘、存盘后回查过**,
|
||
完整重启 EasyEDA 之后那些图形**又回来了而且翻倍**(1546 → 3091)
|
||
⇒ **对这个文档的写入根本没有真正落盘。**
|
||
|
||
~~⚠️ `文件 → 工程历史...` 在这台客户端上点不开,所以历史恢复这条路走不通。~~
|
||
**这句是错的(已于 2026-09-08 推翻)** —— 点不开是因为**当时的活动文档正是卡死的 PCB2**,
|
||
把活动文档换掉之后它就能开。最终正是靠它恢复的,见下面「实际怎么解决的」。
|
||
|
||
#### ✅ 重建配方(已经完整跑通并逐条对账过一次)
|
||
|
||
事故前一刻正好跑过 `pcb2_cfgsel.py --refresh`,把整板几何 dump 进了
|
||
**`_pcb2_route_geom.json`**:导线 2033 段(层 1/2,带网名和线宽)、过孔 894 个、
|
||
焊盘 1000 个(216 元件 + 38 自由)。那份快照是在 `--clean` 之后、`--push` 之前抓的,
|
||
所以**再加上 `_pcb2_cfgsel.json` 账本里那 6 线 2 孔**,正好等于事故前的最终状态。
|
||
|
||
上一轮在旧文档里按这个配方重建了一遍,**对账结果**:
|
||
|
||
| 项 | 结果 |
|
||
|---|---|
|
||
| 216 个元件摆位 | ✅ 与快照逐位一致 |
|
||
| 1000 个焊盘(962 元件 + 38 自由)| ✅ 位号 / 坐标 / 网络 / 层 全对上,缺 0 多 0 |
|
||
| 2039 段铜层导线 | ✅ 逐条一致(网络、层、两端点、线宽),**最大偏差 0.000 mm** |
|
||
| 896 个过孔 | ✅ 逐个一致 |
|
||
| 板框 1 / 穿线槽 10 / 手机位丝印 25 线 + 5 标签 | ✅ |
|
||
|
||
也就是说**材料是齐的、方法是验过的**,只差一个健康的文档。
|
||
|
||
#### ✅ 实际怎么解决的(2026-09-08):工程历史还原 + 新建 PCB 重建
|
||
|
||
**先纠正上面一句话**:文中曾写「`文件 → 工程历史...` 在这台客户端上点不开」——
|
||
那是因为**当时的活动文档正是卡死的 PCB2**。把活动文档换掉之后它就能开了。
|
||
⇒ 判据修正:**某个 GUI 功能点不开时,先怀疑当前活动文档卡住,而不是那个功能坏了。**
|
||
|
||
顺带另一个佐证:右键 `PCB2-CARRIER → 删除` 时服务端直接回 **`delete failed !`** ——
|
||
连删都删不掉,这个文档在服务端侧就是坏的。
|
||
|
||
**实际执行的顺序**
|
||
|
||
| 步 | 操作 | 结果 |
|
||
|---|---|---|
|
||
| 1 | `文件 → 工程历史...`(从健康文档打开)| 版本列表可用:`21:25:27` … `22:24:51` |
|
||
| 2 | 选 **`9月7日 21:37:52`**(= `pcb2_cfgsel.py --push` 存盘后、`pcb2_reload.py` 之前)| —— |
|
||
| 3 | 「还原」→ 弹出「当前历史记录之后同时存在其他PCB的更改,是否同时还原?」→ 选**同时还原** | 损坏的 `PCB2-CARRIER` **被整个移除** |
|
||
| 4 | 核原理图 | ✅ 完好:27 元件、单引脚网络 0、`U32.13`/`R712.2`=`+3V3_HUB`、`R711.2`=`GND` ⇒ `CFG_SEL=110` 仍在 |
|
||
| 5 | 工程树右键 `Board2` → `新建PCB(P)` | ✅ 新文档 **`PCB2` = `942ed1560d81c1e7`** |
|
||
| 6 | `pcb2_retarget.py 942ed1560d81c1e7 --write` | 27 个文件 / 31 处,旧 uuid 一处不剩 |
|
||
|
||
> ⚠️ **为什么敢选「同时还原」**:`21:37:52` 之后被改过的只有 `PCB2-CARRIER`(那是我的重建尝试);
|
||
> 原理图最后一次存盘在 `21:28:01`,在还原点**之前**,所以 `CFG_SEL=110` 不受影响;
|
||
> PCB1 本轮全程没动过板。**选之前先把时间线和每个版本对应的操作核一遍**,别凭感觉点。
|
||
|
||
> 💡 **`pcb2_reload.py` / `pcb2_pour.py` 那两次存盘在历史列表里根本没有条目** ——
|
||
> 这反过来证实了「对损坏文档的写入没有真正落盘」,也正是 `21:37:52` 是最后一个好版本的依据。
|
||
|
||
#### ✅✅ 载板已完全重建并验证通过(2026-09-08 收尾)
|
||
|
||
新文档 **`PCB2` = `942ed1560d81c1e7`**,逐项对账结果:
|
||
|
||
| 项 | 结果 |
|
||
|---|---|
|
||
| 元件 | **216**,摆位与事故前快照**逐位一致** |
|
||
| 焊盘 | **1000**(962 元件 + 38 自由);缺 0 / 多 0 / 坐标·网络·层全一致 |
|
||
| 铜层导线 | **2038**(顶 505 / 底 1533),与快照**逐条一致**,最大偏差 **0.0001 mm** |
|
||
| 过孔 | **896**,逐个一致,最大偏差 0.0000 mm |
|
||
| 板框 / 穿线槽 / M3 孔 / 手机定位孔 / 丝印 | 1 / 10 / 8 / 30 / 25 线 + 5 标签 |
|
||
| 设计规则 | 差分对 **11/11**、线宽指派 **12/12**、铺铜全连接 **5/5**、对内间距 11 条 |
|
||
| 铺铜 | **7/7 填充**,优先级 1<3<5<7<9<11 (L15) + 1 (L16),地平面覆盖 0.6,0.6~219.4,134.4 |
|
||
| `inner1_verify` | 五个 VO 岛**主域占本网铜 100%**,3 焊盘 + 11 过孔全在主域,最窄断面 7.05~28.75(下限 7.0)✅ |
|
||
| `pcb2_net_conn` | **0 / 22 个网络不连通** |
|
||
| **DRC** | **115 条 = 间距错误 115(基线)+ 连接性 0** ✅ |
|
||
|
||
> 比事故前还干净一点:顺手清掉了一条 `PRTDIS7` 的游离导线(见下)。
|
||
|
||
**收尾时踩到并已修的两件事**
|
||
|
||
1. **铺铜填充一直 0/7**,两次都卡住。判据是 §9k 的「窗口底部有条 0% 进度条」——
|
||
实测到了。先查出 `pcb_Document.getCalculatingRatlineStatus()` 是 **`active`**(飞线在算),
|
||
`stopCalculatingRatline()` 停掉了但**没解决**;最后靠 `pcb2_reload.py` 重载才通,
|
||
重载后 `assert_alive()` 回查 216/2644/896/1000 全对,接着铺铜一次 7/7。
|
||
⇒ **修正上文那条「全程不要跑 `pcb2_reload.py`」**:重载本身没问题,
|
||
问题一直是**那个损坏的文档**。在健康文档上重载是安全的,而且是清掉卡死后台任务的唯一办法。
|
||
前提:**重载前先存盘并回读验证,重载后必须过 `assert_alive()`**。
|
||
2. **一条漏网的重叠导线**:`PRTDIS7` L2 `(101.250,62.133)→(101.820,62.133)`。
|
||
`pcb2_cfgsel.py --clean` 当时按两小段删(101.250→101.322、101.322→101.821),
|
||
报告「12/12 全删中、回查清零」,**但板上还有一条跨整段的重叠图元没被覆盖**。
|
||
它跟着进了 `_pcb2_route_geom.json` 快照,重建时又被重放回来,DRC 报「游离的导线」。
|
||
已删并补进 `pcb2_cfgsel.DEAD_LINES`。
|
||
⇒ **教训:删除的回查判据要问「该网络还剩几条」,不能只数「删中了几条」。**
|
||
|
||
#### 驱动 EasyEDA GUI 的几条实测(本轮踩出来的)
|
||
|
||
1. **右键菜单要点在 `tree-node_*` 那一层**,点文本叶子无效。而且必须发完整的
|
||
`pointerdown/mousedown/pointerup/mouseup` + `contextmenu`,坐标取该行的包围盒中心。
|
||
2. **菜单项只认 React 的 `onClick`**:合成鼠标事件对子菜单项静默无效
|
||
(`文件 → 新建 → PCB(P)` 点了三次都没反应)。要往上找 `__reactProps$` 里的 `onClick` 直接调。
|
||
3. **列表行的选中反过来只认原生鼠标事件**:工程历史的版本行用 `onClick` 点了
|
||
`fire` 报成功但 `tree-rowline-selected_*` 不出现,改发原生 pointer/mouse 序列才选中。
|
||
⇒ **两种都要备着,按元件类型试。**
|
||
4. 「删除文档」的确认框里复选框是真 `<input type=checkbox name=delReply>`,
|
||
要 `checked=true` + 触发 React 的 `onChange`,光 `click()` 不行。
|
||
|
||
#### 换文档重建的完整步骤
|
||
|
||
**第 0 步(用户在 GUI 里做)**:工程树右键 `Board2`(phonerail-carrier) → 新建 PCB。
|
||
|
||
```bash
|
||
# 1. 把 27 个脚本里硬编码的载板 uuid 一次性换掉(31 处)
|
||
/c/Python314/python .claude/pcb2_retarget.py # 先看清单
|
||
/c/Python314/python .claude/pcb2_retarget.py <新uuid> --write # 换,并回查旧 uuid 一处不剩
|
||
|
||
# 2. 新建的 PCB 默认 2 层,先切 4 层
|
||
/c/Python314/python .claude/pcb2_place.py --layers
|
||
|
||
# 3. 元件(216 个全部是「增加元件」,「包含设计规则」必须不勾)
|
||
/c/Python314/python .claude/pcb1_import.py --board2 --probe
|
||
/c/Python314/python .claude/pcb1_import.py --board2 --apply
|
||
|
||
# 3b. 设计规则 ⚠️ **必须在导入元件之后**跑
|
||
# 先跑的话网络还不存在,实测:差分对 0/11、线宽指派 0/12、铺铜全连接 0/5 全落空,
|
||
# 而规则本体会成功下发 —— 看起来像成功了。导入后重跑一次就是 11/11、12/12、5/5。
|
||
/c/Python314/python .claude/pcb2_rules.py --push
|
||
|
||
# 4. 摆位 + 机械
|
||
/c/Python314/python .claude/pcb2_place.py --push # 216 件
|
||
/c/Python314/python .claude/pcb2_place.py --outline # 板框 + 10 槽 + 8 个 M3 孔
|
||
/c/Python314/python .claude/pcb2_place.py --mech # 30 个定位孔 + 手机位丝印
|
||
|
||
# 5. 铜(2039 线 + 896 孔,分批 250,自带下发前守卫和落盘后回查)
|
||
/c/Python314/python .claude/pcb2_restore.py --copper --push
|
||
|
||
# 6. 铺铜 + 校核
|
||
/c/Python314/python .claude/pcb2_pour.py --push
|
||
/c/Python314/python .claude/inner1_verify.py
|
||
/c/Python314/python .claude/drc_read.py --pcb2 # 对 115 条基线
|
||
```
|
||
|
||
⚠️ **关于 `pcb2_reload.py`**(此处曾写「全程不要跑」,2026-09-08 已推翻):
|
||
`location.reload()` 本身没问题 —— 它在**健康文档**上完全正常(重建收尾时用它清掉
|
||
卡死的后台任务,重载后回查 216/2644/896/1000 全对)。当初把载板打进「Load Empty」的
|
||
是**那个已损坏的文档**,不是重载动作。
|
||
⇒ 用它之前的两条硬前提:**① 先存盘并回读验证;② 重载后必须过 `assert_alive()`**
|
||
(脚本已内置,读回 0 就 `sys.exit` 且禁止任何 save)。
|
||
|
||
#### 新工具
|
||
|
||
| 文件 | 用途 |
|
||
|---|---|
|
||
| `pcb2_restore.py` | `--survey` 清点 / `--clean-orphans` 删孤儿图形 / `--copper [--push]` 从快照重放铜层。守卫只数**铜层**(1/2),别再被封装带进来的 605 条丝印顶掉 |
|
||
| `pcb2_retarget.py` | 一条命令把 27 个脚本的载板 uuid 换掉,并回查旧 uuid 一处不剩 |
|
||
|
||
---
|
||
### 第三十三轮交接(二):✅ `CFG_SEL=110` —— 原理图侧已完成,不受事故影响
|
||
|
||
用户在本轮拍板走 **(c) 改 `CFG_SEL[2:0]=110` 关掉 strap**(三条路的比较见下面第三十二轮交接)。
|
||
|
||
#### 依据(datasheet `DS00001598C` 原文逐条核过,见 §21.6b)
|
||
|
||
- **Table 5-2**:`110` 那一行**只有**「Internal Default Configuration • Strap Options are Disabled」——
|
||
没有 `111` 的 Ganged Power/OC Switching,没有 `100/101` 的 Dynamic Power Switching,
|
||
没有 `010` 的 Bus Power Operation。**它是唯一干净的「关 strap」档位。**
|
||
- **Table 5-1 + 5-3 的缓冲类型**决定三个脚各自怎么接:
|
||
|
||
| 脚 | 缓冲类型 | 复用 | 怎么接 |
|
||
|---|---|---|---|
|
||
| `CFG_SEL2`(13) | **`I` 纯输入** | 无 | **直接接 `+3V3_HUB`,不加电阻** |
|
||
| `CFG_SEL1`(42) | `I/O12` | `HS_IND`(**输出**)| 必须经 `R712` 10k 上拉 |
|
||
| `CFG_SEL0`(41) | `I/OSD12` 开漏 | `SCL/SMBCLK` | `R711` 10k 下拉,**不动** |
|
||
|
||
⇒ 上一轮计划里的 **`R713` 不需要**:pin 13 本来就是硬接 GND 的,改成硬接 `+3V3_HUB`
|
||
完全对称,还省掉一次「在 U32 西侧找位置 + 布线」。**BOM 净 −7 而不是 −6。**
|
||
- **必须连带删掉 `R714`/`R715`**:strap 一停口 6/7 就开着,那两颗 10k 上拉对 Hub 内部 15k
|
||
下拉分压得 `3.3 × 15/25 = 1.98 V`,正好压在全速设备「已插入」的 2.0 V 判据上 → 幽灵口。
|
||
删掉之后 D+/D− 悬空、被 Hub 自己的 15k 下拉拉低 = 空闲,无害。
|
||
|
||
#### 原理图 C2-HUB 已完成(已存盘)
|
||
|
||
`.claude/c2_cfgsel.py`:删 7 元件 / 4 旗 / 5 端口 / 13 条导线图元,新建 5 线 / 3 旗 / 1 端口,
|
||
页面文字全部重写。验证结果:
|
||
|
||
| 检查 | 结果 |
|
||
|---|---|
|
||
| `verify_sch.py --nets` | 单引脚网络 0 / 无网络名 0 / 一网多名 0;悬空 27→34(+7 全是有意的:5 个 `PRT_SWP` + `USBDN6_DP`/`USBDN7_DP`)|
|
||
| 网表读回 | `U32.13 [+3V3_HUB]`、`R712.2 [+3V3_HUB]`、`R711.2 [GND]` ⇒ **`CFG_SEL[2:0]` 正好是 110** ✅ |
|
||
| `port_audit.py --board Board2` | 455 个旗/端口,可疑 0 |
|
||
| `xpage.py` | 真正漏接 0(`PRTDIS6`/`PRTDIS7` 两个网络已随端口一起消失)|
|
||
| 截图 | `shots/C2-HUB-cfgsel110.png`,已看过,排版干净 |
|
||
|
||
⚠️ 画面上抓到、几何验证抓不到的一处:`+3V3_HUB` 电源旗原本放在 `(970,330)`,
|
||
标签跟右边 25 单位外 `(995,330)` 的地旗标签正好相接,而且**一个电源旗夹在两个地旗中间看着就像地**。
|
||
已下移到 `(970,305)`。(skill §10「几何验证证明不了看着对」的又一例。)
|
||
|
||
#### 设计文档已同步
|
||
|
||
- 决策清单 **#18 划掉**(改为「已被 #19 取代」),**新增 #19** = `CFG_SEL=110`。
|
||
- §21.6b 待补:`CFG_SEL=110` 的完整依据与接法(目前依据都在 `c2_cfgsel.py` 文件头里,内容完整)。
|
||
|
||
---
|
||
|
||
### 第三十三轮交接(三):下板 PCB1 —— 修掉「假板框」留下的 4 个不可达接插件
|
||
|
||
用户本轮的要求是「整体重新布局,降低布线复杂度」。**量化之后结论和直觉相反,先记结论:**
|
||
|
||
#### 1. 「整板重排 301 件」这个说法不成立 —— 202 件被载板钉死
|
||
|
||
| 类别 | 件数 | 为什么动不了 |
|
||
|---|---:|---|
|
||
| 五路通道模块 | **200** | x 由载板 `VOn_P` 三针钉死(`VO_X` = 10.4 / 46.0 / 53.6 / 126.7 / 142.0),`CH_PLACE.bx = VO_X ∓ 6` |
|
||
| `J24` / `J25` | **2** | 由载板 `J31`/`J32` 焊盘反推,脚本里写着「不许改」 |
|
||
| 可自由重排 | **99** | 其中还有 32 件功率件、26 件贴身从属件 ⇒ **真正能按 HPWL 挪的只有 37 件** |
|
||
|
||
#### 2. 「南北分配」这个自由度也没有油水
|
||
|
||
真板框下合法的南北分配有 8 种(假板框下只有 1 种,原注释「VO1 太靠左板边、VO3 太靠右板边」在真板框下不成立)。
|
||
逐一算加权 HPWL:**当前的「南 CH1/CH4/CH5 / 北 CH2/CH3」已经是 8 种里最优的**,其余 +1.7% ~ +7.1%。
|
||
|
||
#### 3. 布线复杂度堆在哪(10 mm 网格实测)
|
||
|
||
| y 带 | 信号铜 | 过孔 | | y 带 | 信号铜 | 过孔 |
|
||
|---|---:|---:|---|---|---:|---:|
|
||
| 15~25 | 536 | 101 | | 65~105 | 1788 | 321 |
|
||
| 25~35 | 669 | 118 | | 105~125 | 180 | 44 |
|
||
| **35~45** | **921** | **145** | | **−5~15** | **0** | **0** |
|
||
| **45~55** | **864** | **146** | | | | |
|
||
|
||
**y 15~55 这 40 mm 吃掉 55% 信号铜 / 54% 过孔**,而 y −5~15、左条 x −30~0、右条 x 160~190 完全空着。
|
||
但热区里 **57/76 件是钉死的通道件**(CH1/CH4/CH5 各 19 件,块高 41 mm 占满 y 18~59),
|
||
只有 19 件是控制簇 —— 所以「把热区疏散开」能做的事有限。
|
||
|
||
#### 4. 理论下界:−10.7%,且有相当部分不该兑现
|
||
|
||
37 件信号件全部放到 HPWL 最优(忽略重叠/板框/高度):6129 → 5471(−10.7%)。
|
||
但下界解里位移最大的 5 件是**把两路 TACH 接收电路从板边搬回板中间** ——
|
||
那会把 12 V 摆幅的裸 TACH 信号重新拉成 100 mm 长线。⇒ 加回约束后现实可得约 −4%~−6%。
|
||
|
||
---
|
||
|
||
#### ✅ 本轮真正做成的:4 个接插件从「插不上线」变成「能装」
|
||
|
||
这才是「假板框 160×125」留下的实质后果。`edgechk` 扫全部连接器,判据是「离**真**板边多远」:
|
||
|
||
| 位号 | 用途 | 离旧假框 | 离真板边(改前)| 改后 |
|
||
|---|---|---:|---:|---:|
|
||
| `J1` | XT30 12V 进线,**90° 板装**,`rot 270` 开口朝 −X | 0.5 | **30.5** ⛔ | **0.5** ✅ |
|
||
| `J22` | 调试 USB-C,`rot 90` 开口朝 +X | 0.4 | **30.4** ⛔ | **0.4** ✅ |
|
||
| `J26` / `J27` | 风扇 4P 直针座(壳高 11.5 mm)| −29.0 | **1.2 / 9.0** ⛔ | **1.0** ✅ |
|
||
| `J24` / `J25` | 板对板排针 | 7.0 | 37.0 | 不需要板边(与载板垂直对插)✅ |
|
||
|
||
**它们原来都缩在板内 30 mm,而上方 13 mm 处压着载板 —— 插头根本插不进去。**
|
||
这不是优化问题,是板子能不能用的问题。
|
||
|
||
**改动(共移动 28 件,`pcb1_place.py` 里已改并通过六项检查)**
|
||
|
||
| 组 | 动作 |
|
||
|---|---|
|
||
| `J1` + 输入首级 `F1`/`Q1`/`D1`/`DZ1`/`C1`/`R1` | 整体西移 30 mm,J1 到 x=−21.5(本体 −29.5~−15.3)|
|
||
| `J22` + CC 下拉 `R602`/`R603` | 东移 30 mm 到 x=184.4(`R602` 距 `J22.A5` 1.30 mm,`SAT` 表自动跟随)|
|
||
| `J26` / `J27` | 到真西/东板边 (−23.9, 115) / (183.9, 115) |
|
||
| 两路 TACH 接收(`R750~R753` / `R754~R757` + `Q9`/`Q10`)| 跟着各自风扇座到板边 |
|
||
|
||
**代价与依据**
|
||
|
||
- 全板加权 HPWL **5886 → 6129(+4.1%)**。这是板子可装配的必要代价,不是退步。
|
||
- ⚠️ `FAN_12V_SW` 压降复核:Q7 居中、两支**各只走 0.67 A**,0.8 mm 线宽下
|
||
西支 125 mm→51 mV、东支 95 mm→39 mV,远低于 `FAN_CIRCUIT` 的 0.2 V 预算。
|
||
当年注释担心的 0.26 V 是「单条 196 mm 走全电流」,分两支后不成立。
|
||
⇒ **`FAN_12V_SW` 要按 0.8 mm 下发,别当普通信号走 0.20。**
|
||
- TACH 拆分净效果只有 −18 mm(`RAW` −148、`TACH_IN/OUT` +183 * 抵消),
|
||
**保留它的理由不是长度而是信号性质**:换掉的是 12 V 摆幅裸信号(现在 12.9 mm),
|
||
留下的是经 N-MOS 整形后的 3.3 V 逻辑。在源头整形是对的做法。
|
||
|
||
**⚠️ 这些改动只在 `pcb1_place.py` 里,还没 `--push`。** 下发会作废现有 2951 段铜,
|
||
所以要和「下板整板重布」放在同一轮做:`--push` → 扇出 → `pcb1_route_sig` → 铺铜 → DRC。
|
||
|
||
**新分析脚本**(都在 scratchpad,需要长期保留的话再收进 `.claude/`):
|
||
`rows.py`(南北分配枚举)、`fp.py`(floorplan HPWL 评估)、`dens.py`(10 mm 网格拥挤度)、
|
||
`slack.py`(离网络重心距离)、`bound2.py`(理论下界)、`edgechk.py`(板边可达性)。
|
||
其中 **`edgechk.py` 值得收进 `.claude/`** —— 「接插件离真板边多远」这条判据本轮抓到 4 个真缺陷。
|
||
|
||
---
|
||
### 下一步(按优先级)
|
||
|
||
#### 1. ⛔ 载板:用户在 GUI 里新建 PCB → 我按脚本重建(**唯一的阻塞项**)
|
||
|
||
`Board2`(phonerail-carrier) 右键 → 新建 PCB。建好之后按「第三十三轮交接(一)」
|
||
那张命令表跑,第一步是 `pcb2_retarget.py <新uuid> --write`(27 个脚本 / 31 处一次换掉)。
|
||
|
||
#### 2. 下板 PCB1:把本轮算好的摆位下发 + 整板重布
|
||
|
||
`pcb1_place.py` 里已改好并通过六项检查 + `edge_access.py`,**但还没 `--push`**。
|
||
下发会作废现有 2951 段铜,所以要连着做完整条链:
|
||
|
||
```bash
|
||
/c/Python314/python .claude/pcb1_place.py --push # 28 件新位置
|
||
/c/Python314/python .claude/pcb1_place.py --outline # 板框/定位孔(若板框常量变过)
|
||
/c/Python314/python .claude/pcb_fanout.py # ⚠️ 扇出必须在铺铜之前
|
||
/c/Python314/python .claude/pcb1_route_sig.py --refresh --ripup --push
|
||
/c/Python314/python .claude/pcb1_pour.py --push
|
||
/c/Python314/python .claude/drc_read.py
|
||
```
|
||
|
||
⚠️ 重布前要先落实的两条(第三十轮就欠着):
|
||
- `pcb1_pour.py` 里「三块 +12V 各自含一个本网通孔焊盘」的保命条件,在 J26~J30 的
|
||
+12V 脚消失之后**已经不成立**,现在靠扇出的过孔活着 ⇒ **必须先扇出再铺铜**。
|
||
- **`FAN_12V_SW` 按 0.8 mm 下发**(2×0.67 A 分两支,见「第三十三轮交接(三)」的压降复核),
|
||
别当普通信号走 0.20。`FAN_PWM_L` / 两路 TACH 也还没布线。
|
||
|
||
#### 3. 仍然欠着的(不阻塞)
|
||
|
||
1. **12V 预算被 FAN-R2 顶到约 9.99 A**,10 A 适配器没余量 —— 要么限功率/降载,要么换适配器。**待用户拍板**。
|
||
2. 同级固件还是旧的单路 TACH,四个引脚定义没补
|
||
(`FAN_EN=IO5` / `FAN_PWM=IO18` 反相 / `FAN_TACH_IN=IO16` / `FAN_TACH_OUT=IO4`)。
|
||
kicad 侧有现成的 `kicad/firmware-sync/fan-r2.patch` 可参考。
|
||
3. 两边都还没解决的:**独立回流**(FR-1/SR-12,五路电池 `P−`/侧键地/USB 地在网表里全是全局 GND,
|
||
而载板已经铺完铜);MCU 的 `IO0`/`RXD0`/`TXD0` 没引出恢复测试点;
|
||
Hub 端口供电由 MCU 控但 `OCS` 未接。
|
||
|
||
#### 4. 本轮新增的常驻工具
|
||
|
||
| 文件 | 用途 |
|
||
|---|---|
|
||
| `edge_access.py` | **板边可达性**:接插件离**真**板边多远。本轮靠它抓到 4 个「插头插不进去」的真缺陷,而六项检查和 DRC 全过。`--board2` 查载板 |
|
||
| `pcb2_restore.py` | 载板事故恢复:`--survey` / `--clean-orphans` / `--copper [--push]` |
|
||
| `pcb2_retarget.py` | 一条命令换掉 27 个脚本里的载板 uuid |
|
||
| `pcb2_reload.py:assert_alive()` | 重载后强制数图元,为 0 就停 —— 当天就救了一次 |
|
||
|
||
---
|
||
### 第三十二轮交接(决策已在第三十三轮拍板为 (c),本段只作依据存档)
|
||
|
||
**这一轮没有半成品留在板上。** 两块板都在自洽状态,随时可以往任一方向走:
|
||
|
||
| | 元件 | 导线 | 过孔 | 铺铜 | 说明 |
|
||
|---|---:|---:|---:|---:|---|
|
||
| 下板 PCB1 | 301 | 2951 | 944 | 15 | 第三十一轮的 FAN-R2 已落地,间距错误 0 |
|
||
| 载板 PCB2 | 223 | 2649 | 896 | 7 | **= 加 strap 之前的基线**,DRC 115 条基线 |
|
||
|
||
---
|
||
|
||
## ⛔ 待拍板:U32 的 strap 脚怎么处理
|
||
|
||
### 事情的来龙去脉
|
||
|
||
设计文档 §21.6 原来写「`LED_A*`/`LED_B*` 都是 Strap,**悬空取默认 '0'**」——
|
||
2026-09-07 核 datasheet 时发现**手册里没有这句话**(依据见 §21.6a,都核过原文):
|
||
|
||
- `DS00001598C` Table 5-3:`IPD` = 带内部弱下拉、`IPU` = 带内部弱上拉,
|
||
而这十个脚全是 **`I/O12`(纯输入输出缓冲,一个字没提内部下拉)**。
|
||
(同表里 `OCS[1..7]_N` 确实是 `IPU`、`TEST` 确实是 `IPD` —— §21.6 那两条是对的。)
|
||
- Table 5-2:`CFG_SEL[2:0]=000` → 「Internal Default Configuration • **Strap Options are Enabled**」,
|
||
这些脚**确实会**在 `RESET_N` negation 时被采样。
|
||
- §7.5 + Figure 7-3(第 42 页):厂家推荐的无源方案是 **100 kΩ**。
|
||
|
||
**用户已拍板缩到五颗**:只做 `PRT_SWP1~5`(U32 脚 51/49/47/33/31 = `R900~R904`)。
|
||
理由是 Table 7-1 内部默认值本来就是 `Port Swap=00h`/`Boost=00h`,电阻不改变设定、
|
||
只是把**采样值**钉成本来就该有的那个 ⇒ 按「万一采到 1 会怎样」筛:
|
||
|
||
| strap | 采到 '1' | 装不装 |
|
||
|---|---|---|
|
||
| `PRT_SWP1~5` | 对应口 `D+/D−` **内部对调** → 那一路手机枚举不出来(且随漏电/温度变,每次上电可能不一样)| ✅ 装 |
|
||
| `PRT_SWP6/7` | 口 6/7 已被 `R714`/`R715` 上拉禁用 | ❌ |
|
||
| `BOOST0/1` | 只影响 SI/EMI | ❌ |
|
||
| `GANG_EN` | 本设计 `PRTPWR`/`OCS` 一根没接 | ❌ |
|
||
|
||
### ⛔ 然后撞上了物理限制
|
||
|
||
原理图五颗**已经画完并验证通过**(见下面「已完成」)。但**载板上摆不下**:
|
||
|
||
`pcb2_strap_solve.py` 对每颗枚举「位置 × 4 个朝向」,当场把地过孔和 strap 走线一并试,
|
||
四件全过才算解。结果:
|
||
|
||
| 电阻 | U32 脚 | 边 | 摆得下 | 有地过孔 | **走线** |
|
||
|---|---|---|---:|---:|---|
|
||
| R903 | 33 `PRT_SWP4` | 东 | 1 | 1 | ✅ 可解 |
|
||
| R904 | 31 `PRT_SWP5` | 北 | 2 | 1 | ✅ 可解 |
|
||
| **R902** | 47 `PRT_SWP3` | 东 | 132 | 116 | ⛔ **0** |
|
||
| **R901** | 49 `PRT_SWP2` | 南 | 195 | 174 | ⛔ **0** |
|
||
| **R900** | 51 `PRT_SWP1` | 南 | 169 | 143 | ⛔ **0** |
|
||
|
||
**摆得下、地也接得出去,就是线出不了 U32 的东/南边。** 根因:
|
||
U32 是 QFN-64 9×9、0.5 mm 间距,**焊盘之间只有约 0.2 mm 缝,穿不过 0.20 mm 的线**,
|
||
唯一出路是垂直出边;而东边紧贴着 `R710`/`C750`/`R709` 排成的一列(x≈106.3)——
|
||
从 `U32.47` 往东**只能走 0.7 mm**(1.0 mm 处离 R710.2 净距 0.134,1.4 mm 处 0.000)。
|
||
|
||
解不出来的正好是口 1/2/3 = **CH1/CH2/CH3 三台手机**,所以「只做能做的两颗」不成立。
|
||
|
||
### 三条路(等你选)
|
||
|
||
**(a) 挪开挡路的元件**:`R710`/`C750`/`R709` 那一列往东让 0.5~1 mm,给 U32 东边开通道。
|
||
代价:这几个网络要局部重布;而且南边 `PRT_SWP1/2` 是另一处,还得再想办法。
|
||
|
||
**(b) 只做能解的两颗**:⛔ 不建议 —— 等于给 CH1/CH2/CH3 留着最难查的失效。
|
||
|
||
**(c) ⭐ 改 `CFG_SEL=110`(Table 5-2:Internal Default Configuration • **Strap Options are Disabled**)**
|
||
strap 根本不采样,一颗电阻都不用,U32 拥挤的东/南两侧一点不用动。
|
||
**Table 7-1 已经逐条核过**:
|
||
|
||
| 寄存器 | 默认 | 对我们 |
|
||
|---|---|---|
|
||
| `FAh Port Swap` | 00h | 极性正常 ✅ 正是要的 |
|
||
| `F6h/F7h/F8h Boost` | 00h | 不加强 ✅ |
|
||
| `09h Non-Removable` | 00h | 和现在的 strap 设定一致 ✅ |
|
||
| `07h CFG2` | 20h | `PORT_PWR=0`/`CURRENT_SNS=00` = 联动通断/过流;我们 `PRTPWR`/`OCS` 没接,无所谓 ✅ |
|
||
| `06h` bit7 | 1 | 自供电 ✅(只有 `CFG_SEL=010` 那行强制总线供电,`110` 不改)|
|
||
| **`0Ah Port Disable`** | **00h** | ⚠️ **七个口全开** —— 见下面这条 |
|
||
|
||
⚠️⚠️ **走 (c) 必须连带去掉 `R714`/`R715`**。口 6/7 现在是靠 strap 关的
|
||
(§21.5:两颗 10k 上拉 `USBDN6_DP`/`USBDN7_DP`)。strap 一停这两个口就开着,
|
||
而那两颗上拉对 Hub 内部 15k 下拉分压得 `3.3 × 15/25 = 1.98 V`,
|
||
**正好压在全速设备「已插入」的 2.0 V 判据上** → 两个幽灵口反复枚举失败。
|
||
去掉之后 D+/D− 悬空、被 Hub 自己的 15k 下拉拉低 = 空闲,无害。
|
||
|
||
**(c) 的完整改动清单**(BOM 净 −6 颗):
|
||
|
||
| 改什么 | 怎么改 | 在哪 |
|
||
|---|---|---|
|
||
| `CFG_SEL2`(U32 pin 13) | 现在**直接焊到 GND**(所以从来没有 R713),改成 10k 上拉到 `+3V3_HUB` | U32 **西**边(东/南两条死路都不碰)|
|
||
| `CFG_SEL1`(`R712`) | 下拉改上拉 | 已有件,改一根短线 |
|
||
| `CFG_SEL0`(`R711`) | 不动(`110` = SEL2/SEL1 高、SEL0 低)| — |
|
||
| `R714` / `R715` | **不装** | 见上 |
|
||
| `R900~R904` | 删掉 | 原理图 + 板上(板上现在零铜)|
|
||
|
||
> 上一会话的倾向是 **(c)**,但这是配置决策(动 §21.3 那条已定稿的 `CFG_SEL=000`),
|
||
> 留给你定。**没有任何东西是必须先回滚的**:板上零 strap 铜。
|
||
|
||
---
|
||
|
||
## 这一轮已经完成、可以直接用的部分
|
||
|
||
| 项 | 状态 |
|
||
|---|---|
|
||
| 依据核实:Table 5-2 / 5-3 / 7-1 / Fig 7-3 原文逐条对过 | ✅ 写进设计文档 §21.6a |
|
||
| 设计文档:新增 §21.6a、决策清单 #18、§21.6 那条错误结论已改 | ✅ |
|
||
| 原理图 C2-HUB:`R900~R904` 接 `PRT_SWP1~5`,两条地母线两个地旗 | ✅ 六项检查全过 |
|
||
| 顺带清掉 C2-HUB 的**三重叠影文字**(22 条 → 9 条,原来有一份压在 J23 上)| ✅ |
|
||
| 载板 PCB 导入变更、223 件、五颗地端都是 GND | ✅ |
|
||
| `pcb2_place.GLOBAL` 里有这五颗(**若走 (c) 要删掉**)| ✅ |
|
||
|
||
**⚠️ 这一轮抓到的两个真错误(都已修,也都写进了 skill / 脚本注释)**
|
||
|
||
1. **地旗落在合并后的导线中段**(skill §8a-3):共地母线分两段建、旗放在中间那点,
|
||
**EasyEDA 会把共线两段合并成一条** ⇒ 旗变成压在中段,判定不相连。
|
||
PCB 网表里那几颗的地端成了 `$16N236` 而不是 `GND`。
|
||
`verify_sch` 四道检查全过 —— **是从 PCB 读回焊盘网名才抓到的**。
|
||
⇒ 旗必须落在「真的有支线接进来」的点上(本项目用某颗电阻的分支 x)。
|
||
2. **清理脚本删过头**:写成「`y==250` 的地旗全删」,把页面原有的
|
||
`+3V3_HUB`(1130,250)(`RESET_N` 上拉 `R716` 的电源端)一起删了 ——
|
||
**是导入对话框那条 `R716:2 +3V3_HUB → $16N210` 暴露的**。已恢复。
|
||
⇒ 只加不删的脚本要自己记账;删除条件必须只认自己放过的坐标。
|
||
|
||
**这一轮新增/改动的脚本**
|
||
|
||
| 文件 | 用途 |
|
||
|---|---|
|
||
| `c2_straps.py` | C2-HUB 放 strap 电阻 + 连线 + 重写页面文字(含全页碰撞检查)|
|
||
| `pcb2_strap_solve.py` | 位置/朝向/地过孔/走线**四件联合求解**;搜索走 2 mm 网格索引,`D.check()` 只在最后验一次 |
|
||
| `pcb2_straps.py` | 只摆这几颗(不动整板 223 件)|
|
||
| `pcb2_strap_gnd.py` | 局部地扇出(不动整板 415 个扇出孔)|
|
||
| `pcb2_strap_place.py` / `pcb2_strap_route.py` | 分步版,已被 `pcb2_strap_solve.py` 取代,留作记录 |
|
||
|
||
> **为什么最后要「联合求解」**:分三步走(摆位 → 地扇出 → 走线)连着踩了三次,
|
||
> 每次都是前一步只顾自己那一项:① 只按空地摆 → 迷宫布线器 10 条只通 3 条;
|
||
> ② 改成贴着引脚 → 地过孔被围死;③ 加了地过孔判据 → **电阻方向反了**
|
||
> (0402 的 GND 端朝着 U32,strap 线要跨过自己的地)。分步搜索每步都局部最优、合起来无解。
|
||
> 另外:搜索循环里**不能**调 `D.check()`(O(全部障碍),单颗跑 40 分钟出不来)。
|
||
|
||
---
|
||
|
||
## ⚠️ 另一件顺手修掉的事:下板板框常量过期了(影响很大)
|
||
|
||
`pcb1_place.py` / `pcb1_env.py` 里一直写着 `BW, BH = 160, 125`(原点 0,0),
|
||
而 `pcb1_outline.py` 从 2026-09-06「两板尺寸取大对齐」那一轮起画的是
|
||
**220 × 135、左下角 (−30, −5)**(回读板上多段线:x −1181.1~7480.3 mil / y −196.9~5118.1 mil,逐条对上)。
|
||
|
||
旧值是真板框的**子集**,所以越框检查一直「偏严但不错」—— 代价是
|
||
**左右各 30 mm、上下各 6 mm 的板面从来没进过摆位视野**
|
||
(301 个件全挤在 x 0.5~159.6 / y 1.4~124.0)。
|
||
`pcb1_env.py` 还把高度禁区裁到 `min(r, 160/125)`,右边和上边那两条 zone 整个丢了。
|
||
|
||
**已修**:两个脚本改用 `BX0,BY0,BX1,BY1 = -30,-5,190,130`,
|
||
`pcb1-env.json` 重新生成(zone 现在最远到 x=188.2),并加了 `board_rect` 字段。
|
||
|
||
**连带后果**:第三十一轮把风扇座摆到「两个上角」(6.3,121)/(151,121) 是按假板框算的,
|
||
其实都在板子中间。按真板框重扫,**左板边 y −4~128.5 整条、右板边 y −4~49 和 65~128.5
|
||
都放得下 11.5 mm 的 4P 风扇座**。
|
||
|
||
---
|
||
|
||
## 下一步(用户已拍板,但还没开工)
|
||
|
||
**下板 PCB1 按真板框 220 × 135 整板重排 301 件。**
|
||
会作废现有 2951 段铜,但下板本来就排着「整板重布」那一步,铜反正要重来。
|
||
重排时顺带把风扇座挪到真板边。
|
||
|
||
其余仍然欠着的:
|
||
|
||
1. 下板 `FAN_12V_SW` / `FAN_PWM_L` / 两路 TACH 还没布线。
|
||
`FAN_12V_SW` 是新电源网(2×0.67 A、最长约 89 mm),**按电流定宽度,别当普通信号走 0.20**。
|
||
2. `pcb1_pour.py` 里「三块 +12V 各自含一个本网通孔焊盘」的保命条件,
|
||
在 J26~J30 的 +12V 脚消失之后**已经不成立**,现在靠扇出的过孔活着。重铺前必须先扇出。
|
||
3. **12V 预算被 FAN-R2 顶到约 9.99 A**,10 A 适配器没余量了 —— 要么限功率/降载,要么换适配器。
|
||
4. 同级固件还是旧的单路 TACH,四个引脚定义没补
|
||
(`FAN_EN=IO5` / `FAN_PWM=IO18` 反相 / `FAN_TACH_IN=IO16` / `FAN_TACH_OUT=IO4`)。
|
||
kicad 侧有现成的 `kicad/firmware-sync/fan-r2.patch` 可参考。
|
||
5. 两边都还没解决的:**独立回流**(FR-1/SR-12,五路电池 `P−`/侧键地/USB 地在网表里全是全局 GND,
|
||
而载板已经铺完铜);MCU 的 `IO0`/`RXD0`/`TXD0` 没引出恢复测试点;
|
||
Hub 端口供电由 MCU 控但 `OCS` 未接。
|
||
|
||
---
|
||
|
||
### 第三十一轮交接(先读这一段)
|
||
|
||
**这一轮做的是「把 kicad 的设计变更同步到立创」**,不是布线轮。范围是用户拍板的两项:
|
||
**FAN-R2 + C737**(其余 kicad 侧改动经评估不需要同步,见下面「评估结论」)。
|
||
|
||
| 项 | 怎么做的 | 状态 |
|
||
|---|---|---|
|
||
| **P6-FAN-EDL 整页重画** | `p6_fan.py --place` → `--wire`:删 J28~J30 / R730~R732、J26/J27 换 4 针、新增 19 件、60 段线 24 件全断言过 | ✅ 六项检查全过 |
|
||
| **P3-CONTROL 三个端口** | `FAN_TACH` → `FAN_TACH_IN`;IO5 加 `FAN_EN`、IO4 加 `FAN_TACH_OUT`(端口只能删了重建,§3b)| ✅ |
|
||
| 跨页对账 | `xpage.py`:真正漏接 0;两个 `*_TACH_RAW` 加进 `NAMING_ONLY`(天然单实例)| ✅ |
|
||
| 端点审计 | `port_audit.py` 下板 457 个旗/端口,可疑 0 | ✅ |
|
||
| **C737 换固态钽** | 原理图删旧建新(**1 脚 = 正极**,看渲染图确认的,引脚名只有 1/2);PCB2 导入 2 条变更 | ✅ |
|
||
| C737 落板 | 底层 **(93.17, 54.0) rot 180**(转 180 是因为 +3V3_HUB 铜在东;东移 0.17 让净距回到 0.265)| ✅ |
|
||
| 载板收尾 | `reload → pour --push → inner1_verify → drc_read --pcb2`:**DRC 115 = 基线**,五岛全达标,`net_conn` 22/22 | ✅ |
|
||
| **下板导入变更** | 38 条(增 19 / 删 8 / 改网络 11),逐条滚出来核过,复选框全未勾 | ✅ |
|
||
| 下板摆位 | `pcb1_fan.py --push`:只动风扇那 24 件,拆废铜 164 线 / 40 孔 | ✅ |
|
||
| 下板收尾 | `pcb1_reload → pcb1_pour --push → drc_read`:**间距错误 0**、连接性 153(未布线)| ✅ |
|
||
| 截图 | `shots/P6-FANR2.png`、`PCB2-c737-zoom.png`、`PCB1-fanr2-north.png` | 待用户看 |
|
||
|
||
**这一轮踩到 / 抓到的**
|
||
|
||
1. ⚠️ **位号撞车**:kicad 把风扇电阻编成 `R740~R751`,而载板 EDL 下拉已经占了 `R741~R745`。
|
||
kicad 两块板是两个独立工程所以撞不出来,**立创是单一位号空间**。
|
||
立创侧整块改用 `R746~R757`,映射表在设计文档 §22.6a。
|
||
2. ⚠️ **摆位本地检查过 ≠ DRC 过**:第一版把风扇块摆进北中块 `y 66~88`,
|
||
焊盘对焊盘全过,**DRC 65 条间距错误** —— 底下压着已布好的 `+12V/+3V3/GND` 铜,
|
||
而 `route_sig --ripup` 只拆自己画过的信号线,**拆不掉电源铜**。挪到 `y 104~121` 的空带后归零。
|
||
3. ⚠️ **风扇座的 y 是被载板压出来的**:4P 塑壳 11.5 mm,下板 `hmax` 来自载板底面元件的投影。
|
||
`y 102~117` 被载板 C801/C821 那两颗 10.5 mm 罐压到 1.5;左边 `y 68~92` 被输入链占满。
|
||
最后取两个上角,J27 的 x 还得内收到 151(`x ≥ 156.29` 是排线槽,hmax 3.0)。
|
||
4. `pcb1_pour.py` 里「三块 +12V 各自含一个本网通孔焊盘」的保命条件,
|
||
在 J26~J30 的 +12V 脚消失之后**已经不成立**,现在靠扇出的过孔活着(已写进脚本注释)。
|
||
5. 三条新的 EasyEDA 行为(已写进 skill §6e / §2b / §12a):
|
||
`create(rot=180, mirror=true)` 的 SOT-23 = **G 左 / S 上 / D 下**(高边 P-MOS 的标准画法,
|
||
单靠 rotation 做不出来);`createNetFlag('Power', 任意网名, …)` 是有效的;
|
||
地旗的 `GND` 字样掉在符号下方约 15 个单位,会压住下面一行文字。
|
||
|
||
**下一步**:
|
||
|
||
1. **用户看三张截图**确认方向与排版(几何验证证明不了「看着对」)。
|
||
2. 下板 `FAN_12V_SW` / `FAN_PWM_L` / 两路 TACH 还没布线(连接性 153 里就有它们)。
|
||
`FAN_12V_SW` 是新电源网(2×0.67 A、最长约 89 mm),**按电流定宽度,别当普通信号走 0.20**。
|
||
3. 下板整板重布(第三十轮清单第 3 条)仍然欠着:`pcb1_route_sig.py --refresh --ripup --push`,
|
||
重布前先扇出、把上面第 4 条那个 +12V 保命条件重新落实。
|
||
4. **12V 预算被这一版顶到约 9.99 A**,10 A 适配器没余量了 —— 要么落实限功率/降载,
|
||
要么换更大适配器。这是个待用户拍板的项(设计文档 §22.6 已记)。
|
||
5. 同级固件还是旧的单路 TACH:要补 `FAN_EN=IO5` / `FAN_PWM=IO18(反相)` /
|
||
`FAN_TACH_IN=IO16` / `FAN_TACH_OUT=IO4` 四个定义。kicad 侧有现成的
|
||
`kicad/firmware-sync/fan-r2.patch` 可参考。
|
||
|
||
**评估结论:kicad 侧今天其余改动为什么不用同步**
|
||
|
||
- 引脚电气类型(906 处 passive 等)、NC 标记、PWR_FLAG、ERC 台账 —— 立创没有等价强度的 ERC。
|
||
- 五条迁移修复(Y 轴翻转、USB-C 长圆孔旋转、裸铜带 F.Paste、tenting 丢失、网名转义)
|
||
—— 都是 EasyEDA→KiCad 转换器的 bug,立创侧本来就是对的。
|
||
- kicad 的 PCB 布局布线(R2 布局、三批局部布线、J1 转向)—— 那是另起炉灶的一套,
|
||
立创 PCB2 已到第三十轮,**绝不能反向覆盖**。
|
||
- ⚠️ **两边都还没解决的**:独立回流(FR-1/SR-12,五路电池 P−/侧键地/USB 地在网表里全是全局 GND,
|
||
而载板已经铺完铜);MCU 的 IO0/RXD0/TXD0 没引出恢复测试点;Hub 端口供电由 MCU 控但 OCS 未接。
|
||
|
||
---
|
||
|
||
### 第三十轮交接(先读这一段)
|
||
|
||
**做完的**(全部已下发到载板 PCB2;回滚快照 `_pcb2_snap_r30_before.json`):
|
||
|
||
| 项 | 怎么做的 | 状态 |
|
||
|---|---|---|
|
||
| 站 1~3 重摆到新 PW/PH | `pcb2_place.py --clean-copper --outline --push --verify`(清铜 2411 线 / 605 孔 / 7 铺铜;槽 10/10 重建;218 件回读全 ✔)。`j7_assert` 51 条常量不符随之消失 | ✅ |
|
||
| **U21 / U22 转向** | rot 90 → **U21 (116.5,66.5) rot 0、U22 (127.5,66.5) rot 180**(脚排朝南北,16 根脚沿 9 mm 边出线;设计文档 §26.23「第三十轮落地」)| ✅ |
|
||
| 铜全部重建 | 顺序:差分 `route_dp --push` → `vo_vias --push` → `dump_pads` + `fanout --push`(415 孔)→ `route_sig --push`(GND 梳子 + 123 网)→ `gnd_patch`(悬空 0)→ **reload → pour → inner1_verify → DRC** | ✅ |
|
||
| 布通 | **123 / 123**(K 线提前到 KEY_* 之前、HUB_RST 提前到 VBUS_UP 之前、`_connect` 加 `'near'` 窗口 + `MAX_CELLS` 3.2M)| ✅ |
|
||
| Inner1 岛 | 最窄 7.00 / 7.30 / 7.20 / 7.70 / 19.2(下限 7.0);`VIA_KEEPOUT` 加 VO2 北带 (86.5,75,101,83.5) | ✅ |
|
||
| DRC | **115 = 全部封装内焊盘对焊盘基线**;`pcb2_net_conn` 22/22;`via_relabel` 0 处 | ✅ |
|
||
| 截图 | `shots/PCB2-r30-routed.png`、`PCB2-r30-595corridor.png` | 待用户看 |
|
||
|
||
**这一轮修掉的 bug / 坑(都写进了脚本注释,skill 加了 §9aa)**
|
||
|
||
1. `pcb2_vo_vias.py` / `pcb2_gnd_patch.py` / `pcb2_dp_long.py` 的路径 key 还在用 `#` 分隔(上一轮 `KSEP` 已改 chr(0))→ 校核把自家过孔当异网,13 条假「过孔-焊盘」。已改用 `R.KSEP`。
|
||
2. **扇出必须在差分之后**:GND 扇出先跑会把差分手写车道的位置占掉(10 条 −0.1 冲突)。顺序 dp → vo_vias → fanout。
|
||
3. `pcb2_route_sig.push_sig` 删旧铜时**无条件删 BM24 框里的 GND 梳子**,`--net` 补布只删不画 → 65 个 GND 脚悬空。现在只有这一轮重画 GND 才删。
|
||
4. `pcb2_gnd_patch.clusters()` 纯两两比对,件数上去之后 20 分钟不出来。加了包围盒预筛。
|
||
5. **`pcb2_reload` 会丢掉铺铜填充**;而 API 新建的线要 reload 之后 DRC 才认(否则新推的网络成片报「断开」)。收尾**固定顺序:reload → pour → inner1_verify → DRC**,pour 之后不许再 reload。
|
||
6. 布线器两个留孤岛的 bug(DRC 连接性 10 条,本地校核不报):从「已连上那坨」出发的起点落在圆焊盘外接矩形的角(J32.7/9/40 铜外 0.2);45° 切角挪走了后布支路钉着的直角铜(VBUS2/+3V3_HUB)。新增 `reanchor_routes()` 在切角后兜底。
|
||
7. `--net` 补布之前**必须刷障碍表**(上一次 `--push` 之后板子就变了):+3V3_HUB 按旧 K1_PWR/+5V 位置算,压线 19 条。加了 `--refresh` 开关,以后一律 `pcb2_route_sig.py --refresh --net ... --push`。
|
||
8. J23 封装里两个 Ø0.6 NPTH(`_pcb2_npth.json`)原来只有 vo_vias 读,`$16N224` 的过孔直接打在孔上。现在 `pcb2_route_dp.geom()` 把它们当无网络通孔盘,两个布线器都躲。
|
||
|
||
**换层 45° 化(用户中途追加,已整板落地)**:`via_chamfer_routes()` 在切角之后把「顶层横线进孔、底层竖线出孔」的直角切成 45°
|
||
(过孔沿出线方向挪 d,进线用斜段接进新孔位)。整板重布一遍:**换层直角 244 → 29、同层直角 132 → 28、123/123 布通、
|
||
DRC 115 = 基线(连接性 0)**,五块岛最窄 7.05 / 7.30 / 7.20 / 7.70 / 28.75,差分 22/22。剩下的 29 + 28 处是净距或孔间距不允许再切的。
|
||
顺带又抓到一个 EasyEDA 行为:**一条线穿过本网焊盘时,`create()` 会在焊盘中心把它截断、后半段连同同位置的出线段一起丢掉**
|
||
(KEY_RCLK 穿 U22.12)。`push_sig` 现在把离本网焊盘中心 < 0.15 的线段在中心处拆成两段再建(skill §9ac)。
|
||
|
||
**下一步**:
|
||
|
||
1. 用户看截图确认 U21/U22 转向后的走廊排法(`PCB2-r30-595corridor.png`)和换层 45° 的样子(`PCB2-r30-viachamfer.png`)。
|
||
2. 用户中途追加的「跨层垂直布线」已问清:**换层点两侧的线不许成 90°,要加一段 45°**。已做成 `via_chamfer_routes()`(设计文档 §10.1b),整板按它重布过一遍——结果见本节末尾「换层 45° 化」。
|
||
3. 下板 PCB1 还没按新规则整板重布(`pcb1_route_sig.py --refresh --ripup --push` 那条固定序列);下板 35 条布不通的处理方案见 `_pcb1_unrouted_report.md`。
|
||
4. 第二十九轮清单里的「一次装夹复测触点位置 ±0.3」「清 J41~J60 厂商料号」仍欠。
|
||
|
||
### 第二十九轮交接(先读这一段)
|
||
|
||
**做完的**(全部已下发到载板 PCB2 并读回核对):
|
||
|
||
| 项 | 怎么做的 | 状态 |
|
||
|---|---|---|
|
||
| 原理图 J41~J60 换封装 | ⚠️ 改库里的器件**不会传到原理图实例**(skill §9z)。用「工具 → 封装管理器」DOM 批量换成 `PAD-D1.5_MI8-KEY`,读回 20/20 | ✅ |
|
||
| Add into BOM | 实例上 `addIntoBom=false`(API 生效);厂商/料号字段 API 清不掉,但已不进 BOM | ✅ |
|
||
| PCB 导入变更 | 对话框恰好 20 行「修改封装」,应用后 `--verify` 218/218、封装 0 不符;`pcb2_parts_dump.py` 已重抓 | ✅ |
|
||
| 20 个盘重摆 | 新脚本 **`pcb2_keypads.py --push`**:只动这 20 个,按 `pcb2_place.plan()` 坐标,读回偏差 ≤ 0.002 mm | ✅ |
|
||
| GND 盘扇出 | `pcb2_keypads.py --gnd`:5 个 GND 盘各一条 0.30 短线 + Ø0.61 过孔(u− 侧 1.85 mm),本地净距校核过 | ✅ |
|
||
| 15 根 POGO 重布 | `pcb2_route_sig.py --net POGO*` 15/15 布通、净距全过、已下发(先删 55 线/18 孔) | ✅ |
|
||
| H5 不打 | `pcb2_place.SKIP_HOLES={'H5'}`,`--mech` 重下发 **30 孔**;J6n 离孔的 5 条报错随之消失,本地检查 0 错 | ✅ |
|
||
| 本地检查假阳性 | `pcb2_place.check()` 对触点盘改按**圆**判(盘心距 ≥ Ø1.5+0.20),原 20 条「重叠」是包围盒误报 | ✅ |
|
||
| **走线方向规则** | 用户拍板「顶层水平、底层纵向」→ `pcb2_route_sig.route_grid` 加 `DIR_PREF/DIR_PENALTY=2.0`(软代价),下板 `pcb1_route_sig.py` 复用同一引擎自动生效。设计文档 §10.1b / §0.1 #15 | ✅ 代码 |
|
||
| 7 个定位孔被旧线穿过 | 新脚本 **`pcb2_hole_dodge.py`**:孔周 2.2 mm 圆盘内本网铜整块删掉,断口用布线器 `_connect()` 重接(8 个网络 / 15 条路径,删 26 线 2 孔)。VBUS2/3、+3V3_HUB 因此不用整网重布 | ✅ |
|
||
| Inner1 `VO2_P` 岛颈 6.30 → 7.05 | 是 `VBUS_EN2` 的过孔 (87.1,70.2) 压在岛颈东沿。布线器新增 **`VIA_KEEPOUT`**(过孔禁区,外层布线器看不见内层岛),单独重布 `VBUS_EN2` | ✅ 五块岛全达标 |
|
||
| 铺铜 / DRC | 重载 → `pcb2_pour.py --push` 7 块全填充 → `inner1_verify` 五块岛 ✅ → `drc_read --pcb2`:**间距错误 45 → 15**(剩的 15 条全是第二十七轮的老账:`e2289` GND 过孔压 VO3_P 线 / J83_1、J63_3 下 4 个无名过孔、C801_2 下 2 个 VO4_P 过孔),**连接性 117**(第二十七轮 506,当时没铺铜) | ✅ |
|
||
|
||
⚠️ **这一轮发现的一个系统性偏差(没修,故意的)**:`pcb2_place.PW/PH` 上一轮从 67.09×44.66 改成 67×44,
|
||
但载板上站 1~3(rot 180)的全部元件还是按旧值摆的,和 `plan()` 差 **(0.09, 0.66) mm**(站 4/5 rot 0 不受影响)。
|
||
后果:`pcb2_route_sig.j7_assert` 对 J71/J72/J73 报 51 条常量不符。本轮只重布 POGO(不碰 J7n),
|
||
把断言改成 `--net` 不涉及 J7n 时降级为警告。**整板 `route_sig --push` 或重画 BM24 梳子 / 差分对之前,
|
||
必须先 `pcb2_place.py --push` 把站 1~3 摆到新坐标**(然后 `route_dp --dump → route_dp --push → route_sig --push → pour`)。
|
||
新摆的 20 个盘和 30 个定位孔都是按新 PW/PH 的,它们之间是自洽的。
|
||
|
||
**本轮沉淀的脚本 / 改动**
|
||
|
||
| 文件 | 用途 |
|
||
|---|---|
|
||
| **`pcb2_keypads.py`** | 只摆 J41~J60(`--push`)+ 5 个 GND 盘扇出(`--gnd`) |
|
||
| **`pcb2_hole_dodge.py`** | 穿定位孔的旧线局部改道(孔周圆盘整块删、断口重接) |
|
||
| `pcb2_route_sig.py` | `DIR_PREF/DIR_PENALTY/DIAG_K`(H/V 规则)、`VIA_KEEPOUT`、`j7_assert(strict=)` |
|
||
| `pcb2_place.py` | `SKIP_HOLES={'H5'}`、触点盘按圆判重叠 |
|
||
| `pcb2_pour.py` | 填充等待 4 min → 90 s(卡住就早退去重载) |
|
||
| skill §9z | 封装管理器 DOM 流程 / 器件改动不传实例 / BOM 字段哪些 API 能改 |
|
||
|
||
**下一步**:
|
||
|
||
1. 走线方向规则目前只对本轮重布的 15 根 POGO 生效过;**两块板的其它信号要在下一次整板重布时按新规则重来**
|
||
(载板要先做上面那条 `pcb2_place.py --push`;下板按「固定收尾序列」`pcb1_route_sig.py --refresh --ripup --push`)。
|
||
2. 载板 8 个没布通的网络(第二十八轮清单第 1 条)仍在。
|
||
3. 触点位置只到 ±0.6 mm(Ø1.5 盘只容许 0.50)—— 打样前用户要做「一次装夹」复测(第二十八轮那一节)。
|
||
4. 用户在客户端里可顺手把 J41~J60 的厂商/料号清掉(纯观感,API 做不到)。
|
||
5. `pcb2_via_relabel.py` 试跑说有 12 条**导线**标签可疑(`+3V3_HUB → EDL_EN2/3/$24N140`、`VBUS3 → GND ×2`、`$20N3x4 → GND`),
|
||
过孔 0 处。这些多半是 8 个没布通网络留下的出线段碰到了邻脚,**没 push**;处理那 8 个网络时一并看。
|
||
6. 剩下 15 条 DRC 间距老账:`e2289`(GND 过孔压在 VO3_P 线上、离 J83_1 6.7 mil)、J63_3 下 4 个无名过孔、C801_2 下 2 个 VO4_P 过孔 ——
|
||
都是「过孔该删还是该重标」的判断题,relabel 判不了(接触网络不唯一),要人看一眼。
|
||
|
||
---
|
||
|
||
### 第二十八轮交接(上一轮,仍有效的部分看「还欠的实测」)
|
||
|
||
**做完的**(细节看下面「主板机械数据重测」整节):
|
||
|
||
| 项 | 结论 | 状态 |
|
||
|---|---|---|
|
||
| 主板本体 | **67 × 44**(旧 67.09 × 44.66;71 是含 SIM 卡托) | ✅ |
|
||
| 7 个定位孔 | 全部重测,**最大错 4.8 mm** | ✅ 两条独立链印证 |
|
||
| 孔径 | 主板 **Φ2.0** ⇒ 载板过孔 **Φ1.8** + M1.6 尼龙 | ✅ |
|
||
| 侧键触点几何 | 菱形,相邻 1.87 / 对角 2.65,盘 Φ1.35 | ✅ 中框金焊盘量的 |
|
||
| 侧键触点簇心 | **(3.42, 5.07)**,离 H1 5.24 mm | ✅ 用户卡尺 5 mm 判死 |
|
||
| 触点身份 | GND=u− · PWR=u+ · VDN=v− · VUP=v+ | ✅ 两条独立描述印证 |
|
||
| **接触方式** | **顶针取消 → 中框式焊盘**,螺丝压紧,立柱 3.0→**1.0 mm** | ✅ 库已改完 |
|
||
| 载板下发 | `--mech --force`:35 孔 Φ1.8 + 25 条丝印,读回偏差 0.0001 mm | ✅ |
|
||
|
||
**下一步按这个顺序做**:
|
||
|
||
1. **手工**(客户端 UI,API 改不动):器件 `MI8-KEY-PAD D1.5` 的 **Add into BOM 改 no、清掉 C5221288 / YIYUAN 料号**,
|
||
否则 BOM 会让人买 20 颗用不上的顶针。
|
||
2. 载板**导入变更** → J41~J60 换成 Ø1.5 盘 → **重抓封装框**(`_pcb2_pads.json` 里还是旧 Ø1.9,
|
||
不重抓的话 `pcb2_place.py` 会一直报那 20 条假重叠)。
|
||
3. 把 J41~J60 摆到新坐标。⚠️ `--push` 会重摆全部 218 个元件,风险大,**只摆这 20 个要单写一条路径**。
|
||
4. **重布这 20 个网络**(原顶针位置的走线全废)。
|
||
5. J6n vs H5 二选一(挪五个 EDL 座重布 10 条线 / 干脆不打 H5,后者代价为零)。
|
||
6. 11 处孔与已有铜擦边(最深 0.95 mm)局部收一收 → 重铺铜 → `pcb2_reload` + DRC。
|
||
|
||
**还欠的实测**(都要用户动手,方法见对应小节):
|
||
|
||
- **触点位置只到 ±0.6 mm,而 Ø1.5 盘只容许 0.50** —— 打样前要用「一次装夹」收到 ±0.3
|
||
(同一张测量底板上先戳 7 孔、再把弹片涂红盖印)。
|
||
- **贴合面(侧键面)还没有可信的板坐标映射**,那张 `MI8-mating-face.png` 的标记是错的、已作废。
|
||
要重做得先在贴合面那一侧的 7 个孔口点红漆再扫。
|
||
- 四个触点的电气身份没用万用表验过(几何身份是可信的)。
|
||
|
||
⚠️ **最重要的一条方法论教训在「环形滤波器配准出来的 7/7 不可信」那一节,动手前必读** ——
|
||
这一轮为此错了两次,其中一次还被当成「独立印证」写进过文档。
|
||
|
||
### 一句话现状
|
||
|
||
原理图:下板 11 页 + 载板 **12 页**(新增 C6-KEYS),**verify_sch 16 页全过、xpage 两板 0 漏接、port_audit 两板 0 可疑**。
|
||
排针 J24/J25 第三版:**37 信号 + 43 地**(跨板只剩 KEY_SER/SRCLK/RCLK/OE# 四根移位链 + 老的 VO/+5V/VBUS_EN/I²C)。
|
||
|
||
PCB:两块板都做了「导入变更 → 重抓封装框 → 清死网铜 → 重摆 / 重布」,**收尾链的结果见下面「板子当前状态」**
|
||
(这一段是 `_chainB.log` 跑完之后补的,如果那里写的是「待补」,说明链没跑完,先看 `.claude/_chainB.log`)。
|
||
|
||
### 本轮改动一览(细节在设计文档 §26.23 落地 / §26.24)
|
||
|
||
| 板 | 原理图 | PCB |
|
||
|---|---|---|
|
||
| 下板 | P2×5 删按键块(`sch_cut.py` 闭包整块删);P3B 删 U21/U22/C604/C605/R609;P6 删 U33/C739;P5-BTB 表第三版重画;P3B/P6 文字重写 | 导入变更 −52 件(290 件);J24/J25 被重建到板外,按老坐标放回;`pcb_prune_nets.py` 删 737 线 / 208 孔 + 253 段孤儿网;板框放大到 220×135(原点不动,画到 (−30,−5)),定位孔 6 个与载板对齐 |
|
||
| 载板 | **新页 C6-KEYS**(`c6_keys.py`);C4-SITE1~5 加三颗 MOS + 六个 0402(`c4_site.py` 【B】重排);C1-CONN 重生成 | 导入变更 +52 件(218 件);`pcb2_place.py --push` 整板重摆(U21/U22 在走廊中段 UP 差分以北那条带、U33 在 J32 东侧、MOS 在顶针背面);顶角补两个 M3 孔、尾插槽东端 65→64;删排母来的 POGO/EDL_EN/HUB_RST 旧铜;36 个新 GND 脚扇出;`pcb2_route_sig.py --push` 全部重布 |
|
||
|
||
### 本轮沉淀的脚本
|
||
|
||
| 文件 | 用途 |
|
||
|---|---|
|
||
| **`sch_cut.py`** | 按**连线闭包**整块删子电路(元件 + 导线 + 旗/端口),闭包碰到别的元件引脚就拒绝 |
|
||
| **`c6_keys.py`** | 载板 C6-KEYS 页(三片 595 + 去耦 + OE# 上拉)|
|
||
| **`pcb_prune_nets.py`** | 删死网铜:正则命中 or 网名不在任何焊盘上(孤儿网)|
|
||
| **`pcb2_via_relabel.py`** | 按实际接触的铜给过孔重标网络(导入变更后必跑)|
|
||
| **`pcb1_outline.py`** | 下板 220×135 板框 + 6 个对齐定位孔(不依赖旧 pcb_place)|
|
||
| `pcb1_import.py --board2` | 同一套导入/对账流程用在载板上(产出 `_p2_sch_bom.json` / `_pcb2_comps.json`)|
|
||
|
||
### ⚠️ 本轮踩到 / 复核的坑
|
||
|
||
1. **端口不能放在直线的中点**(skill §8a-2 又一次):漏极→顶针两段共线导线被合并,POGO 端口落到中段,`port_audit` 报 15 处。改挂到横支线末端。
|
||
2. **整页重画的页导入 PCB 时,EasyEDA 拿待删元件复用成新元件**(skill §9o):载板对话框里一堆「修改封装 C0402→SOIC-16」「J43→J54」。
|
||
对策就是导入后 `pcb2_place.py --push` 整板按位号重摆再 `--verify`;下板 J24/J25 同理被扔到 (25,−8)。
|
||
3. **595 在走廊里摆了三次才对**:先是 rot 90 面对面缝 1.56(出线口互堵、12 根 K 线全布不通),再是 rot 0 压在横穿整个走廊的 UP 差分上(查空地只查了端点在框里的线)。
|
||
4. **`pcb2_route_sig.py` 吃的是 `_pcb2_route_geom.json`(`pcb2_route_dp.py --dump` 产出),不是 `pcb2-copper.json`**——
|
||
改完布局漏跑 `--dump`,布线器报「网络表里没有 KEY_*/K*」。第一遍收尾链就是这么空跑的。
|
||
5. **`drc_read.py` 的结果要先 `pcb2_reload.py`**,否则报的是重摆之前的幽灵位置(一堆「钻孔到贴片焊盘 0 mil」)。
|
||
6. `KEY_OE#` 里的 `#` 又把载板布线引擎的路径 key 拆坏了(下板 §26.19 同款),`pcb2_route_dp.KSEP` 改成 chr(0);`pcb2_dp_long` 不能反向 import 它(循环)。
|
||
7. **导入变更会把老过孔的网络标签重映射**(载板 49 个,铜没动):DRC 成排「导线到过孔 0 mil」、布线器当异网障碍。`pcb2_via_relabel.py` 按接触的铜重标。以后整页重画导入之后必跑。
|
||
8. **`pcb2_route_sig.push_sig` 一个请求里逐条删 + 建 1589 段线,桥接 30 s 超时但 EasyEDA 继续画**(skill §9c 同款):下一步抓几何抓到画了一半的板子,第二遍把 `+3V3_HUB`/`+5V` 画到别人身上(DRC 319)。已改成批量删 + 每 250 段一个请求。
|
||
9. **`pcb2_route_sig.py --net` 补布时障碍表照样摘掉全部 123 个自家网络**(`mine` 没按 `--net` 收窄),补的 8 根线看不见第一遍的 115 个网络,DRC 319 条 0 mil。已改成只摘这一轮要重画的。
|
||
10. 交接表里「25 颗开关 / 73 件」是错的:每路只有 3 颗按键 MOS(Q%03~05),整窝 **52 件**。
|
||
|
||
### ⬅️ 下一步
|
||
|
||
1. **载板 8 个没布通的网络**(§26.23 落地末尾的表):根因是 U21/U22 西排 8 个脚共用一条缝。二选一:U21 北挪 + U22 转 rot 270,或把 EDL_EN×3 和 +3V3_HUB 去 site1 那支写成 `PRE` 前置段。改完 `route_dp --dump` → `route_sig --push`(整板)→ `pcb2_pour.py` → `inner1_verify` → reload → DRC。
|
||
2. 载板 `pcb2_pour.py`:Inner1 五块岛 + GND 底填要不要因新件重铺(新 GND 孔已打在 layer 16;595/MOS 都在岛外的走廊 / 顶针背面,
|
||
`inner1_verify.py` 跑一遍确认岛没被切)。
|
||
3. 两板对齐后的机械件:下板四角孔在 (−22,3)/(182,3)/(−26,126)/(186,126),载板顶角 (4,131)/(216,131) 离板边只有 1 mm 焊盘边——
|
||
打样前让用户看一眼要不要把顶角孔改成非金属化 / 缩焊盘。
|
||
4. `pinmap.py` 里 P3B/P6 那两段 595 端口改名表已经**没有对象**(端口都删了),`--check` 会报 miss;它是历史记录,别再跑 `--push`。
|
||
5. **下板 35 条布不通的处理方案已经由子代理算好**(纯本地,没碰桥接):`.claude/_pcb1_unrouted_report.md`,
|
||
配套脚本 `pcb1_unrouted.py` / `pcb1_ch_reroute.py` / `pcb1_usb_corridor.py`(都是离线的),`pcb1_place.py` 里已改 `ESCAPE_NUDGE` 0.50/0.45 + 新增 `SAT_FLIP`(C609/C612 转 180°)。
|
||
要点:只有 `U6.16`/`U7.16` 两条是几何真出不去(NUDGE 救不了,要 C609/C612 转 180°);C 类是 `R%10` 转 180° 就通;
|
||
USB 束走廊在顶层 y≈17 沿板边东行再 x≈142 北上;D 类是 INA226 南侧口袋被自己人堵,一起拆了按 0.05 栅格重布。
|
||
**下发顺序见报告 §8**,第一条就是「定点动 8 颗,绝不 `pcb1_place.py --push`」。
|
||
6. ⚠️ **同一仓库还有另一个 Claude 会话(dcdc-cd)在动载板文件**(22:02~22:08 改过 `pcb2_place.py` 的 PW/PH、`mi8_mech.json`、`c1_conn.py`,之后又改回去了)。桥接只有一条,两个会话不能同时打;开工前先 ListAgents / 问一句。
|
||
|
||
---
|
||
|
||
## ⚠️ 主板机械数据重测(2026-09-06 第二十八轮)
|
||
|
||
**起因**:给用户出了一张 1:1 打印尺寸图(`shots/PCB2-carrier-1to1.pdf`,`pcb2_pdf.py`),
|
||
他拿真主板一比 —— **孔位最大错 4.8 mm,板长错 1.09 mm,孔径错了 1 mm**。
|
||
原来那套(67.09 × 44.66 + 7 孔)是**从照片提取**的,标称 ±0.5 mm,实际远不止。
|
||
|
||
### 新值(已写进 `pcb2_place.py` 与 `.claude/mi8_mech.json`,旧值保留在 `_prev_2026-09-06`)
|
||
|
||
本体 **67 × 44**;孔 **7 个**,孔径实测 **≈Φ1.5**(M1.4 类)⇒ 载板侧取螺钉过孔 **Φ1.6**
|
||
(原来 Φ2.5 / M2.5,整套错的)。
|
||
|
||
| 新 | (u, v) | 旧最近邻 | 移了 |
|
||
|---|---|---|---|
|
||
| H1 | (1.4, 9.9) | H6 | 2.8 |
|
||
| H2 | (0.7, 27.3) | H5 | 1.9 |
|
||
| H3 | (1.7, 38.7) | H2 | 1.0 |
|
||
| H4 | (41.9, 1.9) | H7 | 1.9 |
|
||
| H5 | (57.4, 41.2) | H1 | 3.4 |
|
||
| H6 | (64.6, 28.1) | H4 | 2.7 |
|
||
| H7 | (64.8, 32.4) | H3 | 3.2 |
|
||
|
||
⚠️ **编号整体重排过**,别拿旧 H 号对新 H 号。u 沿长边、原点在**没有卡托伸出**的那一端;
|
||
v 从接口边起算。
|
||
|
||
**数据来源与复核(两条独立链,这是本轮最值钱的东西)**
|
||
|
||
1. 测量底板(`pcb2_measure_sheet.py`):描轮廓 + 每孔戳一点 → 平板扫描 →
|
||
`pcb2_measure_read.py` 按四个基准圆做单应反算。
|
||
2. ~~真主板平板扫描 7/7 残差 0.38~~ **❌ 这条作废,是假匹配**。2026-09-06 用户看图发现对不上,
|
||
高倍逐孔审计(`audit_c.png`)证实:7 个十字没有一个落在真孔上。
|
||
**成因**:候选点来自灰度环形滤波器,这块板上圆形特征几百个,**7/7 + 小残差可以纯靠撞**。
|
||
同样作废的还有贴合面那张 `MI8-mating-face.png` 的孔/触点标记(底图和摆正是对的,标记错位)。
|
||
3. **✅ 真正站得住的第二条**:把主板用 7 颗螺丝装回中框、螺丝头涂红再扫,HSV 分出品红点 ——
|
||
候选就是**那 7 颗螺丝本身**(不是滤波器噪声),**镜像=False 无解、只有 True 有解**,残差 0.48 mm。
|
||
高倍审计 `shots/MI8-holes-proof.png`:**7 个十字全部落在螺丝正中心**。螺丝长在孔里 ⇒ 直接证据。
|
||
⇒ **孔位模型可以按 ±0.6 mm 用**,支撑是两条独立链(测量底板戳孔 + 红螺丝),不是三条。
|
||
|
||
### ⚠️⚠️ 教训:环形滤波器配准出来的 7/7 不可信,必须高倍逐孔看
|
||
|
||
这块板上圆形特征几百个(过孔、焊盘、测试点、罐体),7 点模型又近似镜像对称 ——
|
||
**「7/7 命中 + 残差 0.4~0.6 mm」在这种候选集里可以纯靠撞出来,两种镜像还都能撞出来**。
|
||
本轮为此错了两次(中框螺柱那次、裸板那次),第二次还被我当成"独立印证"写进了文档。
|
||
|
||
**判据只有两条**:
|
||
1. 候选集必须**本身就是要找的东西**(涂红的螺丝、涂红的触点),不能是通用滤波器的输出;
|
||
2. 出图之后**必须逐孔高倍截图看**(`audit_*.png` 那套,每格 ~11 mm),低倍扫一眼看不出错位。
|
||
|
||
**「拿板子外形轮廓去套」也不行**(2026-09-06 试过):测量底板上那条描线被笔宽撑大 **22%**
|
||
(3371 vs 2770 mm²),板子无论正反都能整个塞进去 ⇒ **两种镜像的 IoU 一模一样(0.8157 = 面积比)**,
|
||
判不了手性。要用外形配准,得先有一条**不带笔宽的**真实轮廓。
|
||
|
||
⇒ **贴合面(侧键面)到现在还没有可信的板坐标映射。** 要做那张图,得在**那一面**也放上
|
||
不含糊的标记:往 7 个孔里各点一点红漆(或把螺丝从贴合面这一侧拧进去)再扫,
|
||
然后照红螺丝那套 HSV 提点 + 配准 + 逐孔审计。
|
||
|
||
⚠️ **板长 67 是裸板**。用户描轮廓时卡托还插着,卡托在 u 大的那一端伸出约 3.3 mm,
|
||
描出来是 70.3。他早先给的 u 值是拿 66 / 70.3 混着换算的 —— 那 3~4 mm 的"怪差"就是这么来的,
|
||
**不是测量误差**。判据:改按「距下端边」算,两边完全一致。
|
||
|
||
### ⚠️ 侧键顶针坐标同样是错的 —— 已实测替换
|
||
|
||
旧的 `POGO_XY`(§22.3b 四个点,跨度 3.3 x 4.5)也是从照片认的,**位置差 2~4 mm、内部间距也不对**。
|
||
顶针打偏 = 按键不通,而且几何验证和 DRC 都测不出来,是本轮最危险的一处。
|
||
|
||
实测办法:用户把四个触点**涂红**再平板扫描,用 7 个定位孔配准(7/7,残差 0.6 mm)反算。
|
||
|
||
| | u | v |
|
||
|---|---|---|
|
||
| C1 | −0.41 | 5.74 |
|
||
| C2 | 1.65 | 5.77 |
|
||
| C3 | −0.29 | 8.61 |
|
||
| C4 | 2.30 | 8.21 |
|
||
|
||
**2×2 排布,跨度 2.71 × 2.87 mm,最小间距 2.06 mm**(顶针选型要卡这个数)。
|
||
|
||
**手性是怎么定的(这条要记住)**:7 孔图案近似镜像对称,**两种镜像都能 7/7 拟合**(残差 0.37 / 0.60),
|
||
配准本身定不了手性,两解相差 60 mm。判据只能来自**扫描件内部的相对关系**:
|
||
触点簇心离 **H1 只有 2.7 mm**,而 H1/H2/H3 是挤在一端的那三个孔;用户确认「三个孔在上端」
|
||
⇒ 触点在 u≈0 那一端。⚠️ 以后凡是拿这块板做配准,**手性都要另找证据,别信拟合残差**。
|
||
|
||
### ✅ 已下发到 EasyEDA(2026-09-06):35 个定位孔 + 5 个主板投影丝印
|
||
|
||
`pcb2_place.py --mech --force`。读回复核:**35 个孔全部 Φ1.8 NPTH,与模型最大偏差 0.0001 mm;
|
||
layer3 丝印 25 条**。板上其它东西(元件、布线、铺铜)**一个字没动**。
|
||
|
||
`--force` 是本轮新加的:只下发 `--mech` / `--outline`(孔、槽、丝印)时,元件级报错按警告放行 ——
|
||
那些是「元件 vs 孔」「元件 vs 元件」,和要写的机械图元无关。**`--push`(重摆元件)永远不允许 force。**
|
||
|
||
⚠️ **下发时挂着 25 条本地报错,都还没解决**(见「还欠什么」)。铺铜和 DRC 也**没跑**
|
||
(`pcb2_reload.py` 会删掉全部铺铜边框,不能随手跑)。
|
||
|
||
### 侧键触点定稿值(2026-09-06)
|
||
|
||
几何来自**中框上那四个金焊盘**(配合件,边界干净):**菱形,相邻 1.87 / 对角 2.65 mm,焊盘 Φ1.35**。
|
||
⚠️ **相邻只有 1.87 mm ⇒ 顶针本体直径必须 < 1.87**,常规 Φ2 以上排不下,得选 Φ1.3~1.5 的细顶针。
|
||
|
||
位置**相对孔给**(载板靠 7 孔定位手机,顶针就得相对孔摆):
|
||
|
||
顶针簇心 = H1 + (-0.59, -2.82) ⇒ 簇心 (0.81, 7.08),离 H1 孔心 2.88 mm
|
||
|
||
这一项是**在同一张扫描件里量的,不经过配准、也不吃手性** —— 这是它比别的路子可信的原因。
|
||
(曾用「中框螺柱 + 7 孔配准」得到簇心 (3.42, 5.07),它推出「簇心到最近孔 5.2 mm」,
|
||
和上面 2.88 的直接实测矛盾;那次 262 个候选里撞出的 7/7 是假解,已弃。)
|
||
|
||
身份 **GND 在 u− · PWR 在 u+ · VDN 在 v− · VUP 在 v+**(半径 1.32)——
|
||
**两条互相独立的描述都对上了**:① 中框基准(蓝圈最近=VUP、正下方=VDN、最靠中框边缘=GND、与 GND 正对=PWR)
|
||
经中框配准的旋转折算;② 主板自身边基准(离短板边最近=GND、与其正对平行=PWR、
|
||
与其垂直且离长板边最近=VDN、与其垂直且比 VDN 更靠另一长边=VUP)。两条都指向同一组。
|
||
顺带印证了坐标系:板的 u = **机身宽度**方向(u=0 端 = 侧键所在的机身侧边),v = 机身长度方向。
|
||
|
||
⚠️ 菱形左顶点算出 u = −0.51(名义在板边外)。原因是 **u 原点取自描的笔迹内沿,比真板边偏内约 1 mm**,
|
||
它**同时偏了孔和触点**,相对关系不受影响。真要修板边(画手机本体投影时),
|
||
把 `PW` 和所有 `u` 一起 +1,别只改一个。
|
||
|
||
### ⬅️ 顶针这条还欠一件事
|
||
|
||
### ⭐ 方案改动(2026-09-06 用户拍板):顶针取消,改成中框式焊盘
|
||
|
||
装配改成:**螺丝把主板压在载板上,主板自己的侧键弹片直接压在载板的裸铜盘上** —— 复刻中框的接触方式。
|
||
|
||
- 立柱高度 **3.0 → 1.0 mm**(中框「螺柱支撑面到金焊盘面」实测 1 mm)。
|
||
- **不用挖空**:用户实测贴合面上元件**全都低于 1 mm**,载板保持平板。
|
||
(原本担心「挖空会和底层 BAND 那组元件打架」——那组就在手机投影正下方 u 13~44 / v 11~26,现在不用挖了。)
|
||
- 排线反而更宽裕(绕边下落 5→3 mm):尾插 ≈44.5 ≤ 50、电池 ≈29.6 ≤ 35,§25.16 的路径不用改。
|
||
- ⚠️ **1 mm 立柱不好买**(M1.6 尼龙立柱通常 3 mm 起)。做法:螺钉从上穿手机孔 + 1 mm 尼龙垫片 +
|
||
穿载板 Φ1.8 孔 + 底面尼龙螺母。垫片可叠。
|
||
|
||
**已落地**:
|
||
|
||
1. 新封装 `PAD-D1.5_MI8-KEY`(`fp_keypad.py --push`,uuid `e106d858…`):顶层单焊盘 **Ø1.5**,
|
||
在原点、无孔,读回校验过。定径依据:四触点**实测**最小间距 **1.78 mm**(不是理想菱形的 1.87)
|
||
⇒ 净距 0.28。旧的 `POGO-SMD1P_D1.9`(Ø1.9)在 1.78 下是**负净距**,正是那 20 条「重叠(L1)」的根。
|
||
2. 器件 `1c8e0ea1…` 就地改名换封装:`YTC1P-2510-01 D1.9` → **`MI8-KEY-PAD D1.5`**,
|
||
封装指向新盘,**符号没换 ⇒ 原理图一个字没动**。
|
||
|
||
**⚠️ 一件必须手工做的**:`lib_Device.modify` 的 `property` 参数**被 API 忽略**(名字/封装/描述能改,
|
||
BOM 字段改不动)。得在客户端里打开这个器件,把 **Add into BOM 改成 no、清掉 C5221288 / YIYUAN 料号**,
|
||
否则 BOM 里会照着买 20 颗用不上的顶针。
|
||
|
||
**⚠️ 工艺(生成不出来,下单时要说)**:接触盘**钢网开口 0(不上锡膏)**,表面处理 **ENIG**。
|
||
弹片压在锡珠上会接触不良,HASL 反复摩擦会磨穿。
|
||
|
||
### ⛔ 还欠什么(下发之后剩下的)
|
||
|
||
1. ~~顶针封装排不下~~ → **已解决**:改成 Ø1.5 焊盘(见上)。但还没走完最后几步:
|
||
**PCB 导入变更**(换封装)→ 把 J41~J60 摆到新坐标 → **重布这 20 个网络**(原顶针位置的走线全废)。
|
||
⚠️ `pcb2_place.py` 的本地自检还会报那 20 条重叠 —— 它吃的是 `_pcb2_pads.json` 缓存里的**旧 Ø1.9**,
|
||
导入变更之后重抓一次封装框才会消。
|
||
⚠️ `--push` 会重摆全部 218 个元件,风险大;只想摆这 20 个的话得单写一条路径。
|
||
2. **J61~J65(EDL 座)离 P\*H5 只有 0.92 mm**(要 2.2)。二选一:挪五个 J6n 重布 10 条线,
|
||
或者干脆**不打 H5**(每台 6 个孔,够用),后者代价为零。
|
||
3. 孔位挪动后**已有铜有 11 处擦边**(最深 0.95 mm,全是走线/过孔蹭到),局部挪线可收。
|
||
4. 铺铜没重铺、DRC 没跑。
|
||
|
||
**四个触点谁是 PWR / VUP / VDN / GND 已按用户指认填上**(GND 靠机身边缘、PWR 与 GND 正对、
|
||
VUP 靠中框那个蓝圈、VDN 在 VUP 正下方),但**没做电气验证**。
|
||
接线前拿万用表对着侧键按下去测通断确认一遍 —— 打偏或接反都是做出板子才发现。
|
||
|
||
另外开工前拿卡尺复核一个数就够:**H1 孔心到四触点菱形中心 ≈ 2.9 mm**。量出来是 5 mm 就说明我错了。
|
||
|
||
### 对已布线载板的冲击(离线算的;`--mech` 已下发,铺铜/DRC 还没跑)
|
||
|
||
35 个孔里 **11 个和已有铜冲突,但都很浅**(最深 −0.95 mm,全是走线/过孔擦边):
|
||
`P2H5` −0.95(走线 VBUS_EN2 L2)· `P2H1` −0.91(过孔 POGO2_VUP)· `P2H7` −0.90(走线 VBUS2 L1)…
|
||
少打几个孔能减到:不打 H5 → 6 个;不打 H5/H6 → 5 个;不打 H5/H6/H7 → 2 个。
|
||
⇒ **不是重来一版**,是十来处局部挪线/挪孔,`pcb2_route_sig.py` 能收。
|
||
|
||
### ⬅️ 还没定 / 还没做
|
||
|
||
1. **两处数据存疑**(所以用户决定先复测再下发):
|
||
- 戳孔那张在 **(63, 3.5)** 还有一个没标注的点 —— 可能是**第 8 个孔**;
|
||
- 下端那两个孔:戳点说距下边 ~1.5 mm,用户尺量 5.5 mm,**差 4 mm**。
|
||
2. **复测底板已打印**:`shots/PCB2-measure-sheet.pdf`(`pcb2_measure_sheet.py`)。
|
||
干净底板 + 四个实心黑圆基准点(圆心矩形 **160 × 110 mm**),描轮廓 + 每孔戳一点,拍照回来反算,约 ±0.3 mm。
|
||
**反算脚本 `pcb2_measure_read.py` 还没写**(照片来了再写;套路见下)。
|
||
3. 复测完才 `pcb2_place.py --mech` 下发,然后 `pcb2_pour.py --push` + `pcb2_reload.py` + `drc_read.py`。
|
||
4. H5 打不打(等于「6 孔 vs 挪五个 J6n 重布 10 条线」)等复测结果再定。
|
||
|
||
### 照片反算这条路是通的(已验证)
|
||
|
||
用户直接在**打印好的 1:1 图第 2 页**上描了轮廓,我用 **SIFT + 单应**把照片和 PyMuPDF 渲染的那一页配准,
|
||
印刷的 7 个孔十字圈**逐个压准**,然后把红笔迹映射回本体 mm。关键几点:
|
||
|
||
- 照片取 **R 通道**当灰度图:红笔迹变白、只剩黑色印刷,配准不受手绘干扰;
|
||
- `cv2.SIFT_create()` + `BFMatcher` + `findHomography(RANSAC)`,本例 1029 good / 139 inlier 就够;
|
||
- 反变换后按本体坐标重采样成「1 mm = 20 px」的正视图(`r2_rectified.png`),量什么都直接读;
|
||
- 描边笔宽约 1.3 mm,**取墨迹内沿**才是真板边,不然板长会大 1.5 mm。
|
||
|
||
⚠️ **别拿手绘草图的像素位置当坐标**:用户第一张徒手草图,比例和他自己写的尺寸能差 5 mm
|
||
(「④ 距左边 12 mm」量出来 16.9、「⑦ 距下边 28」量出来 23.4)。草图只能定拓扑,坐标必须来自尺子或戳孔。
|
||
|
||
---
|
||
|
||
## 板子当前状态(2026-09-06 第二十七轮收尾)
|
||
|
||
### 下板 PCB1
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| 板框 | **220 × 135**,左下角 (−30,−5)(原点不动),定位孔 6 个与载板对齐(`pcb1_outline.py`)|
|
||
| 元件 | 290(−52:595 窝挪走)|
|
||
| 板上铜 | 3118 线 / 985 孔(`route_sig --refresh --ripup --push` 之后)|
|
||
| **DRC 间距错误** | **0** |
|
||
| DRC 连接性错误 | **79**(上一轮 103)|
|
||
| 还欠布通 | **35 条**(K/POGO 那批已不在下板;剩的是 §26.22 的 A/B/C/D/E 老账,子代理的分类报告见 `.claude/_pcb1_unrouted_report.md`)|
|
||
| 铺铜 `--verify` | ✅ 实测和计划对得上 |
|
||
| 本地摆位检查 | ✅ 六项全过(`pcb1_env.py` 按新载板重生成后,J24/J25 80 针网络逐个对上)|
|
||
|
||
### 载板 PCB2
|
||
|
||
| 项 | 值 |
|
||
|---|---|
|
||
| 元件 | 218(+52),全部按 `pcb2_place.py` v5 表 + 新件重摆并 `--verify` 回读 |
|
||
| 定位孔 | 8 个(原 6 + 顶角 (4,131)/(216,131));尾插槽东端 65→64 |
|
||
| 死网铜 / 错标签 | 排母来的 POGO/EDL_EN/HUB_RST 旧线已删;29 孔 / 11 线按接触的铜重标(`pcb2_via_relabel.py`)|
|
||
| 信号布线 | `pcb2_route_sig.py` 整板 123 网布通 **115**,净距 / 钻孔 0;**8 个没布通**(`+3V3_HUB` 去 site1 那支、`K3_VDN` `K5_VDN`、`EDL_EN2/3/5`、`VBUS_EN5`、`+5V` J32.40→J32.4),板上只留出线段。清单与两个候选方向见设计文档 §26.23 落地末尾 |
|
||
| **DRC 间距错误** | **15**(改前基线 115 是封装内焊盘对焊盘;现在剩的是 `e2289` 那个 GND 过孔压在 VO3_P 线上、J63_3 下面两个无名过孔等重标漏网的)|
|
||
| DRC 连接性错误 | 506(8 个没布通的 + 铺铜没重铺)|
|
||
| 差分对 | `pcb2_net_conn.py` 22/22 连通 |
|
||
| ⚠️ 还没做 | `pcb2_pour.py` 没重铺(新件的 GND 孔已打)、`inner1_verify.py` 没跑 |
|
||
|
||
⚠️ 每一轮改动之后的**固定收尾序列**,一步都不能省:
|
||
|
||
/c/Python314/python -u .claude/pcb1_route_sig.py --refresh --ripup --push
|
||
/c/Python314/python .claude/pcb1_pour.py --push --refresh
|
||
/c/Python314/python .claude/pcb1_reload.py # 不重载,DRC 连接性那一支是陈旧的
|
||
/c/Python314/python .claude/drc_read.py
|
||
|
||
### ⚠️ 一条**没做完**的:栅格布线器要的出线道是 0.741 mm,不是 0.60
|
||
|
||
§26.22 的 A-1 把 U6/U7 周围六颗卫星件各挪了 0.30 mm,出线道
|
||
0.312/0.315/0.376 → 0.612/0.615/0.676,`pcb1_escape_audit` 里「几何上出不去」
|
||
从 **7 个降到 2 个**(`U6.6`=SCL、`J25.24` 都解决了)。
|
||
|
||
**但 `U6.16` / `U7.16` 还是布不通**(`$6N532` / `$6N547`,各差 1 条 1.5 mm 的短跳)。
|
||
原因是 0.60 这个门槛算漏了栅格量化余量:布线器的判据是
|
||
**`CLR + 半线宽 + QERR` = 0.20 + 0.10 + 0.0707 = 0.3707,两边就是 0.741 mm**。
|
||
0.615 的道**理论上塞得下、栅格上塞不下**。
|
||
|
||
⇒ 下次把 `pcb1_place.ESCAPE_NUDGE` 从 0.30 加到 **0.50(东列 0.45)**,
|
||
让三个方向的道宽都 ≥ 0.80。改完照 §26.22 那套善后(挪件会压到邻线和换层孔)。
|
||
|
||
### 剩下 46 条布不通的分类(详见 §26.22)
|
||
|
||
| 类 | 条数 | 处理 |
|
||
|---|---:|---|
|
||
| A 焊盘几何出不去 | 2 | 上面那条:`ESCAPE_NUDGE` 加到 0.50 |
|
||
| B USB 差分对 | 4 | **未做**。整束 0.7 mm 找不到走廊,要预留走廊或手写几何 |
|
||
| C 五路母版系统性缺口 | ~14 | **未做**。`$*N676/680/698/727`,2.4~5.7 mm 短跳在多通道同时失败,在**一个**通道解决再复制 |
|
||
| D I²C / INA_ALERT 末端 | ~5 | **未做**。器件脚下顶层口袋里没有合法孔位 |
|
||
| E 单发拥堵 | ~21 | 多跑几轮 `--ripup`(`RIP_LIMIT=1` 是有意的,见源码注释)|
|
||
|
||
---
|
||
|
||
### ✅ 第二十四轮(2026-09-06,用户拍板):I²C 干线改走 Inner2(§26.20)
|
||
|
||
`SDA`/`SCL` 是全板最长的两个网络(各 14 个焊盘、横跨整板),
|
||
既吃布线时间(1516 s)又占着外层最好的通道。用户拍板:**走内层,只挪跨板长干线**。
|
||
新工具 **`.claude/pcb1_i2c_l3.py`**(三层迷宫布线 Top / Bottom / Inner2)。
|
||
|
||
| | 改之前 | 改之后 |
|
||
|---|---|---|
|
||
| I²C 总铜长 | 596 mm,**内层 0** | 609 mm |
|
||
| Inner2 | — | **302 mm** |
|
||
| 顶层 / 底层 | 596 mm | 157 / 150 mm |
|
||
| 连通性 | SCL 3 片 / SDA 4 片 | **一模一样** |
|
||
|
||
**中桥那 13 mm 是唯一留在外层的一段**:`12V-SW+BR` 的中桥(x 61.5~72.6,喂 3.6 A)
|
||
是 Inner2 上东西两半唯一不能割的隔断,I²C 过去就必须横着割 ⇒ 只能外层跳。
|
||
(上一轮 `route_sig` 给 `SDA` 布的就是这个跳法,殊途同归。)
|
||
|
||
三条这一轮踩到的坑(细节全在 §26.20):
|
||
|
||
1. **`PEN_3V3` 决定的不是长度,是平面会不会被切出孤岛。** 1.8 的时候两根线在
|
||
`3V3-SW` 里围出 7.2 mm² 孤岛,**里面有 R415.2 的 +3V3 焊盘** ——
|
||
浮铜检查 / 焊盘覆盖检查 / 连接性 DRC **三样全都不响,只有数连通域看得见**。
|
||
堵孤岛重绕**不收敛**(7.2 → 25.4 → 26.8 → 32.5 mm²)。改成 **4.0**:
|
||
干线走 GND 底填,只在器件旁边**扎盲端**进平面。
|
||
2. **`expand()` 会静默丢掉最后一点上的过孔** —— 引擎 `_end_via` 的注释早写着,又踩一遍。
|
||
3. **`own`(本网铜放行)要按半线宽内缩**,过孔则根本不吃这条放行。
|
||
|
||
**顺带修掉一块和这次无关的浮铜**:板子南沿 y 0.5~9 那条 GND 底填(**1312.8 mm²**)
|
||
在 Inner2 上是孤立的,一个落脚点都没有 —— 它原本靠 x 115~116 那条 1.0 mm 缝接出去,
|
||
被上一轮信号布线的三个过孔的反焊盘掐断了。新脚本 **`.claude/pcb1_gnd_stitch.py`**
|
||
在南沿补了 6 个 GND 缝合孔。⚠️ 这一条**只有铺铜下发后 `verify()` 回读实测铜才量得出来**,
|
||
下发前的 `report()` 栅格不含别的铺铜,算出来 GND 是一整块。
|
||
|
||
**验收**:净距/拐角/孔距 ✅ · 平面完整性 ✅(+12V 1 块 / +3V3 2 块)·
|
||
`pcb1_pour.py --push --verify` ✅ 实测和计划对得上 · DRC 里**没有一条**牵涉 SDA/SCL。
|
||
|
||
---
|
||
|
||
### ✅ 这一轮 C(2026-09-06):8 A 的源只有 3 个过孔(§26.19)
|
||
|
||
第一次跑信号布线跑到 35/196 中止 —— 不是布线器的问题,是它报出来的失败把两个上游问题照了出来。
|
||
|
||
1. **`Rs6.2` → +12V 平面只有 3 个 Ø0.3 过孔 ≈ 3~4.5 A,而它要过 8 A。**
|
||
它是全板 +12V 平面**唯一的源**。这一条**四道验证一条都不管**:铺铜断面只量平面本身、
|
||
扇出只报「孔放下了没有」、连接性 DRC 只看「连上没有」、逃逸审计只看「出得去吗」。
|
||
⇒ `pcb_fanout.py` 新增 **`FORCE_ARRAY`**(整片阵列钉死,逐个仍走全套净距校核),
|
||
Rs6.2 钉 **12 个孔(≈12 A)**,摆在焊盘正南那片空地。
|
||
**规矩:>4 A 的「焊盘 → 平面」转换点,过孔数必须手写。**
|
||
2. **顺带把 U13 的 I²C 放了出来。** 原来那 3 个孔有两个甩到西边,两根 1 mm 引线
|
||
(端帽再往西探 0.5)压死了 U13 南排五个脚唯一的通道;`VINSW-TOP` 北柱又只差 0.379 mm。
|
||
12 个孔改朝南 + 北柱在 y>87 收窄到 x 1.5~5.3(3.8 mm → 8.4 A),
|
||
U13 南边变成一整片 x 5.5~14 / y 91.6~96 的空地。
|
||
3. **扇出不对称又发作了一次**:`C%06.2` 的 GND 孔在 rot 0 的三路往东落到局部 (10.02,27.10)、
|
||
在 rot 180 的 CH2/CH3 往西落到 (6.75,27.10),正压在 eFuse 脚 14/15 的出线口上。
|
||
已加进 `_CH_FORCE_LOCAL`。
|
||
4. **剩下 10 个「被围死」不是板上的铜** —— 报出来的挡路物去 `pcb-copper.json` 里查不到,
|
||
是**审计自己给邻脚预留的出线段**。判据就是这个:**查得到才是真障碍**。
|
||
|
||
---
|
||
|
||
### ✅ 这一轮 A(2026-09-06):v11 的两行排法把 8 A 输入链卡死了,已修(§26.17)
|
||
|
||
§26.16-E 换 XT30 之后把 N-L 块改成两行,摆位的**本地检查六项全过**,
|
||
可是回去重画 §26.11 的顶层宽铜时第一刀就下不去:
|
||
**`VIN_RAW` 从 J1 出来根本没有 3.49 mm 的路** —— XT30 rot 270 之后 GND 在北针 (13.5,74.5)、
|
||
VIN 在南针 (13.5,69.5),而 F1 卧着放和 GND 针同一行,中间又被 D1(17.5,69.5) 堵住,
|
||
实测通道只剩 **1.674 mm**(1 oz 外层约 4.5 A,这里要 8 A)。
|
||
|
||
> **这一类错误几何检查一条都报不出来** —— 不重叠、不越框、高度也够。
|
||
> 抓到它的是「照新坐标把顶层宽铜的多边形重推一遍」这个动作本身。
|
||
> ⇒ **摆位改完不能只看本地检查,必须把 §26.11 那三块多边形重推一次**。
|
||
|
||
三处改动(`pcb1_place.py` 的 N-L 表):
|
||
|
||
| # | 改动 | 拿回了什么 |
|
||
|---|---|---|
|
||
| ① | **F1 卧 → 竖**(rot 0 → **90**),(17.5,74.5) 不动 | `F1.1` 落到 (17.5, **73.06**),正对 J1.2 那片空地 |
|
||
| ② | **D1 (17.5,69.5) → (31.0,74.5)** rot 270 | 通道里最后一个障碍搬走,TVS 贴到漏极铜东缘 |
|
||
| ③ | **C4/C5/C6 x 25 → 30.5,rot 0 → 180** | 让出 y 78.85~83.5 那条 **4.64 mm** 的 VIN_SW 西行干道 |
|
||
|
||
顶层三块宽铜重画后实测断面全过:RAW 颈 **3.50**(要 3.49)、FUSED 5.25、SW 干道 4.75、北柱 5.25 mm。
|
||
面积 59 / 30 / 263 mm²,各 1 个连通域,`check_top_clearance()` 零侵入。
|
||
|
||
**⚠️ 顺带抓到一个静默失效:`Rs6.2` 一个过孔都没打。**
|
||
`12V-N` 为了让开 U13 的 Kelvin 脚,在西边咬了个缺口 `(0.5,93.0)-(12.5,101.5)`,
|
||
而 Rs6.2 的焊盘中心 (9.57,93.50) **正落在缺口里** ⇒ 扇出判成「不在铜面上」,
|
||
**全板唯一的 8 A 源不接电源平面**。`--push` 照样报「失败 0 个」,连接性 DRC 也不响
|
||
(+12V 靠别的 55 个焊盘照样连通,只有**源**那一端是断的)。缺口收成 `(0.5,95.6)-(12.5,102.4)`。
|
||
|
||
---
|
||
|
||
### ✅ 这一轮 B(2026-09-06,用户拍板):三组引脚按几何重排(§26.18)
|
||
|
||
「哪个信号落在哪个物理脚」有三处是自由的,而原来全是按**逻辑顺序**排的,
|
||
和它们在板上要去哪儿一点关系都没有。目标函数用**绕开芯片本体的直角最短路**
|
||
(HPWL 量不出「东边的脚要去西边」有多贵:同一批改动 HPWL 说省 7%,绕障路长说省 15%)。
|
||
|
||
| 组 | 结果 | 挪了几个 |
|
||
|---|---|---|
|
||
| **ESP32-S3 U20** 22 个信号 | 1195 → **1020 mm**(−15%),绕模块的线 3 根 → **0** | 12 |
|
||
| **DAC63204 U6/U7** 5 个通道 | 422 → **352 mm**(−17%),**一根线都不用新画** | 4 |
|
||
| **74HC595 U21/U22/U33** 21 个位 | 1286 → **1141 mm**(−11%),每路三键成束 | 17 |
|
||
|
||
合计省 **约 390 mm**。三处关键决定:
|
||
|
||
1. **放开 IO39~IO42**(原留给引脚 JTAG)—— 西边从 4 个坑变 8 个。
|
||
调试本来就走**原生 USB-Serial-JTAG**(IO19/IO20 → J22,出厂 eFuse 默认就是它),
|
||
板上没有 JTAG 排针。⚠️ **永远别烧 `DIS_USB_JTAG`**,烧了两边都没有。
|
||
让出去的只是「USB 起不来时还能进去」这个兜底。
|
||
`EFUSE_EN1 → IO39`、`VBUS_EN1 → IO40`、`EFUSE_EN4 → IO41`、`VBUS_EN4 → IO42`。
|
||
空出来的是 **IO4 / IO5 / IO7(三个都带 ADC1)+ RXD0/IO44**。
|
||
2. **DAC 只在已画好线的 5 个通道里置换**(U6 管去西半板的 VDAC1/2/4,U7 管去东半板的 VDAC3/5)。
|
||
动用 U6.OUT3 / U7.OUT2/3 还能再省 6 mm,但要新画 OUT/FB 两根线,不值。
|
||
3. **595 加了「每路 3 个按键必须落在同一片的连续三个南脚上」的约束** —— 比自由指派多 40 mm,
|
||
换来三根线出芯片就是一束。U33(y≈70)从「EDL 专用片」变成「北边那一片」,
|
||
接管 CH2/CH3 的六个按键 + HUB_RST,因为它正对 y 87~94 的北排两路。
|
||
|
||
**⛔ U33 现在在 `P6-FAN-EDL` 那一页上带着 CH2/CH3 的按键网络** —— 页面语义乱了一点,
|
||
但三片本来就是一条 24 位链,功能上没区别。
|
||
|
||
#### 落地时踩到的两条 API
|
||
|
||
1. ⚠️⚠️ **`setState_Net` 对 netport 是坏的**:调用之后网络名变成**空字符串**,标签也没了
|
||
(和 skill §3b 的 `setState_X/Y` 同一个毛病)。⇒ 端口只能 **删掉重建**。
|
||
2. ✅ **skill §8b 那句「端口的 dir 读不回来」是错的**:
|
||
`getState_Component().name` 就是 `Netport-BI` / `Netport-IN` / `Netport-OUT`。
|
||
重建前读它原样传回去即可 —— `p1_add.py` 当年「端口只增不重建」的限制可以解除了。
|
||
|
||
#### 顺手治了:图面文字叠了好几代
|
||
|
||
P3 有 **44** 条 `sch_PrimitiveText`、P3B **64** 条、P6 **76** 条,大量是**同坐标同内容的完全重复**
|
||
(历代脚本只 `create` 不 `delete`),还有互相矛盾的旧说明叠在一起。
|
||
**四道验证(verify_sch / xpage / port_audit / DRC)一条都不管文字**,所以它烂了很久没人发现。
|
||
`.claude/sch_text.py` 整页重写:44→13 / 64→14 / 76→16,顺带改掉换脚后变成假话的几条。
|
||
|
||
### 这一轮新增的脚本
|
||
|
||
| 文件 | 用途 |
|
||
|---|---|
|
||
| **`pinmap.py`** | ⭐ 三组「逻辑信号 → 物理脚」映射的**事实来源** + 落地 + `--check` 回读对账 |
|
||
| **`sch_text.py`** | 三页图面文字整页重写(删光旧的再写一套) |
|
||
|
||
### ⚠️ 还欠人眼确认
|
||
|
||
- `PCB1-v11-NL.png`(北左输入链改动前)与改动后的截图 —— **还没截改动后的**
|
||
- `P3-CONTROL-v2.png` / `P3B-EXPAND-v2.png` / `P6-FAN-EDL-v2.png` 三张换脚后的原理图
|
||
- 摆位总图 `PCB1-v11-place.png`(v11 那一版,D1/C4/C5/C6 的新位置还没进图)
|
||
|
||
---
|
||
|
||
### 上一轮(2026-09-06 第二十二轮):拆线重布 + 两处换件 + 控制块按几何重排(§26.16)
|
||
|
||
| # | 改动 | 依据 |
|
||
|---|---|---|
|
||
| 1 | **J1**:`KF128-5.08-2P` → **`XT30PW-M`**(C53373776),(8.5, 72.0) **rot 270** | 用户要插拔式;12V 是 8 A,DC-002 那类只有 1 A |
|
||
| 2 | **J26~J30**:`KF2510-3A`(弯针) → **`2510-3A`(直针)**(C2803349) | 用户要立式;进深 12.01 → **5.81** |
|
||
| 3 | **N-L 块重排** | XT30 比 KF128 宽一圈,原位放不下 ⇒ **这一版被第二十三轮推翻,见上面 A** |
|
||
| 4 | **控制块**:`affine()` → `CTRL` 表(退火求解,`pcb1_ctrl_place.py`)| 原来 U21/U22 中心只隔 8.04 mm,中间塞不进一根线 |
|
||
| 5 | **22 个附属 R/C**:`affine()` → `SAT` 表(逐个贴对端引脚)| `R602`/`R603` 是 USB-C 的 CC 下拉,**离 J22 有 77 mm** |
|
||
|
||
全板 HPWL **9416 → 8935 mm**。摆位大改之后 `pcb1_wipe.py --push` 把板上**全部铜**清空过一次
|
||
(走线 / 过孔 / 铺铜,元件 / 板框 / 丝印不动),13 个旧账本改名成 `.stale`。
|
||
|
||
**这一轮沉淀的脚本**(仍然有效):
|
||
|
||
| 文件 | 用途 |
|
||
|---|---|
|
||
| **`fp_body.py`** | ⭐ 从器件的 `3D Model Transform` 直接读**本体框**(`--scan` / `--check`)。⚠️ 只给 XY,**Z 读不出来** |
|
||
| **`p1p6_conn.py`** | J1 / J26~J30 换件(做到一根导线不动) |
|
||
| **`pcb1_ctrl_place.py`** | 控制块五颗芯片退火求位置(目标 HPWL)。⚠️ 它写的 `_pcb1_ctrl_pos.json` **只是参考**,`pcb1_place.CTRL` 是硬编码的事实来源 |
|
||
| **`pcb1_wipe.py`** | 清空板上全部铜(铜层白名单 1/2/15/16) |
|
||
|
||
**⛔ 三个要记住的地雷(仍然有效)**
|
||
|
||
1. `pcb1_route_sig.py` 的 `--net` / `--limit` 试水以前会把计划缓存清成 `{}`(已修)。
|
||
2. `clean()` 以前只删得掉 59% 的自己的铜(已修,改成覆盖判据)——
|
||
EasyEDA 会合并共线段、在 T 形接点劈线,坐标精确比对认不出来。
|
||
3. 「两个端点钉死 ⇒ 连通性不变」是破的 —— 链会 T 在别的链**中段**上。
|
||
现在先按搭接点切开(409 → 797 条),拆完还要用 `pcb1_netlist.analyze()` 实算碎片数兜底。
|
||
|
||
**⚠️ 已知偏差(是决定,不是遗漏)**
|
||
|
||
- **立式风扇座把装配顺序锁死了**(用户 2026-09-06 拍板接受):立式插口朝上正对载板底面,
|
||
座 + 胶壳约 11.5 mm,13 mm 净空里插拔只剩 1.5 mm ⇒ **必须先插好五根风扇线再合载板**。
|
||
- **`H_FP` 里 XT30 的 11.0 和直针座的 9.0 是估计值** —— `3D Model Transform` 给不出 Z,
|
||
**打样前拿实物量**。
|
||
- ~~控制块的通道分配还没改~~ → **第二十三轮已经做完**(§26.18)。
|
||
- `POGO2_VUP` / `POGO2_VDN` 离 SW 节点 0.54 / 0.74 mm(§10.3 要「远离」),
|
||
`sw_keepaway()` 会一直报,当提示不当错误。
|
||
|
||
---
|
||
|
||
### ✅ 这一轮(2026-09-06 第二十一轮):五路母版三处整改 + 全链重跑(用户拍板 A+B+C)
|
||
|
||
设计文档 **§26.15**。§26.14 抓出的 22 个「几何上没有出路」的引脚,这一轮动手改掉,
|
||
改的全是**母版**(= 五路一起改),改完整条链重跑。
|
||
|
||
| # | 改了什么 | 结果 |
|
||
|---|---|---|
|
||
| A | **SW 不再往南潜**:`C%05` 北移 0.6,`SW-run` 平着走 y 12.500(1.2 宽),删掉 `SW-down` | 五路 `EN` 全部解放;SW 节点 9.6 → **8.9 mm** / 铜面积 10.9 → **9.4 mm²** |
|
||
| B | **`U%8` + `Rs%01` + `C%13` 整体北移 0.8** | eFuse 北排那条缝 0.33 → **1.13 mm** |
|
||
| C | 跟着 B 改的三处:`_CH_FORCE_LOCAL['U%__8','1']`、`F-trunk` 北端、`K-IN±` | 相对几何一格没变 |
|
||
| — | 全链重跑:place → clear → dump → fanout → pour → route_pwr | 342 件 / 498 孔 / 15 铜面,功率级 195 段回读 **0 条对不上** |
|
||
|
||
**「几何上出不去」的焊盘:22 → 8**(`pcb1_escape_audit.py` 实测)。
|
||
剩下 8 个是**和邻脚预留出线段抢地方**,不是硬几何 —— 单独布都能通。
|
||
|
||
#### ⭐ 这一轮踩到的三条
|
||
|
||
**1. 「端帽比端点往外探半个线宽」这一条,一轮里踩了两次。**
|
||
先是 `SW-run` 1.5 mm 的西端帽把 `EN` 封死(在 y=11.5 那一行往西探到 x 11.007,
|
||
比端点多探 0.743);改完起点又发现同一个端帽离 `U%1.13`(BOOT 引脚) 只有 **0.080**。
|
||
⇒ **凡是宽线的端点,心里都要按「端点 ± w/2 的圆」去想**,§26.11 已经写过一次了。
|
||
|
||
**2. 挪 0.1 mm 解决不了拓扑问题。** A 组先试过「`SW-run` 起点东移 0.35」和「收窄到 0.9」,
|
||
两次都卡在 5~20 µm 上 —— 因为 COMP 和 EN **两个脚**要并排出来,缺的不是余量是**车道**。
|
||
把 `C%05` 北移 0.6、让 SW 整条不再下潜,才是解。
|
||
|
||
**3. `verify()` 只认「同宽」的线会报假阳性。**
|
||
一段窄线整个落在宽线的圆头端帽里时 EasyEDA 会**直接吞掉它** —— 铜一点没少,
|
||
回读却报 5 条对不上。判据改成「实测线不窄于计划线,且中心距 ≤ (o_w − p_w)/2」。
|
||
|
||
**4. `chamfer_routes(smooth=True)` 会挪线(最多 0.15 mm),不只是拿掉铜。**
|
||
而它的净距校核拿的是**切之前**的自身路径 ⇒ 两条本轮新画的线会被各自抹到对方身上
|
||
(实测 `$1N227` vs `POGO1_PWR` 压成 **−0.199**,2255 段里 2 段)。
|
||
⇒ 切完再跑一遍 `check()`,**把牵涉到违规的整条退回未切的版本**,最多退 4 轮。
|
||
|
||
---
|
||
|
||
### ✅ 这一轮(2026-09-06 第二十轮):下板信号布线 —— 工具全套建好,⛔ 没下发
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | 新增 **`pcb1_netlist.py`**:按**实测铜**(含回读的铺铜)算全板连通性 | 还欠 **200 个网络 / 384 条连接**;顺带发现 GND 其实早就通了 |
|
||
| 2 | 新增 **`pcb1_route_sig.py`**:下板信号布线器(复用载板栅格引擎,只加不拆)| 379 条里布通 **284 条(75%)**,净距 / 钻孔 / 铺铜 **三样全 0** |
|
||
| 3 | 新增 **`pcb1_escape_audit.py`**:逐个焊盘算「能不能走得出去」 | 563 个待接焊盘里 **22 个几何上出不去** |
|
||
| 4 | Kelvin 三条(`U13.8/9/10` ↔ `Rs6`)单独钉死,不许就近扎平面 | 3 / 3 条,w 0.30 |
|
||
| 5 | USB 差分对「**一整束布线 + 平行偏移**」 | 束长 58.1 mm,W 0.28 / S 0.18,**对内偏斜 0.00 mm** |
|
||
| 6 | 修掉 4 个真 bug(见下) | — |
|
||
|
||
#### ⭐⭐ 这一轮最值得记住的四条
|
||
|
||
**1. POLYGON 焊盘的**包围盒**不是它的形状 —— 又一次。**
|
||
§26.13 抓的是它的 `hole` 是假的;这一次是 `pad[1], pad[2]` 那对宽高。
|
||
TPS54622 的散热盘是个**带四个缺口的多边形**(缺口正是让给 pin 1/7/8/14 的),
|
||
按 2.032 × 4.320 的包围盒当障碍,这四个脚**整个泡在 GND 铜里**:
|
||
`entry_stub` 一个出线方向都找不到,`BUCK_PG` 报「五路全布不通」。
|
||
⇒ **POLYGON 焊盘的任何标量属性都不能直接当几何用**,只能读 `pad[1]` 那串点。
|
||
现在 `pcb1_route_sig.poly_pads()` 把 11 个多边形盘按真实轮廓光栅化成矩形条。
|
||
|
||
**2. 网名里带 `#` 的网络会被引擎的 `netof()` 拆坏。**
|
||
引擎用 `key.split('#')[0]` 从「路径 key」还原网名,而下板有 `KEY_OE#` 和 `IOEXP_INT#`。
|
||
`'IOEXP_INT#' + '#0'` 拆回来是 `IOEXP_INT` ⇒ 校核时它和**自己的焊盘**被当成异网,
|
||
报「线-焊盘 净距 −0.100」,看上去像压线,其实两者本来就该连在一起。
|
||
⇒ 分隔符改成 `chr(0)`。**凡是「用某个字符拼 key」的地方,都要先问一句这个字符会不会出现在数据里。**
|
||
|
||
**3. 45° 切角会切进铺铜里 —— `seg_slack()` 不认铺铜。**
|
||
切角是往拐角**内侧**补铜(不是只拿掉铜),而引擎的切角校核只看焊盘 / 过孔 / 走线。
|
||
实测 `SDA` 在 (6.10, 65.50) 被切进 `VO1_P` 小岛,只剩 0.043。
|
||
⇒ 把铺铜矩形条包装成「假焊盘」一起喂给 `chamfer_routes()` 和 `check()`。
|
||
|
||
**4. 0.5 脚距的脚,「放得下」和「栅格上走得通」是两回事。**
|
||
`U8.3`(INA226 的 ALERT):西边 1.00 mm 是 GND 扇出孔,东边 1.00 mm 是邻脚的出线段。
|
||
0.20 的线需要 **1.005 mm**(差 5 µm 过不去),0.15 的线只要 0.955 mm ——
|
||
可 0.1 mm 栅格上判据要各加一个 QERR 0.0707,变成 1.096 mm,**整片不可达**。
|
||
0.025 mm 栅格的 QERR 只有 0.0177,同一条缝就通了。
|
||
⇒ 新增「**细栅格逃逸**」:0.1 栅格上出不来的脚,先在 4 mm 内用 0.025 栅格单独走出去。
|
||
实测 47 个脚里救回 **25 个**。
|
||
|
||
#### ⛔ 剩下 22 个脚是**几何上就没有出路**,必须动板子
|
||
|
||
| 组 | 焊盘 | 卡在哪 | 差多少 |
|
||
|---|---|---|---|
|
||
| **A** | `U1.10 U2.10 U3.10 U4.10 U5.10`(Buck 的 `EN`)| `pcb1_route_pwr` 的 **SW-run 1.5 mm 铜**,圆头端帽从 (20.05,27.10) 往西探到 x 19.30 | 脚东边净空 0.376,一根 0.2 的线要 0.6 |
|
||
| **B** | `U14.2/3` `U15.2/3/14/15` `U16.2/3/14/15` `U17.2/3` `U18.2/3`(eFuse 北排)| 上面 INA226 的焊盘边 **只隔 0.33 mm**,下面自己的散热盘 **0.25 mm** | 要 ≥ 0.6,缺 ~0.7 mm |
|
||
| **C** | `U10.3`(ALERT)`U13.4`(SDA) `U13.5`(SCL) | 隔壁 GND 扇出孔正对着出线走廊 | **5 µm** |
|
||
|
||
**A 组的解**:EN 是每路都有的信号,本来就该进 §10.2 母版 —— 在 `pcb1_route_pwr.R` 里
|
||
加一条 `EN` 路径,并把 `SW-run` 的起点往东挪 ~0.35 mm(或前 2 mm 收窄到 1.2)。
|
||
收窄反而**符合** §10.2-2「SW 铜箔面积压到刚好够载流」。
|
||
|
||
**B 组的解**:CH1 那一列从下往上是 `C106(顶 43.46) → U14(43.85~47.75) → U8(48.08~53.92)
|
||
→ Rs101(54.27~57.73)`,缝一律 0.33~0.39 mm,**一点余量都没有**。
|
||
唯一的空地在 Rs101 顶到通道北界 y 59 之间的 **1.27 mm**
|
||
⇒ 把 `U8 + Rs101` 整体北移 **0.7~0.8 mm**(母版改一处 = 五路一起改)。
|
||
⚠️ 这会连带作废 **扇出 + 铺铜 + 五路功率级布线**(`U*.9 → Rs*01.1` 的 Kelvin 线也在母版里)。
|
||
|
||
**C 组的解**:给那两三个 GND 扇出孔在 `pcb_fanout._CH_FORCE_LOCAL` 里钉一个偏 0.1~0.2 mm 的位置。
|
||
|
||
#### ⚠️ 另外 95 条是**拥挤**,要拆线重布才能再往前
|
||
|
||
失败集中在**控制块(U21~U23,x 75~107 / y 43~58)**和 **J24/J25 排针**周边;
|
||
按网络族数:`$14N` 9 / `$8N` 7 / `$12N` 7 / `EFUSE_PG` 6 / `$10N` 6 / `INA_ALERT` 5 …
|
||
现在这个布线器是**一遍过、只加不拆**(这是有意的:板上已有 691 条线不能被抹掉),
|
||
所以先布的把后布的堵死了 —— 这正是商业布线器用 **rip-up & reroute**(协商式拥塞)解决的那一类。
|
||
⇒ 下一轮要么加拆线重布,要么等 A/B/C 三组改完再看还剩多少。
|
||
|
||
#### 顺带记两条
|
||
|
||
- `POGO2_VUP` / `POGO2_VDN` 离 SW 节点只有 **0.54 / 0.64 mm**(§10.3 要求「远离」)。
|
||
已经有 `sw_keepaway()` 在报,不当错误、只列出来。
|
||
- 8 个 45° 切不动的拐角(转向 89~90°),都在细缝里,`chamfer45` 试到 0.05 半径仍撞墙。
|
||
|
||
#### 这一轮的产出(都在 `.claude/` 下,**没有一个动过板子**)
|
||
|
||
| 文件 | 用途 |
|
||
|---|---|
|
||
| **`pcb1_netlist.py`** | 按**实测铜**算连通性:焊盘 / 过孔 / 走线 / **回读的铺铜**当图的节点,`--todo` 列还欠几条,`--json` 出任务表。⚠️ 判据不能只测焊盘中心那一格:同网通孔盘在回读的环里是个**洞** |
|
||
| **`pcb1_route_sig.py`** | 下板信号布线器。`--net` / `--limit` / `--push` / `--clean --push` / `--verify` / `--refresh`。内含 Kelvin 强制表 `FORCE`、USB 束 + 偏移、细栅格逃逸、铺铜障碍、`sw_keepaway()` |
|
||
| **`pcb1_escape_audit.py`** | 逐焊盘的**逃逸可达性**:两层泛洪 + `via_ok()` 打通,走不到 4 mm 外就报。`--why <焊盘>` 列出挡路的铜。⚠️ 判据环不能取自由区最外圈(那一圈 `free()` 永远是假的)|
|
||
|
||
---
|
||
|
||
### ✅ 这一轮(2026-09-06 第十九轮):五路功率级精调(§26.13)
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | **修 POLYGON 焊盘的假 `hole`**(`dump_pads` / `pcb_fanout` / `pcb1_parts_dump` 三处)| 七个散热盘回到扇出名单 |
|
||
| 2 | 盘内阵列改成**按真实多边形**撒点 + 自适应间距 + 补中心孔 | U1~U5 **0 → 5** 个孔;U6/U7 0 → 4;eFuse 2 → 6 |
|
||
| 3 | 摆位 v9:`L*01` / `U*14` / `Rs*01` 各转 180°,`C*05` 与三颗输出电容挪位 | 四条回路的朝向全部理顺 |
|
||
| 4 | 新增 **`pcb1_route_pwr.py`**:母版 27 条路径 × 5 路 = 210 段,全部顶层 | 一路 74.8 mm,**SW 13.1 → 9.7 mm** |
|
||
| 5 | 新增 `pcb_fanout._CH_FORCE_LOCAL`:5 个焊盘 × 5 路 = 25 个 `FORCE_VIA` | 五路的扇出终于**真的一样** |
|
||
| 6 | 重跑全链:place → 扇出三步 → 铺铜 → 布线 → DRC | 495 孔 / 691 线 / 间距 0 / 物理 0 / 连接性 594 |
|
||
|
||
#### ⭐⭐ 这一轮最值得记住的四条
|
||
|
||
**1. 「有孔 = 通孔盘」是错的判据 —— POLYGON 盘的 `hole` 是假的。**
|
||
板上 11 个 POLYGON 盘无一例外满足 `hole = 0.600 × min(w,h)`(U1 的 2.032×4.320 → 1.2192,
|
||
U6 的 1.70×1.70 → 1.02,J22 的 1.30×0.60 → 0.36),EasyEDA 渲染出来是实心的。
|
||
判据应该是**层号**:`layer == 12` 才是多层通孔盘。
|
||
|
||
**2. 五路的扇出结果并不相同 —— 明明摆位一模一样。**
|
||
扇出规划器的候选角度按**板坐标**排,而 CH2/CH3 整路转了 180°,
|
||
同一个焊盘在 CH1 往东扇、在 CH2 就往西扇。母版里算好的走廊于是在 CH2/CH3 上被堵死,
|
||
而报出来的是「CH2 的 F-trunk 撞到一个 GND 过孔」——**看上去像布线画错了**。
|
||
⇒ 关键焊盘按 CH1 的解钉死(`FORCE_VIA`),钉死之后照样走全套净距校核。
|
||
|
||
**3. DRC 的「物理错误」那一支平时是空的,容易漏看。**
|
||
0.28/0.25 的线下发之后:**间距错误 0、连接性还降了 125 条** ——
|
||
而 `物理错误·导线` 里躺着 50 条「线宽 11mil,应该 ≥ 11.8mil」
|
||
(`SWNODE`/`PWR4A` 的 `strokeWidthMin` 都是 0.30)。加宽到 0.30 清零。
|
||
|
||
**4. 回读走线不能按端点比:EasyEDA 会在 T 形接点上把已有的线劈成两条。**
|
||
西侧那条 +12V 母线下发之后在板上是两条(支线接在中间)。
|
||
按端点比报「210 段里 40 段对不上」,而铜一点没少。
|
||
⇒ `verify()` 用**覆盖判据**:每 0.2 mm 取一个点,要求被同网同层同线宽的实测线盖住。
|
||
|
||
#### ⚠️ Kelvin 的那一条:`U*8.9` 不许有过孔
|
||
|
||
`U*8.9`(INA226 的 IN−)已经写进 `pcb1_pour.ROUTED_PADS`。
|
||
让它走 `VO*_P` 小岛的话,取样点在岛上而不是分流电阻的焊盘上,中间隔着
|
||
`Rs*01` 那三个扇出孔(并联约 0.5 mΩ)。Rs 只有 5 mΩ、满载才 20 mV,
|
||
**0.5 mΩ × 4 A = 2 mV = 10% 的读数误差**,而 DRC 和连通性检查都看不出来
|
||
(IN− 和 `VO*_P` 本来就是同一个网)。pin 8 是 VBUS,照旧进岛。
|
||
|
||
---
|
||
|
||
### ✅ 上一轮(2026-09-06 第十八轮):F1 → 12 A / R9 → 5 × 2Ω 2512
|
||
|
||
两件都是用户拍板的选型改动,走完整链路:改原理图 → 导入变更 → 重推摆位 →
|
||
重扇出 → 重铺铜 → DRC。详见设计文档 **§26.12**。
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | F1 `F1206HC10A0TM` → **`F1206HC12A0TM`**(C310990)| 同是 1206,**摆位一格没动**;封装对象换了(`F1206`)但焊盘几乎一样 |
|
||
| 2 | R9 立式水泥电阻 → **R9A~R9E 5 × 2Ω 2512 串联** | 10Ω/**10W**,高 **22 → 0.8 mm** |
|
||
| 3 | `pcb1_import.py` 加 **`--bom`** | 原来 `_p1_sch_bom.json` 在仓库里**没有生产者** |
|
||
| 4 | `pcb_fanout.py` 加 **`guard_not_pushed_twice()`** | 我推重了一次,888 个过孔(见下)|
|
||
| 5 | P1-INPUT 文字收拾 | 66 → 14 条,清掉一整代旧说明 |
|
||
| 6 | 结果 | 342 件 / 444 过孔(重复 0)/ 15 块铜面 / DRC **间距 0** + 连接性 725 |
|
||
|
||
#### ⚠️ 先纠一条我上一轮写错的
|
||
|
||
「F1 封装是 1206 但 BOM 写 10A、1206 做不到 10A」—— **错的**。
|
||
`F1206HC10A0TM` 本来就是 1206/10 A,BOM 和封装从来没对不上。
|
||
换 12 A 的真实理由是**降额**:8/10 = 80% 超过保险丝常规的 75% 线,且 I²t 只有 15 A²s。
|
||
|
||
#### ⭐⭐ 这一轮最值得记住的两条
|
||
|
||
**1. `pcb_fanout.py --net all --push` 不幂等 —— 我连推了两遍。**
|
||
板上变成 **888 个过孔**(每个都有同坐标同网的副本),而**短线数没变**(444):
|
||
EasyEDA 把共线重叠的新线并进了旧线。**连接性 DRC 一个字不报**(副本同网,电气上「没错」)。
|
||
唯一判据是**回读过孔数**。现在 `--push` 前会硬拦;重推必须
|
||
`--clean → dump_pads.py → --push` 一次跑完。
|
||
|
||
**2. `H_FP` 里那个 9.5 是照封装名 `W9.5` 抄的,而 R9 是立式件。**
|
||
`RES-TH_L13.5-W9.5-P5.80-D0.7`:**本体 13.5 长、脚距只有 5.80 ⇒ 它站着**
|
||
(同族 3D 模型标 `H52.0`)。那一片 hmax 只有 12.0,
|
||
所以「高度预算全过」在它身上假了整整一轮,**是用户看出来的,不是检查看出来的**。
|
||
⇒ 往 `H_FP` 加直插件的判据:**脚距和本体长度对不上就是立式**,
|
||
高度不是封装名里的 W,是那个对不上的方向。
|
||
|
||
#### ⛔ 新增的两个地雷标记
|
||
|
||
- **`p1_add.py` 已过期**,底稿 `p1-base.json` 停在 2026-09-04。再推一次会把
|
||
R9A~R9E 之间那 6 段导线**静默回退**。已加硬闸门(要跑得带 `--i-know-it-is-stale`)。
|
||
⇒ **改完一页就问一遍:还有哪个脚本会重画这一页。**
|
||
- **改过原理图必须 `pcb1_import.py --bom` 再 `--verify`**,否则是拿新 PCB 和旧原理图对账。
|
||
|
||
截图:**`PCB1-v8-r9f1.png`**(R9A~R9E 的 1+2+2 蛇形)/ **`P1-INPUT-v2.png`**(原理图)。
|
||
**还没等到用户回话。**
|
||
|
||
---
|
||
|
||
### ✅ 这一轮(2026-09-06 第十七轮):8 A 顶层宽铜
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | `pcb1_pour.REGIONS` 加三块顶层铜面 | `VINRAW-TOP` 46 / `VINFUSED-TOP` 19 / `VINSW-TOP` 284 mm²(实测)|
|
||
| 2 | 网名用 `pcb1_rules.resolve_auto()` 当场反查 | `$1N223` / `$1N227` / `$1N236`,**一个字没写死** |
|
||
| 3 | **`Grid` 分内层 / 外层两套障碍模型** | 外层连贴片焊盘一起挡;新增 `obstacles()` 把 438 个过孔 + 441 条走线算进去 |
|
||
| 4 | 新校核 **`check_top_clearance()`**(不过格子)| 当场抓出两处侵入,**其中一处栅格看不见** |
|
||
| 5 | 新校核 **`poly_vs_rects()`** | 手写的 24 个点 vs 它该等于的 8 个矩形,0.05 mm 逐格对照 |
|
||
| 6 | 下发 + 回读实测铜 | 15 块铜面全部铺出来,三段各 **1 个连通域** |
|
||
| 7 | DRC | 间距 **0** / 连接性 **719**(铺顶层铜前是 733)|
|
||
|
||
#### ⭐⭐ 这一轮最值得记住的:**线的端点不是铜的端点**
|
||
|
||
北柱东缘写在 x 6.8,Rs6.2 那条 +12V 出线的端点在 x 7.401 —— 看起来隔 0.6 mm。
|
||
但那条线 **1.0 mm 宽、圆头端帽往外再探 0.5 mm**,实际铜到 x **6.901**,
|
||
真实净距只有 **0.101 mm**。而 0.25 mm 的栅格上这 0.1 mm 一个格心都落不进去
|
||
⇒ **栅格全绿**。真下发下去 EDA 自己会往回缩一点点铜,板子不会报 DRC,
|
||
但**板上那块铜就不再是计划里那块铜,后面所有断面数字全部作废**。
|
||
|
||
⇒ 凡是手画的铜,都要过一遍 `check_top_clearance()` 这种**真实几何**的校核,
|
||
栅格只能用来算连通域和断面。
|
||
|
||
#### 顶层三段长什么样(实测断面,顶层 1 oz)
|
||
|
||
最窄两处:干道 x=12 处 **4.75 mm(10.0 A)**、北柱 y=92 处 **5.00 mm(10.4 A)**,
|
||
8 A 下 ΔT 分别约 12 / 11 °C。其余各点 8.75~21.5 mm。
|
||
|
||
截图:**`PCB1-v7-top8A.png`**(只开顶层 + 焊盘 + 顶丝印)。**还没等到用户回话。**
|
||
|
||
#### ⚠️ 顺带看出来的一件:**F1 的封装是 1206,但 BOM 写的是 10 A**
|
||
|
||
`FUSE-SMD_L3.2-W1.6-1` = 1206,而 §7 的 BOM 写「保险丝 10A 慢断」。
|
||
**1206 的贴片保险丝一般做到 5 A 左右就到顶了**。8 A 的铜宽本身没问题,
|
||
是**器件选型和封装对不上**。换大封装会动 J1→F1 那一段的摆位
|
||
⇒ 要**重推摆位 + 重扇出 + 重铺铜**。这一条留给用户拍板。
|
||
|
||
---
|
||
|
||
### ✅ 这一轮(2026-09-06 第十六轮)做完的
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | **修去耦电容摆位**:新增 `pcb1_place.DECAP` 表 + `place_decaps()` | 7 颗跟着本尊走,最远的储能 3.31 mm,其余 0.76~2.24 mm |
|
||
| 2 | **修 `pcb1_parts_dump.py` 漏了焊盘自身旋转** | 8 个元件的 bb 各长 0.26~0.30 mm(U1~U5 / U6 / U7 / U20)|
|
||
| 3 | 新增 **`pad_clearance_errs()`**:焊盘到焊盘净距 0.2 mm | 全板 1171 个焊盘一条不报 |
|
||
| 4 | 修 `pcb_fanout.TARGET`(还停在 §26.8 之前)| 删掉 `VOn` / `+5V` / 8 A 三段,它们不上 Inner2 |
|
||
| 5 | 修 `_pour_filter()`(指着单板时代的 `pcb_pour.py`)| 改指 `pcb1_pour.REGIONS`;实测滤掉 17 个铜面外的 `+3V3` 焊盘 |
|
||
| 6 | 扇出规划器补五条(见 §26.9)| GND/+12V/+3V3/VOnP **全部失败 0 个** |
|
||
| 7 | 扇出下发 | 438 过孔 + 441 短线,**DRC 间距 0** |
|
||
| 8 | **实现 `pcb1_pour.py --push` / `--verify`** | 12 块铜面已下发;回读实测铜 **24 项全 OK** |
|
||
| 9 | 下发前 / 下发后**共用同一段 `grid_checks()`** | 分两套写只能证明两套代码各自自洽 |
|
||
| 10 | 新校核:**每块碎片都要有本网过孔落脚**(浮铜)| 9 组 (网络,层) 的 12 块碎片全部有落脚 |
|
||
|
||
#### ⭐⭐ 第 1 条是这一轮最重要的发现:ESP32 的储能电容在 48 mm 外
|
||
|
||
追「U6.15 为什么扇不出去」追出来的。全板 20 个 IC 的 `+3V3` 电源脚里
|
||
**只有 1 个的去耦在 3 mm 以内**;`C601`(22 µF「ESP32 储能」)离 U20.2 **48.2 mm**,
|
||
`C602`(100 nF)**45 mm**,U20 电源脚周围 12 mm 内一个元件都没有。
|
||
|
||
根因:控制块是 `affine(['P3-CONTROL','P3B-EXPAND'], ...)` 按**原理图坐标**仿射映射摆的,
|
||
它保「原理图上挨着的板上也挨着」,保不住「去耦贴着电源脚」;
|
||
而 **U20 是上面手工单独摆的 —— 芯片被拎出了仿射集合,去耦却留在原地**。
|
||
|
||
⇒ **动控制块布局时先看 `DECAP` 表**,它是这件事的事实来源,`check()` 里有硬校核。
|
||
表的顺序 = 抢位置的顺序,**小的高频那颗必须排在大的储能之前**(理由见 §26.9)。
|
||
|
||
#### ⭐⭐ 第 2/3 条:本地检查曾经「全绿而板子是错的」
|
||
|
||
改完摆位本地六项全过,DRC 却报 4 条间距错误:`C607_2` 到 `U6_13` 只有 **0.096 mm**。
|
||
两个原因叠在一起 ——
|
||
`pcb1-parts.json` 的包围盒漏了**焊盘自身的旋转**(QFN 侧边脚是长条焊盘转 90° 用的,
|
||
U6 的 bb 在 y 上短 0.26 mm);而 `check()` 只查「包围盒重不重叠」,**不重叠不等于够净距**。
|
||
现在两条都修了,新检查直接照 DRC 那条 0.2 mm 的规则算,量焊盘不量包围盒。
|
||
|
||
> ⚠️ 同一套 API 里 `getAllPinsByPrimitiveId` 的 rotation 是**度**,
|
||
> `pcb_PrimitivePad.getAll()` 的是**弧度**。
|
||
|
||
### 下板 PCB1 接下来的顺序
|
||
|
||
0. **让用户人眼确认摆位 v9 + 功率级布线**(截图已出,见上面「一句话现状」)。
|
||
不算硬阻塞,但这一轮动过五路的摆位,值得看一眼。
|
||
1. ~~设计规则~~ ✅ §26.7 2. ~~定铺铜几何~~ ✅ §26.8
|
||
3. ~~扇出~~ ✅ **§26.9 / §26.13** 4. ~~铺铜~~ ✅ **§26.10,已下发并回读复核**
|
||
5. ~~8 A 输入链顶层宽铜~~ ✅ **§26.11,已下发并回读复核**
|
||
6. ~~五路功率级精调~~ ✅ **§26.13,已下发并回读复核**
|
||
7. ~~写下板信号布线器~~ ✅ **`pcb1_route_sig.py` 已建好并跑通 75%(第二十轮)**,
|
||
`pcb1_route_pwr.py` 那 210 段一根没动(这个布线器只加不拆,删除只按坐标删自己画过的)。
|
||
|
||
8. ~~A/B/C 三组几何整改~~ ✅ **§26.15,用户拍板 A+B+C,已全链重跑并下发**。
|
||
全链的正确顺序(动过摆位就照这个走,一步都不能省):
|
||
`pcb1_place --push` → `pcb1_clear --push` → `dump_pads` → `pcb_fanout --net all --push`
|
||
→ `pcb1_pour --refresh --push` → `pcb1_route_pwr --push` → `pcb1_route_sig --push`
|
||
→ `pcb1_pour --refresh --push`(**给新过孔补反焊盘**)→ `pcb1_reload` → `drc_read`。
|
||
|
||
9. ⬅️ **下一步:给 `pcb1_route_sig.py` 加拆线重布**(rip-up & reroute),收掉剩下的 91 条。
|
||
⚠️ 直接再跑一遍 `pcb1_route_sig.py --refresh --push` 也会有进展(它读板上的铜、
|
||
只补还缺的),但一遍过的策略已经到顶了 —— 真要清零得能拆别人的线。
|
||
|
||
⚠️ **北左角的顶层现在被 8 A 宽铜占了大半**(x 1.5~28.9 / y 68.6~93)。
|
||
U13 的 I2C、U29、R9 那几条信号得**走底层**—— 底层整层基本是空的,不占地方。
|
||
三条还没布的细线已经有名有姓地写在 `pcb1_pour.ROUTED_PADS` 里:
|
||
`U13.10`(Kelvin VIN+,接北柱顶端那一小截死头)/ `DZ1.1` / `C1.1`(栅极)。
|
||
|
||
⚠️ **动了铺铜或摆位就要重跑 `pcb1_pour.py --push`**,它自己会先把计划跑绿再下发;
|
||
下发完自动 `--verify` 回读实测铜。只想看不想改板就 `--verify`(加 `--cache` 用上次的回读)。
|
||
|
||
⚠️ **动过摆位就要重跑扇出三步,不能省也不能并**:
|
||
`pcb_fanout.py --clean` → `dump_pads.py` → `pcb_fanout.py --net all --push`。
|
||
|
||
⚠️ **连接性数字扇出之后会先涨再跌**:布线前基线 1145 → 扇出完 **1336** → 铺完铜 **733**。
|
||
过孔本身是新对象,铺铜之前每一个都是自己网络里的孤岛。
|
||
**只看扇出完那一步会以为扇出把事情弄坏了。**
|
||
|
||
⚠️ **EasyEDA 客户端这一轮掉线过三次**(`EDA window ... disconnected`)。
|
||
掉线时命令**可能已经执行完**只是回话丢了 —— 别直接重试,先回读板上对象数再决定。
|
||
|
||
### ⚠️⚠️ 一条永远别忘的:J24 / J25 的针号是**故意错一位**的(§26.5,用户已拍板选 A)
|
||
|
||
`p5_btb.py` 的 **`MATE_SWAP = True`** 让下板这一侧的网络按针号奇偶对调
|
||
(两颗封装焊盘编号同手性 + 母座在载板底层、顶视图镜像一次,不改的话下板 `VO1_P`
|
||
会顶在载板 `GND` 上)。`c1_conn.py`(载板 C1-CONN)用的是原始表,**一个字没动**。
|
||
⇒ **判据是网络不是针号**:下板 pin(2r−1) 正对载板 pin(2r),差一位是**预期的**。
|
||
每次动完摆位跑 `pcb1_place.py --verify` 逐个焊盘核。
|
||
|
||
### Inner2 分块的结论(详见设计文档 §26.8)
|
||
|
||
| 层 | 网络 | 名称 | 形状 |
|
||
|---|---|---|---|
|
||
| Inner2 | `+12V` | `12V-N` | 北带 y 88~124.5 通板 + 风扇指下伸到 y 66.5,挖掉 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` / `3V3-SE` | 南部两块,**故意不连通**(见下)|
|
||
| Inner2 | `GND` | `GND-FILL-L3` | 剩余全部 |
|
||
| Bottom | `VOn_P` | 五块小岛 | 各约 18 × 13 mm |
|
||
| Inner1 | `GND` | `GND-L2` | 整板,只挖 ESP32 天线区 |
|
||
|
||
**退回走线的四类**(都算过,不是省事):`+5V` 底层 1.2 mm 干线 / `VOn` 顶层 1.5~2.0 mm /
|
||
`VOn_P` 底层小岛 / **8 A 输入链顶层宽铜 ≥3.5 mm**。
|
||
关键数:内层 0.5 oz 与外层 1 oz 差约 **4 倍**(8 A 内层要 18.2 mm,外层只要 3.49 mm),
|
||
而这块板**底层整层是空的** ⇒ 短距离大电流根本不该上内层。
|
||
|
||
⚠️ **`+3V3` 在 Inner2 上是 2 个连通域,是设计意图不是漏接。** 中桥必须纵向穿过
|
||
y 41~58.5 那条带,而 `+3V3` 的南部焊盘横向铺满同一条带 —— 同一层上两个都要连通的
|
||
2-D 区域,交叉拓扑上避不开。让 0.5 A 的那个换层:南西 / 南东各自从北边引一条底层干线。
|
||
|
||
### ⭐ 这一轮校核当场抓到的一个错:孤岛判定是**按铺铜对象**算的,不是按网络
|
||
|
||
第一版把 +12V 写成六个矩形,栅格连通性说「1 个连通域」,看着完全正常。
|
||
新加的孤岛规则校核报出来:`12V-RC`(右通道)**里一个 +12V 焊盘都没有** ——
|
||
哪怕它和北带紧挨着、铺出来是连续铜,它自己那一块里没有本网焊盘/过孔照样被整块删光
|
||
(边框还在、`nPoured` 是 0)。⇒ 并成三个 L / ⌐ 形多边形,每块各自含风扇座的通孔针。
|
||
|
||
另外两条:**只有通孔焊盘在内层挖反焊盘**(贴片对内层透明,板上实测 122 个通孔);
|
||
**区域间净距不能用包围盒估**(L 形的 `3V3-SE` 包围盒把 `12V-FAN` 整个罩住,
|
||
算出来 0.00 mm 像严重违规,实际相距 0.50 mm)。
|
||
|
||
### 下板还欠的几件(都不影响现在动手)
|
||
|
||
- **C2 / C3 罐高必须 ≤ 11.5 mm**(现在按 12.0 建模,`H_FP` 里那一条)。
|
||
载板底面在那块地方是光板,hmax = 12.0,卡着上限过;换一颗矮罐才有余量。§22.3f
|
||
- **CH2 的 `POGO2_*` 三根要横穿 60 mm**(信号在 J25、电源在 J24,载板那边决定的,§26.3)。
|
||
- U20 的天线端离下板边只有 1.5 mm,而且上面还盖着载板 —— **这块板的 WiFi 本来就指望不上**,
|
||
真要用就得把天线引出机箱。
|
||
- 北中块 x 58~118 / y 85~125 有一块约 60 × 40 的空地(CH2/CH3 的排线车道从这里过),
|
||
留给电源面和风扇线,暂时不填。
|
||
|
||
### 下板 v6 的布局长什么样(设计文档 §26.3 / §26.4)
|
||
|
||
```
|
||
y 125 ┌──────────────────────────────────────────────────────────────┐
|
||
│ P1-INPUT │ CH2 (北,rot180) │ P1B + P6 + J28 │ CH3 (北,rot180) │
|
||
│ J1/F1/Q1/D1 │ x 30.1~57.3 │ x 58~118 │ x 118.5~145.7 │
|
||
│ C2/C3/R9/U19 │ │ │ │
|
||
y 66 ├───────────────┴──────────────────┴────────────────┴─────────────────┤
|
||
62.5 │ ==== J24 (x 5.3~58.7) ==== ==== J25 (x 101.3~154.7) ==== │
|
||
y 59 ├───────────────┬──────────────┬─────────────────┬────────────────────┤
|
||
│ CH1 (南) │ CH4 (南) │ P3/P3B 控制块 │ CH5 (南) │
|
||
│ x 10.6~37.8 │ x 42.3~69.5 │ U20/U6/U21~23 │ x 121.8~149.0 │
|
||
y 0 └───────────────┴──────────────┴─────────────────┴────────────────────┘
|
||
J26/J27 左板边 J29/J30 右板边 J28 顶板边 J22 调试口在右板边
|
||
```
|
||
|
||
### 下板新加的工具(`.claude/` 下)
|
||
|
||
| 文件 | 用途 |
|
||
|---|---|
|
||
| **`pcb1_import.py`** | 下板「从原理图导入变更」:`--probe` 读全部变更行 / `--apply` 真的导 / **`--verify` 拿 PCB 元件表和原理图 BOM 逐条对账** |
|
||
| **`pcb1_parts_dump.py`** | 抓 `pcb1-parts.json`(每件的真实焊盘框 + 每个焊盘的本地坐标)。**导入变更之后必须跑** |
|
||
| **`pcb1_env.py`** | 把载板底面折算成下板的**高度预算图** `pcb1-env.json`(zones / lanes / slots / J24-J25 锚点);`hmap()` 打一张 ASCII 高度地图 |
|
||
| **`pcb1_place.py`** | 下板摆位模型 + 本地六项检查 + `--push` / `--verify`(回读焊盘核对插)|
|
||
| **`pcb1_clear.py`** | 拆掉下板全部铜(导线 / 过孔 / 铺铜边框),保留板框、M3 焊盘、丝印 |
|
||
| **`pcb1_rules.py`** | 下板设计规则:线宽 5 档 / 差分 1 对 / 铺铜全连接;**自动命名网按位号+引脚反查**。`--push` / `--check` |
|
||
| **`pcb1_place.DECAP`** | **去耦电容跟着本尊走**的事实来源(第十六轮加)。表里的电容不参与仿射摆位,芯片摆完之后自动贴到电源脚旁边;`check()` 里有硬校核 |
|
||
| **`pcb1_place.pad_clearance_errs()`** | 全板**焊盘到焊盘**净距(0.2 mm,照 DRC 那条规则)。「不重叠」不等于「够净距」 |
|
||
| **`FANOUT_WHY=U6.15`** | 环境变量。打印这个焊盘所有候选孔位**卡在哪一道校核上**,按次数排序 |
|
||
| **`p1_r9f1.py`** | P1-INPUT 换件(F1 → 12 A / R9 → R9A~R9E)。**增量**改法:先 create 后 delete、旗删掉重建、坐标全 5 的倍数、引脚坐标断言不过就停手 |
|
||
| **`p1_text_fix.py`** | P1-INPUT 文字去重 + 挪位。幂等(新增块也走「先删再建」),逐条对账最终 14 条 |
|
||
| **`pcb1_import.py --bom`** | 逐页重抓原理图 BOM(`_p1_sch_bom.json`)。**改过原理图先跑它再 `--verify`**,一页一个请求(`eda.py` 截 20000 字符)|
|
||
| **`pcb_fanout.guard_not_pushed_twice()`** | 板上已有过孔就拒绝 `--push`。这脚本**只加不删不幂等**,推两遍会叠出同坐标副本而**短线数和 DRC 都看不出来** |
|
||
| **`pcb1_pour.check_top_clearance()`** | 顶层手画铜面到异网铜的**真实几何净距**(不过格子)。0.25 mm 栅格漏得掉 0.1 mm 的侵入;**走线的圆头端帽比端点还往外探半个线宽** |
|
||
| **`pcb1_pour.poly_vs_rects()`** | 手写的复杂多边形 vs 它该等于的矩形并集,0.05 mm 逐格对照。写错一个坐标,别的检查一个都发现不了 |
|
||
| **`pcb1_pour.obstacles()`** | 板上已有的铜(438 过孔 + 441 走线)。**顶层铺铜要躲它们**,内层只躲过孔 |
|
||
| **`pcb1_route_pwr.py`** | 五路功率级手工布线的**事实来源**(§10.2 四条回路)。路径写在 CH1 母版局部坐标里,仿射到五路。不带参数 = 计划 + 五项校核;`--push` 下发(`--clean --push` 先删本轮旧线);`--verify` 按实测铜核**覆盖**;`--ch N` 只看一路 |
|
||
| **`pcb1_netlist.py`** | 下板连通性的**事实来源**:按实测铜(含回读的铺铜)算每个网络还欠几条。`--todo` / `--json` / `--refresh`(第二十轮加)|
|
||
| **`pcb1_route_sig.py`** | 下板信号布线器(**只加不拆**)。Kelvin 强制表 / USB 束+偏移 / 细栅格逃逸 / 铺铜当障碍 / `sw_keepaway()`(第二十轮加)|
|
||
| **`pcb1_escape_audit.py`** | 逐焊盘的**逃逸可达性**。「布不通」到底是这一头出不来还是中间挤,只有它分得清(第二十轮加)|
|
||
| `pcb1_reload.py` | 下板专用的客户端重载(DRC 的连接性那一支要 reload 之后才准)。⚠️ **别拿 `pcb2_reload.py` 当通用工具**:那一份写死载板 uuid,而且会把板上全部铺铜边框删掉 |
|
||
| `pcb_fanout._CH_FORCE_LOCAL` | 五路通道里必须**五路一样**的那几个孔(按 CH1 的解钉死再展开)。不钉的话 CH2/CH3 会往反方向扇 |
|
||
| **`pcb1_pour.py`** | 下板铺铜的**事实来源**:`REGIONS` 定义每一块。不带参数 = 计划 + 五类校核 + ASCII 分块图;**`--push`** = 校核跑绿才下发,完事自动回读复核;**`--verify`**(`--cache` 用上次回读)= 只按**实测铜**再跑一遍。下发前后走的是同一段 `grid_checks()` |
|
||
|
||
| **`pcb2_measure_sheet.py`** | 小米8 主板 **1:1 测量底板**(`shots/PCB2-measure-sheet.pdf`):干净底板 + 四个实心黑圆基准点(圆心矩形 160 × 110 mm)。描轮廓 + 每孔戳一点,拍照回来按基准点做单应反算,约 ±0.3 mm |
|
||
| **`pcb2_pdf.py`** | 载板 **1:1 打印用尺寸图 PDF**(`shots/PCB2-carrier-1to1.pdf`)。几何全从客户端实读(板框 / 槽 / 定位孔 / 主板投影),`pcb2_place.py` 的标称值只用来交叉校验。三页:整板 A4 横向、单站详图两种朝向、坐标表。每页带 100 mm 标尺防打印缩放;`--offline` 用上次的 dump |
|
||
|
||
⚠️ `pcb_rules.py` 是**单板时代**的,已被 `pcb1_rules.py` 取代,别再 `--push` 它。
|
||
⚠️ `pcb_fanout.py` **仍然是下板在用的**(`PCB = 7e94…`),载板的 `pcb2_fanout.py` 是它的壳。
|
||
|
||
⚠️ **载板上只有 6 个 M3 孔,`pcb2_place.py` 的 `MH` 表里有 8 个**(2026-09-06 出 1:1 图时实读发现)。
|
||
缺的是顶边两角 **(4, 131) / (216, 131)** —— 就是「两板尺寸取大对齐、四角定位孔对齐」那条要求加的那两个,
|
||
表改了但 `pcb2_place.py --outline` 没再跑(M3 孔归 `push_outline()` 管,不是 `--mech`)。
|
||
要补就跑 `--outline`(先删 `MH*` 再重建 8 个,顺带重画板框和 10 条槽),
|
||
跑完记得重新 `pcb2_clear` / DRC:那两个孔的 Ø6 焊盘离主板投影只有 0.34 mm。
|
||
|
||
⚠️ `pcb_place.py` / `pcb-parts.json` / `pcb-pads.json` 是**单板时代**的,别再拿来摆下板。
|
||
|
||
### ✅ 已拍板并落地:C745 往南挪 2.7 mm(2026-09-06,用户选 A)
|
||
|
||
`C745` 从 A 圈上的 (100.05, 61.70) 挪到 **(100.0, 59.02)**(`pcb2_place.hub_layout()` 里单列一条,
|
||
不再跟着 A 圈的 `for` 循环走)。GND 脚 (100.0, 58.60) / +3V3 脚 (100.0, 59.44),
|
||
扇出孔实际打在**正东** (100.87, 58.60),引线 0.65。
|
||
`pcb2_place --push` → `pcb2_clear`(跨元件净距全过)→ `pcb2_fanout --only C745.2 --push`
|
||
→ reload → pour → `inner1_verify`(五块岛仍各 1 连通域)→ DRC **115 间距(基线)+ 332 连接性**。
|
||
|
||
⇒ **载板上除了 J7n 那 65 个 GND 脚(归 `bm24_pre()` 管),贴片 GND 焊盘已经全部扇出。**
|
||
|
||
`pcb_fanout.py` 顺手加了 `--only 位号[.引脚],...`:板上已经有整轮扇出、只想补一两个漏网的时候用,
|
||
不会重复下发另外那 247 个。
|
||
|
||
<details><summary>当初为什么非挪不可(留作记录)</summary>
|
||
|
||
| 方向 | 挡住的东西 | 余量 |
|
||
|---|---|---|
|
||
| 南 | `UP_DM` 东行段 y=60.60(宽 0.28)| 孔要 0.64,只有 0.41 |
|
||
| 北 | 自己的 pin1 → 再往北是 U32 南排焊盘 y=63.55 | 缝 0.73,要 1.0 |
|
||
| 东 | R715 pin2 | 缝 0.667,要 1.0 |
|
||
| 西 | `UP_DM` 竖段 x=99.25 / `UP_DP` 竖段 x=98.75(相距 0.5)| 塞不下 Ø0.6 的孔 |
|
||
|
||
并到邻近同网焊盘也不行 —— 最近的 GND 是 C743 pin2(2.70 mm 外),中间横着这两条竖段。
|
||
</details>
|
||
|
||
### (已作废)等用户拍板:C745 的 GND 脚被 UP 差分对堵死
|
||
|
||
`C745`(Hub 的 +3V3_HUB 去耦 0402,GND 脚在 (100.05, 61.28))是全板**唯一**扇不出去的焊盘。
|
||
不是搜索不够狠,是几何上真的没有位置:
|
||
|
||
| 方向 | 挡住的东西 | 余量 |
|
||
|---|---|---|
|
||
| 南 | `UP_DM` 东行段 y=60.60(宽 0.28)| 孔要 0.64,只有 0.68−0.27=0.41 |
|
||
| 北 | 自己的 pin1(+3V3_HUB)→ 再往北是 U32 南排焊盘 y=63.55 | 缝 0.73,要 1.0 |
|
||
| 东 | R715 pin2 | 缝 0.667,要 1.0 |
|
||
| 西 | `UP_DM` 竖段 x=99.25 / `UP_DP` 竖段 x=98.75(相距 0.5)| 两条之间塞不下 Ø0.6 的孔;西边那条缝只有 0.01 mm 宽 |
|
||
|
||
并到邻近同网焊盘也不行 —— 最近的 GND 是 C743 pin2(2.70 mm 外),中间横着这两条竖段。
|
||
|
||
**三个选项**(都要改布局,所以留给用户定):
|
||
- **A. C745 转 90° 并东移到 (100.0, 61.7) 一带**(脚变成东西向,GND 脚在西)。
|
||
实算过:孔打在 (100.0, 62.47) 时离 UP_DM 竖段 0.75、离 U32 pin56 焊盘框 0.15,都过。
|
||
- **B. 把 UP_DM / UP_DP 那两条东行段整体往南挪 0.3~0.5 mm**(要重推 `pcb2_dp_long.py`,
|
||
下游 J23 那一头也要跟着动)。
|
||
- **C. 不管它** —— 那一颗去耦电容的地就只能靠 `pcb2_gnd_patch.py` 想办法,
|
||
想不出来就是一条连接性 DRC,实物上等于这颗电容白焊。**不推荐**。
|
||
|
||
### ✅ 这一轮(2026-09-06 第十三轮):**载板 77 个信号网络全部布通并下发,DRC 回到基线**
|
||
|
||
| | 结果 |
|
||
|---|---|
|
||
| `pcb2_route_sig.py` | **87 个网络 / 459 条路径 / 1030 线 / 210 孔**,一个没布通的都没有 |
|
||
| 本地净距校核 | 全部通过 ✔ |
|
||
| `pcb2_gnd_patch --check` | 板上悬空的 GND 连通域 **0 个** |
|
||
| `inner1_verify` | 五块岛各 1 主域、3 焊盘 + 11 过孔全在主域,最窄 29.20 / 7.05 / 7.20 / 7.70 / 7.60 |
|
||
| `pcb2_route_dp`(回归) | 11 对差分偏斜全部 ✔(最大 4.75 mm) |
|
||
| **DRC** | **115 条 = 全部是封装自带的「贴片焊盘到贴片焊盘」基线;间距 0 新增、连接性 0** |
|
||
|
||
⇒ **载板 PCB2 布线完成。** 截图 `PCB2-v6-routed-all.png` / `PCB2-v6-hub.png` / `PCB2-v6-site4.png`。
|
||
|
||
#### BM24 那一段是整个重写的(v4 的常量在 v5 上全错)
|
||
|
||
v5 把 J7n 从 rot 180 改成 rot 0 又挪了位置,站内坐标整体差
|
||
**`u' = u − 5.00` / `v' = 32.00 − v`(v 轴是镜像的)**。
|
||
照抄映射也不行 —— v 一镜像,「前排外侧那条缝」换到了另一边,而那边站着 R76n/R77n。
|
||
v5 的走法(和 v4 反过来,因为**后排 25 个脚在 v5 里全是 GND**,没有信号脚要往外挤):
|
||
|
||
- **前排 5 个 GND(pin 2/8/12/16/24)→ 往内进中央通道**,v=35.00 的 0.30 梳子,4 个孔(跳过 u 50.05)
|
||
- **后排 7 个 GND(pin 1/19/23/29/37/41/47)→ 往外**,v=33.10 的梳子,5 个孔(那一带一路空到 v 26)
|
||
- **pin52** 往东平出到 u=59.60 打一个孔
|
||
- **THERM / CC1 独占前排外侧**:CC1 一根直线上去(R76n 中心特意取 52.233,让 pin1 正好落在 J7n.22 正北);
|
||
THERM 打两个孔走顶层跨过 CC1
|
||
|
||
新增 `j7_assert()`:**每次跑都拿板上实际焊盘核一遍那一堆手写常量**(五个站 × 13 个 GND 脚 + THERM/CC1 + R76n/R77n)。
|
||
没有它的时候,坐标失配的表现是「在空地上画了五套梳子」—— 净距校核当然全过(空地不撞人),
|
||
只有 DRC 的连接性会含糊地多出几十条。
|
||
|
||
#### 这一轮修掉的四个真 bug(都在 `pcb2_route_sig.py` 里)
|
||
|
||
1. **搜索窗口边上没有墙**。障碍是裁到窗口里再栅格化的,**完全落在窗外的铜一格都不标**,
|
||
于是贴着窗口边走的线看不见它。实测 `SCL` 的窗口从 x=44.02 起,J31.6 的焊盘框(42.10~43.80)
|
||
整个在窗外,布线器就在 (44.10, 67.40) 打了个孔,离那焊盘只有 0.134。
|
||
改法:数组往外扩 `RIM=1.2` 标障碍,**再把外面这一圈整体标成占用** —— 可走区域不变,但看得见窗外的铜。
|
||
2. **钻孔间距不分网络,但 `viafree` 只看异网铜**。于是布线器紧挨着 `pcb2_dp_long` 已经打好的孔又打一个
|
||
((92.500,70.000) 与 (92.400,70.500) 中心只隔 0.510),DRC 报「钻孔到钻孔 8.1mil,应 ≥ 11.8mil」,
|
||
净距校核一声不吭。新增 `holefree` 距离场(**所有过孔、不分网络**)。
|
||
3. **手写前置段没有一开始就进障碍表**。原来只有 GND 的在循环里补进去,THERM/CC1/+3V3 的要等轮到自己 ——
|
||
排在前面的网络照样从这些手写坐标上碾过去。
|
||
4. **`+3V3_HUB` 上 `pcb2_dp_long` 画的三条会被静默删掉**。`push_sig()` 是「本脚本负责的网络整网删掉重画」,
|
||
而那三条被 D± 夹着、后面再也挤不进去。改成从**同一个事实来源**(`pcb2_dp_long.build`)取回来当前置段,
|
||
既让最小生成树知道那些焊盘已经连上,下发时也原样重画。
|
||
|
||
#### 四段手写坐标(栅格布线器进不去的地方,理由都写在代码注释里)
|
||
|
||
| 网络 | 为什么手写 |
|
||
|---|---|
|
||
| `THERM_n` | 出阵列后第一次拐弯的 v **只有 0.053 mm 的窗口**(下受前排焊盘、上受 `*_DPJ` 换层孔),而且那一段必须保持 0.11 |
|
||
| `+3V3_HUB` U32.52→U32.46 | pin46 在东排被 VBUS_DET/NONREM0 围死,唯一出路是往 QFN **肚子里**走(南排焊盘上沿与散热盘之间那条 1.6 mm 死带)|
|
||
| `+3V3_HUB` C750.1→R716.2 | R716.2 是最东那颗 +3V3 焊盘,南北被两个 GND 脚夹住,只能翻顶层斜拉过来 |
|
||
| `HUB_RST` / `VBUS_DET` | R709 与 R712 之间只有 **0.66 mm** 的缝。0.15 的线走得过去(上下各 0.23),但栅格判据要 0.371 而半缝只有 0.33 |
|
||
|
||
#### 一处已知的口子(不是错,是要记住的事)
|
||
|
||
`+3V3_HUB` 现在由 **`pcb2_route_sig.py` 下发**(含 `pcb2_dp_long` 那三条)。
|
||
⚠️ **再单独跑 `pcb2_dp_long.py --push` 会把 route_sig 布的整个 +3V3_HUB 删掉重画**(它按网络整删)。
|
||
要改差分的话,顺序是 `dp_long --push` → `route_sig --push`,不能只跑前一半。
|
||
另外 45° 化把那条顶层干线的近直角拐点切成了两个 **51°** 的转折(`sharp_corners` 报「切不动」)——
|
||
净距校核过、不是直角,属于可接受;但它意味着板上那条干线的几何**已经和 `pcb2_dp_long.py` 里写的不完全一样**。
|
||
|
||
#### 为此动的两处布局(都验过并重扇出)
|
||
|
||
- **R76n/R77n:v 37.15 → 38.0**,R76n 的 u 顺带改成 52.233。
|
||
理由:J7n 前排逃逸带原来只剩 0.58 mm,THERM 和 CC1 一个往东一个往北**必然交叉**,同层无解,
|
||
想让 THERM 翻顶层又打不下孔(要离前排 0.5 ⇒ v ≥ 36.80,又要离 R76n 0.5 ⇒ v ≤ 36.38)。
|
||
挪完逃逸带 1.43 mm,两条各走各的。挪之前先用新写的 `pcb2_del_box.py` 把 R77n.2 的旧扇出孔删掉。
|
||
- **C745 往南 2.7 mm**(用户拍板,见下)。
|
||
|
||
#### 新工具
|
||
|
||
`pcb2_del_box.py`:删掉指定框里某个网络的线与过孔(板坐标或**站内坐标**,站内会自动展开到五个位)。
|
||
板上的铜是好几个脚本各画各的,挪了元件之后那颗扇出孔就成了没人认领的孤儿 ——
|
||
谁的删除逻辑都不管,DRC 只报一条「过孔没连上任何东西」,很容易被当噪声放过。
|
||
判据是**完全落在框里才删**(半进半出一律不动)。
|
||
|
||
`pcb_fanout.py --only 位号[.引脚],...`:板上已经有整轮扇出、只想补一两个漏网的时候用。
|
||
|
||
### 上一轮(2026-09-06 第十二轮):GND 扇出 + VOn_P 进岛,两步都下发并复核
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | `pcb_fanout.py` 补三个缺口(见下);`pcb2_fanout.py --push` | **247 孔 / 122 短线**,只有 C745 pin2 扇不出去 |
|
||
| 2 | `pcb2_vo_vias.py` 扩到 35 个焊盘(补 `C8n1.1` 与 `J8n.1`,各 3 孔)并修出线层 | **55 孔 / 55 线**,净距全过、0 个直角 |
|
||
| 3 | `pcb2_reload` → `pcb2_pour --push` → `_refresh_geo` → `inner1_verify` | 五块岛各 **1 连通域**,3 焊盘 + 11 过孔全在主域;最窄 31.30 / 7.05 / 7.20 / 7.70 / 7.60(下限 7.0)|
|
||
| 4 | `drc_read --pcb2` | **450 = 间距 115(与基线一模一样,无新增)+ 连接性 335**(布线前 519,−184)|
|
||
| 5 | 截图 `PCB2-v5-fanout-all.png` / `PCB2-v5-fanout-site1.png` / `PCB2-v5-inner1.png` | |
|
||
|
||
#### 这一轮修掉的四个「一直在但没暴露」的 bug
|
||
|
||
- **扇出规划器从来不看板上已有的走线**(只看焊盘 / 过孔 / 钻孔)。下板做扇出时板上一根线都没有,
|
||
所以从没暴露;载板 v5 是先布了 178 条差分 + 3V3 才扇出的,不修的话过孔会直接压在 D± 上,
|
||
而**几何验证抓不到**(它只查连通性)。现在 `EXIST_LAYERS` 把 1/2/15/16 层的线全登记成障碍,
|
||
**线对线分层比、过孔对线不分层**(过孔贯穿)。
|
||
- **`dump_pads.py` 有 88 个焊盘认不到位号**:pad 坐标是干净的、pin 坐标带 1 µm 噪声,
|
||
两边各自 `Math.round` 到 0.01,落在 `.xx5` 上的值进了不同的桶。改成 Python 端最近邻配(容差 0.02),
|
||
846 个里认到 805(剩下 41 个是螺钉孔和手机定位柱,本来就不属于任何元件)。
|
||
**这个 bug 会静默传染**:J75 pin15/16 认不到主人,「J7n 的 GND 脚整批跳过」就漏掉两个。
|
||
- **第三遍「并到旁边的同网络焊盘」没有长度上限、也不查走线/钻孔**,实测把 C745 pin2
|
||
一路并到 **9.78 mm** 外的 J64 pin3(而且那是另一层的焊盘,画出来根本不通)。
|
||
现在 `LINK_MAX = 3.0`,并且要求目标是通孔焊盘或同层。
|
||
- **`pcb2_vo_vias.py` 的出线层写死 `L_TOP`**。v1 时代器件全在顶层没事;v2 之后 VOn_P 的 35 个焊盘
|
||
**全在底层**,照旧会画出 35 条悬在顶层、一头不搭焊盘的线 —— 而且 `fits()` 拿这个 lay 去筛障碍,
|
||
连净距校核都是照着空荡荡的顶层算的,一条都不会报。
|
||
|
||
#### 两处和上一轮的计划不一样(都是实算之后改的)
|
||
|
||
- **U32 pin13 的孔位没有钉在 (94.6, 71.4)。** 那个位置过孔放得下(西边走廊 x ∈ [94.59, 94.625]),
|
||
但**引线出不去**:pin13 与 pin14 之间只有 0.20 mm,斜着往西北一定切进 pin14 的净距圈;
|
||
平着往西的话过孔又躲不开 `USB5_DP` 的横段(y 69.75,只差 0.5 < 0.64)。
|
||
正解是往**东**打进 QFN 肚子里 —— 引脚环东沿 95.975 到散热盘西沿 97.600 有 1.625 mm 净宽,
|
||
自动搜索把 pin13 放在 (96.50, 70.25)、pin19 放在 (97.25, 71.50),离差分车道都在 2 mm 以上。
|
||
- **J7n 的 65 个 GND 脚整批不扇了**(`SKIP_PAD`)。它们是 `bm24_pre()` 手写死的两条梳子 + pin52 单独出线;
|
||
让自动扇出去碰的后果实测是「十个必然失败 + pin 1/2/52 三个『成功』的孔正好落在梳子和车道上」,
|
||
route_sig 还得写个删除框把它们收回去。
|
||
|
||
#### 一处对设计文档 §10.3 的有意偏离
|
||
|
||
§10.3 写的是「功率网络每个焊盘打 3 个过孔」。这一轮 `VOn_P` 只给
|
||
**`J8n.1`(这一路 4 A 的唯一去路)和 `C8n1.1`(2200 µF 主储能)各 3 个**,
|
||
`C8n2`~`C8n6` 仍是各 1 个 —— 全按 3 个来会往五块岛里再钻 50 个反焊盘,
|
||
最窄断面(下限 7.0)扛不住。这五颗只承担高频纹波,单孔 1~1.5 A 够用。
|
||
|
||
### 上一轮(2026-09-06 第十一轮):v5 差分布线全部落地
|
||
|
||
**详见设计文档 §25.16 补 6。** 走法表、顶层参考面、45° 斜段规矩都在那里,这里只记做了什么和踩了什么。
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | `pcb2_dp_long.py` 整个重写(v3 存 `obsolete/`):pair 1 直西、pair 2 正北、pair 3 绕 Hub 北边东行、**pair 4 整段顶层**、pair 5 绕北边再南下跨 UP、UP 底层直东 | 本地净距全过 |
|
||
| 2 | `SITE_J` 按 v5 站内坐标重写:DMJ 底层 45° 斜进、**DPJ 翻顶层**跳过去(两排之间只有 1.515 mm,孔只能落在 y 36.805~37.31)| 五站同构 |
|
||
| 3 | pin5 / pin10 两条 +3V3 车道 + 顶层干线一起画(被 D± 夹住,后面的布线器进不去);C747 → (88.2, 71.5)、C748 → (92.5, 71.2) | `pcb2_place --push`、`pcb2_clear` 过 |
|
||
| 4 | VO4 岛主体东界 89 → 87(顶层段不许跨岛边);`topref` 检查 0 处跨界 | reload → pour → `inner1_verify` 五块全 ✅ |
|
||
| 5 | `--push`:182 线 / 26 孔;DRC 634 = 间距 115(基线)+ 连接性 519 | 无新增间距错误 |
|
||
|
||
#### ⚠️ 这一轮踩到的
|
||
|
||
- **0.5 脚距的车道之间打不了孔**(孔要离两边车道各 0.645)。出 QFN 的次序只能是「最外侧先拐走,邻居走了才打孔」,
|
||
pair 4 的两个孔为此上下错 0.9、DP4 先抬 0.6 再打。想改走法先在纸上按这条排一遍。
|
||
- **`chamfer()` 不能对 45° 拐再切一刀**:切出来的 22.5° 小段向内挪 0.1,实测把 DP4 抬升段切进 pin10 车道净距圈。已改成转向角 ≤ 46° 不切。
|
||
- 上一版脚本里的 U32 坐标(x 105.55)是 v1 的,U32 早搬到 (100, 68) 了 —— 改布局后**所有写死坐标的布线脚本都要重推**,别只改一处。
|
||
- 同宽共线的两段下发后被 EDA 合并成一条(182 → 178),但**不同宽**的共线段(BM24 出线 0.11 / 0.20 / 0.28 三档)保留 —— 换挡点安全。
|
||
|
||
### ✅ 这一轮(2026-09-06 第八轮):载板 v4 —— 尾插槽到 J1401 正下方,J7n 到主板下方远处
|
||
|
||
**详见设计文档 §25.16「2026-09-06 补 3」。** 用户指令:尾插槽放在主板尾插接口下方;载板尾插座放在主板下方远处、50 mm 排线能到的地方;连接时排线走载板背面。
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | `SLOTS['tail']` → u 45~65 / v 1.4~4.4(J1401 正下方);`TAIL_LANE` u 44.6~62.6 / v 4.4~38.3 不放元件(`check()` 新增一条)| 本地检查过 |
|
||
| 2 | J7n → (53.5, 37.0) **rot 0**;U5n (49.8, 41.5, rot 180) / R76n (52.8, 39.15) / R77n (55.8, 39.15) 挪到 J7n 北边;J6n (62.5, 41);行 D 西移 4.5 | 离 H1 4.0 / H3 2.9,`pcb2_clear` 816 焊盘净距 ≥ 0.20 |
|
||
| 3 | `--outline --push --verify --heights` | 槽 10/10;J71 回读 pin51(VBUS) 西端 (52.47)、pin4/6 北排西端 (54.65/55.0, 121.06)、奇数排南 ✔ |
|
||
| 4 | `pcb2_reload` → `pcb2_pour --push` → `_refresh_geo` → `inner1_verify` | 五块岛各 1 连通域、焊盘全在主域,最窄 7.05 / 7.20 / 7.70 / 7.60 / 20.85(下限 7.0)|
|
||
| 5 | 截图 `PCB2-v4-bottom.png` / `PCB2-v4-ch1.png` | 自己看过:槽在 J1401 下、J7n 在远端、U5n 在北 —— **还要用户确认** |
|
||
|
||
#### 为什么 J7n 从 rot 180 改成 rot 0(不是拍脑袋)
|
||
|
||
排线只绕 u 轴弯(接口边一个 U 形回折 + 槽里一个台阶),不在面内转 ⇒ J7n 的触点图案是 J1401 图案的**平移**;
|
||
J1401 的 pin1/2 端(G1)在 +u ⇒ J7n 的 pin1/2 端要在 −u;封装 pin51 在本地 −X、底层翻层不改 x ⇒ rot 0。
|
||
v3b 的 rot 180 把 VBUS 端放到了东边,和 §24.3「VBUS 落到 −X 端」矛盾。翻面次数(回折 1 次、台阶 0 次)算出来公头朝 +z,正好插朝 −z 的 J7n。
|
||
剩下唯一没定的是封装奇/偶排分配(§24.3 镜像位),错了只改焊盘编号,D± 换到南排西端。
|
||
|
||
### 上一轮(2026-09-06 第七轮):载板 v3 + C8n1 换矮封装(槽位置已被 v4 取代)
|
||
|
||
**详见设计文档 §25.16 末尾「2026-09-06 补」。**
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | 槽挪到主板远端边(v 45.5~48.5),手机位内移 2.5,器件全部收进主板下方 | 本地检查 / 净距 / 镜像回读全过 |
|
||
| 2 | `pcb2_pour.py` ISLANDS v3:走廊主体 + 主板下方整条带,VO2/VO4 为顶层差分收边 | `inner1_check` / `inner1_verify` 五块全 ✅(最窄 7.05)|
|
||
| 3 | C8n1 → Rubycon 6.3TPV2200M10X10.5(C3828985):个人库建器件、`c4_site.py` 五页重画、PCB 导入 80+80 | 极性丝印核过(`PCB2-v3-c801.png`)|
|
||
| 4 | 为差分让位挪 C747/C748、U31 组、U34/C760、R721/722、R717/718 | 见 `pcb2_place.py` 注释 |
|
||
| 5 | 新工具 `pcb2_reload.py`(重载客户端解卡)、`pcb2_snapshot.py` | |
|
||
|
||
#### ⚠️ 这一轮踩到的
|
||
|
||
- **`lib_Device.create()` 返回 undefined 但器件已建出来**;`copy()` 从系统库复制返回 null 且真没建;
|
||
个人库内 `copy()` 可用;给个人库器件 `modify(association.footprint = 系统库封装)` 会把封装**复制进个人库**(新 uuid)。
|
||
建完一律 `search` + `get` 核对,别看返回值(skill §9y)。
|
||
- **铺铜「重建所有」在大量 API 改动之后必卡**(本轮三次),重载后一次就通 ⇒ `pcb2_reload.py` 然后 `--push`。
|
||
- `pcb2_place.py --push` 的 `modify()` 里 layer 和 x/y/rot 分两次下发(一次下发 rot 偶发不生效)。
|
||
|
||
### 上一轮(2026-09-06 第六轮):载板 v2 —— 全部到底层 + 穿线槽(已被 v3 部分取代)
|
||
|
||
|
||
|
||
**详见设计文档 §25.16。** 用户两条指令:正面器件全放背面并在背面重新布局;排线通过板内细长槽穿到载板。
|
||
中途补充:器件可以放到主板投影下方(底层),方便布线。
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | `pcb2_snapshot.py`:先把 v1 全部铜/元件抓成 `_pcb2_snap_topside.json` | 161 件 / 1586 线 / 416 孔 / 7 铺铜,可回滚 |
|
||
| 2 | 实测底层镜像语义(U51/J71/R761 翻到底层读焊盘再翻回来) | 本地 y 翻 → 再转 rot;两脚件 pin1 方向不变,SOT23/BM24 南北排对调 |
|
||
| 3 | `pcb2_place.py` 重写成 v2 | 顶层 20 / 底层 141;槽 10 条;C8n1 卧倒 keep-out;新增「压槽 / 螺钉头 / 顶层只许顶针」三项检查 |
|
||
| 4 | `--clean-copper --outline --mech --push --verify --heights` | 清 1416 线 + 416 孔 + 7 铺铜(另有 16 条漏网线第二遍才删掉);槽建 10/10;镜像回读全 ✔ |
|
||
| 5 | `pcb2_clear.py` | 跨元件净距全部 ≥ 0.20 |
|
||
| 6 | `pcb2-bottom-heights.json` | 底层 141 件高度图 + 10 条槽,给下板布局避让 |
|
||
|
||
#### ⚠️ 这一轮踩到的三条(都写进 skill)
|
||
|
||
- **底层元件的焊盘位置不能推**:翻层不是绕 y 轴镜像,是本地 y 翻。J23 用顶层那版的 rot 90 放到底层,
|
||
口会朝板内;改 rot 270 并把 R717/R718 的 y 对调,`--verify` 回读核过。
|
||
- **挖槽区域 = `pcb_PrimitiveFill.create(12, polygon)`**(layer 12 = MULTI)。跑道形用两段 90° 弧,
|
||
和板框一样逆时针、正角度。
|
||
- **批量 `delete()` 一遍删不干净**:1416 条按 `getAll()` 删完,回读还剩 16 条(旧 BM24 GND 梳子,
|
||
正好压在新槽上)。删除循环要跑到剩余为 0 再收。
|
||
|
||
### 上一轮(2026-09-06 第五轮):载板收尾 —— **已被 v2 整体作废,只留作历史**
|
||
|
||
|
||
|
||
**详见设计文档 §25.15。**
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | `.claude/pcb2_vo_vias.py`:25 个贴片电容各打一个过孔下到 Inner1 的岛 | 25 线 / 25 孔,**全部一段直线**,连接性 −31 |
|
||
| 2 | `.claude/pcb2_gnd_patch.py`:自己算出悬空的 GND 连通域再补孔 | 5 个域(`C749.2`/`R710.2`/`U32.19`/`J23.A1B12`/`J23.B1A12`)→ 6 线 / 5 孔,连接性 −10 |
|
||
| 3 | `.claude/pcb2_npth.py`:从铺铜反焊盘反解**封装自带的非金属化孔** | J23 里两个 **Ø0.600 @ (213.660, 59.100) / (213.660, 64.900)** |
|
||
| 4 | `inner1_verify.py` 加了**过孔**校核 | 五块岛 **5 焊盘 + 5 过孔全在主域**,最窄断面 7.20/9.10/10.15/7.35/7.60(下限 7.0)|
|
||
| 5 | `pcb2_gnd_patch.py --check` | 板上悬空 GND 连通域 **0 个** |
|
||
| 6 | DRC | **125** = 同封装内 115(与基线一模一样)+ 连接性 10 + 间距 0 + 物理 0 |
|
||
|
||
#### ⚠️⚠️ 这一轮最值得记住的:**封装自带的孔,API 一个都读不出来**
|
||
|
||
J23 的封装里有两个 Ø0.60 非金属化定位孔,正卡在 `A1B12`/`B1A12` 两个 GND 焊盘的外侧角上。
|
||
`pcb_PrimitivePad.getAll()` 里没有、`pcb_PrimitiveRegion`/`pcb_PrimitiveFill` 是空的、
|
||
`getPrimitiveByPrimitiveId('e55')` 返回空、`getPrimitiveAtPoint()` 只回最上面那条线。
|
||
**只有 DRC(「挖槽区域 到 导线」)和内层铺铜的反焊盘看得见它们。**
|
||
⇒ `pcb2_npth.py` 拟合铺铜环里的圆弧,用「已知过孔的反焊盘半径 − 过孔半径」标定净距
|
||
(实测 0.3583,234 个样本,离散度 0.005),再反推孔径。
|
||
|
||
#### 另外三条
|
||
|
||
- **净距校核只看铜,钻孔是另一条规则。** 第一版打的孔落在同网 `J23_4` 的**焊盘里**,
|
||
校核全过,DRC 报「钻孔 到 钻孔 距离 0mil」。同网的通孔焊盘/过孔都要按 `DRILL=0.33` 再判一遍。
|
||
- **金属化的槽孔焊盘和非金属化孔待遇完全不同**:线可以压在焊盘自己的孔上,
|
||
不能压在非金属化孔上。混在一起判的话,`J23.1`/`J23.4` 这种槽孔焊盘**连碰都碰不得**
|
||
(焊盘上任何一点离自己的槽都不足 0.80 mm)。
|
||
- **只加不删的下发必须记账。** `pcb2_gnd_patch` 把自己画的坐标存 `_pcb2_gnd_patch.json`,
|
||
下次先删再画。不记账实测多出一对旧坐标的过孔,而且新画的细线被 EasyEDA 并进旧的粗线里。
|
||
|
||
### ✅ 这一轮(2026-09-06 第四轮):栅格迷宫布线器,载板剩下的 77 个网络
|
||
|
||
**详见设计文档 §25.14。** 事实来源是 `.claude/pcb2_route_sig.py`(BM24 周围的车道
|
||
是手写死的几何,其余交给布线器)。
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | 新写布线器 `pcb2_route_sig.py` | 栅格 0.1/0.05/0.025 三档 + scipy 稀疏图 Dijkstra + 45° 整形;**产出过同一份 `check()`** |
|
||
| 2 | 77 个网络 | 431 条路径 / **991 段导线** / **160 个过孔**,净距校核全过 |
|
||
| 3 | BM24 的 65 个 GND 脚(§25.8 的待办)| 两条梳子 + 12 个过孔/站,**中央通道那 1.64 mm 是这一轮才用上的** |
|
||
| 4 | 抓到并修掉 `R76n` 装反 | rot 0 → **180**。不改的话五个站的 `VBUSn` 全布不通 |
|
||
| 5 | `+5V` 线宽 0.80 → **0.60** | §25.10 说了段电流 ≤0.6 A;0.80 在走廊里挤不过去 |
|
||
| 6 | `PWR1A` 的 `strokeWidthMin` 0.25 → **0.15** | `+3V3_HUB` 要穿 Hub 卫星圈 0.659 mm 的缝;载流够(420 mA / 0.15 mm 可载 ~0.8 A)|
|
||
| 7 | 布完线重新铺铜 | 不铺的话 DRC 多出 **445 条**「铺铜区域到过孔/钻孔」(新过孔没有反焊盘)|
|
||
| 8 | DRC | **166** = 同封装内 115(**与 §25.8 基线一模一样**)+ 连接性 51 + 间距 0 + 物理 0 |
|
||
| 9 | **45° 化**(用户拍板)| `sharp_corners` / `chamfer45` / `smooth_micro` 三个工具放在 `pcb2_route_dp.py`,两个脚本共用。差分对 10 → 0、信号线 72 → 0,**DRC 不变** |
|
||
|
||
#### ⚠️⚠️ 这一轮最值得记住的一条:**`expand()` 会静默丢掉路径末端的过孔**
|
||
|
||
`pcb2_route_dp.expand()` 打过孔的条件里有 `i + 1 < n - 1` —— **最后一个点被显式跳过**。
|
||
于是「走到目标正上方再换层落下去」这种路径,过孔没了,两层的铜各画各的、中间断开。
|
||
|
||
**三道校核全都抓不到**:净距校核只看撞没撞(断开当然不撞)、
|
||
`inner1_verify` 只看铜面、DRC 的连接性又要 `location.reload()` 才刷新。
|
||
|
||
踩到两次:布线器自己的路径断了 5 个网络;**手写的 `bm24_pre()` 断了 50 个 GND 过孔**
|
||
(DRC 里 GND 55 条,补上之后掉到 10)。
|
||
⇒ `_end_via()`:末点上有换层就补一个重复点,**所有**路径(含手写的)都要过这一道。
|
||
|
||
#### 另外三条(都写在 §25.14 里)
|
||
|
||
- **障碍要先胀 `QERR` 再栅格化**,否则距离场高估 0.08 mm,净距校核在下发前一刻才炸。
|
||
- **`location.reload()` 会被「离开该页面」确认框挡下来**(文档有未保存改动),
|
||
点「留在该页面」= 根本没重载,客户端仍卡在后台任务上,
|
||
于是 `铺铜管理器…` 点了没反应。**重载前先 `save()`。**
|
||
- **先给所有焊盘留好出线段再开始布线**(escape routing 先行),
|
||
否则先布的网络会把后布的网络出焊盘那 0.6 mm 占掉。
|
||
|
||
### ✅ 这一轮(2026-09-06):载板 Inner1 分割电源面
|
||
|
||
**详见设计文档 §25.11。** 事实来源是 `.claude/pcb2_pour.py` 的 `ISLANDS`,改铜面改那里再 `--push`。
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | 五块 `VOn_P` 岛 + GND 底填落到 Inner1 | 优先级 L15 `VO1<VO2<VO3<VO4<VO5<GND`(岛先占地盘)|
|
||
| 2 | 每条边界都按**具体那颗排母针的反焊盘**卡出来 | 9 条边界逐条列在 §25.11 的表里;最窄的颈是 VO3 的 **7.40 mm**(被 `J32.27`/`J32.35` 夹住)|
|
||
| 3 | 新脚本 `inner1_check.py`(下发前预测)| 按 ISLANDS 多边形 + 异网焊盘/过孔反焊盘栅格化,五块全过 |
|
||
| 4 | 新脚本 `inner1_verify.py`(下发后实测)| 读回 EDA 真吐出来的铜再栅格化:五块各 **1 个连通域**、5/5 本网通孔焊盘在主域,最窄断面 7.20/7.60/7.70/11.70/12.90 mm |
|
||
| 5 | 新脚本 `inner1_diffref.py`(§10.1)| 顶层 5 段 `*J` 差分下方**都只有 `GND-INNER1` 一块铜、覆盖 100%** —— 这条约束从「可以接受」升级成「已实测满足」|
|
||
| 6 | **查出铺铜默认是十字花连接** | 铜面把自己的焊盘挖空只留 4 条 0.254 mm 辐条 ⇒ 校核量到「0.3 mm」。给 VOn_P 挂 `PLANE-DIRECT`(`connectMode:1`)后铜面是一整块。见下 |
|
||
| 7 | `pcb2_rules.py` 收编该规则 | 新增 `PLANE_RULE` / `PLANE_NETS`,`--push` 建条目 + 指派,`--check` 十三项全过 |
|
||
| 8 | 新脚本 `shot_pcb_layers.py` | 只显示指定铜层截图(可带区域),截完自动恢复图层可见性 |
|
||
| 9 | DRC | **499** = 同封装内间距 115(**与基线一模一样**)+ 连接性 384 + 间距错误 0。连接性从 396 掉到 384,正是五块岛接上的那 12 处 |
|
||
|
||
截图 `PCB2-inner1.png`(整板)/ `PCB2-inner1-left.png` / `PCB2-inner1-right.png`(走廊两半,
|
||
能看清五块岛的轮廓和两条颈从排母针缝里穿下去/上来)。
|
||
|
||
#### ⚠️ 这一轮最值得记住的一条:**铺铜的「段数」不能当连通性判据**
|
||
|
||
`getState_PourFills()` 把一块铜面吐成十几个 fill,那多半是**切块**(相邻块共边)不是断开。
|
||
「17 段」既可能是一整块被切碎、也可能真碎成 17 座孤岛,**段数分辨不出来**。
|
||
唯一靠得住的是把所有环画进同一张栅格再做连通域 —— 这就是 `inner1_verify.py`。
|
||
而且十字花连接时那十几个 fill 里有一部分是 `fill:false` 的**描边辐条**(不是填充区),
|
||
只画填充区会得到假的断路。两个坑叠在一起,skill §9j-2 有完整实测表。
|
||
|
||
#### ⚠️ 另一条:优先级的步长是 2,不是 1
|
||
|
||
同层建 6 块铜面,回读的优先级是 **1,3,5,7,9,11**(同层只有一块时是 1)。
|
||
所以脚本里只能断言**相对次序**,不能断言「第 k 块 == k」——
|
||
`pcb2_pour.py` 第一版就是后者,白报了一次「优先级和计划对不上」。已改成断言次序。
|
||
|
||
### ✅ 这一轮(2026-09-05 夜):换件实施全部落地
|
||
|
||
**详见设计文档 §22.3f 末尾的实施清单 + 新的 §25.9。** 上一轮那三条硬约束消掉了两条。
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | **实测两颗新符号的引脚几何** | 公母**完全一样**:第 r 行 = pin 2r−1(左, cx−30)/ 2r(右, cx+30),第 1 行 y = cy+**95** |
|
||
| 2 | `p5_btb.py` 换件 | 器件换 `C55020601`;引脚公式 `r/41−r` → `2r−1/2r`;**`ROW0` 100 → 95**;补上「坐标必须是 5 的倍数」断言 |
|
||
| 3 | `c1_conn.py` 换件 | 器件换 `C5307344`;引脚公式和 `ROW0`(95) 都不用动 |
|
||
| 4 | P5-BTB / C1-CONN 重生成 | `verify_sch` 两页 PASS(C1-CONN 要带 `--nc c1-nets-nc.json`,U34.3 是有意悬空)· `xpage` 0 漏接 · `port_audit` 下板 513 / 载板 330 **可疑 0** |
|
||
| 5 | §22.2 逐针表重写 | 两块板**共用一张表**(`VO1_P` 两边都是 1/3/5 脚),旧的「两套编号」警告整节作废 |
|
||
| 6 | 载板 PCB 从原理图导入变更 | 只有 14 条:C1-CONN 那 7 个元件各一条「移除+增加」(整页重画 ⇒ UUID 全新)。**「包含设计规则」没勾**,11 条规则原样保留 |
|
||
| 7 | **五个 Ø10 电解整体上移 2.5 mm** | `BAND['c1']` 的 v:−11.0 → **−8.0**。见下,这是换件逼出来的 |
|
||
| 8 | 载板重摆 / 重扇 / 重铺 | 161 元件本地四项过 · `pcb2_clear.py` 816 焊盘过 · GND 扇出 **210 孔**(和换件前一样)· Inner2 重铺 **213 段** |
|
||
| 9 | DRC | 511 = 同封装内间距 115(**和基线一模一样**)+ 连接性 396(没布线)+ 其它 0 |
|
||
|
||
截图 `PCB2-carrier-v4.png` / `P5-BTB.png` / `C1-CONN.png`。
|
||
|
||
#### ⚠️ 换成通孔件逼出来的连锁改动:五个大电解必须上移
|
||
|
||
**直插排母 = 顶层也占位**,而 J31/J32 的焊盘区高 4.24 mm。
|
||
原来的走廊里,上排三站的罐底 y=68.25、下排两站的罐顶 y=66.95,**中间只剩 1.30 mm** ——
|
||
怎么摆都塞不进去(贴片排母时代它只在底层,所以从来没露出来过)。
|
||
|
||
罐体在服务带里 **u 5.75~18.25 这一段是独占的**(行 1/2/3 的件都从 u=21 起),
|
||
所以 v 可以一直收到「不进手机投影」为止(v ≤ −6.25)。取 **v = −8.0**(和行 2 齐平):
|
||
|
||
| | |
|
||
|---|---|
|
||
| 罐体边 → 手机板边 | **3.00 mm**(keep-out 边 1.75)|
|
||
| keep-out 边 → J31/J32 焊盘 | **1.63**(上排)/ **1.43**(下排)mm |
|
||
| 实测可行区间 | v ∈ [−9.0, −6.75] 本地四项全过,取中间偏保守 |
|
||
|
||
#### 这一轮踩到的三个坑(都已写死在脚本里)
|
||
|
||
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 三层还在。
|
||
⚠️ **板框是 layer 11 上的 `pcb_PrimitivePolyline`,不是 `Line`** ——
|
||
「剩余导线里有没有 layer 11」不能当板框还在的证据(第一版断言就是这么写错的)。
|
||
3. **通孔焊盘不需要扇出**:`pcb_fanout.one_net()` 的 `todo` 本来就带 `not p['hole']`。
|
||
所以 `SKIP_HDR` 直接关掉即可,J31/J32 那 80 个脚自己就是过孔,
|
||
§25.8 里「33 个 GND 脚扇不出去」这条**自动消失**。
|
||
|
||
### ⛔ 还剩的一条硬约束(另两条已解决)
|
||
|
||
~~1. C2~C6 压在 J24 位置上~~ / ~~3. 两板之间没有立柱位~~ —— 这两条是**下板**的事,
|
||
留到下板重排接口区时一起处理(下面「下一步」第 1 件)。
|
||
|
||
**`C2/C3` 重选时罐高必须 ≤ 11.5 mm**。现在的 `C22383480` 商城**一个参数都没标**,
|
||
§22.3d 那个「约 12 mm」是估的。⚠️ 别换成聚合物(低 ESR 会让输入滤波欠阻尼,同 §6.2 的理)。
|
||
|
||
### ✅ 追加一轮(2026-09-05 夜):排母逐针分配按几何重排
|
||
|
||
铺 Inner1 之前摸底,摸出 §22.2 那张「定稿」表和载板几何对不上,**用户拍板改(方案 A)**。
|
||
全过程见设计文档 **§25.10**,新的逐针表在 §22.2(事实来源仍是 `.claude/p5_btb.py`)。
|
||
|
||
**硬冲突**:排母南排前 16 位全是 GND 焊盘(Ø1.70 / 间距 2.54 ⇒ 缝里只剩 **0.44 mm** 铜网),
|
||
而 4 A 按 IPC 内层 0.5 oz 要 **6.97 mm** ⇒ **4 A 的电源面穿不过排母的地针行**。
|
||
09-04 那版偏偏把 `VO4_P`/`VO5_P` 放在 J32 的**北**排,它们的站却在排母**南**边。
|
||
|
||
**新规矩:北排喂北边的站,南排喂南边的站,一路都不许跨行。**
|
||
J31 正对 site1(北)+site4(南),J32 正对 site3(北)+site5(南),site2 取 J31 北排最右三针。
|
||
|
||
| | 09-04 | 09-05 |
|
||
|---|---|---|
|
||
| 五路 `VOn_P` 最远曼哈顿 | ~120 mm(VO4 要绕排母端头钻手机 2 底下)| **≤42 mm,全部同侧** |
|
||
| `+5V` | 3 针,Inner1 上要一条 150 mm 的横贯脊 | **10 针分散取电**,段电流 ≤0.6 A ⇒ **顶层走线即可,不占内层** |
|
||
| GND | 33 针 | 26 针(0.77 A/针)|
|
||
| Inner1 规划 | 5 岛 + `+5V` + `+3V3_HUB` + 底填 | **5 块 `VOn_P` + GND 底填** |
|
||
|
||
网络表一个都没变,只是落点变了。五路的「正对面 3 针 GND」(§15.4)一条不少,
|
||
`p5_btb.py` 的 `plan()` 逐行断言。
|
||
|
||
**原理图画法改了一处**:GND 也走 netport(不再画地母线)——
|
||
重排后 GND 散成若干段,每段配母线 + 地旗会让旗掉进相邻行的端口里(行距 10 / 旗高 15~20)。
|
||
|
||
验证:`verify_sch` 两页 PASS · `xpage` 0 漏接 · `port_audit` 下板 **544** / 载板 **361** 可疑 0 ·
|
||
载板导入变更 65 条全是 J31/J32 的「修改网络」(无元件增删)·
|
||
**PCB 上 80 个焊盘的网络和逐针表逐行比对一致** ·
|
||
重扇 210 孔 + Inner2 重铺 185 段 · DRC 518 = 同封装内 115(与基线一致)+ 连接性 403 + 其它 0。
|
||
|
||
### ✅ 这一轮(2026-09-06 第二轮):布线开工,连接器侧 5 对差分完成
|
||
|
||
**详见设计文档 §25.12。** 事实来源 `.claude/pcb2_route_dp.py`(`SITE_J` 是路径,同文件里带本地校核)。
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | **抓到并改掉一个摆位错误:U5n 装反** | `USBLC6-2SC6` 是直通器件,朝连接器那一排原来**背对着 J7n**。`BAND['u5']` rot 0→**180**。SOT-23-6 对称,6 个焊盘落在**完全相同的位置**,只是引脚编号对调 ⇒ 无新间距冲突 |
|
||
| 2 | 跑完整的返工流程 | 重摆 161 元件 → `pcb2_clear` 816 焊盘过 → GND 扇出 clean/dump/push **210 孔** → 重铺铜 → `inner1_verify` + `inner1_diffref` 全过,各项数字与改之前**完全一致** |
|
||
| 3 | **判定自动布线器在载板上不可用** | 配置逐条回读断言(所选网络 22 个 / 移除已有 / 只勾顶底层)之后跑:**只画出 J23 自己那两条 A6↔B6/A7↔B7,全板 0 过孔**,30 秒"跑完"。`pcb2_route_diff.py` 连同 `--rollback` 留着,别再试 |
|
||
| 4 | 新工具 `pcb2_route_dp.py` | 路径按**站内坐标**写一遍映射到五站;本地校核线-焊盘/线-过孔/线-线/过孔-×4,一般 0.20、对内 0.15;`--corridors` 扫底层横向走廊 |
|
||
| 5 | **5 对 `USBn_DPJ/DMJ` 布完** | DP 全程顶层 5.05 mm;DM 两端次序相反**必须交叉**,两个过孔沉底层穿过去,9.19 mm,偏斜 4.14(容差 5)。60 段导线 + 10 过孔 |
|
||
| 6 | 出线宽度按几何算死 | BM24 焊盘阵列里 **0.11 mm**(上限算出来是 0.1197,取 0.12 会差 0.00015 卡线);出阵列后两线还隔 0.35 时 **0.20**;分开后 0.28。`DIFF['strokeWidthMin']` 随之降到 0.10 |
|
||
| 7 | DRC | **479 = 同封装内 115(与基线一致)+ 连接性 364 + 间距错误 0** |
|
||
|
||
截图 `PCB2-dp-site1.png`(能看清 DPJ 走顶层、DMJ 沉到底层从它底下穿过去)。
|
||
|
||
#### ⚠️ 加完线和过孔**一定要重铺铜**再看 DRC
|
||
|
||
不重铺时刷出 **40 条间距错误**(「到过孔」20 +「到钻孔」20)——
|
||
那是铺铜还不知道新过孔、没让开它们。重铺之后 GND-INNER1 环数 217→227、
|
||
INNER2 330→340,正好是 10 个新过孔的反焊盘,40 条全消失。
|
||
|
||
### ✅ 这一轮(2026-09-06 第三轮):6 对长差分布完,载板差分对收工
|
||
|
||
**详见设计文档 §25.13。** 事实来源 `.claude/pcb2_dp_long.py`(坐标 + 逐条理由)。
|
||
|
||
决定全局走法的是 **x 112~116 那道隘口**:Hub 北边的 `C751`(1206,底层)
|
||
加 `C815` 的 GND 扇出孔,把北高速掐成「底层低窗 0.535 mm(1 对)」+「底层高窗」+
|
||
「**顶层**窗口 0.58 mm(1 对,C751 在底层所以顶层是通的)」;
|
||
南边被 Hub 的 A 圈 0402 封死(只剩 y≈56 一条缝)。
|
||
三对东行的只能一对一个窗口,而南北次序被 U32 的引脚次序锁死 —— 正好对得上,不用额外交叉。
|
||
**pair4 是全板唯一要横穿其它对的一对**,一出焊盘就上顶层南下。
|
||
|
||
新脚本 / 新用法:
|
||
|
||
/c/Python314/python .claude/pcb2_net_conn.py # 按实际铜算连通域(不看 DRC 面板)
|
||
/c/Python314/python .claude/inner1_diffref.py --routes # §10.1 沿实际走线逐点查参考面
|
||
/c/Python314/python .claude/_refresh_geo.py # 刷 inner1_* 三个脚本的输入缓存
|
||
|
||
#### ⚠️ 三个这一轮踩到的坑
|
||
|
||
1. **`drc_read.py` 不加 `--pcb2` 跑的是下板。** 第一次读到 649 条全是下板的网络。
|
||
2. **DRC 的连接性结果在程序化建线后是陈旧的,`location.reload()` 才刷新。**
|
||
刚下发报 403(每个网络还报 2~7 条"断开了连接"),重载后是 338 —— 比布线前少 26,正合预期。
|
||
间距错误那一支倒是即时的。
|
||
3. **45° 切角会把线甩进旁边焊盘的净距圈。** `chamfer()` 的 r 从 0.6 降到 0.35,
|
||
焊盘阵列附近还要多插一个共线点把切角压到 0.15~0.2。
|
||
|
||
### 下一步
|
||
|
||
| # | 做什么 | 备注 |
|
||
|---|---|---|
|
||
| 1 | **收尾 Hub 卫星圈那三段**(`+3V3_HUB` 2 段 / `VBUS_UP` 1)| **要用户拍板**:方案 ① `R711`/`R716`/`R720` 从半径 8.0 挪到 9.5(这三颗的 GND 扇出要重做;挪完走 §25.12 那套返工流程:`pcb2_place --push` → `pcb2_route_dp --dump` → `pcb2_route_sig --push` → `pcb2_gnd_patch --push` → `pcb2_pour --push` → reload → DRC)。`SCL`/`POGO5_VDN` 已通,`U34` 已挪。见 §25.15 末尾 |
|
||
| 2 | **下板 PCB 导入变更 + 接口区重排** | 删了 15 个连接器 + 53 个 7xx 器件,新增 J24~J30 / U33。J24 中心 (32, 62.5)、本体 53.34×5.08 会压到 `C2`~`C6`,必须挪;`C2/C3` 顺便重选(罐高 ≤11.5)。J24/J25 的 40 个焊盘**按 `pcb2-header-pads.json` 减 (30,5) 摆**,别按引脚号推理 |
|
||
| 3 | 让用户截图确认载板布线 | 已截 `PCB2-vo-vias-site1.png`(VO1 站的电容打孔)/ `PCB2-gnd-j23.png`(J23 那两个屏蔽脚)/ `PCB2-u34-j31.png`(U34 新位置)。⚠️ **EasyEDA 窗口必须在前台**,在后台时 `document.hidden = true`、画布不渲染,`getCurrentRenderedAreaImage()` 只回 88 字节的空 PNG |
|
||
|
||
### ⚠️ 2026-09-05 从实物照片新看出来的两条(都还没处理)
|
||
|
||
**1. ~~原厂排线长约 85~90 mm,只给了 3 mm 水平距离~~ → ✅ 用户 2026-09-05 拍板:不管,装配时折叠。**
|
||
照片上排线从主板下边缘一路走到尾插小板(板上印 `MAIN` + 箭头),
|
||
按主板宽 67.05 mm 标定,两个公头相距约 **87 mm**,而载板的 `J7n` 在 `v = −3.0`、
|
||
离手机板边只有 3 mm ⇒ 有 80 mm 以上的余量。
|
||
**用户原话「排线长度不用管,我到时折叠一下」** —— 所以 `J7n` 不为此挪位,
|
||
也不为此改 §13.5 的「台阶式下折」。留一条给装配:折叠的那一坨会占手机上方的高度,
|
||
定压板高度(`h_up`)时要把它算进去。
|
||
|
||
**2. `J7n` 并没有像注释说的那样「正对 J1401」,横向差 3.9 mm。**
|
||
`mi8_contacts.json`(卡尺校核过)记的 J1401 中心是 **u = 53.58**(长轴沿 u,占 47.46~59.71),
|
||
而 `pcb2_place.BAND['j7']` 是 **u = 57.5**。
|
||
不致命(软板本来就有余量、而且照片上原厂排线自己就是歪的),
|
||
但**不能直接改成 53.58** —— 那会和同一行的 `j6`(EDL 座,占 u 39.8~48.2)撞上 0.7 mm,
|
||
要连着 `j6` / `c3` 一起重排。和上面第 1 条一起决定。
|
||
|
||
✅ **BM24 的镜像位 2026-09-05 已实测(§24.3):结论是「不用改」。**
|
||
用户量出「G1 在右端 / 靠板边那一排是奇数排」,照片确认排线从板边直出,
|
||
所以载板 +Y 排(朝手机那一排)= 奇数排 ⇒ `ODD_ROW_TOP = True` 是对的;
|
||
顺带第二位(贴片方向)也自洽:VBUS 端落在 −X = 手机左端,和「52=GND / 51=VBUS」对上。
|
||
**打样前已经没有会导致重打板的未知量了。**
|
||
|
||
⚠️ 但同一批照片带出**两条新的机械问题**,见下一节。
|
||
|
||
---
|
||
|
||
### 上一轮:排母选型(2026-09-05,用户授权「你来定选型」)—— 已实施
|
||
|
||
**详见设计文档 §22.3f。** 两个占位到此全部消灭。
|
||
|
||
| | 型号 | 立创 | 关键参数 |
|
||
|---|---|---|---|
|
||
| **下板 J24/J25 公头** | AZ-PZ2.54-V11-2\*20P(宝讯)| **C55020601** | 塑高 **2.5**、配合针长 6、端接针长 3;3 A/针、**镀金**、直插 |
|
||
| **载板 J31/J32 母座** | PC104-2\*20(洲日)| **C5307344** | 塑高 **10.5**、行距 **2.54**、2.5 A/针、**直插** |
|
||
|
||
**对插 = 2.5 + 10.5 = 13.0 mm**(塑料对塑料定位),满足 §22.3d 的 ≥13 mm。
|
||
把库里「2.54 间距 + 标了塑高」的排母全扫了一遍,**10.5 mm 这一档只有 PC/104 一族**,
|
||
其余全是 8.3~8.5(对插只有 11 mm,够不到),而 2.54 双排排针的塑高全是 2.5,没法从公头补。
|
||
|
||
**改成插装是比高度更重要的收获**:80 个通孔脚本身就是过孔,
|
||
直接连 Inner1/Inner2 —— §25.8 里被迫跳过的「J31/J32 那 33 个 GND 脚扇不出去」自动消失。
|
||
|
||
(这一节原来的「三条硬约束」与「编号体系已实测」已经实施完,结论搬到文首「这一轮」和设计文档 §22.3f / §25.9。)
|
||
|
||
### 开工前必读(按顺序)
|
||
|
||
1. **`五路直供电源板设计.md` §22.7** —— 两个 Board 各有哪些页、位号怎么分、验证结果。
|
||
2. **§22.2**(J24/J25 逐针表 + **J31/J32 编号对照**)、**§22.4 末尾**(EDL 驱动与载板开关)、
|
||
**§22.6**(风扇 + TACH 分压)、**§13.5**(USB 最终走**方案 D**:原厂主板-尾插排线 +
|
||
载板上同型号 BM24 座;那里也留着已作废的方案 A / C 记录,和「买一块尾插小板当量具」的测法)。
|
||
3. `.claude/skills/easyeda-sch-geometry` —— **§9j-2 是最新一轮(Inner1)加的:
|
||
铺铜的焊盘连接方式 `connectMode` 藏在 DRC 规则里,默认十字花会让几何校核报假断路;
|
||
§9j 第 5 条补了「优先级步长是 2 不是 1」。** §9m / §9n / §9o 是换件那一轮加的:
|
||
包围盒不能在元件摆好之后重抓 / 通用 `clean()` 会删掉丝印 / 「从原理图导入变更」怎么读全。
|
||
§9j~§9l 是铺铜那三条,§6b / §6c / §6d 是「几何量必须读回、不能推」的血泪条目。
|
||
|
||
### 上一轮(2026-09-05):布线前置三件 + 一个必须记住的事实
|
||
|
||
**全部见设计文档 §25.7。** 这一轮**一根走线都没画**(用户拍板停在排母上,见上)。
|
||
|
||
| # | 做了什么 | 结果 |
|
||
|---|---|---|
|
||
| 1 | **载板设计规则整套下发** `.claude/pcb2_rules.py` | `--check` 十一项全过 |
|
||
| 2 | **11 对差分对**(不是 7 对)| 5 长段 + 5 短段 `*J` + UPSTREAM |
|
||
| 3 | **Inner2 整板地平面** | 一块 `GND-INNER2`,重建后 **81 块填充**,已存盘(`.claude/pcb2_pour.py`)|
|
||
| 4 | **两个中跨 M3** (76.6, 80.1) / (148.1, 80.1) | §25.6 ⑤ 那条待办关闭;`pcb2_clear.py` 816 焊盘全过 |
|
||
| 5 | **查清排母占位件是 SMD、排距 4.80** | 成了眼下的路障,见上 |
|
||
| 6 | **解决了「铺铜优先级设不上」** | 优先级 = 同层内的创建顺序,先建的赢;对照实验见 skill §9j |
|
||
| 7 | **GND 扇出** `.claude/pcb2_fanout.py` | **210 个过孔落盘**(全 GND,Ø0.610/0.305),出线 105 顶 + 21 底 |
|
||
| 8 | **查出 BM24 的一个硬约束** | 五颗 J7n 的 **65 个 GND 脚里 51 个打不下过孔**(0.35 间距),见 §25.8 |
|
||
| 9 | **DRC 基线** | 全部 551 = 同封装内间距 115(封装自带)+ 连接性 436(没布线)+ **间距错误 0** |
|
||
|
||
#### ⚠️ 看 DRC 只看「间距错误」那一支
|
||
|
||
「**同封装内间距错误**」那 115 条是 `J71~J75`(0.170 mm) / `U32`(0.125) / `J23`(0.200)
|
||
**封装自带的引脚间距**,安全间距规则 0.2 mm 比这几颗连接器自己的脚距还严,必然报,
|
||
三个数都在嘉立创四层工艺下限 0.1 mm 之上、可以打。
|
||
**别去调低全局安全间距来「修」它们**,那是把全板保护一起放掉。成因逐条见 §25.8 末尾。
|
||
|
||
**为什么差分对是 11 对**:载板上每一路 D± 被 ESD 器件 `U5n` 切成两段 ——
|
||
长段 `USBn_DP/DM`(U32 → U5n,走底层)+ 短段 `USBn_DPJ/DMJ`(U5n → J7n,约 5 mm,走顶层)。
|
||
两段都要建对,否则短段会按普通信号布、在 ESD 那头留一截不受控阻抗。
|
||
|
||
**中跨孔为什么放在手机之间的缝下(y≈80)而不是走廊正中(y≈67.5)**:
|
||
① 要支撑的是 y 85.5~130 那一排手机,80.1 离它 5 mm、67.5 差 18 mm;
|
||
② 走廊正中被 C811/C831 两个 Ø12.5 电解罐夹着,只剩 6.9 mm 高的缝,
|
||
净间距 2.90 mm;缝下那两处是 **5.28 mm**。
|
||
⚠️ 再往上会被顶针 J48/J52(y 87.96)逼住,y=83 掉到 2.41、y=84 只剩 1.41。
|
||
|
||
#### 这一轮踩到的四条 EasyEDA 坑(skill §9j~§9l)
|
||
|
||
1. **铺铜优先级是「数字小的先铺、占地盘」** —— 对话框底部自己写着。
|
||
下板 `pcb_pour.py` 里 GND=1 / 电源岛=5 **是反的**(那边铜面从不重叠所以没出事),
|
||
**抄到载板之前必须翻过来**(Inner1 是分割电源面 + GND 底填,全靠优先级互相裁)。
|
||
2. **`create()` 的 `pourPriority` 参数不生效** —— 优先级 = **同层内的创建顺序**。
|
||
⚠️ `modify()` 补设不生效还会把客户端弄卡死。
|
||
✅ **对照实验已做,规则确认:先建的赢。电源岛先建、GND 底填最后建。**
|
||
`pcb2_pour.py` 的 `plan()` 顺序就是优先级,`--push` 会回读断言。
|
||
3. **「重建所有」点了没反应 = 客户端卡在后台任务上**(窗口底部一条 0% 进度条),
|
||
`location.reload()` 后一次就通。⚠️ **重载会丢掉重载前建的铺铜边框,即使 save 过** ——
|
||
所以「建边框 → 重建 → 确认 → save」必须一气呵成。
|
||
4. **每个下发脚本必须自己 `openDocument`**:这一轮因为上一条命令开了 PCB1,
|
||
把**下板**的 14 块铜面重铺并存了盘(无损失,但两边返回值都看着正常)。
|
||
|
||
另记一条正常行为:`preserveSilos=false` 时区域内没有本网焊盘/过孔,整块会被当孤岛删光
|
||
(边框还在、填充是 0)。**所以扇出必须排在铺铜之前。**
|
||
|
||
### 上上轮(2026-09-05 凌晨):载板切 4 层 + 布线前四处返工
|
||
|
||
**全部见设计文档 §25.6。** 这一轮没加新东西,是把上一版摆位里四处会咬人的地方修掉 ——
|
||
四处**全部**是「原理图侧看不出来、包围盒检查也过」的那一类。
|
||
|
||
| # | 改了什么 | 为什么 |
|
||
|---|---|---|
|
||
| 1 | **载板 2 层 → 4 层** | 11 对 USB HS 要 90 Ω,两层板 1.5 mm 介质做不出来;20 A 没有内层电源面;两面都是元件面 |
|
||
| 2 | **J23 左口袋 → 右口袋** | §25.2 当初只核了下游。上游 J23(x5)→Hub(x110) 曼哈顿 **140 mm**,手册上限 152。挪完上游 104 / 最远下游 113 |
|
||
| 3 | **U31 (25,42) → (105,71)** | §22.7 写了「就近 Hub 供电是 PCB 摆位约束」,上一版没落实,离 90 mm。现在离 U32.pin64 **8.62 mm** |
|
||
| 4 | **Hub 26 件网格粗排 → 逐脚对位手排** | 见下 |
|
||
| 5 | **M3 孔 (8,127)/(212,127) 挪走** | 压在 CH1/CH3 手机本体投影里,其中一个和定位孔 P1H2 重叠 **0.93 mm** |
|
||
|
||
⚠️ **载板的层角色和下板是镜像的**:载板 `Inner1 = 电源面 / Inner2 = 完整地平面`,
|
||
因为 `U32` 在**底层**,所有长距离 D± 都从底层出发,底层的参考面是 Inner2。
|
||
反过来的话底层 D± 就以分割的电源面为参考。嘉立创四层 1.6 mm 叠层上下对称,
|
||
所以 **W0.28 / S0.18 照搬,不用重算**。
|
||
|
||
Hub 手排真正多做的事是**让出三条通道**(网格排法做不到):西侧扇出(10 根下游 D±)、
|
||
南侧竖井(XTAL + UP_D±,宽 2.16 mm)、晶振窝。实测对位距离:
|
||
RBIAS 1.43 / VDD18PLL 1.43 / 各 +3V3 1.46~2.30 / 配置电阻 1.4~3.2 /
|
||
晶振 4.95~5.76(**是通道的代价,不是疏忽**,负载电容贴端子 1.5~1.8 已做到)。
|
||
|
||
#### 新写的检查:`.claude/pcb2_clear.py`(焊盘级净间距)
|
||
|
||
/c/Python314/python .claude/pcb2_clear.py
|
||
|
||
按焊盘**真实形状**两两算净间距,分「同封装内」(只报负值)/「跨元件」(判据 0.2 mm)。
|
||
**M3 孔那个错误只有它抓得到** —— 自由焊盘不属于任何元件,
|
||
`pcb2_place.py` 的包围盒检查根本不看它们(成因写进 skill §9i)。
|
||
|
||
写它踩到两个 API 陷阱,都写进 skill 了:
|
||
- **§9g** 焊盘归属只能靠 `primitiveId` 前缀 —— `getState_ParentComponentPrimitiveId`
|
||
在 `getAll()` 回来的对象上**不存在**,try/catch 包住会静默地把所有焊盘当自由焊盘。
|
||
- **§9h** ⚠️ **焊盘的 rotation 是弧度、元件的是角度**。按角度判会把所有旋转过的
|
||
矩形焊盘长短边认反 —— J23 的 12 个信号焊盘被误报成两两重叠 0.3 mm(真实 +0.2)。
|
||
|
||
#### 本轮验证结果(全过)
|
||
|
||
pcb2_place.py 本地四项 + M3 孔断言 ✔ 161 元件(顶 133 / 底 28)
|
||
pcb2_clear.py 跨元件净间距 >= 0.2 mm ✔ 814 个焊盘
|
||
pcb2_clear.py 同封装内负间距 ✔ 0 对
|
||
铜层数 ✔ 2 -> 4(id 1/15/16/2)
|
||
|
||
截图 `PCB2-carrier-v2.png`。
|
||
|
||
### 上一轮(2026-09-04 晚)做完的两件
|
||
|
||
1. ✅ **顶针占位型号换掉了**:`C9900001338` → **YTC1P-2510-01(立创 C5221288)**,
|
||
配 **3.0 mm 立柱**(原来文档写的 2.0 mm **买不到**,见 §22.3e 的整族对照表)。
|
||
`c4_site.py` 已改,C4-SITE1~5 五页重生成,六项验证 + 跨页对账 + port_audit 全过。
|
||
2. ✅ **C1-CONN 抓到并修好一处真断线**:GND 旗写在 y=362,旗被吸附到 360、导线端点留在 362,
|
||
旗压在导线中段 → **J31 pin1 的地是断的**。`verify_sch` / DRC / 跨页对账全过,
|
||
只有 `port_audit.py` 抓得到。已在 `c1_conn.py` / `c4_site.py` 加「坐标必须是 5 的倍数」断言,
|
||
成因写回 skill §8a-2b。⚠️ **上一轮记的「可疑 0」不能当数,每轮都要重跑。**
|
||
|
||
### 上一轮(2026-09-04 深夜):USB 定为方案 D,载板改造已完成
|
||
|
||
**方案 D**(设计文档 §13.5):手机 J1401 ──原厂「主板→尾插」排线──
|
||
载板上一颗同型号 BM24-50DS 座 ──> 载板上的 USB 电路。
|
||
用户拍板:天线自己另买插主板上,麦克风 / 震动马达不要,「只要能开机正常运行系统就行」。
|
||
|
||
**载板改造做完了,三道验证全绿**(verify_sch 每页 PASS / xpage 0 漏接 /
|
||
port_audit 载板 330 个可疑 0、下板 513 个可疑 0):
|
||
|
||
| 页 | 改了什么 | 脚本 |
|
||
|---|---|---|
|
||
| **C5-J1401A / B**(新)| 五颗 **J71~J75** BM24-50DS 座(`C424561`),A 放 CH1~3、B 放 CH4~5 | `.claude/c5_j1401.py` |
|
||
| **C5-AUX**(新)| 每路 **U5n** USBLC6 ESD + **R76n** 56k(CC1→VBUS) + **R77n** 100k(口温→GND) | `.claude/c5_aux.py` |
|
||
| **C3-USB**(改)| **删掉 J17~J21** 五个 1.25mm 出线座;D± 不再经过这一页,只留 VBUS 负载开关 | `.claude/c3_usb.py` |
|
||
|
||
USB 链路现在是:`C2-HUB 的 U32 → C5-AUX 的 U5n → C5-J1401 的 J7n → 原厂排线 → 手机 J1401`。
|
||
NC 清单 `.claude/c5-nets-nc.json`(每颗座子 34 个悬空脚,含必须悬空的 CC2)。
|
||
截图:`C3-USB.png` / `C5-J1401A.png` / `C5-AUX.png`,都看过。
|
||
|
||
**调试串口(pin24 TX / pin29 RX)故意没引**:1.8V 电平接 ESP32 要加电平转换,
|
||
且 pin29 夹在两个地脚中间会把排版挤垮。要用是一次改板。
|
||
|
||
### 上一轮(2026-09-04 深夜):Board3 画完又作废 —— USB 方案改回 A(后又改成 D)
|
||
|
||
先按方案 C 画完了 Board3(J1401 转接小板),当晚用户确认「用排线连接」之后
|
||
**改回方案 A:装原厂尾插小板 + 一根改端子的 USB-A 转 C 线**。
|
||
Board3 / `phonerail-usbtap` / `PCB3-USBTAP` 已从工程删除,
|
||
生成脚本挪到 `.claude/obsolete/t1_usbtap.py`。理由对照表见设计文档 **§13.5**。
|
||
|
||
方案 A 当时是最优的,但用户随后提出「直接用原厂排线连主板和载板」——
|
||
那就是方案 D,比 A 更紧凑、电路全在载板上好改。**方案 A 已作废**,
|
||
它唯一的优势(保留天线馈点)被「用户自己另买天线」抵消了。
|
||
|
||
作废但仍有效的四条结论留在 **§23**:立创 BM24 封装编号是错的(同时佐证了 §13.4 的引脚表)、
|
||
BM24 只有 10 次插拔寿命、Rp/Rd 分压核算、以及两条 EasyEDA API 经验(skill §8b / §8c)。
|
||
|
||
### 上一轮(2026-09-04 深夜):BM24-50DS 封装自建完成
|
||
|
||
**下一步四件里的第 2 件做完了。** 器件在个人库:`BM24-50DS/2-0.35V(51) HRS-PIN`
|
||
(`771dbf002b714bb79cde47cf86aa0fb1`,封装 `940f093c1578426aa81e91ebf0bfbd76`),
|
||
`c5_j1401.py` 已改用它,C5-J1401A/B 重生成,**三道验证全绿**
|
||
(verify_sch 两页 PASS / xpage 0 漏接 / port_audit 载板 330 个可疑 0)。
|
||
生成脚本 `.claude/fp_bm24.py`,封装截图 `FP-BM24.png`。逐项尺寸与来源写在设计文档 **§24**。
|
||
|
||
几何**不是外推、也不是抄立创**:从 Hirose 官方样本(D47680_en)的 PDF 矢量图里
|
||
逐段反算的,50 芯的 A/B/C 表直接可用。信号焊盘 0.18 × 0.48 @ 0.35 间距、两排 y = ±1.06、
|
||
电源焊盘 0.49 × 0.76 @ x = ±6.03。
|
||
|
||
#### ⚠️⚠️ 但是多出一件必须做的事:**镜像位实测**(§24.3)
|
||
|
||
原来文档里写「两种候选正好差一个 180° 旋转,转贴片方向就能切换」——**这句是错的**,
|
||
候选有 **4 个**:2(1 脚在哪一端)× 2(**奇数脚在哪一排**)。
|
||
前一位靠旋转能纠,后一位是**镜像,错了要重打载板**(D+ 会落到 45 脚 `SPKR_OUT_P`)。
|
||
|
||
BM24 的 DS 座是**完全对称件**(Hirose 样本注 2:*no polarity*,本体两端与上下两排全一样),
|
||
所以「哪一排是奇数排」查图纸查不到 —— 它是**小米8 那块板的布局事实**,只能量。
|
||
|
||
**量法(两个探点,零成本零风险,打样前必做)**:
|
||
1. 两个电源触点(焊盘大好戳)分别对主板地量电阻,~0 Ω 的是 **G1 = 1/2 脚那一端**。
|
||
2. 从 G1 端数,两排各自的**第 2 个信号触点**对地量:通的那排是奇数排(pin3 = GND;
|
||
偶数排第 2 个是 pin4 = `VREG_L19A_3P0`,不通)。
|
||
|
||
结果若是「奇数排在 −Y」,把 `fp_bm24.py` 的 `ODD_ROW_TOP` 改成 `False` 重跑一遍即可。
|
||
|
||
### 上一轮(2026-09-04 深夜):载板 PCB 从零布起
|
||
|
||
**板框 220 × 135(R5 圆角)**,五块主板 **3+2 双排面对面、第二排居中**(用户拍板)。
|
||
原理图 161 个元件全部导入并摆好,本地四项检查全过(位号齐全 / 不越框 / 分层重叠 / 顶层不压主板投影)。
|
||
逐项见设计文档 **§25**,脚本 `.claude/pcb2_place.py`,截图
|
||
`PCB2-carrier-v1.png`(全板)/ `PCB2-site1.png`(CH1 位)/ `PCB2-j23.png`。
|
||
|
||
已落盘的东西:板框 1 条闭合多段线、载板自己 4 个 M3、**35 个手机定位孔(NPTH Φ2.5)**、
|
||
5 个手机位丝印外框 + 标签、161 个元件(顶层 133 / 底层 28)。
|
||
|
||
#### ⚠️ 抓到一个会让侧键永久短路的封装错误(§25.3)
|
||
|
||
立创给顶针 `C5221288` 的封装焊盘是 **Ø2.5**,而小米8 四个侧键触点最近的一对
|
||
(J601↔J604)只隔 **2.217 mm** —— 两个焊盘直接叠在一起,音量+ 会被永久按住。
|
||
顶针法兰其实只有 Ø2.0,是立创把焊盘开大了。**原理图侧完全看不出来**。
|
||
|
||
已自建 `POGO-SMD1P_D1.9`(焊盘 Ø1.9,净间距 0.317 mm),`c4_site.py` 改用新器件,
|
||
C4-SITE1~5 重生成、三道验证全绿、PCB 重新导入。
|
||
|
||
#### 三条布局上的硬决定
|
||
|
||
1. **J31/J32 排母在底层**(下板公头朝上,载板母座必须朝下)。
|
||
「第 r 行对第 r 行」不靠脑补:`--push` 会把载板侧 80 个焊盘坐标导出到
|
||
`.claude/pcb2-header-pads.json`,下板照数值摆即可(下板目标 = 导出值 − (30,5))。
|
||
2. **USB Hub 也在底层、压在通道正中 (110,67)** —— 放左右口袋的话最远那台 D± 要走
|
||
200+ mm,超 USB2517I 手册的 152 mm 上限;放中间后最长 92 mm。
|
||
⚠️ 布下板时别让 C2/C3(12 mm 电解)撞上载板底面的元件。
|
||
3. **35 个定位孔做 NPTH,立柱必须用尼龙** —— 金属化 + 金属立柱 = 五台手机的地
|
||
在载板上并成一根,4 A 回流会绕开专用 `P−` 针,违反 §6.4。
|
||
|
||
#### 载板这一版还欠的(详见 §25.5)
|
||
|
||
✅ J23 已定稿(rot=270、x=5.134,壳体前端面与板边齐平)· ⬜ Hub 那 26 个件是网格粗排、布线前要手调
|
||
· ⬜ 设计规则 / 铺铜 / 布线一根没做 · ⬜ 主板 7 个定位孔的孔径没量
|
||
|
||
### 上一轮写的「下一步四件」(第 1/2/5 件已完成,剩下的搬到文首)
|
||
|
||
| # | 做什么 | 备注 |
|
||
|---|---|---|
|
||
| 1 | ✅ **排母选型 + 换件实施全部完成**(2026-09-05 夜,见文首)|
|
||
| 2 | ✅ **自建 BM24-50DS 封装 + 镜像位实测**(§24.3)—— 全部完成,结论是当前的 `ODD_ROW_TOP = True` 就对 |
|
||
| 3 | **下板 PCB 导入变更** | 删了 15 个连接器 + 53 个 7xx 器件,新增 J24~J30 / U33,接口区要重排,最后统一重铺铜。⚠️ 下板的铜面 2026-09-05 被误重铺过一次(无损失,本来就要重做)|
|
||
| 4 | 🟡 **载板 PCB** —— 摆位 + 规则 + 差分对 + Inner2 地平面 + 6 个 M3 + GND 扇出 + 换件重摆/重扇/重铺 + **Inner1 分割电源面**都已完成。⬜ 只剩 **布线** |
|
||
| 5 | ✅ **载板上半部分的安装点** —— 已加两个中跨 M3 (76.6, 80.1) / (148.1, 80.1),§25.7 ③ |
|
||
|
||
改完照例:`verify_sch.py`(当前页)+ 跨页对账 + `port_audit.py`
|
||
(载板加 `--board Board2`),三个都干净了再让用户看截图。
|
||
**动 PCB 的话再加一条 `pcb2_clear.py`**(焊盘级净间距,自由焊盘只有它管)。
|
||
|
||
#### 载板布线的下一步,按顺序
|
||
|
||
1. ✅ **换设计规则** —— `.claude/pcb2_rules.py --push`,`--check` 十一项全过(§25.7 ①)。
|
||
2. ✅ **建差分对** —— **11 对**(5 长 + 5 短 `*J` + UPSTREAM),短段也建了对。
|
||
3. ✅ **Inner2 整板 GND** —— 一块 `GND-INNER2`,81 块填充,已存盘(`.claude/pcb2_pour.py --push`)。
|
||
4. ✅ **GND 扇出** —— `.claude/pcb2_fanout.py`,换件后已 clean → dump → push 重来一遍,
|
||
**210 个过孔**。J31/J32 那 33 个 GND 脚**不再需要扇出**(通孔件自己就是过孔,
|
||
`one_net()` 的 `todo` 带 `not p['hole']`)。
|
||
⬜ 只剩五颗 BM24 的 51 个 GND 脚(**过孔塞不进 0.35 间距,只能逃逸布线**,§25.8)。
|
||
5. ✅ **Inner1 分割电源面** —— **2026-09-06 铺完**(五块 `VOn_P` 岛 + GND 底填,
|
||
§25.11 / `pcb2_pour.py` 的 `ISLANDS`)。三个校核脚本全过:
|
||
`inner1_check.py`(下发前预测)/ `inner1_verify.py`(下发后实测,最窄颈 7.20 mm)/
|
||
`inner1_diffref.py`(§10.1 参考面)。
|
||
⇒ `+5V` / `+3V3_HUB` / `VOn_P` 的扇出现在可以做了(之前扇过去全是悬空过孔)。
|
||
6. 🟡 **布线** —— 先 D±(长的先走),再电源,最后杂散信号。
|
||
⚠️ **BM24 的逃逸布线单独排一项**:前排往南、后排往北,同排横向穿不过去(净距 0.17 mm)。
|
||
|
||
#### Inner1 分割电源面的规划(⚠️ 这是 09-05 的规划稿;**落地结果与实测见设计文档 §25.11**)
|
||
|
||
**层角色**:Inner1 = 电源面(分割),Inner2 = 完整地平面(§25.6 ①,和下板是镜像的)。
|
||
|
||
**只做三类岛,其余全部 GND 底填**(不是原来写的「+5V / +3V3_HUB / VO1~5_P / VBUS1~5」
|
||
十二块)——理由是内层是 0.5 oz,按 IPC-2221 内层算 4 A 要 **6.97 mm** 净宽、
|
||
2.8 A 要 **4.3 mm**,而两排手机之间的走廊(y 49.66~85.5)只有 35.8 mm 高:
|
||
|
||
| 岛 | 网络 | 为什么要 | 最小颈宽 |
|
||
|---|---|---|---|
|
||
| 5 块 | `VO1_P`~`VO5_P` | 每路 4 A,这是上四层的头号理由 | ≥7.0 mm |
|
||
| 底填 | `GND` | 剩余全部,**优先级数字给最大** | — |
|
||
|
||
> ⚠️ **2026-09-05 夜简化:`+5V` 和 `+3V3_HUB` 两块岛取消了**(§25.10)。
|
||
> 排母逐针分配按几何重排之后,`+5V` 从 3 针变成 **10 针、分散在两颗排母的南北四处**,
|
||
> 每个入口只喂本站的 `U2n` + `C70n`、段电流 ≤0.6 A ⇒ **顶层 0.5~0.8 mm 走线就够**,
|
||
> 内层不用给它留地方。`+3V3_HUB`(420 mA、局部)同理。
|
||
> ⇒ Inner1 只剩「**五块 `VOn_P` + GND 底填**」,五路 4 A 各走各的,互不挤。
|
||
|
||
|
||
**`VBUS1~5` 不做岛**:每口 0.5 A、走线只在本服务带内约 18 mm,`PWR1A`(0.6 mm) 走线足够。
|
||
额外好处:顶层那 5 段 `*J` 差分(U5n→J7n,5 mm)下方的 Inner1 就是**完整的 GND 底填**,
|
||
参考面比分割的电源面干净得多(§25.7 ① 那条警告因此自动消解)。
|
||
|
||
**走廊里已知的障碍**(Inner1 只怕直插焊盘,不怕表贴件):
|
||
`C801/C811/C821` 三个 Ø12.5 电解在 y 68.25~80.75,`C831/C841` 在 y 54.41~66.91,
|
||
两个新中跨 M3 的 Ø6 焊盘在 (76.6, 80.1) / (148.1, 80.1),
|
||
外加 J31/J32 的 **80 个通孔焊盘**(坐标已定稿:J31 x 37.869~86.129 / J32 x 133.869~182.129,
|
||
两行 y = 66.23 / 68.77,见 `pcb2-header-pads.json`)。
|
||
⚠️ 2.54 间距的通孔在内层会把铜面打成筛子(Ø1.7 焊盘 + 0.2 净距 ⇒ 相邻反焊盘之间只剩 0.44 mm 网),
|
||
电源岛的颈宽要绕开这两条带,别指望从排母底下横穿过去。
|
||
|
||
### 还欠用户的五件事
|
||
|
||
0. ~~BM24 的镜像位实测~~ → ✅ **2026-09-05 已完成,结论「不用改」**(§24.3)。
|
||
可选的零成本复核(还没做):奇数排上从 G1 端数,位置 17-18-19 与 22-23-24 各自三连导通
|
||
(`SPKR_OUT_N` 33/35/37 和 `SPKR_OUT_P` 43/45/47),偶数排没有这种三连。
|
||
0b. ~~量排线两个公头之间的距离~~ → ✅ 用户拍板不管,装配时折叠(余量约 80 mm,会占手机上方高度)。
|
||
1. **h_up**:主板**正面**(朝上那面)最高元件高出板面多少。只影响压板高度与整机层高。
|
||
2. ✅ **排针/排母选型已定**(§22.3f):`C55020601` + `C5307344`,对插 13.0 mm。顶针已定稿。
|
||
⬜ **到货要核两件**:母座触头镀层(商城只写了「黄铜」,没写镀层)、
|
||
对插后实测板间距是否真的 13.0 mm(确认是塑料贴合、不是针先顶死)。
|
||
2b. **首件上电前量一次**:`VBUSn` 对 GND 的电阻(确认电源触点 G1/G2 没接反,§13.5)。
|
||
负载开关默认关断,所以这一步零风险、零成本。
|
||
3. **顶针首件必验**:±1 mm 公差链对 1.2~2.2 mm 的侧键触点是危险的,而且
|
||
**选定的顶针冠径只有 Ø0.9 球头、又是贴片不可调**,所以首件实测是**唯一**对策(§22.3c)。
|
||
4. **用卡尺重量那 7 个定位孔**:±1 mm 里有 ±0.5 来自「孔位是从照片提的」,
|
||
量一遍能直接砍掉一半误差 —— 这是眼下性价比最高的一项。
|
||
|
||
---
|
||
|
||
## 这一轮做了什么(2026-09-04 傍晚,载板画完)
|
||
|
||
### 载板 8 页
|
||
|
||
`C1-CONN`(排母 J31/J32 + U31 5V→3.3V + U34 LM75BD 温度芯片 0x48)、
|
||
`C2-HUB`、`C3-USB`、`C4-SITE1~5`(每台手机一页:P+/P− 焊盘 + §6.3 电容组 +
|
||
4 根侧键顶针 + EDL 座/模拟开关/下拉/去耦)。逐页内容与位号见 §22.7。
|
||
|
||
**手机位一台一页**,和下板「一路一页」保持同一结构;五页由 `.claude/c4_site.py`
|
||
同一段代码生成,改一处五页一起变。
|
||
|
||
### 这一轮自己发现并补上的两个洞
|
||
|
||
1. **`UP_VBUS_DET` 在载板上没有源头。** §22.2 给它留了一根排针,但 J23 的 VBUS 是 5V,
|
||
排针那头是 3.3V 域的 IO44。在 C2-HUB 上补了 **R721 10k / R722 20k 分压**(3.33V)。
|
||
2. **载板上原来没有 3.3V。** 排针只送 +5V,而 Hub、温度芯片、五颗 EDL 开关都要 3.3V。
|
||
U31 从下板搬过来后画在 **C1-CONN**(+5V 进来的那一页);§9.5 要求的「就近 Hub 供电」
|
||
是 PCB 摆位约束,与分页无关,已在文档里说清楚。
|
||
|
||
### 两个明知不对、故意先放着的占位型号(⚠️ 顶针那条已于当晚解决,见文首)
|
||
|
||
| 占位 | 差在哪 |
|
||
|---|---|
|
||
| ~~顶针 `C9900001338`~~ ✅已换 | 自由高 **9.0 mm**,§22.3e 要的是工作高 2.0 / 自由高 3.0~3.5 / 冠径 Ø1.5~2 |
|
||
| 排母 `C9900025309` | 高度没按 13 mm 净空选;而且编号体系和公头不同(§22.2 有对照表)|
|
||
|
||
放占位是为了让网表先连通、能跑完整验证;**两个都在 §22.7 里单列了一节,打样前必换。**
|
||
|
||
### ⚠ 一个必须记住的编号陷阱
|
||
|
||
下板公头(DIP 式)第 r 行 = 引脚 r / 41−r;载板母座(IDC 奇偶式)第 r 行 = 引脚 2r−1 / 2r。
|
||
**只能按行对,不能按引脚号对**(`VO1_P` 在下板是 1/2/3 脚,在载板是 1/3/5 脚)。
|
||
原理图这边不会错 —— `c1_conn.py` 直接 import `p5_btb.py` 的行表,两边同一个事实来源。
|
||
**风险在 PCB**:焊盘编号 + 摆放镜像决定第 r 行会不会真对上第 r 行,布板时要实打实核一次。
|
||
|
||
### 新踩的两条 EDA 坑(已写进 skill §6c / §6d)
|
||
|
||
1. **同一颗电解、同样 `create(270)`,在两个图页里 pin1 方向相反。** 方向表一张都别信,
|
||
极性元件放完必须断言(`c4_site.py` 里断言「电解 pin1 的 y 必须大于 pin2」)。
|
||
2. **红黑两个测试点的引脚偏移不一样**(−20 / −10),按名义值算线会画出斜线,
|
||
而 `create()` 对斜线直接抛 `create failed!` 并让整批下发中途断掉。
|
||
现在下发前统一断言「横平竖直且非零长度」。
|
||
|
||
---
|
||
|
||
|
||
## 状态一览
|
||
|
||
| 阶段 | 状态 |
|
||
|---|---|
|
||
| 方案设计 | ✅ 定稿 v1.6(`五路直供电源板设计.md`) |
|
||
| 小米8 侧接口引脚定义 | ✅ 已从原理图逐脚追踪(设计文档 §13) |
|
||
| 器件选型 | ✅ 全部立创有货,UUID 缓存在 `.claude/eda-parts.json` |
|
||
| **P1-INPUT** | ✅ **补完输入侧 INA226(U13+Rs6+C11,§19),六项验证全过,需重新看一眼** |
|
||
| **P2-CHANNEL(CH1)** | ✅ **已删 J2/J7,侧键漏极改挂 `POGO1_*` 端口**,六项全过 |
|
||
| **P2B-CH2 ~ P2E-CH5** | ✅ **同样删了 J3~J6 / J8~J11,改挂 `POGO2~5_*`**,各自六项全过 |
|
||
| **P3-CONTROL** | ✅ 画完,六项验证全过,**等用户看截图** |
|
||
| **P3B-EXPAND** | ✅ 画完,六项验证全过,**等用户看截图** |
|
||
| ~~P4-USB~~ | ➡️ **已整页搬到 Board2 载板,改名 C3-USB**;下板已删 |
|
||
| ~~P4B-HUB~~ | ➡️ **已整页搬到 Board2 载板,改名 C2-HUB**;下板已删。⬜ 还要在载板上补 U31 |
|
||
| **P1B-5V** | ✅ **已摘掉 U31 + C736/C737**(跟 Hub 一起上载板),现在是纯 12V→5V,9 元件,六项全过 |
|
||
| **P5-BTB**(原 P5-HARNESS)| ✅ **整页重画**:J24/J25 两条 2×20,47 信号 + 33 地,六项全过(截图 `P5-BTB.png`)|
|
||
| **P6-FAN-EDL** | ✅ **新建**:U33 第三片 595(EDL_EN1~5)+ 风扇低边驱动 + J26~J30,六项全过(截图 `P6-FAN-EDL.png`)|
|
||
| 跨页网络对账 | ✅ 下板 11 页 **0 漏接 / 0 待补**;✅ 载板 62 个网络 **0 漏接** |
|
||
| `port_audit.py` | ✅ 下板 513 个、载板 260 个,**可疑 0 个**(载板加 `--board Board2`)。⚠️ 2026-09-04 晚重跑时载板曾报 1 个(C1-CONN 的 GND 旗),已修 —— **每轮都要重跑,别信上一轮的数** |
|
||
| **Board2 载板原理图** | ✅ **8 页全部画完**:C1-CONN / C2-HUB / C3-USB / C4-SITE1~5,六项验证 + 跨页对账 + port_audit 全过 |
|
||
| **Board2 载板 PCB** | 🟡 4 层 / 220×135 板框 / 35 个定位孔 / **6 个 M3**(含 2 个中跨)/ 161 个元件已摆完(§25、§25.6、§25.7);⬜ 未布线 |
|
||
| **Board2 载板 GND 扇出** | 🟡 **210 个过孔已落盘**(§25.8),脚本 `pcb2_fanout.py`;⬜ 差 J31/J32 的 33 个(等换件)+ BM24 的 51 个(要逃逸布线)|
|
||
| **Board2 载板 设计规则** | ✅ **整套已下发,`pcb2_rules.py --check` 十三项全过**(四层能力集 / PWR4A·PWR5V·PWR1A / 11 对差分 / USBPAIR 0.15 / 12 个网络指派 / **`PLANE-DIRECT` 铺铜全连接 + 5 个网络指派**)|
|
||
| **Board2 载板 铺铜** | ✅ **两层内层都铺完**:Inner2 整板 GND + **Inner1 五块 `VOn_P` 岛 + GND 底填**(§25.11)。脚本 `pcb2_pour.py`(`ISLANDS` 是事实来源,`--verify` 回读)+ 三个校核脚本 `inner1_check` / `inner1_verify` / `inner1_diffref` |
|
||
| **BM24-50DS 封装** | ✅ **自建完成**(§24),个人库器件 `771dbf00…`,几何来自 Hirose 官方样本。⬜ 镜像位待实测(§24.3)|
|
||
| **PCB 转板** | ⚠️ **已过期**:原理图这一轮删了 15 个连接器 + 53 个 7xx 器件、新增 J24~J30/U33,**还没导入变更** |
|
||
| PCB 板框 | ✅ **160 × 125 mm**,四角 R5 圆角 + 4 个 M3 金属化定位孔(接 GND)|
|
||
| PCB 布局 | 🟡 **第五遍:8 A 输入链整条重排(见下),等用户看 `PCB-layout-v5.png`** |
|
||
| 设计规则 | ✅ **整套已下发,`--check` 七项全 OK**(能力集 / PWR4A / PWR12V / 差分对 / 0.2 mm 间距 / 7 对 / 12 个指派)。上一轮说的「只能手动」是错的,见下 |
|
||
| **PCB 板框** | ⚠️ **改成一条闭合 polyline 了**(原来的 4 直线 + 4 圆弧自动布线器不认,见下)|
|
||
| 设计规则 | ✅ 等长容差 5 mm;新增 `USBPAIR` 0.15 mm,**只挂在每一对自己的两个网络之间** |
|
||
| 铺铜 | ✅ **19 块**(新增 `+5V` / `+3V3_HUB` / `+3V3`×2),三条低压轨的 91 个焊盘已扇出 |
|
||
| **7 对 USB 差分** | ✅ **6 / 7 布通**(USB1~5 + UPSTREAM)。⬜ 只剩 ESP32 调试口 `USB_DP/DM` |
|
||
| PCB 布线 | 🟡 **1208 过孔 / 5814 导线已落盘**(save 后重开验证过)。⚠️ 铺铜是旧填充、接口区马上要大改 —— **先别继续布** |
|
||
| Kelvin / 灌铜网络的漏网焊盘 | ⬜ **要手工布**:INA226 的 VIN±、五路泄放电阻 R*19、输入侧 U13 —— 5 mΩ 分流器满量程才 20 mV,多 1 mΩ 走线就是 20% 误差 |
|
||
| GND 漏网焊盘 | ⬜ 20 个(459 个扇出过孔之外的)|
|
||
| 丝印整理 | ⬜ 位号大面积压字,打样前要单独跑一遍 |
|
||
| **原理图 SCL 断线** | ✅ **U13 的 SCL 压在导线中段、根本没接上,已修**(设计文档 §19.4)。新增全工程扫描 `.claude/port_audit.py` |
|
||
| **板载 USB Hub 改造** | ✅ **原理图 + PCB 布局都做完了** |
|
||
| **两板架构(2026-09-04 拍板)** | ✅ 设计文档 §22 定稿;✅ **下板原理图改造已做完(§22.7)**;⬜ 载板 C1-CONN 未画 |
|
||
| **上板(载板)** | ✅ 原理图 8 页画完;⬜ PCB 还是空板;✅ 顶针已定稿 YTC1P-2510-01;⬜ 只剩排母占位(§22.7)|
|
||
| 散热 | ✅ 定稿 + **电路已画**(P6-FAN-EDL:Q6/D2/J26~J30 + TACH 分压)。⬜ 风扇型号未定(若选 4 线风扇,§22.6 那段 MOS+分压可整段删)|
|
||
| 小米8 主板机械数据 | ✅ **全部到手**:44.66×67.09 实测、7 个定位孔 ±0.5、触点 ±0.3(§22.3)。数据在 `.claude/mi8_mech.json` / `mi8_contacts.json` |
|
||
| **EDL(9008) 控制口** | ✅ **两侧都画完**:下板 U33(第三片 595)→ `EDL_EN1~5` → 排针 → 载板 U41~U45(TS5A3157DBVR)+ J61~J65(1.25mm 2P)+ R741~R745 下拉 |
|
||
|
||
下板原理图 **11 页**(顺序已排):
|
||
P1-INPUT / P1B-5V / P2-CHANNEL / P2B-CH2 / P2C-CH3 / P2D-CH4 / P2E-CH5 /
|
||
P3-CONTROL / P3B-EXPAND / **P5-BTB** / **P6-FAN-EDL**。
|
||
|
||
载板原理图 **8 页**(顺序已排):
|
||
**C1-CONN** / C2-HUB / C3-USB / **C4-SITE1~5**。
|
||
|
||
截图:**12 页里已截 10 页**(缺 P2B/P2C/P2D,它们是 P2 的机械复制)——
|
||
`P1-INPUT.png`、`P1B-5V.png`、`P2-CHANNEL.png`、`P2E-CH5.png`、`P3-CONTROL.png`、
|
||
`P3B-EXPAND.png`、`P4-USB.png`、`P4B-HUB.png`、`P5-HARNESS.png`,PCB 最新是 `PCB-layout-v4.png`。
|
||
(上一轮那三张空白 PNG 是渲染没出来,不是图元缺失;这一轮重截,都是好的。)
|
||
|
||
## 这一轮做了什么(2026-09-04,方案转向)
|
||
|
||
### 一、自动布线(转向前完成的部分)
|
||
|
||
见下面「自动布线终于跑起来了」那节。**结果保留着**:1208 过孔 / 5814 导线,
|
||
6/7 对 USB 差分布通,间距/物理错误 0。但接口区马上要大改,别在这上面继续投入。
|
||
|
||
**三条最贵的教训**(每条都卡了很久):
|
||
|
||
1. **板框必须是一条闭合 polyline**,不能是 4 直线 + 4 圆弧。
|
||
自动布线器取板框走 `fu()`,只扫 polygon 管理器;独立线/弧不在那个表里 →
|
||
`getFilterBoard()` 返回空 → 弹「请先绘制板框!」然后**静默退出**。
|
||
正确写法:`pcb_MathPolygon.createPolygon(SRC)` → `pcb_PrimitivePolyline.create('', 11, poly, 5)`。
|
||
⚠️ 直接把源数组喂给 `create()` 会抛「无法创建多边形图元」而且**真的没建**
|
||
—— 跟铺铜那条「抛了也算成功」方向相反。
|
||
2. **布线跑的时候什么都别碰**。不要 `save()`、不要 `pcb_Drc.check()`、
|
||
连 `getAll()` 这种只读调用都别做。被打断时 `routerResult()` 里
|
||
`state!==1` 会**直接丢弃**结果 —— 画布上看得见、`getAll()` 数得到,
|
||
但没进文档模型。**判据只有一个:save 后重新 `openDocument` 再数一次。**
|
||
3. **差分对要一次统筹全部 7 对**。一对一对布会互相堵死(`保留` 模式下先布的成了障碍)。
|
||
正确姿势:全选 7 对的焊盘 + 「已有导线/过孔 = **移除**」+「布线网络 = 所选网络」。
|
||
|
||
其它:重载客户端会清空自动布线对话框的设置;DRC 面板刷不出来时走
|
||
`设计 → 清除错误` → `设计 → 检查DRC`。
|
||
|
||
### 二、方案转向:两块板(用户 2026-09-04 拍板)
|
||
|
||
用户的原始需求分四次说清楚:
|
||
1. 「做成两块板,五路 usb 移到上板,排针对接,上板加五块主板定位」
|
||
2. 「进入 9008 的控制接口也接入」
|
||
3. 「与主板连接的 usbhub 移到上板,不用排针,排针只需要把下板的电源部分接上来」
|
||
4. 「侧键做顶针,EDL 做 2 针 1.25mm 座子我自己接线,VBUS 通断走排针」
|
||
5. 「不要散热垫,加风扇」→「侧面两侧各 2 个小风扇吸入,顶部 1 个大风扇排出」→「风扇装 3D 打印外壳上」
|
||
|
||
**完整规格写在设计文档 §22**,这里不重复。
|
||
|
||
### 三、⭐ 小米8 主板机械数据:**一直就在我们自己的 PDF 里**
|
||
|
||
**旧结论「PDF 是电气原理图、不含机械尺寸、只能实测」是错的。**
|
||
`小米8原理图/Xiaomi_Mi_8_Schematic.pdf` 共 46 页,
|
||
**前 2 页是正反面位号图**(含完整板框轮廓 + 全部位号),后 44 页才是原理图。
|
||
当初只按「原理图」去读,`get_text()` 一看全是位号就跳过了,**从没渲染出来看一眼**。
|
||
|
||
拿到的数据(方法与精度分档见 §22.3a / §22.3b):
|
||
- 比例尺 **17.0 pt/mm**(从 464 个 0201 封装反推,卡尺验证 0.7%)
|
||
- 主板 **44.66 × 67.09 mm**(卡尺实测)
|
||
- **7 个定位孔**(从用户标红框的照片提取,±0.5 mm)
|
||
- EDL / 尾插 / 侧键触点(从**器件本体图元**提取,±0.3 mm,并被两个卡尺读数交叉验证)
|
||
|
||
### 四、⚠️ 这一轮我判错了四次,都是同一个毛病
|
||
|
||
**没有实物对照就从矢量图元硬推。** 记下来,别再犯:
|
||
|
||
| 判错 | 错因 |
|
||
|---|---|
|
||
| 「主板没有定位孔」 | 轮廓用「逐行取最外侧墨点」提取,**这方法看不见板内的孔和挖空** |
|
||
| 「定位孔就是图纸上那 7 个圆」 | 抓到的是测试点和圆焊盘。摆成横向和用户照片一对就露馅 |
|
||
| 把两个卡尺读数当成「板厚」 | 用户说的是**侧键到板边的距离** |
|
||
| 把 **7.61** 读成 **1.76** | 卡尺屏是旋转的,数字看反了 |
|
||
|
||
**规矩**:卡尺读数先跟用户确认再落档;从图纸推的几何结论,
|
||
必须有一个实物基准交叉验证才能写进文档。
|
||
|
||
### 五、EDL(9008) 电路(原理图 Sheet 17,比维修站的付费短接图可靠)
|
||
|
||
```
|
||
VREG_S4A_1P8 ──[R1204 1.8kΩ 0201]── TP1204 ← 0.75 mm 测试点
|
||
FORCED_USB_BOOT ──┬── TP1205 ← 0.75 mm 测试点
|
||
└── CR1209 PESD3V3V1BCSF ── GND
|
||
```
|
||
|
||
短接两点 = 把 `FORCED_USB_BOOT` 拉到 1.8V → 进 9008。
|
||
**串了 1.8 kΩ,短路电流只有 1 mA**,一颗模拟开关就够。详见 §22.4。
|
||
|
||
---
|
||
|
||
## 这一轮:自动布线终于跑起来了(2026-09-04)
|
||
|
||
### ⚠️⚠️ 头号发现:**板框必须是一条闭合多段线,不能是 4 直线 + 4 圆弧**
|
||
|
||
`布线 → 自动布线... → 运行` **静默失败**:对话框正常关闭、一根导线不画、
|
||
`console` 没有任何异常、也没有网络请求。三次尝试(React onClick / 原生
|
||
dispatchEvent / 等 90 秒)现象完全一样。
|
||
|
||
顺着客户端 bundle 追下去才找到:
|
||
|
||
```
|
||
pcb_ManufactureData.getAutoRouteJsonFile()
|
||
→ ui.js getAutoRouteJson() → windowBridge.rpcCall('getNewAutoRouteJson', …)
|
||
→ pcb.js vP.autoRouting() → createPangolinJson()
|
||
→ getFilterBoard() → fu() → [] ← 就是这里
|
||
→ 弹 "Please draw a board outline first!" 然后 return undefined
|
||
```
|
||
|
||
`fu()` 的判据是(pcb.js 反编译):
|
||
|
||
```js
|
||
[Ni.getInstance().getAllItem(), tn…, Yi…] // 只有 polygon 管理器
|
||
.forEach(t => t.forEach(e => {
|
||
!e.isEmpty && (e.type == "Board Outline" || e.type == "Line" && e.layerId == 11) && o.push(e)
|
||
}))
|
||
```
|
||
|
||
**它只扫多段线(polygon)管理器**。我们的板框是
|
||
`pcb_PrimitiveLine.create()` × 4 + `pcb_PrimitiveArc.create()` × 4,
|
||
八个独立图元,压根不在那个表里 —— 于是 `fu()` 恒返回空。
|
||
|
||
这个错**极难往板框上想**,因为除了自动布线,板框在别处全都是好的:
|
||
渲染正常、铺铜按它的几何铺好了、DRC/ERC 全过、Gerber 也认。
|
||
同一个 `fu()` 还卡着 `getDsnFile()` 和 `getAutoRouteJsonFile()`
|
||
(两个都返回 `undefined`,等于 freerouting 那条路也被堵死了)。
|
||
|
||
**正确姿势(两步,缺一不可)**:
|
||
|
||
```js
|
||
const poly = await eda.pcb_MathPolygon.createPolygon(SRC); // ⚠️ 必须先过这一步
|
||
await eda.pcb_PrimitivePolyline.create('', 11, poly, 5);
|
||
```
|
||
|
||
⚠️ 把 `TPCB_PolygonSourceArray` **直接**喂给 `pcb_PrimitivePolyline.create()`
|
||
会抛「错误:无法创建多边形图元」,而且是**真的没建**(`getAll()` 仍是 0)——
|
||
注意这跟铺铜那条「`create()` 抛了也算成功」的经验**方向正好相反**,别混用。
|
||
|
||
`pcb_place.py` 的 `push_outline()` 已经改成这个写法(新增 `outline_poly()`)。
|
||
|
||
### 一路排查中间踩到的三件事
|
||
|
||
1. **`pcb_PrimitiveArc.getAll()` / `getAllPrimitiveId()` 在本工程恒返回 0。**
|
||
排查时我以为四个 R5 圆角不存在,又补建了四段 —— 于是 layer 11 上现在有
|
||
**8 段重叠圆弧 + 4 条重叠直线**(几何完全重合,Gerber 上是同一条路径描两遍)。
|
||
它们不在 `fu()` 的表里,不影响布线;但**删不掉**(枚举不到就没有 primitiveId),
|
||
要清只能在客户端里手删,或者隐藏其它层后框选 layer 11 全删再重建 polyline。
|
||
2. **桥接的 WS 请求 30 秒硬超时**,`eda.py` 的 `timeout=` 只管 HTTP 那一段。
|
||
JS 里 `sleep` 超过 30 s 一律拿到 `Request … timed out after 30000ms`。
|
||
要等就分多次短调用轮询。
|
||
3. **客户端重连会换 `windowId`**。`curl http://127.0.0.1:49620/eda-windows` 可以确认
|
||
当前只有一个窗口 —— 排查「是不是打到另一个窗口去了」时先看这个,别猜。
|
||
|
||
### 抓静默失败的通用手法(这轮就是靠它破的)
|
||
|
||
页面里挂三层钩子,再触发一次,就能看见吞掉的错误:
|
||
|
||
```js
|
||
// ① console 全接管 ② window.onerror / unhandledrejection ③ fetch / XHR / Worker
|
||
// ④ 最关键:postMessage —— 父窗口与编辑器 iframe 之间的 rpc 都走这里
|
||
window.addEventListener('message', e => { …记录 topic 与 message… }, true);
|
||
document.querySelector('iframe.editframe').contentWindow
|
||
.addEventListener('message', …, true);
|
||
```
|
||
|
||
回包里 `{"topic":"getNewAutoRouteJson_MSG_BUS_RPC_64600","type":"push"}`
|
||
**没有 message 字段** —— 一眼就能断定是 iframe 里的处理函数返回了 undefined,
|
||
而不是参数没传对或者按钮没点上。
|
||
|
||
再配合 `console.warn` 里打 `new Error().stack`,能直接定位到
|
||
`ui.js:1819` 的 `getAutoRouteJson`,然后把 `pro-ui/…/js/ui.js`(17 MB)和
|
||
`pro-pcb/…/js/pcb.js`(10 MB)下下来 grep —— 这两个包是公开 CDN,随便下。
|
||
|
||
### 自动布线的设置(对话框里的状态是持久化的,改一次就记住)
|
||
|
||
| 项 | 取值 | 为什么 |
|
||
|---|---|---|
|
||
| 布线网络 | 所有网络 | |
|
||
| 布线拐角 | 45° | |
|
||
| 已有导线/过孔 | **保留** | 708 个扇出过孔和平面层不能被冲掉 |
|
||
| 效果优先级 | 完成度优先 | |
|
||
| 布线图层 | **只勾顶层 + 底层** | 内层1 是完整地平面、内层2 是电源平面,**不许被信号线割开** |
|
||
| 忽略网络 | **15 个** | `GND`(459 个扇出过孔已经接到地平面了,让它布会刷出一堆顶层地线)+ 7 对差分的 14 个网络(`USB1~5_DP/DM`、`UP_DP/DM`、`USB_DP/DM`,打算之后按对单独布) |
|
||
|
||
对话框是 React 的,`忽略网络` 那个下拉可以直接从 fiber 上取 `onChange` 逐个灌:
|
||
|
||
```js
|
||
const p = /* 从 [data-id^="selectOptionKey_"] 往上找带 {list, onChange} 的 fiber */;
|
||
p.onChange('GND'); // 每加一个 list 就少一个,要重新取 fiber
|
||
```
|
||
|
||
### ⚠️ 自动布线的结果**不到最后不落盘** —— 中途被打断就白跑
|
||
|
||
第二趟(补差分对)跑完,`getAll()` 报 6196 条导线、几何上逐段查过
|
||
**USB1_DP 从 U32.2 一路连到 J17.3、并查集只有一个连通块**,
|
||
但 DRC 咬定这两个焊盘断开。`pcb_Document.save()` 之后
|
||
**重载客户端,板子回到了第一趟的 1095 过孔 / 3455 导线** —— 第二趟一根线都没进文档。
|
||
|
||
原因在 `routerResult()`:
|
||
|
||
```js
|
||
routerResult(t){ if(this.state!==1){ console.error("Auto Routing is stop!", this.state); return; } … }
|
||
```
|
||
|
||
布线结果是一批一批推回来的,`state!==1`(被打断)时**直接丢掉**。
|
||
画布上看得见、`getAll()` 数得到,但那只是 `historyGroup` 里的预览,没有进文档模型 ——
|
||
**所以 DRC 是对的,错的是我**。
|
||
|
||
**判据只有一个:save 之后重新 `openDocument`,再数一次导线/过孔。**
|
||
数字对不上就是没落盘。别信 `getAll()`,也别信画布。
|
||
|
||
跑的时候不要碰客户端:不要 `save()`、不要 `pcb_Drc.check()`、
|
||
连 `pcb_PrimitiveVia.getAll()` 这种只读调用都先别做 —— 第二趟就是这么被打断的
|
||
(第一趟跑满 ~50 分钟、进度条自己消失,结果就落盘了)。
|
||
盯进度只读 DOM 文本:`document.body.innerText` 里那行 `自动布线中...(NN%)`。
|
||
|
||
### 顺带两条
|
||
|
||
- **重载客户端会把自动布线对话框的设置清空**(忽略网络清零、四个布线图层全勾回来)。
|
||
重载之后必须重新配一遍再跑。
|
||
- **DRC 面板刷不出来时走菜单**:`设计 → 清除错误`(`全部 (0)`)→ `设计 → 检查DRC`。
|
||
面板上那个「刷新」按钮不是 DRC 的,`pcb_Drc.check()` 单独调有时也不刷新。
|
||
|
||
### 局部返工:把 7 对 USB 差分抢回通道(2026-09-04,用户拍板)
|
||
|
||
第一趟自动布线之后,**7 对差分只布上 2 对**(USB1/USB2),其余 5 对
|
||
连「所选网络」单独重跑都一根线不画 —— 板子已经被普通信号线占满了。
|
||
用户拍板走「局部返工」而不是整体回滚。四步:
|
||
|
||
**① 先改规则**(`pcb_rules.py --push`),否则布完还是一堆假违规:
|
||
|
||
| 改动 | 从 | 到 | 为什么 |
|
||
|---|---|---|---|
|
||
| `differentailPairLenTolerMax` | 0.5 mm | **5 mm** | USB 2.0 HS 对内偏斜预算 ≈100 ps ≈ 15 mm;实测偏差 1.6~1.9 mm ≈ 10 ps。为凑 0.5 去绕蛇形线是拿串扰换数字 |
|
||
| 新增安全间距条目 `USBPAIR` | — | **0.15 mm** | 只通过 `overwriteNetByNetRules` 挂在**每一对自己的两个网络之间**;对其它网络仍是 0.2 mm |
|
||
|
||
`USBPAIR` 那条**不能**用全表抬下限的循环扫到(会被抬回 0.2),代码里单独跳过了。
|
||
|
||
net-by-net 的条目形状文档没写,是从 `pcb.js` 的 `getBetweenNetDataItem()` 反出来的:
|
||
|
||
```js
|
||
{net1:{type:'net',name:'USB1_DP'}, net2:{type:'net',name:'USB1_DM'},
|
||
rule:'USBPAIR', copperRuleName:null, planeRuleName:null}
|
||
```
|
||
|
||
⚠️ `overwriteNetByNetRules` 是**整表覆盖**,要先 `getNetByNetRules()` 读回来再合并。
|
||
改完 DRC 172 → 166,4 条对内间距 + 2 条等长违规一起消失。
|
||
|
||
**② 三条低压轨改成铺铜**(铜面 15 → **19** 块):
|
||
|
||
| 铜面 | 网络 | 层 | 范围 | 盖住 |
|
||
|---|---|---|---|---|
|
||
| 5V-L3 | `+5V` | L3 | x 11~151 / y 5.5~14 | 10 / 16 |
|
||
| 3V3HUB-L3 | `+3V3_HUB` | L3 | x 59~111 / y 15~31 | **21 / 21** |
|
||
| 3V3-CTRL-L3 | `+3V3` | L3 | x 95.5~150.5 / y 33.5~67 | 合计 45 / 61 |
|
||
| 3V3-CH-L3 | `+3V3` | L3 | x 5~155 / y 100.3~124 | 同上 |
|
||
|
||
都塞在 12V 那三条带子之间的空地里,互相与 12V 都留 ≥0.5 mm。
|
||
`3V3-CTRL-L3` 的右边界 150.5 是被 ESP32 天线禁铺区(x≥151)逼的。
|
||
|
||
这带出两个工具改动:
|
||
|
||
- **`pcb_pour.audit()` 要按网络做并集**。`+3V3` 是**两块**铜面,逐块判「焊盘在不在里面」
|
||
会让每一块都把另一块盖住的焊盘报成「意外漏掉」。
|
||
- **新增 `POUR_PARTIAL = ('+5V', '+3V3')`**:这两条轨的铜面**故意只盖一部分**,
|
||
漏在外面的焊盘靠走线接,不算错。
|
||
|
||
**③ `pcb_fanout.py` 只对「落在自己铜面里」的焊盘扇出**(新增 `_pour_filter()`)。
|
||
在没有铜的地方打一个下到 L3 的过孔 = 一个悬空过孔,DRC 反而多一条断连。
|
||
三条轨一共扇出 91 个过孔,5 个焊盘周围太挤放不下,留给走线。
|
||
|
||
**④ 局部返工的选取判据**(`_snap_before.json` 是基准):
|
||
|
||
```
|
||
删掉「布线器加的」且满足下面任一条的**整个网络**的线与过孔:
|
||
a) 网络已经改成铺铜(+5V / +3V3 / +3V3_HUB)
|
||
b) 该网络在 y < 28 mm 的下带里有走线,且不是 GND/12V/VOn 这类扇出网络、也不是差分对
|
||
```
|
||
|
||
结果:**34 个网络 / 678 条导线 / 68 个过孔**,只占布线器产物的 18%。
|
||
整网删、不留断头,剩下的 80% 一根没动。
|
||
|
||
### ⚠️ 差分对必须**一次统筹全部 7 对**,一对一对布会互相堵死
|
||
|
||
下带清空之后,选中 5 对跑「所选网络」,**只布上 USB4/USB5**;再跑一次,
|
||
一根线都不加。原因是 `保留` 模式下先布好的那两对成了后面的障碍 ——
|
||
USB3 与上游 UP 要横穿它们,而下带就那么宽。
|
||
|
||
正确姿势是**把 7 对全选中 + 「已有导线/过孔 = 移除」**,让布线器把已布的两对
|
||
一起拆掉重排。`clearRoute(false, undefined, this.selectNets)` 只清选中的网络,
|
||
不会波及别处(pcb.js 里确认过)。一趟下来 **6 / 7 对布通**(USB1~5 + UPSTREAM),
|
||
只剩 ESP32 那条调试口 `USB_DP/DM`。
|
||
|
||
顺带澄清一条之前的误判:**「所选网络」模式是好的**。早先它「跑完却一根线不画」
|
||
不是模式坏了,是那时候板子上真的没路了 —— 日志里 `routingRange:1`、选中 24 个焊盘
|
||
都对,弹的也是「自动布线已完成」而不是报错。
|
||
|
||
### 布线跑完之后要做的(按顺序)
|
||
|
||
1. **DRC** —— `python .claude/drc_read.py`。看「间距错误」和「物理错误」两支,
|
||
连接性错误剩多少 = 还有多少没布上。
|
||
2. **七对差分单独布**(`USB1~5_DP/DM`、`UP_DP/DM`、`USB_DP/DM`)。
|
||
规则里已经建好 7 对、W 0.28 / S 0.18 / 等长容差 0.5 mm。
|
||
⚠️ **顺序上其实应该先布差分再自动布线**——这一轮是为了先验证布线器能不能跑才反过来的。
|
||
如果跑完发现差分对已经无路可走,就按快照回滚,改成「先差分后自动」重跑。
|
||
3. **重新铺铜**。底层(layer 2)上有 VO1~5_P 五块铜面,自动布线在底层加了信号线,
|
||
铜面要重建才会让开它们:`工具 → 铺铜管理器... → 重建所有`
|
||
(`pcb_pour.py --rebuild` 里已经把这一串打好了;`rebuildCopperRegion()` API 是坏的)。
|
||
4. **丝印整理** —— 位号大面积压字,打样前要单独跑一遍。
|
||
5. Gerber 预览复核板框闭合 + 四个 M3 定位孔。
|
||
|
||
### 跑之前先存了个快照(`.claude/_snap_before.json`)
|
||
|
||
布线前把 708 个过孔 + 575 条导线的 `primitiveId` 全存了下来。
|
||
万一自动布线的结果不能要,**删掉不在这张表里的线和过孔**就能精确回滚,
|
||
比 `清除布线`(会连扇出一起清)干净得多。
|
||
|
||
---
|
||
|
||
## 上一轮:开始布线(2026-09-03)
|
||
|
||
顺序是「先把面铺好,再拉线」—— 平面定了,信号线的参考面和过孔位置才有依据。
|
||
|
||
### 1. 先抓到一个真的断线:U13 的 SCL 没接上 ⚠️
|
||
|
||
追 12V 母线的网络时发现 PCB 里 `U13.2 / U13.5` 挂在一个只有两个焊盘的
|
||
`$1N257` 上,而 `SCL` 网络 11 个焊盘里没有 U13。**输入侧检流那片 INA226 是死的。**
|
||
|
||
根因不是漏画线,是 **`SCL` 端口的引脚压在一条导线的中段而不是端点**
|
||
(端口在 (920,340),导线是 `[920,320 → 920,570]`)。EasyEDA 只在端点认连接。
|
||
同一页的 SDA 端口恰好落在端点上,所以 SDA 是好的 —— **两个端口在图上一模一样**。
|
||
|
||
DRC / ERC / `verify_sch --nets` / 跨页对账**四道全过**,因为
|
||
`verify_sch` 的判据是「引脚落在某条导线段上」,中段搭接满足这一条。
|
||
|
||
新增 **`.claude/port_audit.py`**:全工程 572 个旗/端口逐个判「是不是某条导线段的端点」。
|
||
修之前 1 个不合格(就是它),修完 0 个。写进 `easyeda-sch-geometry` **§8a-2** 与设计文档 **§19.4**。
|
||
|
||
> 写这个检查时踩了个自伤的坑:第一版按折线解析导线,572 个里报出 **197 个可疑**,
|
||
> 其中一大片是工作正常的 GND 旗。`getState_Line()` 返回的是**端点对**(skill §5),
|
||
> 按折线解析会凭空造出斜线段。误报到这个程度的检查等于没有检查。
|
||
|
||
### 2. 8 A 输入链整条重排
|
||
|
||
原来这一串是仿射映射甩出来的,`J1(x5.8) → F1(x46.6) → Q1(x53) → 体电容(x66/75)
|
||
→ Rs6(x84.6~90.7)`:**8 A 要从 x5.8 走到 x90.7,85 mm**,其中 `$1N223`(J1→F1)
|
||
单独一段就 42 mm。8 A 在 0.5 oz 内层要 ΔT=20 °C 得 **18 mm 宽**铜面
|
||
(IPC-2221 内层按外层 50% 取,面积翻倍),band B 一共才 36 mm 高,塞不下四条。
|
||
|
||
而且这一串在 y 上来回折(F1.2 在 y60.08,Q1 源极在 y62.85,中间还夹着
|
||
`$1N236` 在 y60.56 的一个焊盘),L3 上按 y 切开分块,切线最窄处只剩 0.2 mm。
|
||
|
||
**改成 J1 右手边一条走廊 x 11.5~46 / y 49.5~68.5**(栅极网络放 J1 上方口袋):
|
||
|
||
| | 之前 | 现在 |
|
||
|---|---|---|
|
||
| `$1N223` J1→F1 | 42 mm | **6.9 mm** |
|
||
| 8 A 段的横跨 | x 5.8 ~ 90.7 | x 12 ~ 40 |
|
||
| 分叉点 | x 90.7 | x ≈ 40(Rs6 下游)|
|
||
| 母线最大截面电流 | 8 A 全程 | 顶带 ≤ 6.4 A(往左喂 CH1、往右喂 CH2~5)|
|
||
|
||
顺带把 13.7 × 9.7 的立式泄放电阻 R9 也钉死了 —— 仿射区右缩之后它被推到 x95,
|
||
**本体框伸到 x102 压进 P3 区**。`relax()` 只夹中心坐标、不看外框,这类件必须手钉。
|
||
|
||
### 3. 平面层(`.claude/pcb_pour.py`)
|
||
|
||
| 铜面 | 层 | 网络 | 范围 |
|
||
|---|---|---|---|
|
||
| GND-L2 | L2 | GND | 整板(板框内缩 0.5,挖 ESP32 天线区)|
|
||
| VIN-RAW-L3 | L3 | `$1N223` | x 3~14 / y 45.5~55.5 |
|
||
| VIN-FUSED-L3 | L3 | `$1N227` | x 14.6~19 / y 49.5~56.5 |
|
||
| VIN-SW-L3 | L3 | `$1N236` | 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,带一条下伸臂到分流电阻 |
|
||
|
||
分界线是**焊盘边**定的不是整数:+12V 顶边 81.9 卡在 C102 那排 1210 焊盘(y80.2~81.7);
|
||
VOn 底边 82.5 是因为 C107 pin1 是 rot90 的 1210,焊盘跨到 y83.07~84.55 ——
|
||
按「元件中心在 y85.4」算会把它漏在两块铜面之间的缝里。
|
||
|
||
**U8~U13 的 0.5 mm 间距 Kelvin 脚一律不进铜面**(U13.10 是 VIN+、U13.9 是 VIN−,
|
||
相距 0.5 mm,任何分界线都塞不进去),走顶层细线,本来也不载流。
|
||
`pcb_pour.py` 里 `audit()` 会把「本网焊盘在铜面外」的逐条列出来,
|
||
`EXPECT_OUT` 是白名单,漏在名单外的就要查。
|
||
|
||
### 4. 铺铜 API 的三个坑(都实测过)
|
||
|
||
1. **`rebuildCopperRegion()` 是坏的**,四种写法都抛
|
||
`Cannot read properties of undefined (reading 'length')`。
|
||
唯一能填充的路子是 GUI:**工具 → 铺铜管理器... → 重建所有 → 确认**,
|
||
已用 React 的 `onClick` 打进 `pcb_pour.py`。判据是 `nPoured` 不是 `nPour`。
|
||
2. **多边形必须显式闭合**(末尾把首点再写一遍)。文档说「首尾不重合会自动重合」
|
||
对铺铜边框**不成立**:不闭合就直接不建。`board_poly()` 一直能用是因为
|
||
它最后那段圆弧正好回到起点。
|
||
3. **`create()` 成功了也会抛** `错误:无法创建覆铜边框图元`。返回值和 try/catch
|
||
都不能当判据,只能建完 `getAll()` 按名字核对 —— 而且**名字会被转成大写**。
|
||
|
||
排查时分不清 1 和 2 的办法:不闭合的矩形建完 `getAll()` 数量不变,闭合的 +1,
|
||
**两者抛一模一样的异常**。
|
||
|
||
### 5. GND 扇出:改布局之后必须按这个顺序重跑
|
||
|
||
```bash
|
||
python .claude/pcb_fanout.py --clean # 1. 先清空板上的过孔与走线
|
||
python .claude/dump_pads.py # 2. 再重新抓障碍表
|
||
python .claude/pcb_fanout.py --push # 3. 最后规划 + 下发
|
||
```
|
||
|
||
`--clean --push` 写成一条**会用旧的 `pcb-copper.json`**:清是清干净了,
|
||
规划器看的还是那 459 个已经不存在的过孔,把它们当障碍绕 ——
|
||
实测 459 → 292 个过孔、五路 Buck 的 pin2 全扇不出去、27 个散热盘只打进 4 个孔。
|
||
反过来先 dump 再 `--clean --push` 更糟,板上会剩两套(747 个)。
|
||
|
||
正确顺序的结果(15 个网络一趟跑完):**708 个过孔 / 0 个失败**,
|
||
其中 GND 459、+12V 128、输入链三条 48、五路 VOn 各 17、五路 VOn_P 各 8。
|
||
|
||
### 6b. 出线宽度必须**按焊盘**算,不能按网络算
|
||
|
||
第一版给功率网络一刀切 1.0 mm(= 线宽规则的最小值),结果 **29 个焊盘扇不出去**:
|
||
`+12V` 上挂着 R104 那种 0402 分压抽头,焊盘只有 0.57 × 0.54 mm,
|
||
**1.0 mm 的线比焊盘还宽**。退回 0.3 mm 硬扇出去,又被判
|
||
「线宽 11.8 mil,应在 39.4 ~ 393.7 mil」—— 34 条物理错误。
|
||
|
||
两处一起改才对:
|
||
|
||
1. `PWR4A` / `PWR12V` 的**最小值 1.0 → 0.3**(默认值仍是 1.5 / 2.0)。
|
||
这就是 §10.1 那条「载流靠灌铜保证,不靠 DRC」再走一步。
|
||
2. 出线宽度按**焊盘短边 × 0.9** 取,夹到 [0.3, 1.0];过孔数按焊盘短边 ≥ 0.8 mm 给 3 个、
|
||
否则 1 个 —— 0402 抽头本来就不载功率电流,多打过孔只会把平面打成筛子。
|
||
|
||
### 6c. 扇出的障碍模型漏掉的两件事(DRC 抓出来的)
|
||
|
||
| 现象 | 根因 |
|
||
|---|---|
|
||
| 10 条「导线到过孔 3.4 mil,应 ≥ 7.9 mil」 | 板上已有的过孔只按**钻孔半径 0.15** 登记进 holes,没按**焊盘半径 0.3** 登记进 grid。差的正好是 0.15 mm |
|
||
| 1 条「导线到导线 6.2 mil」 | **出线之间的间距压根没查**过 —— 原来只查了线对焊盘、线对钻孔 |
|
||
|
||
两条都补进 `pcb_fanout.py` 了(`trk_grid` + `seg_seg_dist`)。
|
||
补完重跑:**间距错误 0、物理错误 0**。
|
||
|
||
### 6. 顺手发现的两条 EasyEDA 路子
|
||
|
||
- **设计 → 从原理图导入变更(Alt+I)** 能用 DOM 打开并读出变更表,
|
||
逐条列 `U13:2 $1N257 → SCL`。改完原理图必须走这一步,PCB 才会跟着变。
|
||
- **布线 → 扇出布线... / 自动布线... / 差分对布线 / 等长调节** 都在菜单里。
|
||
信号线那 400 多条不必自己写布线器,下一轮直接驱动它。
|
||
|
||
## 最新一轮:设计规则不用手动了(2026-09-03 深夜,收尾)
|
||
|
||
上一轮结论「规则配置只能在 GUI 里手建」**是错的**。原因是参数形状给错了,
|
||
现在 `python .claude/pcb_rules.py --push` 一条命令把五项全下发,`--check` 七项全 OK:
|
||
|
||
```
|
||
[OK] 四层板能力集已就位(最小线宽 0.102 / 过孔 0.30-0.20,含 0.5oz 内层条目)
|
||
[OK] 线宽规则 PWR12V 存在 [OK] 线宽规则 PWR4A 存在
|
||
[OK] 差分对几何 W 0.280 / S 0.180 mm
|
||
[OK] 安全间距下限 0.2000 mm
|
||
[OK] 差分对 7 对: DEBUG UPSTREAM USB1 USB2 USB3 USB4 USB5
|
||
[OK] 线宽指派 12 个网络
|
||
```
|
||
|
||
### 当初为什么以为不行 —— 两个坑叠在一起
|
||
|
||
1. **`overwriteCurrentRuleConfiguration(x)` 要 config 本体,不要 `{name, config}` 包装。**
|
||
传包装返回 `undefined` 且静默无效;传本体返回 `true`。
|
||
(`saveRuleConfiguration(cfg, name, allowOverwrite)` 确实是三个参数 ——
|
||
上一轮只传了一个 —— 但补齐了照样返回 `false`。**它是真的不能用**,
|
||
好在我们并不需要存命名配置。)
|
||
2. **两种 config 的形状不一样,混用会被默默吃掉。**
|
||
|
||
| 来源 | 线宽 | 安全间距表 |
|
||
|---|---|---|
|
||
| `getRuleConfiguration('<系统能力集>')` | **平**:`form.strokeWidthDefault` | `entry.table` |
|
||
| `getCurrentRuleConfiguration()` | **嵌套**:`form.data['1'].defaultValue` | `entry.tables['1'].content` |
|
||
|
||
正确姿势:**拿 `getCurrentRuleConfiguration().config` 改,原形状送回去**。
|
||
系统能力集只当数据源用(那张内层 0.5 oz 间距表是从它身上抄的)。
|
||
|
||
### 「切到多层板能力集」其实只是五个字段
|
||
|
||
把两个能力集逐值 diff 过:**只差 3 个数 + 2 条默认不启用的条目**,其余 300 多个数完全一致。
|
||
|
||
| 项 | Two Layers | Multiple Layers |
|
||
|---|---|---|
|
||
| `Track/copperThickness1oz` 最小线宽 | 0.127 | **0.102** |
|
||
| 过孔外径最小 | 0.5 | **0.3** |
|
||
| 过孔内径最小 | 0.3 | **0.2** |
|
||
| `Track/copperThickness0.5oz` | 无 | 有(min 0.089,`isSetDefault=false`)|
|
||
| `Safe Spacing/copperThicknessInner0.5oz` | 无 | 有(`isSetDefault=false`)|
|
||
|
||
也就是说,能力集之间的差别**全是放宽限制**,两层板那套只是更保守。
|
||
真正必要的是最小线宽 0.102(U32 那个 0.5 mm 间距 QFN-64 的扇出要用)。
|
||
|
||
### ⚠️ 下发之后千万别做的一件事
|
||
|
||
**别再去 GUI 的 设计 → 设计规则… 里动“配置”下拉框。**
|
||
换一下就是整套重置:`PWR4A` / `PWR12V` 两条线宽规则会被冲掉,
|
||
12 个功率网络的指派立刻变回悬空(**DRC 不报错,线宽也就不生效** —— 查不出来的那种坏)。
|
||
要改规则就改 `pcb_rules.py` 再 `--push`。
|
||
|
||
配置名下发后会自动变成 **“自定义配置”**,这是对的 ——
|
||
说明它已经从系统能力集上摘下来了。
|
||
|
||
### 顺带踩到的一个坑:mm 值会被换算成 mil 再换回来
|
||
|
||
写进去 `0.2`,回读是 `0.19999959999999997`(差 4e-7 mm)。
|
||
**任何几何值都不能做精确比较**,`--check` 的容差已放到 1e-4。
|
||
(第一版容差 1e-9,结果安全间距那项在明明写对的情况下报红。)
|
||
|
||
### DRC 结果读得回来(`.claude/drc_read.py`),而且真抓到了 9 个错
|
||
|
||
先说一句:本轮早些时候写的「DRC 结果读不回来」**是错的**,已推翻。
|
||
|
||
`pcb_Drc.check()` 确实只返回一个 boolean,40 多个方法里没有结果 getter,
|
||
也没有 DRC 标记层可读。**但 DRC 面板在 DOM 里是挂载着的**
|
||
(跟设计规则对话框不一样,那个窗口不前台就不挂载)。三个手法:
|
||
|
||
1. 左边分类树要用 **React 的 onClick** 点 —— 从元素上找 `__reactProps$*`,
|
||
一路往上找到带 `onClick` 的那层直接调。`el.click()` 不管用,不点就不选中,
|
||
右边明细区一直是「空列表」。
|
||
2. **「清除错误」那个反过来**,它是原生 `<button class="i18n">`,没有 React props,
|
||
`el.click()` 直接生效。同一个面板上两种按钮混着,别一条路走到黑。
|
||
3. 明细表 innerText 尾巴上粘着分页组件的一大段 CSS,碰到 `input::-webkit` 截断。
|
||
|
||
跑法:`/c/Python314/python .claude/drc_read.py`(`--no-check` 只读不重跑)。
|
||
|
||
### 那一片黄叉:是 `check()` 画的,不是板子坏了
|
||
|
||
跑完 `check()`,**每个未布线焊盘都盖一个黄叉**,没布线时 1200+ 个,
|
||
满屏都是,看着像出了大事。分类是:
|
||
|
||
```
|
||
全部 (1273) = 间距错误 (9) + 连接性错误 (1264)
|
||
↑真错误 ↑还没布线,预期之内
|
||
```
|
||
|
||
**只看「间距错误」那一支。** 看完用面板上的「清除错误」清掉。
|
||
|
||
### 9 个真错误,两类,都已修掉(1273 → 1264)
|
||
|
||
**① 贴片焊盘到贴片焊盘 ×5 —— 五路的 Cin 挨太近,差 10 µm**
|
||
|
||
`C%01` / `C%02`(Buck 输入去耦,§10.2-1 手调的热回路)两片焊盘只剩
|
||
**0.1905 mm**,安全间距要 0.2 mm,**差 10 µm**,五路一起报。
|
||
这是把全局间距从 0.152 抬到 0.2 mm 的直接后果 —— 老规则下它是过的。
|
||
|
||
改法:`pcb_place.py` 里 `C%02` 的 y 从 14.9 挪到 **14.95**,缝变 0.2405 mm。
|
||
0.05 mm 对约 4 mm 周长的热回路可以忽略。**模型和板子都已改**(五路各挪一颗)。
|
||
|
||
**② 钻孔到钻孔 ×4 —— 四个 M3 定位孔各有一个重影**
|
||
|
||
四个角上各有**两个 `MHn` 焊盘**,焊盘一样大(6.0 mm),钻孔一个 3.2 mm(对的),
|
||
另一个 **0.32 mm** —— 正好差 10 倍,当初建孔时 mm/mil 滑了一位,
|
||
改对之后**旧的那 4 个没删**。两个孔完全同心,距离 0 mil。
|
||
已删掉 4 个 0.32 mm 的,`MHn` 从 8 个回到 4 个,全是 3.2 mm / GND。
|
||
|
||
> ⚠️ 这两类**本地几何检查一个都抓不到** —— `pcb_place.py` 的 `check()` 只看
|
||
> 本体框重叠和越框,不看焊盘间距,更不看钻孔。**布局改完要跑一次 `drc_read.py`。**
|
||
|
||
### 布线时如果 U32 扇出被 0.2 mm 间距卡住
|
||
|
||
0.5 mm 间距 QFN 出线,相邻焊盘到走线边缘算下来约 **0.233 mm**,
|
||
比 0.2 mm 只多 33 µm,能过但很紧。真被刷屏了不要去改全局间距 ——
|
||
`pcb_Drc.getRegionRules` / `overwriteRegionRules` 可以在 U32 周围开一块局部规则区。
|
||
|
||
---
|
||
|
||
## 最新一轮:缩板 + 定位孔 + 设计规则(2026-09-03 深夜)
|
||
|
||
### 1. 板框 200×150 → **160×125**,四角 R5 + 4 个 M3 定位孔
|
||
|
||
用户拍板的尺寸。定位孔 **M3 金属化接 GND**:孔 Φ3.2 / 焊盘 Φ6.0 / 禁布 Φ6.5,
|
||
孔心 (5,5)(155,5)(5,120)(155,120),与圆角同心。
|
||
|
||
**⚠️ 四角定位孔和 band A 的连接器是几何上打架的**,5 × 32 = 160 正好铺满板宽,
|
||
CH1 / CH5 的顶角必然被连接器本体压住。解开靠两条(都写在 `pcb_place.py` 的 CH1 表里):
|
||
|
||
1. **J7~J11(按键出线)是立式座,本来就不需要板边** —— 挪进通道内部 (25.5, 31),
|
||
顶边只留 J2~J6 一个 12 mm 宽的右角式座;
|
||
2. **J2 摆在通道中央**(local x=15,本体 x 9~21),左右各让出 9 mm。
|
||
|
||
功率链那一段(local y 3~42)**一个件都没动** —— §10.2 的四条关键回路是手调出来的,
|
||
缩板不该动它们。按键驱动那 9 个件从「J2 右边一横排」改成右列 x 24/28 的纵排。
|
||
|
||
`check()` 里新加了**定位孔禁布区**这一项。孔不是元件,原来那两项检查都看不见它。
|
||
|
||
### 2. 又是本体框:J2 离板边差了 4 mm
|
||
|
||
`FP_BODY` 里 Micro-Fit 的本体我上一轮手量成 12 × 13.5 mm,**渲染图上重量是 9.8 × 10.1**
|
||
(对得上 43650 两位右角式的 8.6 × 10.1)。偏大 4 mm 的后果是 check() 以为贴着板边、
|
||
实际差 4 mm。已改成 (-4.95, -9.0, 4.95, 1.4) 并把 J2 挪到 local y=49 顶住 y=125。
|
||
|
||
> 这是 FP_BODY 第二次出错了(第一次是 U20 压出板框)。**手量的本体框都要复核一遍**,
|
||
> 偏大是安全方向(连接器缩进去),偏小是危险方向(本体悬空出框)。
|
||
|
||
### 3. Hub 挪到板中央 —— D± 最长砍掉一半
|
||
|
||
原来 U32 在最左边(x=31),到 CH5 要走 **112 mm**。挪到板中央 x=79 之后:
|
||
|
||
| | USB1 | USB2 | USB3 | USB4 | USB5 | 上游 J23 |
|
||
|---|---|---|---|---|---|---|
|
||
| D± 长度 | 64 | 32 | **0** | 32 | 64 mm | 16 mm |
|
||
|
||
⚠️ **U32 正上方就是 CH3 的负载开关块**,所以去耦不能像原来那样在正下方排一横排 ——
|
||
改成上面一排 4 颗 + 左边一列 3 颗。
|
||
|
||
### 4. 设计规则与差分对(`.claude/pcb_rules.py`)
|
||
|
||
**API 能做的已经做了**:
|
||
|
||
- **7 对差分对**:USB1~5(Hub → 五路出线座)、UPSTREAM(J23 → Hub)、DEBUG(J22 → ESP32)。
|
||
- **12 个功率网络指派线宽规则**:VO1~VO5 / VO1_P~VO5_P → `PWR4A`;+12V / +5V → `PWR12V`。
|
||
|
||
**API 做不了的**(当时这么写的,**2026-09-03 深夜已推翻,见下一节**):
|
||
|
||
> ~~`saveRuleConfiguration` / `overwriteCurrentRuleConfiguration` 全部返回 false 或
|
||
> undefined,什么也不做。~~ —— 是参数形状给错了,不是 API 不行。
|
||
|
||
### 5. 外层铜厚:**2 oz → 1 oz(用户 2026-09-03 拍板)**
|
||
|
||
理由:U32 是 0.5 mm 间距的 QFN-64(2 oz 外层最小线宽/间距 0.2 mm 起,扇出很吃力,
|
||
1 oz 是 0.102 mm),而且 **90 Ω 的几何随铜厚变**(2 oz 下同样 W/S 只剩 83 Ω)。
|
||
设计文档 §10.1 已改写,附了完整的载流表。
|
||
|
||
**这条改动连带否掉了一个数**:原来 `PWR12V` 定的 2.5 mm,在 1 oz 下
|
||
**8 A 温升 35 °C**,不能用。已改成:
|
||
|
||
| 规则 | 值 | 说明 |
|
||
|---|---|---|
|
||
| `PWR4A` | 默认 1.5 / 最小 **0.3** / 最大 6.0 mm | 4 A 温升 16.7 °C ✓;最小值 2026-09-03 由 1.0 降到 0.3,见设计文档 §10.1 的补注 |
|
||
| `PWR12V` | 默认 **2.0** / 最小 **0.3** / 最大 10.0 mm | 只给**分支**(每路 1.6 A);0402 抽头引不出 1.0 mm 的线 |
|
||
|
||
> ⚠️ **12V 总干那 8 A 不许当走线画** —— 1 oz 下要 3.49 mm 才够 20 °C。
|
||
> 必须走灌铜:Inner2-PWR(0.5 oz)上要 **≥18 mm 宽**,或顶层灌铜 ≥3.5 mm。
|
||
> 没把 `PWR12V` 的最小值设成 3.5 mm,是因为 +12V 上还有一堆进 0402/SOT-23 焊盘的
|
||
> 短支线,卡 3.5 会刷出几百条假 DRC 错误,规则就没人看了。
|
||
> **载流靠灌铜保证,不靠 DRC。**
|
||
|
||
### 6. 还有一条要用户确认
|
||
|
||
- **90 Ω 的 W/S 必须拿板厂叠层复核**。0.28/0.18 是按嘉立创四层 1.6 mm 标准叠层
|
||
(h=0.2104 mm、εr≈4.3、1 oz 外层)的微带近似算的,叠层一变就得重算。
|
||
|
||
---
|
||
|
||
## 上一轮(2026-09-03 晚)做了什么
|
||
|
||
新增了三个脚本(都在 `.claude/`):
|
||
|
||
| 脚本 | 干什么 |
|
||
|---|---|
|
||
| `refresh_cache.py` | 重抓 `pcb-parts.json` / `pcb-pads.json` / `sch-xy.json`。**改完原理图 + importChanges 之后必跑**,否则 `pcb_place.py` 看到的还是旧元件表 |
|
||
| `shot_pcb.py` | 截整块 PCB(`shot.py` 只能截原理图页,对 PCB 会报错) |
|
||
| `shot_pcb_region.py <out> <x0> <y0> <x1> <y1>` | 截 PCB 的指定 mm 区域。**方向错误只有放大了才看得出来**,整板图上一个 SOT-23-6 才几个像素 |
|
||
|
||
|
||
### 1. PCB 导入终于点下去了:357 → 391 元件
|
||
|
||
上一轮卡在「`importChanges()` 弹了确认框但点不了」(屏幕会话拿不到,`CopyFromScreen`
|
||
报 handle invalid)。**这轮换了个办法绕过去:桥接执行的 JS 能拿到主窗口的 `document`**,
|
||
所以弹窗可以直接用 DOM 点:
|
||
|
||
```js
|
||
[...document.querySelectorAll('button')].filter(b => b.innerText.trim()==='应用修改')[0].click();
|
||
```
|
||
|
||
弹窗本身在 `div[class^=lc_modal_dialog__body]` 里,变更表是**虚拟滚动**的,
|
||
DOM 里只有可见的那几行(想抓全表得滚动收集,实测容易撞 30 s 桥接超时,没必要)。
|
||
|
||
结果 **357 → 391**(新增 39、删掉 5 个 USB-A)。上一轮预估的 386 少算了几个。
|
||
|
||
**做了一次逐位号对账**(`.claude/refresh_cache.py` 顺带的能力):
|
||
原理图进 PCB 的 391 个 ↔ PCB 的 391 个,**重号 0 / 漏 0 / 多余 0**,
|
||
C801~C806 正确地没进来。
|
||
|
||
### 2. 【C】带按板载 Hub 重排(`.claude/pcb_place.py`)
|
||
|
||
USB-A 腾出来的 75 mm 板边给了 Hub。现在是:
|
||
|
||
```
|
||
x 2..28 【C1】12V→5V(U30 + L3 + Cin/Cout)—— 靠左板边,离 J1 的 12V 近
|
||
x 30..62 【C2】板载 Hub:J23 USB-C 在下板边 / U32 QFN-64 / Y1 / U31 3V3 LDO
|
||
x 64..198 【C3】五路 TPS22918 + J17~J21 出线,节距 27 mm
|
||
```
|
||
|
||
D± 全程留在这一带里,不纵穿五路 Buck 的电感与 SW 铜箔(§15.3)。
|
||
Hub 那 27 个件**全部手排**:仿射映射会把 strap 电阻甩进 U32 与晶振之间那条
|
||
1.8 mm 的缝里,而两个落在**同一点**的器件在推挤迭代里是对称的、永远分不开
|
||
(R719/R720 就卡在那儿,`relax()` 跑 3000 轮也出不来)。
|
||
|
||
### 3. 截图看出来的四个真错误(几何检查全都查不到)
|
||
|
||
| # | 错误 | 为什么本地检查抓不到 |
|
||
|---|---|---|
|
||
| 1 | **U30 的 Cin 摆在了封装的另一侧**,热回路绕整个封装 | 检查只管重叠/越框,不管「哪个焊盘挨着哪个」 |
|
||
| 2 | **五路负载开关的四个卫星件全部左右镜像**(CIN/ON 该在右、COUT/CT 该在左) | 同上,而且五路一起错 |
|
||
| 3 | **J22 调试口开口朝板内** | 封装本体外形 API 取不到,`box()` 用的是对称框 |
|
||
| 4 | **U20 ESP32 模组整块压出右板框 2.7 mm** | 同上 —— 模组原点在焊盘形心,天线端往外还有 7 mm |
|
||
|
||
**根因是同一个**:`rot=0` 时 SOT-23-6 的 **1/2/3 在右列、4/5/6 在左列**,
|
||
和画原理图时的直觉相反。现在是照着焊盘坐标读回来写死在注释里的,不是猜的:
|
||
|
||
```
|
||
U30 / U24~U28 (SOT-23-6, rot=0)
|
||
右列 自下而上 pin1(-0.94) / pin2(0) / pin3(+0.96)
|
||
左列 自下而上 pin6(-0.94) / pin5(0) / pin4(+0.96)
|
||
```
|
||
|
||
3 和 4 已经在 `FP_BODY` 里补了两条**手量的不对称本体框**(USB-C、ESP32 模组),
|
||
以后再动这两个器件,`check()` 就能自己拦住了。
|
||
|
||
> **读回焊盘框有个坑**:`getState_Pad()` 给的 `w/h` 是**未旋转**的,
|
||
> 所以对 `rot≠0` 的元件,我那段「px−w/2」算出来的框是错的(J22 的 x/y 跨度和
|
||
> 同封装的 J23 对不上就是这么发现的)。要拿准确的框,得先把元件转回 `rot=0` 读一遍再转回去。
|
||
> `pcb_place.py` 的 `FP_PAD` 只收 `rot==0` 的实例,正是为了避开这一条。
|
||
|
||
### 4. P4B-HUB 的压字
|
||
|
||
6 行注释横穿 J23 的符号(几何验证不看文字)。注释挪到 U32 右下的空白带
|
||
(`sch (460, 210~300)`)—— 一次挪过头压到标题栏上,又上移了 30。
|
||
|
||
> 每次重画 P4B,`importChanges` 都会报 4 行 `J23/R717/R718 修改网络`:
|
||
> CC1/CC2 是**没有旗/端口的页内两脚网络**,`w('CC1', …)` 那个名字不会落到网表上,
|
||
> 每次重画都重新分配一个 `$15Nxxx`。**是噪声不是错误**,已按提示应用。
|
||
> 想根治就给这两条网络各加一对端口。
|
||
|
||
---
|
||
|
||
## 前四轮做了什么(都在 2026-09-03)
|
||
|
||
### 0. P5-HARNESS(新增,原理图 10 页画齐了)
|
||
|
||
线束页,§20。四个分区:【A】三条线束的板端↔手机端连接图、【B】手机侧电容组(真电路)、
|
||
【C】五路对照表、【D】五条红字警告。除【B】外全是**非电气图元**
|
||
(矩形 / 折线 / 富文本),不参与网表。模型在 `.claude/p5_harness.py`。
|
||
|
||
**手机侧电容组 C801~C806 是离板件**:`addIntoBom=false / addIntoPcb=false`,
|
||
读回确认过。只画了 CH1 一套,CH2~CH5 位号见页上的【C】表。
|
||
|
||
**顺手补了一个真缺口**:`VOn_P`(Rs*01 之后 → J*.1 / Q*02 / INA226 的 VIN−、VBUS)
|
||
原来是**页内一段没名字的网络**,P5 的电容组挂不上去。已在五页各加一个
|
||
`VOn_P` 端口(`(960,745)`,`dir='OUT'`,从 J2 那根横线上引 50 长支线),
|
||
五页重推 + 六项验证全过。
|
||
|
||
> ⚠️ `VO2_P`~`VO5_P` 全工程只有 1 个实例(P5 只画了 CH1 一套电容组),
|
||
> 这不是漏接。`.claude/xpage.py` 新增 `NAMING_ONLY` 集合把它们列为例外,
|
||
> 哪天补画 CH2~CH5 的电容组就删掉。
|
||
|
||
---
|
||
|
||
## 前三轮
|
||
|
||
### 1. 五路复制(新增 P2B~P2E 四页)
|
||
|
||
用 `dmt_Schematic.copySchematicPage` 从 P2 复制,再由
|
||
`.claude/p2gen.py`(模型)+ `.claude/p2push.py`(下发)按通道号改写位号 / 网络名 / 地址跳线。
|
||
|
||
**复制时发现母版上有两个真问题,五页一起修了**:
|
||
|
||
1. **`K1_VUP` 端口其实没连上。** 它的引脚坐标和 `R122.1` 完全重合,
|
||
靠一段**零长度导线**"连着"。几何验证在旧 P2 上不报,是因为那段零长度线
|
||
恰好落在引脚上;真按这个网表打样,那一路音量+ 很可能是断的。
|
||
三个按键端口 + `VDAC1` 现在统一改走**向上 40 的短支线**,末端才放端口。
|
||
2. **两处标签压字**:`VDAC1` 与 `K1_PWR` 的标签面对面撞在一起(渲染成 `VDACK1_PWR`);
|
||
J7 的地旗文字压在 `Q105` 的位号上(渲染成 `G5)5`)。
|
||
|
||
⚠️ **所以 CH1 也重画了一遍**(元件没动,只重画了导线 / 旗 / 端口 / 文字)。
|
||
用户之前确认过的是旧版 P2,**这一页要重新看一眼**。
|
||
|
||
### 2. INA226 地址按布线难度重排(§8.2)
|
||
|
||
INA226 的 A1/A0 各能接 GND / VS / SDA / SCL,但**只用 GND 和 VS 只能凑出 4 个地址**
|
||
(0x40/0x41/0x44/0x45),全板要 6 个,必然有两片得把地址脚搭到 I²C 线上。
|
||
原来的顺排(0x40~0x44)会让 CH3 接 SDA、CH4 接 SCL,而 A0 脚上下正好夹着
|
||
Alert 和 SDA 两根横线,往 SCL 拉必然跨线。
|
||
|
||
| | 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 |
|
||
|
||
这样五个通道里只有 CH5 需要搭 SDA(0 交叉),剩下那个 SCL 落到 U13 头上——
|
||
它画在 P1 的空白区,布线自由。
|
||
**代价:通道号不再等于地址低位,固件里要查表,不能算。**
|
||
|
||
### 3. P1 补输入侧检流(§19)
|
||
|
||
`U13 INA226 + Rs6 5mΩ + C11`,量 12V 母线,地址 **0x43**(A1=GND / A0=SCL)。
|
||
体电容在 Rs6 **上游**,所以量到的是负载电流;满板约 8A → 40mV(满量程 81.92mV)。
|
||
U13 转了 90°,VIN+/VIN−/VBUS/GND/VS+ 五个脚朝上正对分流电阻,I²C 朝下走空白区。
|
||
|
||
**又挖出一个同类真错误**:P1 上 `BLD_REF`/`BLD_A` 两个端口的引脚坐标和 U29(TL431) 的
|
||
REF / 阴极完全重合,靠**零长度导线**"连着"。已挪开 40 并补真导线。
|
||
这类错误几何验证抓不到(零长度段会让"引脚落在导线上"通过),只有重画那一页才暴露——
|
||
规律已写进 skill §8a。
|
||
|
||
### 4. 之前:P4-USB(§18)
|
||
|
||
五路 TPS22918 负载开关,一路一列,D±/GND 直通、只切 VBUS,全页 0 处交叉。
|
||
`ON` 下拉 / `CT` 摆率 100pF / `QOD` 短接 VOUT / `CIN>COUT` 四条按 datasheet 定稿。
|
||
|
||
> ⚠️ **TPS22918 的引脚号**:datasheet 引脚图的文字被排版拆开后读起来像
|
||
> `1 VOUT / 2 QOD / …`,和 Pin Functions 表相反。按文字坐标还原后确认**表是对的**:
|
||
> `1 VIN / 2 GND / 3 ON / 4 CT / 5 QOD / 6 VOUT`。接反了图上看不出来。
|
||
|
||
## ✅ 板载 USB Hub(2026-09-03 做完原理图部分)
|
||
|
||
外部只留**一根 USB 线**。用户拍板:**USB2517I 单片 7 口** + **USB-C 上游口**。
|
||
硬件配置逐条对 datasheet 复核,写在设计文档 **§21**;5V 轨与 LDO 见 **§9.4 / §9.5**。
|
||
|
||
### 最终方案
|
||
|
||
| 项 | 结论 |
|
||
|---|---|
|
||
| Hub | **U32 = USB2517I-JZX**(C478081,QFN-64);口 1~5 给手机,口 6/7 用 10k 上拉禁用 |
|
||
| 配置 | `CFG_SEL[2:0]=000` → 内部默认配置 + strap 使能;**寄存器 06h 默认 9Bh、bit7=1 = 自供电** |
|
||
| 上游口 | **J23 USB-C(UFP)**,CC1/CC2 各 5.1k 下拉,不做 PD |
|
||
| 下行 VBUS | **板上 5V 轨**(U30 = 第二片 LMR51430,12V→4.98V),经 U24~U28 由 ESP32 通断 |
|
||
| Hub 的 3.3V | **U31 AMS1117-3.3 专供**(Hub 满配约 420mA,挂不上 U19 那条 0.5A 控制轨) |
|
||
| Hub 复位 | **U22.Q7**(74HC595 唯一那个空着的输出)→ `HUB_RST`,R716 10k 上拉 |
|
||
| 删除 | **J12~J16 五个 USB-A 母座** |
|
||
|
||
### 三个 datasheet 陷阱(都已避开,细节在 §21)
|
||
|
||
1. **别下错手册**:Microchip 站上 `00001692C.pdf` 是 USB251x**B** 系列(另一世代)。
|
||
我们这颗要看 **`2517.pdf`(SMSC USB2517 Rev 2.8)**。
|
||
2. **引脚图和引脚表打架**(`RBIAS` 图上读作 64、表里是 63)。
|
||
按坐标还原引脚图后确认**表是对的** —— 和 §18 的 TPS22918 同一个套路。
|
||
库里的符号也与表一致,三方对上了才动笔。
|
||
3. **必须是自供电**。声明成总线供电,主机按每口 100mA 做功率预算,
|
||
而手机描述符要 500mA → **主机拒绝配置,手机根本枚举不上**。
|
||
靠 `CFG_SEL=000` 走内部默认值拿到自供电,不需要 EEPROM。
|
||
|
||
### 验证结果
|
||
|
||
| 页 | 结果 |
|
||
|---|---|
|
||
| P4B-HUB | 27 元件 / 112 导线段,六项全过,**0 处交叉**,32 个脚在 NC 清单 |
|
||
| P1B-5V | 12 元件 / 44 导线段,六项全过,2 处合法交叉(+12V×SW5V、SW5V×CB5V) |
|
||
| P4-USB | 30 元件 / 180 导线段,六项全过,0 交叉 |
|
||
| P3B-EXPAND | 重推(加 HUB_RST),六项全过 |
|
||
| 跨页对账 | **0 个漏接**(12 页);`+5V`/`+3V3_HUB`/`HUB_RST`/`USB1~5_D±` 全部两端对上 |
|
||
|
||
> **顺手修了一个遗留真错误**:P3B 的 `C611`(DAC 的 CAP 旁路 2.2µF)在页面上被挪动过,
|
||
> 位置与 `p3b_nets.py` 的接线对不上,两个脚都是悬空的。上一轮没重跑 P3B 的验证所以没发现。
|
||
> 已按 skill §8d 用 `rot=270` 摆回横放(**这颗 0805 传 rot=0 反而是竖的**)。
|
||
|
||
### 这一页为什么满是网络端口
|
||
|
||
U32 是 65 脚 QFN,33 脚在左、32 脚在右,脚间距只有 10。外围器件直接连脚必然打结。
|
||
做法:每个用到的脚只引一小段 stub,末端放**网络端口当页内标号**,
|
||
器件按功能分块摆在四周,块间靠端口名对上。
|
||
netport 约 10 单位高,在 10 的脚间距上排一列不重叠(skill §8b-2);netflag 有 20 高,放不下。
|
||
J23 的 USB-C 正反脚也用**端口重名**并联,省掉了 Type-C 固有的一堆交叉(P3 的 J22 当年是靠绕线解的)。
|
||
|
||
### 这三件收尾都已经做完(2026-09-03 晚)
|
||
|
||
- PCB 导入已应用(357 → 391),逐位号对账通过。
|
||
- 【C】带已按 Hub 重排并下发,391 个全部在框内、无重叠。
|
||
- 三张空白截图已重截,都是好的。
|
||
|
||
---
|
||
|
||
## ⭐⭐ 第二件事:主板载板(2026-09-03 用户提出,尚未动手)
|
||
|
||
**需求原话**:「底板是现在设计的电源板,另外做一块板子,按照主板定位孔设计,
|
||
将 5 块主板固定在这块板子上,固定主板的板子直接对插到我们现在设计的这块板子」。
|
||
|
||
即两块板叠起来:
|
||
|
||
```
|
||
┌─────────────────────────────────────┐
|
||
│ 载板:按小米8 主板定位孔打孔,装 5 块主板 │
|
||
│ 每台的 P+/P− 焊盘 + §6.3 电容组 │
|
||
│ 侧键触点(顶针?)+ USB │
|
||
└───────────┬─────────────────────────┘
|
||
│ 板对板对插(电源 4A×5 + 信号约 30 根)
|
||
┌───────────┴─────────────────────────┐
|
||
│ 底板:现在这块 200×150 五路电源板 │
|
||
└─────────────────────────────────────┘
|
||
```
|
||
|
||
### 这是好事,但先说清楚它推翻了什么
|
||
|
||
**推翻的:**
|
||
- **§15.4 的线束基本消失** —— 现在图上的 J2~J6(Micro-Fit)/ J7~J11 / J17~J21
|
||
共 15 个连接器,会被**板对板连接器**取代。
|
||
- **P5-HARNESS 那页要重写**(它现在画的是线束)。
|
||
- **PCB 布局的连接器分边决策作废**。我 2026-09-03 排的「上边=电源+按键、
|
||
下边=USB 子系统」是为了线束走向和 D± 不穿功率区;改成板对板之后,
|
||
接口位置由**机械叠层**决定,不是由「线从哪出」决定。【A】【C】两带都要重排。
|
||
|
||
**变好的(值得高兴的一条):**
|
||
- **§6「最容易翻车的地方」大幅缓解。** 原方案是 20 cm 线缆 ≈ 300 nH,
|
||
射频突发 2 A/µs 时压降 0.6 V。改成板对板后回路电感掉到大约 30~50 nH 量级,
|
||
同样 di/dt 下压降约 0.1 V。粗算 L=50nH / C=2200µF:
|
||
f_res 从 6.2 kHz 升到约 15 kHz,Z0 从 11.7 mΩ 降到约 4.8 mΩ,
|
||
Q = 4.8/(走线+触点 R + ESR 60mΩ) ≈ 0.07,**比原来还过阻尼**。
|
||
→ **§6.1 / §6.2 的数要重算**;C801 用普通铝电解做阻尼这条依然成立(更保险了)。
|
||
- **§6.4「大电容必须在排线端」自动满足** —— 电容组直接放在载板上 P+/P− 焊盘旁边,
|
||
离得比原来更近,而且是贴片工艺,不用手焊线束。
|
||
|
||
### ✅ 头号阻塞项已解除(2026-09-04):机械数据一直就在我们手里
|
||
|
||
**下面这段旧结论是错的,留着当教训**:曾经断定
|
||
「`Xiaomi_Mi_8_Schematic.pdf` 是电气原理图,不含任何机械尺寸,只能实测」。
|
||
|
||
实际上那份 PDF 共 46 页,**前 2 页是正反面位号图**(含完整板框轮廓 + 全部位号),
|
||
后 44 页才是原理图。当初只按「原理图」去读,`get_text()` 一看全是位号就跳过了,
|
||
从没渲染出来看一眼 —— **一张图看 5 秒就能推翻的结论,靠翻文字翻了一整轮**。
|
||
|
||
已经从中反推出:比例尺 17.0 pt/mm、主板 ≈ 45.0 × 66.8 mm、
|
||
J600 / J1401 / TP1204 / TP1205 / J601~J604 的坐标与所在面。方法与数据见设计文档 **§22.3**。
|
||
|
||
⚠️ 仍需用户做一件事:**用卡尺核一次主板长宽**。45 mm 对 74.8 mm 的机身偏窄,
|
||
怕比例尺有系统性偏差;后面所有孔位都按这个尺子换算。
|
||
|
||
### 六个待定项
|
||
|
||
1. **电池那一路怎么接。** §13.5 已经论证过:**必须保留原厂 BM3E 排线**
|
||
(立创只有母座 `5050040812`,**没有对插的公座**;而且 `BATT_ID` 可能是
|
||
1-wire 认证 IC,复制不了)。所以载板上做 `P+`/`P−` **焊盘**,
|
||
排线一头焊在载板、另一头插回主板 J600。
|
||
⚠️ **§13.5 那条「别焊错边」的坑原样保留** —— 只是从焊线束变成焊到载板焊盘。
|
||
2. **侧键触点怎么接。** J601~J604 是主板上的**弹片触点**。
|
||
载板上用**弹簧顶针(pogo pin)**顶上去最干净,但要求机械对位准
|
||
(定位孔正好提供这个基准)。前提是主板装上去时触点那一面朝着载板 —— 要先确认第 2 项。
|
||
3. **USB 怎么从尾插小板引到载板。** USB-C 母座在原厂尾插小板上,
|
||
小板靠 FPC 插主板 J1401。最省事:一根短 USB 线从小板 USB-C 到载板上的连接器。
|
||
要不要把尾插小板也固定在载板上,一起定。
|
||
4. **板对板连接器选型 —— 这条最难。** 每台 2 根电源(**4A**)+ 4 根按键 + 4 根 USB = 10 根,
|
||
五台共 50 根,其中电源合计要过 **20 A**。单个信号 BTB 扛不住。
|
||
现实做法是**电源与信号分开**:电源用大电流连接器或多针并联,
|
||
信号用普通 BTB;D± 那 5 对还要满足 §15.3 的 90Ω 差分。
|
||
5. **叠层间距(立柱高度)。** 底板上现在有一批**高个子**:
|
||
C2/C3 470µF 直插电解(约 10~12 mm)、R9 水泥电阻(约 9 mm)、
|
||
~~J12~J16 USB-A 母座~~(Hub 改造后已全部删除,板上最高的连接器变成 J23 USB-C,约 3.2 mm)、
|
||
U20 ESP32 模组。要么立柱够高,要么把这些挪到不被载板压住的区域。
|
||
6. **和「板载 USB Hub」那件事的关系。** 两件事都动 USB 接口,**建议一起设计**:
|
||
Hub 改造让外部只剩一根线,载板改造让内部不用线束 —— 合起来才是
|
||
「一根 USB + 一根 12V 进来,五台手机插上去就行」。
|
||
|
||
### 建议的推进顺序
|
||
|
||
1. **先量主板**(上表 1~4)。拿不到机械数据,载板一步都走不了。
|
||
2. 量的同时可以**并行做 Hub 改造**(那件事不依赖机械数据)。
|
||
3. 机械数据到手后:定叠层与板对板连接器 → 画载板外形与孔位 →
|
||
反过来改底板的接口区布局。
|
||
4. **底板的功率部分(P1、五路 Buck、控制)不受影响**,不用重画。
|
||
受影响的只有「接口怎么出板」这一层。
|
||
|
||
### 改完要同步的地方
|
||
|
||
| 位置 | 改什么 |
|
||
|---|---|
|
||
| 设计文档 **§6.1 / §6.2** | 线缆电感 300nH → 板对板约 50nH,压降与 Q 重算 |
|
||
| 设计文档 **§6.3 / §6.4** | 电容组从「装在排线端」改成「装在载板上 P+/P− 焊盘旁」 |
|
||
| 设计文档 **§13.3** | 侧键从飞线改成顶针(如果定了顶针方案) |
|
||
| 设计文档 **§15.4** | 线束表基本作废,改成板对板接口定义表 |
|
||
| 设计文档 **新增一节** | 载板:机械、孔位、叠层、板对板连接器 |
|
||
| 原理图 **P5-HARNESS** | 从「线束页」改成「载板接口页」 |
|
||
| 原理图 **P2 系列 / P4** | J2~J6 / J7~J11 / J17~J21 换成板对板连接器的一部分 |
|
||
| **PCB** | 接口区重排;载板是**第二块 PCB**(EasyEDA 里新建一个 Board) |
|
||
|
||
---
|
||
|
||
## PCB(2026-09-03 转板完成)
|
||
|
||
`PCB1`(uuid `7e9415a16a909c51`)挂在 Board1 下,关联原理图 `c63aa0a04d951314`。
|
||
|
||
| 项 | 结果 |
|
||
|---|---|
|
||
| 铜层 | `pcb_Layer.setTheNumberOfCopperLayers(4)` → 顶层 / **Inner1-GND** / **Inner2-PWR** / 底层 |
|
||
| 元件 | **357 个**,与原理图逐个对上,无重号 |
|
||
| 网络 | 227 个 |
|
||
| 日志 | 致命错误 0 / 错误 0 / 警告 0 |
|
||
| P5 的 C801~C806 | ✅ **没有进来**(`addIntoPcb=false` 生效) |
|
||
|
||
### 转板要知道的三件事
|
||
|
||
1. **`pcb_Document.importChanges()` 返回 `true` 只表示「弹窗开了」**,不代表导入完成。
|
||
它会弹一个「确认导入信息」对话框列出全部变更,要点右下角的 **「应用修改」** 才真的写进去。
|
||
API 里没有确认这一步的接口,canvas 截图也拍不到弹窗(截图只有画布)——
|
||
要看弹窗得截整屏(`System.Drawing` 的 `CopyFromScreen`)。
|
||
2. **导入前先 `sch_Document.save()`**,否则 API 改的内容可能还没落盘。
|
||
3. **「元件 $Ixx 唯一 ID 与其他元件重复」那 578 条提示是良性的。**
|
||
来源是 P2B~P2E 由 `copySchematicPage` 复制而来、内部唯一 ID 撞车,
|
||
EasyEDA 生成网表时自动重分配。**担心的是「每次重分配结果不同 → 以后改原理图会把布局冲掉」,
|
||
已实测排除**:第二次 `importChanges` 日志是「无变更,原理图与 PCB 已经匹配!」,
|
||
说明重分配是确定性的,后续是增量更新。
|
||
|
||
## PCB 布局(2026-09-03;第一遍见下,第二遍见开头「本轮」那节)
|
||
|
||
板框 **200 × 150 mm**,原点在**左下角**,**Y 向上**,API 单位 **mil**(`sys_Unit.getFrontendDataUnit()`)。
|
||
模型在 `.claude/pcb_place.py`(`--push` 下发)。
|
||
截图:`PCB-layout-v1.png`(第一遍,357 元件)/ **`PCB-layout-v2.png`(当前,391 元件)**。
|
||
|
||
### 分区(2026-09-03 用户拍板板框尺寸 + 连接器边)
|
||
|
||
```
|
||
y=150 ── 上边:每路 J2~J6 电源 Micro-Fit + J7~J11 按键 4P(去手机)
|
||
【A】五路功率级 y 86~150,每路 40 mm 宽,同方向横排(§10.3)
|
||
y= 86 ──
|
||
【B】P1 输入(左 x0~96) │ P3/P3B 控制(右 x96~200) y 42~86
|
||
y= 42 ──
|
||
【C】USB 子系统 y 0~42(**已按板载 Hub 重排**,见开头「本轮」第 2 节)
|
||
y= 0 ── 下边:唯一的外部 USB 口 J23 在这条边上
|
||
```
|
||
|
||
左短边 = J1 12V 接线端子;右短边 = J22 调试 USB-C + U20 ESP32(天线朝板边)。
|
||
|
||
### ⚠️ 与用户选择的一处偏离(已知,等确认)
|
||
|
||
用户选的是「手机的三根线束全部同点出板」。但 J17~J21 放上边的话,
|
||
**D± 必须纵穿五路 Buck 的电感与 SW 铜箔**,这是 §15.3 明令禁止的
|
||
(比线长本身严重得多)。所以实际排的是:
|
||
|
||
- 上边 = 每路的**电源 + 按键**(两根线束同点出板)
|
||
- 下边 = **整个 USB 子系统**,J12(上游)与 J17(去手机)相距约 19 mm,D± 全程留在 USB 带里
|
||
|
||
要恢复成「三根同点」就把 J17~J21 挪到上边,代价是 D± 穿功率区。
|
||
|
||
### 怎么排的
|
||
|
||
- **五路功率级是显式手排**(`pcb_place.py` 的 `CH1` 表),自下而上:
|
||
反馈/补偿 → Buck(Cin 贴 VIN/GND)→ 电感/输出 → eFuse → 分流+INA226(Kelvin)→ 连接器。
|
||
按键驱动放右列,远离 SW。CH1 排好后按 40 mm 节距平移复制五份(§10.3 同方向)。
|
||
- **P1 / P3 / P3B 按原理图坐标仿射映射**进各自分区,再跑分离迭代消重叠——
|
||
原理图上的功能分组画图时就想清楚了,直接当粗排初值。
|
||
- 本地检查:重叠 0、越框 0。
|
||
|
||
### 踩到的三个坑
|
||
|
||
1. **封装本体不一定以原点对称。** USB-A(KH-AF90ZJ)本体从原点往 −Y 伸 **10.7 mm**、
|
||
往 +Y 只有 1 mm。按对称尺寸算,第一次放 y=8 时本体伸出板框 2.7 mm,
|
||
而本地检查(用对称框)查不出来,是截图看出来的。已改到 y=11.5。
|
||
2. **API 取不到封装的本体外形。** `pcb_PrimitiveLine.getAll()` 只返回板框那 4 条,
|
||
元件内部的丝印 / 外形图元不外露(和原理图里 `sch_PrimitivePin.getAll()` 对元件实例
|
||
返回空是同一个套路)。能读回来的只有**焊盘**:
|
||
`component.getState_Pads()` 给的是 `{primitiveId, net, padNumber}`,
|
||
要用 `pcb_PrimitiveComponent.getAllPinsByPrimitiveId(id)` 才拿得到真实坐标,
|
||
焊盘尺寸在 `pad.getState_Pad()` = `["RECT", w, h, r]`。
|
||
所以 `pcb_place.py` 的占位框 = 标称本体框 ∪ 真实焊盘框,
|
||
板边连接器另有一张**手量的** `FP_BODY`。**「本体伸出板框」只能靠截图人眼看。**
|
||
3. **`zoomToRegion` 的参数是 `(left, right, top, bottom)`**,不是 (x0,y0,x1,y1)。
|
||
传错了不报错,只是没缩放。
|
||
|
||
### 下一步(按顺序)
|
||
|
||
1. **人眼确认 `PCB-layout-v4.png`**,尤其下面「等确认」那几条。
|
||
2. ~~设计规则~~ **已全部下发**(`pcb_rules.py --push`,`--check` 七项全 OK)。
|
||
Hub 到五路的 D± 最长约 **140 mm**(U32 在 x=45、CH5 在 x=185),
|
||
USB 2.0 HS 走得了,但必须是受控阻抗,且五对要**等长成对**。
|
||
3. 精调关键回路(§10.2):五路 Buck 的 Cin 热回路 / SW 铜箔 / FB 走线 / Kelvin 取样,
|
||
调好再重新复制五份;**U30 那一路的 SW 只能走 x 13.9~15.4 那条 1.5 mm 的缝**
|
||
(VIN 与 GND 夹着 SW 是这个封装的固有形状,绕不开)。
|
||
4. U31(SOT-223,耗散约 0.71 W)与 U32 的散热铺铜。
|
||
5. 灌铜(Inner1-GND 整片不许割断;Inner2-PWR 走 12V + 5V + 五路输出)→ 布线 → DRC。
|
||
|
||
### 等用户确认的事(几何验证证明不了)
|
||
|
||
- **板边连接器的朝向**。都是**从渲染图上量出来的推断,要对着连接器图纸核一眼**——
|
||
接反了板子做出来插不进去:
|
||
- `J2~J6` Molex **43650 右角式**,转 180° 让开口朝上板边(未改动)。
|
||
- `J23` / `J22` USB-C:焊盘在 +Y、壳体往 −Y 伸 5.2 mm,也就是 **rot=0 时开口朝 −Y**。
|
||
J23 rot=0 开口朝下板边;**J22 这轮从 270 改成了 90**(原来开口朝板内)。
|
||
- `J1` KF128:丝印上两个大箭头 = 进线方向,rot=0 时朝 +Y(板内),
|
||
**这轮改成了 90,进线朝左板边**。箭头到底是不是进线方向,请核一眼。
|
||
- `U20` ESP32 模组:**这轮从 x=186 挪到 183.2**,让整块模组(含天线端)不出框。
|
||
如果你本来就想让天线**伸出板外**,那要挪回去并把板框改成带缺口的形状。
|
||
- 丝印位号大面积压字(EasyEDA 自动生成的),布线前要单独跑一遍丝印整理。
|
||
|
||
## 打样前的阻塞项(都不需要电源板,可并行做)
|
||
|
||
1. **排线旁路验证**(设计文档 §13.7)—— 确认焊在 `P+`/`P−` 而非 `B+`/`B−`。
|
||
判定性测试是第 3 步:可调电源升到 **4.40V**,BTB 座电压必须跟随且不断开。
|
||
2. **侧键触点定位**(§13.3)—— 万用表 5 分钟,拍照存档。带电验证那一步是安全闸门。
|
||
3. **环路补偿实测**(§9.2)—— 图上按 fco≈18kHz 放了 R106/C110/C111,三个位置都留了焊盘。
|
||
|
||
## 已知遗留
|
||
|
||
- **上游用的是 USB-A 母座**(§15.1 定的),所以板到 Hub 之间是一根 **A 公 - A 公**线。
|
||
这不是标准 USB 用法;好处是物理上插不了充电头(VBUS 一旦被抬到 9V,
|
||
TPS22918 的绝对最大 6V 会当场炸)。要换 USB-B / Type-C 就趁现在,改 5 个连接器而已。
|
||
- **C7(P1 上 U19 的输入去耦)只有 2.2 µF**,datasheet 要求高频去耦 ≥4.7 µF。
|
||
建议改成 10 µF/50V 0805(C440198,BOM 里已有)。不改也能工作,
|
||
但 PCB 上必须把 C7 贴到引脚旁。§9.3
|
||
- **电感 Isat 略低于目标**:SPM6530T-4R7M 是 Isat 6.2A,原定 ≥7A。
|
||
正常峰值 4.61A、eFuse 限流工况 5.08A 都够;但 Buck 高侧限流 datasheet 是
|
||
**8/11/14A**,打嗝保护触发时电感会短暂深度饱和。首板要确认发热与饱和表现。
|
||
- **eFuse 最坏容差下可能到 4.519V 才跳**,超过 1S 上限 4.45V 约 60mV。已接受,理由见 §5。
|
||
- **PCA9555 的 4 个备用脚直接接地**(不串电阻),依赖"上电默认为输入"。
|
||
**固件严禁把 Port0[7] / Port1[7:5] 配成输出。**
|
||
- **U29 泄放的 R9 是突发额定**(10Ω/5W,13.3V 下 17.7W),
|
||
持续故障靠固件监控输入电压兜底:>13.0V 关全部 VBUS,>13.8V 关全部 EFUSE_EN。
|
||
- 交叉点:P2 系列各 6 处、P3 有 1 处(USB-C 的 D± 交叉,Type-C 固有)、P4 是 0 处。
|
||
几何验证确认互不相连。
|
||
- **手机侧 C802/C803 用了 MLCC 代替聚合物**(§6.3)。立创基础库里没有 100µF/6.3V 聚合物,
|
||
改用 100µF/6.3V X5R 1206(C15008)。**3.9V 偏压下每颗只剩约 40 µF**,
|
||
中频段储能从 200 µF 掉到约 80 µF。C801 的 2200 µF 才是主力,估计影响不大,
|
||
但这是个**待用户拍板**的偏离:要严格照原方案就得单独采购聚合物。
|
||
- **C801 是选型陷阱**:必须买普通铝电解(C49256788,ESR 数十 mΩ)。
|
||
同尺寸的聚合物 C53446724(ESR 12 mΩ)会让线缆 LC 的 Q 从 0.19 回到 4.5 而振铃。
|
||
这一条已写成 P5 页上的红字。
|
||
|
||
## 沉淀下来的工具(`.claude/` 下)
|
||
|
||
| 文件 | 用途 |
|
||
|---|---|
|
||
| `eda.py` | 跑任意 JS 到桥接:`python .claude/eda.py x.js`。HTTP 500 会带出中文错误原文 |
|
||
| `place.py` / `place4.py` | 批量放置元件;`place4.py` 支持 mirror(位置表 `p4_pos.py`) |
|
||
| `fetch_pins.py` | 导出某页的真实引脚坐标成 `pins.json` |
|
||
| `build.py` | 本地几何检查 + **分批**推送(`--push`),用于 P3/P3B/P4 |
|
||
| **`p2gen.py`** | **五路母版模型**:几何来自 `p2-ch1.json`,按通道号改位号 / 网络名 / 地址跳线 |
|
||
| **`p2push.py`** | `python .claude/p2push.py <n> <pageUuid> --temp\|--final\|--push` |
|
||
| `p2-ch1.json` | CH1 页的几何快照(导线 / 旗 / 元件),是五页的唯一事实来源 |
|
||
| `shot.py` | 截图某页存 PNG —— **画完先自己看一眼,能省掉大部分返工** |
|
||
| `xpage.py` | 跨页网络对账,找"全工程只有一个实例"的网络 |
|
||
| **`drc_read.py`** | **跑 DRC 并把结果读回来**(DOM 抓 DRC 面板)。布局一改就跑,本地几何检查抓不到焊盘/钻孔间距 |
|
||
| `p3_nets.py` / `p3b_nets.py` / `p4_nets.py` | 三页的网表源码(改图改这里,再跑 build.py) |
|
||
| **`p4b_nets.py`** + `p4b_pos.py` | **P4B-HUB**:USB2517I 那一页的位置表与网表 |
|
||
| **`p1b_nets.py`** | **P1B-5V**:12V→5V + Hub 专用 LDO |
|
||
| **`p1_add.py`** | P1 的增量:导线/旗/文字整页重画(底稿 `p1-base.json`),**端口只增不重建** |
|
||
| **`p5_harness.py`** | **P5 整页模型 + 下发**(含文字越界 / 压标题栏的本地自检) |
|
||
| **`pcb_place.py`** | **PCB 布局模型 + 下发**(分区表 + CH1 手排 + 仿射映射 + 重叠/越框自检) |
|
||
| `pcb-parts.json` | PCB 侧 357 个元件的位号 / 封装 / 坐标(`--push` 前要重新读) |
|
||
| `pcb-pads.json` | 每个元件的**真实焊盘外框**(封装不对称时靠它,见上面的坑 1) |
|
||
| `sch-xy.json` | 每页元件的原理图坐标,仿射映射的输入 |
|
||
| `eda-parts.json` | 器件 + 工程/图纸/**全部 10 页**的 UUID |
|
||
|
||
> ⚠️ P2 早期的 `p2-nets.py` / `p2-pos.py` 等四个文件已和页面对不上(位号还是改号前的
|
||
> C1/R1,端口位置也是旧的),已挪到 **`.claude/obsolete/`**,别 import。
|
||
> 五路的唯一事实来源是 `p2-ch1.json` + `p2gen.py`。
|
||
|
||
### 位号改名要分两趟
|
||
|
||
`copySchematicPage` 会把复制页的位号自动改成不撞车的(C11~C24、U2/U3/U4……),
|
||
而这些恰好就是别的通道要用的号。一趟改名会撞号被 EasyEDA 悄悄改掉,
|
||
所以 `p2push.py` 先把**所有页**都改成 `Z<n>T<i>` 临时名(`--temp`),
|
||
再统一改成目标名(`--final`)。
|
||
|
||
## 新会话开工检查清单
|
||
|
||
0. **当前状态**:
|
||
- 🔴 **R2 刀片 PCB 正在推进中,见 `刀片式方案规划-R2.md` §25(2026-09-08 M5)**:
|
||
器件已全部翻到手机主板的**另一面**(A 面只留 10 件:`K1~K4`/`J5`/`J4`/`C60`/`J2`/`J3`/`J1`),
|
||
功率级改成手排,§7.2 四条关键回路全部达标(`loop_check.py` 是新的机器判据)。
|
||
布线 747 段 / 280 过孔,**DRC 间距 0 / 物理 0**,Buck 的 SW/BOOT/FB 都已接上。
|
||
⛔ **还欠**:**13 个网络**没接完(全是信号类,清单 `.claude/r2/_blade_open_nets.txt`;
|
||
这个数和之前记的「29 处」不可比,因为布线器原来在**六个地方**静默断线,见 R2 §25.8/25.10)、
|
||
**铺铜不落盘**(reload 后只剩 2 块,待查)。
|
||
- ✅ **板载 USB Hub 的原理图部分做完了**(12 页,跨页 0 漏接)。
|
||
还欠:**把新器件导进 PCB** + 【C】带重排 + **人眼看三张新图的截图**。
|
||
- ⭐⭐ **主板载板**(5 块主板固定在一块载板上,对插到底板)——
|
||
**卡在「没有小米8 主板的机械数据」**,只能等用户实测。
|
||
1. 桥接在不在:`/c/Python314/python .claude/eda.py` 随便跑一段 JS;不通就按下面「环境」起服务。
|
||
2. 页面 UUID 全在 `.claude/eda-parts.json` 的 `pages` 里(**12 页**都有),不用重新枚举。
|
||
3. **动手前读 `easyeda-sch-geometry` skill**,尤其 §8a(零长度导线)、§8b(端口 dir 决定标签朝向)、
|
||
§2(旗的 rot 语义,四种组合都实测过了)。
|
||
4. 还欠人眼确认的页:**P1-INPUT、P2-CHANNEL、P3-CONTROL、P3B-EXPAND、P5-HARNESS**,
|
||
以及这轮新改/新增的 **P4-USB、P4B-HUB、P1B-5V**
|
||
(P2B~P2E 与 P2-CHANNEL 完全同构,看一页即可)。
|
||
⚠️ 截图 API 有时会抓到**另一个窗口**(返回的 `windowId` 会变),拍出来只有元件没有导线。
|
||
遇到就换个时机重截,或直接在客户端里看 —— 先用 API 读回图元数量确认数据在不在,再判断。
|
||
5. 改完任何一页,跑 `verify_sch.py`(当前页)+ `xpage.py`(全工程),两个都要干净。
|
||
|
||
## 环境
|
||
|
||
- EasyEDA 桥接:`node C:/Users/35138/.claude/skills/easyeda-api/scripts/bridge-server.mjs`
|
||
后台运行,端口 49620~49629 自动选。客户端里要装 `run-api-gateway.eext` 扩展。
|
||
- Python:`/c/Python314/python`(Windows 路径写 `C:\Python314\python.exe`)。
|
||
已装 `pymupdf` —— **datasheet 可以直接下下来用 `fitz` 抽文字**(`get_text("words")`
|
||
带坐标,用来还原被排版拆散的引脚图,P4 就是靠这个确认 TPS22918 引脚号的)。
|
||
- 验证:`/c/Python314/python .claude/skills/easyeda-sch-geometry/scripts/verify_sch.py --nets`
|
||
(跑的是**当前打开的那一页**,所以要先 `openDocument`)。
|
||
- 清空上下文后,先看 `CLAUDE.md`,再看这份,然后读 `easyeda-sch-geometry` skill。
|