Can not receive CAN DATA from Arduino UNO with MCP2515 Module.

I have managed to get hold of the electrical schemas of the car and this explains a lot. There are indeed multiple CAN buses in the car. The radio is on a seperate comfort CAN bus, which runs on 125kbps. So that explains quite a bit.

I've also read a bit more into CAN bus specifications and this clears things up quite a bit. The radio CAN bus signals actually are typical for a Low speed or Fault tolerant CAN bus. High speed transceivers are not compatible with such a bus, so I'll have to find a suitable fault tolerant CAN bus transceiver. Maybe build my own PCB.

Wikipedia: Low speed/Fault tolerant CAN signaling drives the CAN high wire towards 5V and the CAN low wire towards 0V when transmitting a dominant (0), and does not drive either wire when transmitting a recessive (1). The dominant differential voltage must be greater than 2.3V (with a 5V Vcc) and the recessive differential voltage must be less than 0.6V The termination resistors passively return the CAN low wire to RTH where RTH is a minimum of 4.7V (Vcc-0.3V where Vcc is 5V nominal) and the CAN high wire to RTL where RTL is a maximum of 0.3V. Both wires must be able to handle -27 to 40V without damage. |500x190

High speed transceivers are not compatible with such a bus, so I'll have to find a suitable fault tolerant CAN bus transceiver. Maybe build my own PCB. My question now is, will the MCP2515 controller and library work with such a transceiver?

My question now is, will the MCP2515 controller and library work with such a transceiver?

reynard80: My question now is, will the MCP2515 controller and library work with such a transceiver?

The transceiver and physical bus are independent of the protocol controller and the library wouldn't even notice the difference.

From a quick look, it appears that all low-speed transceivers are larger than a SOIC8 package due to the extra pins required for the termination resistors among other features, so a board would need to be made for this. Looking at how each device is terminated, it seems to me that a good confirmation of your thought about the bus being low-speed fault-tolerant would be to disconnect the battery and measure the resistance between the CAN High and CAN Low of that bus to see if it reads around 60 ohms or not. From what I'm seeing, I would expect a higher resistance or an open to be read when they are unpowered, but I could be wrong as I've not messed with this physical specification yet. Its also worthy to note that a low-speed fault-tolerant bus is designed for a specific number of nodes in mind since each device has a termination resistance. Hopefully the vendor thought about future proofing and the total line resistance is greater than 100 ohms allowing for an additional device or so.

Now I'm suddenly skeptical about my Jeep's 125k bus even though the high speed transceivers in the CAN adapter I was using was reading the data fine.

coryjfowler:
The transceiver and physical bus are independent of the protocol controller and the library wouldn’t even notice the difference.

I thought and hoped so already. so that’s good to hear…

coryjfowler:
From a quick look, it appears that all low-speed transceivers are larger than a SOIC8 package due to the extra pins required for the termination resistors among other features, so a board would need to be made for this. Looking at how each device is terminated, it seems to me that a good confirmation of your thought about the bus being low-speed fault-tolerant would be to disconnect the battery and measure the resistance between the CAN High and CAN Low of that bus to see if it reads around 60 ohms or not. From what I’m seeing, I would expect a higher resistance or an open to be read when they are unpowered, but I could be wrong as I’ve not messed with this physical specification yet. Its also worthy to note that a low-speed fault-tolerant bus is designed for a specific number of nodes in mind since each device has a termination resistance. Hopefully the vendor thought about future proofing and the total line resistance is greater than 100 ohms allowing for an additional device or so.

Now I’m suddenly skeptical about my Jeep’s 125k bus even though the high speed transceivers in the CAN adapter I was using was reading the data fine.

I want to make my own board indeed, soldering a PCB is not a real problem. I have looked in to some circuit diagrams and it seems pretty easy to do.

The termination is good point though, I also read about this. I think the manufacturer thought about at least one more device, as there is a connection to a CD changer available on the radio with CANL and CANH. Also, there is an option for a handsfree set, which I don’t have. I’m thinking of using the CD changer connection (this way I’ll also have a neat solution for connecting my device).

