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 |