3. EtherCAT#

EtherCAT(Ethernet Control Automation Technology)是一种高性能实时以太网通信协议,用于在工业自动化领域中进行实时控制和通信。

IgH EtherCAT是运⾏于Linux系统的开源EtherCAT主站程序,IgH EtherCAT主站通过构建Linux字符设备, 应⽤程序通过对字符设备的访问实现与EtherCAT主站模块的通信。

IgH EtherCAT开发包配套EtherCAT⼯具,该⼯具提供各种可在Linux⽤户层运⾏的命令,可直接实现对从站的访问和设置, 如设置从站地址、显⽰总线配置、显⽰PDO数据、读写SDO参数等。

LubanCat板卡使用IgH EtherCAT可作为EtherCAT主站使用。目前已对使用rk3588、rk3588s、rk3576的LubanCat板卡做了适配验证。

备注

仅支持Linux kernel-6.1版本的LubanCat SDK和系统镜像

3.1. 运行环境组件编译#

EtherCAT整体分为四个部分,分别是内核,驱动,用户态还有EtherCAT应⽤。以下将从这四部分对EtherCat主站环境的搭建做说明。

EtherCat环境的适配需要编译Linux内核和EtherCAT-IgH源码,为了便于操作,可以借助板卡配套SDK进行编译。 所以在进行EtherCat环境适配编译之前,需要先从网盘配套资料中下载 LubanCat_Linux_Gen_Full_SDK 并搭建SDK编译环境。 有关SDK编译环境搭建的详细说明见文档: 《 嵌入式Linux镜像构建与部署 -> LubanCat_Gen_SDK 》

3.1.1. 修改内核并编译#

EtherCAT IgH需要保证⾼实时性,因此使用Linux-RT实时内核。我们已经为LubanCat板卡适配好了实时内核, 以下内容仅对实时内核的修改编译和安装做说明,有关实时内核的详细信息,请参考 RT-Linux 章节。

在Linux-RT实时内核的基础上,还需要进行一些修改来进一步适配EtherCAT功能并优化。

Linux内核源码仓库地址为:https://github.com/LubanCat/kernel

rk3576和rk3588对应的实时内核分支为:lbc-develop-6.1-rt36

可在SDK根目录执行以下命令,将普通Linux内核源码替换为Linux-RT内核源码并打上EtherCat补丁:

 1#删除旧内核源码
 2rm -rf kernel-6.1/
 3
 4#拉取新内核源码并保存到kernel-6.1目录,只拉取最新一次提交,指定lbc-develop-6.1-rt36分支
 5git clone --depth=1 -b lbc-develop-6.1-rt36 https://github.com/LubanCat/kernel.git kernel-6.1
 6
 7# 进入内核源码目录
 8cd kernel-6.1
 9
10# 打EtherCat补丁,根据内核版本优先使用linux-6.1.99-rt36-9版本
11git am ../external/ethercat_igh/0001-add-support-ethercat-for-lubancat-linux-6.1.99-rt36-9.patch
12
13# 如果打补丁失败,回退打补丁操作
14git am --abort
15
16# 打EtherCat旧版补丁linux-6.1.99-rt36-9版本
17git am ../external/ethercat_igh/0001-add-support-ethercat-for-lubancat-linux-6.1.99-rt36-7.patch

补丁文件存放在SDK的ethercat_igh/0001-add-support-ethercat-for-lubancat-linux-6.1.99-rt36-x.patch。 这里存放了两个补丁文件,因为内核有部分文件名称有变更,适配不同的版本。

