ethercat-linux/docs/8b-bridge-design.md
Tony Cao aabfe31526 Enable EL6695 DC-Synchron mode (AssignActivate 0x320)
- DC selection must use the structured <Dc><Data AssignActivate/> XSD
  element; legacy DcData hex writes get normalized to zeros by TwinCAT
- TwinCAT converts it to DcData '2003...' (0x0320) on save: SYNC0/SYNC1
  cyclic + SYNC0 activate for the bridge
- Verified: clean activation, ticker OP, bSync=True, 90k cycles 0 errors,
  timing unchanged (jitter 7.3us mean)
- docs: pitfall #10 (DC selection method)
2026-08-09 15:32:56 +08:00

13 KiB
Raw Blame History

EL6695 桥接 8 字节双向实时通讯 — 设计文档

版本: 1.1(新增 §8 800B 变体) 日期: 2026-07-27 状态: 已实现并验证通过 前置文档: 1kb-verification-progress.md(1KB 版本演进史)


1. 系统概述

在 TwinCAT PC 与 J1900(无 TwinCAT 授权的 Linux RT 工控机)之间,通过 Beckhoff EL6695 EtherCAT 桥接端子实现 1 kHz 实时数据交换。本设计将过程数据(PDO)从 1KB 缩减为 8 字节,以降低总线负载并验证 EL6695 虚拟 PDO 的可配置性。

1.1 硬件拓扑

TwinCAT PC (Windows, TwinCAT 3.1.4026)
  │  网卡: 以太网 2 (TwinCAT-Intel PCI, MAC 00-15-17-8A-B3-DA)
  │  IP: 169.254.176.217 / AmsNetId: 169.254.176.217.1.1
  ▼
EK1100 (总线耦合器)
  ├─ EL2202  (2ch DO, 信号源)
  ├─ EL1252  (2ch DI + DC 锁存)
  ├─ EL2262  (2ch DO, DC 同步)
  ├─ EL2008  (8ch DO)
  ├─ EL6851-0010 (DMX)
  ├─ EL6022  (RS422/RS485)
  ├─ EL6695  (EtherCAT 桥接端子, Primary 侧) ◄── 本设计核心
  └─ EL9011  (总线末端)

EL6695 X1 (Secondary 侧)
  │
  ▼
J1900 (Linux 6.6.135-rt74, PREEMPT_RT)
  IP: 192.168.68.100 (经跳板机 192.168.58.8 SSH 访问)
  eth1 直连 EL6695 次要端口

1.2 角色分工

角色 运行实体 职责
TwinCAT PC EtherCAT 主站 (Primary) TwinCAT 实时内核 + PLC (PlcTask, 1ms) 写 aOut1(8B 测试图案)→ 读 aIn1 并校验
J1900 EtherCAT 主站 (Secondary) el6695_rt(Rust/ethercrab, FIFO 80, 核 2) 读 rx(8B)→ 逐字节 XOR 0x5A → 写 tx

EL6695 内部含双 EtherCAT 从站控制器与共享 DPRAM,两侧各有独立的 SM/FMMU 寄存器组,固件在两侧 DPRAM 区间转发过程数据。


2. EL6695 配置设计

2.1 PDO 设计

EL6695 的 IO PDO 在 ESI 中标记为 Virtual="1",尺寸由主站配置决定:

PDO 索引 方向(Primary 视角) SyncMan 条目 尺寸
IO Outputs 0x1608 TwinCAT → J1900 SM2 0x7000:01, ARRAY [0..7] OF BYTE 8 B
IO Inputs 0x1A08 J1900 → TwinCAT SM3 0x6000:01, ARRAY [0..7] OF BYTE 8 B

重要设计决策:不为 SM3 分配 0x1A01 "SYNC Inputs" 诊断 PDO。 1KB 配置中 SM3 长度为 1026 = 2B 诊断 + 1024B payload。EL6695 固件按 PDO 赋值计算 SM 长度要求;TwinCAT 在 8B 配置下重算 SM3 长度时未计入 2B 诊断,导致设备拒绝(sync manager 3: size not allowed (min 0xa, max 0xa))。取消诊断 PDO 赋值后,两侧统一为纯 8B payload。代价:失去 "TxPDO toggle / External device not connected" 等在线状态位。

