固件 0.1.0-c3:计划内重启不断电(OTA / 回滚锁住 EFUSE_EN,新固件接管;SR-6 改写)
- warm_esp.{h,c}:warm_restart() 记下开着的路(RTC_NOINIT,魔数 + 掩码 + 反码)→ gpio_hold 锁五根 EN → 重启;
目标镜像没有能力标记(第 288 字节 PRCAPS1,.rodata_custom_desc)就不锁 —— 老固件写不动锁住的 EN。
warm_take():软件复位 + 标记对得上才接管,一次性;再读 EN 真电平核对
- bringup:adopt 掩码;rail_en_init_keep() 接管的路写高、五根一律放开 hold(崩溃时旧锁可能还在);
刀片不在 / mux 失联的接管路立刻关(SLOT_EMPTY arg 1);第二段已开着的路不重开、不等 PG
- pca9555_init_keep():方向寄存器是本固件写的才留 VBUS(掉过电的片子锁存器是 0xFF),键 / EDL 清零
- HAL:hal_gpio_hold();ESP 输出脚配 INPUT_OUTPUT(读得到真电平);sim 给 hold 建模
- 事件 LOG_EV_OTA arg 7 = 接管;兜底定时器回滚故意不走接管
- 顶层 CMake:phonerail.h 进 CMAKE_CONFIGURE_DEPENDS(否则镜像头版本停在旧值);-u g_phonerail_caps 防 gc
- test_bringup 加 6 例(接管 / 非计划复位全关 / 空槽 / mux 失联 / PCA 掉过电 / hold 冻结),全工程 448 例全绿
- rack:固件库识别能力标记,推送对话框按「支持 / 不支持重启不断电」给不同提示(已部署)
- 需求文档:SR-6 改为「非计划复位全关」+ 计划内重启例外;§10.9 新增「重启不断电」
- 板 B:台架镜像(空槽强制 CH1 在位,未提交)开 CH1 → OTA 带重启 → 事件 18/7 mv=1,CH1 一直开着;
现跑 0.1.0-c3。未测:示波器看重启期间 EN / 输出毛刺(要插刀片)
Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
@@ -175,7 +175,7 @@ USB 通断」这些原本要人手做的动作全部电气化,交给板上 MCU
|
||||
| **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-6** | **复位安全**:ESP32 **非计划**复位(上电、崩溃、看门狗、按 EN、esptool)期间,五路输出全关、五路 VBUS 全断、15 路按键全不按、5 路 EDL 全不触发、风扇不转。靠**上下拉电阻**保证,不靠固件。<br>**例外(2026-09-27 用户定)**:固件自己发起的**计划内重启**(OTA 换固件、自证超时回滚)锁住 `EFUSE_EN`、新固件接管,手机不断电;按键 / EDL 仍全松,VBUS 保持。见 §10.9「重启不断电」 | §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 |
|
||||
@@ -334,6 +334,7 @@ USB 通断」这些原本要人手做的动作全部电气化,交给板上 MCU
|
||||
|
||||
- 任务优先级不需要为保护让路,只需要保证遥测不被执行器序列饿死;
|
||||
- 看门狗复位是**可接受的失效**(复位即全关,SR-6),不需要为了「保持输出」而弱化看门狗;
|
||||
(计划内重启不断电是另一回事:那是固件自己选的时机、自己留的标记,§10.9「重启不断电」。)
|
||||
- 固件可以随时被重启、被降级运行,硬件安全性不变。
|
||||
|
||||
### 10.2 架构的第一个判断:失联 ≠ 断电
|
||||
@@ -341,6 +342,7 @@ USB 通断」这些原本要人手做的动作全部电气化,交给板上 MCU
|
||||
| 状态 | 输出该怎么办 | 为什么 |
|
||||
|---|---|---|
|
||||
| ESP32 复位 / 上电中 | **全关**(硬件下拉保证,SR-6) | 状态未知,且此刻手机本来就没在跑 |
|
||||
| ESP32 **计划内**重启(OTA / 回滚) | **保持**(EN 锁住,新固件接管) | 重启前的状态是已知的;为换一次固件让五台手机全掉电不值得 |
|
||||
| 与上位机失联 | **保持供电不动** | 五台手机正在跑业务;因为控制链路断了就把它们全断电,是把一次网络故障放大成一次全场停机 |
|
||||
| 本地判据触发(SR-5 / SW-8 / 过温) | **关对应那一路** | 已知的危险,且范围可控 |
|
||||
|
||||
@@ -857,8 +859,8 @@ base = `phonerail/<id>`,id = 板子 STA MAC 的 12 位小写十六进制(板
|
||||
`{"seq":N,"cmd":"ota","url":"http://home.example:7765/fw/<sha256 前 16 位>.bin","sha256":"<64 位小写>","size":N,"reboot":false}`
|
||||
回 `{"seq":N,"ok":true,"act":"start"|"reboot"|"ready"}`;下载中再来 `busy`;新固件还没自证时 `state`;size 超一个槽(3 MB)`range`。
|
||||
url 只收 `http://`、≤64 字节(命令字符串上限)。
|
||||
- ⚠️ **`reboot` 默认 false**:ESP 一复位 EN 就被下拉,**五台手机硬断电一次**,起来后按意图逐路恢复。
|
||||
默认只下载 + 校验 + 切启动分区、下次复位生效;同一个镜像已就绪时再发带 `"reboot":true` 的,不重下、直接重启。回滚也是一次复位。
|
||||
- ⚠️ **`reboot` 默认 false**:只下载 + 校验 + 切启动分区、下次复位生效;同一个镜像已就绪时再发带 `"reboot":true` 的,不重下、直接重启。
|
||||
重启 / 超时回滚:板上固件 ≥0.1.0-c3 且目标镜像认接管 ⇒ **手机不断电**(§10.9「重启不断电」);否则 ESP 一复位 EN 就被下拉,**五台手机硬断电一次**。
|
||||
- status 多一块 `"ota":{"st":"idle|dl|ready","got":N,"size":N,"err":null|"http|size|hash|flash|image|boot|noslot","pend":bool,"bad":null|"版本号"}`;
|
||||
`pend` = 正在跑的固件还没自证,`bad` = 被判无效回滚掉的那份的版本号(镜像头版本 = `PHONERAIL_FW_VERSION`)。
|
||||
- 新事件 **`LOG_EV_OTA`(18)**,arg:1 开始 / 2 就绪 / 3 失败(bus_mv = 原因号)/ 4 自证健康 / 5 回滚 / 6 为换固件重启。新命令号 **`ota` = 13**。
|
||||
@@ -900,6 +902,20 @@ base = `phonerail/<id>`,id = 板子 STA MAC 的 12 位小写十六进制(板
|
||||
PCA9555 读不到时改按 INA226 电压(≥ 设定 − 100 mV)判;两样都读不到 = **开着、报「确认不了」**,不当成坏了。
|
||||
- `HUB_RST#` 只在上电复位时脉冲,其余复位原因连配置都不做(配成输出那一刻就是一次复位)。
|
||||
|
||||
**重启不断电(2026-09-27,`firmware/main/warm_esp.c` + `bringup.h` 的 `adopt`)**——用户定:只管计划内重启,VBUS 也保持。
|
||||
- 重启前(`warm_restart()`):记下开着的路(RTC_NOINIT:魔数 + 掩码 + 反码)→ `gpio_hold` 锁住五根 `EFUSE_EN` → 重启。
|
||||
**目标固件不认接管就不锁**(镜像第 288 字节的能力标记 `PRCAPS1`,`.rodata_custom_desc`):推老版本(≤0.1.0-c2)时
|
||||
它起来写不动被锁住的 EN,五路会**永远关不掉** —— 所以对它照老样子全断重启。
|
||||
- 起来后(`warm_take()`,bringup 之前):复位原因 = `ESP_RST_SW` **且**标记对得上才接管;标记一次性。
|
||||
再读 EN 脚真电平核对(输出脚配成 INPUT_OUTPUT,锁住时输入缓冲还开着),线上是低的那路不接管。
|
||||
- 第 1 步 `rail_en_init_keep(adopt)`:接管的路写高,**五根一律放开 hold** —— 崩溃 / 看门狗时上一条命的锁可能还在,不放开就关不掉。
|
||||
刀片不在 / mux 失联的接管路立刻关(`adopt_dropped`,空槽记 `SLOT_EMPTY` arg 1)。
|
||||
- PCA9555 用 `pca9555_init_keep(VBUS 位)`:方向寄存器已是本固件写的才留 VBUS(掉过电的片子锁存器是 0xFF,照留 = 凭空开 VBUS),键 / EDL 清零。
|
||||
- 第 5~6 步:已开着的路不重开、不等 PG。DAC 照常 init(中间约 1 ms Hi-Z ⇒ 输出退化到 3.890 V,设计文档「DAC 未供电 / 输出 Hi-Z」那一行),自定义电压回到 3.90 V(本来就不持久化)。
|
||||
- 事件:`LOG_EV_OTA` arg 7,bus_mv = 接管掩码,µA 列 = 关掉的掩码。
|
||||
- 代价:esp_restart → 新固件 t_safety 起来约 1~2 s,SR-5 / SW-8 不判(eFuse 硬件保护在)。兜底定时器回滚、新固件崩溃都**不**走接管。
|
||||
- 实测(板 B,空槽强制 CH1 在位的台架镜像):CH1 开着 → OTA 带重启 → 新固件读到 IO9 仍为高、记 `18/7 mv=1` → CH1 一直开着。
|
||||
|
||||
### 10.10 降级矩阵
|
||||
|
||||
| 失效 | 检测方式 | 行为 |
|
||||
|
||||
在新工单中引用
屏蔽一个用户