问题描述
在学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总线的波特率,并且必须保证各个结点的波特率一致。文章来源:https://www.toymoban.com/news/detail-503321.html
Bit Rate计算
上面说到了要根据实际需求配置CAN总线的波特率,那么应该怎么算呢,官方数据手册是这样给的:
文章来源地址https://www.toymoban.com/news/detail-503321.html
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;
//配置引脚用于CAN
EALLOW;
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; //Rx
ECanbShadow.CANMD.bit.MD1 = 1; //Rx
ECanbShadow.CANMD.bit.MD2 = 1; //Rx
ECanbShadow.CANMD.bit.MD3 = 1; //Rx
ECanbShadow.CANMD.bit.MD4 = 1; //Rx
ECanbShadow.CANMD.bit.MD5 = 1; //Rx
ECanbShadow.CANMD.bit.MD16 = 0; //Tx
ECanbShadow.CANMD.bit.MD17 = 0; //Tx
ECanbShadow.CANMD.bit.MD18 = 0; //Tx
ECanbShadow.CANMD.bit.MD19 = 0; //Tx
ECanbRegs.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 = 15
ECanbShadow.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; //选择中断线0
ECanbRegs.CANGIM.all = ECanbShadow.CANGIM.all;
PieCtrlRegs.PIECTRL.bit.ENPIE=1;
PieCtrlRegs.PIEIER9.bit.INTx7=1; //9.7
PieVectTable.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位,即中断标志位
}
到了这里,关于基于DSP28335的CAN通信(附代码)的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!