Files
DCU_APP/docs/compose/spec/lan9252-perf-audit.md
T
cbb 6afaacd03a feat(comm): LAN9252增加csrRead验证分级并实现PDO差分写功能
为提升EtherCAT通信性能,实现以下两项优化:

1. 对EscLan9252::csrRead方法增加verify参数,支持分级验证:
   - verify=true(默认):保持原有的双读比对+重试机制,用于SM/AL/邮箱等
     关键路径防止EXMC毛刺
   - verify=false:单读模式,用于诊断回读/MII busy轮询/init轮询等低风
     险场景,节省一半CSR间接访问时间

2. 实现PDO输入差分写ESC功能:
   - 将输入PDO分为三区:段1桥状态(0-31)、段2电机密排(32-543)、段3+5
     快照诊断(544-599)
   - 采用3-buffer冲刷协议:变化后连续写3拍确保3个缓冲区全部更新
   - 对内容稳定的段跳过写操作,显著减少PRAM字节搬运时间
   - 全段跳过时强制写末2字节完成SM事件应答

同时更新配置版本至1.6.25,添加相关配置选项和文档说明。
2026-09-12 20:10:52 +08:00

8.5 KiB
Raw Blame History

feature, status, updated, branch, commits
feature status updated branch commits
lan9252-perf-audit delivered 2026-02-14 master <no-commit — analysis-only on dirty master WIP>

LAN9252 使用效率审计

Report

What was built — LAN9252 使用效率审计 + 后续 P1/P2 实现。结论:DPRAM 用得满但是设计上的满,不算差;真正的速度瓶颈是 PRAM 字节搬运(约 0.44µs/B)。1.6.25 落地:(1) 输入 PDO 三区差分写 ESC(段1 桥状态 / 段2 电机密排 / 段3+5 快照诊断,变化后 3-buffer 冲刷 3 拍才允许跳过);(2) csrRead 增加 verify 参数,SM/AL/邮箱保持双读,诊断/MII busy/init 轮询单读。

Verification — 本报告为静态代码审计,对照仓库内 DWT 实测注释与布局常量交叉验证;未在本回合重跑上机测量(DIFF-STATS 当前 CONFIG_ECAT_DIFF_STATS=0,写侧基线须置 0 重测才可对拍)。

Journey log

  1. 先验怀疑「内存差」不成立:3-buffer 硬上限把 out+in 钉在 ≤1024B,当前 984B 已是极限附近。
  2. 1.6.0 PRAM 批量弹 DWORD 因短读损坏回退——任何再加速不能走回未弄清语义的批量模式。
  3. 工作区 master 上有未提交的 1.6.22–1.6.24(稀疏写 + pmDrive),审计不改动这些 WIP。
  4. 1.6.25 已实现 P1 差分写(三区 + 3-buffer 冲刷)与 P2 csrRead verify 分级;上机对拍 sub10 待做。

[S1] Problem

用户问题:

  1. LAN9252 使用是否有提升效率/速度的优化空间?
  2. 现在是不是内存空间使用比较差?

需要基于当前代码(含未提交 1.6.22 稀疏写)给出可执行的结论与优先级,而不是泛泛「还能优化」。

[S2] Design / 分析结论

S2.1 内存:不是“差”,是 3-buffer 硬上限下的近满设计

ESC 片内 DPRAM 4KB 布局(LAN9252)

区域 范围 占用
邮箱 SM0/SM1 0x1000–0x13FF 2×256B 固定
过程数据 SM2(out)+SM3(in) 0x1400–0x1FFF 3072B 可用
3-buffer 实占 (384+600)×3 = 2952B 余 120B

推导见 comm/ethercat_pdo_size.h:(out+in)×3 ≤ 3072 ⇒ out+in ≤ 1024B 是硬上限。当前 384+600=984B,已用到 96%。

