Go Down

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

mikrotron

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

tobuhs

#16
Jul 03, 2017, 11:46 pm Last Edit: Jul 04, 2017, 01:54 pm by tobuhs
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 https://github.com/coryjfowler/MCP_CAN_lib 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 ;-)

coryjfowler

Code: [Select]

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


MCP_ANY disables filtering, try MCP_STDEXT.
"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

coryjfowler

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


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

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.

KVNMRSMN

Hi,

this post has already helped me a lot to understand the mask and filter features but I still don't fully understand the mask. I understand that the mask tells the controller to check certain bits. But the reason you have to use 0x7FF in both mask's is a mystery to me.

What would happen is you used other values than 0x7FF?
Do you have to use the same value in both mask's? or can you use different ones in each mask?


coryjfowler

#21
Aug 09, 2017, 08:28 pm Last Edit: Aug 09, 2017, 08:58 pm by coryjfowler
Hi,

this post has already helped me a lot to understand the mask and filter features but I still don't fully understand the mask. I understand that the mask tells the controller to check certain bits. But the reason you have to use 0x7FF in both mask's is a mystery to me.

What would happen is you used other values than 0x7FF?
The bits of the mask that are zero will not be checked against the filter values.

If I were to use 0x7F0 as the mask and I had 0x125 and 0x137 as filter values, I would see any message that has an ID beginning with 0x120 and 0x130, the last nibble is ignored.

Do you have to use the same value in both mask's? or can you use different ones in each mask?
No, you do not have to keep them the same, but if you do use different values, you will need to be aware of the bucket bit and how that bit effects received data.  You will also need to be aware that mask 0 and filters 0 and 1 are for receive buffer 0 and mask 1 and filters 2, 3, 4, and 5 are for receive buffer 1.
"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

KVNMRSMN

Thank you for the reply, it explains the things I wasn't sure about.

One last question, if I use 0x7FF in both masks it is going to check all bits, right?
Or are there still bits the controller won't check?

coryjfowler

Thank you for the reply, it explains the things I wasn't sure about.

One last question, if I use 0x7FF in both masks it is going to check all bits, right?
Or are there still bits the controller won't check?
Depends..

For standard IDs, the filtering core can check against the first two data bytes, so instead of 0x07FF0000, the mask could be 0x07FFFFFF which would include the first two data bytes in the filter check, applications for this are rare and limited though.

For extended IDs, the filtering core can only check against the ID, so a mask would be 0x1FFFFFFF to check all 29 bits of the ID.
"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

Wirless63

#24
Jan 15, 2018, 09:06 pm Last Edit: Jan 16, 2018, 12:00 am by Wirless63
Hello.

First time posting here! I'm using an Arduino Uno, SPI Can-Bus Shield V1.2, mcp_can.

Masks and filters are working to get only the ID (STD) I want but, I also need to filter the first data byte.  My ECU sends message rows using the first byte and I only want to get message rows with 0,1, and 2 in the first byte.

I understand that the MCP2515 can also filter on two bytes but I haven't been able to configure those to work. Here is one example I've tried in the Sketch:

  CAN0.init_Mask(x,0,0x0FFFFF00);       
     CAN0.init_Filt(0,0,0x0???0000);
     CAN0.init_Filt(1,0,0x0???0100);       
     CAN0.init_Filt(2,0,0x0???0200);
     ...

Does the 2515 need to be set to a mode other that NORMAL to allow defining the two byte filters?

Thank you for the assistance.

I had been using an 2014 version on mcp_can. Trying the latest.



coryjfowler

[...] I understand that the MCP2515 can also filter on two bytes but I haven't been able to configure those to work. Here is one example I've tried in the Sketch:

  CAN0.init_Mask(x,0,0x0FFFFF00);      
     CAN0.init_Filt(0,0,0x0???0000);
     CAN0.init_Filt(1,0,0x0???0100);      
     CAN0.init_Filt(2,0,0x0???0200);
     ...
Looks correct, but 0x07FFFF00 would be more appropriate for your mask.