Determining the value of the termination resistors is one thing I’ll have to solve indeed. But I’m not sure how to do this exactly. I have included a (crude, sorry for that) diagram of the ECU’s, as found in the official technical documentation of the car. So it seems I have six nodes on this bus, but I am not sure how to find the value for the termination resistors for my project. I’m not sure how to measure the termination resistance of each node, as measuring over CANH and CANL is not correct in this case I think. CANH and CANL don’t seem to be connected by the termination resistance.

Update for future searchers:

I managed to receive messages on the comfort/fault tolerant/low speed CAN bus of my Peugeot 207, via the RD4 radio. I finally got it working with the circuit as described in this paper. Comparable designs and more information can also be found on a few German and Russian forums. Google Translate is my friend :slight_smile:

I still have to develop a refined ‘production’ board, as I now only have a breadboard prototype. Also, I haven’t tested sending messages yet.

While I have a working board now, I'm still running into some trouble. I'm receiving messages, but after a short while, this stops. It seems the MCP2515 does not give an interupt anymore, as there is some error situation.

The error does not seem to be with the transceiver, as it does not signal an error on its error-pin.

Is it possible to see the errors the MCP2515 encounters, with the library? When I read the datasheet, it seems that error flags can be read from the chip register? How can this be done?

reynard80: Is it possible to see the errors the MCP2515 encounters, with the library? When I read the datasheet, it seems that error flags can be read from the chip register? How can this be done?

Add the below to your main loop someplace. When an error occurs, it will flood your terminal window. With this piece of code in the main loop of my J1939 test application connected to my bench bus that has an ECM on it, I eventually get a receive buffer 0 overflow error which I expect to get on occasion since the ECM transmits cyclic messages at some high rates.

 if(CAN0.checkError() == CAN_CTRLERROR){
    Serial.print("Error register value: ");
    byte tempErr = CAN0.getError() & MCP_EFLG_ERRORMASK; // We are only interested in errors, not warnings.
    Serial.println(tempErr, BIN);
    
    Serial.print("Transmit error counter register value: ");
    tempErr = CAN0.errorCountTX();
    Serial.println(tempErr, DEC);
    
    Serial.print("Receive error counter register value: ");
    tempErr = CAN0.errorCountRX();
    Serial.println(tempErr, DEC);
    
    //I do not have a function that clears errors and that has been added to my todo list. 04/26/17 CJF
  }

coryjfowler:
Add the below to your main loop someplace. When an error occurs, it will flood your terminal window.
With this piece of code in the main loop of my J1939 test application connected to my bench bus that has an ECM on it, I eventually get a receive buffer 0 overflow error which I expect to get on occasion since the ECM transmits cyclic messages at some high rates.

Thanks, is there an overview of the error codes somewhere? I can’t find it in the datasheet, or am I overlooking it? I am receiving errors like this, where the counter is counting down:

Error register value: 1000000
Transmit error counter register value: 0
Receive error counter register value: 65

The error bits are read from the EFLG (ERROR FLAG) register of the MCP2515. Looks like the 6th bit is set which the datasheet says is RX0 overflow which is expected on a busy CAN bus. What concerns me is the 65 receive errors...

coryjfowler: The error bits are read from the EFLG (ERROR FLAG) register of the MCP2515. Looks like the 6th bit is set which the datasheet says is RX0 overflow which is expected on a busy CAN bus. What concerns me is the 65 receive errors...

This may be a rather stupid question, but how do you see the 6th bit is set? Because there are 6 zeroes? I think it is a busy CAN bus indeed, but does this mean the controller just hasn't got enough capacity to handle this busy bus? Or can something be done about it? Will setting a mask/filter help keeping the RX buffer from overflowing?

I have the serial output formatted to binary in the error code snippet, just need to see a 1 and its zero-based position.

As for overflow, its not typically an issue unless RX1 also overflowed since I have the BUKT bit set by default. BUKT being set moves the packet from RX0 to RX1 when a received message is destined for RX0. Filtering for only the CAN IDs you are interested in would definitely alleviate any overflows. Anything to increase the microcontroller's ability to read from the CAN controller would also help, like increasing the SPI clock speed, removing/fixing blocking functions, limiting unnecessary serial writes and/or increasing the serial speed, etc.

As for the SPI clock speed, Arduino added some new SPI features that I've not had time to incorporate into the library and test out which has been on the todo list. Something like SPISettings(10000000, MSBFIRST, SPI_MODE0) added below the CAN0.begin(...) function would help maximize the SPI clock.

