目录

  • 问题描述
  • 配置步骤
    • 初始化
    • 配置引脚和邮箱
    • 中断配置
  • 注意事项
    • 移植代码时输入输出引脚的改变
    • 波特率选择
    • Bit Rate计算
  • CAN模块代码
    • CAN初始化
    • CAN接受中断

问题描述

在学DSP28335的时候由于寄存器数量多且配置复杂,网上各路大神给出的代码基本上都不太能跑的通(可能是我移植的时候有些寄存器没配置好),所以在看了好几遍官方数据手册并且自己动手写了一遍代码之后,将一些容易错的地方记录了下来,文末也附上了一份代码,希望能对大家有所帮助,也欢迎各位一起谈论。

配置步骤

初始化

初始化主要是配置BRPREG和BT,这里需要注意的是CCR和CCE这两个位的读和写,具体流程图参考官方数据手册中给出的初始化流程,这里我也截图放在下面了。

配置引脚和邮箱

这一步就是根据需求配置发送接收引脚和输入输出邮箱,比较简单。

中断配置

中断的配置算是有些复杂的,下面结合官方数据手册中的中断结构图进行说明。

以接收中断为例进行说明。当接收到消息后RMP会被硬件置位,此时想要把成功接收的信息传达给中断线需要经过三个开关。第一个开关是CANMIM[x],这个位是中断使能位,如果被置位就说明RMP被置位后就会引起中断;第二个开关是CANMIL[x],这个位用来选择将前一个开关带来的接收成功的消息送到中断线0还是中断线1,因为CAN模块有两根中断线,所以要这第二个开关进行一个选择,与此同时对应中断标志位GMIF会被置位;最后一个开关是CANGIM,是用来选择是否将中断线接到CPU上去(这个说法不准确,但是可以先这样理解)。总之仔细看看这张图大概就能知道中断应该怎么配了。
同时在接收中断函数中,中断标志位的清除是通过向CANRMP对应位写1实现的,而无法通过GIFx.GMFx位实现。

注意事项

移植代码时输入输出引脚的改变

TI官方例程中将GPIO16、GPIO17分别配置成了ECanb的发送和接收引脚,进行代码移植时要注意自己开发板CAN模块的引脚是否与例程一致,不一致则要进行修改。

波特率选择

不同CAN通信设备的带宽是不一样的,要根据实际需求配置CAN总线的波特率,并且必须保证各个结点的波特率一致。

Bit Rate计算

上面说到了要根据实际需求配置CAN总线的波特率,那么应该怎么算呢,官方数据手册是这样给的:

CAN模块代码

CAN初始化