若将来还要更大,只有两条路,都有代价:

  • 邮箱压到 MIN_MBX_SIZE(0x22) → 上限约 1280B,拖慢 SDO/FoE
  • 改 1-buffer → 上限 3072B,失去三缓冲并发保护

结论:DPRAM 满是约束结果,不是浪费。段 2 密排(1.6.21)已经把空节点从有效载荷里挤掉。

MCU 侧 RAM

  • aPdInputData + aPdOutputData = 1024B(SSC 对象存储)
  • EthercatPdo::s_out/s_in/s_build = 3×384~600B 级
  • 段 2 影子 s_motShadow ≈ 512B 量级
  • DIFF-STATS 自持 600B 快照(仅开启时)

相对 GD32E508 的 128KB SRAM 可忽略。MCU 内存不是瓶颈。

S2.2 速度:热成本在 PRAM 搬运,不在“存不下”

已实测的通道速率(仓库内 DWT 注释,0x2000 sub9/sub10)

场景 耗时 占 1ms 周期
输入 640B 整包写(历史) 296µs 29.7%
输入 496B 整包写(1.6.1) 218.7µs 21.9%
输入 600B 整包写(1.6.15) ≈265µs(600×0.441) 26.5%
满载 1024B PRAM(历史估算) ≈218µs(更早时序) —
输出 384B 全量读(被探针跳过) ≈190µs 已优化

通道近似线性:≈0.44–0.463 µs/B。写多少、读多少,时间就按字节缩放。

已落地的减法(正确方向)

  1. 输出按需读(1.6.0,ecatappl.c):每拍先读 12B 头探针;seq 无变化则跳过 384B 全量读,只补读末字应答。
  2. 段 2 差分填充(1.6.21,ethercat_can_bridge.cpp::fillMotorRound):节点集合与各 seq 未变时整段复用影子,跳过 MotorState 重读与逐槽拷贝——省的是 MCU 侧填充,不直接省 PRAM 字节。
  3. 稀疏写 ESC(1.6.22,工作区未提交):CONFIG_ECAT_SPARSE_ESC_WRITE=1 时,密排 count 有效则只写「段1+段2有效区」与「段3+段5」,跳过空槽区。count=3 时约省 (9−3)×56 ≈ 336B PRAM 写 ≈ 150µs/拍。magic 不对/count 撑满自动回退整包。
  4. 输入 PDO 瘦身(1.6.1,历史):640→496 已证明“减字节=减时间”;1.6.15 为批量窗扩回 600 是容量权衡,不是速度回退。

未做 / 被否决的加速

尝试 结果 依据
PRAM 批量弹 DWORD(用 AVAIL_CNT) 已回退(1.6.2) 短读首 DWORD 新鲜、后续取陈旧项;窗口冻结
EXMC 慢档时序试速 无效 当年失败根因是访问模型错误,与时序无关
压缩总线时序 不建议 BUSLAT 1→4 是为温漂可靠(+3HCLK≈16.7ns/访问)

S2.3 仍有空间的优化点(按 ROI 排序)

P1 — 输入 PDO 真正的差分写 ESC

  • 现状:填充侧有段 2 影子;写侧仍是整包 600B 或稀疏两段,段 1/3/5 每拍全写。
  • 前提:开 CONFIG_ECAT_DIFF_STATS=1 采 0x2000 sub13..23(changedMax / runsMax / 各段变化字节),拿分布再定 A1(语义分区条件写)或 A2(块粒度差分,N 由 runsMax 定)。
  • 预期:若稳定工况下每拍变化字节数远小于 600,写侧可再省数十至上百 µs。
  • 风险:run 碎片会把一次大写退化成多次带 AVAIL 轮询的小写;必须设碎片上限,超限回退整段/整包。
  • 验收:CONFIG_ECAT_DIFF_STATS=0 对拍 sub10 与 load_perm;布局/SII/主站解码不变。

