前言

IgH EtherCAT Master 是一个开源的EtherCAT主站驱动程序,用于管理EtherCAT从站设备,支持Linux操作系统,工控上使用的比较多。

dls ethercat是由英国钻石光源开发的用于 EPICS 控制系统 EtherCAT 设备的支持程序,基于 IgH Master 主站程序开发,实现对 EtherCAT 总线设备的读写。

交叉编译环境:Ubuntu

运行开发板:龙芯2K0500金龙开发板

内核版本:Linux LS-GD 5.10.0-rt17.lsgd #1 PREEMPT_RT

相关软件包下载地址

配置交叉编译环境

关于这一节,之前的文章已经详细讲过,参考配置交叉编译环境

如果你使用的是其他开发套件,请按照开发手册安装配置好环境。

编译 IgH EtherCAT Master

源码一定要下载 stable-1.5 分支的,其他版本我也没有测试!

打补丁

1
2
3
4
5
6
7
# 先将补丁复制到ethercat驱动源码下
cp ethercat-master/etc/makeDocumentation/configurable-error-suppression.patch ethercat-stable-1.5/

cd ethercat-stable-1.5/
# 打补丁
patch -p1 < configurable-error-suppression.patch
# 这里需要注意一下patch的输出结果

由于补丁的时间比较早,跟现有的源码不太匹配,有些地方补丁会失败(FAILED)。比如我这里的报错,可能需要再手动修改一下。

 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
patching file lib/Makefile.am
Hunk #1 succeeded at 32 (offset -2 lines).
patching file lib/common.c
patching file lib/domain.c
patching file lib/liberror-documentation.txt
patching file lib/liberror.c
patching file lib/liberror.h
patching file lib/master.c
Hunk #1 succeeded at 37 (offset -2 lines).
...
Hunk #12 FAILED at 419.
Hunk #13 FAILED at 448.
...
2 out of 31 hunks FAILED -- saving rejects to file lib/master.c.rej
patching file lib/reg_request.c
Hunk #1 succeeded at 39 (offset -2 lines).
...
patching file lib/sdo_request.c
Hunk #1 succeeded at 39 (offset -2 lines).
...
patching file lib/slave_config.c
Hunk #1 succeeded at 39 (offset -1 lines).
...
patching file lib/voe_handler.c
Hunk #1 succeeded at 40 (offset -2 lines).
...

我们参考lib/master.c.rej,手动修改一下。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
# lib/master.c.rej
--- lib/master.c	Tue Feb 12 17:31:08 2013 +0100
+++ lib/master.c	Mon Mar 23 15:52:53 2015 +0000
@@ -419,7 +431,8 @@
         if (EC_IOCTL_ERRNO(ret) == EIO && abort_code) {
             *abort_code = download.abort_code;
         }
-        fprintf(stderr, "Failed to execute SDO download: %s\n",
+        ecrt_errcode = ECRT_ERRMASTERSDODOWNLOAD;
+        ERRPRINTF("Failed to execute SDO download: %s\n",
             strerror(EC_IOCTL_ERRNO(ret)));
         return -EC_IOCTL_ERRNO(ret);
     }
@@ -448,7 +461,8 @@
         if (EC_IOCTL_ERRNO(ret) == EIO && abort_code) {
             *abort_code = download.abort_code;
         }
-        fprintf(stderr, "Failed to execute SDO download: %s\n",
+        ecrt_errcode = ECRT_ERRMASTERSDODOWNLOADCOMPLETE;
+        ERRPRINTF("Failed to execute SDO download: %s\n",
             strerror(EC_IOCTL_ERRNO(ret)));
         return -EC_IOCTL_ERRNO(ret);
     }

然后这个补丁还有点问题,我们需要手动修改一下lib/liberror.c。这里源文件和头文件变量定义不一致,编译会报错,以头文件为准。

1
2
3
4
5
6
7
#include "liberror.h"

int ecrt_err_to_stderr = 1;
// char *ecrt_errstring[ERRSTRING_LEN];
char ecrt_errstring[ERRSTRING_LEN];