2.2 SyncManager 配置(Primary 侧, tsproj)

SM 起始地址 长度 ctrl 用途
SM0 0x1000 1024 0x26 邮箱输出(CoE/EoE/FoE)
SM1 0x1600 1024 0x22 邮箱输入
SM2 0x1C00 8 0x64 过程数据输出(TwinCAT→J1900)
SM3 0x8E00 8 0x20 过程数据输入(J1900→TwinCAT)

tsproj 中的十六进制记录(24 字节,激活时由 TwinCAT 校验/重算):

SM2: 001c08006400010003000000000000000000001c64010000
SM3: 008e08002000010004000000000000000200008e20010000

2.3 类型系统与 GUID 编码

TwinCAT 对 PDO 条目类型的解析方式直接决定配置能否生效:

  • 基类型(如 ULINT)按名称解析;
  • 数组类型必须提供 GUID,且在 <DataTypes> 段中声明一致的 GUID + 名称;
  • TwinCAT 为 PLC 生成的数组类型使用随机 GUID(CoCreateGuid);
  • 历史 TwinCAT 项目中的 {18071995-0000-0000-0000-00XX00YYYYYY} 形式 GUID,后缀 YYYYYY = 元素个数(十六进制),如 000300000400 = 1024 元素 BYTE 数组。手写该命名空间的 GUID 会被 TwinCAT 类型系统错误回退(名称被改写、SM 被清零),不可使用。

本设计的最终方案:直接复用 PLC 构建时生成的数组类型: {FE565D85-927B-2D08-1043-124F5F921E35} = ARRAY [0..7] OF BYTE,PDO 条目与 PLC 变量类型完全一致。

2.4 PLC ↔ IO 链接

链接 VarA VarB 尺寸
输入 PlcTask Inputs^GVL_Sync.aIn1 IO Inputs^IO Inputs 8 B
输出 PlcTask Outputs^GVL_Sync.aOut1 IO Outputs^IO Outputs 8 B

关键教训:链接指向数组元素 IO Inputs[0] 时,TwinCAT 按两侧较小者建链(1 字节);指向不存在的路径时映射 0 字节。必须通过自动化 API ITcSysManager.LinkVariables 以整数组路径创建链接(脚本 scripts/tc-relink.ps1)。


3. 数据协议设计(8B 逐字节验证协议)

设计目标:证明 8 个字节中的每一个都真实地完成了 TwinCAT → J1900 → 软件处理 → TwinCAT 的完整环路,而非只有低位计数器字节在动。

3.1 发送图案(TwinCAT,每周期)

aOut1[i] = (nCycles + i*32) mod 256,  i = 0..7
  • 8 个字节互不相同(步进 32,模 256 下 8 个值不重叠);
  • 每个字节每周期都变化;
  • 图案周期 256 个 PLC 周期,任意 16 个连续周期的 8 字节组全局唯一(支撑延迟匹配)。

3.2 J1900 变换

tx[i] = rx[i] XOR 0x5A,  i = 0..7

逐字节独立的读-算-写。XOR 0x5A 是软件才能完成的变换,可证明数据经过了 J1900 的处理而非硬件透传;同时逐字节可逆,便于 TwinCAT 校验。

3.3 TwinCAT 校验(发送历史环)

PLC 维护 16 槽发送历史环 aHist[0..15, 0..7],每周期在槽位 nCycles mod 16 保存刚发送的 8 字节:

bSync = TRUE  ⟺  ∃ h∈[0,15]: ∀i∈[0,7]: (aIn1[i] XOR 0x5A) == aHist[h, i]
nMatchLag   = 匹配槽对应的延迟周期数 (实测稳定为 4)

历史环设计天然容忍桥接管线延迟,无需预设固定延迟值;16 槽 >> 实测延迟 4 周期,且不会误判(256 周期内图案唯一)。

3.4 派生指标

变量 含义
bSync 本周期回显 8 字节整组匹配成功
nMatchLag 桥接往返延迟(PLC 周期数)
nReturnedSeq 回显对应的原始发送周期序号
nMismatch 失配周期累计计数
bProcessingOk = bSync(J1900 处理证明)
nRttMin/Max/Sum/Count RTT 统计

4. J1900 侧软件设计(el6695_rt)

4.1 架构

