Can Shield - Buffer full?

Hi,

im trying to read some data from an automotive ECU which is sending 5 data packets. Can IDs are 0x2000, 0x2001, 0x2002, 0x2003, 0x2004 and 0x2005.

Overall communication is working, i receive data - actually i only need ids 2000, 2001 and 2003. My issue is, that obviously im not reading messages quick enough, so they get lost.

My Code:

#include <mcp_can.h>
#include <SPI.h>

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];

MCP_CAN CAN0(10); // Set CS to pin 10

void setup()
{
delay(1000);

Serial.begin(115200);

int canStatus = CAN0.begin(CAN_1000KBPS);
if (canStatus != 0) {
Serial.println("Can init failed!");
}
else {
Serial.println("Can init ok!");
}

attachInterrupt(0, blink, CHANGE);
}

void blink() {

while(digitalRead(2) == LOW) {
CAN0.readMsgBuf(&len, rxBuf);
rxId = CAN0.getCanId(); // Get message ID
Serial.print("id: ");
Serial.println(rxId, HEX);
}

}

void loop()
{
}

Output:

Can init ok!
id: 2000
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2001

As you see, id 2003 is missing completely. Anyone got a clue, what im doing wrong, or how to improve this?

Thanks

You can't do Serial output in an interrupt service routine.

ISRs are supposed to be lightening fast. Yours is not even close to being jiffy.

Thanks for the suggestion.

I already tried this option:

#include <mcp_can.h>
#include <SPI.h>

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];

boolean interruptFlag = false;

MCP_CAN CAN0(10);                               // Set CS to pin 10

void setup()
{
  delay(1000);

  Serial.begin(115200);

  int canStatus = CAN0.begin(CAN_1000KBPS);
  if (canStatus != 0) {
    Serial.println("Can init failed!");
  }
  else {
    Serial.println("Can init ok!");
  }

  attachInterrupt(0, blink, CHANGE);
}

void blink() {  
  interruptFlag = true;
}

void loop()
{  
  if(interruptFlag) {
    while(CAN_MSGAVAIL == CAN0.checkReceive())
    {
      CAN0.readMsgBuf(&len, rxBuf);        
      rxId = CAN0.getCanId();                    // Get message ID      
      Serial.print("id: ");
      Serial.println(rxId, HEX);                  
    }
    interruptFlag = false;
  }
}

It doesnt work at all. Output of above code:

Can init ok!

I know that its possible to use masks and filters with the can shield, but i didnt figured out, how to use them properly. I think that would be the key to my problem. Anyone familiar with the Filters? Or other suggestions?

Thanks a lot!

Sorry my fault, cable wasnt plug in correctly...

So with this code

#include <mcp_can.h>
#include <SPI.h>

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];

boolean interruptFlag = false;

MCP_CAN CAN0(10);                               // Set CS to pin 10

void setup()
{
  delay(1000);

  Serial.begin(115200);

  int canStatus = CAN0.begin(CAN_1000KBPS);
  if (canStatus != 0) {
    Serial.println("Can init failed!");
  }
  else {
    Serial.println("Can init ok!");
  }

  attachInterrupt(0, blink, CHANGE);
}

void blink() {  
  interruptFlag = true;
}

void loop()
{  
  if(interruptFlag) {
    while(CAN_MSGAVAIL == CAN0.checkReceive())
    {
      CAN0.readMsgBuf(&len, rxBuf);        
      rxId = CAN0.getCanId();                    // Get message ID      
      Serial.print("id: ");
      Serial.println(rxId, HEX);                  
    }
    interruptFlag = false;
  }
}

Im getting this output. So there are still messages missing

Can init ok!
id: 2000
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002
id: 2005
id: 2001
id: 2000
id: 2002

Variables shared by interrupt service routines and other functions must be volatile.

There is nothing magic, or smart, about the interrupt service routine's name.

PaulS:
Variables shared by interrupt service routines and other functions must be volatile.

Even if they are a single byte?

Even if they are a single byte?

The volatile keyword tells the compiler that it must fetch the value every time it is referenced. Size has nothing to do with that need.

What happens if you change

while(CAN_MSGAVAIL == CAN0.checkReceive())

to

if (CAN_MSGAVAIL == CAN0.checkReceive())

...R

Robin2:
What happens if you change

while(CAN_MSGAVAIL == CAN0.checkReceive())

to

if (CAN_MSGAVAIL == CAN0.checkReceive())

...R

Then the ISR is only entered 2 times. As i remember, the pin stays low as long as there is data in the buffer.

I found this example, could anyone help me adjusting the filters to receive only 0x2003 id? Thanks!

http://www.hobbytronics.co.uk/download/leonardo-canbus/test_receive_filter.ino

filth:
Then the ISR is only entered 2 times. As i remember, the pin stays low as long as there is data in the buffer.

That does not make sense to me.

You are using the ISR to identify if something has been received. How many items are received for every interrupt?

My concern is that the WHILE will delay the moment when interruptFlag is set back to false so that the next item can be detected.

And do you need a CHANGE interrupt or would RISING or FALLING be better ?

...R

The ECU is sending 5 Messages for every interrupt. Changing interrupt type does not help.

What about the filters?

filth:
The ECU is sending 5 Messages for every interrupt.

Can you read the whole thing as a single item and split it up later - that should be faster. Serial.print() is slow.

Or perhaps you could read (say) 50 items into an array before you print any of them ?

Or maybe just read the 5 into an array before printing anything ?

Can you post a link to the datasheet for the mcp_can library that you are using ?

...R

Im using this Lib

I cant split stuff, as the messages are getting lost on the hardware side - im not able to read them fast enough from the can shield.

filth:
I cant split stuff, as the messages are getting lost on the hardware side - im not able to read them fast enough from the can shield.

I meant that you read them before you split them so that you can read them faster.

It is also a good idea to do experiments to see what works. Even if it cannot be a long term solution it may help to figure out the cause of the problem. Have you tried reading 50 values like I suggested ?

I will look at your link later today.

...R

Have you tried the example with interrupts that is in the Library link

There are at least two notable differences

  • It uses a FALLING interrupt
  • It sets Flag_Recv = 0; as the first thing, not the last thing

and it seems to be using a lower speed.

...R