int ecrt_errcode;

准备内核源码

由于需要将源码编译成相应的系统驱动,所以这里需要使用内核的源码。

如果是标准系统,可以直接安装linux-headers

1
2
# Ubuntu/Debian
sudo apt install linux-headers-$(uname -r)

树莓派系统

1
sudo apt install raspberrypi-kernel-headers

而对于开发板系统,我们可以使用随开发板提供的内核源码。

内核的编译步骤请根据开发板的用户手册完成。

最好再给内核打上 PREEMPT_RT 补丁。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
# 解压内核源码
tar -xvf linux-5.10-2k500-src-f45937d-build.20230721100738.tar.gz
# linux-5.10-2k500-cbd-src
cd linux-5.10-2k500-cbd-src/

# 为内核打上实时补丁(可选)
patch -p1 < patch-5.10-rt17.patch

# 配置交叉编译器
./set_env.sh

# 编译内核
make loongson_2k500_defconfig
# make menuconfig
make uImage

# 编译模块
make modules

编译 EtherCAT Master 驱动

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
cd ethercat-stable-1.5/
# to create the configure script, if downloaded from the repo
./bootstrap
# 这里需要注意是否出现报错,需要安装 autoconf、pkg-config 等工具

# 执行configure
# --host 指定程序运行的主机架构
# --with-linux-dir 指定源码目录
# 如果是安装的linux-headers,通常在 /usr/src/linux-headers-xxx
# 如果直接使用内核源码,则必须通过上述编译步骤!
# --prefix 指定安装目录
./configure --host=loongarch64-linux-gnu CC=loongarch64-linux-gnu-gcc --enable-generic=yes --enable-8139too=no --with-linux-dir=/path/to/linux-5.10-2k500-cbd-src --prefix=/path/to/__install_dir

# 编译
make all modules
# 或者
# make
# make ARCH=loongarch CORSS_COMPILE=loongarch64-linux-gnu- modules

# 安装生成的文件
# make install

如果完全按照上述步骤,应该可以编译成功。

下面整理一下生成的文件。

1
2
3
4
5
# 复制生成的主程序
cp tool/ethercat /path/to/__install_dir/bin/
# 复制生成的驱动程序
cp device/ec_generic.ko /path/to/__install_dir/modules/
cp master/ec_master.ko /path/to/__install_dir/modules/

这是我整理的文件,后面需要将这些文件下载到开发板。

__install_dir
├─ bin
│   └─ ethercat (主程序)
├─ etc (配置)
├─ include (头文件)
├─ lib (libethercat.so)
├─ modules (驱动目录)
│   ├─ ec_master.ko
│   └─ ec_generic.ko
├─ sbin
│   └─ ethercatctl
└─ share
    └─ bash-completion/ (bash自动补全)

编译 EPICS ethercat 模块

以下步骤需要先安装好EPICS Base!

编译 asyn

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
cd asyn
touch configure/RELEASE.local
vi configure/RELEASE.local

# 修改成和EPICS Base一样的架构
EPICS_HOST_ARCH=linux-loong64
# EPICS Base路径(示例)
EPICS_BASE=/home/ubuntu/loongson/base-7.0.8
# 放置EPICS模块的路径(示例)
SUPPORT=/home/ubuntu/loongson/modules
# SSCAN模块路径
# SSCAN=$(SUPPORT)/sscan
# CALC模块路径
# CALC=$(SUPPORT)/calc

# 直接编译
# make
# 交叉编译(示例)
make LD=loongarch64-linux-gnu-ld CC=loongarch64-linux-gnu-gcc CCC=loongarch64-linux-gnu-g++

编译 autosave

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
cd autosave
touch configure/RELEASE.local
vi configure/RELEASE.local

# 修改成和EPICS Base一样的架构
EPICS_HOST_ARCH=linux-loong64
# EPICS Base路径(示例)
EPICS_BASE=/home/ubuntu/loongson/base-7.0.8
# 放置EPICS模块的路径(示例)
SUPPORT=/home/ubuntu/loongson/modules

