Toggle navigation
首页
问答
文章
积分商城
专家
专区
更多专区...
文档中心
返回主站
搜索
提问
会员
中心
登录
注册
CANFD_fdcan
一文读懂CANFD的接收模式
发布于 2021-12-26 21:13:10 浏览:6275
订阅该版
[tocm] # 前言 在使用 CANFD 的接收模式的首先要对 CANFD 有一定的认识,可以查看我[之前的文章](https://blog.csdn.net/whj123999/category_11547055.html)。本文以 STM32H7 为例将对以下关键词进行详细的讲解。 - 中断线 - RXFIFO0/RXFIFO1 - RXBUFF - 滤波器 - 标准帧/扩展帧 - 接收水印 - 高优先级报文 ## 一,CANFD 的两条中断线  STM32H7 的 CANFD 外设提供了两条线: - fdcan_intr0_it : 中断线 0 - fdcan_intr1_it :中断线 1 使用以下代码实现中断的开启 ``` HAL_NVIC_SetPriority(FDCAN1_IT0_IRQn, 0, 0); HAL_NVIC_EnableIRQ(FDCAN1_IT0_IRQn); HAL_NVIC_SetPriority(FDCAN1_IT1_IRQn, 0, 0); HAL_NVIC_EnableIRQ(FDCAN1_IT1_IRQn); ``` 本文会用到的 CANFD 中断种类: ``` /* @defgroup FDCAN_Rx_Fifo0_Interrupts FDCAN Rx FIFO 0 Interrupts */ #define FDCAN_IT_RX_FIFO0_FULL FDCAN_IE_RF0FE /*!< Rx FIFO 0 full */ #define FDCAN_IT_RX_FIFO0_WATERMARK FDCAN_IE_RF0WE /*!< Rx FIFO 0 fill level reached watermark */ #define FDCAN_IT_RX_FIFO0_NEW_MESSAGE FDCAN_IE_RF0NE /*!< New message written to Rx FIFO 0 */ /* @defgroup FDCAN_Rx_Fifo1_Interrupts FDCAN Rx FIFO 1 Interrupts */ #define FDCAN_IT_RX_FIFO1_FULL FDCAN_IE_RF1FE /*!< Rx FIFO 1 full */ #define FDCAN_IT_RX_FIFO1_WATERMARK FDCAN_IE_RF1WE /*!< Rx FIFO 1 fill level reached watermark */ #define FDCAN_IT_RX_FIFO1_NEW_MESSAGE FDCAN_IE_RF1NE /*!< New message written to Rx FIFO 1 */ /* @defgroup FDCAN_Rx_Interrupts FDCAN Rx Interrupts */ #define FDCAN_IT_RX_HIGH_PRIORITY_MSG FDCAN_IE_HPME /*!< High priority message received */ #define FDCAN_IT_RX_BUFFER_NEW_MESSAGE FDCAN_IE_DRXE /*!< At least one received message stored into a Rx Buffer */ ``` 可以分为以下几类: - 接收新消息中断。(每次接收到新的消息就会触发一次中断) - 消息 FIFO 满中断。(Message RAM 设置的 FIFO 深度已满,没有及时的将消息读取走,触发的中断) - 触发水位(watermark)中断。(有的地方翻译成了水印,感觉不是很贴切,这里应该理解为警戒线的意思,如果 FIFO 深度为 10,那么可以把水位设置为 8,这样在接收到新的报文的时候,会触发一次水印中断,通过标志位的检测,可以知道 FIFO 即将满了,必须及时的将数据取走,避免触发 FIFO 满中断,导致的数据丢失) ### 1 新消息接收中断 CANFD 的消息通过中断模式接收,在不进行任何中断线配置的情况下,默认使用中断线 0 ,通过以下的代码实现接收数据由中断线 1 响应 ``` /* FDCAN1 在 RXFIFO0 接收到新的一帧数据由中断线 1 响应 */ HAL_FDCAN_ConfigInterruptLines(&hfdcan1, FDCAN_IT_RX_FIFO0_NEW_MESSAGE, FDCAN_INTERRUPT_LINE1); ``` ### 2 消息 FIFO 满中断 在 CANFD 初始化的时候需要设置 FIFO0/1 的深度,根据设置的深度会决定 FIFO0/1 满中断触发的时机 ``` /* 设置 RXFIFO0/1 的深度是 10,接收元素的大小是 64 个字节 */ hfdcan1.Init.RxFifo0ElmtsNbr = 10; hfdcan1.Init.RxFifo0ElmtSize = FDCAN_DATA_BYTES_64; hfdcan1.Init.RxFifo1ElmtsNbr = 10; hfdcan1.Init.RxFifo1ElmtSize = FDCAN_DATA_BYTES_64; /* FDCAN1 在 RXFIFO0 接收满时触发 FIFO 满中断,由中断线 0 响应 */ HAL_FDCAN_ConfigInterruptLines(&hfdcan1, FDCAN_IT_RX_FIFO0_FULL, FDCAN_INTERRUPT_LINE0); ``` ### 3 接收水印中断 接收水印中断来通知用户 FIFO 将满,请及时处理 ``` /* 设置 RXFIFO0 的水印深度为 8 */ HAL_FDCAN_ConfigFifoWatermark(&hfdcan1, FDCAN_CFG_RX_FIFO0, 8); /* 激活 RXFIFO0 水印中断响应 */ HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_WATERMARKE, 0); ``` ### 4 中断回调函数 不同的中断线使用的是一样的回调函数: ``` /* RXFIFO0 接收中断回调 */ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo0ITs) { /* todo */ } /* RXFIFO1 接收中断回调 */ void HAL_FDCAN_RxFifo0Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo1ITs) { /* todo */ } /* RXBUFF 接收中断回调 */ void void HAL_FDCAN_RxBufferNewMessageCallback(FDCAN_HandleTypeDef *hfdcan) { /* todo */ } ``` RXFIFO 接收回调中的 `RxFifo0ITs` `RxFifo1ITs` 是接收数据类型的标志位,通过对标志位的检查,可知接收的是哪种标志位的数据,可用标志位是以下几种类型 ``` /* @defgroup FDCAN_Rx_Fifo0_Interrupts FDCAN Rx FIFO 0 Interrupts */ #define FDCAN_IT_RX_FIFO0_FULL FDCAN_IE_RF0FE /*!< Rx FIFO 0 full */ #define FDCAN_IT_RX_FIFO0_WATERMARK FDCAN_IE_RF0WE /*!< Rx FIFO 0 fill level reached watermark */ #define FDCAN_IT_RX_FIFO0_NEW_MESSAGE FDCAN_IE_RF0NE /*!< New message written to Rx FIFO 0 */ /* @defgroup FDCAN_Rx_Fifo1_Interrupts FDCAN Rx FIFO 1 Interrupts */ #define FDCAN_IT_RX_FIFO1_FULL FDCAN_IE_RF1FE /*!< Rx FIFO 1 full */ #define FDCAN_IT_RX_FIFO1_WATERMARK FDCAN_IE_RF1WE /*!< Rx FIFO 1 fill level reached watermark */ #define FDCAN_IT_RX_FIFO1_NEW_MESSAGE FDCAN_IE_RF1NE /*!< New message written to Rx FIFO 1 */ ``` ### 5 注意事项 - 接收水印只有 RXFIFO 有,而 RXBUFF 没有。 - RXFIFO0, RXFIFO1, RXBUFF 可以同时使用。 - 中断线0, 中断线1 可以同时使用。 - 默认使用中断线0,对于没有特殊需求的情况下,默认使用中断线 0 ,能满足大部分的需求场景。 - RXFIFO 模式下对于接收 FIFO FULL 状态下有两种处理模式:阻止模式和覆盖模式。阻止模式,就是新的消息不在接收;覆盖模式,就是直接覆盖 Message RAM RXFIFO 里面最旧的一条消息。默认为阻止模式,可以通过以下的代码切换到覆盖模式。 ``` /* 设置 RXFIFO1 在接收满的情况下使用覆盖模式 */ HAL_FDCAN_ConfigRxFifoOverwrite(&hfdcan1, FDCAN_RX_FIFO1, FDCAN_RX_FIFO_OVERWRITE); ``` ## 二,RXFIFO 与 RXBUFF 在 CANFD 中有 RXFIFO0 ,RXFIFO1,RXBUFF。RXFIFO 最大支持深度为 64,RXBUFF 的最大支持个数为 64.。  关于 RXFIFO 和 RXBUFF 的区别见上图,在做几点补充: - RXFIFO 和 RXBUFF 模式模式情况下,在接收数据满了以后会阻止新的数据接收,但是 RXFIFO 可以修改为覆盖模式来进行继续接收,而 RXBUFF 必须手动清除 RXBUFF 对应的 BUFF index ,也就是 FDCAN_NDAT 的 bit 位,NDAT1(0 - 31),NDAT2(32 - 63)。 - RXFIFO 按照接收数据的顺序依次放入到 RXFIFO 当中,RXBUFF 需要用户自己设置滤波器规则,来放入自定序列号的 BUFF。 ### 1 RXFIFO 获取新的消息 当进入 RXFIFO 的回调函数之后,可以检测当前的接收数据的标志位,来进行数据的接收 ``` /* RXFIFO1 接收到一帧新的消息,然后获取新的消息 */ void HAL_FDCAN_RxFifo1Callback(FDCAN_HandleTypeDef *hfdcan, uint32_t RxFifo1ITs) { if (hfdcan == &hfdcan1) { if ((RxFifo1ITs & FDCAN_IT_RX_FIFO1_NEW_MESSAGE) != RESET) { HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO1, &FDCAN1_RxHeader, rxdata); HAL_FDCAN_ActivateNotification(hfdcan, FDCAN_IT_RX_FIFO1_NEW_MESSAGE, 0); } } } ``` ### 2 RXBUFF 获取新的消息 RXBUFF 接收到的数据,必须放到指定的 BUFF 索引,因此必须在进入 RXBUFF 接收回调之后进行检查,是哪个索引触发了接收中断 ``` /* RXBUFF 接收到一帧新的消息,遍历 BUFF ,然后找到对应索引号,然后获取数据 */ #define RXBUFF_INDEX_MAX 64 void HAL_FDCAN_RxBufferNewMessageCallback(FDCAN_HandleTypeDef *hfdcan) { uint16_t index; for (index = 0; index < RXBUFF_INDEX_MAX; index++) { /* code */ if(HAL_FDCAN_IsRxBufferMessageAvailable(hfdcan, index)) { HAL_FDCAN_GetRxMessage(hfdcan, index, &FDCAN1_RxHeader, rxdata); HAL_FDCAN_ActivateNotification(hfdcan, FDCAN_IT_RX_BUFFER_NEW_MESSAGE, 0); } } } ``` 注意 `RXBUFF_INDEX_MAX` 的最大值,必须与 Message RAM 中设置的 `hfdcan1.Init.RxBuffersNbr ` 保持一致。 ### 3 注意事项 - 中断回调函数的本身是在中断环境中,RXBUFF 的查询是一个开销比较大的操作,可以在裸机环境中可以使用全局变量的作为标志位的去通知,在 RTOS 环境中可以使用信号量的方式。 - 前面提到 RXBUFF 需要手动清楚 RXBUFF 接收数据的 index , 实际上在使用 `HAL_FDCAN_GetRxMessage` 的时候已经帮用户清除了 FDCAN_NDAT 标志位。 ## 三,滤波器 滤波器的作用就是对 CANFD 的帧 ID 进行匹配,匹配成功之后按照用户的设置的规则进行响应,在 STM32H7 的 CANFD 中,相对于 BxCAN 滤波器进行了升级,本文只做 CAFDN 的滤波器说明,不做对比。在认识滤波器之前,一定要明白**滤波器只在接收报文时生效,发送模式与滤波器无关**。 通过对 Message RAM 的配置可知,CANFD 的滤波器配置可以分为两套,分别是: - 标准帧标识符。(ID范围:0x000 - 0x7FF) - 扩展帧标识符。(ID范围:0x0000 0000 - 0x1FFF FFFF) 滤波器可以设置的滤波模式: - FDCAN_FILTER_RANGE (范围过滤) - FDCAN_FILTER_DUAL (精确过滤) - FDCAN_FILTER_MASK (掩码过滤) - FDCAN_FILTER_RANGE_NO_EIDM (范围过滤,但是忽略 EIDM,该模式仅在扩展帧标识符模式下生效) 滤波器匹配之后的行为: - FDCAN_FILTER_TO_RXFIFO0 (保存在 RXFIFO0) - FDCAN_FILTER_TO_RXFIFO1 (保存在 RXFIFO1) - FDCAN_FILTER_REJECT (拒绝该报文) - FDCAN_FILTER_HP (设置为高优先级报文,仅通知) - FDCAN_FILTER_TO_RXFIFO0_HP (设置为高优先级报文,并保存在 RXFIFO0) - FDCAN_FILTER_TO_RXFIFO1_HP (设置为高优先级报文,并保存在 RXFIFO0) - FDCAN_FILTER_TO_RXBUFFER (保存在 RXBUFF) 了解以上这些特性之后,分别对 标准帧标识符和扩展帧标识符分别进行说明。 ### 1 标准帧标识符的滤波器设置 标准帧标识符的滤波器的个数根据 Message RAM 配置来决定,最大支持 128 个过滤器组。 #### 1.1 标准帧标识符符的范围过滤 ``` FDCAN1_RXFilter.IdType = FDCAN_STANDARD_ID; //标准帧 FDCAN1_RXFilter.FilterIndex = 0; //滤波器索引 0 FDCAN1_RXFilter.FilterType = FDCAN_FILTER_RANGE; //范围过滤 FDCAN1_RXFilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; //过滤器关联到 FIFO0 FDCAN1_RXFilter.FilterID1 = 0x100; //范围过滤的起始帧 ID FDCAN1_RXFilter.FilterID2 = 0x110; //范围过滤的结束帧 ID HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter); ``` 以上设置为:标准帧标识符过滤器的第 0 组,过滤条件但是范围过滤,过滤匹配的数据会被保存在 RXFIFO0,过滤的范围是 `0x100 - 0x110` #### 1.2 标准帧标识符的精确过滤 ``` FDCAN1_RXFilter.IdType = FDCAN_STANDARD_ID; //标准帧 FDCAN1_RXFilter.FilterIndex = 1; //滤波器索引 1 FDCAN1_RXFilter.FilterType = FDCAN_FILTER_DUAL; //精确过滤 FDCAN1_RXFilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO1; //过滤器 1 关联到FIFO1 FDCAN1_RXFilter.FilterID1 = 0x200; //精确过滤的 ID1 FDCAN1_RXFilter.FilterID2 = 0x210; //精确过滤的 ID2 HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter); ``` 以上设置为:标准帧标识符过滤器的第 1 组,过滤条件但是精确过滤,过滤匹配的数据会被保存在 RXFIFO1,只会接受帧ID为 `0x200` 和 `0x210` 的报文,接收后会被保存在 RXFIFO1 #### 1.3 标准帧标识符的掩码过滤 ``` FDCAN1_RXFilter.IdType = FDCAN_STANDARD_ID; //标准帧 FDCAN1_RXFilter.FilterIndex = 2; //滤波器索引 2 FDCAN1_RXFilter.FilterType = FDCAN_FILTER_MASK; //掩码过滤 FDCAN1_RXFilter.FilterConfig = FDCAN_FILTER_TO_RXBUFFER; //过滤器 2 关联到 RXBUFF FDCAN1_RXFilter.RxBufferIndex = 1; //接收到的消息保存到 RXBUFF 索引号为 1 的空间 FDCAN1_RXFilter.FilterID1 = 0x301; //过滤的帧 ID FDCAN1_RXFilter.FilterID2 = 0x3FF; //过滤帧 ID 的掩码 HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter); ``` 以上设置为:标准帧标识符过滤器的第 2 组,过滤条件但是掩码过滤,过滤匹配的数据会被保存在 RXBUFF。 过滤帧 ID 是 0x300 , 转化成二进制就是:`0000 0011 0000 0001`, 帧 ID 的掩码是 0x3FF,转换成二进制就是:`0000 0011 1111 1111`, 对他们进行求与运算的结果就是 `0000 0011 0000 00001` , 对 bit 位是 1 的位关心,对 bit 位是 0 的位不关心,因此这个滤波器设置的的可以选范围是 `0x301` `0x311` `0x321` `0x331` 等等,当然还包括 `0x701` `0x711` `0x721` `0x731` 等。 ### 2 扩展帧标识符过滤器 扩展帧标识符的滤波器的个数根据 Message RAM 配置来决定,最大支持 64 个过滤器组。 #### 2.1 扩展帧标识符的范围过滤 ``` FDCAN1_RXFilter.IdType = FDCAN_EXTENDED_ID; //扩展帧 FDCAN1_RXFilter.FilterIndex = 0; //滤波器索引 0 FDCAN1_RXFilter.FilterType = FDCAN_FILTER_RANGE; //范围过滤 FDCAN1_RXFilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; //过滤器关联到 FIFO0 FDCAN1_RXFilter.FilterID1 = 0x10000100; //范围过滤的起始帧 ID FDCAN1_RXFilter.FilterID2 = 0x10000110; //范围过滤的结束帧 ID HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter); /* 设置 EIDM 的掩码为 0x1000 0001 */ HAL_FDCAN_ConfigExtendedIdMask(&hfdcan1, 0x10000001); ``` 以上设置为:扩展帧标识符过滤器的第 0 组,过滤条件但是范围过滤,过滤匹配的数据会被保存在 RXFIFO0,接收帧 ID 的范围是 `0x10000100 - 0x10000110`,但是因为设置了 EIDM 的掩码为 `0x1000 0001` 因此接收的帧 ID 的应该是 `0x10000100 - 0x10000110` 范围内且 ID 最低位是 1 的帧 ID,如: `0x10000101` `0x10000103` 。 #### 2.2 扩展帧标识符的精确过滤 ``` FDCAN1_RXFilter.IdType = FDCAN_EXTENDED_ID; //标准帧 FDCAN1_RXFilter.FilterIndex = 1; //滤波器索引 1 FDCAN1_RXFilter.FilterType = FDCAN_FILTER_DUAL; //精确过滤 FDCAN1_RXFilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO1; //过滤器 1 关联到FIFO1 FDCAN1_RXFilter.FilterID1 = 0x10000200; //精确过滤的 ID1 FDCAN1_RXFilter.FilterID2 = 0x10000210; //精确过滤的 ID2 HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter); ``` 以上设置为:扩展帧标识符过滤器的第 1 组,过滤条件但是精确过滤,过滤匹配的数据会被保存在 RXFIFO1,只会接受帧 ID 为 `0x10000200` 和 `0x10000210` 的报文,接收后会被保存在 RXFIFO1 #### 2.3 扩展帧标识符的掩码过滤 ``` FDCAN1_RXFilter.IdType = FDCAN_EXTENDED_ID; //标准帧 FDCAN1_RXFilter.FilterIndex = 2; //滤波器索引 2 FDCAN1_RXFilter.FilterType = FDCAN_FILTER_MASK; //掩码过滤 FDCAN1_RXFilter.FilterConfig = FDCAN_FILTER_TO_RXBUFFER; //过滤器 2 关联到 RXBUFF FDCAN1_RXFilter.RxBufferIndex = 0; //接收到的消息保存到 RXBUFF 索引号为 0 的空间 FDCAN1_RXFilter.FilterID1 = 0x10000000; //过滤的帧 ID FDCAN1_RXFilter.FilterID2 = 0x1FFFFFFF; //过滤帧 ID 的掩码 HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter); ``` 以上设置为:扩展帧标识符过滤器的第 2 组,过滤条件但是掩码过滤,过滤匹配的数据会被保存在 RXBUFF。 过滤帧 ID 是 0x10000000, 转化成二进制就是:`0001 0000 0000 0000 0000 0000 0000 00000`帧 ID 的掩码是 0x1FFFFFFF,转换成二进制就是:`0001 1111 1111 1111 1111 1111 1111 1111`, 对他们进行求与运算的结果就是 `0001 0000 0000 0000 0000 0000 0000 00000` , 对 bit 位是 1 的位关心,对 bit 位是 0 的位不关心,因此这个滤波器设置的的可以选范围是 `0x1000 0000 - 0x1FFF FFFF`。 #### 2.4 扩展帧标识符的范围过滤忽略 EIDM EIDM是 Extended ID and Mask ,扩展帧掩码的过滤器。 ``` FDCAN1_RXFilter.IdType = FDCAN_EXTENDED_ID; //标准帧 FDCAN1_RXFilter.FilterIndex = 3; //滤波器索引 2 FDCAN1_RXFilter.FilterType = FDCAN_FILTER_RANGE_NO_EIDM; //掩码过滤,忽略 EIDM FDCAN1_RXFilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0; //过滤器 3 关联到 RXFIFO0 FDCAN1_RXFilter.RxBufferIndex = 2; //接收到的消息保存到 RXBUFF 索引号为 0 的空间 FDCAN1_RXFilter.FilterID1 = 0x10000000; //过滤的帧 ID FDCAN1_RXFilter.FilterID2 = 0x10000010; //过滤帧 ID 的掩码 HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter); /* 设置 EIDM 的掩码为 0x1FFF FFFF */ HAL_FDCAN_ConfigExtendedIdMask(&hfdcan1, 0x1FFFFFFF); ``` 以上设置为:扩展帧标识符过滤器的第 3 组,过滤条件但是范围过滤忽略 EIDM,过滤匹配的数据会被保存在 RXFIFO0,接收帧 ID 的范围是 `0x10000100 - 0x10000110`。 ### 3 使能滤波器配置 在完成滤波器的配置之后,还需要对滤波器进行使能才能使滤波器生效。 ``` HAL_FDCAN_ConfigGlobalFilter(&hfdcan1, FDCAN_REJECT, FDCAN_REJECT, FDCAN_FILTER_REMOTE , FDCAN_FILTER_REMOTE); if (HAL_FDCAN_Start(&hfdcan1) != HAL_OK) { Error_Handler(); } ``` `HAL_FDCAN_ConfigGlobalFilter` 用来设置在符合滤波器的匹配条件之后的动作。 ``` /** * @brief Configure the FDCAN global filter. * @param hfdcan pointer to an FDCAN_HandleTypeDef structure that contains * the configuration information for the specified FDCAN. * @param NonMatchingStd Defines how received messages with 11-bit IDs that * do not match any element of the filter list are treated. * This parameter can be a value of @arg FDCAN_Non_Matching_Frames. * @param NonMatchingExt Defines how received messages with 29-bit IDs that * do not match any element of the filter list are treated. * This parameter can be a value of @arg FDCAN_Non_Matching_Frames. * @param RejectRemoteStd Filter or reject all the remote 11-bit IDs frames. * This parameter can be a value of @arg FDCAN_Reject_Remote_Frames. * @param RejectRemoteExt Filter or reject all the remote 29-bit IDs frames. * This parameter can be a value of @arg FDCAN_Reject_Remote_Frames. * @retval HAL status */ HAL_StatusTypeDef HAL_FDCAN_ConfigGlobalFilter(FDCAN_HandleTypeDef *hfdcan, uint32_t NonMatchingStd, uint32_t NonMatchingExt, uint32_t RejectRemoteStd, uint32_t RejectRemoteExt) ``` 这个函数有五个参数,第一个就忽略不讲,主要讲一下后面四个参数: - NonMatchingStd :不匹配的标准帧 ID 的处理行为 - NonMatchingExt :不匹配的扩展帧 ID 的处理行为 - RejectRemoteStd :拒绝远程标准帧 - RejectRemoteExt : 拒绝远程扩展帧 对不匹配的标准/扩展帧 ID 的处理行为,有以下三种方式: ``` #define FDCAN_ACCEPT_IN_RX_FIFO0 ((uint32_t)0x00000000U) /*!< Accept in Rx FIFO 0 */ #define FDCAN_ACCEPT_IN_RX_FIFO1 ((uint32_t)0x00000001U) /*!< Accept in Rx FIFO 1 */ #define FDCAN_REJECT ((uint32_t)0x00000002U) /*!< Reject */ ``` 可以选择保存在 RXFIFO0 ,RXFIFO1,或者拒绝接收,这里设置为拒绝接收。 拒绝远程标准/扩展帧 ``` #define FDCAN_FILTER_REMOTE ((uint32_t)0x00000000U) /*!< Filter remote frames */ #define FDCAN_REJECT_REMOTE ((uint32_t)0x00000001U) /*!< Reject all remote frames */ ``` - FDCAN_FILTER_REMOTE 允许(标准/扩展帧)的远程帧经过滤波器 - FDCAN_REJECT_REMOTE 拒绝(标准/扩展帧)的远程帧经过滤波器 这里设置为允许远程帧经过滤波器。 ## 四,高优先级报文 在 CANFD 中支持高优先级报文的功能,高优先级的报文顾名思义就是等级比较高的报文,他可以第一时间被通知到用户。需要注意的是高优先级的报文只能在 FIFO 模式下使用。 CANFD 的高优先报文是在经过滤波器之后将该报文设置为高优先级,所以高优先级的报文配置是在需要通过滤波器来配置。高优先级的报文支持两种模式: - 设置高优先级的消息但是保存该消息 - 设置高优先级的消息并将该消息保存到 RXFIFO0/1 中 高优先级的消息使用了接收回调的方式来通知到用户 ``` void HAL_FDCAN_HighPriorityMessageCallback(FDCAN_HandleTypeDef *hfdcan) { /* todo */ } ``` ### 1 接收高优先级的消息但不保存 通过对滤波器的设置,可以设置对应帧 ID 的消息为高优先级消息 ``` FDCAN1_RXFilter.IdType = FDCAN_STANDARD_ID; //标准ID FDCAN1_RXFilter.FilterIndex = 3; //滤波器索引为 3 FDCAN1_RXFilter.FilterType = FDCAN_FILTER_DUAL; //精确过滤 FDCAN1_RXFilter.FilterConfig = FDCAN_FILTER_HP; //将符合过滤帧 ID 的报文设置为高优先级 FDCAN1_RXFilter.FilterID1 = 0x402; //精确ID1 FDCAN1_RXFilter.FilterID2 = 0x403; //精确ID2 HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter); HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_HIGH_PRIORITY_MSG, 0); ``` 以上的设置为:标准帧 ID 为 `0x402` 和 `0x403` 的报文会通过滤波器并在高优先级的回调函数中通知到用户,但是通过以下的代码是 **无法** 读取到高优先的消息 ``` void HAL_FDCAN_HighPriorityMessageCallback(FDCAN_HandleTypeDef *hfdcan) { if (hfdcan == &hfdcan1) { HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &FDCAN1_RxHeader, rxdata); HAL_FDCAN_ActivateNotification(hfdcan, FDCAN_IT_RX_HIGH_PRIORITY_MSG, 0); } } ``` ### 2 接收高优先级的消息保存在 RXFIFO0/1 中 通过对滤波器的设置,可以设置对应帧 ID 的消息为高优先级消息 ``` FDCAN1_RXFilter.IdType = FDCAN_STANDARD_ID; //标准ID FDCAN1_RXFilter.FilterIndex = 4; //滤波器索引为4 FDCAN1_RXFilter.FilterType = FDCAN_FILTER_DUAL; //精确过滤 FDCAN1_RXFilter.FilterConfig = FDCAN_FILTER_TO_RXFIFO0_HP; //将符合过滤器帧 ID 的报文设置为高优先级,并保存在 RXFIFO0 FDCAN1_RXFilter.FilterID1 = 0x500; //精确 ID 1 FDCAN1_RXFilter.FilterID2 = 0x510; //精确 ID 2 HAL_FDCAN_ConfigFilter(&hfdcan1,&FDCAN1_RXFilter); HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_HIGH_PRIORITY_MSG, 0); ``` 以上的设置为:标准帧 ID 为 `0x500` 和 `0x510` 的报文会通过滤波器并在高优先级的回调函数中通知到用户,但是通过以下高优先级消息的回调函数是 **无法** 直接读取到高优先的消息 ``` void HAL_FDCAN_HighPriorityMessageCallback(FDCAN_HandleTypeDef *hfdcan) { if (hfdcan == &hfdcan1) { HAL_FDCAN_GetRxMessage(hfdcan, FDCAN_RX_FIFO0, &FDCAN1_RxHeader, rxdata); HAL_FDCAN_ActivateNotification(hfdcan, FDCAN_IT_RX_HIGH_PRIORITY_MSG, 0); } } ``` 高优先级的消息是保存在 RXFIFO 当中,所以在接收到高优先级的消息之后,应该应该尽快的将缓存在 RXFIFO 中的消息都取出,来获取到高优先级帧 ID 的消息。 ### 3 注意事项 1. 高优先级的消息在 RXFIFO 中不会插队,因此收到高优先级的消息后要尽快的取出 RXFIFO 中的数据; 2. 如果滤波器 0 与 滤波器 4 中的帧 ID 设置一致,那么该消息不会被设置为高优先级的消息,因为滤波器是采用遍历的滤波器索引的方式去检查该报文是否可以通过,一旦符合滤波器的规则,那么将不会继续向下索引。 ## 五,总结 CANFD 的配置非常灵活,这些配置与 Message RAM 的配置息息相关,熟练掌握 CANFD 的接收模式,有利于设计出更加健壮的程序,针对以上未提到的几个知识点在做以下总结: - CANFD 的滤波设计会从滤波器的索引 0 开始遍历,直到找到一个符合滤波器规则的通道之后,再接收这个数据,所以一个优秀的滤波器索引设计会提高程序的执行效率; - CANFD 的接收模式虽然很多且复杂,但实际上,直接用默认的 中断线 0,RXFIFO0,应付一般的场景也是游刃有余; - 同时使用多种接收方式的时候需要是用一下方式来进行激活通知 ``` HAL_FDCAN_ActivateNotification(&hfdcan1, FDCAN_IT_RX_FIFO0_WATERMARK | FDCAN_IT_RX_FIFO0_NEW_MESSAGE | FDCAN_IT_RX_FIFO1_NEW_MESSAGE | FDCAN_IT_RX_BUFFER_NEW_MESSAGE | FDCAN_IT_RX_HIGH_PRIORITY_MSG, 0); ``` 在回调函数里面接收完数据之后,只需要根据具体的类型的再次执行激活函数即可; - 参考文档《RM0433》《AN5348》。
6
条评论
默认排序
按发布时间排序
登录
注册新账号
关于作者
whj467467222
开源,分享,交流,共同进步
文章
32
回答
1222
被采纳
149
关注TA
发私信
相关文章
1
ARTPi 的FDCAN使用官方工程如何发送数据?
2
STM32H750 FDCAN通信异常
3
ART-PI 的FDCAN功能使用
4
ART-PI FDCAN使用卡在rt_completion_wait处
5
ART PI FDCAN 死在rt_device_write
6
Art Pi FDCAN 到底能不能用呀?
7
CAN.c 与drv_fdcan.c兼容么?
8
出现这样的异常如何解决
9
能否有偿指导一下art-pi的hdcan使用
10
FDCAN报错 FDCAN报错
推荐文章
1
RT-Thread应用项目汇总
2
玩转RT-Thread系列教程
3
国产MCU移植系列教程汇总,欢迎查看!
4
机器人操作系统 (ROS2) 和 RT-Thread 通信
5
五分钟玩转RT-Thread新社区
6
【技术三千问】之《玩转ART-Pi》,看这篇就够了!干货汇总
7
关于STM32H7开发板上使用SDIO接口驱动SD卡挂载文件系统的问题总结
8
STM32的“GPU”——DMA2D实例详解
9
RT-Thread隐藏的宝藏之completion
10
【ART-PI】RT-Thread 开启RTC 与 Alarm组件
热门标签
RT-Thread Studio
串口
Env
LWIP
SPI
AT
Bootloader
Hardfault
CAN总线
FinSH
ART-Pi
DMA
USB
文件系统
RT-Thread
SCons
RT-Thread Nano
线程
MQTT
STM32
RTC
rt-smart
FAL
I2C_IIC
UART
ESP8266
cubemx
WIZnet_W5500
ota在线升级
PWM
BSP
flash
freemodbus
packages_软件包
潘多拉开发板_Pandora
定时器
ADC
GD32
flashDB
socket
编译报错
中断
Debug
rt_mq_消息队列_msg_queue
keil_MDK
ulog
SFUD
msh
C++_cpp
MicroPython
本月问答贡献
RTT_逍遥
10
个答案
3
次被采纳
xiaorui
3
个答案
2
次被采纳
winfeng
2
个答案
2
次被采纳
三世执戟
8
个答案
1
次被采纳
KunYi
8
个答案
1
次被采纳
本月文章贡献
catcatbing
3
篇文章
5
次点赞
lizimu
2
篇文章
9
次点赞
swet123
1
篇文章
4
次点赞
Days
1
篇文章
4
次点赞
YZRD
1
篇文章
2
次点赞
回到
顶部
发布
问题
投诉
建议
回到
底部