CAN bus MCP2515 library, mask filters

Hello, magicians.

Hate to disturb people with dumb questions, But I am struggling with setting up mask and filter for ID on canbus. I have read alot of topics on this matter and it was easy with different library, but... never easy quest .. library I used before was conflicting with another that I need for the project... My hair went grey with trying to establish whats going on.

Now I am using this library:
mcp2515.h

And I need to filter by ID - 418.

I will need other IDs at a later stage, but help with setting first one up will be sufficient for me to continue on my quest and hopefully grasp the logic of writing this filter/mask.

So whoever reached this fat here is a backstory of the idea:

Soon I am going to be doing an engine and gearbox swap into much older vehicle that is very analogue. I would like to keep as much as possible from original setup so inside should be as stock as possible. It doesn't have separate indicator on dash for Gear selector position, but does have a little rectangular warning icon right in the middle that is spot on for small OLED 128x64 0.96"display. So I want to show selector position on there plus current gear ( will be 7 speed auto gearbox). I have vehicle with same box and I found IDs and bytes that are changing.

With first library that I tried mcp_can.h everything separately works great, very easy to setup mask and filter, but if I start OLED before I start mcp2515 - CAN starts dumping zeroes over serial monitor or will show CAN data, but will "'self generate" last signal when can is switched off. If I enable CAN first and then OLED ( I2C by the way) , it will fail to allocate OLED.

Anyway I have programmed separate Nano + MCP2515 to send every 2 seconds data over can ID 418, every time changing bytes responsible for current gear and it works 100% as a bench guineapig. Even more so I have managed with current library to get OLED to display correct gear, but due to too much data over CAN on vehicle it starts misbehaving on the spot when hooked up to car without Mask and filter.

Can somebody with more knowledge help me with setting up the mask and filter on this library. Bare in mine I am complete noob in this field and all accomplished is based on days of research and alot of "exotic" words in few languages that I can speak.

Future development ideally will include few additional stages, at which point I am sure nano will not cut it.

Desirable addons:
Get vehicle speed from CAN ( oh yes it will have way more modern ABS) and convert it to analogue to be able to drive original speedo (its electronic, but analogue),
Maybe RPM,
Maybe coolant temp,
deffo MIL for engine, transmission and ABS ( plus flashy light for traction control).

Stay tuned as will most definitely encounter problems and few thousand heads here are way better than one that is new to this.

That sounds like your Nano is running out of memory. I suspect that that switching libraries is only going to be a temporary fix. As the project grows you'll probably see similar problems occuring again.

Look at the memory stats after compilation, and use freeMemory() or similar functions to see the run time stats.

Long term you'll probably need to switch to a microcontroller that has more RAM such as the Mega2560.

Check this information, the arduino is not the best choice. You need one designed for the automotive environment. Here is why:
Arduinos were designed for and are are intended for experimentation and learning, often with breadboards and loose wires that eventually break if vibrated. Most important, the boards are not protected against harsh, dirty or electrically noisy environments found in industrial, automotive and other commercial applications. It is unreliable as it is not suitable for industrial, automotive and other commercial operation.

There is many good app notes such as AN2689 by ST on automotive electronics. reading it will help you a lot.
https://www.st.com/resource/en/application_note/cd00181783-protection-of-automotive-electronics-from-electrical-hazards-guidelines-for-design-and-component-selection-stmicroelectronics.pdf
Also take a look at these: Distilled Automotive Electronics Design | Analog Devices and
Transient Voltage Suppression in Automotive Applications
AEC-100 https://media.monolithicpower.com/mps_cms_document/w/e/Webinar_-_Fundamentals_of_AEC-
Understanding Automotive Electronics, An Engineering Perspective by William B. Ribbens
(PDF) .Understanding Automotive Electronics, Seventh Edition An Engineering Perspective by William Ribbens | Roman Perez - Academia.edu

To be fair I never planned to use nano in the end and would switch up to something more powerful. I was looking into teensy 4.0 at one point. but for experimental purposes this should work with Nano. it does it with current library and I am quite confident it will do this first stage as long as I set up the mask and filters correctly.

I will surely read these ( I think I did read one of these before), thank you for pointers.

Thing is as its only on the receiving end, would be mounted behind instrument cluster so in better environment than average automotive stuff and I might be noob in programming arduino, but I have designed SMD PCBs, had them manufactured and being used in much harsher environment than that for the last 3-4 years. No failures to report. So it wont be loose wires, dodgy solder or proto board. Currently for experiment purposes it is on a matrix prototype pcb, all soldered though, no wires at all.

I suggest you place a thermometer there and put it in the hot sun for a few hours. Look at this AEC-Q200 standard. The area you are planning is I believe 105C but could be 85C depending on the design. I always worked with the 105C number.

I am with you if I was selling it, but again at this stage its getting way too far ahead. I just want to build 1, I am not going to make it commercially, just for my own project. If it glitches due to overheating, tough sh*t , I am not going to be crying about it. MCUs can easily be upgraded, Custom PCBs made with all automotive grade components , maybe stm32 mcu or something amongst those lines. As long as Its compatible with Arduino IDE swapping MCUs is a 5 minute job on software side of it.

