2026-09-12 20:10:47 +08:00
|
|
|
|
<!DOCTYPE html>
|
|
|
|
|
|
<html lang="zh-CN"><head><meta charset="utf-8">
|
|
|
|
|
|
<meta name="viewport" content="width=device-width,initial-scale=1">
|
|
|
|
|
|
<title>EtherCAT 单拍耗时 345µs→124µs:改动原理与验证</title>
|
|
|
|
|
|
<style>
|
|
|
|
|
|
:root{--fg:#111827;--mut:#6b7280;--bd:#e5e7eb;--bg:#f8fafc;--acc:#1d4ed8;--warn:#b45309;--bad:#b91c1c;--ok:#047857}
|
|
|
|
|
|
*{box-sizing:border-box}
|
|
|
|
|
|
body{margin:0;background:#fff;color:var(--fg);
|
|
|
|
|
|
font:15.5px/1.72 -apple-system,"Segoe UI","Microsoft YaHei",system-ui,sans-serif}
|
|
|
|
|
|
main{max-width:1120px;margin:0 auto;padding:40px 28px 90px}
|
|
|
|
|
|
h1{font-size:29px;line-height:1.3;margin:0 0 6px;letter-spacing:-.2px}
|
|
|
|
|
|
h2{font-size:20px;margin:44px 0 12px;padding-bottom:7px;border-bottom:2px solid var(--bd)}
|
|
|
|
|
|
h3{font-size:16px;margin:26px 0 8px;color:#374151}
|
|
|
|
|
|
p,li{margin:8px 0}
|
|
|
|
|
|
.meta{color:var(--mut);font-size:13.5px;margin-bottom:26px}
|
|
|
|
|
|
.card{background:var(--bg);border:1px solid var(--bd);border-left:4px solid var(--acc);
|
|
|
|
|
|
border-radius:8px;padding:16px 20px;margin:18px 0}
|
|
|
|
|
|
.card.warn{border-left-color:var(--warn);background:#fffbeb}
|
|
|
|
|
|
.card.bad{border-left-color:var(--bad);background:#fef2f2}
|
|
|
|
|
|
.card.ok{border-left-color:var(--ok);background:#ecfdf5}
|
|
|
|
|
|
.card h3{margin:0 0 8px;font-size:15px;color:inherit}
|
|
|
|
|
|
.grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(430px,1fr));gap:18px;margin:18px 0}
|
|
|
|
|
|
.fig{border:1px solid var(--bd);border-radius:8px;padding:12px 10px 8px;background:#fff}
|
|
|
|
|
|
.fig > .cap{font-size:12.5px;font-weight:600;color:#374151;margin:0 0 4px 8px}
|
|
|
|
|
|
.fig > .sub{font-size:11.5px;color:var(--mut);margin:0 0 4px 8px}
|
|
|
|
|
|
table{border-collapse:collapse;width:100%;font-size:13px;margin:14px 0}
|
|
|
|
|
|
th,td{border:1px solid var(--bd);padding:6px 9px;text-align:right}
|
|
|
|
|
|
th{background:#f1f5f9;font-weight:600;text-align:center}
|
|
|
|
|
|
td:first-child,th:first-child{text-align:left}
|
|
|
|
|
|
tr.best td{background:#ecfdf5;font-weight:600}
|
|
|
|
|
|
code{background:#f1f5f9;padding:1.5px 5px;border-radius:4px;font-size:12.5px;
|
|
|
|
|
|
font-family:ui-monospace,"Cascadia Mono",Consolas,monospace}
|
|
|
|
|
|
.kpi{display:flex;gap:14px;flex-wrap:wrap;margin:22px 0 8px}
|
|
|
|
|
|
.kpi div{flex:1 1 168px;border:1px solid var(--bd);border-radius:8px;padding:13px 15px;background:#fff}
|
|
|
|
|
|
.kpi b{display:block;font-size:23px;line-height:1.25;color:var(--acc)}
|
|
|
|
|
|
.kpi span{font-size:12px;color:var(--mut)}
|
|
|
|
|
|
ul{padding-left:22px}
|
|
|
|
|
|
.foot{margin-top:44px;padding-top:16px;border-top:1px solid var(--bd);
|
|
|
|
|
|
font-size:12.5px;color:var(--mut)}
|
|
|
|
|
|
.legend{font-size:12px;color:#374151;margin:2px 0 4px 8px}
|
|
|
|
|
|
.legend i{display:inline-block;width:11px;height:11px;border-radius:2px;margin:0 4px -1px 10px}
|
|
|
|
|
|
</style></head><body><main>
|
|
|
|
|
|
<h1>EtherCAT 单拍耗时 345µs→124µs:改动原理与验证</h1>
|
|
|
|
|
|
<div class="meta">调查日期 2026-09-11 · 台子:i7-14700K + Intel I210(100 Mbps 全双工)+ DCU(GD32E508 + LAN9252)+ 3 台电机 · 源报告 <code>tools/ecat/REPORT_ecat_beat_tail_20260911.md</code> · 本页所有数字已对照源码与实机复测核验(<code>layout=dense</code>、rx p50=92.1µs、wkc 3/3、v1.6.22.0)</div>
|
|
|
|
|
|
|
2026-09-13 04:13:28 +08:00
|
|
|
|
<div class="kpi"><div><b>345 → 124µs</b><span>9/11 当天 0.5ms 档整拍 p50 实测(cyc_us.work)</span></div><div><b>310 → 92µs</b><span>主站等回包 rx p50 —— 变化都在这一段</span></div><div><b>124.6µs</b><span>9/8 同为 win 布局的实测单拍(CSV)—— 345µs 并非 win 固有成本</span></div><div><b>线速主导</b><span>主站 rx ≈ 帧在线上的往返(~1KB @100Mbit ≈ 80µs 量级);从站写 ESC 是另一段时间</span></div></div>
|
2026-09-12 20:10:47 +08:00
|
|
|
|
|
|
|
|
|
|
<div class="card"><h3>结论(2026-09-12 修订)</h3>
|
|
|
|
|
|
<ul>
|
|
|
|
|
|
<li><b>实测事实不变</b>:9/11 当天 0.5ms 档整拍从 345µs 变 124µs、rx 从 ~310µs 变 92.1µs(≈纯线路 81.3µs + ~10µs),与板子重启进 1.6.21/22 密排同时发生;1.6.22 稀疏写开关 A/B/A 无可测影响(92.2 / 92.2 / 93.0µs)。</li>
|
|
|
|
|
|
<li><b>但"345µs 是 win 布局的固有成本、密排省出 220µs"这条归因已被动摇</b>:9/8 的存量扫描在同样 win 布局下实测单拍 <b>124.6µs</b>(0.125ms 档 7780Hz 的硬约束),与 dense 相同——345µs 是 9/10 夜才出现的异常态,不是 win 的常态。详见下方"重大更正"卡。</li>
|
|
|
|
|
|
<li><b>仍然成立的独立事实</b>:刷写 ≠ 生效(镜像 01:44 刷入、约 10 小时后断电重启才生效,三方计数器锚点);台账只能证明"写进去了"——<code>flash_gd32.py</code> 已加生效守卫。</li>
|
|
|
|
|
|
</ul></div>
|
|
|
|
|
|
<div class="card bad"><h3>重大更正(2026-09-12 复核):220µs 的归因被动摇,两个变量被混在一起</h3>
|
|
|
|
|
|
<p>用户质疑"5 个 STATUS 变 3 个,怎么会差 20 倍"——顺着查,发现两件原调查没做的事:</p>
|
|
|
|
|
|
<ul>
|
2026-09-13 04:13:28 +08:00
|
|
|
|
<li><b>机制核对(代码层)</b>:两版 buildInput 逐行对比,纯 CPU 差仅 <b>1~3µs</b>(旧:5×48B + 5×44B 无条件拷贝;新:27 槽选最新 + 影子比对 + 3×48B)。对 ESC 的 PRAM 写两版同为整块 600B(从站侧写 ESC 成本,与主站 rx 不是同一段时间),且 A/B/A 证明它对主站往返不可见——<b>"删掉覆盖窗 / 差分填充省出的 CPU"解释不了 229µs</b>。另:差分填充在本台工况下基本不命中(STATUS ~1.25 帧/拍/台,槽 seq 几乎每拍都变,重建路径照样走)。</li>
|
2026-09-12 20:10:47 +08:00
|
|
|
|
<li><b>反例数据(9/8 存量扫描)</b>:<code>lab/ecat_rate_sweep.csv</code>——win 布局、0.5ms 档 cyc_p50=<b>124.6µs</b>、达成 100%;1ms=126.9µs;0.125ms=119.5µs 且实测 7780Hz(单拍必须 ≤128µs 才可能)。与 dense 的 124µs 同水平。</li>
|
|
|
|
|
|
</ul>
|
|
|
|
|
|
<p><b>混淆的变量</b>(刷板台账 git 史 + 主站 git 史):9/8 板上镜像 <code>201832b5…</code>(win)→ 9/10 前已刷 <code>4e84a354…</code>(win 期 1.6.15→1.6.20 演进);主站 9/9 03:05 提交 <code>97fab23</code>(三布局自适应、发现窗基址 {0,7,14,20}→{0,5,10,15,20,22}、覆盖窗按 seq 归一)。<b>345µs 出现在这两个改动之后、9/8 之前</b>——原归因把回归记在 1.6.21 密排头上,但密排也可能只是"绕开"了回归(dense 下主站强制 n_bases=1,不轮转窗口)。</p>
|
|
|
|
|
|
<p><b>钉死实验(一次刷板,未执行)</b>:① 刷回 <code>959e2ae</code>(win 固件)+ <code>build_native/ecat_native.prev.exe</code>(9/6 构建,早于 97fab23;它不认识 dense 布局,必须配 win 板)→ 回 ~124µs 即主站回归实锤;② 同 win 板 + 现主站 → 345µs 复现即双向确认;③ 若 prev.exe 也 345µs ⇒ 回归在从站 win 期固件演进里,对 1.6.15→1.6.20 bisect;④ win 模式读 DWT 剖分计数器 0x2000 sub5/6/9/10(PDI_Isr 全程 / 输出映射 / 输入映射 / 其中写侧)——SDO 走独占路由会停环掉 OP,需专门开窗。</p></div>
|
|
|
|
|
|
|
|
|
|
|
|
<h2>一、一拍的生命周期:210µs 差在哪一环</h2>
|
|
|
|
|
|
<p>主站每一拍做的事:<b>组帧 → <code>pcap_sendpacket</code> 发出 → 等帧从线路绕回来(<code>pcap_next_ex</code>)→ 解码</b>。等回包(rx)的时长 = 线路传输时间 + <b>从站把这一拍的输入镜像备好的时间</b>——LAN9252 的 SM2 事件触发 PDI 中断,从站要在 ESC 把输入区搬上线路之前把 600B 输入镜像写好,主站就得等这段活干完。</p>
|
|
|
|
|
|
<div class="grid">
|
|
|
|
|
|
<div class="fig"><div class="cap">① 同一 0.5ms 档、同一静默判据下的一拍构成(µs)</div>
|
|
|
|
|
|
<div class="legend"><i style="background:#94a3b8"></i>主站自身(pre+post 合计 0.3µs)<i style="background:#2563eb"></i>发送(组帧 0.2 + pcap_sendpacket ≈28.4)<i style="background:#fca5a5"></i>线路传输 81.3µs(两布局相同)<i style="background:#dc2626"></i>从站每拍准备(PDI buildInput)</div>
|
|
|
|
|
|
<svg viewBox="0 0 620 212" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="一拍构成对比">
|
|
|
|
|
|
<line x1="150" y1="180" x2="600" y2="180" stroke="#9aa3af" stroke-width="1.2"/>
|
|
|
|
|
|
<line x1="150" y1="28" x2="150" y2="180" stroke="#9aa3af" stroke-width="1.2"/>
|
|
|
|
|
|
<line x1="278" y1="176" x2="278" y2="184" stroke="#9aa3af"/><text x="278" y="197" text-anchor="middle" font-size="10.5" fill="#6b7280">100</text>
|
|
|
|
|
|
<line x1="406" y1="176" x2="406" y2="184" stroke="#9aa3af"/><text x="406" y="197" text-anchor="middle" font-size="10.5" fill="#6b7280">200</text>
|
|
|
|
|
|
<line x1="534" y1="176" x2="534" y2="184" stroke="#9aa3af"/><text x="534" y="197" text-anchor="middle" font-size="10.5" fill="#6b7280">300</text>
|
|
|
|
|
|
<text x="150" y="197" text-anchor="middle" font-size="10.5" fill="#6b7280">0</text>
|
|
|
|
|
|
<text x="596" y="197" text-anchor="middle" font-size="10.5" fill="#6b7280">µs</text>
|
|
|
|
|
|
<text x="142" y="64" text-anchor="end" font-size="12" fill="#374151">1.6.15 滑窗</text>
|
|
|
|
|
|
<text x="170" y="40" text-anchor="middle" font-size="10.5" fill="#1e40af">发送 ≈28.6µs</text>
|
|
|
|
|
|
<rect x="150" y="48" width="2" height="24" fill="#94a3b8"/>
|
|
|
|
|
|
<rect x="152" y="48" width="36.6" height="24" fill="#2563eb"/>
|
|
|
|
|
|
<rect x="188.6" y="48" width="104.1" height="24" fill="#fca5a5"/>
|
|
|
|
|
|
<rect x="292.7" y="48" width="293.1" height="24" fill="#dc2626"/>
|
|
|
|
|
|
<rect x="585.8" y="48" width="2" height="24" fill="#94a3b8"/>
|
|
|
|
|
|
<text x="240" y="64" text-anchor="middle" font-size="10.5" fill="#7f1d1d" font-weight="600">线路 81.3</text>
|
|
|
|
|
|
<text x="439" y="64" text-anchor="middle" font-size="10.5" fill="#fff" font-weight="600">从站每拍准备 ≈229µs</text>
|
|
|
|
|
|
<text x="152" y="86" text-anchor="start" font-size="11" font-weight="600" fill="#b91c1c">rx 往返 ≈310µs = 线路 81.3 + 从站准备 ≈229 · 整拍 p50 345µs · 达成 93.9%</text>
|
|
|
|
|
|
<text x="142" y="134" text-anchor="end" font-size="12" fill="#374151">1.6.21 密排</text>
|
|
|
|
|
|
<text x="308" y="110" text-anchor="start" font-size="11.5" font-weight="600" fill="#047857">整拍 p50 124µs · 达成 99.9%</text>
|
|
|
|
|
|
<rect x="150" y="118" width="2" height="24" fill="#94a3b8"/>
|
|
|
|
|
|
<rect x="152" y="118" width="36.6" height="24" fill="#2563eb"/>
|
|
|
|
|
|
<rect x="188.6" y="118" width="104.1" height="24" fill="#fca5a5"/>
|
|
|
|
|
|
<rect x="292.7" y="118" width="12.8" height="24" fill="#dc2626"/>
|
|
|
|
|
|
<rect x="305.5" y="118" width="2" height="24" fill="#94a3b8"/>
|
|
|
|
|
|
<text x="240" y="134" text-anchor="middle" font-size="10.5" fill="#7f1d1d" font-weight="600">线路 81.3</text>
|
|
|
|
|
|
<text x="152" y="156" text-anchor="start" font-size="11" font-weight="600" fill="#047857">rx 92.1µs = 线路 81.3 + 从站准备 ≈10(差分填充命中,接近纯线时)</text>
|
|
|
|
|
|
<line x1="292.7" y1="30" x2="292.7" y2="172" stroke="#dc2626" stroke-width="1" stroke-dasharray="4,3" opacity="0.55"/>
|
|
|
|
|
|
<text x="298" y="36" font-size="10.5" fill="#b91c1c">虚线处线路段用完(28.6+81.3≈110µs),之后整段在等从站</text>
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
<div class="sub">数字出处:整拍与 rx 取自同机同档静默窗实测(win 345 / 310;dense 124 / 92.2,1ms 档复测 92.1);发送 ≈28.6µs 为 0.5ms 档 A 臂 p50(1ms 档 dbg 拆段 26.6~31.3µs,内含组帧 0.2µs);线路 81.3µs = 1016B×8÷100Mbps;win 从站准备 ≈229 = 310−81.3,与固件自量 buildInput 357µs(更重负载下所测)同量级。三段的逐层组成见下表。</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<h3>三段逐层拆解(对应图中蓝 / 粉 / 红三个色块)</h3>
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<tr><th>段</th><th>0.5ms 实测 p50</th><th>从外到内的组成</th><th>出处 / 尚未拆开的部分</th></tr>
|
|
|
|
|
|
<tr><td>发送(蓝)</td><td>28.6µs</td><td>组帧 ≈0.2µs(组 LRW + 填输出区)→ <code>pcap_sendpacket</code> ≈28.4µs:NPF 栈把 1016B 交给 I210 驱动并提交发送</td><td><code>/api/motor/dbg</code> 拆段(sd_us 列)。驱动/DMA 内部无仪表;B 臂曾见发送 p99 348.9µs 的偶发阻塞(单窗样本,未立论)</td></tr>
|
|
|
|
|
|
<tr><td>线路(粉)</td><td>81.3µs</td><td>帧 1016B = 过程数据 984B(输出 384 + 输入 600)+ 以太网头 14 + EtherType 2 + 数据报头 10 + WKC 2 + FCS 4;8128bit ÷ 100Mbps;再加前导 8B + 帧间隙 12B ≈ +1.6µs;从站 ESC 硬件转发 µs 级</td><td>由帧构成计算,两布局逐字节同长——结构上不可能解释 220µs 差</td></tr>
|
2026-09-13 04:13:28 +08:00
|
|
|
|
<tr><td>从站准备(红)· win</td><td>≈229µs</td><td>1.6.15 每拍在 PDI 里:① 按 win_base 轮转准备 27 槽表 ② 段4 覆盖窗 5×44B 拷贝 ③ MotorState 重读 + 逐槽 48B 拷贝 ④ 整块 600B 写入 ESC</td><td>实测差值 310−81.3。①②③ 纯 CPU 差仅 1~3µs;④ 是从站写 ESC(两布局同在、不影响主站往返)——229µs 载体未闭环;9/8 同布局 124.6µs 表明"345µs=win 固有"不成立</td></tr>
|
2026-09-12 20:10:47 +08:00
|
|
|
|
<tr><td>从站准备(红)· dense</td><td>≈10µs</td><td>差分填充命中:节点集合与各 seq 未变 → 整段复用影子,①②③全免;只剩 count 个槽的更新推送 + ESC 取数</td><td>rx 92.1 − 81.3。220µs 的差全部消失在这里</td></tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<p class="meta">口径备注:win 时代插桩拆段亦记录到 <code>pcap_sendpacket</code> 181.1µs、其后续中位 1 次 poll 即得帧(§四表)——该口径下发送调用内部吸收了部分等待,<b>发送/等回包两段的分界随仪表口径浮动</b>;但整拍总量(345)与"扣除线路后的从站侧总延迟"(≈229)不受此影响。另 1ms 档每拍 next_ex 轮询中位 79 次(轮询间隔 ~1.2µs),0.5ms 档为紧轮询。</p>
|
|
|
|
|
|
<p><b>原理(按 9/11 当天的观测口径):</b>SM 长度(600B)与线速两布局完全相同,所以"线路那一截"不变;rx 的差值实测全部落在"等从站"这一段。但这段差值的载体机制存在重大疑点——两版 buildInput 的纯 CPU 差仅 1~3µs,且 9/8 同布局实测 124.6µs 表明 345µs 并非 win 固有成本——见开头"重大更正"卡。图①对比的是 9/11 上午 win 异常态 vs 午后 dense 的实测,不代表两种布局的固有差距。</p>
|
|
|
|
|
|
|
|
|
|
|
|
<h2>二、改动原理 A:从站输入映射 1.6.15 滑窗 → 1.6.21 密排整轮</h2>
|
|
|
|
|
|
<p>两种布局的输入区都是 600B(SM 长度、SII 都不变),只靠输入区第 35 字节的魔数 <code>0xA5</code> 区分(<code>ecat_native.c:74-84</code>,固件 <code>ethercat_can_bridge.h:154</code> 同款注释):</p>
|
|
|
|
|
|
<div class="grid">
|
|
|
|
|
|
<div class="fig"><div class="cap">② 输入 PDO 600B 布局对比(按字节偏移)</div>
|
|
|
|
|
|
<svg viewBox="0 0 620 252" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="输入区布局对比">
|
|
|
|
|
|
<text x="142" y="68" text-anchor="end" font-size="12" fill="#374151">1.6.15 滑窗</text>
|
|
|
|
|
|
<rect x="150" y="52" width="22.4" height="26" fill="#cbd5e1"/>
|
|
|
|
|
|
<rect x="172.4" y="52" width="5.6" height="26" fill="#64748b"/>
|
|
|
|
|
|
<rect x="178" y="52" width="196" height="26" fill="#2563eb"/>
|
|
|
|
|
|
<rect x="374" y="52" width="28" height="26" fill="#7c3aed"/>
|
|
|
|
|
|
<rect x="402" y="52" width="156.8" height="26" fill="#dc2626"/>
|
|
|
|
|
|
<rect x="558.8" y="52" width="11.2" height="26" fill="#16a34a"/>
|
|
|
|
|
|
<text x="276" y="68" text-anchor="middle" font-size="10.5" fill="#fff" font-weight="600">段2 STATUS 5×56B(固定 5 槽,空槽占位)</text>
|
|
|
|
|
|
<text x="480" y="47" text-anchor="middle" font-size="10.5" fill="#b91c1c" font-weight="600">段4 覆盖窗 5×44B(每拍维护)</text>
|
|
|
|
|
|
<text x="480" y="90" text-anchor="middle" font-size="10" fill="#7f1d1d">fillRxWindow / RxWinSlot 整套</text>
|
|
|
|
|
|
<text x="161" y="47" text-anchor="middle" font-size="10" fill="#475569">桥计数</text>
|
|
|
|
|
|
<text x="142" y="178" text-anchor="end" font-size="12" fill="#374151">1.6.21 密排</text>
|
|
|
|
|
|
<rect x="150" y="162" width="22.4" height="26" fill="#cbd5e1"/>
|
|
|
|
|
|
<rect x="172.4" y="162" width="5.6" height="26" fill="#64748b"/>
|
|
|
|
|
|
<rect x="178" y="162" width="117.6" height="26" fill="#2563eb"/>
|
|
|
|
|
|
<rect x="295.6" y="162" width="235.2" height="26" fill="#eff6ff" stroke="#93c5fd" stroke-dasharray="4,3"/>
|
|
|
|
|
|
<rect x="530.8" y="162" width="28" height="26" fill="#7c3aed"/>
|
|
|
|
|
|
<rect x="558.8" y="162" width="11.2" height="26" fill="#16a34a"/>
|
|
|
|
|
|
<text x="236" y="178" text-anchor="middle" font-size="10.5" fill="#fff" font-weight="600">密排槽×3(56B/台)</text>
|
|
|
|
|
|
<text x="413" y="157" text-anchor="middle" font-size="10" fill="#1d4ed8">按 count 扩展,最多 9 台(空节点不占位)</text>
|
|
|
|
|
|
<text x="413" y="200" text-anchor="middle" font-size="10" fill="#1d4ed8">1.6.22 稀疏写:这段不再推入 ESC RAM</text>
|
|
|
|
|
|
<text x="413" y="178" text-anchor="middle" font-size="10" fill="#6b7280">count=3 时空闲</text>
|
|
|
|
|
|
<text x="161" y="157" text-anchor="middle" font-size="10" fill="#475569">桥计数</text>
|
|
|
|
|
|
<line x1="150" y1="216" x2="570" y2="216" stroke="#9aa3af" stroke-width="1.2"/>
|
|
|
|
|
|
<text x="150" y="233" text-anchor="middle" font-size="10" fill="#6b7280">0</text>
|
|
|
|
|
|
<text x="220" y="233" text-anchor="middle" font-size="10" fill="#6b7280">100</text>
|
|
|
|
|
|
<text x="290" y="233" text-anchor="middle" font-size="10" fill="#6b7280">200</text>
|
|
|
|
|
|
<text x="360" y="233" text-anchor="middle" font-size="10" fill="#6b7280">300</text>
|
|
|
|
|
|
<text x="430" y="233" text-anchor="middle" font-size="10" fill="#6b7280">400</text>
|
|
|
|
|
|
<text x="500" y="233" text-anchor="middle" font-size="10" fill="#6b7280">500</text>
|
|
|
|
|
|
<text x="570" y="233" text-anchor="middle" font-size="10" fill="#6b7280">600(字节)</text>
|
|
|
|
|
|
<text x="150" y="248" font-size="10" fill="#6b7280">头区 32..39:win= active/boot/win_base/win_count/gseq@36 · 密排= count/active/boot/magic@35/gseq@36 —— 两种布局 gseq 同在偏移 36</text>
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
<div class="sub">段3 长帧(CONFIG/版本应答):win 在 320..359,密排前移到 544..583;段5 诊断两者都在 584..599。主站 <code>decode_input</code> 每拍判 magic@35 自适应,两端可任意先后升级。</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<h3>1.6.21 的三个子改动,各砍掉什么活</h3>
|
|
|
|
|
|
<div class="card"><h3>① 密排整轮:固定 5 槽 + win_base 轮转扫 27 槽 → count 个密排槽</h3>
|
|
|
|
|
|
<p>旧方案段 2 固定 5 个 STATUS 槽(空槽 node_id=0 也占位),主站按 <code>win_base</code> 轮转窗口才能盖到 9 节点×3 通道=27 槽的表——接 3 台电机却会看到 5 个状态帧。新方案一拍直接带齐总线上全部电机(本台 3 台=3 槽×56B),槽内按 node_id 升序,主站按 <code>count</code> 迭代。砍掉的是<b>主站轮转窗口带来的多拍刷新分频</b>与从站"为凑满 5 槽而做的填充"。</p></div>
|
|
|
|
|
|
<div class="card"><h3>② 删段 4 覆盖窗口(fillRxWindow / RxWinSlot 整套)</h3>
|
|
|
|
|
|
<p>旧方案每拍要把非 STATUS 帧抄进 5×44B 的历史覆盖窗反复重发——这是纯粹的每拍 CPU 拷贝活。新方案非 STATUS 帧只走段 1/3 的"最近一帧",覆盖窗整套删除(图中 win 红段在密排侧不复存在)。</p></div>
|
|
|
|
|
|
<div class="card"><h3>③ 差分填充:节点集合与各 seq 未变时整段复用影子</h3>
|
|
|
|
|
|
<p>注意一个容易误解的点:电机"不动"≠数据不变——STATUS 帧按电机自己的节奏持续上报(本台 3 台合计 ~3750 帧/s,每台 ~1.25 帧/拍),所以大多数拍里槽 seq 都变了、重建路径照样走(实测槽 seq 每 ~1 拍刷新一次)。差分填充真正的收益是"没变的槽不重读不重拷、重建范围从无条件 5 槽缩到实际变化的槽"——量级是 µs 级的,<b>不能用它解释 rx 310→92</b>(见开头"重大更正"卡)。</p></div>
|
|
|
|
|
|
|
|
|
|
|
|
<h2>三、改动原理 B:1.6.22 稀疏写为何对主站往返"无效"</h2>
|
|
|
|
|
|
<p>1.6.22 的思路:PDI 往 ESC RAM 写输入镜像时按 count 只写「段1+段2 有效区」与「段3+段5」,跳过空槽区,省 <code>HW_EscWriteIsr</code> 的 PRAM 字节。<b>方向是对的,但省错了地方</b>——这里有一个关键的不对称:</p>
|
|
|
|
|
|
<div class="card warn"><h3>不对称原理:差分填充有效、稀疏写无效</h3>
|
|
|
|
|
|
<ul>
|
|
|
|
|
|
<li>主站等的关键路径 = <b>SM 交换</b>(ESC 引擎把 600B 输入区搬上线路)+ 交换前从站把镜像<b>备好</b>。</li>
|
|
|
|
|
|
<li><b>差分填充砍的是"备好镜像"的 CPU 活</b>(MotorState 重读、逐槽拷贝、覆盖窗维护)→ 直接缩短关键路径 ⇒ rx 310→92µs。</li>
|
|
|
|
|
|
<li><b>稀疏写砍的是"推镜像进 ESC RAM"的字节数</b>,但 ESC 引擎上线搬运量由 <b>SM 长度(600B)</b>决定,不看 PDI 实际写了多少 → 主站等待不变。</li>
|
|
|
|
|
|
</ul></div>
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<tr><th>A/B/A 轮次(只改这一个开关)</th><th>板上版本</th><th>0.5ms 达成</th><th>长拍%</th><th>发送 p50/p99 µs</th><th>等回包 rx p50/p99 µs</th><th>load_perm</th></tr>
|
|
|
|
|
|
<tr class="best"><td>A:稀疏写=1(出厂)</td><td>1.6.22.0</td><td>99.90%</td><td>0.10</td><td>28.6 / 45.9</td><td>92.2 / 190.9</td><td>489</td></tr>
|
|
|
|
|
|
<tr><td>B:整包写=0(A/B 基线)</td><td>1.6.22.1</td><td>99.42%</td><td>0.83</td><td>29.8 / 348.9</td><td>92.2 / 210.4</td><td>441</td></tr>
|
|
|
|
|
|
<tr class="best"><td>A 回归</td><td>1.6.22.0</td><td>99.85%</td><td>0.10</td><td>29.4 / 86.9</td><td>93.0 / 101.2</td><td>—</td></tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<p class="meta">判读:rx p50 三轮 92.2/92.2/93.0µs ⇒ 稀疏写对主站往返无可测影响;<code>load_perm</code> 反而在整包写侧更低(441 vs 489)⇒ 它不能当这项的验收口径(真正该看 ESC 对象 0x2000 sub10,需独占路由停循环才能读,未做)。B 臂发送 p99 348.9µs 与 A 臂不同量级,但单窗样本不足以立论。当前 <code>config.h</code> 已回置出厂 A 臂(<code>CONFIG_ECAT_SPARSE_ESC_WRITE=1</code>)。</p>
|
|
|
|
|
|
|
|
|
|
|
|
<h2>四、配套改动:把"看不见的东西"变成仪表</h2>
|
|
|
|
|
|
<p>排查过程暴露了四个观测缺口,对应的改动与各自原理:</p>
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<tr><th>改动</th><th>解决什么问题</th><th>原理</th><th>验证</th></tr>
|
|
|
|
|
|
<tr><td><code>flash_gd32.py</code> 生效守卫</td><td>台账只能证明"写进去了",不能证明"板上在跑"(本次 10 小时空窗的根因)</td><td>刷前记 <code>ota.gd32_app</code> 版本 + <code>gd32_adc.uptime_sec</code>;刷完必须"版本变了<b>或</b> uptime 归零"才写台账,否则非零退出不写</td><td>两轮真实刷写 1.6.22.0→.1→.0 通过</td></tr>
|
|
|
|
|
|
<tr><td><code>ecat_native.c</code> <code>cyc_us.late/lost</code> 接真值</td><td>两字段旧为硬编码 0,超期/跳拍完全不可见</td><td>最近 STATS_N 拍窗口内统计:<code>late</code>=起跑即超期(k>0)的拍数,<code>lost</code>=这些拍跳过的周期数(累计仍在 skip_total)</td><td>重载窗 late=21/lost=28,健康窗 0/0</td></tr>
|
|
|
|
|
|
<tr><td><code>/api/motor/dbg</code> 尾部追加两列</td><td>发送段是黑盒:不知 sendpacket 花多久、轮询了几次</td><td>第 7/8 列 = 本拍 <code>pcap_sendpacket</code> 净耗时与 <code>pcap_next_ex</code> 次数;旧列序不变,按前 6 列下标读的消费方不受影响</td><td>0.5ms 档 181µs 调用、每拍中位 1 次 poll</td></tr>
|
|
|
|
|
|
<tr><td><code>soem-src/oshw/win32/nicdrv.c</code> pcap 调用计数</td><td>主/从栈调用混在一起没法归因</td><td>只在 <code>stacknumber==0</code>(主栈)累加 QPC 计数,冗余栈不计防双计</td><td>A/B 与旧构建行为一致(中性)</td></tr>
|
|
|
|
|
|
<tr><td><code>watch_beat_tail.py</code>(新)</td><td>跨分钟现象无法回溯(布局翻转恰好发生在两次采样之间)</td><td>每 10s 只读一轮 <code>motor/state</code>+<code>rxraw</code>+<code>app/load</code>,落 27 列 CSV(layout/work/send/rx/late/lost/λ/达成)</td><td><code>--once</code> 跑通</td></tr>
|
|
|
|
|
|
<tr><td><code>transport-ecat.js</code> 常量适配</td><td>前端仍按旧 5 槽/6 周期口径显示</td><td>密排下一拍整轮:<code>MOT_SLOTS_PER_PDO</code> 5→9、<code>MOTOR_SCAN_CYCLES</code> 6→1;能否拿齐电机由后端 decode 决定,常量只影响展示口径</td><td>电机页原样复用,无回归</td></tr>
|
|
|
|
|
|
<tr><td><code>lab/spi_test.html</code> 跳拍卡</td><td>旧版需开逐拍环才有超期数据</td><td>直接读 <code>cyc_us.late/lost</code>(最近 400 拍窗),并注明旧后端恒报 0 不可当"无超期"</td><td>真机复跑成功,<code>node --check</code> 通过</td></tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
|
|
<h2>五、证据:dense 是真的,以及为什么今天才生效</h2>
|
|
|
|
|
|
<div class="grid">
|
|
|
|
|
|
<div class="fig"><div class="cap">③ 判据:槽 seq 距当前 gseq 的滞后分布(111 次连续采样 ×3 槽=333 样本)</div>
|
|
|
|
|
|
<svg viewBox="0 0 560 232" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="槽滞后分布">
|
|
|
|
|
|
<rect x="376" y="20" width="160" height="180" fill="#dc2626" opacity="0.06"/>
|
|
|
|
|
|
<rect x="376" y="20" width="160" height="180" fill="none" stroke="#dc2626" stroke-dasharray="4,3" opacity="0.5"/>
|
|
|
|
|
|
<text x="456" y="52" text-anchor="middle" font-size="10.5" fill="#b91c1c" font-weight="600">滑窗方案预期落点</text>
|
|
|
|
|
|
<text x="456" y="68" text-anchor="middle" font-size="10" fill="#7f1d1d">每槽每 ≥2 拍才轮到一次</text>
|
|
|
|
|
|
<text x="456" y="82" text-anchor="middle" font-size="10" fill="#7f1d1d">滞后应 ≈4~8 帧 —— 实测 0 个样本</text>
|
|
|
|
|
|
<rect x="73" y="24.5" width="34" height="170.5" fill="#2563eb"/>
|
|
|
|
|
|
<rect x="125" y="63.3" width="34" height="131.7" fill="#2563eb"/>
|
|
|
|
|
|
<rect x="177" y="75.7" width="34" height="119.3" fill="#2563eb"/>
|
|
|
|
|
|
<rect x="229" y="102" width="34" height="93" fill="#2563eb"/>
|
|
|
|
|
|
<rect x="281" y="193.5" width="34" height="1.5" fill="#2563eb"/>
|
|
|
|
|
|
<text x="90" y="20" text-anchor="middle" font-size="10" fill="#1e40af">110</text>
|
|
|
|
|
|
<text x="142" y="58" text-anchor="middle" font-size="10" fill="#1e40af">85</text>
|
|
|
|
|
|
<text x="194" y="71" text-anchor="middle" font-size="10" fill="#1e40af">77</text>
|
|
|
|
|
|
<text x="246" y="97" text-anchor="middle" font-size="10" fill="#1e40af">60</text>
|
|
|
|
|
|
<text x="298" y="189" text-anchor="middle" font-size="10" fill="#1e40af">1</text>
|
|
|
|
|
|
<line x1="60" y1="195" x2="536" y2="195" stroke="#9aa3af" stroke-width="1.2"/>
|
|
|
|
|
|
<text x="90" y="211" text-anchor="middle" font-size="10.5" fill="#6b7280">0</text>
|
|
|
|
|
|
<text x="142" y="211" text-anchor="middle" font-size="10.5" fill="#6b7280">1</text>
|
|
|
|
|
|
<text x="194" y="211" text-anchor="middle" font-size="10.5" fill="#6b7280">2</text>
|
|
|
|
|
|
<text x="246" y="211" text-anchor="middle" font-size="10.5" fill="#6b7280">3</text>
|
|
|
|
|
|
<text x="298" y="211" text-anchor="middle" font-size="10.5" fill="#6b7280">4</text>
|
|
|
|
|
|
<text x="456" y="211" text-anchor="middle" font-size="10.5" fill="#6b7280">≥6(帧)</text>
|
|
|
|
|
|
<text x="60" y="16" font-size="10.5" fill="#6b7280">样本数 · λ≈3.75 帧/拍(3750 帧/s @ 1kHz)</text>
|
|
|
|
|
|
<text x="280" y="228" text-anchor="middle" font-size="11" fill="#374151">槽 seq 滞后于当前 global_seq(帧数)</text>
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
<div class="sub">三台电机落在槽 2/5/8:滑窗方案盖住它们需 ≥2 个基址轮转 → 每槽每 ≥2 拍才刷新、滞后应集中在 4~8 帧。实测 1/3 样本滞后为 0、全部 ≤4 帧 ⇒ 只能是"每拍带齐整轮"的密排语义。seq 与 gseq 都是 GD32 自己盖的号,滞后能对上同时证明解码偏移没错。(原报告曾把"gseq≡rx_count"当最强证据,复核发现两种布局 gseq 同在偏移 36,该条不能区分布局,已撤换为本判据。)</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<div class="fig"><div class="cap">④ 时间线:刷写 ≠ 生效</div>
|
|
|
|
|
|
<svg viewBox="0 0 620 150" width="100%" xmlns="http://www.w3.org/2000/svg" role="img" aria-label="时间线">
|
|
|
|
|
|
<line x1="70" y1="70" x2="560" y2="70" stroke="#9aa3af" stroke-width="1.6"/>
|
|
|
|
|
|
<circle cx="100" cy="70" r="5" fill="#2563eb"/>
|
|
|
|
|
|
<circle cx="290" cy="70" r="5" fill="#dc2626"/>
|
|
|
|
|
|
<circle cx="430" cy="70" r="5" fill="#b45309"/>
|
|
|
|
|
|
<circle cx="530" cy="70" r="5" fill="#047857"/>
|
|
|
|
|
|
<text x="100" y="30" text-anchor="middle" font-size="11" fill="#374151">01:44 镜像刷入 1.6.22</text>
|
|
|
|
|
|
<text x="100" y="45" text-anchor="middle" font-size="10" fill="#6b7280">台账 sha=hex 展平 ✓</text>
|
|
|
|
|
|
<text x="290" y="30" text-anchor="middle" font-size="11" fill="#b91c1c">白天:仍在跑老代码</text>
|
|
|
|
|
|
<text x="290" y="45" text-anchor="middle" font-size="10" fill="#6b7280">主站实测 win 布局 · 232B · 整拍 345µs</text>
|
|
|
|
|
|
<text x="430" y="100" text-anchor="middle" font-size="11" fill="#b45309">中午断电重启</text>
|
|
|
|
|
|
<text x="530" y="100" text-anchor="middle" font-size="11" fill="#047857">生效:dense · 124µs</text>
|
|
|
|
|
|
<path d="M100,84 L100,96 L430,96 L430,84" fill="none" stroke="#b45309" stroke-width="1.4"/>
|
|
|
|
|
|
<text x="265" y="115" text-anchor="middle" font-size="11.5" font-weight="600" fill="#b45309">≈10 小时:写入 ≠ 生效</text>
|
|
|
|
|
|
<text x="70" y="140" font-size="10" fill="#6b7280">三方计数器锚点(不依赖系统时钟):主站进程存活 2084s · GD32 桥计数归零 1914s(gseq÷λ)· ESP32 上电 1922s —— 后两者差 8s,GD32 与 ESP32 同次上电;板子比主站晚 ~2.8 分钟重启,且 uptime 单调增(只重启过一次)</text>
|
|
|
|
|
|
</svg>
|
|
|
|
|
|
<div class="sub">主站在 02:3x 直接读到 <code>layout="win" len=232</code> 配 345µs——刷入后 10 小时仍是老代码在跑。台账 <code>_last_gd32_sha.txt</code> 当时就与 Release hex 展平一致,即"写进去了"为真,"在跑了"为假。(A/B/A 之后台账现为 dda92d11…,对应 12:46 刷回 A 臂的产物,本次复核独立展平重算一致。)</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
</div>
|
|
|
|
|
|
<h3>同机同日前后对照(观察性证据)</h3>
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<tr><th>从站布局</th><th>rx 往返</th><th>整拍 p50</th><th>达成</th><th>长拍>1.4×</th><th>跳拍 k>0</th><th>gap p99</th></tr>
|
|
|
|
|
|
<tr><td><code>win</code>(1.6.15 滑窗)</td><td>~310µs</td><td>345µs</td><td>93.9%(1879Hz)</td><td>7.9%</td><td>8.6%</td><td>1144µs</td></tr>
|
|
|
|
|
|
<tr class="best"><td><code>dense</code>(1.6.21/22 密排)</td><td>92.2µs</td><td>123µs</td><td>99.9%(1998Hz)</td><td>0.10%</td><td>~0.6%</td><td>=周期本身</td></tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
<p class="meta">0.5ms 档余量从 155µs 变为 377µs:旧方案任何调度抖动都会成片跳拍,新方案长拍基本消失。另 1ms 档现网 <code>late/lost</code>(k>0 口径,连 1µs 超期都算)为个位数/400 拍窗,与"长拍>1.4×≈0%"不矛盾——两套阈值灵敏度不同,并列引用时必须标注口径。</p>
|
|
|
|
|
|
|
|
|
|
|
|
<h2>六、被实测排除的原因(别再重测)</h2>
|
|
|
|
|
|
<table>
|
|
|
|
|
|
<tr><th>候选解释</th><th>排除依据</th></tr>
|
|
|
|
|
|
<tr><td>线路变快 / 帧变小</td><td>两种布局 Ibytes 同为 600B(<code>ecat_native.c:74</code> 与固件头文件双侧注释),帧长 ~1016B 不变,线速仍 100Mbps 全双工</td></tr>
|
|
|
|
|
|
<tr><td>收帧超时(EC_TIMEOUTRET)</td><td>预算 2000µs(µs 单位),11,264 拍里仅 1 拍 EC_NOFRAME;win 时代 rx p50 7~9µs 起步,预算从不消耗——收紧它是自证式"变好"</td></tr>
|
|
|
|
|
|
<tr><td>主站构建差异 / 双实例</td><td>插桩版与旧构建 A/B 一致;单进程单端口;旧 exe 留档 <code>build_native/ecat_native.pre-instr.exe</code></td></tr>
|
|
|
|
|
|
<tr><td>观察者负载</td><td>面板全量 10Hz×3、单 dbg 10Hz(≈1.5MB/s JSON)、零请求静默窗,三者结果在噪声内相同</td></tr>
|
|
|
|
|
|
<tr><td>CPU 抢占</td><td>另开 4 / 12 个纯算线程压机,send/rx/work 一动不动</td></tr>
|
|
|
|
|
|
<tr><td>"PRAM 逐 DWORD 轮数 150→45"</td><td>被 A/B/A 否:整包写 600B 的 B 臂同样 92µs——写侧省字节数不进入主站关键路径(§三不对称原理)</td></tr>
|
|
|
|
|
|
</table>
|
|
|
|
|
|
|
|
|
|
|
|
<h2>七、复核更正(本次排查自己错过又改掉的判断)</h2>
|
|
|
|
|
|
<div class="card bad"><h3>证据层的两处撤换</h3>
|
|
|
|
|
|
<ul>
|
|
|
|
|
|
<li><b>"gseq≡rx_count,差恒 0"是同义反复</b>:<code>MOTW_OFF_GLOBAL_SEQ</code> 与 <code>MOTW_OFF_GSEQ_DENSE</code> 都是偏移 36(<code>ecat_native.c:69,82</code>),两种布局读同一字节,分不开 dense 与 win。已撤换为 §五-③ 的槽滞后判据。</li>
|
|
|
|
|
|
<li><b>魔数 0xA5 无法从主机侧直接读</b>:<code>/api/motor/rxraw</code> 返回的是批量接收区缓冲快照,不是 PDO 输入镜像;路由表中没有任何路由吐输入镜像。故"直接验魔数"这条路不存在,dense 判定只能靠上述间接判据 + 60s×30 与 111 次采样稳定性(layout 恒 dense、len 恒 176、count 恒 3、win_bases 恒 None)。</li>
|
|
|
|
|
|
</ul></div>
|
|
|
|
|
|
<div class="card bad"><h3>限制声明的一处更正(本次复核新增)</h3>
|
|
|
|
|
|
<ul>
|
|
|
|
|
|
<li><b>"DCU_APP 不在任何 git 仓库、布局无法 A/B"不成立</b>:<code>DCU_APP</code> 是独立 git 仓库(38 个提交)——<code>959e2ae</code> = 1.6.14~1.6.20 滑窗覆盖窗源码、<code>1742d9a</code> = 1.6.21 密排;命令行构建链(cbuild + AC6)现成。因此"win→dense 换来 220µs"这一环<b>可以做受控实验钉死</b>:checkout <code>959e2ae</code> 重编刷板 → 预期 rx 回到 ~310µs → 再刷回 1.6.22(flash_gd32.py 生效守卫会留台账)。属刷板操作,未执行。</li>
|
|
|
|
|
|
<li><b>遗留:重刷同一版本无法证明生效</b>——<code>gd32_adc.uptime_sec</code> 实测不随 GD32 换镜像归零,守卫的"uptime 归零"分支不可靠,目前只能靠版本号变化。根治要 BOOT 上报复位计数/复位原因,或 OTA 完成后强制 APP 复位回读。</li>
|
|
|
|
|
|
</ul></div>
|
|
|
|
|
|
<div class="card warn"><h3>归因的置信度边界(2026-09-12 修订)</h3>
|
|
|
|
|
|
<ul>
|
|
|
|
|
|
<li>已受控验证:稀疏写开关(A/B/A,单臂 2048 拍静默窗,效应上界 ≲1µs/拍);排除项(§六);"刷写≠生效"时间锚点(§五)。</li>
|
|
|
|
|
|
<li><b>已动摇</b>:win→dense 与 220µs 的因果归因——9/8 同布局实测 124.6µs 的反例 + 两版 buildInput 纯 CPU 差仅 1~3µs。原"三条独立吻合"里"旧值≈357µs"一条存疑:357µs 是 1.6.11 时代(496B 输入 + 环形批量区)的测量,与滑窗 600B 版不同代。</li>
|
|
|
|
|
|
<li>待做:开头"重大更正"卡的刷板 A/B(959e2ae + prev.exe 双轮)是当前唯一能闭合因果的实验。</li>
|
|
|
|
|
|
</ul></div>
|
|
|
|
|
|
|
|
|
|
|
|
<h2>八、遗留与下一步</h2>
|
|
|
|
|
|
<div class="card"><h3>按优先级</h3>
|
|
|
|
|
|
<ul>
|
|
|
|
|
|
<li><b>布局 A/B 钉死归因(方案已更新)</b>:刷回 <code>959e2ae</code>(win 固件)后做两轮——配 <code>ecat_native.prev.exe</code>(旧主站,≤78fe6cf)与现主站各测一轮 0.5ms:124µs / 345µs 的分野即判定回归在主站还是从站 win 期固件;再用 0x2000 sub5/6/9/10 定位。刷板会中断 OP 会话,需专门安排。</li>
|
|
|
|
|
|
<li><b>0.25ms 档第一次有理论余量</b>(124/250=50%),值得按同一静默判据实测——但注意此前结论:从站 SSC 的 SM2 事件路径在快档有自己的墙,别只看主站达成率。</li>
|
|
|
|
|
|
<li><b>重刷同版本的生效证明</b>:BOOT 上报复位计数,或 OTA 后强制 APP 复位回读版本。</li>
|
|
|
|
|
|
<li><code>0x2000 sub10</code>(EscWrite 周期)精确验收需独占路由(停循环、从站掉 OP),要专门开一窗。</li>
|
|
|
|
|
|
<li>ms 级离群未清零:dense 时代仍见 work max 2153µs / rx max 1658µs(p90 仅 ~110µs),量级无害但没定位。</li>
|
|
|
|
|
|
<li>本次全部改动<b>未提交</b>(tools/ecat 3 文件+报告、tools/ESP32 7 文件、DCU_APP 4 文件),旧主站 exe 留档在 <code>build_native/ecat_native.pre-instr.exe</code>。</li>
|
|
|
|
|
|
</ul></div>
|
|
|
|
|
|
<div class="foot">本报告依据 <code>tools/ecat/REPORT_ecat_beat_tail_20260911.md</code>、当日调查会话与复核证据整理;所有代码引证(偏移定义、357µs、路由表、台账 sha)已于 2026-09-11 对照源码与实机独立核验,实时复测 rx p50=92.1µs / layout=dense / wkc 3/3 / v1.6.22.0。相关页面:<a href="ECAT_RATE_TRADEOFF.html">ECAT_RATE_TRADEOFF.html</a>(周期×故障率×CPU 调研)· <code>lab/spi_test.html</code>(SPI/ECAT 测速)。</div>
|
|
|
|
|
|
</main></body></html>
|