目前网上我看到的例子多是CAN1实现了过滤表功能,而且只是一个过滤表项,实际项目中肯定会有两个CAN一起开,同时用过滤表的情况的。
H系列之前的ST芯片的CAN IP核都是bxCAN,那个的使用方法可以看我之前的写的帖子
自己写的F7的CAN总线过滤帖子
H系列的CAN升级了,多了TT CAN和FDCAN,然后它内部的设计也是翻天覆地的彻头彻尾改了
这个功能看着就很厉害,更厉害的在后面[ma fan]
这一代的CAN的消息存储方式和之前不一样了,不是以前的固定的邮箱和FIFO那种玩法,而是ST给你10K的专有内存,任你搞,就问你牛不牛B,就问你麻不麻烦,这一代的CAN的收发的数据结构你需要自己用寄存器OR 写的很烂的HAL库来自己做,而且你做错了,它不检查!!!!!!!!!!这个非常的坑
这一代的过滤功能,加强了,表扬一下,但是注意多了一个全局过滤器配置GFC的寄存器,这个一定要注意
看典型位这个就够用了,还是以前熟悉的掩码/ID过滤,但是这一代这个做的人性了一些
就是这一代的CAN ID是直接填写的,远程帧那个单独拿出来了,不用像之前bxCAN要自己推算下
这个寄存器算是整个过滤器的总开关了,一定要注意
首先安利一个老哥的帖子
感谢这位老哥为H743的贡献了【H743 CAN1的过滤表实现】
结合他的帖子我来说说2个CAN同时用过滤表怎么搞
首先,还记得前面的消息RAM的那个图和FDCAN的特性描述嘛?
- 这一代的两个CAN共用一个过滤表
- 那个专有内存需要自己管理
一个CAN的时候,你不需要在意这个专有内存的问题,但是两个CAN一起来的时候你就要关心了,因为你不能把两个CAN用的内存重合在一起,一定要分开用,一段给CAN1,另一段给CAN2.前代的bxCAN是芯片内部帮我们分开了,但是这一代ST把这个权力交给了开发者,所以一点要注意,在初始化完CAN1后,记录下你的消息RAM的结尾地址,让CAN2接着CAN1的内存继续用!!!!这个非常关键,因为不这样,过滤表会有问题,至少目前我的理解和实际测试,重合在一起是有问题的
而且HAL库帮我们考虑了这个问题【代码搬运自某原子,稍微修改】
uint8_t FDCAN1_Mode_Init(uint8_t tnsjw,uint16_t tseg1,uint8_t tseg2,uint16_t tnbrp,uint8_t mode)
{
FDCAN_ClkCalUnitTypeDef FDCAN1_ClkCalUnit;
FDCAN_FilterTypeDef FDCAN1_RXFilter;
//初始化FDCAN1
HAL_FDCAN_DeInit(&FDCAN1_Handler); //先清除以前的设置
FDCAN1_Handler.Instance=FDCAN1;
FDCAN1_Handler.Init.FrameFormat=FDCAN_FRAME_CLASSIC; //传统模式
FDCAN1_Handler.Init.Mode=mode; //模式设置
FDCAN1_Handler.Init.AutoRetransmission=DISABLE; //关闭自动重传!传统模式下一定要关闭!!!
FDCAN1_Handler.Init.TransmitPause=DISABLE; //关闭传输暂停
FDCAN1_Handler.Init.ProtocolException=DISABLE; //关闭协议异常处理
FDCAN1_Handler.Init.NominalPrescaler=tnbrp; //分频系数
FDCAN1_Handler.Init.NominalSyncJumpWidth=tnsjw; //重新同步跳跃宽度范围:2~128
FDCAN1_Handler.Init.NominalTimeSeg1=tseg1; //tseg1范围:2~256
FDCAN1_Handler.Init.NominalTimeSeg2=tseg2; //tseg2范围:2~128
FDCAN1_Handler.Init.MessageRAMOffset=0; //消息RAM偏移【这个到CAN2就有用了】
FDCAN1_Handler.Init.StdFiltersNbr=0; //标准信息ID滤波器个数【这里原代码注释乱写,这个必须要写,有多少个过滤器就要写多少个】
FDCAN1_Handler.Init.ExtFiltersNbr=2; //扩展信息ID滤波器个数【这里原代码注释乱写,这个必须要写,有多少个过滤器就要写多少个】
FDCAN1_Handler.Init.RxFifo0ElmtsNbr=1; //接收FIFO0元素编号
FDCAN1_Handler.Init.RxFifo0ElmtSize=FDCAN_DATA_BYTES_8; //接收FIFO0元素大小:8字节
FDCAN1_Handler.Init.RxBuffersNbr=0; //接收缓冲编号
FDCAN1_Handler.Init.TxEventsNbr=0; //发送事件编号
FDCAN1_Handler.Init.TxBuffersNbr=0; //发送缓冲编号
FDCAN1_Handler.Init.TxFifoQueueElmtsNbr=1; //发送FIFO序列元素编号
FDCAN1_Handler.Init.TxFifoQueueMode=FDCAN_TX_FIFO_OPERATION; //发送FIFO序列模式
FDCAN1_Handler.Init.TxElmtSize=FDCAN_DATA_BYTES_8; //发送大小:8字节
if(HAL_FDCAN_Init(&FDCAN1_Handler)!=HAL_OK) return 1; //初始化FDCAN
FDCAN1_ClkCalUnit.ClockCalibration=DISABLE; //不使用时钟校准功能
FDCAN1_ClkCalUnit.ClockDivider=FDCAN_CLOCK_DIV1; //4分频,得到50Mhz的fdca_tq_ck
HAL_FDCAN_ConfigClockCalibration(&FDCAN1_Handler,&FDCAN1_ClkCalUnit); //设置分频
//配置我自己的RX滤波器【ID/掩码的原理自己去看其他的帖子,我这里随便写一个ID/掩码】
FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID; //扩展ID
FDCAN1_RXFilter.FilterIndex=0; //滤波器索引
FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK; //滤波器类型
FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //过滤器0关联到FIFO0
FDCAN1_RXFilter.FilterID1= 0x4000000;//ID; //32位ID
FDCAN1_RXFilter.FilterID2=0x1c00000; //如果FDCAN配置为传统模式的话,这里是32位掩码
if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
FDCAN1_RXFilter.IdType=FDCAN_EXTENDED_ID; //扩展ID
FDCAN1_RXFilter.FilterIndex=1; //滤波器索引
FDCAN1_RXFilter.FilterType=FDCAN_FILTER_MASK; //滤波器类型
FDCAN1_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //过滤器0关联到FIFO0
FDCAN1_RXFilter.FilterID1= 0x400000;//ID; //32位ID
FDCAN1_RXFilter.FilterID2=0x1c00000; //如果FDCAN配置为传统模式的话,这里是32位掩码
if(HAL_FDCAN_ConfigFilter(&FDCAN1_Handler,&FDCAN1_RXFilter)!=HAL_OK) return 2;//滤波器初始化
下面这一句是配置全局滤波器配置寄存器的,一定要写,否则配置了也没用
HAL_FDCAN_ConfigGlobalFilter(&FDCAN1_Handler, FDCAN_REJECT, FDCAN_REJECT, FDCAN_REJECT_REMOTE, FDCAN_REJECT_REMOTE);
HAL_FDCAN_Start(&FDCAN1_Handler); //开启FDCAN
HAL_FDCAN_ActivateNotification(&FDCAN1_Handler,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);
return 0;
}
到CAN2的初始化的时候,那个消息RAM偏移要这么写,其他基本上不变
FDCAN2_Handler.Init.MessageRAMOffset=FDCAN1_Handler.msgRam.EndAddress-SRAMCAN_BASE
uint8_t FDCAN2_Mode_Init(uint8_t tnsjw,uint16_t tseg1,uint8_t tseg2,uint16_t tnbrp,uint8_t mode)
{
FDCAN_ClkCalUnitTypeDef FDCAN2_ClkCalUnit;
FDCAN_FilterTypeDef FDCAN2_RXFilter;
//初始化FDCAN1
HAL_FDCAN_DeInit(&FDCAN2_Handler); //先清除以前的设置
FDCAN2_Handler.Instance=FDCAN2;
FDCAN2_Handler.Init.FrameFormat=FDCAN_FRAME_CLASSIC; //传统模式
FDCAN2_Handler.Init.Mode=mode; //模式设置
FDCAN2_Handler.Init.AutoRetransmission=DISABLE; //关闭自动重传!传统模式下一定要关闭!!!
FDCAN2_Handler.Init.TransmitPause=DISABLE; //关闭传输暂停
FDCAN2_Handler.Init.ProtocolException=DISABLE; //关闭协议异常处理
FDCAN2_Handler.Init.NominalPrescaler=tnbrp; //分频系数
FDCAN2_Handler.Init.NominalSyncJumpWidth=tnsjw; //重新同步跳跃宽度范围:2~128
FDCAN2_Handler.Init.NominalTimeSeg1=tseg1; //tseg1范围:2~256
FDCAN2_Handler.Init.NominalTimeSeg2=tseg2; //tseg2范围:2~128
FDCAN2_Handler.Init.MessageRAMOffset=FDCAN1_Handler.msgRam.EndAddress-SRAMCAN_BASE;//消息RAM偏移[字为单位]
FDCAN2_Handler.Init.StdFiltersNbr=0; //标准信息ID滤波器总数
FDCAN2_Handler.Init.ExtFiltersNbr=2; //扩展信息ID滤波器总数
FDCAN2_Handler.Init.RxFifo0ElmtsNbr=1; //接收FIFO0元素编号
FDCAN2_Handler.Init.RxFifo0ElmtSize=FDCAN_DATA_BYTES_8; //接收FIFO0元素大小:8字节
FDCAN2_Handler.Init.RxBuffersNbr=0; //接收缓冲编号
FDCAN2_Handler.Init.TxEventsNbr=0; //发送事件编号
FDCAN2_Handler.Init.TxBuffersNbr=0; //发送缓冲编号
FDCAN2_Handler.Init.TxFifoQueueElmtsNbr=1; //发送FIFO序列元素编号
FDCAN2_Handler.Init.TxFifoQueueMode=FDCAN_TX_FIFO_OPERATION; //发送FIFO序列模式
FDCAN2_Handler.Init.TxElmtSize=FDCAN_DATA_BYTES_8; //发送大小:8字节
if(HAL_FDCAN_Init(&FDCAN2_Handler)!=HAL_OK) return 1; //初始化FDCAN
FDCAN2_ClkCalUnit.ClockCalibration=DISABLE; //不使用时钟校准功能
FDCAN2_ClkCalUnit.ClockDivider=FDCAN_CLOCK_DIV1; //4分频,得到50Mhz的fdca_tq_ck
HAL_FDCAN_ConfigClockCalibration(&FDCAN2_Handler,&FDCAN2_ClkCalUnit); //设置分频
配置我自己的RX滤波器【ID/掩码的原理自己去看其他的帖子,我这里随便写一个ID/掩码】
FDCAN2_RXFilter.IdType=FDCAN_EXTENDED_ID; //扩展ID
FDCAN2_RXFilter.FilterIndex=0; //滤波器索引
FDCAN2_RXFilter.FilterType=FDCAN_FILTER_MASK; //滤波器类型
FDCAN2_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //过滤器0关联到FIFO0
FDCAN2_RXFilter.FilterID1=0x4000000; //32位ID
FDCAN2_RXFilter.FilterID2=0x7c00000; //如果FDCAN配置为传统模式的话,这里是32位掩码
if(HAL_FDCAN_ConfigFilter(&FDCAN2_Handler,&FDCAN2_RXFilter)!=HAL_OK) return 2;//滤波器初始化
FDCAN2_RXFilter.IdType=FDCAN_EXTENDED_ID; //扩展ID
FDCAN2_RXFilter.FilterIndex=1; //滤波器索引
FDCAN2_RXFilter.FilterType=FDCAN_FILTER_MASK; //滤波器类型
FDCAN2_RXFilter.FilterConfig=FDCAN_FILTER_TO_RXFIFO0; //过滤器0关联到FIFO0
FDCAN2_RXFilter.FilterID1= 0x400000;//ID; //32位ID
FDCAN2_RXFilter.FilterID2=0x7c00000; //如果FDCAN配置为传统模式的话,这里是32位掩码
if(HAL_FDCAN_ConfigFilter(&FDCAN2_Handler,&FDCAN2_RXFilter)!=HAL_OK) return 2;//滤波器初始化
下面这一句是配置全局滤波器配置寄存器的,一定要写,否则配置了也没用
HAL_FDCAN_ConfigGlobalFilter(&FDCAN2_Handler, FDCAN_REJECT, FDCAN_REJECT, FDCAN_REJECT_REMOTE, FDCAN_REJECT_REMOTE);
HAL_FDCAN_Start(&FDCAN2_Handler); //开启FDCAN
HAL_FDCAN_ActivateNotification(&FDCAN2_Handler,FDCAN_IT_RX_FIFO0_NEW_MESSAGE,0);
return 0;
}
这样两个CAN的过滤表就都能够用了
把做法记录下来,方便后人也供自己备忘