KEA128芯片CAN驱动调试

13 篇文章 21 订阅

进入汽车电子有两年了,一直在做BSP的工作,竟然没有接触过CAN调试,这次有机会给上层做一个CAN接口,调试过程中遇到了一些问题,记录如下。
1、CAN总线波特率的计算
以前接触的的通信协议,波特率都可以直接赋值,但是CAN的一次采样分成4个时间段。
在这里插入图片描述它的波特率计算公式为:
BAUD_RATE_CLOCK/(BAUD_RATE_BRP+1)/(1 +(BAUD_RATE_TSEG1+1)+(BAUD_RATE_TSEG2+1))
为了给上层提供方便的接口,在时钟源选择后,将波特率的配置写死,并且选择一个较为通用的采样点,同时将同步跳转宽度用宏定义的方式留出来。

	if(baudrate == CAN_BAUD_500K)
	{
		//BAUD_RATE_CLOCK/(BAUD_RATE_BRP+1)/(1 +(BAUD_RATE_TSEG1+1)+(BAUD_RATE_TSEG2+1))
		sMSCANConfig.sBaudRateSetting.SJW = USR_DEF_SJW; //同步跳转宽度,为保持同步,一位中最多可被缩短或延长的时间量子时钟周期的数目
    	sMSCANConfig.sBaudRateSetting.BRP = 1; //波特率预分频器
    	sMSCANConfig.sBaudRateSetting.SAMP = BAUD_RATE_SAMP; // 0
    	sMSCANConfig.sBaudRateSetting.TSEG1= 15;  //总线定时寄存器时段1
    	sMSCANConfig.sBaudRateSetting.TSEG2= 2;  //总线定时寄存器时段2
	}
	if(baudrate == CAN_BAUD_250K)
	{
		sMSCANConfig.sBaudRateSetting.SJW = USR_DEF_SJW; 
    	sMSCANConfig.sBaudRateSetting.BRP = 3; 
    	sMSCANConfig.sBaudRateSetting.SAMP = BAUD_RATE_SAMP; 
    	sMSCANConfig.sBaudRateSetting.TSEG1= 15;  
    	sMSCANConfig.sBaudRateSetting.TSEG2= 2;  
	}
	else
	{
		sMSCANConfig.sBaudRateSetting.SJW = USR_DEF_SJW; 
    	sMSCANConfig.sBaudRateSetting.BRP = 7; 
    	sMSCANConfig.sBaudRateSetting.SAMP = BAUD_RATE_SAMP;
    	sMSCANConfig.sBaudRateSetting.TSEG1= 15; 
    	sMSCANConfig.sBaudRateSetting.TSEG2= 2; 
	}

2、CAN的接收报文过滤
CAN的消息ID可以简单理解为一个报文过滤标示位,所以在接收的时候要提供报文过滤接口。一般的报文过滤都是ID+MASK的形式构成。通过阅读芯片手册,发现KEA128的ID和MSK寄存器有点复杂。
KEA128提供两组32位的寄存器用来设置ID和MSK,每组都是标准帧(11bit)和扩展帧(29bit)共用的(比较特殊的是这款芯片的MRn的位设置为0表示去匹配掩码,设置为1表示不匹配。这一点我在底层接口做了转换)
在这里插入图片描述从上面寄存器的位分布可以看到,标准帧和扩展帧的ID位置分布。所以必须为各种帧格式提供配置接口。所以做了下面一个函数,用来计算IDAR和IDMR寄存器

//参数1是帧类型,参数2是任意需要过滤的ID组中之一,参数3为掩码,参数4是寄存器组ID(分别是0、1)
void can_fliter_interface(can_frame_type_t type,uint32_t id_base,uint32_t mask,uint8_t flt_group)
{
	uint32_t code = id_base;
	uint32_t code_high;
	uint32_t code_low;
	uint32_t mask_high;
	uint32_t mask_low;
	if(CAN_STD_FRAME == type)
	{
		//标准帧 11位code
		switch(flt_group)
		{
			case 0:
			{
				code = code<<21;
				uIDAR0 = code;
				mask = mask<<21;
				uIDMR0 = ~mask;//底层做反码转换
			}
			break;
			case 1:
			{	
				code = code<<21;
				uIDAR1 = code;
				mask = mask<<21;
				uIDMR1 = ~mask;
			}
			break;
			default:
			break;
		}
		
	}
	if(CAN_EXT_FRAME == type)
	{
		//扩展帧  29位code
		switch(flt_group)
		{
			case 0:
			{
				//取code的高11位并移动到32位的高11位
				code_high= (code&0x1FFC0000)<<3;
				//取code的低18位并移动到32位的1~19位
				code_low = (code&0x3FFFF)<<1; 
				uIDAR0 = (code_high|((uint32_t)0x18<<16)|code_low);
				mask_high= (mask&0x01FFC0000)<<3;
				mask_low = (mask&0x3FFFF)<<1; 
				uIDMR0 = ~(mask_high|(0x01|(uint32_t)0x10<<16)|mask_low);

			}
			break;
			case 1:
			{
				code_high= (code&0x1FFC0000)<<3;
				code_low = (code&0x3FFFF)<<1; 
				uIDAR1 = (code_high|((uint32_t)0x18<<16)|code_low);
				mask_high= (mask&0x01FFC0000)<<3;
				mask_low = (mask&0x3FFFF)<<1; 
				uIDMR1 = ~(mask_high|(0x01|(uint32_t)0x10<<16)|mask_low);
			}
			break;
			default:
			break;
              }
        }
}

最终将计算出来的IDAR和IDMR赋值给初始化数组对象

	sMSCANConfig.u32IDAR0 = uIDAR0;
	sMSCANConfig.u32IDAR1 = uIDAR1;
	//标识符屏蔽寄存器指定标识符验收寄存器中哪些对应的位与验收滤波相关
	sMSCANConfig.u32IDMR0 = uIDMR0;
	sMSCANConfig.u32IDMR1 = uIDMR1;

3、过滤测试,在初始化CAN接口之前配置过滤

	#define NODE_ID2 	0x801
    can_fliter_interface(CAN_EXT_FRAME,NODE_ID2,0x1FFFFFFC,0); //设置过滤扩扩展帧 29位,掩码放开后两位
    //可以过两次接收ID为0x800,0x801,0x802和0x803的扩展帧
 	mscan_hal_init(CAN_BAUD_250K);						//初始化波特率为250K
  •  

CAN接口主要就是配置波特率、采样点位置和过滤规则,KEA128的过滤接口可以完全参考上面的接口代码给应用层使用。希望和大家一起分享。

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 1
    评论
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值