1.SOEM-master-1.4.0源码
/**
* @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)初始化从站分组逻辑起始地址
SOEM源码使用memset函数将从站、分组列表内容全部设置为0x00,相关语句如下:
memset(context->slavelist, 0x00, sizeof(ec_slavet) * context->maxslave);
memset(context->grouplist, 0x00, sizeof(ec_groupt) * context->maxgroup);
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)
{
......
}
这里按顺序为每个从站分组逻辑起始地址设置为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;
}
ecx_init_context函数是SOEM主站在初始化网卡及端口参数后首个执行的函数,用于初始化句柄,该函数具体的工作如下:
(1)初始化从站、分组列表
(2)清空EEPROM缓存
(3)初始化从站分组逻辑起始地址