EtherCAT主站SOEM源码解析----IOmap

本文详细介绍了SOEM通过函数ec_config_map(&IOmap)完成逻辑地址和物理地址映射的过程,包括映射关系、具体实现及实例。通过读写数组IOmap[], 应用程序可以实现与从站的数据交换。

SOEM通过函数ec_config_map(&IOmap)完成逻辑地址和物理地址的映射,应用程序需要定义一个数组IOmap,例如:
char IOmap[4096];
完成映射后,应用程序就可以通过读写数组IOmap[]来完成与从站的数据交换。

1、映射关系

SOEM首先将所有从站的输出映射到IOmap[]的开始位置,然后是输入,如下图所示:
这里写图片描述

2、具体实现

函数ec_config_map(&IOmap)最终会调用/soem/EthercatConfig.c中的以下函数完成映射。
int ecx_config_map_group(ecx_contextt *context, void *pIOmap, uint8 group)

该函数完成主要的功能为:
1. 读取从站EEPROM中的PDO信息,统计需要映射的输入输出长度;
2. 根据步骤1的结果配置从站SM寄存器;
3. 将从站的输出映射到IOmap[],并配置从站FMMU寄存器;
4. 将从站的输入映射到Iomap[],并配置从站FMMU寄存器;
5. 为应用程序提供读写IOmap[]的接口。

具体代码如下:

int ecx_config_map_group(ecx_contextt *context, void *pIOmap, uint8 group)
{
    ......

   if ((*(context->slavecount) > 0) && (group < context->maxgroup))
   {   
      ......

      /* find CoE and SoE mapping of slaves in multiple threads */
      for (slave = 1; slave <= *(context->slavecount); slave++)
      {
       ......
               ecx_map_coe_soe(context, slave);
       ......
       }

      /* find SII mapping of slave and program SM */
      for (slave = 1; slave <= *(context->slavecount); slave++)
      {
         if (!group || (group == context->slavelist[slave].group))
         {             
            ecx_map_sii(context, slave);  //统计需要mapping的输入输出长度,单位为bit
            ecx_map_sm(context, slave); //配置从站SM寄存器
         }
      }

      /* do input mapping of slave and program FMMUs */ //源代码注释的bug? 此处input 应为output
      for (slave = 1; slave <= *(context->slavecount); slave++)
      {

       .....

                  /* program FMMU for output */配置从站FMMU寄存器
                  ecx_FPWR(context->port, configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc),
                     sizeof(ec_fmmut), &(context->slavelist[slave].FMMU[FMMUc]), EC_TIMEOUTRET3);
       ......

       //为应用程序提供接口            
      context->grouplist[group].outputs = pIOmap;
      context->grouplist[group].Obytes = LogAddr;
      context->grouplist[group].nsegments = currentsegment + 1;  //currentsegment初始值为0
      context->grouplist[group].Isegment = currentsegment;
      context->grouplist[group].Ioffset = segmentsize;

      /* do input mapping of slave and program FMMUs */   //output mapping?
      for (slave = 1; slave <= *(context->slavecount); slave++)
      {
         ......

                     /* program FMMU for input */配置从站FMMU寄存器
                     ecx_FPWR(context->port, configadr, ECT_REG_FMMU0 + (sizeof(ec_fmmut) * FMMUc), 
                        sizeof(ec_fmmut), &(context->slavelist[slave].FMMU[FMMUc]), EC_TIMEOUTRET3);

          ......
      }
      //为应用程序提供接口
      context->grouplist[group].IOsegment[currentsegment] = segmentsize;
      context->grouplist[group].nsegments = currentsegment + 1;
      context->grouplist[group].inputs = (uint8 *)(pIOmap) + context->grouplist[group].Obytes;
      context->grouplist[group].Ibytes = LogAddr - context->grouplist[group].Obytes;

   }

   return 0;
}   

3、映射实例

