ethercat-linux/README.md

127 lines
7.1 KiB
Markdown
Raw Normal View History

# el6695-rt — J1900 ↔ TwinCAT 1 kHz 通讯验证EL6695 EtherCAT 桥)
J1900 (Linux, PREEMPT_RT) 经 EL6695 EtherCAT 桥与 TwinCAT Windows PC 之间
1 kHz 双向过程数据1024 字节/方向)通讯验证程序。参考
`rustbootd/gateway-workspace``ecat_el6695_*` 示例重新实现,并修复了
评审中发现的问题(见文末)。
## 拓扑
```
J1900(eth1) → EK1100 → EBUS → EL6695(X2/primary) → X1 → EK1100 → TwinCAT 主机
```
- SM2 @0x1C001024BJ1900 → TwinCATTwinCAT 侧 `aIn1`
- SM3 @0x8E001026Bticker 模式2B 诊断 + 1024B
1046Bfollow/probe 模式22B 0x1A02 时间戳 + 1024BTwinCAT → J1900
- 每周期fprd SM3 → 原样回显 → fpwr SM2本地周期号写在字节 8..16
TwinCAT PLC 用字节 0..8 的自身序列号计算往返)
## 构建与部署
```bash
# Windows + Git Bash交叉编译 musl 静态二进制
RUSTFLAGS="-C linker=rust-lld -C link-self-contained=y" \
cargo build --release --target x86_64-unknown-linux-musl
# 部署(经跳板,按实际地址调整)
scp -J tonycao@192.168.58.8 \
target/x86_64-unknown-linux-musl/release/el6695-rt \
root@192.168.68.100:/root/gateway/el6695_rt
```
## 运行J1900 上root
```bash
el6695_rt eth1 --mode follow --duration 600 # DC 跟随(推荐)
el6695_rt eth1 --mode ticker --duration 60 # 本地 1ms 自由跑
el6695_rt eth1 --mode probe --duration 10 --debug-ts 40 # 时间戳探针
```
参数:`--phase-us N`follow 模式网格相位,默认 500、`--cycle-us N`、
`--core N`(绑核,默认 2、`--prio N`SCHED_FIFO默认 80
`--quiet`(不打每秒状态行)。`--duration 0` = 跑到 Ctrl-C/SIGTERM 为止,
信号触发优雅退出并打印完整统计。
`--el2202`(默认关闭):每周期翻转 EL2202 数字输出0x01/0x00产生
~500Hz 方波供示波器观察发送时序抖动。`--el2202-dual`:双通道同相翻转
(写 0x05/0x00输出 1 → EL1252 回采、输出 2 → 示波器,同一信号两种
视角。**注意 EL2202 过程字节语义**EEPROM PDO 0x1600/0x1601 实证):
`bit0=通道1数据, bit1=通道1三态, bit2=通道2数据, bit3=通道2三态`——
写 0x03 会把通道 1 置为高阻(三态),双通道必须写 0x05。实现手动
配置 EL2202 SM0输出物理地址 0x0F001 字节ctrl 0x44enable 0x09
按 EEPROM裸 AL 驱动进 OP写回读验证后才启用翻转帧使单圈执行
时间从 ~410µs 增至 ~650µs仍在 1ms 预算内)。**注意:输出端子可能
接着真实执行器,确认接线后再启用。** 简单 DO 端子无邮箱且 SM/FMMU
在组 PREOP→SAFEOP 转换时才被编程(我们跳过该转换),这是必须手动配
SM0 的原因。
`--el2262`默认关闭EL2262 XFC 输出 DC 同步锁定方波(方案 B
配置 DC 同步单元SYNC0/1 周期 1ms、+100ms 启动、0x0980=0x03并手动
配 SM00x1000/1B/0x64/0x09输出沿锁定 DC 1ms 网格,可作示波器或
EL1252 回采的基准。
`--el1252`默认关闭EL1252 锁存时间戳回采(方案 C。每周期读
ESC 寄存器 0x09AE 起 34 字节status + 双通道 Latch Pos/Neg u64
统计两通道上升沿间隔与沿相位。详见 docs/scope-waveform-design.md §8。
帧预算A+C 或 B+C 组合单圈 ~898µsA+B+C 不要同开(超 1ms
## 三种模式
- **ticker**`clock_nanosleep(TIMER_ABSTIME)` 绝对时间网格,无漂移;
SM3 布局为 0x1A01 诊断字。
- **follow**(默认):软件 PLL 跟随 TwinCAT DC 时钟0x1A02 外部时间戳),
读点锁在 TC 网格边界 + phase。与参考实现的差异见下。
- **probe**ticker 节拍 + follow 布局,不做 PLL 反馈,只 dump 原始
时间戳相位(诊断用)。
## 相对参考实现rustbootd ecat_el6695_*)的修复
1. **DC 跟随 PLL 的周期二狩猎(最重要)**:参考实现每个周期用原始
采样直接重算锚点deadbeat`floor(ext)+1ms+phase`)。实测该环路是
带延迟的反馈系统TwinCAT 发送相位与我们的帧时序相互耦合),存在
多个周期轨道:相位关系漂移(实测 ~155ppm到不利区间时周期时间
在 0.4/1.6ms 间交替、相位误差双峰跨度 >1ms。参考二进制只是恰好落
在稳定轨道上。本实现:锚点变化 slew 限幅 ±50µs/周期,且检测到
卡死(误差连续 100 周期顶在同一限幅边界,即"读到上一帧"的双稳态
陷阱)时一次性 snap 重锚定deadline 落后 >2ms 时 re-prime同时
丢弃被污染的 offset。修复后此前必现狩猎的 phase=500 配置:
**30000 周期/30s 精确 1kHzphase_err p50=164µs、std 4.4µs
period_jitter p99.9=0.2µs**锁相质量优于参考实现std 6~10µs
2. **合理性与稳定性评测发现的参考实现其它问题**
- `bridge_dump` 用自旋凑满 1ms无绝对时间锚点超时即永久相移 →
本实现 ticker 模式用绝对时间网格。
- 统计用逐样本 Vec 再排序(~30MB/小时/指标)→ 有界直方图 + Welford。
- 无信号处理Ctrl-C 丢失全部统计 → SIGINT/SIGTERM 优雅退出。
- 配置代码在 4+ 个 example 中复制粘贴 ~300 行 → 单一 `bridge` 模块。
- 错误只计数不上报,死链静默累积 → 连续 1000 周期错误即中止。
- 时间戳合理性过滤与"上一个原始样本"比较(而非上一个已接受样本),
单个坏样本最多造成两次拒绝、自动恢复(过滤与已接受值比较会在启动
离群值后永久死锁——实测踩中)。
- 移除模拟内存 loopback 线程/mutexCH368/RFM2G 模拟遗留RT 路径
直接回显。
- 删除循环内嵌 PLC 时间戳的端到端延迟指标(跨时钟域且依赖 PLC 程序
内嵌格式,实测数据无意义;端到端延迟应在 TwinCAT 侧用 PLC RTT 统计
测量)。
## 保留的参考实现经验(全部实测有效)
- EL6695 用户 OD 在主站更替时被固件清空,每次上线自检自配。
- 映射对象必须 Complete Access 单条邮箱消息写(`vendor/ethercrab` 补丁
`sdo_write_complete`),标准分段流程被固件拒绝 MBXERR_INVALIDSIZE。
- PDO 布局逐字节复制 TwinCAT 线格式0x1608/0x1A08 各 35 条目
(首条目 @240bit + 33 条 0x0000 延续 + 1 条 @32bit)。
- SM 用裸寄存器配置AL 状态机裸 fpwr/fprd 驱动SAFEOP 后邮箱坏死,
数据循环内禁止 SDO。
- RT 手段PREEMPT_RT 内核 + SCHED_FIFO 80 + 绑核 + mlockall + 栈
prefaultmusl 静态链接下 `sched_setscheduler` 需走 raw syscall。
## 目录
- `src/main.rs` — 主循环ticker/follow/probe、PLL、信号处理
- `src/bridge.rs` — EL6695 自检自配、SM 裸配置、AL 状态机
- `src/rt.rs` — RT 提升、绝对时间睡眠、Ticker
- `src/stats.rs` — 有界在线统计(直方图 + Welford
- `vendor/ethercrab` — 带 `sdo_write_complete`/`send_raw_coe` 补丁的
ethercrab 0.7.1(复制自 rustbootd/gateway-workspace/vendor