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]>
这个提交包含在:
+17
-1
@@ -70,6 +70,17 @@ static bool act_pg_from_safety(void *ctx, int rail, bool *pg)
|
||||
return true;
|
||||
}
|
||||
|
||||
/* A10 的事件出口。**A11 会把这里换成环形缓冲的入队**(§10.7:`t_safety` 只入队、
|
||||
不落盘),在那之前先打到日志上 —— 一条也不留才是最坏的结果。
|
||||
⚠️ 这个回调是在断电之后、不持任何锁的情况下被调的,所以里面不许阻塞。 */
|
||||
static void log_safety_event(void *ctx, const safety_event_t *ev)
|
||||
{
|
||||
(void)ctx;
|
||||
ESP_LOGW(TAG, "安全事件 t=%u ms CH%u %s V=%d mV I=%d uA", (unsigned)ev->t_ms,
|
||||
(unsigned)ev->rail, t_safety_ev_str((safety_ev_t)ev->type),
|
||||
(int)ev->bus_mv, (int)ev->current_ua);
|
||||
}
|
||||
|
||||
static void task_safety(void *arg)
|
||||
{
|
||||
(void)arg;
|
||||
@@ -187,9 +198,14 @@ void app_main(void)
|
||||
与**降级矩阵**是 A15 的启动顺序那一包。在那之前 t_safety 读回来的电流恒为 0
|
||||
(Calibration 还没写),这是预期的,不是故障。 */
|
||||
|
||||
/* 执行器:PG 从巡检的快照里取,本任务自己不碰 I²C(t_actuator.h 开头那一段)。 */
|
||||
/* 执行器:PG 从巡检的快照里取,本任务自己不碰 I²C(t_actuator.h 开头那一段)。
|
||||
⚠️ 必须在 `spawn(TASK_SAFETY, ...)` 之前:判据要关路时会先 `t_actuator_abort()`,
|
||||
而没 init 的执行器只会直接返回,那时序列还在跑,电关掉几秒又会被抬回来。 */
|
||||
t_actuator_init(act_pg_from_safety, NULL);
|
||||
|
||||
/* 事件出口。同样要在巡检起来之前接上,否则第一批事件没人接。 */
|
||||
t_safety_set_event_sink(log_safety_event, NULL);
|
||||
|
||||
spawn(TASK_SAFETY, task_safety);
|
||||
spawn(TASK_THERMAL, task_thermal);
|
||||
spawn(TASK_ACTUATOR, task_actuator);
|
||||
|
||||
在新工单中引用
屏蔽一个用户