A10:安全巡检的判据(SR-5 / SW-8)

判据全在 t_safety_step() 里、**放锁之后**、直接写引脚(§10.3 原话:不经任何
队列或抽象层):

  SR-5   |实测 − 该路设定值| > 100 mV **连着两圈** → 先断 VBUS 再关 eFuse
  SW-8   I < −50 mA,或 VBUS 期间电压被顶高 > +100 mV → **一圈就断 VBUS**

七条实现约定(详见需求文档 §10.2):

· 「持续 20 ms」数的是圈,不是墙钟毫秒;
· 反灌不设确认窗口,与过压那 20 ms 的不对称是有意的 —— 误断 VBUS 只丢一次
  USB 数据,漏判会把能量泵回 12V 母线连累另外四台(设计文档 §15.2);
· 判据只在「该路该有电 + 这一圈的值新鲜 + 过了 60 ms 缓启动窗口」时武装
  (对应 §10.10 的「盲跑 → 保持供电,禁用该路判据」);
· 比的是该路 DAC 设定值的影子,不是 3900 这个常数(SW-4 要单路微调);
· SR-5 关路关干净(不留「只靠 USB 供着电」的窗口),SW-8 只断 VBUS 不碰 eFuse;
· 断电之前先 t_actuator_abort(),断 VBUS 时只打断 EDL(只有它写 VBUS_EN);
· 动作在前、记录在后,事件走回调出去,A11 在那儿接环形缓冲。

判据一条 I²C 事务都不发(设定值、两根 EN、正在跑的序列全部走影子),
§10.3 那 7.8 % 的预算不变。顺带新增两处影子:rail_efuse_is_on()/rail_vbus_is_on()
与 rail_setpoint_mv(),都**只在写成功时更新**,两个方向都倒向安全的那一侧。

29 个用例;25 条注错逐个跑过,24 条变红。第一版把「持续 20 ms」按墙钟算,
测试一半红一半绿 —— 巡检的采样时刻带亚毫秒残差(一圈占 1.56 ms 总线,
而睡到下一拍按整毫秒算),相邻两次判据的时刻是 21/19 ms 交替,19 ms 那一半
要拖到第三圈 = 40 ms,超验收且间歇性。改成数圈之后一次不飘,
并留了一条跑 20 轮、两种相位都踩得到的回归拦网。

Co-Authored-By: Claude Opus 5 <[email protected]>
这个提交包含在:
zhou yang
2026-09-07 08:41:53 +08:00
共同撰写人 Claude Opus 5
父节点 b3206005ab
当前提交 273c53347e
共修改 11 个文件,包含 1354 行新增和 206 行删除
+27 -2
查看文件
@@ -218,6 +218,21 @@ static hal_err_t en_write(int pin, bool on)
return hal_gpio_write(pin, on ? 1 : 0);
}
/* 两根线的影子(契约见 rail_cfg.h)。写失败时**不更新** —— 那一次的线上电平
是未知的,而「保留上一次成功的意图」在两个方向上都倒向安全的那一侧。 */
static bool s_efuse_on[PHONERAIL_RAIL_COUNT];
static bool s_vbus_on[PHONERAIL_RAIL_COUNT];
bool rail_efuse_is_on(int rail)
{
return rail >= 1 && rail <= PHONERAIL_RAIL_COUNT && s_efuse_on[rail - 1];
}
bool rail_vbus_is_on(int rail)
{
return rail >= 1 && rail <= PHONERAIL_RAIL_COUNT && s_vbus_on[rail - 1];
}
hal_err_t rail_en_init(void)
{
for (int rail = 1; rail <= PHONERAIL_RAIL_COUNT; rail++) {
@@ -236,6 +251,8 @@ hal_err_t rail_en_init(void)
return err;
}
}
s_efuse_on[rail - 1] = false;
s_vbus_on[rail - 1] = false;
}
return HAL_OK;
}
@@ -245,7 +262,11 @@ hal_err_t rail_efuse_enable(int rail, bool on)
if (rail < 1 || rail > PHONERAIL_RAIL_COUNT) {
return HAL_ERR_ARG;
}
return en_write(k_cfg[rail - 1].efuse_en, on);
const hal_err_t err = en_write(k_cfg[rail - 1].efuse_en, on);
if (err == HAL_OK) {
s_efuse_on[rail - 1] = on;
}
return err;
}
hal_err_t rail_vbus_enable(int rail, bool on)
@@ -253,7 +274,11 @@ hal_err_t rail_vbus_enable(int rail, bool on)
if (rail < 1 || rail > PHONERAIL_RAIL_COUNT) {
return HAL_ERR_ARG;
}
return en_write(k_cfg[rail - 1].vbus_en, on);
const hal_err_t err = en_write(k_cfg[rail - 1].vbus_en, on);
if (err == HAL_OK) {
s_vbus_on[rail - 1] = on;
}
return err;
}
hal_err_t rail_all_off(void)