• 正文
  • 相关推荐
申请入驻 产业图谱

为什么CAN接收少了一帧消息‌

06/15 10:28
159
加入交流群
扫码加入
获取工程师必备礼包
参与热点资讯讨论

有开发者在STM32H743新品开发项目中用到了片内FDCAN外设。前期针对FDCAN作基础性验证测试时,发现即使在回环模式下也会发生丢帧现象。

具体情况是这样的:将FDCAN配置在传统经典模式,配置了3个过滤器。其中2个过滤器只接收特定ID的消息,过滤选择后的消息存入指定的Buffer;另外1个过滤器针对一定范围的ID的消息进行接收,接收到的消息将存入FIFO0。

CAN的滤波器的配置是这样的:

第一个过滤器,允许通过的消息ID范围是0x200~0x2FF,消息存入Rx FIFO0

第二个过滤器,允许通过的消息ID固定是0x111,消息存入Rx Buffer0

第三个过滤器,允许通过的消息ID固定是0x222,消息存入Rx Buffer1

三个过滤器的配置代码如下:

static void FDCAN1_Filter0_ToFifo0_Config(void){  FDCAN_FilterTypeDef sFilterConfig = {0};    sFilterConfig.IdType = FDCAN_STANDARD_ID;              /* 标准ID */  sFilterConfig.FilterIndex = 0;                         /* Index 0 */  sFilterConfig.FilterType = FDCAN_FILTER_RANGE;         /* 范围模式 */  sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXFIFO0;  /* 命中后送入FIFO0 */  sFilterConfig.FilterID1 = 0x200;                       /* 范围起始 */  sFilterConfig.FilterID2 = 0x2FF;                       /* 范围结束 */    if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)  {      Error_Handler();  }  }/* * FDCAN1_Filter1_ToRxBuffer0_Config — 配置 FDCAN1 滤波器 Index 1:精确匹配 0x111 → Rx Buffer0 * */static void FDCAN1_Filter1_ToRxBuffer0_Config(void){    FDCAN_FilterTypeDef sFilterConfig = {0};    sFilterConfig.IdType = FDCAN_STANDARD_ID;    sFilterConfig.FilterIndex = 1;                         /* Index 1 */    sFilterConfig.FilterType = FDCAN_FILTER_MASK;    sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXBUFFER;    sFilterConfig.FilterID1 = 0x111;    sFilterConfig.FilterID2 = 0x7FF;   // 精确匹配    sFilterConfig.RxBufferIndex = 0;    /* 命中后送入BUFFER 0 */    if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)    {        Error_Handler();    }}/* * FDCAN1_Filter2_ToRxBuffer1_Config — 配置 FDCAN1 滤波器 Index 2:精确匹配 0x222 → Rx Buffer1 * */static void FDCAN1_Filter2_ToRxBuffer1_Config(void){    FDCAN_FilterTypeDef sFilterConfig = {0};    sFilterConfig.IdType = FDCAN_STANDARD_ID;    sFilterConfig.FilterIndex = 2;                        /* Index 2 */      sFilterConfig.FilterType = FDCAN_FILTER_MASK;    sFilterConfig.FilterConfig = FDCAN_FILTER_TO_RXBUFFER;    sFilterConfig.FilterID1 = 0x222;    sFilterConfig.FilterID2 = 0x7FF;   // 精确匹配    sFilterConfig.RxBufferIndex = 1;   /* 命中后送入BUFFER 1 */    if (HAL_FDCAN_ConfigFilter(&hfdcan1, &sFilterConfig) != HAL_OK)    {        Error_Handler();    }}

启动基于FIFO和BUFFER接收的新消息CAN中断【注:这里没启用FIFO满和丢消息中断】。

  if (HAL_FDCAN_ActivateNotification(&hfdcan1,                               FDCAN_IT_RX_FIFO0_NEW_MESSAGE |FDCAN_IT_RX_BUFFER_NEW_MESSAGE,                               0) != HAL_OK)  {      Error_Handler();  }

现在让FDCAN工作在回环模式,程序里每隔几秒钟一次性发送三帧消息。每次发的第一帧消息的ID在0x200~0x2FF间变化,另外两帧的ID分别是0x111和0x222,并依次先后发送。测试过程中,他发现了个奇怪的现象。

虽然每次发送三帧消息,可总是只收到2帧消息。具体收到的就是ID为x0111和0x222的消息。下面截图是实际测试结果。

从串口打印的结果来看,0x111的消息被正确接收到了buffer0,0x222的消息虽然收到了,但它并不是进的buffer1,而是进到rx FIFO。

怎么会这样呢?从目前的CAN Filter配置来看,3个Filter的配置索引是这样的:

其实,消息是依次从Filter0~Filter2进行过滤匹配的,若在上级发生匹配后就进入相应消息缓存【FIFO或buffer】,不再往下做匹配。

现在Filter 0允许通过的ID是0x200~0x2FF,而ID 0x222又落在这个区间,导致ID 0x222的消息总是进入到FIFO而没有机会经Filter 2进入Buffer1.这就不难理解ID 0x222的消息虽能收到,但进入的是FIFO而不是Buffer。

既然这样,我们将目前filter 0和filter 3的索引号换一下,像下面这样:

其它不动,再行测试。下面是输出结果:

图中信息显示,ID 0x111的消息进入buffer0, ID 0x222的消息进入了buffer1,ID位于0x200~0x2ff的消息进入了FIFO。

不难看出,调整filter索引顺序后的运行结果是正确的,各ID消息进到各自的接收缓冲,没有丢帧现象,一切都符合预期。到此,似乎一切都圆满解决了。

其实还不能这么说,针对filter索引调整之前的输出结果还有待探究的地方。因为即使基于调整前的配置,顶多发生ID 0x222的消息没有按预期进到buffer而进到了FIFO,但ID位于0x200~0x2ff的消息完全接收不到,从原理上还是解释不通!

换句话说,在初始配置下,每次发3帧过来后,RXFIFO里应该有2帧数据,其中除了ID 0x222那帧外,另外一帧应该就是来自0x200~0x2ff的某ID帧。

从目前运行结果来看,围绕FDCAN的硬件配置应该是没啥问题的,难道是CAN接收处理代码有问题?于是,重点检查FDCAN FIFO接收中断的相关代码,代码里有针对FIFO填充深度的检查,并逐一提取。

提取的信息放在缓冲数组,并设置消息收到标志,在主循环里基于消息标志实施打印输出。经过代码的仔细检查,结果发现在CAN消息接收中断处理代码里有个bug,具体就是所有接收消息共用了同一个缓冲数组,导致数组里每次只放最后从FIFO里提取出来的消息。

如果说每次FIFO里最多就一个消息倒没事,不会出错。若FIFO里每次提取时存入了2个甚至更多帧消息时,这时就会出现问题,即每次最终只打印输出最后进FIFO的那帧消息。

鉴于此,为了满足每次接收可能出现多条FIFO消息的打印输出,便根据预设的FIFO深度【比方8】准备了多个将用于打印输出的数组缓冲,避免消息覆盖问题【当然,你采用别的方式也是可以的】。调整了基于FIFO接收中断的回调处理函数后,先退回最初的CAN Filter配置,再进行验证测试。一起来看看输出结果:

显然这次没有发生丢帧的现象,只不过每次FIFO里收到了两帧消息,一帧是ID 0x222的,另外一帧是0x200~0x2ff内某ID的。聊到这里,我们应该明白了,刚开始以为的丢帧,在硬件上是不存在的,只是用户软件处理代码bug导致的误会,属于软件层面。

当然,之前的ID 0x222的消息进不到buffer是不符合设计预期的,后来的filter索引顺序的调整就正好解决了这个问题,最终实现每帧消息均进入预设的目标缓冲区(精确ID进Buffer,范围型ID进FIFO)。OK,今天的话题就分享到这里。

相关推荐