fix(ui): Task #32 P0/P1/P2 — 解耦 UI 心跳、修 adc 压环与截止期、加测量探针
Task #32 UI 看门狗停摆(docs/问题记录/UI任务看门狗停摆分析.md) P0 adc_task.c(已上板验证): - 仅 r==1 才压环+重算;上板印证 ring==frames(修前 ring=frames+idle) - osDelayUntil 返回值重同步,落后拉回基准,解除永久空转死锁 P1-4a ui_task.c v1.3: task_wd_beat 提到 ui_net_sink_poll 之前 → 心跳测"UI 活着"而非"netTask 响应",解开 §4.2 心跳依赖 → 未上 P1-3(提优先级会掩盖 §4.2/§4.4);P1-5 暂缓 P2 新增 App/util/task_prof.c/.h: DWT 常开探针,测各任务周期/耗时/ 推流往返/ADC 轮询/控制台排空/syslog 落盘/net_poll 最坏值;心跳位图 1→0 边沿裸 UART 直发 [PROF]/[PROF2] 快照;uvprojx 已登记 doc: 分析 doc §7 补良性启动 episode 与复位非诊断项;§8 加处置落地 验证: P0+P1 累计 32 次上板启动 0/32 复现(原 L2 基线 3/10),构建 0/0
This commit is contained in:
+43
-3
@@ -6,6 +6,18 @@
|
||||
* 创建日期:2026-08-30
|
||||
* 修改记录:
|
||||
* v1.1 2026-09-14 王建锋 新增待机显示页初始化(ui_standby_init,空闲 60s 切入)
|
||||
* v1.2 2026-10-10 王建锋 Task #32 的 P2 测量埋点:主循环加常开探针
|
||||
* (循环周期 / 单轮工作耗时 / ui_net_sink_poll 往返),
|
||||
* 用于把"心跳缺席"拆成 饿死 / 阻塞在往返 / 自身拖长
|
||||
* 三种互斥机理(见 docs/问题记录/UI任务看门狗停摆分析.md)
|
||||
* v1.3 2026-10-10 王建锋 Task #32 的 P1-4a(解耦心跳,§4.2):把 task_wd_beat
|
||||
* (TASK_WD_UI) 提到 ui_net_sink_poll() **之前**。原写法心跳
|
||||
* 在推流往返之后 → 心跳周期 = 渲染 + 一次 netTask 往返 + 10ms,
|
||||
* 实测 uiw≈uis≈50ms(心跳被 netTask 往返主导),心跳实际测的是
|
||||
* "netTask 响应性"而非"UI 活着"。提到往返之前后,心跳测的是
|
||||
* "UI 自己被调度到了"。注:若往返**永久**阻塞,本改仍不能救
|
||||
* (心跳只发一次)→ 真要彻底去掉依赖须走事件驱动 accept
|
||||
* (NET_EVENT_CONNECTED 回调),待复现快照确认阻塞机理后再定。
|
||||
*/
|
||||
#include "ui_task.h"
|
||||
|
||||
@@ -22,6 +34,7 @@
|
||||
#include "test_config.h" /* TEST_LATENCY_PROBE(链路时延探针编译开关) */
|
||||
#include "net_latency_test.h" /* M3 探针:ui_loop(生产循环实测周期) */
|
||||
#include "task_watchdog.h"
|
||||
#include "task_prof.h" /* P2 常开探针:循环周期 / 工作耗时 / 推流往返 */
|
||||
|
||||
/*
|
||||
* 函数功能:待机屏底部时钟提供回调(平台差异:MCU = sys_clock_get_str)
|
||||
@@ -114,7 +127,21 @@ void ui_task_func(void *argument) {
|
||||
uint8_t tm_loop_valid = 0U;
|
||||
#endif
|
||||
|
||||
/* P2 常开探针(Task #32):TEST_LATENCY_PROBE 只在 CH395F 套件构建下打开,
|
||||
* 且样本消费者是 testTask(产品构建里不跑)→ 产品构建拿不到任何 UI 周期数据。
|
||||
* 故此处独立埋点,恒定生效、只写本模块的静态计数,由 defaultTask 周期上报。 */
|
||||
|
||||
while (1) {
|
||||
/* 循环周期用 enter/exit 测:exit 结算"上轮起点 → 本轮起点",enter 记本轮起点。
|
||||
* 首轮 exit 时尚未 enter 过 → 内部直接返回,不会拿 0 当起点。
|
||||
* 选 enter/exit 而非"自己存一个 prev"的额外收益:两次循环之间段内标志保持为 1
|
||||
* → 报告可读出"本轮已进行多久"。**这正是'uiTask 是否被饿住'的直接证据**:
|
||||
* 若该值在两次报告间持续增长而 uic 不动,就是被调度饿死/阻塞,而非渲染拖长。 */
|
||||
task_prof_exit(TASK_PROF_UI_PERIOD);
|
||||
task_prof_enter(TASK_PROF_UI_PERIOD);
|
||||
|
||||
const uint32_t prof_t0 = task_prof_cyc(); /* 单轮工作耗时基准 */
|
||||
|
||||
#if defined(TEST_LATENCY_PROBE)
|
||||
if (tm_loop_valid != 0U) {
|
||||
lat_probe_add_seg("ui_loop", lat_mark_us(&tm_loop));
|
||||
@@ -123,10 +150,23 @@ void ui_task_func(void *argument) {
|
||||
tm_loop_valid = 1U;
|
||||
#endif
|
||||
ui_port_step(10);
|
||||
ui_net_sink_poll();
|
||||
/* 心跳:ui_port_step 内含 LVGL 渲染,单轮耗时可能逼近 10ms 量级;
|
||||
* 100ms 抽样窗内可容纳多轮,此埋点足够 */
|
||||
/* 心跳**先于**推流往返发出(P1-4a,Task #32 §4.2):UI 心跳测的是
|
||||
* "UI 自身被调度到了",而非"netTask 回执快慢"。原写法心跳在 sink 之后,
|
||||
* 致实测 uiw≈uis≈50ms(心跳被 netTask 往返主导)。提到往返之前后,
|
||||
* 即使往返偶发变慢,心跳也不被其拖垮。
|
||||
* ⚠ 若往返**永久**阻塞(xTaskNotifyWait portMAX_DELAY 不返回),本改只能发
|
||||
* 一次心跳,救不了 → 彻底解耦须走事件驱动 accept,见文件头 v1.3 说明。 */
|
||||
task_wd_beat(TASK_WD_UI);
|
||||
/* 推流轮询段单独 enter/exit:它内部经 net_accept → net_wait_result 走到
|
||||
* xTaskNotifyWait(portMAX_DELAY) 的**无限期阻塞**。若 uiTask 永久卡在这里,
|
||||
* 样本永不结算,只有 task_prof 的"仍在段内已 X us"能证明它卡在何处 */
|
||||
task_prof_enter(TASK_PROF_UI_SINK);
|
||||
ui_net_sink_poll();
|
||||
task_prof_exit(TASK_PROF_UI_SINK);
|
||||
|
||||
/* 单轮工作耗时(不含 osDelay):与循环周期对比即得"调度延迟" */
|
||||
task_prof_sample(TASK_PROF_UI_WORK, task_prof_cyc() - prof_t0);
|
||||
|
||||
osDelay(10);
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user