SOEM源码解析——ecx_init_context(初始化句柄)

0 工具准备

1.SOEM-master-1.4.0源码

1 ecx_init_context函数总览

/**
 * @brief 初始化句柄
 * @param context 句柄
 */
void ecx_init_context(ecx_contextt *context)
{
   int lp;
   *(context->slavecount) = 0;
   /* clean ec_slave array */
   /* 清空从站信息数组 */
   memset(context->slavelist, 0x00, sizeof(ec_slavet) * context->maxslave);
   memset(context->grouplist, 0x00, sizeof(ec_groupt) * context->maxgroup);
   /* clear slave eeprom cache, does not actually read any eeprom */
   /* 清空EEPROM缓存,实际上不读取任何EEPROM */
   ecx_siigetbyte(context, 0, EC_MAXEEPBUF);
   for(lp = 0; lp < context->maxgroup; lp++)
   {
      /* default start address per group entry */
      /* 设置每个组条目的默认起始地址 */
      context->grouplist[lp].logstartaddr = lp << EC_LOGGROUPOFFSET;
   }
}

从以上代码可以看出,ecx_init_context的工作主要分为3块:
(1)初始化从站、分组列表
(2)清空EEPROM缓存
(3)初始化从站分组逻辑起始地址

1.1 初始化从站、分组列表

SOEM源码使用memset函数将从站、分组列表内容全部设置为0x00,相关语句如下:

memset(context->slavelist, 0x00, sizeof(ec_slavet) * context->maxslave);
memset(context->grouplist, 0x00, sizeof(ec_groupt) * context->maxgroup);

1.2 清空EEPROM缓存

SOEM源码通过ecx_siigetbyte函数去读取EEPROM,ecx_siigetbyte函数原型如下:

/** Read one byte from slave EEPROM via cache.通过从站EEPROM缓存区读取一个字节
 *  If the cache location is empty then a read request is made to the slave. 如果读取的缓存区为空则向从站发起读取
 *  Depending on the slave capabilities the request is 4 or 8 bytes.
 *  @param[in] context = context struct 句柄
 *  @param[in] slave   = slave number 从站序号
 *  @param[in] address = eeprom address in bytes (slave uses words) EEPROM数据地址(从站使用字为单位)
 *  @return requested byte, if not available then 0xff 读取结果,如果不可用则返回0xff
 */
uint8 ecx_siigetbyte(ecx_contextt *context, uint16 slave, uint16 address)

ecx_init_context函数传入该函数的参数2为0、参数3为EC_MAXEEPBITMAP
(1)当传入的slave不是EEPROM缓存数据从站拥有者时,就会清空EEPROM缓存区。相关语句如下:

/* cache里的EEPROM数据不属于传入从站 */
   if (slave != context->esislave)
   {
      /* clear esibuf cache map */
      /* 清空esibuf指向的EEPROM缓存区*/
      memset(context->esimap, 0x00, EC_MAXEEPBITMAP * sizeof(uint32));
      /* 将EEPROM cache所属从站设置为传入从站*/
      context->esislave = slave;
   }

其中context->esislave的初始值为0,如果有从站的EEPROM被读取到缓存区,则该值>0。这样当重复初始化从站时便会将之前读取到的EEPROM缓存区清空。简单来说,该语句可以保证context->esislave的值为0,这样后续有人使用到该函数都会因为slave不等于context->esislave从而绕过缓存区去直接读取EEPROM获取EEPROM数据。
(2)当传入的address大于等于EC_MAXEEPBUF不会进行任何操作,这样便完成了EEPROM缓存区的清空操作。相关语句如下:

if (address < EC_MAXEEPBUF)
   {
      ......
   }

1.3 初始化从站分组逻辑起始地址

这里按顺序为每个从站分组逻辑起始地址设置为0 * 65536、1 * 65536…n * 65536,这样相当于每个分组逻辑寻址空间大小为64KB,这恰好等于ESC支持的最大DPRAM存储空间:64KB。这样大的逻辑寻址空间对于每一个分组来说都绰绰有余,实际的应用中单个从站PDO一般仅几十字节。
在这里插入图片描述
相关语句如下:

for(lp = 0; lp < context->maxgroup; lp++)
   {
      /* default start address per group entry */
      /* 设置每个组条目的默认起始地址 */
      context->grouplist[lp].logstartaddr = lp << EC_LOGGROUPOFFSET;
   }

2 总结

ecx_init_context函数是SOEM主站在初始化网卡及端口参数后首个执行的函数,用于初始化句柄,该函数具体的工作如下:
(1)初始化从站、分组列表
(2)清空EEPROM缓存
(3)初始化从站分组逻辑起始地址

你可能感兴趣的:(工业以太网,EtherCAT,SOEM,主站,工业以太网,初始化)