P2 — csrRead 双读校验分级

  • 现状:EscLan9252::csrRead 对每次事务读两遍 CSR_DATA 并比较(1.5.59),不一致整事务重跑一次。对 EXMC 毛刺防护有效,但 CSR 路径访问次数近似翻倍。
  • 热路径调用方:AL Event(每拍 1–2 次)、邮箱长度/SM 状态、看门狗状态、LED、诊断。
  • 可行做法:提供 csrReadOnce(或按寄存器关键级别开关);几何/状态关键寄存器(SM、AL、邮箱)保持双读;LED/诊断/低频路径可单读。
  • 风险:去掉防护的路径可能偶发读错;须限定白名单,不可一刀切。
  • 预期:CSR 间接访问(多步 HBI)减少约一半;相对 600B PRAM 写占比更小,属次优先。

P3 — 稀疏写收益标定(已实现,待验收)

  • 工作区已实现 sparseEscWritePlan + CONFIG_ECAT_SPARSE_ESC_WRITE=1。
  • 验收动作:同工况开关 0/1 各测一轮 sub10;count 越小收益越大。
  • 空洞区为 SM 缓冲上次残留,主站必须只按 count 迭代(1.6.21 已如此)。

不建议再碰

  • EXMC 时序收紧:BUSLAT=4 / DSET=20 为全温区可靠性的已知代价;已有“慢档无效、访问模型才是当年根因”的记录。除非板级时序重测给出明确裕量,否则不动。
  • 恢复 PRAM 批量弹 DWORD:短读语义未弄清前禁止。
  • 改 1-buffer 扩 DPRAM:失去三缓冲,并发读写会拿到半新半旧过程数据。

S2.4 访问模型备忘(审计时反复踩过的坑)

主站帧
  → LAN9252 DPRAM (4KB)
      邮箱 0x1000+ / PDO 0x1400+
  ← PDI (HBI Indexed)
      HBI_IDX_0 / HBI_DATA_0   ← 仅系统 CSR + 访问端口
      ECAT_CSR_CMD/DATA 0x304/0x300  ← 核心 CSR 0x0000–0x0FFF
      PRAM FIFO 0x000–0x03C + 0x308–0x314  ← 过程 RAM 0x1000–0x1FFF
  → EXMC NE0 @ 0x60000000, 16-bit

核心 CSR 不能直读 HBI 索引(1.5.37 之前全 0 的根因)。过程数据 必须走 PRAM FIFO。

[S3] Out of Scope

  • 不重生成 SII、不烧录、不改主站解码。
  • 不审计主站侧解码或 CAN 桥竞态(另见 1.6.9–1.6.21 修复记录)。
  • 不重新设计 PDO 布局或 EEPROM。
  • 上机 A/B 对拍(T3/T6)待现场执行。

Tasks

  • T1: 审计 DPRAM/MCU 内存占用与 PRAM 热路径 — acceptance: 本报告 S2.1/S2.2 有依据与数字 (covers: S2)
  • T2: 给出优化优先级与不做清单 — acceptance: S2.3 含 ROI/风险/验收 (covers: S2)
  • T4: (1.6.25)实现输入 PDO 差分写 — acceptance: 三区影子+3-buffer 冲刷;全跳过写末 2 字节;SII 不变;CONFIG_ECAT_DIFF_ESC_WRITE 门控 (covers: S2.3)
  • T5: (1.6.25)csrRead 分级单读 — acceptance: verify 参数;SM/AL 默认双读;MII busy/init/诊断回读单读 (covers: S2.3)
  • T3: (后续)开 DIFF-STATS + 上机对拍 sub10 — acceptance: 记录写侧耗时 A/B(差分开/关)(covers: S2.3)
  • T6: (遗留)验收工作区稀疏写 A/B — acceptance: CONFIG_ECAT_SPARSE_ESC_WRITE 0/1 同工况 sub10 对比入档 (covers: S2.3)