STM32F105双CAN总线16位列表模式过滤器仅前2组可用求助
双CAN总线STM32F105的16位列表模式CAN过滤器异常问题
配置具备双CAN总线的STM32F105时,遇到以下异常:16位列表模式下仅前2个过滤器组可正常工作,但相同配置在单CAN总线的STM32F103上运行正常。
相关代码
bool CanSetFilter(CAN_HandleTypeDef *can, uint8_t bank, uint16_t id1, uint16_t id2, uint16_t id3, uint16_t id4) { return CanSetFilterList16bit(can, bank, (uint32_t(id1)<<21) | (uint32_t(id2)<<5), (uint32_t(id3)<<21) | (uint32_t(id4)<<5), CAN_FILTERMODE_IDLIST, CAN_FILTERSCALE_16BIT, CAN_FILTER_FIFO0); } bool CanSetFilterList16bit(CAN_HandleTypeDef *can, uint8_t bank_num, uint32_t filter_id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, uint32_t fifo) { CAN_FilterTypeDef sFilterConfig; sFilterConfig.FilterBank = bank_num; sFilterConfig.FilterMode = filter_mode; sFilterConfig.FilterScale = filter_scale; sFilterConfig.FilterFIFOAssignment = fifo; sFilterConfig.FilterActivation = ENABLE; sFilterConfig.FilterIdHigh = filter_id&0xFFFF; sFilterConfig.FilterIdLow = filter_id>>16; sFilterConfig.FilterMaskIdHigh = mask&0xFFFF; sFilterConfig.FilterMaskIdLow = mask>>16; bool result = (HAL_CAN_ConfigFilter(can, &sFilterConfig ) == HAL_OK); return result; } // 应用过滤器 uint16_t canFilterIds[] = { 0x076, 0x077, 0x07D, 0x167, 0x171, 0x204, 0x213, 0x217, 0x230, 0x3B3, 0x42F, 0x43E, // 这组分配到bank3,实际不生效 }; const int canFiltersCount = sizeof(canFilterIds) / sizeof(canFilterIds[0]); int filter = 0; for (int i=0; (i<canFiltersCount) && (filter<28); filter++) { uint32_t f1 = (i<canFiltersCount) ? canFilterIds[i++] : canFilterIds[i]; uint32_t f2 = (i<canFiltersCount) ? canFilterIds[i++] : canFilterIds[i]; uint32_t f3 = (i<canFiltersCount) ? canFilterIds[i++] : canFilterIds[i]; uint32_t f4 = (i<canFiltersCount) ? canFilterIds[i++] : canFilterIds[i]; CanSetFilter(&hcan1, filter, f1, f2, f3, f4); }
调试情况
三次CanSetFilter(...)调用均执行成功,对应CAN_FilterTypeDef的配置参数符合预期:
- 第1次调用配置bank0,对应ID:0x076、0x077、0x07D、0x167
- 第2次调用配置bank1,对应ID:0x171、0x204、0x213、0x217
- 第3次调用配置bank2,对应ID:0x230、0x3B3、0x42F、0x43E
但只有前两个过滤器组能正常匹配报文,第三个组完全不生效。
解决思路及修正示例
1. 检查双CAN过滤器组分配
STM32F105的28个过滤器组默认会在CAN1和CAN2之间拆分(通常前14组给CAN1,后14组给CAN2)。如果未手动指定分配规则,后续的过滤器组可能被分配给了CAN2,导致CAN1无法使用。
修正方法:在CAN初始化阶段,将所有过滤器组分配给CAN1:
// 在HAL_CAN_Init之后添加过滤器组分配配置 void MX_CAN1_Init(void) { CAN_FilterTypeDef sFilterConfig; hcan1.Instance = CAN1; hcan1.Init.Prescaler = 12; hcan1.Init.Mode = CAN_MODE_NORMAL; hcan1.Init.SyncJumpWidth = CAN_SJW_1TQ; hcan1.Init.TimeSeg1 = CAN_BS1_8TQ; hcan1.Init.TimeSeg2 = CAN_BS2_1TQ; hcan1.Init.TimeTriggeredMode = DISABLE; hcan1.Init.AutoBusOff = ENABLE; hcan1.Init.AutoWakeUp = DISABLE; hcan1.Init.AutoRetransmission = ENABLE; hcan1.Init.ReceiveFifoLocked = DISABLE; hcan1.Init.TransmitFifoPriority = DISABLE; if (HAL_CAN_Init(&hcan1) != HAL_OK) { Error_Handler(); } // 将所有28个过滤器组分配给CAN1(SlaveStartFilterBank设置为28表示CAN2无过滤器组) sFilterConfig.SlaveStartFilterBank = 28; sFilterConfig.FilterBank = 0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh = 0x0000; sFilterConfig.FilterIdLow = 0x0000; sFilterConfig.FilterMaskIdHigh = 0x0000; sFilterConfig.FilterMaskIdLow = 0x0000; sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; sFilterConfig.FilterActivation = DISABLE; if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK) { Error_Handler(); } }
2. 修正16位列表模式的ID位映射
STM32 16位列表模式下,每个过滤器组的4个ID需要按照正确的位格式存储:标准ID(11位)需要左移5位,同时要带上帧类型标志(CAN_ID_STD、CAN_RTR_DATA)。原代码的位偏移(<<21、<<5)不符合16位过滤器的存储规则。
修正后的过滤器配置函数:
bool CanSetFilter(CAN_HandleTypeDef *can, uint8_t bank, uint16_t id1, uint16_t id2, uint16_t id3, uint16_t id4) { // 标准ID+数据帧的格式:(ID <<5) | CAN_ID_STD | CAN_RTR_DATA uint16_t id1_formatted = (id1 << 5) | CAN_ID_STD | CAN_RTR_DATA; uint16_t id2_formatted = (id2 << 5) | CAN_ID_STD | CAN_RTR_DATA; uint16_t id3_formatted = (id3 << 5) | CAN_ID_STD | CAN_RTR_DATA; uint16_t id4_formatted = (id4 << 5) | CAN_ID_STD | CAN_RTR_DATA; // 组合成32位值:高16位是第二个ID,低16位是第一个ID uint32_t filter_ids = ((uint32_t)id2_formatted << 16) | id1_formatted; // 列表模式下,Mask寄存器存储另外两个ID uint32_t filter_ids_ext = ((uint32_t)id4_formatted << 16) | id3_formatted; return CanSetFilterList16bit(can, bank, filter_ids, filter_ids_ext, CAN_FILTERMODE_IDLIST, CAN_FILTERSCALE_16BIT, CAN_FILTER_FIFO0); } bool CanSetFilterList16bit(CAN_HandleTypeDef *can, uint8_t bank_num, uint32_t filter_id, uint32_t mask, uint32_t filter_mode, uint32_t filter_scale, uint32_t fifo) { CAN_FilterTypeDef sFilterConfig; sFilterConfig.FilterBank = bank_num; sFilterConfig.FilterMode = filter_mode; sFilterConfig.FilterScale = filter_scale; sFilterConfig.FilterFIFOAssignment = fifo; sFilterConfig.FilterActivation = ENABLE; // 16位模式下:FilterIdHigh是第二个ID,FilterIdLow是第一个ID sFilterConfig.FilterIdHigh = (filter_id >> 16) & 0xFFFF; sFilterConfig.FilterIdLow = filter_id & 0xFFFF; // Mask寄存器存储第三、第四个ID,FilterMaskIdHigh是第四个,FilterMaskIdLow是第三个 sFilterConfig.FilterMaskIdHigh = (mask >> 16) & 0xFFFF; sFilterConfig.FilterMaskIdLow = mask & 0xFFFF; return (HAL_CAN_ConfigFilter(can, &sFilterConfig ) == HAL_OK); }
3. 验证单个过滤器组
单独测试第三个过滤器组,只配置bank2的4个ID,确认对应的报文是否能被接收,排除循环索引错误或报文本身的问题。
内容的提问来源于stack exchange,提问作者brigadir
相关产品推荐
相关产品推荐

