MCP2515 CANBus filtering

Im working on a project for my car that is collecting data from the canbus, Im using an Uno and the Sparkfun CAN bus shield. I have the code working and Im receiving good data but I want to implement using mask and filters on the MCP2515 chip to offload a lot of wasted Uno processing time.

My car's CAN bus is running at 500k and uses standard data frames(11bit identifiers).

From reading the MCP2515 datasheet (http://ww1.microchip.com/downloads/en/devicedoc/21801e.pdf) starting on page 32 it seems to me that the mask and filtering ignore the identifier bits and only filter based on the data bits? Am I reading that correctly or am I wrong and it actually is filtering based on the identifier?

Just for more information...the data I am after is part of ID: 0201 bytes 1 and 2

The mask and filter bits on the MCP2515 work in an odd way.
If you are using extended identifiers(29 bits) the entire mask and filter applies to only the identifier.
If you are using standard identifiers(11 bits) the remaining eighteen bits of the mask and filters are matched to the first two data bytes, with the two most significant bits of those eighteen bits left unused. (11 + 2 + 16 = 29)

As you said you are using standard identifiers; you would need to set the extended identifier portions of the filters and mask to zero so the controller does not try to match the data bytes unless there is a way to incorporate that into your design of course.

Yes this is an old post, but it was also unanswered... I am only populating an answer for anyone asking the same question.

coryjfowler:
The mask and filter bits on the MCP2515 work in an odd way.
If you are using extended identifiers(29 bits) the entire mask and filter applies to only the identifier.
If you are using standard identifiers(11 bits) the remaining eighteen bits of the mask and filters are matched to the first two data bytes, with the two most significant bits of those eighteen bits left unused. (11 + 2 + 16 = 29)

As you said you are using standard identifiers; you would need to set the extended identifier portions of the filters and mask to zero so the controller does not try to match the data bytes unless there is a way to incorporate that into your design of course.

Yes this is an old post, but it was also unanswered... I am only populating an answer for anyone asking the same question.

Thanks for posting this but can I ask you to expand on filters and masks a little more. Im struggling with understanding the mask/filter setup.

Im trying to filter out all messages but ID 0x7E8

So my filter is set to 0x7E8
My mask is set to 0x7E8 or 0xFFFF or 0xF817

to test my filter/mask I send out a range of id's from 0x7E0 - 0x7F0
but 98% of the time the ID 0x7E0 is captured with a almost random capture of 0x7E8

My understanding is
Mask0 is used for Filter 0 and 1
Mask 1 is used for Filter 2-4

I also see that the first two data bytes are also involved in the filter when an 11bit identifier is used. So this adds to my confusion. What is the correct mask and filter for only capture the ID 0x7E8?

A mask and filter of 0x7E8 would be entered as 0x1FA00000.

        111 1110 1000 = 0x7E8
  MASK: 111 1110 1000 00 0000 0000 0000 0000
FILTER: 111 1110 1000 00 0000 0000 0000 0000

This above scenario will accept anything with those specific bits set (high).

        111 1111 1111 = 0x7FF entered in as 0x1FFC0000
  MASK: 111 1111 1111 00 0000 0000 0000 0000
FILTER: 111 1110 1000 00 0000 0000 0000 0000

This above scenario will accept ONLY the 0x7E8 identifier.

Essentially, the mask tells the controller which specific bits to check and the filter tells it how those bits should be set (or unset).
I suggest making both masks identical and unused filters identical to one of the used filters to prevent any stray data from getting accepted.

(Sorry for the delay, been busy.)

1 Like

Hi.
I am trying to replicate the above filtering (previous posting) both the 11 bit and the 2 data bytes without success. My set-up is 2 Arduino Unos with Seeed CAN bus shields. The CAN library is by Loovee and Cory J Fowler.

The basic calls are;

For the sender
CAN.sendMsgBuf( id, 0, sizeof(stmp), stmp); // CAN standard message

For the receive
CAN.initMask( 0, 0, 0x3ff );
CAN.initMask( 1, 0, 0x3ff ); // Set the 2 masks as CAN Standard

CAN.initFilt( 0, 0, 0x04 ); // Set up the 2 filters and 4 filters (for Mask 0 and 1 respectively)
up to .....
CAN.initFilt( 0, 0, 0x09 );

CAN.readMsgBuf( &len, buf); // Read either CAN standard or extended

The above I get to work, where it filters id from 4 to 9 while the others (0 to 3) are omitted in the serial presentation. The transmission are a rolling count of 0 to 9 (for the ids) from the transmitter. However the above is filtering only the ids. The previous posting suggest that the Mask value and Filter values need to by multiplied by 0x04 * 0x10000 (i.e. 0x40000 for an 18 bit shift to the right). If I do this, then I receive nothing (of course if it work OK prior to this). Like wise if I change the set up from CAN standard to CAN extended ( i.e. middle parameter to 1) I get nothing.

So I trust that someone can help me with this endeavor to filter on both 29 bit ids or 11 bit ids plus 16 data bits ??

Regards JC......

I am not sure what version of the library you are using, but a lot of updates were pushed to it from a sub-development branch over the summer. There are two examples on filtering included with it.

coryjfowler:
A mask and filter of 0x7E8 would be entered as 0x1FA00000.

        111 1110 1000 = 0x7E8

MASK: 111 1110 1000 00 0000 0000 0000 0000
FILTER: 111 1110 1000 00 0000 0000 0000 0000



This above scenario will accept anything with those specific bits set (high).



111 1111 1111 = 0x7FF entered in as 0x1FFC0000
 MASK: 111 1111 1111 00 0000 0000 0000 0000
FILTER: 111 1110 1000 00 0000 0000 0000 0000



This above scenario will accept ONLY the 0x7E8 identifier.


Essentially, the mask tells the controller which specific bits to check and the filter tells it how those bits should be set (or unset).
I suggest making both masks identical and unused filters identical to one of the used filters to prevent any stray data from getting accepted.

(Sorry for the delay, been busy.)

Mr. Fowler,

Thank you for this explanation. It makes sense to me in binary. I am still confused because the example I am using from Seeed, written by Loovee, sets both masks to 0x3ff. That computes to 0000 0000 0011 1111 1111 in binary. That is 20 digits (bits), which does not conform to the 11 bit identifier or anything else that I can think of.

The filters are set to range from 0x04 to 0x09. That ranges from 0000 0000 0000 0100 to 0000 0000 0000 1001, which are 16 digits (bits). As I understand it, the masks and filters should all actually have 29 digits (bits). It almost looks like the filters are set for the 16 data bits which can't be the case.

I hope you can discern what I am not understanding in this and set me straight. Thank you in advance for your help in my education.

Regards,

Quadrant5

Forgive me. I have already noticed one error in my thinking, I think.

It seems that "0x" is just an expression that identifies what follows as a hex number. For some reason my hex/binary convertor uses that to mean "put a lot of zeros before the number".

Even so, 3ff still only yields 10 digits (bits) and 04 through 09 yield 3 or 4 digits (bits).

Long story short, still confused.

Regards,

Quadrant5

Quadrant5:
Mr. Fowler,

Thank you for this explanation. It makes sense to me in binary. I am still confused because the example I am using from Seeed, written by Loovee, sets both masks to 0x3ff.

The 0x3FF is a typo, it should be 0x7FF so that all 11 bits of the standard ID are "masked" and checked against the filters. Using 0x3FF would allow 0x004 to 0x009 to enter in addition to 0x404 to 0x409 since bit 0x400 was left unmasked.

Quadrant5:
That computes to 0000 0000 0011 1111 1111 in binary. That is 20 digits (bits), which does not conform to the 11 bit identifier or anything else that I can think of.
The filters are set to range from 0x04 to 0x09. That ranges from 0000 0000 0000 0100 to 0000 0000 0000 1001, which are 16 digits (bits). As I understand it, the masks and filters should all actually have 29 digits (bits). It almost looks like the filters are set for the 16 data bits which can't be the case.

I'm not sure what you are using to go from hex to binary, but it appears to be incorrectly turning the 0 and x into two nibbles alone, regardless it is mostly okay to ignore leading zeros in binary and hexadecimal much like we do in decimal.

Quadrant5:
I hope you can discern what I am not understanding in this and set me straight. Thank you in advance for your help in my education.

Regards,

Quadrant5

You should try the examples in my version of the library.

Thank you for your quick reply. Where may I find your version of the library?

Quadrant5:
Thank you for your quick reply. Where may I find your version of the library?

Hello Cory,
imfind your lib very usefull, but miss some documentation :slight_smile:
I currently had an issue with loosing/unprocessed packets in a setup with two MCP acting as a gateway/filter. I try to bring them inline in front of a radio to change some ID content with my own data. But even in a simple pass-Through (bidirectional) its missing packets and i get weird results in my radio.

My setup uses the INT lines of both boards inside the main. I assume that INT is set to low if the MCP has fully received a CAN message, and stays low until i read this message from its buffer.

Or do i have to "clear/reset" the INT line somehow after reading?
Or is it down for other purposes also, so i had to check if there is an incoming message?

I also assume that after normal initialization i do not need to clear any filters/masks to receive ANY ID.

Would it be wise to look into some error count/flag while reading/sending?

Thank you! Oliver

mikrotron:
Hello Cory,
imfind your lib very usefull, but miss some documentation :slight_smile:

You're more than welcome to start documenting it. :wink:

mikrotron:
I currently had an issue with loosing/unprocessed packets in a setup with two MCP acting as a gateway/filter. I try to bring them inline in front of a radio to change some ID content with my own data. But even in a simple pass-Through (bidirectional) its missing packets and i get weird results in my radio.

How utilized are your CAN buses? Does your code do any serial writes or hard delays? Are you using a unique pin for each INT line, right? Are you using an UNO or similar with a 16MHz main oscillator frequency?

mikrotron:
My setup uses the INT lines of both boards inside the main. I assume that INT is set to low if the MCP has fully received a CAN message, and stays low until i read this message from its buffer.

This is correct, the INT line stays low until the reason it was triggered is cleared by the MCU.

mikrotron:
Or do i have to "clear/reset" the INT line somehow after reading?

The library handles this.

mikrotron:
Or is it down for other purposes also, so i had to check if there is an incoming message?

It can be, but the library only configures interrupt for either receive buffer being full.

mikrotron:
I also assume that after normal initialization i do not need to clear any filters/masks to receive ANY ID.

The library will configure the masks and filters generically.

mikrotron:
Would it be wise to look into some error count/flag while reading/sending?

Thank you! Oliver

The only testing I've done on bridging was one direction using a NMEA 2000 GPS receiver, a breadboard ATmega328 running at 16MHz loaded with the Uno bootloader with 2 MCP2515's and transceivers. I never seen any dropped packets during the NMEA fastpacket transmissions from the GPS. I've not done any testing past this and it could just be a matter of "time". (Eg, the Uno is too slow and/or you are trying to do too much.)

I read your code in MCP lib and have some questions about it:
1.) The instantiator of the MCP_CAN class has this code

