第 3 章 第一次运行 Hello EtherCAT
导读摘要:完成编译安装后,接下来要让 EtherCAT Master 真正跑起来。本章将带你从配置文件开始,逐步加载内核模块、启动 Master、用命令行工具探索总线,最后分别运行内核态和用户态示例程序。读完本章,你将完成从"装好了"到"跑通了"的关键一步。
3.1 配置文件 ethercat.conf 详解
EtherCAT Master 的运行参数集中在一个配置文件中:/etc/ethercat.conf。启动脚本 ethercatctl 会在启动时 source 这个文件,把其中的 Shell 变量读入内存。
核心配置项
配置文件中最重要的变量有三组:
1) MASTER0_DEVICE ------ 指定主网卡
bash
# 方式一:使用 MAC 地址
MASTER0_DEVICE="00:00:08:44:ab:66"
# 方式二:使用网卡接口名(脚本会自动解析为 MAC)
MASTER0_DEVICE="eth0"
# 方式三:广播地址,表示接受任意网卡(仅用于快速测试)
MASTER0_DEVICE="ff:ff:ff:ff:ff:ff"
如果需要多个 Master 实例,依次设置 MASTER1_DEVICE、MASTER2_DEVICE 即可。脚本会从 MASTER0 开始循环,遇到空值即停止,变量个数决定了 Master 实例数量。
2) MASTER0_BACKUP ------ 冗余备份网卡(可选)
bash
#MASTER0_BACKUP=""
冗余模式(Cable Redundancy)下使用。如果你只有一块网卡,可以忽略此项。
3) DEVICE_MODULES ------ 网卡驱动模块
bash
# 可选值: 8139too, e100, e1000, e1000e, r8169, generic, igb, igc 等
DEVICE_MODULES="generic"
这个变量告诉启动脚本加载哪个 EtherCAT 专用网卡驱动。generic 是通用驱动,兼容性最好,适合入门。专用驱动(如 e1000e、igb)性能更优,但需要在编译时用 --enable-<driver> 开启。
4) UPDOWN_INTERFACES ------ 自动启停的网络接口
bash
UPDOWN_INTERFACES="eth0"
使用 generic 驱动时,网卡必须在 Master 启动前处于 UP 状态,否则所有帧都会超时。将接口名填入此变量,脚本会在 start 时自动执行 ip link set dev eth0 up。
最小可运行配置
对于只有一块 Intel 网卡的测试环境,最小配置如下:
bash
MASTER0_DEVICE="eth0"
DEVICE_MODULES="generic"
UPDOWN_INTERFACES="eth0"
3.2 加载内核模块与启动 Master
IgH EtherCAT Master 的启动由 systemd 服务 + 控制脚本协同完成。下面是它们的协作流程:
┌──────────────────────────────────────────────────────┐
│ systemd: ethercat.service │
│ │
│ ExecStart = /usr/sbin/ethercatctl start │
│ ExecStop = /usr/sbin/ethercatctl stop │
└─────────────────────┬────────────────────────────────┘
│
▼
┌──────────────────────────────────────────────────────┐
│ ethercatctl start 流程 │
│ │
│ 1. source /etc/ethercat.conf │
│ 2. ip link set dev <UPDOWN_INTERFACES> up │
│ 3. 解析 MASTER*_DEVICE → MAC 地址列表 │
│ 4. modprobe ec_master main_devices=<MAC> │
│ 5. rmmod 原生驱动 (如 e1000e) │
│ 6. modprobe ec_<DEVICE_MODULES> │
└──────────────────────────────────────────────────────┘
使用 systemd 启动
bash
# 启动 Master
sudo systemctl start ethercat
# 查看状态
sudo systemctl status ethercat
# 设置开机自启
sudo systemctl enable ethercat
手动启动(调试用)
有时候我们需要绕过 systemd 直接操作,便于观察错误输出:
bash
# 手动加载主模块,指定网卡 MAC
sudo modprobe ec_master main_devices="00:00:08:44:ab:66"
# 加载网卡驱动模块(以 generic 为例)
sudo modprobe ec_generic
# 验证模块加载
lsmod | grep ec_
成功加载后,ec_master 模块会在内核日志中打印版本信息。我们可以通过 dmesg 确认:
bash
dmesg | grep -i ethercat
# 预期输出类似:
# EtherCAT: Master driver 1.6.x
# EtherCAT: 1 master waiting for devices.
# EtherCAT: Accepting eth0 as main device for master 0.
当 ec_master 加载后,它会进入 Idle 阶段(Phase),等待网卡驱动通过 ecdev_offer() 接口提供网络设备。一旦驱动加载并完成匹配,Master 即进入正常工作状态。
停止 Master
bash
# 通过 systemd
sudo systemctl stop ethercat
# 或手动卸载
sudo rmmod ec_generic
sudo rmmod ec_master
停止顺序与启动相反:先卸载网卡驱动模块,再卸载主模块。脚本还会重新加载原生网卡驱动,恢复普通网络功能。
3.3 使用 ethercat 命令行工具探索总线
Master 启动后,我们可以用 ethercat 命令行工具与之交互。这是日常调试最常用的工具。
查看 Master 状态
bash
ethercat master
输出示例:
Master0
Phase: Idle
Active: no
Slaves: 3
...
扫描从站
bash
# 列出总线上所有从站
ethercat slaves
# 输出示例:
# 0 0:0 PREOP + EK1100 EtherCAT Coupler
# 1 0:1 PREOP + EL2004 4Ch. Dig. Output 24V
# 2 0:2 PREOP + EL3152 2Ch. Ana. Input 4-20mA
每行含义依次为:从站绝对位置(Absolute Position)、别名:位置、当前 AL 状态(Application Layer State)、连接标志、设备描述。
常用子命令速查
| 命令 | 说明 |
|---|---|
ethercat master |
查看 Master 概要信息 |
ethercat slaves |
列出所有从站及其状态 |
ethercat pdos |
查看从站 PDO(Process Data Object)映射 |
ethercat sdos |
查看从站 SDO(Service Data Object)字典 |
ethercat upload -p0 --type uint16 0x1018 1 |
读取从站 SDO 条目 |
ethercat xml |
导出从站信息为 XML 格式 |
ethercat graph |
输出拓扑结构(Graphviz DOT 格式) |
这些命令通过 /dev/EtherCAT0 字符设备与内核 Master 通信。如果遇到权限问题,请确保当前用户在正确的用户组中,或使用 sudo。
3.4 运行 mini 内核示例程序
examples/mini/mini.c 是一个内核模块(Kernel Module)形式的示例,演示了在内核态使用 EtherCAT 实时接口的完整流程。
核心流程
示例代码的 init_mini_module() 函数展示了标准的初始化步骤:
c
// 1. 请求 Master 实例
master = ecrt_request_master(0);
// 2. 创建过程数据域(Domain)
domain1 = ecrt_master_create_domain(master);
// 3. 获取从站配置
sc_ana_in = ecrt_master_slave_config(master, AnaInSlavePos, Beckhoff_EL3152);
// 4. 配置 PDO 映射
ecrt_slave_config_pdos(sc_ana_in, EC_END, el3152_syncs);
// 5. 注册 PDO 条目
ecrt_domain_reg_pdo_entry_list(domain1, domain1_regs);
// 6. 激活 Master
ecrt_master_activate(master);
// 7. 启动周期性任务(100 Hz 定时器)
timer_setup(&timer, cyclic_task, 0);
周期性任务 cyclic_task() 中的数据交换循环是 EtherCAT 通信的核心:
c
// 接收数据
ecrt_master_receive(master);
ecrt_domain_process(domain1);
// 写过程数据
EC_WRITE_U8(domain1_pd + off_dig_out, blink ? 0x06 : 0x09);
// 发送数据
ecrt_domain_queue(domain1);
ecrt_master_send(master);
编译与运行
bash
# 进入示例目录
cd examples/mini
# 编译(需要已安装的内核头文件和 EtherCAT 头文件)
make
# 加载模块(确保 Master 已启动)
sudo insmod ec_mini.ko
# 观察内核日志
dmesg | tail -20
# 卸载模块
sudo rmmod ec_mini
加载成功后,dmesg 中会看到类似输出:
ec_mini: Starting...
ec_mini: Registering domain...
ec_mini: Configuring PDOs...
ec_mini: Activating master...
ec_mini: Started.
ec_mini: 3 slave(s).
ec_mini: AL states: 0x08.
ec_mini: Link is up.
注意:mini 示例使用内核定时器(Timer),周期为 10ms(100Hz),精度有限。生产环境中通常使用 RTAI、Xenomai 或 PREEMPT_RT 内核配合更高精度的定时机制。
3.5 运行 user 用户空间示例程序
examples/user/main.c 演示了在用户空间(User Space)使用 EtherCAT 的方法。与内核态相比,用户态程序更容易开发和调试,是大多数应用的推荐起点。
与内核态的关键差异
用户态示例使用了 POSIX 实时调度机制代替内核定时器:
c
// 设置 FIFO 实时调度策略
struct sched_param param = {};
param.sched_priority = sched_get_priority_max(SCHED_FIFO);
sched_setscheduler(0, SCHED_FIFO, ¶m);
// 锁定内存,防止页面换出
mlockall(MCL_CURRENT | MCL_FUTURE);
// 使用 clock_nanosleep 实现 1ms 周期
#define PERIOD_NS (1000000) // 1ms
clock_nanosleep(CLOCK_MONOTONIC, TIMER_ABSTIME, &wakeup_time, NULL);
EtherCAT API 调用方式与内核态完全一致------ecrt_request_master()、ecrt_master_create_domain()、ecrt_master_activate() 等函数签名和语义不变。这是 IgH Master 设计的一大优点:同一套 API,内核态和用户态通用。
编译与运行
bash
# 编译(安装时已生成 Makefile)
cd examples/user
make
# 运行(需要 root 权限,因为要访问 /dev/EtherCAT0 和设置实时优先级)
sudo ./ec_user_example
预期输出:
Configuring PDOs...
Activating master...
Using priority 99.
Starting RT task with dt=1000000 ns.
3 slave(s).
AL states: 0x08.
Link is up.
Domain1: WC 3.
按 Ctrl+C 终止程序。用户态程序退出时会自动释放 Master,Master 回到 Idle 阶段。
用户态 vs 内核态选择建议
| 维度 | 内核态 (mini) | 用户态 (user) |
|---|---|---|
| 开发难度 | 高,需内核编程经验 | 低,标准 C 编程 |
| 调试手段 | printk / dmesg | printf / gdb |
| 实时性 | 极高(配合 RT 内核) | 高(PREEMPT_RT 内核下) |
| 稳定性风险 | bug 可能导致内核崩溃 | bug 只影响用户进程 |
| 推荐场景 | 极端实时要求 | 绝大多数工业应用 |
3.6 常见启动问题排查
初次运行时,以下问题出现频率最高。我们逐一解析。
问题 1:No network cards for EtherCAT specified
原因 :ethercat.conf 中 MASTER0_DEVICE 为空。
解决:填写正确的网卡 MAC 地址或接口名。
bash
# 查看可用网卡
ip link show
问题 2:Master 一直卡在 waiting for devices
原因 :ec_master 已加载,但没有网卡驱动向它注册设备。
排查步骤:
- 检查
DEVICE_MODULES是否设置且模块已编译 - 确认
ec_generic(或对应驱动)已加载:lsmod | grep ec_ - 使用 generic 驱动时,确认网卡接口已 UP
问题 3:Master already in use!
原因:已有程序(如 mini 模块)占用了 Master。每个 Master 实例同一时间只能被一个应用请求。
解决:先卸载或终止占用程序,再运行新程序。
问题 4:Failed to enter OPERATION phase
原因:网卡驱动未正确绑定,或网线未连接。
排查:
bash
# 检查内核日志
dmesg | grep -i ethercat
# 确认物理连接
ethtool eth0 | grep "Link detected"
问题 5:权限不足,无法访问 /dev/EtherCAT0
原因:用户态程序需要对字符设备的读写权限。
解决:
bash
# 临时方案
sudo chmod 666 /dev/EtherCAT0
# 永久方案:添加 udev 规则
echo 'KERNEL=="EtherCAT[0-9]*", MODE="0666"' | \
sudo tee /etc/udev/rules.d/99-ethercat.rules
问题 6:所有帧超时(Timeout)
原因:使用 generic 驱动时,网卡接口未激活。
解决 :在 ethercat.conf 中设置 UPDOWN_INTERFACES,或手动执行 ip link set dev eth0 up。
3.7 小结
本章我们完成了 EtherCAT Master 的首次运行全流程:
- 配置 :
ethercat.conf中的三个核心变量(MASTER0_DEVICE、DEVICE_MODULES、UPDOWN_INTERFACES)决定了 Master 的基本行为 - 启动 :通过 systemd 服务或手动 modprobe 加载
ec_master和网卡驱动模块 - 探索 :
ethercat命令行工具可以查看 Master 状态、扫描从站、读写 SDO - 内核态示例 :mini 模块展示了
ecrt_request_master()→ecrt_master_activate()→ 周期任务的标准流程 - 用户态示例:user 程序使用相同的 API,配合 POSIX 实时调度实现毫秒级周期控制
- 排查:大多数启动问题源于配置遗漏或驱动未正确加载
如果你能看到 ethercat slaves 输出从站列表,并且示例程序正常打印状态信息,恭喜你------EtherCAT 总线已经跑通了。
下一章预告:第 4 章将深入讲解网络设备驱动的选型与配置,帮助你在 Generic 通用驱动和各种 Native 原生驱动之间做出正确选择,并掌握驱动的配置方法。