前言
昨天一直在进行eCAN模块远程帧的调试,今天早上终于调通了,下面把个人心得及使用体会分享出来,一方面作为个人经验总结,另一方面为初学者提供指导。
根据官方手册,DSP中远程帧邮箱的处理有两种功能,一个是模块向一个节点发出数据请求,二是节点应答模块发出的数据请求。简单来说,一个节点需要其他节点的数据,这时候就可以通过远程帧来获取,这个过程涉及两个对象,一个是需求方,另一个是应答方,需求方给应答方发送一个远程帧,请求应答方发送数据,应答方收到数据请求,将数据发送给需求方进行应答,这就是整个远程帧的数据请求及应答过程。
笔者调试环境有限,只能在一台电脑,一个DSP板之间进行调试,具体为电脑使用Can_Tool给DSP发送远程帧,然后DSP给Can_Tool发送一组数据进行应答。同样的,本次调试的目的是理解掌握远程帧的使用,距离实际工程应用仍然有一定的距离。
远程帧邮箱的配置
本次调试过程中,DSP作为应答方,应该按照应答远程请求的方式进行配置,因为应答方需要向请求方发送数据进行应答,因此邮箱CANMD应清零配置为发送邮箱,与数据帧不同的是,使用远程帧MSGID寄存器中的自动应答模式位AAM应置位,以使DSP收到远程请求时能够自动应答。这要在邮箱处于屏蔽状态下完成,配置完成后使能邮箱。
由于在实际工程中应答方的数据在不断的更新,因此,需求方应该得到应答方不断更新的数据,这就要求每次应答后更新数据域MDH及MDL,根据数据手册,配置在自动应答模式下,数据域应按照以下步骤更新:(1)置位主控制器CANMC的变化数据请求位CDR,设置邮箱号码MBNR,笔者使用8号邮箱作为自动应答邮箱,因此配置主控制器ECanaRegs.CANMC.all = 0x00000108;(2)写入数据到数据寄存器;(3)清除CDR以使能对象 ECanaRegs.CANMC.all = 0x00000000;
DSP应答远程帧的过程
根据数据手册,当DSP收到远程请求时,TRS位会自动置位,数据发送完成后TA位置位,然后可以更新数据域。
总结
本次调试并没有在多个节点中进行,后续考虑在多块DSP直接进行调试
调试记录及源代码
硬件条件:
调试结果:
原代码:
子函数
void eCAN_Remote_Config()
{
struct ECAN_REGS ECanaShadow;
EALLOW;
ECanaShadow.CANMD.all = ECanaRegs.CANMD.all;
ECanaShadow.CANMD.bit.MD8 = 0; //0发送;1接收
ECanaRegs.CANMD.all = ECanaShadow.CANMD.all;
ECanaMboxes.MBOX8.MSGID.all = 0xA0000008; //扩展帧,自动应答,邮箱标识
ECanaMboxes.MBOX8.MSGCTRL.bit.DLC = 8;
ECanaRegs.CANMC.all = 0x00000108;
ECanaMboxes.MBOX8.MDL.byte.BYTE0 = 0;
ECanaMboxes.MBOX8.MDL.byte.BYTE1 = 0;
ECanaMboxes.MBOX8.MDL.byte.BYTE2 = 0;
ECanaMboxes.MBOX8.MDL.byte.BYTE3 = 0;
ECanaMboxes.MBOX8.MDH.byte.BYTE4 = 0;
ECanaMboxes.MBOX8.MDH.byte.BYTE5 = 0;
ECanaMboxes.MBOX8.MDH.byte.BYTE6 = 0;
ECanaMboxes.MBOX8.MDH.byte.BYTE7 = 0;
ECanaRegs.CANMC.all = 0x00000000;
ECanaShadow.CANME.all = ECanaRegs.CANME.all;
ECanaShadow.CANME.bit.ME8 = 1;
ECanaRegs.CANME.all = ECanaShadow.CANME.all;
EDIS;
}
extern int i;
void eCAN_Remote()
{
struct ECAN_REGS ECanaShadow;
ECanaShadow.CANTRS.all = ECanaRegs.CANTRS.all;
if(ECanaShadow.CANTRS.bit.TRS8 == 1) //收到远程帧TRS会自动置位
{
do
{
ECanaShadow.CANTA.all = ECanaRegs.CANTA.all;
}
while(ECanaShadow.CANTA.bit.TA8 != 1); //数据发送之后TA被置位
ECanaShadow.CANTA.bit.TA8 = 0; //手动清零,等下次发送
ECanaRegs.CANTA.all = ECanaShadow.CANTA.all;
ECanaShadow.CANTRS.bit.TRS8 = 0; //清零
ECanaRegs.CANTRS.all = ECanaShadow.CANTRS.all;
}
}
主函数
#include "DSP28x_Project.h"
#include "eCAN.h"
int i;
void interrupt Timer1_isr();
void main(void)
{
InitSysCtrl(); //系统初始化
DINT; //关闭中断
InitPieCtrl(); //初始化中断
IER = 0x0000; //关闭中断使能
IFR = 0x0000; //清空中断标志
InitPieVectTable(); //初始化PIE中断向量表
eCAN_Init();
eCAN_Config();
eCAN_Remote_Config();
EALLOW;
PieVectTable.TINT1 = &Timer1_isr;
EDIS;
InitCpuTimers();
ConfigCpuTimer(&CpuTimer1, 20, 10000000);// (定时时间~s)
CpuTimer1Regs.TCR.all = 0x4001;
StartCpuTimer1();
IER |= M_INT13;
EINT;
ERTM;
for(;;)
{
eCAN_Remote();
eCAN_Rec();
}
}
void interrupt Timer1_isr()
{
if(i == 10)
{
i = 0;
}
else i++;
EALLOW;
ECanaRegs.CANMC.all = 0x00000108;
EDIS;
ECanaMboxes.MBOX8.MDL.byte.BYTE0 = i;
ECanaMboxes.MBOX8.MDL.byte.BYTE1 = i+1;
ECanaMboxes.MBOX8.MDL.byte.BYTE2 = i+2;
ECanaMboxes.MBOX8.MDL.byte.BYTE3 = i+3;
ECanaMboxes.MBOX8.MDH.byte.BYTE4 = i+4;
ECanaMboxes.MBOX8.MDH.byte.BYTE5 = i+5;
ECanaMboxes.MBOX8.MDH.byte.BYTE6 = i+6;
ECanaMboxes.MBOX8.MDH.byte.BYTE7 = i+7;
EALLOW;
ECanaRegs.CANMC.all = 0x00000000;
EDIS;
//eCAN_Send();
}