MCP_CAN::MCP_CAN(INT8U _CS)
{
    MCPCS = _CS;
    pinMode(MCPCS, OUTPUT);
    MCP2515_UNSELECT();
}

Question: Isn't it good practice to first set value of a port and then the direction?!. In my opinion, this should be like this:

MCP_CAN::MCP_CAN(INT8U _CS)
{
    MCPCS = _CS;
    MCP2515_UNSELECT();
    pinMode(MCPCS, OUTPUT);
}

2.) Question: What are all those delayMicroseconds() in sending routines good for?
I found them in several places, with big ammounts about 250us and such. I never see them in other libs for this chip, nor finding notes in the datasheet indicating waiting time somewhere. It seems that the chip can handle SPI transfers up to given max of 10 MHz without any delay.

  1. Question: With a logicanalyzer i can see that sendMsgBuf() returns if message could br sent on CAN (detected by teading TX flag) or after 200 ms timeout.
    Wouldn't it be better to send this via ISR and use and software controlled output buffer it that takes so long?
    Shure it depends on the CAN speed and usage, also.

Hello, I hope I'm at the right spot for my question.

I'm unable to get the mask and filter part to work.
I can send CAN frames, I can receive CAN frames, but I can't get the filter to work.
(Which also holds for the filter example)

Setup