# 直接编译
# make
# 交叉编译(示例)
make LD=loongarch64-linux-gnu-ld CC=loongarch64-linux-gnu-gcc CCC=loongarch64-linux-gnu-g++

编译 busy

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
cd busy
touch configure/RELEASE.local
vi configure/RELEASE.local

# 修改成和EPICS Base一样的架构
EPICS_HOST_ARCH=linux-loong64
# EPICS Base路径(示例)
EPICS_BASE=/home/ubuntu/loongson/base-7.0.8
# 放置EPICS模块的路径(示例)
SUPPORT=/home/ubuntu/loongson/modules
# ASYN模块路径
ASYN=$(SUPPORT)/asyn
# AUTOSAVE模块路径
AUTOSAVE=$(SUPPORT)/autosave
# BUSY模块路径
BUSY=$(SUPPORT)/busy

# 直接编译
# make
# 交叉编译(示例)
make LD=loongarch64-linux-gnu-ld CC=loongarch64-linux-gnu-gcc CCC=loongarch64-linux-gnu-g++

编译 ethercat

这一步可以说是最麻烦,问题最多的。编译出什么问题都需要去找到相应的Makefile修改。

由于该软件包已经长时间无人维护,建议使用我修改过的版本

首先需要安装所需的包libxml2-dev。但我们实际上并不需要用这个软件包,我们只需要它的头文件。

软件依赖的动态库(.so)文件,我们则需要从开发板系统中拷贝出来,无法直接用编译电脑的动态库。

 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
cd ethercat-master/

# 创建 3rd 目录,用于放置所需的头文件和动态库
mkdir 3rd
mkdir 3rd/include
mkdir 3rd/lib

# 安装 libxml2-dev
sudo apt install libxml2-dev
# 从系统目录中复制出libxml2的头文件
# 因为还需要做一些修改,不能直接使用
cp -r /usr/include/libxml2/ ./3rd/include/

# 复制刚刚编译生成的 libethercat
cp /path/to/__install_dir/lib/libethercat.so* ./3rd/lib/
# 从开发板系统复制所需要的动态库
# libxml2 依赖 libz 和 liblzma
scp root@192.168.1.10:/usr/lib/libxml2.so.2.9.12 ./3rd/lib/
scp root@192.168.1.10:/usr/lib/libz.so.1.2.11 ./3rd/lib/
scp root@192.168.1.10:/usr/lib/liblzma.so.5.2.5 ./3rd/lib/
# 手动创建一下链接
cd 3rd/lib/
ln -s libxml2.so.2.9.12 libxml2.so.2
ln -s libxml2.so.2 libxml2.so
ln -s liblzma.so.5.2.5 liblzma.so.5
ln -s liblzma.so.5 liblzma.so
ln -s libz.so.1.2.11 libz.so.1
ln -s libz.so.1 libz.so

然后需要修改一下libxml2的头文件,不然编译的时候会报错。

报错信息:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
In file included from ../../../libxml2/libxml/parser.h:812,
                 from ../../../libxml2/libxml/globals.h:18,
                 from ../../../libxml2/libxml/threads.h:35,
                 from ../../../libxml2/libxml/xmlmemory.h:218,
                 from ../../../libxml2/libxml/tree.h:1307,
                 from ../parser.c:10:
../../../libxml2/libxml/encoding.h:31:10: fatal error: unicode/ucnv.h: No such file or directory
 #include <unicode/ucnv.h>
          ^~~~~~~~~~~~~~~~
compilation terminated.

解决方法:

1
2
3
4
5
6
# 修改 xmlversion.h
vi 3rd/include/libxml2/libxml/xmlversion.h

# 找到下面行,禁用 LIBXML_ICU_ENABLED
#define LIBXML_ICU_ENABLED
# 将 #if 1 改为 #if 0
1
2
3
4
5
6
7
8
9
/**
 * LIBXML_ICU_ENABLED:
 *
 * Whether icu support is available
 */
