MCP2515 CAN loopback example

Sketch:

/*
 * Loopback example for CAN MCP2515.
 */

#include <SPI.h>

// https://github.com/coryjfowler/MCP_CAN_lib
#include <mcp_can.h>

#define INT 10 // grey
#define CS 9   // yellow

// Definition of SPI:
// SI -> 11  blue
// SO -> 12  green
// SCK -> 13 purple

MCP_CAN Canbus(CS);

void setup() {
  Serial.begin(9600);

  while(true) {
    delay(1000);
    // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
    if(Canbus.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK) {
      Serial.println("MCP2515 Initialized Successfully.");
      break;
    }
    else {
      Serial.println("Error Initializing MCP2515...");
      delay(3 * 1000);
    }
  }
  pinMode(INT, INPUT);

  Canbus.setMode(MCP_LOOPBACK);

  Serial.println("setup() done");
}

// https://github.com/coryjfowler/MCP_CAN_lib/blob/master/examples/CAN_loopback/CAN_loopback.ino
unsigned long prevTX = 0;                                        // Variable to store last execution time
const unsigned int invlTX = 1000;                           // 10 second interval constant
byte data[] = {0xAA, 0x55, 0x01, 0x10, 0xFF, 0x12, 0x34, 0x56};  // Generic CAN data to send
long unsigned int rxId;
unsigned char len;
unsigned char rxBuf[8];
char msgString[128];

void loop()
{
  if(!digitalRead(INT)) // If CAN0_INT pin is low, read receive buffer
  {
    Serial.print(" < ");
    Canbus.readMsgBuf(&rxId, &len, rxBuf);              // Read data: len = data length, buf = data byte(s)
    
    if((rxId & 0x80000000) == 0x80000000)             // Determine if ID is standard (11 bits) or extended (29 bits)
      sprintf(msgString, "Extended ID: 0x%.8lX  DLC: %1d  Data:", (rxId & 0x1FFFFFFF), len);
    else
      sprintf(msgString, "Standard ID: 0x%.3lX       DLC: %1d  Data:", rxId, len);
  
    Serial.print(msgString);
  
    if((rxId & 0x40000000) == 0x40000000){            // Determine if message is a remote request frame.
      sprintf(msgString, " REMOTE REQUEST FRAME");
      Serial.print(msgString);
    } else {
      for(byte i = 0; i<len; i++){
        sprintf(msgString, " 0x%.2X", rxBuf[i]);
        Serial.print(msgString);
      }
    }
        
    Serial.println();
  }
  
  if(millis() - prevTX >= invlTX){                    // Send this at a one second interval. 
    Serial.print(" > ");
    prevTX = millis();
    byte sndStat = Canbus.sendMsgBuf(0x100, 8, data);
    Serial.print(" > ");
    
    if(sndStat == CAN_OK)
      Serial.println("Message Sent Successfully!");
    else
      Serial.println("Error Sending Message...");
  }
}

Output:

Entering Configuration Mode Successful!
Setting Baudrate Successful!
MCP2515 Initialized Successfully.
setup() done
 >

Conclusion: Canbus.sendMsgBuf is hanging.

Any suggestions? I am completely stuck.

Is your code from the old Seed-studio example?

If so download the latest coryjfowler library and example sketch from github and replace the old library.
If required, adjust the pin mappings to match your hardware.

If the sendMsgBuf problem persists edit the library mcp_can.cpp file and put some Serial.println messages into the sendMsgBuf and sendMsg functions to see how far it gets.

Thanks for the suggestion on editing the source; I hadn't realised you could do that.

So:

Canbus.sendMsgBuf(0x100, 8, data);

calls

INT8U MCP_CAN::sendMsgBuf(INT32U id, INT8U len, INT8U *buf)

which calls

INT8U MCP_CAN::sendMsg()

which calls

INT8U MCP_CAN::mcp2515_readRegister(const INT8U address)                                                                     
{
    INT8U ret;
	
    SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
    MCP2515_SELECT();
    spi_readwrite(MCP_READ);
	Serial.print("mcp2515_readRegister-4\r\n");
    spi_readwrite(address);
	Serial.print("mcp2515_readRegister-5\r\n");
    ret = spi_read();
    MCP2515_UNSELECT();
    SPI.endTransaction();

    return ret;
}

which hangs on

ret = spi_read();

And now the behaviour is changing according to where I add Serial.print!

prints

INT8U MCP_CAN::mcp2515_readRegister(const INT8U address)                                                                     
{
    INT8U ret;
	
    SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));
    MCP2515_SELECT();
    spi_readwrite(MCP_READ);
    //Serial.print(" spi_readwrite... ");
    spi_readwrite(address);
    //Serial.print(" OK\r\n");
	
    Serial.print(" spi_read... ");
    ret = spi_read(); // THIS hangs
    Serial.print(" OK\r\n");
    MCP2515_UNSELECT();
    SPI.endTransaction();

    return ret;
}

Output with code as shown

  spi_read...  OK
Entering Configuration Mode Successful! ------ 1
Setting Baudrate Successful!
 spi_read...  OK
MCP2515 Initialized Successfully. ------ 2
 spi_read...  OK
setup() done --------------------------------- 3
 >  spi_read...  OK ------------------------------ 4
 spi_read...  OK ------------------------------ 5
 > Message Sent Successfully!
 <

Output with the other two prints enabled

 spi_readwrite...  OK
 spi_read...  OK
Entering Configuration Mode Successful! ------ 1
Setting Baudrate Successful!
 spi_readwrite...  OK
 spi_read...  OK
MCP2515 Initialized Successfully. ------ 2
 spi_readwrite...  OK
 spi_read...  OK
setup() done --------------------------------- 3
 >  spi_readwrite...  OK
 spi_read...  OK ------------------------------ 4
 spi_readwrite...  OK
 spi_read...  ------------------------------ 4

And if I remove both sets of prints then

Entering Configuration Mode Successful!
Setting Baudrate Successful!
MCP2515 Initialized Successfully.
setup() done

So is serial somehow interfering with SPI?

I found this

which I do not understand, however it says something about not using pin 10 for INT.

Moved INT from pin 10 to pin 2 and now it's working!