需求:系统配置N个通道,CAN总线只接收0-N节点的数据。 example:系统通道总数为51,那么只接收0,1,2,3,4,....51的数据。
如下为CAN协议格式。
CAN协议格式
所以采用拓展帧,在筛选器的选择上选择了32位的掩码模式。
通过查阅F4的参考手册得知,bxCAN具有28个筛选器。
bxCAN特性
bxCAN的外设框图
CAN框图
CAN共有28个筛选器组,每个筛选器可配置4种模式,分别是1个32位掩码,2个32位标识符,2个16位掩码,4个16位标识符。根据我32位的掩码模式使用场景,也就是说可以配置28个32位掩码的筛选器。
所以采用的算法思路:比如系统通道数为51,小于51的二次幂项是32,配置一个0-31的区间筛选器,然后32到51每个单独配置一个筛选器。所以筛选器数量为1个区间筛选器+20(51-32+1)指定筛选器。
代码如下:
- void Bsp_Can_FilterConfig(void)
- {
- CAN_FilterTypeDef sFilterConfig;
- HAL_StatusTypeDef status;
- const uint32_t Can_Id = 0x10000000;
- const uint16_t packet_sum = 128; //包总数
- uint16_t ps_nearest_pow = 0; //向上寻找包总数最近的二次幂
-
- struct
- {
- uint8_t node_total; //节点总数
- uint8_t pow_nearst_down; //向下最近二次幂
- uint8_t filter_num; //滤波器编号
- uint8_t node_num; //节点编号
-
- uint32_t id;
- uint32_t mask_range; //区间
- }Can_Filter;
- Can_Filter.filter_num = 0;
- Can_Filter.node_total = Get_Mid_Property_Node_Total();
- ps_nearest_pow = pow(2, ceil(log2(packet_sum)));
- Can_Filter.pow_nearst_down = pow(2, floor(log2(Can_Filter.node_total)));
-
- Can_Filter.mask_range = 0x1fffffff;
- Can_Filter.mask_range &= (~((ps_nearest_pow-1) << 0));
- Can_Filter.mask_range &= (~((ps_nearest_pow-1) << 9));
- Can_Filter.mask_range &= (~((Can_Filter.pow_nearst_down-1) << 20));
- Can_Filter.mask_range <<= 3;
-
- /***************** 配置区间滤波器 *********************/
- sFilterConfig.FilterActivation = ENABLE;
- sFilterConfig.FilterBank = Can_Filter.filter_num;
- sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
- sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
- sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
- sFilterConfig.FilterMaskIdHigh = (Can_Filter.mask_range>>16)&0xffff;
- sFilterConfig.FilterMaskIdLow = (Can_Filter.mask_range&0xffff);
-
- sFilterConfig.FilterIdHigh = ((Can_Id<<3)>>16)&0xffff;
- sFilterConfig.FilterIdLow = ((Can_Id<<3)&0xffff);
- sFilterConfig.SlaveStartFilterBank = 0;
- HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);
- /********************************************************/
-
- /***************** 配置指定滤波器 *********************/
- sFilterConfig.FilterMaskIdHigh = (0x0ff00000<<3) >> 16;
- sFilterConfig.FilterMaskIdLow = 0;
-
- for(Can_Filter.node_num=Can_Filter.pow_nearst_down;
- Can_Filter.node_num<=Can_Filter.node_total;
- Can_Filter.node_num++)
- {
- Can_Filter.id = 0;
- Can_Filter.filter_num++;
-
- if( Can_Filter.filter_num < 14 )
- {
- sFilterConfig.SlaveStartFilterBank = 0;
- }
- else
- {
- sFilterConfig.SlaveStartFilterBank = 14;
- }
-
- if( Can_Filter.filter_num > 28 )
- {
- log_i("Can Filter Num Over Range");
- break;
- }
-
- sFilterConfig.FilterBank = Can_Filter.filter_num;
-
- Can_Filter.id = Can_Filter.node_num << 20;
- sFilterConfig.FilterIdHigh = (Can_Filter.id <<3)>>16;
- sFilterConfig.FilterIdLow = 0;
-
- status = HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig);
- }
复制代码 测试方法:一个CAN发送设备,每隔100ms发送设备地址0-128的数据。作为接收设备,在接收中断把CAN EXID的设备地址打印出来。如系统设置为51通道,串口每隔100ms显示0-51。
测试现象:只收到0-44。
测试现象
疑问点:从测试现象分析,31+13=44,CAN1好像只有14个筛选器起到了作用。只要筛选器编号超过14就不起作用,我在程序debug时查了所有筛选器硬件寄存器的值和算法是对应的。
我再次查了资料,筛选器数量28还是14说的模棱两可。
所以我的疑问是stm32F407ZET6,为什么CAN1的14-28筛选器不起作用?
|