简述
此部分内容主要基于EtherCAT的igh学习与研究(一)的后续记录
正文
1.1 双主站与多主站配置
IgH EtherCAT Master 支持多个主站实例,每个主站独立管理自己的 EtherCAT 从站网络。
多主站应用场景:
-
🔴 冗余备份 - 主主站故障时备用主站接管
-
🔵 网络隔离 - 不同物理网络使用不同主站
-
🟢 负载分担 - 大型系统分散到多个主站
-
🟡 功能分区 - 不同安全等级设备使用不同主站
1.1.1 多主站架构概述

1.1.1双主站配置示例
方案 A:双网卡冗余配置(推荐)
硬件配置:
-
主站 0:eth0 (MAC: c4:83:4f:27:30:5a) - 主用
-
主站 1:eth1 (MAC: c4:83:4f:27:30:5b) - 备用
配置文件 (/etc/ethercat.conf):
# ===== 主站 0 配置 =====
MASTER0_DEVICE="c4:83:4f:27:30:5a"
MASTER0_NAME="Primary_Master"
# ===== 主站 1 配置 =====
MASTER1_DEVICE="c4:83:4f:27:30:5b"
MASTER1_NAME="Backup_Master"
# 设备驱动(两个主站使用相同驱动)
DEVICE_MODULES="dwmac-rk dwmac-rk"
# 可选:启动时设置网口 UP
LINK_DEVICES="eth0 eth1"

用户空间应用:
// 应用 1 - 使用主站 0
ec_master_t *master0 = ecrt_request_master(0); // 主用
ec_domain_t *domain0 = ecrt_master_create_domain(master0);
// 应用 2 - 使用主站 1
ec_master_t *master1 = ecrt_request_master(1); // 备用
ec_domain_t *domain1 = ecrt_master_create_domain(master1);
1.1.3 多主站配置示例
四主站配置
# 主站 0 - 生产网络
MASTER0_DEVICE="c4:83:4f:27:30:50"
# 主站 1 - 测试网络
MASTER1_DEVICE="c4:83:4f:27:30:51"
# 主站 2 - 冗余备份
MASTER2_DEVICE="c4:83:4f:27:30:52"
# 主站 3 - 扩展网络
MASTER3_DEVICE="c4:83:4f:27:30:53"
# 四个主站使用相同或不同驱动
DEVICE_MODULES="dwmac-rk dwmac-rk dwmac-rk dwmac-rk"
# 启动所有网口
LINK_DEVICES="eth0 eth1 eth2 eth3"
**设备节点**:
- `/dev/EtherCAT0` - 主站 0
- `/dev/EtherCAT1` - 主站 1
- `/dev/EtherCAT2` - 主站 2
- `/dev/EtherCAT3` - 主站 3
1.1.4 主站间关系与通信
主站独立性:

