- 规则:铜层 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
191 行
9.4 KiB
Python
191 行
9.4 KiB
Python
# -*- 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()
|