以下是对补丁文件内容的说明, 节选部分内容,以LubanCat-3IO为例,其他板卡类似的部份不再单独说明,实际补丁内容以补丁文件中的为准

 1diff --git a/arch/arm64/boot/dts/rockchip/rk3576-linux.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-linux.dtsi
 2index 37b76f2e3cf62..069586ee2e5b3 100644
 3--- a/arch/arm64/boot/dts/rockchip/rk3576-linux.dtsi
 4+++ b/arch/arm64/boot/dts/rockchip/rk3576-linux.dtsi
 5@@ -12,7 +12,7 @@ aliases {
 6    };
 7
 8    chosen: chosen {
 9# 更新启动参数,隔离cpu7资源给EtherCat单独使用
10-           bootargs = "earlycon=uart8250,mmio32,0x2ad40000 console=ttyFIQ0 root=PARTUUID=614e0000-0000 rw rootwait rcupdate.rcu_expedited=1 rcu_nocbs=all";
11+           bootargs = "earlycon=uart8250,mmio32,0x2ad40000 console=ttyFIQ0 root=PARTUUID=614e0000-0000 isolcpus=7 nohz_full=7 rcu_nocbs=7 rw rootwait rcupdate.rcu_expedited=1";
12    };
13
14    fiq_debugger: fiq-debugger {
15diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
16index 9dd309efd801a..1ccc1a45f561f 100644
17--- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi
18+++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
19@@ -295,7 +295,7 @@ cpu_l0: cpu@0 {
20            operating-points-v2 = <&cluster0_opp_table>;
21            #cooling-cells = <2>;
22            dynamic-power-coefficient = <120>;
23# 关闭CPU休眠,所有核心都要修改
24-                   cpu-idle-states = <&CPU_SLEEP>;
25+                   // cpu-idle-states = <&CPU_SLEEP>;
26        };
27
28@@ -4402,7 +4402,7 @@ pcie1_intc: legacy-interrupt-controller {
29    };
30
31    gmac0: ethernet@2a220000 {
32# 使用ethercat专用的网口驱动
33-           compatible = "rockchip,rk3576-gmac", "snps,dwmac-4.20a";
34+           compatible = "rockchip,rk3576-gmac-ethercat", "snps,dwmac-4.20a";
35        reg = <0x0 0x2a220000 0x0 0x10000>;
36        interrupts = <GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>,
37                <GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>;
38@@ -4441,13 +4441,15 @@ gmac0_stmmac_axi_setup: stmmac-axi-config {
39        };
40
41        gmac0_mtl_rx_setup: rx-queues-config {
42# 支持TSN功能
43-                   snps,rx-queues-to-use = <1>;
44+                   snps,rx-queues-to-use = <2>;
45            queue0 {};
46+                   queue1 {};
47        };
48
49        gmac0_mtl_tx_setup: tx-queues-config {
50# 支持TSN功能
51-                   snps,tx-queues-to-use = <1>;
52+                   snps,tx-queues-to-use = <2>;
53            queue0 {};
54+                   queue1 {};
55        };
56    };
57
58diff --git a/arch/arm64/boot/dts/rockchip/uEnv/rk3576/uEnvLubanCat3IO.txt b/arch/arm64/boot/dts/rockchip/uEnv/rk3576/uEnvLubanCat3IO.txt
59index 864a95f909703..13fe62ea125b7 100644
60--- a/arch/arm64/boot/dts/rockchip/uEnv/rk3576/uEnvLubanCat3IO.txt
61+++ b/arch/arm64/boot/dts/rockchip/uEnv/rk3576/uEnvLubanCat3IO.txt
62@@ -1,6 +1,6 @@
63uname_r=
64size=0x1000000
65# 更新启动参数,隔离cpu7资源给EtherCat单独使用
66-cmdline="earlyprintk console=ttyFIQ0 console=tty1 consoleblank=0 loglevel=7 rootwait rw rootfstype=ext4"
67+cmdline="earlyprintk console=ttyFIQ0 consoleblank=0 loglevel=7 rootwait rw rootfstype=ext4 isolcpus=7 nohz_full=7 rcu_nocbs=7"
68
69enable_uboot_overlays=1
70#overlay_start

修改完成后,在SDK的顶层目录执行下面的命令编译生成内核deb更新包,方便后续使用

1#编译内核deb包
2./build.sh kerneldeb

编译出来的linux-headers-6.1.99-rt36-rk3576和linux-image-6.1.99-rt36-rk3576内核deb包传到板卡备用

3.1.2. 用户态文件和驱动编译#

用户态主要是两个⽂件,ethercat和libethercat.so,⼀个是EtherCAT IgH的调试⼯具,⼀个是EtherCAT IgH的动态库,⽤来提供⽤户层接口。

驱动部分主要是ec_master.ko和⼀些RK优化后的ko。ec_master.ko是⼀个Linux内核模块,⽤于⽀持EtherCAT主站的功能, 这个模块负责管理EtherCAT总线上的通信,实现主站与从站之间的数据交换和同步。ec_stmmac.ko是RK优化过实时性的网口驱动。

EtherCAT IgH的源码保存在SDK的external/ethercat_igh目录下,此源码根据开源项目修改优化得来,可以直接编译使用。

在使用下面的命令时需要注意,/home/dev/LubanCat_Linux_SDK是SDK目录的绝对路径,要在使用时替换为用户SDK的实际路径。 如果不确定,可以使用cd命令进入SDK顶层目录,使用pwd命令获取当前目录的绝对路径。

 1# 进入ethercat_igh目录
 2cd external/ethercat_igh
 3
 4# 导出编译器路径到环境变量
 5export PATH=/home/dev/LubanCat_Linux_SDK/prebuilts/gcc/linux-x86/aarch64/gcc-arm-10.3-2021.07-x86_64-aarch64-none-linux-gnu/bin:$PATH
 6
 7# 初始化构建环境
 8./bootstrap
 9./configure --prefix=/home/dev/LubanCat_Linux_SDK/external/ethercat_igh/output --host=aarch64-none-linux-gnu --with-linux-dir=/home/dev/LubanCat_Linux_SDK/kernel-6.1 --enable-8139too=no --enable-stmmac=yes --enable-generic=no --enable-wildcards=yes
10
11# 编译
12make -j8
13
14# 将编译生成的内容安装到output目录
15make install systemdsystemunitdir=/home/dev/LubanCat_Linux_SDK/external/ethercat_igh/output
16
17# 编译内核外部模块
18make modules ARCH=arm64 CROSS_COMPILE=aarch64-none-linux-gnu- -C /home/dev/LubanCat_Linux_SDK/kernel-6.1 M=$PWD -j32

编译生成的用户态文件保存在ethercat_igh的output目录下,生成的ko模块文件保存在master/ec_master.ko和devices/stmmac/ec_stmmac.ko

将output目录和ec_master.ko、ec_stmmac.ko传输到板卡中备用。

3.1.3. EtherCat应用编译#

EtherCAT IgH应⽤需要根据具体的伺服器来编写,demo目录下的ec_master_test_CD02.c是一个用于测试LubanCat板卡连接 SERVOTRONIX-CDHD2S 伺服驱动器EtherCat性能的示例程序, 在external/ethercat_igh/demo目录下调用./build.sh脚本编译,得到ec_master_test_CD02可执行文件,此测试程序可以用于rk3588板卡和rk3576板卡。

将ec_master_test_RK3588_CD02传输到板卡备用

3.2. 板卡运行环境搭建#

板卡运行环境推荐使用debian12 lite版本,无桌面版本占用资源少,实时性更高。

3.2.1. 获取网卡MAC地址#

启动板卡,此时板卡还没有安装实时内核更新包,由于后面会用到网卡的MAC地址,此时需要记录一下。 如果是多网口,此时建议把所有网口的MAC地址都记录一下,有时候设备树里的网口顺序会和系统里的网口顺序不一致, 后面搭建好环境就看不到网卡MAC地址了,记错了会很麻烦。

 1ifconfig
 2
 3eth0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
 4        ether 1a:04:65:66:d0:a0  txqueuelen 1000  (Ethernet)
 5        RX packets 0  bytes 0 (0.0 B)
 6        RX errors 0  dropped 0  overruns 0  frame 0
 7        TX packets 564  bytes 94196 (91.9 KiB)
 8        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
 9        device interrupt 57
10
11eth1: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
12        ether 1e:04:65:66:d0:a0  txqueuelen 1000  (Ethernet)
13        RX packets 645  bytes 58599 (57.2 KiB)
14        RX errors 0  dropped 0  overruns 0  frame 0
15        TX packets 725  bytes 65614 (64.0 KiB)
16        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
17        device interrupt 59

两个网口的MAC地址分别是1a:04:65:66:d0:a0和1e:04:65:66:d0:a0

3.2.2. 配置用户态环境#

进入传输到板卡中的output目录,将传输到板卡中的用户态文件复制到系统目录中

1# 进入output目录
2cd output/
3
4# 复制库和可执行程序
5cp -fv lib/libethercat.* /usr/lib/
6cp -fv bin/ethercat /usr/bin/

3.2.3. 安装实时内核#

进入板卡上存放内核更新包的位置,运行下面的命令将修改后的实时内核更新到板卡

1# 卸载旧内核
2apt remove linux-headers-6.1.99-rk3576 linux-image-6.1.99-rk3576
3
4# 安装实时内核和内核头文件
5dpkg -i linux-image-6.1.99-rt36-rk3576_*_arm64.deb
6dpkg -i linux-headers-6.1.99-rt36-rk3576_*_arm64.deb
7
8# 重启
9reboot

安装完成后重启板卡,实时内核就会生效

3.2.4. 加载内核模块#

ec_master和ec_stmmac是使用ethercat_igh编译的内核模块,需要手动加载。

main_devices=后面是EtherCAT网口对应的mac地址,根据前面的步骤记录, 我们记录了两个网卡的MAC地址,现在将两个网口中的其中一个作为EtherCat使用,并在设备树中设置修改为使用专用驱动。

使用ifconfig查看网络接口,此时只有eth0,排除eth0网卡的MAC地址,另一个MAC地址就是要设置为EtherCat的网卡地址。

1ifconfig
2
3eth0: flags=4099<UP,BROADCAST,MULTICAST>  mtu 1500
4        ether 1e:04:65:66:d0:a0  txqueuelen 1000  (Ethernet)
5        RX packets 134  bytes 13288 (12.9 KiB)
6        RX errors 0  dropped 0  overruns 0  frame 0
7        TX packets 159  bytes 14002 (13.6 KiB)
8        TX errors 0  dropped 0 overruns 0  carrier 0  collisions 0
9        device interrupt 96

一定要添加并确认地址正确

1insmod ec_master.ko main_devices=1a:04:65:66:d0:a0
2insmod ec_stmmac.ko

3.2.5. 简单测试#

 1# 主站状态
 2ethercat master
 3
 4# 输出识别到的从站
 5ethercat slaves
 6
 7#如果通讯成功,就会显⽰出识别到的从站位置信息,别名和型号,如下:
 80 0(别名):0(位置) PREOP  +  CD02 EtherCAT Drive (CoE)
 9
10#输出pdo信息,这些pdo信息只是默认的,具体要根据需求,参考伺服驱动器⼿册来编写
11ethercat pdos
12
13#以c语⾔的形式输出pdo信息
14ethercat cstruct

3.2.6. 板卡性能优化#

 1# 调整soc为性能模式,cpu时钟运行在最高频率
 2echo performance | tee $(find /sys/ -name *governor)
 3
 4# 关闭网络时间同步功能,防止与TSN争抢系统时钟
 5# 关闭ntp同步时间(debian)
 6systemctl stop ntpsec
 7systemctl disable ntpsec
 8
 9# 关闭chrony时间同步(buildroot)
10killall chronyd
11ls /etc/init.d/S*chronyd | xargs rm
12
13# 开启TSN与系统时钟同步
14# 查看EtherCat网口对应的ptp设备
15ls -l /sys/class/ptp
16
17# 同步系统时间和gmac ptp时间
18apt install linuxptp
19phc2sys -s /dev/ptp1 -c CLOCK_REALTIME -O 0 &

3.3. 性能测试#

运行demo测试示例,可以测试EtherCat主站与从站通信时的周期抖动和调度延迟。

用网线连接LubanCat板卡的EtherCAT口和伺服驱动器的EtherCAT输入接口,此处连接 SERVOTRONIX-CDHD2S 伺服驱动器。 由于EtherCat从站配置有差异,需要单独适配示例程序,此处以编译好的ec_master_test_CD02为例,在板卡上运行。

1# 绑定CPU核心为资源隔离的核心运行示例程序
2# -c 指定绑定的核心
3./ec_master_test_CD02 -c 7

3.3.1. 测试结果和说明#

测试程序运行时,当出现一个周期抖动值时,打印输出周期时间和抖动值,并记录此时的值作为当前最大值。 每个测试周期进行300000次测试循环,在一个测试周期中,每当出现新的最大抖动值都将打印输出,也就是打印信息输出了当前测试周期的最大最大周期抖动。

以下测试结果选取10个连续的测试周期,统计这10个测试周期中的最小周期时间、最大周期时间和最大周期抖动值。

3.3.1.1. RK3588(LubanCat-5IO)测试结果#

设定周期时间

最小周期时间

最大周期时间

最大周期抖动

1000μs

996042ns

1004792ns

4.8μs

500μs

495250ns

505167ns

5.2μs

125μs

122792ns

128042ns

3.0μs

3.3.1.2. RK3576(LubanCat-3IO)测试结果#

设定周期时间

最小周期时间

最大周期时间

最大周期抖动

1000μs

986315ns

1012564ns

13.7μs

500μs

489696ns

509304ns

10.3μs

125μs

117189ns

134740ns

9.7μs