STM32 bxCAN的过滤器组与过滤器编号详解

来源:互联网 发布:免费汽车维修软件 编辑:程序博客网 时间:2024/05/18 17:01

过滤器组(Filter Bank)


在互联型产品中, bxCAN控制器为应用程序提供了28个位宽可变的、可配置的过滤器组(27~0);在其它产品中, bxCAN控制器为应用程序提供了14个位宽可变的、可配置的过滤器组(13~0)。每个过滤器组x由2个32位寄存器, CAN_FxR0和CAN_FxR1组成。

sFilterConfig.FilterNumber = x;

程序中通过此句代码选择哪一个过滤器组进行初始化并配置过滤器;在互联型产品中,CAN1和CAN2分享28个过滤器组,x的值为0~27;在其他产品中有14个过滤器组,x的值为0~13.

sFilterConfig.BankNumber = n;

此句代码针对双CAN的STM32产品,配置CAN2可使用的过滤器组的起始编号,n取值范围为0~28.从编号为n的过滤器组到编号为27的过滤器组分配给CAN2使用。如果此句配置不在代码中明确写出来,默认值就是14. 即硬件默认将编号为14起往后的过滤器组分配给CAN2使用。

过滤器


过滤器组并不等同于过滤器,每个过滤器组x由2个32位寄存器CAN_FxR0和CAN_FxR1组成;而且每个过滤器组x的位宽可独立设置,过滤器组x有几个过滤器取决于过滤器组的模式和位宽的设置。

/*## Configure the CAN Filter ###########################################*/ sFilterConfig.FilterNumber = 2;                    //过滤器组2sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;  //标识符列表模式sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //位宽32位sFilterConfig.FilterIdHigh = (((ID_LIST_2 << 3) & 0xFFFF0000)) >> 16; //要过滤的ID高位sFilterConfig.FilterIdLow = ((ID_LIST_2 << 3) | CAN_ID_EXT | CAN_RTR_REMOTE) & 0xFFFF; //要过滤的ID低位以及帧类型(扩展帧/标准帧、数据帧/远程帧)sFilterConfig.FilterMaskIdHigh = (((ID_LIST_1 << 3) & 0xFFFF0000)) >> 16;//要过滤的ID高位sFilterConfig.FilterMaskIdLow = ((ID_LIST_1 << 3) | CAN_ID_EXT | CAN_RTR_REMOTE) & 0xFFFF; //要过滤的ID低位以及帧类型(扩展帧/标准帧、数据帧/远程帧)sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; //关联到FIFO0sFilterConfig.FilterActivation = ENABLE;               //使能if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK){    /* Filter configuration Error */    Error_Handler();}

上面的配置将过滤器组2配置成32位的过滤器列表模式,屏蔽寄存器也被当作标识符寄存器用,相当于2个过滤器,接收报文标识符的每一位都必须跟过滤器标识符(即程序中的宏ID_LIST_1和ID_LIST_2)相同.

过滤器编号/过滤器匹配序号(Filter match index)


过滤器组中的每个过滤器,都被编号为(叫做过滤器号)从0开始,到某个最大数值-取决于过滤器组的模式和位宽的设置。

一旦收到的报文被存入FIFO,就可被应用程序访问。通常情况下,报文中的数据被拷贝到SRAM中;为了把数据拷贝到合适的位置,应用程序需要根据报文的标识符来辨别不同的数据。 bxCAN提供了过滤器匹配序号,以简化这一辨别过程。根据过滤器优先级规则,过滤器匹配序号和报文一起,被存入邮箱中。因此每个收到的报文,都有与它相关联的过滤器匹配序号。

/**  * @brief  CAN Rx message structure definition  */typedef struct{  uint32_t StdId;     uint32_t ExtId;         uint32_t IDE;           uint32_t RTR;          uint32_t DLC;         uint8_t Data[8];       uint32_t FMI;         /* 过滤器编号/过滤器匹配序号 */  uint32_t FIFONumber;  }CanRxMsgTypeDef;

过滤器匹配序号按照过滤器组的顺序从0开始,在给过滤器编号时,并不考虑过滤器组是否为激活状态,到某个最大数值-取决于过滤器组的模式和位宽的设置。另外,每个FIFO各自对其关联的过滤器进行编号。下图为STM32F103x参考手册提供的过滤器编号的例子。

STM32F103x参考手册上的过滤器编号的例子

/*## Configure the CAN Filter ###########################################*/ sFilterConfig.FilterNumber = 0;                                       //过滤器组0                      sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;                     //标识符屏蔽模式sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;                    //位宽32位sFilterConfig.FilterIdHigh = (((ID_MASK_1 << 3) & 0xFFFF0000)) >> 16; //要过滤的ID高位sFilterConfig.FilterIdLow = ((ID_MASK_1 << 3) | CAN_ID_EXT | CAN_RTR_REMOTE) & 0xFFFF; //要过滤的ID低位以及帧类型(扩展帧/标准帧、数据帧/远程帧)sFilterConfig.FilterMaskIdHigh = 0xFFFF;                              //过滤器高16位每位必须匹配 sFilterConfig.FilterMaskIdLow = 0xFFFF;                               //过滤器低16位每位必须匹配 /*报文ID必须全部匹配与设置成过滤器列表模式实现的功能相同,在实际应用中可能只需要某些位匹配即可,灵活性很大,此处只是为了举例说明过滤器编号故简化设置*/sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;                //过滤器组0关联到FIFO0sFilterConfig.FilterActivation = ENABLE;                              //使能if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)           {    /* Filter configuration Error */    Error_Handler();}sFilterConfig.FilterNumber = 1;                                      //过滤器组1sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;                    //标识符列表模式sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;                   //位宽32位sFilterConfig.FilterIdHigh = (((ID_LIST_2 << 3) & 0xFFFF0000)) >> 16;sFilterConfig.FilterIdLow = ((ID_LIST_2 << 3) | CAN_ID_EXT | CAN_RTR_REMOTE) & 0xFFFF;sFilterConfig.FilterMaskIdHigh = (((ID_LIST_1 << 3) & 0xFFFF0000)) >> 16;sFilterConfig.FilterMaskIdLow = ((ID_LIST_1 << 3) | CAN_ID_EXT | CAN_RTR_REMOTE) & 0xFFFF;sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;sFilterConfig.FilterActivation = ENABLE;sFilterConfig.BankNumber = 14;if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK){    /* Filter configuration Error */    Error_Handler();}