Rust + ethercrab 0.7(本地 patch: sdo_write_complete 单报文 Complete Access 下载,EL6695 固件强制要求)。1 kHz ticker 线程绑定核 2,SCHED_FIFO 80,mlockall。

4.2 配置流程(ConfigOwner 角色)

EL6695 固件约束:主站切换时用户 OD 被擦除,配置与数据循环必须在同一会话内完成。

  1. 扫描网段(INIT→PREOP);
  2. Complete Access 写 PDO 映射:
    • 8B 模式: twin_layout_blob_sized(obj, 8) — 单条目 [64, 1, obj_lo, obj_hi](64 bit 挂在 0x6000:01 / 0x7000:01 上);
    • 1KB 模式: 35 条目 TwinCAT 行格式(1×240bit 真实对象 + 33×240bit 延续 + 1×32bit);
  3. 写 PDO 赋值: 0x1C12=[0x1608], 0x1C13=[0x1A08](均不含诊断 PDO);
  4. 写 SM2/SM3 寄存器(start=0x1C00/0x8E00, len=8, ctrl=0x64/0x20)与 FMMU;
  5. INIT→PREOP→SAFEOP→OP;
  6. 数据循环: 读 SM3 区域 8B → XOR 0x5A → 写 SM2 区域 8B,周期统计。

4.3 关键常量(8B 构建)

const SM_TX_ADDR: u16 = 0x1C00;  // SM2: J1900 -> TwinCAT
const SM_TX_LEN: usize = 8;
const SM_RX_ADDR: u16 = 0x8E00;  // SM3: TwinCAT -> J1900
const SM_RX_LEN: usize = 8;
const SM_RX_PLD_LEN: usize = 8;
const PAYLOAD_LEN: usize = 8;

1KB 专属逻辑(256B 图案校验、偏移 264280 的时间戳/抖动字段)用编译期常量守卫(if PAYLOAD_LEN >= 280 等),8B 构建时死代码消除。

4.4 交叉编译

$env:RUSTFLAGS="-C linker=rust-lld"   # musl 目标无系统 cc,用 rust-lld
cargo build --release --target x86_64-unknown-linux-musl --bin el6695-rt
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_8b_xor

5. TwinCAT 侧配置(tsproj 关键修改)

位置 修改
PDO 0x1608/0x1A08 条目 <Type GUID="{FE565D85-...}">ARRAY [0..7] OF BYTE</Type>
<DataTypes> PLC 构建自动注册 {FE565D85-...} 类型
SM2 记录 001c080064...(len=8)
SM3 记录 008e080020...(len=8)
0x1A01 Pdo 标签 移除 SyncMan="3" 属性(取消诊断 PDO 赋值)
GVL_Sync aIn1/aOut1 : ARRAY[0..7] OF BYTE,新增 aHist, nMatchLag
MAIN 逐字节图案 + 历史环校验(见 §3)

备份: TwinCATProject1.tsproj.bak-1k 为可用的 1KB 配置。


6. 已解决的典型陷阱(排查手册)

# 现象 根因 解决
1 只有 1 字节过 bridge 链接指向数组元素 [0],按 1 字节建链 LinkVariables 整数组链接
2 改整数组名后变 0 字节 链接路径无法解析 同上,用 API 而非手改 XML
3 手写 GUID 000300000008 后名称被改回 [0..1023]、SM3 清零 TwinCAT 类型系统对该命名空间 GUID 回退 复用 PLC 生成的随机 GUID 类型
4 SM3 反复被清零,事件日志 size not allowed (min 0xa, max 0xa) 0x1A01 诊断 PDO(2B)在赋值中,设备要求 SM3=10,TwinCAT 重算为 8 取消 0x1A01 的 SM3 赋值,两侧统一 8B
5 J1900 配置后 TwinCAT 激活又清零 EL6695 固件在主站切换时擦除用户 OD 先激活 TwinCAT,再启动 ticker(同会话)
6 RPC_E_CALL_REJECTED 持续拒绝 VS 构建期间 COM 忙 全部 COM 调用加重试;先等 30s 再操作
7 bSync 用当前 nCycles 校验永假 桥接 ~4 周期管线延迟 发送历史环匹配

