Ethercat主从站移植时的问题记录(二)—无法进入OP状态且从站PDI中断不触发
项目场景:
将SSC生成的V5.12的Ethercat从站协议栈移植到GD32H7单片机上,采用SPI通讯。用SOEM主站进行通讯验证。
问题描述
一、上一章Ethercat主从站移植时的问题记录(一)—OBJ_DWORD_ALIGN配置解决了无法进入SAFEOP状态的问题,但是后面又遇到了无法进入OP状态的问题。
二、同时用wireshark抓包发现主站的TXPDO数据是有的(由于不在OP状态,从站是无法获取TXPDO数据的),但是RXPDO数据一直是0。
而对从站代码打断点发现明明是有数据传出的,也就是SYNC0中断是一直被触发的,但是从抓包数据看,LWR中RXPDO部分的数据一直是0,而实际我是每个数据都有值的。如下图所示:
原因分析:
一、先从从站状态切换函数入手,看看到底为什么没有切换到OP状态
从站的状态切换主要是void AL_ControlInd(UINT8 alControl, UINT16 alStatusCode)和void AL_ControlRes(void)这两个函数控制。先看函数AL_ControlInd,单片机的好处就是打断点方便所以先打断点看看,如下图所示:
可以发现在这个函数中,SAFEOP->OP状态的切换是正常的。但是由于真正将从站状态写入ESC寄存器,主要是通过AL_ControlRes进行的,因此继续在AL_ControlRes函数的SAFEOP2OP状态中打断点,如下所示:
可以发现在这个函数中i16WaitForPllRunningCnt一直为0,所以无法进入OP状态。那么看看这个变量是在哪里自增的。
可以看到由于if(sSyncManOutPar.u16SmEventMissedCounter < sErrorSettings.u16SyncErrorCounterLimit)这个条件不满足,所以一直无法让变量i16WaitForPllRunningCnt增加。因此继续看sSyncManOutPar.u16SmEventMissedCounter这个变量,这个应该是PDI和SYNC0同步丢失计数器。
可以看到他是在Sync0_Isr中断里面自增,在PDI_Isr中断里面自减,因此看看PDI_Isr中断是不是出问题了。结果果然发现PDI_Isr这个中断居然不触发(DC模式下TXPDO映射),也就是说目前只有Sync0_Isr这个中断正常触发(主要是DC模式下RXPDO的映射)。但是同步用twincat3做主站发现safeop状态下,PDI_Isr中断是正常触发的。那就比较奇怪了,难道是主站的问题?带着这个疑问进一步分析下去。
二、分析寄存器0x204和0x220
因为PDI_Isr中断不触发,而这个中断管理又是由寄存器0x204和0x220负责的,因此看看是不是这个寄存器配置出问题了。
通过ect从站协议栈的读写寄存器函数,获取寄存器0x220的数据,如下图所示:
可以看到这个寄存器的第10位使能了,也就是SM2的中断会映射到PDI_Isr中断上,而一般我们配置是SM0-写邮箱 SM1-读邮箱 SM2-写PDO SM3-读PDO。因此这里PDI_Isr中断是主站TXPDO的中断映射,是没有问题的。所以寄存器配置也没问题。因此怀疑可能是同步管理器的配置或者FMMU的配置出问题,导致TXPDO数据的通道出问题了,无法触发中断。
三、先分析FMMU的配置
在分析FMMU的配置的时候,这样看到了这篇文章链接:Ethercat学习-电机调试问题总结,对该问题很有参考意义。
LAN9252一共有3个FMMU,这里由于是双端口模式,只有一个过程写数据和过程读数据,因此只用了前两个FMMU。而且FMMU的配置从下图手册看,都是由主站进行配置的,因此要通过wireshark抓包分析了。
通过wireshark进行抓包和过滤,可以看到下图关于FMMU寄存器的相关配置:
从上图看就感觉有点不对劲了,因为从XML的配置看(相当于存储在EEPROM中的配置是按照这个来的,后面会讲到),SM2是TXPDO的过程数据通道,物理地址是0x1200。FMMU0是TXPDO的逻辑地址和物理地址映射的管理器,所以FMMU0(0x600)对应SM2(0x810)的物理地址应该是0x1200,且应该是配置为开启写访问映射,忽略读访问映射;FMMU1(0x610)对应SM2(0x818)的物理地址应该是0x1300,且应该是配置为开启读访问映射,忽略写访问映射。而从上图看FMMU0的物理地址被设置成了0x1300和写访问,FMMU1的物理地址被设置成了0x1200和读访问映射。这个完全乱了,看来问题应该是出在这里了。那么为什么会出现这个问题呢,这就需要进一步分析了。
出现这个问题应该有两种情况:
一个是SM2和SM3寄存器的物理地址设置就错了,没有按照XML(EEPROM)中的配置来,比如SM2的物理地址设置成了0x1300且是主站写从站读访问,SM3的物理地址设置成了0x1200且是主站读从站写访问。
第二个是SM2和SM3寄存器的设置是对的,但是主站由于某种原因给FMMU配置错了。
四、先分析SM2/SM3的配置是否出问题了
1、首先看一下同步管理器的配置,主要看寄存器0x0810和0x0818(0x0800和0x0808是邮箱收发的SM,由于可以进入safeop状态而且从wireshark看,邮箱数据可以正常交互,因此这两个寄存器组的配置应该没问题)。先看主站和从站没有连接的时候寄存器的数据如下图所示:
可以看到SM2和SM3在主站没有开始发起连接的时候,物理地址和长度都是没有配置的,同步管理器也是禁止请求的,也就是还没有进行配置。
而当主站开始初始化,直到进入safeop状态的时候,SM2和SM3已经完成配置了,也就是配置是在主站初始化开始之后进行的。从站中的配置数据和wireshark抓包数据如下图所示:
可以看到主站通过邮箱数据,对从站的0x810(SM2)和0x818(SM3)寄存器组进行了配置。而且SM2的物理地址是0x1200,方向是写;而SM3的物理地址是0x1300,方向是读。这个和XML配置是一样的,那就说明同步管理器SM2和SM3的配置应该是没问题的。
虽然通过前面基本可以判定SM2和SM3的配置是没问题的,但是这里又产生了一个疑惑,我的SOEM是在STM32H7上跑的并没有解析XML,是手动配置的。那么主站是怎么知道SM2的物理地址要配置成0x1200,方向是写;而SM3的物理地址配置成0x1300,方向是读的呢。
五、分析主站如何获取SM配置信息并对从站SyncManager寄存器进行配置
这里既然有了这个疑惑,那秉着学习精神先分析一下主站如何获取SM配置信息并对从站SyncManager寄存器进行配置的。
首先先看SOEM的源码,如下图所示:
从上面可以看到ecat_init函数会调用ec_config_map函数,在ec_config_map函数中最终会执行ecx_config_map_group函数,在这个函数中会对同步管理器的寄存器组(0x800开始)进行配置。那接下来就要看看&context->slavelist[slave].SM[nSM]这里面的数据是怎么来的。
可以看到在ecx_config_init函数会调用ecx_siiSM(context, slave, context->eepSM)函数,在这个函数中会通过获取EEPROM里面的数据,从而获取关于同步管理器的配置(物理地址,长度等),然后将这些数据保存到context->eepSM里面,最终写入context->slavelist[slave].SM后,再配置给从站。那继续往下看看ecx_siiSM(context, slave, context->eepSM)这个函数。
可以看到这个函数其实是通过ecx_siifind,寻找存储SM信息的EEPROM地址,然后通过该地址读取EEPROM里面具体的SM信息数据从而获得SM的物理地址和长度等信息,然后再通过邮箱写入到0x800-0x818寄存器中。而具体ecx_siifind函数如下图所示:
具体做法是从0x0040这个EEPROM地址开始寻找EERPOM中category的类型,直到该类型是41,那就代表后面的数据就是SM同步管理器相关的信息。关于EEPROM存储信息可以看ethercat相关文档:《ETG2010_S_R_V1i0i3_EtherCATSubDeviceInformationInterface》和《ethercat_esc_datasheet_sec1_technology_2i3》。里面有关于EERPOM存储信息结构的描述,如下图所示:
从文档中可以看到0x40代表SubDevice Information Interface categories开始的地方,每一个category都分为header和data部分,header一共32bit,前16bit代表类型,后16bit代表数据长度。因此检查如果类型是41代表后面data中是sync manager type的结构内容。
六、分析主站对从站的FMMU的配置
通过前面的分析,我们可以看到主站对从站的SM寄存器组(0x800)配置是正确的,和我们一般规则也是一致的,也就是SM0-邮箱写;SM1-邮箱读;SM2-过程数据写;SM3-过程数据读。那么问题应该出在主站对从站的FMMU配置的。前面我们通过抓包发现主站在配置0x600和0x610这两个FMMU寄存器组的时候,确实和SM寄存器组中配置是相反的,和XML中的配置也是相反的。那么这个时候我们就要看主站的代码到底出了什么问题了。
可以看到函数ecx_config_map_group中会进行FMMU相关的配置,而配置的信息是存储在context->slavelist[slave].FMMU[FMMUc]中的,那接下来看一下context->slavelist[slave].FMMU[FMMUc]这个里面的数据。
可以看到FMMU[0]里面的数据是物理地址0x1300且主站写,FMMU[1]里面的数据是物理地址0x1200且主站读。因此这里的数据和我们设计上的FMMU0是0x1200且主站写,FMMU1是0x1300且主站写反了。那继续看这里面的数据是从那边来的,如下图所示:
以FMMU0数据的获取为例,是找到context->slavelist[slave].SMtype[SMc]中类型为3,也就是认为3的时候是TXPDO的配置,然后将context->slavelist[slave].SM[SMc]中的数据赋值到FMMU0中。因此从上图可以看到context->slavelist[slave].SMtype[0]、context->slavelist[slave].SMtype[1]、context->slavelist[slave].SMtype[2]、context->slavelist[slave].SMtype[3]的顺序没有按照1,2,3,4排列(1-代表邮箱写 2-代表邮箱读 3-代表过程数据写 4-代表过程数据读),排列顺序变成了1,2,4,3。所以FMMU0和FMMU1获取的的数据是FMMU0对应SM3的信息,FMMU1对应SM2的信息,错开了。那么接下来就要找到context->slavelist[slave].SMtype[SMc]是在哪里赋值的。
如下图所示:
可以看到主站是通过读取从站中0x1C00索引中的数据,来确定SMtype[2]、SMtype[3]中的数据的。这里可以看到在wireshark抓包数据中,确实读取0x1C00-子索引3的数据是4,0x1C00-子索引4的数据是3。按照正常配置应该是0x1C00一共4个子索引(每个8bit),顺序是1-代表邮箱写 2-代表邮箱读 3-代表过程数据写 4-代表过程数据读,而这里错乱了。所以最终看问题应该还是出在从站上。那么继续看从站的0x1C00的配置数据,如下图所示:
从上图看到数据按照字节从低到高的排列,确实乱了,没有按照1、2、3、4的类型排列。那么破案了,确实是从站的问题,所以这里把从站改为下图所示,就正常可以进入OP了。
不过这里产生了几个疑问:
(1)为什么Twincat3作为主站就正常可以OP呢?
通过wireshark抓包发现,Twincat3在初始化过程中并没有读取从站0x1C00中的数据,但是配置0x600和0x610的时候是正确的,那么我猜测应该是Twincat3直接根据XML中的配置对FMMU进行配置了,因此从站的这个BUG没有发生在Twincat3上面。
(2)用SSC V5.12生成的配置就是TOBJ1C00 sSyncmanagertype = {0x04, {0x0102, 0x0304}},但是用V5.13生成的就是TOBJ1C00 sSyncmanagertype = {0x04, {0x0201, 0x0403}};不知道这是不是个BUG。
解决方案:
将从站0x1C00的数据由TOBJ1C00 sSyncmanagertype = {0x04, {0x0102, 0x0304}};改成TOBJ1C00 sSyncmanagertype = {0x04, {0x0201, 0x0402}};就正常了。