Search code examples
cfiltermaskcan-busesp32

CAN-Controller acceptance filtering with the SJA1000 (ESP32)


I'm try to use the acceptance filter from the SJA1000 CAN-Controller on a ESP23. The Messages should be filtered in a defined area (e.g. Arbitration ID from: 0x30 to: 0x35).

Example for filtering a single message (0x30):

#define CAN_FILTER_CONFIG_ACCEPT()  {.acceptance_code = 0x1500000, .acceptance_mask = 0xffffff, .single_filter = true}

If I want to filter a defined area (0x30 - 0x35):

int calc_mask(int startID, int endID) {
    int size_of_range = endID - startID;
    unsigned int acceptance_mask = 0xFFFFFFFF;
    int i;

    for (i = startID; i <= endID; i++ {
    acceptance_mask = ~(acceptance_mask & i);
    }

    return acceptance_mask;     
}

acceptance_code = 0x30;
acceptance_mask = calc_mask(0x30, 0x35);

0x30 : 110000
NAND 0x31: 110001
NAND 0x32: 110010
NAND 0x33: 110011
NAND 0x34: 110100
NAND 0x35: 110101
0xF : 001111
acceptance_code = 0x6000000: 0000 0110 0000 0000 0000 0000 0000 0000
acceptance_mask = 0x1FFFFFF: 0000 0001 1111 1111 1111 1111 1111 1111

filtered Messages:
wanted:
14:21:17.754 -> CAN Message: 30 110000
14:21:17.754 -> CAN Message: 31 110001
14:21:17.787 -> CAN Message: 32 110010
14:21:17.787 -> CAN Message: 33 110011
14:21:17.787 -> CAN Message: 34 110100
14:21:17.821 -> CAN Message: 35 110101
unwanted:
14:21:17.821 -> CAN Message: 36 110110
14:21:17.821 -> CAN Message: 37 110111
14:21:17.855 -> CAN Message: 38 111000
14:21:17.855 -> CAN Message: 39 111001
14:21:17.855 -> CAN Message: 3A 111010
14:21:17.889 -> CAN Message: 3B 111011
14:21:17.889 -> CAN Message: 3C 111100
14:21:17.889 -> CAN Message: 3D 111101
14:21:17.923 -> CAN Message: 3E 111110
14:21:17.923 -> CAN Message: 3F 111111

Documentation ESP32 CAN-Controller (Acceptance Filter):
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/can.html#acceptance-filter

Documentation SJA1000 CAN-Controller (6.4.15 Acceptance filter): https://www.nxp.com/docs/en/data-sheet/SJA1000.pdf

Does anyone have an idea how to get the not wanted Messages filtered?


Solution

  • You probably cannot filter all unwanted messages. But you can narrow down a bit. For a suitable mask you must treat the ones and the zeros separately.

    uint32 mask_ones = mask_zeros = ~0;
    
    for (int id = startId; id < endId; id++)
    {
      mask_ones  &=  id;
      mask_zeros &= ~id;
    }
    uint32 mask = mask_ones | mask_zeroes;
    uint32 value = startId & mask;
    

    This creates a mask which includes all bits that are set to 1 in every allowed value and also all bits that are set to 0 in every allowed value. This should get rid of all values above 0x37.

    Example:

    ones = zeros = 11111111
    CAN Message: 30 110000 => mask_ones = 00110000; mask_zeros = 11001111
    CAN Message: 31 110001 => mask_ones = 00110000; mask_zeros = 11001110
    CAN Message: 32 110010 => mask_ones = 00110000; mask_zeros = 11001100
    CAN Message: 33 110011 => mask_ones = 00110000; mask_zeros = 11001100
    CAN Message: 34 110100 => mask_ones = 00110000; mask_zeros = 11001000
    CAN Message: 35 110101 => mask_ones = 00110000; mask_zeros = 11001000
    unwanted:
    CAN Message: 36 110110
    CAN Message: 37 110111
    CAN Message: 38 111000
    
    mask =  00110000 | 11001000 = 11111000 = 0xF8
    value =  00110000 & 11111000 = 00110000 = 0x30
    

    Update: The calculation above was broken. Fixed it.