CANBUS ID Filter

Hi, searched in hours and now I give up and sign me up here to search for help. Im trying to filter a specified ID:s from my car's canbus, im want to only get message from the specific ID.
Using the MCP_CAN Library with a MCP2515 shield and a arduino uno, with CAN_Recieve example I has successfully received my canbus line as you can see but want to show only from specific ID. The idea is that when a specific message is received, a function starts (for example start relay X). Tested the Standard_MaskFilter example without luck.
Someone which can help me in the right direction and it will get me very happy

It will make us very happy too, if you can post your code so far.
Then it may be as simple as a small change to your existing code.

#include <mcp_can.h>
#include <SPI.h>

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];

MCP_CAN CAN0(10);                          // Set CS to pin 10

void setup()
{
  Serial.begin(115200);
  if(CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_16MHZ) == CAN_OK) Serial.print("MCP2515 Init Okay!!\r\n");
  else Serial.print("MCP2515 Init Failed!!\r\n");
  pinMode(2, INPUT);                       // Setting pin 2 for /INT input


  CAN0.init_Mask(0,0,0x010F0000);                // Init first mask...
  CAN0.init_Filt(0,0,0x01000000);                // Init first filter...
  CAN0.init_Filt(1,0,0x01010000);                // Init second filter...
  
  CAN0.init_Mask(1,0,0x010F0000);                // Init second mask... 
  CAN0.init_Filt(2,0,0x01030000);                // Init third filter...
  CAN0.init_Filt(3,0,0x01040000);                // Init fouth filter...
  CAN0.init_Filt(4,0,0x01060000);                // Init fifth filter...
  CAN0.init_Filt(5,0,0x01070000);                // Init sixth filter...
  
  Serial.println("MCP2515 Library Mask & Filter Example...");
  CAN0.setMode(MCP_NORMAL);                // Change to normal mode to allow messages to be transmitted
}

