文件
phonerail/.claude/p3b_nets.py
T
zhou yang和Claude Opus 5 2bfe308b30 初始导入: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
2026-09-06 18:18:14 +08:00

144 行
7.9 KiB
Python
原始文件 Blame 文件历史

此文件含有模棱两可的 Unicode 字符
此文件含有可能会与其他字符混淆的 Unicode 字符。 如果您是想特意这样的,可以安全地忽略该警告。 使用 Escape 按钮显示他们。
# -*- coding: utf-8 -*-
"""P3B-EXPAND 网表(74HC595 x2 按键驱动 + PCA9555 输入扩展 + DAC63204 x2 调压)。"""
import os, sys
sys.path.insert(0, os.path.dirname(os.path.abspath(__file__)))
sys.path.insert(0, os.path.join(os.path.dirname(os.path.abspath(__file__)),
'skills', 'easyeda-sch-geometry', 'scripts'))
import local_netcheck as N
w, gnd, pwr, port, txt = N.w, N.gnd, N.pwr, N.port, N.txt
def gnd_up(x, y): # 接地旗朝上(引脚在下),用于导线自下方接入
N.FLAGS.append(('Ground', 'GND', x, y, 180))
def pwr_dn(x, y): # 电源旗朝下(引脚在上),用于导线自上方接入
N.FLAGS.append(('Power', '+3V3', x, y, 180))
# == 【A】74HC595 x2 —— 15 路按键 ================================
SR = [
(730, ['K1_VUP', 'K1_VDN', 'K2_PWR', 'K2_VUP', 'K2_VDN', 'K3_PWR', 'K3_VUP'],
'K1_PWR', 'KEY_SER', 'SR_CAS', 500),
# U22 的 Q7 原来空着,2026-09-03 拿来做板载 Hub 的远程复位(§21.7)
(560, ['K4_PWR', 'K4_VUP', 'K4_VDN', 'K5_PWR', 'K5_VUP', 'K5_VDN', 'HUB_RST'],
'K3_VDN', 'SR_CAS', None, 500),
]
for cy, qs, q0, ds, q7s, cx in SR:
L, R = 210, 290
for i, net in enumerate(qs): # Q1..Q7 左侧单列(rot180 标签朝左)
if net is None:
continue
y = cy + 35 - i * 10
w(net, (L, y), (195, y))
port(net, 195, y, 180)
w('GND', (L, cy - 35), (175, cy - 35), (175, cy - 60))
gnd(175, cy - 60)
w('+3V3', (R, cy + 35), (325, cy + 35), (325, cy + 65)) # VCC
pwr('+3V3', 325, cy + 65)
w(q0, (R, cy + 25), (340, cy + 25)); port(q0, 340, cy + 25, 0)
w(ds, (R, cy + 15), (340, cy + 15)); port(ds, 340, cy + 15, 0)
w('KEY_OE#', (R, cy + 5), (340, cy + 5)); port('KEY_OE#', 340, cy + 5, 0)
w('KEY_RCLK', (R, cy - 5), (340, cy - 5)); port('KEY_RCLK', 340, cy - 5, 0)
w('KEY_SRCLK', (R, cy - 15), (340, cy - 15)); port('KEY_SRCLK', 340, cy - 15, 0)
w('+3V3', (R, cy - 25), (440, cy - 25), (440, cy - 45)) # MR# 拉高
pwr_dn(440, cy - 45)
if q7s:
w(q7s, (R, cy - 35), (340, cy - 35))
port(q7s, 340, cy - 35, 0)
w('+3V3', (cx, cy + 40), (cx, cy + 65)); pwr('+3V3', cx, cy + 65) # VCC 去耦
w('GND', (cx, cy), (cx, cy - 30)); gnd(cx, cy - 30)
# KEY_OE# 上拉 100k:ESP32 复位期间 595 输出高阻
w('+3V3', (600, 560), (600, 590)); pwr('+3V3', 600, 590)
w('KEY_OE#', (600, 520), (600, 495)); port('KEY_OE#', 600, 495, 0)
# == 【B】PCA9555 输入扩展(地址 0x20)===========================
L, R = 710, 810
for y, net in [(755, 'IOEXP_INT#'), (725, 'EFUSE_FLT1'), (715, 'EFUSE_FLT2'),
(705, 'EFUSE_FLT3'), (695, 'EFUSE_FLT4'), (685, 'EFUSE_FLT5'),
(675, 'BUCK_PG'), (665, 'INA_ALERT')]:
w(net, (L, y), (640, y))
port(net, 640, y, 180)
for y in (745, 735, 645): # A1 / A2 / VSS
w('GND', (L, y), (450, y))
w('GND', (450, 645), (450, 745)); gnd(450, 645)
w('GND', (L, 655), (690, 655), (690, 645)) # IO0_7 备用脚就近接地
for y, net in [(645, 'EFUSE_PG1'), (655, 'EFUSE_PG2'), (665, 'EFUSE_PG3'),
(675, 'EFUSE_PG4'), (685, 'EFUSE_PG5'), (735, 'SCL'), (745, 'SDA')]:
w(net, (R, y), (850, y))
port(net, 850, y, 0)
for y in (695, 705, 715, 725): # IO1_5~7 备用 + A0(地址位)
w('GND', (R, y), (830, y))
w('GND', (830, 695), (830, 725))
w('GND', (830, 725), (1030, 725), (1030, 640)); gnd(1030, 640)
w('+3V3', (R, 755), (845, 755), (845, 795)); pwr('+3V3', 845, 795) # VDD
w('+3V3', (845, 775), (860, 775)) # C606
w('GND', (900, 775), (930, 775), (930, 800)); gnd_up(930, 800)
# == 【C】DAC63204 x2 —— 5 路调压 ================================
def dac(cx, cy, a0_to, outs, gpio_net, cap_net, vref_net, xs):
L, R = cx - 60, cx + 60
ySDA, yA0, ySCL, yGPIO = cy - 40, cy - 30, cy - 20, cy - 10
yj = ySDA if a0_to == 'SDA' else ySCL
w(a0_to, (L, yA0), (xs['jog'], yA0), (xs['jog'], yj), (L, yj))
w('SDA', (L, ySDA), (xs['i2c'], ySDA)); port('SDA', xs['i2c'], ySDA, 180)
w('SCL', (L, ySCL), (xs['i2c'], ySCL)); port('SCL', xs['i2c'], ySCL, 180)
w(gpio_net, (L, yGPIO), (xs['rg'] + 20, yGPIO)) # GPIO -> 10k 下拉
w('GND', (xs['rg'] - 20, yGPIO), (xs['gndL'], yGPIO), (xs['gndL'], cy - 50))
gnd(xs['gndL'], cy - 50)
if outs.get('OUT2'): # OUT2 / FB2
n = outs['OUT2']
w(n, (L, cy + 10), (xs['o2'], cy + 10), (xs['o2'], cy), (L, cy))
w(n, (xs['o2'], cy + 5), (xs['p2'], cy + 5))
port(n, xs['p2'], cy + 5, 180)
n0 = outs['OUT0'] # OUT0 / FB0
w(n0, (R, cy - 10), (xs['j0'], cy - 10), (xs['j0'], cy - 20))
w(n0, (R, cy - 20), (xs['p0'], cy - 20)); port(n0, xs['p0'], cy - 20, 0)
n1 = outs['OUT1'] # OUT1 / FB1
w(n1, (R, cy - 40), (xs['j1'], cy - 40), (xs['j1'], cy - 30))
w(n1, (R, cy - 30), (xs['p1'], cy - 30)); port(n1, xs['p1'], cy - 30, 0)
w(cap_net, (R, cy), (xs['cap'], cy), (xs['cap'], cy + 60)) # CAP -> 2.2uF
w('GND', (xs['cap'] + 40, cy + 60), (xs['capg'], cy + 60), (xs['capg'], cy + 100))
gnd_up(xs['capg'], cy + 100)
w(vref_net, (R, cy + 30), (xs['vref'], cy + 30), (xs['vref'], cy + 85))
w('+3V3', (xs['vref'], cy + 125), (xs['vref'], cy + 150)) # VREF 10k 上拉
pwr('+3V3', xs['vref'], cy + 150)
w(vref_net, (xs['vref'], cy + 80), (xs['cvr'], cy + 80)) # VREF 100nF 到地
w('GND', (xs['cvr'], cy + 120), (xs['cvr'], cy + 140)); gnd_up(xs['cvr'], cy + 140)
w('+3V3', (R, cy + 20), (xs['vdd'], cy + 20), (xs['vdd'], cy + 140))
pwr('+3V3', xs['vdd'], cy + 140)
w('+3V3', (xs['vdd'], cy + 120), (xs['vdd'] + 15, cy + 120)) # VDD 去耦
w('GND', (xs['vdd'] + 55, cy + 120), (xs['cvd'], cy + 120), (xs['cvd'], cy + 150))
gnd_up(xs['cvd'], cy + 150)
w('GND', (R, cy + 10), (xs['agnd'], cy + 10), (xs['agnd'], cy + 50))
gnd_up(xs['agnd'], cy + 50)
w('GND', (R, cy + 40), (xs['ep'], cy + 40), (xs['ep'], cy + 140))
gnd_up(xs['ep'], cy + 140)
X6 = dict(jog=150, i2c=100, rg=110, gndL=50, o2=145, p2=130,
j0=330, p0=390, j1=360, p1=480, cap=450, capg=520,
vref=330, cvr=390, vdd=420, cvd=500, agnd=440, ep=310)
X7 = {k: v + 530 for k, v in X6.items()}
X7.update(i2c=630, p0=920, p1=1010)
dac(230, 290, 'SDA', {'OUT0': 'VDAC1', 'OUT1': 'VDAC2', 'OUT2': 'VDAC3'},
'GPIO6', 'CAP6', 'VREF6', X6)
dac(760, 290, 'SCL', {'OUT0': 'VDAC4', 'OUT1': 'VDAC5', 'OUT2': None},
'GPIO7', 'CAP7', 'VREF7', X7)
# == 文字 ========================================================
txt('[A] 74HC595 x2 —— 15 路侧键驱动', 45, 806)
txt('[B] PCA9555 输入扩展(地址 0x20)', 600, 806)
txt('[C] DAC63204 x2 —— 5 路调压', 150, 205)
txt('595: U21 在前,Q7S 级联到 U22.DS;先移入的位落到 U22.Q7。', 45, 190)
txt('U22.Q7 = HUB_RST,远程复位板载 USB Hub(§21.7);OE# 高阻时靠 R716 上拉保持不复位。', 45, 175)
txt('OE# 上拉 100k —— ESP32 复位期间 15 路输出全部高阻。', 45, 178)
txt('PCA9555 备用脚 IO0_7 / IO1_5~7 直接接地(上电默认即输入),', 45, 166)
txt('固件严禁把 Port0[7] / Port1[7:5] 配成输出。', 45, 154)
txt('DAC 地址:U6 = 0x4A(A0->SDA),U7 = 0x4B(A0->SCL)。', 45, 142)
txt('FBx 必须接回 OUTx;CAP 接 2.2uF 到 AGND;VREF 空置时', 45, 130)
txt('100nF 到地 + 10k 上拉 VDD。内部基准 1.212V x2 = 2.424V。', 45, 118)
NC = {
'U22': ['9'], # Q7S 未用(Q7 已给 HUB_RST)
'U6': ['1', '2'], # FB3 / OUT3(第 4 通道未用)
'U7': ['1', '2', '3', '4'], # FB3/OUT3/OUT2/FB2(第 3、4 通道未用)
}