固件 0.1.1-c3:I²C 不应答不再被报成「没初始化 / 忙」(关电回 busy 的根因)

- 根因:IDF 5.4 的 i2c_master_transmit / receive / transmit_receive 在从机 NACK / SCL 超时时返回
  ESP_ERR_INVALID_STATE,HAL 照翻成 HAL_ERR_STATE(= 没 init);命令层 from_hal 又把 STATE 当成
  「执行器忙」⇒ PCA9555 不应答时 power off 回 busy(eFuse 其实已关、意图已清),I2C_LOST 错误码是 5
- hal_i2c_esp.c:传输函数用 map_xfer_err(INVALID_STATE → NAK);总线没建起来仍单独报 STATE
- cmd_exec.c:新增 from_bus,set_voltage / vbus / power 的器件失败一律 io;from_hal 只留给执行器
- sim:sim_i2c_inject_err_ch() 可指定注入的错误码;test_cmd 加 STATE 注入 ⇒ 必须 io 不是 busy
  (改回 from_hal 时这段确实红)。26 个 ctest 全绿
- 板 B(台架镜像,CH1 强制在位,未提交):power off 回 io、CH1 关掉;I2C_LOST 错误码 5 → 2。现跑 0.1.1-c3

Co-Authored-By: Claude Opus 5.5 <[email protected]>
这个提交包含在:
zhou yang
2026-09-27 14:45:38 +08:00
共同撰写人 Claude Opus 5.5
父节点 7bf30e3c38
当前提交 284571de20
共修改 8 个文件,包含 76 行新增和 13 行删除
+12 -3
查看文件
@@ -1,11 +1,21 @@
# 交接
更新:2026-09-27 **0.1.0-c3:重启不断电**(计划内重启锁住 EFUSE_EN、新固件接管;SR-6 已改写)
更新:2026-09-27 **0.1.1-c3**:修了 I²C 不应答被报成 STATE / 关电回 busy(下面「0.1.1」);**0.1.0-c3:重启不断电**
## 一句话现状
OTA 换固件 / 超时回滚现在走 `warm_restart()`(`main/warm_esp.c`):目标固件认接管 ⇒ 手机不断电;
崩溃 / 看门狗 / 上电 / 兜底回滚仍全关(SR-6)。**26 个 ctest、448 个用例全绿**。板 B 跑 **0.1.0-c3**(经 OTA 推上去的)。
崩溃 / 看门狗 / 上电 / 兜底回滚仍全关(SR-6)。**26 个 ctest、448 个用例全绿**。板 B 跑 **0.1.1-c3**(经 OTA 推上去的)。
定稿写在需求 §10.9「重启不断电」。C2 OTA 的说明在下面。
## 0.1.1:I²C 不应答被报成 STATE(真板独有,sim 测不出)
- 根因:IDF 5.4 的 `i2c_master_transmit/receive/transmit_receive` 在**从机 NACK / SCL 超时**时返回 `ESP_ERR_INVALID_STATE`,
HAL 照翻成 `HAL_ERR_STATE`(= 没 init)。于是:I2C_LOST 事件的错误码是 5;命令层 `from_hal` 又把 STATE 当成「执行器忙」⇒
PCA9555 不应答时 `power off` 回 `busy`(eFuse 其实已经关了、意图也清了),上位机会以为没执行。
- 修:`hal_i2c_esp.c` 传输函数用 `map_xfer_err`(INVALID_STATE → NAK);`cmd_exec.c` 新增 `from_bus`,
I²C / GPIO 路径(set_voltage / vbus / power)失败一律 `io`,`from_hal` 只留给执行器。
- 测试:sim 加 `sim_i2c_inject_err_ch()`(指定注入的错误码);`test_cmd` 加一段 STATE 注入 ⇒ 必须是 io 不是 busy
(把关电那行改回 from_hal 时这段确实红,回应就是台架上看到的 `{"err":"busy"}`)。
- 上板(台架镜像,CH1 强制在位):`power off` 回 `io`、CH1 关掉;I2C_LOST 的错误码 5 → **2**。
## 重启不断电(c3)
- 三道闸:RTC 标记(软件复位 + 魔数 / 反码,一次性)· 目标镜像能力标记(第 288 字节 `PRCAPS1`,老固件不认就不锁)· 起来后读 EN 真电平核对。
- `rail_en_init_keep(adopt)` **五根一律放开 hold**:崩溃时上一条命的锁可能还在。
@@ -17,7 +27,6 @@ OTA 换固件 / 超时回滚现在走 `warm_restart()`(`main/warm_esp.c`):
## 下一步(没人定,候选)
- 示波器验证:插一片刀片,CH 开着,OTA 带重启,抓 EN / 输出电压(`scope_*` 工具)。
- 小毛病(以前就有):PCA9555 不应答时 `power off` 回 `busy`,其实 eFuse 已经关了、意图也清了(`from_hal` 把 VBUS 失败的 HAL_ERR_STATE 映射成了 busy)。
- 服务器 fw 目录不会自动清理旧镜像(每个 ~1 MB,问题不大)。
## 踩到的坑(c3)