问题
CAN模块相对与其他模块,寄存器配置较为复杂,官方历程不能实现期望的功能,网上搜到的程序并不全面,在不断的调试更改代码之后,实现了DSP与上位机之间的通信。
配置流程
寄存器初始化:首先需要对寄存器初始化,以满足CAN通信基本的寄存器要求。具体配置过程与官方实例基本相同,首先对GPIO口配置,复用CAN功能。然后通过CANTIOC及CANRIOC配置CAN的接收及发送功能,通过SCB位选择16邮箱或32邮箱模式,然后对邮箱初始化,然后相关的标志位置位,具体按照官方实例配置,需要注意的是波特率BTC寄存器的配置,波特率的计算公式为:
波特率=SysClock/[2*(BRP+1)*[(TSEGREG1+1)+(TSEGREG2+1)+1]],且要满足TSEG1REG1> TSEG1REG2
与SCI不同的是,如果波特率不对,CAN是接收不到或者发送不了数据的,而SCI波特率不对则是乱码,因此,如果在调试过程中出现收不到数据的情况,需要格外注意波特率的配置,笔者所用用的DSP为TMS320F28062,CPU最大主频为90MHz,晶振20MHz,起初笔者认为就是20MHz,与是按照
=20MHz配置BTC寄存器,一直无法通信,一度的怀疑初始化程序有问题,后来按照90MHz配置,BRP=5,TSEGREG1=10,TSEGREG2=2,波特率为500K,功能就正常了。在配置BTC寄存器前,CCR位置位,以允许对BTC配置,然后等待CCE置位进行下一步配置,BTC配置完成后CCE需要清零,配置完成后需要确保所有邮箱处于屏蔽状态,因为只有在邮箱处于屏蔽状态才能对邮箱标识符进行配置。
邮箱配置:经过以上流程CAN模块配置完成,具备了CAN功能,然后进行邮箱配置,首先配置邮箱标识符寄存器MSGID,然后配置邮箱为发送或者接收,然后使能邮箱,接收邮箱还需要配置数据长度,数据长度最大为8。通过以上步骤CAN模块就具备了接收及发送功能。
发送及接收函数:发送及接收消息数据寄存器同为CANMDL及CANMDH,消息发送前需要先对CANMDL及CANMDH赋值,然后相应的CANTRS寄存器置位以启动发送,消息发送完成后CANTA置位,表明消息发送成功。在接受消息时,当接收到消息时CANRMP寄存器相应的位置位,然后读取消息数据寄存器同为CANMDL及CANMDH的值,读取完成后,接收到消息时CANRMP寄存器相应的位清零,以等待下一次接收数据。
总结:通过以上操作便可以实现CAN与上位机的通信,需要注意的是,以上配置流程只是为了进一步对CAN模块的理解,以便掌握CAN模块的使用,更复杂的应用仍然需要不断的尝试。
调试过程
邮箱0~3为发送邮箱,4~7为接收邮箱,DSP通过定时器中断发送数据给上位机,在主函数中接收上位机发送的数据。
硬件条件:
软件条件:
接收结果:
具体代码:
子函数
#include "DSP28x_Project.h"
/*eCAN模块初始化,*/
void eCAN_Init()
{
struct ECAN_REGS ECanaShadow;
/*GPIO配置*/
EALLOW;
GpioCtrlRegs.GPAPUD.bit.GPIO30 = 0;
GpioCtrlRegs.GPAPUD.bit.GPIO31 = 0;
GpioCtrlRegs.GPAQSEL2.bit.GPIO30 = 3;
GpioCtrlRegs.GPAMUX2.bit.GPIO30 = 1;
GpioCtrlRegs.GPAMUX2.bit.GPIO31 = 1;
EDIS;
/*配置发送及接收功能*/
EALLOW;
ECanaShadow.CANTIOC.all = ECanaRegs.CANTIOC.all;
ECanaShadow.CANTIOC.bit.TXFUNC = 1;
ECanaRegs.CANTIOC.all = ECanaShadow.CANTIOC.all;
ECanaShadow.CANRIOC.all = ECanaRegs.CANRIOC.all;
ECanaShadow.CANRIOC.bit.RXFUNC = 1;
ECanaRegs.CANRIOC.all = ECanaShadow.CANRIOC.all;
/*eCAN增强模式*/
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.SCB = 1;
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
/*邮箱初始化*/
ECanaMboxes.MBOX0.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX1.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX2.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX3.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX4.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX5.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX6.MSGCTRL.all = 0x00000000;
ECanaMboxes.MBOX7.MSGCTRL.all = 0x00000000;
/*发送消息成功标志位初始化*/
ECanaRegs.CANTA.all = 0xFFFFFFFF;
/*接收消息挂起标志位初始化*/
ECanaRegs.CANRMP.all = 0xffffffff;
/*中断初始化*/
ECanaRegs.CANGIF0.all = 0xFFFFFFFF;
ECanaRegs.CANGIF1.all = 0xFFFFFFFF;
/*CCR为1时允许对BTC配置*/
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.CCR = 1 ;
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
/*CCE为1时进行下一步*/
do
{
ECanaShadow.CANES.all = ECanaRegs.CANES.all;
}
while(ECanaShadow.CANES.bit.CCE != 1 );
ECanaShadow.CANBTC.all = 0;
/* 设置波特率
* 波特率=SysClock/2/[(brp+1)/(tseg1+1+tseg2+1+1)]
* 90MHz系统时钟波特率为90/2/6/15=0.5M=500k
*/
ECanaShadow.CANBTC.bit.BRPREG = 5;
ECanaShadow.CANBTC.bit.TSEG2REG = 2;
ECanaShadow.CANBTC.bit.TSEG1REG = 10;
ECanaRegs.CANBTC.all = ECanaShadow.CANBTC.all;
/*清除CCR位,对主控制器配置*/
ECanaShadow.CANMC.all = ECanaRegs.CANMC.all;
ECanaShadow.CANMC.bit.CCR = 0 ;
ECanaRegs.CANMC.all = ECanaShadow.CANMC.all;
/*CCE位清除表明eCAN模块配置完成*/
do
{
ECanaShadow.CANES.all = ECanaRegs.CANES.all;
}
while(ECanaShadow.CANES.bit.CCE != 0 );
/*MSGIDs配置前屏蔽邮箱,MSGIDs只能在邮箱屏蔽时配置*/
ECanaRegs.CANME.all = 0;
EDIS;
}
void eCAN_Config()
{
ECanaMboxes.MBOX0.MSGID.all = 0x80000000;
ECanaMboxes.MBOX1.MSGID.all = 0x80000001;
ECanaMboxes.MBOX2.MSGID.all = 0x80000002;
ECanaMboxes.MBOX3.MSGID.all = 0x80000003;
ECanaMboxes.MBOX4.MSGID.all = 0x80000004;
ECanaMboxes.MBOX5.MSGID.all = 0x80000005;
ECanaMboxes.MBOX6.MSGID.all = 0x80000006;
ECanaMboxes.MBOX7.MSGID.all = 0x80000007;
ECanaRegs.CANMD.all = 0x000000f0; //0~3发送邮箱,4~7接收邮箱
ECanaRegs.CANME.all = 0x000000ff; //使能0~7号邮箱
ECanaMboxes.MBOX0.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX1.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX2.MSGCTRL.bit.DLC = 8;
ECanaMboxes.MBOX3.MSGCTRL.bit.DLC = 8;
}
void eCAN_Send()
{
ECanaMboxes.MBOX0.MDL.all = 0x01000000;
ECanaMboxes.MBOX0.MDH.all = 0x00000000;
ECanaMboxes.MBOX1.MDL.all = 0x02000000;
ECanaMboxes.MBOX1.MDH.all = 0x00000000;
ECanaMboxes.MBOX2.MDL.all = 0x03000000;
ECanaMboxes.MBOX2.MDH.all = 0x00000000;
ECanaMboxes.MBOX3.MDL.all = 0x04000000;
ECanaMboxes.MBOX3.MDH.all = 0x00000000;
ECanaRegs.CANTRS.all = 0x0000000f;
while(ECanaRegs.CANTA.all != 0x0000000f) {}
ECanaRegs.CANTA.all = 0x0000000f;
}
int Rec_msg[] = {0,0,0,0,0,0,0,0};
void eCAN_Rec()
{
struct ECAN_REGS ECanaShadow;
ECanaShadow.CANRMP.all = ECanaRegs.CANRMP.all;
if(ECanaShadow.CANRMP.bit.RMP4 == 1) //RMP置位表明邮箱中包含一个接收到的消息,
{
Rec_msg[0] = ECanaMboxes.MBOX4.MDL.byte.BYTE0;
Rec_msg[1] = ECanaMboxes.MBOX4.MDL.byte.BYTE1;
Rec_msg[2] = ECanaMboxes.MBOX4.MDL.byte.BYTE2;
Rec_msg[3] = ECanaMboxes.MBOX4.MDL.byte.BYTE3;
Rec_msg[4] = ECanaMboxes.MBOX4.MDH.byte.BYTE4;
Rec_msg[5] = ECanaMboxes.MBOX4.MDH.byte.BYTE5;
Rec_msg[6] = ECanaMboxes.MBOX4.MDH.byte.BYTE6;
Rec_msg[7] = ECanaMboxes.MBOX4.MDH.byte.BYTE7;
}
ECanaShadow.CANRMP.bit.RMP4 = 0; //接收消息读完清零,等待下一次接收消息
ECanaRegs.CANRMP.all = ECanaShadow.CANRMP.all;
}
主函数:
#include "DSP28x_Project.h"
#include "eCAN.h"
void interrupt Timer1_isr();
void main(void)
{
InitSysCtrl(); //系统初始化
DINT; //关闭中断
InitPieCtrl(); //初始化中断
IER = 0x0000; //关闭中断使能
IFR = 0x0000; //清空中断标志
InitPieVectTable(); //初始化PIE中断向量表
eCAN_Init();
eCAN_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_Rec();
}
}
void interrupt Timer1_isr()
{
eCAN_Send();
}