227 lines
9.8 KiB
Markdown
227 lines
9.8 KiB
Markdown
|
|
# EL6695 桥接 8 字节双向实时通讯 — 设计文档
|
|||
|
|
|
|||
|
|
> **版本**: 1.0
|
|||
|
|
> **日期**: 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 构建)
|
|||
|
|
|
|||
|
|
```rust
|
|||
|
|
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 图案校验、偏移 264–280 的时间戳/抖动字段)用编译期常量守卫(`if PAYLOAD_LEN >= 280` 等),8B 构建时死代码消除。
|
|||
|
|
|
|||
|
|
### 4.4 交叉编译
|
|||
|
|
|
|||
|
|
```powershell
|
|||
|
|
$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` 中恢复多条目延续格式。
|