在SOEM 说明文档中有1个IOmap的例子,如下图所示:
http://openethercatsociety.github.io/doc/soem/tutorial_8txt.html

这里写图片描述

Slave2 EL4001 的1*16bit 输出被映射到逻辑地址的最开始处。
Slave6、7、8、9每个站只有2bit,被映射到一个逻辑地址中。

### SOEM EtherCAT 主站配置步骤及代码实现 #### 1. 基本环境准备 在使用SOEM库构建EtherCAT主站前,需确保已安装并配置好必要的开发环境。这包括Linux操作系统、GCC编译器以及网络适配器支持[^1]。 #### 2. 初始化EtherCAT主站 初始化阶段涉及加载网络接口卡(NIC),通常指定为主机上的某个网口(如`eth0`)。此操作由`ec_init()`完成,该函数会尝试绑定到指定的网络接口。 ```c if (!ec_init("eth0")) { printf("Failed to initialize EtherCAT on eth0\n"); return -1; } ``` #### 3. 配置网络参数 调用`ec_config_init()`来扫描连接至EtherCAT总线的所有从站设备,并生成相应的映射表。这一过程自动检测每个节点的位置及其PDO映射关系。 ```c if (!ec_config_init(FALSE)) { printf("No slaves found!\n"); ec_close(); return -1; } ``` #### 4. 映射I/O地址空间 通过调用`ec_config_map()`将所有从站的过程数据对象(PDOs)映射到主机内存中的连续区域(IOmap),以便后续访问这些共享变量变得简单高效。 ```c ec_config_map(&IOmap); ``` #### 5. 设置工作状态 进入运行模式之前,需要逐步改变系统的整体状态直到达到OPERATIONAL级别。这是通过多次调用来达成的——分别检查INIT、PREOP、SAFE_OP直至最终目标态。 ```c ec_statecheck(0, EC_STATE_INIT, EC_TIMEOUTSTATE); ec_statecheck(0, EC_STATE_PRE_OP, EC_TIMEOUTSTATE); ec_statecheck(0, EC_STATE_SAFE_OP, EC_TIMEOUTSTATE); ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE); ``` #### 6. 数据处理循环 一旦系统处于正常运作状态下,则启动一个无限循环,在其中持续发送接收周期性的过程数据包,并监控任何可能发生的错误条件或者特殊事件响应机制。 ```c while (1) { ec_send_processdata(); ec_receive_processdata(EC_TIMEOUTRET); // Handle specific application logic here... usleep(1000); // Adjust sleep duration as needed. } ``` #### 完整示例代码 以下是综合以上各部分的一个完整例子展示如何利用SOEM创建基本框架下的EtherCAT master应用程序: ```c #include "soem/ethercat.h" int main(void) { if (!ec_init("eth0")) { fprintf(stderr, "Could not init Ethernet interface.\n"); return -1; } if (!ec_config_init(FALSE)) { fprintf(stderr, "No slave answers.\n"); ec_close(); return -1; } ec_config_map(&IOmap); ec_writestate(0); do { ec_readstate(); for (slave = 1; slave <= ec_slavecount; slave++) { if ((ec_group[slave].state != ECSAFEOP) && (ec_group[slave].ALstatuscode == 0x0000)) { break; } } } while (slave <= ec_slavecount); ec_statecheck(0, EC_STATE_OPERATIONAL, EC_TIMEOUTSTATE * 4); while (running) { ec_send_processdata(); ec_receive_processdata(EC_TIMEOUTRET); // Application-specific code goes here... usleep(1000); } ec_close(); return 0; } ``` ### 注意事项 - **硬件兼容性**:确认所使用的以太网控制器能够被SOEM正确识别和支持[^2]。 - **实时性能需求**:对于某些严格要求低延迟的应用场合来说,普通桌面级OS或许无法完全胜任;此时考虑采用RT-Linux或其他专门设计过的RTOS解决方案可能会更加合适一些[^3]。
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
红包 添加红包
表情包 插入表情
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值