diff --git a/.zcode/plans/plan-sess_f45c58da-6d27-48e7-b6a0-bfc16cf9c956.md b/.zcode/plans/plan-sess_f45c58da-6d27-48e7-b6a0-bfc16cf9c956.md new file mode 100644 index 0000000..9582953 --- /dev/null +++ b/.zcode/plans/plan-sess_f45c58da-6d27-48e7-b6a0-bfc16cf9c956.md @@ -0,0 +1,31 @@ +# 诊断结论(本次核心交付) + +你的怀疑正确,确实冲突,且共两层: + +1. **主站楔死看门狗无豁免(自动拉起的推手)** + `G:\Robot_v2\DCU\tools\ecat\ecat_native.c` 的 wedge_worker 后台线程:WKC 异常持续 5s 即判死,之后每 ~8s 无限重拉 INIT→OP,直到成功,全程无「用户手动休眠」豁免。日志实锤(`build_native\native_stdout.log`): + `t=176002.9s 判死(从站掉 OP) → 重拉失败(枚举不到从站) → t=176011.0s 重拉成功已进 OP`,与你任务管理器图上 ~20s 流量缺口完全吻合。 + +2. **GD32 固件进睡眠时没冻结 HBI 访问者(芯片睡不住的根因)** + `EscLan9252::pmDrive()` 写完 PMT_CTRL 进入 D1-D3 后,GD32 侧 SSC 主循环 `MainLoop()→ECAT_Main()` 每圈仍无条件 HBI 读 0x220(AL 事件寄存器),另有 250ms AL mask 守护、5s AL 心跳,全部无睡眠门控。按 1.6.24 实测「任何 HBI 访问(含读)都会唤醒芯片」,**芯片进入睡眠后毫秒级就被 GD32 自己打回 D0**。你看到的低谷不是「睡了多久」,而是被唤醒后 SM/FMMU 失效、主站重建连接所需的时间。 + +3. 次要发现:电源页 `enterMode` 已正确暂停轮询并写 sessionStorage(同标签页安全),但换新标签页打开会丢标记 → 自动状态读(HBI 读)直接把芯片唤醒,属潜在坑。 + +# 修复计划 + +## Phase A:PC 侧(立即生效,不动固件) +- **A1** `ecat_native.c`:新增 `g_pm_hold` 标志 + `POST /api/pm/hold {on:0|1}`;在三处跳过——pdo_worker 的楔死判定(~859-908 行)、wedge_worker 巡检(~2940-2990 行)、`/api/motor/state` 路由快路径(~2262-2300 行);hold 时重置检测计时避免恢复后误触发。`build_new.bat` 重编,`verify_wedge_fix.py` 回归。 +- **A2** `lab\lan9252_pm.html`:enterMode 成功后发 `pm/hold on=1`;手动唤醒/NRST 流程开头先发 `on=0`(恢复主站自愈)再走 recoverEcatMaster;banner 文案同步。 +- **A3**(小改)睡眠标记另写一份带时间戳的 localStorage,新标签页打开时据此跳过自动状态读。 +- 效果:休眠期间主站不再自动拉回 OP;但芯片仍会被 GD32 自己唤醒,EtherCAT 保持断开直到你手动唤醒(行为=「我睡了就是睡了」,但低功耗目的未真正达成)。 + +## Phase B:GD32 固件根因修复(需 cbuild 构建 + 刷板) +- **B1** `G:\Robot_v2\DCU\DCU_APP\GD32E508_DCU_APP\comm\esc_lan9252.cpp/.h`:新增全局挂起标志;pmDrive op=1/2/3 成功进睡眠时置位,op=4 唤醒成功/nrstDrive/hardwareReset 时清除。 +- **B2** 门控点:`sys\task_runner.cpp` 的 `MainLoop()`、`ethercatAleMaskGuard()`、`ethercatAlHeartbeat()`;PDI/Sync0 EXTI ISR 顶部查标志直接返回(ISR 内 HBI 读同样会唤醒芯片)。0xC5/0xC4 轮询不碰 ESC,无需改。 +- **B3** 核对唤醒后 SSC 阴影状态一致性(现有页面唤醒路径一律 NRST+motor/start,NRST 会全复位芯片)。 +- **B4** 按 cbuild+vcpkg AC6+ninja 链构建刷板,刷完 `/api/motor/start` 恢复 OP。 +- 加上 B 后芯片才能真正保持 D1-D3 低功耗态。 + +## 验证 +- 进睡眠后任务管理器流量掉 0 并**保持**,native 日志无 WEDGE 重拉;GD32 串口 `[ECAT][HB]` 心跳停止(B 后);间隔 2s/10s/30s 查询状态仍为睡眠态;手动唤醒后流量恢复进 OP。 +- hold=0 时正常楔死自愈回归不受影响。 \ No newline at end of file diff --git a/ECAT_BEAT_TAIL_REPORT.html b/ECAT_BEAT_TAIL_REPORT.html index a737198..24556a4 100644 --- a/ECAT_BEAT_TAIL_REPORT.html +++ b/ECAT_BEAT_TAIL_REPORT.html @@ -43,7 +43,7 @@ ul{padding-left:22px}

EtherCAT 单拍耗时 345µs→124µs:改动原理与验证

调查日期 2026-09-11 · 台子:i7-14700K + Intel I210(100 Mbps 全双工)+ DCU(GD32E508 + LAN9252)+ 3 台电机 · 源报告 tools/ecat/REPORT_ecat_beat_tail_20260911.md · 本页所有数字已对照源码与实机复测核验(layout=dense、rx p50=92.1µs、wkc 3/3、v1.6.22.0)
-
345 → 124µs9/11 当天 0.5ms 档整拍 p50 实测(cyc_us.work)
310 → 92µs主站等回包 rx p50 —— 变化都在这一段
124.6µs9/8 同为 win 布局的实测单拍(CSV)—— 345µs 并非 win 固有成本
0.44µs/BPRAM 写单价(DWT 实测)—— 600B≈265µs/拍,两布局共同成本
+
345 → 124µs9/11 当天 0.5ms 档整拍 p50 实测(cyc_us.work)
310 → 92µs主站等回包 rx p50 —— 变化都在这一段
124.6µs9/8 同为 win 布局的实测单拍(CSV)—— 345µs 并非 win 固有成本
线速主导主站 rx ≈ 帧在线上的往返(~1KB @100Mbit ≈ 80µs 量级);从站写 ESC 是另一段时间

结论(2026-09-12 修订)