void ECAN_Init(void){struct ECAN_REGS ECanbShadow;//配置引脚EALLOW;GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 2;GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 2;GpioCtrlRegs.GPAPUD.bit.GPIO16= 0;GpioCtrlRegs.GPAPUD.bit.GPIO17= 0;GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3;EDIS;//配置引脚用于CANEALLOW;ECanbShadow.CANTIOC.all = ECanbRegs.CANTIOC.all;ECanbShadow.CANTIOC.bit.TXFUNC = 1;ECanbRegs.CANTIOC.all = ECanbShadow.CANTIOC.all;ECanbShadow.CANRIOC.all = ECanbRegs.CANRIOC.all;ECanbShadow.CANRIOC.bit.RXFUNC = 1;ECanbRegs.CANRIOC.all = ECanbShadow.CANRIOC.all;EDIS;ECanbRegs.CANME.all = 0;//接收邮箱ECanbMboxes.MBOX0.MSGID.all= 0x9555AAA0;ECanbMboxes.MBOX1.MSGID.all= 0x9555AAA1;ECanbMboxes.MBOX2.MSGID.all= 0x9555AAA2;ECanbMboxes.MBOX3.MSGID.all= 0x9555AAA3;ECanbMboxes.MBOX4.MSGID.all= 0x9555AAA4;ECanbMboxes.MBOX5.MSGID.all= 0x9555AAA5;//发送邮箱ECanbMboxes.MBOX16.MSGID.all = 0x9555AAB0;ECanbMboxes.MBOX17.MSGID.all = 0x9555AAB1;ECanbMboxes.MBOX18.MSGID.all = 0x9555AAB2;ECanbMboxes.MBOX19.MSGID.all = 0x9555AAB3;EALLOW;ECanbShadow.CANMD.all = ECanbRegs.CANMD.all;ECanbShadow.CANMD.bit.MD0= 1;//RxECanbShadow.CANMD.bit.MD1= 1;//RxECanbShadow.CANMD.bit.MD2= 1;//RxECanbShadow.CANMD.bit.MD3= 1;//RxECanbShadow.CANMD.bit.MD4= 1;//RxECanbShadow.CANMD.bit.MD5= 1;//RxECanbShadow.CANMD.bit.MD16 = 0;//TxECanbShadow.CANMD.bit.MD17 = 0;//TxECanbShadow.CANMD.bit.MD18 = 0;//TxECanbShadow.CANMD.bit.MD19 = 0;//TxECanbRegs.CANMD.all = ECanbShadow.CANMD.all;ECanbShadow.CANME.all = ECanbRegs.CANME.all;ECanbShadow.CANME.bit.ME0= 1;ECanbShadow.CANME.bit.ME1= 1;ECanbShadow.CANME.bit.ME2= 1;ECanbShadow.CANME.bit.ME3= 1;ECanbShadow.CANME.bit.ME4= 1;ECanbShadow.CANME.bit.ME5= 1;ECanbShadow.CANME.bit.ME16 = 1;ECanbShadow.CANME.bit.ME17 = 1;ECanbShadow.CANME.bit.ME18 = 1;ECanbShadow.CANME.bit.ME19 = 1;ECanbRegs.CANME.all = ECanbShadow.CANME.all;EDIS;ECanbMboxes.MBOX0.MSGCTRL.bit.DLC= 8;ECanbMboxes.MBOX1.MSGCTRL.bit.DLC= 8;ECanbMboxes.MBOX2.MSGCTRL.bit.DLC= 8;ECanbMboxes.MBOX3.MSGCTRL.bit.DLC= 8;ECanbMboxes.MBOX4.MSGCTRL.bit.DLC= 8;ECanbMboxes.MBOX5.MSGCTRL.bit.DLC= 8;ECanbMboxes.MBOX16.MSGCTRL.bit.DLC = 8;ECanbMboxes.MBOX17.MSGCTRL.bit.DLC = 8;ECanbMboxes.MBOX18.MSGCTRL.bit.DLC = 8;ECanbMboxes.MBOX19.MSGCTRL.bit.DLC = 8;ECanbMboxes.MBOX16.MSGCTRL.bit.RTR= 0;ECanbMboxes.MBOX17.MSGCTRL.bit.RTR= 0;ECanbMboxes.MBOX18.MSGCTRL.bit.RTR= 0;ECanbMboxes.MBOX19.MSGCTRL.bit.RTR= 0;EALLOW;ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;ECanbShadow.CANMC.bit.CCR = 1;ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;EDIS;do{ECanbShadow.CANES.all = ECanbRegs.CANES.all;}while(ECanbShadow.CANES.bit.CCE != 1 );EALLOW;ECanbShadow.CANBTC.all = ECanbRegs.CANBTC.all;ECanbShadow.CANBTC.bit.BRPREG = 9;ECanbShadow.CANBTC.bit.TSEG2REG = 2 ;ECanbShadow.CANBTC.bit.TSEG1REG = 10;// Bit time = 15ECanbShadow.CANBTC.bit.SAM = 1;ECanbRegs.CANBTC.all = ECanbShadow.CANBTC.all;ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;ECanbShadow.CANMC.bit.CCR = 0;ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;EDIS;do{ECanbShadow.CANES.all = ECanbRegs.CANES.all;} while(ECanbShadow.CANES.bit.CCE != 0 );ECanbRegs.CANTA.all = 0xFFFFFFFF;//清除所有TA位EALLOW;ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;ECanbShadow.CANMC.bit.STM = 0;ECanbShadow.CANMC.bit.SCB = 1;// eCAN mode (reqd to access 32 mailboxes)ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;EDIS;EALLOW;ECanbRegs.CANGIM.all = 0;ECanbRegs.CANMIM.all = 0x003F;//使能上面的接收邮箱(0-5号邮箱)中断ECanbRegs.CANMIL.all = 0;ECanbShadow.CANGIM.all = ECanbRegs.CANGIM.all;ECanbShadow.CANGIM.bit.I0EN = 1;//选择中断线0ECanbRegs.CANGIM.all = ECanbShadow.CANGIM.all;PieCtrlRegs.PIECTRL.bit.ENPIE=1;PieCtrlRegs.PIEIER9.bit.INTx7=1;//9.7PieVectTable.ECAN0INTB = &ISRECanRx;IER|=M_INT9;EINT;EDIS;}

CAN接受中断

interrupt void ISRECanbRx(void){PieCtrlRegs.PIEACK.bit.ACK9 = 1;struct ECAN_REGS ECanbShadow;Uint16 group;Uint32 high;//用于存储接收邮箱的内容Uint32 low; //用于存储接收邮箱的内容volatile struct MBOX* Mailbox;group = (ECanbRegs.CANGIF0.all)&0x3F; //判断是哪个接收邮箱触发的中断Mailbox = &ECanbMboxes.MBOX0 + group; //取触发中断邮箱的地址switch(group)//我这里是把0-5号邮箱配置成了接收邮箱,所以下面case的取值是0-5{case 0:low = Mailbox->MDL.all//低32位high= Mailbox->MDH.all//高32位break;case 1://跟上面是一样的,把邮箱里的数取出来break;case 2:break;case 3:break;case 4:break;case 5:break;default:break;}ECanbRegs.CANRMP.all = 0x0000003F; //清除GIF0.GMIF位,即中断标志位}