- #if 0
+ #if 1
#define LIBXML_ICU_ENABLED
#endif

做好上面的准备工作,还需要修改源码中的路径配置,然后才能正常编译。
下面都是我踩坑留下的记录。

  1. 修改 configure/RELEASE
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
cd ethercat-master/

# 首先修改 configure/RELEASE
vi configure/RELEASE

# 需要修改的有4项
# 放置EPICS模块的路径(示例)
SUPPORT=/home/ubuntu/loongson/modules
# ASYN模块路径
ASYN=$(SUPPORT)/asyn
# BUSY模块路径
BUSY=$(SUPPORT)/busy

# 修改成和EPICS Base一样的架构
EPICS_HOST_ARCH=linux-loong64
# EPICS Base路径(示例)
EPICS_BASE=/home/ubuntu/loongson/base-7.0.8
  1. 修改 ethercatApp/scannerSrc/Makefile
 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
cd ethercat-master/
# 修改 ethercatApp/scannerSrc/Makefile
vi ethercatApp/scannerSrc/Makefile

# 需要修改 EtherCAT Master 源码相关路径、
# libxml2头文件路径、动态库(.so)路径

# 修改 ETHERLAB 源码路径
ETHERLAB=/path/to/ethercat-stable-1.5
ETHERLABPREFIX=$(ETHERLAB)

USR_INCLUDES += -I$(ETHERLABPREFIX)/include

# 修改动态库路径
USR_LDFLAGS += -L$(TOP)/3rd/lib -Wl,-rpath=$(TOP)/3rd/lib
# 修改 libxml2 头文件路径
USR_INCLUDES += -I$(TOP)/3rd/include/libxml2
USR_SYS_LIBS += ethercat xml2

# 下面类似
scanner_INCLUDES += -I$(ETHERLAB)/lib

serialtool_INCLUDES += -I$(ETHERLAB)/master

get-slave-revisions_INCLUDES += -I$(ETHERLAB)/master
  1. 修改 ethercatApp/src/Makefile,与上面类似。
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
cd ethercat-master/
# 修改 ethercatApp/src/Makefile
vi ethercatApp/src/Makefile

# 需要修改 EtherCAT Master 源码相关路径、
# libxml2头文件路径、动态库(.so)路径

# 修改 ETHERLAB 源码路径
ETHERLAB=/path/to/ethercat-stable-1.5
# ecAsyn_INCLUDES += -I$(ETHERLAB)/src/ethercat-$(subst -,.,$(VERSION))/include
# gadc_INCLUDES += -I$(ETHERLAB)/src/ethercat-$(subst -,.,$(VERSION))/include
ecAsyn_INCLUDES += -I$(ETHERLAB)/include
gadc_INCLUDES += -I$(ETHERLAB)/include

# 修改 libxml2 头文件路径
USR_INCLUDES += -I$(TOP)/3rd/include/libxml2

# 添加动态库路径
USR_LDFLAGS += -L$(TOP)/3rd/lib -Wl,-rpath=$(TOP)/3rd/lib
USR_SYS_LIBS += xml2
  1. 修改源码

由于ethercat-master的源码原本是为x86_64架构编写的,编译到LoongArch架构的设备上运行可能会出现一些奇怪的错误。

例如,在运行slaveinfo时会出现Segmentation fault错误,而这通常是空指针导致内存访问出错。

原因分析:

slaveinfo在运行时会根据程序自己的路径寻找slave-types.txt文件,问题就出在这里。来看源码 ethercatApp/scannerSrc/slave-list-path.c

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
// ethercatApp/scannerSrc/slave-list-path.c

int get_root_dir_index(const char *program_name)
{
    // Search for the binary path
    char binary_dir[] = "bin/linux-x86_64/";

    // Find the binary path in the program path and return the pointer
    char *found = strstr(program_name, binary_dir);

    // Handle the case where it is not found
    if (found == NULL)
    {
        return -1;
    }
    
    // Calculate the difference in the pointers to get the index
    return found - program_name;
}

