STM32H743 FDCAN双CAN过滤表设置

前景提示

目前网上我看到的例子多是CAN1实现了过滤表功能,而且只是一个过滤表项,实际项目中肯定会有两个CAN一起开,同时用过滤表的情况的。

H系列之前的ST芯片的CAN IP核都是bxCAN,那个的使用方法可以看我之前的写的帖子
自己写的F7的CAN总线过滤帖子

H系列的CAN升级了,多了TT CAN和FDCAN,然后它内部的设计也是翻天覆地的彻头彻尾改了
STM32H743 FDCAN双CAN过滤表设置_第1张图片

H系列的CAN多了啥呢

STM32H743 FDCAN双CAN过滤表设置_第2张图片

这个功能看着就很厉害,更厉害的在后面[ma fan]

H743的CAN ID过滤功能【划重点】

STM32H743 FDCAN双CAN过滤表设置_第3张图片
注意看黄色字的部分,后面的大坑就在这

这一代的CAN的消息存储方式和之前不一样了,不是以前的固定的邮箱和FIFO那种玩法,而是ST给你10K的专有内存,任你搞,就问你牛不牛B,就问你麻不麻烦,这一代的CAN的收发的数据结构你需要自己用寄存器OR 写的很烂的HAL库来自己做,而且你做错了,它不检查!!!!!!!!!!这个非常的坑

STM32H743 FDCAN双CAN过滤表设置_第4张图片

这一代的过滤功能,加强了,表扬一下,但是注意多了一个全局过滤器配置GFC的寄存器,这个一定要注意

STM32H743 FDCAN双CAN过滤表设置_第5张图片

看典型位这个就够用了,还是以前熟悉的掩码/ID过滤,但是这一代这个做的人性了一些

标准帧过滤表

STM32H743 FDCAN双CAN过滤表设置_第6张图片
STM32H743 FDCAN双CAN过滤表设置_第7张图片

扩展帧过滤表

STM32H743 FDCAN双CAN过滤表设置_第8张图片
STM32H743 FDCAN双CAN过滤表设置_第9张图片

就是这一代的CAN ID是直接填写的,远程帧那个单独拿出来了,不用像之前bxCAN要自己推算下

STM32H743 FDCAN双CAN过滤表设置_第10张图片

这个寄存器算是整个过滤器的总开关了,一定要注意

具体代码实现

首先安利一个老哥的帖子
感谢这位老哥为H743的贡献了【H743 CAN1的过滤表实现】

结合他的帖子我来说说2个CAN同时用过滤表怎么搞

首先,还记得前面的消息RAM的那个图和FDCAN的特性描述嘛?

  1. 这一代的两个CAN共用一个过滤表
  2. 那个专有内存需要自己管理

一个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的过滤表就都能够用了
把做法记录下来,方便后人也供自己备忘

你可能感兴趣的:(STM32)