7. 限制与后续工作

  1. 无诊断 PDO: 8B 配置不含 "External device not connected" 等状态位。若需要,须在 SM3 同时赋值 0x1A01+0x1A08 并保持 SM3=10(TwinCAT 侧重算逻辑需相应修正)。
  2. 延迟: 往返固定 4 个 PLC 周期(≈4ms @1kHz),未做 DC 同步优化。
  3. 尺寸扩展: 本设计的修改方法(GUID 类型 + SM 记录 + J1900 常量)适用于任意 ≤240bit 的单条目尺寸;更大尺寸需在 twin_layout_blob_sized 中恢复多条目延续格式。

8. 800B 变体(已实现并验证)

在 8B 验证通路基础上,扩展出 800 字节 PDO 工程 TwinCAT_EL6695_Primary_800B,作为实际应用的带宽档位,并验证了任意尺寸的映射 blob 生成规则。

8.1 与 8B 设计的差异

8B 800B
PDO 条目类型 ARRAY [0..7] OF BYTE ARRAY [0..799] OF BYTE(GUID {7D10FDFE-13E3-A012-D822-BE30F7D36D23},PLC 构建生成)
SM2/SM3 长度 8 / 8 800 / 800(0x0320)
0x1A01 诊断 PDO 不挂 SM3 同左(沿用,否则设备报 size not allowed)
映射 blob 单条目 64bit 27 条目(见 §8.2)
数据协议 每字节 XOR 0x5A + 历史环 seq + f(x)=x·7+3 + 逐字节图案 + 反推校验(类 1KB)
周期 1kHz(基线) 1kHz

8.2 多条目映射 blob 生成规则

EL6695 固件接受 TwinCAT 行格式:1 真实对象条目 @240bit + N 延续条目(0x0000:00)@240bit + 1 余量延续条目。

800 B = 6400 bit = 26 × 240 bit + 160 bit
blob = [27 (u16 LE)]
     + [240, 1, obj_lo, obj_hi]   真实对象 (0x6000:01 / 0x7000:01)
     + 25 × [240, 0, 0, 0]        延续
     + 1 × [160, 0, 0, 0]         余量延续

twin_layout_blob_sized(obj, n) 泛化实现:≤240bit 单条目;>240bit 按上式多条目;1024B 特判保持原 35 条目格式(字节级兼容)。

8.3 800B 数据布局

偏移 内容 方向
[0..7] TwinCAT nCycles → J1900 回 nCycles*7+3 双向
[8..15] J1900 本地周期号 J→T
[16..263] 逐字节图案 (nCycles+i) mod 256,J1900 原样回显 双向
[264..267] J1900 周期抖动 ns J→T
[268..271] J1900 图案失配计数 J→T
[272..279] J1900 回存的原始 tc_seq J→T
[280..799] 逐字节图案(同上) 双向

设计要点:图案区必须避开 [264..279] 统计字段——首版实现按 [16..799] 连续图案,J1900 统计字段覆盖 16 字节导致 PLC 每周期 16 字节失配。

8.4 新增陷阱(800B 实测)

# 现象 根因 解决
8 激活时 EL6695 SAFEOP 失败,AL 状态码 0x0003 激活与 J1900 ticker 会话并发:relink 激活时 ticker 正在跑,桥两侧主站会话冲突 激活必须在 J1900 空闲时进行;失败后空载重新激活即恢复
9 数据通但 PLC bSync=False,每周期固定 16 字节失配 图案区 [16..799] 与 J1900 统计字段 [264..279] 重叠 图案区改为 [16..263]+[280..799](见 §8.3)
10 手写 <DcData> 十六进制被 TwinCAT 归一化为全零 DC 模式选择不接受 legacy hex 直写 用 XSD 结构化形式 <Dc><Data AssignActivate="#x320"/></Dc>,TwinCAT 读取后自动生成正确 DcData(2003...,即 0x0320)并启用 DC-Synchron(2026-08-09 已验证)

8.5 800B 实测性能

指标
J1900 exec(800B,同步写) 均值 384µs / p99 400µs
FPRD(读 800B) 均值 139µs / p99 156µs(8B 时为 71µs)
FPWR(写 800B) 均值 244µs / p99 260µs(与 8B 基本持平)
桥接 RTT(1kHz) 4 周期(lag=4,同 8B/1KB 结构)