# 五路手机直供电源板 —— 项目需求文档 | 项 | 值 | |---|---| | 文档版本 | **v1.2**(2026-09-06)—— 上位机链路定稿为**方案 C(WiFi 常态 + USB CDC 兜底)**,回填 §10.8,新增 D5a / SW-12 / IF-19 与两条验收
v1.1 —— 新增 **§10 软件架构设计**,原 §10~§14 顺延为 §11~§15 | | 项目代号 | PhoneRail | | 对应设计文档 | `五路直供电源板设计.md` v1.6 及其后续增补(§22 起的两板架构) | | 状态 | 需求已冻结;硬件处于 PCB 布线阶段(见 `PROGRESS.md`) | > **本文档与设计文档的分工** > 本文只回答 **「要做成什么样、凭什么算做到了」**; > **「怎么做到」** 一律在 `五路直供电源板设计.md` 里,本文只给条目号交叉引用。 > 两者冲突时:**电气数值以设计文档为准**(它是逐项算过并对过 datasheet 的), > **需求的取舍与验收标准以本文为准**。 > 设计文档 §0.1 的 13 条决策已定稿,本文把它们表述成需求,不重新讨论。 > **唯一的例外是 §10 软件架构设计** —— 那是「怎么做」,但固件在设计文档里没有落脚点, > 暂放本文,理由写在该节开头。 --- ## 1. 背景与目标 ### 1.1 要解决的问题 手机农场里成排运行的小米8(dipper)主板,用原装电池供电有三个绕不开的问题: 1. **电池会老化、会鼓包**,几十台规模下变成持续的维护负担和安全隐患; 2. **手机卡死时没法远程恢复** —— 人必须跑到机架前拔电池 / 长按电源键; 3. **充电管理系统一直在工作**,长期 100% 电量反而触发系统的异常逻辑。 ### 1.2 项目目标 做一块**电池位直供**的电源板:拆掉电芯与保护板,从主板电池座直接灌一个受控的、 稳定在正常锂电范围内的电压;同时把「断电重启、按键模拟、进 Fastboot / 9008、 USB 通断」这些原本要人手做的动作全部电气化,交给板上 MCU 远程执行。 **一句话验收目标**:五台小米8 主板挂在这套板子上连续跑 24 小时无异常重启, 任何一台卡死时都能在**不到机架前**的情况下恢复到正常运行状态。 ### 1.3 目标用户与使用场景 | 用户 | 场景 | |---|---| | 农场运维 | 日常挂机;某台无响应时下发一次重启;查某台的电流曲线定位接触不良 | | 刷机 / 开发 | 远程进 Fastboot 或 9008(EDL) 刷包;有线 adb 抓日志 | | 本项目自身 | 首板调试、长稳测试、失效注入验证 | --- ## 2. 范围 ### 2.1 交付范围(In Scope) | # | 交付物 | |---|---| | D1 | **下板(电源板)**:12V 输入 → 五路 4 A 直供 + eFuse + 遥测 + ESP32-S3 控制 | | D2 | **上板(载板)**:五块主板的机械承载 + 板载 USB Hub + VBUS 开关 + 侧键顶针 + EDL 口 | | D3 | 两板对插的板对板接口(两条 2×20 排针,共 80 针) | | D4 | 手机侧线束与离板电容组(电池排线改造、尾插 USB 线、EDL 引线) | | D5 | ESP32-S3 固件(遥测、两级重启、按键 / EDL 模拟、VBUS 通断、风扇闭环、告警) | | D5a | **双链路命令接口**(2026-09-06 用户拍板):**WiFi 为常态、USB CDC 为兜底**,两条链路共用同一套命令语义。上位机侧的调用方由农场既有系统实现(N7),本项目交付板侧协议与实现,见 §10.8 | | D6 | 完整原理图(11 页)+ 两块 PCB + BOM + 首板调试与验收记录 | ### 2.2 明确不做(Out of Scope) | # | 不做 | 理由 | |---|---|---| | N1 | 电池充放电管理、模拟真实电池阻抗 | 直供不需要,电芯已移除 | | N2 | 支持 1S 以外的机型 / 非小米8 主板 | 全部机械与引脚定义都是 dipper 专用(§13) | | N3 | 自制 USB-C 尾插转接板 | 决策 10:装原厂尾插小板,口温 NTC / CC / ESD / 天线馈点全在上面 | | N4 | USB PD / BC1.2 协商,接快充充电器 | 决策 11:上游只接电脑 / Hub,VBUS 恒 5 V | | N5 | 把过流保护做进 MCU 实时环路 | 那是 eFuse 的职责(SR-3) | | N6 | 五路 Buck 错相同步 | §8.4 已否决:器件离散度远大于想制造的相位差 | | N7 | 上位机管理软件 / Web 界面 | 本期只交付固件与命令接口,上层由农场既有系统对接 | --- ## 3. 系统组成(需求视角) ```diagram=system 12V/10A 适配器 │ ┌────┴─────────────── 下板(电源 + 大脑)────────────────────┐ │ 输入保护 → 五路独立 Buck → eFuse → 分流检测 → 输出 │ │ ESP32-S3 + DAC ×2 + INA226 ×6 + 74HC595 ×3 + PCA9555 │ │ 侧键驱动管 ×15 · 风扇驱动 · 辅助 3V3 / 5V │ └────┬──────────── 2×20 排针 ×2(无高速信号)─────────────────┘ ┌────┴─────────────── 上板(载板)────────────────────────────┐ │ 5 × 小米8 主板(NPTH 定位孔 + 尼龙立柱) │ │ USB2517I 7 口 Hub + 上游 USB-C + VBUS 负载开关 ×5 │ │ 侧键顶针 ×15 · EDL 模拟开关 ×5 · P+/P− 焊盘 + 电容组 ×5 │ └──────────────────────────────────────────────────────────────┘ ``` 两板之间保留 **13 mm 缝**,既是装配空间也是散热风道。 --- ## 4. 功能需求(FR) | ID | 需求 | 优先级 | 设计出处 | |---|---|---|---| | **FR-1** | 同时为 **5 台**小米8 主板供电,各路**电气独立**(独立回流地,不在手机端共地) | 必须 | §1 / §6.4 | | **FR-2** | 每路输出电压可**独立微调**,调节在正常锂电范围内进行,步进优于 1 mV | 必须 | §4 | | **FR-3** | 每路可**独立硬断电并主动放电**,实现真正意义上的「拔电池」 | 必须 | §7 | | **FR-4** | 每台手机可模拟 **3 个侧键**(PWR / VOL+ / VOL−),支持组合键 | 必须 | §13.3 | | **FR-5** | 每台手机可远程进入 **EDL(9008)** 模式 | 必须 | §22.4 | | **FR-6** | 每台手机的 **USB VBUS 可独立通断**,默认断开 | 必须 | §15.1 | | **FR-7** | 对外只用**一根 USB 线**,五路下行由板载 Hub 分 | 必须 | §15.1 | | **FR-8** | 每路可实时读取**输出电压与电流**;整板可读取**输入电压与电流** | 必须 | §8.2 | | **FR-9** | 上报每路 eFuse 故障、电源好(PG)等状态 | 必须 | §8.2 | | **FR-10** | 主动风冷,风扇转速可调、可检测「有风扇停转」 | 必须 | §22.6 | | **FR-11** | 记录过流 / 故障事件(哪一路、何时、多大电流) | 高 | §8.3 | | **FR-12** | 模拟电量曲线,避免系统因「电量永远 100%」触发异常逻辑 | 中(可选) | §8.3 | | **FR-13** | 板级温度监控,超阈值先降流再关路 | 高 | §8.3 | | **FR-14** | 整板功率预算,超过适配器能力时按优先级降载 | 中 | §8.3 | | **FR-15** | 调试口不依赖外部转串口芯片,插上 USB-C 即可下载与看日志 | 必须 | §8.1 | ### 4.1 崩溃恢复流程(FR-3 / FR-4 的组合,本项目的核心价值) 固件必须实现**两级重启**,且**先软后硬**: | 级 | 动作 | 触发条件 | 要求 | |---|---|---|---| | 一级(软) | 长按电源键 ≈10 s | `adb` 探活连续失败 N 次,或电流曲线卡死 | 优先使用,对闪存和文件系统友好 | | 二级(硬) | `EFUSE_EN` ↓ → 放电 → 等 3~5 s → `EFUSE_EN` ↑ | 一级无效 | 输出必须真的掉到 <0.5 V,不能靠自然放电 | > **为什么二级必须有主动放电**:手机侧 2200 µF 配 ≈50 µA 关机待机电流,自然放电到安全 > 电压要 **154 秒**,「断电 10 秒」根本不触发重启。见 §7.1。 --- ## 5. 电气与性能需求(PR) | ID | 参数 | 要求 | 出处 | |---|---|---|---| | **PR-1** | 输入电压 | 12 V ±10%,成品适配器 | §1 | | **PR-2** | 输入电流 | ≤ 8 A(含风扇 ≈8.3 A),建议配 12 V / 10 A(120 W) | §1 / §22.6 | | **PR-3** | 输出路数 | 5,彼此独立不共地 | §1 | | **PR-4** | 输出电压范围 | **3.52 ~ 4.01 V** 连续可调 | §4.3 | | **PR-5** | **硬件电压上限** | 标称 **4.01 V**,最坏容差 **4.12 V**,**软件无法越过** | §4.4 | | **PR-6** | 电压设定分辨率 | 12 位 DAC 微调,步进 ≈0.12 mV | §4.5 | | **PR-7** | 输出电流 | 4 A / 路(峰值);手机常态 0.3 ~ 1 A | §1 | | **PR-8** | 输出纹波 | < 20 mVpp(板端测试点) | §1 | | **PR-9** | 开关频率 | 480 kHz,五路统一,不错相 | §1 / §8.4 | | **PR-10** | 整板功率 | 峰值 80 W(不会发生);常态 10 ~ 25 W | §1 | | **PR-11** | 电流测量分辨率 | ≥ 0.5 mA(5 mΩ 分流 + Kelvin 四线) | §8.2 | | **PR-12** | 负载阶跃响应 | 0→4 A 阶跃(带 20 cm 线 + 电容组)压降 < 300 mV,**无 6 kHz 振铃** | §6.2 | | **PR-13** | 满载温升 | 4 A 连续 30 min,电感 / IC 温升 < 40 K | §11 | | **PR-14** | 断电放电时间 | `EFUSE_EN` ↓ 后 **200 ms 内**输出 < 0.5 V | §7.2 | | **PR-15** | 上电斜坡 | 缓启动 0.36 V/ms,涌流 ≤ 0.8 A;`EN`↑ 到稳定 ≈17 ms | §5 | ### 5.1 输出上限为什么定在 4.01 V(这条需求的来源) 去掉原厂保护板后,输出上限**由 1S 锂电端子的绝对上限 4.45 V 反推**,而不是由保护板决定。 4.01 V 这个数字不是「够用就行」,是为了**给 eFuse 的过压跳闸窗口让开 86 mV** —— 若按早期的 4.22 V,第一层的最坏输出(4.34 V)会和 eFuse 的最坏跳闸下沿(4.206 V)重叠, 坏角落下 DAC 失效会**误跳保护**。详见 §5 的容差窗口分析。 **因此 PR-4 / PR-5 是安全需求的一部分,不得为了「多给一点电压」而放宽。** --- ## 6. 安全需求(SR)—— 本项目最高优先级 > **必须记录的失效模式**:直供电最致命的失效**不是固件写错电压值**,而是 > **反馈分压的下电阻开路 → FB = 0 V → Buck 满占空比 → 输出直接跳到 12 V**。 > **软件对此完全无能为力。** 全部安全需求都要围绕这一条来读。 | ID | 需求 | 出处 | |---|---|---| | **SR-1** | **三层保护彼此独立**:任何一层单独失效都不得导致手机损坏 | §5 | | **SR-2** | **第一层 · 拓扑限幅**:分压网络与 DAC 量程在物理上把输出限死在 3.42 ~ 4.12 V(含最坏容差),全部落在正常锂电电压内。防固件 bug / I²C 误码 / MCU 跑飞 | §4 | | **SR-3** | **第二层 · eFuse 独立过压断开**(每路一颗,**最后一道硬件防线**):OVP 4.36 V 标称、**断开而非钳位**、响应 2 µs;限流 4.45 A 恒流、不依赖 MCU | §5 | | **SR-4** | eFuse 的过压响应**必须来得及**:按最坏值(Buck 高侧限流 14 A、负载 2200 µF)核算,余量 ≥ 10 倍 | §5 | | **SR-5** | **第三层 · 软件监控**:电压偏离设定 >±100 mV 且持续 20 ms → 拉低该路 EN 并上报。**仅承担记录与告警,不承担实时保护** | §5 | | **SR-6** | **复位安全**:ESP32 复位 / 上电期间,五路输出全关、五路 VBUS 全断、15 路按键全不按、5 路 EDL 全不触发、风扇不转。靠**上下拉电阻**保证,不靠固件 | §8.1 / §22.4 | | **SR-7** | 放电 MOS 与 eFuse EN **硬件反相联锁**,物理上不可能同时导通 | §7.3 | | **SR-8** | **输入保护**:保险丝 + TVS + P-MOS 反接保护 | §2 | | **SR-9** | **12 V 母线泄放**:母线 >13.2 V 时导通泄放,防 USB 反灌或突卸能量抬高母线 | §15.2 | | **SR-10** | **USB 反灌三条对策全做,一条都不能省**:① 软件关充电 ② VBUS 负载开关 ③ 母线泄放 | 决策 12 / §13.5 | | **SR-11** | 上游 USB 不做 PD 协商(CC 双 5.1 kΩ 下拉,纯 UFP),杜绝 VBUS 被抬到 9 / 12 V | §15.1 | | **SR-12** | 五台手机的地**不得**在载板上并成一根:定位孔做 **NPTH**,立柱用**尼龙** | §25.2 | | **SR-13** | 固件**不得**提供任何能让输出超过 4.2 V 的接口 | §8.3 | | **SR-14** | 任一路输出**不得**给 ESP32 供电(用独立的 12 V→3.3 V 小 Buck) | §8.3 | | **SR-15** | 电源**必须**接原厂排线的 `P+`/`P−`(保护板输出侧),**不是** `B+`/`B−` | 决策 6 / §13.5 | > ⚠️ **SR-15 是最容易在装配环节做错、且常温下完全测不出来的一条。** > 焊在 `B+`/`B−` 时一切表现正常,只有过压时才暴露 —— 那时保护板仍串在通路里。 > 判别与验证步骤见 §13.5 / §13.7,已列为打样前阻塞项(V-1)。 > ⚠️ **`J600` 的 `GND3`/`GND4` 固定脚实际接的是 VBATT,`J1401` 的 `GND2` 是 USB_VBUS。** > 按名字当地用会直接短路电池。 --- ## 7. 接口需求(IF) > **编号只增不改**:新增接口一律取下一个空号,位置按逻辑归类 —— > 所以表内序号不一定连续(如 IF-19 排在 IF-14 后面)。ID 是稳定的引用标识, > 不是目录序号;改动已有编号会让所有交叉引用与验收记录失效。 ### 7.1 手机侧接口(每台一套) | ID | 接口 | 要求 | 出处 | |---|---|---|---| | **IF-1** | 供电 | 原装 BM3E 电池排线的 `P+`/`P−` 焊点;保留 BTB 公座 / NTC / ID,**旁路保护板**;电芯移除 | §13.2 / §13.5 | | **IF-2** | 侧键 | J601(VOL+) / J602(VOL−) / J603(PWR) / J604(公共地),**对地短接**方式,绝不从外部灌电压 | §13.3 | | **IF-3** | EDL | 短接主板上的 TP1204 ↔ TP1205(1.8 V / 1 mA),用**模拟开关**,不用普通 N-MOS | §22.4 | | **IF-4** | USB | 装**原厂尾插小板**,本板只接 VBUS / D± / GND 四根 | 决策 10 / §15.1 | | **IF-5** | 离板电容组 | 每路 2200 µF **普通铝电解**(靠 ESR 阻尼)+ 100 µF ×2 + 22 µF ×2 + 100 nF,**必须装在排线端,不在电源板上** | §6.3 | | **IF-6** | 线缆 | ≤ 20 cm、18 AWG 或更粗、正负双绞或紧贴平行;板端用 Micro-Fit 3.0 / XT30,**不用杜邦线** | §6.4 | > ⚠️ **IF-5 的 2200 µF 千万不能买成聚合物电容。** 整个阻尼设计靠的就是普通铝电解那 > 几十 mΩ 的 ESR;换成 12 mΩ 的聚合物,Q 从 0.19 跳回 4.5,线缆 LC 会在 6.2 kHz 上振铃。 > ⚠️ **IF-5 的大电容必须在排线端。** 放在电源板上等于隔着 300 nH 的线缆电感,基本无效。 ### 7.2 板对板接口 | ID | 需求 | 出处 | |---|---|---| | **IF-7** | 两条 2×20 排针(共 80 针),分列板子两端 | §22.2 / §25.10 | | **IF-8** | **一根高速差分都不穿连接器** —— Hub、上游 USB-C、VBUS 开关全部上移到载板 | §22.1 | | **IF-9** | 排针只走电源与低速控制;每路 `P+`/`P−` 独立分配针位,保证独立回流(FR-1) | §22.2 | | **IF-10** | 两板间净空 13 mm;载板底面元件与下板高元件的高度预算必须逐点核过 | §26.2 | ### 7.3 对外接口 | ID | 接口 | 要求 | |---|---|---| | **IF-11** | 电源输入 | DC 12 V 插座(XT30 级),配 10 A 适配器 | | **IF-12** | 上游 USB | 载板 USB-C(UFP),一根线接电脑 | | **IF-13** | 调试 USB | 下板 USB-C,ESP32-S3 原生 USB-Serial-JTAG;**VBUS 故意不接**(物理上杜绝反灌 3V3)。**同一个口兼作 SW-12 的兜底命令链路**(原生 USB-Serial-JTAG 本身就是 CDC-ACM,不影响 esptool 下载),分帧要求见 §10.8 | | **IF-14** | 风扇 | 5 × KF2510-3A(+12 V / 回流 / TACH) | | **IF-19** | 控制网络 | **WiFi(ESP32-S3 板载,无需增加器件)**,SW-12 的常态命令链路。凭据与服务端地址存 NVS,**不编译进固件** —— 新板上架时先用 IF-13 的 USB 链路配网 | > ⚠️ **IF-12 与 IF-13 是两个长得一样的 USB-C,插错的现象是「adb 整排不见」**, > 很难联想到是插错口。**丝印必须写清楚**,建议用不同颜色座子或在外壳上做标记。 ### 7.4 内部数字接口 | ID | 需求 | |---|---| | **IF-15** | I²C 单条总线挂 10 个器件:INA226 ×6(0x40/41/44/45/42/43)、DAC63204 ×2(0x4A / 0x4B)、PCA9555(0x20)、LM75BD(0x48),地址互不冲突 | | **IF-16** | ⚠️ **INA226 的通道号 ≠ 地址低位**(为布线让路重排过),固件必须**查表**,不能算 | | **IF-17** | 74HC595 ×3 级联成 **24 位**移位链:15 路侧键 + `HUB_RST` + 5 路 `EDL_EN`;**先移入的字节落在 U33 上** | | **IF-18** | `EFUSE_EN` ×5 与 `VBUS_EN` ×5 **必须 GPIO 直连**,不得经移位寄存器 —— 安全关键,故障瞬间要能立刻关断 | --- ## 8. 机械与热需求(MR / TR) | ID | 需求 | 出处 | |---|---|---| | **MR-1** | 载板 220 × 135 mm,四角 R5;五块主板 **3+2 双排面对面**,第二排居中 | §25.1 | | **MR-2** | 下板 160 × 125 mm,装配时相对载板原点偏移 (30, 5) | §25.2 | | **MR-3** | 每台手机 7 个定位孔,全部 **NPTH Φ2.5 + 尼龙立柱**(见 SR-12) | §25.2 | | **MR-4** | 侧键用顶针接触,顶针焊盘必须避免把相邻触点短路 | §25.3 | | **MR-5** | 排线穿槽:电池排线 8×38 → 槽 10×3.0;尾插排线 18×55 → 槽 20×3.0(在 J1401 正下方) | §25.16 | | **TR-1** | 总热负荷 ≈25 W(5×SDM845 满载 10~15 W + 下板功率级 ≈9 W) | §22.6 | | **TR-2** | 强制风冷 **4 进 1 出 = 机箱正压**(灰尘往外走);两板间 13 mm 缝作天然风道 | §22.6 | | **TR-3** | 所需风量仅 ≈2.9 CFM,**风量不是瓶颈,风道与正压才是设计要点** | §22.6 | | **TR-4** | 风扇 5 × 12 V ≈0.70 A;低边 N-MOS + PWM,漏极**必须并续流二极管** | §22.6 | | **TR-5** | 风扇闭环的测温点**放载板**(测的是手机),不能用下板功率级的两路 NTC 做反馈 | §22.6 | | **TR-6** | TACH 必须分压后再进 GPIO;⚠️ 低边调速下 **PWM 关断期间读不到转速**,固件需在导通窗口采样 | §22.6 | --- ## 9. 固件需求(SW) > 本节只列「固件要做到什么」。**怎么组织成一份固件见 §10 软件架构设计。** ### 9.1 必做 | ID | 需求 | |---|---| | **SW-1** | 崩溃检测 + 两级自动重启(§4.1)—— **整块板子最核心的价值** | | **SW-2** | 20 ms 周期巡检六路 INA226,电压偏离 >±100 mV 持续 20 ms 即关路告警(SR-5) | | **SW-3** | 过流 / 故障事件记录:路号、时刻、电流值 —— 排查排线接触不良的唯一线索 | | **SW-4** | 单路电压微调接口(跑不稳的手机提到 4.0 V,或反向降压降温),**上限受 SR-13 约束** | | **SW-5** | 侧键序列:短按 100 ms 唤醒 / 长按 2 s 开机 / 长按 10 s 强制重启 / VOL−+PWR 进 Fastboot / VOL++PWR 进 Recovery | | **SW-6** | EDL 时序**固定为** `EDL_EN=1` → `VBUS_EN=1` → 等枚举 → `EDL_EN=0`(先短接再插 USB) | | **SW-7** | 开机脚本执行「关充电」(写 `input_suspend` 类节点),路径需在首台机上确认后写死 | | **SW-8** | USB 反灌保护:检测到该路电流转负或母线上升,**200 ms 内**断开该路 VBUS | | **SW-9** | 风扇 PWM 闭环(以载板 LM75BD 为反馈)+ TACH 停转告警 | | **SW-10** | 整板功率预算:读输入侧 INA226,超适配器能力时按优先级降载 | | **SW-11** | 上电默认全关:五路输出关、VBUS 断、按键不按、EDL 不触发 | | **SW-12** | **双链路命令接口**:WiFi 为常态、USB CDC 为兜底,两条同时在线、共用同一套命令语义与同一个命令处理器;命令带全局序号做幂等判重。链路失联**不触发任何动作**。架构见 §10.8 | ### 9.2 明确禁止 | ID | 禁止事项 | 理由 | |---|---|---| | **SW-N1** | 让 ESP32 参与过流保护的实时环路 | 那是 eFuse 的活,MCU 不够快也不够可靠 | | **SW-N2** | 提供任何能让输出超过 4.2 V 的接口 | SR-13 | | **SW-N3** | 烧写 `DIS_USB_JTAG` eFuse | 烧了之后引脚 JTAG 和 USB 两边都进不去,板上没有 JTAG 排针 | | **SW-N4** | 把 INA226 通道号当地址算 | IF-16 | --- ## 10. 软件架构设计 > **这一节为什么在需求文档里**:本文原则上只讲「做成什么样」,但**固件在设计文档里没有 > 落脚点** —— 设计文档 §8.3 只有一张按价值排序的功能清单,没有结构。在补出一份独立的 > 软件设计文档之前,架构先放这里,与 §9 的固件需求贴在一起看。 > 硬件的「怎么做」仍然一律在设计文档。 ### 10.1 分层与职责边界 ```diagram=layers ┌─ 农场管理系统(既有,本项目不交付 —— N7)────────────────────────┐ │ adb 探活 / 业务调度 / 崩溃判定 │ └───────┬────────────────────────────────┬──────────────────────────┘ │ adb over WiFi(业务面) │ 控制面(10.8,⚠️ 链路待定) ▼ ▼ 5 台小米8 主板 ┌─────────────────────┐ ▲ │ PhoneRail 控制器 │ │ 供电 / 侧键 / EDL / VBUS │ ESP32-S3 固件 │ └──────────────────────────┤ 遥测 · 执行 · 记录 │ └──────────┬──────────┘ │ 只能建议,不能否决 ┌───────────────▼───────────────┐ │ 硬实时层:eFuse OVP / 限流 │ │ 放电 MOS 反相联锁 / 上下拉 │ │ —— 不含任何软件(SR-3、SR-7) │ └───────────────────────────────┘ ``` **一条边界决定了下面所有取舍**:固件是**遥测 + 执行器 + 记录仪**,不是保护装置 (SR-5、SW-N1)。凡是「必须及时」的事都已经在硬件里了;固件里没有任何一条路径 是「不跑到就会烧手机」的。因此: - 任务优先级不需要为保护让路,只需要保证遥测不被执行器序列饿死; - 看门狗复位是**可接受的失效**(复位即全关,SR-6),不需要为了「保持输出」而弱化看门狗; - 固件可以随时被重启、被降级运行,硬件安全性不变。 ### 10.2 架构的第一个判断:失联 ≠ 断电 | 状态 | 输出该怎么办 | 为什么 | |---|---|---| | ESP32 复位 / 上电中 | **全关**(硬件下拉保证,SR-6) | 状态未知,且此刻手机本来就没在跑 | | 与上位机失联 | **保持供电不动** | 五台手机正在跑业务;因为控制链路断了就把它们全断电,是把一次网络故障放大成一次全场停机 | | 本地判据触发(SR-5 / SW-8 / 过温) | **关对应那一路** | 已知的危险,且范围可控 | ⚠️ 这三行看起来像常识,但它们互相矛盾过一次:**「安全默认值 = 关」只对未知状态成立**。 失联是已知状态,此时最安全的动作是「什么都不做」。固件里不要写「心跳超时就关输出」。 **推论**:失联期间固件必须能独立运行全部本地职责 —— 巡检、风扇闭环、事件记录、 按队列执行未完成的序列。上位机回来之后靠事件日志补齐时间线(10.7)。 ### 10.3 任务划分(FreeRTOS / ESP-IDF) | 任务 | 周期 | 优先级 | 职责 | 失败后果 | |---|---|---|---|---| | `t_safety` | **20 ms** | 最高 | 读 6 片 INA226(V+I)与 PCA9555 输入;执行 SW-2 / SW-8 判据;越界直接操作 `EFUSE_EN` / `VBUS_EN`(**GPIO 直连,不经任何队列或抽象层**) | 告警延迟;保护本身不受影响(eFuse 是硬件) | | `t_thermal` | 1 s | 中 | 两路 NTC(下板功率级)+ 载板 LM75BD(手机侧)→ 风扇 PWM 闭环;过温先降流后关路(FR-13、TR-5) | 风扇维持上一个占空比 | | `t_actuator` | 事件驱动 | 中 | 每路一个状态机:断电重启 / 按键序列 / EDL 序列(10.6) | 序列停在中间 —— 必须有超时兜底 | | `t_link` | 事件驱动 | 低 | 上位机命令解析与遥测上报(10.8) | 见 10.2:不影响本地职责 | | `t_log` | 空闲 | 最低 | 环形缓冲落盘(10.7) | 丢日志,不丢功能 | **共享资源只有两个**,各配一把互斥锁: 1. **I²C 总线** —— 10 个器件在同一条上(IF-15),其中 LM75BD 还在排针另一侧的载板上。 2. **74HC595 的 24 位链** —— 全板共享,见 10.6 的影子寄存器。 **I²C 带宽核算**(400 kHz,`t_safety` 是唯一的高频用户): ``` 一次 INA226 寄存器读 ≈ 46 个位周期 ≈ 115 µs 6 片 × 2 个寄存器(总线电压 + 分流电压) = 12 次 ≈ 1.4 ms PCA9555 读两个输入端口 ≈ 0.12 ms 合计 ≈ 1.5 ms / 20 ms = 约 8 % 占用 ``` 余量充足,`t_thermal` 和偶发的 DAC 写完全挤得下。**首板上电时用逻辑分析仪实测复核一次** ——这个数是按理想时序算的,没算时钟延展和重试。 ### 10.4 五路一张表:禁止用通道号算任何东西 这是**本项目最容易写出「看起来对、实际错一路」的地方**。三组编号都不是逻辑顺序: - **INA226 地址**按布线难度重排过(IF-16,设计文档 §8.2); - **74HC595 的位序**按 PCB 几何排(设计文档 §17.2 / §22.4); - **GPIO 编号**按出线方向倒推(设计文档 §26.18)。 所以固件里**只允许有一张静态配置表**,全部五路循环都索引它: ```c typedef struct { uint8_t ina_addr; /* 0x40 0x41 0x44 0x45 0x42 —— 查表,不能算 */ uint8_t dac_chip; /* 0x4A: CH1-3 0x4B: CH4-5 */ uint8_t dac_ch; /* U6.OUT0/1/2 U7.OUT0/1 */ gpio_num_t efuse_en; /* GPIO 直连 */ gpio_num_t vbus_en; /* GPIO 直连 */ uint8_t key_bit[3]; /* PWR / VUP / VDN 在 24 位链里的位号 */ uint8_t edl_bit; /* U33 上的位号 */ uint8_t flt_bit; /* PCA9555 IO0_0..4 */ uint8_t pg_bit; /* PCA9555 IO1_0..4 */ } rail_cfg_t; ``` > ⚠️ **`ina_addr = 0x40 + ch` 这行代码一定会被写出来,而且只有 CH3/CH4/CH5 是错的。** > 实际地址是 `0x40 / 0x41 / 0x44 / 0x45 / 0x42`。查表,不要算。 > **A3 已落地**:表在 `firmware/components/drv/include/ina226.h`,取值只走 > `ina226_rail_addr(rail)`(rail 是 1~5,越界 abort), > `test_channel_index_is_not_the_address_low_bits` 专门拦「改回算式」这一手。 > 同处还记了两条 INA226 的实现约定:**寄存器指针不自增**(每次读前重写指针, > sim 会自增、真件不会,靠自增在宿主机上测不出来);**Calibration 丢了不报错、 > 只让 Current/Power 恒读 0**,所以巡检要定期 `ina226_check()`。 同理,**PCA9555 的方向寄存器只能配成全输入**:备用脚 Port0[7] / Port1[7:5] 在硬件上 直接接地,配成输出并写 1 就是对地短路(设计文档 §17.2 已在图纸上注明)。 > **A6 已落地**:驱动在 `firmware/components/drv/include/pca9555.h`, > **根本不提供「把某个脚配成输出」的接口**(和 sr595.h 不提供「抬 OE#」同一条规矩)。 > 方向字一律过 `pca9555_dir_safe()`,不安全直接 abort。 > 同处还记了四条这一片的实现约定: > ① ⚠️ **Output Port 寄存器的复位值是 0xFF** —— 所以把接地脚配成输出的那一刻它就 > 输出高电平,中间没有「先写个 0 再说」的余地,这比「配错方向」本身更急; > ② **极性反转寄存器必须无条件清零**,不能赌复位值:看门狗只复位 ESP32, > PCA9555 不掉电,上一条命的残留值原样留着,而写错的现象是「五路同时报故障」 > 或者更糟的「五路故障全都看不见」,I²C 一切正常; > ③ **三种极性**(FLT# 低有效 / PGOOD 高有效 / INA_ALERT 低有效)各自只在 > `pca9555_rail_fault()` 等四个函数里出现一次,上层不许自己去 & 位; > ④ **INT# 是加速路径不是主路径**:它要读走输入端口才释放,漏读一次就再也等不到 > 下一个沿,所以 `t_safety` 必须无条件轮询(§10.3 的 20 ms 就是按这个排的)。 > > ⚠️ **FLT 与 PG 两张位表这次确实是顺排的**(都是 `bit = rail - 1`), > 和 INA226 地址、595 位号那两张表不一样。所以这里最容易写出来的错不是「算式」, > 而是**把 Port0 和 Port1 搞反** —— 两个端口的 bit0~4 长得一模一样,搞反之后 > 「有故障」会被读成「电源良好」,方向正好相反,而且**静息态两个端口读回来都是 > 全 1,单看一帧完全看不出来**。`test_one_rail_at_a_time` 专门拦这一手。 > **A7 已落地**(2026-09-07):那张 `rail_cfg_t` 表在 `firmware/main/rail_cfg.h` / > `rail_cfg.c`,取值只走 `rail_cfg(rail)`(1~5,越界 abort)。六列的样子: > > | CH | INA226 | DAC | 按键位 PWR/VUP/VDN | EDL 位 | EFUSE_EN | VBUS_EN | > |---|---|---|---|---|---|---| > | 1 | 0x40 | U6.OUT2 | 1 / 2 / 3 | 16 | IO39 | IO40 | > | 2 | 0x41 | U6.OUT0 | 19 / 17 / 18 | 7 | **IO48** | IO10 | > | 3 | 0x44 | **U7**.OUT0 | 22 / 21 / 20 | 6 | IO6 | IO11 | > | 4 | 0x45 | U6.OUT1 | 9 / 10 / 11 | 0 | IO41 | IO42 | > | 5 | 0x42 | U7.OUT1 | 15 / 14 / 13 | 5 | IO8 | IO17 | > > 落地时定下来的五条: > ① **本表与四个驱动那四张表是「两处写同一个数」,所以要对账而不是现算。** > 开机自检 `rail_selftest()` 逐格拿本表和 `ina226_rail_addr()` 等取值函数比一遍, > 对不上就报 `RAIL_SELFTEST_TABLE`。做成「开机从驱动现算」的话按定义就查不出分家, > 而且表不再是 const 的、用之前得先记着初始化。 > ② **判据本身也要被测**:真表是 const 的,测试改不动它,所以判据单拎成 > `rail_selftest_table(t)`,测试喂几张故意写坏的表进去看它认不认 > (分家 / 引脚重复 / 撞 SDA / strapping / 不存在的号 / 越界,六种都验过)。 > ③ **两列 GPIO 是全固件唯一一处出处**,没有第二张表能对账 —— 所以 > 「`EFUSE_EN1` 和 `VBUS_EN1` 写反」这种错自检**查不出来**(两个都是合法空闲脚、 > 不重复、不越界)。唯一的拦网是 `test_en_pins_match_the_pcb_netlist` 里钉死的 > 十个值(出处:`.claude/pcb1-parts.json` 的 U20 焊盘网络)和 B1 上板实测。 > ④ **「不是顺排」要看整列,不能逐格撞算式**:CH4 的按键位正好是 9/10/11、 > CH1 的 EDL 位正好是 16、CH3 的两根 EN 正好等于「IO4 起 / IO9 起」那个算式 —— > 单看任何一路都「像顺排」。测试改成断言整列**不是等差数列**。 > ⑤ ⚠️ **HAL 两侧的 GPIO 上限原来是 `pin < 48`,把 IO48 关在了门外**, > 而 `EFUSE_EN2` 就在 IO48 上 —— 现象是 CH2 的 eFuse 既开不了也**关不掉**。 > 已改成 0~48(含)。ESP32-S3 的编号是连续的但芯片不是:IO22~IO25 不存在、 > IO26~IO32 是模组内部 flash/PSRAM,写进配置表 `gpio_config()` 不报错也不干活, > 所以自检把这些号也当成越界。 > > 同处还落地了**全板引脚表** `firmware/main/board_pins.h`(§8.1 那张表里 > 「全板独一份」的那些脚)与两根 EN 线的表驱动遍历 > (`rail_en_init()` / `rail_efuse_enable()` / `rail_vbus_enable()` / `rail_all_off()`)。 > `rail_all_off()` **先断五路 VBUS 再关五路 eFuse**,中间不留「手机只靠 USB > 供着电」的窗口;十个脚全部试一遍,不因为某一个失败就提前返回。 > 高有效这件事只在 `en_write()` 里出现一次。 ### 10.5 电压通道:DAC 只做微调,而且是反向的 | 事实 | 含义 | |---|---| | `Vd = 0 V` → 输出 **4.010 V**(上限) | **DAC 写得越大,输出越低** | | `Vd = 0.548 V` → 输出 3.90 V(NVM 出厂默认) | 上电即安全值,不依赖 ESP32 初始化成功 | | `Vd = 2.424 V`(满量程)→ 输出 **3.524 V**(下限) | 满量程是 2.424 V,不是 2.5 V(内部基准 1.212 V ×2) | > ⚠️ **反向关系是本节最容易写反的一条。** 写反的现象不是报错,而是 > 「调高电压的命令把手机调到了 3.52 V」——手机照样能开机,只是更容易在负载尖峰下掉电, > 而且**要跑一阵子才看得出来**。固件里把这一步封成 `rail_set_mv()` 单一入口, > 内部做 mV → Vd → code 的换算,**不要在别处直接写 DAC 码值**。 三条固件规矩: 1. **越界即拒绝**:`rail_set_mv()` 收到 >4010 mV 的请求直接返回错误并记事件(SR-13)。 注意这是**第四道**限制,前三道在硬件里 —— 它的作用只是让操作者早点知道自己写错了。 2. **不用 DAC 做保护**:任何时候都不要靠「把电压调低」来处理异常,那是 `EFUSE_EN` 的活。 3. **出厂标定**:分压网络与 DAC 基准都有 ±1 % 级的容差,用该路 INA226 读回实际输出, 做一次两点线性标定存进 NVS。标定值缺失时退回理论公式(误差约 ±40 mV,可用)。 > **A4 已落地**:换算与设定在 `firmware/main/rail.c`,唯一入口 `rail_set_mv(rail, mv)` > (rail 是 **1~5**)。三个验收点各有一条测试:4020 mV 被拒、码大电压低、3900 mV ↔ Vd 0.548 V。 > 标定(本节规矩 3)**还没做**,现在走的是理论公式;`RAIL_VOUT0_UV` / `RAIL_DAC_SPAN_UV` > 两个常量就是将来要被标定值顶替的地方。 > > 同处记下三条 DAC63204 的实现约定(出处 SLASEX3A): > - **12 位码在 `DAC-X-DATA`(19h~1Ch) 里是左对齐的**(bit15-4)。忘了 `<< 4` 不报错, > 只让输出变成 1/16 —— 而在本板上那表现为「五路都是 4.010 V 满电」,看不出异常。 > - **`EN-INT-REF` 要先于增益设定写**,且**上电安全码要写在通道上电之前**: > 复位码是 0,而 Vd = 0 就是输出上限 4.010 V。`dac63204_init()` 因此把 > `COMMON-CONFIG` 写两次(先按住输出,写完码再上电)。 > - **通道分配不是 `rail−1`**(设计文档 §26.18 重排过,五路里四路对不上): > CH1→U6.OUT2 / CH2→U6.OUT0 / CH3→**U7**.OUT0 / CH4→U6.OUT1 / CH5→U7.OUT1。 > 四通道电气对等 ⇒ 接错了照样工作,只是调错路,功能测试测不出来。 ### 10.6 执行器:三个状态机 + 一个影子寄存器 **每路三个序列,彼此互斥、不可重入**(同一路上同时只能跑一个): | 序列 | 时序 | 关键约束 | |---|---|---| | 硬重启 | `EN↓` → 等 3~5 s → `EN↑` → 等 **17 ms**(tON 5.1 ms + 缓启动斜坡 11.5 ms)→ 等 PG 置位 | 放电由硬件联锁自动完成(SR-7),固件**不要**去控制放电 MOS | | 按键 | 置位 → 保持 T(100 ms / 2 s / 10 s)→ 清零 | 组合键(VOL−+PWR)必须**同一帧**写进去,不能先后两次 | | EDL | `EDL_EN=1` → `VBUS_EN=1` → 等枚举 → `EDL_EN=0` | 顺序固定(SW-6):先短接再插 USB | **影子寄存器是这一节的核心**:15 路按键 + `HUB_RST` + 5 路 `EDL_EN` 全在**同一条 24 位 移位链**上,写任何一位都要把整条链重发一遍。 ``` ESP32.KEY_SER → U21 → U22 → U33 (先移入的字节落在链尾 U33) 写入顺序:U33 字节 → U22 字节 → U21 字节,最后一个 RCLK 上升沿统一生效 ``` 规矩:**内存里保存一份 24 位影子值,全固件只有一个函数能写 595**,任何任务改按键 或 EDL 都是「改影子 → 请求刷新」。多处直接操作移位链,症状是**另一台手机的按键被顺手 清掉**,而且复现要靠两个动作正好撞在一起 —— 属于会拖很久的那类 bug。 > `RCLK` 打点之前输出不变,所以整帧刷新是原子的;`OE#` 保持有效,**不要**用拉高 `OE#` > 的方式「临时全松开」——那会让 15 个栅极同时进高阻,靠的是每个栅极自己的 100 kΩ 下拉, > 是复位路径,不是正常控制路径。 > **2026-09-06 A5 落地**:`components/drv/sr595.{h,c}`。影子是一个 24 位整数 > (bit0 = U21.QA 链首 … bit23 = U33.QH 链尾),唯一写入点是 `sr595_flush()`; > 别处只准 `sr595_modify()` 改影子,组合键走 `sr595_write(mask, value)` 一帧发完。 > 位表见设计文档 §17.2(§26.18 重排后的那张,**不是 09-04 那张**)。 > > 同处记下三条这一层的实现约定: > - **上电顺序是「先锁存安全值,再使能 `OE#`」,不能换。** 三片的 `MR#` 接死在 +3V3, > 没有复位线 ⇒ 上电时移位寄存器内容**不确定**。先拉低 `OE#` 就是把那坨随机值 > 放到 15 个栅极上 —— 五台手机的电源键可能一起被按下去。所以 `sr595_init()` 里 > `KEY_OE#` 在安全值锁存完之前**根本不配成输出**,靠板上 R609 上拉着。 > (ESP-IDF 的 `gpio_config()` 一配成输出就开始驱动,输出寄存器复位值是 0。) > - **`HUB_RST` 低有效**,所以上电安全影子是 `1 << 23` 而不是 0。写成 0 的现象是 > 「Hub 插上枚举不出来」,而五路电压电流全都正常,看不出跟固件有关。 > - **发送失败要留着脏**(`sr595_flush()` 失败不清 dirty,下次重发整帧)。 > 丢了脏标志 = 链上和影子永久对不上,而后面每一次 flush 都会「成功」。 ### 10.7 事件记录与存储 事件是 SW-3 的交付物,也是排查排线接触不良的唯一线索,所以**记录路径不能依赖上位机在线**。 | 项 | 设计 | |---|---| | 缓冲 | RAM 环形缓冲,≥256 条;`t_safety` 只入队,不落盘 | | 落盘 | `t_log` 空闲时批量写 NVS / SPIFFS 分区 | | 单条 | 时间戳 + 路号 + 事件类型 + 当时的 V/I(16 B 量级) | | 容量 | 4096 条 ≈ 64 KB,按每天几十条算够存半年以上 | | 时间 | 上电从 0 计;上位机连上后下发一次墙钟做偏移校正(不加 RTC 芯片) | 必记事件:eFuse FAULT / PG 变化、SR-5 触发关路、SW-8 反灌断 VBUS、过温降载、 每次重启序列(软 / 硬、谁下的命令)、越界命令被拒、I²C 器件失联、风扇停转。 ### 10.8 上位机接口 ✅ 已定稿(2026-09-06 用户拍板:方案 C) **这一节回答的问题**:SW-1 的触发条件写的是「`adb` 探活连续失败 N 次」, 而 **ESP32 跑不了 adb** —— 所以崩溃判定必然发生在上位机,板子只负责执行动作。 这意味着必须有一条控制链路,而在此之前**全部文档里都没有定过它**。 **结论:WiFi 为常态链路,USB CDC 为兜底链路,两条同时在线。** 选它不是因为「都要」,而是因为 **SW-1 是这块板子的核心价值, 而 WiFi 与手机 adb 走的是同一张网** —— 只做 WiFi 等于让「救援通道」和「故障通道」 共命运,恰好在最需要它的时候一起失效。USB 的增量成本很低:线本来就插着。 留档备查的两个单选方案: | 方案 | 优点 | 为什么不单独用 | |---|---|---| | A. 只做 WiFi | 无线、可多台组网;设计文档 §9.5 的 3V3 预算里**已经给 ESP32-S3 的 WiFi 突发留了 ≈350 mA**,说明当初就是按带 WiFi 设计的 | 网炸了救砖通道跟着炸,见上 | | B. 只做 USB CDC | 最可靠,不依赖网络 | 每块板占上位机一个 USB 口;机架规模上去之后不现实 | #### 两条链路怎么共存 ```diagram=links WiFi (MQTT/HTTP) USB CDC (J22) │ │ ┌───────▼────────┐ ┌────────▼───────┐ │ 传输适配器 A │ │ 传输适配器 B │ ← 只管收发字节与分帧 └───────┬────────┘ └────────┬───────┘ └──────────┬─────────────┘ ┌──────▼───────┐ │ 单一命令处理器 │ ← 全部鉴权、限幅、幂等判重都在这里 └──────┬───────┘ ▼ 执行器 / 遥测 ``` 四条规矩: 1. **命令处理器只有一个。** 两条链路是**传输**,不是两套功能。任何安全约束 (SR-13 的限幅、越界拒绝、序号判重)都写在处理器里,绝不写进适配器 —— 否则以后加第三条链路时必然漏掉一处,而**功能测试完全测不出来**。 2. **不做主备切换,两条都常开。** 谁先送到算谁的,靠 3 的序号去重。 做「主备」就要判定"主链路死了没有",而那个判定本身就是新的故障点。 3. **序号是全局的,不分链路。** 上位机给每条命令一个单调递增的序号, 板子记住最近 N 个已执行的序号。WiFi 重传 + USB 又发了一遍同一条命令时, 第二次必须被丢弃 —— 否则「按 10 秒电源键」会执行两遍,第二遍正好按在刚开机的手机上。 4. **USB 链路与日志共用一条流。** ESP32-S3 的原生 USB-Serial-JTAG 本身就是 CDC-ACM,不需要切到 TinyUSB,也不影响 esptool 下载(FR-15 不变)。 代价是命令响应和运行日志在同一条串流上,**必须分帧**(建议命令用带前缀的单行 JSON,日志走另一个前缀),否则日志一刷就把响应冲散。 > ⚠️ **别把 WiFi 凭据和 MQTT 地址编译进固件。** 放 NVS,用 USB 链路配置 —— > 这正好是兜底链路的第二个用途:新板子上架时先插 USB 配网。 命令语义与链路无关,两条链路完全一致: | 命令 | 参数 | 说明 | |---|---|---| | `status` | — | 五路 V/I/PG/FLT、输入 V/I、两路 NTC + 载板温度、风扇转速、各路状态机状态 | | `set_voltage` | 路号, mV | 走 `rail_set_mv()`,越界拒绝(10.5) | | `power_cycle` | 路号, 断电秒数 | 二级硬重启(4.1) | | `key` | 路号, 键位掩码, 保持 ms | 单键与组合键同一个接口 | | `edl` | 路号, on/off | 内部按 SW-6 的固定时序展开 | | `vbus` | 路号, on/off | 默认断开 | | `fan` | 占空比 / auto | `auto` 交回 `t_thermal` 闭环 | | `events` | 起始序号 | 增量拉取事件日志 | 三条接口硬约束: - **没有任何命令能让输出超过 4.2 V**(SR-13)—— 包括「原始 DAC 写入」这类调试命令, 它压根不该存在于发布固件里。 - **命令必须幂等或带序号**:链路重传时不能让「按 10 秒电源键」执行两遍(上面第 3 条)。 - **链路失联不触发任何动作**(10.2):没有心跳超时关输出这回事。 ### 10.9 启动顺序 ``` 1 上电:GPIO 全部显式置安全态(硬件下拉已保证,固件再确认一次) 2 I²C 扫描 10 个器件 —— 缺任何一个都进「降级模式」(10.10),不要照常启动 3 读回 DAC 通道值(NVM 默认 3.90 V),与期望比对 4 载入 NVS 里的标定值与上次的每路使能状态 5 逐路上电,**路与路之间错开 100 ms** 6 等各路 PG,超时则记事件并保持该路关闭 7 起风扇闭环,起链路任务 ``` > ⚠️ **第 5 步的错开不是讲究,是必须**:单路缓启动涌流 0.8 A,五路同时开就是 4 A > 叠在 12 V 输入上,而输入预算本来就是 8.3 A(PR-2)。错开 100 ms 之后 > 各路的斜坡(11.5 ms)完全不重叠。 ### 10.10 降级矩阵 | 失效 | 检测方式 | 行为 | |---|---|---| | 某片 INA226 无应答 | I²C NAK | 该路失去遥测 → **保持供电**,标记为「盲跑」,禁用该路的 SR-5 / SW-8 判据并持续告警 | | I²C 总线挂死(SDA 被拉低) | 连续超时 | 发 9 个时钟脉冲做总线恢复;仍不通则复位 I²C 外设;再不通进降级模式 | | DAC 无应答 | I²C NAK | **不关输出** —— DAC 不响应时输出停在 NVM 默认的 3.90 V,是安全值 | | PCA9555 无应答 | I²C NAK | 失去 FAULT / PG 可见性;改用 INA226 的电压判据兜底 | | 载板 LM75BD 无应答 | I²C NAK | 多半是排针接触不良(它在排针另一侧)→ **风扇转到 100 %** 并告警,不要按「读不到温度=不热」处理 | | 上位机失联 | 心跳超时 | 见 10.2:**什么都不做** | | 看门狗复位 | — | 复位即全关(SR-6),重启后按 10.9 恢复,并记一条复位事件 | **降级模式**的定义:只保留「关断能力」与「事件记录」,不再自动上电、不接受调压命令, 持续告警。宁可五台手机不开机,也不要在盲态下带电跑。 ### 10.11 关于 FR-12「模拟电量曲线」的一个说明 这条需求的实现方式和它的字面意思不一样,值得在架构层写清楚:**手机的电量计是从 电池端电压推算 SoC 的**,我们给的电压就是它看到的全部信息。所以「模拟电量曲线」 = **按锂电放电曲线缓慢改变输出电压**(比如 12 小时从 4.01 V 走到 3.60 V,再跳回去)。 两个后果: - 它**不需要**任何新硬件,是 `rail_set_mv()` 之上的一个慢速调度器; - 它与 SW-4(单路电压微调)**共用同一个执行器**,两者必须互斥 —— 否则运维把某台调到 4.0 V,曲线任务转头又把它拉回 3.6 V。 FR-12 是「中(可选)」,建议**首版先不做**,把接口留出来即可。 ### 10.12 架构层面的待定项 | 项 | 状态 | |---|---| | ~~上位机链路选型(10.8)~~ | ✅ **2026-09-06 用户拍板:方案 C**,WiFi 常态 + USB CDC 兜底 | | **OTA 升级** | 既然定了 WiFi,**建议做**:双分区 + 失败回滚。没有 OTA 的话一次坏固件要把板子从机架上拆下来插 USB,而 USB 兜底链路本身也能烧 —— 所以这是「省事」不是「救命」,可以排在首版之后 | | WiFi 掉线重连策略 | 指数退避 + 上限;**重连过程不得阻塞 `t_safety`**(10.3),链路任务优先级最低就是为这个 | | 时间同步 | 当前方案是上位机下发墙钟做偏移,不加 RTC。若日志要脱机长期归档需重议 | | FR-12 电量曲线 | 建议首版不做,只留接口(10.11) | | `input_suspend` 节点路径 | 与 SW-7 / V-8 是同一件事,首台机上确认后写死 | --- ## 11. 约束与假设 ### 11.1 硬约束 | ID | 约束 | |---|---| | **C-1** | 全部为 1S 机型,负载固定为小米8(dipper)主板 | | **C-2** | 原厂电池保护板**被旁路** ⇒ 失去一层与本板独立的防线,全部安全责任落在 SR-2 / 3 / 5 上 | | **C-3** | 无电池 ⇒ 失去一个内阻只有几十 mΩ 的缓冲电容。**瞬态阻抗设计(§6)比电压精度重要得多**,是这类板子的主要故障来源 | | **C-4** | ESP32-S3-WROOM-1 可用 IO 有限(19 根信号已排满),新增功能只能走移位寄存器或 I²C 扩展 | | **C-5** | USB2517I 要求 D± 走线 ≤ 6 inch(152 mm) ⇒ Hub 只能放在载板通道正中 | | **C-6** | BM24(尾插)连接器只有 **10 次插拔寿命** ⇒ 装配流程必须减少反复插拔 | | **C-7** | 小米8 原理图 PDF 是第三方扫描件,**一切引脚 / 机械结论以实测为准** | ### 11.2 假设(若不成立需重新评估) | ID | 假设 | |---|---| | **A-1** | 上游 USB 恒为 5 V(只接电脑 / Hub,不接快充头) | | **A-2** | 手机关机待机电流在 ≈50 µA 量级 | | **A-3** | 目标 ROM 上存在可写的「关充电」sysfs 节点(SW-7,路径待确认) | | **A-4** | 手机常态功耗 0.3 ~ 1 A / 路,五路同时 4 A 满载不会发生 | --- ## 12. 验收准则 ### 12.1 首板上电验收(17 步,**严禁第一次上电就接手机**) 完整步骤与通过标准见设计文档 **§11**。其中: - **第 5 步(人为断开 R2,模拟致命故障)** 与 **第 6 步(负载阶跃 + 阻尼验证)** 是这块板子的两个**核心验证项,不得跳过** —— 它们分别验证 SR-3 和 PR-12 / C-3。 - **第 12 步(ESP32 复位安全测试)** 验证 SR-6。 - **第 14 步(USB 反灌测试)** 验证 SR-10 / SW-8。 ### 12.2 需求 → 验收方法对照 | 需求 | 验收方法 | 通过标准 | |---|---|---| | PR-4 / PR-5 | 扫 DAC 全量程 | 输出扫过 3.52 ~ 4.01 V,与公式误差 <1%;**任何码值都到不了 4.2 V** | | SR-2 | 固件写越界值 | 输出被拓扑限死,不越过上限 | | SR-3 / SR-4 | 人为断开反馈下电阻 | eFuse 断开,输出侧尖峰不超过 4.7 V | | SR-5 | 注入 ±150 mV 偏差 | 20 ms 内关路并产生告警记录 | | SR-6 | 手动复位 ESP32 | 示波器确认五路立即关断、15 路按键无一误触发、EDL 无触发 | | SR-7 | 固件同时置位 EN 与放电 | 硬件互斥,10 Ω 上无持续功耗 | | SR-9 | 可调电源把母线升到 13.5 V | 泄放导通并拉回 13.2 V 以下 | | SR-10 / SW-8 | 不关充电直接接 USB | 电流转负 → 固件 200 ms 内断 VBUS | | SR-15 | 排线加 4.40 V | **不断开**(断开说明焊到了 `B+`/`B−`) | | PR-12 | 0→4 A 阶跃(带 20 cm 线 + 电容组) | 压降 <300 mV,**无 6 kHz 振铃** | | PR-13 | 满载 4 A 跑 30 min | 温升 <40 K | | PR-14 | 断电重启时序 | 输出 200 ms 内 <0.5 V | | FR-4 / SW-5 | 逐项试按键 | 短按唤醒 / 长按 10 s 强制重启 / VOL−+PWR 进 Fastboot 均有效 | | FR-5 / SW-6 | 下发 EDL 序列 | 主机可见 9008 设备 | | FR-7 | 五台全接 | `adb devices` 与 `fastboot devices` 均可见 | | FR-10 / TR-6 | 拔掉一个风扇 | TACH 频率下降约 1/5,产生告警 | | SW-12 | 断开 WiFi(拔 AP / 关热点),从 USB 下命令 | 命令照常执行;**五路输出不受影响**(10.2 的失联行为) | | SW-12 | 同一序号的命令从两条链路各发一遍 | **只执行一次**,第二条被判重丢弃并记事件 | | **总体目标** | 五台长稳 | **24 h 无重启、无告警** | ### 12.3 装配前必做的实物验证(阻塞项) | 项 | 内容 | 出处 | |---|---|---| | V-1 | **排线旁路验证**:确认焊在 `P+`/`P−`,4.40 V 不断开 | §13.7 | | V-2 | **侧键触点定位**:万用表 5 分钟,拍照存档 | §13.3 | | V-3 | **环路补偿实测扫频**(三个位置已留焊盘) | §9.2 | | V-4 | **量两个新连接器实物高度**(XT30PW-M / 2510-3A)—— 余量只有 1~3 mm,**别信估计值** | §26.16 | | V-5 | **两条排线路径试装**(电池 / 尾插穿槽走背面) | §25.16 | | V-6 | **J7n 镜像位按底层装法复做**;装好后做两点通断复核 | §24.3 / §25.16 | | V-7 | **风扇线装配顺序**:必须「先插五根风扇线,再合上载板」 | §26.16 | | V-8 | 确认目标 ROM 上 `input_suspend` 的实际路径 | §15.2 | > 完整的待办 / 已关闭清单以设计文档 **§12** 为准,本表只列对需求验收有约束的。 --- ## 13. 已知风险与已接受的取舍 | # | 风险 | 处置 | |---|---|---| | R1 | 去掉原厂保护板 = 少一层独立防线 | **已接受**。定量核算 eFuse 余量 ≈11 倍;且 eFuse 断开后 2200 µF 仍撑着,手机继续运行不掉电,表现优于保护板断开 | | R2 | 最坏角落下 eFuse 可能到 4.519 V 才跳,超 1S 上限约 60 mV | **已接受**。走到这一步说明第一层已失效,输出以 6.4 mV/µs 冲过这 70 mV 只需 ≈10 µs,远短于锂电过压损伤时间常数 | | R3 | 两个同款 USB-C 插错 | **已接受**(用户在 USB-B / USB-C 之间选了 C)。靠丝印 + 颜色 + 外壳标记缓解 | | R4 | 低边调速导致 PWM 关断期间读不到转速 | **已接受**。若最终选 4 线 PWM 风扇,MOS + 续流管 + 分压可全删 | | R5 | IF-5 的 100 µF MLCC 在 3.9 V 偏压下只剩 ≈40 µF,中频储能从 200 µF 降到 ≈80 µF | **待复核**。严格照原方案需换真聚合物 | | R6 | 电感 SPM6530T-4R7M 的 Isat 6.2 A < 原定的 7 A | **已接受**,裕量分析见设计文档「已知遗留」 | | R7 | BM24 仅 10 次插拔寿命 | 靠装配流程规避(C-6) | | R8 | 手机主板机械固定方式(是否连中框)未定 | **不阻塞打样** | --- ## 14. 需求 → 设计追溯表(速查) | 需求域 | 设计文档章节 | |---|---| | 规格 / 输入输出 | §1、§3 | | 电压范围与本质安全 | §4(含 §4.4 失效态验算) | | 三层保护链 | §5 | | 瞬态阻抗与阻尼(C-3) | §6 | | 断电重启与放电 | §7 | | MCU 接口 / GPIO / I²C | §8、§26.18 | | 选型与 BOM | §9 | | PCB 与叠层 | §10、§25、§26 | | 验收与调试 | §11、§14 | | 手机侧接口 | §13 | | USB 子系统 | §15、§18、§21 | | 两板架构与机械 | §22、§25 | | 散热 | §22.6 | | EDL | §22.4 | | **软件架构** | **设计文档里没有对应章节 —— 见本文 §10** | --- ## 15. 术语 | 术语 | 含义 | |---|---| | **直供** | 拆掉电芯与保护板,从电池座直接供给受控电压 | | **dipper** | 小米8 的代号 | | **P+ / P−** | 电池保护板的**输出侧**焊点(本项目的接入点) | | **B+ / B−** | 电芯侧焊点(**接错这里是本项目最隐蔽的装配错误**) | | **eFuse** | 带可调过压 / 限流 / 缓启动的电子保险丝(TPS25940A) | | **EDL / 9008** | 高通紧急下载模式 | | **本质安全** | 靠拓扑与元件取值在物理上限死危险状态,而不是靠软件判断 | | **下板 / 载板** | 下板 = 电源板;载板(上板)= 承载五块手机主板的板 |