ethercat-linux/docs/scope-waveform-design.md
Tony Cao 21b2d3bf99 J1900 <-> TwinCAT 1 kHz verification over EL6695 bridge
Re-implementation of rustbootd's ecat_el6695_* examples as a single binary
with fixes found in review and on hardware:

- DC-follow PLL hardened against period-2 hunting: slew-limited anchor
  (+/-50us/cycle), bistable-trap snap re-anchor, re-prime on stale deadline
- drift-free absolute-grid ticker mode; probe mode for timestamp forensics
- bounded-memory online stats (histograms), graceful SIGINT/SIGTERM shutdown
  with full report, error-streak abort
- timestamp plausibility filter comparing against the previous raw sample
  (avoids the deadlock after a startup outlier)
- XFC scope waveform options: --el2202 (with --el2202-dual), --el2262,
  --el1252 latch timestamp readback with per-channel edge statistics
- register access unified in regs.rs: named bit constants everywhere,
  read-modify-write for enable/activation bytes
- vendored patched ethercrab 0.7.1 (sdo_write_complete, send_raw_coe)

Verified on J1900 (PREEMPT_RT 6.6.135): 600k cycles/600s exact 1 kHz,
tx/rx zero errors, phase_err p50=164us std=5us; EL2202<->EL1252 loopback
edge interval mean 2000.24us std=24.65us.
2026-07-22 08:55:41 +08:00

9.5 KiB
Raw Permalink Blame History

TwinCAT Scope 通讯周期/抖动波形设计

  • 日期:2026-07-21
  • 状态:设计已确认,待实现
  • 相关项目:ethercat-linux(J1900 侧 el6695-rt)、free/TwinCATProject1/PlcSync(TwinCAT 侧 PLC)

1. 目标

在 TwinCAT Scope View 中以波形直观展示 J1900 ↔ TwinCAT 经 EL6695 桥的 1 kHz 通讯的周期与抖动,用于实时观测和稳定性评估。

2. 原理

让 PLC 每个 1ms 任务周期计算若干"测量变量",用 TwinCAT Scope View 按 PLC 任务周期(1 kHz 采样率)经 ADS 符号采样绘图。现有数据通路已经齐 全:PLC 每周期刷新 aOut1(序列号 + 图案 + 发送时间戳),J1900 侧 el6695_rt 每周期将 SM3 载荷原样回显到 SM2 并在字节 [8..16] 写入自己的 周期号。

关键洞察:发送时间戳(F_GetSystemTime)经回显路径原样返回,往返测量 全程在 TwinCAT 自己的时钟域内,无跨时钟域误差——这是端到端抖动的 理想波形信号。

3. 波形通道设计

# Scope 通道 来源 含义 正常形态
1 nRttUs nEchoTimestamp - nSendTimestamp(aIn1[256..263] 回显时间戳 − 本周期发送时间戳) 端到端往返延迟(同时钟域) ~4000µs 水平带,带宽 = 抖动
2 nInSeqDelta nReturnedSeq 的周期差分 TwinCAT 视角的输入帧间隔 恒为 1;0 = 重读旧帧,2 = 丢帧
3 nJ1900Delta nJ1900Cycle 的周期差分 J1900 循环节拍在 TwinCAT 侧的投影 恒为 1;偏离即对端周期异常
4 nJ1900JitterNs J1900 写入回显帧 payload[264..268] 的自测唤醒抖动(i32 LE) 对端内部定时质量 follow 模式锁定后 <1µs
5 nJ1900PhaseErrNs payload[268..272] 的相位误差(i32 LE) 对端读点与 TC 网格的相位 ~165µs 直线,慢漂移可见

通道优先级:1 > 2 > 3 > 4 > 5。

  • 通道 1 把"周期抖动"直接变为 µs 量级波形,是最有价值的一条。
  • 通道 2/3 把 1 kHz 周期本身可视化为恒 1 直线,任何毛刺都显眼。
  • 通道 4/5 需要 J1900 侧配合(见 §4.2),用于观测对端内部状态。

4. 实现方案

4.1 PLC 侧(PlcSync 工程,追加 ~20 行 ST)

GVL_Sync.TcGVL 增加:

nRttUs          : DINT;   // 端到端往返 (us),同时钟域
nInSeqDelta     : DINT;   // nReturnedSeq 周期差分
nJ1900Delta     : DINT;   // nJ1900Cycle 周期差分
nJ1900JitterNs  : DINT;   // J1900 自测唤醒抖动 (ns),来自 aIn1[264..267]
nJ1900PhaseErrNs: DINT;   // J1900 相位误差 (ns),来自 aIn1[268..271]
nPrevRetSeq     : ULINT;  // 差分寄存器
nPrevJ1900      : ULINT;  // 差分寄存器