have similar problems than above. I use the sketch from post #11. I use the Nirem CAN interface. If I set it to 500 kbs and 8 MHz and LOOPBACK Mode I get initialized OK, and send message OK, but do not receive anything. If I set it to 125 kbs I get an iitialization error. As some wrote low baudrates are not working fine with 8 MHz cristal. I bulld up a circuit with original MCP2515 DILand 16 Mhz cristal. Here I get and send message error with the same sketch. I think it is clear that I changed the initializtions string acording the cristal. Adrduino board isoriginal Arduino UNO with the SMD Arduino. connections are CS=10, SO =12, SI=11,SCK=13,INT=2 Thanks for any help or hint

muekno:
I use the Nirem CAN interface.

This thing? interfaces:niren - wiki.kewl.org

You would be somewhere around the third individual to have no luck with those boards and unless you have access to an actual CAN interface dongle and tools(Peak, Kvaser, Vector, etc) troubleshooting will be difficult. I cannot recommend that CAN interface board.

I have Arduino UNO and Mega2560 with CAN bus shields from SEEED and Sparcfun and everything works fine. These shields use a 16MHz Q. Tested against each other RX/TX, Keysight Oscilloscope with CAN bus capability, against Garmin nmea2000 marine network and finally against Märklin digital toy train ! (Märklin uses CAN bus also...) Eveything works perfectly!

I now use the CAN library from Cory Fowler with support also for 8 MHz. Now I also have tried the NiRem Canbus board from China with a 8 MHz Q. Tested 4 pieces and it simply does not work (only modification in code is 8MHz).

I think the problem is in these boards/PCB. I have run out of ideas to test more.

Regarding CAN library I am a bit confused.

In early 2016 I used the library from SEEED studio. This worked fine for my experiments. However there was no support for other than 16 MHz Q.

Then in 2016 I used The library from Cory Fowler, and also changed some of my code. In this library there are support also for 8 MHz Q (and other). I also noticed not to use "CAN.getCanId(); ".

Now I see a new library from Adlerweb and still the use of "CAN.getCanId();

As I am new to this I would appreciate some clarifications.

And what library to use.

Christer_A: Regarding CAN library I am a bit confused. [...] I also noticed not to use "CAN.getCanId(); ".

Now I see a new library from Adlerweb and still the use of "CAN.getCanId();

I removed it because I gave the CAN receive function ("CAN0.readMsgBuf(&rxID, &len, rxBuf)") the ability get that information into the user's "sketch" in one function call instead of two.

I would go to assume Adlerweb forked his version of the library before my changes we made. At one point my change made it to Seeed's library, but they added it back for whatever reason.

Christer_A: As I am new to this I would appreciate some clarifications.

And what library to use.

You're welcome to use any library you want, but the sweet thing is, if you use mine I am more willing to help you when a problem occurs. For instance, if you want to send me a couple of those boards you're not having luck with, I can take a look at them and see what I can come up with.

I actually have two of those boards I linked to in my previous post on this thread working, but I've not had near as many issues as I've encountered from the community which makes me feel like a counterfeit part is ruining an otherwise nice product.

PM me if you're interested.

Using the Cory Fowler library. I forgot to say that the 8MHz "NiRem" board Initialize correct. But there is nothing transmitted on the CAN bus.

Today I tested 3 other CAN shields. The 1.2 version from SEEED, Sparcfun CAN bus shild and also a shield from ElecFreaks in China. All three with the same formfactor and using 16 MHz Q. Tested these shields tested against different Arduini UNO and MEGA 2560.

Everything works fine.

Checked against Garmin GPS plotter with nmea2000 network and also tested against a Microchip CAN development box.

It is only the NiRem boards that will not work !

Christer_A: Using the Cory Fowler library. I forgot to say that the 8MHz "NiRem" board Initialize correct. But there is nothing transmitted on the CAN bus.

Correct. I have seen this from others before you. I purchased a few of those boards a year ago and they did work for me. I do not know what is going on with the other boards until I get my hands on some, but I suspect a bad, possibly counterfeit, part.

Christer_A: Today I tested 3 other CAN shields. The 1.2 version from SEEED, Sparcfun CAN bus shild and also a shield from ElecFreaks in China. All three with the same formfactor and using 16 MHz Q. Tested these shields tested against different Arduini UNO and MEGA 2560.

