DSP

DSP28335的CAN总线通讯

2019-07-13 10:22发布

本文将演示DSP28335的CAN通讯,并用示波器验证CAN总线、CAN模块的RX、TX管脚的电压波形。话不多说,直接上代码 Uint32 TestMbox1 = 0;//用来接收mailbox里面的值 Uint32 TestMbox2 = 0; Uint32 TestMbox3 = 0; Uint32 TestMbox4 = 0; Uint32 TestMbox5 = 0; Uint32 TestMbox6 = 0; Uint32 received1[20]; Uint32 received2[20]; Uint32 cnt=0; Uint32 i1=0; Uint32 j1=0; interrupt void ECAN1Receiver(void) { if(ECanbRegs.CANRMP.bit.RMP25==1){ Mailbox1 = &ECanbMboxes.MBOX0 + 25; //CANB读数据 TestMbox1 = Mailbox1->MDL.all; // = 0x (n is the MBX number) TestMbox2 = Mailbox1->MDH.all; // = 0x (a constant) received1[i1]=TestMbox1; received1[i1+1]=TestMbox2; i1=i1+2; TestMbox3 = Mailbox1->MSGID.all;// = 0x (n is the MBX number) ECanbRegs.CANRMP.bit.RMP25=1; } if(ECanbRegs.CANRMP.bit.RMP26==1){ Mailbox2 = &ECanbMboxes.MBOX0 + 26; //CANB读数据 TestMbox4 = Mailbox2->MDL.all; // = 0x (n is the MBX number) TestMbox5 = Mailbox2->MDH.all; // = 0x (a constant) TestMbox6 = Mailbox2->MSGID.all;// = 0x (n is the MBX number) received2[j1]=TestMbox4; received2[j1+1]=TestMbox5; j1=j1+2; ECanbRegs.CANRMP.bit.RMP26=1; } PieCtrlRegs.PIEACK.bit.ACK9=1; } void main(){ struct ECAN_REGS ECanbShadow;//因为CAN的控制寄存器需要32位寻址,不能单独对位操作,所以定义一个中间的寄存器 InitSysCtrl(); InitECanbGpio();//这里使用Ecan模块的b模块,直接用例程的,代码就不贴了 DINT; InitPieCtrl(); IER = 0x0000; IFR = 0x0000; InitPieVectTable(); EALLOW; ECanbRegs.CANGIM.bit.I0EN=1;//中断线0使能 PieVectTable.ECAN0INTB=&ECAN1Receiver;//关联中断子函数,CAN模块的中断线有0和1,这里我使用了0中断线 EDIS; InitECan();//这个是Ecan模块的初始化部分,这里直接抄例程的,代码就不贴出来了。波特率设置为500k baud/s Eallow; ECanbRegs.CANMIM.bit.MIM25=1;//邮箱中断使能 ECanbRegs.CANMIM.bit.MIM26=1;//邮箱中断使能 ECanbRegs.CANMIL.all=0;//邮箱中断级别,设置为0则对应在中断线0出产生中断 ECanbRegs.CANGIF0.all=0xffffffff;//全局中断标志寄存器,写1清0 PieCtrlRegs.PIEIER9.bit.INTx7=1; IER |=0x0100; IFR=0x0000; EDIS; EINT; ERTM; ECanbMboxes.MBOX24.MSGID.all = 0x95555555;//扩展帧,标识符29位 ECanbMboxes.MBOX25.MSGID.all = 0x96666666;//扩展帧,标识符29位 ECanbMboxes.MBOX26.MSGID.all = 0x97777777; //扩展帧,标识符29位 ECanbShadow.CANMD.all = ECanbRegs.CANMD.all; ECanbShadow.CANMD.bit.MD24=0;//配置24作为发送 ECanbShadow.CANMD.bit.MD25 = 1;//配置eCANB的25和26号作为接收邮箱 ECanbShadow.CANMD.bit.MD26=1; ECanbRegs.CANMD.all = ECanbShadow.CANMD.all; //在配置标识符之前必须unable,然后在enable ECanbShadow.CANME.all = ECanbRegs.CANME.all; ECanbShadow.CANME.bit.ME24 = 1; ECanbShadow.CANME.bit.ME25 = 1; ECanbShadow.CANME.bit.ME26 = 1; ECanbRegs.CANME.all = ECanbShadow.CANME.all;//使能邮箱 ECanbMboxes.MBOX24.MSGCTRL.bit.DLC = 8;//8字节的发送数据 ECanbMboxes.MBOX24.MDL.all = 0xAABBCCDD;//发送的数据 ECanbMboxes.MBOX24.MDH.all = 0xDDCCBBAA; for(i=0; i < 20; i++){ //连发20帧数据 ECanbShadow.CANTRS.all = 0; ECanbShadow.CANTRS.bit.TRS24 = 1; // TRS一旦被置位,则立即发送 ECanbRegs.CANTRS.all = ECanbShadow.CANTRS.all; do { ECanbShadow.CANTA.all = ECanbRegs.CANTA.all; } while(ECanbShadow.CANTA.bit.TA24 == 0 ); // Wait for TA5 bit to be set..//如果线没有连接,如果线连接错误 ECanbShadow.CANTA.all = 0; ECanbShadow.CANTA.bit.TA24 = 1; // Clear TA5 ECanbRegs.CANTA.all = ECanbShadow.CANTA.all; } } 以上就是发送和接收的程序。下面我将展示主DSP发送、子DSP接收时的情况
在这里插入图片描述
对应的帧格式如上所示,具体可以参考这篇博文。CAN协议帧格式
这里采用扩展帧,对于发送部分用示波器测的CAN总线上的波形如下,黄 {MOD}代表CAN总线电压,红 {MOD}代表子模块DSP的接收RX管脚电压。这里看到RX管脚和CAN总线相反。是因为CAN总线显性逻辑"0"对应电压2V,而隐性逻辑"1"对应电压0V
在这里插入图片描述
根据500k的波特率,上图128位刚好发送256us,再来看一下数据帧起始地方是否和协议相对应,如下图
在这里插入图片描述
黄 {MOD}代表RX1,红 {MOD}代表RX2(两个DSP的CAN模块来接收)可见首先发送0,再发送1 0101 0101 01 (起始帧+前11位标识符)完全正确 再看数据区
在这里插入图片描述
黄线代表CAN总线差分电压。数据从第40位开始。故对应78us。数据我定义发送AABBCCDD DDCCAABB 这8个字节。这里可以看出白 {MOD}这条虚线左边对应DLC 刚好是1000(0111取反),右边是数据对应AAB(后面的就不一一列出来了)。 当然实际中的CAN不会这么简单。 1. 考虑多个邮箱同时发送,这是要对邮箱设置优先级
2. 同时向总线请求发送时,这时涉及竞争机制。即比较标识符的位
3. 当接收邮箱不断接收到值时,是否覆盖原来的值,这也是需要考虑的问题
4. 使能接收屏蔽,标识符匹配才能被正确的接收。如果只需要一部分匹配,那就要设置接受屏蔽寄存器
5. 另外,此次发了8 byte个数据,不过我发现如果前面发送i byte个数据,再发送j byte个数据,其中i>j,那么后面的数据只会替代掉属于它的那几个byte,有几个byte还是上一次发送i 个byte时候的数据。这个问题暂时还没有解决。还望大家指导下。
6. 最后一点也是最近调试的时候发现了,当CAN 总线上检测出现5个相同的电平位之后,会自动发送一个相反的电平位。这个要注意下