Go Down

Topic: MCP2515 CANBus filtering (Read 20288 times) previous topic - next topic

snax01

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

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.
"Taking the time to make a proper, punctuated, post is a mark of courtesy and respect."  http://forum.arduino.cc/index.php?topic=149022.0

Bravo685


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?

coryjfowler

A mask and filter of 0x7E8 would be entered as 0x1FA00000.
Code: [Select]

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

Code: [Select]

        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.)
"Taking the time to make a proper, punctuated, post is a mark of courtesy and respect."  http://forum.arduino.cc/index.php?topic=149022.0

jmClifford

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......


coryjfowler

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.
"Taking the time to make a proper, punctuated, post is a mark of courtesy and respect."  http://forum.arduino.cc/index.php?topic=149022.0

Quadrant5

A mask and filter of 0x7E8 would be entered as 0x1FA00000.
Code: [Select]

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

Code: [Select]

        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

Quadrant5

#7
Jun 03, 2017, 09:11 am Last Edit: Jun 03, 2017, 09:26 am by 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

coryjfowler

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.

Quote from: 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.

Quote from: 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.
"Taking the time to make a proper, punctuated, post is a mark of courtesy and respect."  http://forum.arduino.cc/index.php?topic=149022.0

Quadrant5

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

coryjfowler

Thank you for your quick reply. Where may I find your version of the library?
https://github.com/coryjfowler/MCP_CAN_lib
"Taking the time to make a proper, punctuated, post is a mark of courtesy and respect."  http://forum.arduino.cc/index.php?topic=149022.0

mikrotron

Hello Cory,
imfind your lib very usefull, but miss some documentation :-)
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

coryjfowler

Hello Cory,
imfind your lib very usefull, but miss some documentation :-)
You're more than welcome to start documenting it.  :smiley-wink:

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?

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.

Or do i have to "clear/reset" the INT line somehow after reading?
The library handles this.

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.

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.

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.)
"Taking the time to make a proper, punctuated, post is a mark of courtesy and respect."  http://forum.arduino.cc/index.php?topic=149022.0

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
Code: [Select]
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:
Code: [Select]
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.

Go Up