ethercat-linux/docs/rt-link-verification-report.md

288 lines
15 KiB
Markdown
Raw Blame History

This file contains ambiguous Unicode characters

This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.

# TwinCAT ↔ J1900 实时数据通讯验证报告(EL6695 桥接)
> **版本**: 1.0
> **日期**: 2026-08-12
> **结论**: ✅ 全部通过(4kHz 3 小时 soak 零错误;8kHz RTT min 0.75ms / mean 1.04ms)
> **关联文档**: `8b-bridge-design.md`、`8b-verification-methodology.md`、`500us-latency-plan.md`、`jitter-analysis.md`
---
## 1. 摘要
本报告覆盖 TwinCAT PC 与 J1900 嵌入式平台之间经 EL6695 EtherCAT 桥接的实时数据通讯验证,
包括数据完整性、长期稳定性、周期扩展(1kHz→8kHz)、双侧 DC-Synchron、RTT 延迟优化与
断电恢复能力。
**核心结果**:
| 验证项 | 结果 |
|---|---|
| 数据完整性(800B 载荷,双向交叉校验) | 3 小时 4537 万周期零错误 |
| 长期稳定性(4kHz soak 11400s) | bSync=True ×190 采样点,nMismatch delta=0 |
| J1900 侧自校验 | 33.6M 帧 payload mismatch=0,tx/rx err=0 |
| RTT(8kHz + tx_rx RT 提权) | min 0.75ms / mean 1.04ms / max 1.38ms |
| 单向延迟(推导) | 典型 0.3–0.5ms,最坏 ~0.6ms |
| 死链路检测 | lag 指标 + bSync 双重敏感(实测 5 秒内可检出) |
| DC-Synchron(双侧) | 从站侧固件 sync_mode=2 接受,180s 同步计数器全零 |
| 断电恢复 | TwinCAT 自恢复 Run;J1900 重建 /tmp 后 <2 分钟恢复全链路 |
---
## 2. 系统架构与测试环境
### 2.1 硬件拓扑
```
TwinCAT PC (Windows, TwinCAT 3.1.4026.24)
└─ EtherCAT 主站网卡 "以太网 2" (TwinCAT-Intel PCI, MAC 00-15-17-8A-B3-DA)
└─ EK1100 → EL2202 → EL1252 → EL2262 → EL2008 → EL6851-0010 → EL6022
→ EL6695 (桥接端子, 主站侧 X2)
└─ EL6695 从站侧 X1 ←直连→ J1900 eth1
J1900 (Linux 6.6.135-rt74 PREEMPT_RT, Celeron J1900 4 核)
```
| 项 | 值 |
|---|---|
| TwinCAT AmsNetId | `169.254.176.217.1.1` |
| J1900 管理 IP | `192.168.68.100`(DHCP,曾漂移至 .101,MAC `00:e2:69:34:71:2c`) |
| SSH 跳板 | `tonycao@192.168.58.8` |
| EL6695 从站侧站址 | `0x1000` |
| J1900 内核 | 6.6.135-rt74(PREEMPT_RT,io_uring 可用) |
### 2.2 软件与工程
| 项 | 位置 |
|---|---|
| TwinCAT 工程(800B 变体) | `C:\Users\tonycao\work\twincat3-auto-cli\TwinCAT_EL6695_Primary_800B\` |
| J1900 源码 | `C:\Users\tonycao\work\ethercat-linux`(Rust,ethercrab 0.7 本地 patch) |
| 构建目标 | `x86_64-unknown-linux-musl`(静态链接,零运行时依赖) |
| 关键 commits | `f0163d8`(800B) → `aabfe31`(DC-Synchron) → `cdb90c3`(800B 异步 FPWR) → `253f4b3`(J1900 DC) → `4083df0`(8kHz+RT 提权) |
| 配置备份 | tsproj `.bak-1k-dc` / `.bak-4k`;TcTTO `.bak-1k` / `.bak-4k` |
### 2.3 载荷布局(800B)
| 偏移 | 内容 | 方向 |
|---|---|---|
| `[0..7]` | 序列号:PLC 写 `tc_seq=nCycles`;J1900 回写 `f(tc_seq)=tc_seq*7+3` | 双向 |
| `[8..15]` | J1900 本地周期计数 | 上行 |
| `[16..799]` | 图案区:`(seq + i) mod 256`(J1900 原样回传) | 双向 |
| `[264..267]` | J1900 周期抖动 i32(统计区,不参与校验) | 上行 |
| `[268..271]` | J1900 payload mismatch 计数 | 上行 |
| `[272..279]` | 原始 tc_seq 保留(供 PLC 交叉验证) | 上行 |
---
## 3. 验证方法学
### 3.1 数据完整性证明链
单向"收到数据"不能证明通讯正确。本方案用**双向交叉校验 + 数学变换**构成闭环证明:
1. **PLC 侧写入**:`aOut1[i] = (nCycles + i) mod 256`(图案区),`aOut1[0..7] = tc_seq`
2. **J1900 侧处理**(证明"读取+计算+写回"三个动作真实发生):
- 校验收到图案 `[16..256)` 与 `tc_seq` 一致(不一致计入 `payload_mismatch`)
- 对序列号做不可由硬件桥接伪造的数学变换:`f(x) = x*7 + 3`
- 回写 `aIn1[0..7] = f(tc_seq)`,图案区原样回传,`[272..279]` 保留原始 tc_seq
3. **PLC 侧验证**:
- 从 `aIn1[0..7]` 反解 `nReturnedSeq = (x-3)/7`(整除性本身是一道校验)
- `bSync := 全部 aIn1[i] == (nReturnedSeq + i) mod 256`(768 字节逐字节)
**设计要点**:
- `f(x)=7x+3` 保证回传数据不可能由桥接端子透传/环回伪造
- 用 `nReturnedSeq`(回传帧自带的序号)而非本地 `nCycles` 做图案比对,
使校验对传输滞后免疫——校验的是"回传帧内部自洽性"
- J1900 侧独立再做一遍正向校验,两侧互为佐证
### 3.2 新鲜度(liveness)证明
自洽性校验的盲区:回传通道冻结时数据仍自洽。对策:
- **`nMatchLag = nCycles - nReturnedSeq`**(PLC 内每周期原子计算):
回传帧的产生时刻距当前的周期数。通道健康时稳定在小范围;
通道死亡时以任务频率无界增长
- **实测死链路响应**:杀掉 J1900 ticker 后 5 秒内 lag 从 6 → 8.1 亿且以 4000/s 增长,
bSync 同步翻 False(EL6695 从站侧失联使输入映像清零)
- **反向验证**:重启 ticker 后 lag 立即回落至 4–6 周期
### 3.3 方法学盲区(如实声明)
| 盲区 | 说明 | 缓解 |
|---|---|---|
| 桥转发冻结而两侧 ESC 保持 OP | aIn1 冻结时自洽校验仍通过,任何黑盒测试无法检出 | 概率极低;需侵入式手段 |
| J1900 侧图案校验仅覆盖 `[16..256)`(240/800 字节) | PLC 侧覆盖 768 字节,互补 | 可扩大 J1900 校验范围 |
| J1900 处理帧率低于发送帧率(设计性跳帧) | echo 恒为最新帧(lag 指标证明),无陈旧累积 | 见 5.4 |
---
## 4. 指标详解
### 4.1 PLC 侧(GVL_Sync,ADS 可读)
| 指标 | 类型 | 定义 | 意义与解读 |
|---|---|---|---|
| `nCycles` | ULINT | PLC 任务周期计数 | 任务存活与速率基准;速率 = Δ/Δt,偏离任务频率即异常 |
| `bSync` | BOOL | 当前周期 768 字节图案全部匹配 | **瞬时**正确性。单次 False 可能是瞬态;持续 False = 链路/配置故障 |
| `nMismatch` | DINT | 累计失配字节数(仅 diff>0 时累加) | **历史**错误总量。soak 中看 delta=0;注意 int32,错误率 3M/s 时约 11 分钟回绕 |
| `nReturnedSeq` | ULINT | 回传帧携带的原始序号(反解后) | 回传链路的"时间戳";与 nCycles 之差即 lag |
| `nMatchLag` | DINT | `nCycles - nReturnedSeq`,每周期原子更新 | **新鲜度核心指标**:回传 RTT 的周期数表示。健康值=小范围稳定;无界增长=回传通道死 |
**ADS 采样注意**:`nCycles` 与 `nReturnedSeq` 分两次读取会产生撕裂(高速任务下可读出负 lag 假象);
必须直接读原子计算的 `nMatchLag`。
### 4.2 J1900 侧(ticker S 行遥测)
| 字段 | 定义 | 异常含义 |
|---|---|---|
| `cyc` | J1900 处理循环计数 | 速率 = 实际处理能力上限的度量 |
| `raw` / `proc` | 收到的 tc_seq / 回写的 f(tc_seq) | 与 PLC 侧 nCycles 对账,验证双向一致 |
| `txe` / `rxe` | FPWR/FPRD 事务错误 | 持续增长 = 链路劣化或 ESC 掉态 |
| `late` | 异步 FPWR 响应未在下一周期收齐的次数 | 少量(<0.1%)正常;暴涨 = 总线拥塞或 RT 调度劣化 |
| `stale` | tc_seq 未变化(读到旧帧)占比 | spin 模式下少量正常(跳帧);100% = TwinCAT 侧停发 |
| `mono` | tc_seq 回退次数 | 非零 = 帧乱序/映像撕裂,严重异常 |
| `cerr` | J1900 内部计算自洽错误 | 必须恒为 0(软件自检) |
| `mism` | J1900 侧图案失配累计 | 必须冻结(delta=0) |
| `dcph` | EL6695 从站侧 DC 系统时间 mod 周期 | DC 时钟相位观测 |
| `dcdr` | DC 时钟相对 CLOCK_MONOTONIC 的累计漂移 | 无持续漂移补偿时有界 wander(实测 ±几十 ppm) |
### 4.3 时延类统计(OnlineStats,结束报告)
| 统计 | 定义 | 实测(3h soak, 4kHz spin) |
|---|---|---|
| `exec_time` | 单周期处理耗时(读→变换→写就绪) | p50=25µs, p99=44µs, max=300µs |
| `period_jitter` | spin 循环相邻 fresh 检测的间隔偏差 | p50=12µs, mean=88µs(受跳帧节奏支配,非调度抖动) |
| `fprd_rtt` / `fpwr_rtt` | 单次事务往返 | 800B FPRD ≈ 160µs(决定 spin 检测粒度) |
### 4.4 RTT 分解模型(8kHz,125µs/周期)
实测 RTT mean 1.04ms ≈ 8.3 周期,分解:
| 环节 | 典型耗时 | 性质 | 可优化性 |
|---|---|---|---|
| TwinCAT 输出量化(任务边界→帧发出) | ~62µs(0–125) | 整周期 | 仅能提频 |
| 正向:线缆+EL6695 桥固件转发 | ~150µs | 连续 | 桥固件决定,不可控 |
| J1900 spin 检测(FPRD 轮询粒度 160µs) | ~125µs(0–250) | 量化 | 受 800B 事务往返物理下限约束 |
| J1900 处理 + 异步 FPWR 上线 | ~45µs | 连续 | 已优化至极限(24–25µs exec) |
| 回程:线缆+桥转发 | ~150µs | 连续 | 同上 |
| TwinCAT 输入量化(帧到达→任务读取) | ~62µs(0–125) | 整周期 | 仅能提频 |
| 整周期簿记(lag 按整周期计) | ~125–250µs | 量化 | — |
**单向延迟推导**(TwinCAT→J1900,去掉回程三项):典型 **0.3–0.5ms**,最坏 ~0.6ms。
适用设定值级控制、配方下发、同步基准传递;紧伺服闭环受限于完整 RTT(~1ms,闭环带宽 ~100Hz 量级)。
---
## 5. 测试结果
### 5.1 配置演进总表
| 阶段 | TwinCAT 任务 | J1900 模式 | 结果 | commit |
|---|---|---|---|---|
| 8B 原理验证 | 1kHz | ticker | 通过(XOR 逐字节证明) | `309aaba` |
| 800B + SM 精确匹配 | 1kHz | ticker | 5h 零错误(18M 周期) | `f0163d8` |
| TwinCAT 侧 DC-Synchron | 1kHz | ticker | 激活干净,90k 周期零错误 | `aabfe31` |
| spin-lock + 异步 FPWR | 4kHz | spin | J1900 2040/s,数据零错误 | `cdb90c3` |
| J1900 侧 DC-Synchron | 4kHz | spin+dc | 180s 同步计数器全零 | `253f4b3` |
| **3 小时 soak** | **4kHz** | **spin+dc** | **全绿(见 5.2)** | — |
| RTT 优化 | 8kHz | spin+dc+RT 提权 | RTT min 0.75ms / mean 1.04ms | `4083df0` |
### 5.2 3 小时 soak(4kHz + spin + DC,2026-08-11 22:12 → 01:21)
**PLC 侧**(ADS 每 60s 采样 ×190):
| 指标 | 结果 |
|---|---|
| bSync | True ×190/190 |
| nMismatch delta | 0 ×190/190 |
| ADS 错误 | 0 |
| 任务速率 | 4000.9/s 恒定 |
| 总周期 | 45,370,909 |
**J1900 侧**(`--duration 11400` 整):
| 指标 | 结果 |
|---|---|
| 处理周期 | 33,711,687(~2957/s,74% 帧率,设计性跳帧) |
| payload 校验 | checked=33,598,819,mismatch=0 |
| tx_err / rx_err / comp_err | 0 / 0 / 0 |
| stale | 0.3%(跳帧读旧,正常) |
| late | 15,741(0.05%) |
| exec_time | p50=25µs,p99=44µs |
| DC 漂移 dcdr | 3.2h 累计 ~-9.8ms(≈-0.85ppm,有界 wander) |
### 5.3 DC-Synchron 验证细节
| 发现 | 证据 |
|---|---|
| ethercrab init 已分发从站侧 DC 系统时间 | 0x0920 offset 非零、0x0930 漂移补偿激活、0x0910 以真实速率推进 |
| EL6695 从站侧 ESC SYNC 寄存器(0x0980+)ECAT 侧不可读 | FPRD WKC=0;写入 WKC=1(固件经 PDI 自管) |
| 正确启用路径是 CoE | `0x1C32/0x1C33:01 sync_mode=2` 写入被固件接受且回读保持 |
| DC 模式下运行无副作用 | 180s:sm_event_missed=0,cycle_exceeded=0,sync_error=0(SM2+SM3) |
**未证实项**:SYNC0 脉冲全程实际激活状态(收尾计数器复读失败);
dcph 全范围游走表明 J1900 处理时序锁的是帧到达(spin)而非 SYNC0 网格。
表述应为"DC 配置下数据通路无异常",而非"DC 对性能有贡献"。
### 5.4 RTT 优化实验矩阵
| 配置 | RTT min | RTT mean | RTT max | J1900 处理率 | 结论 |
|---|---|---|---|---|---|
| 4kHz AF_PACKET | 1.0ms | 1.45ms | 1.75ms | 2957/s (74%) | 基线 |
| 8kHz AF_PACKET | 0.75ms | 1.09ms | 1.5ms | ~4000/s (50%) | 两端量化减半生效 |
| 8kHz io_uring 后端 | 1.13ms | 1.42ms | 1.75ms | 2043/s | ❌ 阻塞式设计更差,弃用 |
| **8kHz + tx_rx RT 提权** | **0.75ms** | **1.04ms** | **1.38ms** | ~3100–4000/s | ✅ 当前最优 |
**结论**:p50=1.0ms、min=0.75ms,"1ms 内"在最优/中位情形达成;mean 超出 4%。
剩余耗时为结构性(桥固件转发、FPRD 检测粒度、两端量化),
16kHz 提频预期收益仅 ~60µs 且引入 TcTTO 整数 µs 取整、PLC exec 预算、EL6695 能力三重风险,不建议。
### 5.5 鲁棒性测试
| 场景 | 结果 |
|---|---|
| ticker 误退(默认 60s 时长) | PLC 侧 bSync→False、nMismatch 增长——故障可观测;`--duration 0` 为正确用法 |
| 死链路注入(杀 ticker) | lag 5s 内 6→8.1 亿,bSync=False;重启后 4–6 周期恢复 |
| 双实例抢网卡(误操作注入) | 错误计数(txe/rxe)立即暴露,err_streak 超限自动退出 |
| 整机断电重启 | TwinCAT 随 boot project 自恢复 Run+PLC Run(4kHz 配置保持);J1900 /tmp 清空需重建(脚本化 <2 分钟);DHCP 地址漂移 .101→.100 需 ARP 扫描定位 |
---
## 6. 已知限制与残余风险
1. **J1900 处理帧率 < 发送帧率**(8kHz 时 ~50%):受 800B FPRD 事务往返 ~160µs 物理约束。
echo 恒为最新帧(lag 指标证明),数据正确性不受影响,但每帧独立处理的场景不适用
2. **无持续 DC 漂移补偿**:ethercrab 仅静态补偿,dcdr 以 ±几十 ppm wander。
事件驱动(spin)交换不受影响;若需 J1900 硬锁 DC 网格需加周期性 FRMW 补偿
3. **TwinCAT 试用许可 7 天过期**:长期运行需周期性重新激活(过期症状:851 端口缺失、卡 Config 态)
4. **J1900 DHCP 地址漂移**:建议静态化或按 MAC 扫描定位(已备脚本化流程)
5. **方法学盲区**:桥转发冻结而 ESC 保持 OP 的失效模式黑盒不可检出(见 3.3)
## 7. 结论与建议
**结论**:TwinCAT 4kHz(250µs)/8kHz(125µs) + EL6695 桥 + J1900 spin-lock + 双侧 DC-Synchron
配置下,800B 双向实时通讯经 3 小时 4500 万周期验证零数据错误;
RTT 达 min 0.75ms / p50 1.0ms / mean 1.04ms,单向延迟典型 0.3–0.5ms。
数据完整性、新鲜度、故障可观测性、断电恢复均经实证。
**建议**:
1. 生产化时将图案区替换为真实过程数据(帧结构/序号校验/延迟特性已验证可直接复用)
2. soak 采样脚本已内置 lag 监控(`tc-ads-soak.ps1`),后续长测自动覆盖新鲜度
3. 若需 mean RTT 严格 <1ms,评估 LRW 单帧交换(需 FMMU 配置,改动中等)前先量化收益
4. J1900 管理口建议配置静态 IP,消除 DHCP 漂移运维成本
## 8. 附录:复现命令
```sh
# J1900 侧(经跳板)
ssh -J tonycao@192.168.58.8 root@192.168.68.100
/tmp/el6695_rt_dc eth1 --duration 0 --cycle-us 125 --spin --dc # 8kHz 常驻
/tmp/kill_el6695.sh # 停止全部实例
# TwinCAT 侧(非提权可读)
scripts\tc-ads-state.ps1 # 运行状态
scripts\tc-ads-quick.ps1 # 速率 + bSync
scripts\tc-ads-lag.ps1 # nMatchLag 新鲜度采样
scripts\tc-ads-mismatch-delta.ps1 # nMismatch 冻结检查
scripts\tc-ads-soak.ps1 -Minutes N -LogFile X # 长测采样(WMI 方式后台启动)
scripts\tc-deploy-retry-800b.ps1 # 提权部署(构建+激活+重启)
```