void InitECanbGpio(void)
{
EALLOW;//配置GPIO引脚工作在eCAN功能
GpioCtrlRegs.GPAPUD.bit.GPIO16 = 1; // Disable pull-up for GPIO16 (CANTXB)
GpioCtrlRegs.GPAPUD.bit.GPIO17 = 0; // Enable pull-up for GPIO17 (CANRXB)
GpioCtrlRegs.GPAQSEL2.bit.GPIO17 = 3; // Asynch qual for GPIO17 (CANRXB)
GpioCtrlRegs.GPAMUX2.bit.GPIO16 = 2; // Configure GPIO16 for CANTXB operation
GpioCtrlRegs.GPAMUX2.bit.GPIO17 = 2; // Configure GPIO17 for CANRXB operation
EDIS;
}
使用到的寄存器如下所示:
上拉输入的好处是减小了电流,输入的电平不会上下浮动而导致输入信号不稳定,在没有信号输入的情况下可以稳定在高电平。
总结:
EALLOW; //配置eCAN的RX和TX分别为eCAN的接收和发送引脚
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;
EALLOW;
ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;
ECanbShadow.CANMC.bit.STM = 0;//非自测模式
ECanbShadow.CANMC.bit.SCB = 1;//eCAN模式
ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;
EDIS;
//初始化所有主设备控制区域为0,MCF所有的位都初始化为0
ECanbMboxes.MBOX0.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX1.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX2.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX3.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX4.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX5.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX6.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX7.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX8.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX9.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX10.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX11.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX12.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX13.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX14.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX15.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX16.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX17.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX18.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX19.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX20.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX21.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX22.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX23.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX24.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX25.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX26.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX27.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX28.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX29.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX30.MSGCTRL.all = 0x00000000;
ECanbMboxes.MBOX31.MSGCTRL.all = 0x00000000;
接下来进行的是相关寄存器的置位工作,包括邮箱发送和接收相关、中断标志位置位,并请求对SCC模式下的CANBTC寄存器进行设置。
EALLOW;
ECanbShadow.CANTA.all = ECanbRegs.CANTA.all;
ECanbShadow.CANTA.all = 0xFFFFFFFF;
ECanbRegs.CANTA.all = ECanbShadow.CANTA.all;
ECanbShadow.CANRMP.all = ECanbRegs.CANRMP.all;
ECanbShadow.CANRMP.all = 0xFFFFFFFF;
ECanbRegs.CANRMP.all = ECanbShadow.CANRMP.all;
//添加
ECanbShadow.CANGIF0.all = ECanbRegs.CANGIF0.all;
ECanbShadow.CANGIF0.all = 0xFFFFFFFF;
ECanbRegs.CANGIF0.all = ECanbShadow.CANGIF0.all;
//添加
ECanbShadow.CANGIF1.all = ECanbRegs.CANGIF1.all;
ECanbShadow.CANGIF1.all = 0xFFFFFFFF;
ECanbRegs.CANGIF1.all = ECanbShadow.CANGIF1.all;
/* Configure bit timing parameters for eCANB*/
ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;
ECanbShadow.CANMC.bit.CCR = 1 ; // Set CCR = 1
ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;
CANME寄存器的CCE为被置位后,可以进行波特率的设置了。
do
{ECanbShadow.CANES.all=ECanbRegs.CANES.all;}
while(ECanbShadow.CANES.bit.CCE != 1 ) ; // Wait for CCE bit to be set..
ECanbShadow.CANBTC.all = ECanbRegs.CANBTC.all; //添加
ECanbShadow.CANBTC.all = 0;
ECanbShadow.CANBTC.bit.BRPREG = 9;
/* TQ=1/(SYSCLKOUT/4)×(BRPREG+1) */
ECanbShadow.CANBTC.bit.TSEG2REG = 2;
ECanbShadow.CANBTC.bit.TSEG1REG = 10;
ECanbShadow.CANBTC.bit.SAM = 1;
ECanbRegs.CANBTC.all = ECanbShadow.CANBTC.all;
ECanbShadow.CANMC.all = ECanbRegs.CANMC.all;
ECanbShadow.CANMC.bit.CCR = 0 ; // Set CCR = 0
ECanbRegs.CANMC.all = ECanbShadow.CANMC.all;
do
{
ECanbShadow.CANES.all = ECanbRegs.CANES.all;
} while(ECanbShadow.CANES.bit.CCE != 0 ); // Wait for CCE bit to be cleared..
对邮箱的相应配置进行设置。
ECanbRegs.CANME.all = 0;//屏蔽所有邮箱,在写MSGID之前必须要做
EDIS;
ECanbMboxes.MBOX0.MSGID.bit.IDE = 0;//标准帧格式
...
ECanbMboxes.MBOX31.MSGID.bit.IDE = 0;
ECanbMboxes.MBOX0.MSGCTRL.bit.DLC = 8;//数据长度8个字节
...
ECanbMboxes.MBOX31.MSGCTRL.bit.DLC = 8;//数据长度8个字节
ECanbMboxes.MBOX0.MSGCTRL.bit.TPL = 0;//设置优先级
...
ECanbMboxes.MBOX31.MSGCTRL.bit.TPL = 31;//设置优先级
ECanbMboxes.MBOX0.MSGCTRL.bit.RTR = 0;//没有远程帧请求
...
ECanbMboxes.MBOX31.MSGCTRL.bit.RTR = 0;//没有远程帧请求
EALLOW;
EALLOW;
ECanbRegs.CANMIM.all = 0xFFFFFFFE;
//邮箱中断将产生在ECAN0INT
ECanbRegs.CANMIL.all = 0;
ECanbRegs.CANGIF0.all = 0xFFFFFFFF;
ECanbRegs.CANGIF1.all = 0xFFFFFFFF;
//ECAN0INT中断请求线被使能
ECanbRegs.CANGIM.bit.I0EN = 1;
EDIS;
总结:
先要对中断向量进行配置,这里要查看中断向量表,查看ECAN0INTB中断是在哪一条中断线上,又是这条中断线上的第几个中断向量。
EALLOW;
PieVectTable.TINT0 = &ISRTimer0;//计时器中断向量
PieVectTable.ECAN0INTB = &ISRCanb;//eCAN模块中断向量
EDIS;
PieCtrlRegs.PIECTRL.bit.ENPIE = 1;//所有向量取自PIE向量表
PieCtrlRegs.PIEIER1.bit.INTx5 = 1;//XINT2
PieCtrlRegs.PIEIER1.bit.INTx7 = 1;//TINT0
PieCtrlRegs.PIEIER9.bit.INTx7 = 1;//ECAN0INTB
IER |= M_INT9;//中断9使能
IER |= M_INT1;//中断1使能
IER |= M_INT14;//中断14使能
EINT;//使能全局中断
ERTM;//使能实时中断
接下来要设置接收邮箱和发送邮箱。
MSGb_Init(0,0,0x0601); //cana mail 0 send 电机1
MSGb_Init(1,1,0x0581); //cana mail 1 resive
MSGb_Init(2,0,0x0602); //cana mail 2 send 电机2
MSGb_Init(3,1,0x0582); //cana mail 3 resive 电机2
MSGb_Init(4,0,0x0080); //cana mail 4 send 发送同步帧
MSGb_Init(5,0,0x0203); //cana mail 5 send 发送数字量邮箱
MSGb_Init(6,0,0x0303); //cana mail 6 send 发送模拟量邮箱
MSGb_Init(7,0,0x0403); //cana mail 7 send 发送模拟量邮箱
MSGb_Init(8,1,0x0183); //cana mail 8 resive
MSGb_Init(9,1,0x0283); //cana mail 9 resive
MSGb_Init(10,1,0x0383); //cana mail 10 resive
MSGb_Init(11,1,0x0483); //cana mail 11 resive
MSGb_Init(12,0,0x0000); //启动所有节点
MSGb_Init(13,0,0x0603); //配置周期发送
我们需要看一下MSGb_Init函数是怎么配置邮箱的。
void MSGb_Init(Uint16 msgnum,Uint16 dir,Uint32 id)
{
struct ECAN_REGS ECanbShadow;
switch (msgnum)
{
case 0:
ECanbShadow.CANMD.all = ECanbRegs.CANMD.all;
ECanbShadow.CANMD.bit.MD0 = dir; //邮箱0设置为发送
ECanbRegs.CANMD.all = ECanbShadow.CANMD.all;
if(dir==1)
{
ECanbMboxes.MBOX0.MSGID.bit.AME=1;//接收屏蔽
}
ECanbMboxes.MBOX0.MSGID.all = (id << 18);
ECanbShadow.CANME.all = ECanbRegs.CANME.all;
ECanbShadow.CANME.bit.ME0 = 1;//使能
ECanbRegs.CANME.all = ECanbShadow.CANME.all;
break;
......
当我们定义的接收邮箱收到信息后,就会触发邮箱中断,转而去执行中断子程序,中断路线如下。
根据之前的初始化工作,我们知道当邮箱1或邮箱3收到信息后,就会将其RMP为置1,即触发中断邮箱接收中断,同时若CANMIM和CANMIL寄存器对应位都被使能,则会通过CANGIM寄存器将所有中断映射到ECAN0INT中断线上。
interrupt void ISRCanb(void)
{
switch(ECanbRegs.CANRMP.all)//如果收到消息,CANRMP将有位被置1
{
......
case 0x00000002://1
ECanbRegs.CANRMP.all=0xffffffff;//清除接收完成标志
L[1] = ECanbMboxes.MBOX1.MDL.all;
H[1] = ECanbMboxes.MBOX1.MDH.all;
if(L[1] == 0x436C6000)
{
HisBuffer_v1[0] = 0x05;
HisBuffer_v1[1] = 0x81;
HisBuffer_v1[2] = (L[1] >> 24) & 0xff;
HisBuffer_v1[3] = (L[1] >> 16) & 0xff;
HisBuffer_v1[4] = (L[1] >> 8) & 0xff;
HisBuffer_v1[5] = L[1] & 0xff;
HisBuffer_v1[6] = H[1] & 0xff;
HisBuffer_v1[7] = (H[1] >> 8) & 0xff;
HisBuffer_v1[8] = (H[1] >> 16) & 0xff;
HisBuffer_v1[9] = (H[1] >> 24) & 0xff;
flag_send_v1 = 1;
}
break;
case 0x00000004: //2
ECanbRegs.CANRMP.all=0xffffffff;
L[2] = ECanbMboxes.MBOX2.MDL.all;
H[2]= ECanbMboxes.MBOX2.MDH.all;
break;
case 0x00000008: //3 电机2
ECanbRegs.CANRMP.all=0xffffffff;//清除接收完成标志
L[3] = ECanbMboxes.MBOX3.MDL.all;
H[3] = ECanbMboxes.MBOX3.MDH.all;
if(L[3] == 0x436C6000)
{
HisBuffer_v2[0] = 0x05;
HisBuffer_v2[1] = 0x82;
HisBuffer_v2[2] = (L[3] >> 24) & 0xff;
HisBuffer_v2[3] = (L[3] >> 16) & 0xff;
HisBuffer_v2[4] = (L[3] >> 8) & 0xff;
HisBuffer_v2[5] = L[3] & 0xff;
HisBuffer_v2[6] = H[3] & 0xff;
HisBuffer_v2[7] = (H[3] >> 8) & 0xff;
HisBuffer_v2[8] = (H[3] >> 16) & 0xff;
HisBuffer_v2[9] = (H[3] >> 24) & 0xff;
flag_send_v2 = 1;
}
break;
......
由程序可以发现,当任意RMP位被置位后,就会进入中断,而我们使能的接收邮箱是邮箱1和邮箱3,那么其对应RMP位被置位,就会进入对应的程序段。我们所要做的是将接收到的数据重新进行处理,写入数组HisBuffer中,然后将以太网发送标志置1,再通过以太网发送出去。以太网通信是后续我们需要讨论的了。