R2 底板改 4 层(D15):规则 / 几何 / 背面摆位 / 4 层布线与铺铜,已下发
- 规则:铜层 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
@@ -28,32 +28,26 @@
|
|||||||
"EFUSE_EN2": 5,
|
"EFUSE_EN2": 5,
|
||||||
"EFUSE_EN3": 6,
|
"EFUSE_EN3": 6,
|
||||||
"EFUSE_EN4": 7,
|
"EFUSE_EN4": 7,
|
||||||
"SCL": 8,
|
"EFUSE_EN5": 12,
|
||||||
|
"FAN_PWM": 24,
|
||||||
|
"FAN_TACH": 25,
|
||||||
|
"IOEXP_INT#": 31,
|
||||||
|
"KEY_OE#": 23,
|
||||||
|
"KEY_RCLK": 11,
|
||||||
"KEY_SER": 9,
|
"KEY_SER": 9,
|
||||||
"KEY_SRCLK": 10,
|
"KEY_SRCLK": 10,
|
||||||
"KEY_RCLK": 11,
|
"NTC1": 39,
|
||||||
"EFUSE_EN5": 12,
|
"NTC2": 38,
|
||||||
|
"SCL": 8,
|
||||||
|
"SDA": 22,
|
||||||
|
"UP_VBUS_DET": 36,
|
||||||
"VBUS_EN1": 17,
|
"VBUS_EN1": 17,
|
||||||
"VBUS_EN2": 18,
|
"VBUS_EN2": 18,
|
||||||
"VBUS_EN3": 19,
|
"VBUS_EN3": 19,
|
||||||
"VBUS_EN4": 20,
|
"VBUS_EN4": 20,
|
||||||
"VBUS_EN5": 21,
|
"VBUS_EN5": 21
|
||||||
"SDA": 22,
|
|
||||||
"KEY_OE#": 23,
|
|
||||||
"FAN_PWM": 24,
|
|
||||||
"FAN_TACH": 25,
|
|
||||||
"IOEXP_INT#": 31,
|
|
||||||
"UP_VBUS_DET": 36,
|
|
||||||
"NTC2": 38,
|
|
||||||
"NTC1": 39
|
|
||||||
},
|
},
|
||||||
"pin2io": {
|
"pin2io": {
|
||||||
"4": "IO4",
|
|
||||||
"5": "IO5",
|
|
||||||
"6": "IO6",
|
|
||||||
"7": "IO7",
|
|
||||||
"8": "IO15",
|
|
||||||
"9": "IO16",
|
|
||||||
"10": "IO17",
|
"10": "IO17",
|
||||||
"11": "IO18",
|
"11": "IO18",
|
||||||
"12": "IO8",
|
"12": "IO8",
|
||||||
@@ -67,12 +61,56 @@
|
|||||||
"24": "IO47",
|
"24": "IO47",
|
||||||
"25": "IO48",
|
"25": "IO48",
|
||||||
"31": "IO38",
|
"31": "IO38",
|
||||||
"36": "IO44",
|
|
||||||
"38": "IO2",
|
|
||||||
"39": "IO1",
|
|
||||||
"32": "IO39",
|
"32": "IO39",
|
||||||
"33": "IO40",
|
"33": "IO40",
|
||||||
"34": "IO41",
|
"34": "IO41",
|
||||||
"35": "IO42"
|
"35": "IO42",
|
||||||
|
"36": "IO44",
|
||||||
|
"38": "IO2",
|
||||||
|
"39": "IO1",
|
||||||
|
"4": "IO4",
|
||||||
|
"5": "IO5",
|
||||||
|
"6": "IO6",
|
||||||
|
"7": "IO7",
|
||||||
|
"8": "IO15",
|
||||||
|
"9": "IO16"
|
||||||
|
},
|
||||||
|
"r2_base": {
|
||||||
|
"EFUSE_EN1": 21,
|
||||||
|
"EFUSE_EN2": 20,
|
||||||
|
"EFUSE_EN3": 19,
|
||||||
|
"EFUSE_EN4": 18,
|
||||||
|
"EFUSE_EN5": 17,
|
||||||
|
"FAN_EN": 7,
|
||||||
|
"FAN_PWM": 6,
|
||||||
|
"FAN_TACH_IN": 5,
|
||||||
|
"FAN_TACH_OUT": 4,
|
||||||
|
"HUB_RST": 12,
|
||||||
|
"INA_ALERT": 31,
|
||||||
|
"INT#": 32,
|
||||||
|
"IO0": 27,
|
||||||
|
"MUX_RST#": 33,
|
||||||
|
"NTC1": 39,
|
||||||
|
"NTC2": 38,
|
||||||
|
"PRSNT1#": 11,
|
||||||
|
"PRSNT2#": 10,
|
||||||
|
"PRSNT3#": 9,
|
||||||
|
"PRSNT4#": 8,
|
||||||
|
"PRSNT5#": 22,
|
||||||
|
"SCL": 35,
|
||||||
|
"SDA": 34,
|
||||||
|
"UP_VBUS_DET": 23,
|
||||||
|
"USB6_DM": 13,
|
||||||
|
"USB6_DP": 14
|
||||||
|
},
|
||||||
|
"r2_base_nc": {
|
||||||
|
"15": "IO3 strapping(JTAG_SEL)",
|
||||||
|
"16": "IO46 strapping + input-only",
|
||||||
|
"24": "IO47 备用",
|
||||||
|
"25": "IO48 备用",
|
||||||
|
"26": "IO45 strapping(VDD_SPI)",
|
||||||
|
"28": "IO35 留给 R8 版八线 PSRAM",
|
||||||
|
"29": "IO36 同上",
|
||||||
|
"30": "IO37 同上"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -1,6 +1,35 @@
|
|||||||
{
|
{
|
||||||
"opened": true,
|
"opened": true,
|
||||||
"seq": [],
|
"seq": [
|
||||||
|
{
|
||||||
|
"top": 0,
|
||||||
|
"txt": "DZ3\n\t\t\t\t\n\n\t修改封装\tSOD-123_L2.7-W1.6-LS3.7-RD-1:封装\tSOD-123_L2.7-W1.6-LS3.7-RD-1\tSOT-23_L2.9-W1.3-P1.90-LS2.4-BR\n\nJ1\n\t\t\t\t\n\n\t移除元件\tJ1\tJ1\t\n\nJ26\n\t\t\t\t\n\n\t修改封装\tCONN-TH_4P-P2.54_CAX_2510-4A:封装\tCONN-TH_4P-P2.54_CAX_2510-4A\tR0402\n\nJ27\n\t\t\t\t\n\n\t修改属性\tJ26:通道ID\t$17I175\t$17I174\n\n\t修改属性\tJ26:位号\tJ27\tJ26\n\n\t修改网络\tJ26:3\tFAN_OUT_TACH_RAW\tFAN_IN_TACH_RAW\n\nQ7\n\t\t\t\t\n\n\t修改封装\tSOT-23_L2.9-W1.3-P1.90-LS2.4-BR:封装\tSOT-23_L2.9-W1.3-P1.90-LS2.4-BR\tCONN-TH_4P-P2.54_CAX_2510-4A\n\nQ8\n\t\t\t\t\n\n\t修改封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR:封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR\tR0402"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"top": 188,
|
||||||
|
"txt": "DZ3\n\t\t\t\t\n\n\t修改封装\tSOD-123_L2.7-W1.6-LS3.7-RD-1:封装\tSOD-123_L2.7-W1.6-LS3.7-RD-1\tSOT-23_L2.9-W1.3-P1.90-LS2.4-BR\n\nJ1\n\t\t\t\t\n\n\t移除元件\tJ1\tJ1\t\n\nJ26\n\t\t\t\t\n\n\t修改封装\tCONN-TH_4P-P2.54_CAX_2510-4A:封装\tCONN-TH_4P-P2.54_CAX_2510-4A\tR0402\n\nJ27\n\t\t\t\t\n\n\t修改属性\tJ26:通道ID\t$17I175\t$17I174\n\n\t修改属性\tJ26:位号\tJ27\tJ26\n\n\t修改网络\tJ26:3\tFAN_OUT_TACH_RAW\tFAN_IN_TACH_RAW\n\nQ7\n\t\t\t\t\n\n\t修改封装\tSOT-23_L2.9-W1.3-P1.90-LS2.4-BR:封装\tSOT-23_L2.9-W1.3-P1.90-LS2.4-BR\tCONN-TH_4P-P2.54_CAX_2510-4A\n\nQ8\n\t\t\t\t\n\n\t修改封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR:封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR\tR0402\n\nQ9\n\t\t\t\t\n\n\t修改封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR:封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR\tR0402\n\nQ10\n\t\t\t\t\n\n\t修改属性\tQ9:通道ID\t$17I223\t$17I222\n\n\t修改属性\tQ9:位号\tQ10\tQ9\n\n\t修改网络\tQ9:1\t$17N233\t$17N226\n\n\t修改网络\tQ9:3\tFAN_TACH_OUT\tFAN_TACH_IN\n\n\t增加元件\tQ10\t-\tQ10\n\nR746\n\t\t\t\t\n\n\t修改封装\tR0402:封装\tR0402\tSOD-123_L2.7-W1.6-LS3.7-RD-1\n\nR747\n\t\t\t\t\n\n\t修改封装\tR0402:封装\tR0402\tDC-IN-TH_DC-005-2\n\nR748\n\t\t\t\t\n\n\t修改封装\tR0402:封装\tR0402\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR\n\nR749\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1003TCE\t0402WGF1001TCE\n\nR750\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1003TCE"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"top": 376,
|
||||||
|
"txt": "\t修改封装\tCONN-TH_4P-P2.54_CAX_2510-4A:封装\tCONN-TH_4P-P2.54_CAX_2510-4A\tR0402\n\nJ27\n\t\t\t\t\n\n\t修改属性\tJ26:通道ID\t$17I175\t$17I174\n\n\t修改属性\tJ26:位号\tJ27\tJ26\n\n\t修改网络\tJ26:3\tFAN_OUT_TACH_RAW\tFAN_IN_TACH_RAW\n\nQ7\n\t\t\t\t\n\n\t修改封装\tSOT-23_L2.9-W1.3-P1.90-LS2.4-BR:封装\tSOT-23_L2.9-W1.3-P1.90-LS2.4-BR\tCONN-TH_4P-P2.54_CAX_2510-4A\n\nQ8\n\t\t\t\t\n\n\t修改封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR:封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR\tR0402\n\nQ9\n\t\t\t\t\n\n\t修改封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR:封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR\tR0402\n\nQ10\n\t\t\t\t\n\n\t修改属性\tQ9:通道ID\t$17I223\t$17I222\n\n\t修改属性\tQ9:位号\tQ10\tQ9\n\n\t修改网络\tQ9:1\t$17N233\t$17N226\n\n\t修改网络\tQ9:3\tFAN_TACH_OUT\tFAN_TACH_IN\n\n\t增加元件\tQ10\t-\tQ10\n\nR746\n\t\t\t\t\n\n\t修改封装\tR0402:封装\tR0402\tSOD-123_L2.7-W1.6-LS3.7-RD-1\n\nR747\n\t\t\t\t\n\n\t修改封装\tR0402:封装\tR0402\tDC-IN-TH_DC-005-2\n\nR748\n\t\t\t\t\n\n\t修改封装\tR0402:封装\tR0402\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR\n\nR749\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1003TCE\t0402WGF1001TCE\n\nR750\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1003TCE\n\nR751\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1502TCE\t0402WGF1002TCE\n\nR752\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1502TCE\n\nR753\n\t\t\t\t\n\n\t修改属性\tR752:通道ID\t$17I168\t$17I166\n\n\t修改属性\tR752:位号\tR753\tR752\n\n\t修改网络\tR752:1\tFAN_TACH_IN\tGND"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"top": 564,
|
||||||
|
"txt": "Q8\n\t\t\t\t\n\n\t修改封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR:封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR\tR0402\n\nQ9\n\t\t\t\t\n\n\t修改封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR:封装\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR\tR0402\n\nQ10\n\t\t\t\t\n\n\t修改属性\tQ9:通道ID\t$17I223\t$17I222\n\n\t修改属性\tQ9:位号\tQ10\tQ9\n\n\t修改网络\tQ9:1\t$17N233\t$17N226\n\n\t修改网络\tQ9:3\tFAN_TACH_OUT\tFAN_TACH_IN\n\n\t增加元件\tQ10\t-\tQ10\n\nR746\n\t\t\t\t\n\n\t修改封装\tR0402:封装\tR0402\tSOD-123_L2.7-W1.6-LS3.7-RD-1\n\nR747\n\t\t\t\t\n\n\t修改封装\tR0402:封装\tR0402\tDC-IN-TH_DC-005-2\n\nR748\n\t\t\t\t\n\n\t修改封装\tR0402:封装\tR0402\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR\n\nR749\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1003TCE\t0402WGF1001TCE\n\nR750\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1003TCE\n\nR751\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1502TCE\t0402WGF1002TCE\n\nR752\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1502TCE\n\nR753\n\t\t\t\t\n\n\t修改属性\tR752:通道ID\t$17I168\t$17I166\n\n\t修改属性\tR752:位号\tR753\tR752\n\n\t修改网络\tR752:1\tFAN_TACH_IN\tGND\n\n\t修改网络\tR752:2\t+3V3\t$17N226\n\nR754\n\t\t\t\t\n\n\t修改属性\tR753:通道ID\t$17I169\t$17I168\n\n\t修改属性\tR753:位号\tR754\tR753\n\n\t修改网络\tR753:1\tFAN_OUT_TACH_RAW\tFAN_TACH_IN\n\n\t修改网络\tR753:2\tFAN_12V_SW\t+3V3\n\nR755\n\t\t\t\t"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"top": 752,
|
||||||
|
"txt": "\t修改网络\tQ9:3\tFAN_TACH_OUT\tFAN_TACH_IN\n\n\t增加元件\tQ10\t-\tQ10\n\nR746\n\t\t\t\t\n\n\t修改封装\tR0402:封装\tR0402\tSOD-123_L2.7-W1.6-LS3.7-RD-1\n\nR747\n\t\t\t\t\n\n\t修改封装\tR0402:封装\tR0402\tDC-IN-TH_DC-005-2\n\nR748\n\t\t\t\t\n\n\t修改封装\tR0402:封装\tR0402\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR\n\nR749\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1003TCE\t0402WGF1001TCE\n\nR750\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1003TCE\n\nR751\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1502TCE\t0402WGF1002TCE\n\nR752\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1502TCE\n\nR753\n\t\t\t\t\n\n\t修改属性\tR752:通道ID\t$17I168\t$17I166\n\n\t修改属性\tR752:位号\tR753\tR752\n\n\t修改网络\tR752:1\tFAN_TACH_IN\tGND\n\n\t修改网络\tR752:2\t+3V3\t$17N226\n\nR754\n\t\t\t\t\n\n\t修改属性\tR753:通道ID\t$17I169\t$17I168\n\n\t修改属性\tR753:位号\tR754\tR753\n\n\t修改网络\tR753:1\tFAN_OUT_TACH_RAW\tFAN_TACH_IN\n\n\t修改网络\tR753:2\tFAN_12V_SW\t+3V3\n\nR755\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1502TCE\t0402WGF1002TCE\n\nR756\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1502TCE\n\nR757\n\t\t\t\t\n\n\t修改属性\tR756:通道ID\t$17I173\t$17I171\n\n\t修改属性\tR756:位号\tR757\tR756\n\n\t修改网络\tR756:1\tFAN_TACH_OUT\tGND\n\n\t修改网络\tR756:2\t+3V3\t$17N233"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"top": 940,
|
||||||
|
"txt": "\t修改封装\tR0402:封装\tR0402\tSOT-23-3_L2.9-W1.3-P1.90-LS2.4-BR\n\nR749\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1003TCE\t0402WGF1001TCE\n\nR750\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1003TCE\n\nR751\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1502TCE\t0402WGF1002TCE\n\nR752\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1502TCE\n\nR753\n\t\t\t\t\n\n\t修改属性\tR752:通道ID\t$17I168\t$17I166\n\n\t修改属性\tR752:位号\tR753\tR752\n\n\t修改网络\tR752:1\tFAN_TACH_IN\tGND\n\n\t修改网络\tR752:2\t+3V3\t$17N226\n\nR754\n\t\t\t\t\n\n\t修改属性\tR753:通道ID\t$17I169\t$17I168\n\n\t修改属性\tR753:位号\tR754\tR753\n\n\t修改网络\tR753:1\tFAN_OUT_TACH_RAW\tFAN_TACH_IN\n\n\t修改网络\tR753:2\tFAN_12V_SW\t+3V3\n\nR755\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1502TCE\t0402WGF1002TCE\n\nR756\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1502TCE\n\nR757\n\t\t\t\t\n\n\t修改属性\tR756:通道ID\t$17I173\t$17I171\n\n\t修改属性\tR756:位号\tR757\tR756\n\n\t修改网络\tR756:1\tFAN_TACH_OUT\tGND\n\n\t修改网络\tR756:2\t+3V3\t$17N233"
|
||||||
|
},
|
||||||
|
{
|
||||||
|
"top": 1000,
|
||||||
|
"txt": "R750\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1003TCE\n\nR751\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1502TCE\t0402WGF1002TCE\n\nR752\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1502TCE\n\nR753\n\t\t\t\t\n\n\t修改属性\tR752:通道ID\t$17I168\t$17I166\n\n\t修改属性\tR752:位号\tR753\tR752\n\n\t修改网络\tR752:1\tFAN_TACH_IN\tGND\n\n\t修改网络\tR752:2\t+3V3\t$17N226\n\nR754\n\t\t\t\t\n\n\t修改属性\tR753:通道ID\t$17I169\t$17I168\n\n\t修改属性\tR753:位号\tR754\tR753\n\n\t修改网络\tR753:1\tFAN_OUT_TACH_RAW\tFAN_TACH_IN\n\n\t修改网络\tR753:2\tFAN_12V_SW\t+3V3\n\nR755\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1502TCE\t0402WGF1002TCE\n\nR756\n\t\t\t\t\n\n\t替换器件\tR0402:器件\t0402WGF1002TCE\t0402WGF1502TCE\n\nR757\n\t\t\t\t\n\n\t修改属性\tR756:通道ID\t$17I173\t$17I171\n\n\t修改属性\tR756:位号\tR757\tR756\n\n\t修改网络\tR756:1\tFAN_TACH_OUT\tGND\n\n\t修改网络\tR756:2\t+3V3\t$17N233"
|
||||||
|
}
|
||||||
|
],
|
||||||
"buttons": [
|
"buttons": [
|
||||||
"刷新",
|
"刷新",
|
||||||
"新增",
|
"新增",
|
||||||
|
|||||||
@@ -1 +1 @@
|
|||||||
[{"net": "GND", "x": 151.9259, "y": 48.8, "num": "A1B12", "layer": 1, "pts": [6006.923, 1933.068, "L", 6006.923, 1921.258, 6006.929, 1921.258, 6006.929, 1909.447, 5955.747, 1909.447, 5955.747, 1921.257, 5955.741, 1921.257, 5955.741, 1933.068, 6006.923, 1933.068]}, {"net": "GND", "x": 151.9259, "y": 55.2, "num": "B1A12", "layer": 1, "pts": [5955.741, 2161.413, "L", 5955.741, 2173.224, 5955.741, 2173.225, 5955.741, 2185.036, 6006.921, 2185.036, 6006.921, 2173.225, 6006.921, 2173.224, 6006.921, 2161.413, 5955.741, 2161.413]}, {"net": "", "x": 151.9259, "y": 54.4002, "num": "B4A9", "layer": 1, "pts": [6006.921, 2153.546, "L", 6006.921, 2141.735, 6006.921, 2141.734, 6006.921, 2129.923, 5955.741, 2129.923, 5955.741, 2141.734, 5955.741, 2141.735, 5955.741, 2153.546, 6006.921, 2153.546]}, {"net": "", "x": 151.9259, "y": 49.5998, "num": "A4B9", "layer": 1, "pts": [6006.927, 1964.564, "L", 6006.927, 1952.755, 6006.928, 1952.755, 6006.928, 1940.943, 5955.748, 1940.943, 5955.748, 1952.752, 5955.747, 1952.752, 5955.747, 1964.564, 6006.927, 1964.564]}, {"net": "GND", "x": 16.8001, "y": 27.5001, "num": "15", "layer": 1, "pts": [621.424, 1122.676, "L", 645.676, 1122.676, 645.676, 1167.715, 655.125, 1167.715, 655.125, 1139.369, 667.723, 1139.369, 667.723, 1167.715, 677.172, 1167.715, 677.172, 1122.676, 701.424, 1122.676, 701.424, 1042.676, 677.172, 1042.676, 677.172, 997.637, 667.723, 997.637, 667.723, 1025.983, 655.125, 1025.983, 655.125, 997.637, 645.676, 997.637, 645.676, 1042.676, 621.424, 1042.676, 621.424, 1122.676]}, {"net": "GND", "x": 51.0891, "y": 98.0001, "num": "15", "layer": 1, "pts": [2051.376, 3818.274, "L", 2027.124, 3818.274, 2027.124, 3773.235, 2017.675, 3773.235, 2017.675, 3801.581, 2005.077, 3801.581, 2005.077, 3773.235, 1995.628, 3773.235, 1995.628, 3818.274, 1971.376, 3818.274, 1971.376, 3898.274, 1995.628, 3898.274, 1995.628, 3943.313, 2005.077, 3943.313, 2005.077, 3914.967, 2017.675, 3914.967, 2017.675, 3943.313, 2027.124, 3943.313, 2027.124, 3898.274, 2051.376, 3898.274, 2051.376, 3818.274]}, {"net": "GND", "x": 139.4691, "y": 98.0001, "num": "15", "layer": 1, "pts": [5530.906, 3818.274, "L", 5506.654, 3818.274, 5506.654, 3773.235, 5497.205, 3773.235, 5497.205, 3801.581, 5484.607, 3801.581, 5484.607, 3773.235, 5475.158, 3773.235, 5475.158, 3818.274, 5450.906, 3818.274, 5450.906, 3898.274, 5475.158, 3898.274, 5475.158, 3943.313, 5484.607, 3943.313, 5484.607, 3914.967, 5497.205, 3914.967, 5497.205, 3943.313, 5506.654, 3943.313, 5506.654, 3898.274, 5530.906, 3898.274, 5530.906, 3818.274]}, {"net": "GND", "x": 48.469, "y": 27.5001, "num": "15", "layer": 1, "pts": [1868.234, 1122.676, "L", 1892.486, 1122.676, 1892.486, 1167.715, 1901.935, 1167.715, 1901.935, 1139.369, 1914.533, 1139.369, 1914.533, 1167.715, 1923.982, 1167.715, 1923.982, 1122.676, 1948.234, 1122.676, 1948.234, 1042.676, 1923.982, 1042.676, 1923.982, 997.637, 1914.533, 997.637, 1914.533, 1025.983, 1901.935, 1025.983, 1901.935, 997.637, 1892.486, 997.637, 1892.486, 1042.676, 1868.234, 1042.676, 1868.234, 1122.676]}, {"net": "GND", "x": 128, "y": 27.5001, "num": "15", "layer": 1, "pts": [4999.374, 1122.676, "L", 5023.626, 1122.676, 5023.626, 1167.715, 5033.075, 1167.715, 5033.075, 1139.369, 5045.673, 1139.369, 5045.673, 1167.715, 5055.122, 1167.715, 5055.122, 1122.676, 5079.374, 1122.676, 5079.374, 1042.676, 5055.122, 1042.676, 5055.122, 997.637, 5045.673, 997.637, 5045.673, 1025.983, 5033.075, 1025.983, 5033.075, 997.637, 5023.626, 997.637, 5023.626, 1042.676, 4999.374, 1042.676, 4999.374, 1122.676]}, {"net": "GND", "x": 79.5801, "y": 38.01, "num": "17", "layer": 1, "pts": [3166.541, 1529.919, "L", 3166.541, 1462.989, 3099.611, 1462.989, 3099.611, 1516.139, 3113.391, 1529.919, 3166.541, 1529.919]}, {"net": "GND", "x": 109.5701, "y": 34.71, "num": "17", "layer": 1, "pts": [4347.251, 1399.999, "L", 4347.251, 1333.069, 4280.321, 1333.069, 4280.321, 1386.219, 4294.101, 1399.999, 4347.251, 1399.999]}]
|
[{"net": "GND", "x": 181.9258, "y": 48.8, "num": "A1B12", "layer": 1, "pts": [7188.023, 1933.068, "L", 7188.023, 1921.258, 7188.029, 1921.258, 7188.029, 1909.447, 7136.847, 1909.447, 7136.847, 1921.257, 7136.841, 1921.257, 7136.841, 1933.068, 7188.023, 1933.068]}, {"net": "GND", "x": 181.9258, "y": 55.2, "num": "B1A12", "layer": 1, "pts": [7136.841, 2161.413, "L", 7136.841, 2173.224, 7136.841, 2173.225, 7136.841, 2185.036, 7188.021, 2185.036, 7188.021, 2173.225, 7188.021, 2173.224, 7188.021, 2161.413, 7136.841, 2161.413]}, {"net": "", "x": 181.9258, "y": 54.4002, "num": "B4A9", "layer": 1, "pts": [7188.021, 2153.546, "L", 7188.021, 2141.735, 7188.021, 2141.734, 7188.021, 2129.923, 7136.841, 2129.923, 7136.841, 2141.734, 7136.841, 2141.735, 7136.841, 2153.546, 7188.021, 2153.546]}, {"net": "", "x": 181.9258, "y": 49.5998, "num": "A4B9", "layer": 1, "pts": [7188.027, 1964.564, "L", 7188.027, 1952.755, 7188.028, 1952.755, 7188.028, 1940.943, 7136.848, 1940.943, 7136.848, 1952.752, 7136.847, 1952.752, 7136.847, 1964.564, 7188.027, 1964.564]}, {"net": "GND", "x": 16.8001, "y": 27.5001, "num": "15", "layer": 1, "pts": [621.424, 1122.676, "L", 645.676, 1122.676, 645.676, 1167.715, 655.125, 1167.715, 655.125, 1139.369, 667.723, 1139.369, 667.723, 1167.715, 677.172, 1167.715, 677.172, 1122.676, 701.424, 1122.676, 701.424, 1042.676, 677.172, 1042.676, 677.172, 997.637, 667.723, 997.637, 667.723, 1025.983, 655.125, 1025.983, 655.125, 997.637, 645.676, 997.637, 645.676, 1042.676, 621.424, 1042.676, 621.424, 1122.676]}, {"net": "GND", "x": 51.0891, "y": 98.0001, "num": "15", "layer": 1, "pts": [2051.376, 3818.274, "L", 2027.124, 3818.274, 2027.124, 3773.235, 2017.675, 3773.235, 2017.675, 3801.581, 2005.077, 3801.581, 2005.077, 3773.235, 1995.628, 3773.235, 1995.628, 3818.274, 1971.376, 3818.274, 1971.376, 3898.274, 1995.628, 3898.274, 1995.628, 3943.313, 2005.077, 3943.313, 2005.077, 3914.967, 2017.675, 3914.967, 2017.675, 3943.313, 2027.124, 3943.313, 2027.124, 3898.274, 2051.376, 3898.274, 2051.376, 3818.274]}, {"net": "GND", "x": 139.4691, "y": 98.0001, "num": "15", "layer": 1, "pts": [5530.906, 3818.274, "L", 5506.654, 3818.274, 5506.654, 3773.235, 5497.205, 3773.235, 5497.205, 3801.581, 5484.607, 3801.581, 5484.607, 3773.235, 5475.158, 3773.235, 5475.158, 3818.274, 5450.906, 3818.274, 5450.906, 3898.274, 5475.158, 3898.274, 5475.158, 3943.313, 5484.607, 3943.313, 5484.607, 3914.967, 5497.205, 3914.967, 5497.205, 3943.313, 5506.654, 3943.313, 5506.654, 3898.274, 5530.906, 3898.274, 5530.906, 3818.274]}, {"net": "GND", "x": 48.469, "y": 27.5001, "num": "15", "layer": 1, "pts": [1868.234, 1122.676, "L", 1892.486, 1122.676, 1892.486, 1167.715, 1901.935, 1167.715, 1901.935, 1139.369, 1914.533, 1139.369, 1914.533, 1167.715, 1923.982, 1167.715, 1923.982, 1122.676, 1948.234, 1122.676, 1948.234, 1042.676, 1923.982, 1042.676, 1923.982, 997.637, 1914.533, 997.637, 1914.533, 1025.983, 1901.935, 1025.983, 1901.935, 997.637, 1892.486, 997.637, 1892.486, 1042.676, 1868.234, 1042.676, 1868.234, 1122.676]}, {"net": "GND", "x": 128, "y": 27.5001, "num": "15", "layer": 1, "pts": [4999.374, 1122.676, "L", 5023.626, 1122.676, 5023.626, 1167.715, 5033.075, 1167.715, 5033.075, 1139.369, 5045.673, 1139.369, 5045.673, 1167.715, 5055.122, 1167.715, 5055.122, 1122.676, 5079.374, 1122.676, 5079.374, 1042.676, 5055.122, 1042.676, 5055.122, 997.637, 5045.673, 997.637, 5045.673, 1025.983, 5033.075, 1025.983, 5033.075, 997.637, 5023.626, 997.637, 5023.626, 1042.676, 4999.374, 1042.676, 4999.374, 1122.676]}, {"net": "GND", "x": 79.5801, "y": 38.01, "num": "17", "layer": 1, "pts": [3166.541, 1529.919, "L", 3166.541, 1462.989, 3099.611, 1462.989, 3099.611, 1516.139, 3113.391, 1529.919, 3166.541, 1529.919]}, {"net": "GND", "x": 109.5701, "y": 34.71, "num": "17", "layer": 1, "pts": [4347.251, 1399.999, "L", 4347.251, 1333.069, 4280.321, 1333.069, 4280.321, 1386.219, 4294.101, 1399.999, 4347.251, 1399.999]}]
|
||||||
@@ -4,7 +4,7 @@ import json, os, sys
|
|||||||
HERE = os.path.dirname(os.path.abspath(__file__)); sys.path.insert(0, HERE)
|
HERE = os.path.dirname(os.path.abspath(__file__)); sys.path.insert(0, HERE)
|
||||||
from eda import run
|
from eda import run
|
||||||
JS = u"""
|
JS = u"""
|
||||||
await eda.dmt_EditorControl.openDocument('f126ffb29c92f9b2');
|
await eda.dmt_EditorControl.openDocument('942ed1560d81c1e7');
|
||||||
await new Promise(r=>setTimeout(r,1800));
|
await new Promise(r=>setTimeout(r,1800));
|
||||||
const name = {};
|
const name = {};
|
||||||
for (const c of await eda.pcb_PrimitiveComponent.getAll())
|
for (const c of await eda.pcb_PrimitiveComponent.getAll())
|
||||||
|
|||||||
@@ -1,23 +0,0 @@
|
|||||||
await eda.dmt_EditorControl.openDocument('7e9415a16a909c51');
|
|
||||||
await new Promise(r => setTimeout(r, 1200));
|
|
||||||
const M = 39.3701;
|
|
||||||
const R = (x0,y0,x1,y1) => [x0*M,y0*M,'L',x1*M,y0*M,x1*M,y1*M,x0*M,y1*M];
|
|
||||||
const tries = [
|
|
||||||
['rect-L3-+12V', '+12V', 16, R(100,20,120,30)],
|
|
||||||
['rect-L3-$net', '$1N223', 16, R(100,35,120,45)],
|
|
||||||
['rect-L4-VO1_P', 'VO1_P', 2, R(100,50,120,60)],
|
|
||||||
];
|
|
||||||
const out = [];
|
|
||||||
for (const [name, net, layer, src] of tries) {
|
|
||||||
const row = {name};
|
|
||||||
try {
|
|
||||||
const poly = await eda.pcb_MathPolygon.createComplexPolygon([src]);
|
|
||||||
row.poly = !!poly;
|
|
||||||
const pour = await eda.pcb_PrimitivePour.create(net, layer, poly, 'solid', false, name, 3, 10);
|
|
||||||
row.pour = !!pour;
|
|
||||||
if (pour) await eda.pcb_PrimitivePour.delete(pour.primitiveId);
|
|
||||||
} catch (e) { row.err = String(e).slice(0, 140); }
|
|
||||||
out.push(row);
|
|
||||||
}
|
|
||||||
out.nPourNow = (await eda.pcb_PrimitivePour.getAll()).length;
|
|
||||||
return out;
|
|
||||||
@@ -1,25 +0,0 @@
|
|||||||
await eda.dmt_EditorControl.openDocument('7e9415a16a909c51');
|
|
||||||
await new Promise(r => setTimeout(r, 1200));
|
|
||||||
const M = 39.3701;
|
|
||||||
const R = (x0,y0,x1,y1) => [x0*M,y0*M,'L',x1*M,y0*M,x1*M,y1*M,x0*M,y1*M];
|
|
||||||
const Rc= (x0,y0,x1,y1) => [x0*M,y0*M,'L',x1*M,y0*M,x1*M,y1*M,x0*M,y1*M,x0*M,y0*M]; // 显式闭合
|
|
||||||
const Rr= (x0,y0,x1,y1) => ['R',x0*M,y0*M,x1*M,y1*M,0,0]; // R 矩形模式
|
|
||||||
const cases = [
|
|
||||||
['L15-rect', 'GND', 15, R(100,20,120,30)],
|
|
||||||
['L16-rect-close','+12V',16, Rc(100,35,120,45)],
|
|
||||||
['L16-Rmode', '+12V',16, Rr(100,50,120,60)],
|
|
||||||
['L1-rect', '+12V', 1, R(100,65,120,75)],
|
|
||||||
];
|
|
||||||
const out = [];
|
|
||||||
for (const [name, net, layer, src] of cases) {
|
|
||||||
const row = {name};
|
|
||||||
try {
|
|
||||||
const poly = await eda.pcb_MathPolygon.createComplexPolygon([src]);
|
|
||||||
row.poly = !!poly;
|
|
||||||
const pour = await eda.pcb_PrimitivePour.create(net, layer, poly, 'solid', false, name, 3, 10);
|
|
||||||
row.pour = !!pour;
|
|
||||||
if (pour) await eda.pcb_PrimitivePour.delete(pour.primitiveId);
|
|
||||||
} catch (e) { row.err = String(e).slice(0, 90); }
|
|
||||||
out.push(row);
|
|
||||||
}
|
|
||||||
return out;
|
|
||||||
@@ -3,7 +3,8 @@ u"""载板 C4-SITE1 ~ C4-SITE5:每台手机一页。
|
|||||||
|
|
||||||
一页里三块:
|
一页里三块:
|
||||||
【A】电池排线 4 焊盘直焊座 J8n(P+/P−/TEMP/ID,2026-09-06 取代 TP8n1/2)+ TEMP 10k / ID 68k + §6.3 电容组(六颗)
|
【A】电池排线 4 焊盘直焊座 J8n(P+/P−/TEMP/ID,2026-09-06 取代 TP8n1/2)+ TEMP 10k / ID 68k + §6.3 电容组(六颗)
|
||||||
【B】四根侧键顶针(PWR / VUP / VDN + J604 三键公共地)
|
【B】四根侧键顶针(PWR / VUP / VDN + J604 三键公共地)+ 三颗按键 MOS(2N7002 + 1k 栅阻 + 100k 下拉)
|
||||||
|
—— 2026-09-06 随 74HC595 从下板 P2 搬来(§26.23),位号沿用 Q%d03~05 / R%d20~25
|
||||||
【C】EDL:1.25mm 2P 座 + TS5A3157 模拟开关 + 100k 下拉 + 去耦
|
【C】EDL:1.25mm 2P 座 + TS5A3157 模拟开关 + 100k 下拉 + 去耦
|
||||||
|
|
||||||
用法: /c/Python314/python .claude/c4_site.py [--push] [--only N]
|
用法: /c/Python314/python .claude/c4_site.py [--push] [--only N]
|
||||||
@@ -50,6 +51,8 @@ P = {
|
|||||||
'CONN2P': '6461e6e5749d421bb997627984866425', # C225104 A1251WV-S-2P
|
'CONN2P': '6461e6e5749d421bb997627984866425', # C225104 A1251WV-S-2P
|
||||||
'SW': '5acafd8eb5a641fcaf05190902930635', # C353034 TS5A3157DBVR
|
'SW': '5acafd8eb5a641fcaf05190902930635', # C353034 TS5A3157DBVR
|
||||||
'R100K': 'acc294b6661948399f609b41c77ed19f', # C25741 100k 0402
|
'R100K': 'acc294b6661948399f609b41c77ed19f', # C25741 100k 0402
|
||||||
|
'NMOS': 'f8007837564a4f1fa0e6b57b81dccb0d', # C8545 2N7002(按键 MOS,从下板搬来)
|
||||||
|
'R1K': '65abbad5fa864933b552e0f016ece0db', # C11702 1k 0402(栅极串阻)
|
||||||
}
|
}
|
||||||
|
|
||||||
# ---- 版面常量 ----
|
# ---- 版面常量 ----
|
||||||
@@ -63,9 +66,14 @@ J8 = (225, 630) # 排线直焊座:符号 4 脚朝**左**(实
|
|||||||
COL = {'1': 100, '2': 130, '3': 170, '4': 190}
|
COL = {'1': 100, '2': 130, '3': 170, '4': 190}
|
||||||
R78, R79 = (170, 575), (190, 575) # TEMP / ID 电阻(竖放),下端直接落在 GND 母线上
|
R78, R79 = (170, 575), (190, 575) # TEMP / ID 电阻(竖放),下端直接落在 GND 母线上
|
||||||
|
|
||||||
POGO_X = [220, 320, 420, 520] # 【B】四根顶针的元件中心
|
# 【B】三个按键列(PWR / VUP / VDN),每列:顶针在上、按键 MOS 在下、K 端口从最底下进来。
|
||||||
Y_POGO = 380
|
# 列内相对顶针中心 x_p:MOS (x_p-25, 360) → G(x_p-45,360) S(x_p-15,340) D(x_p-15,380);
|
||||||
POGO_PORT_Y = [330, 300, 270, 240]
|
# 栅阻 R%20/22/24 (x_p-45, 330) 竖放;下拉 R%21/23/25 (x_p-75, 330) 竖放;
|
||||||
|
# K 端口 (x_p-45, 250);POGO 端口挂在漏极竖线旁的横支线末端 (x_p+5, 410)(给 PCB 网络起名)。
|
||||||
|
# 列距 120:一列占 x_p-85 ~ x_p+85(POGO 标签),最东一列的标签 515 < 【C】那根 x=530 的竖线。
|
||||||
|
KEY_X = [190, 310, 430]
|
||||||
|
GND_POGO_X = 80 # 第四根顶针(J604 公共地)
|
||||||
|
Y_POGO = 440
|
||||||
|
|
||||||
J6, U4 = (660, 400), (880, 400) # 【C】
|
J6, U4 = (660, 400), (880, 400) # 【C】
|
||||||
R74, C76 = (975, 370), (1060, 370)
|
R74, C76 = (975, 370), (1060, 370)
|
||||||
@@ -88,6 +96,9 @@ def names(n):
|
|||||||
'j8': 'J8%d' % n, 'r78': 'R78%d' % n, 'r79': 'R79%d' % n,
|
'j8': 'J8%d' % n, 'r78': 'R78%d' % n, 'r79': 'R79%d' % n,
|
||||||
'pogo': ['J%d' % (41 + (n - 1) * 4 + i) for i in range(4)],
|
'pogo': ['J%d' % (41 + (n - 1) * 4 + i) for i in range(4)],
|
||||||
'j6': 'J6%d' % n, 'u4': 'U4%d' % n, 'r74': 'R74%d' % n, 'c76': 'C76%d' % n,
|
'j6': 'J6%d' % n, 'u4': 'U4%d' % n, 'r74': 'R74%d' % n, 'c76': 'C76%d' % n,
|
||||||
|
'q': ['Q%d0%d' % (n, k) for k in (3, 4, 5)], # PWR / VUP / VDN
|
||||||
|
'rg': ['R%d2%d' % (n, k) for k in (0, 2, 4)], # 1k 栅阻
|
||||||
|
'rp': ['R%d2%d' % (n, k) for k in (1, 3, 5)], # 100k 下拉
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -102,8 +113,12 @@ def placement(n):
|
|||||||
# 和 skill §6 那张表相反 —— 所以传 90。下面 EXPECT 会再断言一次。
|
# 和 skill §6 那张表相反 —— 所以传 90。下面 EXPECT 会再断言一次。
|
||||||
rot = 90 if key == 'C2200U' else 270
|
rot = 90 if key == 'C2200U' else 270
|
||||||
out.append([d['caps'][i], P[key], CAP_X[i], Y_CAP, rot, LIB_POGO if key == 'C2200U' else LIB])
|
out.append([d['caps'][i], P[key], CAP_X[i], Y_CAP, rot, LIB_POGO if key == 'C2200U' else LIB])
|
||||||
for i, x in enumerate(POGO_X):
|
for i, x in enumerate(KEY_X):
|
||||||
out.append([d['pogo'][i], P['POGO'], x, Y_POGO, 0, LIB_POGO])
|
out.append([d['pogo'][i], P['POGO'], x, Y_POGO, 0, LIB_POGO])
|
||||||
|
out.append([d['q'][i], P['NMOS'], x - 25, 360, 0, LIB])
|
||||||
|
out.append([d['rg'][i], P['R1K'], x - 45, 330, 90, LIB])
|
||||||
|
out.append([d['rp'][i], P['R100K'], x - 75, 330, 90, LIB])
|
||||||
|
out.append([d['pogo'][3], P['POGO'], GND_POGO_X, Y_POGO, 0, LIB_POGO])
|
||||||
out += [[d['j6'], P['CONN2P'], J6[0], J6[1], 0, LIB],
|
out += [[d['j6'], P['CONN2P'], J6[0], J6[1], 0, LIB],
|
||||||
[d['u4'], P['SW'], U4[0], U4[1], 0, LIB],
|
[d['u4'], P['SW'], U4[0], U4[1], 0, LIB],
|
||||||
[d['r74'], P['R100K'], R74[0], R74[1], 270, LIB],
|
[d['r74'], P['R100K'], R74[0], R74[1], 270, LIB],
|
||||||
@@ -153,16 +168,41 @@ def wiring(n, pins):
|
|||||||
w(top[0], top[1], top[0], Y_VO)
|
w(top[0], top[1], top[0], Y_VO)
|
||||||
w(bot[0], bot[1], bot[0], Y_GND)
|
w(bot[0], bot[1], bot[0], Y_GND)
|
||||||
|
|
||||||
# ---------- 【B】侧键顶针 ----------
|
# ---------- 【B】侧键顶针 + 按键 MOS ----------
|
||||||
labels = ['POGO%d_PWR' % n, 'POGO%d_VUP' % n, 'POGO%d_VDN' % n, None]
|
for i, key in enumerate(('PWR', 'VUP', 'VDN')):
|
||||||
for i in range(4):
|
|
||||||
px, py = pins[d['pogo'][i]]['1']
|
px, py = pins[d['pogo'][i]]['1']
|
||||||
yy = POGO_PORT_Y[i]
|
q = pins[d['q'][i]]
|
||||||
w(px, py, px, yy)
|
g, sr, dr = q['1'], q['2'], q['3'] # 2N7002:1=G 2=S 3=D(下面 build_page 里断言过)
|
||||||
if labels[i]:
|
assert px == dr[0] == sr[0] and dr[1] < py, (d['q'][i], q, px, py)
|
||||||
PT.append(['BI', labels[i], px, yy, 180])
|
# 漏极 -> 顶针一根直线;POGO 端口挂在旁边一根 20 长的横支线末端(给 PCB 网络起名)。
|
||||||
else:
|
# ⚠️ 不能把端口放在直线的中点:两段共线导线会被 EasyEDA 合并成一段,端口就落在中段 =
|
||||||
F.append(['Ground', 'GND', px, yy, 0])
|
# 真断线(skill §8a-2,2026-09-06 第一版就是这么被 port_audit 抓到 15 处的)。
|
||||||
|
mid = dr[1] + 30
|
||||||
|
w(dr[0], dr[1], px, py)
|
||||||
|
w(dr[0], mid, dr[0] + 20, mid)
|
||||||
|
PT.append(['BI', 'POGO%d_%s' % (n, key), dr[0] + 20, mid, 0])
|
||||||
|
# 源极 -> 地
|
||||||
|
w(sr[0], sr[1], sr[0], 300)
|
||||||
|
F.append(['Ground', 'GND', sr[0], 300, 0])
|
||||||
|
# 栅极 <- 1k <- K 端口(从底下进来)
|
||||||
|
rg = pins[d['rg'][i]]
|
||||||
|
gt = max(rg.values(), key=lambda v: v[1])
|
||||||
|
gb = min(rg.values(), key=lambda v: v[1])
|
||||||
|
assert gt[0] == g[0] and gt[1] < g[1], (d['rg'][i], rg, g)
|
||||||
|
w(g[0], g[1], gt[0], gt[1])
|
||||||
|
w(gb[0], gb[1], gb[0], 250)
|
||||||
|
PT.append(['IN', 'K%d_%s' % (n, key), gb[0], 250, 180])
|
||||||
|
# 栅极 100k 下拉(复位期间 / 排针没插时不误按)
|
||||||
|
rp = pins[d['rp'][i]]
|
||||||
|
pt = max(rp.values(), key=lambda v: v[1])
|
||||||
|
pb = min(rp.values(), key=lambda v: v[1])
|
||||||
|
assert pt[0] < g[0] and pt[1] < g[1], (d['rp'][i], rp, g)
|
||||||
|
w(g[0], g[1], pt[0], g[1], pt[0], pt[1])
|
||||||
|
w(pb[0], pb[1], pb[0], 300)
|
||||||
|
F.append(['Ground', 'GND', pb[0], 300, 0])
|
||||||
|
px, py = pins[d['pogo'][3]]['1'] # J604 三键公共地
|
||||||
|
w(px, py, px, 400)
|
||||||
|
F.append(['Ground', 'GND', px, 400, 0])
|
||||||
|
|
||||||
# ---------- 【C】EDL ----------
|
# ---------- 【C】EDL ----------
|
||||||
j, u = pins[d['j6']], pins[d['u4']]
|
j, u = pins[d['j6']], pins[d['u4']]
|
||||||
@@ -205,11 +245,11 @@ def wiring(n, pins):
|
|||||||
% names(n)['j8'], 10),
|
% names(n)['j8'], 10),
|
||||||
(45, 772, u' %s 10k 代替保护板上的 NTC(模拟 25 °C),%s 68k 照抄保护板上的 ID 电阻,都对 P−。'
|
(45, 772, u' %s 10k 代替保护板上的 NTC(模拟 25 °C),%s 68k 照抄保护板上的 ID 电阻,都对 P−。'
|
||||||
% (names(n)['r78'], names(n)['r79']), 10),
|
% (names(n)['r78'], names(n)['r79']), 10),
|
||||||
(45, 470, u'【B】四根顶针顶主板反面的 J601~J604(§13.3)。J604 是三键公共地,', 10),
|
(45, 522, u'【B】四根顶针顶主板反面的 J601~J604(§13.3),J604 是三键公共地,直接接本路的电源返回地。按键 = MOS 把触点对地短接(主板上已串 1k)。', 10),
|
||||||
(45, 454, u' 直接接本路的电源返回地。驱动 MOS 在下板,这里只有顶针。', 10),
|
(45, 508, u' %s 2N7002 由 C6-KEYS 的 74HC595 驱动(K%d_PWR/VUP/VDN),栅极 1k 串阻 + 100k 下拉:复位期间 / 排针没插时不会误按(2026-09-06 从下板搬来,§26.23)。'
|
||||||
(45, 438, u'顶针 = YTC1P-2510-01(立创 C5221288):自由高 3.5 / 行程 0.8 / 压到底 2.7 mm。', 10),
|
% ('/'.join(names(n)['q']), n), 10),
|
||||||
(45, 422, u' 配 3.0mm 立柱 → 压缩 0.5mm(62% 行程,约 62g),屏蔽罩净空 1.6mm。', 10),
|
(45, 494, u' 顶针 YTC1P-2510-01(C5221288):自由高 3.5 / 行程 0.8 / 压到底 2.7 mm;配 3.0mm 立柱压缩 0.5mm(62% 行程,约 62g),屏蔽罩净空 1.6mm。', 10),
|
||||||
(45, 406, u' 冠径只有 Ø0.9 球头,±1mm 落点公差靠首件实测校正(§22.3c / §22.3e)。', 10),
|
(45, 480, u' 冠径只有 Ø0.9 球头,±1mm 落点公差靠首件实测校正(§22.3c / §22.3e)。', 10),
|
||||||
(45, 205, u'【C】%s 是 1.25mm 2P 座,两根线焊到主板正面的 TP1204 / TP1205(§22.4)。'
|
(45, 205, u'【C】%s 是 1.25mm 2P 座,两根线焊到主板正面的 TP1204 / TP1205(§22.4)。'
|
||||||
% names(n)['j6'], 10),
|
% names(n)['j6'], 10),
|
||||||
(45, 189, u' %s 导通即短接两点 → 手机进 9008。串了 1.8k,短路电流只有 1mA。'
|
(45, 189, u' %s 导通即短接两点 → 手机进 9008。串了 1.8k,短路电流只有 1mA。'
|
||||||
@@ -332,6 +372,10 @@ return k;
|
|||||||
for k, v in want.items():
|
for k, v in want.items():
|
||||||
if got.get(k, '').upper().replace('VCC', 'V+') != v:
|
if got.get(k, '').upper().replace('VCC', 'V+') != v:
|
||||||
bad.append(u'%s.%s 引脚名期望 %s 实测 %s' % (d['u4'], k, v, got.get(k)))
|
bad.append(u'%s.%s 引脚名期望 %s 实测 %s' % (d['u4'], k, v, got.get(k)))
|
||||||
|
for qd in d['q']:
|
||||||
|
q = pins[qd]
|
||||||
|
if not (sorted(q) == ['1', '2', '3'] and q['1'][0] < q['2'][0] == q['3'][0] and q['2'][1] < q['1'][1] < q['3'][1]):
|
||||||
|
bad.append(u'%s 2N7002 引脚应是 1=G(左) 2=S(右下) 3=D(右上),实测 %s' % (qd, q))
|
||||||
if bad:
|
if bad:
|
||||||
raise SystemExit(pname + u' 引脚核对失败:\n ' + '\n '.join(bad))
|
raise SystemExit(pname + u' 引脚核对失败:\n ' + '\n '.join(bad))
|
||||||
|
|
||||||
|
|||||||
@@ -43,7 +43,14 @@ sys.path.insert(0, HERE)
|
|||||||
from eda import run
|
from eda import run
|
||||||
|
|
||||||
# 默认下板;载板加参数:/c/Python314/python .claude/drc_read.py --pcb2
|
# 默认下板;载板加参数:/c/Python314/python .claude/drc_read.py --pcb2
|
||||||
PCB = 'f126ffb29c92f9b2' if '--pcb2' in sys.argv else '7e9415a16a909c51'
|
# 2026-09-08:加 `--blade` / `--base` 跑 R2 的两块板(UUID 从 .claude/r2/r2-uuids.json 取)
|
||||||
|
if '--blade' in sys.argv or '--base' in sys.argv:
|
||||||
|
import json as _j, io as _io, os as _os
|
||||||
|
_u = _j.load(_io.open(_os.path.join(_os.path.dirname(_os.path.abspath(__file__)),
|
||||||
|
'r2', 'r2-uuids.json'), encoding='utf-8'))
|
||||||
|
PCB = _u['boards']['BASE' if '--base' in sys.argv else 'BLADE']['pcb']['uuid']
|
||||||
|
else:
|
||||||
|
PCB = '942ed1560d81c1e7' if '--pcb2' in sys.argv else '7e9415a16a909c51'
|
||||||
|
|
||||||
JS_TREE = u"""
|
JS_TREE = u"""
|
||||||
await eda.dmt_EditorControl.openDocument('%s');
|
await eda.dmt_EditorControl.openDocument('%s');
|
||||||
|
|||||||
@@ -38,7 +38,7 @@ HERE = os.path.dirname(os.path.abspath(__file__))
|
|||||||
sys.path.insert(0, HERE)
|
sys.path.insert(0, HERE)
|
||||||
from eda import run
|
from eda import run
|
||||||
|
|
||||||
# 默认下板;载板用 `python .claude/dump_pads.py f126ffb29c92f9b2 pcb2-copper.json`
|
# 默认下板;载板用 `python .claude/dump_pads.py 942ed1560d81c1e7 pcb2-copper.json`
|
||||||
PCB = sys.argv[1] if len(sys.argv) > 1 else '7e9415a16a909c51'
|
PCB = sys.argv[1] if len(sys.argv) > 1 else '7e9415a16a909c51'
|
||||||
MIL = 39.3701
|
MIL = 39.3701
|
||||||
OUT = os.path.join(HERE, sys.argv[2] if len(sys.argv) > 2 else 'pcb-copper.json')
|
OUT = os.path.join(HERE, sys.argv[2] if len(sys.argv) > 2 else 'pcb-copper.json')
|
||||||
|
|||||||
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"_note": "EasyEDA 器件与工程 UUID 缓存。新会话直接用,不必重新 lib_Device.search。role 里带 ⚠️ 的是踩过的坑。P2 单路取值见设计文档 §16.2。⚠️ 作废:C25907(5.23k)、C25743(107k) 已被 C407675(5.49k)、C25755(150k) 取代,不要再用。 ⚠️ Board3(自制转接板) 已删除,改走方案 D:载板上放 BM24-50DS 座 + 原厂排线。 ⚠️ BM24 座子已改用个人库自建封装版 771dbf00…(见 parts.BM24-HRS-PIN),立创原件 C424561 的封装编号是错的。",
|
"_note": "EasyEDA 器件与工程 UUID 缓存。新会话直接用,不必重新 lib_Device.search。role 里带 ⚠️ 的是踩过的坑。P2 单路取值见设计文档 §16.2。⚠️ 作废:C25907(5.23k)、C25743(107k) 已被 C407675(5.49k)、C25755(150k) 取代,不要再用。 ⚠️ Board3(自制转接板) 已删除,改走方案 D:载板上放 BM24-50DS 座 + 原厂排线。 ⚠️ BM24 座子已改用个人库自建封装版 771dbf00…(见 parts.BM24-HRS-PIN),立创原件 C424561 的封装编号是错的。",
|
||||||
"_generated": "2026-09-05 夜:板对板连接器换件实施完毕 —— 下板 C55020601 公头 / 载板 C5307344 母座(对插 13.0mm、双双插装、公母同一套 IDC 奇偶式编号)。P5-BTB / C1-CONN 两页已重生成,载板 PCB 已重摆/重扇/重铺。",
|
"_generated": "2026-09-08:R2 底板 M3 新增 4 个器件(TCA9548APWR / NCP18XH103F03RB / PCIE-064-02-F-D-TH 插槽 / 1x5 排针),引脚坐标均为空页实测。",
|
||||||
"library_uuid": "0819f05c4eef4c71ace90d822a990e87",
|
"library_uuid": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
"project": {
|
"project": {
|
||||||
"uuid": "1e5745f4caff4b15a921694d2fd912e4",
|
"uuid": "1e5745f4caff4b15a921694d2fd912e4",
|
||||||
@@ -107,7 +107,7 @@
|
|||||||
"uuid": "9b2474b02bb94569a00ded395421ea45",
|
"uuid": "9b2474b02bb94569a00ded395421ea45",
|
||||||
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
"fp": "R0402",
|
"fp": "R0402",
|
||||||
"role": "R 4.7k 0402 — ⚠️ 曾误当 eFuse ILIM 用;TPS25940 的 R_ILIM 合法范围是 16.9~150k,4.7k 非法。现无用途"
|
"role": "R 4.7k 0402 — R2 刀片的 I²C 上拉(B2-CTRL 的 R40/R41,挂本槽 mux 分支)。⚠️ 曾误当 eFuse ILIM 用,那是非法的(合法范围 16.9~150k)"
|
||||||
},
|
},
|
||||||
"C2653873": {
|
"C2653873": {
|
||||||
"name": "TPS25940ARVCR",
|
"name": "TPS25940ARVCR",
|
||||||
@@ -526,16 +526,6 @@
|
|||||||
"lcsc": "C424561",
|
"lcsc": "C424561",
|
||||||
"role": "J71~J75 实际用的就是这一条(2026-09-04 自建)。焊盘按 **Hirose 奇偶行编号**:奇数 1,3,5..49 在 +Y 排、偶数 2,4,6..50 在 −Y 排,1 脚在 −X 端;pin51 = 1/2 脚那端的电源触点(x=−6.03),pin52 = 49/50 脚那端(x=+6.03)。几何来自 Hirose 官方样本反算,生成脚本 .claude/fp_bm24.py。⚠ 「哪一排是奇数排」还没有实证(§13.5 的 §MIRROR),打样前必须做那一次实测。"
|
"role": "J71~J75 实际用的就是这一条(2026-09-04 自建)。焊盘按 **Hirose 奇偶行编号**:奇数 1,3,5..49 在 +Y 排、偶数 2,4,6..50 在 −Y 排,1 脚在 −X 端;pin51 = 1/2 脚那端的电源触点(x=−6.03),pin52 = 49/50 脚那端(x=+6.03)。几何来自 Hirose 官方样本反算,生成脚本 .claude/fp_bm24.py。⚠ 「哪一排是奇数排」还没有实证(§13.5 的 §MIRROR),打样前必须做那一次实测。"
|
||||||
},
|
},
|
||||||
"POGO-D1.9": {
|
|
||||||
"name": "YTC1P-2510-01 D1.9",
|
|
||||||
"uuid": "1c8e0ea1e66142a8860d6812b1dbe356",
|
|
||||||
"lib": "543725e8f0454017a5691e7e570aeef6",
|
|
||||||
"lib_note": "个人库",
|
|
||||||
"fp": "POGO-SMD1P_D1.9",
|
|
||||||
"fp_uuid": "2cbabda783f34133b4fe450e98f282bc",
|
|
||||||
"lcsc": "C5221288",
|
|
||||||
"role": "J41~J60 侧键顶针,**实际用的就是这一条**。立创原封装 SMD-1_BD2.0-H3.6 焊盘 Ø2.5,而小米8 四个侧键触点最近的一对(J601↔J604)只隔 2.217 mm → 焊盘会叠在一起把音量+ 永久短路。自建封装缩到 Ø1.9(净间距 0.317 mm)。法兰本来就只有 Ø2.0。见设计文档 §25.3。"
|
|
||||||
},
|
|
||||||
"C55020601": {
|
"C55020601": {
|
||||||
"name": "AZ-PZ2.54-V11-2*20P",
|
"name": "AZ-PZ2.54-V11-2*20P",
|
||||||
"uuid": "c0ab04240dc64fca8d6203d15f8a8a68",
|
"uuid": "c0ab04240dc64fca8d6203d15f8a8a68",
|
||||||
@@ -575,6 +565,123 @@
|
|||||||
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
"fp": "R0402",
|
"fp": "R0402",
|
||||||
"role": "R 68k 0402 — R79n 电池 ID 电阻(实测原保护板 ≈68k 对 P−)"
|
"role": "R 68k 0402 — R79n 电池 ID 电阻(实测原保护板 ≈68k 对 P−)"
|
||||||
|
},
|
||||||
|
"MI8-KEY-PAD": {
|
||||||
|
"name": "MI8-KEY-PAD D1.5",
|
||||||
|
"uuid": "1c8e0ea1e66142a8860d6812b1dbe356",
|
||||||
|
"lib": "543725e8f0454017a5691e7e570aeef6",
|
||||||
|
"lib_note": "个人库",
|
||||||
|
"fp": "PAD-D1.5_MI8-KEY",
|
||||||
|
"fp_uuid": "e106d85830014c088c1fba82f91a26f6",
|
||||||
|
"sym_uuid": "f524af799aa247f2b91e8f56171fa171",
|
||||||
|
"lcsc": "",
|
||||||
|
"role": "J41~J60 侧键触点盘。**2026-09-06 方案改**:顶针取消,改成和中框一样的焊盘 —— 螺丝把主板压在载板上(1 mm 间隙),主板自己的弹片直接压在这个裸铜盘上。器件 uuid 没变(就是原来那颗顶针器件改的),所以**原理图一个字没动**,符号也没换。封装 Ø1.5:四触点实测最小间距 1.78 mm,净距 0.28。⚠️ 旧的 POGO-SMD1P_D1.9 是按「最近一对 2.217 mm」缩的,在真实 1.78 下是负净距。⚠️ 器件属性里的 BOM 字段(Add into BOM=yes / C5221288 / YIYUAN)**API 改不动**,要在客户端手工改成不进 BOM 并清掉料号,否则会照着买 20 颗用不上的顶针。⚠️ 工艺:这是接触盘,**钢网开口 0(不上锡膏)**,表面处理走 ENIG。"
|
||||||
|
},
|
||||||
|
"C15127": {
|
||||||
|
"name": "AO3401A_C15127",
|
||||||
|
"uuid": "be56508f80684877b262e15e4d50e175",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "SOT-23_L2.9-W1.3-P1.90-LS2.4-BR",
|
||||||
|
"role": "Q7 P-MOS 高边开关(风扇 FAN_12V_SW)。Vgs 绝对最大 ±12V ⇒ 必须配 DZ3 钳位。⚠ 封装名和 AO3400A 那颗不一样(SOT-23_ 不是 SOT-23-3_),H_FP 要单独加一条"
|
||||||
|
},
|
||||||
|
"C2891776": {
|
||||||
|
"name": "BZT52C8V2",
|
||||||
|
"uuid": "46e19a04908e4d7f9d40ab2982f52315",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "SOD-123_L2.7-W1.6-LS3.7-RD-1",
|
||||||
|
"role": "DZ3 8.2V/500mW 稳压管,钳 Q7 的负 Vgs。K 接源极、A 接栅极;create(rot=90) 才是 K 上 A 下"
|
||||||
|
},
|
||||||
|
"C25756": {
|
||||||
|
"name": "0402WGF1502TCE",
|
||||||
|
"uuid": "6d104587f1cd4b509c6a5fb272570507",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "R0402",
|
||||||
|
"role": "R 15k 0402 1% — 两路 TACH 接收的栅极串阻(10k 会让高电平不够)"
|
||||||
|
},
|
||||||
|
"C2847671": {
|
||||||
|
"name": "2510-4A",
|
||||||
|
"uuid": "04ed497706104166a1f88dbf2d16083e",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "CONN-TH_4P-P2.54_CAX_2510-4A",
|
||||||
|
"role": "J26/J27 四线风扇座(直针 1x4P 2.54)。1=GND 2=FAN_12V_SW 3=TACH 4=PWM,与旧 3 针针序不同。塑壳 11.5mm,下板上只有两个上角和 y 68~92 放得下"
|
||||||
|
},
|
||||||
|
"C116575": {
|
||||||
|
"name": "T491A226K010AT",
|
||||||
|
"uuid": "950f101b742e488fa85dafd0c53e49eb",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "CASE-A_3216",
|
||||||
|
"role": "C737 AMS1117-3.3 输出 22uF/10V **固态钽**(手册 §Stability 要求,陶瓷不算数)。⚠ **1 脚是正极**(rot 0 时在上),装配时钽的条纹 = 正极,别按铝电解的习惯"
|
||||||
|
},
|
||||||
|
"PCIE-X4-EDGE-64P": {
|
||||||
|
"name": "PCIE-X4-EDGE-64P",
|
||||||
|
"uuid": "787309ccc49040b1b6383a339fd8c405",
|
||||||
|
"lib": "543725e8f0454017a5691e7e570aeef6",
|
||||||
|
"lib_note": "个人库,不是系统库 —— 放元件时 libraryUuid 要用这个",
|
||||||
|
"symbol": "1083524aa7614bde8c2394b7d1fe5bf3",
|
||||||
|
"role": "R2 刀片 J1:PCI-E x4 金手指(板边本身,不采购)。符号借自系统库 PCIE-064-02-F-D-TH,脚号 A1~A32 在左列(自上而下,pitch 10)、B1~B32 在右列,与 PCIe CEM 命名一一对应。⛔ 封装还没建(64 个板边焊盘,1.0 mm 间距,正反两面),属 M4 —— ✅ **T3 已定(2026-09-08):做斜边 20°/1.0 mm,金手指区电镀硬金(不是 ENIG),板厚必须 1.6 mm**,所以现在可以开画。⚠ 斜边会吃掉手指前端约 1.0 mm 的镀层 ⇒ 金手指长度按 PCIe CEM 画,别自己缩短。"
|
||||||
|
},
|
||||||
|
"C310990": {
|
||||||
|
"name": "F1206HC12A0TM",
|
||||||
|
"uuid": "507cd700b60b451caa0f3237e41baf6d",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "1206",
|
||||||
|
"role": "下板 / R2 底板 F1:12A 贴片保险丝(35V,分断 150A)。整机最坏 9.99A(设计文档 §22.6),⚠ 与刀片上那颗 F1(2A 慢断,T7 还是 10A 占位件 C310989)不是一回事,别搞混。"
|
||||||
|
},
|
||||||
|
"C2570006": {
|
||||||
|
"name": "RHC2512FT2R00",
|
||||||
|
"uuid": "3c25870a08a64dc7b809655f380d8ce9",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "2512",
|
||||||
|
"role": "R9A~R9E:2Ω 2W 2512,5 颗串联 = 10Ω/10W 母线泄放电阻。高 0.8mm —— 原来的立式水泥电阻站起来超高度预算,才拆成 5 颗贴片。"
|
||||||
|
},
|
||||||
|
"C9900017043": {
|
||||||
|
"name": "DC-005-5.5*2.5",
|
||||||
|
"uuid": "66ed565d4c984ace901de00bbc83af82",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "DC-005",
|
||||||
|
"role": "J1 圆形 DC 电源座(2026-09-08 用户拍板换掉 XT30PW-M,不降载)。脚 1 = 中心极正 → 保险丝;脚 2/3 = 负极静/动触点,两个都接地并联降接触电阻。⚠ 家族额定 2~5A 而整机最坏 9.99A —— 已知风险、用户明确接受,发热点在插头内芯与弹片的接触面,板上加铜救不了。"
|
||||||
|
},
|
||||||
|
"C130026": {
|
||||||
|
"name": "TCA9548APWR",
|
||||||
|
"uuid": "98a0404e89ff4ecdb0427f14520ce65a",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "TSSOP-24_L7.8-W4.4-P0.65-LS6.4-BL",
|
||||||
|
"role": "U35 TCA9548A 8 通道 I²C 多路器(R2 底板,D8:一槽一路)。实测引脚(rot 0,相对中心):左列自上而下 1 A0(-50,+55) 2 A1(+45) 3 RESET#(+35) 4 SD0(+25) 5 SC0(+15) 6 SD1(+5) 7 SC1(-5) 8 SD2(-15) 9 SC2(-25) 10 SD3(-35) 11 SC3(-45) 12 GND(-55);右列自下而上 13 SD4(+50,-55) 14 SC4(-45) 15 SD5(-35) 16 SC5(-25) 17 SD6(-15) 18 SC6(-5) 19 SD7(+5) 20 SC7(+15) 21 A2(+25) 22 SCL(+35) 23 SDA(+45) 24 VCC(+55)。⚠ SD/SC 成对,通道 n 的 SDn/SCn 脚号相邻但**SD 在前 SC 在后**,别按 SCL/SDA 的习惯顺序接反。"
|
||||||
|
},
|
||||||
|
"C13564": {
|
||||||
|
"name": "NCP18XH103F03RB",
|
||||||
|
"uuid": "26d83c83abc7457cb451b4cf76e659b1",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "R0603",
|
||||||
|
"role": "RT601/RT602 NTC 10k B=3380K 0603(R1 P3-CONTROL 原件,R2 挪到 A6-FAN)。两脚件,rot 0 时 1 在左(-20,0)、2 在右(+20,0),无极性。"
|
||||||
|
},
|
||||||
|
"C4597619": {
|
||||||
|
"name": "PCIE-064-02-F-D-TH",
|
||||||
|
"uuid": "3ea1a15bda65451a97a33a1549965ce3",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "插件 P=1mm(SAMTEC)",
|
||||||
|
"role": "J34~J38:R2 底板的 5 个 PCI-E x4 插槽。**符号与刀片 J1(PCIE-X4-EDGE-64P)同源**,脚号 A1~A32 在左列(-35,自上而下 pitch 10,A1 在 +155)、B1~B32 在右列(+35,同 y)。⛔ **T8 风险**:这是 SAMTEC 的贵料,客户端 lib_Device.search 够不着立创全库里那些几毛钱的PC 标准 PCI-E 4X 插槽(同 T7)。下单前必须换成便宜的同针位插槽并核对封装。"
|
||||||
|
},
|
||||||
|
"C50951": {
|
||||||
|
"name": "2.54mm 1*5P 直排针",
|
||||||
|
"uuid": "e2ae8b0c17dd425aa2f9a1952b667332",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "HDR-TH_5P-P2.54",
|
||||||
|
"role": "J33 应急 UART 口(D13 的保命口:GND/TXD0/RXD0/EN/IO0)。rot 0 实测引脚全部朝左:1(-20,+20) 2(-20,+10) 3(-20,0) 4(-20,-10) 5(-20,-20)。位号前缀是 P?,放件后要显式 setState_Designator(\"J33\")。"
|
||||||
|
},
|
||||||
|
"C19188869": {
|
||||||
|
"name": "PCIE-64P11L",
|
||||||
|
"uuid": "568ba50f7a8e4226aed9ac603b235162",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "PCIE-SMD_PCIE-64P11L",
|
||||||
|
"role": "J34~J38:R2 底板的 5 个 PCI-E x4 插槽(SOFNG 硕方,PCIE 64PIN 镀金加强 **贴片立式**)。2026-09-08 取代 SAMTEC PCIE-064-02-F-D-TH(C4597619)结掉 T8 —— 用户要 PC 标准便宜料。⚠ **脚号与刀片金手指不一样**:本符号的**脚号是 1~64**(脚名才是 A1~A32/B1~B32),而刀片 PCIE-X4-EDGE-64P 的脚号直接就是 A1~A32/B1~B32。换算:A(n) → 脚号 n,B(n) → 脚号 32+n。引脚**相对坐标与 Samtec 那颗完全一致**(A 排 x=-35、B 排 x=+35,y = 155-10*(n-1)),所以版图一个字没动。⚠ 还多一根 **65 脚 = 外壳/屏蔽,在 (0,+175)**(符号顶端正中),本项目接 GND。⛔ **贴片立式**:保持力只靠焊盘剪切,不如原来那颗直插 —— 五片刀片各驮一块手机主板,M4 布板时要给刀片加固定件(梳齿/压条),不能只靠插槽。"
|
||||||
|
},
|
||||||
|
"C310998": {
|
||||||
|
"name": "F1206SB2000V063TM",
|
||||||
|
"uuid": "256f75e322a94be48a90613406f07457",
|
||||||
|
"lib": "0819f05c4eef4c71ace90d822a990e87",
|
||||||
|
"fp": "1206",
|
||||||
|
"role": "刀片 B1-POWER 的 F1:**2A 慢断**贴片保险丝(AEM,SB = Slow Blow),1206 / 63V / 分断 50A / 熔断 I²t = 0.63 A²s。2026-09-08 结掉 T7,取代同封装的 10A 占位件 C310989(F1206HC10A0TM)。⚠ **封装 uuid 与占位件不同**(bceff889… vs 66116fae…,10A/150A 分断那颗焊盘更大),刀片 PCB 还没布(M4),所以无影响;原理图侧的导线是按读回引脚坐标算的,自动跟随。⚠ 刀片满载约 1.45 A(16 W 手机 ÷ 92% ÷ 12 V)= 额定的 73%,正压在保险丝「连续 ≤75%」的降额线上,机箱内 40~50 ℃ 还要再降 ——要更大裕量就换 F1206SB2500V032TM(C310999,2.5A/32V/I²t 0.9)。⚠ 别和底板那两颗混:底板 F1 是 C310990 F1206HC12A0TM(12A,整机 9.99 A)。"
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
"schematic_boards": {
|
"schematic_boards": {
|
||||||
@@ -586,7 +693,7 @@
|
|||||||
},
|
},
|
||||||
"Board2": {
|
"Board2": {
|
||||||
"schematic": "302e115180aaa8fc",
|
"schematic": "302e115180aaa8fc",
|
||||||
"pcb": "f126ffb29c92f9b2",
|
"pcb": "942ed1560d81c1e7",
|
||||||
"board": "c6594605c7cbe2b3",
|
"board": "c6594605c7cbe2b3",
|
||||||
"role": "上板 载板(carrier)",
|
"role": "上板 载板(carrier)",
|
||||||
"pages": {
|
"pages": {
|
||||||
@@ -600,7 +707,8 @@
|
|||||||
"C4-SITE5": "e58ef2c0a55e744a",
|
"C4-SITE5": "e58ef2c0a55e744a",
|
||||||
"C5-J1401A": "967543b084075b4b",
|
"C5-J1401A": "967543b084075b4b",
|
||||||
"C5-J1401B": "63413775cfc3aafc",
|
"C5-J1401B": "63413775cfc3aafc",
|
||||||
"C5-AUX": "b1ffbaef65ef82c9"
|
"C5-AUX": "b1ffbaef65ef82c9",
|
||||||
|
"C6-KEYS": "f44d1c8b0ad64fad"
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,35 +1,35 @@
|
|||||||
{
|
{
|
||||||
"frame": "顶视,板左下角原点,mm",
|
"frame": "顶视,板左下角原点,mm",
|
||||||
"board_w": 67.09,
|
"board_w": 44.0,
|
||||||
"board_h": 44.66,
|
"board_h": 67.0,
|
||||||
"holes": {
|
"holes": {
|
||||||
"H1": [
|
"H1": [
|
||||||
54.2,
|
1.4,
|
||||||
42.3
|
9.9
|
||||||
],
|
],
|
||||||
"H2": [
|
"H2": [
|
||||||
2.6,
|
0.7,
|
||||||
38.2
|
27.3
|
||||||
],
|
],
|
||||||
"H3": [
|
"H3": [
|
||||||
61.9,
|
1.7,
|
||||||
33.7
|
38.7
|
||||||
],
|
],
|
||||||
"H4": [
|
"H4": [
|
||||||
62.1,
|
41.9,
|
||||||
29.2
|
1.9
|
||||||
],
|
],
|
||||||
"H5": [
|
"H5": [
|
||||||
2.6,
|
57.4,
|
||||||
27.0
|
41.2
|
||||||
],
|
],
|
||||||
"H6": [
|
"H6": [
|
||||||
4.0,
|
64.6,
|
||||||
10.8
|
28.1
|
||||||
],
|
],
|
||||||
"H7": [
|
"H7": [
|
||||||
42.6,
|
64.8,
|
||||||
3.7
|
32.4
|
||||||
]
|
]
|
||||||
},
|
},
|
||||||
"contacts_up": {
|
"contacts_up": {
|
||||||
@@ -71,5 +71,28 @@
|
|||||||
2.73,
|
2.73,
|
||||||
4.38
|
4.38
|
||||||
]
|
]
|
||||||
}
|
},
|
||||||
|
"hole_d": 2.0,
|
||||||
|
"_source": "2026-09-06 测量底板扫描件反算(pcb2_measure_read.py,基准点单应,±0.5mm)。板长 67 = 裸板;描的轮廓 70.3 含 SIM 卡托伸出的 3.3mm(卡托在 u 大的那一端)",
|
||||||
|
"side_key_contacts": {
|
||||||
|
"PWR": [
|
||||||
|
4.72,
|
||||||
|
5.16
|
||||||
|
],
|
||||||
|
"VUP": [
|
||||||
|
3.42,
|
||||||
|
6.37
|
||||||
|
],
|
||||||
|
"VDN": [
|
||||||
|
3.49,
|
||||||
|
3.74
|
||||||
|
],
|
||||||
|
"GND": [
|
||||||
|
2.05,
|
||||||
|
4.99
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"_side_key_note": "2026-09-06 实测:中框金焊盘 + 7 孔配准反算,残差 0.57mm。菱形 相邻1.87/对角2.65,焊盘 Φ1.35。簇心 (3.42,5.07),用户卡尺「H1 孔心到簇心 5mm」判死(另一条 2.88 的解已弃)。身份两条独立描述印证:GND 离短板边最近、PWR 与之正对、VDN 离长板边最近、VUP 次之。",
|
||||||
|
"frame_boss_to_pad_mm": 1.0,
|
||||||
|
"_frame_boss_note": "2026-09-06 用户实测:中框螺柱支撑面到侧键金焊盘面 1 mm = 载板面到主板贴合面该有的间隙"
|
||||||
}
|
}
|
||||||
@@ -56,14 +56,23 @@ HDR = 'c0ab04240dc64fca8d6203d15f8a8a68' # C55020601 AZ-PZ2.54-V11-2*20P
|
|||||||
# 不是为了电流(2.8 A / 10 = 0.28 A/针),是为了**让它就近落地、
|
# 不是为了电流(2.8 A / 10 = 0.28 A/针),是为了**让它就近落地、
|
||||||
# 不必在 Inner1 上拉一条横贯全板的脊**(§25.10)
|
# 不必在 Inner1 上拉一条横贯全板的脊**(§25.10)
|
||||||
# · GND 从 33 针减到 **26 针**,20 A 回流 = 0.77 A/针,仍很宽裕
|
# · GND 从 33 针减到 **26 针**,20 A 回流 = 0.77 A/针,仍很宽裕
|
||||||
|
# ## 2026-09-06 第三版:74HC595 + 15 颗按键 MOS 整窝挪到载板(§26.23)
|
||||||
|
#
|
||||||
|
# 跨排针的不再是 15 条 `POGO*` + 5 条 `EDL_EN*` + `HUB_RST`(21 针),
|
||||||
|
# 而是移位链的 4 根线 `KEY_SER` / `KEY_SRCLK` / `KEY_RCLK` / `KEY_OE#`。
|
||||||
|
# 净腾 17 针,全部补成 GND(回流从 26 针加到 43 针)。
|
||||||
|
# 4 根 KEY_* 放在 **J25 北排 3~6 行**(载板 x 139~147):595 摆在载板走廊中段
|
||||||
|
# (J31 与 J32 之间,x 110~133),从 J32 西端出线最近;下板这头 ESP32 在 (88,18),
|
||||||
|
# U21/U22 腾出来之后 x 88~97 / y 35~55 整片是空的,四根线北上到 J25 西端没有障碍。
|
||||||
|
# `POGO*` / `EDL_EN*` / `HUB_RST` 从此是**载板内部网络**。
|
||||||
J24 = [
|
J24 = [
|
||||||
('VO1_P', 'GND'), ('VO1_P', 'GND'), ('VO1_P', 'GND'), # 1~3 -> site1(北)
|
('VO1_P', 'GND'), ('VO1_P', 'GND'), ('VO1_P', 'GND'), # 1~3 -> site1(北)
|
||||||
('+5V', 'GND'), ('+5V', 'GND'), # 4~5 -> C701/U24(北)
|
('+5V', 'GND'), ('+5V', 'GND'), # 4~5 -> C701/U24(北)
|
||||||
('POGO1_PWR', 'POGO4_PWR'), # 6~10 北=CH1 信号
|
('GND', 'GND'), # 6~9 原 POGO1/POGO4/EDL_EN1/EDL_EN4,
|
||||||
('POGO1_VUP', 'POGO4_VUP'), # 南=CH4 信号
|
('GND', 'GND'), # 2026-09-06 随 595 上载板腾空 -> GND
|
||||||
('POGO1_VDN', 'POGO4_VDN'),
|
('GND', 'GND'),
|
||||||
('EDL_EN1', 'EDL_EN4'),
|
('GND', 'GND'),
|
||||||
('VBUS_EN1', 'VBUS_EN4'),
|
('VBUS_EN1', 'VBUS_EN4'), # 10
|
||||||
('SDA', '+5V'), ('SCL', '+5V'), # 11~12 南=U27/C704(南)
|
('SDA', '+5V'), ('SCL', '+5V'), # 11~12 南=U27/C704(南)
|
||||||
('GND', 'UP_VBUS_DET'), # 13 R722 在底层 y62.2
|
('GND', 'UP_VBUS_DET'), # 13 R722 在底层 y62.2
|
||||||
('GND', 'GND'), # 14
|
('GND', 'GND'), # 14
|
||||||
@@ -72,18 +81,16 @@ J24 = [
|
|||||||
]
|
]
|
||||||
J25 = [
|
J25 = [
|
||||||
('+5V', '+5V'), ('+5V', '+5V'), # 1~2 北->C702/U25 南->U28/C705
|
('+5V', '+5V'), ('+5V', '+5V'), # 1~2 北->C702/U25 南->U28/C705
|
||||||
('POGO2_PWR', 'VBUS_EN5'), # 3~4 南=CH5 的两个使能
|
('KEY_SER', 'VBUS_EN5'), # 3~6 北=74HC595 移位链 4 根(原 POGO2_* / EDL_EN2)
|
||||||
('POGO2_VUP', 'EDL_EN5'), # (U28/U45 就在 x133~136)
|
('KEY_SRCLK', 'GND'), # 南=CH5 的 VBUS 使能(原 EDL_EN5 -> GND)
|
||||||
('POGO2_VDN', 'GND'),
|
('KEY_RCLK', 'GND'),
|
||||||
('EDL_EN2', 'GND'),
|
('KEY_OE#', 'GND'),
|
||||||
('VBUS_EN2', 'GND'),
|
('VBUS_EN2', 'GND'), # 7
|
||||||
('HUB_RST', 'GND'), # 8
|
('GND', 'GND'), # 8 原 HUB_RST -> 载板内部
|
||||||
('GND', 'VO5_P'), ('GND', 'VO5_P'), ('GND', 'VO5_P'), # 9~11 -> site5(南)
|
('GND', 'VO5_P'), ('GND', 'VO5_P'), ('GND', 'VO5_P'), # 9~11 -> site5(南)
|
||||||
('POGO3_PWR', 'POGO5_PWR'), # 12~14 北=CH3 南=CH5 顶针
|
('GND', 'GND'), ('GND', 'GND'), ('GND', 'GND'), # 12~14 原 POGO3_* / POGO5_* -> GND
|
||||||
('POGO3_VUP', 'POGO5_VUP'),
|
|
||||||
('POGO3_VDN', 'POGO5_VDN'),
|
|
||||||
('VO3_P', 'GND'), ('VO3_P', 'GND'), ('VO3_P', 'GND'), # 15~17 -> site3(北)
|
('VO3_P', 'GND'), ('VO3_P', 'GND'), ('VO3_P', 'GND'), # 15~17 -> site3(北)
|
||||||
('EDL_EN3', 'GND'), ('VBUS_EN3', 'GND'), # 18~19
|
('GND', 'GND'), ('VBUS_EN3', 'GND'), # 18~19 原 EDL_EN3 -> GND
|
||||||
('+5V', '+5V'), # 20 -> C703/U26(北)
|
('+5V', '+5V'), # 20 -> C703/U26(北)
|
||||||
]
|
]
|
||||||
|
|
||||||
@@ -166,7 +173,7 @@ def plan():
|
|||||||
(60, 698, u'⚠ 北排喂北边的站、南排喂南边的站,一路都不许跨行 —— 4A 的电源面穿不过排母的地针行(缝里只剩 0.44mm 铜)。', 10),
|
(60, 698, u'⚠ 北排喂北边的站、南排喂南边的站,一路都不许跨行 —— 4A 的电源面穿不过排母的地针行(缝里只剩 0.44mm 铜)。', 10),
|
||||||
(60, 215, u'每路 VOn_P 用 3 针并联(4A / 3 = 1.33A 每针,母座额定 2.5A 每针),正对面 3 针地做本路回流(§15.4)。', 10),
|
(60, 215, u'每路 VOn_P 用 3 针并联(4A / 3 = 1.33A 每针,母座额定 2.5A 每针),正对面 3 针地做本路回流(§15.4)。', 10),
|
||||||
(60, 195, u'+5V 用 10 针、分散在两颗排母的南北四处:不是为了电流(0.28A 每针),是为了就近落地,免得在 Inner1 上拉一条横贯全板的脊。', 10),
|
(60, 195, u'+5V 用 10 针、分散在两颗排母的南北四处:不是为了电流(0.28A 每针),是为了就近落地,免得在 Inner1 上拉一条横贯全板的脊。', 10),
|
||||||
(60, 175, u'合计 54 个信号 + 26 个地(20A 回流 = 0.77A 每针)。', 10),
|
(60, 175, u'合计 37 个信号 + 43 个地(2026-09-06 起:74HC595 + 按键 MOS 整窝在载板,跨板只剩 KEY_SER/SRCLK/RCLK/OE# 四根,§26.23)。', 10),
|
||||||
(60, 155, u'对插高度 = 2.5 + 10.5 = 13.0mm(塑料对塑料定位),满足 §22.3d 的净空要求。', 10),
|
(60, 155, u'对插高度 = 2.5 + 10.5 = 13.0mm(塑料对塑料定位),满足 §22.3d 的净空要求。', 10),
|
||||||
(60, 135, u'⚠ 下板 C2/C3 罐高必须 <= 11.5mm,且 C2~C6 压在 J24 位置上、PCB 上要挪开(§22.3f)。', 10),
|
(60, 135, u'⚠ 下板 C2/C3 罐高必须 <= 11.5mm,且 C2~C6 压在 J24 位置上、PCB 上要挪开(§22.3f)。', 10),
|
||||||
]
|
]
|
||||||
|
|||||||
@@ -1,343 +1,464 @@
|
|||||||
{
|
{
|
||||||
"U33": [
|
"Q6": {
|
||||||
[
|
"name": "AO3400A_C20917",
|
||||||
"1",
|
"pins": [
|
||||||
210,
|
[
|
||||||
635
|
"3",
|
||||||
],
|
"D",
|
||||||
[
|
330,
|
||||||
"2",
|
350
|
||||||
210,
|
],
|
||||||
625
|
[
|
||||||
],
|
"1",
|
||||||
[
|
"G",
|
||||||
"3",
|
300,
|
||||||
210,
|
330
|
||||||
615
|
],
|
||||||
],
|
[
|
||||||
[
|
"2",
|
||||||
"4",
|
"S",
|
||||||
210,
|
330,
|
||||||
605
|
310
|
||||||
],
|
]
|
||||||
[
|
|
||||||
"5",
|
|
||||||
210,
|
|
||||||
595
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"6",
|
|
||||||
210,
|
|
||||||
585
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"7",
|
|
||||||
210,
|
|
||||||
575
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"8",
|
|
||||||
210,
|
|
||||||
565
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"9",
|
|
||||||
290,
|
|
||||||
565
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"10",
|
|
||||||
290,
|
|
||||||
575
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"11",
|
|
||||||
290,
|
|
||||||
585
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"12",
|
|
||||||
290,
|
|
||||||
595
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"13",
|
|
||||||
290,
|
|
||||||
605
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"14",
|
|
||||||
290,
|
|
||||||
615
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"15",
|
|
||||||
290,
|
|
||||||
625
|
|
||||||
],
|
|
||||||
[
|
|
||||||
"16",
|
|
||||||
290,
|
|
||||||
635
|
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"C739": [
|
"R733": {
|
||||||
[
|
"name": "0402WGF1001TCE",
|
||||||
"2",
|
"pins": [
|
||||||
120,
|
[
|
||||||
710
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
220,
|
||||||
"1",
|
330
|
||||||
120,
|
],
|
||||||
670
|
[
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
180,
|
||||||
|
330
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"R735": [
|
"R734": {
|
||||||
[
|
"name": "0402WGF1003TCE",
|
||||||
"2",
|
"pins": [
|
||||||
430,
|
[
|
||||||
680
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
250,
|
||||||
"1",
|
250
|
||||||
430,
|
],
|
||||||
640
|
[
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
250,
|
||||||
|
290
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"R736": [
|
"D2": {
|
||||||
[
|
"name": "SS34_C8678",
|
||||||
"2",
|
"pins": [
|
||||||
490,
|
[
|
||||||
680
|
"2",
|
||||||
],
|
"A",
|
||||||
[
|
430,
|
||||||
"1",
|
640
|
||||||
490,
|
],
|
||||||
640
|
[
|
||||||
|
"1",
|
||||||
|
"K",
|
||||||
|
430,
|
||||||
|
680
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"R737": [
|
"C738": {
|
||||||
[
|
"name": "CL31A226KAHNNNE",
|
||||||
"2",
|
"pins": [
|
||||||
550,
|
[
|
||||||
680
|
"1",
|
||||||
],
|
"1",
|
||||||
[
|
490,
|
||||||
"1",
|
675
|
||||||
550,
|
],
|
||||||
640
|
[
|
||||||
|
"2",
|
||||||
|
"2",
|
||||||
|
490,
|
||||||
|
645
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"R738": [
|
"R747": {
|
||||||
[
|
"name": "0402WGF1001TCE",
|
||||||
"2",
|
"pins": [
|
||||||
610,
|
[
|
||||||
680
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
150,
|
||||||
"1",
|
680
|
||||||
610,
|
],
|
||||||
640
|
[
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
150,
|
||||||
|
640
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"R739": [
|
"Q8": {
|
||||||
[
|
"name": "AO3400A_C20917",
|
||||||
"2",
|
"pins": [
|
||||||
670,
|
[
|
||||||
680
|
"3",
|
||||||
],
|
"D",
|
||||||
[
|
290,
|
||||||
"1",
|
580
|
||||||
670,
|
],
|
||||||
640
|
[
|
||||||
|
"1",
|
||||||
|
"G",
|
||||||
|
260,
|
||||||
|
560
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2",
|
||||||
|
"S",
|
||||||
|
290,
|
||||||
|
540
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"Q6": [
|
"R748": {
|
||||||
[
|
"name": "0402WGF1001TCE",
|
||||||
"3",
|
"pins": [
|
||||||
710,
|
[
|
||||||
350
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
220,
|
||||||
"1",
|
560
|
||||||
680,
|
],
|
||||||
330
|
[
|
||||||
],
|
"1",
|
||||||
[
|
"1",
|
||||||
"2",
|
180,
|
||||||
710,
|
560
|
||||||
310
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"R733": [
|
"R749": {
|
||||||
[
|
"name": "0402WGF1003TCE",
|
||||||
"2",
|
"pins": [
|
||||||
620,
|
[
|
||||||
330
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
230,
|
||||||
"1",
|
530
|
||||||
580,
|
],
|
||||||
330
|
[
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
230,
|
||||||
|
490
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"R734": [
|
"R750": {
|
||||||
[
|
"name": "0402WGF1002TCE",
|
||||||
"2",
|
"pins": [
|
||||||
660,
|
[
|
||||||
290
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
960,
|
||||||
"1",
|
740
|
||||||
660,
|
],
|
||||||
250
|
[
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
960,
|
||||||
|
700
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"D2": [
|
"R751": {
|
||||||
[
|
"name": "0402WGF1502TCE",
|
||||||
"2",
|
"pins": [
|
||||||
790,
|
[
|
||||||
450
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
830,
|
||||||
"1",
|
690
|
||||||
790,
|
],
|
||||||
410
|
[
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
790,
|
||||||
|
690
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"C738": [
|
"R752": {
|
||||||
[
|
"name": "0402WGF1002TCE",
|
||||||
"1",
|
"pins": [
|
||||||
880,
|
[
|
||||||
605
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
790,
|
||||||
"2",
|
670
|
||||||
880,
|
],
|
||||||
635
|
[
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
790,
|
||||||
|
630
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"R730": [
|
"R753": {
|
||||||
[
|
"name": "0402WGF1002TCE",
|
||||||
"2",
|
"pins": [
|
||||||
950,
|
[
|
||||||
320
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
710,
|
||||||
"1",
|
770
|
||||||
950,
|
],
|
||||||
280
|
[
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
710,
|
||||||
|
730
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"R731": [
|
"R754": {
|
||||||
[
|
"name": "0402WGF1002TCE",
|
||||||
"2",
|
"pins": [
|
||||||
890,
|
[
|
||||||
240
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
960,
|
||||||
"1",
|
500
|
||||||
850,
|
],
|
||||||
240
|
[
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
960,
|
||||||
|
460
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"R732": [
|
"R755": {
|
||||||
[
|
"name": "0402WGF1502TCE",
|
||||||
"2",
|
"pins": [
|
||||||
950,
|
[
|
||||||
220
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
830,
|
||||||
"1",
|
450
|
||||||
950,
|
],
|
||||||
180
|
[
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
790,
|
||||||
|
450
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"J26": [
|
"R756": {
|
||||||
[
|
"name": "0402WGF1002TCE",
|
||||||
"1",
|
"pins": [
|
||||||
1065,
|
[
|
||||||
710
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
790,
|
||||||
"2",
|
430
|
||||||
1065,
|
],
|
||||||
700
|
[
|
||||||
],
|
"1",
|
||||||
[
|
"1",
|
||||||
"3",
|
790,
|
||||||
1065,
|
390
|
||||||
690
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"J27": [
|
"R757": {
|
||||||
[
|
"name": "0402WGF1002TCE",
|
||||||
"1",
|
"pins": [
|
||||||
1065,
|
[
|
||||||
630
|
"2",
|
||||||
],
|
"2",
|
||||||
[
|
710,
|
||||||
"2",
|
530
|
||||||
1065,
|
],
|
||||||
620
|
[
|
||||||
],
|
"1",
|
||||||
[
|
"1",
|
||||||
"3",
|
710,
|
||||||
1065,
|
490
|
||||||
610
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"J28": [
|
"J26": {
|
||||||
[
|
"name": "2510-4A",
|
||||||
"1",
|
"pins": [
|
||||||
1065,
|
[
|
||||||
550
|
"1",
|
||||||
],
|
"1",
|
||||||
[
|
1065,
|
||||||
"2",
|
710
|
||||||
1065,
|
],
|
||||||
540
|
[
|
||||||
],
|
"2",
|
||||||
[
|
"2",
|
||||||
"3",
|
1065,
|
||||||
1065,
|
700
|
||||||
530
|
],
|
||||||
|
[
|
||||||
|
"3",
|
||||||
|
"3",
|
||||||
|
1065,
|
||||||
|
690
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"4",
|
||||||
|
"4",
|
||||||
|
1065,
|
||||||
|
680
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"J29": [
|
"J27": {
|
||||||
[
|
"name": "2510-4A",
|
||||||
"1",
|
"pins": [
|
||||||
1065,
|
[
|
||||||
470
|
"1",
|
||||||
],
|
"1",
|
||||||
[
|
1065,
|
||||||
"2",
|
470
|
||||||
1065,
|
],
|
||||||
460
|
[
|
||||||
],
|
"2",
|
||||||
[
|
"2",
|
||||||
"3",
|
1065,
|
||||||
1065,
|
460
|
||||||
450
|
],
|
||||||
|
[
|
||||||
|
"3",
|
||||||
|
"3",
|
||||||
|
1065,
|
||||||
|
450
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"4",
|
||||||
|
"4",
|
||||||
|
1065,
|
||||||
|
440
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"J30": [
|
"Q7": {
|
||||||
[
|
"name": "AO3401A_C15127",
|
||||||
"1",
|
"pins": [
|
||||||
1065,
|
[
|
||||||
390
|
"3",
|
||||||
],
|
"D",
|
||||||
[
|
310,
|
||||||
"2",
|
710
|
||||||
1065,
|
],
|
||||||
380
|
[
|
||||||
],
|
"1",
|
||||||
[
|
"G",
|
||||||
"3",
|
280,
|
||||||
1065,
|
730
|
||||||
370
|
],
|
||||||
|
[
|
||||||
|
"2",
|
||||||
|
"S",
|
||||||
|
310,
|
||||||
|
750
|
||||||
|
]
|
||||||
]
|
]
|
||||||
],
|
},
|
||||||
"_page": "fd00f13e59336392"
|
"DZ3": {
|
||||||
|
"name": "BZT52C8V2",
|
||||||
|
"pins": [
|
||||||
|
[
|
||||||
|
"1",
|
||||||
|
"K",
|
||||||
|
150,
|
||||||
|
770
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2",
|
||||||
|
"A",
|
||||||
|
150,
|
||||||
|
730
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"R746": {
|
||||||
|
"name": "0402WGF1003TCE",
|
||||||
|
"pins": [
|
||||||
|
[
|
||||||
|
"2",
|
||||||
|
"2",
|
||||||
|
240,
|
||||||
|
770
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"1",
|
||||||
|
"1",
|
||||||
|
240,
|
||||||
|
730
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Q9": {
|
||||||
|
"name": "AO3400A_C20917",
|
||||||
|
"pins": [
|
||||||
|
[
|
||||||
|
"3",
|
||||||
|
"D",
|
||||||
|
710,
|
||||||
|
710
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"1",
|
||||||
|
"G",
|
||||||
|
740,
|
||||||
|
690
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2",
|
||||||
|
"S",
|
||||||
|
710,
|
||||||
|
670
|
||||||
|
]
|
||||||
|
]
|
||||||
|
},
|
||||||
|
"Q10": {
|
||||||
|
"name": "AO3400A_C20917",
|
||||||
|
"pins": [
|
||||||
|
[
|
||||||
|
"3",
|
||||||
|
"D",
|
||||||
|
710,
|
||||||
|
470
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"1",
|
||||||
|
"G",
|
||||||
|
740,
|
||||||
|
450
|
||||||
|
],
|
||||||
|
[
|
||||||
|
"2",
|
||||||
|
"S",
|
||||||
|
710,
|
||||||
|
430
|
||||||
|
]
|
||||||
|
]
|
||||||
|
}
|
||||||
}
|
}
|
||||||
@@ -25,7 +25,9 @@ from eda import run
|
|||||||
DX, DY = 30.0, 5.0 # 下板原点在载板坐标里的位置
|
DX, DY = 30.0, 5.0 # 下板原点在载板坐标里的位置
|
||||||
GAP = 13.0 # 两板净空
|
GAP = 13.0 # 两板净空
|
||||||
MARGIN = 1.0 # 装配余量
|
MARGIN = 1.0 # 装配余量
|
||||||
BW, BH = 160.0, 125.0
|
# 2026-09-07:跟 pcb1_place 一起改成真板框(220x135,左下角 (-30,-5))。
|
||||||
|
BX0, BY0, BX1, BY1 = -30.0, -5.0, 190.0, 130.0
|
||||||
|
BW, BH = BX1 - BX0, BY1 - BY0
|
||||||
|
|
||||||
LANE_H = 1.0 # 排线(0.2 厚)+ 走线余量,按 1 mm 算
|
LANE_H = 1.0 # 排线(0.2 厚)+ 走线余量,按 1 mm 算
|
||||||
|
|
||||||
@@ -37,7 +39,7 @@ def shift(x0, y0, x1, y1):
|
|||||||
def clip(r):
|
def clip(r):
|
||||||
u"""裁到下板板框内;完全在框外返回 None。"""
|
u"""裁到下板板框内;完全在框外返回 None。"""
|
||||||
x0 = max(r[0], 0.0); y0 = max(r[1], 0.0)
|
x0 = max(r[0], 0.0); y0 = max(r[1], 0.0)
|
||||||
x1 = min(r[2], BW); y1 = min(r[3], BH)
|
x1 = min(r[2], BX1); y1 = min(r[3], BY1)
|
||||||
if x1 <= x0 or y1 <= y0:
|
if x1 <= x0 or y1 <= y0:
|
||||||
return None
|
return None
|
||||||
return [round(x0, 2), round(y0, 2), round(x1, 2), round(y1, 2)]
|
return [round(x0, 2), round(y0, 2), round(x1, 2), round(y1, 2)]
|
||||||
@@ -54,7 +56,7 @@ def header_anchors():
|
|||||||
pads = json.load(io.open(os.path.join(HERE, 'pcb2-header-pads.json'), encoding='utf-8'))['pads']
|
pads = json.load(io.open(os.path.join(HERE, 'pcb2-header-pads.json'), encoding='utf-8'))['pads']
|
||||||
nets = {}
|
nets = {}
|
||||||
r = run("""
|
r = run("""
|
||||||
await eda.dmt_EditorControl.openDocument('f126ffb29c92f9b2');
|
await eda.dmt_EditorControl.openDocument('942ed1560d81c1e7');
|
||||||
await new Promise(r=>setTimeout(r,2000));
|
await new Promise(r=>setTimeout(r,2000));
|
||||||
const out = {};
|
const out = {};
|
||||||
for (const c of await eda.pcb_PrimitiveComponent.getAll()) {
|
for (const c of await eda.pcb_PrimitiveComponent.getAll()) {
|
||||||
@@ -116,7 +118,7 @@ def build():
|
|||||||
data = {
|
data = {
|
||||||
'frame': u'下板 PCB1 坐标系 mm,原点左下角,Y 向上。下板坐标 = 载板坐标 − (30,5)。'
|
'frame': u'下板 PCB1 坐标系 mm,原点左下角,Y 向上。下板坐标 = 载板坐标 − (30,5)。'
|
||||||
u'hmax = 该矩形内下板元件允许的最大高度 = 13(净空) − h(载板底面元件) − 1(余量)',
|
u'hmax = 该矩形内下板元件允许的最大高度 = 13(净空) − h(载板底面元件) − 1(余量)',
|
||||||
'gap': GAP, 'board': [BW, BH],
|
'gap': GAP, 'board': [BW, BH], 'board_rect': [BX0, BY0, BX1, BY1],
|
||||||
'anchors': anchors, 'zones': zones, 'lanes': lanes, 'slots': slots,
|
'anchors': anchors, 'zones': zones, 'lanes': lanes, 'slots': slots,
|
||||||
}
|
}
|
||||||
out = os.path.join(HERE, 'pcb1-env.json')
|
out = os.path.join(HERE, 'pcb1-env.json')
|
||||||
|
|||||||
@@ -156,11 +156,18 @@ def main():
|
|||||||
pours = R.pour_rects()
|
pours = R.pour_rects()
|
||||||
obstacles = R.obstacles_of(pads, vias, lines, pours)
|
obstacles = R.obstacles_of(pads, vias, lines, pours)
|
||||||
js = R.jobs(pads, want, skip=() if want else R.SKIP)
|
js = R.jobs(pads, want, skip=() if want else R.SKIP)
|
||||||
|
# ⚠️ 2026-09-06 起 `route_sig` 把出线段也下发了 —— 布不通的焊盘在板上是
|
||||||
|
# 「一个焊盘 + 一小截自己的出线段」,不再是光焊盘。只认光焊盘会报「0 个」。
|
||||||
|
# 出线段全长 ≤ 1.2 mm、没有过孔的碎片,一样当孤立焊盘审。
|
||||||
need = set()
|
need = set()
|
||||||
for net, frags in js:
|
for net, frags in js:
|
||||||
for fr in frags:
|
for fr in frags:
|
||||||
if len(fr['pads']) == 1 and not fr['vias'] and not fr['lines']:
|
if len(fr['pads']) != 1 or fr['vias']:
|
||||||
need.add(fr['pads'][0]['tag'])
|
continue
|
||||||
|
q = fr['pads'][0]
|
||||||
|
if all(max(math.hypot(l['x0'] - q['x'], l['y0'] - q['y']),
|
||||||
|
math.hypot(l['x1'] - q['x'], l['y1'] - q['y'])) <= 1.2 for l in fr['lines']):
|
||||||
|
need.add(q['tag'])
|
||||||
order = [n for n, _f in js]
|
order = [n for n, _f in js]
|
||||||
stubs, alts = R.plan_stubs(order, pads, obstacles, need)
|
stubs, alts = R.plan_stubs(order, pads, obstacles, need)
|
||||||
audit.stubs = stubs
|
audit.stubs = stubs
|
||||||
|
|||||||
@@ -70,7 +70,10 @@ E = RS.E # 引擎(polish / _l_shapes / board_mask 从这
|
|||||||
#: **但 2026-09-06 试着加进来没跑通**:它板上的铜整片都在顶层、且集中在控制块那一带,
|
#: **但 2026-09-06 试着加进来没跑通**:它板上的铜整片都在顶层、且集中在控制块那一带,
|
||||||
#: 六条连线里有四条报「L2 源0 / L16 源0」—— 主碎片周围一个合法孔位都没有,扎不下去。
|
#: 六条连线里有四条报「L2 源0 / L16 源0」—— 主碎片周围一个合法孔位都没有,扎不下去。
|
||||||
#: 要挪它得先把控制块那一带的顶层拆开,不是改这一行的事。
|
#: 要挪它得先把控制块那一带的顶层拆开,不是改这一行的事。
|
||||||
NETS = ('SCL', 'SDA')
|
NETS = ('SCL', 'SDA', 'BUCK_PG')
|
||||||
|
# ── 侧键模拟线 POGO3_PWR / POGO3_VDN / POGO4_VDN / POGO5_PWR / POGO5_VUP(第二十六轮加)
|
||||||
|
# 2026-09-06 随 74HC595 + 按键 MOS 整窝挪到载板(§26.23)之后,下板上不再有 POGO* 网络,
|
||||||
|
# 已从候选表拿掉;它们在 Inner2 上的铜由 pcb_prune_nets.py 一并清掉了。
|
||||||
L_TOP, L_BOT, L3 = 1, 2, 16
|
L_TOP, L_BOT, L3 = 1, 2, 16
|
||||||
LAYS = (L_TOP, L_BOT, L3)
|
LAYS = (L_TOP, L_BOT, L3)
|
||||||
|
|
||||||
@@ -108,6 +111,14 @@ CLUSTERS = {
|
|||||||
'U12': (121.5, 45.5, 129.5, 52.5), # CH5 INA226
|
'U12': (121.5, 45.5, 129.5, 52.5), # CH5 INA226
|
||||||
'U13': (3.0, 90.5, 11.0, 100.0), # 输入侧 INA226
|
'U13': (3.0, 90.5, 11.0, 100.0), # 输入侧 INA226
|
||||||
'J24': (30.0, 60.5, 38.5, 67.0), # 排针(通孔针,L3 上直接落脚)
|
'J24': (30.0, 60.5, 38.5, 67.0), # 排针(通孔针,L3 上直接落脚)
|
||||||
|
# 五路 Buck 控制器:`BUCK_PG` 在 U*.14 上。**不划框的话整条出线短线也被拆掉**,
|
||||||
|
# 而那几个脚在 0.5 mm 脚距的 QFN 上,`entry_stub` 重建不回来 ⇒ 整个网络断成 6 片
|
||||||
|
# (2026-09-06 实测,连通性保险当场拦下)。框只罩住芯片本体 + 0.6 mm。
|
||||||
|
'U1': (14.4, 25.1, 19.2, 29.9),
|
||||||
|
'U2': (48.7, 95.6, 53.5, 100.4),
|
||||||
|
'U3': (137.1, 95.6, 141.9, 100.4),
|
||||||
|
'U4': (46.1, 25.1, 50.9, 29.9),
|
||||||
|
'U5': (125.6, 25.1, 130.4, 29.9),
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -964,6 +975,8 @@ def main():
|
|||||||
|
|
||||||
pads, vias, lines = NL.geom(refresh)
|
pads, vias, lines = NL.geom(refresh)
|
||||||
print(u'板上:焊盘 %d / 过孔 %d / 走线 %d' % (len(pads), len(vias), len(lines)))
|
print(u'板上:焊盘 %d / 过孔 %d / 走线 %d' % (len(pads), len(vias), len(lines)))
|
||||||
|
# ⚠️ 只拆**这一轮要动的**网络(`--net` 限定时尤其重要)
|
||||||
|
globals()['NETS'] = tuple(nets)
|
||||||
keep_l, drop_l, keep_v, drop_v = split_old(pads, vias, lines)
|
keep_l, drop_l, keep_v, drop_v = split_old(pads, vias, lines)
|
||||||
dlen = sum(math.hypot(lines[i]['x1'] - lines[i]['x0'],
|
dlen = sum(math.hypot(lines[i]['x1'] - lines[i]['x0'],
|
||||||
lines[i]['y1'] - lines[i]['y0']) for i in drop_l)
|
lines[i]['y1'] - lines[i]['y0']) for i in drop_l)
|
||||||
@@ -1016,7 +1029,48 @@ def main():
|
|||||||
if worse:
|
if worse:
|
||||||
# ⚠️ 这条保险是必需的:本脚本会把这些网络在簇框外的铜**全部拆掉**重来。
|
# ⚠️ 这条保险是必需的:本脚本会把这些网络在簇框外的铜**全部拆掉**重来。
|
||||||
# 拆得动、重连不上的话,板子会比动手之前更差,而净距校核照样全绿。
|
# 拆得动、重连不上的话,板子会比动手之前更差,而净距校核照样全绿。
|
||||||
sys.exit(u'⛔ %s 的连通性变差了 —— 不下发' % ' / '.join(worse))
|
#
|
||||||
|
# 但**不要因此把整轮毙掉** —— `NETS` 是一张「候选表」,里面难免有挪不动的
|
||||||
|
# (2026-09-06 实测 `BUCK_PG`:五个分支要去板子四角,而 L3 上 y<34 往东
|
||||||
|
# 只剩 x115~116 那条 1.0 mm 缝,`+12V` 把别的通道全占了)。
|
||||||
|
# 把变差的那几个**踢出去重算一遍**,剩下的照常下发。
|
||||||
|
print(u' → %s 挪进内层会变差,踢出候选表重算一轮' % ' / '.join(worse))
|
||||||
|
keep = [n for n in nets if n not in worse]
|
||||||
|
if not keep:
|
||||||
|
sys.exit(u'⛔ 候选表里一个都留不下 —— 不下发')
|
||||||
|
# ⚠️ **拆除清单必须跟着重算**。第一版只换了 `run_plan` 的网络表,
|
||||||
|
# 而 `drop_l/drop_v` 还是按完整候选表算的 ⇒ `--push` 会把被踢掉那个网络的
|
||||||
|
# 铜删掉、又不给它重布,板子直接变差(净距校核照样全绿)。
|
||||||
|
globals()['NETS'] = tuple(keep)
|
||||||
|
keep_l, drop_l, keep_v, drop_v = split_old(pads, vias, lines)
|
||||||
|
vlines, vvias = virtual(pads, vias, lines, drop_l, drop_v)
|
||||||
|
print(u' 重算后要拆:%d 段 / %d 孔(%d 个网络)'
|
||||||
|
% (len(drop_l), len(drop_v), len(keep)))
|
||||||
|
del BLOCK[:]
|
||||||
|
routes = run_plan(pads, vvias, vlines, keep)
|
||||||
|
routes = chamfer(routes, pads, vvias, vlines)
|
||||||
|
msgs, _r = plane_report(routes, pads_raw, obs_board)
|
||||||
|
for m in msgs:
|
||||||
|
print(u' ⚠️ ' + m)
|
||||||
|
if msgs:
|
||||||
|
sys.exit(u'⛔ 重算之后仍有孤岛 —— 不下发')
|
||||||
|
summarize(routes)
|
||||||
|
bad = verify(routes, pads, vvias, vlines)
|
||||||
|
for b in bad[:20]:
|
||||||
|
print(u' ✗ ' + b)
|
||||||
|
if bad:
|
||||||
|
sys.exit(u'⛔ 重算之后校核不过 —— 不下发')
|
||||||
|
nets = keep
|
||||||
|
worse2 = []
|
||||||
|
for net, n, det in connectivity(routes, pads, vvias, vlines):
|
||||||
|
was = len(frags(net, pads, vias, lines))
|
||||||
|
print(u' 连通性 %s:%d 个碎片 %s%s'
|
||||||
|
% (net, n, det if n > 1 else u'✅',
|
||||||
|
u'' if n <= was else u' ⛔ 仍然变差'))
|
||||||
|
if n > was and net in keep:
|
||||||
|
worse2.append(net)
|
||||||
|
if worse2:
|
||||||
|
sys.exit(u'⛔ %s 重算之后仍然变差 —— 不下发' % ' / '.join(worse2))
|
||||||
if not push:
|
if not push:
|
||||||
print(u'\n(只算不下发。要下发加 --push)')
|
print(u'\n(只算不下发。要下发加 --push)')
|
||||||
return
|
return
|
||||||
|
|||||||
@@ -20,6 +20,14 @@ HERE = os.path.dirname(os.path.abspath(__file__)); sys.path.insert(0, HERE)
|
|||||||
from eda import run
|
from eda import run
|
||||||
|
|
||||||
PCB = '7e9415a16a909c51'
|
PCB = '7e9415a16a909c51'
|
||||||
|
# 2026-09-06:加 `--board2` 就对载板 PCB2 做同一套事(BOM / 对话框 / 对账),产出文件带 _p2_ 前缀
|
||||||
|
BOARD2 = '--board2' in sys.argv
|
||||||
|
if BOARD2:
|
||||||
|
PCB = '942ed1560d81c1e7'
|
||||||
|
sys.argv = [a for a in sys.argv if a != '--board2']
|
||||||
|
BOM_FILE = '_p2_sch_bom.json' if BOARD2 else '_p1_sch_bom.json'
|
||||||
|
COMPS_FILE = '_pcb2_comps.json' if BOARD2 else '_pcb1_comps.json'
|
||||||
|
ROWS_FILE = '_p2_import_rows.json' if BOARD2 else '_p1_import_rows.json'
|
||||||
|
|
||||||
HELPERS = u"""
|
HELPERS = u"""
|
||||||
const sleep = ms => new Promise(r => setTimeout(r, ms));
|
const sleep = ms => new Promise(r => setTimeout(r, ms));
|
||||||
@@ -90,14 +98,14 @@ JS_DUMP = u"""
|
|||||||
// 少了这一行,紧跟在 --bom(最后停在某张原理图上)之后跑 --verify,
|
// 少了这一行,紧跟在 --bom(最后停在某张原理图上)之后跑 --verify,
|
||||||
// `pcb_PrimitiveComponent.getAll()` 在原理图文档上直接抛
|
// `pcb_PrimitiveComponent.getAll()` 在原理图文档上直接抛
|
||||||
// `Cannot read properties of null (reading 'map')` —— 报错信息完全指不到根因。
|
// `Cannot read properties of null (reading 'map')` —— 报错信息完全指不到根因。
|
||||||
await eda.dmt_EditorControl.openDocument('7e9415a16a909c51');
|
await eda.dmt_EditorControl.openDocument('%s');
|
||||||
await new Promise(r => setTimeout(r, 1800));
|
await new Promise(r => setTimeout(r, 1800));
|
||||||
const cs = await eda.pcb_PrimitiveComponent.getAll();
|
const cs = await eda.pcb_PrimitiveComponent.getAll();
|
||||||
const out = [];
|
const out = [];
|
||||||
for (const c of cs) out.push({d: c.designator, x: c.x, y: c.y, rot: c.rotation, lay: c.layer,
|
for (const c of cs) out.push({d: c.designator, x: c.x, y: c.y, rot: c.rotation, lay: c.layer,
|
||||||
fp: (c.footprint && c.footprint.name) ? c.footprint.name : (c.footprint || null)});
|
fp: (c.footprint && c.footprint.name) ? c.footprint.name : (c.footprint || null)});
|
||||||
return out;
|
return out;
|
||||||
"""
|
""" % PCB
|
||||||
|
|
||||||
JS_BOM = u"""
|
JS_BOM = u"""
|
||||||
const sleep = ms => new Promise(r => setTimeout(r, ms));
|
const sleep = ms => new Promise(r => setTimeout(r, ms));
|
||||||
@@ -123,7 +131,8 @@ def refresh_bom():
|
|||||||
⚠️ **一页一个请求**,不要一次抓 11 页 —— `eda.py` 把返回值截到 20000 字符再打印,
|
⚠️ **一页一个请求**,不要一次抓 11 页 —— `eda.py` 把返回值截到 20000 字符再打印,
|
||||||
整本 BOM 装不下,截断之后 `json.load` 直接炸在中间(2026-09-06 踩过)。
|
整本 BOM 装不下,截断之后 `json.load` 直接炸在中间(2026-09-06 踩过)。
|
||||||
"""
|
"""
|
||||||
pages = json.load(io.open(os.path.join(HERE, 'eda-parts.json'), encoding='utf-8'))['pages']
|
ep = json.load(io.open(os.path.join(HERE, 'eda-parts.json'), encoding='utf-8'))
|
||||||
|
pages = ep['schematic_boards']['Board2']['pages'] if BOARD2 else ep['pages']
|
||||||
bom, bad = {}, []
|
bom, bad = {}, []
|
||||||
for name, uuid in pages.items():
|
for name, uuid in pages.items():
|
||||||
r = run(JS_BOM % (uuid, name.upper()), timeout=300)
|
r = run(JS_BOM % (uuid, name.upper()), timeout=300)
|
||||||
@@ -141,9 +150,9 @@ def refresh_bom():
|
|||||||
for b in bad:
|
for b in bad:
|
||||||
print(u' · ' + b)
|
print(u' · ' + b)
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
io.open(os.path.join(HERE, '_p1_sch_bom.json'), 'w', encoding='utf-8').write(
|
io.open(os.path.join(HERE, BOM_FILE), 'w', encoding='utf-8').write(
|
||||||
json.dumps(bom, ensure_ascii=False))
|
json.dumps(bom, ensure_ascii=False))
|
||||||
print(u'已写 _p1_sch_bom.json:%d 页 / %d 件' % (len(bom), sum(len(v) for v in bom.values())))
|
print(u'已写 ' + BOM_FILE + u':%d 页 / %d 件' % (len(bom), sum(len(v) for v in bom.values())))
|
||||||
|
|
||||||
|
|
||||||
def dump():
|
def dump():
|
||||||
@@ -153,8 +162,8 @@ def dump():
|
|||||||
|
|
||||||
def verify():
|
def verify():
|
||||||
cs = dump()
|
cs = dump()
|
||||||
io.open(os.path.join(HERE, '_pcb1_comps.json'), 'w', encoding='utf-8').write(json.dumps(cs, ensure_ascii=False))
|
io.open(os.path.join(HERE, COMPS_FILE), 'w', encoding='utf-8').write(json.dumps(cs, ensure_ascii=False))
|
||||||
bom = json.load(io.open(os.path.join(HERE, '_p1_sch_bom.json'), encoding='utf-8'))
|
bom = json.load(io.open(os.path.join(HERE, BOM_FILE), encoding='utf-8'))
|
||||||
sch = {}
|
sch = {}
|
||||||
for pg, v in bom.items():
|
for pg, v in bom.items():
|
||||||
for c in v:
|
for c in v:
|
||||||
@@ -179,7 +188,7 @@ if __name__ == '__main__':
|
|||||||
r = run(JS_PROBE, timeout=400)
|
r = run(JS_PROBE, timeout=400)
|
||||||
if not r.get('success'): sys.exit(json.dumps(r, ensure_ascii=False)[:800])
|
if not r.get('success'): sys.exit(json.dumps(r, ensure_ascii=False)[:800])
|
||||||
res = r['result']
|
res = r['result']
|
||||||
io.open(os.path.join(HERE, '_p1_import_rows.json'), 'w', encoding='utf-8').write(json.dumps(res, ensure_ascii=False, indent=1))
|
io.open(os.path.join(HERE, ROWS_FILE), 'w', encoding='utf-8').write(json.dumps(res, ensure_ascii=False, indent=1))
|
||||||
print(u'opened=%s 快照 %d 屏' % (res.get('opened'), len(res.get('seq') or [])))
|
print(u'opened=%s 快照 %d 屏' % (res.get('opened'), len(res.get('seq') or [])))
|
||||||
print(res.get('buttons'))
|
print(res.get('buttons'))
|
||||||
elif a == '--apply':
|
elif a == '--apply':
|
||||||
|
|||||||
@@ -166,8 +166,14 @@ def analyze(net, pads, vias, lines, pgrids):
|
|||||||
play, g, cid = node
|
play, g, cid = node
|
||||||
if play != lay:
|
if play != lay:
|
||||||
return False
|
return False
|
||||||
i0, i1 = int((x - hw) / G), int((x + hw) / G) + 1
|
# ⚠️ 必须走 pcb1_pour 的 gi/gj —— 板框左下角是 (−30, −5),不是 (0, 0)。
|
||||||
j0, j1 = int((y - hh) / G), int((y + hh) / G) + 1
|
# 2026-09-08 踩过:pcb1_pour 把 BW/BH 从假板框 160×125 改成真板框 220×135
|
||||||
|
# 并加了 BX0/BY0 之后,这里还在 `int(x / G)`,坐标整体偏了 30 mm ——
|
||||||
|
# 表现是「靠平面连通的网络(+12V/GND/+3V3/VOn_P)忽然全部碎成几十片」,
|
||||||
|
# 而 pcb1_pour --verify 回读的实测铺铜完全健康。**两边对不上时信实测那一边。**
|
||||||
|
# 更贵的是 pcb1_orphan_cu 走的就是这套栅格,据此误删过 12 个好过孔。
|
||||||
|
i0, i1 = PO.gi(x - hw), PO.gi(x + hw) + 1
|
||||||
|
j0, j1 = PO.gj(y - hh), PO.gj(y + hh) + 1
|
||||||
for j in range(max(0, j0), min(g.ny, j1 + 1)):
|
for j in range(max(0, j0), min(g.ny, j1 + 1)):
|
||||||
for i in range(max(0, i0), min(g.nx, i1 + 1)):
|
for i in range(max(0, i0), min(g.nx, i1 + 1)):
|
||||||
if g.lab[j][i] == cid:
|
if g.lab[j][i] == cid:
|
||||||
|
|||||||
@@ -43,9 +43,20 @@ from eda import run
|
|||||||
|
|
||||||
PCB = '7e9415a16a909c51'
|
PCB = '7e9415a16a909c51'
|
||||||
MIL = 39.3700787401575
|
MIL = 39.3700787401575
|
||||||
BW, BH = 160.0, 125.0
|
# ⚠️⚠️ 2026-09-07 修正:这两个数从 2026-09-06「两板尺寸取大对齐」那一轮起就过期了 ——
|
||||||
|
# 板上实测的板框是 **220 x 135、左下角 (-30,-5)**(`pcb1_outline.py` 就是这么画的,
|
||||||
|
# 回读多段线 x -1181.1~7480.3 mil / y -196.9~5118.1 mil 逐条对上)。
|
||||||
|
# 旧值 (0,0,160,125) 是真板框的**子集**,所以越框检查一直是「偏严但不错」——
|
||||||
|
# 代价是**左右各 30 mm、上下各 6 mm 的板面从来没进过摆位视野**。
|
||||||
|
# 板边元件(风扇座、电源座、调试口)按旧值挑位置会挑到板子中间去。
|
||||||
|
BX0, BY0, BX1, BY1 = -30.0, -5.0, 190.0, 130.0 # 真板框,mm
|
||||||
|
BW, BH = BX1 - BX0, BY1 - BY0 # 220 x 135
|
||||||
CORNER_R = 5.0
|
CORNER_R = 5.0
|
||||||
MH = [(5.0, 5.0), (BW - 5.0, 5.0), (5.0, BH - 5.0), (BW - 5.0, BH - 5.0)]
|
# 2026-09-06 用户指令「两板尺寸取大对齐、四角定位孔对齐」:板框改成和载板一样的 220×135,
|
||||||
|
# **坐标原点不动**(下板坐标 = 载板坐标 − (30,5),pcb1_env.py 那条约定不变),板框画到 (−30,−5)~(190,130)。
|
||||||
|
# 定位孔 = 载板 `pcb2_place.MH` 减 (30,5):四角 + 两侧中点。载板中跨那两个 (46.6,74.5)/(118.1,74.5)
|
||||||
|
# 落在下板 CH2 功率级 / 布好的线上,不打。板框与孔由 `pcb_place.py --outline` 下发(同一张表)。
|
||||||
|
MH = [(-22.0, 3.0), (182.0, 3.0), (-26.0, 126.0), (186.0, 126.0), (-23.0, 55.0), (183.0, 40.0)]
|
||||||
MH_HOLE, MH_PAD, MH_KEEPOUT = 3.2, 6.0, 6.5
|
MH_HOLE, MH_PAD, MH_KEEPOUT = 3.2, 6.0, 6.5
|
||||||
|
|
||||||
PARTS = {c['d']: c for c in json.load(io.open(os.path.join(HERE, 'pcb1-parts.json'), encoding='utf-8'))}
|
PARTS = {c['d']: c for c in json.load(io.open(os.path.join(HERE, 'pcb1-parts.json'), encoding='utf-8'))}
|
||||||
@@ -63,8 +74,18 @@ FP_BODY = {
|
|||||||
# 上面这几条当年是拿放大截图量出来的,六条全部对得上(误差 ≤0.31)。
|
# 上面这几条当年是拿放大截图量出来的,六条全部对得上(误差 ≤0.31)。
|
||||||
# ⇒ 新加板边连接器时先跑 `fp_body.py --scan <关键词>`,别再猜 ±4.5。
|
# ⇒ 新加板边连接器时先跑 `fp_body.py --scan <关键词>`,别再猜 ±4.5。
|
||||||
# ── 2026-09-06 换件:J1 → XT30PW-M,J26~J30 → 2510-3A 直针座 ──
|
# ── 2026-09-06 换件:J1 → XT30PW-M,J26~J30 → 2510-3A 直针座 ──
|
||||||
'CONN-TH_XT30PW-M': (-6.65, -7.98, 6.65, 5.97), # 12V XT30 公头(90°板装)
|
'CONN-TH_XT30PW-M': (-6.65, -7.98, 6.65, 5.97), # 12V XT30 公头(已换掉,见下一条)
|
||||||
'CONN-TH_2510-3A': (-3.81, -2.88, 3.81, 2.93), # 风扇 3P **直针**座
|
# ── 2026-09-08 换件:J1 → 圆形 DC 电源座 DC-005-5.5*2.5(用户拍板,不降载)──
|
||||||
|
# ⚠️ 这个数不是量截图量出来的,是 `pcb_Primitive.getPrimitivesBBox([pid])` 直接读的
|
||||||
|
# (把件建在板外 (200,0) rot 0 读完再删)。**它含丝印/装配层,比塑壳本体大一圈** ——
|
||||||
|
# 同法读 XT30 得 14.85 x 13.55,而本体表里是 13.30 x 13.95,x 方向多 0.90。
|
||||||
|
# 偏大的方向是安全的(净距检查偏严),本体真值待打样时拿实物量(§12 待确认项)。
|
||||||
|
# 本体几乎全在 −X 侧、三个脚挤在 +X 端 ⇒ **桶口朝 −X**,朝西板边用 rot 0,不用转。
|
||||||
|
'DC-IN-TH_DC-005-2': (-10.68, -7.16, 3.92, 3.22), # 圆形 DC 座 5.5x2.5
|
||||||
|
'CONN-TH_2510-3A': (-3.81, -2.88, 3.81, 2.93), # 风扇 3P **直针**座(已换掉,见下一条)
|
||||||
|
# ── 2026-09-07 FAN-R2:五个 3 针风扇座 → 两个 4 针(一进一出,山洋 9G0612P4S001)──
|
||||||
|
'CONN-TH_4P-P2.54_CAX_2510-4A': (-5.08, -2.79, 5.08, 3.01), # 风扇 4P 直针座(fp_body --scan 读出)
|
||||||
|
'SOD-123_L2.7-W1.6-LS3.7-RD-1': (-1.93, -0.85, 1.93, 0.85), # DZ3 BZT52C8V2;本体比焊盘框宽 0.4
|
||||||
# 下面两条是换下来的,留着当对照(**别再用**):
|
# 下面两条是换下来的,留着当对照(**别再用**):
|
||||||
'CONN-TH_P5.08_KF128-5.08-2P': (-5.20, -5.20, 5.20, 5.20), # 旧 12V 螺钉端子
|
'CONN-TH_P5.08_KF128-5.08-2P': (-5.20, -5.20, 5.20, 5.20), # 旧 12V 螺钉端子
|
||||||
# ⚠️ KF2510-3A 是**弯针**座:焊盘一排,塑壳整个往 +Y 伸 11.7 mm,开口在远端。
|
# ⚠️ KF2510-3A 是**弯针**座:焊盘一排,塑壳整个往 +Y 伸 11.7 mm,开口在远端。
|
||||||
@@ -113,8 +134,13 @@ H_FP = {
|
|||||||
# ⚠️⚠️ 换成立式**省的是板面、付的是高度**:直针座塑壳竖起来。
|
# ⚠️⚠️ 换成立式**省的是板面、付的是高度**:直针座塑壳竖起来。
|
||||||
# `3D Model Transform` 只给 XY,**Z 读不出来** —— 下面两个数是按同系列
|
# `3D Model Transform` 只给 XY,**Z 读不出来** —— 下面两个数是按同系列
|
||||||
# 常规值取的保守估计,**打样前必须拿实物量**(§12 待确认项)。
|
# 常规值取的保守估计,**打样前必须拿实物量**(§12 待确认项)。
|
||||||
'CONN-TH_XT30PW-M': 11.0, # XT30 90° 板装公头,本体躺着
|
'CONN-TH_XT30PW-M': 11.0, # XT30 90° 板装公头,本体躺着(已换掉)
|
||||||
'CONN-TH_2510-3A': 9.0, # 2510 直针座,塑壳竖立
|
'DC-IN-TH_DC-005-2': 11.0, # 圆形 DC 座:同系列常规值,**打样前拿实物量**
|
||||||
|
# 放在西条(x −29~−1)上,那一条 hmax = 99(载板底面没东西),所以这个数目前不吃紧
|
||||||
|
'CONN-TH_2510-3A': 9.0, # 2510 直针座,塑壳竖立(3P,已换掉)
|
||||||
|
'CONN-TH_4P-P2.54_CAX_2510-4A': 11.5, # 2510 直针 4P:厂家属性 Z-Height of the Board = 11.5
|
||||||
|
'SOT-23_L2.9-W1.3-P1.90-LS2.4-BR': 1.2, # Q7 AO3401A(和另一个 SOT-23-3 同高,封装名不同)
|
||||||
|
'SOD-123_L2.7-W1.6-LS3.7-RD-1': 1.2, # DZ3 BZT52C8V2
|
||||||
# 排针本身就是对插件,不参与高度核算
|
# 排针本身就是对插件,不参与高度核算
|
||||||
'HDR-TH_40P-P2.54_AZ-PZ2.54-V11-2X20P': None,
|
'HDR-TH_40P-P2.54_AZ-PZ2.54-V11-2X20P': None,
|
||||||
}
|
}
|
||||||
@@ -238,12 +264,7 @@ CH1 = [
|
|||||||
# 放电联锁
|
# 放电联锁
|
||||||
('Q%01', 13.8, 35.5, 0), ('R%18', 16.4, 35.5, 0),
|
('Q%01', 13.8, 35.5, 0), ('R%18', 16.4, 35.5, 0),
|
||||||
('Q%02', 13.8, 39.5, 0), ('R%19', 17.8, 40.0, 90),
|
('Q%02', 13.8, 39.5, 0), ('R%19', 17.8, 40.0, 90),
|
||||||
# 按键驱动(远离 SW)
|
# 按键驱动 Q%03~05 / R%20~25:2026-09-06 随 74HC595 整窝挪到载板(§26.23),这一片空出来了
|
||||||
('Q%03', 24.0, 12.0, 0), ('Q%04', 28.0, 12.0, 0),
|
|
||||||
('Q%05', 24.0, 16.0, 0), ('R%20', 28.0, 16.0, 0),
|
|
||||||
('R%21', 24.0, 19.5, 0), ('R%22', 28.0, 19.5, 0),
|
|
||||||
('R%23', 24.0, 22.5, 0), ('R%24', 28.0, 22.5, 0),
|
|
||||||
('R%25', 24.0, 25.5, 0),
|
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -294,7 +315,20 @@ put('J25', 128.0, 62.5, 0)
|
|||||||
# **原来 F1 那个位置 (14.5,71.5) 正好被吃掉**。
|
# **原来 F1 那个位置 (14.5,71.5) 正好被吃掉**。
|
||||||
# 而东边的墙是硬的:北排 CH2 从 **x 29.6** 起,D1(SMB) 再往东就撞上去。
|
# 而东边的墙是硬的:北排 CH2 从 **x 29.6** 起,D1(SMB) 再往东就撞上去。
|
||||||
# ⇒ J1 东边只剩 15 mm 给 F1/Q1/D1/DZ1/C1/R1 六件,一行排不下(要 15+ mm),改**两行**。
|
# ⇒ J1 东边只剩 15 mm 给 F1/Q1/D1/DZ1/C1/R1 六件,一行排不下(要 15+ mm),改**两行**。
|
||||||
put('J1', 8.5, 72.0, 270) # 12V XT30 公头,插口朝左板边(rot 270)
|
# 2026-09-08 ⛔ **硬缺陷修复**:J1 原来在 x=8.5(本体 x 0.5~14.7)——
|
||||||
|
# 那是按**过期的假板框 160×125**挑的“西板边”。真板框西边在 x=−30,
|
||||||
|
# 于是这个 **90° 板装** XT30 的插口缩在板内 30.5 mm,上方 13 mm 处还压着载板
|
||||||
|
# —— **插头根本插不进去**。不是优化问题,是板子能不能用的问题。
|
||||||
|
# → 整个输入首级(J1/F1/Q1/D1 + Q1 的栅极卫星 DZ1/C1/R1)西移 30 mm。
|
||||||
|
# 西条 x −29~−1 整条 hmax = 99(载板底面没东西),高件随便放。
|
||||||
|
# 代价:加权 HPWL +1~3%(源头离负载远了)—— 这是板子可装配的必要代价。
|
||||||
|
# 2026-09-08 换成圆形 DC 电源座(用户拍板:DC-005 5.5x2.5,**不降载**,接受插座超额定)。
|
||||||
|
# ⚠️ 整机 12V 最坏 9.99 A(§22.6),而 DC-005 家族额定 2~5 A —— 这是全板唯一一处
|
||||||
|
# 明知超额定还要装的地方,发热在**插头内芯与插座弹片的接触面**,板上加铜救不了。
|
||||||
|
# 板端能做的只有一件:pin2 / pin3 两个负极触点**都接地并联**,接触电阻减半(见 p1_dcjack.py)。
|
||||||
|
# 桶口朝 −X ⇒ **rot 0**(XT30 那颗要 rot 270,别照抄)。本体 x −10.68~+3.92 相对中心,
|
||||||
|
# 放 x=−18.8 时本体 x −29.48~−14.88,离真西板边 (−30) 0.52 mm,和原来 XT30 的 0.5 一致。
|
||||||
|
put('J1', -18.8, 72.0, 0) # 12V 圆形 DC 座,桶口朝**真**西板边(本体 x −29.5~−14.9)
|
||||||
# ⚠⚠ **v11 的两行排法把 8 A 链卡死了**(2026-09-06 第二十三轮重排)。
|
# ⚠⚠ **v11 的两行排法把 8 A 链卡死了**(2026-09-06 第二十三轮重排)。
|
||||||
# XT30 rot 270 之后 **GND 在北针 (13.5,74.5)、VIN 在南针 (13.5,69.5)**,
|
# XT30 rot 270 之后 **GND 在北针 (13.5,74.5)、VIN 在南针 (13.5,69.5)**,
|
||||||
# 而 F1 卵在 (17.5,74.5) 卧着放 ⇒ VIN_RAW 要从南针绕到 GND 盘东侧再北上,
|
# 而 F1 卵在 (17.5,74.5) 卧着放 ⇒ VIN_RAW 要从南针绕到 GND 盘东侧再北上,
|
||||||
@@ -304,12 +338,12 @@ put('J1', 8.5, 72.0, 270) # 12V XT30 公头,插口朝左板边(rot 270
|
|||||||
# ② D1 挪到东边空列 ⇒ J1.2 → F1.1 一片 6.5 × 7.9 mm 的铜,不再有颈;
|
# ② D1 挪到东边空列 ⇒ J1.2 → F1.1 一片 6.5 × 7.9 mm 的铜,不再有颈;
|
||||||
# ③ C4/C5/C6 一起东移 ⇒ 腾出 y 78.85~83.5 那条 4.65 mm 的 VIN_SW 西行干道
|
# ③ C4/C5/C6 一起东移 ⇒ 腾出 y 78.85~83.5 那条 4.65 mm 的 VIN_SW 西行干道
|
||||||
# (干道北提是因为 J1 的机械脚 J1.4 在 (3.5,77.5),占到 y 78.6)。
|
# (干道北提是因为 J1 的机械脚 J1.4 在 (3.5,77.5),占到 y 78.6)。
|
||||||
put('F1', 17.5, 74.5, 90) # 立着放:F1.1(VIN_RAW) 在南、F1.2(VIN_FUSED) 在北
|
put('F1', -12.5, 74.5, 90) # 立着放:F1.1(VIN_RAW) 在南、F1.2(VIN_FUSED) 在北
|
||||||
put('Q1', 24.0, 74.5, 270) # SOP-8 P-MOS 防反接
|
put('Q1', -6.0, 74.5, 270) # SOP-8 P-MOS 防反接
|
||||||
put('D1', 31.0, 74.5, 270) # SMBJ13A TVS(挪出 VIN_RAW 通道,贴在漏极铜东缘)
|
put('D1', 1.0, 74.5, 270) # SMBJ13A TVS(挪出 VIN_RAW 通道,贴在漏极铜东缘)
|
||||||
put('DZ1', 22.0, 68.0, 0) # 栅极钳位
|
put('DZ1', -8.0, 68.0, 0) # 栅极钳位
|
||||||
put('C1', 25.5, 68.0, 0)
|
put('C1', -4.5, 68.0, 0)
|
||||||
put('R1', 28.0, 71.5, 0)
|
put('R1', -2.0, 71.5, 0)
|
||||||
put('C2', 6.5, 84.5, 0) # 470µF/25V
|
put('C2', 6.5, 84.5, 0) # 470µF/25V
|
||||||
put('C3', 16.0, 84.5, 0)
|
put('C3', 16.0, 84.5, 0)
|
||||||
# C4/C5/C6:rot 180 让 $1N236 那一脚朝西迎着漏极铜,GND 脚朝东好打过孔
|
# C4/C5/C6:rot 180 让 $1N236 那一脚朝西迎着漏极铜,GND 脚朝东好打过孔
|
||||||
@@ -360,28 +394,73 @@ put('R707', 60.0, 71.5, 180)
|
|||||||
put('L3', 70.5, 78.0, 0)
|
put('L3', 70.5, 78.0, 0)
|
||||||
put('C734', 77.5, 78.0, 90)
|
put('C734', 77.5, 78.0, 90)
|
||||||
put('C735', 80.0, 78.0, 90)
|
put('C735', 80.0, 78.0, 90)
|
||||||
# 第三片 595(EDL_EN1~5)+ 风扇低边驱动
|
# ── 风扇 FAN-R2(2026-09-07):两只 4 线 PWM 风扇,一进一出 ──────────────
|
||||||
put('U33', 92.0, 71.0, 0)
|
# 旧的「低边切回流 + 5 个 3 针座 + TACH 分压」整块作废:R730~R732、J28~J30 已删。
|
||||||
|
# 现在是「高边默认关电 + 独立 PWM 开漏 + 两路独立测速接收」,见设计文档 §22.6。
|
||||||
|
# ⚠️ 摆位约束不只是「元件之间不重叠」:这一块北中区 y 64~100 底下压着已布好的
|
||||||
|
# +12V / +3V3 / GND 铜和过孔,而 `pcb1_route_sig --ripup` **只拆自己画过的信号线**,
|
||||||
|
# 拆不掉电源铜。第一版把新件摆进 y 66~88 直接刷出 65 条间距错误。
|
||||||
|
# ⇒ 新件整体上移到 **y 104~121 那条空带**(J28 删掉之后腾出来的),
|
||||||
|
# 留用件 Q6 / R733 / R734 原地不动(它们原来的位置本来就是干净的)。
|
||||||
|
# 【A】高边电源开关:+12V --Q7(P-MOS)--> FAN_12V_SW,MCU 高阻时默认断电
|
||||||
|
put('R746', 91.0, 120.0, 0) # 100k 栅极拉回源极
|
||||||
|
put('Q7', 95.0, 120.0, 0) # AO3401A
|
||||||
|
put('DZ3', 99.5, 120.0, 0) # BZT52C8V2 钳位负 Vgs(Q7 的 Vgs 绝对最大 ±12V)
|
||||||
|
put('C738', 105.0, 120.0, 0) # 22uF/25V,开关后母线本地储能
|
||||||
|
put('D2', 111.5, 120.0, 0) # SS34:K 接 FAN_12V_SW、A 接 GND(负向钳位,不再是续流)
|
||||||
|
put('R747', 91.0, 116.0, 0) # 1k 栅极串阻 -> Q8 漏极
|
||||||
|
put('Q8', 95.0, 116.0, 0) # AO3400A 拉低 Q7 栅极
|
||||||
|
put('R748', 99.5, 116.0, 0) # 1k FAN_EN(IO5) -> Q8 栅极
|
||||||
|
put('R749', 103.0, 116.0, 0) # 100k Q8 栅极下拉 = 复位默认断电
|
||||||
|
# 【B】两路独立测速接收(10k 上拉到 FAN_12V_SW -> 15k/10k 分压 -> N-MOS -> 3V3 上拉)
|
||||||
|
# 2026-09-08:**跟着各自的风扇座走到真板边**。
|
||||||
|
# 链路是 J2n.TACH → R75x(上拉到 FAN_12V_SW) → 分压 → Q(N-MOS) → FAN_TACH_xx(3V3 逻辑)。
|
||||||
|
# `FAN_IN_TACH_RAW` / `FAN_OUT_TACH_RAW` 是**座子到分压器**的本地网络:
|
||||||
|
# 接收电路留在中间的话,这两个网络要横跨大半块板(121 / 104 mm);
|
||||||
|
# 挪到座子旁边只剩几毫米。代价是 `FAN_TACH_IN/OUT`(已经是 3.3 V 逻辑、
|
||||||
|
# 经 N-MOS 整形过)各长约 16 mm —— 净赚一百多毫米,而且换掉的是**未整形的
|
||||||
|
# 12 V 摆幅裸信号**,抗扰上也是对的。
|
||||||
|
put('R750', -26.0, 108.0, 0) # 进风:贴着西板边的 J26
|
||||||
|
put('R751', -21.0, 108.0, 0)
|
||||||
|
put('Q9', -26.0, 104.0, 0)
|
||||||
|
put('R752', -21.0, 104.0, 0)
|
||||||
|
put('R753', -26.0, 100.0, 0)
|
||||||
|
put('R754', 181.0, 108.0, 0) # 排风:贴着东板边的 J27
|
||||||
|
put('R755', 186.0, 108.0, 0)
|
||||||
|
put('Q10', 181.0, 104.0, 0)
|
||||||
|
put('R756', 186.0, 104.0, 0)
|
||||||
|
put('R757', 181.0, 100.0, 0)
|
||||||
|
# 【C】PWM 低边开漏:Q6 / R733 / R734 保持 2026-09-06 的原位(现在只拉风扇 PWM 脚)
|
||||||
put('Q6', 102.0, 69.5, 0)
|
put('Q6', 102.0, 69.5, 0)
|
||||||
put('D2', 108.5, 69.5, 0)
|
put('R733', 98.0, 80.5, 0)
|
||||||
put('C738', 102.0, 74.0, 0)
|
|
||||||
put('C739', 107.0, 74.0, 0)
|
|
||||||
put('R730', 98.0, 78.0, 0)
|
|
||||||
put('R731', 101.5, 78.0, 0)
|
|
||||||
put('R732', 105.0, 78.0, 0)
|
|
||||||
put('R733', 98.0, 80.5, 0)
|
|
||||||
put('R734', 101.5, 80.5, 0)
|
put('R734', 101.5, 80.5, 0)
|
||||||
# 风扇座:4 个侧吸 + 1 个顶排,全部放板边(§22.6)
|
# 风扇座:一进一出,分列**真**左右板边(顶排风孔取消,见 THERMAL_TWO_FAN)
|
||||||
put('J26', 5.0, 16.0, 0) # 左板边(南)
|
# ⚠️ 4P 座比 3P 宽 2.54 ⇒ 半宽 3.81 → 5.08。本体 (-5.08,-2.79)-(5.08,3.01),rot 0。
|
||||||
put('J27', 5.0, 30.0, 0)
|
#
|
||||||
put('J29', 154.9, 16.0, 0) # 右板边(南)
|
# 2026-09-08 挪位:原来在 (6.3,121) / (151,121) —— 那是按**过期的假板框 160×125** 挑的
|
||||||
put('J30', 154.9, 30.0, 0)
|
# 「两个上角」,在真板框 220×135 / 左下角 (−30,−5) 里其实都在**板子中间**,
|
||||||
put('J28', 100.0, 112.7, 0) # 顶板边一侧;弯针塑壳往 +Y 伸 11.7,壳顶顶到 y 124.4
|
# 风扇线缆没法横着出去(直针座是垂直插拔,板边的意义就在于让线缆走得掉)。
|
||||||
|
#
|
||||||
|
# 当年退到「上角」的理由是:4P 座塑壳 11.5 mm(厂家 Z-Height),而下板 hmax 由
|
||||||
|
# **载板底面元件**的投影压出来(pcb1-env.json zones),假板框上 hmax >= 11.5 的
|
||||||
|
# 板边只有 y 68~92 一段,还被输入链占满。**真板框下这个约束消失**:
|
||||||
|
# 左条 x −30~0 整条 hmax 无限制,右条 x 160~190 有 84% 无限制。
|
||||||
|
# 实扫(`_fanpos2.py`):西边 y 2~49 与 61~120、东边 y 2~34 与 67~120 都可用。
|
||||||
|
#
|
||||||
|
# ⚠️ 压降复核(原注释担心的那一条):`FAN_12V_SW` 总共 2×0.67 A,但 Q7 居中、
|
||||||
|
# 两支**各只走 0.67 A**。0.8 mm 线宽下 R = ρL/(Wt):
|
||||||
|
# 西支 125 mm → 0.077 Ω → 51 mV;东支 95 mm → 0.058 Ω → 39 mV
|
||||||
|
# 都远在 FAN_CIRCUIT 那 0.2 V 预算之内。当年算的 0.26 V 是「单条 196 mm 走全电流」,
|
||||||
|
# 分成两支之后不成立。⇒ **这条线要按 0.8 mm 下发,别当普通信号走 0.20。**
|
||||||
|
put('J26', -23.9, 115.0, 0) # 真西板边 = 进风(本体 x −29.0~−18.8,离板框 1.0)
|
||||||
|
put('J27', 183.9, 115.0, 0) # 真东板边 = 排风(本体 x 178.8~189.0)
|
||||||
|
|
||||||
# ══════════════════ 【S-M】P3 / P3B 控制块 ══════════════════
|
# ══════════════════ 【S-M】P3 / P3B 控制块 ══════════════════
|
||||||
# 南中块 x 69.5~119.5 / y 0.5~59
|
# 南中块 x 69.5~119.5 / y 0.5~59
|
||||||
put('U20', 88.0, 18.2, 180) # ESP32-S3:天线端转到 −Y 朝下板边
|
put('U20', 88.0, 18.2, 180) # ESP32-S3:天线端转到 −Y 朝下板边
|
||||||
put('J22', 154.4, 52.0, 90) # 调试 USB-C,rot 90 = 开口朝 +X 右板边
|
# 2026-09-08 ⛔ 同一类硬缺陷:J22 原来在 x=154.4(本体到 159.6)= 假板框的东边,
|
||||||
|
# 真板框东边在 x=190,于是 USB-C 开口缩在板内 30.4 mm,线插不进去。
|
||||||
|
put('J22', 184.4, 52.0, 90) # 调试 USB-C,rot 90 = 开口朝**真**东板边(本体到 189.6)
|
||||||
# (下板边放不下:C841 罐的 1.5 mm 禁区压到 y 8.4)
|
# (下板边放不下:C841 罐的 1.5 mm 禁区压到 y 8.4)
|
||||||
put('RT601', 70.8, 36.0, 90) # 电感区测温:贴着 CH4 的电感那一排
|
put('RT601', 70.8, 36.0, 90) # 电感区测温:贴着 CH4 的电感那一排
|
||||||
put('RT602', 70.8, 26.0, 90) # MOS 区测温
|
put('RT602', 70.8, 26.0, 90) # MOS 区测温
|
||||||
@@ -413,8 +492,7 @@ put('RT602', 70.8, 26.0, 90) # MOS 区测温
|
|||||||
DECAP = [
|
DECAP = [
|
||||||
('C602', 'U20', '2', 3.0), # 100 nF 0402,ESP32 高频去耦 —— 先占位
|
('C602', 'U20', '2', 3.0), # 100 nF 0402,ESP32 高频去耦 —— 先占位
|
||||||
('C601', 'U20', '2', 8.0), # 22 µF 1206,ESP32 储能
|
('C601', 'U20', '2', 8.0), # 22 µF 1206,ESP32 储能
|
||||||
('C604', 'U21', '10', 3.0), # 74HC595 #1 VCC
|
# C604 / C605(74HC595 去耦)2026-09-06 随 595 挪到载板
|
||||||
('C605', 'U22', '10', 3.0), # 74HC595 #2 VCC
|
|
||||||
('C606', 'U23', '24', 3.0), # PCA9555 VDD
|
('C606', 'U23', '24', 3.0), # PCA9555 VDD
|
||||||
('C607', 'U6', '15', 3.0), # DAC63204 #1 VDD
|
('C607', 'U6', '15', 3.0), # DAC63204 #1 VDD
|
||||||
('C610', 'U7', '15', 3.0), # DAC63204 #2 VDD
|
('C610', 'U7', '15', 3.0), # DAC63204 #2 VDD
|
||||||
@@ -457,8 +535,7 @@ def affine(pagelist, x0, y0, w, h):
|
|||||||
# 给走线留通道),结果钉在下面这张表里。附属的 22 个 R/C 不再跟着仿射走,
|
# 给走线留通道),结果钉在下面这张表里。附属的 22 个 R/C 不再跟着仿射走,
|
||||||
# 改成 `SAT` 表逐个贴到**它真正的对端引脚**旁边。
|
# 改成 `SAT` 表逐个贴到**它真正的对端引脚**旁边。
|
||||||
CTRL = {
|
CTRL = {
|
||||||
'U21': (92.25, 52.37),
|
# U21 (92.25,52.37) / U22 (92.84,38.01) 2026-09-06 挪到载板(§26.23)—— x 88~97 / y 35~55 空出来
|
||||||
'U22': (92.84, 38.01),
|
|
||||||
'U23': (76.50, 49.63),
|
'U23': (76.50, 49.63),
|
||||||
'U6': (79.58, 38.01),
|
'U6': (79.58, 38.01),
|
||||||
'U7': (109.57, 34.71),
|
'U7': (109.57, 34.71),
|
||||||
@@ -489,7 +566,6 @@ SAT = [
|
|||||||
('R608', 'U23', '1', 6.0, u'IOEXP_INT# 上拉'),
|
('R608', 'U23', '1', 6.0, u'IOEXP_INT# 上拉'),
|
||||||
('R606', 'U23', '9', 6.0, u'BUCK_PG 上拉'),
|
('R606', 'U23', '9', 6.0, u'BUCK_PG 上拉'),
|
||||||
('R607', 'U23', '10', 6.0, u'INA_ALERT 上拉'),
|
('R607', 'U23', '10', 6.0, u'INA_ALERT 上拉'),
|
||||||
('R609', 'U21', '13', 7.0, u'KEY_OE# 上拉(三片 595 共用)'),
|
|
||||||
('C608', 'U6', '13', 4.0, u'DAC #1 内部基准/输出滤波'),
|
('C608', 'U6', '13', 4.0, u'DAC #1 内部基准/输出滤波'),
|
||||||
('C609', 'U6', '16', 4.0, u'DAC #1'),
|
('C609', 'U6', '16', 4.0, u'DAC #1'),
|
||||||
('R614', 'U6', '16', 5.0, u'DAC #1'),
|
('R614', 'U6', '16', 5.0, u'DAC #1'),
|
||||||
@@ -586,7 +662,7 @@ def _fits(des, cx, cy, rot, clear=0.3):
|
|||||||
u"""摆在这里会不会撞人 / 越框 / 压定位孔 / 超高。"""
|
u"""摆在这里会不会撞人 / 越框 / 压定位孔 / 超高。"""
|
||||||
b = box(des, rot)
|
b = box(des, rot)
|
||||||
ab = (cx + b[0], cy + b[1], cx + b[2], cy + b[3])
|
ab = (cx + b[0], cy + b[1], cx + b[2], cy + b[3])
|
||||||
if ab[0] < 0.4 or ab[2] > BW - 0.4 or ab[1] < 0.4 or ab[3] > BH - 0.4:
|
if ab[0] < BX0 + 0.4 or ab[2] > BX1 - 0.4 or ab[1] < BY0 + 0.4 or ab[3] > BY1 - 0.4:
|
||||||
return False
|
return False
|
||||||
r = MH_KEEPOUT / 2.0
|
r = MH_KEEPOUT / 2.0
|
||||||
for hx, hy in MH:
|
for hx, hy in MH:
|
||||||
@@ -756,7 +832,7 @@ def check():
|
|||||||
for d in sorted(POS):
|
for d in sorted(POS):
|
||||||
x0, y0, x1, y1 = abs_box(d)
|
x0, y0, x1, y1 = abs_box(d)
|
||||||
m = 0.4
|
m = 0.4
|
||||||
if x0 < m or x1 > BW - m or y0 < m or y1 > BH - m:
|
if x0 < BX0 + m or x1 > BX1 - m or y0 < BY0 + m or y1 > BY1 - m:
|
||||||
errs.append(u'越出板框: %-6s 框 %.2f..%.2f / %.2f..%.2f' % (d, x0, x1, y0, y1))
|
errs.append(u'越出板框: %-6s 框 %.2f..%.2f / %.2f..%.2f' % (d, x0, x1, y0, y1))
|
||||||
|
|
||||||
r = MH_KEEPOUT / 2.0
|
r = MH_KEEPOUT / 2.0
|
||||||
@@ -840,6 +916,53 @@ def mate_report():
|
|||||||
% (p, v[2], v[0], v[3], u'✔' if v[2] == v[3] else u'✘'))
|
% (p, v[2], v[0], v[3], u'✔' if v[2] == v[3] else u'✘'))
|
||||||
|
|
||||||
|
|
||||||
|
# ══════════ 出线道加宽(2026-09-06 第二十六轮,用户拍板)══════════
|
||||||
|
#: **「够净距」不等于「出得去线」。** `pad_clearance_errs` 判的是焊盘净距 ≥ 0.20,
|
||||||
|
#: 而一根 0.2 mm 的线要从两个焊盘中间出去,需要 0.20 + 0.20 + 0.20 = **0.60**。
|
||||||
|
#: U6 / U7(WQFN-16 3×3,四边出脚)周围的卫星件正好卡在 **0.31 ~ 0.38** ——
|
||||||
|
#: 本地六项全过、DRC 也没有间距错误,可 `pcb1_escape_audit` 报「被围死」、
|
||||||
|
#: 布线器报「几何上就出不去」,`SCL`(U6.6) / `$6N532`(U6.16) / `$6N547`(U7.16)
|
||||||
|
#: 三个网络因此永远布不通。这里把堵住出线道的六颗按**背离芯片**的方向各挪 0.30 mm。
|
||||||
|
#:
|
||||||
|
#: ⚠️ 挪完 `C607` / `R617` 会分别压到 `SDA` / `SCL` 的换层孔(净距 0.029 / 0.113)——
|
||||||
|
#: 那两个孔是 `pcb1_i2c_l3.py` 每轮重算的,**挪件之后必须重跑它**,孔会自己让开。
|
||||||
|
#:
|
||||||
|
#: ⚠️ §26.22b:门槛不是 0.60 而是 **0.741**(CLR + 半线宽 + 栅格量化余量 QERR,两侧各 0.3707)。
|
||||||
|
#: 0.30 挪出来的 0.612/0.615/0.676 理论上塞得下、0.1 栅格上塞不下 ⇒ 2026-09-06 第二十八轮
|
||||||
|
#: 改成 **0.50(东列 0.45)**,三个方向都 ≥ 0.80。板上现在(`_pcb1_place_now.json`)是按 0.30 摆的,
|
||||||
|
#: 再挪 0.20 / 0.15 会压到的铜见 `.claude/_pcb1_unrouted_report.md` §A(VDAC4 孔、SDA 线+孔,
|
||||||
|
#: 以及 10 段要按新位置重做的扇出短线)。
|
||||||
|
#: ⚠️⚠️ **这一手救不了 `U6.16` / `U7.16`**(`pcb1_ch_reroute.py` 本地实测:挪完照样「几何上就出不去」)——
|
||||||
|
#: 它们被 C609 / C612 的 GND 脚 + GND 扇出孔从西边、C607 / C610 从北边、U6.15 的 +3V3 出线段从东边
|
||||||
|
#: 三面围死,北挪 C607 只是把北墙推远,西墙东墙不动。真正的解法是下面的 `SAT_FLIP`。
|
||||||
|
ESCAPE_NUDGE = {
|
||||||
|
'R615': (0.0, -0.50), # U6 南排(U6.5 / U6.6=SCL) 0.312 -> 0.812
|
||||||
|
'C607': (0.0, +0.50), # U6 北排(U6.13/15/16) 0.315 -> 0.815
|
||||||
|
'C608': (+0.45, 0.0), # U6 东列(VDAC2 / VDAC4) 0.376 -> 0.826
|
||||||
|
'R617': (0.0, -0.50), # U7 南排(U7.5 / U7.6) 0.315 -> 0.815
|
||||||
|
'C610': (0.0, +0.50), # U7 北排(U7.13/15/16) 0.312 -> 0.812
|
||||||
|
'C611': (+0.45, 0.0), # U7 东列(VDAC3 / VDAC5) 0.376 -> 0.826
|
||||||
|
}
|
||||||
|
for _d, (_dx, _dy) in sorted(ESCAPE_NUDGE.items()):
|
||||||
|
if _d in POS:
|
||||||
|
_x, _y, _r = POS[_d]
|
||||||
|
POS[_d] = (round(_x + _dx, 3), round(_y + _dy, 3), _r)
|
||||||
|
|
||||||
|
# ══════════ VREF 电容转 180°(2026-09-06 第二十八轮,A 类唯一真正的几何解)══════════
|
||||||
|
#: `C609` / `C612` 是 DAC63204 的 VREF 电容(pin 16),`place_sats()` 把它们竖着(rot 90)贴在
|
||||||
|
#: U6.16 / U7.16 的西北角:**GND 脚在南(离引脚近)、VREF 脚在北(离引脚远)**,
|
||||||
|
#: GND 扇出孔又打在 GND 脚正南 —— 于是 U6.16 往西北去找 VREF 脚的那条道被自家 GND 孔 + GND 短线堵死。
|
||||||
|
#: 转 180°(rot 90 -> 270)之后 VREF 脚朝南正对 U6.16(0.8 mm),GND 脚朝北。
|
||||||
|
#: `pcb1_ch_reroute.py --win 73,32,87,47 --nets '$6N532' --move C609:0:0:180 --drop-via 78.03,39.61`
|
||||||
|
#: 本地实测:`$6N532` 3.6 mm 一次布通、净距 0;U7 同理。下发时要删 2 段扇出短线 + 补 1 个 GND 孔
|
||||||
|
#: (见 `_pcb1_unrouted_report.md` §A)。
|
||||||
|
SAT_FLIP = {'C609': 180, 'C612': 180}
|
||||||
|
for _d, _dr in sorted(SAT_FLIP.items()):
|
||||||
|
if _d in POS:
|
||||||
|
_x, _y, _r = POS[_d]
|
||||||
|
POS[_d] = (_x, _y, (_r + _dr) % 360)
|
||||||
|
|
||||||
|
|
||||||
def summary():
|
def summary():
|
||||||
ext = ch_extent()
|
ext = ch_extent()
|
||||||
print(u'母版局部包围盒 x %.2f~%.2f y %.2f~%.2f(%.1f x %.1f)'
|
print(u'母版局部包围盒 x %.2f~%.2f y %.2f~%.2f(%.1f x %.1f)'
|
||||||
|
|||||||
@@ -71,6 +71,11 @@ J24 焊盘 x 6.97~57.03、J25 x 102.97~153.03,两排 y 61.2 / 63.8,Ø1.8 焊
|
|||||||
|
|
||||||
**南边要 5.6 A**(CH1 + CH4 + CH5 各 1.6 A,加左右四个风扇约 0.4+0.4 A)。
|
**南边要 5.6 A**(CH1 + CH4 + CH5 各 1.6 A,加左右四个风扇约 0.4+0.4 A)。
|
||||||
分法:**中桥喂 CH1 + CH4 + 左风扇 = 3.6 A,右通道喂 CH5 + 右风扇 = 2.0 A。**
|
分法:**中桥喂 CH1 + CH4 + 左风扇 = 3.6 A,右通道喂 CH5 + 右风扇 = 2.0 A。**
|
||||||
|
|
||||||
|
> ⚠️ 2026-09-07 FAN-R2:五个 3 针风扇座删成两个 4 针,而且挪到了**北边两个上角**,
|
||||||
|
> 供电也从 `+12V` 改成 Q7 开关之后的 `FAN_12V_SW`。所以**南边现在只有 4.8 A**
|
||||||
|
> (中桥 3.2 / 右通道 1.6),风扇那 1.34 A 全部走北带经 Q7。上面两个 3.6 / 2.0 的
|
||||||
|
> 判据没改,现在只是更保守,不用重算。
|
||||||
左通道不用 —— 它的北端要从 J1 (6.0,74) 和 C2.1 (4.8,82) 两个通孔旁边挤过去,
|
左通道不用 —— 它的北端要从 J1 (6.0,74) 和 C2.1 (4.8,82) 两个通孔旁边挤过去,
|
||||||
只剩 2.8 mm、带 2.06 A,够不上一路通道的量,而且那一片正好在 8 A 输入链的顶层大铜下面,
|
只剩 2.8 mm、带 2.06 A,够不上一路通道的量,而且那一片正好在 8 A 输入链的顶层大铜下面,
|
||||||
留成 GND 底填**比塞一条 12V 细带有用得多**。
|
留成 GND 底填**比塞一条 12V 细带有用得多**。
|
||||||
@@ -135,7 +140,15 @@ VIN_RAW, VIN_FUSED, VIN_SW = AUTO['VIN_RAW'], AUTO['VIN_FUSED'], AUTO['VIN_SW']
|
|||||||
CHAIN = ((VIN_RAW, 'VIN_RAW'), (VIN_FUSED, 'VIN_FUSED'), (VIN_SW, 'VIN_SW'))
|
CHAIN = ((VIN_RAW, 'VIN_RAW'), (VIN_FUSED, 'VIN_FUSED'), (VIN_SW, 'VIN_SW'))
|
||||||
|
|
||||||
MIL = 39.3700787401575
|
MIL = 39.3700787401575
|
||||||
BW, BH = 160.0, 125.0
|
# ⚠️⚠️ 2026-09-08:这里原来写的是 `BW, BH = 160.0, 125.0`,栅格从 (0,0) 起索引 ——
|
||||||
|
# 那是**过期的假板框**,和 `pcb1_place.py` 当年那条是同一个病(它已在第三十轮改掉)。
|
||||||
|
# 真板框是 **220 × 135、左下角 (−30, −5)**(`pcb1_outline.py` 就是这么画的)。
|
||||||
|
# 后果:**本地校核看不见 x<0 / y<0 那两条边**,落在那里的铜一律算成 0 ——
|
||||||
|
# 板上的铜不受影响(多边形是原样下发给 EasyEDA 的、由它去填),
|
||||||
|
# 但**任何摆到负坐标的东西,断面/连通性校核都会静悄悄地给出 0**。
|
||||||
|
# 第三十四轮把输入首级西移到 x −17~2 之后当场撞上:三块顶层铜全报「碎成 0 块」。
|
||||||
|
BX0, BY0 = -30.0, -5.0 # 板框左下角
|
||||||
|
BW, BH = 220.0, 135.0 # 板框尺寸
|
||||||
INSET = 0.5 # 铜面离板边
|
INSET = 0.5 # 铜面离板边
|
||||||
CLEAR = 0.2 # 安全间距(pcb1_rules.MIN_CLEARANCE)
|
CLEAR = 0.2 # 安全间距(pcb1_rules.MIN_CLEARANCE)
|
||||||
|
|
||||||
@@ -167,6 +180,24 @@ def rect(x0, y0, x1, y1):
|
|||||||
return [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]
|
return [(x0, y0), (x1, y0), (x1, y1), (x0, y1)]
|
||||||
|
|
||||||
|
|
||||||
|
# ── 毫米 ↔ 栅格:**一律走这四个函数,不要再写 int(x / G)** ──────────────
|
||||||
|
# 板框左下角不是 (0,0),直接除 G 会把负坐标截成 0(见上面 BX0/BY0 那段)。
|
||||||
|
def gi(x):
|
||||||
|
return int((x - BX0) / G)
|
||||||
|
|
||||||
|
|
||||||
|
def gj(y):
|
||||||
|
return int((y - BY0) / G)
|
||||||
|
|
||||||
|
|
||||||
|
def gx(i):
|
||||||
|
return BX0 + (i + 0.5) * G
|
||||||
|
|
||||||
|
|
||||||
|
def gy(j):
|
||||||
|
return BY0 + (j + 0.5) * G
|
||||||
|
|
||||||
|
|
||||||
CORNER_R = 5.0
|
CORNER_R = 5.0
|
||||||
|
|
||||||
|
|
||||||
@@ -179,10 +210,10 @@ def board_poly(inset=INSET, seg=6):
|
|||||||
"""
|
"""
|
||||||
r = CORNER_R - inset
|
r = CORNER_R - inset
|
||||||
pts = []
|
pts = []
|
||||||
for cx, cy, a0 in ((BW - CORNER_R, CORNER_R, -90.0),
|
for cx, cy, a0 in ((BX0 + BW - CORNER_R, BY0 + CORNER_R, -90.0),
|
||||||
(BW - CORNER_R, BH - CORNER_R, 0.0),
|
(BX0 + BW - CORNER_R, BY0 + BH - CORNER_R, 0.0),
|
||||||
(CORNER_R, BH - CORNER_R, 90.0),
|
(BX0 + CORNER_R, BY0 + BH - CORNER_R, 90.0),
|
||||||
(CORNER_R, CORNER_R, 180.0)):
|
(BX0 + CORNER_R, BY0 + CORNER_R, 180.0)):
|
||||||
for k in range(seg + 1):
|
for k in range(seg + 1):
|
||||||
a = math.radians(a0 + 90.0 * k / seg)
|
a = math.radians(a0 + 90.0 * k / seg)
|
||||||
pts.append((cx + r * math.cos(a), cy + r * math.sin(a)))
|
pts.append((cx + r * math.cos(a), cy + r * math.sin(a)))
|
||||||
@@ -201,12 +232,18 @@ REGIONS = [
|
|||||||
# 载板 `pcb2_pour.py` 文件头第 4 条)。
|
# 载板 `pcb2_pour.py` 文件头第 4 条)。
|
||||||
# ⇒ 把中桥并进南西、右通道并进南东、风扇指并进北带,凑成三个 L / T 形多边形,
|
# ⇒ 把中桥并进南西、右通道并进南东、风扇指并进北带,凑成三个 L / T 形多边形,
|
||||||
# 每块各自含 J28.1 / J26.1+J27.1 / J29.1+J30.1,**不依赖扇出就活得下来**。
|
# 每块各自含 J28.1 / J26.1+J27.1 / J29.1+J30.1,**不依赖扇出就活得下来**。
|
||||||
|
# ⚠️⚠️ **2026-09-07 FAN-R2 之后上面这句不再成立**:J28/J29/J30 删了,J26/J27 挪到两个上角
|
||||||
|
# 而且 pin2 已经从 `+12V` 改成开关后的 `FAN_12V_SW`(经 Q7)——
|
||||||
|
# 三块 +12V 里**一个风扇座的通孔焊盘都不剩了**,现在靠 `pcb_fanout` 打的过孔活着
|
||||||
|
# (实测三块各填出 1 段,没被当孤岛删)。⇒ **重铺之前必须先扇出**,
|
||||||
|
# 否则会退回「边框还在、nPoured=0」那个状态。整板重布时把这三块各自含一个本网
|
||||||
|
# 通孔焊盘的条件重新落实一次,别再依赖扇出的运气。
|
||||||
dict(net='+12V', layer=L_PWR, name='12V-N', poly=[
|
dict(net='+12V', layer=L_PWR, name='12V-N', poly=[
|
||||||
# 北大块 y 88~124.5 通板 + 风扇指下伸到 y 66.5,**挖掉 U13 那一角**(Kelvin 脚,§10.4)
|
# 北大块 y 88~124.5 通板 + 风扇指下伸到 y 66.5,**挖掉 U13 那一角**(Kelvin 脚,§10.4)
|
||||||
(0.5, 88.0), (96.5, 88.0), (96.5, 66.5), (112.0, 66.5), (112.0, 88.0),
|
(0.5, 88.0), (96.5, 88.0), (96.5, 66.5), (112.0, 66.5), (112.0, 88.0),
|
||||||
(159.5, 88.0), (159.5, 124.5), (0.5, 124.5),
|
(159.5, 88.0), (159.5, 124.5), (0.5, 124.5),
|
||||||
(0.5, 102.4), (12.5, 102.4), (12.5, 95.6), (0.5, 95.6)],
|
(0.5, 102.4), (12.5, 102.4), (12.5, 95.6), (0.5, 95.6)],
|
||||||
note=u'北带(CH2/CH3 的 Cin、U19、U29、J28)+ 风扇指(R730/C738/D2);'
|
note=u'北带(CH2/CH3 的 Cin、U19、U29;FAN-R2 之后还含 Q7 源极 = 风扇 1.34 A 的入口)+ 风扇指(现已空载);'
|
||||||
u'**源 Rs6.2 的焊盘是 (8.93~10.21, 91.77~95.23)** —— U13 那个缺口原来写成 y 93.0~101.5,'
|
u'**源 Rs6.2 的焊盘是 (8.93~10.21, 91.77~95.23)** —— U13 那个缺口原来写成 y 93.0~101.5,'
|
||||||
u'正好把 Rs6.2 的中心咬掉,扇出于是把这颗 8 A 源判成「不在铜面里」一个过孔都没打(2026-09-06 抓到)。'
|
u'正好把 Rs6.2 的中心咬掉,扇出于是把这颗 8 A 源判成「不在铜面里」一个过孔都没打(2026-09-06 抓到)。'
|
||||||
u'缺口收成 y 95.6~102.4,只罩住 U13 十个脚(96.08~101.92)与 C11'),
|
u'缺口收成 y 95.6~102.4,只罩住 U13 十个脚(96.08~101.92)与 C11'),
|
||||||
@@ -225,11 +262,11 @@ REGIONS = [
|
|||||||
# 把 +12V 推到 72.6,缝就没了;离 3V3-SE 还有 0.4,够。
|
# 把 +12V 推到 72.6,缝就没了;离 3V3-SE 还有 0.4,够。
|
||||||
(0.5, 9.0), (72.6, 9.0), (72.6, 88.0), (61.5, 88.0), (61.5, 40.7),
|
(0.5, 9.0), (72.6, 9.0), (72.6, 88.0), (61.5, 88.0), (61.5, 40.7),
|
||||||
(54.0, 40.7), (54.0, 34.0), (0.5, 34.0)],
|
(54.0, 40.7), (54.0, 34.0), (0.5, 34.0)],
|
||||||
note=u'CH1 + CH4 的 Cin、J26/J27 左风扇;中桥穿中间通道下来,喂 3.6 A'),
|
note=u'CH1 + CH4 的 Cin(FAN-R2 之后南边没有风扇了);中桥穿中间通道下来,喂 3.2 A,校核仍按 3.6 A 卡'),
|
||||||
dict(net='+12V', layer=L_PWR, name='12V-SE+RC', poly=[
|
dict(net='+12V', layer=L_PWR, name='12V-SE+RC', poly=[
|
||||||
# 南东块 + 右通道:L 形。J22 只有两个无网络的壳体通孔在 x=151.9,不挡 x≥153.5
|
# 南东块 + 右通道:L 形。J22 只有两个无网络的壳体通孔在 x=151.9,不挡 x≥153.5
|
||||||
(116.0, 9.0), (159.5, 9.0), (159.5, 88.0), (153.5, 88.0), (153.5, 34.0), (116.0, 34.0)],
|
(116.0, 9.0), (159.5, 9.0), (159.5, 88.0), (153.5, 88.0), (153.5, 34.0), (116.0, 34.0)],
|
||||||
note=u'CH5 的 Cin、J29/J30 右风扇;右通道接回北带,喂 2.0 A'),
|
note=u'CH5 的 Cin(FAN-R2 之后南边没有风扇了);右通道接回北带,喂 1.6 A,校核仍按 2.0 A 卡'),
|
||||||
|
|
||||||
# ── +3V3:南部两块,各自从北边的源单独引底层干线(见文件头「绕不过去的结论」)──
|
# ── +3V3:南部两块,各自从北边的源单独引底层干线(见文件头「绕不过去的结论」)──
|
||||||
dict(net='+3V3', layer=L_PWR, name='3V3-SW', poly=rect(0.8, 41.0, 58.5, 58.5),
|
dict(net='+3V3', layer=L_PWR, name='3V3-SW', poly=rect(0.8, 41.0, 58.5, 58.5),
|
||||||
@@ -273,19 +310,36 @@ REGIONS = [
|
|||||||
# ⚠️ 顶层和内层挡路的东西不一样(Grid 的表):这一片里 J1/C2/C3 的通孔、
|
# ⚠️ 顶层和内层挡路的东西不一样(Grid 的表):这一片里 J1/C2/C3 的通孔、
|
||||||
# D1/C4/C5/C6/R1 的 GND 贴片焊盘、以及扇出给它们打的 9 个 GND 过孔 + 短线,
|
# D1/C4/C5/C6/R1 的 GND 贴片焊盘、以及扇出给它们打的 9 个 GND 过孔 + 短线,
|
||||||
# **每一样都要躲**。下面每一条边界后面括号里写的就是它躲的那个东西。
|
# **每一样都要躲**。下面每一条边界后面括号里写的就是它躲的那个东西。
|
||||||
|
# ⚠️⚠️ 2026-09-08 第三十四轮**整段重画**:输入首级(J1/F1/Q1/D1 + 栅极卫星)西移了 30 mm
|
||||||
|
# (J1 换圆形 DC 座并挪到真西板边)。旧的那一版坐标写在 x 11.9~22.5,
|
||||||
|
# 那一片现在**一个本网焊盘都没有** —— 铺出来是孤岛、会被整块删掉,
|
||||||
|
# 而断面校核量到的是空气(报 0.00 mm)。这是本文件第二次踩同一条,
|
||||||
|
# 第一次是第二十三轮(注释还在下面 CUTS 里)。⇒ **摆位一改就要回来重画这三块。**
|
||||||
|
#
|
||||||
|
# 新链路是**单向**的,比旧版顺:J1(−18.8) → F1(−12.5) → Q1(−6) → D1(1) → 东北去 C2/C3/Rs6。
|
||||||
|
# 旧版是 J1 一路向东到 Q1、再折回西边找 Rs6,多绕了一圈。
|
||||||
dict(net=VIN_RAW, layer=L_TOP, name='VINRAW-TOP',
|
dict(net=VIN_RAW, layer=L_TOP, name='VINRAW-TOP',
|
||||||
poly=[(11.9, 65.4), (19.6, 65.4), (19.6, 73.08), (18.58, 73.08),
|
poly=[(-17.0, 70.7), (-11.5, 70.7), (-11.5, 73.80),
|
||||||
(18.58, 73.78), (15.0, 73.78), (15.0, 73.0), (11.9, 73.0)],
|
(-13.65, 73.80), (-13.65, 76.5), (-17.0, 76.5)],
|
||||||
note=u'J1.2(13.5,69.5) → F1.1(17.5,73.06)。F1 竖着放之后这一段是一片 7.7×7.7 的大铜;'
|
note=u'J1.1(−15.80,74.35,中心正极,通孔盘 1.6×3.8) → F1.1(−12.50,73.06)。'
|
||||||
u'西北那个阶梯是躲 J1.1 的 GND 通孔(Φ2.5, 净距后 r=1.45),'
|
u'南边 70.7 躲 J1.3 的 GND 通孔盘(顶 70.450);'
|
||||||
u'东边 19.6 躲 Q1.4 栅极脚(20.215)与 DZ1.1(19.890),'
|
u'东边 −11.5 刚好盖住 F1.1(东 −11.637),离 Q1 源极三脚(西 −9.786) 还有 1.7;'
|
||||||
u'北边两段台阶各给 VINFUSED 让 0.2'),
|
u'x −13.65 那级台阶是躲 F1.2(西 −13.364, 南 75.350) —— 台阶以东只铺到 73.80,'
|
||||||
|
u'盖住 F1.1(顶 73.651) 并给 VIN_FUSED 让 0.30。'
|
||||||
|
u'**载流断面在 J1.1 与 F1.1 之间**(x≈−14.2),那里是满高 5.8 mm;'
|
||||||
|
u'台阶以东那 3.10 mm 不走穿过电流,F1.1 就是终点。'
|
||||||
|
u'⚠️ 两块的**竖直边**也要拉开:VINRAW 东界 −11.5 与 VINFUSED 的台阶 −11.15 '
|
||||||
|
u'差 0.35 —— 第一版这两条边只隔 0.20(正好压在下限上),是校核报出来的'),
|
||||||
dict(net=VIN_FUSED, layer=L_TOP, name='VINFUSED-TOP',
|
dict(net=VIN_FUSED, layer=L_TOP, name='VINFUSED-TOP',
|
||||||
poly=[(16.4, 74.0), (18.8, 74.0), (18.8, 73.3), (22.5, 73.3),
|
poly=[(-13.4, 74.10), (-11.15, 74.10), (-11.15, 73.3),
|
||||||
(22.5, 78.5), (16.4, 78.5)],
|
(-7.5, 73.3), (-7.5, 77.8), (-13.4, 77.8)],
|
||||||
note=u'F1.2(17.5,75.95) → Q1.1~3(源极三脚, x 20.2~22.2)。'
|
note=u'F1.2(−12.50,75.95) → Q1.1~3(源极三脚, x −9.786~−7.751)。'
|
||||||
u'南边两段:西半 74.0 躲 F1.1(顶 73.651),东半 73.3 躲 Q1.4(顶 72.882) '
|
u'南边两段:西半 74.10 同时躲 F1.1(顶 73.651) 和 VINRAW 的台阶(顶 73.80,让 0.30),'
|
||||||
u'并盖住 Q1.3(底 73.578);北边 78.5 给 VIN_SW 西行干道让 0.35'),
|
u'东半 73.3 躲 Q1.4 栅极脚(顶 72.882) 并盖住 Q1.3(底 73.578);'
|
||||||
|
u'东边 −7.5 离 Q1 漏极四脚(西 −4.250) 还有 3.25。'
|
||||||
|
u'断面在 F1.2 与源极之间(x≈−10.7)= 4.5 mm。'
|
||||||
|
u'⚠️ DZ1.1/C1.1 这两个栅极钳位件同属本网但在 y≈68,**不进这块铜** ——'
|
||||||
|
u'µA 级,交给 pcb1_route_sig 拉一条细线'),
|
||||||
|
|
||||||
# ⚠ `VIN_SW` 必须是**一个铺铜对象**,不能拆成几块靠互相重叠连起来。
|
# ⚠ `VIN_SW` 必须是**一个铺铜对象**,不能拆成几块靠互相重叠连起来。
|
||||||
# 同层同网两块铜重叠时,低优先级那块会被高优先级那块裁掉 —— 裁的时候
|
# 同层同网两块铜重叠时,低优先级那块会被高优先级那块裁掉 —— 裁的时候
|
||||||
@@ -294,16 +348,17 @@ REGIONS = [
|
|||||||
# ⇒ 宁可手写 18 个点。下面的 `rects` 是这 18 个点该等于的矩形并集,
|
# ⇒ 宁可手写 18 个点。下面的 `rects` 是这 18 个点该等于的矩形并集,
|
||||||
# `report()` 里逐格对照,写错一个点当场就报(check_poly_rects)。
|
# `report()` 里逐格对照,写错一个点当场就报(check_poly_rects)。
|
||||||
dict(net=VIN_SW, layer=L_TOP, name='VINSW-TOP',
|
dict(net=VIN_SW, layer=L_TOP, name='VINSW-TOP',
|
||||||
poly=[(25.6, 72.1), (29.68, 72.1), (29.68, 73.45), (32.3, 73.45),
|
poly=[(-4.45, 72.10), (-0.30, 72.10), (-0.30, 73.40), (2.40, 73.40),
|
||||||
(32.3, 78.85), (30.47, 78.85), (30.47, 86.47), (28.6, 86.47),
|
(2.40, 78.85), (30.46, 78.85), (30.46, 86.47), (28.6, 86.47),
|
||||||
(28.6, 83.49), (16.72, 83.49), (16.72, 85.5), (12.5, 85.5),
|
(28.6, 83.49), (16.72, 83.49), (16.72, 85.5), (12.5, 85.5),
|
||||||
(12.5, 83.49), (6.65, 83.49), (6.65, 87.0), (5.3, 87.0),
|
(12.5, 83.49), (6.65, 83.49), (6.65, 87.0), (5.3, 87.0),
|
||||||
(5.3, 95.25), (1.5, 95.25), (1.5, 78.85), (25.6, 78.85)],
|
(5.3, 95.25), (1.5, 95.25), (1.5, 83.49), (-4.45, 83.49)],
|
||||||
rects=[(25.6, 72.1, 29.68, 78.85), # Q1 漏极四脚(南边 72.1 躲 R1 的 GND 过孔 26.675,71.5)
|
rects=[(-4.45, 72.10, -0.30, 78.85), # Q1 漏极四脚(x −4.250~−2.215)。南边 72.10 躲 R1 两脚(顶 71.772),留 0.328
|
||||||
(25.6, 73.45, 32.3, 78.85), # D1.1 TVS(南边 73.45 躲 D1.2 的 GND 盘顶 73.163 与它 6 个扇出孔)
|
(-0.30, 73.40, 2.40, 78.85), # D1.1 TVS(−0.096~2.096, 75.838~77.885)。
|
||||||
(28.6, 78.85, 30.47, 86.47), # C4.2/C5.2/C6.2 去耦(东边 30.47 躲 C6.1 的 GND 盘 30.670)
|
# 南边抬到 73.40 是躲 D1.2 的 GND 盘(顶 73.163) 和它正下方 6 个扇出孔
|
||||||
(1.5, 78.85, 28.6, 83.49), # ★ 8 A 西行干道,y 净宽 4.64 mm;
|
(-4.45, 78.85, 28.6, 83.49), # ★ 8 A 干道,y 净宽 4.64 mm。**西端由 1.5 延到 −4.45**:
|
||||||
# 南边 78.85 躲 J1 的机械脚 J1.4(顶 78.401),北边 83.49 躲 C2/C3 的四个通孔(底 83.700)
|
# 旧版西端卡在 1.5 是因为老 J1 的机械脚 J1.4(顶 78.401) 顶着,那颗件已经挪走
|
||||||
|
(28.6, 78.85, 30.46, 86.47), # C4.2/C5.2/C6.2 去耦(东边 30.46 躲 C6.1 的 GND 盘 30.670)
|
||||||
(12.5, 83.49, 16.72, 85.5), # C3.1 口袋(东边 16.72 躲 C3.2 GND 通孔 16.950)
|
(12.5, 83.49, 16.72, 85.5), # C3.1 口袋(东边 16.72 躲 C3.2 GND 通孔 16.950)
|
||||||
(1.5, 83.49, 6.65, 87.0), # C2.1 口袋(净宽 5.15 mm)
|
(1.5, 83.49, 6.65, 87.0), # C2.1 口袋(净宽 5.15 mm)
|
||||||
(1.5, 87.0, 5.3, 95.25)], # 北柱到 Rs6.1(净宽 **3.8 mm** = 8.5 A)
|
(1.5, 87.0, 5.3, 95.25)], # 北柱到 Rs6.1(净宽 **3.8 mm** = 8.5 A)
|
||||||
@@ -312,8 +367,11 @@ REGIONS = [
|
|||||||
# 顶到 y 95.4 —— 离 U13.2 只剩 0.379 mm,`pcb1_escape_audit` 报「被围死」。
|
# 顶到 y 95.4 —— 离 U13.2 只剩 0.379 mm,`pcb1_escape_audit` 报「被围死」。
|
||||||
# 收窄之后 U13 南边是一整片 x 5.5~14 / y 91.6~96 的空地。
|
# 收窄之后 U13 南边是一整片 x 5.5~14 / y 91.6~96 的空地。
|
||||||
# (Rs6.2 那两根往西甩的 1 mm 扇出短线也一起没了 —— 见 pcb_fanout.FORCE_ARRAY)
|
# (Rs6.2 那两根往西甩的 1 mm 扇出短线也一起没了 —— 见 pcb_fanout.FORCE_ARRAY)
|
||||||
note=u'**8 A 主干**:Q1 漏极 → 北上 → 西行干道 → C3.1/C2.1 → 北柱 → Rs6.1,一路无过孔;'
|
note=u'**8 A 主干**:Q1 漏极(−3.2) → 东经 D1 → 北上 → **东行**干道 → C2.1/C3.1 → 北柱 → Rs6.1,'
|
||||||
u'东边挂 D1(TVS) 与 C4/C5/C6 去耦。干道比 v10 北提了 2.8 mm —— XT30 的机械脚占到 y 78.4'),
|
u'一路无过孔;东端挂 C4/C5/C6 去耦。'
|
||||||
|
u'⚠️ 第三十四轮之后干道是**东行**不是西行 —— 源头 Q1 从 x 24 挪到了 x −6,'
|
||||||
|
u'而 C2/C3/Rs6/C4~C6 一颗没动,于是电流方向整个翻过来了。'
|
||||||
|
u'旧注释「干道比 v10 北提 2.8 mm 躲 XT30 机械脚」已作废:那颗 XT30 已经不在这块板上'),
|
||||||
]
|
]
|
||||||
|
|
||||||
# ── 断面校核:每一条都是「这里必须能过多少安」──────────────────────────
|
# ── 断面校核:每一条都是「这里必须能过多少安」──────────────────────────
|
||||||
@@ -332,7 +390,9 @@ CUTS = [
|
|||||||
(u'南西块 → CH1', '+12V', L_PWR, 'x', 33.0, (9.0, 34.0), 2.0),
|
(u'南西块 → CH1', '+12V', L_PWR, 'x', 33.0, (9.0, 34.0), 2.0),
|
||||||
(u'南西块 → CH4+CH1', '+12V', L_PWR, 'x', 61.0, (9.0, 34.0), 3.6),
|
(u'南西块 → CH4+CH1', '+12V', L_PWR, 'x', 61.0, (9.0, 34.0), 3.6),
|
||||||
(u'南东块 → CH5', '+12V', L_PWR, 'x', 140.0, (9.0, 34.0), 1.6),
|
(u'南东块 → CH5', '+12V', L_PWR, 'x', 140.0, (9.0, 34.0), 1.6),
|
||||||
(u'风扇指 @接北带', '+12V', L_PWR, 'y', 87.0, (94.0, 114.0), 1.0),
|
# FAN-R2 之后风扇指下面已经没有 +12V 负载(风扇改吃开关后的 FAN_12V_SW)。
|
||||||
|
# 这一条留着当**几何回归**:北带往南这一指还在,断面别被后来的布线啃掉。
|
||||||
|
(u'风扇指 @接北带(现空载)', '+12V', L_PWR, 'y', 87.0, (94.0, 114.0), 1.0),
|
||||||
(u'北大块 @Rs6 东出', '+12V', L_PWR, 'x', 20.0, (86.0, 124.5), 8.0),
|
(u'北大块 @Rs6 东出', '+12V', L_PWR, 'x', 20.0, (86.0, 124.5), 8.0),
|
||||||
(u'3V3 南西块', '+3V3', L_PWR, 'x', 33.0, (41.0, 58.5), 0.5),
|
(u'3V3 南西块', '+3V3', L_PWR, 'x', 33.0, (41.0, 58.5), 0.5),
|
||||||
(u'3V3 南东块 @控制块', '+3V3', L_PWR, 'x', 95.0, (9.0, 58.5), 0.5),
|
(u'3V3 南东块 @控制块', '+3V3', L_PWR, 'x', 95.0, (9.0, 58.5), 0.5),
|
||||||
@@ -341,10 +401,14 @@ CUTS = [
|
|||||||
# 8 A 输入链(顶层 1 oz)。J1 → F1 → Q1 → D1/C4~C6 → C3/C2 → Rs6,分叉之前全程 8 A。
|
# 8 A 输入链(顶层 1 oz)。J1 → F1 → Q1 → D1/C4~C6 → C3/C2 → Rs6,分叉之前全程 8 A。
|
||||||
# ⚠ 这一排坐标跟着摆位走,**摆位一改就要重定**:2026-09-06 第二十三轮把
|
# ⚠ 这一排坐标跟着摆位走,**摆位一改就要重定**:2026-09-06 第二十三轮把
|
||||||
# F1 竖过来、D1 与 C4/C5/C6 挪到东列之后,旧的 `x=10` 那一刀量到的是空气(报 0.00 mm)。
|
# F1 竖过来、D1 与 C4/C5/C6 挪到东列之后,旧的 `x=10` 那一刀量到的是空气(报 0.00 mm)。
|
||||||
(u'RAW J1→F1 颈', VIN_RAW, L_TOP, 'y', 73.4, (14.0, 20.0), 8.0),
|
# 2026-09-08:输入首级西移 30 mm,下面前四条**全部重定**。
|
||||||
(u'RAW J1.2 东出', VIN_RAW, L_TOP, 'x', 15.5, (64.0, 76.0), 8.0),
|
# ⚠️ 断面要卡在「电流真正流过的那一段」,不是随便找个地方量:
|
||||||
(u'FUSED F1.2→Q1 源极', VIN_FUSED, L_TOP, 'x', 19.5, (72.0, 80.0), 8.0),
|
# VIN_RAW 的载流段是 J1.1 与 F1.1 **之间**(x≈−14.2);台阶以东那 3.15 mm
|
||||||
(u'SW Q1 漏极北出', VIN_SW, L_TOP, 'y', 77.5, (24.0, 34.0), 8.0),
|
# 是 F1.1 的落脚区、不走穿过电流,在那里量会得到一个偏严且没意义的数。
|
||||||
|
(u'RAW J1.1→F1.1', VIN_RAW, L_TOP, 'x', -14.2, (68.0, 79.0), 8.0),
|
||||||
|
(u'FUSED F1.2→Q1 源极', VIN_FUSED, L_TOP, 'x', -10.7, (70.0, 80.0), 8.0),
|
||||||
|
(u'SW Q1 漏极东出', VIN_SW, L_TOP, 'x', -1.5, (69.0, 81.0), 8.0),
|
||||||
|
(u'SW 过 D1 北上', VIN_SW, L_TOP, 'x', 2.0, (70.0, 86.0), 8.0),
|
||||||
(u'SW 干道 @x24 东端', VIN_SW, L_TOP, 'x', 24.0, (74.0, 86.0), 8.0),
|
(u'SW 干道 @x24 东端', VIN_SW, L_TOP, 'x', 24.0, (74.0, 86.0), 8.0),
|
||||||
(u'SW 干道 @x12', VIN_SW, L_TOP, 'x', 12.0, (74.0, 86.0), 8.0),
|
(u'SW 干道 @x12', VIN_SW, L_TOP, 'x', 12.0, (74.0, 86.0), 8.0),
|
||||||
(u'SW 干道拐北 @y84', VIN_SW, L_TOP, 'y', 84.0, (0.5, 12.0), 8.0),
|
(u'SW 干道拐北 @y84', VIN_SW, L_TOP, 'y', 84.0, (0.5, 12.0), 8.0),
|
||||||
@@ -373,7 +437,6 @@ ROUTED_PADS = {
|
|||||||
'U12.9': u'Kelvin(IN−):单独引线到 Rs501.1 的焊盘,不进 VO5_P 小岛',
|
'U12.9': u'Kelvin(IN−):单独引线到 Rs501.1 的焊盘,不进 VO5_P 小岛',
|
||||||
'C11.1': u'陪 U13 一起挖出去,走顶层到 L2 输出',
|
'C11.1': u'陪 U13 一起挖出去,走顶层到 L2 输出',
|
||||||
'U13.6': u'INA226 的 VS+,陪 U13 一起挖出去(C11 就在旁边)',
|
'U13.6': u'INA226 的 VS+,陪 U13 一起挖出去(C11 就在旁边)',
|
||||||
'C739.1': u'孤零零落在风扇指里,走 11 mm 顶层线到 U33.10',
|
|
||||||
# U23 西侧那两颗(v11 控制块退火重排之后落到 x 71.9~72.4):
|
# U23 西侧那两颗(v11 控制块退火重排之后落到 x 71.9~72.4):
|
||||||
# 那一条 x 是 `12V-SW+BR`(东界 72.6) 与 `3V3-SE`(西界 73.0) 中间的 0.4 mm 缝,
|
# 那一条 x 是 `12V-SW+BR`(东界 72.6) 与 `3V3-SE`(西界 73.0) 中间的 0.4 mm 缝,
|
||||||
# 两块内层平面谁都够不着。**贴片焊盘对内层透明,所以不是错误**,走顶层短线即可:
|
# 两块内层平面谁都够不着。**贴片焊盘对内层透明,所以不是错误**,走顶层短线即可:
|
||||||
@@ -385,12 +448,24 @@ ROUTED_PADS = {
|
|||||||
u'不能从大铜面上随便找个点接',
|
u'不能从大铜面上随便找个点接',
|
||||||
'DZ1.1': u'Q1 栅极钳位齐纳的上端,µA 级;夹在 F1.1 与 Q1.4 之间只有 3.1 mm,走细线',
|
'DZ1.1': u'Q1 栅极钳位齐纳的上端,µA 级;夹在 F1.1 与 Q1.4 之间只有 3.1 mm,走细线',
|
||||||
'C1.1': u'Q1 栅极 RC 的上端,µA 级;同 DZ1.1',
|
'C1.1': u'Q1 栅极 RC 的上端,µA 级;同 DZ1.1',
|
||||||
|
# 2026-09-08 第三十四轮:两路 TACH 接收跟着风扇座搬到了东西**板边**
|
||||||
|
# (R753 在 x −25.6、R757 在 x 181,都在 y≈100),离 `3V3-SW`/`3V3-SE` 两块内层
|
||||||
|
# 平面各有 80~100 mm。**不要为这两颗把平面拉过去** —— 10 kΩ 上拉到 3.3 V
|
||||||
|
# 只有 **0.33 mA**,外层 0.2 mm 线绰绰有余,而拉一条 100 mm 的内层电源面
|
||||||
|
# 会把 Inner2 的分割搅乱。它们是「接收电路在信号源头整形」那条设计决定的代价。
|
||||||
|
'R753.2': u'进风 TACH 的 3.3V 上拉(10k, 0.33 mA),随风扇座在西板边;走顶层细线',
|
||||||
|
'R757.2': u'排风 TACH 的 3.3V 上拉(10k, 0.33 mA),随风扇座在东板边;走顶层细线',
|
||||||
}
|
}
|
||||||
# 整块「有意不进平面」的区域(位号前缀 → 说明)
|
# 整块「有意不进平面」的区域(位号前缀 → 说明)
|
||||||
ROUTED_BLOCKS = [
|
ROUTED_BLOCKS = [
|
||||||
((14.0, 100.0, 30.0, 124.0), u'北左辅助 Buck 那一窝:12V 与 3V3 在 16×24 mm 里交错,整窝走顶层'),
|
((14.0, 100.0, 30.0, 124.0), u'北左辅助 Buck 那一窝:12V 与 3V3 在 16×24 mm 里交错,整窝走顶层'),
|
||||||
((36.0, 70.0, 58.0, 84.0), u'CH2 的 +3V3(5 个,50 mA):沿 y≈84 走顶层到中间那块'),
|
((36.0, 70.0, 58.0, 84.0), u'CH2 的 +3V3(5 个,50 mA):沿 y≈84 走顶层到中间那块'),
|
||||||
((126.0, 70.0, 146.0, 84.0), u'CH3 的 +3V3(5 个,50 mA):同上'),
|
((126.0, 70.0, 146.0, 84.0), u'CH3 的 +3V3(5 个,50 mA):同上'),
|
||||||
|
# `R518.1`(CH5 的 +3V3):2026-09-06 第二十六轮起不再落在 Inner2 的 +3V3 上 ——
|
||||||
|
# 它本来就是「短线 + 扇出孔」那一类,只是以前**碰巧**还压着平面所以没被点名。
|
||||||
|
# 实测通路:R518.1 → 顶层 0.66 mm → +3V3 扇出孔 (134.575, 51.000) → 平面,
|
||||||
|
# `pcb1_netlist` 里 +3V3 整网连通(不在「还差」名单里)。框只罩这一颗。
|
||||||
|
((135.0, 50.4, 136.0, 51.6), u'CH5 的 R518.1:顶层 0.66 mm 短线到 (134.575,51.000) 的 +3V3 扇出孔'),
|
||||||
]
|
]
|
||||||
|
|
||||||
|
|
||||||
@@ -531,6 +606,16 @@ def inside(poly, x, y):
|
|||||||
# ══════════════════ 栅格化 + 校核 ══════════════════
|
# ══════════════════ 栅格化 + 校核 ══════════════════
|
||||||
G = 0.25 # 栅格(mm)。0.25 下 45 mm 的通道是 180 格,够细
|
G = 0.25 # 栅格(mm)。0.25 下 45 mm 的通道是 180 格,够细
|
||||||
|
|
||||||
|
#: 浮铜检查的**最小面积**(mm²)。小于它的当栅格碎屑放过,只打印不判红。
|
||||||
|
#:
|
||||||
|
#: ⚠️ 这不是"把检查关小声点",是给它一个说得出理由的下限:布线一多,
|
||||||
|
#: 过孔的反焊盘之间必然夹出 0.25×0.25(**正好一个栅格**)这种碎屑 ——
|
||||||
|
#: 2026-09-06 第二十五轮实测两粒:Inner1 (68.9,74.6) 0.06 mm²、Inner2 (138.5,75.2) 0.19 mm²,
|
||||||
|
#: 都比一个过孔盘还小,电气上没有意义,而且嘉立创铺铜自己也会按死铜阈值清掉。
|
||||||
|
#: 门槛定在 1.0 mm²(1×1 mm):这一轮真正抓到的两条 —— 南沿那条 **1312.8 mm²** 的
|
||||||
|
#: GND 底填、`3V3-SW` 里那块 **7.2 mm²** 的孤岛 —— 都远在门槛之上,一条都不会漏。
|
||||||
|
MIN_FLOAT_AREA = 1.0
|
||||||
|
|
||||||
|
|
||||||
class Grid(object):
|
class Grid(object):
|
||||||
u"""某一层上某个网络的铜:先按区域填,再挖异网的反焊盘 / 过孔 / 走线。
|
u"""某一层上某个网络的铜:先按区域填,再挖异网的反焊盘 / 过孔 / 走线。
|
||||||
@@ -554,11 +639,11 @@ class Grid(object):
|
|||||||
for r in regions:
|
for r in regions:
|
||||||
xs = [p[0] for p in r['poly']]
|
xs = [p[0] for p in r['poly']]
|
||||||
ys = [p[1] for p in r['poly']]
|
ys = [p[1] for p in r['poly']]
|
||||||
i0, i1 = int(min(xs) / G), int(max(xs) / G) + 1
|
i0, i1 = gi(min(xs)), gi(max(xs)) + 1
|
||||||
j0, j1 = int(min(ys) / G), int(max(ys) / G) + 1
|
j0, j1 = gj(min(ys)), gj(max(ys)) + 1
|
||||||
for j in range(max(0, j0), min(self.ny, j1)):
|
for j in range(max(0, j0), min(self.ny, j1)):
|
||||||
for i in range(max(0, i0), min(self.nx, i1)):
|
for i in range(max(0, i0), min(self.nx, i1)):
|
||||||
if not self.c[j][i] and inside(r['poly'], (i + .5) * G, (j + .5) * G):
|
if not self.c[j][i] and inside(r['poly'], gx(i), gy(j)):
|
||||||
self.c[j][i] = True
|
self.c[j][i] = True
|
||||||
# 反焊盘:异网焊盘(内层只算通孔,外层连贴片一起算)
|
# 反焊盘:异网焊盘(内层只算通孔,外层连贴片一起算)
|
||||||
self.carved = 0
|
self.carved = 0
|
||||||
@@ -580,21 +665,21 @@ class Grid(object):
|
|||||||
# 天线禁铺(全层)
|
# 天线禁铺(全层)
|
||||||
for j in range(self.ny):
|
for j in range(self.ny):
|
||||||
for i in range(self.nx):
|
for i in range(self.nx):
|
||||||
if self.c[j][i] and ANT[0] <= (i + .5) * G <= ANT[2] \
|
if self.c[j][i] and ANT[0] <= gx(i) <= ANT[2] \
|
||||||
and ANT[1] <= (j + .5) * G <= ANT[3]:
|
and ANT[1] <= gy(j) <= ANT[3]:
|
||||||
self.c[j][i] = False
|
self.c[j][i] = False
|
||||||
self.label()
|
self.label()
|
||||||
|
|
||||||
def _carve(self, x0, y0, x1, y1):
|
def _carve(self, x0, y0, x1, y1):
|
||||||
u"""挖掉一个矩形(已经把净距算进去了)。返回有没有真挖到东西。"""
|
u"""挖掉一个矩形(已经把净距算进去了)。返回有没有真挖到东西。"""
|
||||||
hit = False
|
hit = False
|
||||||
for j in range(max(0, int(y0 / G)), min(self.ny, int(y1 / G) + 1)):
|
for j in range(max(0, gj(y0)), min(self.ny, gj(y1) + 1)):
|
||||||
yc = (j + .5) * G
|
yc = gy(j)
|
||||||
if not (y0 <= yc <= y1):
|
if not (y0 <= yc <= y1):
|
||||||
continue
|
continue
|
||||||
row = self.c[j]
|
row = self.c[j]
|
||||||
for i in range(max(0, int(x0 / G)), min(self.nx, int(x1 / G) + 1)):
|
for i in range(max(0, gi(x0)), min(self.nx, gi(x1) + 1)):
|
||||||
if row[i] and x0 <= (i + .5) * G <= x1:
|
if row[i] and x0 <= gx(i) <= x1:
|
||||||
row[i] = False
|
row[i] = False
|
||||||
hit = True
|
hit = True
|
||||||
return hit
|
return hit
|
||||||
@@ -628,15 +713,15 @@ class Grid(object):
|
|||||||
u"""沿一条线量本网铜的总宽与最长连续段(mm)。"""
|
u"""沿一条线量本网铜的总宽与最长连续段(mm)。"""
|
||||||
tot = run_max = run = 0
|
tot = run_max = run = 0
|
||||||
if axis == 'y':
|
if axis == 'y':
|
||||||
j = int(coord / G)
|
j = gj(coord)
|
||||||
for i in range(int(span[0] / G), int(span[1] / G) + 1):
|
for i in range(gi(span[0]), gi(span[1]) + 1):
|
||||||
v = 0 <= i < self.nx and 0 <= j < self.ny and self.c[j][i]
|
v = 0 <= i < self.nx and 0 <= j < self.ny and self.c[j][i]
|
||||||
tot += 1 if v else 0
|
tot += 1 if v else 0
|
||||||
run = run + 1 if v else 0
|
run = run + 1 if v else 0
|
||||||
run_max = max(run_max, run)
|
run_max = max(run_max, run)
|
||||||
else:
|
else:
|
||||||
i = int(coord / G)
|
i = gi(coord)
|
||||||
for j in range(int(span[0] / G), int(span[1] / G) + 1):
|
for j in range(gj(span[0]), gj(span[1]) + 1):
|
||||||
v = 0 <= i < self.nx and 0 <= j < self.ny and self.c[j][i]
|
v = 0 <= i < self.nx and 0 <= j < self.ny and self.c[j][i]
|
||||||
tot += 1 if v else 0
|
tot += 1 if v else 0
|
||||||
run = run + 1 if v else 0
|
run = run + 1 if v else 0
|
||||||
@@ -645,8 +730,8 @@ class Grid(object):
|
|||||||
|
|
||||||
def hit(self, x, y, hx, hy):
|
def hit(self, x, y, hx, hy):
|
||||||
u"""这个焊盘有没有落在本网主连通域上(焊盘框内任一格)。"""
|
u"""这个焊盘有没有落在本网主连通域上(焊盘框内任一格)。"""
|
||||||
i0, i1 = int((x - hx) / G), int((x + hx) / G) + 1
|
i0, i1 = gi(x - hx), gi(x + hx) + 1
|
||||||
j0, j1 = int((y - hy) / G), int((y + hy) / G) + 1
|
j0, j1 = gj(y - hy), gj(y + hy) + 1
|
||||||
for j in range(max(0, j0), min(self.ny, j1 + 1)):
|
for j in range(max(0, j0), min(self.ny, j1 + 1)):
|
||||||
for i in range(max(0, i0), min(self.nx, i1 + 1)):
|
for i in range(max(0, i0), min(self.nx, i1 + 1)):
|
||||||
if self.lab[j][i]:
|
if self.lab[j][i]:
|
||||||
@@ -1004,7 +1089,9 @@ def ascii_map_top(pads, obs=()):
|
|||||||
看不出「是被 GND 扇出孔啃的还是被自己的边界切的」。
|
看不出「是被 GND 扇出孔啃的还是被自己的边界切的」。
|
||||||
"""
|
"""
|
||||||
g = 0.5
|
g = 0.5
|
||||||
x0, x1, y0, y1 = 1.0, 31.0, 65.0, 95.0
|
# 2026-09-08:窗口跟着输入首级西移 —— 旧值 (1,31,65,95) 现在只剩右半条链。
|
||||||
|
# 链路实际占 x −17~30.5 / y 70~95.3,取 0.5 mm/格 一行 96 字,够宽。
|
||||||
|
x0, x1, y0, y1 = -18.0, 32.0, 69.0, 96.0
|
||||||
sym = [(VIN_RAW, 'R'), (VIN_FUSED, 'F'), (VIN_SW, 'S')]
|
sym = [(VIN_RAW, 'R'), (VIN_FUSED, 'F'), (VIN_SW, 'S')]
|
||||||
grids = [(s, Grid(net, L_TOP,
|
grids = [(s, Grid(net, L_TOP,
|
||||||
[r for r in REGIONS if r['layer'] == L_TOP and r['net'] == net],
|
[r for r in REGIONS if r['layer'] == L_TOP and r['net'] == net],
|
||||||
@@ -1029,7 +1116,7 @@ def ascii_map_top(pads, obs=()):
|
|||||||
x = x0 + (i + .5) * g
|
x = x0 + (i + .5) * g
|
||||||
ch = '.'
|
ch = '.'
|
||||||
for s, gr in grids:
|
for s, gr in grids:
|
||||||
ii, jj = int(x / G), int(y / G)
|
ii, jj = gi(x), gj(y)
|
||||||
if 0 <= ii < gr.nx and 0 <= jj < gr.ny and gr.c[jj][ii]:
|
if 0 <= ii < gr.nx and 0 <= jj < gr.ny and gr.c[jj][ii]:
|
||||||
ch = s
|
ch = s
|
||||||
break
|
break
|
||||||
@@ -1058,10 +1145,10 @@ def ascii_map(pads, obs=()):
|
|||||||
for j in range(ny - 1, -1, -1):
|
for j in range(ny - 1, -1, -1):
|
||||||
row = ''
|
row = ''
|
||||||
for i in range(nx):
|
for i in range(nx):
|
||||||
x, y = (i + .5) * g, (j + .5) * g
|
x, y = BX0 + (i + .5) * g, BY0 + (j + .5) * g
|
||||||
ch = ' '
|
ch = ' '
|
||||||
for net, gr in grids:
|
for net, gr in grids:
|
||||||
ii, jj = int(x / G), int(y / G)
|
ii, jj = gi(x), gj(y)
|
||||||
if 0 <= ii < gr.nx and 0 <= jj < gr.ny and gr.c[jj][ii]:
|
if 0 <= ii < gr.nx and 0 <= jj < gr.ny and gr.c[jj][ii]:
|
||||||
ch = sym[net]
|
ch = sym[net]
|
||||||
break
|
break
|
||||||
@@ -1214,10 +1301,10 @@ def _cells_from_rings(rings):
|
|||||||
xs_ = pts[0::2]
|
xs_ = pts[0::2]
|
||||||
ys_ = pts[1::2]
|
ys_ = pts[1::2]
|
||||||
n = len(xs_)
|
n = len(xs_)
|
||||||
j0 = max(0, int(min(ys_) / G))
|
j0 = max(0, gj(min(ys_)))
|
||||||
j1 = min(ny - 1, int(max(ys_) / G) + 1)
|
j1 = min(ny - 1, gj(max(ys_)) + 1)
|
||||||
for j in range(j0, j1 + 1):
|
for j in range(j0, j1 + 1):
|
||||||
y = (j + 0.5) * G
|
y = gy(j)
|
||||||
cr = []
|
cr = []
|
||||||
for k in range(n):
|
for k in range(n):
|
||||||
y1, y2 = ys_[k], ys_[(k + 1) % n]
|
y1, y2 = ys_[k], ys_[(k + 1) % n]
|
||||||
@@ -1227,10 +1314,10 @@ def _cells_from_rings(rings):
|
|||||||
cr.sort()
|
cr.sort()
|
||||||
row = acc[j]
|
row = acc[j]
|
||||||
for a in range(0, len(cr) - 1, 2):
|
for a in range(0, len(cr) - 1, 2):
|
||||||
ia = max(0, int(cr[a] / G))
|
ia = max(0, gi(cr[a]))
|
||||||
ib = min(nx - 1, int(cr[a + 1] / G))
|
ib = min(nx - 1, gi(cr[a + 1]))
|
||||||
for i in range(ia, ib + 1):
|
for i in range(ia, ib + 1):
|
||||||
xc = (i + 0.5) * G
|
xc = gx(i)
|
||||||
if cr[a] <= xc <= cr[a + 1]:
|
if cr[a] <= xc <= cr[a + 1]:
|
||||||
row[i] ^= 1
|
row[i] ^= 1
|
||||||
return [[bool(v) for v in r] for r in acc]
|
return [[bool(v) for v in r] for r in acc]
|
||||||
@@ -1317,16 +1404,22 @@ def verify(refresh=True):
|
|||||||
g = G_[k]
|
g = G_[k]
|
||||||
live = set()
|
live = set()
|
||||||
for x, y in anchors.get(k, ()):
|
for x, y in anchors.get(k, ()):
|
||||||
i, j = int(x / G), int(y / G)
|
i, j = gi(x), gj(y)
|
||||||
if 0 <= i < g.nx and 0 <= j < g.ny and g.lab[j][i]:
|
if 0 <= i < g.nx and 0 <= j < g.ny and g.lab[j][i]:
|
||||||
live.add(g.lab[j][i])
|
live.add(g.lab[j][i])
|
||||||
dead = [(cid, n) for cid, n in g.sizes.items() if cid not in live]
|
dead = [(cid, n) for cid, n in g.sizes.items() if cid not in live]
|
||||||
|
big = [(c, n) for c, n in dead if n * G * G >= MIN_FLOAT_AREA]
|
||||||
|
dust = [(c, n) for c, n in dead if n * G * G < MIN_FLOAT_AREA]
|
||||||
lay = {1: 'Top', 2: 'Bottom', 15: 'Inner1', 16: 'Inner2'}[k[1]]
|
lay = {1: 'Top', 2: 'Bottom', 15: 'Inner1', 16: 'Inner2'}[k[1]]
|
||||||
chk(not dead,
|
if dust:
|
||||||
|
print(u' (%s %s 另有 %d 粒 < %.1f mm² 的碎屑,按 MIN_FLOAT_AREA 放过:%s mm²)'
|
||||||
|
% (lay, k[0], len(dust), MIN_FLOAT_AREA,
|
||||||
|
' '.join('%.2f' % (n * G * G) for _c, n in sorted(dust, key=lambda t: -t[1])[:6])))
|
||||||
|
chk(not big,
|
||||||
u'%s %s 的 %d 块碎片各自都有本网焊盘/过孔落脚' % (lay, k[0], g.ncomp),
|
u'%s %s 的 %d 块碎片各自都有本网焊盘/过孔落脚' % (lay, k[0], g.ncomp),
|
||||||
u'%s %s 有 %d 块**浮铜**(没有任何本网落脚点):%s mm²'
|
u'%s %s 有 %d 块**浮铜**(没有任何本网落脚点):%s mm²'
|
||||||
% (lay, k[0], len(dead),
|
% (lay, k[0], len(big),
|
||||||
' '.join('%.1f' % (n * G * G) for _c, n in sorted(dead, key=lambda t: -t[1])[:6])))
|
' '.join('%.1f' % (n * G * G) for _c, n in sorted(big, key=lambda t: -t[1])[:6])))
|
||||||
|
|
||||||
grid_checks(G_, pads, chk)
|
grid_checks(G_, pads, chk)
|
||||||
return bad
|
return bad
|
||||||
|
|||||||
@@ -82,6 +82,7 @@ TRACK_RULES = {
|
|||||||
'PWR4A': {'strokeWidthDefault': 1.5, 'strokeWidthMin': 0.3, 'strokeWidthMax': 6.0},
|
'PWR4A': {'strokeWidthDefault': 1.5, 'strokeWidthMin': 0.3, 'strokeWidthMax': 6.0},
|
||||||
'PWR5V': {'strokeWidthDefault': 1.2, 'strokeWidthMin': 0.3, 'strokeWidthMax': 6.0},
|
'PWR5V': {'strokeWidthDefault': 1.2, 'strokeWidthMin': 0.3, 'strokeWidthMax': 6.0},
|
||||||
'PWR1A': {'strokeWidthDefault': 0.6, 'strokeWidthMin': 0.15, 'strokeWidthMax': 3.0},
|
'PWR1A': {'strokeWidthDefault': 0.6, 'strokeWidthMin': 0.15, 'strokeWidthMax': 3.0},
|
||||||
|
'FAN12V': {'strokeWidthDefault': 0.8, 'strokeWidthMin': 0.3, 'strokeWidthMax': 3.0},
|
||||||
}
|
}
|
||||||
|
|
||||||
# ── 有名字的网络 → 线宽规则 ────────────────────────────────────────────
|
# ── 有名字的网络 → 线宽规则 ────────────────────────────────────────────
|
||||||
@@ -93,6 +94,13 @@ NET_TRACK['+12V'] = 'PWR12V'
|
|||||||
NET_TRACK['+5V'] = 'PWR5V'
|
NET_TRACK['+5V'] = 'PWR5V'
|
||||||
NET_TRACK['+3V3'] = 'PWR1A'
|
NET_TRACK['+3V3'] = 'PWR1A'
|
||||||
NET_TRACK['SW3V3'] = 'PWR1A' # U19 SW → L2,0.5 A
|
NET_TRACK['SW3V3'] = 'PWR1A' # U19 SW → L2,0.5 A
|
||||||
|
# 2026-09-08 第三十三轮:风扇高边开关的下游母线。Q7 居中、东西两支**各只走 0.67 A**
|
||||||
|
# (FAN-R2 两把风扇 2 x 0.67 A),0.8 mm 外层 1 oz 下西支 125 mm -> 51 mV、东支 95 mm -> 39 mV,
|
||||||
|
# 在 `FAN_CIRCUIT` 的 0.2 V 预算之内。**默认信号线 0.20 mm 扛不住** ——
|
||||||
|
# 0.20 mm 下同样两支是 204 / 155 mV,单是西支就吃掉全部预算。
|
||||||
|
# ⚠️ 早年注释里担心的 0.26 V 是「一条 196 mm 走全电流 1.33 A」的算法,
|
||||||
|
# J26/J27 分到东西两板边、Q7 居中之后不成立。
|
||||||
|
NET_TRACK['FAN_12V_SW'] = 'FAN12V'
|
||||||
|
|
||||||
# ── 自动命名网 → 线宽规则(按「位号.引脚」反查,见文件头第 4 条)──────
|
# ── 自动命名网 → 线宽规则(按「位号.引脚」反查,见文件头第 4 条)──────
|
||||||
# 值是 (探针, 校核端):两端查出来的必须是同一个网,否则说明位号/引脚写错了。
|
# 值是 (探针, 校核端):两端查出来的必须是同一个网,否则说明位号/引脚写错了。
|
||||||
@@ -105,7 +113,10 @@ for _n, _u in zip(range(1, 6), (1, 2, 3, 4, 5)):
|
|||||||
# TPS25940(WQFN-20) 的 OUT 是 pin 4~8,Rs*01 的上游脚是 pin 2。
|
# TPS25940(WQFN-20) 的 OUT 是 pin 4~8,Rs*01 的上游脚是 pin 2。
|
||||||
AUTO_TRACK['VO%d_F' % _n] = ('PWR4A', ('Rs%d' % _c, '2'), ('U%d' % (13 + _n), '5'))
|
AUTO_TRACK['VO%d_F' % _n] = ('PWR4A', ('Rs%d' % _c, '2'), ('U%d' % (13 + _n), '5'))
|
||||||
# 8 A 输入链(§10.2b):J1 → F1 → Q1 → C2/C3/D1 → Rs6。分叉之前全程 8 A。
|
# 8 A 输入链(§10.2b):J1 → F1 → Q1 → C2/C3/D1 → Rs6。分叉之前全程 8 A。
|
||||||
AUTO_TRACK['VIN_RAW'] = ('PWR12V', ('J1', '2'), ('F1', '1'))
|
# ⚠️ 2026-09-08 J1 换成圆形 DC 座之后**正极从 pin2 挪到了 pin1**
|
||||||
|
# (XT30:1=`−` / 2=`+`;DC-005:1=中心正极 / 2、3=两个负极触点)。
|
||||||
|
# 探针写错时这里是硬失败("J1.2 上是 GND,不是自动命名网"),不会静默放过 —— 这是对的。
|
||||||
|
AUTO_TRACK['VIN_RAW'] = ('PWR12V', ('J1', '1'), ('F1', '1'))
|
||||||
AUTO_TRACK['VIN_FUSED'] = ('PWR12V', ('F1', '2'), ('Q1', '1'))
|
AUTO_TRACK['VIN_FUSED'] = ('PWR12V', ('F1', '2'), ('Q1', '1'))
|
||||||
AUTO_TRACK['VIN_SW'] = ('PWR12V', ('Rs6', '1'), ('C2', '1'))
|
AUTO_TRACK['VIN_SW'] = ('PWR12V', ('Rs6', '1'), ('C2', '1'))
|
||||||
# 第二路辅助 Buck 的 SW(§9.4,12V→5V,最坏 2.8 A)
|
# 第二路辅助 Buck 的 SW(§9.4,12V→5V,最坏 2.8 A)
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ HERE = os.path.dirname(os.path.abspath(__file__))
|
|||||||
sys.path.insert(0, HERE)
|
sys.path.insert(0, HERE)
|
||||||
from eda import run
|
from eda import run
|
||||||
|
|
||||||
PCB = 'f126ffb29c92f9b2'
|
PCB = '942ed1560d81c1e7'
|
||||||
MIL = 39.3700787401575
|
MIL = 39.3700787401575
|
||||||
COPPER = (1, 15, 16, 2)
|
COPPER = (1, 15, 16, 2)
|
||||||
|
|
||||||
|
|||||||
@@ -27,7 +27,7 @@ sys.path.insert(0, HERE)
|
|||||||
from eda import run
|
from eda import run
|
||||||
from pcb2_place import SITES, to_board
|
from pcb2_place import SITES, to_board
|
||||||
|
|
||||||
PCB = 'f126ffb29c92f9b2'
|
PCB = '942ed1560d81c1e7'
|
||||||
MIL = 39.3700787401575
|
MIL = 39.3700787401575
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -47,6 +47,8 @@ U5n 朝 Hub 那排的 DP/DM 相距 1.9 mm,车道并排 0.48 到最后 1.4 mm
|
|||||||
(转弯规则:向右拐时左边那根变成外侧,连拐两次回到原样)。
|
(转弯规则:向右拐时左边那根变成外侧,连拐两次回到原样)。
|
||||||
"""
|
"""
|
||||||
import math
|
import math
|
||||||
|
import sys as _s, os as _o; _s.path.insert(0, _o.path.dirname(_o.path.abspath(__file__)))
|
||||||
|
KSEP = chr(0) # 路径 key 的分隔符,与 pcb2_route_dp.KSEP 同值(不能 import:route_dp --dump 会反过来 import 本模块,循环)
|
||||||
|
|
||||||
L_TOP, L_BOT = 1, 2
|
L_TOP, L_BOT = 1, 2
|
||||||
W = 0.28
|
W = 0.28
|
||||||
@@ -183,10 +185,10 @@ UP = {
|
|||||||
# ⚠ 表贴焊盘只到 x=213.04,过孔要离它 0.505 ⇒ 最西只能放到 213.55;出线前 0.65 mm 必须平着走(阵列上方起坡会蹭隔壁脚)。
|
# ⚠ 表贴焊盘只到 x=213.04,过孔要离它 0.505 ⇒ 最西只能放到 213.55;出线前 0.65 mm 必须平着走(阵列上方起坡会蹭隔壁脚)。
|
||||||
# 另一根的 61.75 横线离 (213.85, 62.25) 那个孔只有 0.165 —— 这是同一对的两根(UP_DP vs UP_DM),按对内 0.15 判。
|
# 另一根的 61.75 横线离 (213.85, 62.25) 那个孔只有 0.165 —— 这是同一对的两根(UP_DP vs UP_DM),按对内 0.15 判。
|
||||||
J23_TIE = {
|
J23_TIE = {
|
||||||
'UP_DP#2': [(212.392, 62.25, L_BOT, W), (213.85, 62.25), (213.85, 62.25, L_TOP),
|
'UP_DP' + KSEP + '2': [(212.392, 62.25, L_BOT, W), (213.85, 62.25), (213.85, 62.25, L_TOP),
|
||||||
(213.85, 60.70), (213.85, 60.70, L_BOT), (213.50, 61.25),
|
(213.85, 60.70), (213.85, 60.70, L_BOT), (213.50, 61.25),
|
||||||
(213.20, 61.25), (212.392, 61.25)],
|
(213.20, 61.25), (212.392, 61.25)],
|
||||||
'UP_DM#2': [(212.392, 61.75, L_BOT, W), (213.20, 61.75), (213.50, 61.75),
|
'UP_DM' + KSEP + '2': [(212.392, 61.75, L_BOT, W), (213.20, 61.75), (213.50, 61.75),
|
||||||
(214.25, 61.30), (214.75, 61.30), (214.75, 61.30, L_TOP),
|
(214.25, 61.30), (214.75, 61.30), (214.75, 61.30, L_TOP),
|
||||||
(214.75, 63.20), (214.75, 63.20, L_BOT), (214.25, 63.20),
|
(214.75, 63.20), (214.75, 63.20, L_BOT), (214.25, 63.20),
|
||||||
(213.50, 62.75), (213.20, 62.75), (212.392, 62.75)],
|
(213.50, 62.75), (213.20, 62.75), (212.392, 62.75)],
|
||||||
@@ -223,12 +225,12 @@ def power_lanes(pads):
|
|||||||
if p['ref'] == 'U31' and p['num'] == '2':
|
if p['ref'] == 'U31' and p['num'] == '2':
|
||||||
assert abs(p['x'] - 90.47) < 0.05 and abs(p['y'] - 60.5) < 0.05, u'U31 pin2 挪了,改 V_TRUNK'
|
assert abs(p['x'] - 90.47) < 0.05 and abs(p['y'] - 60.5) < 0.05, u'U31 pin2 挪了,改 V_TRUNK'
|
||||||
return {
|
return {
|
||||||
'+3V3_HUB#p5': [(PAD_X, 66.25), (90.40, 66.25), (V_P5[0], V_P5[1]),
|
'+3V3_HUB' + KSEP + 'p5': [(PAD_X, 66.25), (90.40, 66.25), (V_P5[0], V_P5[1]),
|
||||||
(V_P5[0], V_P5[1], L_TOP), (V_P5W[0], V_P5W[1]),
|
(V_P5[0], V_P5[1], L_TOP), (V_P5W[0], V_P5W[1]),
|
||||||
(V_P5W[0], V_P5W[1], L_BOT), (c747[0], c747[1])],
|
(V_P5W[0], V_P5W[1], L_BOT), (c747[0], c747[1])],
|
||||||
'+3V3_HUB#p10': [(PAD_X, 68.75), (92.95, 68.75), (92.95, 69.55), (V_P10[0], V_P10[1]),
|
'+3V3_HUB' + KSEP + 'p10': [(PAD_X, 68.75), (92.95, 68.75), (92.95, 69.55), (V_P10[0], V_P10[1]),
|
||||||
(c748[0], c748[1])],
|
(c748[0], c748[1])],
|
||||||
'+3V3_HUB#trunk': [(90.30, 61.00), (V_TRUNK[0], V_TRUNK[1]),
|
'+3V3_HUB' + KSEP + 'trunk': [(90.30, 61.00), (V_TRUNK[0], V_TRUNK[1]),
|
||||||
(V_TRUNK[0], V_TRUNK[1], L_TOP), (90.30, 70.40), (V_P5[0], V_P5[1]),
|
(V_TRUNK[0], V_TRUNK[1], L_TOP), (90.30, 70.40), (V_P5[0], V_P5[1]),
|
||||||
(V_P10[0], V_P10[1]), (V_P10[0], V_P10[1], L_BOT), (c748[0], c748[1])],
|
(V_P10[0], V_P10[1]), (V_P10[0], V_P10[1], L_BOT), (c748[0], c748[1])],
|
||||||
}
|
}
|
||||||
|
|||||||
@@ -1,7 +1,7 @@
|
|||||||
# -*- coding: utf-8 -*-
|
# -*- coding: utf-8 -*-
|
||||||
u"""载板 PCB2-CARRIER 的扇出 —— 复用下板 `pcb_fanout.py` 的规划器,只换掉板子相关的常量。
|
u"""载板 PCB2-CARRIER 的扇出 —— 复用下板 `pcb_fanout.py` 的规划器,只换掉板子相关的常量。
|
||||||
|
|
||||||
/c/Python314/python .claude/dump_pads.py f126ffb29c92f9b2 pcb2-copper.json # 1. 抓障碍表
|
/c/Python314/python .claude/dump_pads.py 942ed1560d81c1e7 pcb2-copper.json # 1. 抓障碍表
|
||||||
/c/Python314/python .claude/pcb2_fanout.py # 2. 只规划
|
/c/Python314/python .claude/pcb2_fanout.py # 2. 只规划
|
||||||
/c/Python314/python .claude/pcb2_fanout.py --push # 3. 下发
|
/c/Python314/python .claude/pcb2_fanout.py --push # 3. 下发
|
||||||
|
|
||||||
@@ -47,7 +47,7 @@ F = importlib.util.module_from_spec(_spec)
|
|||||||
_spec.loader.exec_module(F)
|
_spec.loader.exec_module(F)
|
||||||
|
|
||||||
# ── 换掉板子相关的常量 ────────────────────────────────────────────────
|
# ── 换掉板子相关的常量 ────────────────────────────────────────────────
|
||||||
F.PCB = 'f126ffb29c92f9b2' # PCB2-CARRIER
|
F.PCB = '942ed1560d81c1e7' # PCB2-CARRIER
|
||||||
F.SRC = os.path.join(HERE, 'pcb2-copper.json')
|
F.SRC = os.path.join(HERE, 'pcb2-copper.json')
|
||||||
F.BOARD = (0.0, 0.0, 220.0, 135.0)
|
F.BOARD = (0.0, 0.0, 220.0, 135.0)
|
||||||
F.R_CORNER = 5.0
|
F.R_CORNER = 5.0
|
||||||
@@ -168,7 +168,7 @@ def clean2():
|
|||||||
def main():
|
def main():
|
||||||
if not os.path.exists(F.SRC):
|
if not os.path.exists(F.SRC):
|
||||||
sys.exit(u'先抓障碍表:/c/Python314/python .claude/dump_pads.py '
|
sys.exit(u'先抓障碍表:/c/Python314/python .claude/dump_pads.py '
|
||||||
u'f126ffb29c92f9b2 pcb2-copper.json')
|
u'942ed1560d81c1e7 pcb2-copper.json')
|
||||||
print(u'载板扇出:板框 %.0f × %.0f,元件面 %s,GND -> layer %d'
|
print(u'载板扇出:板框 %.0f × %.0f,元件面 %s,GND -> layer %d'
|
||||||
% (F.BOARD[2], F.BOARD[3], F.FANOUT_LAYERS, F.TARGET['GND']))
|
% (F.BOARD[2], F.BOARD[3], F.FANOUT_LAYERS, F.TARGET['GND']))
|
||||||
if SKIP_HDR:
|
if SKIP_HDR:
|
||||||
|
|||||||
@@ -94,8 +94,27 @@ def clusters(pads, vias, lines):
|
|||||||
return False
|
return False
|
||||||
return touch(b, a)
|
return touch(b, a)
|
||||||
|
|
||||||
for i in range(n):
|
# 2026-09-07:包围盒预筛。原来纯两两比对,第三十轮 GND 件数上去之后跑了 20 多分钟没出来。
|
||||||
for j in range(i + 1, n):
|
# 每件算一个外扩 EPS 的包围盒,先按 x 排序,只比 x 区间相交的对。
|
||||||
|
def _bb(it):
|
||||||
|
k, _, o = it
|
||||||
|
if k == 'line':
|
||||||
|
r = o['w'] / 2.0
|
||||||
|
return (min(o['x0'], o['x1']) - r, min(o['y0'], o['y1']) - r,
|
||||||
|
max(o['x0'], o['x1']) + r, max(o['y0'], o['y1']) + r)
|
||||||
|
if k == 'via':
|
||||||
|
return (o['x'] - o['r'], o['y'] - o['r'], o['x'] + o['r'], o['y'] + o['r'])
|
||||||
|
return (o['x'] - o['hw'], o['y'] - o['hh'], o['x'] + o['hw'], o['y'] + o['hh'])
|
||||||
|
bbs = [_bb(it) for it in items]
|
||||||
|
order = sorted(range(n), key=lambda i: bbs[i][0])
|
||||||
|
for oi, i in enumerate(order):
|
||||||
|
bi = bbs[i]
|
||||||
|
for j in order[oi + 1:]:
|
||||||
|
bj = bbs[j]
|
||||||
|
if bj[0] > bi[2] + EPS:
|
||||||
|
break
|
||||||
|
if bj[1] > bi[3] + EPS or bj[3] < bi[1] - EPS:
|
||||||
|
continue
|
||||||
if touch(items[i], items[j]):
|
if touch(items[i], items[j]):
|
||||||
a, b = find(i), find(j)
|
a, b = find(i), find(j)
|
||||||
if a != b:
|
if a != b:
|
||||||
@@ -223,7 +242,7 @@ def main():
|
|||||||
pad, lay, w, segs, (vx, vy) = best
|
pad, lay, w, segs, (vx, vy) = best
|
||||||
other = R.L_BOT if lay == R.L_TOP else R.L_TOP
|
other = R.L_BOT if lay == R.L_TOP else R.L_TOP
|
||||||
pts = [(segs[0][1], segs[0][2], lay, w)] + [(x1, y1, lay, w) for _l, _a, _b, x1, y1, _w in segs]
|
pts = [(segs[0][1], segs[0][2], lay, w)] + [(x1, y1, lay, w) for _l, _a, _b, x1, y1, _w in segs]
|
||||||
routes[u'%s#patch%d' % (NET, k)] = pts + [(vx, vy, other, w), (vx, vy, other, w)]
|
routes[u'%s%spatch%d' % (NET, R.KSEP, k)] = pts + [(vx, vy, other, w), (vx, vy, other, w)]
|
||||||
for l_, x0, y0, x1, y1, w_ in segs:
|
for l_, x0, y0, x1, y1, w_ in segs:
|
||||||
mine.append((NET, l_, x0, y0, x1, y1, w_))
|
mine.append((NET, l_, x0, y0, x1, y1, w_))
|
||||||
mvias.append((NET, vx, vy))
|
mvias.append((NET, vx, vy))
|
||||||
|
|||||||
@@ -12,7 +12,7 @@ HERE = os.path.dirname(os.path.abspath(__file__))
|
|||||||
sys.path.insert(0, HERE)
|
sys.path.insert(0, HERE)
|
||||||
from eda import run
|
from eda import run
|
||||||
|
|
||||||
PCB = 'f126ffb29c92f9b2' # PCB2-CARRIER
|
PCB = '942ed1560d81c1e7' # PCB2-CARRIER
|
||||||
OUT = os.path.join(HERE, 'pcb2-parts.json')
|
OUT = os.path.join(HERE, 'pcb2-parts.json')
|
||||||
|
|
||||||
JS = u"""
|
JS = u"""
|
||||||
|
|||||||
@@ -79,28 +79,95 @@ HERE = os.path.dirname(os.path.abspath(__file__))
|
|||||||
sys.path.insert(0, HERE)
|
sys.path.insert(0, HERE)
|
||||||
from eda import run
|
from eda import run
|
||||||
|
|
||||||
PCB = 'f126ffb29c92f9b2' # PCB2-CARRIER
|
PCB = '942ed1560d81c1e7' # PCB2-CARRIER
|
||||||
MIL = 39.3700787401575
|
MIL = 39.3700787401575
|
||||||
|
|
||||||
BW, BH = 220.0, 135.0 # 板框 mm
|
BW, BH = 220.0, 135.0 # 板框 mm
|
||||||
CORNER_R = 5.0
|
CORNER_R = 5.0
|
||||||
# 载板自己的 M3 安装孔(来历见 obsolete/pcb2_place_topside_2026-09-06.py 文件头,位置没动)。
|
# 载板自己的 M3 安装孔(来历见 obsolete/pcb2_place_topside_2026-09-06.py 文件头,位置没动)。
|
||||||
MH = [(8.0, 8.0), (212.0, 8.0), (7.0, 60.0), (213.0, 45.0),
|
MH = [(8.0, 8.0), (212.0, 8.0), (7.0, 60.0), (213.0, 45.0),
|
||||||
(76.6, 79.5), (148.1, 79.5)] # v3:中跨孔随上排下移 0.6(焊盘顶 82.5 < 83.0)
|
(76.6, 79.5), (148.1, 79.5), # v3:中跨孔随上排下移 0.6(焊盘顶 82.5 < 83.0)
|
||||||
|
# 2026-09-06 用户指令「两板尺寸取大对齐、四角定位孔对齐」:下板改成同样的 220×135、
|
||||||
|
# 四角孔与本板重合。底部两角本来就有 (8,8)/(212,8);顶部两角被上排主板(y ≤ 127.66)和
|
||||||
|
# 尾插槽(site1 x 8.09~27.09,见 SLOTS 注释)夹住,只剩板角 4×4 那一块:
|
||||||
|
# 孔心 (4,131)/(216,131),焊盘 Ø6 → 离板边 1.0、离主板边 0.34(主板架在 3 mm 立柱上,螺钉头 ≤ 2)、离槽 1.09。
|
||||||
|
(4.0, 131.0), (216.0, 131.0)]
|
||||||
MH_HOLE, MH_PAD = 3.2, 6.0
|
MH_HOLE, MH_PAD = 3.2, 6.0
|
||||||
MH_KEEP = 3.5 # 底层元件离 M3 孔中心的最小距离(螺钉头 Ø6)
|
MH_KEEP = 3.5 # 底层元件离 M3 孔中心的最小距离(螺钉头 Ø6)
|
||||||
|
|
||||||
# ---- 小米8 主板(顶视,板左下角原点,mm)----
|
# ---- 小米8 主板(顶视,板左下角原点,mm)----
|
||||||
PW, PH = 67.09, 44.66
|
# 2026-09-06 实测替换(旧值的 7 孔是**从照片认的**,最大错 4.8 mm)。
|
||||||
HOLES = {'H1': (54.2, 42.3), 'H2': (2.6, 38.2), 'H3': (61.9, 33.7), 'H4': (62.1, 29.2),
|
# 新值来源:测量底板(四基准点 Φ6,圆心矩形 160x110)上描轮廓 + 每孔戳一点 -> 扫描 ->
|
||||||
'H5': (2.6, 27.0), 'H6': (4.0, 10.8), 'H7': (42.6, 3.7)}
|
# `pcb2_measure_read.py` 单应反算。**再拿真主板平板扫描件做了一次独立复核**:
|
||||||
HOLE_D = 2.5 # 载板上的定位孔,NPTH
|
# 用这 7 个孔去套扫描件上的孔,**7/7 命中、平均残差 0.38 mm**(`_fit.png`)。
|
||||||
HOLE_KEEP = 2.8 # 底层元件离定位孔中心的最小距离(M2.5 尼龙螺钉头 Ø4.5 + 余量)
|
# ⚠️ 编号整体重排过,别拿旧 H 号对新 H 号。
|
||||||
|
# ⚠️ 板长 67 = **裸板**。用户描轮廓时 SIM 卡托还插着,卡托在 u 大的那一端伸出约 3.3 mm,
|
||||||
|
# 所以描出来是 70.3。他早先给的 u 值是拿 66 / 70.3 混着换算的,才有那 3~4 mm 的怪差。
|
||||||
|
PW, PH = 67.0, 44.0
|
||||||
|
HOLES = {'H1': (1.4, 9.9), 'H2': (0.7, 27.3), 'H3': (1.7, 38.7), 'H4': (41.9, 1.9),
|
||||||
|
'H5': (57.4, 41.2), 'H6': (64.6, 28.1), 'H7': (64.8, 32.4)}
|
||||||
|
HOLE_D = 1.8 # 载板上的定位孔,NPTH。2026-09-06 用户卡尺:**主板孔 Φ2.0**
|
||||||
|
# (先前口头的 Φ1.5 作废)。Φ2.0 是手机自己的过孔 ⇒ 配 **M1.6 尼龙立柱**
|
||||||
|
# (M2 螺杆 Φ2.0 塞 Φ2.0 没余量,不选);载板这侧是螺钉过孔,取 M1.6 的通孔 Φ1.8。
|
||||||
|
# 原来整套按 Φ2.5 / M2.5 做的,是错的。
|
||||||
|
HOLE_KEEP = 2.2 # 底层元件离定位孔中心的最小距离(M1.6 尼龙螺钉头 Ø3.2 + 余量)
|
||||||
|
# 2026-09-07:**H5 不打**。J61~J65(EDL 座)离 P*H5 只有 0.92(要 2.2),二选一里「不打 H5」代价为零:
|
||||||
|
# 每台还有 6 颗螺钉,H5 在 u 大 / v 大那个角(离侧键触点最远的角),那里没有需要压紧的东西。
|
||||||
|
# 模型里 HOLES 保留 7 个(它是实测数据),只在下发孔 / 螺钉头避让时跳过这里列的。
|
||||||
|
SKIP_HOLES = {'H5'}
|
||||||
|
|
||||||
# 侧键触点(§22.3b,已折算成顶视投影)。顶针顺序 = c4_site.py 的 pogo[0..3]
|
# 侧键触点。旧值(§22.3b 那四个点)是从照片认的,**内部排布是错的**,见下。
|
||||||
POGO_XY = [(3.11, 6.91), (2.70, 4.60), (5.41, 6.52), (2.12, 2.46)]
|
#
|
||||||
|
# ---- 已经问清楚的(可信)----
|
||||||
|
# 触点是 **4 个 Φ1.35 的圆盘,排成菱形**:相邻 1.87 mm、对角 2.65 mm。
|
||||||
|
# 来源:中框(配合件)上那四个金色焊盘的平板扫描,边界干净,k-means 分开后直接量。
|
||||||
|
# ⚠️ **顶针本体直径必须 < 1.87 mm**,常规 Φ2 以上的排不下 —— 选型硬约束。
|
||||||
|
#
|
||||||
|
# ---- 位置:**中框螺柱配准**那一版(已被卡尺判定为正确)----
|
||||||
|
# 2026-09-06:用户卡尺实测 **H1 孔心到四触点菱形中心 = 5 mm**,判死了两条路之争:
|
||||||
|
# 中框配准版 (3.42, 5.07) -> 离 H1 5.24 mm ✔ 采信
|
||||||
|
# 红漆配准版 (0.81, 7.08) -> 离 H1 2.88 mm �’ 弃
|
||||||
|
# 红漆那条当时的论据是「同图内量到最近孔 2.7 mm,不经配准也不吃手性」,**论据是错的**:
|
||||||
|
# 那个「最近的孔」是环形滤波器几百个候选里的一个,多半是过孔/焊盘误报,不是真孔。
|
||||||
|
# ⚠️ 教训:环形滤波器在这块板上误报率极高,**任何"离最近的孔多少"都不能直接用**,
|
||||||
|
# 必须先确认那个候选真的是 7 孔之一。
|
||||||
|
# 旁证:中框版四个点全在板内(红漆版算出 GND 在板边外 0.5 mm,与用户「GND 离短板边最近」矛盾),
|
||||||
|
# 而且和旧 §22.3b 的簇心 (3.34, 5.12) 只差 0.1 mm —— 旧数据的**簇心本来就是对的,错的是内部排布**。
|
||||||
|
# 下面四个坐标直接取中框配准的实测值(不是理想菱形),残差 0.57 mm。
|
||||||
|
POGO_XY = [(4.72, 5.16), # PWR 电源 u+
|
||||||
|
(3.42, 6.37), # VUP 音量+ v+
|
||||||
|
(3.49, 3.74), # VDN 音量- v-
|
||||||
|
(2.05, 4.99)] # GND u-
|
||||||
POGO_TAG = ['J603 PWR', 'J601 VUP', 'J602 VDN', 'J604 GND']
|
POGO_TAG = ['J603 PWR', 'J601 VUP', 'J602 VDN', 'J604 GND']
|
||||||
|
|
||||||
|
# ---- 2026-09-06 用户改方案:**顶针取消,改成和中框一样的焊盘** ----
|
||||||
|
# 装配方式跟着改:不再靠顶针弹力,而是**用螺丝把主板压在载板上**,
|
||||||
|
# 由主板自己的侧键弹片直接压在载板的焊盘上 —— 完全复刻中框的接触方式。
|
||||||
|
# 好处:顶针那个「本体必须 < 1.87 mm」的硬卡点直接消失(现有 POGO-SMD1P_D1.9 的 Ø1.9
|
||||||
|
# 在真实 1.78 mm 最小间距下是负净距,正是那 20 条重叠的来源)。
|
||||||
|
#
|
||||||
|
# 焊盘定径:四点实测最小间距 **1.78 mm**(不是理想菱形的 1.87)⇒
|
||||||
|
# 净距 0.20 -> 最大 Ø1.58 · 净距 0.25 -> Ø1.53 · 净距 0.30 -> Ø1.48
|
||||||
|
# 中框原盘 Ø1.35。取 **Ø1.5**:净距 0.28(好做),容许位置误差 0.50 mm。
|
||||||
|
POGO_PAD_D = 1.5
|
||||||
|
# ⚠️ **位置不确定度 ±0.6 mm 已经吃掉全部余量**(Ø1.5 只容许 0.50)。
|
||||||
|
# 打样前必须把触点位置收到 ±0.3:办法是「**一次装夹**」——
|
||||||
|
# 主板放测量底板上,先戳 7 个孔、再把弹片涂红盖印,孔和触点落进同一套基准圆,一次量完。
|
||||||
|
# ⚠️ **立柱高度 3.0 -> 1.0 mm**:2026-09-06 用户实测中框「螺柱支撑面 到 金焊盘面 = 1 mm」,
|
||||||
|
# 这就是载板面到主板贴合面该有的间隙。原来是 3.0 mm 立柱 + 顶针压缩 0.5,整套作废。
|
||||||
|
# ✅ **不用挖空**:2026-09-06 用户实测「贴合面上元件全都低于 1 mm」(屏蔽罩、SIM 卡座都算过),
|
||||||
|
# 所以载板**保持平板**,1.0 mm 间隙直接成立。曾担心的「挖空会和底层 BAND 那组元件打架」不存在了。
|
||||||
|
# ✅ 排线反而更宽裕(绕边下落 5 -> 3 mm):
|
||||||
|
# 尾插 2.9 + 3 + 2.9 + 1.6 + 34.1 ≈ 44.5 ≤ 50(原 46.5)
|
||||||
|
# 电池 4.6 + 3 + ... ≈ 29.6 ≤ 35(原 31.6)
|
||||||
|
# ⇒ §25.16 那串长度核算只会更松,不用改路径。
|
||||||
|
# ⚠️ **1 mm 立柱不好买**:M1.6 尼龙立柱通常从 3 mm 起。可行做法是
|
||||||
|
# 「螺钉从上穿过手机孔 + 1 mm 尼龙垫片 + 穿过载板 Φ1.8 孔 + 底面尼龙螺母」。垫片可叠。
|
||||||
|
# ⚠️ 顶角那两个 M3 孔(4,131)/(216,131) 的旧注释写着「主板架在 3 mm 立柱上,螺钉头 ≤ 2」——
|
||||||
|
# 现在只剩 1 mm,那两个孔真要补的话螺钉头必须 ≤ 1 或者挪开。(它们本来就没打到板上。)
|
||||||
|
POGO_STANDOFF_H = 1.0
|
||||||
|
|
||||||
|
|
||||||
# ---- 五个手机位:本体左下角 + 旋转(0 = 接口边朝下,180 = 接口边朝上;to_board 里 rot 180 是绕本体中心转,位置矩形不变)----
|
# ---- 五个手机位:本体左下角 + 旋转(0 = 接口边朝下,180 = 接口边朝上;to_board 里 rot 180 是绕本体中心转,位置矩形不变)----
|
||||||
# v3(2026-09-06 用户拍板):穿线槽挪到**主板投影外侧、靠板边**那一条,排线(按 6 cm 算)
|
# v3(2026-09-06 用户拍板):穿线槽挪到**主板投影外侧、靠板边**那一条,排线(按 6 cm 算)
|
||||||
# 跨过主板正面到远端边、下穿、再折回底面。上排下移 / 下排上移各 2.5 mm,让板边那条留出
|
# 跨过主板正面到远端边、下穿、再折回底面。上排下移 / 下排上移各 2.5 mm,让板边那条留出
|
||||||
@@ -132,7 +199,9 @@ SLOTS = {
|
|||||||
# 2026-09-06 v4c(用户拍板):尾插槽挪到**和电池槽同一条线**(接口边外侧 v −4.2~−1.2),排线翻过接口边直接下穿,
|
# 2026-09-06 v4c(用户拍板):尾插槽挪到**和电池槽同一条线**(接口边外侧 v −4.2~−1.2),排线翻过接口边直接下穿,
|
||||||
# 不再从主板反面 3.0 mm 的缝里钻。背面到 J7n 变长 5.6,J7n 从 v 37 收到 **v 35**:
|
# 不再从主板反面 3.0 mm 的缝里钻。背面到 J7n 变长 5.6,J7n 从 v 37 收到 **v 35**:
|
||||||
# 2.86 + 绕边 5 + 到槽心 2.7 + 穿板 1.6 + 背面 37.7 ≈ 49.9 ≤ 50 ✔(实长 55)。
|
# 2.86 + 绕边 5 + 到槽心 2.7 + 穿板 1.6 + 背面 37.7 ≈ 49.9 ≤ 50 ✔(实长 55)。
|
||||||
'tail': (45.0, 65.0, -4.2, -1.2), # 尾插排线:接口边外侧,与电池槽同线,正对 J1401 (u 47.5~59.7)
|
# 2026-09-06 顶角 M3 孔 (4,131):site1 rot 180 下槽的 x = 72.09 − u,u=65 → x 7.09 会压到 Ø6 焊盘(边 7.0)。
|
||||||
|
# 东端 65 → 64(x 8.09,离焊盘 1.09)。排线 18 宽盖 u 44.6~62.6,64 端还余 1.4。
|
||||||
|
'tail': (45.0, 64.0, -4.2, -1.2), # 尾插排线:接口边外侧,与电池槽同线,正对 J1401 (u 47.5~59.7)
|
||||||
}
|
}
|
||||||
# 排线在背面占的车道(本体坐标)。**车道里不放任何元件**(排线要平贴着走到插头 / 焊盘,0402 也别放):
|
# 排线在背面占的车道(本体坐标)。**车道里不放任何元件**(排线要平贴着走到插头 / 焊盘,0402 也别放):
|
||||||
# 尾插排线 u 44.6~62.6,v 4.4 ~ J7n 北沿(EDL 组 / VBUS 组因此整体西移到 u ≤ 44);
|
# 尾插排线 u 44.6~62.6,v 4.4 ~ J7n 北沿(EDL 组 / VBUS 组因此整体西移到 u ≤ 44);
|
||||||
@@ -195,6 +264,19 @@ BAND = {
|
|||||||
'r76': (52.233, 38.0, 0), # R76n 56k CC1→VBUS,pin1 (51.800) = J7n.22 正北
|
'r76': (52.233, 38.0, 0), # R76n 56k CC1→VBUS,pin1 (51.800) = J7n.22 正北
|
||||||
'r77': (54.8, 38.0, 0), # R77n 100k,pin1 (54.367) 收 THERM
|
'r77': (54.8, 38.0, 0), # R77n 100k,pin1 (54.367) 收 THERM
|
||||||
'j6': (62.5, 41.0, 0), # J6n EDL 1.25mm 2P,J7n 东北、H1 keep-out 东侧;EDL 飞线随尾插排线穿槽走背面 ~40 mm
|
'j6': (62.5, 41.0, 0), # J6n EDL 1.25mm 2P,J7n 东北、H1 keep-out 东侧;EDL 飞线随尾插排线穿槽走背面 ~40 mm
|
||||||
|
# ── 按键 MOS 三列(2026-09-06 随 74HC595 从下板搬来,§26.23):顶针(顶层,u 2.1~5.4 / v 2.5~7)背面那片空地。
|
||||||
|
# 列距 3.5;SOT-23 框 ±1.5×±1.27,0402 框 ±0.72×±0.27(竖放 ±0.27×±0.72)。
|
||||||
|
# 东沿 15.5+1.5 = 17.0 < 电池排线车道 18.8;离 H6 (4,10.8) 最近的是 R%21 (8.5,10):4.6 > 2.8;
|
||||||
|
# 漏极→顶针焊盘要换层(顶针是顶层单面焊盘),过孔由布线器自己打。
|
||||||
|
'q3': (8.5, 4.0, 0), # Q%03 PWR
|
||||||
|
'q4': (12.0, 4.0, 0), # Q%04 VUP
|
||||||
|
'q5': (15.5, 4.0, 0), # Q%05 VDN
|
||||||
|
'r20': (8.5, 7.5, 90), # R%20 1k 栅阻
|
||||||
|
'r22': (12.0, 7.5, 90),
|
||||||
|
'r24': (15.5, 7.5, 90),
|
||||||
|
'r21': (8.5, 10.0, 90), # R%21 100k 栅极下拉
|
||||||
|
'r23': (12.0, 10.0, 90),
|
||||||
|
'r25': (15.5, 10.0, 90),
|
||||||
}
|
}
|
||||||
# SMD 罐体 keep-out(相对元件原点):10.3 见方 + 单边 0.25
|
# SMD 罐体 keep-out(相对元件原点):10.3 见方 + 单边 0.25
|
||||||
CAN_BODY = (-5.4, -5.4, 5.4, 5.4)
|
CAN_BODY = (-5.4, -5.4, 5.4, 5.4)
|
||||||
@@ -211,6 +293,9 @@ def desig(n):
|
|||||||
'j7': 'J7%d' % n, 'u5': 'U5%d' % n, 'r76': 'R76%d' % n, 'r77': 'R77%d' % n,
|
'j7': 'J7%d' % n, 'u5': 'U5%d' % n, 'r76': 'R76%d' % n, 'r77': 'R77%d' % n,
|
||||||
'u2': 'U%d' % (23 + n), 'c70': 'C70%d' % n, 'c71': 'C71%d' % n,
|
'u2': 'U%d' % (23 + n), 'c70': 'C70%d' % n, 'c71': 'C71%d' % n,
|
||||||
'c72': 'C72%d' % n, 'r70': 'R70%d' % n,
|
'c72': 'C72%d' % n, 'r70': 'R70%d' % n,
|
||||||
|
'q3': 'Q%d03' % n, 'q4': 'Q%d04' % n, 'q5': 'Q%d05' % n,
|
||||||
|
'r20': 'R%d20' % n, 'r21': 'R%d21' % n, 'r22': 'R%d22' % n,
|
||||||
|
'r23': 'R%d23' % n, 'r24': 'R%d24' % n, 'r25': 'R%d25' % n,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -246,7 +331,23 @@ GLOBAL = {
|
|||||||
# v3 布线:U31 组挪到 J31 东端**南**侧(走廊北带 y 70~80 留给差分对上顶层北上)
|
# v3 布线:U31 组挪到 J31 东端**南**侧(走廊北带 y 70~80 留给差分对上顶层北上)
|
||||||
'U31': (87.5, 60.5, 0), # 底边 57.65 让开 CH4 电池槽(y ≤ 56.36 + 0.5);USB1 车道改走 y 64.0/64.46
|
'U31': (87.5, 60.5, 0), # 底边 57.65 让开 CH4 电池槽(y ≤ 56.36 + 0.5);USB1 车道改走 y 64.0/64.46
|
||||||
'C736': (80.5, 58.5, 0), # +5V 输入 0805(U31 西侧)
|
'C736': (80.5, 58.5, 0), # +5V 输入 0805(U31 西侧)
|
||||||
'C737': (93.0, 54.0, 0), # +3V3 输出 1206,Hub 晶振窝西南、CH4 电池槽东侧
|
# ── 2026-09-07:U32 的 PRT_SWP1~5 五个 strap 脚的 100k 下拉(R900~R904,见 §21.6a)──
|
||||||
|
# BOOST/GANG_EN/SWP6-7 那五颗用户拍板不装(采到 1 也无功能后果)。
|
||||||
|
# ⚠️ 第一版把十颗全摆在 U32 北边 y=79 那一排(那一片唯一的整块空地),
|
||||||
|
# `pcb2_route_sig` **10 条只布通 3 条** —— 南边(49/50/51)、西边(15/17)、东南(47/48)
|
||||||
|
# 那七个脚要绕过整颗 QFN 和一圈去耦,绕不出去。改成**每颗贴着自己的引脚**。
|
||||||
|
# 坐标是 `pcb2_strap_place.py` 按布线器的障碍表搜出来的(以引脚为心一圈圈往外找,
|
||||||
|
# 判据:两个焊盘离异网铜 >= 0.20 且不落进任何已有元件的本体投影)。改摆位请重跑它。
|
||||||
|
'R904': (103.458, 73.632, 0), # U32.31 PRT_SWP5,离脚 1.2 mm
|
||||||
|
'R903': (105.632, 71.958, 90), # U32.33 PRT_SWP4,离脚 1.2 mm
|
||||||
|
'R902': (106.635, 62.145, 0), # U32.47 PRT_SWP3,离脚 3.4 mm
|
||||||
|
'R901': (103.021, 59.414, 0), # U32.49 PRT_SWP2,离脚 4.2 mm
|
||||||
|
'R900': (102.750, 58.550, 0), # U32.51 PRT_SWP1,离脚 5.0 mm
|
||||||
|
# 2026-09-07:C737 由 1206 陶瓷换成 KEMET T491A226K010AT 固态钽(AMS1117 手册 §Stability
|
||||||
|
# 要求的 22uF 固态钽)。钽是极性件且 1 脚 = 正极,而板上 +3V3_HUB 的铜在东、GND 在西,
|
||||||
|
# 所以必须 rot 180;再东移 0.17 mm,让 1 脚(+3V3_HUB)西沿离那颗 GND 过孔 0.265 mm。
|
||||||
|
# 改这两个数之前先读 §26.25:0.17 是算出来的净距,不是随手摆的。
|
||||||
|
'C737': (93.17, 54.0, 180), # +3V3 输出,CASE-A_3216 固态钽
|
||||||
# LM75BD 测温 + 100nF(SCL/SDA 在 J31.21/23 = x 63.3/65.8,北排;走线从排母针缝里穿到南边)
|
# LM75BD 测温 + 100nF(SCL/SDA 在 J31.21/23 = x 63.3/65.8,北排;走线从排母针缝里穿到南边)
|
||||||
# v2 第二版:挪到 J31 **南**边(走廊北带 y 70~76 要留给差分高速路)。CH4 行 B 只剩 U54(48.3)/R764/R774,这里是空的。
|
# v2 第二版:挪到 J31 **南**边(走廊北带 y 70~76 要留给差分高速路)。CH4 行 B 只剩 U54(48.3)/R764/R774,这里是空的。
|
||||||
# v3 布线:J31 **南**边(USB1 那对在底层 y 62.9/63.6 从排母南边一路西行,U34 顶边 62.2)
|
# v3 布线:J31 **南**边(USB1 那对在底层 y 62.9/63.6 从排母南边一路西行,U34 顶边 62.2)
|
||||||
@@ -255,6 +356,30 @@ GLOBAL = {
|
|||||||
# 上游 VBUS 分压 -> UP_VBUS_DET -> J31 pin36 (81.049, 65.100),跟着高阻端走
|
# 上游 VBUS 分压 -> UP_VBUS_DET -> J31 pin36 (81.049, 65.100),跟着高阻端走
|
||||||
'R721': (80.0, 61.5, 180), # pin1 = VBUS_UP(v3:让开 U31 与 USB1 车道)
|
'R721': (80.0, 61.5, 180), # pin1 = VBUS_UP(v3:让开 U31 与 USB1 车道)
|
||||||
'R722': (78.0, 61.5, 180), # pin1 = UP_VBUS_DET, pin2 = GND
|
'R722': (78.0, 61.5, 180), # pin1 = UP_VBUS_DET, pin2 = GND
|
||||||
|
# ── 三片 74HC595(2026-09-06 从下板搬来,§26.23)。SOIC-16 框 9.5 × 7.44(rot 90 后 7.44 宽 × 9.5 高)。
|
||||||
|
# 走廊中段 x 113~132 里能用的其实只有 **y 60.8~75.26 那条带**:UP_DP/UP_DM(底层 y 60.1/60.6)从 x 99 一路横穿到 205,
|
||||||
|
# 下面 y 52.5/53.0 是 USB5,上面 y 75.4/77.0 是 USB3(第一版只查了端点落在框里的线,把 UP 这对漏了,
|
||||||
|
# U21 rot 0 摆在 y 58.5 直接压在 UP 上;再上一版 rot 90 面对面缝 1.56,16 个脚的出线口互相堵死)。
|
||||||
|
# U21 (117,66.5) / U22 (128,66.5) rot 90:x 113.28~120.72 / 124.28~131.72(缝 3.56,出线段各 1.3 还剩 1 mm),
|
||||||
|
# y 61.75~71.25:离 UP_DM 线边 60.74 有 1.0,离 USB3_DP 线边 75.26 有 4.0;离 USB5 竖段 111.44 有 1.84、离 J32 焊盘边 133.0 有 1.28。
|
||||||
|
# U33 单独放 **J32 东侧**(x 183~208 / y 52~86 只有 UP 那对在 y 60.1/60.6 横穿):(193.5,68.5) rot 90 → y 63.75~73.25,离 UP_DM 3.0。
|
||||||
|
# 四根控制线从 J32 北排 3~6 行(x 138.95~146.57)进来,正好夹在两处中间。
|
||||||
|
# 2026-09-07 第三十轮:rot 90 的两片各 8 个西排脚全从 x 113~114 / 124 那两条竖缝出线,8 个网络布不通
|
||||||
|
# (EDL_EN2/3/5、K5_VDN 等,§26.23 落地末尾)。改成 **rot 0 / 180:引脚排朝南北**,16 根脚沿 9 mm 宽的边出线:
|
||||||
|
# 北带 y 70.23~75.26(5 mm,C604/R609/C605 在 y 73)、南带 y 60.74~62.77(2 mm,够打一排换层孔到顶层)。
|
||||||
|
# 底层 rot 0:脚 1~8(K/EDL 输出)在**北**排、9~16(控制/+3V3)在南排;rot 180 反过来。
|
||||||
|
# U21 rot 0:K1 去 site1(西北)、EDL_EN2/3 去 site2/3(北),输出朝北顺路;控制脚南排沿 y≈63 东行去 J32。
|
||||||
|
# U22 rot 180:K4/K5 去 site4/5(南),输出朝南,从南带换层到顶层跨过 UP 差分;控制脚北排。
|
||||||
|
# U21 (116.5,66.5):焊盘 x 111.56~121.44,离 USB5 竖段线边 111.4 有 0.5(≥0.2);
|
||||||
|
# U22 (127.5,66.5):焊盘 x 122.56~132.44,离 J32.1 盘边 ~133.1 有 0.6;两片焊盘之间 1.1。
|
||||||
|
'U21': (116.5, 66.5, 0),
|
||||||
|
'U22': (127.5, 66.5, 180),
|
||||||
|
'U33': (193.5, 68.5, 90),
|
||||||
|
# 去耦 / OE# 上拉都放两片北边那条带(y 72.73~73.27,离芯片上沿 71.25 有 1.5、离 USB3_DP 有 2.0)
|
||||||
|
'C604': (117.0, 73.0, 0),
|
||||||
|
'C605': (128.0, 73.0, 0),
|
||||||
|
'R609': (122.5, 73.0, 0),
|
||||||
|
'C739': (199.5, 68.5, 90),
|
||||||
}
|
}
|
||||||
HDR = {'J31': (62.0, 67.5, 0), 'J32': (158.0, 67.5, 0)}
|
HDR = {'J31': (62.0, 67.5, 0), 'J32': (158.0, 67.5, 0)}
|
||||||
HUB_CENTER = (100.0, 68.0) # v1 是 (110, 67):西移 10 让开 CH2 行 A / CH5 行 B,北移 1 让 C741 离开 CH4 电池槽
|
HUB_CENTER = (100.0, 68.0) # v1 是 (110, 67):西移 10 让开 CH2 行 A / CH5 行 B,北移 1 让 C741 离开 CH4 电池槽
|
||||||
@@ -416,9 +541,20 @@ def check(pos):
|
|||||||
errs.append(u'越框: %s @ (%.1f, %.1f)' % (d, pos[d][0], pos[d][1]))
|
errs.append(u'越框: %s @ (%.1f, %.1f)' % (d, pos[d][0], pos[d][1]))
|
||||||
|
|
||||||
# 同层重叠
|
# 同层重叠
|
||||||
|
# 侧键触点盘(J41~J60)是 Ø1.5 的圆盘、盘心距最小 1.78 ⇒ 净距 0.28。
|
||||||
|
# 包围盒判会把菱形里相邻的两个盘报成重叠(dx 1.30 < 1.50),所以这一组按**圆**判:
|
||||||
|
# 盘心距 >= POGO_PAD_D + 0.20(DRC 净距)。
|
||||||
|
pogo = set()
|
||||||
|
for n in SITES:
|
||||||
|
pogo |= set(desig(n)['pogo'])
|
||||||
for i in range(len(items)):
|
for i in range(len(items)):
|
||||||
for j in range(i + 1, len(items)):
|
for j in range(i + 1, len(items)):
|
||||||
a, b_ = items[i], items[j]
|
a, b_ = items[i], items[j]
|
||||||
|
if a in pogo and b_ in pogo:
|
||||||
|
dd = math.hypot(pos[a][0] - pos[b_][0], pos[a][1] - pos[b_][1])
|
||||||
|
if dd < POGO_PAD_D + 0.20:
|
||||||
|
errs.append(u'触点盘太近: %s x %s 盘心距 %.2f(要 >= %.2f)' % (a, b_, dd, POGO_PAD_D + 0.20))
|
||||||
|
continue
|
||||||
shared = set(layers(a, pos[a][3])) & set(layers(b_, pos[b_][3]))
|
shared = set(layers(a, pos[a][3])) & set(layers(b_, pos[b_][3]))
|
||||||
for L in sorted(shared):
|
for L in sorted(shared):
|
||||||
if _overlap(abs_box(a, L), abs_box(b_, L)):
|
if _overlap(abs_box(a, L), abs_box(b_, L)):
|
||||||
@@ -474,6 +610,8 @@ def check(pos):
|
|||||||
b = abs_box(d, 2)
|
b = abs_box(d, 2)
|
||||||
for n in SITES:
|
for n in SITES:
|
||||||
for hn, (u_, v_) in HOLES.items():
|
for hn, (u_, v_) in HOLES.items():
|
||||||
|
if hn in SKIP_HOLES:
|
||||||
|
continue
|
||||||
hx, hy, _ = to_board(n, u_, v_)
|
hx, hy, _ = to_board(n, u_, v_)
|
||||||
dd = _dist_box_pt(b, hx, hy)
|
dd = _dist_box_pt(b, hx, hy)
|
||||||
if dd < HOLE_KEEP:
|
if dd < HOLE_KEEP:
|
||||||
@@ -641,11 +779,13 @@ return k;
|
|||||||
|
|
||||||
|
|
||||||
def mech_items():
|
def mech_items():
|
||||||
u"""35 个手机定位孔(NPTH)+ 5 个手机位的丝印外框与标签。"""
|
u"""手机定位孔(NPTH,7 孔模型减去 SKIP_HOLES ⇒ 30 个)+ 5 个手机位的丝印外框与标签。"""
|
||||||
holes, lines, texts = [], [], []
|
holes, lines, texts = [], [], []
|
||||||
for n in SITES:
|
for n in SITES:
|
||||||
x0, y0, rho = SITES[n]
|
x0, y0, rho = SITES[n]
|
||||||
for hn, (u, v) in HOLES.items():
|
for hn, (u, v) in HOLES.items():
|
||||||
|
if hn in SKIP_HOLES: # 2026-09-07:H5 不打(push_mech 会先删掉板上全部 P*H* 再建)
|
||||||
|
continue
|
||||||
x, y, _ = to_board(n, u, v)
|
x, y, _ = to_board(n, u, v)
|
||||||
holes.append(['P%d%s' % (n, hn), round(x * MIL, 2), round(y * MIL, 2)])
|
holes.append(['P%d%s' % (n, hn), round(x * MIL, 2), round(y * MIL, 2)])
|
||||||
c = [(x0, y0), (x0 + PW, y0), (x0 + PW, y0 + PH), (x0, y0 + PH)]
|
c = [(x0, y0), (x0 + PW, y0), (x0 + PW, y0 + PH), (x0, y0 + PH)]
|
||||||
@@ -791,6 +931,7 @@ return out;
|
|||||||
HEIGHT = {
|
HEIGHT = {
|
||||||
'J31': 8.5, 'J32': 8.5, # 直插排母本体(C5307344)
|
'J31': 8.5, 'J32': 8.5, # 直插排母本体(C5307344)
|
||||||
'J23': 3.2, 'U31': 1.8, 'U32': 0.9, 'Y1': 1.2, 'U34': 1.6,
|
'J23': 3.2, 'U31': 1.8, 'U32': 0.9, 'Y1': 1.2, 'U34': 1.6,
|
||||||
|
'C737': 1.8, # KEMET A 壳 EIA-3216-18,最大高 1.8(不是 1206 的 1.7)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
@@ -850,8 +991,15 @@ if __name__ == '__main__':
|
|||||||
print(' ', e)
|
print(' ', e)
|
||||||
if len(errs) > 40:
|
if len(errs) > 40:
|
||||||
print(u' ...还有 %d 条' % (len(errs) - 40))
|
print(u' ...还有 %d 条' % (len(errs) - 40))
|
||||||
sys.exit(1)
|
# --force:只下发 --mech / --outline(孔、槽、丝印)时,元件级的报错不该挡路 ——
|
||||||
print(u'本地检查通过:无重叠、无越框、没人压槽、顶层只有顶针、底层件避开了螺钉头')
|
# 那些是「元件 vs 孔」「元件 vs 元件」,和要写的机械图元本身无关。
|
||||||
|
# ⚠️ 但 --push(重摆元件)绝不允许 force,摆错了会连着布线一起烂。
|
||||||
|
if '--force' in sys.argv and '--push' not in sys.argv:
|
||||||
|
print(u'--force:以上按警告处理,继续下发机械图元(元件没动)')
|
||||||
|
else:
|
||||||
|
sys.exit(1)
|
||||||
|
else:
|
||||||
|
print(u'本地检查通过:无重叠、无越框、没人压槽、顶层只有顶针、底层件避开了螺钉头')
|
||||||
if '--layers' in sys.argv:
|
if '--layers' in sys.argv:
|
||||||
push_layers()
|
push_layers()
|
||||||
if '--clean-copper' in sys.argv:
|
if '--clean-copper' in sys.argv:
|
||||||
|
|||||||
@@ -108,7 +108,7 @@ HERE = os.path.dirname(os.path.abspath(__file__))
|
|||||||
sys.path.insert(0, HERE)
|
sys.path.insert(0, HERE)
|
||||||
from eda import run
|
from eda import run
|
||||||
|
|
||||||
PCB = 'f126ffb29c92f9b2' # PCB2-CARRIER
|
PCB = '942ed1560d81c1e7' # PCB2-CARRIER
|
||||||
MIL = 39.3700787401575
|
MIL = 39.3700787401575
|
||||||
|
|
||||||
L_TOP, L_PWR, L_GND, L_BOT = 1, 15, 16, 2 # ⚠ 载板:Inner1=电源 / Inner2=地
|
L_TOP, L_PWR, L_GND, L_BOT = 1, 15, 16, 2 # ⚠ 载板:Inner1=电源 / Inner2=地
|
||||||
@@ -441,7 +441,9 @@ def main():
|
|||||||
r = call(JS_REBUILD)
|
r = call(JS_REBUILD)
|
||||||
if r.get('err'):
|
if r.get('err'):
|
||||||
sys.exit(u'!! 打不开铺铜管理器: ' + r['err'])
|
sys.exit(u'!! 打不开铺铜管理器: ' + r['err'])
|
||||||
for i in range(60):
|
# 2026-09-07:正常一次填充 7 块 < 30 s;卡在 0/7 超过 ~90 s 就是客户端卡住了(§9k),
|
||||||
|
# 再等到 4 分钟也不会好,早点退出去重载。
|
||||||
|
for i in range(22):
|
||||||
time.sleep(4)
|
time.sleep(4)
|
||||||
n = call(JS_POLL, timeout=40)['poured']
|
n = call(JS_POLL, timeout=40)['poured']
|
||||||
print(u' 填充 %d / %d' % (n, len(ps)))
|
print(u' 填充 %d / %d' % (n, len(ps)))
|
||||||
|
|||||||
@@ -10,7 +10,7 @@ const nat = b => { const o={bubbles:true,cancelable:true,view:window,button:0};
|
|||||||
b.dispatchEvent(new (t.startsWith('pointer')?PointerEvent:MouseEvent)(t,o)); };
|
b.dispatchEvent(new (t.startsWith('pointer')?PointerEvent:MouseEvent)(t,o)); };
|
||||||
for (const b of document.querySelectorAll('button'))
|
for (const b of document.querySelectorAll('button'))
|
||||||
if ((b.innerText||'').trim()==='取消' && b.offsetParent!==null) { nat(b); await sleep(800); }
|
if ((b.innerText||'').trim()==='取消' && b.offsetParent!==null) { nat(b); await sleep(800); }
|
||||||
await eda.dmt_EditorControl.openDocument('f126ffb29c92f9b2');
|
await eda.dmt_EditorControl.openDocument('942ed1560d81c1e7');
|
||||||
await sleep(1200);
|
await sleep(1200);
|
||||||
let n = 0;
|
let n = 0;
|
||||||
for (const o of await eda.pcb_PrimitivePour.getAll()) { await eda.pcb_PrimitivePour.delete(o.primitiveId); n++; }
|
for (const o of await eda.pcb_PrimitivePour.getAll()) { await eda.pcb_PrimitivePour.delete(o.primitiveId); n++; }
|
||||||
@@ -29,9 +29,48 @@ def wid():
|
|||||||
w0 = wid()
|
w0 = wid()
|
||||||
r = run(JS, timeout=60)
|
r = run(JS, timeout=60)
|
||||||
print(u'重载前 windowId %s,删铺铜边框 %s' % (w0, (r.get('result') or {}).get('deletedPours')))
|
print(u'重载前 windowId %s,删铺铜边框 %s' % (w0, (r.get('result') or {}).get('deletedPours')))
|
||||||
|
COUNT_JS = u"""
|
||||||
|
await eda.dmt_EditorControl.openDocument('942ed1560d81c1e7');
|
||||||
|
await new Promise(r => setTimeout(r, 9000));
|
||||||
|
let nc=0, nl=0, nv=0, npad=0;
|
||||||
|
for (const c of await eda.pcb_PrimitiveComponent.getAll()) nc++;
|
||||||
|
for (const l of await eda.pcb_PrimitiveLine.getAll()) nl++;
|
||||||
|
for (const v of await eda.pcb_PrimitiveVia.getAll()) nv++;
|
||||||
|
for (const p of await eda.pcb_PrimitivePad.getAll()) npad++;
|
||||||
|
return {doc: (await eda.dmt_Pcb.getCurrentPcbInfo() || {}).name, nc, nl, nv, npad};
|
||||||
|
"""
|
||||||
|
|
||||||
|
|
||||||
|
def assert_alive():
|
||||||
|
u"""⚠⚠ 重载之后**必须**先数一遍图元,确认桥接和文档真的接上了再往下走。
|
||||||
|
|
||||||
|
2026-09-07 就是漏了这一步把载板弄丢的:重载回来后铜层读回全 0
|
||||||
|
(skill §9ae 那个陈旧上下文),而紧接着跑的 `pcb2_pour.py --push`
|
||||||
|
又在那个状态下调了一次 `save()` —— 把“空”写回了文档,
|
||||||
|
301 件的下板没事、223 件的载板只剩下丝印和板框,只能走工程历史恢复。
|
||||||
|
|
||||||
|
“重载成功”的判据不是 windowId 变了,是**图元数不为零**。
|
||||||
|
不过关、绝不允许后面任何一步 save()。
|
||||||
|
"""
|
||||||
|
r = run(COUNT_JS, timeout=120)
|
||||||
|
if not r.get('success'):
|
||||||
|
sys.exit(u'!! 重载后数图元失败,**不要再跑任何会 save() 的脚本**: %s'
|
||||||
|
% json.dumps(r, ensure_ascii=False)[:400])
|
||||||
|
d = r['result']
|
||||||
|
print(u'重载后回查:%s 元件 %s / 导线 %s / 过孔 %s / 焊盘 %s'
|
||||||
|
% (d.get('doc'), d.get('nc'), d.get('nl'), d.get('nv'), d.get('npad')))
|
||||||
|
if not d.get('nc') or not d.get('nl') or not d.get('npad'):
|
||||||
|
sys.exit(u'!! 铜层读回 0 —— 桥接与文档失同步(skill §9ae)。\n'
|
||||||
|
u' **立刻停手,不要 save(),不要跑 pcb2_pour.py** —— 那一步会把空写回去。\n'
|
||||||
|
u' 先 API Gateway → 重新连接,不行就重启客户端,再跑一次本脚本确认数字回来了。')
|
||||||
|
|
||||||
|
|
||||||
for i in range(30):
|
for i in range(30):
|
||||||
time.sleep(5)
|
time.sleep(5)
|
||||||
w = wid()
|
w = wid()
|
||||||
if w and w != w0:
|
if w and w != w0:
|
||||||
print(u'已重载,新 windowId %s(%d s)' % (w, (i + 1) * 5)); time.sleep(10); sys.exit(0)
|
print(u'已重载,新 windowId %s(%d s)' % (w, (i + 1) * 5))
|
||||||
|
time.sleep(10)
|
||||||
|
assert_alive()
|
||||||
|
sys.exit(0)
|
||||||
sys.exit(u'!! 150 s 内 windowId 没变,重载没成功')
|
sys.exit(u'!! 150 s 内 windowId 没变,重载没成功')
|
||||||
|
|||||||
@@ -40,7 +40,7 @@ HERE = os.path.dirname(os.path.abspath(__file__))
|
|||||||
sys.path.insert(0, HERE)
|
sys.path.insert(0, HERE)
|
||||||
from eda import run
|
from eda import run
|
||||||
|
|
||||||
PCB = 'f126ffb29c92f9b2'
|
PCB = '942ed1560d81c1e7'
|
||||||
SNAP = os.path.join(HERE, '_pcb2_snap_prerouting.json')
|
SNAP = os.path.join(HERE, '_pcb2_snap_prerouting.json')
|
||||||
|
|
||||||
# 11 对差分 = 22 个网络(和 pcb2_rules.PAIRS 同源,这里独立列一遍并断言一致)
|
# 11 对差分 = 22 个网络(和 pcb2_rules.PAIRS 同源,这里独立列一遍并断言一致)
|
||||||
|
|||||||
@@ -46,7 +46,7 @@ from eda import run
|
|||||||
from pcb2_clear import half, deg
|
from pcb2_clear import half, deg
|
||||||
from pcb2_place import SITES, to_board
|
from pcb2_place import SITES, to_board
|
||||||
|
|
||||||
PCB = 'f126ffb29c92f9b2'
|
PCB = '942ed1560d81c1e7'
|
||||||
MIL = 39.3700787401575
|
MIL = 39.3700787401575
|
||||||
GEOM = os.path.join(HERE, '_pcb2_route_geom.json')
|
GEOM = os.path.join(HERE, '_pcb2_route_geom.json')
|
||||||
|
|
||||||
@@ -73,10 +73,15 @@ PAIR_OF['UP_DP'] = 'UP_DM'
|
|||||||
PAIR_OF['UP_DM'] = 'UP_DP'
|
PAIR_OF['UP_DM'] = 'UP_DP'
|
||||||
|
|
||||||
|
|
||||||
|
KSEP = chr(0)
|
||||||
|
|
||||||
|
|
||||||
def netof(key):
|
def netof(key):
|
||||||
u"""路径的 key -> 网络名。`NET#2` 这样的后缀表示**同一个网络的第二条支路**
|
u"""路径的 key -> 网络名。`NET#2` 这样的后缀表示**同一个网络的第二条支路**
|
||||||
(J23 的 A6↔B6 / A7↔B7 短接线就是这么加的),下发时按 `NET` 建线。"""
|
(J23 的 A6↔B6 / A7↔B7 短接线就是这么加的),下发时按 `NET` 建线。"""
|
||||||
return key.split('#')[0]
|
# ⚠️ 分隔符不能用 '#':载板上有 `KEY_OE#`(2026-09-06 595 上载板之后),按 '#' 拆会把它拆成
|
||||||
|
# `KEY_OE`,校核时和自己的焊盘当成异网(下板 §26.19 踩过同一条)。用 chr(0)。
|
||||||
|
return key.split(KSEP)[0]
|
||||||
|
|
||||||
|
|
||||||
# ── 站内坐标(u, v):J7n ↔ U5n 的短差分(v5:全部**底层**,接口边朝板边)────────
|
# ── 站内坐标(u, v):J7n ↔ U5n 的短差分(v5:全部**底层**,接口边朝板边)────────
|
||||||
@@ -165,6 +170,13 @@ def geom():
|
|||||||
lines = [{'id': i, 'net': n or '', 'lay': l, 'x0': a / MIL, 'y0': b / MIL,
|
lines = [{'id': i, 'net': n or '', 'lay': l, 'x0': a / MIL, 'y0': b / MIL,
|
||||||
'x1': c / MIL, 'y1': e / MIL, 'w': w / MIL}
|
'x1': c / MIL, 'y1': e / MIL, 'w': w / MIL}
|
||||||
for i, n, l, a, b, c, e, w in d['lines']]
|
for i, n, l, a, b, c, e, w in d['lines']]
|
||||||
|
# 2026-09-07:封装自带的非金属化孔(J23 里两个 Ø0.60,`pcb2_npth.py --write` 产出)当成无网络的通孔盘,
|
||||||
|
# 两个布线器就都会躲开(原来只有 pcb2_vo_vias 读它,`$16N224` 的过孔直接打在孔上,DRC「挖槽区域到过孔 0mil」)。
|
||||||
|
npth = os.path.join(HERE, '_pcb2_npth.json')
|
||||||
|
if os.path.exists(npth):
|
||||||
|
for cx, cy, r in json.load(open(npth, encoding='utf-8')):
|
||||||
|
pads.append({'ref': 'NPTH', 'num': '', 'net': '', 'lay': 12,
|
||||||
|
'x': cx, 'y': cy, 'hw': r, 'hh': r})
|
||||||
return pads, vias, lines
|
return pads, vias, lines
|
||||||
|
|
||||||
|
|
||||||
|
|||||||
@@ -4,6 +4,7 @@ u"""载板电源 + 杂散信号布线:**栅格迷宫布线器**(`pcb2_route_
|
|||||||
/c/Python314/python .claude/pcb2_route_sig.py # 全部算 + 本地校核,不下发
|
/c/Python314/python .claude/pcb2_route_sig.py # 全部算 + 本地校核,不下发
|
||||||
/c/Python314/python .claude/pcb2_route_sig.py --net +5V # 只算这几个网络(可多个)
|
/c/Python314/python .claude/pcb2_route_sig.py --net +5V # 只算这几个网络(可多个)
|
||||||
/c/Python314/python .claude/pcb2_route_sig.py --push # 下发(只删本脚本负责的网络)
|
/c/Python314/python .claude/pcb2_route_sig.py --push # 下发(只删本脚本负责的网络)
|
||||||
|
/c/Python314/python .claude/pcb2_route_sig.py --refresh ... # 先 pcb2_route_dp.dump() 刷障碍表再算(**每次 --push 之后板子就变了,下一次 --net 必须带**)
|
||||||
/c/Python314/python .claude/pcb2_route_sig.py --plot out.png # 画一张自己算的图
|
/c/Python314/python .claude/pcb2_route_sig.py --plot out.png # 画一张自己算的图
|
||||||
|
|
||||||
## 为什么这里用布线器,差分对却是手写坐标
|
## 为什么这里用布线器,差分对却是手写坐标
|
||||||
@@ -43,9 +44,9 @@ from scipy import ndimage
|
|||||||
|
|
||||||
HERE = os.path.dirname(os.path.abspath(__file__))
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
sys.path.insert(0, HERE)
|
sys.path.insert(0, HERE)
|
||||||
from pcb2_route_dp import (geom, check, expand, netof, push, MIL, PCB,
|
from pcb2_route_dp import (geom, check, expand, netof, push, MIL, PCB, KSEP,
|
||||||
L_TOP, L_BOT, CLR, VIA_D, VIA_H, seg_rect, seg_pt, seg_seg,
|
L_TOP, L_BOT, CLR, VIA_D, VIA_H, seg_rect, seg_pt, seg_seg,
|
||||||
chamfer_routes, sharp_corners)
|
chamfer_routes, sharp_corners, turn_deg, SHARP, CHAMFER_R, seg_slack)
|
||||||
from pcb2_place import SITES, to_board, BW, BH, PW, PH
|
from pcb2_place import SITES, to_board, BW, BH, PW, PH
|
||||||
|
|
||||||
GRID = 0.1 # 栅格步长 mm
|
GRID = 0.1 # 栅格步长 mm
|
||||||
@@ -55,10 +56,32 @@ CORNER_R = 5.0
|
|||||||
VIA_R = VIA_D / 2.0
|
VIA_R = VIA_D / 2.0
|
||||||
HOLE_CLR = 0.30 # 钻孔到钻孔(规则 otherClearance.hole2Hole),**不分网络**
|
HOLE_CLR = 0.30 # 钻孔到钻孔(规则 otherClearance.hole2Hole),**不分网络**
|
||||||
VIA_COST = 2.5 # 换一次层折算成多少 mm 路程(压住"没事就打孔")
|
VIA_COST = 2.5 # 换一次层折算成多少 mm 路程(压住"没事就打孔")
|
||||||
|
# 2026-09-07 用户定的布线规则:**顶层走水平、底层走纵向**(经典 H/V 分层)。
|
||||||
|
# 做成**软代价**而不是硬禁止:逆向走法每 mm 按 DIR_PENALTY 倍计价,45° 斜段按中间值计。
|
||||||
|
# 硬禁止会让出线段 / 1~2 mm 的短跳全布不通(焊盘出线方向由封装决定,不由层决定)。
|
||||||
|
# 取 2.0:一段 5 mm 的逆向直线代价 10 mm,正好等于「打两个孔翻到顺向层再走 5 mm」(2×2.5+5),
|
||||||
|
# 所以 >5 mm 的逆向走线会被自动翻层,<5 mm 的短跳留在原层 —— 这就是想要的分界。
|
||||||
|
# ⚠️ pcb1_route_sig.py 复用本引擎的 route_grid,下板同样生效。
|
||||||
|
DIR_PREF = {L_TOP: 'H', L_BOT: 'V'}
|
||||||
|
DIR_PENALTY = 2.0
|
||||||
|
# 斜步:第一版取 (1+DIR_PENALTY)/2 = 1.5(按分量计价的「一致」值),实测 15 根 POGO 顶层斜段 73 mm、
|
||||||
|
# 水平 31 mm —— 45° 斜走等于同时吃到横竖两个分量,比「先横后竖」便宜,规则形同虚设。
|
||||||
|
# 改成 DIAG_K = DIR_PENALTY × 1.2:斜走 1 mm 的代价 (2.4×√2 = 3.4) 略高于横 1 + 竖 2 = 3,
|
||||||
|
# 长斜段被拆成横竖(polish 再并成 L 形),只剩出线口和 45° 倒角那种短斜段。
|
||||||
|
DIAG_K = DIR_PENALTY * 1.2
|
||||||
|
# 过孔禁区 (x0, y0, x1, y1) mm。2026-09-07:`VBUS_EN2` 的过孔 (87.1, 70.2) 压在 Inner1 `VO2_P` 岛的颈
|
||||||
|
# (`pcb2_pour.ISLANDS` 的 VO2 第一块矩形 x 80~87.3,是这块岛去 J31 的唯一通道)东沿上,
|
||||||
|
# 反焊盘把颈从 7.3 掐到 6.30(要 ≥ 7.0,4 A / ΔT 20 °C)。外层布线器不知道内层有岛,只能显式禁掉。
|
||||||
|
# 范围比矩形各放 0.5(反焊盘半径 0.305 + 净距 0.2)。别的岛的颈目前 ≥ 7.2,没列。
|
||||||
|
# 2026-09-07 第三十轮:VO2 的第二块矩形(Hub 北边横带 x 87~100.5 / y 75.5~83,高 7.5)也要禁:
|
||||||
|
# K1_PWR (97.6,78.4) / K1_VDN (97.0,79.2) / +3V3_HUB (98.7,77.7) 三个孔把这条带从 7.5 掐到 5.30。
|
||||||
|
VIA_KEEPOUT = [(79.5, 67.1, 87.8, 83.5), (86.5, 75.0, 101.0, 83.5)]
|
||||||
TURN_COST = 0.30 # 拐一次弯折算成多少 mm(换来长直段,少几百条碎线)
|
TURN_COST = 0.30 # 拐一次弯折算成多少 mm(换来长直段,少几百条碎线)
|
||||||
BBOX_PAD = 10.0 # 每次连线的搜索窗口比两端包围盒大多少
|
BBOX_PAD = 10.0 # 每次连线的搜索窗口比两端包围盒大多少
|
||||||
ASTAR_W = 1.3 # 加权 A*:h 乘这个数。放弃严格最优换速度
|
ASTAR_W = 1.3 # 加权 A*:h 乘这个数。放弃严格最优换速度
|
||||||
MAX_CELLS = 1200000 # 单层格数超过这个才把栅格放粗一档(只有跨半块板的网络会碰到)
|
MAX_CELLS = 3200000 # 单层格数超过这个才把栅格放粗一档(只有跨半块板的网络会碰到)
|
||||||
|
# 2026-09-07:1.2M 时全板窗口 (220×135) 在 0.1 栅格下 2.97M 格 -> 被放粗到 0.2,
|
||||||
|
# 排母 2.54 间距的 0.84 缝在 0.2 栅格上整片不可达;3.2M 让全板窗口保住 0.1。
|
||||||
|
|
||||||
W_ARR = 0.11 # 还在 BM24 焊盘阵列里那一段
|
W_ARR = 0.11 # 还在 BM24 焊盘阵列里那一段
|
||||||
W_ESC = 0.20 # 刚出阵列
|
W_ESC = 0.20 # 刚出阵列
|
||||||
@@ -377,8 +400,15 @@ class Field(object):
|
|||||||
return f
|
return f
|
||||||
|
|
||||||
def via_ok(self):
|
def via_ok(self):
|
||||||
return ((self.viafree >= CLR + VIA_R + self.qerr)
|
ok = ((self.viafree >= CLR + VIA_R + self.qerr)
|
||||||
& (self.holefree >= VIA_H / 2.0 + HOLE_CLR + self.qerr))
|
& (self.holefree >= VIA_H / 2.0 + HOLE_CLR + self.qerr))
|
||||||
|
# 过孔禁区(Inner1 电源岛的颈):外层布线器看不见内层的岛,一个过孔的反焊盘就能把 4 A 的颈掐窄。
|
||||||
|
if VIA_KEEPOUT:
|
||||||
|
xs = self.x0 + np.arange(self.nx) * self.g
|
||||||
|
ys = self.y0 + np.arange(self.ny) * self.g
|
||||||
|
for x0, y0, x1, y1 in VIA_KEEPOUT:
|
||||||
|
ok &= ~(((xs >= x0) & (xs <= x1))[None, :] & ((ys >= y0) & (ys <= y1))[:, None])
|
||||||
|
return ok
|
||||||
|
|
||||||
def clear_seg(self, x0, y0, x1, y1, lay, w):
|
def clear_seg(self, x0, y0, x1, y1, lay, w):
|
||||||
u"""一段任意角度的线是否安全(沿线采样,EDT 是 1-Lipschitz 所以可加采样余量)。"""
|
u"""一段任意角度的线是否安全(沿线采样,EDT 是 1-Lipschitz 所以可加采样余量)。"""
|
||||||
@@ -447,12 +477,20 @@ def route_grid(f, src, tgt, w):
|
|||||||
N = nx * ny
|
N = nx * ny
|
||||||
rows, cols, vals = [], [], []
|
rows, cols, vals = [], [], []
|
||||||
for li in (0, 1):
|
for li in (0, 1):
|
||||||
|
pref = DIR_PREF.get(LAY[li])
|
||||||
for dx, dy in ((1, 0), (0, 1), (1, 1), (1, -1)):
|
for dx, dy in ((1, 0), (0, 1), (1, 1), (1, -1)):
|
||||||
fr, to = _edges(ok[li], dx, dy, nx, ny, li * N)
|
fr, to = _edges(ok[li], dx, dy, nx, ny, li * N)
|
||||||
if len(fr):
|
if len(fr):
|
||||||
|
# H/V 分层:顶层纵向步 / 底层横向步按 DIR_PENALTY 计价,斜步取中间值
|
||||||
|
if dx and dy:
|
||||||
|
k = DIAG_K if pref else 1.0
|
||||||
|
elif (pref == 'H' and dy) or (pref == 'V' and dx):
|
||||||
|
k = DIR_PENALTY
|
||||||
|
else:
|
||||||
|
k = 1.0
|
||||||
rows.append(fr)
|
rows.append(fr)
|
||||||
cols.append(to)
|
cols.append(to)
|
||||||
vals.append(np.full(len(fr), g * (math.sqrt(2) if dx and dy else 1.0),
|
vals.append(np.full(len(fr), g * k * (math.sqrt(2) if dx and dy else 1.0),
|
||||||
np.float32))
|
np.float32))
|
||||||
vm = f.via_ok() & ok[0] & ok[1]
|
vm = f.via_ok() & ok[0] & ok[1]
|
||||||
jj, ii = np.nonzero(vm)
|
jj, ii = np.nonzero(vm)
|
||||||
@@ -901,15 +939,33 @@ def _connect(net, a, b, obstacles, w, pad=BBOX_PAD, relax=None):
|
|||||||
# 窗口一大栅格就被放粗到 0.2 以上,QFN 东侧 0.71 mm 的走廊(U32.46 的出线端)
|
# 窗口一大栅格就被放粗到 0.2 以上,QFN 东侧 0.71 mm 的走廊(U32.46 的出线端)
|
||||||
# 在粗栅格上整片不可达 —— 单独布它能通、全量布就不通,根子在这里不在拥挤。
|
# 在粗栅格上整片不可达 —— 单独布它能通、全量布就不通,根子在这里不在拥挤。
|
||||||
# 小窗口里只有离目标近的那部分 `a` 当种子,别的部分对这一段本来也没用。
|
# 小窗口里只有离目标近的那部分 `a` 当种子,别的部分对这一段本来也没用。
|
||||||
|
# 2026-09-07:加一档 **'near'**:窗口 = 目标 + 「已连上那坨里离目标最近的一件」。
|
||||||
|
# 大网络(+3V3_HUB 33 个焊盘)的远支路(site1 的 U41)在 'tgt' 小窗里没有种子,
|
||||||
|
# 直接退到 'all' 全板大窗 -> 栅格放粗 -> 排母缝 / 元件簇进不去。'near' 窗只框住真正要连的那一段。
|
||||||
tries = [('tgt', 0, 1), ('tgt', 0, 2), ('tgt', 0, 4), ('tgt', 1, 2), ('tgt', 1, 4),
|
tries = [('tgt', 0, 1), ('tgt', 0, 2), ('tgt', 0, 4), ('tgt', 1, 2), ('tgt', 1, 4),
|
||||||
|
('near', 0, 1), ('near', 0, 2), ('near', 1, 1), ('near', 1, 2), ('near', 2, 2),
|
||||||
('all', 0, 1), ('all', 0, 2), ('all', 0, 4), ('all', 1, 1), ('all', 1, 2),
|
('all', 0, 1), ('all', 0, 2), ('all', 0, 4), ('all', 1, 1), ('all', 1, 2),
|
||||||
('all', 1, 4), ('all', 2, 1), ('all', 2, 4)]
|
('all', 1, 4), ('all', 2, 1), ('all', 2, 4)]
|
||||||
|
bc = _bbox(b.shapes, 0.0)
|
||||||
|
bcx, bcy = (bc[0] + bc[2]) / 2.0, (bc[1] + bc[3]) / 2.0
|
||||||
|
|
||||||
|
def _d2(s_):
|
||||||
|
bb = _bbox([s_], 0.0)
|
||||||
|
return (((bb[0] + bb[2]) / 2.0 - bcx) ** 2 + ((bb[1] + bb[3]) / 2.0 - bcy) ** 2)
|
||||||
|
a_near = min(a.shapes, key=_d2) if a.shapes else None
|
||||||
for mode, grow, fine in tries:
|
for mode, grow, fine in tries:
|
||||||
base = b.shapes if mode == 'tgt' else a.shapes + b.shapes
|
if mode == 'tgt':
|
||||||
|
base = b.shapes
|
||||||
|
elif mode == 'near':
|
||||||
|
if a_near is None:
|
||||||
|
continue
|
||||||
|
base = b.shapes + [a_near]
|
||||||
|
else:
|
||||||
|
base = a.shapes + b.shapes
|
||||||
x0, y0, x1, y1 = _bbox(base, pad + grow * 20.0)
|
x0, y0, x1, y1 = _bbox(base, pad + grow * 20.0)
|
||||||
x0, y0 = max(0.0, x0), max(0.0, y0)
|
x0, y0 = max(0.0, x0), max(0.0, y0)
|
||||||
x1, y1 = min(BW, x1), min(BH, y1)
|
x1, y1 = min(BW, x1), min(BH, y1)
|
||||||
if mode == 'tgt':
|
if mode in ('tgt', 'near'):
|
||||||
a_in = [s_ for s_ in a.shapes if _bbox([s_], 0.0)[2] > x0 and _bbox([s_], 0.0)[0] < x1
|
a_in = [s_ for s_ in a.shapes if _bbox([s_], 0.0)[2] > x0 and _bbox([s_], 0.0)[0] < x1
|
||||||
and _bbox([s_], 0.0)[3] > y0 and _bbox([s_], 0.0)[1] < y1]
|
and _bbox([s_], 0.0)[3] > y0 and _bbox([s_], 0.0)[1] < y1]
|
||||||
if not a_in:
|
if not a_in:
|
||||||
@@ -941,6 +997,8 @@ def _connect(net, a, b, obstacles, w, pad=BBOX_PAD, relax=None):
|
|||||||
# ⚠️ 端点处可能有**一串重合点**(换层),要整串一起挪,不能只挪最后一个。
|
# ⚠️ 端点处可能有**一串重合点**(换层),要整串一起挪,不能只挪最后一个。
|
||||||
if a.center:
|
if a.center:
|
||||||
_snap_end(path, a.center, False)
|
_snap_end(path, a.center, False)
|
||||||
|
else:
|
||||||
|
_anchor_start(path, a.shapes)
|
||||||
if b.center:
|
if b.center:
|
||||||
_snap_end(path, b.center, True)
|
_snap_end(path, b.center, True)
|
||||||
path = _end_via(path)
|
path = _end_via(path)
|
||||||
@@ -997,6 +1055,261 @@ def _snap_end(path, xy, at_end):
|
|||||||
path[i] = (round(xy[0], 4), round(xy[1], 4), path[i][2], path[i][3])
|
path[i] = (round(xy[0], 4), round(xy[1], 4), path[i][2], path[i][3])
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
def via_corners(routes, limit=SHARP):
|
||||||
|
u"""换层点两侧的线在平面上成"直角"的那些:[(key, i, (x, y), 转向角)]。
|
||||||
|
`sharp_corners` 故意跳过换层点(那是过孔);用户 2026-09-07 要求换层处也不许 90°。"""
|
||||||
|
out = []
|
||||||
|
for key, path in sorted(routes.items()):
|
||||||
|
for i in range(1, len(path) - 2):
|
||||||
|
b, b2 = path[i], path[i + 1]
|
||||||
|
if not _same(b, b2) or b[2] == b2[2]:
|
||||||
|
continue
|
||||||
|
a, c = path[i - 1], path[i + 2]
|
||||||
|
if _same(a, b) or _same(b2, c):
|
||||||
|
continue
|
||||||
|
t = turn_deg(a, b, c)
|
||||||
|
if t > limit:
|
||||||
|
out.append((key, i, (b[0], b[1]), t))
|
||||||
|
return out
|
||||||
|
|
||||||
|
|
||||||
|
def via_chamfer_routes(routes, pads, vias, lines):
|
||||||
|
u"""换层点的 45° 化(2026-09-07 用户要求:「两层中的走线连接处不要垂直,增加一段锐角走线」)。
|
||||||
|
|
||||||
|
顶层横线进孔、底层竖线出孔,在平面上就是一个直角。做法和普通拐角一样切一刀,
|
||||||
|
但过孔要挪到斜切段的一端:
|
||||||
|
A 型:进线层上 R->Q 走 45°,过孔放在 Q(= 原孔位沿出线方向挪 d),出线从 Q 直着走;
|
||||||
|
B 型:过孔放在 R(= 原孔位沿进线方向退 d),出线层上 R->Q 走 45°。
|
||||||
|
先试 A 再试 B,半径按 CHAMFER_R 逐档退让;斜切段过 `seg_slack`,新孔位过 `_via_legal`。
|
||||||
|
校核用的是**改之前**的其它段(保守)。返回 (新 routes, 切掉的数量)。
|
||||||
|
"""
|
||||||
|
mine, mvias = [], []
|
||||||
|
for key, path in routes.items():
|
||||||
|
for x0, y0, x1, y1, lay, w in expand(path)[0]:
|
||||||
|
mine.append((netof(key), lay, x0, y0, x1, y1, w))
|
||||||
|
for vx, vy in expand(path)[1]:
|
||||||
|
mvias.append((netof(key), vx, vy))
|
||||||
|
|
||||||
|
def via_legal(x, y, net, old=None):
|
||||||
|
for x0, y0, x1, y1 in VIA_KEEPOUT:
|
||||||
|
if x0 <= x <= x1 and y0 <= y <= y1:
|
||||||
|
return False
|
||||||
|
for q in pads:
|
||||||
|
if q['net'] != net and q['lay'] in (12, L_TOP, L_BOT):
|
||||||
|
if seg_rect((x, y), (x, y), q['x'], q['y'], q['hw'], q['hh']) - VIA_R < CLR - 1e-4:
|
||||||
|
return False
|
||||||
|
if q['lay'] == 12 and math.hypot(x - q['x'], y - q['y']) < q['hw'] + VIA_H / 2.0 + HOLE_CLR:
|
||||||
|
return False # 钻孔间距不分网络;焊盘半宽当孔半径,保守
|
||||||
|
for v in vias:
|
||||||
|
d = math.hypot(x - v['x'], y - v['y'])
|
||||||
|
if v['net'] != net and d - VIA_R - v['r'] < CLR - 1e-4:
|
||||||
|
return False
|
||||||
|
if d < VIA_H + HOLE_CLR - 1e-4:
|
||||||
|
return False
|
||||||
|
for n2, vx, vy in mvias:
|
||||||
|
if old is not None and abs(vx - old[0]) < 1e-6 and abs(vy - old[1]) < 1e-6:
|
||||||
|
continue # 本路径自己原来那个孔(马上要挪走)
|
||||||
|
d = math.hypot(x - vx, y - vy)
|
||||||
|
if n2 != net and d - 2 * VIA_R < CLR - 1e-4:
|
||||||
|
return False
|
||||||
|
if d < VIA_H + HOLE_CLR - 1e-4:
|
||||||
|
return False
|
||||||
|
for l in lines:
|
||||||
|
if l['net'] != net and seg_pt(l['x0'], l['y0'], l['x1'], l['y1'], x, y) - VIA_R - l['w'] / 2.0 < CLR - 1e-4:
|
||||||
|
return False
|
||||||
|
for n2, lay, x0, y0, x1, y1, w in mine:
|
||||||
|
if n2 != net and seg_pt(x0, y0, x1, y1, x, y) - VIA_R - w / 2.0 < CLR - 1e-4:
|
||||||
|
return False
|
||||||
|
return True
|
||||||
|
|
||||||
|
out, ncut = {}, 0
|
||||||
|
for key, path in routes.items():
|
||||||
|
net = netof(key)
|
||||||
|
ok = lambda x0, y0, x1, y1, lay, w, _n=net: (
|
||||||
|
seg_slack(x0, y0, x1, y1, lay, w, _n, pads, vias, lines, mine, mvias) >= -1e-4)
|
||||||
|
res = []
|
||||||
|
i = 0
|
||||||
|
while i < len(path):
|
||||||
|
b = path[i]
|
||||||
|
if not (1 <= i <= len(path) - 3):
|
||||||
|
res.append(b)
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
b2 = path[i + 1]
|
||||||
|
a, c = path[i - 1], path[i + 2]
|
||||||
|
if not _same(b, b2) or b[2] == b2[2] or _same(a, b) or _same(b2, c) or turn_deg(a, b, c) <= SHARP:
|
||||||
|
res.append(b)
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
ax, ay = b[0] - a[0], b[1] - a[1]
|
||||||
|
cx, cy = c[0] - b[0], c[1] - b[1]
|
||||||
|
la, lc = math.hypot(ax, ay), math.hypot(cx, cy)
|
||||||
|
wa, wb = a[3], b2[3]
|
||||||
|
done = None
|
||||||
|
for r in CHAMFER_R:
|
||||||
|
d = min(r, la / 2.0, lc / 2.0)
|
||||||
|
if d < 0.05:
|
||||||
|
break
|
||||||
|
R = (round(b[0] - ax / la * d, 4), round(b[1] - ay / la * d, 4))
|
||||||
|
Q = (round(b[0] + cx / lc * d, 4), round(b[1] + cy / lc * d, 4))
|
||||||
|
# A 型:斜段在进线层,孔在 Q
|
||||||
|
if ok(R[0], R[1], Q[0], Q[1], a[2], wa) and via_legal(Q[0], Q[1], net, (b[0], b[1])):
|
||||||
|
done = [(R[0], R[1], a[2], wa), (Q[0], Q[1], a[2], wa), (Q[0], Q[1], b2[2], wb)]
|
||||||
|
break
|
||||||
|
# B 型:孔在 R,斜段在出线层
|
||||||
|
if ok(R[0], R[1], Q[0], Q[1], b2[2], wb) and via_legal(R[0], R[1], net, (b[0], b[1])):
|
||||||
|
done = [(R[0], R[1], a[2], wa), (R[0], R[1], b2[2], wb), (Q[0], Q[1], b2[2], wb)]
|
||||||
|
break
|
||||||
|
if done is None:
|
||||||
|
res.append(b)
|
||||||
|
i += 1
|
||||||
|
continue
|
||||||
|
res.extend(done)
|
||||||
|
ncut += 1
|
||||||
|
i += 2 # 跳过 b2(旧孔位的第二个点)
|
||||||
|
out[key] = res
|
||||||
|
return out, ncut
|
||||||
|
|
||||||
|
def reanchor_routes(routes, pads):
|
||||||
|
u"""切角 / 焊盘矩形角两类问题的兜底:让每条路径的两端都落在本网的铜里。返回补的段数。"""
|
||||||
|
by_net = {}
|
||||||
|
for key, path in routes.items():
|
||||||
|
by_net.setdefault(netof(key), []).append(key)
|
||||||
|
padix = {}
|
||||||
|
for q in pads:
|
||||||
|
if q['net']:
|
||||||
|
padix.setdefault(q['net'], []).append(q)
|
||||||
|
nfix = 0
|
||||||
|
for net, keys in by_net.items():
|
||||||
|
segs, vias = [], []
|
||||||
|
for k in keys:
|
||||||
|
sg, vv = expand(routes[k])
|
||||||
|
segs += [(k, x0, y0, x1, y1, lay, w) for x0, y0, x1, y1, lay, w in sg]
|
||||||
|
vias += [(k, x, y) for x, y in vv]
|
||||||
|
for k in keys:
|
||||||
|
path = routes[k]
|
||||||
|
if len(path) < 2:
|
||||||
|
continue
|
||||||
|
for at_end in (False, True):
|
||||||
|
x, y, lay, w = path[-1] if at_end else path[0]
|
||||||
|
inside = False
|
||||||
|
for q in padix.get(net, []):
|
||||||
|
if (q['lay'] == 12 or q['lay'] == lay) and math.hypot(x - q['x'], y - q['y']) <= min(q['hw'], q['hh']) + 1e-6:
|
||||||
|
inside = True
|
||||||
|
break
|
||||||
|
if not inside:
|
||||||
|
for k2, vx, vy in vias:
|
||||||
|
if math.hypot(x - vx, y - vy) <= VIA_R + 1e-6:
|
||||||
|
inside = True
|
||||||
|
break
|
||||||
|
if not inside:
|
||||||
|
for k2, x0, y0, x1, y1, l2, w2 in segs:
|
||||||
|
if k2 == k or l2 != lay:
|
||||||
|
continue
|
||||||
|
if seg_pt(x0, y0, x1, y1, x, y) <= w2 / 2.0 + 1e-6:
|
||||||
|
inside = True
|
||||||
|
break
|
||||||
|
if inside:
|
||||||
|
continue
|
||||||
|
best = None
|
||||||
|
for k2, x0, y0, x1, y1, l2, w2 in segs:
|
||||||
|
if k2 == k or l2 != lay:
|
||||||
|
continue
|
||||||
|
dx, dy = x1 - x0, y1 - y0
|
||||||
|
L2 = dx * dx + dy * dy
|
||||||
|
tt = 0.0 if L2 < 1e-12 else max(0.0, min(1.0, ((x - x0) * dx + (y - y0) * dy) / L2))
|
||||||
|
qx, qy = x0 + tt * dx, y0 + tt * dy
|
||||||
|
d = math.hypot(x - qx, y - qy)
|
||||||
|
if best is None or d < best[0]:
|
||||||
|
best = (d, qx, qy)
|
||||||
|
for q in padix.get(net, []):
|
||||||
|
if q['lay'] == 12 or q['lay'] == lay:
|
||||||
|
d = math.hypot(x - q['x'], y - q['y'])
|
||||||
|
if best is None or d < best[0]:
|
||||||
|
best = (d, q['x'], q['y'])
|
||||||
|
if best is None or best[0] > 1.5:
|
||||||
|
print(u' [!!] %s 的%s点 (%.3f,%.3f) L%d 不在本网铜里,附近 1.5 mm 内也没有可接的铜'
|
||||||
|
% (k.replace(KSEP, '|'), u'终' if at_end else u'起', x, y, lay))
|
||||||
|
continue
|
||||||
|
pt = (round(best[1], 4), round(best[2], 4), lay, w)
|
||||||
|
if at_end:
|
||||||
|
path.append(pt)
|
||||||
|
else:
|
||||||
|
path.insert(0, pt)
|
||||||
|
nfix += 1
|
||||||
|
return nfix
|
||||||
|
|
||||||
|
|
||||||
|
def _anchor_start(path, shapes):
|
||||||
|
u"""从「已连上的一坨」出发的路径,起点若落在某个**矩形焊盘形状**里但没在圆心,补一个圆心点。
|
||||||
|
|
||||||
|
2026-09-07 第三十轮实测:Comp 的注释早就写了「圆焊盘存的是外接矩形,停在角上搭不到铜」,
|
||||||
|
单焊盘的起终点因此钉在圆心;但 MST 后续每条边的**起点**是整坨铜的掩膜(矩形),
|
||||||
|
Dijkstra 挑离目标最近的种子 = 矩形角,离 Ø1.7 排母脚圆心 1.2 mm,铜外 0.2 ——
|
||||||
|
KEY_SRCLK/KEY_RCLK/+5V 在 J32 上、VBUS2/+3V3_HUB 在贴片盘上各留了一个孤岛(DRC 连接性 10 条)。
|
||||||
|
补的这一段全程在本网焊盘内部 / 焊盘自己的净距圈里,不会碰别的网。
|
||||||
|
"""
|
||||||
|
if not path:
|
||||||
|
return
|
||||||
|
x, y, lay, w = path[0]
|
||||||
|
if os.environ.get('ANCHOR_DEBUG'):
|
||||||
|
nb = []
|
||||||
|
for s_ in shapes:
|
||||||
|
if s_[0] == 'seg':
|
||||||
|
d = seg_pt(s_[1], s_[2], s_[3], s_[4], x, y) - s_[5]
|
||||||
|
elif s_[0] == 'via':
|
||||||
|
d = math.hypot(x - s_[1], y - s_[2]) - s_[3]
|
||||||
|
else:
|
||||||
|
d = seg_rect((x, y), (x, y), s_[1], s_[2], s_[3], s_[4])
|
||||||
|
if d < 1.0:
|
||||||
|
nb.append((round(d, 3), s_))
|
||||||
|
nb.sort(key=lambda t: t[0])
|
||||||
|
print(u' [dbg] 起点 (%.3f,%.3f) L%d 附近形状: %s' % (x, y, lay, nb[:4]))
|
||||||
|
# 起点已经落在本网的导线 / 过孔铜里(比如出线段的末端)就不用补
|
||||||
|
for s_ in shapes:
|
||||||
|
if lay not in s_[-1]:
|
||||||
|
continue
|
||||||
|
if s_[0] == 'seg' and seg_pt(s_[1], s_[2], s_[3], s_[4], x, y) <= s_[5] + 1e-6:
|
||||||
|
return
|
||||||
|
if s_[0] == 'via' and math.hypot(x - s_[1], y - s_[2]) <= s_[3] + 1e-6:
|
||||||
|
return
|
||||||
|
best = None
|
||||||
|
for s_ in shapes:
|
||||||
|
if s_[0] != 'rect' or lay not in s_[-1]:
|
||||||
|
continue
|
||||||
|
_, cx, cy, hw, hh, _ = s_
|
||||||
|
d = math.hypot(x - cx, y - cy)
|
||||||
|
if d <= math.hypot(hw, hh) + 0.05 and (best is None or d < best[0]):
|
||||||
|
best = (d, cx, cy)
|
||||||
|
if best is not None and best[0] >= 1e-3:
|
||||||
|
path.insert(0, (round(best[1], 4), round(best[2], 4), lay, w))
|
||||||
|
return
|
||||||
|
if best is not None:
|
||||||
|
return
|
||||||
|
if os.environ.get('ANCHOR_DEBUG'):
|
||||||
|
cont = []
|
||||||
|
for s_ in shapes:
|
||||||
|
if lay not in s_[-1]:
|
||||||
|
continue
|
||||||
|
if s_[0] == 'seg' and seg_pt(s_[1], s_[2], s_[3], s_[4], x, y) <= s_[5] + 1e-6:
|
||||||
|
cont.append(s_)
|
||||||
|
elif s_[0] == 'via' and math.hypot(x - s_[1], y - s_[2]) <= s_[3] + 1e-6:
|
||||||
|
cont.append(s_)
|
||||||
|
print(u' [dbg] 起点 (%.3f,%.3f) L%d 落在: %s' % (x, y, lay, cont[:3]))
|
||||||
|
# 诊断:起点不在本网任何形状里(2026-09-07 追 VBUS2 / +3V3_HUB 的孤岛)
|
||||||
|
near = []
|
||||||
|
for s_ in shapes:
|
||||||
|
if s_[0] == 'seg':
|
||||||
|
near.append((seg_pt(s_[1], s_[2], s_[3], s_[4], x, y) - s_[5], s_))
|
||||||
|
elif s_[0] == 'via':
|
||||||
|
near.append((math.hypot(x - s_[1], y - s_[2]) - s_[3], s_))
|
||||||
|
else:
|
||||||
|
near.append((math.hypot(x - s_[1], y - s_[2]), s_))
|
||||||
|
near.sort(key=lambda t: t[0])
|
||||||
|
print(u' [?] 起点 (%.3f,%.3f) L%d 不在本网铜里;最近 %s' % (x, y, lay, near[:2]))
|
||||||
|
|
||||||
|
|
||||||
def _end_via(path):
|
def _end_via(path):
|
||||||
u"""路径**最后一个点上的过孔**要补一个重复点,`expand()` 才认得出来。
|
u"""路径**最后一个点上的过孔**要补一个重复点,`expand()` 才认得出来。
|
||||||
|
|
||||||
@@ -1131,10 +1444,13 @@ def net_order():
|
|||||||
# **结果更糟**:它有 33 个焊盘,先布就把 Hub 周围铺满,
|
# **结果更糟**:它有 33 个焊盘,先布就把 Hub 周围铺满,
|
||||||
# `XTAL1`/`CFGSEL0`/`PRTDIS6`/`PRTDIS7`/`HUB_RST` 五根配置线全布不通
|
# `XTAL1`/`CFGSEL0`/`PRTDIS6`/`PRTDIS7`/`HUB_RST` 五根配置线全布不通
|
||||||
# (没布通的从 4 个涨到 7 个)。⇒ 大网络必须排在点对点的小网络之后。
|
# (没布通的从 4 个涨到 7 个)。⇒ 大网络必须排在点对点的小网络之后。
|
||||||
hub = ['GND'] + lanes0 + ['VBUS_UP'] + [
|
# 2026-09-07:`HUB_RST` 提到 `VBUS_UP` 之前。R716.1 唯一的出口是 R716/R711 之间 0.66 的底层缝,
|
||||||
|
# 缝东头是 USB5 竖线墙、必须换层;VBUS_UP 先布时从 R709.1 出来在顶层 y 67.2 横穿卫星圈东行,
|
||||||
|
# 和 +3V3 前置线(顶层 y 66.2)夹成 0.8 的带,塞不下换层孔 -> HUB_RST 布不通(第三十轮实测)。
|
||||||
|
hub = ['GND'] + lanes0 + ['HUB_RST', 'VBUS_UP'] + [
|
||||||
'RBIAS', 'VDD18', 'VDD18PLL', 'XTAL1', 'XTAL2',
|
'RBIAS', 'VDD18', 'VDD18PLL', 'XTAL1', 'XTAL2',
|
||||||
'CFGSEL0', 'CFGSEL1', 'NONREM0', 'NONREM1', 'PRTDIS6', 'PRTDIS7',
|
'CFGSEL0', 'CFGSEL1', 'NONREM0', 'NONREM1', 'PRTDIS6', 'PRTDIS7',
|
||||||
'HUB_RST', '+3V3_HUB', 'VBUS_DET']
|
'+3V3_HUB', 'VBUS_DET']
|
||||||
# `EDL_ENn` / `VBUS_ENn` 在 U4n / U2n 上是**紧挨着 +3V3 脚的那一针**,
|
# `EDL_ENn` / `VBUS_ENn` 在 U4n / U2n 上是**紧挨着 +3V3 脚的那一针**,
|
||||||
# 排在 `+3V3_HUB` 之前,否则 3V3 的长支干会从这 0.95 mm 的缝里横穿过去。
|
# 排在 `+3V3_HUB` 之前,否则 3V3 的长支干会从这 0.95 mm 的缝里横穿过去。
|
||||||
en = ['EDL_EN%d' % n for n in range(1, 6)] + ['VBUS_EN%d' % n for n in range(1, 6)]
|
en = ['EDL_EN%d' % n for n in range(1, 6)] + ['VBUS_EN%d' % n for n in range(1, 6)]
|
||||||
@@ -1156,9 +1472,19 @@ def net_order():
|
|||||||
# 让它先挑路;长的绕得起。site4/site5 上这条规则把 `VDN` 提到最前 ——
|
# 让它先挑路;长的绕得起。site4/site5 上这条规则把 `VDN` 提到最前 ——
|
||||||
# 它的源在最东、靶点却在最西(J59 比 J57/J58 靠里),后布就被另外两根夹死
|
# 它的源在最东、靶点却在最西(J59 比 J57/J58 靠里),后布就被另外两根夹死
|
||||||
# (`POGO5_VDN` 原来就是这么布不通的)。
|
# (`POGO5_VDN` 原来就是这么布不通的)。
|
||||||
|
# 2026-09-06 595 上载板:移位链 4 根(各 4 个焊盘:J32 + 三片)+ 两根级联 + 15 根 K 栅极线(点对点),
|
||||||
|
# 排在 POGO 之前 —— K 线从走廊中段扇到五个站,比站内的 POGO 短线更需要先挑路。
|
||||||
|
# 2026-09-07 第三十轮(U21 rot 0 / U22 rot 180 之后):**K 线排在移位链控制线之前**。
|
||||||
|
# U22 南排的 K4/K5 六根只能从南带(UP 差分线边 60.74 ~ 焊盘下沿 62.77,2 mm)换层出去;
|
||||||
|
# KEY_* 先布时把这条带在顶层横着占满(U21 南排 -> U22 北排 -> J32 北排的直路),K4_VDN/K5_VUP/K5_VDN 布不通。
|
||||||
|
# 控制线有别的路(U22 两排脚之间 y 64.75~68.25 那 3.5 mm 的通道、J32 北侧),K 线没有。
|
||||||
|
keys = ['K%d_%s' % (n, k) for n in range(1, 6) for k in ('PWR', 'VUP', 'VDN')]
|
||||||
|
keys += ['KEY_SER', 'KEY_SRCLK', 'KEY_RCLK', 'KEY_OE#', 'SR_CAS', 'SR_CAS2']
|
||||||
ctrl = [n for n in _pogo_by_length()] + ['SDA', 'SCL']
|
ctrl = [n for n in _pogo_by_length()] + ['SDA', 'SCL']
|
||||||
|
# 2026-09-06:K 线 / 移位链提前到 `up` 之前 —— 它们是点对点细线,单独布 0.6 s 就通,
|
||||||
|
# 排在 +5V / VBUS / 站内局部网之后就被挤死(实测两轮各 11~12 根布不通)。
|
||||||
out, seen = [], set()
|
out, seen = [], set()
|
||||||
for n in hub + up + site + power + ctrl:
|
for n in hub + keys + up + site + power + ctrl:
|
||||||
if n not in seen:
|
if n not in seen:
|
||||||
seen.add(n)
|
seen.add(n)
|
||||||
out.append(n)
|
out.append(n)
|
||||||
@@ -1205,11 +1531,13 @@ def gnd_boxes():
|
|||||||
return out
|
return out
|
||||||
|
|
||||||
|
|
||||||
JS_PUSH_SIG = u"""
|
# ⚠️ 2026-09-06:原来一个请求里「逐条删 + 逐条建 1589 段」,桥接 30 s 超时(EasyEDA 那边还在继续画),
|
||||||
const NETS = %s, BOXES = %s, SEGS = %s, VIAS = %s, MIL = %f;
|
# 下一步抓几何抓到画了一半的板子。现在拆成:一次性批量删 -> 每 250 段一个请求建线 -> 建孔 -> 存盘。
|
||||||
|
JS_PUSH_DEL = u"""
|
||||||
|
const NETS = %s, BOXES = %s, MIL = %f;
|
||||||
const S = new Set(NETS);
|
const S = new Set(NETS);
|
||||||
const inBox = (x, y) => BOXES.some(b => x >= b[0] && x <= b[2] && y >= b[1] && y <= b[3]);
|
const inBox = (x, y) => BOXES.some(b => x >= b[0] && x <= b[2] && y >= b[1] && y <= b[3]);
|
||||||
let dl = 0, dv = 0;
|
const dl = [], dv = [];
|
||||||
for (const o of await eda.pcb_PrimitiveLine.getAll()) {
|
for (const o of await eda.pcb_PrimitiveLine.getAll()) {
|
||||||
const L = o.getState_Layer(); if (L !== 1 && L !== 2) continue;
|
const L = o.getState_Layer(); if (L !== 1 && L !== 2) continue;
|
||||||
const n = o.getState_Net();
|
const n = o.getState_Net();
|
||||||
@@ -1217,23 +1545,35 @@ for (const o of await eda.pcb_PrimitiveLine.getAll()) {
|
|||||||
? !(inBox(o.getState_StartX()/MIL, o.getState_StartY()/MIL) &&
|
? !(inBox(o.getState_StartX()/MIL, o.getState_StartY()/MIL) &&
|
||||||
inBox(o.getState_EndX()/MIL, o.getState_EndY()/MIL))
|
inBox(o.getState_EndX()/MIL, o.getState_EndY()/MIL))
|
||||||
: !S.has(n);
|
: !S.has(n);
|
||||||
if (!keep) { await eda.pcb_PrimitiveLine.delete(o.getState_PrimitiveId()); dl++; }
|
if (!keep) dl.push(o.getState_PrimitiveId());
|
||||||
}
|
}
|
||||||
for (const o of await eda.pcb_PrimitiveVia.getAll()) {
|
for (const o of await eda.pcb_PrimitiveVia.getAll()) {
|
||||||
const n = o.getState_Net();
|
const n = o.getState_Net();
|
||||||
const keep = n === 'GND' ? !inBox(o.getState_X()/MIL, o.getState_Y()/MIL) : !S.has(n);
|
const keep = n === 'GND' ? !inBox(o.getState_X()/MIL, o.getState_Y()/MIL) : !S.has(n);
|
||||||
if (!keep) { await eda.pcb_PrimitiveVia.delete(o.getState_PrimitiveId()); dv++; }
|
if (!keep) dv.push(o.getState_PrimitiveId());
|
||||||
}
|
}
|
||||||
let nl = 0, nv = 0;
|
for (let i = 0; i < dl.length; i += 300) await eda.pcb_PrimitiveLine.delete(dl.slice(i, i + 300));
|
||||||
|
for (let i = 0; i < dv.length; i += 300) await eda.pcb_PrimitiveVia.delete(dv.slice(i, i + 300));
|
||||||
|
return {del_lines: dl.length, del_vias: dv.length};
|
||||||
|
"""
|
||||||
|
JS_PUSH_LINES = u"""
|
||||||
|
const SEGS = %s, MIL = %f; let nl = 0;
|
||||||
for (const [net, lay, x0, y0, x1, y1, w] of SEGS) {
|
for (const [net, lay, x0, y0, x1, y1, w] of SEGS) {
|
||||||
await eda.pcb_PrimitiveLine.create(net, lay, x0*MIL, y0*MIL, x1*MIL, y1*MIL, w*MIL); nl++;
|
await eda.pcb_PrimitiveLine.create(net, lay, x0*MIL, y0*MIL, x1*MIL, y1*MIL, w*MIL); nl++;
|
||||||
}
|
}
|
||||||
|
return nl;
|
||||||
|
"""
|
||||||
|
JS_PUSH_VIAS = u"""
|
||||||
|
const VIAS = %s, MIL = %f; let nv = 0;
|
||||||
for (const [net, x, y] of VIAS) {
|
for (const [net, x, y] of VIAS) {
|
||||||
await eda.pcb_PrimitiveVia.create(net, x*MIL, y*MIL, %f*MIL, %f*MIL); nv++;
|
await eda.pcb_PrimitiveVia.create(net, x*MIL, y*MIL, %f*MIL, %f*MIL); nv++;
|
||||||
}
|
}
|
||||||
|
return nv;
|
||||||
|
"""
|
||||||
|
JS_PUSH_SAVE = u"""
|
||||||
await eda.pcb_Document.save();
|
await eda.pcb_Document.save();
|
||||||
await new Promise(r => setTimeout(r, 2500));
|
await new Promise(r => setTimeout(r, 2500));
|
||||||
return {del_lines: dl, del_vias: dv, lines: nl, vias: nv};
|
return 1;
|
||||||
"""
|
"""
|
||||||
|
|
||||||
|
|
||||||
@@ -1243,21 +1583,47 @@ def push_sig(routes):
|
|||||||
net = netof(key)
|
net = netof(key)
|
||||||
s_, v_ = expand(path)
|
s_, v_ = expand(path)
|
||||||
for x0, y0, x1, y1, lay, w in s_:
|
for x0, y0, x1, y1, lay, w in s_:
|
||||||
segs.append([net, lay, round(x0, 4), round(y0, 4), round(x1, 4), round(y1, 4), w])
|
# 2026-09-07:穿过**本网焊盘中心**的线段在中心处拆成两段。EasyEDA 建一条穿过焊盘的线时会在焊盘中心截断、
|
||||||
|
# 后半段直接丢掉(KEY_RCLK 穿 U22.12 去接出线段末端,板上只剩到焊盘中心那一半,DRC 连接性 2 条)。
|
||||||
|
pts = [(x0, y0)]
|
||||||
|
L = math.hypot(x1 - x0, y1 - y0)
|
||||||
|
cuts = []
|
||||||
|
for q in PADS_ALL:
|
||||||
|
if q['net'] != net or (q['lay'] != 12 and q['lay'] != lay) or L < 1e-6:
|
||||||
|
continue
|
||||||
|
t = ((q['x'] - x0) * (x1 - x0) + (q['y'] - y0) * (y1 - y0)) / (L * L)
|
||||||
|
if 0.02 < t < 0.98 and seg_pt(x0, y0, x1, y1, q['x'], q['y']) < 0.15: # 0.15 < 焊盘半宽 0.3,拆出的小折角仍在焊盘里
|
||||||
|
cuts.append((t, q['x'], q['y']))
|
||||||
|
for _t, qx, qy in sorted(cuts):
|
||||||
|
pts.append((qx, qy))
|
||||||
|
pts.append((x1, y1))
|
||||||
|
for (ax, ay), (bx, by) in zip(pts, pts[1:]):
|
||||||
|
segs.append([net, lay, round(ax, 4), round(ay, 4), round(bx, 4), round(by, 4), w])
|
||||||
for x, y in v_:
|
for x, y in v_:
|
||||||
vs.append([net, round(x, 4), round(y, 4)])
|
vs.append([net, round(x, 4), round(y, 4)])
|
||||||
nets = sorted(set(netof(k) for k in routes) - {'GND'})
|
nets = sorted(set(netof(k) for k in routes) - {'GND'})
|
||||||
js = ("await eda.dmt_EditorControl.openDocument('%s');"
|
|
||||||
"await new Promise(r=>setTimeout(r,1800));" % PCB) + (
|
|
||||||
JS_PUSH_SIG % (json.dumps(nets), json.dumps(gnd_boxes()), json.dumps(segs),
|
|
||||||
json.dumps(vs), MIL, VIA_H, VIA_D))
|
|
||||||
from eda import run
|
from eda import run
|
||||||
r = run(js, timeout=1800)
|
OPEN = ("await eda.dmt_EditorControl.openDocument('%s');"
|
||||||
if not r.get('success'):
|
"await new Promise(r=>setTimeout(r,1800));" % PCB)
|
||||||
sys.exit(u'下发失败: ' + json.dumps(r, ensure_ascii=False)[:600])
|
|
||||||
d = r['result']
|
def call(js, what):
|
||||||
print(u'下发完成:先删 %d 线 / %d 孔,再画 %d 线 / %d 孔'
|
r = run(OPEN + js, timeout=600)
|
||||||
% (d['del_lines'], d['del_vias'], d['lines'], d['vias']))
|
if not r.get('success'):
|
||||||
|
sys.exit(u'下发失败(%s): %s' % (what, json.dumps(r, ensure_ascii=False)[:600]))
|
||||||
|
return r['result']
|
||||||
|
# 2026-09-07:BM24 框里的 GND 梳子只有在这一轮**重画 GND** 时才删。
|
||||||
|
# 原来无条件删:`--net HUB_RST ...` 补布把 65 个 BM24 GND 脚的逃逸段全删了没重画(gnd_patch 报 65 个悬空域)。
|
||||||
|
has_gnd = any(netof(k) == 'GND' for k in routes)
|
||||||
|
d = call(JS_PUSH_DEL % (json.dumps(nets), json.dumps(gnd_boxes() if has_gnd else []), MIL), u'删旧铜')
|
||||||
|
nl = 0
|
||||||
|
for i in range(0, len(segs), 250):
|
||||||
|
nl += call(JS_PUSH_LINES % (json.dumps(segs[i:i + 250]), MIL), u'建线 %d~' % i)
|
||||||
|
nv = 0
|
||||||
|
for i in range(0, len(vs), 250):
|
||||||
|
nv += call(JS_PUSH_VIAS % (json.dumps(vs[i:i + 250]), MIL, VIA_H, VIA_D), u'建孔 %d~' % i)
|
||||||
|
call(JS_PUSH_SAVE, u'存盘')
|
||||||
|
print(u'下发完成:先删 %d 线 / %d 孔,再画 %d 线 / %d 孔(分批,每批 250)'
|
||||||
|
% (d['del_lines'], d['del_vias'], nl, nv))
|
||||||
|
|
||||||
|
|
||||||
def _to_site_uv(n, x, y):
|
def _to_site_uv(n, x, y):
|
||||||
@@ -1268,7 +1634,7 @@ def _to_site_uv(n, x, y):
|
|||||||
return (PW - (x - x0), PH - (y - y0))
|
return (PW - (x - x0), PH - (y - y0))
|
||||||
|
|
||||||
|
|
||||||
def j7_assert(pads):
|
def j7_assert(pads, strict=True):
|
||||||
u"""**把上面那一堆 J7_* 常量和板上的实际焊盘对一遍**(五个站逐一)。
|
u"""**把上面那一堆 J7_* 常量和板上的实际焊盘对一遍**(五个站逐一)。
|
||||||
|
|
||||||
⚠️ 这个断言是 2026-09-06 补的,起因是它不在的时候踩的坑:
|
⚠️ 这个断言是 2026-09-06 补的,起因是它不在的时候踩的坑:
|
||||||
@@ -1323,22 +1689,34 @@ def j7_assert(pads):
|
|||||||
if bad:
|
if bad:
|
||||||
for t in bad[:20]:
|
for t in bad[:20]:
|
||||||
print(u' !! ' + t)
|
print(u' !! ' + t)
|
||||||
sys.exit(u'\nBM24 的手写常量和板上对不上(%d 条)—— 先改常量再布线。' % len(bad))
|
if strict:
|
||||||
|
sys.exit(u'\nBM24 的手写常量和板上对不上(%d 条)—— 先改常量再布线。' % len(bad))
|
||||||
|
# 2026-09-07:pcb2_place 的 PW/PH 改成 67x44 后,站 1~3(rot 180)的元件在板上仍按旧 67.09x44.66 摆着,
|
||||||
|
# 和 plan() 差 (0.09, 0.66)。只重布不碰 J7n 的网络(如 POGO*)时降级成警告;
|
||||||
|
# 整板 --push 或重画 BM24 梳子之前必须先 pcb2_place.py --push 把站 1~3 摆到新坐标。
|
||||||
|
print(u' ⚠ BM24 常量和板上对不上(%d 条),但这一轮 --net 的网络都不碰 J7n,按警告放行' % len(bad))
|
||||||
|
return
|
||||||
print(u'BM24 手写常量与板上实测一致(五个站 × 13 个 GND 脚 + THERM/CC1 + R76n/R77n)✔')
|
print(u'BM24 手写常量与板上实测一致(五个站 × 13 个 GND 脚 + THERM/CC1 + R76n/R77n)✔')
|
||||||
|
|
||||||
|
|
||||||
def main():
|
def main():
|
||||||
only = [a for a in sys.argv[1:] if not a.startswith('--')]
|
only = [a for a in sys.argv[1:] if not a.startswith('--')]
|
||||||
|
if '--refresh' in sys.argv:
|
||||||
|
from pcb2_route_dp import dump as _dump
|
||||||
|
_dump()
|
||||||
pads, vias, lines = geom()
|
pads, vias, lines = geom()
|
||||||
ALL_NETS.update(p['net'] for p in pads if p['net'])
|
ALL_NETS.update(p['net'] for p in pads if p['net'])
|
||||||
PADS_ALL[:] = pads
|
PADS_ALL[:] = pads
|
||||||
j7_assert(pads)
|
j7nets = set(p['net'] for p in pads if p['ref'].startswith('J7') and p['net'])
|
||||||
|
j7_assert(pads, strict=not only or bool(set(only) & j7nets))
|
||||||
# ⚠️ 下发时要删掉五个 BM24 框里的旧 GND 铜(§25.8 自动扇出的产物),
|
# ⚠️ 下发时要删掉五个 BM24 框里的旧 GND 铜(§25.8 自动扇出的产物),
|
||||||
# 所以**算的时候就得当它们已经没了** —— 否则手写的车道会跟一堆
|
# 所以**算的时候就得当它们已经没了** —— 否则手写的车道会跟一堆
|
||||||
# 马上就要消失的过孔"撞车",而真正的冲突反而被淹没。
|
# 马上就要消失的过孔"撞车",而真正的冲突反而被淹没。
|
||||||
boxes = gnd_boxes()
|
boxes = gnd_boxes()
|
||||||
inbox = lambda x, y: any(b[0] <= x <= b[2] and b[1] <= y <= b[3] for b in boxes)
|
inbox = lambda x, y: any(b[0] <= x <= b[2] and b[1] <= y <= b[3] for b in boxes)
|
||||||
mine = set(net_order()) - {'GND'}
|
# ⚠️ 2026-09-06:带 `--net` 补布时只能摘**这一轮要重画的**网络,其余 115 个网络的旧铜是真障碍——
|
||||||
|
# 原来按完整候选表摘,第二遍把 +3V3_HUB / +5V 直接画到第一遍的线上(DRC 319 条 0 mil)。
|
||||||
|
mine = (set(only) if only else set(net_order())) - {'GND'}
|
||||||
n0 = len(vias) + len(lines)
|
n0 = len(vias) + len(lines)
|
||||||
# ① 本脚本负责的网络:下发时整网删掉重画,所以**算的时候就当它们不存在**。
|
# ① 本脚本负责的网络:下发时整网删掉重画,所以**算的时候就当它们不存在**。
|
||||||
# 不摘的话,第二次跑会把自己上一轮的线当成障碍 —— 结果既不幂等,
|
# 不摘的话,第二次跑会把自己上一轮的线当成障碍 —— 结果既不幂等,
|
||||||
@@ -1472,7 +1850,7 @@ def main():
|
|||||||
if not ok:
|
if not ok:
|
||||||
failed.append(net)
|
failed.append(net)
|
||||||
for k, p in enumerate(ps):
|
for k, p in enumerate(ps):
|
||||||
routes[net if k == 0 else '%s#%d' % (net, k + 1)] = p
|
routes[net if k == 0 else '%s%s%d' % (net, KSEP, k + 1)] = p
|
||||||
print(u' %-12s %2d 段路径 / %3d 导线 / %2d 过孔 %5.1fs %s'
|
print(u' %-12s %2d 段路径 / %3d 导线 / %2d 过孔 %5.1fs %s'
|
||||||
% (net, len(ps), sum(len(expand(q)[0]) for q in ps),
|
% (net, len(ps), sum(len(expand(q)[0]) for q in ps),
|
||||||
sum(len(expand(q)[1]) for q in ps), time.time() - t,
|
sum(len(expand(q)[1]) for q in ps), time.time() - t,
|
||||||
@@ -1488,7 +1866,61 @@ def main():
|
|||||||
# 斜切只会拿掉铜,所以拿"未切之前"的其它段做校核是保守且正确的。
|
# 斜切只会拿掉铜,所以拿"未切之前"的其它段做校核是保守且正确的。
|
||||||
n0 = len(sharp_corners(routes))
|
n0 = len(sharp_corners(routes))
|
||||||
t = time.time()
|
t = time.time()
|
||||||
|
raw = dict(routes)
|
||||||
routes = chamfer_routes(routes, pads, vias, lines, smooth=True)
|
routes = chamfer_routes(routes, pads, vias, lines, smooth=True)
|
||||||
|
# ⚠️ `smooth=True` 会挪动路径(最多 0.15 mm),不只是拿掉铜;而它的净距校核拿的是切之前的自身路径
|
||||||
|
# ⇒ 切完再 check(),把牵涉到违规的那几条整条退回未切版本(下板 pcb1_route_sig §26.15 同款;
|
||||||
|
# 2026-09-06 载板 `$22N139` 就这么被抹到 GND 线上 −0.200)。
|
||||||
|
for _round in range(4):
|
||||||
|
bad0 = check(routes, pads, vias, lines, verbose=False)
|
||||||
|
hurt = set()
|
||||||
|
for t_, n1, n2, lay_, d_, a_, b_ in bad0:
|
||||||
|
for key, path in routes.items():
|
||||||
|
if netof(key) not in (n1, n2) or key not in raw or routes[key] == raw[key]:
|
||||||
|
continue
|
||||||
|
for x0, y0, x1, y1, ll, ww in expand(path)[0]:
|
||||||
|
if seg_seg((x0, y0), (x1, y1), a_, b_) < 1e-6:
|
||||||
|
hurt.add(key)
|
||||||
|
break
|
||||||
|
if not hurt:
|
||||||
|
break
|
||||||
|
print(u' 45° 化后有 %d 条压线,把 %s 退回未切的版本' % (len(bad0), ' '.join(sorted(netof(k) for k in hurt))))
|
||||||
|
for k in hurt:
|
||||||
|
routes[k] = raw[k]
|
||||||
|
# ── 换层点 45° 化(2026-09-07 用户要求)──
|
||||||
|
nv0 = len(via_corners(routes))
|
||||||
|
raw2 = dict(routes)
|
||||||
|
routes, ncut = via_chamfer_routes(routes, pads, vias, lines)
|
||||||
|
for _round in range(4):
|
||||||
|
bad0 = check(routes, pads, vias, lines, verbose=False)
|
||||||
|
hurt = set()
|
||||||
|
for t_, n1, n2, lay_, d_, a_, b_ in bad0:
|
||||||
|
for key, path in routes.items():
|
||||||
|
if netof(key) not in (n1, n2) or key not in raw2 or routes[key] == raw2[key]:
|
||||||
|
continue
|
||||||
|
for x0, y0, x1, y1, ll, ww in expand(path)[0]:
|
||||||
|
if seg_seg((x0, y0), (x1, y1), a_, b_) < 1e-6:
|
||||||
|
hurt.add(key)
|
||||||
|
break
|
||||||
|
for vx, vy in expand(path)[1]:
|
||||||
|
if seg_seg((vx, vy), (vx, vy), a_, b_) < 1e-6:
|
||||||
|
hurt.add(key)
|
||||||
|
break
|
||||||
|
if not hurt:
|
||||||
|
break
|
||||||
|
print(u' 换层 45° 化后有 %d 条压线,把 %s 退回' % (len(bad0), ' '.join(sorted(netof(k) for k in hurt))))
|
||||||
|
for k in hurt:
|
||||||
|
routes[k] = raw2[k]
|
||||||
|
nv1 = len(via_corners(routes))
|
||||||
|
print(u'换层点直角:%d -> %d(切了 %d 处)' % (nv0, nv1, ncut))
|
||||||
|
|
||||||
|
# ── 端点复接(2026-09-07 第三十轮)──
|
||||||
|
# 切角会挪走直角处的铜,而后布的支路起点可能正钉在那个角上(VBUS2 (105.9,99.1)、+3V3_HUB (198.1,70.0));
|
||||||
|
# 另外从整坨出发的路径起点也可能落在圆焊盘外接矩形的角上(J32.7/9、J32.40)。
|
||||||
|
# 统一在这里兜底:路径两端若不在本网任何铜(别的路径 / 过孔 / 焊盘)里,补一段接到最近的本网铜。
|
||||||
|
nfix = reanchor_routes(routes, pads)
|
||||||
|
if nfix:
|
||||||
|
print(u' 端点复接:补了 %d 段' % nfix)
|
||||||
left = sharp_corners(routes)
|
left = sharp_corners(routes)
|
||||||
print(u'\n45° 化:直角拐点 %d -> %d(%.0f 秒)' % (n0, len(left), time.time() - t))
|
print(u'\n45° 化:直角拐点 %d -> %d(%.0f 秒)' % (n0, len(left), time.time() - t))
|
||||||
for key, i, xy, ang in left[:20]:
|
for key, i, xy, ang in left[:20]:
|
||||||
|
|||||||
@@ -11,6 +11,21 @@ u"""载板 PCB2-CARRIER 设计规则 + D± 差分对(2026-09-05)。
|
|||||||
· 写进去的 mm 会被换算成 mil 再换回来,`0.2` 回读是 `0.19999959999999997`,
|
· 写进去的 mm 会被换算成 mil 再换回来,`0.2` 回读是 `0.19999959999999997`,
|
||||||
任何几何比较都留 1e-4 容差
|
任何几何比较都留 1e-4 容差
|
||||||
|
|
||||||
|
## ⚠⚠ 必须在「从原理图导入变更」**之后**跑(2026-09-08 实测)
|
||||||
|
|
||||||
|
网络指派(差分对 / 线宽 / 铺铜连接方式)是**按网络名**挂上去的,
|
||||||
|
而网络是元件导入时才在 PCB 上出现的。在空板上跑本脚本:
|
||||||
|
|
||||||
|
差分对 0 / 11 对
|
||||||
|
线宽指派 0 / 12 个网络
|
||||||
|
铺铜全连接指派 0 / 5 个网络
|
||||||
|
|
||||||
|
—— **而“规则配置已下发”那几行照常打印成功**,看上去像做完了。
|
||||||
|
导入元件后重跑一次就是 11/11、12/12、5/5。
|
||||||
|
|
||||||
|
⇒ 重建板子的顺序是:**切 4 层 → 导入元件 → 下规则 → 摆位**。
|
||||||
|
判据就是上面那三个分数,不是“没报错”。
|
||||||
|
|
||||||
## 和下板不同的三处
|
## 和下板不同的三处
|
||||||
|
|
||||||
1. **差分对 11 对,不是 7 对。** 载板上每一路 D± 被 ESD 器件 `U5n` 切成两段:
|
1. **差分对 11 对,不是 7 对。** 载板上每一路 D± 被 ESD 器件 `U5n` 切成两段:
|
||||||
@@ -51,7 +66,7 @@ HERE = os.path.dirname(os.path.abspath(__file__))
|
|||||||
sys.path.insert(0, HERE)
|
sys.path.insert(0, HERE)
|
||||||
from eda import run
|
from eda import run
|
||||||
|
|
||||||
PCB = 'f126ffb29c92f9b2' # PCB2-CARRIER
|
PCB = '942ed1560d81c1e7' # PCB2-CARRIER
|
||||||
|
|
||||||
# ── 线宽规则(mm)──────────────────────────────────────────────────────
|
# ── 线宽规则(mm)──────────────────────────────────────────────────────
|
||||||
TRACK_RULES = {
|
TRACK_RULES = {
|
||||||
|
|||||||
@@ -11,7 +11,7 @@ HERE = os.path.dirname(os.path.abspath(__file__))
|
|||||||
sys.path.insert(0, HERE)
|
sys.path.insert(0, HERE)
|
||||||
from eda import run
|
from eda import run
|
||||||
|
|
||||||
PCB = 'f126ffb29c92f9b2'
|
PCB = '942ed1560d81c1e7'
|
||||||
JS = u"""
|
JS = u"""
|
||||||
await eda.dmt_EditorControl.openDocument('%s');
|
await eda.dmt_EditorControl.openDocument('%s');
|
||||||
await new Promise(r=>setTimeout(r,1500));
|
await new Promise(r=>setTimeout(r,1500));
|
||||||
|
|||||||
@@ -363,7 +363,8 @@ def solve(pads, vias, lines):
|
|||||||
want = N_VIA.get(ref, 1)
|
want = N_VIA.get(ref, 1)
|
||||||
for k in range(want):
|
for k in range(want):
|
||||||
# push()/check() 靠 netof(key) 取网络名,所以 '#' 前面必须是网络名
|
# push()/check() 靠 netof(key) 取网络名,所以 '#' 前面必须是网络名
|
||||||
key = u'%s#%s' % (net, ref) if want == 1 else u'%s#%s-%d' % (net, ref, k + 1)
|
# 2026-09-07:分隔符改用 R.KSEP(chr(0)),'#' 会和 KEY_OE# 撞、也让 netof() 拆不开(第三十轮实测 13 条假「过孔-焊盘」)
|
||||||
|
key = u'%s%s%s' % (net, R.KSEP, ref) if want == 1 else u'%s%s%s-%d' % (net, R.KSEP, ref, k + 1)
|
||||||
# ⚠️ 出线画在**焊盘自己那一层**,不是写死顶层。
|
# ⚠️ 出线画在**焊盘自己那一层**,不是写死顶层。
|
||||||
# v1 时代全板器件在顶层,写死 L_TOP 没暴露问题;v2 之后
|
# v1 时代全板器件在顶层,写死 L_TOP 没暴露问题;v2 之后
|
||||||
# VOn_P 的 35 个焊盘**全在底层**,照旧写 L_TOP 会画出 35 条
|
# VOn_P 的 35 个焊盘**全在底层**,照旧写 L_TOP 会画出 35 条
|
||||||
|
|||||||
@@ -32,10 +32,14 @@ HERE = os.path.dirname(os.path.abspath(__file__))
|
|||||||
sys.path.insert(0, HERE)
|
sys.path.insert(0, HERE)
|
||||||
PCB = '7e9415a16a909c51'
|
PCB = '7e9415a16a909c51'
|
||||||
MIL = 39.3701 # 1 mm = 39.3701 mil
|
MIL = 39.3701 # 1 mm = 39.3701 mil
|
||||||
BW, BH = 160.0, 125.0 # 板框 mm
|
BW, BH = 160.0, 125.0 # 元件区 mm(原点左下角,坐标系不变)
|
||||||
|
# 2026-09-06 用户指令:两板尺寸取大对齐 —— 下板板框放大到载板的 220×135,原点不动,
|
||||||
|
# 板框左下角在 (−30,−5)(下板坐标 = 载板坐标 − (30,5),见 pcb1_env.py)。
|
||||||
|
OX, OY, OW, OH = -30.0, -5.0, 220.0, 135.0
|
||||||
CORNER_R = 5.0 # 四角圆角半径 mm
|
CORNER_R = 5.0 # 四角圆角半径 mm
|
||||||
# 定位孔:M3 金属化,孔 Φ3.2 / 焊盘 Φ6.0 / 禁布 Φ6.5,孔心与圆角同心
|
# 定位孔:M3 金属化,孔 Φ3.2 / 焊盘 Φ6.0 / 禁布 Φ6.5,孔心与圆角同心
|
||||||
MH = [(5.0, 5.0), (BW - 5.0, 5.0), (5.0, BH - 5.0), (BW - 5.0, BH - 5.0)]
|
# 定位孔与载板 pcb2_place.MH 对齐(减 (30,5)):四角 + 两侧中点;事实来源是 pcb1_place.MH,这里同表
|
||||||
|
MH = [(-22.0, 3.0), (182.0, 3.0), (-26.0, 126.0), (186.0, 126.0), (-23.0, 55.0), (183.0, 40.0)]
|
||||||
MH_HOLE, MH_PAD, MH_KEEPOUT = 3.2, 6.0, 6.5
|
MH_HOLE, MH_PAD, MH_KEEPOUT = 3.2, 6.0, 6.5
|
||||||
|
|
||||||
# ── 封装占位尺寸(mm,含焊盘;未旋转时 x 向宽 w、y 向高 h)──────────────
|
# ── 封装占位尺寸(mm,含焊盘;未旋转时 x 向宽 w、y 向高 h)──────────────
|
||||||
@@ -469,14 +473,15 @@ def outline_poly():
|
|||||||
要求闭合,不闭合就建不出来)。ARC 的角度**正值 = 逆时针**(本工程 Y 轴朝上)。
|
要求闭合,不闭合就建不出来)。ARC 的角度**正值 = 逆时针**(本工程 Y 轴朝上)。
|
||||||
"""
|
"""
|
||||||
R = CORNER_R
|
R = CORNER_R
|
||||||
|
X0, Y0, X1, Y1 = OX, OY, OX + OW, OY + OH
|
||||||
pts = []
|
pts = []
|
||||||
L = lambda x, y: pts.append(('L', x, y))
|
L = lambda x, y: pts.append(('L', x, y))
|
||||||
A = lambda x, y: pts.append(('ARC', 90.0, x, y))
|
A = lambda x, y: pts.append(('ARC', 90.0, x, y))
|
||||||
start = (R, 0.0)
|
start = (X0 + R, Y0)
|
||||||
L(BW - R, 0.0); A(BW, R)
|
L(X1 - R, Y0); A(X1, Y0 + R)
|
||||||
L(BW, BH - R); A(BW - R, BH)
|
L(X1, Y1 - R); A(X1 - R, Y1)
|
||||||
L(R, BH); A(0.0, BH - R)
|
L(X0 + R, Y1); A(X0, Y1 - R)
|
||||||
L(0.0, R); A(R, 0.0) # 回到起点
|
L(X0, Y0 + R); A(X0 + R, Y0) # 回到起点
|
||||||
|
|
||||||
src, mode = [start[0] * MIL, start[1] * MIL], None
|
src, mode = [start[0] * MIL, start[1] * MIL], None
|
||||||
for p in pts:
|
for p in pts:
|
||||||
@@ -549,8 +554,8 @@ return {del, made: r ? r.primitiveId : null, left};
|
|||||||
if n['left'] != 1:
|
if n['left'] != 1:
|
||||||
print(u' !! layer 11 上有 %d 条多段线,应为 1 —— 板框没建成或有残留' % n['left'])
|
print(u' !! layer 11 上有 %d 条多段线,应为 1 —— 板框没建成或有残留' % n['left'])
|
||||||
sys.exit(1)
|
sys.exit(1)
|
||||||
print(u'板框: 1 条闭合多段线(4 直边 + 4 圆角 R%.0f),%.0f x %.0f mm;'
|
print(u'板框: 1 条闭合多段线(4 直边 + 4 圆角 R%.0f),%.0f x %.0f mm,左下角 (%.0f,%.0f);'
|
||||||
u'顺带删掉 %d 个旧图元' % (CORNER_R, BW, BH, n['del']))
|
u'顺带删掉 %d 个旧图元' % (CORNER_R, OW, OH, OX, OY, n['del']))
|
||||||
|
|
||||||
n = call("""
|
n = call("""
|
||||||
const MH = %s;
|
const MH = %s;
|
||||||
|
|||||||
@@ -43,7 +43,13 @@ from eda import run
|
|||||||
TOL = 0.6
|
TOL = 0.6
|
||||||
_CACHE = json.load(io.open(os.path.join(HERE, 'eda-parts.json'), encoding='utf-8'))
|
_CACHE = json.load(io.open(os.path.join(HERE, 'eda-parts.json'), encoding='utf-8'))
|
||||||
# 默认扫下板;`--board Board2` 扫载板(两块板的页表都在 eda-parts.json 里)
|
# 默认扫下板;`--board Board2` 扫载板(两块板的页表都在 eda-parts.json 里)
|
||||||
if '--board' in sys.argv:
|
# `--r2 BLADE` / `--r2 BASE` 扫 R2 刀片式工程(页表在 .claude/r2/r2-uuids.json)——
|
||||||
|
# ⚠ 它只按 uuid 打开文档,不切工程:跑之前先让客户端停在 PhoneRail-R2 上。
|
||||||
|
if '--r2' in sys.argv:
|
||||||
|
_b = sys.argv[sys.argv.index('--r2') + 1]
|
||||||
|
PAGES = json.load(io.open(os.path.join(HERE, 'r2', 'r2-uuids.json'),
|
||||||
|
encoding='utf-8'))['boards'][_b]['pages']
|
||||||
|
elif '--board' in sys.argv:
|
||||||
_b = sys.argv[sys.argv.index('--board') + 1]
|
_b = sys.argv[sys.argv.index('--board') + 1]
|
||||||
PAGES = _CACHE['schematic_boards'][_b]['pages']
|
PAGES = _CACHE['schematic_boards'][_b]['pages']
|
||||||
else:
|
else:
|
||||||
|
|||||||
@@ -0,0 +1,225 @@
|
|||||||
|
# R2 底板(BASE)剩余四页的**跨页契约** — 2026-09-08
|
||||||
|
|
||||||
|
`A1-INPUT` / `A2-AUX` 已画完。本文件钉死 `A3-CTRL` / `A4-HUB` / `A5-SLOTS` / `A6-FAN`
|
||||||
|
四页之间的**网络名、方向、器件归属、位号区段**。四页由四个子代理并行设计,
|
||||||
|
**只有主代理能下发到 EasyEDA**(全机只有一个 EDA 客户端,`openDocument` 是全局状态,
|
||||||
|
两个人同时推必然把图元放到别人的页上)。
|
||||||
|
|
||||||
|
⛔ **子代理绝对不许**:跑 `.claude/eda.py`、`dump_page.py`、`xpage.py`、`shot.py`、
|
||||||
|
`verify_sch.py`、任何带 `--push` 的脚本,或任何会连 `127.0.0.1:4962x` 的东西。
|
||||||
|
你的交付物是**一个能本地自检通过的 Python 脚本**,主代理负责下发与几何验证。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 0. 已经存在的东西(不要重画,也不要改名)
|
||||||
|
|
||||||
|
| 页 | 内容 | 对外端口 / 旗 |
|
||||||
|
|---|---|---|
|
||||||
|
| `A1-INPUT` | J1 DC-005 → F1 → Q1 反接 → C2~C6 → Rs6 → 12V 母线;U13 INA226(0x43);U29 TL431 泄放 | `+12V`(旗) `GND`(旗) `+3V3`(旗) `SDA` `SCL` `INA_ALERT`(端口) |
|
||||||
|
| `A2-AUX` | U19 12V→3V3(0.5A);U30 12V→5V(2A) | `+12V` `+3V3` `GND`(旗) `+5V`(端口,OUT) |
|
||||||
|
|
||||||
|
`xpage` 现在的 4 个单实例 `+5V` / `SDA` / `SCL` / `INA_ALERT` 就是等你们补对端的。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 1. 网络名总表(**唯一事实来源**)
|
||||||
|
|
||||||
|
### 1.1 电源
|
||||||
|
|
||||||
|
| 网络 | 图元类型 | 说明 |
|
||||||
|
|---|---|---|
|
||||||
|
| `+12V` | **Power 旗** | 全板 12V 母线 |
|
||||||
|
| `+3V3` | **Power 旗** | U19 出来的控制轨(0.5A),给 ESP32 / mux / DAC / 刀片逻辑 |
|
||||||
|
| `+5V` | **端口** | U30 出来的 5V(2A)。A2 已发 OUT,A4/A5 用 **IN** |
|
||||||
|
| `+3V3_HUB` | **Power 旗**(仅 A4 页内) | U31 AMS1117 给 U32 专用,**不许**和 `+3V3` 并 |
|
||||||
|
| `FAN_12V_SW` | **Power 旗**(仅 A6 页内) | Q7 高边开关之后的风扇 12V |
|
||||||
|
| `GND` | **Ground 旗** | — |
|
||||||
|
|
||||||
|
### 1.2 跨页信号(发出方 → 接收方)
|
||||||
|
|
||||||
|
| 网络 | 发出 | 接收 | 说明 |
|
||||||
|
|---|---|---|---|
|
||||||
|
| `SDA` / `SCL` | A1(U13) | **A3**(上拉 + ESP32 + U35 上游 + U6/U7 DAC) | I²C **主干**,不经 mux |
|
||||||
|
| `INA_ALERT` | A1(U13) | **A3**(ESP32 GPIO) | 开漏,上拉放在 A3 |
|
||||||
|
| `SDA1`~`SDA5` / `SCL1`~`SCL5` | **A3**(U35 通道 0~4) | **A5**(槽 1~5) | mux 分支,**上拉在刀片上**(B2-CTRL 的 R40/R41),底板这一侧不加 |
|
||||||
|
| `VDAC1`~`VDAC5` | **A3**(U6/U7) | **A5** | 模拟量,跨金手指进刀片 |
|
||||||
|
| `EFUSE_EN1`~`EFUSE_EN5` | **A3**(ESP32 直驱) | **A5** | 不经 IO 扩展 |
|
||||||
|
| `PRSNT1#`~`PRSNT5#` | **A5**(槽 **B31** 一针) | **A3**(ESP32 输入 + 上拉) | ⚠️ **2026-09-08 修正**:底板是**主板侧**,`A1` 与 `B31` 必须是**两个节点** —— `A1 → GND`、`B31 → PRSNT{n}#`。短接 A1↔B31 的是**刀片**(`b4_edge.py`,PCIe add-in card 的标准做法),插上刀片才把 B31 拉到地。若底板也照字面「镜像」把两针并成一个网,回路里一个对地通路都没有 ⇒ **插不插都读「未插入」,而 DRC/ERC/几何验证/跨页对账四道全过**。见 `a5_slots.py` 表头的对照表 |
|
||||||
|
| `INT#` | **A5**(五槽 B11 并联) | **A3**(ESP32 + **唯一一颗 10k 上拉到 +3V3**) | 开漏 wire-OR,五槽共一个网络 |
|
||||||
|
| `HUB_RST` | **A3**(ESP32) | **A4**(U32) | ⚠ 见 §3 的保命约束 |
|
||||||
|
| `UP_VBUS_DET` | **A4** | **A3**(ESP32) | 电脑在不在 |
|
||||||
|
| `USB1_DP/DM` ~ `USB5_DP/DM` | **A4**(U32 下行口 1~5) | **A5**(槽 B14/B15) | |
|
||||||
|
| `USB6_DP` / `USB6_DM` | **A4**(U32 下行口 6) | **A3**(ESP32 原生 USB,IO19=D−/IO20=D+) | D13 |
|
||||||
|
| `FAN_EN` | **A3**(ESP32) | **A6** | 高边总开关,复位态必须**关电** |
|
||||||
|
| `FAN_PWM` | **A3**(ESP32) | **A6** | 两只风扇共用(A6 里经反相成 `FAN_PWM_L`) |
|
||||||
|
| `FAN_TACH_IN` / `FAN_TACH_OUT` | **A6** | **A3**(ESP32) | 两路独立测速 |
|
||||||
|
| `NTC1` / `NTC2` | **A6**(RT601/RT602 分压节点) | **A3**(ESP32 **ADC1** 脚) | ⚠ 必须 ADC1(IO1~IO10),ADC2 与 WiFi 冲突 |
|
||||||
|
|
||||||
|
### 1.3 页内网络(不跨页,别在别的页上用这些名字)
|
||||||
|
|
||||||
|
- A3:`MUX_RST#`(U35 的 RESET#,10k 上拉 + 一个 ESP32 GPIO)、`EN` / `IO0` / `TXD0` / `RXD0`(J33)
|
||||||
|
- A4:`UP_DP` `UP_DM` `VBUS_UP` `VBUS_DET` `XTAL1` `XTAL2` `RBIAS` `VDD18` `VDD18PLL`
|
||||||
|
`CFGSEL0` `CFGSEL1` `NONREM0` `NONREM1`(全部沿用 R1 `C2-HUB` 的名字)
|
||||||
|
- A6:`FAN_PWM_L` `FAN_IN_TACH_RAW` `FAN_OUT_TACH_RAW`
|
||||||
|
- A5:无(全是 §1.2 的网络 + 电源 + 地)
|
||||||
|
|
||||||
|
### 1.4 **明确不存在**的网络(R1 有、R2 没有,写了就是错)
|
||||||
|
|
||||||
|
`BUCK_PG`(A2 的 U19 没引 PG)、`IOEXP_INT#`(改叫 `INT#`)、
|
||||||
|
`EFUSE_PG*` / `EFUSE_FLT*`(eFuse 在刀片上,状态走刀片自己的 PCA9555)、
|
||||||
|
`VBUS_EN*`(在刀片 B2-CTRL 上)、`KEY_*`(74HC595 已作废,D9)、
|
||||||
|
`USB_DP` / `USB_DM` 不带编号的形式(那是刀片页内的名字)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 2. 位号区段(防撞)
|
||||||
|
|
||||||
|
| 页 | 允许使用 |
|
||||||
|
|---|---|
|
||||||
|
| A1(已画) | `J1` `F1` `Q1` `Q3` `DZ1` `D1` `R1` `R4` `R5` `R6` `R9A~R9E` `C1~C6` `C11` `Rs6` `U13` `U29` |
|
||||||
|
| A2(已画) | `U19` `U30` `L2` `L3` `R2` `R3` `R706` `R707` `C7~C10` `C731~C735` |
|
||||||
|
| **A3-CTRL** | `U20` `U35` `U6` `U7` `J33`,新增无源件用 `R601~R650` / `C601~C650` |
|
||||||
|
| **A4-HUB** | `U31` `U32` `Y1` `J23`,无源件 `R708~R730` / `C737` `C740~C759` |
|
||||||
|
| **A5-SLOTS** / **A5B-SLOTS** | 插槽 `J34~J38`(槽 1~5)、D± 退路座 `J39~J43`,无源件 `R760~R790` / `C761~C790` |
|
||||||
|
| **A6-FAN** | `Q6~Q10` `D2` `DZ3` `J26` `J27` `RT601` `RT602`,电容 `C736` `C738` `C739`,电阻 `R733` `R734` `R746~R757` + 新增 `R660~R699` |
|
||||||
|
|
||||||
|
> ⚠️ **2026-09-08 修订**:原表里 A4 的 `C740~C760` 与 A5 的 `C760~C790` 在 `C760` 上撞车(A6 代理发现),
|
||||||
|
> 已改成 `C740~C759` / `C761~C790`。A6 原来只点名了 `C738`,现补 `C736` / `C739`(全表仅剩的两个无主号)。
|
||||||
|
> `A5B-SLOTS` 是 2026-09-08 新开的第七页(`e493f8bce3a51aae`),与 A5 共用同一段号。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 3. 三条会烧板 / 会自断后路的硬约束
|
||||||
|
|
||||||
|
1. **`HUB_RST` 必须外部上拉到 `+3V3_HUB`(10k),且 ESP32 复位期间 Hub 保持工作。**
|
||||||
|
ESP32 的控制台就挂在这颗 Hub 后面(D13),误复位 = 自断控制台 + 下次烧不进去。
|
||||||
|
固件侧只在启动自检脉冲一次 —— 硬件侧要保证「不驱动 = 不复位」。
|
||||||
|
2. **`FAN_EN` 复位态必须是关电。** Q7 是 P-MOS 高边,栅极靠 Q6 拉低才导通;
|
||||||
|
Q6 栅极要有 100k 下拉,ESP32 高阻时风扇不转(R1 P6 已经是这个拓扑,照抄)。
|
||||||
|
3. **`+3V3_HUB` 与 `+3V3` 是两条轨**(U32 满载 ≈420 mA,挂不进 U19 那条 0.5A 轨)。
|
||||||
|
两者只共地。A4 页上不许出现把它们并起来的导线或同名旗。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 4. 器件与引脚几何(全部实测,直接用,不要自己猜)
|
||||||
|
|
||||||
|
`.claude/eda-parts.json` 是器件表;下面是**这四页要用到的新器件**的引脚相对坐标(rot 0,相对元件中心):
|
||||||
|
|
||||||
|
```
|
||||||
|
TCA9548APWR (C130026) 左列 x=-50,右列 x=+50
|
||||||
|
1 A0 (-50, 55) 13 SD4 (50,-55)
|
||||||
|
2 A1 (-50, 45) 14 SC4 (50,-45)
|
||||||
|
3 RESET#(-50, 35) 15 SD5 (50,-35)
|
||||||
|
4 SD0 (-50, 25) 16 SC5 (50,-25)
|
||||||
|
5 SC0 (-50, 15) 17 SD6 (50,-15)
|
||||||
|
6 SD1 (-50, 5) 18 SC6 (50, -5)
|
||||||
|
7 SC1 (-50, -5) 19 SD7 (50, 5)
|
||||||
|
8 SD2 (-50,-15) 20 SC7 (50, 15)
|
||||||
|
9 SC2 (-50,-25) 21 A2 (50, 25)
|
||||||
|
10 SD3 (-50,-35) 22 SCL (50, 35)
|
||||||
|
11 SC3 (-50,-45) 23 SDA (50, 45)
|
||||||
|
12 GND (-50,-55) 24 VCC (50, 55)
|
||||||
|
|
||||||
|
NCP18XH103F03RB (C13564) 1 (-20,0) 2 (+20,0) 无极性
|
||||||
|
2.54mm 1*5P 直排针 (C50951) 1(-20,20) 2(-20,10) 3(-20,0) 4(-20,-10) 5(-20,-20) 全部朝左
|
||||||
|
AMS1117-3.3 (C6186) 1 GND(-45,10) 2 VOUT(-45,0) 3 VIN(-45,-10) 4 VOUT(+45,0)
|
||||||
|
PCIE-064-02-F-D-TH (C4597619) A1~A32: x=-35, y=155-10*(n-1)
|
||||||
|
B1~B32: x=+35, y=155-10*(n-1)
|
||||||
|
```
|
||||||
|
|
||||||
|
其余器件(ESP32-S3-WROOM-1 / DAC63204 / USB2517I / Y1 / AO3400A / AO3401A /
|
||||||
|
SS34 / BZT52C8V2 / TYPE-C-31-M-12 / 2510-4A / A1251WV-S-4P / 各种 0402)的引脚坐标
|
||||||
|
**从 R1 的实测 dump 里直接读**,见 §5。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 5. R1 参照版图(已 dump 成 JSON,直接读,**不要连 EDA**)
|
||||||
|
|
||||||
|
| 文件 | 是哪一页 | 给谁用 |
|
||||||
|
|---|---|---|
|
||||||
|
| `.claude/r2/_p3_live.json` | R1 `P3-CONTROL`(U20 ESP32 + J22 + RT601/602) | **A3**(ESP32 那一块整块搬)、**A6**(NTC 分压那一小块搬走) |
|
||||||
|
| `.claude/r2/_p3b_live2.json` | R1 `P3B-EXPAND`(U6/U7 DAC + U23 PCA9555) | **A3**(两颗 DAC 整块搬,U23 不要) |
|
||||||
|
| `.claude/r2/_c2hub_live.json` | R1 `C2-HUB`(U32 + Y1 + J23 + 一堆去耦) | **A4**(整页搬,加第 6 个下行口) |
|
||||||
|
| `.claude/r2/_p6_live.json` | R1 `P6-FAN-EDL`(风扇部分 + EDL 部分) | **A6**(**只要风扇部分**,EDL 已挪去刀片 B3-PHONE) |
|
||||||
|
| `.claude/r2/b4_edge.py` | R2 刀片 `B4-EDGE`(金手指 64 针分配) | **A5**(针位表照抄并做**逐脚对账**) |
|
||||||
|
|
||||||
|
JSON 结构见 `.claude/r2/dump_page.py` 的文档串:
|
||||||
|
`parts` = `[位号, 器件名, 子部件, x, y, rot, mirror, uuid, libraryUuid, [[脚号,脚名,x,y],...]]`,
|
||||||
|
`wires` = **端点对**(不是折线),`flags` = `[种类, 网名, x, y, rot]`,
|
||||||
|
`ports` = `[dir, 网名, x, y, rot]`,`texts` = `[x, y, 内容, rot, 字号]`。
|
||||||
|
|
||||||
|
⚠️ **搬版图时引脚坐标是绝对坐标**:算出 `(引脚x - 元件x, 引脚y - 元件y)` 得到相对量,
|
||||||
|
再加上你的新元件中心。**不要相信任何"方向表"**(skill §6c:同一个 `rot` 在不同型号上语义相反)。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 6. 每页交付物
|
||||||
|
|
||||||
|
一个 `.claude/r2/aN_xxx.py`,**照抄 `a1_input.py` / `a2_aux.py` 的骨架**:
|
||||||
|
|
||||||
|
```python
|
||||||
|
HERE = os.path.dirname(os.path.abspath(__file__))
|
||||||
|
sys.path.insert(0, HERE)
|
||||||
|
from schcheck import Sheet, by_rel, two_pin, pins_of, _on # 按需
|
||||||
|
|
||||||
|
PAGE, NAME = '<页uuid>', '<页名>'
|
||||||
|
|
||||||
|
def placement(): ... # [[位号, eda-parts的键, x, y, rot], ...]
|
||||||
|
def expect(): ... # {位号: {脚号: (绝对x, 绝对y)}} 放件后逐脚回读比对用
|
||||||
|
def build(): ... # 返回填好 W/F/PT/TX 的 Sheet
|
||||||
|
|
||||||
|
def main():
|
||||||
|
s = build(); s.assert_grid()
|
||||||
|
errs = s.netcheck(PINS, NC, ALLOW_SPLIT)
|
||||||
|
s.report(len(placement()), errs)
|
||||||
|
if '--push' in sys.argv:
|
||||||
|
s.clear(); s.place(placement(), expect()); s.push_geometry()
|
||||||
|
```
|
||||||
|
|
||||||
|
**页 uuid**(`.claude/r2/r2-uuids.json` 的 `boards.BASE.pages`):
|
||||||
|
|
||||||
|
| 页 | uuid |
|
||||||
|
|---|---|
|
||||||
|
| A3-CTRL | `38327f806bc13133` |
|
||||||
|
| A4-HUB | `09d583ff95cd35d9` |
|
||||||
|
| A5-SLOTS | `2c73c5bf77f34053` |
|
||||||
|
| A6-FAN | `68c9ffaa578572d3` |
|
||||||
|
|
||||||
|
跑 `/c/Python314/python .claude/r2/aN_xxx.py`(**不带 `--push`**)必须打印出:
|
||||||
|
|
||||||
|
```
|
||||||
|
元件 N 导线 N 旗 N 端口 N 文字 N
|
||||||
|
交叉点(不相连,供人工确认): N
|
||||||
|
本地自检通过(短路 0 / 漏连 0 / 悬空 0 / 旗端口全在端点)
|
||||||
|
```
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 7. 画图硬规矩(全部来自 `.claude/skills/easyeda-sch-geometry/SKILL.md`,**先读它**)
|
||||||
|
|
||||||
|
1. **Y 轴向上**(§1)。
|
||||||
|
2. 所有坐标必须是 **5 的倍数**(§3、§8a-2b)—— 否则旗/端口静默不连。
|
||||||
|
3. 导线只能**横平竖直**,用 `s.w(net, p1, p2, p3...)` 逐段声明。
|
||||||
|
4. 旗 / 端口的锚点必须落在**某段导线的端点**上,不能压在中段(§8a-2),
|
||||||
|
也不能和元件引脚**同坐标**(§8a:那会变成零长度导线,验证过得去、重画就断)。
|
||||||
|
5. 同一个锚点上如果有两段**共线**的导线,合并后就成了中段 —— `netcheck` 会报。
|
||||||
|
6. 页面范围 `x 20~1145` / `y 10~812`;**标题栏**在 `x>455 且 y<192`,文字不许伸进去(§8c)。
|
||||||
|
7. 文字宽度经验值:`右边界 ≈ x + 字号 × (中文字数 + 0.5×其余字符数)`。
|
||||||
|
8. **叠字是这个项目的常见事故**:端口的符号+标签往锚点**左边**伸出去约 70 个单位,
|
||||||
|
`flag_clash` 那种「横向 <20」的判据够不着。排版时给端口左边留 ≥80 的空白。
|
||||||
|
9. 电源/地旗的 `rot`:`0` = 符号朝上(往上挂),`180` = 朝下。极性件别信方向表,按**脚号**断言。
|
||||||
|
10. `ALLOW_SPLIT` 只放行「靠同名旗/端口成网、导线上天然分块」的网络(`GND` `+12V` `+3V3` `+5V` 这类)。
|
||||||
|
信号网络出现「被拆成 N 块」就是真漏连,不许往 `ALLOW_SPLIT` 里加来消错。
|
||||||
|
|
||||||
|
---
|
||||||
|
|
||||||
|
## 8. 汇报格式
|
||||||
|
|
||||||
|
做完后回报(**不要贴整段脚本**):
|
||||||
|
|
||||||
|
1. 脚本路径 + dry-run 的那三行统计输出(原样贴)。
|
||||||
|
2. 本页画了什么(一句话一块)。
|
||||||
|
3. **你发出/接收的端口清单**(网名 + dir),主代理要拿它对账。
|
||||||
|
4. 你做的**设计决定**与依据(尤其是 GPIO 分配、strap 电平、上下拉取值)。
|
||||||
|
5. 你发现的**风险 / 与方案文档不一致的地方**(B3=+12V 那种错就是这么揪出来的)。
|
||||||
|
6. 交叉点清单(如果有),说明为什么可接受。
|
||||||
|
之后 宽度: | 高度: | 大小: 564 KiB |
|
之后 宽度: | 高度: | 大小: 205 KiB |
|
之后 宽度: | 高度: | 大小: 524 KiB |
|
之后 宽度: | 高度: | 大小: 457 KiB |
|
之后 宽度: | 高度: | 大小: 509 KiB |
@@ -0,0 +1,38 @@
|
|||||||
|
# M6 手工补线作业单(按板上实际铜算,5 个网)
|
||||||
|
|
||||||
|
布线方向约定:底层(器件面)纵向、顶层横向;信号线宽 0.15,过孔 0.6/0.3。
|
||||||
|
⚠ 这些脚的出口都被**自家邻脚的引出脚 / 过孔**封死(如 `U2.15` 被 `EFUSE_EN` 的孔 (89.5,31) 卡到只剩 0.04 mm),脚本布线器四种办法(换顺序 / PathFinder / 只补线 / 过孔扇出)都到不了。交互式布线时先挪开挡路的那根引出脚或过孔再拉线。
|
||||||
|
|
||||||
|
|
||||||
|
## VDAC(2 只脚)— R8.2 一根铜都没有
|
||||||
|
- `J1.A16` (49.50, 3.45) 底层
|
||||||
|
- `R8.2` (93.50, 49.85) 底层
|
||||||
|
现有铜 7.8 mm
|
||||||
|
|
||||||
|
## $1N147(3 只脚)— U2.15 一根铜都没有
|
||||||
|
- `R9.2` (77.20, 27.35) 底层
|
||||||
|
- `R10.1` (79.33, 27.35) 底层
|
||||||
|
- `U2.15` (89.75, 30.02) 底层
|
||||||
|
现有铜 2.1 mm
|
||||||
|
|
||||||
|
## $1N156(2 只脚)— R11.1 U2.17 一根铜都没有
|
||||||
|
- `R11.1` (82.33, 27.35) 底层
|
||||||
|
- `U2.17` (91.00, 29.27) 底层
|
||||||
|
现有铜 0.0 mm
|
||||||
|
|
||||||
|
## EFUSE_PG(3 只脚)— U2.2 一根铜都没有
|
||||||
|
- `R15.1` (79.33, 31.35) 底层
|
||||||
|
- `U2.2` (89.75, 27.02) 底层
|
||||||
|
- `U4.16` (79.32, 20.12) 底层
|
||||||
|
现有铜 52.7 mm
|
||||||
|
|
||||||
|
## $1N165(8 只脚)— R16.1 一根铜都没有
|
||||||
|
- `R16.1` (79.33, 29.35) 底层
|
||||||
|
- `Rs1.2` (87.87, 23.04) 底层
|
||||||
|
- `U2.6` (87.75, 27.02) 底层
|
||||||
|
- `U2.5` (88.25, 27.02) 底层
|
||||||
|
- `U2.4` (88.75, 27.02) 底层
|
||||||
|
- `U2.8` (87.00, 28.27) 底层
|
||||||
|
- `U2.7` (87.00, 27.77) 底层
|
||||||
|
- `U3.10` (85.05, 19.10) 底层
|
||||||
|
现有铜 23.1 mm
|
||||||
@@ -0,0 +1,92 @@
|
|||||||
|
# 手工布线作业单(13 条)
|
||||||
|
|
||||||
|
布线方向约定:**底层(器件面)纵向、顶层横向**;线宽 ≥ 规则下限(信号 0.15)。
|
||||||
|
|
||||||
|
## VBUS_EN(3 只脚)
|
||||||
|
- `R62.2` (59.20, 14.85) 底层
|
||||||
|
- `U4.8` (73.28, 19.47) 底层
|
||||||
|
- `U5.3` (42.45, 21.45) 底层
|
||||||
|
现有铜 0.00 mm;一根都没有,整条要画
|
||||||
|
|
||||||
|
## EFUSE_EN(4 只脚)
|
||||||
|
- `J1.A11` (42.50, 3.45) 底层
|
||||||
|
- `Q1.1` (78.55, 35.28) 底层
|
||||||
|
- `R14.1` (82.33, 31.35) 底层
|
||||||
|
- `U2.14` (89.25, 30.02) 底层
|
||||||
|
现有铜 88.19 mm;已有部分,缺的是把它们连成一片
|
||||||
|
|
||||||
|
## $1N164(3 只脚)
|
||||||
|
- `R16.2` (80.20, 29.35) 底层
|
||||||
|
- `R17.1` (82.33, 29.35) 底层
|
||||||
|
- `U2.3` (89.25, 27.02) 底层
|
||||||
|
现有铜 2.13 mm;已有部分,缺的是把它们连成一片
|
||||||
|
|
||||||
|
## USB_DPJ(2 只脚)
|
||||||
|
- `J4.6` (48.26, 19.94) 顶层
|
||||||
|
- `U7.3` (49.04, 17.75) 底层
|
||||||
|
现有铜 0.00 mm;一根都没有,整条要画
|
||||||
|
|
||||||
|
## $1N151(2 只脚)
|
||||||
|
- `R12.2` (77.20, 29.35) 底层
|
||||||
|
- `U2.19` (91.00, 28.27) 底层
|
||||||
|
现有铜 0.00 mm;一根都没有,整条要画
|
||||||
|
|
||||||
|
## SCL(4 只脚)
|
||||||
|
- `J1.B5` (36.50, 3.45) 顶层
|
||||||
|
- `R41.1` (77.83, 25.45) 底层
|
||||||
|
- `U3.5` (83.05, 14.87) 底层
|
||||||
|
- `U4.22` (79.32, 16.23) 底层
|
||||||
|
现有铜 245.61 mm;已有部分,缺的是把它们连成一片
|
||||||
|
|
||||||
|
## KEY_PWR(2 只脚)
|
||||||
|
- `R42.2` (2.30, 22.85) 底层
|
||||||
|
- `U4.4` (73.28, 16.88) 底层
|
||||||
|
现有铜 0.00 mm;一根都没有,整条要画
|
||||||
|
|
||||||
|
## INT#(2 只脚)
|
||||||
|
- `J1.B11` (42.50, 3.45) 顶层
|
||||||
|
- `U4.1` (73.28, 14.93) 底层
|
||||||
|
现有铜 7.75 mm;已有部分,缺的是把它们连成一片
|
||||||
|
|
||||||
|
## PRSNT#(2 只脚)
|
||||||
|
- `J1.A1` (32.50, 4.00) 底层
|
||||||
|
- `J1.B31` (64.50, 4.00) 顶层
|
||||||
|
现有铜 15.50 mm;已有部分,缺的是把它们连成一片
|
||||||
|
|
||||||
|
## +3V3(14 只脚)
|
||||||
|
- `C13.1` (86.38, 18.00) 底层
|
||||||
|
- `C40.1` (72.30, 25.45) 底层
|
||||||
|
- `C69.1` (67.30, 22.35) 底层
|
||||||
|
- `J1.A10` (41.50, 3.45) 底层
|
||||||
|
- `J1.A9` (40.50, 3.45) 底层
|
||||||
|
- `J1.B8` (39.50, 3.45) 顶层
|
||||||
|
- `R13.1` (76.33, 31.35) 底层
|
||||||
|
- `R15.2` (80.20, 31.35) 底层
|
||||||
|
- `R18.1` (80.83, 33.35) 底层
|
||||||
|
- `R40.2` (75.70, 25.45) 底层
|
||||||
|
- `R41.2` (78.70, 25.45) 底层
|
||||||
|
- `U3.6` (83.05, 19.10) 底层
|
||||||
|
- `U4.24` (79.32, 14.93) 底层
|
||||||
|
- `U6.5` (65.30, 21.30) 底层
|
||||||
|
现有铜 131.15 mm;已有部分,缺的是把它们连成一片
|
||||||
|
|
||||||
|
## VBUS(6 只脚)
|
||||||
|
- `C67.1` (44.80, 14.85) 底层
|
||||||
|
- `J4.51` (45.73, 21.00) 顶层
|
||||||
|
- `R64.2` (45.70, 16.85) 底层
|
||||||
|
- `U5.5` (45.15, 20.50) 底层
|
||||||
|
- `U5.6` (45.15, 19.55) 底层
|
||||||
|
- `U7.5` (48.09, 15.45) 底层
|
||||||
|
现有铜 21.65 mm;已有部分,缺的是把它们连成一片
|
||||||
|
|
||||||
|
## EFUSE_FLT(3 只脚)
|
||||||
|
- `R13.2` (77.20, 31.35) 底层
|
||||||
|
- `U2.20` (91.00, 27.77) 底层
|
||||||
|
- `U4.13` (79.32, 22.07) 底层
|
||||||
|
现有铜 57.31 mm;已有部分,缺的是把它们连成一片
|
||||||
|
|
||||||
|
## EFUSE_PG(3 只脚)
|
||||||
|
- `R15.1` (79.33, 31.35) 底层
|
||||||
|
- `U2.2` (89.75, 27.02) 底层
|
||||||
|
- `U4.16` (79.32, 20.12) 底层
|
||||||
|
现有铜 49.57 mm;已有部分,缺的是把它们连成一片
|
||||||
|
之后 宽度: | 高度: | 大小: 440 KiB |
|
之后 宽度: | 高度: | 大小: 282 KiB |
|
之后 宽度: | 高度: | 大小: 281 KiB |
|
之后 宽度: | 高度: | 大小: 264 KiB |
|
之后 宽度: | 高度: | 大小: 284 KiB |
|
之后 宽度: | 高度: | 大小: 272 KiB |
|
之后 宽度: | 高度: | 大小: 595 KiB |
|
之后 宽度: | 高度: | 大小: 522 KiB |
|
之后 宽度: | 高度: | 大小: 608 KiB |
|
之后 宽度: | 高度: | 大小: 97 KiB |
|
之后 宽度: | 高度: | 大小: 134 KiB |
|
之后 宽度: | 高度: | 大小: 243 KiB |
|
之后 宽度: | 高度: | 大小: 366 KiB |
|
之后 宽度: | 高度: | 大小: 468 KiB |
|
之后 宽度: | 高度: | 大小: 482 KiB |
|
之后 宽度: | 高度: | 大小: 243 KiB |
|
之后 宽度: | 高度: | 大小: 138 KiB |
|
之后 宽度: | 高度: | 大小: 141 KiB |
|
之后 宽度: | 高度: | 大小: 188 KiB |
|
之后 宽度: | 高度: | 大小: 474 KiB |
|
之后 宽度: | 高度: | 大小: 319 KiB |
|
之后 宽度: | 高度: | 大小: 592 KiB |
|
之后 宽度: | 高度: | 大小: 404 KiB |
|
之后 宽度: | 高度: | 大小: 524 KiB |
|
之后 宽度: | 高度: | 大小: 734 KiB |
|
之后 宽度: | 高度: | 大小: 426 KiB |
|
之后 宽度: | 高度: | 大小: 426 KiB |
|
之后 宽度: | 高度: | 大小: 273 KiB |
|
之后 宽度: | 高度: | 大小: 413 KiB |
|
之后 宽度: | 高度: | 大小: 423 KiB |
|
之后 宽度: | 高度: | 大小: 392 KiB |
|
之后 宽度: | 高度: | 大小: 302 KiB |
|
之后 宽度: | 高度: | 大小: 379 KiB |
|
之后 宽度: | 高度: | 大小: 270 KiB |
|
之后 宽度: | 高度: | 大小: 422 KiB |
|
之后 宽度: | 高度: | 大小: 350 KiB |
|
之后 宽度: | 高度: | 大小: 458 KiB |
|
之后 宽度: | 高度: | 大小: 372 KiB |