需求:移植ethercat至imx6q板,使用内核版本为4.1.15
准备工作:
1.在官网 http://www.etherlab.org/en/ethercat/ 下载ethercat-1.5.2.tar.bz2。
2.准备目标arm板运行的内核源码,编译通过。
3.安装或者解压目标arm板相应的交叉编译工具。
步骤:
1.解压IGH源码进入目录
#tar xjf ethercat-1.5.2.tar.bz2
#cd ethercat-1.5.2/
#./configure --prefix=/opt/ethercat-1.5.2/ --with-linux-dir=/opt/linux/xxx/kernel_imx --enable-8139too=no --enable-generic=yes CC=arm-none-linux-gnueabi-gcc --host=arm-none-linux-gnueabi
2.编译源码
#make
错误:
/home/mm/work/project/ethercat/ethercat-1.5.2/devices/generic.c: In function 'ec_gen_device_init':
/home/mm/work/project/ethercat/ethercat-1.5.2/devices/generic.c:152:77: error: macro "alloc_netdev" requires 4 arguments, but only 3 given
dev->netdev = alloc_netdev(sizeof(ec_gen_device_t *), &null, ether_setup);
^
/home/mm/work/project/ethercat/ethercat-1.5.2/devices/generic.c:152:19: error: 'alloc_netdev' undeclared (first use in this function)
dev->netdev = alloc_netdev(sizeof(ec_gen_device_t *), &null, ether_setup);
^
/home/mm/work/project/ethercat/ethercat-1.5.2/devices/generic.c:152:19: note: each undeclared identifier is reported only once for each function it appears in
/home/mm/work/project/ethercat/ethercat-1.5.2/devices/generic.c:146:10: warning: unused variable 'null' [-Wunused-variable]
char null = 0x00;
t/ethercat/ethercat-1.5.2/master/ethernet.c:151:72: error: macro "alloc_netdev" requires 4 arguments, but only 3 given
if (!(eoe->dev = alloc_netdev(sizeof(ec_eoe_t *), name, ether_setup))) {
^
/home/mm/work/project/ethercat/ethercat-1.5.2/master/ethernet.c:151:22: error: 'alloc_netdev' undeclared (first use in this function)
if (!(eoe->dev = alloc_netdev(sizeof(ec_eoe_t *), name, ether_setup))) {
修改:
sudo vi devices/generic.c
152行 dev->netdev = alloc_netdev(sizeof(ec_gen_device_t *), &null, ether_setup);
改为
dev->netdev = alloc_netdev(sizeof(ec_gen_device_t *), &null, NET_NAME_UNKNOWN, ether_setup);
sudo vi master/ethernet.c
151行if (!(eoe->dev = alloc_netdev(sizeof(ec_eoe_t *), name, ether_setup))) {
改为
if (!(eoe->dev = alloc_netdev(sizeof(ec_eoe_t *), name,NET_NAME_UNKNOWN, ether_setup))) {
3.指定交叉编译工具,编译modules
#make ARCH=arm CROSS_COMPILE=arm-linux-gnueabihf- modules
//编译通过会对应生成ethercat-1.5.2/devices/ec_generic.ko和ethercat-1.5.2/master/ec_master.ko
4.安装
#make install
//make install 会在前面指定/opt/ethercat目录下有编译生成的各种用户空间的文件
5.在/opt/ethercat目录下创建modules文件夹,并复制ec_generic.ko和ec_master.ko到modules下
#mkdir -p /opt/ethercat/modules
#cp devices/ec_generic.ko /opt/ethercat/modules/
#cp master/ec_master.ko /opt/ethercat/modules/
7.将ethercat文件夹打包
# ls
bin etc include lib modules sbin
#tar -cjf ethercat.tar.bz2 ethercat
/至此IGH交叉编译完成,下面是在对应arm目标板上的操作*/
注意:
1.arm目标板上要使用的东西都在ethercat文件夹下或者是ethercat.tar.bz2
2.ethercat文件夹下包含链接文件,可以通过nfs/ftp等方式cp到板子上,不是通过挂载的方式只能下载ethercat.tar.bz2到板子再解压
1.将ethercat.tar.bz2拷贝到板子根目录下解压(这里不做说明)
root@EmbedSky-Board:/# tar xvf ethercat.tar.bz2
ethercat/
ethercat/ec_generic.ko
ethercat/lib/
ethercat/lib/libethercat.a
ethercat/lib/libethercat.so.1
ethercat/lib/libethercat.so
ethercat/lib/libethercat.la
ethercat/lib/libethercat.so.1.0.0
ethercat/lib/systemd/
ethercat/lib/systemd/system/
ethercat/lib/systemd/system/ethercat.service
ethercat/include/
ethercat/include/ectty.h
ethercat/include/ecrt.h
ethercat/bin/
ethercat/bin/ethercat
ethercat/sbin/
ethercat/sbin/ethercatctl
ethercat/ec_master.ko
ethercat/etc/
ethercat/etc/init.d/
ethercat/etc/init.d/ethercat
ethercat/etc/sysconfig/
ethercat/etc/sysconfig/ethercat
ethercat/etc/ethercat.conf
root@EmbedSky-Board:/#
2.进入ethercat目录下
root@EmbedSky-Board:/# cd /ethercat
root@EmbedSky-Board:/ethercat# ls
bin etc include lib modules sbin
root@EmbedSky-Board:/ethercat#
将ethercat目录下各文件目录的内容复制到板子根文件系统根目录下相应目录下,例如:cp bin/ethercat /bin/
3.复制ec_master.ko到/lib/modules/内核版本号/
root@EmbedSky-Board:/ethercat# cp /ethercat/modules/ec_master.ko /lib/modules/4.1.15
//这里的内核版本是4.1.15,可以通过uname -r 查看
root@EmbedSky-Board:/ethercat# depmod
4.配置rules,创建设备号
root@EmbedSky-Board:/ethercat#vi /etc/sysconfig/ethercat
将引号中的内容 “echo KERNEL==\"EtherCAT[0-9]*\", MODE=\"0664\" > /etc/udev/rules.d/99-EtherCAT.rules” 加进去。
5.获取板子MAC地址
root@EmbedSky-Board:/ethercat#ifconfig
//eth2 Link encap:以太网 硬件地址 00:0c:29:01:69:aa
/**************至此板子上的配置结束,下面是启动EtherCAT ***************/
通过网线直连ethercat主从站,从站启动完成后,打开主站电源
1.配置主站的MAC地址
root@EmbedSky-Board:/ethercat#modprobe ec_master main_devices=1E:ED:19:27:1A:B3
2.启动ethercat
root@EmbedSky-Board:/ethercat# /etc/init.d/ethercat start
Starting EtherCAT master 1.5.2 done
3.安装通用网卡驱动
root@EmbedSky-Board:/ethercat#insmod /modules/ec_generic.ko
//上面两步加载了 EtherCAT 的内核模块,下面就可以使用 ethercat 工具来进行一些操作
/4.通过ethercat查看信息/
root@EmbedSky-Board:/ethercat#ethercat
//输入ethercat得到帮助菜单
/到此移植过程结束***/
附主站测试代码
#include <errno.h>
#include <signal.h>
#include <stdio.h>
#include <string.h>
#include <sys/resource.h>
#include <sys/time.h>
#include <sys/types.h>
#include <unistd.h>
/****************************************************************************/
#include "ecrt.h"
/****************************************************************************/
// Application parameters
#define FREQUENCY 100
#define PRIORITY 1
// Optional features
#define CONFIGURE_PDOS 1
/****************************************************************************/
// EtherCAT
static ec_master_t *master = NULL;
static ec_master_state_t master_state = {};
static ec_domain_t *domain1 = NULL;
static ec_domain_state_t domain1_state = {};
static ec_domain_t *domain2 = NULL;
static ec_domain_state_t domain2_state = {};
static ec_slave_config_t *sc;
static ec_slave_config_state_t sc_ana_in_state = {};
// Timer
static unsigned int sig_alarms = 0;
static unsigned int user_alarms = 0;
/****************************************************************************/
// process data
static uint8_t *domain1_pd = NULL;
static uint8_t *domain2_pd = NULL;
#define BusCouplerPos 0, 0
#define TI_AM3359ICE 0xE000059D, 0x54490001
// offsets for PDO entries
static unsigned int off_dig_out2;
static unsigned int off_dig_in2;
static unsigned int counter = 0;
static unsigned int blink = 0x00;
/*****************************************************************************/
#if CONFIGURE_PDOS
ec_pdo_entry_info_t slave_0_pdo_entries[] = {
{0x7010, 0x00, 32},
{0x6000, 0x00, 4*8},
};
ec_pdo_info_t slave_0_pdos[] = {
{0x1601, 1, slave_0_pdo_entries + 0},
{0x1a00, 1, slave_0_pdo_entries + 1},
};
static ec_sync_info_t slave_0_pdo_syncs[] = {
{2, EC_DIR_OUTPUT, 1, slave_0_pdos + 0},
{3, EC_DIR_INPUT, 1, slave_0_pdos + 1},
{0xff}
};
#endif
/*****************************************************************************/
void check_domain1_state(void)
{
ec_domain_state_t ds;
ecrt_domain_state(domain1, &ds);
if (ds.working_counter != domain1_state.working_counter)
printf("Domain1: WC %u.\n", ds.working_counter);
if (ds.wc_state != domain1_state.wc_state)
printf("Domain1: State %u.\n", ds.wc_state);
domain1_state = ds;
}
/*****************************************************************************/
void check_domain2_state(void)
{
ec_domain_state_t ds;
ecrt_domain_state(domain2, &ds);
if (ds.working_counter != domain2_state.working_counter)
printf("Domain2: WC %u.\n", ds.working_counter);
if (ds.wc_state != domain2_state.wc_state)
printf("Domain2: State %u.\n", ds.wc_state);
domain2_state = ds;
}
/*****************************************************************************/
void check_master_state(void)
{
ec_master_state_t ms;
ecrt_master_state(master, &ms);
if (ms.slaves_responding != master_state.slaves_responding)
printf("%u slave(s).\n", ms.slaves_responding);
if (ms.al_states != master_state.al_states)
printf("AL states: 0x%02X.\n", ms.al_states);
if (ms.link_up != master_state.link_up)
printf("Link is %s.\n", ms.link_up ? "up" : "down");
master_state = ms;
}
/*****************************************************************************/
void check_slave_config_states(void)
{
ec_slave_config_state_t s;
ecrt_slave_config_state(sc, &s);
if (s.al_state != sc_ana_in_state.al_state)
printf("AnaIn: State 0x%02X.\n", s.al_state);
if (s.online != sc_ana_in_state.online)
printf("AnaIn: %s.\n", s.online ? "online" : "offline");
if (s.operational != sc_ana_in_state.operational)
printf("AnaIn: %soperational.\n",
s.operational ? "" : "Not ");
sc_ana_in_state = s;
}
/*****************************************************************************/
void cyclic_task()
{
// receive process data
ecrt_master_receive(master);
ecrt_domain_process(domain1);
ecrt_domain_process(domain2);
// check process data state (optional)
check_domain1_state();
check_domain2_state();
// if (counter) {
// counter--;
// } else { // do this at 1 Hz
counter = FREQUENCY;
// calculate new process data
blink ++;
// check for master state (optional)
check_master_state();
// check for islave configuration state(s) (optional)
check_slave_config_states();
// printf("AnaIn: value=0x%x\n", EC_READ_U32(domain2_pd + off_dig_in2));
printf("AnaIn: value=0x%x\n", EC_READ_U32(domain2_pd + off_dig_in2));
//printf("AnaIn: value=0x%x\n", EC_READ_U32(domain2_pd + off_dig_in2 + 4));
EC_WRITE_U32(domain1_pd + off_dig_out2, blink);
// printf("AnaIn: value=0x%x\n", EC_READ_U32(domain1_pd + off_dig_out2));
// }
// send process data
ecrt_domain_queue(domain1);
ecrt_domain_queue(domain2);
ecrt_master_send(master);
}
/****************************************************************************/
void signal_handler(int signum) {
switch (signum) {
case SIGALRM:
sig_alarms++;
break;
}
}
/****************************************************************************/
int main(int argc, char **argv)
{
struct sigaction sa;
struct itimerval tv;
master = ecrt_request_master(0);
if (!master)
return -1;
domain1 = ecrt_master_create_domain(master);
if (!domain1)
return -1;
domain2 = ecrt_master_create_domain(master);
if (!domain2)
return -1;
#if CONFIGURE_PDOS
if (!(sc = ecrt_master_slave_config(
master, BusCouplerPos, TI_AM3359ICE))) {
fprintf(stderr, "Failed to get slave configuration.\n");
return -1;
}
if (ecrt_slave_config_pdos(sc, EC_END, slave_0_pdo_syncs)) {
fprintf(stderr, "Failed to configure PDOs.\n");
return -1;
}
printf("Configuring PDOs...\n");
// Create configuration for bus coupler
off_dig_out2 = ecrt_slave_config_reg_pdo_entry(sc,
0x7010, 0, domain1, NULL);
if (off_dig_out2 < 0)
return -1;
off_dig_in2 = ecrt_slave_config_reg_pdo_entry(sc,
0x6000, 0, domain2, NULL);
if (off_dig_in2 < 0)
return -1;
#endif
printf("Activating master...\n");
if (ecrt_master_activate(master))
return -1;
if (!(domain1_pd = ecrt_domain_data(domain1))) {
return -1;
}
if (!(domain2_pd = ecrt_domain_data(domain2))) {
return -1;
}
sa.sa_handler = signal_handler;
sigemptyset(&sa.sa_mask);
sa.sa_flags = 0;
if (sigaction(SIGALRM, &sa, 0)) {
fprintf(stderr, "Failed to install signal handler!\n");
return -1;
}
printf("Starting timer...\n");
tv.it_interval.tv_sec = 0;
tv.it_interval.tv_usec = 1000000 / FREQUENCY;
tv.it_value.tv_sec = 0;
tv.it_value.tv_usec = 2000;
if (setitimer(ITIMER_REAL, &tv, NULL)) {
fprintf(stderr, "Failed to start timer: %s\n", strerror(errno));
return 1;
}
printf("Started.\n");
while (1) {
pause();
while (sig_alarms != user_alarms) {
cyclic_task();
user_alarms++;
}
}
return 0;
}
/****************************************************************************/
/***********IGH demo编译*****************/
arm-linux-gnueabi-gcc main.c -o ethercat_test -I../../ethercat/include/ -L../..ethercat/lib -lethercat