文件
phonerail/.claude/r2/b3_phone.py
T
zhou yang和Claude Opus 5 efcba30a0c R2 底板改 4 层(D15):规则 / 几何 / 背面摆位 / 4 层布线与铺铜,已下发
- 规则:铜层 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
2026-09-10 21:02:10 +08:00

191 行
9.4 KiB
Python
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
u"""R2 刀片 **B3-PHONE** 页:手机侧机械接口 —— 电池排线 + 阻尼组 + 侧键焊盘 + EDL。
/c/Python314/python .claude/r2/b3_phone.py # 只算 + 本地自检
/c/Python314/python .claude/r2/b3_phone.py --push # 清页 + 重画(幂等)
## ⚠️ M2c 拆成两页
R1 把同样的内容铺在**四页**上(`C4-SITE1` 电池/阻尼/顶针/EDL、`C5-J1401A` 尾插座、
`C5-AUX` ESD/Rp/口温、`C3-USB` VBUS 开关)。塞进一张 A4 会挤到没法看,所以拆成:
| 页 | 内容 |
|---|---|
| **`B3-PHONE`**(本页)| `J5` 电池排线 4 焊盘 + 阻尼电容组 + `K1~K4` 侧键中框焊盘 + EDL(`J3` + `U6`)|
| **`B3B-USB`** | `J4` BM24-50DS 尾插座 + `U7` USBLC6 ESD + Rp/口温 + `U5` TPS22918 VBUS 开关 |
## 位号(方案 §7.2b,D11b 之后 U 序顺移)
| 位号 | 器件 | 出处 |
|---|---|---|
| `J5` | MI8-BAT-FPC-4P(个人库自建,4 焊盘直焊排线)| R1 §13.5 的 `J81` |
| `R60/R61` | 10k TEMP→GND / 68k ID→GND | R1 的 `R781/R791`,阻值抄保护板实测 |
| `C60~C65` | 2200µF + 100µF×2 + 22µF×2 + 100nF | R1 §6.3 阻尼组 `C801~C806` 原样 |
| `K1~K3` | 侧键中框焊盘(Ø1.5 裸铜盘,`MI8-KEY-PAD`)| R1 §22.3e:顶针取消,螺丝把主板压在焊盘上 |
| `K4` | 侧键**公共地**焊盘(手机 J604)| 同上 |
| `J3` `U6` `R63` `C69` | EDL 1.25mm 2P 座 + TS5A3157 模拟开关 + 100k 下拉 + 去耦 | R1 §22.4 的 `J61/U41/R741/C761` |
## 两条要紧的
1. **`P+`/`P−` 接的是保护板输出侧**(R1 §13.5):排线从保护板焊点处剪断,
4 个焊盘 `1=P+ 2=P− 3=TEMP 4=ID`,`TEMP`/`ID` 都是**对 P− 的**,
按「对负极线」量会得出「三个都不通」的假结论。
2. **`EDL_EN` 的 100k 下拉(`R63`)放在本页**(贴 `U6` 的 `IN` 脚),
B2-CTRL 上没有 —— PCA9555 复位时是高阻输入,全靠这颗保证模拟开关断开。
"""
import os
import sys
HERE = os.path.dirname(os.path.abspath(__file__))
sys.path.insert(0, HERE)
from schcheck import Sheet, two_pin, by_rel, pins_of # noqa: E402
PAGE, NAME = 'cf32a688430fc2d1', 'B3-PHONE'
FPC, KEYPAD, EDLJ, SW = 'MI8-BAT-FPC-4P', 'MI8-KEY-PAD', 'C225104', 'C353034'
C2200U, C100U, C22U, C100N = 'C3828985', 'C15008', 'C12891', 'C1525'
R10K, R68K, R100K = 'C25744', 'C36871', 'C25741'
# 引脚偏移(R1 实测,见 _c4s1_live.json);rot 270 按 (x,y)->(y,-x) 推,放完断言
FPC_REL = {'1': (-20, 15), '2': (-20, 5), '3': (-20, -5), '4': (-20, -15)}
EDLJ_R270 = {'1': (5, 25), '2': (-5, 25), '3': (25, 25), '4': (-25, 25)}
SW_R270 = {'1': (10, 35), '2': (0, 35), '3': (-10, 35),
'4': (-10, -35), '5': (0, -35), '6': (10, -35)}
KEY_REL = {'1': (-15, 0)}
NC = {'U6': ['3']} # NC 脚不接(R1 的 U41.3 也是空的)
ALLOW_SPLIT = set(['GND', '+3V3'])
RAIL_Y = 760 # VO_P 母线
CAPS = [('C60', C2200U, 320, 20), ('C61', C100U, 400, 15), ('C62', C100U, 480, 15),
('C63', C22U, 560, 15), ('C64', C22U, 640, 15), ('C65', C100N, 720, 20)]
KEYS = [('K1', 'KPAD_PWR', 700), ('K2', 'KPAD_VUP', 640), ('K3', 'KPAD_VDN', 580)]
J5 = (260, 700)
J3 = (200, 340)
U6 = (620, 340)
def placement():
out = [['J5', FPC, J5[0], J5[1], 0],
['R60', R10K, 170, 640, 270], ['R61', R68K, 220, 600, 270],
['J3', EDLJ, J3[0], J3[1], 270], ['U6', SW, U6[0], U6[1], 270],
['R63', R100K, 760, 310, 270], ['C69', C100N, 1000, 300, 270]]
for des, lcsc, x, half in CAPS:
out.append([des, lcsc, x, RAIL_Y - 10 - half, 270])
for des, _net, y in KEYS:
out.append([des, KEYPAD, 1100, y, 0])
out.append(['K4', KEYPAD, 1100, 520, 0])
return out
def expect():
exp = {'J5': by_rel(J5[0], J5[1], FPC_REL),
'J3': by_rel(J3[0], J3[1], EDLJ_R270),
'U6': by_rel(U6[0], U6[1], SW_R270),
'R60': two_pin(170, 640), 'R61': two_pin(220, 600),
'R63': two_pin(760, 310), 'C69': two_pin(1000, 300)}
for des, _l, x, half in CAPS:
cy = RAIL_Y - 10 - half
if des == 'C60':
# ⚠ C60 是 2200µF **电解**:pin1(+) 必须在上(接 VO_P 母线)。
# 只比坐标集合是不够的 —— skill §6c:同一个料号在不同页 rot 语义能相反,
# 本页实测 rot 270 给出的就是「pin1 在下」,第一次推下去极性是反的,
# 而几何验证、DRC 全过,只有网表里「C60.2 在 VO_P」能看出来。
exp[des] = {'1': (x, cy + half), '2': (x, cy - half)}
else:
exp[des] = two_pin(x, cy, half)
for des, _net, y in KEYS:
exp[des] = by_rel(1100, y, KEY_REL)
exp['K4'] = by_rel(1100, 520, KEY_REL)
return exp
def build():
s = Sheet(PAGE, NAME)
# ── 1. 电池排线 + 阻尼组 ─────────────────────────────────────────
# 四个脚都朝左出,越靠下的脚拐得越靠右,往下走时才不会撞上面几行的横线
px = J5[0] - 20
s.w('VO_P', (px, 715), (200, 715), (200, RAIL_Y)) # 1 P+
s.w('GND', (px, 705), (120, 705), (120, 660)) # 2 P−
s.gnd(120, 660, 0)
s.w('BAT_TEMP', (px, 695), (170, 695), (170, 660)) # 3 TEMP -> R60
s.w('GND', (170, 620), (170, 595))
s.gnd(170, 595, 0)
s.w('BAT_ID', (px, 685), (220, 685), (220, 620)) # 4 ID -> R61
s.w('GND', (220, 580), (220, 555))
s.gnd(220, 555, 0)
s.w('VO_P', (200, RAIL_Y), (800, RAIL_Y)) # 母线
s.port('IN', 'VO_P', 800, RAIL_Y, 180)
for _des, _l, x, half in CAPS:
cy = RAIL_Y - 10 - half
s.w('VO_P', (x, RAIL_Y), (x, cy + half))
s.w('GND', (x, cy - half), (x, 685))
s.gnd(x, 685, 0)
# ── 2. 侧键中框焊盘 ──────────────────────────────────────────────
for _des, net, y in KEYS:
s.w(net, (1085, y), (1000, y))
s.port('IN', net, 1000, y, 0)
s.w('GND', (1085, 520), (1040, 520), (1040, 495)) # K4 公共地
s.gnd(1040, 495, 0)
# ── 3. EDL:J3 两根信号经 U6 串在中间,EDL_EN 高 = 短接 ──────────
# J3 rot270 四个脚都朝上。排线顺序(从左到右)= 4 / 2 / 1 / 3:
# 外侧两个固定脚(4/3)就近入地、拐得比信号低;内侧两个信号往上翻出去,
# 这样「外侧先拐、内侧后拐」就不产生交叉(U6.COM 是下排脚,只能从下面绕过去)。
s.w('GND', (175, 365), (175, 385), (135, 385), (135, 340)) # 4 固定脚
s.gnd(135, 340, 0)
s.w('GND', (225, 365), (225, 405), (285, 405), (285, 430)) # 3 固定脚
s.gnd(285, 430, 180)
s.w('EDL_A', (205, 365), (205, 510), (630, 510), (630, 375)) # 1 -> U6.NO(上排)
s.w('EDL_B', (195, 365), (195, 400), (100, 400), # 2 -> U6.COM(下排)
(100, 245), (610, 245), (610, 305))
s.w('GND', (620, 375), (620, 400), (580, 400), (580, 425)) # U6.2 GND
s.gnd(580, 425, 180)
# V+ 从下排出来往右走 y=265 这条道:它在 COM 那条横线(245)之上、
# 又在 EDL_EN 那几根竖线(275 起)之下,是唯一一条不产生交叉的高度
s.w('+3V3', (620, 305), (620, 265), (960, 265), (960, 290)) # U6.5 V+
s.pwr('+3V3', 960, 290, 0)
s.w('+3V3', (960, 280), (1000, 280)) # -> C69 下脚
s.w('GND', (1000, 320), (1000, 345))
s.gnd(1000, 345, 180)
s.w('EDL_EN', (630, 305), (630, 275), (860, 275)) # U6.6 IN
s.w('EDL_EN', (760, 275), (760, 290)) # -> R63 下脚
s.w('GND', (760, 330), (760, 355)) # R63 上脚 -> 地
s.gnd(760, 355, 180)
s.w('EDL_EN', (860, 275), (900, 275), (900, 320))
s.port('IN', 'EDL_EN', 900, 320, 0)
# ── 4. 文字 ─────────────────────────────────────────────────────
s.txt(45, 795, u'【B3-PHONE】手机侧接口:电池排线 4 焊盘 + 阻尼组 + 侧键中框焊盘 ×3 + EDL', 14)
s.txt(60, 200, u'J5 = 小米8 电池排线剪断后的 4 焊盘(R1 §13.5):1=P+ 2=P− 3=TEMP 4=ID。', 10)
s.txt(60, 182, u'⚠ 接的是保护板输出侧 P+/P−,不是 B+/B−;TEMP 与 ID 都是对 P− 的,', 10)
s.txt(60, 164, u' 按「对负极线」量会得出「三个都不通」的假结论。保护板整块不装。', 10)
s.txt(60, 146, u'R60 10k 代替原 NTC(固定模拟 25°C)、R61 68k 复制原 BATT_ID。', 10)
s.txt(60, 128, u'K1~K3 中框式裸铜焊盘,K4 是三键公共地(J604);顶针已取消(§22.3e)。', 10)
return s
def main():
push = '--push' in sys.argv
place = placement()
exp = expect()
s = build()
s.assert_grid()
errs = s.netcheck(pins_of(exp), NC, ALLOW_SPLIT)
s.report(len(place), errs)
if not push:
return
s.clear()
s.place(place, exp)
s.push_geometry()
print(u'接着跑 verify_sch.py --nets --nc .claude/r2/b3-nc.json')
if __name__ == '__main__':
main()