Seems thread is being side-tracked from main objective at this point - mask and filters. Anyone managed to get ID filter setup using this library ???

you should specifiy WHAT kind of messages you have got so far and WHAT messages should pass your filter. You must specify them in bits because you can't filter by the description RPM, coolant temp or MIL.

that is not quite right.

the MCP2515 will only filter the CAN ID. you can see an example here. the syntax btw looks very similar to the library @vitaliym is using.

Personally never used it but if we kept the same syntax as in the example, then to filter for CAN id 0x418 (assuming standard CAN ID and value you posted is in HEX) then you need to modify the example code to this:

CAN.init_Mask(0,0,0x07FF0000);                // Init first mask...
  CAN.init_Filt(0,0,0x04180000);                // Init first filter...
  CAN.init_Filt(1,0,0x04180000);                // Init second filter..
  CAN.init_Mask(1,0,0x07FF0000);                // Init second mask...   
  CAN.init_Filt(2,0,0x04180000);                // Init third filter...
  CAN.init_Filt(3,0,0x04180000);                // Init fourth filter...
  CAN.init_Filt(4,0,0x04180000);                // Init fifth filter...
  CAN.init_Filt(5,0,0x04180000);                // Init sixth filter...

As I said, never used the library @vitaliym are using so no idea if the above syntax will also work with it!

Good Luck! :slight_smile:

if that's not true, show how to filter for "RPM", "coolant temp", or "MIL".

I would need the ID of these messages to be able to provide a somehow working example.
I prefer to see them in binary because it makes the usage of the filter easier for me.
You can expect that I will be able to convert a hex value in a binary value.

read OP request again... it is essentially a 2 part question

to reduce the load on the uC, OP wants to filter for the required ID (which he has specified) which the MCP2515 can and will do if setup correctly.

as for the 'signal' themselves, that can only be done on the uC here to extract (not filter) the desired ones from the filtered IDs.

Try this link: Filtering and Masking in CAN bus it has a good explanation.

Basically by using can hacker and same very board setup programmed to work with it I found out that TCU ( transmission control unit) is sending 4 different IDs, but 418 seems to be the one that I need . Its the bit number 4 that changes depending on the gear. so lets say its in park - its DD, in third gear its actually 33. To be completely fair its a little bit more complex, as first digit is what is requested gear, second digit is what is current gear, but for all intents and purposes it will do me fine to say for it to print "P" on OLED when it sees at data position 4 value DD. This bit I have successfully done, but my MCU tries to read all CANbus on car without mask and ID filter.

Filter and mask example above I did try before even considering writing here, but it wouldn't even compile the code. Need to double check though as tried several variations.

As said using different library setting up mask and filter was very easy.

 CAN0.init_Mask(0, 0, 0x07FF0000);            
  CAN0.init_Filt(0, 0, 0x04180000);     
  CAN0.init_Filt(1, 0, 0x04180000);     

  CAN0.init_Mask(1, 0, 0x07FF0000);              
  CAN0.init_Filt(2, 0, 0x04180000);             
  CAN0.init_Filt(3, 0, 0x04180000);            
  CAN0.init_Filt(4, 0, 0x04180000);             
  CAN0.init_Filt(5, 0, 0x04180000);          

That is how I have done it before an worked good. i think i tried as well just setting both masks as per description and only filter 0 with my can ID and result was identical, but from examples online it looked like everyone has set it up in this way. For people that are trying to understand the how to use the example above - if filtering for ID 0 use same mask as me and just in filters use your needed ones. This is covered very well online.

As for comparing bytes I use this line and it works:

 if(canMsg.can_id==0x418, canMsg.data[4]==DD) {IN HERE WHAT I WANT IT TO DO}

Hope this clarifies few things. I am working very long hours, nightshift but only 3 per week and now I am just after second one. Will have a play and try that syntax and few variations later in the week

So that mentioned approach above is the one that works witht he other library, but not this one. Basically I tried to implement it with same syntax on current library onto the example CAN read sketch:

#include <SPI.h>
#include <mcp2515.h>

struct can_frame canMsg;
MCP2515 mcp2515(10);


void setup() {
  Serial.begin(115200);
  SPI.begin();
  
  mcp2515.reset();
  mcp2515.setBitrate (CAN_500KBPS,  MCP_16MHZ);
  mcp2515.setNormalMode();


  MCP2515.init_Mask(0, 0, 0x07FF0000);              // Init first mask...
  MCP2515.init_Filt(0, 0, 0x04180000);              // Init first filter...
  MCP2515.init_Filt(1, 0, 0x04180000);              // Init second filter...

  MCP2515.init_Mask(1, 0, 0x07FF0000);              // Init second mask...
  MCP2515.init_Filt(2, 0, 0x04180000);              // Init third filter...
  MCP2515.init_Filt(3, 0, 0x04180000);              // Init fouth filter...
  MCP2515.init_Filt(4, 0, 0x04180000);              // Init fifth filter...
  MCP2515.init_Filt(5, 0, 0x04180000);              // Init sixth filter...
  
  Serial.println("------- CAN Read ----------");
  Serial.println("ID  DLC   DATA");
}

