# 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` 增加: ```iecst 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` 末尾追加: ```iecst // 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 之前,把本周期自测值写入回显帧: ```rust // 回显之后: 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)。