MCP2515 CAN FILTERING

Hello to all.

Im using mcp2515 CAN shield with arduino all works fine but seems I can't figure out those mask and filters. the way they work. it's defiantly an odd way.

The mcp 2515 has 2 masks and 6 filters and if i need to see a specific IDs I can no problem doing this for example:

CAN.init_Filt(0, 0, 0x0500);
CAN.init_Filt(1, 0, 0x0600);

CAN.init_Mask(0, 0, 0x1fff );
CAN.init_Mask(1, 0, 0x1fff );

But if I want to see the IDs in certain range.... forget it... It's for sure passable but how is no forums and no datasheets will explain in understanding way ))))

So how should I set up the mask and filters if I want to see IDs in the range 0x700 - 0x7FF.. 11 bit and don't care about 2 first data bytes.

here is some links:

http://www.cse.dmu.ac.uk/~eg/tele/CanbusIDandMask.html - does not work like his...

just a though as a work around but would it not be easier to initialised the board to let all thru and let arduino accept/reject the CAN IDs... that's what I did...

sherzaad:
just a though as a work around but would it not be easier to initialised the board to let all thru and let arduino accept/reject the CAN IDs... that's what I did...

Yes that's what I do now...

int idCheck = cp.id >> 8;

if(idCheck == 0x07){
}

But it's a load on MCU you know. And why the filters and masks is there...we got to use'em

The details should be in the datasheet:

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

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);

Thank you johnwasser for the huge replay..

It's still a bit confusing but after a couple test this is what I found.

Im using both boards v1.2 and v2.0 they are actually has different strangeness..

First I guess is very important for both is that if you implementing masks and filters in the setup. before you upload a sketch you got to take the OBD cable out of board otherwise it will not implement the filtering... It's a bag I guess.

After a couple of couple of couples tests it seems like THAT to me. But again with that cable thing and all the weirdness what happening I might slightly wrong...

So

if you want to see a specific IDs for example in my case it was 0x740 and 0x4C0 then we need to set mask and filter like that:

CAN.init_Mask(0, 0, 0x07FF);
CAN.init_Filt(0, 0, 0x740);

CAN.init_Mask(1, 0, 0x04FF);
CAN.init_Filt(1, 0, 0x4C0);

Human speaking of my understanding .. the first byte of the massage to be accepted must to match corresponding byte in the mask so the byte 7 and 4 passes the mask. then the other 2 bytes(which is FF in mask) if you need the specific massage to be shown must match the filter byte.

Now if you want to see a rang from address to address and here I didn't get all the ting yet but works like that... in my case I wanted to see range 0x700 to 0x7FF . So it's definitely not passes any massages below 0x700 and my car has no massages with address above 0x7FF so I didn't figure the top one yet.

CAN.init_Mask(0, 0, 0x0700);
CAN.init_Filt(0, 0, 0x700);

CAN.init_Mask(1, 0,0x0700);
// CAN.init_Filt(1, 0, 0x7E8);

So now any massages on CANBus has to match the first byte of the mask to be accepted which is 7 and other 2 bytes on the mask is 00 which means don't care and passes. The ting is here that why then we need CAN.init_Filt - it doesn't work without. So we have to have it and what is more that the addres could be any. I mean CAN.init_Filt(0, 0, 0x7any);

Slavka85:
So

if you want to see a specific IDs for example in my case it was 0x740 and 0x4C0 then we need to set mask and filter like that:

        CAN.init_Mask(0, 0, 0x07FF);                         

CAN.init_Filt(0, 0, 0x740);
 
       CAN.init_Mask(1, 0, 0x04FF);  
       CAN.init_Filt(1, 0, 0x4C0);

Close enough. Remember that a Standard Address is always 11 bits so you always use 0x7FF if you want one specific address. Also remember that Mask0 is for Filter0 and Filter1. Mask1 is only for Filter2, 3, 4, and 5 so there is no need to set it for Filter0 and Filter1. Try this instead:

        CAN.init_Mask(0, 0, 0x07FF);                         
        CAN.init_Filt(0, 0, 0x740); 
        CAN.init_Filt(1, 0, 0x4C0);

