使用 SJA1000 (ESP32) 的 CAN 控制器验收过滤

CAN-Controller acceptance filtering with the SJA1000 (ESP32)

我正在尝试在 ESP23 上使用 SJA1000 CAN 控制器的验收过滤器。 应在定义的区域中过滤消息(例如仲裁 ID 从:0x30 到:0x35)。

过滤单个消息 (0x30) 的示例:

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

如果我要过滤定义区域(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

已过滤的消息:
想要:
14:21:17.754 -> CAN 消息:30 110000
14:21:17.754 -> CAN 消息:31 110001
14:21:17.787 -> CAN 消息:32 110010
14:21:17.787 -> CAN 消息:33 110011
14:21:17.787 -> CAN 消息:34 110100
14:21:17.821 -> CAN 消息:35 110101
不需要的:
14:21:17.821 -> CAN 消息:36 110110
14:21:17.821 -> CAN 消息:37 110111
14:21:17.855 -> CAN 消息:38 111000
14:21:17.855 -> CAN 消息:39 111001
14:21:17.855 -> CAN 报文:3A 111010
14:21:17.889 -> CAN 消息:3B 111011
14:21:17.889 -> CAN 消息:3C 111100
14:21:17.889 -> CAN 报文:3D 111101
14:21:17.923 -> CAN 报文:3E 111110
14:21:17.923 -> CAN 消息:3F 111111

文档 ESP32 CAN 控制器(验收过滤器):
https://docs.espressif.com/projects/esp-idf/en/latest/api-reference/peripherals/can.html#acceptance-filter

文档 SJA1000 CAN 控制器(6.4.15 验收过滤器): https://www.nxp.com/docs/en/data-sheet/SJA1000.pdf

有谁知道如何过滤不需要的消息吗?

在我看来,如果您使用单个过滤器,您将无法实现您想要实现的目标。例如,您可以定义

   .acceptance_code = 0x30,
   .acceptance_mask = 0x03,

这将接受 0x30 到 0x33 范围内的 ID - 但不包括 0x34 和 0x35。

另一方面,对于 acceptance code = 0x34acceptance mask = 0x01,您将允许 0x34 和 0x35 - 但不包括 0x30 - 0x33。

我注意到验收过滤器可以置于 双重 过滤器模式,但是 - 附带条件是它不能用于过滤扩展 ID。也许这将允许您定义上面定义的补充过滤器。

您可能无法过滤所有不需要的消息。但是你可以缩小范围。 对于合适的掩码,您必须分别处理 1 和 0。

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;

这将创建一个掩码,其中包括在每个允许值中设置为 1 的所有位以及在每个允许值中设置为 0 的所有位。 这应该摆脱 0x37.

以上的所有值

示例:

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

更新: 上面的计算被打破了。已修复。