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

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

1、映射关系
SOEM首先将所有从站的输出映射到IOmap[]的开始位置,然后是输入,如下图所示:
EtherCAT主站SOEM源码解析----IOmap_第1张图片

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的例子,如下图所示:
SOEM: tutorial.txt File Reference

EtherCAT主站SOEM源码解析----IOmap_第2张图片

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

原文地址:EtherCAT主站SOEM源码解析----IOmap_ec_config_map_ethercat_i7的博客-CSDN博客 

你可能感兴趣的:(ethercat,SOEM,IOmap)