Slavka85:
Now if you want to see a rang from address to address and here I didn't get all the ting yet but works like that... in my case I wanted to see range 0x700 to 0x7FF . So it's definitely not passes any massages below 0x700 and my car has no massages with address above 0x7FF so I didn't figure the top one yet.

        CAN.init_Mask(0, 0, 0x0700);                        

CAN.init_Filt(0, 0, 0x700);
       CAN.init_Mask(1, 0,0x0700);
  //   CAN.init_Filt(1, 0, 0x7E8);

Again, close enough. Mask1 isn't needed since you are only using Filter0. The mask is set to match 0XX through 7XX and the filter is set to match only if the top three bits are a 7. That should match 0x700 through 0x7FF.

I think the Mask and Filter registers are initialized to 0. I don't know if that means that addresses 000 through 0FF will match Filter1 and get accepted but that is something to look out for. If that is a problem it might be prudent to ALSO set Filter1 t0 0x700.

       CAN.init_Mask(0, 0, 0x07FF);                         
        CAN.init_Filt(0, 0, 0x740); 
        CAN.init_Filt(1, 0, 0x4C0);

Yes you right about that and the filter 0 and 1 to mask 0 But it has to be both masks set it just doesn't work without the second one. So it will be like that

 CAN.init_Mask(0, 0, 0x07FF);                         // there are 2 mask in mcp2515, you need to set both of them
        CAN.init_Mask(1, 0,  0x07FF);
        CAN.init_Filt(0, 0, 0x740); 
  
 
        CAN.init_Filt(1, 0, 0x4C0);

So about this guyes:

       CAN.init_Mask(0, 0, 0x0700);                        
        CAN.init_Filt(0, 0, 0x700); 
        CAN.init_Mask(1, 0,0x0700);
   //   CAN.init_Filt(1, 0, 0x7E8);

You saying that the mask will passes any IDs where the first byte of ID will be from 0 to 7 like 0x1xx 0x2xx up to 0x7xx and then if that byte matches to filter byte the ID passes. So in the filter it's really matters the firts byte which is set to 7 in our case and just because in the mask the 3rd and 4 byte are 0 which means don't care it's no need to match the filter so it's passes anyway. Right???
it's all make sense though I just was thinking that the Id has to much that first byte of mask not the filter. So it's not. and if the bytes set to 0 0 in the mask the filter coresponding bytes can be set to any because it's not checking against it ....

Slavka85:

        CAN.init_Mask(0, 0, 0x07FF);                         

CAN.init_Filt(0, 0, 0x740);
       CAN.init_Filt(1, 0, 0x4C0);


Yes you right about that and the filter 0 and 1 to mask 0 But it has to be both masks set it just doesn't work without the second one. So it will be like that

Have you tested that? I would not have expected that to be the case from my reading of the datasheet.

Slavka85:
if the bytes set to 0 0 in the mask the filter corresponding bytes can be set to any because it's not checking against it ....

That may not be the case. Setting the mask to 0x700 and the filter to 0x740 (for example) may not accept any addresses at all. I'm guessing that the incoming address is ANDed with the mask. That would force the second and third digits to 0. The arriving address of 0x740 would be masked to 0x700 and that would NOT match a filter of 0x740.

[/quote]

Slavka85:
So how should I set up the mask and filters if I want to see IDs in the range 0x700 - 0x7FF.. 11 bit and don't care about 2 first data bytes.

You've posted a simple question.
Here's a straight answer. For RXM0 = 00 and EXIDE = 0 we have
Mask0: 0x0700
Filter0: 0x07xy
Filter1: 0x07xy
where "x" and "y" can have any values

Note: The actual Mask0 of MCP2515 will look like $1C000000. As RXM0 = 00 and EXIDE = 0 that means $00, $00 masks on byte0, byte1 so only ID11 part will count. That is 0x0700

With the above setup all messages with ids ranging from $700 to $7FF will land in Buffer 0.
All other ids will be rejected and routed to Mask1/Filters2...5 to be sorted out there.

cheers