243 行
11 KiB
Python
243 行
11 KiB
Python
# -*- coding: utf-8 -*-
|
||
u"""载板 C6-KEYS:三片 74HC595(U21 / U22 / U33,24 位链)—— 15 路侧键 + 5 路 EDL_EN + HUB_RST。
|
||
|
||
2026-09-06 从下板 P3B-EXPAND / P6-FAN-EDL 整窝搬过来(设计文档 §26.23)。
|
||
位号原样保留(U21 / U22 / U33 / C604 / C605 / C739 / R609),BOM 好对账。
|
||
输出位分配沿用 §26.18 那张表(固件 `sr595_key_bit()` / `sr595_edl_bit()` 不用改):
|
||
|
||
影子位 QA(15) QB(1) QC(2) QD(3) QE(4) QF(5) QG(6) QH(7)
|
||
U21 EDL_EN4 K1_PWR K1_VUP K1_VDN 空 EDL_EN5 EDL_EN3 EDL_EN2
|
||
U22 空 K4_PWR K4_VUP K4_VDN 空 K5_VDN K5_VUP K5_PWR
|
||
U33 EDL_EN1 K2_VUP K2_VDN K2_PWR K3_VDN K3_VUP K3_PWR HUB_RST
|
||
|
||
供电是载板的 **+3V3_HUB**(U31 AMS1117),不再是下板的 +3V3;
|
||
四根控制线 KEY_SER / KEY_SRCLK / KEY_RCLK / KEY_OE# 从排母 J32 北排 3~6 行进来(C1-CONN)。
|
||
|
||
用法: /c/Python314/python .claude/c6_keys.py [--push]
|
||
"""
|
||
import json
|
||
import os
|
||
import sys
|
||
import time
|
||
|
||
HERE = os.path.dirname(os.path.abspath(__file__))
|
||
sys.path.insert(0, HERE)
|
||
from eda import run # noqa: E402
|
||
|
||
SCH = '302e115180aaa8fc' # phonerail-carrier
|
||
LIB = '0819f05c4eef4c71ace90d822a990e87'
|
||
PNAME = 'C6-KEYS'
|
||
|
||
P = {
|
||
'HC595': '94fc47f3127c49c1b8e18e741938eebc', # C5947 74HC595D,118
|
||
'C100N': '87bb635d0b2f489a9f60e7cd225beb3c', # C1525 100nF 0402
|
||
'R100K': 'acc294b6661948399f609b41c77ed19f', # C25741 100k 0402
|
||
}
|
||
|
||
# 74HC595 符号:左列 x=cx-40:1=QB(cy+35) 2=QC 3=QD 4=QE 5=QF 6=QG 7=QH 8=GND(cy-35)
|
||
# 右列 x=cx+40:9=QH'(cy-35) 10=SRCLR# 11=SRCLK 12=RCLK 13=OE# 14=SER 15=QA 16=VCC(cy+35)
|
||
CX = 250
|
||
# (位号, cy, 去耦位号, [QB..QH 七个网络], QA 网络, SER 网络, QH' 网络)
|
||
CHIPS = [
|
||
('U21', 660, 'C604', ['K1_PWR', 'K1_VUP', 'K1_VDN', None, 'EDL_EN5', 'EDL_EN3', 'EDL_EN2'],
|
||
'EDL_EN4', 'KEY_SER', 'SR_CAS'),
|
||
('U22', 490, 'C605', ['K4_PWR', 'K4_VUP', 'K4_VDN', None, 'K5_VDN', 'K5_VUP', 'K5_PWR'],
|
||
None, 'SR_CAS', 'SR_CAS2'),
|
||
('U33', 320, 'C739', ['K2_VUP', 'K2_VDN', 'K2_PWR', 'K3_VDN', 'K3_VUP', 'K3_PWR', 'HUB_RST'],
|
||
'EDL_EN1', 'SR_CAS2', None),
|
||
]
|
||
CAP_X = 500
|
||
R609 = (600, 500) # KEY_OE# 上拉 100k(竖放)
|
||
PWR = '+3V3_HUB'
|
||
|
||
NC = {'U21': ['4'], 'U22': ['4', '15'], 'U33': ['9']} # 空输出 + 链尾 QH'
|
||
|
||
|
||
def call(js, timeout=180):
|
||
r = run(js, timeout=timeout)
|
||
if not r.get('success'):
|
||
raise RuntimeError(json.dumps(r, ensure_ascii=False)[:800])
|
||
return r['result']
|
||
|
||
|
||
def placement():
|
||
out = []
|
||
for d, cy, cap, *_ in CHIPS:
|
||
out.append([d, P['HC595'], CX, cy, 0])
|
||
out.append([cap, P['C100N'], CAP_X, cy + 20, 270])
|
||
out.append(['R609', P['R100K'], R609[0], R609[1], 270])
|
||
return out
|
||
|
||
|
||
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 d, cy, cap, qs, qa, ser, q7s in CHIPS:
|
||
pm = pins[d]
|
||
L, R = CX - 40, CX + 40
|
||
for i, net in enumerate(qs): # QB..QH 左列,标签朝左
|
||
y = cy + 35 - i * 10
|
||
assert pm[str(i + 1)] == (L, y), (d, i + 1, pm[str(i + 1)])
|
||
if net is None:
|
||
continue
|
||
w(L, y, L - 15, y)
|
||
PT.append(['BI', net, L - 15, y, 180])
|
||
assert pm['8'] == (L, cy - 35) and pm['16'] == (R, cy + 35)
|
||
w(L, cy - 35, L - 35, cy - 35, L - 35, cy - 60) # 8 GND
|
||
F.append(['Ground', 'GND', L - 35, cy - 60, 0])
|
||
w(R, cy + 35, R + 35, cy + 35, R + 35, cy + 65) # 16 VCC
|
||
F.append(['Power', PWR, R + 35, cy + 65, 0])
|
||
if qa: # 15 QA
|
||
w(R, cy + 25, R + 50, cy + 25)
|
||
PT.append(['BI', qa, R + 50, cy + 25, 0])
|
||
w(R, cy + 15, R + 50, cy + 15) # 14 SER
|
||
PT.append(['BI', ser, R + 50, cy + 15, 0])
|
||
w(R, cy + 5, R + 50, cy + 5) # 13 OE#
|
||
PT.append(['BI', 'KEY_OE#', R + 50, cy + 5, 0])
|
||
w(R, cy - 5, R + 50, cy - 5) # 12 RCLK
|
||
PT.append(['BI', 'KEY_RCLK', R + 50, cy - 5, 0])
|
||
w(R, cy - 15, R + 50, cy - 15) # 11 SRCLK
|
||
PT.append(['BI', 'KEY_SRCLK', R + 50, cy - 15, 0])
|
||
w(R, cy - 25, R + 150, cy - 25, R + 150, cy - 45) # 10 SRCLR# 拉高
|
||
F.append(['Power', PWR, R + 150, cy - 45, 180])
|
||
if q7s: # 9 QH' 级联
|
||
w(R, cy - 35, R + 50, cy - 35)
|
||
PT.append(['BI', q7s, R + 50, cy - 35, 0])
|
||
# 去耦:上脚 -> 电源旗,下脚 -> 地旗(按坐标认上下,不认引脚号)
|
||
cp = pins[cap]
|
||
top = max(cp.values(), key=lambda v: v[1])
|
||
bot = min(cp.values(), key=lambda v: v[1])
|
||
assert top[0] == bot[0] == CAP_X, (cap, cp)
|
||
w(top[0], top[1], top[0], top[1] + 25)
|
||
F.append(['Power', PWR, top[0], top[1] + 25, 0])
|
||
w(bot[0], bot[1], bot[0], bot[1] - 30)
|
||
F.append(['Ground', 'GND', bot[0], bot[1] - 30, 0])
|
||
|
||
# KEY_OE# 上拉 100k:ESP32 复位期间 / 排针断开时 24 路输出全部高阻
|
||
rp = pins['R609']
|
||
top = max(rp.values(), key=lambda v: v[1])
|
||
bot = min(rp.values(), key=lambda v: v[1])
|
||
w(top[0], top[1], top[0], top[1] + 30)
|
||
F.append(['Power', PWR, top[0], top[1] + 30, 0])
|
||
w(bot[0], bot[1], bot[0], bot[1] - 25)
|
||
PT.append(['BI', 'KEY_OE#', bot[0], bot[1] - 25, 0])
|
||
|
||
TX += [
|
||
(45, 806, u'【C6-KEYS】三片 74HC595 —— 15 路侧键 + 5 路 EDL_EN + HUB_RST(2026-09-06 从下板搬来,§26.23)', 13),
|
||
(45, 790, u'链序 U21 → U22 → U33,整条 24 位;SRCLK / RCLK / OE# 三片共用,四根控制线从 J32 北排 3~6 行进来(C1-CONN)。', 10),
|
||
(45, 776, u'先移入的字节落在 U33;固件发送顺序 U33 → U22 → U21,每字节 QH 先发。输出位表见设计文档 §17.2(固件 sr595_key_bit / sr595_edl_bit)。', 10),
|
||
(45, 762, u'供电 +3V3_HUB(U31)。OE# 上拉 100k(R609):ESP32 复位期间 / 排针没插时 24 路输出全高阻,', 10),
|
||
(45, 748, u'配合每个 MOS 栅极 / EDL_EN 的 100k 下拉(C4-SITEn),15 个按键不会误按、五台手机不会误进 9008。', 10),
|
||
(720, 640, u'HUB_RST 是低有效(USB2517I RESET_N,R716 上拉):', 10),
|
||
(720, 624, u'影子位 = 1 才是「Hub 正常跑」,上电安全影子是 1<<23 不是 0。', 10),
|
||
(720, 600, u'K*_PWR / K*_VUP / K*_VDN 去 C4-SITE1~5 的按键 MOS 栅极;', 10),
|
||
(720, 584, u'EDL_EN1~5 去 C4-SITE1~5 的 TS5A3157。全是载板内部网络,不再过排针。', 10),
|
||
(720, 560, u'空脚:U21.QE、U22.QA、U22.QE;U33.QH\' 是链尾。', 10),
|
||
]
|
||
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 kind, lst in (('flag', F), ('port', PT)):
|
||
for it in lst:
|
||
assert it[2] % 5 == 0 and it[3] % 5 == 0, u'%s %s 坐标不是 5 的倍数' % (kind, it[1])
|
||
return W, F, PT, TX
|
||
|
||
|
||
def main():
|
||
push = '--push' in sys.argv
|
||
place = placement()
|
||
if not push:
|
||
print(u'元件 %d 个(未推送,加 --push)' % len(place))
|
||
return
|
||
|
||
page = call("""
|
||
const info = await eda.dmt_Schematic.getSchematicInfo('%s');
|
||
for (const p of (info.page||[])) if (p.name==='%s') return p.uuid;
|
||
const u = await eda.dmt_Schematic.createSchematicPage('%s');
|
||
await eda.dmt_Schematic.modifySchematicPageName(u,'%s');
|
||
return u;
|
||
""" % (SCH, PNAME.lower(), SCH, PNAME))
|
||
print(u'页面 %s' % page)
|
||
|
||
call("""
|
||
await eda.dmt_EditorControl.openDocument('%s'); await new Promise(r=>setTimeout(r,900));
|
||
const n=(await eda.dmt_Schematic.getCurrentSchematicPageInfo()).name;
|
||
if (n!=='%s') throw new Error('page='+n);
|
||
for (const c of await eda.sch_PrimitiveComponent.getAll()){
|
||
if (c.getState_ComponentType()==='sheet') continue;
|
||
await eda.sch_PrimitiveComponent.delete(c.getState_PrimitiveId());
|
||
}
|
||
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());
|
||
return 1;
|
||
""" % (page, PNAME))
|
||
|
||
call("""
|
||
globalThis.__pl = {done: 0, err: null, n: %d};
|
||
(async () => {
|
||
for (const [d, uuid, x, y, rot] of %s) {
|
||
try { await eda.sch_PrimitiveComponent.create({libraryUuid: '%s', uuid}, x, y, undefined, rot, false, true, true); }
|
||
catch (e) { globalThis.__pl.err = d + ': ' + String(e).slice(0, 150); }
|
||
globalThis.__pl.done++;
|
||
}
|
||
})();
|
||
return 'fired';
|
||
""" % (len(place), json.dumps(place), LIB))
|
||
for _ in range(90):
|
||
st = call("return globalThis.__pl;")
|
||
if st['err']:
|
||
raise SystemExit(u'放置失败: %s' % st['err'])
|
||
if st['done'] >= st['n']:
|
||
break
|
||
time.sleep(2)
|
||
else:
|
||
raise SystemExit(u'放置超时 %d/%d' % (st['done'], st['n']))
|
||
|
||
named = call("""
|
||
const P = %s; let k = 0;
|
||
const cs = (await eda.sch_PrimitiveComponent.getAll()).filter(c => c.getState_ComponentType() === 'part');
|
||
for (const [d, uuid, x, y] of P) for (const c of cs) {
|
||
if (Math.round(c.getState_X()) !== x || Math.round(c.getState_Y()) !== y) continue;
|
||
await c.toAsync().setState_Designator(d).done(); k++; break;
|
||
}
|
||
return k;
|
||
""" % json.dumps([[d, u, x, y] for d, u, x, y, r in place]))
|
||
if named != len(place):
|
||
raise SystemExit(u'只认领到 %d/%d 个位号' % (named, len(place)))
|
||
|
||
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], 15,
|
||
"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;")
|
||
call("await eda.sch_Document.save(); return 1;")
|
||
json.dump(NC, open(os.path.join(HERE, 'c6-nets-nc.json'), 'w', encoding='utf-8'),
|
||
ensure_ascii=False, indent=1)
|
||
print(u'%s: 元件 %d 导线 %d 旗 %d 端口 %d 文字 %d (%s)'
|
||
% (PNAME, len(place), len(W), len(F), len(PT), len(TX), page))
|
||
|
||
|
||
if __name__ == '__main__':
|
||
main()
|