J1900 <-> TwinCAT realtime communication verification over EL6695 bridge (Rust/ethercrab)
Go to file
2026-08-10 01:56:41 +08:00
.cargo D2000 (aarch64) migration: cross-build works with zero code changes 2026-08-06 02:05:05 +08:00
docs Enable EL6695 DC-Synchron mode (AssignActivate 0x320) 2026-08-09 15:32:56 +08:00
scripts Extend async pipelined FPWR to 800B: 4kHz spin loop 2040->2960 cycles/s 2026-08-10 01:28:43 +08:00
src J1900-side DC-Synchron: EL6695 secondary firmware sync_mode=2 via CoE, DC telemetry, verified 180s zero sync errors 2026-08-10 01:56:41 +08:00
vendor/ethercrab J1900 <-> TwinCAT 1 kHz verification over EL6695 bridge 2026-07-22 08:55:41 +08:00
.gitignore EL6695 8-byte bidirectional exchange with per-byte verification 2026-07-27 19:01:05 +08:00
Cargo.lock EL6695 8-byte bidirectional exchange with per-byte verification 2026-07-27 19:01:05 +08:00
Cargo.toml EL6695 8-byte bidirectional exchange with per-byte verification 2026-07-27 19:01:05 +08:00
deploy_800b_dc.log Enable EL6695 DC-Synchron mode (AssignActivate 0x320) 2026-08-09 15:32:56 +08:00
deploy_800b_dc2.log Enable EL6695 DC-Synchron mode (AssignActivate 0x320) 2026-08-09 15:32:56 +08:00
deploy_800b_elevated.log Enable EL6695 DC-Synchron mode (AssignActivate 0x320) 2026-08-09 15:32:56 +08:00
deploy_800b_regress.log Enable EL6695 DC-Synchron mode (AssignActivate 0x320) 2026-08-09 15:32:56 +08:00
deploy_800b_regress2.log Enable EL6695 DC-Synchron mode (AssignActivate 0x320) 2026-08-09 15:32:56 +08:00
deploy_800b_regress3.log Enable EL6695 DC-Synchron mode (AssignActivate 0x320) 2026-08-09 15:32:56 +08:00
monitor_5h.csv 800B PDO variant + long-term stability evidence + analysis docs 2026-08-06 01:10:50 +08:00
README.md J1900 <-> TwinCAT 1 kHz verification over EL6695 bridge 2026-07-22 08:55:41 +08:00
uia_dump.py Enable EL6695 DC-Synchron mode (AssignActivate 0x320) 2026-08-09 15:32:56 +08:00
uia_edits.py 2kHz spin-lock mode: RTT halved to 2ms, per-byte XOR proof at 500us cycle 2026-07-28 00:11:34 +08:00
uia_explore.py 2kHz spin-lock mode: RTT halved to 2ms, per-byte XOR proof at 500us cycle 2026-07-28 00:11:34 +08:00
uia_find_dc.py Enable EL6695 DC-Synchron mode (AssignActivate 0x320) 2026-08-09 15:32:56 +08:00
uia_open_el6695.py Enable EL6695 DC-Synchron mode (AssignActivate 0x320) 2026-08-09 15:32:56 +08:00
uia_open_rt.py 2kHz spin-lock mode: RTT halved to 2ms, per-byte XOR proof at 500us cycle 2026-07-28 00:11:34 +08:00
uia_tasks.py 2kHz spin-lock mode: RTT halved to 2ms, per-byte XOR proof at 500us cycle 2026-07-28 00:11:34 +08:00
uia_tree.py 2kHz spin-lock mode: RTT halved to 2ms, per-byte XOR proof at 500us cycle 2026-07-28 00:11:34 +08:00

el6695-rt — J1900 ↔ TwinCAT 1 kHz 通讯验证EL6695 EtherCAT 桥)

J1900 (Linux, PREEMPT_RT) 经 EL6695 EtherCAT 桥与 TwinCAT Windows PC 之间 1 kHz 双向过程数据1024 字节/方向)通讯验证程序。参考 rustbootd/gateway-workspaceecat_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 的自身序列号计算往返)

构建与部署

# 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

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 Nfollow 模式网格相位,默认 500--cycle-us N--core N(绑核,默认 2--prio NSCHED_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

三种模式

  • tickerclock_nanosleep(TIMER_ABSTIME) 绝对时间网格,无漂移; SM3 布局为 0x1A01 诊断字。
  • follow(默认):软件 PLL 跟随 TwinCAT DC 时钟0x1A02 外部时间戳), 读点锁在 TC 网格边界 + phase。与参考实现的差异见下。
  • probeticker 节拍 + follow 布局,不做 PLL 反馈,只 dump 原始 时间戳相位(诊断用)。

相对参考实现rustbootd ecat_el6695_*)的修复

  1. DC 跟随 PLL 的周期二狩猎(最重要):参考实现每个周期用原始 采样直接重算锚点deadbeatfloor(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