R2:底板 / 刀片布局布线脚本、快照、截图与规划文档更新(含外壳、打印件、布线归档)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
+48
-35
@@ -146,7 +146,7 @@ K_22U = 'C12891' # 1206 22µF(引脚 ±15,不是 ±20)
|
||||
|
||||
U20X, U20Y = 250, 600 # ESP32 中心
|
||||
U35X, U35Y = 450, 280 # TCA9548A 中心
|
||||
J33X, J33Y = 430, 455 # 应急 UART 排针中心(挪到 U20 与 U35 之间那条空带)
|
||||
J33X, J33Y = 450, 420 # 应急 UART 排针中心(U20 与 U35 之间那条空带;2026-09-11 方案 B 从 (430,455) 挪来)
|
||||
COL1, COL2 = 340, 470 # ESP32 信号端口的两列锚点 x
|
||||
|
||||
# ── U20 引脚相对坐标(实测自 `_p3_live.json`,rot 0)────────────────────
|
||||
@@ -179,27 +179,30 @@ ADC1 = set('IO%d' % i for i in range(1, 11))
|
||||
# (模组脚号, 网络名, dir, 端口列, 理由)
|
||||
# dir 是**本页这一侧**的方向:ESP32 输出 = OUT,ESP32 采样 = IN,双向 = BI。
|
||||
PINMAP = [
|
||||
# ⚠ 2026-09-11 起按**方案 B**(PROGRESS「U20 一簇诊断」;页面由 `u20_remap_b.py` 改、PCB 由 `pcb_pinswap.py` 同步):
|
||||
# NTC 挪到南排 ADC1 的 IO4/IO5(去南边的热敏电阻),风扇整组挪到西列北段 IO14/IO21/IO47/IO48(去西北角风扇电路),
|
||||
# 38/39(IO2/IO1)空出。EFUSE_EN / PRSNT 那 9 只按 §29.5 的换脚(pinmap_base.py 当时只改了页面,这张表一直没跟上)。
|
||||
('27', 'IO0', 'BI', COL1, u'strapping/下载;接 J33 第 5 脚,悬空=正常启动'),
|
||||
('39', 'NTC1', 'IN', COL2, u'IO1 = ADC1_CH0 —— 必须 ADC1,ADC2 与 WiFi 冲突'),
|
||||
('38', 'NTC2', 'IN', COL1, u'IO2 = ADC1_CH1 —— 同上'),
|
||||
('4', 'FAN_TACH_OUT', 'IN', COL2, u'IO4 测速脉冲输入,任意 GPIO'),
|
||||
('5', 'FAN_TACH_IN', 'IN', COL1, u'IO5 测速脉冲输入,任意 GPIO'),
|
||||
('6', 'FAN_PWM', 'OUT', COL2, u'IO6 LEDC PWM,任意 GPIO'),
|
||||
('7', 'FAN_EN', 'OUT', COL1, u'IO7 复位高阻=关电,由 A6 的 100k 下拉保证'),
|
||||
('4', 'NTC1', 'IN', COL2, u'IO4 = ADC1_CH3 —— 必须 ADC1,ADC2 与 WiFi 冲突(方案 B,原 IO1)'),
|
||||
('5', 'NTC2', 'IN', COL1, u'IO5 = ADC1_CH4 —— 同上(方案 B,原 IO2)'),
|
||||
('6', 'UP_VBUS_DET', 'IN', COL2, u'IO6 电脑在不在,A4 分压后送来(方案 B,原 IO21)'),
|
||||
('7', 'PRSNT5#', 'IN', COL1, u'IO7 在位检测,本页外部 10k 上拉(方案 B,原 IO14)'),
|
||||
('12', 'HUB_RST', 'OUT', COL2, u'IO8 非 strapping;不复位由 A4 的 10k 上拉保证'),
|
||||
('17', 'EFUSE_EN5', 'OUT', COL1, u'IO9 直驱刀片 eFuse EN'),
|
||||
('18', 'EFUSE_EN4', 'OUT', COL2, u'IO10 直驱刀片 eFuse EN'),
|
||||
('17', 'EFUSE_EN1', 'OUT', COL1, u'IO9 直驱刀片 eFuse EN'),
|
||||
('18', 'EFUSE_EN2', 'OUT', COL2, u'IO10 直驱刀片 eFuse EN'),
|
||||
('19', 'EFUSE_EN3', 'OUT', COL1, u'IO11 直驱刀片 eFuse EN'),
|
||||
('20', 'EFUSE_EN2', 'OUT', COL2, u'IO12 直驱刀片 eFuse EN'),
|
||||
('21', 'EFUSE_EN1', 'OUT', COL1, u'IO13 直驱刀片 eFuse EN'),
|
||||
('22', 'PRSNT5#', 'IN', COL2, u'IO14 在位检测,本页外部 10k 上拉'),
|
||||
('8', 'PRSNT4#', 'IN', COL1, u'IO15 在位检测,本页外部 10k 上拉'),
|
||||
('9', 'PRSNT3#', 'IN', COL2, u'IO16 在位检测,本页外部 10k 上拉'),
|
||||
('10', 'PRSNT2#', 'IN', COL1, u'IO17 在位检测,本页外部 10k 上拉'),
|
||||
('11', 'PRSNT1#', 'IN', COL2, u'IO18 在位检测,本页外部 10k 上拉'),
|
||||
('20', 'EFUSE_EN4', 'OUT', COL2, u'IO12 直驱刀片 eFuse EN'),
|
||||
('21', 'EFUSE_EN5', 'OUT', COL1, u'IO13 直驱刀片 eFuse EN'),
|
||||
('22', 'FAN_TACH_OUT', 'IN', COL2, u'IO14 测速脉冲输入,任意 GPIO(方案 B,原 IO4)'),
|
||||
('8', 'PRSNT1#', 'IN', COL1, u'IO15 在位检测,本页外部 10k 上拉'),
|
||||
('9', 'PRSNT2#', 'IN', COL2, u'IO16 在位检测,本页外部 10k 上拉'),
|
||||
('10', 'PRSNT3#', 'IN', COL1, u'IO17 在位检测,本页外部 10k 上拉'),
|
||||
('11', 'PRSNT4#', 'IN', COL2, u'IO18 在位检测,本页外部 10k 上拉'),
|
||||
('13', 'USB6_DM', 'BI', COL1, u'IO19 ⚠ 原生 USB PHY 硬连线 D−,不可改'),
|
||||
('14', 'USB6_DP', 'BI', COL2, u'IO20 ⚠ 原生 USB PHY 硬连线 D+,不可改'),
|
||||
('23', 'UP_VBUS_DET', 'IN', COL1, u'IO21 电脑在不在,A4 分压后送来'),
|
||||
('23', 'FAN_TACH_IN', 'IN', COL1, u'IO21 测速脉冲输入,任意 GPIO(方案 B,原 IO5)'),
|
||||
('24', 'FAN_PWM', 'OUT', COL1, u'IO47 LEDC PWM(方案 B,原 IO6;原备用脚)'),
|
||||
('25', 'FAN_EN', 'OUT', COL1, u'IO48 复位高阻=关电,由 A6 的 100k 下拉保证(方案 B,原 IO7;原备用脚)'),
|
||||
('31', 'INA_ALERT', 'IN', COL2, u'IO38 A1 的 U13 开漏,本页 10k 上拉'),
|
||||
('32', 'INT#', 'IN', COL1, u'IO39 五槽 wire-OR 开漏,本页唯一一颗 10k 上拉'),
|
||||
('33', 'MUX_RST#', 'BI', COL2, u'IO40 U35 复位;本页 10k 上拉 ⇒ 高阻=不复位'),
|
||||
@@ -207,10 +210,11 @@ PINMAP = [
|
||||
('35', 'SCL', 'BI', COL2, u'IO42 I²C 主干(不经 mux)'),
|
||||
]
|
||||
# 有意不接(进 NC 表,不算悬空)
|
||||
U20_NC = ['15', '16', '24', '25', '26', '28', '29', '30']
|
||||
U20_NC = ['15', '16', '26', '28', '29', '30', '38', '39']
|
||||
U20_NC_WHY = {
|
||||
'15': u'IO3 strapping(JTAG_SEL)', '16': u'IO46 strapping + input-only',
|
||||
'24': u'IO47 备用', '25': u'IO48 备用', '26': u'IO45 strapping(VDD_SPI)',
|
||||
'38': u'IO2 方案 B 空出(NTC2 挪到 IO5)', '39': u'IO1 方案 B 空出(NTC1 挪到 IO4)',
|
||||
'26': u'IO45 strapping(VDD_SPI)',
|
||||
'28': u'IO35 留给 R8 版八线 PSRAM', '29': u'IO36 同上', '30': u'IO37 同上',
|
||||
}
|
||||
|
||||
@@ -225,7 +229,8 @@ U35_REL = {
|
||||
}
|
||||
# (SDn 脚号, SCn 脚号, 槽号)。通道 0~3 在左列,通道 4 在右列(脚 13=SD4 / 14=SC4)
|
||||
U35_CH_L = [('4', '5', 1), ('6', '7', 2), ('8', '9', 3), ('10', '11', 4)]
|
||||
U35_NC = ['15', '16', '17', '18', '19', '20'] # 通道 5~7 悬空
|
||||
U35_NC = ['15', '16', '17', '18', '19', '20'] # 通道 5~7 悬空。⚠ 2026-09-12 起 CH224A 改挂主 I²C(SDA/SCL),不再走通道 5:
|
||||
# PCB 上 U35.15/16 两只脚被 J36 一带的原有布线围在北半边,与南带的 U36 在布线网格上根本不连通(d16_reach 泛洪诊断),用户选改接主总线
|
||||
|
||||
# ── 上拉电阻组(左下):(y, 位号, 器件键, 网名, dir, 说明) ───────────────
|
||||
BANK_X_BUS, BANK_X_R, BANK_X_PT = 45, 85, 145
|
||||
@@ -488,17 +493,15 @@ def build_local(s):
|
||||
place.append(['J33', K_HDR, J33X, J33Y, 0])
|
||||
J = rel(J33X, J33Y, J33_REL)
|
||||
exp['J33'] = dict(J)
|
||||
# 脚1 的地往左走到 x=115 再下去 —— 往右走会贴着连接器符号的上沿画过去,
|
||||
# 往下走会撞上第 5 脚那一排端口标签(x73..140)。
|
||||
# 脚1 的地从**第 2~5 脚那排引出线的上方**往左走再下去 —— 从下面走会切到那四根线。
|
||||
s.w('GND', J['1'], (340, J['1'][1]))
|
||||
# 地旗的引脚落在 y=415 而不是 440:地符号往下伸约 20,440 时它会压住
|
||||
# 第 5 脚(IO0)那个端口的标签(x310..370 @ y435)。
|
||||
s.w('GND', (340, 415), (340, J['1'][1]))
|
||||
s.gnd(340, 415, 0) # 符号在下、引脚在上,导线从上方 ✓
|
||||
# 2026-09-11 方案 B:J33 从 (430,455) 挪到 (450,420)(`u20_remap_b.py` 已在页面上改过)——
|
||||
# U20 的 24/25 两行(y 480/470)要接 FAN_PWM / FAN_EN,原来 J33 的地线 (410,475)→(340,475)→(340,415)
|
||||
# 和四个端口标签(x 303~370)正好占着这两行。
|
||||
# 端口放 x 400(标签 333~400,离 U20 地干线 x 320 留 13);1 脚的地从**第 2~5 脚那排引出线的上方**
|
||||
# 直接接到 U20 地干线已有的节点 (320,440),不再单挂地旗。
|
||||
s.w('GND', J['1'], (320, J['1'][1]))
|
||||
for pin, net in J33_MAP:
|
||||
s.w(net, (370, J[pin][1]), J[pin])
|
||||
s.port('BI', net, 370, J[pin][1], port_rot('BI', 'L'))
|
||||
s.w(net, (400, J[pin][1]), J[pin])
|
||||
s.port('BI', net, 400, J[pin][1], port_rot('BI', 'L'))
|
||||
|
||||
# ── D 区:TCA9548A ─────────────────────────────────────────────────
|
||||
place.append(['U35', K_MUX, U35X, U35Y, 0])
|
||||
@@ -512,6 +515,7 @@ def build_local(s):
|
||||
for pin, net in (('13', 'SDA5'), ('14', 'SCL5')):
|
||||
s.w(net, M[pin], (545, M[pin][1]))
|
||||
s.port('BI', net, 545, M[pin][1], port_rot('BI', 'R'))
|
||||
# (D16 第一版这里给通道 5 引出 SDA6/SCL6 接 CH224A;2026-09-12 CH224A 改挂主 I²C,脚 15/16 回到悬空,见 U35_NC)
|
||||
# RESET# -> MUX_RST#(10k 上拉在 B 区)
|
||||
s.w('MUX_RST#', (350, M['3'][1]), M['3'])
|
||||
s.port('BI', 'MUX_RST#', 350, M['3'][1], port_rot('BI', 'L'))
|
||||
@@ -520,9 +524,12 @@ def build_local(s):
|
||||
s.w('GND', (370, M['2'][1]), M['2'])
|
||||
s.w('GND', (370, 325), (370, 355))
|
||||
s.gnd(370, 355, 180) # 符号在上、引脚在下,导线从下方 ✓
|
||||
s.w('GND', M['21'], (585, M['21'][1])) # A2 从右侧绕出去,避开 SDA5/SCL5
|
||||
s.w('GND', (585, 270), (585, 305))
|
||||
s.gnd(585, 270, 0)
|
||||
# A2 从右侧绕出去,避开 SDA5/SCL5。D16 起右列多了 PD_SDA/PD_SCL(y 245/255,标签 525~605),
|
||||
# 原来那面旗在 (585,270),符号正好压在 PD_SCL 标签上;x 655 又压到 DAC 那一列的 SCL/VDAC1。
|
||||
# 改走通道 6/7 空脚(17~20 不接线)旁边那条空道:(530,305) 下到 (530,290) 挂旗。
|
||||
s.w('GND', M['21'], (530, M['21'][1]))
|
||||
s.w('GND', (530, 290), (530, 305))
|
||||
s.gnd(530, 290, 0)
|
||||
# GND 脚
|
||||
s.w('GND', (370, M['12'][1]), M['12'])
|
||||
s.w('GND', (370, 205), (370, 225))
|
||||
@@ -722,7 +729,7 @@ def main():
|
||||
pins = pins_of(exp) # 把 {'?': {两个坐标}} 摊平成 {脚号: (x,y)}
|
||||
errs = s.netcheck(pins, nc, ALLOW_SPLIT)
|
||||
errs += text_clash(s, pins) + flag_clash(s) + label_clash(s)
|
||||
print(u'ESP32:用掉 %d 脚,有意不接 %d 脚(其中 IO47/IO48 是仅剩的备用)'
|
||||
print(u'ESP32:用掉 %d 脚,有意不接 %d 脚(方案 B 之后仅剩的备用是 IO1/IO2 = 脚 39/38,都是 ADC1)'
|
||||
% (len(PINMAP), len(U20_NC)))
|
||||
s.report(len(place), errs)
|
||||
dump_pinmap()
|
||||
@@ -733,7 +740,13 @@ def main():
|
||||
s.clear()
|
||||
s.place(place, exp)
|
||||
s.push_geometry()
|
||||
print(u'接着跑 verify_sch.py --nets')
|
||||
# 2026-09-11(D16):不接脚清单以前只在内存里用,磁盘上的 a3-ctrl-nc.json 一直是旧的
|
||||
# (还把 U35.15/16 当悬空、漏了方案 B 空出来的 IO1/IO2)⇒ verify_sch --nc 报假悬空。推送时顺手写回。
|
||||
io.open(os.path.join(HERE, 'a3-ctrl-nc.json'), 'w', encoding='utf-8').write(
|
||||
json.dumps(nc, ensure_ascii=False, indent=1))
|
||||
# 存盘才分到 uniqueId(a1_input.py 同款);不存的话 uid_sync_base.py 读回全是空
|
||||
call(u"return await eda.sch_Document.save();")
|
||||
print(u'接着跑 verify_sch.py --nets --nc .claude/r2/a3-ctrl-nc.json')
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
|
||||
在新工单中引用
屏蔽一个用户