初始导入:PhoneRail 五路手机直供电源板
原理图/PCB 已在 EasyEDA 里做到 12 页跨页 0 漏接,固件刚完成骨架包 A1。 这次是把已有的一切一次性纳入版本控制,没有改动任何设计内容。 纳入: - 设计与需求文档、PROGRESS.md、小米8 参考原理图 PDF 与追脚脚本 - .claude/ 下的 EasyEDA 桥接工具链与几何/网表缓存(eda-parts.json、 pcb-parts.json、pcb-pads.json、p2-ch1.json 等,是重画各页的唯一事实来源) - 117 张验证截图(本项目所有方向问题都是靠人眼看截图发现的,属于证据不是垃圾) - firmware/ 的 A1 骨架与 site/ 文档站源码 .gitignore 排除:构建产物(firmware/build、host/build、sdkconfig)、 site/node_modules、__pycache__、桥接日志 _bridge.log、脚本自标的 *.stale。 .gitattributes 默认 `* -text`:现有 .py/.json 大多是 CRLF,原样存, 不让 git 重写行尾。唯一例外是 *.sh 强制 LF —— 带 \r 的 shell 脚本 bash 跑不了。 Co-Authored-By: Claude Opus 5 <[email protected]> Claude-Session: https://claude.ai/code/session_01QYuExfgyYa6DzRRcUso8M8
这个提交包含在:
+175
@@ -0,0 +1,175 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
u"""载板 C3-USB:五路 USB 的 VBUS 负载开关(TPS22918)。
|
||||
|
||||
2026-09-04 方案 D 改造:**删掉 J17~J21 那五个 1.25mm 出线座**。
|
||||
现在 USB 是「C2-HUB → C5-AUX 的 ESD → C5-J1401 的 BM24 座 → 原厂排线 → 手机」,
|
||||
本页只负责切 VBUS,D± 根本不经过这一页。
|
||||
|
||||
本页原来由 `p4_nets.py` + `build.py` 生成(那时还叫 P4-USB,在下板上)。
|
||||
这个脚本是自带布线的重写版:**元件位置一律沿用页面上现成的**(只删 J1x),
|
||||
所以不会动到已经验证过的开关部分排版。
|
||||
|
||||
用法: /c/Python314/python .claude/c3_usb.py [--push]
|
||||
"""
|
||||
import json
|
||||
import os
|
||||
import sys
|
||||
|
||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||
sys.path.insert(0, HERE)
|
||||
from eda import run
|
||||
|
||||
PAGE = 'f924c6608ffd1bc1' # C3-USB
|
||||
XS = [130, 345, 560, 775, 990]
|
||||
|
||||
|
||||
def call(js, timeout=180):
|
||||
r = run(js, timeout=timeout)
|
||||
if not r.get('success'):
|
||||
raise RuntimeError(json.dumps(r, ensure_ascii=False)[:900])
|
||||
return r['result']
|
||||
|
||||
|
||||
def wiring(pins):
|
||||
W, F, PT, TX = [], [], [], []
|
||||
|
||||
def w(*p):
|
||||
for i in range(0, len(p) - 2, 2):
|
||||
W.append([p[i], p[i + 1], p[i + 2], p[i + 3]])
|
||||
|
||||
for n, X in enumerate(XS, 1):
|
||||
u = pins['U%d' % (23 + n)]
|
||||
c70, c71, c72 = pins['C70%d' % n], pins['C71%d' % n], pins['C72%d' % n]
|
||||
r70 = pins['R70%d' % n]
|
||||
# 元件位置沿用页面上现成的 —— 这里把每一个用到的坐标都断言一遍
|
||||
exp = [(u['1'], (X + 75, 600), 'U.VIN'), (u['2'], (X + 85, 600), 'U.GND'),
|
||||
(u['3'], (X + 95, 600), 'U.ON'), (u['4'], (X + 95, 480), 'U.CT'),
|
||||
(u['5'], (X + 85, 480), 'U.QOD'), (u['6'], (X + 75, 480), 'U.VOUT'),
|
||||
(c70['2'], (X + 35, 595), 'C70.2'), (c70['1'], (X + 35, 555), 'C70.1'),
|
||||
(c71['1'], (X + 55, 420), 'C71.1'), (c71['2'], (X + 55, 380), 'C71.2'),
|
||||
(c72['1'], (X + 95, 450), 'C72.1'), (c72['2'], (X + 95, 420), 'C72.2'),
|
||||
(r70['1'], (X + 125, 660), 'R70.1'), (r70['2'], (X + 125, 620), 'R70.2')]
|
||||
for got, want, nm in exp:
|
||||
assert tuple(got) == want, u'CH%d 的 %s 实测 %s 期望 %s' % (n, nm, got, want)
|
||||
|
||||
# ---- 板上 5V 轨 -> 开关 VIN,带 2.2µF 输入电容 C70n ----
|
||||
# +5V 端口原来放在 y=660,正好和 (X+65,640) 那个朝上的 GND 旗叠在一起(截图上看出来的),
|
||||
# 往上挪到 700 就干净了 —— VBUS_EN 的横线在 y=685,只跨 X+25~X+95,不碰 X+15。
|
||||
w(X + 15, 700, X + 15, 610, X + 75, 610)
|
||||
w(X + 75, 610, X + 75, 600)
|
||||
PT.append(['BI', '+5V', X + 15, 700, 0])
|
||||
w(X + 35, 610, X + 35, 595)
|
||||
w(X + 35, 555, X + 35, 540)
|
||||
F.append(['Ground', 'GND', X + 35, 540, 0])
|
||||
|
||||
# ---- 开关自己的地 ----
|
||||
w(X + 85, 600, X + 85, 620, X + 65, 620)
|
||||
w(X + 65, 620, X + 65, 640)
|
||||
F.append(['Ground', 'GND', X + 65, 640, 180])
|
||||
|
||||
# ---- ON:VBUS_ENn 端口 + 100k 下拉 R70n ----
|
||||
w(X + 95, 600, X + 95, 685, X + 25, 685)
|
||||
w(X + 25, 685, X + 25, 675)
|
||||
PT.append(['BI', 'VBUS_EN%d' % n, X + 25, 675, 0])
|
||||
w(X + 95, 660, X + 125, 660)
|
||||
w(X + 125, 620, X + 125, 605)
|
||||
F.append(['Ground', 'GND', X + 125, 605, 0])
|
||||
|
||||
# ---- 输出 VBUSn:QOD 短接 VOUT,100nF 输出电容 C71n,再送去 C5-AUX / C5-J1401 ----
|
||||
w(X + 75, 480, X + 75, 330)
|
||||
w(X + 75, 330, X + 15, 330)
|
||||
PT.append(['BI', 'VBUS%d' % n, X + 15, 330, 180])
|
||||
w(X + 85, 480, X + 85, 455, X + 75, 455)
|
||||
w(X + 75, 420, X + 55, 420)
|
||||
w(X + 55, 380, X + 55, 365)
|
||||
F.append(['Ground', 'GND', X + 55, 365, 0])
|
||||
|
||||
# ---- CT 摆率电容 C72n ----
|
||||
w(X + 95, 480, X + 95, 450)
|
||||
w(X + 95, 420, X + 95, 405)
|
||||
F.append(['Ground', 'GND', X + 95, 405, 0])
|
||||
|
||||
TX.append((X + 45, 705, u'CH%d' % n, 13))
|
||||
|
||||
TX += [
|
||||
(45, 796, u'【载板 C3-USB】五路 VBUS 负载开关(TPS22918)—— 本页只切电,D± 不经过这一页', 14),
|
||||
(45, 776, u'USB 链路:C2-HUB 的 U32 → C5-AUX 的 ESD → C5-J1401 的 BM24 座 → 原厂排线 → 手机 J1401。', 10),
|
||||
(45, 185, u'TPS22918: 1~5.5V / 2A / Ron 52mΩ,ON 脚不得悬空', 11),
|
||||
(45, 168, u'R701~705 100k 下拉 → ESP32 复位期间 VBUS 全断', 11),
|
||||
(45, 151, u'CT 100pF C0G: tR≈425µs,涌流≈94mA(10µF 负载)', 11),
|
||||
(45, 134, u'QOD 短接 VOUT: 内部 RPD≈24Ω,关断约 200µs 归零', 11),
|
||||
(45, 117, u'CIN 2.2µF > COUT 100nF;VBUS 来自板上 5V 轨 U30,不吃上游线电流(§9.4)', 11),
|
||||
(45, 100, u'2026-09-04 方案 D:J17~J21 五个 1.25mm 出线座已删 —— USB 改走原厂尾插排线(§13.5)', 11),
|
||||
]
|
||||
|
||||
# 下发前的几何断言(skill §6c / §8a-2b)
|
||||
for a, b, c, e in W:
|
||||
assert (a == c) != (b == e), u'有一段导线不是横平竖直或零长度: %s' % ((a, b, c, e),)
|
||||
for v in (a, b, c, e):
|
||||
assert v % 5 == 0, u'导线坐标 %d 不是 5 的倍数: %s' % (v, (a, b, c, e))
|
||||
for lst in (F, PT):
|
||||
for it in lst:
|
||||
assert it[2] % 5 == 0 and it[3] % 5 == 0, \
|
||||
u'%s 坐标 (%d,%d) 不是 5 的倍数' % (it[1], it[2], it[3])
|
||||
return W, F, PT, TX
|
||||
|
||||
|
||||
def main():
|
||||
push = '--push' in sys.argv
|
||||
if not push:
|
||||
print(u'C3-USB:删 J17~J21,重画布线(元件位置沿用现成的)。加 --push 执行')
|
||||
return
|
||||
|
||||
# 只删 J17~J21 这五个连接器 + 全部旗/端口/导线/文字;其余元件原地不动
|
||||
n = call("""
|
||||
await eda.dmt_EditorControl.openDocument('%s'); await new Promise(r=>setTimeout(r,1400));
|
||||
const nm=(await eda.dmt_Schematic.getCurrentSchematicPageInfo()).name;
|
||||
if (nm!=='C3-USB') throw new Error('page='+nm);
|
||||
let conn=0, flag=0;
|
||||
for (const c of await eda.sch_PrimitiveComponent.getAll()){
|
||||
const t=c.getState_ComponentType();
|
||||
if (t==='sheet') continue;
|
||||
if (t==='netflag'||t==='netport'){ await eda.sch_PrimitiveComponent.delete(c.getState_PrimitiveId()); flag++; continue; }
|
||||
if (t==='part' && /^J(1[7-9]|2[01])$/.test(c.getState_Designator())){
|
||||
await eda.sch_PrimitiveComponent.delete(c.getState_PrimitiveId()); conn++; }
|
||||
}
|
||||
for (const w of await eda.sch_PrimitiveWire.getAll()) await eda.sch_PrimitiveWire.delete(w.getState_PrimitiveId());
|
||||
for (const t of await eda.sch_PrimitiveText.getAll()) await eda.sch_PrimitiveText.delete(t.getState_PrimitiveId());
|
||||
const left=(await eda.sch_PrimitiveComponent.getAll()).filter(c=>c.getState_ComponentType()==='part').length;
|
||||
return {conn, flag, left};
|
||||
""" % PAGE)
|
||||
print(u'删掉连接器 %d 个、旗/端口 %d 个,剩余元件 %d 个' % (n['conn'], n['flag'], n['left']))
|
||||
# 第一次跑删掉 5 个;之后重跑时它们已经不在了,conn=0 也是正常的。
|
||||
# ⚠ 这个守卫原来写成 `!=5 就退出`,第二次跑就会在「导线已经删光」之后才退出,
|
||||
# 把页面留在半清空状态(2026-09-04 踩过一次)。守卫要么放在删之前,要么就别拦。
|
||||
if n['conn'] not in (0, 5):
|
||||
raise SystemExit(u'期望删掉 5 个或 0 个连接器,实际 %d 个 —— 先查清楚再跑' % n['conn'])
|
||||
if n['left'] != 25:
|
||||
raise SystemExit(u'剩余元件 %d 个,期望 25(5 路 x 5 件)—— 先查清楚再跑' % n['left'])
|
||||
|
||||
raw = call("""
|
||||
const out={};
|
||||
for (const c of await eda.sch_PrimitiveComponent.getAll()){
|
||||
if (c.getState_ComponentType()!=='part') continue;
|
||||
out[c.getState_Designator()] = (await c.getAllPins()).map(
|
||||
p=>[p.getState_PinNumber(), Math.round(p.getState_X()), Math.round(p.getState_Y())]);
|
||||
}
|
||||
return out;
|
||||
""")
|
||||
pins = {k: {p: (x, y) for p, x, y in v} for k, v in raw.items()}
|
||||
W, F, PT, TX = wiring(pins)
|
||||
|
||||
def batch(items, size, js):
|
||||
for i in range(0, len(items), size):
|
||||
call(js % json.dumps(items[i:i + size], ensure_ascii=False))
|
||||
|
||||
batch(W, 40, "for (const s of %s) await eda.sch_PrimitiveWire.create(s); return 1;")
|
||||
batch(PT, 25, "for (const p of %s) await eda.sch_PrimitiveComponent.createNetPort(p[0],p[1],p[2],p[3],p[4],false); return 1;")
|
||||
batch(F, 25, "for (const f of %s) await eda.sch_PrimitiveComponent.createNetFlag(f[0],f[1],f[2],f[3],f[4],false); return 1;")
|
||||
batch([list(t) for t in TX], 12,
|
||||
"for (const t of %s) await eda.sch_PrimitiveText.create(t[0],t[1],t[2],0,null,null,t[3],false,false,false,0); return 1;")
|
||||
print(u'C3-USB: 导线 %d 旗 %d 端口 %d 文字 %d' % (len(W), len(F), len(PT), len(TX)))
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
||||
在新工单中引用
屏蔽一个用户