这个get_root_dir_index函数是用于计算当前程序(slaveinfo)所在的目录。这里向上查找的路径为bin/linux-x86_64,当然不能找到LoongArch的目录bin/linux-loong64了。所以,此函数只在路径为bin/linux-x86_64/slaveinfo时才能正常运行,其它情况都返回-1。(第一次见到这样写的,真无语了……)

 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
//  ethercatApp/scannerSrc/slave-list-path.c

char *get_slave_list_filename(const char *program_path)
{
    char relative_path[] = "etc/scripts/slave-types.txt";
    char *slave_list_filename = NULL;

    // Get absolute path of application
    char *real_path = calloc(PATH_MAX, sizeof(char));
    get_app_path(program_path, real_path);

    // Get root directory
    int root_dir_index = get_root_dir_index(real_path);
    if (root_dir_index != -1)
    {
        slave_list_filename = calloc(root_dir_index + strlen(relative_path) + 1, sizeof(char));
        strncpy(slave_list_filename, real_path, root_dir_index);
    }

    // Append relative path
    strcat(slave_list_filename, relative_path);

    // Check file
    struct stat fstat;
    int result = stat(slave_list_filename, &fstat);
    if (result)
    {
        printf("Could not find slave list file at %s\n", slave_list_filename);
    }

    // Cleanup
    free(real_path);

    return slave_list_filename;
}

而在get_slave_list_filename函数中,只处理了get_root_dir_index正常返回的情况。当get_root_dir_index返回-1时,slave_list_filename始终为NULL,这就导致后续操作出错。

其实这个问题直接把程序放到bin/linux-x86_64目录下运行就可以了,不过既然找到了问题,索性就改一改。

现在已经知道了出错的地方,该如何修改呢?这里我本着尽量少改动源码的原则,在get_root_dir_index查找目录出错时,直接使用当前目录。

 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
char *get_slave_list_filename(const char *program_path)
{
    char relative_path[] = "etc/scripts/slave-types.txt";
    char *slave_list_filename = NULL;

    // Get absolute path of application
    char *real_path = calloc(PATH_MAX, sizeof(char));
    get_app_path(program_path, real_path);

    // Get root directory
    int root_dir_index = get_root_dir_index(real_path);
    if (root_dir_index != -1)
    {
        slave_list_filename = calloc(root_dir_index + strlen(relative_path) + 1, sizeof(char));
        strncpy(slave_list_filename, real_path, root_dir_index);
    }
+    else
+    {
+        slave_list_filename = calloc(PATH_MAX, sizeof(char));
+        if (NULL != getcwd(slave_list_filename, PATH_MAX))
+        {
+            strcat(slave_list_filename, "/");
+        }
+    }

    // Append relative path
    strcat(slave_list_filename, relative_path);

    // Check file
    struct stat fstat;
    int result = stat(slave_list_filename, &fstat);
    if (result)
    {
        printf("Could not find slave list file at %s\n", slave_list_filename);
    }

    // Cleanup
    free(real_path);

    return slave_list_filename;
}

目前只发现了这个问题,希望后面没有坑了。

  1. 编译

最后终于可以开始编译了。

1
2
3
cd ethercat-master/
# 执行交叉编译
make LD=loongarch64-linux-gnu-ld CC=loongarch64-linux-gnu-gcc CCC=loongarch64-linux-gnu-g++

到这里,编译过程还可能会出错,不过已经可以编译出我们所需要的东西了。
最终编译得到scannerslaveinfo程序就可以了。

