cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F0 bxCan Filters

Artur Vieira
Associate III
Posted on March 24, 2018 at 22:40

Hello

Today i was playing around with the bxCan module in a NUCLEO-F091RC, and trying to understand how the filter works.

Afterrading some posts here in the forum i was able to understand the concept of ID and MASK, but while making some experiments i am having some problems.

As an example i was trying to setup filters to only accept CAN messages with ID '0x651' or ID between '0x7E8' and '0x7EF' and this was my code:

 CAN_FilterInitStructure.CAN_FilterNumber = 0;
 CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
 CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_16bit;
 CAN_FilterInitStructure.CAN_FilterIdLow = (0x7E8 << 5);
 CAN_FilterInitStructure.CAN_FilterIdHigh = (0x651 << 5);
 CAN_FilterInitStructure.CAN_FilterMaskIdLow = (0x7F8 << 5);
 CAN_FilterInitStructure.CAN_FilterMaskIdHigh = (0x7FF << 5);
 CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
 CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;
 CAN_FilterInit(&CAN_FilterInitStructure);�?�?�?�?�?�?�?�?�?�?

But nothing was being received (i am using a 'CANDOISO' device to simulate messages in the CAN BUS). The CANDOISO device is working, if i don't have any filters configured (or configure a MASK and ID as '0') i am able to receive messages.

The only way for it to work, was to modify the way the registers related to the filters are loaded, i had to change the ST provided driver from:

/* First 16-bit identifier and First 16-bit mask */
/* Or First 16-bit identifier and Second 16-bit identifier */
CAN->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR1 =
 ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdLow) << 16) |
 (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdLow);
/* Second 16-bit identifier and Second 16-bit mask */
/* Or Third 16-bit identifier and Fourth 16-bit identifier */
CAN->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR2 = ((0x0000FFFF & (uint32_t) CAN_FilterInitStruct->CAN_FilterMaskIdHigh) << 16)
 | (0x0000FFFF & (uint32_t) CAN_FilterInitStruct->CAN_FilterIdHigh);�?�?�?�?�?�?�?�?�?�?

to:

/* First 16-bit identifier and First 16-bit mask */
 /* Or First 16-bit identifier and Second 16-bit identifier */
CAN->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR1 = 
 (0x0000FFFF & (uint32_t) CAN_FilterInitStruct->CAN_FilterMaskIdLow)
 | ((0x0000FFFF & (uint32_t) CAN_FilterInitStruct->CAN_FilterIdLow) << 16);
/* Second 16-bit identifier and Second 16-bit mask */
 /* Or Third 16-bit identifier and Fourth 16-bit identifier */
CAN->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR2 = 
 (0x0000FFFF & (uint32_t) CAN_FilterInitStruct->CAN_FilterMaskIdHigh)
 | ((0x0000FFFF & (uint32_t) CAN_FilterInitStruct->CAN_FilterIdHigh) << 16);�?�?�?�?�?�?�?�?�?�?�?

Basically switching the position of the Filter ID and Mask in the registers, that is going against what is states in the reference manual (section 7.4 Figure 315).

For usingthe filter in 16 bit mode the code at the moment with this modification is working, but i really need to have filters working for CAN 29 bit ID, and for this mode (using the filter in 32Bit mode) it is not working, even if i change the order of WORDs in the configuration registers.