Does the 2515 need to be set to a mode other that NORMAL to allow defining the two byte filters? [...]
Actually, going off bus has proven to be the most reliable way of setting masks and filters and I have the library setup so that the begin() function initializes the MCP2515 in loopback mode.  In the examples where masks and filters are set, going to NORMAL mode is the final step before leaving the setup routine in the sketch.
"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

Starina

@coryjfowler, thank you for your awesome library.

Please help me understand filters and masks.

Lets's say I need to receive only standard IDs from 7E8 to 7EF and 7DF.
With the range 7E8 to 7EF we are ignoring last 3 bits, so the mask will be 0x07F80000 and the filter will be 0x07E80000.

For the value 7DF mask will be 0x07FF0000 (we need to check all bits) and the filter will be 0x07DF0000.

It works.

However, I spent some time trying to understand your previous message:


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.

According this my mask for the range should be
Code: [Select]

0x7F8 = 111 1111 1000
(adding 2 unused bits and 2 bytes for data filtering) 00 0000 0000 0000 0000
111 1111 1000 00 0000 0000 0000 0000 = 1 1111 1110 0000 0000 0000 0000 0000 = 0x1FE00000

So, the mask should be 0x1FE00000. And so on with filters.
But it doesn't work.

Can you tell me what I am missing and what is the right way to calculate masks/filters? I assume it will be the first one as it works.

If the first option as far as I understand 2 bits were moved to the beginning and in the second they are in the middle.

Thanks.

coryjfowler

@coryjfowler, thank you for your awesome library.

Please help me understand filters and masks.

Lets's say I need to receive only standard IDs from 7E8 to 7EF and 7DF.
With the range 7E8 to 7EF we are ignoring last 3 bits, so the mask will be 0x07F80000 and the filter will be 0x07E80000.

For the value 7DF mask will be 0x07FF0000 (we need to check all bits) and the filter will be 0x07DF0000.

It works.
This all sounds correct.

Basically:
M0 = 0x07FF0000
F0 = F1 = 0x07DF0000

M1 = 0x07F80000
F2 = F3 = F4 = F5 = 0x07E80000


However, I spent some time trying to understand your previous message:


According this my mask for the range should be
Code: [Select]

0x7F8 = 111 1111 1000
(adding 2 unused bits and 2 bytes for data filtering) 00 0000 0000 0000 0000
111 1111 1000 00 0000 0000 0000 0000 = 1 1111 1110 0000 0000 0000 0000 0000 = 0x1FE00000

So, the mask should be 0x1FE00000. And so on with filters.
But it doesn't work.

Can you tell me what I am missing [...]
Yes, you are missing the date; that is over three years old and no longer applies.  The filtering examples included with the library reflect what is current.
"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

Starina

Yes, you are missing the date; that is over three years old and no longer applies.  The filtering examples included with the library reflect what is current.
Oh, thanks! I really didn't notice it.

While playing with my car can I got another question. Is it possible to make MCP2515 to throttle messages?
I mean to configure it in some way to receive some PIDs lets say once per second or once per 10 seconds.

Right now I do it using code. I save the latest received message in the settings array
Code: [Select]

msgId   Delay   LastReceivedTime
0x001   10000  11000
0x002   60000  12000
0x003   10000  13000

and check with the next message :
I search by it's id and check if (millis() - lastReceivedTime > Delay) then I accept the message and update lastReceivedTime.

Is there a way to do it more nicely?

Thank you.

Wirless63

Mr. Fowler,

Thank you for the response on Jan 16th.  It took a while but, I did manage to get the mask and filter to work perfectly! :)

I'm now struggling with ".sendMsgBuf()".  I'm trying to find a way to send custom bytes and rxBuf[n] within sendMsgBuf(). Example: CAN1.sendMsgBuf(0x7E8, 0, 3, (0x41, 0x0A, rxBuf[1])).
I may have to revert to serial between two Unos with CAN shields so I can customize the serial messages.

Thank you for the libraries and the support on the forum!

Go Up