MAIN.TcPOU 末尾追加:

// Waveform channel 1: same-clock-domain round-trip time.
IF GVL_Sync.nEchoTimestamp > 0 AND GVL_Sync.nEchoTimestamp >= GVL_Sync.nSendTimestamp THEN
    // F_GetSystemTime 单位为 100ns
    GVL_Sync.nRttUs := ULINT_TO_DINT((GVL_Sync.nEchoTimestamp - GVL_Sync.nSendTimestamp) / 10);
ELSE
    GVL_Sync.nRttUs := -1;
END_IF

// Waveform channels 2/3: per-cycle deltas of the echoed sequence numbers.
GVL_Sync.nInSeqDelta  := ULINT_TO_DINT(GVL_Sync.nReturnedSeq - GVL_Sync.nPrevRetSeq);
GVL_Sync.nJ1900Delta  := ULINT_TO_DINT(GVL_Sync.nJ1900Cycle  - GVL_Sync.nPrevJ1900);
GVL_Sync.nPrevRetSeq  := GVL_Sync.nReturnedSeq;
GVL_Sync.nPrevJ1900   := GVL_Sync.nJ1900Cycle;

// Waveform channels 4/5: J1900 self-measured diagnostics from the payload.
MEMCPY(ADR(GVL_Sync.nJ1900JitterNs),   ADR(GVL_Sync.aIn1[264]), 4);
MEMCPY(ADR(GVL_Sync.nJ1900PhaseErrNs), ADR(GVL_Sync.aIn1[268]), 4);

布局约束(重要):图案校验覆盖字节 [16..255],发送时间戳占 [256..263], 因此 J1900 诊断字放在 [264..271],不会触发 nMismatch。

需要重新激活配置(free/rt-activate2.ps1),TwinCAT PLC 任务会中断几秒。

4.2 J1900 侧(el6695-rt 小改,无副作用)

在回显之后、fpwr 之前,把本周期自测值写入回显帧:

// 回显之后:
tx_buf[264..268].copy_from_slice(&(jitter_ns as i32).to_le_bytes());
// follow 模式的相位误差(ticker 模式写 0)
tx_buf[268..272].copy_from_slice(&(phase_err_ns as i32).to_le_bytes());

交叉编译部署即可,不影响现有协议与 PLC 校验逻辑。

4.3 Scope 工程配置

  1. XAE 中 PlcSync 工程旁新建 TwinCAT Measurement / Scope 工程。
  2. 新建 YT Chart,数据源选 PLC 符号(ADS),采样率挂到 PLC 任务 (1 kHz,与数据更新率一致)。
  3. 将 §3 的 5 个变量拖为通道;通道 1(µs)与通道 2/3(计数)分双 Y 轴。
  4. 长时间观测:ADS 记录受缓冲限制,如需小时级统计,在 PLC 中追加滑动 窗口 min/max 寄存器(例如每 1000 周期输出一次窗口极值),Scope 只画 统计曲线。

5. 验收标准

  • 跑 60s el6695_rt(follow 模式),Scope 中:
    • nRttUs 为 ~4000µs 水平带(实测均值 ~4.0–4.3 个 PLC 周期);
    • nInSeqDelta、nJ1900Delta 恒为 1,无毛刺;
    • nJ1900JitterNs < 1µs(锁定后),nJ1900PhaseErrNs ≈ 165µs 直线。
  • 停掉 J1900 侧程序,通道 2/3 应立即偏离 1(断链可见)。

6. 备注

  • 参考实现的 follow 代码从 data[258..266] 读发送时间戳,与 PLC 实际 写入位置 aOut1[256..263] 错位 2 字节——通道 1 必须使用 256 偏移。
  • 断链时 EL6695 输出替代值(全 0),nEchoTimestamp 为 0,通道 1 输出 -1 作为无效标记。

7. 示波器方案(EL2202,已实现 2026-07-21)

除 Scope 软件波形外,--el2202 参数让 el6695_rt 每周期翻转 EL2202 (总线 [1],站地址 0x1001)的一个数字输出,示波器可直接观察 ~500Hz 方波的沿抖动(= J1900 RT 环路发送时序抖动,PREEMPT_RT + follow 锁定下 为 µs 级)。