This is the configuration i am trying to load in the case of 29 bit ID's (the goal is to only accepts ID 0x--FEEE--)

 CAN_FilterInitStructure.CAN_FilterNumber = 0;
 CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
 CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
 CAN_FilterInitStructure.CAN_FilterIdHigh = ((0x00FEEE00) & 0x7FF) << 5;
 CAN_FilterInitStructure.CAN_FilterIdHigh |= (((0x00FEEE00) & 0x1F000000) >> 24);
 CAN_FilterInitStructure.CAN_FilterIdLow = (0x00FEEE00 & 0x00FF0000) >> 8;
 CAN_FilterInitStructure.CAN_FilterIdLow |= ((0x00FEEE00 & 0x0000F800) >> 8);
 CAN_FilterInitStructure.CAN_FilterMaskIdHigh = ((0x00FFFF00) & 0x7FF) << 5;
 CAN_FilterInitStructure.CAN_FilterMaskIdHigh |= (((0x00FFFF00) & 0x1F000000) >> 24);
 CAN_FilterInitStructure.CAN_FilterMaskIdLow = (0x00FFFF00 & 0x00FF0000) >> 8;
 CAN_FilterInitStructure.CAN_FilterMaskIdLow |= ((0x00FFFF00 & 0x0000F800) >> 8);
 CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
 CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;�?�?�?�?�?�?�?�?�?�?�?�?�?

I am using the SPL (v1.5.0) but i have checked the code in HAL v1.9.0 and the code for the filters setup is mostly the same, the same for the F4 family (was the other HAL library i had on the PC at the moment).

Any feedback is appreciated..

Artur

#corrections-reference-manual #can-bxcan
5 REPLIES 5
Ben K
Senior III
Posted on March 25, 2018 at 01:16

The bxCAN filter configuration is no straightforward task, and the SPL/HAL functions don't get you far. The

https://github.com/IntergatedCircuits/STM32_XPD/blob/master/STM32F0_XPD/src/xpd_can.c#L714

function illustrates the complexity of setting up an array of filters, and calculating their Filter Match Indexes. In this case the usage would look like this:

const CAN_FilterType filters[2] = {
 {
 .Pattern.Value = 0x651,
 .Pattern.Type = CAN_IDTYPE_STD_DATA,
 .Mode = CAN_FILTER_MATCH,
 .FIFO = 0,
 },
 {
 .Pattern.Value = 0x7E8,
 .Pattern.Type = CAN_IDTYPE_STD_DATA,
 .Mode = CAN_FILTER_MASK,
 .Mask = 0x7F8,
 .FIFO = 0,
 },
};
uint8_t FMIs[2]; /* same element count as filters */
CAN_HandleType hcan = {
 .Inst = CAN,
 .CtrlPos = RCC_POS_CAN,
};
void filterConfig(void)
{
 /* Peripheral clock is already enabled here */
 CAN_eFilterConfig(Can, filters, FMIs, 2);
}�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?�?

As you can see, this function takes sensible inputs (individual filters instead of precalculated filter banks), and returns the FMI for each filter which can be used during reception to easily identify the passing filter.

T J
Lead
Posted on March 25, 2018 at 15:01

Wow, @'Ben K'  that's intense.

here is my humble method in comparison

    //##-2- Configure the CAN Filter ###########################################

      sFilterConfig.FilterNumber                     = 0;

    sFilterConfig.FilterMode                       = CAN_FILTERMODE_IDMASK;

    sFilterConfig.FilterScale                      = CAN_FILTERSCALE_32BIT;

    sFilterConfig.FilterIdHigh                     = 0x400 << 5;  //11-bit ID in top bits

    sFilterConfig.FilterIdLow                      = 0x0000;

    sFilterConfig.FilterMaskIdHigh                  = 0x600 << 5;     // resolves as 0x0400 - 0x05FF

    sFilterConfig.FilterMaskIdLow                = 0x0000;

    sFilterConfig.FilterFIFOAssignment            = 0;

    sFilterConfig.FilterActivation                = ENABLE;

    sFilterConfig.BankNumber                     = 0;

    if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)

    {

        // Filter configuration Error

        _Error_Handler(__FILE__, __LINE__);

        char string[38];

        sprintf( string, 'Can Filter configuration Error\n\r');

        puts1( string);

    }

    

    //##-2- Configure the 2nd CAN Filter ###########################################

      sFilterConfig.FilterNumber                     = 1;

    sFilterConfig.FilterMode               = CAN_FILTERMODE_IDMASK;

    sFilterConfig.FilterScale              = CAN_FILTERSCALE_32BIT;

    sFilterConfig.FilterIdHigh             = 0x600 << 5;  //11-bit ID in top bits        // command channel

    sFilterConfig.FilterIdLow              = 0x0000;

    sFilterConfig.FilterMaskIdHigh        = 0x700 << 5;     // resolves as 0x0600 - 0x06FF

    sFilterConfig.FilterMaskIdLow        = 0x0000;

    sFilterConfig.FilterFIFOAssignment    = 1;

    sFilterConfig.FilterActivation        = ENABLE;

    sFilterConfig.BankNumber             = 1;

    if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)

    {

        // Filter configuration Error

        _Error_Handler(__FILE__, __LINE__);

        char string[38];

        sprintf( string, 'Can Filter configuration Error\n\r');

       puts1( string);

    }

}

