ECAT_Main函数在MainLoop中轮询下面是ECAT_Main中的运行流程。MBX_Main();在MBX_Main中获取sMbxReceiveQueue中的数据包括COE的SDO和FOE。对SDO数据进行处理然后回复Master。if(bMbxRunning){HW_EscReadWord(sm1Activate,(ESC_SYNCMAN_ACTIVE_OFFSETSIZEOF_SM_REGISTER));sm1ActivateSWAPWORD(sm1Activate);}bMbxRunning 在成功进入Bootstrap或者Pre-OP状态的时候变为TRUE。这里读取0x80E寄存器的值。SWAPWORD用于大小端的转换ESC是小端芯片如果从机的MCU是大端的话需要进行转换这里用的小端的MCU所以SWAPWORD没什么作用。ALEventRegHW_GetALEventRegister();ALEventRegSWAPWORD(ALEventReg);读取AL事件请求寄存器0x220的值if((ALEventRegAL_CONTROL_EVENT)!bEcatWaitForAlControlRes){HW_EscReadWord(EscAlControl,ESC_AL_CONTROL_OFFSET);EscAlControlSWAPWORD(EscAlControl);ALEventReg~((AL_CONTROL_EVENT)|(SM_CHANGE_EVENT));AL_ControlInd((UINT8)EscAlControl,0);}需要满足的判断条件有两个0x220的bit0置1也就是产生了主站状态请求事件bEcatWaitForAlControlRes标志位为FALSE。bEcatWaitForAlControlRes在一般状态下是FALSE的只有在safeop到OP状态的转换的时候会先将bEcatWaitForAlControlRes标记为TRUE然后等待OP条件满足例如DC模式下需要200ms内稳定收到PDO数据或者其他模式下需要收到一帧PDO数据如果nPdOutputSize为则不需要PDO接收PDO数据。在条件满足后从站会将bEcatWaitForAlControlRes标记为FALSE然后设置状态为OP。进入这个判断后读取0x120寄存器的值这个值就是主站请求的状态将ALEventReg的bit0和bit4清0。这里的清0主要是避免后续重复调用AL_ControlInd函数。这里清0只是清除变量里的值若要寄存器清0对0x120读操作0x220的bit0清0对0x806进行读操作0x220的bit4清0。调用AL_ControlInd设置状态if((ALEventRegSM_CHANGE_EVENT)!bEcatWaitForAlControlRes(nAlStatusSTATE_CHANGE)0(nAlStatus~STATE_CHANGE)!STATE_INIT){ALEventReg~(SM_CHANGE_EVENT);AL_ControlInd(nAlStatusSTATE_MASK,0);}需要满足的判断条件有四个0x220的bit4置1也就是SM激活寄存器SM配置寄存器0x6产生了变化bEcatWaitForAlControlRes标志位为FALSE当前从站的状态未报错当前从站的状态不是INIT进入这个判断以后将ALEventReg的bit4清0调用AL_ControlInd设置状态这里的目的不是为了改变状态因为填入的请求状态参数是当前的状态值。这里主要目的是当SM激活寄存器发生改变后使用AL_ControlInd函数中的CheckSmSettings来检查SM的配置。这也解释了为什么在上一步会将ALEventReg的bit0和bit4都清0了。因为在上一步调用AL_ControlInd已经检查过了不需要重复检查了。if(bEcatWaitForAlControlRes){AL_ControlRes();}bEcatWaitForAlControlRes是在safeop转换OP的时候标记未TRUE的AL_ControlRes主要是判断OP条件是否满足当条件满足后会将从站状态改变为OP并标记bEcatWaitForAlControlRes为FALSE。if(!(sm1ActivateSM_SETTING_ENABLE_VALUE)){AL_ControlInd(nAlStatusSTATE_MASK,0);}这里应该还是对邮箱配置进行检查但是因为我的邮箱一直都是激活状态所以全程没有进入到这个条件中去。if(ALEventReg(MAILBOX_READ_EVENT)){u16dummy0;HW_EscWriteWord(u16dummy,u16EscAddrSendMbx);ALEventReg~(MAILBOX_READ_EVENT);MBX_MailboxReadInd();}需要满足的判断条件一个SM1通道有事件发生主站读取了SM1中的数据进入这个判断后写取SM1的第一个字节用于清除0x220中的SM1事件的置位。清除变量中相应位置的置位。MBX_MailboxReadInd查看发送队列中是否还有待发送的数据如果有将数据写入SM1的缓存中if(((sm1ActivateSM_SETTING_REPAET_REQ_MASK)!bMbxRepeatToggle)||(!(sm1ActivateSM_SETTING_REPAET_REQ_MASK)bMbxRepeatToggle)){MBX_MailboxRepeatReq();if(bMbxRepeatToggle){sm1Activate|SM_SETTING_REPEAT_ACK;}else{sm1Activate~SM_SETTING_REPEAT_ACK;}sm1ActivateSWAPWORD(sm1Activate);HW_EscWriteWord(sm1Activate,(ESC_SYNCMAN_ACTIVE_OFFSETSIZEOF_SM_REGISTER));}判断条件一个重复请求位SM配置寄存器0x6 的bit1是否翻转bMbxRepeatToggle是上一次bit1的值。进入这个判断后调用MBX_MailboxRepeatReq将之前保存的上一包数据重新写入邮箱之中并且更新bMbxRepeatToggle的值。写重复请求应答位SM配置寄存器0x7 的bit1该位与重复请求位相同时表示PDI对前面设置的重复请求应答。其实也可以理解为主站翻转0x6的bit1来告诉从站需要重传然后主站一直检测0x7的bit1发现翻转后说明重传数据已经放入邮箱了主站再去读从站邮箱里的数据。ALEventRegHW_GetALEventRegister();ALEventRegSWAPWORD(ALEventReg);if(ALEventReg(MAILBOX_WRITE_EVENT)){ALEventReg~(MAILBOX_WRITE_EVENT);MBX_CheckAndCopyMailbox();}重新读取0x220的寄存器的值或者这个值已经变了。判断SM0事件是否发生了主机是否有数据写进来了如果SM0数据发生了那么先将变量ALEventReg相应的位清0然后调用MBX_CheckAndCopyMailbox将有效数据写入 sMbxReceiveQueue中。sMbxReceiveQueue会在MBX_Main()里面进行处理。