Everything works fine.

That's great! Glad those are working fine.

Christer_A: Checked against Garmin GPS plotter with nmea2000 network and also tested against a Microchip CAN development box.

Oh thats nice... I need to borrow one of those so I can figure out the plotter turns GLONASS on in the GPS I have. They will not give me any information on their NMEA 2K GPS, its pretty silly. I have a sketch decoding the output of the GPS otherwise.

Christer_A: It is only the NiRem boards that will not work !

I'm as baffled as you are until I can investigate further.

Problem solved !
Thanks Cory Fowler for support.
The main problem was some bad cables between the Arduino and the NiRem board !
Stupid problem. I tried several boards but I did not change the cables.

When digging into this I could not resist to build my own CAN BUS “shield” on a breadboard.
Jpg attached. The local electronics shop here in my town stores MCP2515, MCP2551 and also 8 and 16 MHz Quarz. I did not expect this. This breadboard shield worked directly, and was very stable.
Easy to change between 8 and 16 MHz Quarz.
I also added two LEDs with resistors for TXD and RXD so I could get indication of something transmitted and received.

I now have 3 NiRem boards here and 2 of them works perfectly. The third one is not stable. When moving my finger on the PCB it could stop working or start working.

i am using the elekfreaks shield with Arduino UNO and SparkFun Can Library. Everything’s working fine. I tried to use coryjfowler’s can Lib because i need dual can support. I connected 2 shield to Arduino, one shield with INT 2 and CS 10 and the other with INT 3 and CS 9. both CAN: Init OK Baudrate Successful and Configuration Mode Successful. i can see data incoming. The RX Led is blinking but nothing is being printed on the serial console. I tried the receive example with one shield attached only. But same problem. Everything is been initialized ok but i am not receiving anything. The shield is running on 16 Mhz. With the same setup i can start the receive example script from spark fun library and its working fine. (without changing any wires) what could be the problem?

// Demo: Dual CAN-BUS Shields, Data Pass-through
// Written by: Cory J. Fowler
// January 31st 2014
// This examples the ability of this library to support more than one MCP2515 based CAN interface.


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

unsigned long rxId;
byte len;
byte rxBuf[8];

byte txBuf0[] = {};
byte txBuf1[] = {};

MCP_CAN CAN0(10);                              // CAN0 interface usins CS on digital pin 10
MCP_CAN CAN1(9);                               // CAN1 interface using CS on digital pin 9

void setup()
{
  Serial.begin(115200);
  
  // init CAN0 bus, baudrate: 250k@16MHz
  if(CAN0.begin(MCP_ANY, CAN_100KBPS, MCP_16MHZ) == CAN_OK){
  Serial.print("CAN0: Init OK!\r\n");
  CAN0.setMode(MCP_NORMAL);
   pinMode(2, INPUT);  
  } else Serial.print("CAN0: Init Fail!!!\r\n");
  
  // init CAN1 bus, baudrate: 250k@16MHz
  if(CAN1.begin(MCP_ANY, CAN_100KBPS, MCP_16MHZ) == CAN_OK){
  Serial.print("CAN1: Init OK!\r\n");
  CAN1.setMode(MCP_NORMAL);
   pinMode(3, INPUT);  
  } else Serial.print("CAN1: Init Fail!!!\r\n");
  
  SPI.setClockDivider(SPI_CLOCK_DIV2);         // Set SPI to run at 8MHz (16MHz / 2 = 8 MHz)
}

void loop(){  
  if(!digitalRead(2)){                         // If pin 2 is low, read CAN0 receive buffer
    CAN0.readMsgBuf(&rxId, &len, rxBuf);       // Read data: len = data length, buf = data byte(s)
    if(rxId == 0x130)
    {
      Serial.println("0x130 empfangen");
      byte rxBuf[5] = {0x45,0x41,0x21,0x8F,0x57};
      CAN1.sendMsgBuf(rxId, 0, len, rxBuf);
    }
    else        
      CAN1.sendMsgBuf(rxId, 0, len, rxBuf);      // Immediately send message out CAN1 interface
  }  
  if(!digitalRead(3)){                         // If pin 3 is low, read CAN1 receive buffer
    CAN1.readMsgBuf(&rxId, &len, rxBuf);       // Read data: len = data length, buf = data byte(s)
    Serial.print("ID: ");
    Serial.print(rxId,HEX);
    Serial.print(", ");
    Serial.print("Data: ");
    for(int i=0;i<len;i++)
    {
      Serial.print(rxBuf[i],HEX);
      Serial.print(" ");
    }
    Serial.println("");
  }
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

Having just about wasted the whole day trying to get a simple send/receive working, using two Nano v3.0s and two NiRen MCP2515 modules. (Using Corys wonderfull library with crystal set to 8Mhz)

The problem turned out to be that Nano V3.0 powered from it's USB port does not provide enough voltage to allow the NiRen modules to function correctly....

They look like they're working and initialise OK but sending fails and nothing is received...

Power every thing from a separate 5v power supply and everything works as expected :-)

