SOEM(Simple Open EtherCAT Master)是一个开源的EtherCAT主站。
本文介绍其中读取从站EEPROM信息的步骤。
1、ESC EEPROM访问控制寄存器
从站控制芯片ESC EEPROM控制寄存器如下:
2、读EEPROM步骤
读的一般步骤为:
(1) 读取EEPROM控制/状态寄存器0x0502:0x0503的内容,确认EEPROM没有处于Busy状态
(2) 向0x0502:0x0503写入读控制命令,写入的值为0x0100,向0x0504:0x0507写入需要读的EEPROM地址
(3) 重复步骤(1)
(4) 从寄存器0x0508:0x050F中读取对应EEPROM地址的内容
读取一次SOEM主站需要发送4帧数据。
步骤(1)和(2)在SOEM源码中对应的实现函数为ecx_readeeprom1()。
步骤(3)和(4)在SOEM源码中对应的实现函数为ecx_readeeprom2()。
3、ecx_readeeprom1()函数
void ecx_readeeprom1(ecx_contextt *context, uint16 slave, uint16 eeproma)
{
uint16 configadr, estat;
ec_eepromt ed;
int wkc, cnt = 0;
ecx_eeprom2master(context, slave); /* set eeprom control to master */
configadr = context->slavelist[slave].configadr;
if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, EC_TIMEOUTEEP))
{
if (estat & EC_ESTAT_EMASK) /* error bits are set */
{
estat = htoes(EC_ECMD_NOP); /* clear error bits */
wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(estat), &estat, EC_TIMEOUTRET3);
}
ed.comm = htoes(EC_ECMD_READ); //EC_ECMD_READ=0x0100
ed.addr = htoes(eeproma);
ed.d2 = 0x0000;
do
{
wkc = ecx_FPWR(context->port, configadr, ECT_REG_EEPCTL, sizeof(ed), &ed, EC_TIMEOUTRET);
}
while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
}
}
4、ecx_readeeprom2()函数
uint32 ecx_readeeprom2(ecx_contextt *context, uint16 slave, int timeout)
{
uint16 estat, configadr;
uint32 edat;
int wkc, cnt = 0;
configadr = context->slavelist[slave].configadr;
edat = 0;
estat = 0x0000;
if (ecx_eeprom_waitnotbusyFP(context, configadr, &estat, timeout))
{
do
{
//ECT_REG_EEPDAT = 0x0508,
wkc = ecx_FPRD(context->port, configadr, ECT_REG_EEPDAT, sizeof(edat), &edat, EC_TIMEOUTRET);
}
while ((wkc <= 0) && (cnt++ < EC_DEFAULTRETRIES));
}
return edat;
}
5、读VendorID
VendorID在EEPROM中的地址为0x000a,在/soem/EtheratConfig.c文件中,函数ecx_config_init()读取VendorID的代码如下:
for (slave = 1; slave <= *(context->slavecount); slave++)
{
context->slavelist[slave].eep_man =
etohl(ecx_readeeprom2(context, slave, EC_TIMEOUTEEP)); /* Manuf */
ecx_readeeprom1(context, slave, ECT_SII_ID); /* ID */** //ECT_SII_ID = 0x000a
}
for (slave = 1; slave <= *(context->slavecount); slave++)
{
context->slavelist[slave].eep_id =
etohl(ecx_readeeprom2(context, slave, EC_TIMEOUTEEP)); /* ID */
ecx_readeeprom1(context, slave, ECT_SII_REV); /* revision */
}
使用Wireshark监控可以看到对应的EtherCAT帧如下:
其中帧95、96、99和100对应步骤1,查询EEPROM状态。
帧97/98对应步骤2,向0x0502:0x0503中写入读命令0x0100,向0x0504:0x0507写入VendorID所在的EEPROM地址0x000a。
帧101/102从0x0508:0x050F读取VendorID的值。