以下是我编译时的输出:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
...
Installing library ../../../lib/linux-loong64/libscannerlib.a
...
Installing created executable ../../../bin/linux-loong64/serialtool
Installing created executable ../../../bin/linux-loong64/get-slave-revisions
Installing created executable ../../../bin/linux-loong64/scanner
Installing created executable ../../../bin/linux-loong64/slaveinfo
Installing created executable ../../../bin/linux-loong64/parsertest
...
Installing shared library ../../../lib/linux-loong64/libecAsyn.so
Installing library ../../../lib/linux-loong64/libecAsyn.a
Installing created executable ../../../bin/linux-loong64/parsertest
...
Installing template file ../../../db/EK1100.template
...
make -C ./protocol install
make[2]: 进入目录“/home/deepin/ethercat-master/ethercatApp/protocol”
make[2]: *** 没有规则可制作目标“install”。 停止。
make[2]: 离开目录“/home/deepin/ethercat-master/ethercatApp/protocol”
make[1]: *** [/usr/local/epics/base-7.0.8/configure/RULES_DIRS:85:protocol.install] 错误 2
make[1]: 离开目录“/home/deepin/ethercat-master/ethercatApp”
make: *** [/usr/local/epics/base-7.0.8/configure/RULES_DIRS:85:ethercatApp.install] 错误 2

最后的错误,我直接忽略了,因为已经得到了需要的可执行程序。

整理一下编译生成的文件:

ethercat-master
├─ bin
│   └─ linux-loong64
├─ db
├─ dbd
└─ lib
    └─ linux-loong64

测试运行

将整理好的文件下载到开发板后,我们测试运行一下。

测试安装 EtherCAT 主站驱动程序。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
[root@LS-GD modules]# modinfo ec_generic.ko
filename:       /root/__install/modules/ec_generic.ko
version:        1.5.2 unknown
license:        GPL
description:    EtherCAT master generic Ethernet device module
author:         Florian Pose <fp@igh-essen.com>
srcversion:     848BB80F1C588A2FDA42EDB
depends:        ec_master
name:           ec_generic
vermagic:       5.10.0-rt17.lsgd preempt_rt mod_unload modversions LOONGARCH 64BIT
[root@LS-GD modules]# insmod ec_master.ko
[root@LS-GD modules]# insmod ec_generic.ko
[root@LS-GD modules]# lsmod
Module                  Size  Used by
ec_generic              6427  0
ec_master             464125  1 ec_generic

测试ethercat主程序。

 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
[root@LS-GD tool]# ./ethercat
Please specify a command!

Usage: ethercat <COMMAND> [OPTIONS] [ARGUMENTS]

Commands (can be abbreviated):
  alias      Write alias addresses.
  config     Show slave configurations.
  crc        CRC error register diagnosis.
  cstruct    Generate slave PDO information in C language.
  data       Output binary domain process data.
  debug      Set the master's debug level.
  domains    Show configured domains.
  download   Write an SDO entry to a slave.
  eoe        Display Ethernet over EtherCAT statictics.
  foe_read   Read a file from a slave via FoE.
  foe_write  Store a file on a slave via FoE.
  graph      Output the bus topology as a graph.
  master     Show master and Ethernet device information.
  pdos       List Sync managers, PDO assignment and mapping.
  reg_read   Output a slave's register contents.
  reg_write  Write data to a slave's registers.
  rescan     Rescan the bus.
  sdos       List SDO dictionaries.
  sii_read   Output a slave's SII contents.
  sii_write  Write SII contents to a slave.
  slaves     Display slaves on the bus.
  soe_read   Read an SoE IDN from a slave.
  soe_write  Write an SoE IDN to a slave.
  states     Request application-layer states.
  upload     Read an SDO entry from a slave.
  version    Show version information.
  xml        Generate slave information XML.

Global options:
  --master  -m <master>  Comma separated list of masters
                         to select, ranges are allowed.
                         Examples: '1,3', '5-7,9', '-3'.
                         Default: '-' (all).
  --force   -f           Force a command.
  --quiet   -q           Output less information.
  --verbose -v           Output more information.
  --help    -h           Show this help.

Numerical values can be specified either with decimal (no
prefix), octal (prefix '0') or hexadecimal (prefix '0x') base.

Call 'ethercat <COMMAND> --help' for command-specific help.

Send bug reports to fp@igh.de.

测试scanner主程序。

