1、CAN模块结构
5744CAN模块主要由CHI(Control Host Interface)、PE(Protocol Engine)和MBs三个部分组成,其中CHI负责发送仲裁和接收匹配,PE负责时钟等的配置,MBs进行消息的存储。结构如下图所示:
2、MB(Message Buffer)结构
5744含有多达64个MB(Mailbox)进行数据的收发,通过配置对应MB的C/S寄存器来进行数据发送或接收。其结构如下:
-
CODE 缓存器码,是进行缓存器匹配和仲裁过程的一部分,编码如下所示:
0b0000 MB用于接收且未激活
0b0100 MB用于发送、激活并且为空,准备接收数据
0b0010 MB用于接收且为满
0b0110 MB用于接收且为OVERRUN,并且被overwrite
0b1010 MB接收到一个远程帧数据并发送一帧数据作为回应
0bxxx1 MB用于接收且正在更新MB的内容,此时CPU禁止范围MB。
0b1000 MB为用于发送且未激活
0b1001 MB用于发送且被中止
0b1100 MB用于发送,当RTR为0时内部消息为数据帧,当 RTR为1时,内部消息为远程帧
0b1110 MB用于发送,为进入的远程请求帧发送一帧数据作为回应 -
SRR 替代远程请求 固定为隐形,该位发送时必须被设置为1,若接收到时不为1,则仲裁丢失
-
IDE ID标识位 1:MB内为扩展帧 0:MB内为标准帧
-
RTR 远程传输请求 1 :当前MB有一个远程请求帧要传输 0:当前MB有一个数据帧要传输
-
DLC 当前MB内数据的字节长度
-
TIMESTAMP 自由运行时间戳
-
PRIO 本地优先级,使能情况下,对于发送信箱有意义,参与发送仲裁过程
-
ID 帧ID
-
DATA BYTE0-7 数据域
3、模块配置
1、波特率设置
CAN时钟可选择外设时钟或晶振时钟作为时钟源,再时钟源选定以后可进行波特率的配置。公式如下:
其中Time Quanta的组成如下:
则可通过配置PRESDIV、PSEG1、PSEG2、PROPSEG的值配置不同的波特率,综合上述两个式子波特率计算公式为:
Bit Rate=
fcanclk/([1 + (PSEG1 + 1) + (PSEG2 + 1) + (PROPSEG + 1)] x (PRESDIV + 1))
其中各个值的范围和彼此的限制关系如下:
由于CAN模块具有较多的MB,在进行发送仲裁的时候需要耗费一定的时间,为了给发送仲裁留充足的时间,外设时钟(控制CHI的时钟)和比特率需要保证一定的比率,也就是在处理每CAN bit的外设时钟数要足够大,计算公式如下:
fsys为系统时钟,即是外设桥时钟,NCCP就是每CAN bit 耗费的外设时钟数,随着采用MB的数目的增加应调整NCCP的值,对应关系如下:
2、CAN模块配置过程
1)多路复用功能选择
2)运行模式选择
3)进行时钟源的选择(需要先失能CAN模块然后再打开);
4)使能Frzee模式并进入Frzee模式以进行波特率配置;
5)进行波特率的配置
6)退出Frzee模式并确认
3、示例代码
/******************************************* 名称 CAN_CAN0_Init* 说明 进行CAN0的初始化* 输入参数 无* 返回值 无* 示例 CAN_CAN0_Init();//进行CAN0的初始化*******************************************/
void CAN_CAN0_Init()
{uint8_t i=0;SIUL2.MSCR[16].B.SSS=1; //PB0复用为CAN0_TXSIUL2.MSCR[16].B.OBE=1;SIUL2.MSCR[16].B.SRC=3;SIUL2.MSCR[17].B.IBE=1; //PB1复用为CAN0_RXSIUL2.IMCR[32].B.SSS=2;MC_ME.PCTL79.B.RUN_CFG=0; //选择运行模式0CAN_0.MCR.B.MDIS=1; //关闭CAN模块CAN_0.CTRL1.B.CLKSRC=0; //选择晶振作为CAN时钟源CAN_0.MCR.B.MDIS=0; //开启CAN模块CAN_0.MCR.B.FRZ=1; //允许进入Frzee 模式CAN_0.MCR.B.HALT=1; //请求进入Frzee 模式while(!CAN_0.MCR.B.FRZACK);//确认进入frzee 模式CAN_0.CTRL1.B.PRESDIV=9; //bit rate=fcanclk/([1+(PSEG1+1)+(PSEG2+1)+(PROPSEG+1)]x(PRESDIV+1))CAN_0.CTRL1.B.PSEG1=3; //=40MHz/((1+4+4+7)*10)=1/4MHz=250kHzCAN_0.CTRL1.B.PSEG2=3;CAN_0.CTRL1.B.PROPSEG=6;CAN_0.CTRL1.B.RJW=3; //配置 Resync Jump Width为3+1=4for(i=0;i<64;i++) //复位MBs为失活状态{CAN_0.MB[0].CS.B.CODE=0;}CAN_0.MCR.B.MAXMB=63; //选择最大可以数据缓存为默认,默认为63CAN_0.MCR.B.HALT=0; //退出 Frzee模式while(CAN_0.MCR.B.FRZACK & CAN_0.MCR.B.NOTRDY); //等待退出Frzee模式
}
4、缓存器配置
在进行CAN模块的配置后,在使用CAN收发之前,还需要对所需的缓冲器进行配置,具体函数及实现如下:
/********************************************************** 名称 CAN_CAN0_TMB_Config* 说明 将制定MB配置为发送缓存器* 输入参数* CAN_MBx* 配置为发送的MB x可为0-63* 返回值 无* 示例 CAN_CAN0_TMB_Config(CAN_MB0);//配置MB0为发送缓存器*/
void CAN_CAN0_TMB_Config(uint8_t CAN_MBx)
{CAN_0.MB[CAN_MBx].CS.B.CODE=0; //设置CAN_MBx为失活CAN_0.MB[CAN_MBx].CS.B.CODE=8; //设置CAN_MBx为发送激活
}/********************************************************** 名称 CAN_CAN0_RMB_Config* 说明 将指定MB配置为接收缓冲器 并设置接收ID和接收中断优先级* 输入参数* CAN_MBx* 所指定的MB x可为0~63* id* 所指定的MB可接收的CAN帧ID* prio* 所指定MB接收数据的优先级* 返回值 无* 示例 CAN_CAN0_RMB_Config(CAN_MB7,0x18FF9400,11);//配置MB7接收帧ID为0x18FF9400的数据,且设置其接收中断优先级为11*/
void CAN_CAN0_RMB_Config(uint8_t CAN_MBx,uint32_t id,uint8_t prio)
{CAN_0.MB[CAN_MBx].CS.B.CODE=0; //将CAN_MBx设为失活CAN_0.MB[CAN_MBx].CS.B.IDE=1; //设置CAN_MBx接收扩展帧CAN_0.MB[CAN_MBx].ID.R=id; //设置CAN_MBx能接收的数据帧的IDif(CAN_MBx <= 31) //打开CAN_MBx的接收中断{CAN_0.IMASK1.R |=(1<<CAN_MBx);}else{CAN_0.IMASK2.R |=(1<<(CAN_MBx-32));}INTC_0.PSR[522+CAN_MBx/4].R=0x8000|prio; //设置CAN_MBx的接收中断优先级CAN_0.MB[CAN_MBx].CS.B.CODE=4;
}
4、传输过程
1、发送过程
1)检测对应标志位是否被置位并清除;
2)如果要使用的MB为激活状态,则写入中止码(0b1001)中止传输过程(或直接写入失活码(0b1000)失活对应MB);
3)写入ID、数据字节、数据长度,设置SRR、RTR、IDE等;
4)写入激活码激活MB参与发送仲裁进行传输。
2、示例代码
/******************************************************** 名称 CAN_CAN0_Send* 说明 采用CAN0发送指定数据* 输入参数* can_msg* 要发送的CAN信息* 返回值 无* 示例 CAN_CAN0_Send(can_msg);//发送CAN信息can_msg********************************************************/
void CAN_CAN0_Send(uint8_t CAN_MBx,const CAN_Msg_Struct can_msg)
{uint8_t i=0;CAN_0.MB[CAN_MBx].CS.B.CODE=0b1000; //失活MB0CAN_0.MB[CAN_MBx].ID.R=can_msg.id; //设置IDfor(i=0;i<8;i++)CAN_0.MB[CAN_MBx].DATA.B[i]=can_msg.data[i];//设置数据CAN_0.MB[CAN_MBx].CS.B.DLC=can_msg.len; //设置数据长度CAN_0.MB[CAN_MBx].CS.B.SRR=1; //设置SRR 强制为1CAN_0.MB[CAN_MBx].CS.B.IDE=1; //发送帧为扩展帧CAN_0.MB[CAN_MBx].CS.B.RTR=0; //非请求帧CAN_0.MB[CAN_MBx].CS.B.CODE=0b1100; //设置MB0为发送激活 参与发送仲裁进行发送
}
3、接收过程
接收过程一般采用中断,本文只介绍CAN接收过程,具体中断配置参见PIT模块的介绍。
1)为保证数据完整新,先读取MB的C/S寄存器上锁MB;
2)读取ID、数据长度、数据等;
3)读取自由运行定时器解锁MB;
4)清零对应标志位;
4、示例代码
/************************************** 名称 CAN_CAN0_Msg_Set* 说明 将CAN_MBx内的数据加载入对应的数据帧内* 输入参数* p_can_msg* 对应数据帧的指针* CAN_MBx* 要赋值的数据帧对应的MB* 返回值 无*/
void CAN_CAN0_Msg_Set(CAN_Msg_Struct* p_can_msg,uint8_t CAN_MBx)
{uint8_t i=0;uint32_t dummy=0;dummy=CAN_0.MB[CAN_MBx].CS.R;p_can_msg->id=CAN_0.MB[CAN_MBx].ID.R; //用于测试p_can_msg->len=CAN_0.MB[CAN_MBx].CS.B.DLC;for(i=0;i<p_can_msg->len;i++){p_can_msg->data[i]=CAN_0.MB[CAN_MBx].DATA.B[i];}dummy=CAN_0.TIMER.R;
}
/**************************************** 函数名 CAN_CAN0_Rx4_7_Isr* 功能 CAN_0 MB4-7中断接收函数* 输入参数 无* 返回值 无****************************************/
void CAN_CAN0_Rx4_7_Isr()
{uint32_t flags=0;flags=CAN_0.IFLAG1.R;if((flags&0x000000F0)== CAN_MB4_FLAG){CAN_CAN0_Msg_Set(&GL_Can_Msg,CAN_MB4);CAN_0.IFLAG1.R |= (1<<CAN_MB4);}else if((flags&0x000000F0)== CAN_MB5_FLAG){//GPIO_ToggleBit(GPIO_PORTC,GPIO_PIN12);CAN_CAN0_Msg_Set(&GL_Can_Msg,CAN_MB5);CAN_0.IFLAG1.R |= (1<<CAN_MB5);}else if((flags&0x000000F0)== CAN_MB6_FLAG){CAN_CAN0_Msg_Set(&GL_Can_Msg,CAN_MB6);CAN_0.IFLAG1.R |= (1<<CAN_MB6);}else{CAN_CAN0_Msg_Set(&GL_Can_Msg,CAN_MB7);CAN_0.IFLAG1.R |= (1<<CAN_MB7);}
}