void loop() {
  
  if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
      
    Serial.print(canMsg.can_id, HEX); // print ID
    Serial.print(" "); 
    Serial.print(canMsg.can_dlc, HEX); // print DLC
    Serial.print(" ");
    
    for (int i = 0; i<canMsg.can_dlc; i++)  {  // print the data
        
      Serial.print(canMsg.data[i],HEX);
      Serial.print(" ");

    }

    Serial.println();      
  }

}

And as said it doesnt even compile it... Comes with this message

Not used: C:\Users\vitas\Documents\Arduino\libraries\arduino-mcp2515-master
exit status 1
expected unqualified-id before '.' token

Library description describes it like this:

MCP2515::ERROR setFilterMask(const MASK mask, const bool ext, const uint32_t ulData)
MCP2515::ERROR setFilter(const RXF num, const bool ext, const uint32_t ulData)

But I till am puzzled how to structure it correctly to filter ID

I wonder why you don't use the functions fitting to your library setFilterMask and setFilter:

Well, because seems like I am useless in understanding language properly. I tried before inputting my mask and filter using those functions, but failed to do that successfully.

1 Like

With my limited understanding I tried to follow the logic, but something terribly eludes me..

  MCP2515::ERROR setFilterMask(const MCP2515::MASK0, const bool false, const uint32_t 0x07FF0000)
  MCP2515::ERROR setFilter(const MCP2515::RXF0, const bool false, const uint32_t 0x04180000)
  MCP2515::ERROR setFilterMask(const MCP2515::MASK1, const bool false, const uint32_t 0x07FF0000)

Obviously doesnt work.

I think the 'issue' is this routine that is used the the filter and mask routines:

void MCP2515::prepareId(uint8_t *buffer, const bool ext, const uint32_t id)
{
    uint16_t canid = (uint16_t)(id & 0x0FFFF);

    if (ext) {
        buffer[MCP_EID0] = (uint8_t) (canid & 0xFF);
        buffer[MCP_EID8] = (uint8_t) (canid >> 8);
        canid = (uint16_t)(id >> 16);
        buffer[MCP_SIDL] = (uint8_t) (canid & 0x03);
        buffer[MCP_SIDL] += (uint8_t) ((canid & 0x1C) << 3);
        buffer[MCP_SIDL] |= TXB_EXIDE_MASK;
        buffer[MCP_SIDH] = (uint8_t) (canid >> 5);
    } else {
        buffer[MCP_SIDH] = (uint8_t) (canid >> 3);
        buffer[MCP_SIDL] = (uint8_t) ((canid & 0x07 ) << 5);
        buffer[MCP_EID0] = 0;
        buffer[MCP_EID8] = 0;
    }
}

unlike the coryjfowler CAN library, its not using the full length of the uint32_t.

so maybe inplace of 0x07FF0000 and 0x04180000 those should be set as

0x000007FF and 0x00000418 respectively.

hope that helps....

Hm,, hasnt changed a thing. Still IDE will not verify sketch:

CAN_read:16:47: error: 'MASK0' in 'class MCP2515' does not name a type
.....
CAN_read:16:65: error: expected ',' or '...' before 'false'
.....
CAN_read:17:3: error: expected initializer before 'MCP2515'
.....
'MASK0' in 'class MCP2515' does not name a type

As I say I am complete noob when it comes to programming and I bet I make stupid mistakes

doubtful given how ambitious your project it! :wink:

anyway... sample code:
(Compiles, NOT tested!)

#include <SPI.h>
#include <mcp2515.h>

struct can_frame canMsg;
MCP2515 mcp2515(10);


void setup() {
  Serial.begin(115200);
  
  mcp2515.reset();
  mcp2515.setBitrate(CAN_500KBPS);

  mcp2515.setFilterMask(MCP2515::MASK0, false, 0x000007FF);
  mcp2515.setFilter(MCP2515::RXF0, false, 0x00000418);
  mcp2515.setFilter(MCP2515::RXF1, false, 0x00000418);
  mcp2515.setFilterMask(MCP2515::MASK1, false, 0x000007FF);
  mcp2515.setFilter(MCP2515::RXF2, false, 0x00000418);
  mcp2515.setFilter(MCP2515::RXF3, false, 0x00000418);
  mcp2515.setFilter(MCP2515::RXF4, false, 0x00000418);
  mcp2515.setFilter(MCP2515::RXF5, false, 0x00000418);

  mcp2515.setNormalMode();
  
  Serial.println("------- CAN Read ----------");
  Serial.println("ID  DLC   DATA");
}

void loop() {
  if (mcp2515.readMessage(&canMsg) == MCP2515::ERROR_OK) {
    Serial.print(canMsg.can_id, HEX); // print ID
    Serial.print(" "); 
    Serial.print(canMsg.can_dlc, HEX); // print DLC
    Serial.print(" ");
    
    for (int i = 0; i<canMsg.can_dlc; i++)  {  // print the data
      Serial.print(canMsg.data[i],HEX);
      Serial.print(" ");
    }

    Serial.println();      
  }
}

Good luck!