CAN BUS MCP2515

Dear Colleagues,

I'm trying to assemble some motor controllers, which contain an Arduino nano, an MD-01 motor driver, an MCP2515 CAN Module and a 4-digit display.

The goal would be later to have an Arduino mega on a CAN Module as well which would send orders to the motor controllers, and the controllers would send back their status (RPM based on the motor's encoder, the speed based on PWM strength and the direction).

I created two of the controllers (including the cables as well), see attached image.

I'm not too much into the topic of CAN but I I found some code and I could initialize them.
The codes I use are the following:

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

#define CAN_INT 2
#define MOT_SE1 3
#define MOT_SE2 4
#define MOT_PWM 5
#define MOT_DIR 7
#define DIO 8
#define CLK 9
#define CAN_SPI 10  
//CAN_SI 11 
//CAN_SO 12 
//CAN_SCK 13;

const short DEV_ID = 0x100;

// CAN RX Variables
long unsigned int rxId;
unsigned char len = 0;
unsigned char buf[8];

TM1637Display display(CLK, DIO);
MCP_CAN CAN(CAN_SPI); 

void setup() {
  display.setBrightness(0x0a);  //set the diplay to maximum brightness
  display.showNumberDec(DEV_ID); //Display the Variable value;
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(MOT_PWM, OUTPUT);
  pinMode(MOT_DIR, OUTPUT);
  analogWrite(MOT_PWM, 240);
  pinMode(MOT_SE1, INPUT);
  pinMode(MOT_SE2, INPUT);

  Serial.begin(9600);
  initCanModule();
}

void initCanModule(){
  Serial.println("CAN BUS: starting controller");
  byte errCode;
  while (CAN_OK != (errCode = CAN.begin(MCP_STDEXT, CAN_500KBPS, MCP_8MHZ)))
  {
    Serial.println("CAN BUS: starting error! Trying again...");
    Serial.print("Error Code: "); 
    Serial.println(errCode);
    delay(500);
  }

  // Allow all Standard IDs
  Serial.println("CAN BUS: setting standard filters");
  CAN.init_Mask(0,0x0000000);                // Init first mask...
  CAN.init_Filt(0,0x0000000);                // Init first filter...
  CAN.init_Filt(1,0x0000000);                // Init second filter...
  // Allow all Extended IDs
  Serial.println("CAN BUS: setting extended filters");
  CAN.init_Mask(1,0x8000000);                // Init second mask...
  CAN.init_Filt(2,0x8000000);                // Init third filter...
  CAN.init_Filt(3,0x8000000);                // Init fouth filter...
  CAN.init_Filt(4,0x8000000);                // Init fifth filter...
  CAN.init_Filt(5,0x8000000);                // Init sixth filter...
  
  // Set operation mode to normal so the MCP2515 sends acks to received data.
  Serial.println("CAN BUS: setting mode normal");
  CAN.setMode(MCP_NORMAL);

  // Configuring pin for /INT input
  Serial.println("CAN BUS: setting input interrupt");
  pinMode(CAN_INT, INPUT);
  
  Serial.println("CAN BUS: shield init successful");
}

void loop() {
  //receiveMsg();
  sendStatus();
  delay(2000);
}

void receiveMsg() {
  if (LOW == digitalRead(CAN_INT)) {        // If CAN_INT_PIN pin is low, read receive buffer
    CAN.readMsgBuf(&rxId, &len, buf);       // Read data: len = data length, buf = data byte(s)
    
    Serial.print("<");
    Serial.print(rxId);
    Serial.print(",");
    for(int i = 0; i < len; i++) {
      Serial.print(buf[i]);
      Serial.print(",");
    }
    Serial.print(">");
    Serial.println();
  }    
}

void sendStatus(){
  byte data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
  byte sndStat = CAN.sendMsgBuf(DEV_ID, 0, 8, data);
  if(sndStat == CAN_OK){
    Serial.println("Message Sent Successfully!");
  } else {
    Serial.println("Error Sending Message...");
    Serial.print("Error Code: "); 
    Serial.println(sndStat);
  }
}
#include <mcp_can.h>
#include <SPI.h>
#include <TM1637Display.h>

#define CAN_INT 2
#define MOT_SE1 3
#define MOT_SE2 4
#define MOT_PWM 5
#define MOT_DIR 7
#define DIO 8
#define CLK 9
#define CAN_SPI 10  
//CAN_SI 11 
//CAN_SO 12 
//CAN_SCK 13;

const short DEV_ID = 0x101;

// CAN RX Variables
long unsigned int rxId;
unsigned char len = 0;
unsigned char buf[8];

TM1637Display display(CLK, DIO);
MCP_CAN CAN(CAN_SPI); 

void setup() {
  display.setBrightness(0x0a);  //set the diplay to maximum brightness
  display.showNumberDec(DEV_ID); //Display the Variable value;
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(MOT_PWM, OUTPUT);
  pinMode(MOT_DIR, OUTPUT);
  analogWrite(MOT_PWM, 240);
  pinMode(MOT_SE1, INPUT);
  pinMode(MOT_SE2, INPUT);

  Serial.begin(9600);
  initCanModule();
}

void initCanModule(){
  Serial.println("CAN BUS: starting controller");
  byte errCode;
  while (CAN_OK != (errCode = CAN.begin(MCP_STDEXT, CAN_500KBPS, MCP_8MHZ)))
  {
    Serial.println("CAN BUS: starting error! Trying again...");
    Serial.print("Error Code: "); 
    Serial.println(errCode);
    delay(500);
  }

  // Allow all Standard IDs
  Serial.println("CAN BUS: setting standard filters");
  CAN.init_Mask(0,0x0000000);                // Init first mask...
  CAN.init_Filt(0,0x0000000);                // Init first filter...
  CAN.init_Filt(1,0x0000000);                // Init second filter...
  // Allow all Extended IDs
  Serial.println("CAN BUS: setting extended filters");
  CAN.init_Mask(1,0x8000000);                // Init second mask...
  CAN.init_Filt(2,0x8000000);                // Init third filter...
  CAN.init_Filt(3,0x8000000);                // Init fouth filter...
  CAN.init_Filt(4,0x8000000);                // Init fifth filter...
  CAN.init_Filt(5,0x8000000);                // Init sixth filter...
  
  // Set operation mode to normal so the MCP2515 sends acks to received data.
  Serial.println("CAN BUS: setting mode normal");
  CAN.setMode(MCP_NORMAL);

  // Configuring pin for /INT input
  Serial.println("CAN BUS: setting input interrupt");
  pinMode(CAN_INT, INPUT);
  
  Serial.println("CAN BUS: shield init successful");
}

void loop() {
  receiveMsg();
  //sendStatus();
  //delay(2000);
}

void receiveMsg() {
  if (LOW == digitalRead(CAN_INT)) {        // If CAN_INT_PIN pin is low, read receive buffer
    CAN.readMsgBuf(&rxId, &len, buf);       // Read data: len = data length, buf = data byte(s)
    
    Serial.print("<");
    Serial.print(rxId);
    Serial.print(",");
    for(int i = 0; i < len; i++) {
      Serial.print(buf[i]);
      Serial.print(",");
    }
    Serial.print(">");
    Serial.println();
  }    
}

void sendStatus(){
  byte data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
  byte sndStat = CAN.sendMsgBuf(DEV_ID, 0, 8, data);
  if(sndStat == CAN_OK){
    Serial.println("Message Sent Successfully!");
  } else {
    Serial.println("Error Sending Message...");
    Serial.print("Error Code: "); 
    Serial.println(sndStat);
  }
}

I decided to try out if my two controllers can communicate before I move on. The initialization is successful at both controllers, but when I try to send a message, I receive error code 7 three times, then I constantly get error code 6 for each loop after that:

CAN BUS: starting controller
Entering Configuration Mode Successful!
Setting Baudrate Successful!
CAN BUS: setting standard filters
Starting to Set Mask!
Setting Mask Successful!
Starting to Set Filter!
Setting Filter Successfull!
Starting to Set Filter!
Setting Filter Successfull!
CAN BUS: setting extended filters
Starting to Set Mask!
Setting Mask Successful!
Starting to Set Filter!
Setting Filter Successfull!
Starting to Set Filter!
Setting Filter Successfull!
Starting to Set Filter!
Setting Filter Successfull!
Starting to Set Filter!
Setting Filter Successfull!
CAN BUS: setting mode normal
CAN BUS: setting input interrupt
CAN BUS: shield init successful
Error Sending Message...
Error Code: 7
Error Sending Message...
Error Code: 7
Error Sending Message...
Error Code: 7
Error Sending Message...
Error Code: 6
Error Sending Message...
Error Code: 6
Error Sending Message...
Error Code: 6
Error Sending Message...
Error Code: 6

I'm also not sure if I should put any jumpers on the CAN Modules (for setting the master).
I'm also not sure if it is possible to use a module as a transmitter and receiver at once (however I saw a video which proves that it works).

Any help is appreciated, thanks.

I tried another library https://github.com/Seeed-Studio/CAN_BUS_Shield after a few adjustments but the result is the same:

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

#define CAN_INT 2
#define MOT_SE1 3
#define MOT_SE2 4
#define MOT_PWM 5
#define MOT_DIR 7
#define DIO 8
#define CLK 9
#define CAN_SPI 10  
//CAN_SI 11 
//CAN_SO 12 
//CAN_SCK 13;

const short DEV_ID = 0x101;

// CAN RX Variables
long unsigned int rxId;
unsigned char len = 0;
unsigned char buf[8];

TM1637Display display(CLK, DIO);
MCP_CAN CAN(CAN_SPI); 

void setup() {
  display.setBrightness(0x0a);  //set the diplay to maximum brightness
  display.showNumberDec(DEV_ID); //Display the Variable value;
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(MOT_PWM, OUTPUT);
  pinMode(MOT_DIR, OUTPUT);
  analogWrite(MOT_PWM, 240);
  pinMode(MOT_SE1, INPUT);
  pinMode(MOT_SE2, INPUT);

  Serial.begin(9600);
  initCanModule();
}

void initCanModule(){
  Serial.println("CAN BUS: starting controller");
  byte errCode;
  while (CAN_OK != (errCode = CAN.begin(CAN_500KBPS)))
  {
    Serial.println("CAN BUS: starting error! Trying again...");
    Serial.print("Error Code: "); 
    Serial.println(errCode);
    delay(500);
  }

  Serial.println("CAN BUS: setting input interrupt");
  pinMode(CAN_INT, INPUT);                             
  
  Serial.println("CAN BUS: shield init successful");
}

void loop() {
  receiveMsg();
  //sendStatus();
  //delay(2000);
}

void receiveMsg() {
  if(CAN_MSGAVAIL == CAN.checkReceive())  {        
    CAN.readMsgBuf(&len, buf);      
    rxId = CAN.getCanId();
    Serial.print("<");
    Serial.print(rxId);
    Serial.print(",");
    for(int i = 0; i < len; i++) {
      Serial.print(buf[i]);
      Serial.print(",");
    }
    Serial.print(">");
    Serial.println();
  }    
}

void sendStatus(){
  byte data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
  byte sndStat = CAN.sendMsgBuf(DEV_ID, 0, 8, data);
  if(sndStat == CAN_OK){
    Serial.println("Message Sent Successfully!");
  } else {
    Serial.println("Error Sending Message...");
    Serial.print("Error Code: "); 
    Serial.println(sndStat);
  }
}

Additionally:

  • error 7 is CAN_SENDMSGTIMEOUT
  • error 6 is CAN_GETTXBFTIMEOUT

Tried another library: https://github.com/coryjfowler/MCP_CAN_lib, now it works!

OK Noe the problem is that nothing is received. I enabled sending and receiving on both controllers to check if something is working. I Only changed the DEV_ID (now it’s a byte and I use 0x10 (16) and 0x11 (17) for the controllers)

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

#define CAN_INT 2
#define MOT_SE1 3
#define MOT_SE2 4
#define MOT_PWM 5
#define MOT_DIR 7
#define DIO 8
#define CLK 9
#define CAN_SPI 10  
//CAN_SI 11 
//CAN_SO 12 
//CAN_SCK 13;

const byte DEV_ID = 0x10;

// CAN RX Variables
long unsigned int rxId;
unsigned char len = 0;
unsigned char buf[8];

TM1637Display display(CLK, DIO);
MCP_CAN CAN(CAN_SPI); 

void setup() {
  display.setBrightness(0x0a);  //set the diplay to maximum brightness
  display.showNumberDec(DEV_ID); //Display the Variable value;
  pinMode(LED_BUILTIN, OUTPUT);
  pinMode(MOT_PWM, OUTPUT);
  pinMode(MOT_DIR, OUTPUT);
  analogWrite(MOT_PWM, 240);
  pinMode(MOT_SE1, INPUT);
  pinMode(MOT_SE2, INPUT);

  Serial.begin(9600);
  initCanModule();
}

void initCanModule(){
  Serial.println("CAN BUS: starting controller");
  byte errCode;
  while (CAN_OK != (errCode = CAN.begin(MCP_ANY, CAN_250KBPS, MCP_8MHZ)))
  {
    Serial.println("CAN BUS: starting error! Trying again...");
    Serial.print("Error Code: "); 
    Serial.println(errCode);
    delay(500);
  }

  Serial.println("CAN BUS: setting mode");
  CAN.setMode(MCP_LOOPBACK);

  Serial.println("CAN BUS: setting input interrupt");
  pinMode(CAN_INT, INPUT);                             
  
  Serial.println("CAN BUS: shield init successful");
}

void loop() {
  receiveMsg();
  sendStatus();
  delay(2000);
}

void receiveMsg() {
  if(!digitalRead(CAN_INT))  {       
    CAN.readMsgBuf(&rxId, &len, buf);      
    Serial.print("<");
    Serial.print(rxId);
    Serial.print(",");
    for(int i = 0; i < len; i++) {
      Serial.print(buf[i]);
      Serial.print(",");
    }
    Serial.print(">");
    Serial.println();
  } else {
    Serial.println("No message.");
  }    
}

void sendStatus(){
  byte data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
  byte sndStat = CAN.sendMsgBuf(DEV_ID, 0, 8, data);
  if(sndStat == CAN_OK){
    Serial.println("Message Sent Successfully!");
  } else {
    Serial.println("Error Sending Message...");
    Serial.print("Error Code: "); 
    Serial.println(sndStat);
  }
}

Now each Controller receives its own message only:

<16,0,1,2,3,4,5,6,7,>
Message Sent Successfully!
<16,0,1,2,3,4,5,6,7,>
Message Sent Successfully!
<16,0,1,2,3,4,5,6,7,>

If I set the mode back to MCP_NORMAL, I receive error 7 and 6 again…

Do you have any idea?
Thanks

I tried another example and now I'm suspecting a soldering problem on one of the controllers. Controller A can receive Controller B's messages, but controller B says error 6 or 7 however the message had been sent. Controller B also doesn't receive controller A's messages.