1
2
3
[root@LS-GD linux-loong64]# chmod +x scanner
[root@LS-GD linux-loong64]# ./scanner
usage: scanner [-m master_index] [-s] [-q] scanner.xml socket_path

可以看到,驱动程序和主程序都能在开发板上运行,说明已经编译完成了。

安装 EtherCAT 主站到开发板系统

首先将编译好的EtherCAT Master下载到开发板系统,然后将各个目录下的文件放到相应的系统目录下。(这里我还以__install_dir的目录结构为例。)

原文件/目录系统文件/目录
bin/ethercat/usr/bin/ethercat
etc/init.d/ethercat/etc/init.d/ethercat
etc/sysconfig/ethercat/etc/sysconfig/ethercat
etc/ethercat.conf/etc/ethercat.conf
include/-
lib/libethercat.so*/usr/lib/libethercat.so*
modules//lib/modules/5.10.0-rt17.lsgd/
sbin/ethercatctl/sbin/ethercatctl
share/bash-completion//usr/share/bash-completion/

注意:如果系统目录存在/lib/modules/{内核版本}目录,则可以将modules目录下的ec_master.koec_generic.ko复制到该目录下,然后在终端执行depmod命令。否则,可以按照下面的步骤做相应修改。

例如,将modules下的驱动文件放到开发板文件系统的/root/modules/目录下。

修改/etc/init.d/ethercat/sbin/ethercatctl脚本文件。

例:/etc/init.d/ethercat

 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
LSMOD=/sbin/lsmod
MODPROBE=/sbin/modprobe
+ INSMOD=/sbin/insmod
RMMOD=/sbin/rmmod
MODINFO=/sbin/modinfo
- ETHERCAT=/home/loongson/__install_dir/bin/ethercat
+ ETHERCAT=/usr/bin/ethercat
MASTER_ARGS=
+ MODULE_DIR=/root/modules

start)
    echo -n "Starting EtherCAT master 1.5.2 "

...

# load master module
- if ! ${MODPROBE} ${MODPROBE_FLAGS} ec_master "${MASTER_ARGS}" \
+ if ! ${INSMOD} ${MODULE_DIR}/ec_master.ko "${MASTER_ARGS}" \
        main_devices="${DEVICES}" backup_devices="${BACKUPS}"; then
    exit_fail
fi

# check for modules to replace
for MODULE in ${DEVICE_MODULES}; do
    ECMODULE=ec_${MODULE}
-    if ! ${MODINFO} "${ECMODULE}" > /dev/null; then
-        continue # ec_* module not found
-    fi
    if [ "${MODULE}" != "generic" ]; then
        if ${LSMOD} | grep "^${MODULE} " > /dev/null; then
            if ! ${RMMOD} "${MODULE}"; then
                exit_fail
            fi
        fi
    fi
-    if ! ${MODPROBE} ${MODPROBE_FLAGS} "${ECMODULE}"; then
+    if ! ${INSMOD} "${MODULE_DIR}/${ECMODULE}.ko"; then
        if [ "${MODULE}" != "generic" ]; then
            ${MODPROBE} ${MODPROBE_FLAGS} "${MODULE}" # try to restore
        fi
        exit_fail
    fi
done

exit_success
;;

例:/sbin/ethercatctl

 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
LSMOD=/sbin/lsmod
MODPROBE=/sbin/modprobe
+ INSMOD=/sbin/insmod
RMMOD=/sbin/rmmod
MODINFO=/sbin/modinfo
IP=/bin/ip

- ETHERCAT=/home/loongson/__install_dir/bin/ethercat
+ ETHERCAT=/usr/bin/ethercat
+ MODULE_DIR=/root/modules

#------------------------------------------------------------------------------

- ETHERCAT_CONFIG=/home/loongson/__install_dir/etc/ethercat.conf
+ ETHERCAT_CONFIG=/etc/ethercat.conf

start)

...