上面的程序中配置了过滤器组0、1,位宽都设置为32位,分别工作在标识符屏蔽模式和列表模式;过滤ID为ID_MASK_1的过滤器编号为0,过滤ID为ID_LIST_2的过滤器编号为1,过滤ID为ID_LIST_1的过滤器编号为2.因此可以在接收回调函数中运用过滤器匹配序号,简化程序辨别:

/** * @brief  Transmission complete callback in non blocking mode * @param  hcan: pointer to a CAN_HandleTypeDef structure that contains *         the configuration information for the specified CAN. * @retval None */void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan){    HAL_UART_Transmit(&huart2,(uint8_t*)"\r\nReceived Successfully!!!\r\n",strlen("\r\nReceived Successfully!!!\r\n"),100);    if (hcan->pRxMsg->FMI == 0)       // 接收到ID为ID_MASK_1的报文    {                   // add code    }    else if (hcan->pRxMsg->FMI == 1)  // 接收到ID为ID_LIST_2的报文    {        // add code    }    else if (hcan->pRxMsg->FMI == 2) // 接收到ID为ID_LIST_1的报文    {        // add code    }    __HAL_CAN_ENABLE_IT(hcan,CAN_IT_FMP0);}

上面的例程里让每一个过滤器只过滤一个ID,实现的功能很简单,理解起来应该也比较容易,若程序功能比较复杂,根据过滤器的不同配置,有可能一个报文标识符能通过多个过滤器的过滤;在这种情况下,存放在接收邮箱中的过滤器匹配序号,根据下列优先级规则来确定:

  • 位宽为32位的过滤器,优先级高于位宽为16位的过滤器
  • 对于位宽相同的过滤器,标识符列表模式的优先级高于屏蔽位模式
  • 位宽和模式都相同的过滤器,优先级由过滤器号决定,过滤器号小的优先级高

/*## Configure the CAN Filter ###########################################*/ sFilterConfig.FilterNumber = 0;                                       //过滤器组0                      sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;                     //标识符屏蔽模式sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;                    //位宽32位sFilterConfig.FilterIdHigh = (((ID_MASK_1 << 3) & 0xFFFF0000)) >> 16; //要过滤的ID高位sFilterConfig.FilterIdLow = ((ID_MASK_1 << 3) | CAN_ID_EXT | CAN_RTR_REMOTE) & 0xFFFF; //要过滤的ID低位以及帧类型(扩展帧/标准帧、数据帧/远程帧)sFilterConfig.FilterMaskIdHigh = 0xFFFF;                              //过滤器高16位每位必须匹配 sFilterConfig.FilterMaskIdLow = 0xFFFF;                               //过滤器低16位每位必须匹配 报文ID必须全部匹配与设置成过滤器列表模式实现的功能相同sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;                //过滤器组0关联到FIFO0sFilterConfig.FilterActivation = ENABLE;                              //使能if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK)           {    /* Filter configuration Error */    Error_Handler();}sFilterConfig.FilterNumber = 1;                                      //过滤器组1sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST;                    //标识符列表模式sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;                   //位宽32位sFilterConfig.FilterIdHigh = (((ID_MASK_1 << 3) & 0xFFFF0000)) >> 16;sFilterConfig.FilterIdLow = ((ID_MASK_1 << 3) | CAN_ID_EXT | CAN_RTR_REMOTE) & 0xFFFF;sFilterConfig.FilterMaskIdHigh = (((ID_LIST_1 << 3) & 0xFFFF0000)) >> 16;sFilterConfig.FilterMaskIdLow = ((ID_LIST_1 << 3) | CAN_ID_EXT | CAN_RTR_REMOTE) & 0xFFFF;sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;sFilterConfig.FilterActivation = ENABLE;sFilterConfig.BankNumber = 14;if(HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK){    /* Filter configuration Error */    Error_Handler();}

上面的程序同样配置过滤器组0、1位宽为32位,过滤器组0为标识符屏蔽位模式,过滤器组1为标识符列表模式,若收到的报文ID为ID_MASK_1,则该报文既能通过过滤器组0,也能通过过滤器组1,但根据上述的优先级规则可知,该报文的过滤器匹配序号为1.

说了这么多,不知道我有没有讲清楚STM32 CAN外设的过滤器组以及过滤器匹配序号的分配规则,其实,通过STM32CubeMX可以很方便的开发STM32,在自动生成的工程上,结合STM32参考手册多配置几个不同模式的过滤器组,应该很快就可以掌握CAN外设过滤器的使用,毕竟实践出真知!若我有什么讲解不对的地方,希望大家可以留言!!!

阅读全文
0 0