I'm using an ATmega328 µC with the MCP2515 CAN Controller and an MCP2562 CAN Tranceiver.
Both the µC and the Controller run with a 16MHz crystal at 5V DC.
The CAN library is cloned from GitHub - coryjfowler/MCP_CAN_lib: MCP_CAN Library and I'm on commit 870c43ea from 2017-03-24. (Edit 1; corrected commit date from 2017-03-17)
Arduino IDE is in Version 1.8.3 (for what it is worth).

THE MCP2515 is connected via SPI and the /INT signal has also been connected to pin 2.

I'm using two other MCP2515 & MCP2562 combinations on two Raspberry Pi's, one to transmit frames manually and one to monitor whats actually going over the wires.
The CAN interface has been configured with 'sudo ip link set can0 up type can bitrate 500000'

Idea

  • for my little experiment the Arduino should only receive CAN frames
  • only standard frames are being send
  • each frame has a payload ≥ 4 byte
  • the payload data has no meaning for the filter
  • which frames get signaled to the µC depends upon the CAN ID
  • for whichever reason only frames with the ID 0b001001xxxxx or 0b100001xxxxx shall be allowed

Problem

Frankly, I can't the filters to work; every frame gets accepted regardless of it's ID.
(by which I mean the /INT produces an interrupt which should not happen if the filters were working)