# load master module
- if ! ${MODPROBE} ${MODPROBE_FLAGS} ec_master \
+ if ! ${INSMOD} ${MODULE_DIR}/ec_master.ko \
        main_devices="${DEVICES}" backup_devices="${BACKUPS}"; then
    exit 1
fi

LOADED_MODULES=ec_master

# check for modules to replace
for MODULE in ${DEVICE_MODULES}; do
    ECMODULE=ec_${MODULE}
-    if ! ${MODINFO} "${ECMODULE}" > /dev/null; then
-        continue # ec_* module not found
-    fi

    if [ "${MODULE}" != "generic" ] && [ "${MODULE}" != "ccat" ]; then
        # unload standard module and check if unloading was successful
        ${RMMOD} "${MODULE}" 2> /dev/null || true
        if ${LSMOD} | grep "^${MODULE} " > /dev/null; then
            # could not unload module
            ${RMMOD} ${LOADED_MODULES}
            exit 1
        fi
    fi

-    if ! ${MODPROBE} ${MODPROBE_FLAGS} "${ECMODULE}"; then
+    if ! ${INSMOD} "${MODULE_DIR}/${ECMODULE}.ko"; then
        if [ "${MODULE}" != "generic" ] && [ "${MODULE}" != "ccat" ]; then
            ${MODPROBE} ${MODPROBE_FLAGS} "${MODULE}" # try to restore
        fi
        ${RMMOD} ${LOADED_MODULES}
        exit 1
    fi

    LOADED_MODULES="${ECMODULE} ${LOADED_MODULES}"
done

exit 0
;;

修改 EtherCAT Master 配置文件。

例:/etc/sysconfig/ethercat/etc/ethercat.conf

1
2
3
4
5
6
MASTER0_DEVICE="00:11:22:33:44:55"
#MASTER1_DEVICE=""

#MASTER0_BACKUP=""

DEVICE_MODULES="generic"

MASTER<X>_DEVICE配置网卡的物理地址(MAC),可通过ifconfig命令查看。
DEVICE_MODULES配置使用的模块名称,这里仅使用通用网卡驱动generic

运行 EtherCAT Master

  • 启动EtherCAT主站程序。

    1
    2
    3
    
    /etc/init.d/ethercat start
    # 或者
    /sbin/ethercatctl start
    

    如果一切正常,可以看到/dev目录下有EtherCAT0设备文件。

  • 查看主站信息

     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
    
    [root@LS-GD ~]# ethercat master
    Master0
    Phase: Idle
    Active: no
    Slaves: 1
    Ethernet devices:
      Main: 00:11:22:33:44:55 (attached)
        Link: UP
        Tx frames:   370862
        Tx bytes:    22319896
        Rx frames:   370861
        Rx bytes:    22319836
        Tx errors:   0
        Tx frame rate [1/s]:    125    125    125
        Tx rate [KByte/s]:      7.3    7.3    7.3
        Rx frame rate [1/s]:    125    125    125
        Rx rate [KByte/s]:      7.3    7.3    7.3
      Common:
        Tx frames:   1108336
        Tx bytes:    66704720
        Rx frames:   1108307
        Rx bytes:    66702980
        Lost frames: 29
        Tx frame rate [1/s]:    125    125    125
        Tx rate [KByte/s]:      7.3    7.3    7.3
        Rx frame rate [1/s]:    125    125    125
        Rx rate [KByte/s]:      7.3    7.3    7.3
        Loss rate [1/s]:          0      0      0
        Frame loss [%]:         0.0    0.0    0.0
    Distributed clocks:
      Reference clock:   Slave 0
      DC reference time: 0
      Application time:  0
                         2000-01-01 00:00:00.000000000
    
  • 查看从站设备

    1
    2
    
    [root@LS-GD ~]# ethercat slaves
    0  0:0  PREOP  +  XB6-EC0002(Modules/Slots and MDP)
    
  • 生成从站信息XML文件

    1
    
    [root@LS-GD ~]# ethercat xml > scanner.xml
    
  • 其他ethercat命令

    使用ethercat -h命令查看其他命令的使用方法。

参考