if you look at the last filter above,

sFilterConfig.FilterMaskIdHigh        = 0x700 << 5;     // resolves as 0x0600 - 0x06FF

this filter is only checking these 3 bits      0x700

in those 3 bits the MsgID must contain these 3bits  0x6xx

therefore any MsgID with 0x6xx is accepted

the first filter

sFilterConfig.FilterMaskIdHigh            = 0x600 << 5;     // resolves as 0x0400 - 0x05FF

here only 2 bits are checked                   0x600

sFilterConfig.FilterIdHigh                     = 0x400 << 5;  //11-bit ID in top bits

in those 2 bits the MsgID must have 0x4xx set and 0x2xx cleared.

0   000

1   001

2   010

3   011

4   100    <- 4 is set and 2 is cleared,   this one is accepted

5   101    <- 4 is set and 2 is cleared,   this one is accepted

6   110

7   111

hence the top filter resolves as 0x0400 - 0x05FF

Artur Vieira
Associate III
Posted on March 25, 2018 at 17:33

For Future reference the way to setup CAN ID 29 bits filters is something like

 CAN_FilterInitStructure.CAN_FilterNumber = 0;
 CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask;
 CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit;
 CAN_FilterInitStructure.CAN_FilterIdHigh = ((0x00FEEE00) & 0x1FFFE000) >> 13; //Accept ID -> 0x--FEEE--
 CAN_FilterInitStructure.CAN_FilterIdLow = (0x00FEEE00 & 0x1FFF) << 3; //Accept ID -> 0x--FEEE--
 CAN_FilterInitStructure.CAN_FilterMaskIdHigh = ((0x00FFFF00) & 0x1FFFE000) >> 13;
 CAN_FilterInitStructure.CAN_FilterMaskIdLow = (0x00FFFF00 & 0x1FFF) << 3;
 CAN_FilterInitStructure.CAN_FilterFIFOAssignment = 0;
 CAN_FilterInitStructure.CAN_FilterActivation = ENABLE;�?�?�?�?�?�?�?�?�?

In this case it accepts all messages that match the ID xxFEEExx, for example to only get messages on a J1939 bus related to PGN 65262 'Engine Temperature 1'.

Regarding the use of filters in 16Bit mode, can anybodycheck on what i said that it seems the reference manual is wrong (and the drivers) or if i am making some mistake.

Thank You

Posted on March 25, 2018 at 16:46

Hello TJ

In 32bit mask mode if i make a configuration as such it works if a send the CAN messages with 11bit ID. But if i send the message as 29 CAN ID it doesn't pass (using the same ID -> 600).

PS. Never mind...

I just realized that the CAN ID 29 bit is composed differently from what i was thinking

I was assuming that would be EXT[17...0] + STD[10...0] and it is actually STD[10..0] + EXT[17...0].

If i send the message in CAN ID 29 bits as '0x18000000' it pass the filter and the device receives it.

Posted on March 25, 2018 at 17:34

Thanks Ben

I am going to check that source code, and possibly get some things to implement on my side.