EtherCAT主站实现:主站基于安路DR190M
EtherCAT主站实现:主站基于安路DR190M# 1、EtherCAT主站
安路今年推出一款的FPSoC DR190M,组合了硬核处理器系统和FPGA,通过高带宽总线进行二者的互联。多核 ARM/RISC-V 处理器系统与安路FPGA可编程逻辑相结合于一颗芯片中,提供了应用类ARM/RISC-V处理器的性能 与生态系统,并且具备安路FPGA的灵活性、低功耗、可扩展 SoC平台。ARM/RISC-V CPU是处理器系统的核心,同时系统还包含on-chip RAM,内存接口和丰富的外设互联接口,定位复杂嵌入式系统、低功耗和高性能芯片市场。
DR190M芯片的PS端有两个以太网控制器,基于以太网的功能,可以实现EtherCAT主站控制功能。
!(https://www.eefocus.com/forum/data/attachment/forum/202505/30/082506fethq3pq0i8vpo0m.png)
## 1.1 编译SOEM
SOEM(Simple Opensource EtherCAT Master)协议栈是很便于使用的开源EtherCAT Master主站协议栈。下载(https://github.com/OpenEtherCATsociety/SOEM)源码。
!(https://www.eefocus.com/forum/data/attachment/forum/202505/30/082518jdb6vdedmk4a2ddn.png)
在DR190M开发环境中配置交叉编译需要使用的编译器。配置脚本的内容下,路径需要根据具体的开发环境进行修改
```bash
#!/bin/sh
export PATH=$PATH:<具体的工具链安放位置>/MYD-YM90X-Distribution-L6.1.54-V1.0.0//toolchains/aarch64-linux/bin
export CROSS_COMPILE=aarch64-linux-gnu
export ARCH=arm64
export PREFIX=aarch64-linux-gnu
export AS=aarch64-linux-gnu-as
export LD=aarch64-linux-gnu-ld
export CC=aarch64-linux-gnu-gcc
export CXX=aarch64-linux-gnu-g++
export AR=aarch64-linux-gnu-ar
export NM=aarch64-linux-gnu-nm
export STRIP=aarch64-linux-gnu-strip
export OBJCOPY=aarch64-linux-gnu-objcopy
export OBJDUMP=aarch64-linux-gnu-objdump
```
使用source指令导入上述脚本,使开发环境配置生效。
```bash
source xxx.sh
```
解压下载的SOEM源代码。
!(https://www.eefocus.com/forum/data/attachment/forum/202505/30/082538y41k4onuyyunromu.png)
修改其中的示例代码slaveinfo用于**的演示。
```c
#include <stdlib.h>
#include <sched.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <pthread.h>
#include <math.h>
#include "osal.h"
#include "ethercattype.h"
#include "nicdrv.h"
#include "ethercatbase.h"
#include "ethercatmain.h"
#include "ethercatdc.h"
#include "ethercatcoe.h"
#include "ethercatfoe.h"
#include "ethercatconfig.h"
#include "ethercatprint.h"
#include "ethercat.h"
static char IOmap;
volatile uint8_t mode = 0;
static uint8_t slave = 1;
static volatile boolean inOP;
volatile int wkc;
int expectedWKC;
uint8 currentgroup = 0;
uint16 output_fsm=0;
void show_slave_info()
{
for (int cnt = 1; cnt <= ec_slavecount; cnt++)
{
printf("\nSlave:%d\n Name:%s\n Output size: %dbits\n Input size: %dbits\n State: %d\n Delay: %d\n Has DC: %d\n",cnt, ec_slave.name, ec_slave.Obits,ec_slave.Ibits, ec_slave.state,ec_slave.pdelay, ec_slave.hasdc);
printf(" Activeports:%d.%d.%d.%d\n", (ec_slave.activeports & 0x01) > 0 ,(ec_slave.activeports & 0x02) > 0 ,(ec_slave.activeports & 0x04) > 0 ,(ec_slave.activeports & 0x08)>0 );
printf(" Configured address: %x\n", ec_slave.configadr);
printf(" Outputs address: %p\n", ec_slave.outputs);
printf(" Inputs address: %p\n", ec_slave.inputs);
for (int j = 0; j < ec_slave.FMMUunused; j++)
{
printf(" FMMU%1d Ls:%x Ll:%4d Lsb:%d Leb:%d Ps:%x Psb:%d Ty:%x Act:%x\n", j, \
(int) ec_slave.FMMU.LogStart, ec_slave.FMMU.LogLength, \
ec_slave.FMMU.LogStartbit, ec_slave.FMMU.LogEndbit, \
ec_slave.FMMU.PhysStart, ec_slave.FMMU.PhysStartBit, \
ec_slave.FMMU.FMMUtype, ec_slave.FMMU.FMMUactive);
}
printf(" FMMUfunc 0:%d 1:%d 2:%d 3:%d\n", ec_slave.FMMU0func, ec_slave.FMMU1func, \
ec_slave.FMMU2func, ec_slave.FMMU3func);
}
}
int main(void)
{
const char *ifname = "eth0";
ecx_context.manualstatechange = 1;
printf("Test LED \r\n");
if (ecx_init(&ecx_context, ifname))
{
printf("EtherCAT Init NIC\r\n");
wkc = ecx_config_init(&ecx_context, FALSE);
if (wkc > 0)
{
printf("wkc is %d\r\n",wkc);
ecx_context.slavelist.state = EC_STATE_PRE_OP;
ecx_writestate(&ecx_context, slave);
ecx_statecheck(&ecx_context, slave, EC_STATE_PRE_OP, 5000);
if (ecx_context.slavelist.state != EC_STATE_PRE_OP)
{
ecx_readstate(&ecx_context);
for(int i = 1; i <= *(ecx_context.slavecount) ; i++)
{
if(ecx_context.slavelist.state != EC_STATE_PRE_OP)
{
}
}
}
ecx_configdc(&ecx_context);
ecx_config_map_group(&ecx_context, &IOmap, currentgroup);
expectedWKC = (ec_group.outputsWKC * 2) + ec_group.inputsWKC;
ecx_context.slavelist.state = EC_STATE_SAFE_OP;
ecx_writestate(&ecx_context, slave);
ecx_statecheck(&ecx_context, slave, EC_STATE_SAFE_OP, 5000);
if (ecx_context.slavelist.state != EC_STATE_SAFE_OP)
{
ecx_readstate(&ecx_context);
for(int i = 1; i <= *(ecx_context.slavecount) ; i++)
{
if(ecx_context.slavelist.state != EC_STATE_SAFE_OP)
{
}
}
}
ecx_readstate(&ecx_context);
show_slave_info();
inOP = FALSE;
expectedWKC = (ec_group.outputsWKC * 2) + ec_group.inputsWKC;
ecx_context.slavelist.state = EC_STATE_OPERATIONAL;
ecx_send_processdata(&ecx_context);
wkc = ecx_receive_processdata(&ecx_context, EC_TIMEOUTRET);
ecx_writestate(&ecx_context, slave);
if (ecx_context.slavelist.state == EC_STATE_OPERATIONAL)
{
inOP = TRUE;
ec_send_processdata();
wkc = ec_receive_processdata(EC_TIMEOUTRET);
while (inOP)
{
switch(output_fsm){
case 0:
output_fsm=1;
*(ecx_context.slavelist.outputs)=1;
break;
case 1:
output_fsm=2;
*(ecx_context.slavelist.outputs)=2;
break;
case 2:
output_fsm=3;
*(ecx_context.slavelist.outputs)=4;
break;
case 3:
output_fsm=4;
*(ecx_context.slavelist.outputs)=8;
break;
case 4:
output_fsm=5;
*(ecx_context.slavelist.outputs)=16;
break;
case 5:
output_fsm=6;
*(ecx_context.slavelist.outputs)=32;
break;
case 6:
output_fsm=7;
*(ecx_context.slavelist.outputs)=64;
break;
case 7:
output_fsm=0;
*(ecx_context.slavelist.outputs)=128;
break;
}
ec_send_processdata();
wkc = ec_receive_processdata(EC_TIMEOUTRET);
osal_usleep(1000000);
}
}
else
{
ecx_close(&ecx_context);
}
}
else
{
printf("wkc is %d\r\n",wkc);
}
}
else
{
printf("ecx_config_init failed\r\n");
}
printf("End Program\r\n");
return 0;
}
```
接下来对SOEM源码进行编译。依次执行下列指令,完成SOEM代码的编译。
```bash
cd SOEM
mkdir -p build
cd build
cmake ..
make
```
!(https://www.eefocus.com/forum/data/attachment/forum/202505/30/082650stqppjtvmvstqsup.png)
复制编译出的`SOEM/build/test/linux/slaveinfo`可执行文件到DR190M开发板。在开发板的eth0口连接一个EtherCAT从站。执行slaveinfo,可以看到EtherCAT从站上的LED循环变化。
!(https://www.eefocus.com/forum/data/attachment/forum/202505/30/082619d4a00mfbbhx0i0qp.gif)
页:
[1]