实现要点(实机验证通过):

  • 简单 DO 端子无邮箱,SM/FMMU 仅在组 PREOP→SAFEOP 转换时由主站编程; 本程序跳过该转换(EL6695 走裸配置),因此 EL2202 的 SM0 也手动配置: 起始 0x0F00、长度 1、ctrl 0x44、enable 0x09(按 EEPROM 类别 41)。
  • EL2202 过程字节语义(EEPROM PDO 0x1600/0x1601 实证): bit0=通道1数据, bit1=通道1三态(高阻), bit2=通道2数据, bit3=通道2三态。 单通道写 0x01/0x00;双通道(--el2202-dual)必须写 0x05/0x00—— 写 0x03 会把通道 1 置高阻,表现为"输出 1 失效"(实测踩中)。
  • 裸 AL 驱动 SAFEOP→OP,写 0x01 回读验证通过后才启用逐周期翻转。
  • 翻转帧使单圈执行时间 ~410µs → ~650µs(帧开销为主,仍在 1ms 预算内); 60s 回归:60000 周期精确 1kHz,tx/rx/el2202 错误均为 0, phase_err p50=164µs、std 5.3µs(与不开 EL2202 时一致)。
  • 升级路径:总线 [3] EL2262(XFC 时间戳输出)可在 DC 网格精确翻转,与 EL2202 沿做双通道对比获得绝对相位基准;[2] EL1252(XFC 时间戳输入) 可回采沿时刻做数值统计。

8. XFC 方案 B/C(已实现 2026-07-21)

8.1 关键事实(实机 EEPROM 探明)

  • EL1252/EL2262 均无 CoE/邮箱(手册 §4.5 "This device has no CoE"; EEPROM SM 类别 41 中无邮箱 SM),配置只能走 EEPROM 默认值 + 裸寄存器。
  • EEPROM 类别在 41(SM)、40(FMMU 用途)、50/51(PDO), 不是 4。EL2262 输出 SM0@0x1000(ctrl 0x64, enable 0x09); EL1252 输入 SM0@0x1000。
  • EL1252 锁存时间戳直接在 ESC 寄存器里(PDO 0x1A13 的存储位置): 0x09AE=status0、0x09AF=status1、0x09B0=Latch0Pos、0x09B8=Latch0Neg、 0x09C0=Latch1Pos、0x09C8=Latch1Neg(通道 1→Latch0,通道 2→Latch1)。 无需 SM/OP 配置,PREOP 下即可 fprd 读取。
  • 两台端子的 DC 时钟(0x910)出厂即在运行(自由跑,未总线同步)。

8.2 方案 B:--el2262(DC 网格基准方波)

  • 配置 EL2262 DC 同步单元:0x0990=启动时间(当前+100ms)、 0x09A0=0x09A4=1ms、0x0980=0x03(SYNC0+SYNC1 激活);手动配 SM0 (0x1000/1B/0x64/0x09),裸 AL 驱动 OP。
  • 数据在 SYNC 事件才应用 → 输出沿锁定 DC 1ms 网格,与帧到达抖动无关。
  • 注意:该端子(本台硬件版本)EEPROM 未提供 StartTimeNextOutput PDO (32 位版本见新固件),采用 SYNC 锁定方式实现。

8.3 方案 C:--el1252(沿时间戳回采统计)

  • 每周期 fprd 34B @0x09AE,跟踪两个通道 LatchXPos 变化,输出上升沿 间隔统计(名义 2ms)与沿在 1ms 周期内的相位统计。
  • 帧预算:每帧往返 ~160-245µs。A+C 或 B+C 组合 = 4 帧/周期, 单圈执行 ~898µs(锁相保持,phase_err p50≈164µs);A+B+C 五帧超预算, 不要同开。

8.4 接线与验证步骤(需要现场操作)

端子点位(三种 2 通道端子布局相同,已核手册):点 1 = 通道 1, 点 2/6 = +24V,点 3/7 = 0V,点 4/8 = PE(接地,不是通道 2!), 点 5 = 通道 2。

  1. EL2202 输出 1(点 1)→ EL1252 输入 1(点 1): --el2202 --el1252,el1252_ch1_edge_interval 应为 2000µs 均值、 抖动 µs 级。
  2. EL2262 输出 1(点 1)→ EL1252 输入 2(点 5): --el2262 --el1252,el1252_ch2_edge_interval 同样 2000µs,且 ch2_edge_phase 应锁定在固定相位(DC 网格)——与通道 1(环路驱动) 的相位漂移对比即为环路相位误差。
  3. 示波器双通道:CH1=EL2262 点 1(DC 基准)、CH2=EL2202 点 1(环路 驱动),地夹接点 3/7(0V,勿接点 4/8 的 PE)。