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 2 3 4 5 6 7 8 9 10 11 | #删除旧内核源码
rm -rf kernel-6.1/
#拉取新内核源码并保存到kernel-6.1目录,只拉取最新一次提交,指定lbc-develop-6.1-rt36分支
git clone --depth=1 -b lbc-develop-6.1-rt36 https://github.com/LubanCat/kernel.git kernel-6.1
# 进入内核源码目录
cd kernel-6.1
# 打EtherCat补丁
git am ../external/ethercat_igh/0001-add-support-ethercat-for-lubancat.patch
|
补丁文件存放在SDK的external/ethercat_igh/0001-add-support-ethercat-for-lubancat.patch。以下是对补丁文件内容的说明, 节选部分内容,以LubanCat-3IO为例,其他板卡类似的部份不再单独说明,实际补丁内容以补丁文件中的为准
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 | diff --git a/arch/arm64/boot/dts/rockchip/rk3576-linux.dtsi b/arch/arm64/boot/dts/rockchip/rk3576-linux.dtsi
index 37b76f2e3cf62..069586ee2e5b3 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576-linux.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3576-linux.dtsi
@@ -12,7 +12,7 @@ aliases {
};
chosen: chosen {
# 更新启动参数,隔离cpu7资源给EtherCat单独使用
- bootargs = "earlycon=uart8250,mmio32,0x2ad40000 console=ttyFIQ0 root=PARTUUID=614e0000-0000 rw rootwait rcupdate.rcu_expedited=1 rcu_nocbs=all";
+ 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";
};
fiq_debugger: fiq-debugger {
diff --git a/arch/arm64/boot/dts/rockchip/rk3576.dtsi b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
index 9dd309efd801a..1ccc1a45f561f 100644
--- a/arch/arm64/boot/dts/rockchip/rk3576.dtsi
+++ b/arch/arm64/boot/dts/rockchip/rk3576.dtsi
@@ -295,7 +295,7 @@ cpu_l0: cpu@0 {
operating-points-v2 = <&cluster0_opp_table>;
#cooling-cells = <2>;
dynamic-power-coefficient = <120>;
# 关闭CPU休眠,所有核心都要修改
- cpu-idle-states = <&CPU_SLEEP>;
+ // cpu-idle-states = <&CPU_SLEEP>;
};
@@ -4402,7 +4402,7 @@ pcie1_intc: legacy-interrupt-controller {
};
gmac0: ethernet@2a220000 {
# 使用ethercat专用的网口驱动
- compatible = "rockchip,rk3576-gmac", "snps,dwmac-4.20a";
+ compatible = "rockchip,rk3576-gmac-ethercat", "snps,dwmac-4.20a";
reg = <0x0 0x2a220000 0x0 0x10000>;
interrupts = <GIC_SPI 293 IRQ_TYPE_LEVEL_HIGH>,
<GIC_SPI 298 IRQ_TYPE_LEVEL_HIGH>;
@@ -4441,13 +4441,15 @@ gmac0_stmmac_axi_setup: stmmac-axi-config {
};
gmac0_mtl_rx_setup: rx-queues-config {
# 支持TSN功能
- snps,rx-queues-to-use = <1>;
+ snps,rx-queues-to-use = <2>;
queue0 {};
+ queue1 {};
};
gmac0_mtl_tx_setup: tx-queues-config {
# 支持TSN功能
- snps,tx-queues-to-use = <1>;
+ snps,tx-queues-to-use = <2>;
queue0 {};
+ queue1 {};
};
};
diff --git a/arch/arm64/boot/dts/rockchip/uEnv/rk3576/uEnvLubanCat3IO.txt b/arch/arm64/boot/dts/rockchip/uEnv/rk3576/uEnvLubanCat3IO.txt
index 864a95f909703..13fe62ea125b7 100644
--- a/arch/arm64/boot/dts/rockchip/uEnv/rk3576/uEnvLubanCat3IO.txt
+++ b/arch/arm64/boot/dts/rockchip/uEnv/rk3576/uEnvLubanCat3IO.txt
@@ -1,6 +1,6 @@
uname_r=
size=0x1000000
# 更新启动参数,隔离cpu7资源给EtherCat单独使用
-cmdline="earlyprintk console=ttyFIQ0 console=tty1 consoleblank=0 loglevel=7 rootwait rw rootfstype=ext4"
+cmdline="earlyprintk console=ttyFIQ0 consoleblank=0 loglevel=7 rootwait rw rootfstype=ext4 isolcpus=7 nohz_full=7 rcu_nocbs=7"
enable_uboot_overlays=1
#overlay_start
|
修改完成后,在SDK的顶层目录执行下面的命令编译生成内核deb更新包,方便后续使用
1 2 | #编译内核deb包
./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 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | # 进入ethercat_igh目录
cd external/ethercat_igh
# 导出编译器路径到环境变量
export 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
# 初始化构建环境
./bootstrap
./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
# 编译
make -j8
# 将编译生成的内容安装到output目录
make install systemdsystemunitdir=/home/dev/LubanCat_Linux_SDK/external/ethercat_igh/output
# 编译内核外部模块
make 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地址了,记错了会很麻烦。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | ifconfig
eth0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether 1a:04:65:66:d0:a0 txqueuelen 1000 (Ethernet)
RX packets 0 bytes 0 (0.0 B)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 564 bytes 94196 (91.9 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 57
eth1: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether 1e:04:65:66:d0:a0 txqueuelen 1000 (Ethernet)
RX packets 645 bytes 58599 (57.2 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 725 bytes 65614 (64.0 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 59
|
两个网口的MAC地址分别是1a:04:65:66:d0:a0和1e:04:65:66:d0:a0
3.2.2. 配置用户态环境¶
进入传输到板卡中的output目录,将传输到板卡中的用户态文件复制到系统目录中
1 2 3 4 5 6 | # 进入output目录
cd output/
# 复制库和可执行程序
cp -fv lib/libethercat.* /usr/lib/
cp -fv bin/ethercat /usr/bin/
|
3.2.3. 安装实时内核¶
进入板卡上存放内核更新包的位置,运行下面的命令将修改后的实时内核更新到板卡
1 2 3 4 5 6 7 8 9 | # 卸载旧内核
apt remove linux-headers-6.1.99-rk3576 linux-image-6.1.99-rk3576
# 安装实时内核和内核头文件
dpkg -i linux-image-6.1.99-rt36-rk3576_*_arm64.deb
dpkg -i linux-headers-6.1.99-rt36-rk3576_*_arm64.deb
# 重启
reboot
|
安装完成后重启板卡,实时内核就会生效
3.2.4. 加载内核模块¶
ec_master和ec_stmmac是使用ethercat_igh编译的内核模块,需要手动加载。
main_devices=后面是EtherCAT网口对应的mac地址,根据前面的步骤记录, 我们记录了两个网卡的MAC地址,现在将两个网口中的其中一个作为EtherCat使用,并在设备树中设置修改为使用专用驱动。
使用ifconfig查看网络接口,此时只有eth0,排除eth0网卡的MAC地址,另一个MAC地址就是要设置为EtherCat的网卡地址。
1 2 3 4 5 6 7 8 9 | ifconfig
eth0: flags=4099<UP,BROADCAST,MULTICAST> mtu 1500
ether 1e:04:65:66:d0:a0 txqueuelen 1000 (Ethernet)
RX packets 134 bytes 13288 (12.9 KiB)
RX errors 0 dropped 0 overruns 0 frame 0
TX packets 159 bytes 14002 (13.6 KiB)
TX errors 0 dropped 0 overruns 0 carrier 0 collisions 0
device interrupt 96
|
一定要添加并确认地址正确
1 2 | insmod ec_master.ko main_devices=1a:04:65:66:d0:a0
insmod ec_stmmac.ko
|
3.2.5. 简单测试¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 | # 主站状态
ethercat master
# 输出识别到的从站
ethercat slaves
#如果通讯成功,就会显⽰出识别到的从站位置信息,别名和型号,如下:
0 0(别名):0(位置) PREOP + CD02 EtherCAT Drive (CoE)
#输出pdo信息,这些pdo信息只是默认的,具体要根据需求,参考伺服驱动器⼿册来编写
ethercat pdos
#以c语⾔的形式输出pdo信息
ethercat cstruct
|
3.2.6. 板卡性能优化¶
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 | # 调整soc为性能模式,cpu时钟运行在最高频率
echo performance | tee $(find /sys/ -name *governor)
# 关闭网络时间同步功能,防止与TSN争抢系统时钟
# 关闭ntp同步时间(debian)
systemctl stop ntpsec
systemctl disable ntpsec
# 关闭chrony时间同步(buildroot)
killall chronyd
ls /etc/init.d/S*chronyd | xargs rm
# 开启TSN与系统时钟同步
# 查看EtherCat网口对应的ptp设备
ls -l /sys/class/ptp
# 同步系统时间和gmac ptp时间
apt install linuxptp
phc2sys -s /dev/ptp1 -c CLOCK_REALTIME -O 0 &
|
3.3. 性能测试¶
运行demo测试示例,可以测试EtherCat主站与从站通信时的周期抖动和调度延迟。
用网线连接LubanCat板卡的EtherCAT口和伺服驱动器的EtherCAT输入接口,此处连接 SERVOTRONIX-CDHD2S 伺服驱动器。 由于EtherCat从站配置有差异,需要单独适配示例程序,此处以编译好的ec_master_test_CD02为例,在板卡上运行。
1 2 3 | # 绑定CPU核心为资源隔离的核心运行示例程序
# -c 指定绑定的核心
./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 |
