EtherCAT主站SOEM源码解析—-EEPROM访问


1
2
SOEM(Simple Open EtherCAT Master)是一个开源的EtherCAT主站。
本文介绍其中读取从站EEPROM信息的步骤。

1、ESC EEPROM访问控制寄存器

从站控制芯片ESC EEPROM控制寄存器如下:
这里写图片描述

2、读EEPROM步骤

1
2
3
4
5
6
7
8
  读的一般步骤为:
  (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()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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()函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
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

1
 VendorID在EEPROM中的地址为0x000a,在/soem/EtheratConfig.c文件中,函数ecx_config_init()读取VendorID的代码如下:
1
2
3
4
5
6
7
8
9
10
11
12
      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的值。