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
22
23
24
 | cd ethercat-stable-1.5/
# to create the configure script, if downloaded from the repo
./bootstrap
# 这里需要注意是否出现报错,需要安装 autoconf、libtool、pkg-config 等工具
# 执行configure
# `--host` 指定程序运行的主机架构
# `--with-linux-dir` Linux内核源码
# `--with-devices` 冗余接口需要 > 1
# `--enable-hrtimer` 使用高分辨率定时器让主状态机在发送帧之间休眠
# `--enable-wildcards` 允许使用0xffffff作为供应商ID和产品代码的通配符
# 如果是安装的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 devices/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
 | 
做好上面的准备工作,还需要修改源码中的路径配置,然后才能正常编译。
下面都是我踩坑留下的记录。
- 修改 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
 | 
- 修改 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
 | 
- 修改 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
 | 
- 修改源码
由于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;
}
 | 
目前只发现了这个问题,希望后面没有坑了。
修改scanner.c,不再引用liberror.h,这样就不需要修改IgH 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
 | #include "unpack.h"
#include "simulation.h"
#include "version.h"
- #include "liberror.h"
@@ -290,8 +297,6 @@ void cyclic_task(void * usr)
        nslaves++;
    }
-    /* suppress errors to stderr */
-    ecrt_err_to_stderr = 0;
    while(1)
    {
        rtMessageQueueReceive(scanner->workq, msg, scanner->max_message);
@@ -500,7 +505,7 @@ void cyclic_task(void * usr)
            {
                if (error_to_console)
                {
-                    fprintf(stderr,"etherlab library error: %s", ecrt_errstring);
+                    fprintf(stderr,"etherlab library error: %d", slave_info_status);
                    error_to_console = FALSE;
                }
            }
 | 
- 编译
最后终于可以开始编译了。
| 1
2
3
 | cd ethercat-master/
# 执行交叉编译
make LD=loongarch64-linux-gnu-ld CC=loongarch64-linux-gnu-gcc CCC=loongarch64-linux-gnu-g++
 | 
到这里,编译过程还可能会出错,不过已经可以编译出我们所需要的东西了。
最终编译得到scanner、slaveinfo程序就可以了。
以下是我编译时的输出:
|  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.ko和ec_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#