void loop()
{
    if(!digitalRead(2))                    // If pin 2 is low, read receive buffer
    {
      CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
      Serial.print("ID: ");
      Serial.print(rxId, HEX);
      Serial.print(" Data: ");
      for(int i = 0; i<len; i++)           // Print each byte of the data
      {
        if(rxBuf[i] < 0x10)                // If data byte is less than 0x10, add a leading zero
        {
          Serial.print("0");
        }
        Serial.print(rxBuf[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
    }
}

Here is what I came up with last time this question went by:

MCP2515 CAN BUS filtering

From the block diagram it appears that there are separate masks and filters for the two receive buffers:
RXB0 has RXM0 (Mask 0), RXF0, and RXF1 (Filter 0 and Filter 1).
RXB1 has RXM1 (Mask 1), RXF2, RXF3, RXF4, and RXF5 (Filters 2, 3, 4, and 5).

If filters for both buffers match, only RXB0 is used.

Each filter and or mask consists of four 8-bit registers:
Standard Addressing High: Top 8 bits of the 11-bit Standard Address field.
Standard Addressing Low: Bottom 3 bits of the 11-bit Standard Address field plus bits 17 and 16 of the 18-bit Extended Addressing field.
Extended Addressing High: Bits 15-8 of the Extended Addressing Field (or Data Byte 0 when using Standard Addressing)
Extended Addressing Low: Bits 7-0 of the Extended Addressing Field (or Data Byte 1 when using Standard Addressing)

If the Mask bit is set to 0, the Filter bit is a "Don't Care" and the bit will be accepted.
If the Mask bit is set to 1 then the Address/Data bit must match the Filter bit for the bit to be accepted.
If all 29 bits (11+18) are accepted the message is accepted.

The library should be accepting 16 bits (unsigned int) for the Standard Address, 32 bits (unsigned long) for the Extended Address (or Data), and a boolean for the Standard/Extended flag. In Standard mode, only 11 bits of the address will be used and 16 bits of the Data. In Extended mode, 11 bits of the Standard Address and 18 bits of the Extended Address should be used. I don't know if they implemented the filters and masks correctly.

To select a particular single Standard Address you should set the 11 Address Mask bits to 1 and set the Address Filter bits to the address.

Looks like the code is implemented here:

https://github.com/Seeed-Studio/CAN_BUS_Shield/blob/master/mcp_can.cpp 36

byte MCP_CAN::init_Mask(byte num, byte ext, unsigned long ulData)
byte MCP_CAN::init_Filt(byte num, byte ext, unsigned long ulData)

When you set the EXT flag:
Bits 7-0 go into the low byte register of the Extended Address.
Bits 15-8 go into the high byte register of the Extended Address.
Bits 17-16 go into the low bits of the low byte of the Standard Address (high 2 bits of Extended Address)
Bits 20-18 go into the top 3 bits of the low byte of the Standard Address (low 3 bits of Standard Address)
Bits 28-21 go into the high byte register of the Standard Address

If you don’t set the EXT flag:
The low byte register of the Extended Address is set to 0.
The high byte register of the Extended Address is set to 0.
Bits 2-0 go into top 3 bits of the low byte of the Standard Address.
Bits 10-3 go into the high byte of the Standard Address.

    // Examples:
    unsigned long SA = address;  // 11 bits
    const unsigned long SAMask = 0x07FF;  // 11 bits
    unsigned long EA = extended_address;  // 18 bits
    const unsigned long EAMask = 0x03FFFF;  // 18 bits

    // Set Mask 0 + Filter 0, Standard Addressing
    MCP_CAN::init_Mask(0, 0, SAMask);
    MCP_CAN::init_Filt(0, 0, SA);

    // Set Mask 1 + Filter 2, Extended Addressing
    MCP_CAN::init_Mask(1, 1, (SA<<18) | EA);
    MCP_CAN::init_Filt(2, 1, (SAMask<<18) | EAMask);

Big thanks johnwasser but I don't understund yet, it feels like rocket science for me. Im trying to put in your example code in to my but arduino give me faut "address' was not declared in this scope". Do you have a more complete code as I can test with?

What is the CAN-bus address in the message you are looking for? Did you want Standard ID 0x290 like circled in the picture you posted?

Yes, or not just only but we can take it as a example. I want when the message 0x80 0x00 0x80 0x00 0x00 0x00 0x00 0x00 from ID 0x290 as the picture, a function start.

The filter for a Standard ID can only cover the first two bytes of data.

I think the filter for Standard ID=0x290, Data=0x8000.... would look like this:

  CAN0.init_Mask(0, 0, 0x07FFFFFF);
  CAN0.init_Filt(0, 0, 0x02908000);
  CAN0.init_Filt(1, 0, 0x02908000);

  CAN0.init_Mask(1, 0, 0x07FFFFFF);
  CAN0.init_Filt(2, 0, 0x02908000);
  CAN0.init_Filt(3, 0, 0x02908000);
  CAN0.init_Filt(4, 0, 0x02908000);
  CAN0.init_Filt(5, 0, 0x02908000);

Both masks and all six filters are set to select the same messges.

Yes it works :smiley:, it now only show from ID 0x290 when I press a button. ID 0x290 are the steering wheel buttons to stereo. Is it possible to make Data=0x8000 longer to Data0x8000800080000000 so it only filter just one specific message

You can only filter the first two bytes. After you receive the message you can compare it to whatever patterns you want. The filter is just to limit the number of messages you have to look at.

do you know how i can do it

const byte Pattern[] = {0x80, 0x00, 0x80, 0x00, 0x80, 0x00, 0x00, 0x00};

  CAN0.readMsgBuf(&rxId, &len, rxBuf); // Read data: len = data length, buf = data byte(s)
  if (len == sizeof Pattern && memcmp(Pattern, rxBuf, len) == 0)
  {
    // Matches patern
  }

awesome, now I can control things with my car's canbus, example the steering wheel buttons. Thanks

I fail to send the video so I send a picture of it when I press 3 of the buttons to create 3 words