/* 刷机模式(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 #include #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 */