关键特性:
-
✅ 独立运行 - 每个主站独立管理自己的从站网络
-
✅ 无共享状态 - 主站间不共享配置和状态
-
✅ 独立应用 - 不同应用可以访问不同主站
-
✅ 物理隔离 - 每个主站使用独立网卡和网络
主站间协调(需要用户空间实现):
// 示例:主从备份逻辑
if (master0_active()) {
use_master(0); // 使用主站 0
} else if (master1_active()) {
use_master(1); // 切换到主站 1
}
1.1.5 启动脚本示例
systemd 服务(多主站)
创建多个服务文件:
/etc/systemd/system/ethercat0.service (主站 0):
[Unit]
Description=EtherCAT Master 0 Service
After=network.target
[Service]
Type=oneshot
ExecStart=/sbin/modprobe ec_master MASTER0_DEVICE=c4:83:4f:27:30:5a
ExecStart=/sbin/modprobe ec_dwmac-rk
RemainAfterExit=yes
ExecStop=/sbin/rmmod ec_dwmac-rk
ExecStop=/sbin/rmmod ec_master
[Install]
WantedBy=multi-user.target
/etc/systemd/system/ethercat1.service (主站 1):
[Unit]
Description=EtherCAT Master 1 Service
After=ethercat0.service
[Service]
Type=oneshot
ExecStart=/sbin/modprobe ec_master MASTER1_DEVICE=c4:83:4f:27:30:5b
ExecStart=/sbin/modprobe ec_dwmac-rk
RemainAfterExit=yes
ExecStop=/sbin/rmmod ec_dwmac-rk
ExecStop=/sbin/rmmod ec_master
[Install]
WantedBy=multi-user.target
启动命令:
# 启动主站 0
sudo systemctl start ethercat0.service
# 启动主站 1
sudo systemctl start ethercat1.service
# 查看状态
systemctl status ethercat0.service
systemctl status ethercat1.service
# 查看设备节点
ls -l /dev/EtherCAT*
1.1.6 配置对比表
| 配置项 | 单主站 | 双主站 | 多主站 |
|---|---|---|---|
| 配置文件 | MASTER0_DEVICE |
MASTER0_DEVICE MASTER1_DEVICE |
MASTER0_DEVICE MASTER1_DEVICE MASTER2_DEVICE... |
| 设备节点 | /dev/EtherCAT0 |
/dev/EtherCAT0 /dev/EtherCAT1 |
/dev/EtherCAT0 /dev/EtherCAT1 /dev/EtherCAT2... |
| 驱动实例 | 1 个 | 2 个 | N 个 |
| 网卡数量 | 1 个 | 2 个 | N 个 |
| 应用访问 | ecrt_request_master(0) |
ecrt_request_master(0) ecrt_request_master(1) |
ecrt_request_master(0~N) |
| 适用场景 | 简单系统 | 冗余备份 | 大型分布式系统 |
1.2 多主站时钟同步
1.2.1 DC 同步原理
分布式时钟(Distributed Clocks, DC) 是 EtherCAT 实现高精度同步的核心机制。
单主站 DC 同步:

多主站同步挑战:
-
❌ 每个主站有独立的参考从站
-
❌ 不同主站的时钟源可能不同步
-
❌ 需要跨主站的时间基准统一
1.2.2 多主站同步方案
方案 A:统一时钟源(推荐)
原理:所有主站使用同一个外部时钟源(如 PTP、GPS、IRIG-B)

实现步骤:
-
安装 PTP 服务(linuxptp):
安装 PTP 守护进程
sudo apt install linuxptp
启动 PTP 从时钟(同步到 PTP 主时钟)
sudo ptp4l -i eth0 -s -m
sudo phc2sys -s eth0 -c CLOCK_REALTIME -m
2. 应用层同步代码:
/ 每个主站的应用都从系统时钟获取时间
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
uint64_t app_time = TIMESPEC2NS(ts);
// 同步到各自的主站
ecrt_master_application_time(master0, app_time);
ecrt_master_sync_reference_clock(master0);
ecrt_master_sync_slave_clocks(master0);
ecrt_master_application_time(master1, app_time);
ecrt_master_sync_reference_clock(master1);
ecrt_master_sync_slave_clocks(master1);
3.周期性同步(每 10 个周期同步一次):
static int sync_counter = 0;
void cyclic_task(void) {
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
uint64_t app_time = TIMESPEC2NS(ts);
// 每 10 周期同步一次 DC
if (++sync_counter >= 10) {
sync_counter = 0;
// 同步主站 0
ecrt_master_application_time(master0, app_time);
ecrt_master_sync_reference_clock(master0);
ecrt_master_sync_slave_clocks(master0);
// 同步主站 1
ecrt_master_application_time(master1, app_time);
ecrt_master_sync_reference_clock(master1);
ecrt_master_sync_slave_clocks(master1);
}
// 发送过程数据
ecrt_domain_queue(domain0);
ecrt_master_send(master0);
ecrt_domain_queue(domain1);
ecrt_master_send(master1);
}
方案 B:主从主站同步
原理:一个主站作为时间主站,其他主站同步到主站的时间