Hope this saves someone a bit of time!

Cheers Ken

Hi,

I have meet the same problem.

I use Arduino Uno and Niren MCP2515(8 Mhz) Modul, I also use a CAN Generator that creates CAN BUS signals.

MCP_CAN_LIB source files: https://github.com/Seeed-Studio/CAN_BUS_Shield

And the code is very simple with send and receive functions just as the Library.

BUT the digitalRead(CAN_INT) ist always HIGH and I can receive nothing. I habe tried all the receive code examples in the library and no one works.

Has anyone got this problem? What can I do to solve it?
I wasted fast a week.

// CAN Send Example
//
#include <SPI.h>
#include <avr/wdt.h>


#include "mcp_can.h"
#include "Arduino.h"

//initial all parametrs
const int CAN_INT=2;
const int SPI_CS_PIN=10;

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

byte data[] = {0xAA, 0x55, 0x01, 0x10, 0xFF, 0x12, 0x34, 0x56}; 


MCP_CAN CAN(SPI_CS_PIN);     // Set CS to pin 10


void setup()
{
    // Pins definieren
  pinMode(SPI_CS_PIN, OUTPUT);
  pinMode(CAN_INT, INPUT); // CAN_INT set to 2
  
  Serial.begin(115200);
  Serial.print("Starting CAN-Bus: ");
  // Initialize MCP2515 running at 8MHz with a baudrate of 500kb/s and the masks and filters disabled.
 while (CAN_OK != CAN.begin(MCP_STDEXT, CAN_500KBPS, MCP_8MHZ))    // init can bus : baudrate = 500k
    {
        Serial.println("CAN BUS Shield init fail");
        Serial.println(" Init CAN BUS Shield again");
        delay(100);
    }
    Serial.println("CAN BUS Shield init ok!");

    /*
     * set mask, set both the mask to 0x3ff
     */
    CAN.init_Mask(0, 0, 0x000);                         // there are 2 mask in mcp2515, you need to set both of them
    CAN.init_Mask(1, 0, 0xfff);


    /*
     * set filter, we can receive id from 0x04 ~ 0x09
     */
    CAN.init_Filt(0, 0, 0x04);                          // there are 6 filter in mcp2515
    CAN.init_Filt(1, 0, 0x05);                          // there are 6 filter in mcp2515

    CAN.init_Filt(2, 0, 0x06);                          // there are 6 filter in mcp2515
    CAN.init_Filt(3, 0, 0x07);                          // there are 6 filter in mcp2515
    CAN.init_Filt(4, 0, 0x08);                          // there are 6 filter in mcp2515
    CAN.init_Filt(5, 0, 0x09);                          // there are 6 filter in mcp2515
    
   CAN.setMode(MCP_NORMAL);
}

void loop()
{ 
    Serial.println("Start receiving Data:");
    
    if(!digitalRead(CAN_INT))
  {
    CAN.readMsgBuf(&rxId, &len, rxBuf);   // read data,  len: data length, buf: data buf
    Serial.print("rxID: ");
    Serial.println(rxId);
    Serial.print("Readdetails:   ");
    for(int i=0;i<sizeof(rxBuf);i++)
    {
      Serial.print("0x");
      Serial.print(rxBuf[i],HEX);
      Serial.print("  ");
    }
  }
  else
  {
    Serial.println("Error receiving Message..."); 
  }
    Serial.println();
    
    Serial.println("Start sending Data:");
    CAN.sendMsgBuf(0x100, 0, 8, data);
    delay(10000);
}