Introduction
This is a rather specific post that is motivated by the rather unintuitive use of Identifier filtering on an STM32Fxx CAN Bus and by the impossibility to find some easy examples. For a general overview, refer to the official manual from page 1092 onwards.
Identifier filtering
Every CAN message has an associated ID sent with its content. A receiver can decide on a hardware level which IDs to accept by using 27 so called filter banks which can implement either one 32-bit filter or two 16-bit filter. The usage of these also depends on your scale of CAN Msg IDs which can either be standard IDs (11-bit) or extended IDs (29-bit). In this post we assume the usage of the extended IDs.
Mask Mode
The filter makes use of two 29-bit numbers – composed in a FilterId and a FilterMask and there are two modes to be used: Identifier Mode and Mask Mode. The identifier mode is pretty simple: both numbers represent IDs that should be caught by the filter. For the Mask Mode that we are presenting here, the FilterMask specifies which bits to compare with the FilterId, some examples for extended IDs:
MASK = 0x1FFFFFFEandID = 0x00000002will catch IDs 2 and 3.MASK = 0x1FFFFFF8andID = 0x00000000will catch IDs 0 to 7.MASK = 0x1FFFFFFFandID = 0x00000008will catch ID 8.MASK = 0x00000001andID = 0x00000001will catch all odd IDs.
So for “normal” operations, you can only filter either single IDs or ranges in the form 2^N - (2^(N-1) - 1) but there are also possibilities such as only accepting odd IDs and whatever you can combine with these representations. Each filter is also associated with a number, with generally being the lower the number the higher the priority, other priority rules are given in the documentation. One important point that is not mentioned though: In mask mode, a mask of 0x00 means that all IDs gets passed, be aware that this filter will “grab” all IDs from all other filters and the filter number doesn’t play a role anymore!
Implementation
The actual filters are actually used by configuring the CAN_FilterInitTypeDef struct of the stm32f4xx_can.h filter, which has various fields. For the specific case of this post, the filter is setup as seen in this snippet, with filter_id and filter_mask being an input from the user as specified before:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 |
CAN_FilterInitTypeDef filter; filter.CAN_FilterIdHigh = ((filter_id << 5) | (filter_id >> (32 - 5))) & 0xFFFF; // STID[10:0] & EXTID[17:13] filter.CAN_FilterIdLow = (filter_id >> (11 - 3)) & 0xFFF8; // EXID[12:5] & 3 Reserved bits filter.CAN_FilterMaskIdHigh = ((filter_mask << 5) | (filter_mask >> (32 - 5))) & 0xFFFF; filter.CAN_FilterMaskIdLow = (filter_mask >> (11 - 3)) & 0xFFF8; filter.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; filter.CAN_FilterNumber = filter_num; filter.CAN_FilterMode = CAN_FilterMode_IdMask; filter.CAN_FilterScale = CAN_FilterScale_32bit; filter.CAN_FilterActivation = ENABLE; CAN_FilterInit(&filter); |
The reasoning behind this bit shifting is best understood by having a look at the referenced manual on p. 1092. Whereas High and Low are the higher and lower indices of the filter registers respectively.
For ID list mode, each filter applied to 2 IDS
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 |
#define REMOTE_FRAME 0 /* If = 1 the frame should be a remote frame. If = 0 the frame will be a data frame */ #define EXTID 1 /* If = 0 the frame should be a frame with standard ID. If = 1 the frame should be a frame with extended ID */ #define ID1 0x0CF00400 #define ID2 0x0CFD9200 #define FILTER_ID ((ID1 << 3) | (REMOTE_FRAME<<1) | (EXTID <<2)) // ID1 = 0x0CF00400 (FxFR1[31:0]) #define FILTER_MASK ((ID2 << 3) | (REMOTE_FRAME<<1) | (EXTID <<2)) // ID2 = 0x0CFD9200 (FxFR2[31:0]) sFilterConfig.FilterMode = CAN_FILTERMODE_IDLIST; sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; sFilterConfig.FilterIdHigh = (FILTER_ID >> 16); // Filter ID2 LSB (FxFR2[0:15]) sFilterConfig.FilterIdLow = (FILTER_ID & 0xFFFF); // Filter ID1 LSB (FxFR1[0:15]) sFilterConfig.FilterMaskIdHigh = (FILTER_MASK >> 16); // Filter ID2 MSB (FxFR2[16:31]) sFilterConfig.FilterMaskIdLow = (FILTER_MASK & 0xFFFF); // Filter ID1 MSB (FxFR1[16:31]) |
Use more filters to filter more IDS
For each filter (new filter configuration) you need to increment .FilterBank:
sFilterConfig.FilterBank = 0; -> filter number 0
sFilterConfig.FilterBank = 1; -> filter number 1
sFilterConfig.FilterBank = 2; -> filter number 2 etc ..
Working codes:
|
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 |
void CAN_filter_config(uint8_t filter_index, uint32_t ID, uint32_t MASK) { CAN_FilterTypeDef sFilter_config; // Create a new filter config structure for each call sFilter_config.FilterBank = filter_index; sFilter_config.FilterMode = CAN_FILTERMODE_IDLIST; sFilter_config.FilterScale = CAN_FILTERSCALE_32BIT; sFilter_config.FilterIdHigh = (ID >> 16); sFilter_config.FilterIdLow = (ID & 0xFFFF); sFilter_config.FilterMaskIdHigh = (MASK >> 16); sFilter_config.FilterMaskIdLow = (MASK & 0xFFFF); sFilter_config.FilterFIFOAssignment = CAN_FILTER_FIFO0; sFilter_config.FilterActivation = ENABLE; if (HAL_CAN_ConfigFilter(&hcan, &sFilter_config) != HAL_OK) { CAN_error(); } } |
|
1 2 3 4 5 6 7 8 9 10 11 |
#define FILTER_ID1 ((ID1 << 3) | (REMOTE_FRAME<<1) | (EXTID <<2)) #define FILTER_MASK1 ((ID2 << 3) | (REMOTE_FRAME<<1) | (EXTID <<2)) #define FILTER_ID2 ((ID3 << 3) | (REMOTE_FRAME<<1) | (EXTID <<2)) #define FILTER_MASK2 ((ID4 << 3) | (REMOTE_FRAME<<1) | (EXTID <<2)) #define FILTER_ID3 ((ID5 << 3) | (REMOTE_FRAME<<1) | (EXTID <<2)) #define FILTER_MASK3 ((ID6 << 3) | (REMOTE_FRAME<<1) | (EXTID <<2)) #define FILTER_ID4 ((ID7 << 3) | (REMOTE_FRAME<<1) | (EXTID <<2)) #define FILTER_MASK4 ((ID8 << 3) | (REMOTE_FRAME<<1) | (EXTID <<2)) |