// 主站 0 - 时间主站
void master0_sync_task(void) {
static int counter = 0;
if (++counter >= 10) {
counter = 0;
struct timespec ts;
clock_gettime(CLOCK_REALTIME, &ts);
uint64_t app_time = TIMESPEC2NS(ts);
// 正常同步
ecrt_master_application_time(master0, app_time);
ecrt_master_sync_reference_clock(master0);
ecrt_master_sync_slave_clocks(master0);
}
ecrt_domain_queue(domain0);
ecrt_master_send(master0);
}
// 主站 1 - 时间从站
void master1_sync_task(void) {
static int counter = 0;
if (++counter >= 100) { // 每 100ms 同步一次到主站 0
counter = 0;
// 从主站 0 获取参考时间
uint32_t ref_time;
if (ecrt_master_reference_clock_time(master0, &ref_time) == 0) {
// 使用主站 0 的时间同步自己的从站
ecrt_master_application_time(master1, ref_time);
ecrt_master_sync_reference_clock(master1);
ecrt_master_sync_slave_clocks(master1);
}
}
ecrt_domain_queue(domain1);
ecrt_master_send(master1);
}
方案 C:共享参考从站(特殊场景)
说明:如果两个主站连接到同一个物理从站网络,可以让一个主站的参考从站作为另一个主站的参考
# 主站 0 - 使用从站 1 作为参考
MASTER0_DEVICE="c4:83:4f:27:30:5a"
DEVICE_MODULES="dwmac-rk"
# 主站 1 - 使用相同的参考从站
MASTER1_DEVICE="c4:83:4f:27:30:5b"
DEVICE_MODULES="dwmac-rk"
1.2.3 同步精度对比
| 同步方案 | 精度 | 实现复杂度 | 适用场景 |
|---|---|---|---|
| 方案 A:统一时钟源 | ±1μs | 中等 | 高精度要求系统 |
| 方案 B:主从主站 | ±10μs | 简单 | 一般工业应用 |
| 方案 C:共享参考 | ±5μs | 复杂 | 特殊网络拓扑 |
1.2.4 完整同步示例代码
双主站同步应用:
#include <ecrt.h>
#include <time.h>
#include <pthread.h>
// 主站句柄
static ec_master_t *master0 = NULL;
static ec_master_t *master1 = NULL;
static ec_domain_t *domain0 = NULL;
static ec_domain_t *domain1 = NULL;
// 同步计数器
static int sync_counter = 0;
static const int SYNC_INTERVAL = 10; // 每 10 个周期同步一次
// 初始化主站
int init_masters(void) {
// 获取主站 0
master0 = ecrt_request_master(0);
if (!master0) {
fprintf(stderr, "Failed to get master 0\n");
return -1;
}
// 获取主站 1
master1 = ecrt_request_master(1);
if (!master1) {
fprintf(stderr, "Failed to get master 1\n");
ecrt_release_master(master0);
return -1;
}
// 创建域
domain0 = ecrt_master_create_domain(master0);
domain1 = ecrt_master_create_domain(master1);
return 0;
}
// 同步任务(实时线程)
void cyclic_sync_task(void) {
struct timespec ts;
uint64_t app_time;
// 获取当前时间
clock_gettime(CLOCK_REALTIME, &ts);
app_time = TIMESPEC2NS(ts);
// 周期性同步 DC
if (++sync_counter >= SYNC_INTERVAL) {
sync_counter = 0;
// 同步主站 0
ecrt_master_application_time(master0, app_time);
ecrt_master_sync_reference_clock(master0);
ecrt_master_sync_slave_clocks(master0);
// 同步主站 1
ecrt_master_application_time(master1, app_time);
ecrt_master_sync_reference_clock(master1);
ecrt_master_sync_slave_clocks(master1);
// 可选:监控同步误差
uint32_t sync_diff0, sync_diff1;
ecrt_master_sync_monitor_queue(master0);
ecrt_master_sync_monitor_queue(master1);
sync_diff0 = ecrt_master_sync_monitor_process(master0);
sync_diff1 = ecrt_master_sync_monitor_process(master1);
if (sync_diff0 > 1000 || sync_diff1 > 1000) {
fprintf(stderr, "Sync error too large: %u, %u\n",
sync_diff0, sync_diff1);
}
}
// 发送过程数据
ecrt_domain_queue(domain0);
ecrt_master_send(master0);
ecrt_domain_queue(domain1);
ecrt_master_send(master1);
}
// 主函数
int main(void) {
if (init_masters() != 0) {
return 1;
}
printf("Dual-master EtherCAT system started\n");
// 实时循环
while (1) {
cyclic_sync_task();
usleep(1000); // 1ms 周期
}
ecrt_release_master(master0);
ecrt_release_master(master1);
return 0;
}
1.2.5 最佳实践建议
-
✅ 使用 PTP 统一时钟源 - 最高精度和可靠性
-
✅ 降低同步频率 - 每 10-100 个周期同步一次即可
-
✅ 监控同步误差 - 实时检测同步质量
-
✅ 选择稳定从站 - 参考从站应连接稳定
-
✅ 网络隔离 - 不同主站使用独立物理网络
-
❌ 避免频繁同步 - 过度同步会增加网络负载
-
❌ 避免多个参考源 - 会导致时钟漂移
1.3 实际部署步骤
1.3.1 文件部署清单
解压 rk3576-ethercat-6.1-*.tar.gz 后,需要配置以下文件:
| 文件 | 源位置 | 目标位置 | 是否需配置 |
|---|---|---|---|
| ethercat.conf | /usr/local/etc/ethercat.conf | /etc/ethercat.conf | ✅ 需修改 |
| ethercat.service | /usr/local/lib/systemd/system/ethercat.service | /etc/systemd/system/ethercat.service | 可选 |
| ec_master.ko | /lib/modules/ethercat/ec_master.ko | /lib/modules/$(uname -r)/kernel/drivers/ethercat/ | ✅ 需加载 |
| ec_dwmac-rk.ko | /lib/modules/ethercat/ec_dwmac-rk.ko | /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/ | ✅ 需加载 |
1.3.2 部署步骤(RK3576)
步骤 1: 加载内核模块
# 创建模块目录
sudo mkdir -p /lib/modules/$(uname -r)/kernel/drivers/ethercat/
sudo mkdir -p /lib/modules/$(uname -r)/kernel/drivers/net/ethernet/stmmac/
# 拷贝模块
sudo cp /tmp/lib/modules/ethercat/*.ko /lib/modules/$(uname -r)/kernel/drivers/
# 更新模块依赖
sudo depmod -a
# 测试加载
sudo modprobe ec_master
sudo modprobe ec_dwmac-rk
# 验证加载
lsmod | grep ec
步骤 2: 配置 ethercat.conf
获取网卡 MAC 地址
ip link show eth0
# 编辑配置文件
sudo vi /etc/ethercat.conf
# 添加配置
MASTER0_DEVICE="c4:83:4f:27:30:5b"
DEVICE_MODULES="dwmac-rk"
LINK_DEVICES="eth0"
步骤 3: 配置 systemd 服务
# 拷贝服务文件
sudo cp /tmp/usr/local/lib/systemd/system/ethercat.service /etc/systemd/system/
# 重载 systemd
sudo systemctl daemon-reload
# 启动服务
sudo systemctl start ethercat
# 设置开机自启
sudo systemctl enable ethercat
步骤 4: 验证状态
# 查看服务状态
sudo systemctl status ethercat
# 查看主站状态
sudo ethercat master
# 查看从站状态
sudo ethercat slaves
# 查看内核日志
dmesg | grep -i ethercat
1.4 常见问题与调试
1.4.1 启动失败排查指南
| 步骤 | 问题 | 检查命令 | 解决方法 |
|---|---|---|---|
| 1 | 模块加载失败 | lsmod | grep ec | 重新编译匹配内核的模块 |
| 2 | MAC 地址无效 | ip link show | 使用正确格式 |
| 3 | 驱动替换失败 | lsmod | grep igb | 先手动 rmmod 原驱动 |
| 4 | 设备节点不存在 | ls /dev/EtherCAT* | 重新加载 ec_master 模块 |
| 5 | 主站状态异常 | ethercat master | 检查网卡 link 状态 |
常用调试命令:
# 模块相关
lsmod | grep ec # 查看已加载的 EtherCAT 模块
dmesg | grep EtherCAT # 查看内核日志
modinfo ec_master # 查看模块信息
# 设备节点
ls -la /dev/EtherCAT* # 查看设备节点
ls -la /sys/class/EtherCAT/ # 查看设备类
# 主站状态
ethercat master # 查看主站状态
ethercat slaves # 查看从站列表
1.4.2 内核日志分析
正常启动日志示例:
dmesg | grep -i ethercat
# 输出示例:
[ 123.456789] EtherCAT: Master module initialized
[ 123.567890] EtherCAT: Registered device /dev/EtherCAT0
[ 123.678901] EtherCAT: Device c4:83:4f:27:30:5b attached
[ 123.789012] EtherCAT: Master 0 is now IDLE
错误日志示例及解决方法:
# 错误 1: 找不到设备
[ 123.456789] EtherCAT: ERROR: Device c4:83:4f:27:30:5b not found
# 解决:检查 MAC 地址是否正确,网卡是否已识别
# 错误 2: 模块版本不匹配
[ 123.456789] ec_master: disagrees about version of symbol module_layout
# 解决:重新编译匹配当前内核版本的模块
# 错误 3: 驱动加载失败
[ 123.456789] EtherCAT: Failed to load ec_dwmac-rk module
# 解决:检查模块路径,确认依赖关系
1.4.3 性能调试
查看主站周期时间:
# 使用 ethercat 工具
ethercat master -v
# 输出示例:
Master 0: State INIT, HW address: c4:83:4f:27:30:5b
Cycle Time: 1000 us (configured: 1000 us)
Jitter: 5 us
查看系统延迟:
# 安装 cyclictest
sudo apt install rt-tests
# 运行测试
sudo cyclictest -m -t -p 95 -n -D 10s
# 输出示例:
# Max Latencies: 00000015 00000012 00000010 00000008 00000005
优化建议:
-
使用 Preempt-RT 内核
-
隔离 CPU 核心(isolcpus 内核参数)
-
设置 IRQ 亲和性
-
禁用节能模式(intel_idle.max_cstate=0)
1.5 小结
| 类别 | 内容 |
|---|---|
| 配置文件 | ethercat.conf, sysconfig/ethercat, init.d/ethercat, ethercatctl, ethercat.service |
| 启动方式 | systemd(现代标准)/ SysV init(兼容性好) |
| 启动流程 | 读取配置 → 设置网口 → 加载主站模块 → 替换网卡驱动 → 设备就绪 |
| 核心参数 | MASTER0_DEVICE, DEVICE_MODULES, LINK_DEVICES |
| 技术原理 | MAC 地址匹配网卡、驱动替换、绕过网络栈、DMA 直接收发 |
| 部署步骤 | 拷贝模块 → 配置 MAC → 加载驱动 → 启动服务 → 验证状态 |
| 调试方法 | dmesg 日志、lsmod 模块、ethercat 工具、cyclictest 性能测试 |
关键要点:
-
配置文件决定行为 - MAC 地址必须与实际网卡匹配
-
驱动替换是关键 - 必须卸载原网卡驱动才能加载 EtherCAT 驱动
-
模块版本必须匹配 - 内核版本不一致会导致加载失败
-
实时性能优化 - Preempt-RT 内核 + CPU 隔离 + IRQ 亲和性