- 0.1.5/0.1.6:刷机模式(flash_mode,最多 2 路,60 分钟可加钟)——窗口内顶高按 4450 mV 绝对值判、不断 VBUS - 0.1.7/0.1.8:反灌断 VBUS 阈值放宽到 -300 mA(adb reboot bootloader 过渡实测 -208 mA) - 0.1.9:WiFi 最多存 4 组,连不上轮换;NVS v1 自动迁移并双写(OTA 回滚仍能上网) - 0.1.10:热插拔进来的刀片重新初始化 PCA9555 + INA226(否则 VBUS 常开、电流恒读 0) - 0.1.11:i2cbus 嵌套检测改看本任务持锁(原全局标志让 key 随机回 busy、vbus 随机回 io) - 0.1.12:硬重启先断 VBUS,开机校验通过 60 s 后再接回(否则假重启 / 误判没开机 / 进关机充电) - 0.1.13:这一路被安全判据断电时一并退出刷机模式(事件 21 arg 254) 26 ctest 全绿;新增用例均先在旧代码上确认变红。板 B 已 OTA 到 0.1.13-c5 并实测。 Co-Authored-By: Claude Opus 5.5 (1M context) <[email protected]>
88 行
4.6 KiB
C
88 行
4.6 KiB
C
/* 刷机模式(0.1.5,2026-09-28 用户定):某一路 VBUS 通着时**允许手机充电、不断 USB**。
|
||
|
||
为什么要有它:fastboot / bootloader 阶段我们的内核补丁还没起来,手机充电器会把电池端
|
||
(我们的直供节点)顶到它的浮充电压 ~4.4 V。平时 SW-8 会立刻断 VBUS(事件 PUSHED_UP),
|
||
刷到一半的 fastboot 就断了。
|
||
|
||
为什么放得开:
|
||
· 每路 eFuse(TPS25940A)自带**反向阻断**(V(IN)−V(OUT) < −9.3 mV 断开)——
|
||
充电器顶高节点时 eFuse 自己断开,能量进不了 Buck、到不了 12V 母线。
|
||
2026-09-28 板 B 五次顶高实测电流 0 ~ −0.5 mA,印证了这一点;
|
||
· 4.4 V 是小米8 高压电芯 + 手机充电芯片自己的设计点,保护板已旁路。
|
||
|
||
刷机模式下(这一路、窗口内)t_safety 的判据改成:
|
||
| 判据 | 平时 | 刷机模式 |
|
||
|---|---|---|
|
||
| SW-8 顶高断 VBUS | > 设定 +100 mV | > CHG_MODE_MAX_MV(绝对值) |
|
||
| SR-5 过压关路 | > 设定 +100 mV 持续 20 ms | > CHG_MODE_MAX_MV 持续 20 ms |
|
||
| SW-8 反灌断 VBUS | I < −300 mA | **不变**(eFuse 之外的第二道) |
|
||
| SR-5 欠压关路 | < 设定 −250 mV | **不变** |
|
||
窗口结束后再留 CHG_MODE_GRACE_MS 的「过压仍按绝对值判」:窗口一过 SW-8 立刻断 VBUS,
|
||
节点从 4.4 V 往回落要几毫秒,不能被 SR-5 当成过压把手机关掉。
|
||
|
||
**最多同时 CHG_MODE_MAX_RAILS 路**:下行 VBUS 由板上一片 3 A 的 5V(U30)供,
|
||
一台充电 0.5 A(SDP)~1.5 A(CDP),五台一起会把 5V 拉垮、全部 USB 掉线。
|
||
|
||
---- 线程 ----------------------------------------------------------------
|
||
**只有执行器任务写**(`chgmode_set()` 由命令处理器调,`chgmode_tick()` 在执行器循环里调,
|
||
两者同一个任务),巡检任务(t_safety)**只读**。每路状态是一个 32 位截止时刻 + 一个字节标志,
|
||
单字读写本身原子;「先写时刻、后置标志」保证巡检不会读到半截。
|
||
为什么要 tick 清标志:时钟是 32 位毫秒,过期的窗口放着不管,~24.8 天后
|
||
`(int32_t)(until - now)` 会翻回正数,窗口「复活」。 */
|
||
#ifndef CHGMODE_H
|
||
#define CHGMODE_H
|
||
|
||
#include <stdbool.h>
|
||
#include <stdint.h>
|
||
|
||
#include "hal_err.h"
|
||
|
||
#ifdef __cplusplus
|
||
extern "C" {
|
||
#endif
|
||
|
||
#define CHG_MODE_MAX_RAILS 2
|
||
#define CHG_MODE_DEFAULT_MIN 60 /* 2026-09-28 用户改:30 → 60 */
|
||
#define CHG_MODE_MAX_MIN 120
|
||
#define CHG_MODE_MAX_MV 4450 /* 手机充电器浮充 ~4.4 V(实测 4395)+ 余量;超过 = 充电器异常 */
|
||
#define CHG_MODE_GRACE_MS 1000
|
||
|
||
/* LOG_EV_CHG_MODE 的 arg(开的时候是分钟数 1~120)。⚠️ 进 flash,冻结。
|
||
加钟:CHG_EV_EXTEND | 加的分钟数(1~120 ⇒ 129~248)。 */
|
||
#define CHG_EV_OFF 0u
|
||
#define CHG_EV_EXTEND 0x80u
|
||
#define CHG_EV_EXPIRED 255u
|
||
#define CHG_EV_DROPPED 254u /* 0.1.13:这一路断了电(刀片拔走 / 安全判据关路),自动退出 */
|
||
|
||
/* 开 / 关。minutes = 0 关(进入宽限期),1~CHG_MODE_MAX_MIN 开(覆盖原窗口)。
|
||
HAL_ERR_ARG —— 路号 / 分钟越界;
|
||
HAL_ERR_STATE —— 要开第 CHG_MODE_MAX_RAILS+1 路(本路已开着的续期不算新增)。 */
|
||
hal_err_t chgmode_set(int rail, uint32_t minutes, uint32_t now);
|
||
|
||
/* 加钟(0.1.6):在**正开着**的窗口上再加 minutes(1~CHG_MODE_MAX_MIN)。
|
||
加完剩余时间超过 CHG_MODE_MAX_MIN 的按它截断(「最长 120 分钟」是剩余时间的上限,不是一次窗口的)。
|
||
HAL_ERR_ARG —— 路号 / 分钟越界;
|
||
HAL_ERR_STATE —— 这一路没开着(过期了 / 宽限期里也算没开:要重新开,不是加钟)。 */
|
||
hal_err_t chgmode_extend(int rail, uint32_t minutes, uint32_t now);
|
||
|
||
/* 过期清理(执行器循环里调,每拍一次即可)。返回本次**自然到期**的路的位图(bit0 = CH1),
|
||
调用方据此记事件;被命令关掉的不在其中(关的那一刻命令层已经记过)。宽限期结束才清标志。 */
|
||
uint32_t chgmode_tick(uint32_t now);
|
||
|
||
/* 窗口内:放开「顶高断 VBUS」。 */
|
||
bool chgmode_active(int rail, uint32_t now);
|
||
/* 窗口内或宽限期内:过压按 CHG_MODE_MAX_MV 绝对值判。 */
|
||
bool chgmode_relaxed(int rail, uint32_t now);
|
||
/* 剩余秒数(不在窗口内为 0)。status 上报用。 */
|
||
uint32_t chgmode_left_s(int rail, uint32_t now);
|
||
/* 窗口内的路数。 */
|
||
int chgmode_count(uint32_t now);
|
||
|
||
void chgmode_reset(void); /* 全关(上电 / 宿主机测试) */
|
||
|
||
#ifdef __cplusplus
|
||
}
|
||
#endif
|
||
|
||
#endif /* CHGMODE_H */
|