A bit more detail

I'm running 'candump any' on the second Raspberry Pi to monitor what is going over the wires.

Using the first Raspberry Pi 'cansend can0 120#DEADBEEF' should get accepted by the CAN controller.
I get the candump output 'can0 120 [4] DE AD BE EF' so sending went fine.
And indeed, the MCP2515 signals a new frame has been accepted via /INT.

Now for the second case, a non matching ID.
Using the first Raspberry Pi 'cansend can0 220#DEADBEEF' should NOT get accepted by the CAN controller.
I get the candump output 'can0 220 [4] DE AD BE EF' so sending went fine.
But why does the MCP2515 signal a new frame has been accepted?

Arduino Code

A lot has been omitted, see attachments for full code. (sorry if the horizontal layout is off)
I set the masks based upon the previous example in this thread.

...
byte _canState = CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ);

// 0b000|MSB...LSB|xxxxxxxxxxxxxxxxxx
CAN0.init_Mask(0, 0b00011111100000000000000000000000);
CAN0.init_Filt(0, 0b00000100100000000000000000000000); // allow data type 1 for Node 1 (ID = 0x12.)
CAN0.init_Filt(1, 0b00010000100000000000000000000000); // allow data type 2 for Node 1 (ID = 0x42.)

// 0b000|MSB...LSB|xxxxxxxxxxxxxxxxxx
CAN0.init_Mask(1, 0b00011111111111000000000000000000); // since we don't need them, set all bits
CAN0.init_Filt(2, 0b00011111111111000000000000000000); // to 1 which is a frame that will never
CAN0.init_Filt(3, 0b00011111111111000000000000000000); // occur in this application
CAN0.init_Filt(4, 0b00011111111111000000000000000000); // *
CAN0.init_Filt(5, 0b00011111111111000000000000000000); // *
...

Conclusion

I have no Idea why the filters aren't working.
My C is bad enough, from what I could understand the library should do its job just fine. The register addresses for the MCP2515 given in 'mcp_can_dfs.h' check out to the data sheet. The mode gets switch to config and back…
I have no Idea which simple little thing I have overlooked.

If somebody is be able to point me into the right direction would be welcome :wink:

MCP-Filter.ino (2.12 KB)

tobuhs:

    byte _canState = CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ);

MCP_ANY disables filtering, try MCP_STDEXT.

mikrotron:
I read your code in MCP lib and have some questions about it:
1.) The instantiator of the MCP_CAN class has this code

MCP_CAN::MCP_CAN(INT8U _CS)

{
   MCPCS = _CS;
   pinMode(MCPCS, OUTPUT);
   MCP2515_UNSELECT();
}




Question: Isn't it good practice to first set value of a port and then the direction?!. In my opinion, this should be like this:


MCP_CAN::MCP_CAN(INT8U _CS)
{
   MCPCS = _CS;
   MCP2515_UNSELECT();
   pinMode(MCPCS, OUTPUT);
}

mikrotron:
2.) Question: What are all those delayMicroseconds() in sending routines good for?
I found them in several places, with big ammounts about 250us and such. I never see them in other libs for this chip, nor finding notes in the datasheet indicating waiting time somewhere. It seems that the chip can handle SPI transfers up to given max of 10 MHz without any delay.

These are all relics from the original version of the library before I improved extended ID support and they have not caused me any issues. Good point on the 250µs delays though, not a clue as to what that was doing. I also decreased the 10ms delay in the reset to 10µs. I've tested this in one of my applications and nothing seems to have changed for the worse, so I pushed them to github.

Thanks Cory. I also added a flag to the sendMsgBuf() function which, when set will return as soon as the message is transferred to the MCP. If not set (default) it will wait until the message is sent.
I would provide a pull request on Git, that would be easer to implement.