CAN BUS Sheild V2.0 not working with Teensy 4.1

I am trying to use the CAN BUS Sheild V2.0 with a Teensy 4.1. I assumed that it would work fine, however I have not been able to get it working.
I have tried running the code below taken from the DF Robots CAN library examples.
I currently have the GND, 3v3 and 5v pins of the teensy connected to the respective pins on the CAN shield. Then I have the CS, MOSI, MISO and SCK on the CAN shield pins (10, 11, 12 and 13) connected to the teensy’s CS, MOSI, MISO and SCK pins (10, 11, 12 and 13), the teensy uses the same pins for these as the Arduino Uno.
When trying this the serial output on the teensy just says “DFROBOT’s CAN BUS Shield init fail”. I have tried not connecting the 5v pin so everything runs at 3v3 and I’ve also tried level shifting all the SPI pins to 5v with a logic converter. Also tried the CS going to 9 on the CAN shield as it is listed as 9 in some documents. Any help would be greatly apreciated :slight_smile:

 // demo: CAN-BUS Shield, send data
  #include <df_can.h>
  #include <SPI.h>

  const int SPI_CS_PIN = 10;

  MCPCAN CAN(SPI_CS_PIN);                                    // Set CS pin

  void setup()
  {
      Serial.begin(115200);
      int count = 50;                                     // the max numbers of initializint the CAN-BUS, if initialize failed first!.
      do {
          CAN.init();   //must initialize the Can interface here!
          if(CAN_OK == CAN.begin(CAN_500KBPS))                   // init can bus : baudrate = 500k
          {
              Serial.println("DFROBOT's CAN BUS Shield init ok!");
              break;
          }
          else
          {
              Serial.println("DFROBOT's CAN BUS Shield init fail");
              Serial.println("Please Init CAN BUS Shield again");

              delay(100);
              if (count <= 1)
                  Serial.println("Please give up trying!, trying is useless!");
          }

      }while(count--);

}

unsigned char data[8] = {'D', 'F', 'R', 'O', 'B', 'O', 'T', '!'};
void loop()
  {
      // send data:  id = 0x06, standrad flame, data len = 8, data: data buf
      CAN.sendMsgBuf(0x06, 0, 8, data);
      delay(100);                       // send data per 100ms
  }

4 Likes

Hi Hayden,

Hmm, odd. I’ve had a bit of a look at the library code and the Wiki page.

Just to check, do you have the power switch on the shield set to off?
image

Somewhat confusingly, it needs to be turned off in order to receive power from your Teensy (a better label would’ve been DB9 and 5V instead of ON and OFF). I can’t see it in your photo as it’s hidden by jumper cables.

The code compiles without even any warnings, so no issues there. FYI, here’s the relevant functions from the library, so it’s a bit clearer what the initialisation code in the setup() is doing.

image

It’s basically just doing SPI.begin(),then trying to reset the CAN Shield, then checking to see if it works.

3 Likes

The power switch is definetly set to off. Just tried it again with and without steping up the SPI pins still no luck it fails to initialise. I also just tried it with a teensy 4.0 I had lying around which also did not initialise.

3 Likes

Hi Hayden,

Do you have an Uno or Nano (328P based board) that you can test it out with to confirm the shield is working correctly?

Another possibility is that the Teensy’s SPI frequency is set to something incompatible with the CAN shield. There’s some good info here:
https://forum.pjrc.com/threads/57754-Teensy-4-0-SPI-Clock-Speed
https://www.pjrc.com/teensy/td_libs_SPI.html
http://www.gammon.com.au/forum/?id=10892

You may need to modify the library (particularly the SPI calls) for it to work correctly on your Teensy.

According to the datasheet, the chip on the CAN-BUS Shield is good for 10MHz:
image

3 Likes

I don’t have a Uno or Nano handy so I can’t test that unfortunatly.

I have tried altering the CAN library so it makes a call to startTransaction and endTransaction each time SPI is used see the below code. The settings are set to 10MHz and I tried SPI_MODE0, SPI_MODE1, SPI_MODE2, SPI_MODE3. The sheild is still failing to initialise

/*
  mcp_can.h
  2015 Copyright (c) DFROBOT Technology Inc.  All right reserved.

  Author:Jansion	
  Contributor:
  2015-5-25
  
*/

#include "df_can.h"

#define ReadWriteOneByte SPI.transfer
#define Read() SPI.transfer(0x00)

// SPI settings 10MHz 
SPISettings settings(10000000, MSBFIRST, SPI_MODE1);


void MCPCAN::mcp_reset(void)
{   
    SPI.beginTransaction(settings);
    MCPSPI_SELECT();
    ReadWriteOneByte(MCP_RESET);
    MCPSPI_UNSELECT();
    SPI.endTransaction();
    delay(10);
}


INT8U MCPCAN::mcp_readRegister(const INT8U RegAddr)                                                                     
{
    INT8U ret;
    SPI.beginTransaction(settings);
    MCPSPI_SELECT();
    ReadWriteOneByte(MCP_READ);
    ReadWriteOneByte(RegAddr);
    ret = Read();
    MCPSPI_UNSELECT();
    SPI.endTransaction();

    return ret;
}

void MCPCAN::mcp_readMulitiRegisters(const INT8U RegAddr, INT8U *buf, INT8U len)
{
	INT8U i;

	if ( len > CAN_MAX_MESSAGE_LENGTH)
	{
		len = CAN_MAX_MESSAGE_LENGTH;
	}

    SPI.beginTransaction(settings);
	MCPSPI_SELECT();
	ReadWriteOneByte(MCP_READ);
	ReadWriteOneByte(RegAddr);

	for (i=0; i < len; i++) {
		buf[i] = Read();
	}
	MCPSPI_UNSELECT();
    SPI.endTransaction();
}

 
void MCPCAN::mcp_setRegister(const INT8U RegAddr, const INT8U value)
{
    SPI.beginTransaction(settings);
    MCPSPI_SELECT();
    ReadWriteOneByte(MCP_WRITE);
    ReadWriteOneByte(RegAddr);
    ReadWriteOneByte(value);
    MCPSPI_UNSELECT();
    SPI.endTransaction();
}


void MCPCAN::mcp_setMulitRegisterS(const INT8U RegAddr, const INT8U *buf, const INT8U len)
{
    INT8U i;
    SPI.beginTransaction(settings);
    MCPSPI_SELECT();
    ReadWriteOneByte(MCP_WRITE);
    ReadWriteOneByte(RegAddr);
       
    for (i=0; i < len; i++) 
    {
        ReadWriteOneByte(buf[i]);
    }
    MCPSPI_UNSELECT();
    SPI.endTransaction();
}



void MCPCAN::mcp_modifyRegister(const INT8U RegAddr, const INT8U mask, const INT8U data)
{
    SPI.beginTransaction(settings);
    MCPSPI_SELECT();
    ReadWriteOneByte(MCP_BITMOD);
    ReadWriteOneByte(RegAddr);
    ReadWriteOneByte(mask);
    ReadWriteOneByte(data);
    MCPSPI_UNSELECT();
    SPI.endTransaction();
}

INT8U MCPCAN::mcp_readStatus(void)                             
{
	INT8U ret;
    SPI.beginTransaction(settings);
	MCPSPI_SELECT();
	ReadWriteOneByte(MCP_RX_STATUS);
	ret = Read();
	MCPSPI_UNSELECT();
    SPI.endTransaction();
	return ret;
}


INT8U MCPCAN::mcp_setMode(const INT8U newMode)
{
    INT8U ret;

    mcp_modifyRegister(MCPCANCTRL, MODE_MASK, newMode);
    ret = mcp_readRegister(MCPCANCTRL);
    ret &= MODE_MASK;

    if ( ret == newMode ) 
    {
        return MCP_OK;
    }

    return MCP_FAIL;

}

INT8U MCPCAN::mcp_configRate(const INT8U canSpeed)            
{
    INT8U preSet, cfg1, cfg2, cfg3;
	
    preSet = 0;
    switch (canSpeed) 
    {
        case (CAN_5KBPS):
        cfg1 = MCP_16MHz_5kBPS_CFG1;
        cfg2 = MCP_16MHz_5kBPS_CFG2;
        cfg3 = MCP_16MHz_5kBPS_CFG3;
        break;

        case (CAN_10KBPS):
        cfg1 = MCP_16MHz_10kBPS_CFG1;
        cfg2 = MCP_16MHz_10kBPS_CFG2;
        cfg3 = MCP_16MHz_10kBPS_CFG3;
        break;

        case (CAN_20KBPS):
        cfg1 = MCP_16MHz_20kBPS_CFG1;
        cfg2 = MCP_16MHz_20kBPS_CFG2;
        cfg3 = MCP_16MHz_20kBPS_CFG3;
        break;
        
        case (CAN_31K25BPS):
        cfg1 = MCP_16MHz_31k25BPS_CFG1;
        cfg2 = MCP_16MHz_31k25BPS_CFG2;
        cfg3 = MCP_16MHz_31k25BPS_CFG3;
        break;

        case (CAN_33KBPS):
        cfg1 = MCP_16MHz_33kBPS_CFG1;
        cfg2 = MCP_16MHz_33kBPS_CFG2;
        cfg3 = MCP_16MHz_33kBPS_CFG3;
        break;

        case (CAN_40KBPS):
        cfg1 = MCP_16MHz_40kBPS_CFG1;
        cfg2 = MCP_16MHz_40kBPS_CFG2;
        cfg3 = MCP_16MHz_40kBPS_CFG3;
        break;

        case (CAN_50KBPS):
        cfg1 = MCP_16MHz_50kBPS_CFG1;
        cfg2 = MCP_16MHz_50kBPS_CFG2;
        cfg3 = MCP_16MHz_50kBPS_CFG3;
        break;

        case (CAN_80KBPS):
        cfg1 = MCP_16MHz_80kBPS_CFG1;
        cfg2 = MCP_16MHz_80kBPS_CFG2;
        cfg3 = MCP_16MHz_80kBPS_CFG3;
        break;

        case (CAN_83K3BPS):
        cfg1 = MCP_16MHz_83k3BPS_CFG1;
        cfg2 = MCP_16MHz_83k3BPS_CFG2;
        cfg3 = MCP_16MHz_83k3BPS_CFG3;
        break;  

        case (CAN_95KBPS):
        cfg1 = MCP_16MHz_95kBPS_CFG1;
        cfg2 = MCP_16MHz_95kBPS_CFG2;
        cfg3 = MCP_16MHz_95kBPS_CFG3;
        break;

        case (CAN_100KBPS):                                           
        cfg1 = MCP_16MHz_100kBPS_CFG1;
        cfg2 = MCP_16MHz_100kBPS_CFG2;
        cfg3 = MCP_16MHz_100kBPS_CFG3;
        break;

        case (CAN_125KBPS):
        cfg1 = MCP_16MHz_125kBPS_CFG1;
        cfg2 = MCP_16MHz_125kBPS_CFG2;
        cfg3 = MCP_16MHz_125kBPS_CFG3;
        break;

        case (CAN_200KBPS):
        cfg1 = MCP_16MHz_200kBPS_CFG1;
        cfg2 = MCP_16MHz_200kBPS_CFG2;
        cfg3 = MCP_16MHz_200kBPS_CFG3;
        break;

        case (CAN_250KBPS):
        cfg1 = MCP_16MHz_250kBPS_CFG1;
        cfg2 = MCP_16MHz_250kBPS_CFG2;
        cfg3 = MCP_16MHz_250kBPS_CFG3;
        break;

        case (CAN_500KBPS):
        cfg1 = MCP_16MHz_500kBPS_CFG1;
        cfg2 = MCP_16MHz_500kBPS_CFG2;
        cfg3 = MCP_16MHz_500kBPS_CFG3;
        break;
        
        case (CAN_1000KBPS):
        cfg1 = MCP_16MHz_1000kBPS_CFG1;
        cfg2 = MCP_16MHz_1000kBPS_CFG2;
        cfg3 = MCP_16MHz_1000kBPS_CFG3;
        break;  

        default:
        preSet = 1;
        break;
    }

    if (!preSet) {
        mcp_setRegister(MCP_CNF1, cfg1);
        mcp_setRegister(MCP_CNF2, cfg2);
        mcp_setRegister(MCP_CNF3, cfg3);
        return MCP_OK;
    }
    else {
        return MCP_FAIL;
    }
}


void MCPCAN::mcp_initBuffers(void)
{
    INT8U i, a1, a2, a3;
 
    a1 = MCP_TXB0CTRL;
    a2 = MCP_TXB1CTRL;
    a3 = MCP_TXB2CTRL;
    for (i = 0; i < 14; i++) {                                        
        mcp_setRegister(a1, 0);
        mcp_setRegister(a2, 0);
        mcp_setRegister(a3, 0);
        a1++;
        a2++;
        a3++;
    }
    mcp_setRegister(MCP_RXB0CTRL, 0);
    mcp_setRegister(MCP_RXB1CTRL, 0);
}

INT8U MCPCAN::mcp_init(const INT8U canSpeed)                    
{

  INT8U res;

   
    res = mcp_setMode(MODE_CONFIG);
    if(res > 0)
    {
      delay(10);
      return res;
    }
	delay(10);


                                                                       
    if(mcp_configRate(canSpeed))
    {
	  delay(10);
      return res;
    }
	delay(10);


    if ( res == MCP_OK ) {

                                                                       
        mcp_initBuffers();

                                                                       
        mcp_setRegister(MCPCANINTE, MCP_RX0IF | MCP_RX1IF);

                                                                 
        mcp_modifyRegister(MCP_RXB0CTRL,
        MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK,
        MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK );
        mcp_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK,
        MCP_RXB_RX_STDEXT);
                                                                       
        res = mcp_setMode(MODE_NORMAL);                                                                
        if(res)
        {  
          delay(10);
          return res;
        }

        delay(10);

    }
    return res;

}


void MCPCAN::mcp_writeid( const INT8U mcp_addr, const INT8U ext, const INT32U id )
{
    uint16_t canid;
    INT8U tbufdata[4];

    canid = (uint16_t)(id & 0x0FFFF);

    if ( ext == 1) 
    {
        tbufdata[MCP_EID0] = (INT8U) (canid & 0xFF);
        tbufdata[MCP_EID8] = (INT8U) (canid >> 8);
        canid = (uint16_t)(id >> 16);
        tbufdata[MCP_SIDL] = (INT8U) (canid & 0x03);
        tbufdata[MCP_SIDL] += (INT8U) ((canid & 0x1C) << 3);
        tbufdata[MCP_SIDL] |= MCP_TXB_EXIDE_M;
        tbufdata[MCP_SIDH] = (INT8U) (canid >> 5 );
    }
    else 
    {
        tbufdata[MCP_SIDH] = (INT8U) (canid >> 3 );
        tbufdata[MCP_SIDL] = (INT8U) ((canid & 0x07 ) << 5);
        tbufdata[MCP_EID0] = 0;
        tbufdata[MCP_EID8] = 0;
    }
    mcp_setMulitRegisterS( mcp_addr, tbufdata, 4 );
}

void MCPCAN::mcp_readid( const INT8U mcp_addr, INT8U* ext, INT32U* id )
{
    INT8U id_Buf[4];

    mcp_readMulitiRegisters( mcp_addr, (INT8U *)id_Buf, 4 );

    *id = (id_Buf[MCP_SIDH]<< 3) + (id_Buf[MCP_SIDL]>>5);

    if ( (id_Buf[MCP_SIDL] & 1 << 3)) 
    {
                                                                       
        *id = (*id<<2) + (id_Buf[MCP_SIDL] & 0x03);
        *id = (*id<<8) + id_Buf[MCP_EID8];
        *id = (*id<<8) + id_Buf[MCP_EID0];
        *ext = 1;
    }
}

void MCPCAN::mcp_writecanMsg( const INT8U sidh_addr)
{
    INT8U mcp_addr;
    mcp_addr = sidh_addr;
    mcp_setMulitRegisterS(mcp_addr+5, can_Dta, can_Dlc );                 
    if ( can_Rtr == 1)                                                   
    {
        can_Dlc |= MCP_RTR_MASK;  
    }
    mcp_setRegister((mcp_addr+4), can_Dlc );                        
    mcp_writeid(mcp_addr, can_ExtFlg, can_ID );                     
}





void MCPCAN::mcp_readcanMsg( const INT8U idh_addr)        
{

    mcp_readid( idh_addr, &can_ExtFlg,&can_ID );   

    can_Rtr = mcp_readRegister( idh_addr - 1 );
    can_Dlc = mcp_readRegister( idh_addr + 4 );

    if ((can_Rtr & (1 << 3))) {
        can_Rtr = 1;
    }
    else {
        can_Rtr = 0;
    }

    can_Dlc &= MCP_DLC_MASK;
    mcp_readMulitiRegisters( idh_addr+5, (INT8U *)can_Dta, can_Dlc);
}

void MCPCAN::mcp_starttransmit(const INT8U mcp_addr)              
{
    mcp_modifyRegister( mcp_addr-1 , MCP_TXB_TXREQ_M, MCP_TXB_TXREQ_M );
}


INT8U MCPCAN::mcp_getNextFreeTXBuf(INT8U *txbuf_n)                 
{
    INT8U res, i, ctrlval;
    INT8U ctrlregs[MCP_N_TXBUFFERS] = { MCP_TXB0CTRL, MCP_TXB1CTRL, MCP_TXB2CTRL };

    res = MCP_ALLTXBUSY;
    *txbuf_n = 0x00;

                                                                       
    for (i=0; i < MCP_N_TXBUFFERS; i++) {
        ctrlval = mcp_readRegister( ctrlregs[i] );
        if ( (ctrlval & MCP_TXB_TXREQ_M) == 0 ) {
            *txbuf_n = ctrlregs[i]+1;                                   
                                                                        
            res = MCP_OK;
            return res;                                                 
        }
    }
    return res;
}




 

/*!
* @brief the MCPCAN class' constructor. 
*
* @parameter: 
		@_CS:
			indicate the spi select pin when mcu commication with the can controler e.i MCP2515
*
* @return void
*/ 



MCPCAN::MCPCAN(INT8U _CS)
{
   
    SPI_CS = _CS;
    pinMode(SPI_CS, OUTPUT);
	
    MCPSPI_UNSELECT();

}


/*!
* @brief: initialize the Can controler. 
*
* @parameter:  void
*
* @return void
*/ 

void MCPCAN::init(void)
{
	SPI.begin();
    mcp_reset();

}

/*!
* @brief: config the the Can baud rate,  buffer, and interrupt. 
*
* @parameter:  void
*
* @return if successful, it return CAN_OK, or CAN_FAILINIT
*/
INT8U MCPCAN::begin(INT8U speedset)
{
    INT8U res;
	
    res = mcp_init(speedset);
    if (res == MCP_OK) return CAN_OK;
    else return CAN_FAILINIT;
}



/*!
* @brief: initialize the mask register. 
*
* @parameter:  
		@Masker_num: 
			maybe set MCP_RXM0 or MCP_RXM1.
		@ext:
			extend flag. if ext = 1, indicate the frame is extended frame.
*
* @return the status. if success, return MCP_OK.
*/
INT8U MCPCAN::init_Mask(Masker_t Masker_num, INT8U ext, INT32U ulData)
{
    INT8U res = MCP_OK;  
	
	delay(10);
    res = mcp_setMode(MODE_CONFIG);
    if(res > 0){  
	delay(10);
    return res;
    }
    
    if (Masker_num == MCP_RXM0){
        mcp_writeid(MCP_RXM0SIDH, ext, ulData);

    }
    else if(Masker_num == MCP_RXM1){
        mcp_writeid(MCP_RXM1SIDH, ext, ulData);
    }
    else res =  MCP_FAIL;
    
    res = mcp_setMode(MODE_NORMAL);
    if(res > 0){

	delay(10);
    return res;
  }  
    delay(10);
    return res;
}


/*!
* @brief: initialize the fileter register. 
*
* @parameter:  
		@Masker_num: 
			maybe set MCP_RXF0, MCP_RXF1、 MCP_RXF2、 MCP_RXF3、 MCP_RXF4、 MCP_RXF5.
		@ext:
			extend flag. if ext = 1, indicate the frame is extended frame.
*
* @return the status. if success, return MCP_OK.
*/


INT8U MCPCAN::init_Filter(Filter_t Filter_num, INT8U ext, INT32U Data)
{
    INT8U res = MCP_OK;  
	delay(10);
	
    res = mcp_setMode(MODE_CONFIG);
	
    if(res > 0)
    {  
      delay(10);
      return res;
    }
    
    switch( Filter_num )
    {
        case MCP_RXF0:
	
        mcp_writeid(MCP_RXF0SIDH, ext, Data);
        break;

        case MCP_RXF1:
        mcp_writeid(MCP_RXF1SIDH, ext, Data);
        break;

        case MCP_RXF2:
        mcp_writeid(MCP_RXF2SIDH, ext, Data);
        break;

        case MCP_RXF3:
        mcp_writeid(MCP_RXF3SIDH, ext, Data);
        break;

        case MCP_RXF4:
        mcp_writeid(MCP_RXF4SIDH, ext, Data);
        break;

        case MCP_RXF5:
        mcp_writeid(MCP_RXF5SIDH, ext, Data);
        break;

        default:
        res = MCP_FAIL;
    }
    
    res = mcp_setMode(MODE_NORMAL);
    if(res > 0)
    {  
      delay(10);
      return res;
    }  
	
	delay(10);

    return res;
}





INT8U MCPCAN::setMsg(INT32U id, INT8U ext, INT8U len, INT8U rtr, INT8U *pData)
{
    int i = 0;
    can_ExtFlg = ext;
    can_ID     = id;
    can_Dlc    = len;
    can_Rtr    = rtr;
    for(i = 0; i < MAX_MESSAGE_LENGTH; i++)
    {
        can_Dta[i] = pData[i];
    }
    return MCP_OK;
}


INT8U MCPCAN::setMsg(INT32U id, INT8U ext, INT8U len, INT8U *pData)
{
    int i = 0;
    can_ExtFlg = ext;
    can_ID     = id;
    can_Dlc    = len;
    for(i = 0; i < MAX_MESSAGE_LENGTH; i++)
    {
        can_Dta[i] = *(pData+i);
    }
    return MCP_OK;
}

INT8U MCPCAN::clearMsg()
{

    can_ID       = 0;
    can_Rtr      = 0;
    can_ExtFlg   = 0;
    can_filhit   = 0;
    can_Dlc      = 0;
    for(int i = 0; i<can_Dlc; i++ )
      can_Dta[i] = 0x00;

    return MCP_OK;
}


INT8U MCPCAN::sendMsg()
{
    INT8U res, txindex;
    uint16_t uiTimeOut = 0;

    do {
        res = mcp_getNextFreeTXBuf(&txindex);                       
        uiTimeOut++;
    } while (res == MCP_ALLTXBUSY && (uiTimeOut < TIMEOUTVALUE));

    if(uiTimeOut == TIMEOUTVALUE) 
    {   
        return CAN_GETTXBFTIMEOUT;                                     
    }
    uiTimeOut = 0;
    mcp_writecanMsg( txindex);
    mcp_starttransmit( txindex );
    do
    {
        uiTimeOut++;        
        res = mcp_readRegister(txindex);  			                
        res = res & 0x08;                               		
    }while(res && (uiTimeOut < TIMEOUTVALUE));   
    if(uiTimeOut == TIMEOUTVALUE)                                       
    {
        return CAN_SENDMSGTIMEOUT;
    }
    return CAN_OK;

}

/*!
* @brief: send the remote requestion message. 
*
* @parameter:  
		@id: 
			the message id num. 
		@ext:
			extend flag. if ext = 1, indicate the frame is extended frame.
		@len:
			the len of the data to send.
		@rtr:
			the flag of the remote requestion. if rtr = 1, the frame seem as the remote requestion frame , or the frame is the normal data frame..
		@buf:
			the data to send.
			
*
* @return the status. if success, return MCP_OK.
*/

INT8U MCPCAN::sendMsgBuf(INT32U id, INT8U ext, INT8U rtr, INT8U len, INT8U *buf)
{
    setMsg(id, ext, len, rtr, buf);
    return sendMsg();
}



/*!
* @brief: send one data frame. 
*
* @parameter:  
		@id: 
			the message id num. 
		@ext:
			extend flag. if ext = 1, indicate the frame is extended frame.
		@len:
			the len of the data to send.
	
		@buf:
			the data to send.
			
*
* @return the status. if success, return MCP_OK.
*/

INT8U MCPCAN::sendMsgBuf(INT32U id, INT8U ext, INT8U len, INT8U *buf)
{
    setMsg(id, ext, len, buf);
    return sendMsg();
}


INT8U MCPCAN::readMsg()
{
    INT8U status, res;
   
	
    status = mcp_readStatus();
    
    if ( status & MCP_MESGE_RXB0_MSK )                        
    {
        mcp_readcanMsg( MCP_RXBUF_0);             //0x61
        mcp_modifyRegister(MCPCANINTF, MCP_RX0IF, 0);
        res = CAN_OK;
    }
    else if ( status & MCP_MESGE_RXB1_MSK )               //message in rx buf1                   
    {
        mcp_readcanMsg( MCP_RXBUF_1);
        mcp_modifyRegister(MCPCANINTF, MCP_RX1IF, 0);
        res = CAN_OK;
    }
    else if (status & MCP_MESGE_RXB01_MSK)
    {
        res = CAN_OK;
    }
	else
	{
		res = CAN_NOMSG;
	}
		
    return res;
}

/*!
* @brief: read one data frame from the cache in inner can controler. 
*
* @parameter:  
		
		@len:
			the len of the data to read.
	
		@buf:
			the data out from the Can controler store into the buf.
			
*
* @return the status. if success, return MCP_OK.
*/
INT8U MCPCAN::readMsgBuf(INT8U *len, INT8U *buf)
{
    INT8U  res, i;
    
    res= readMsg();
    
    if (res == CAN_OK) {
       *len = can_Dlc;
       for( i = 0; i<can_Dlc; i++) {
         buf[i] = can_Dta[i];
       } 
    } else {
       	 *len = 0;
    }
    return res;
}
/*!
* @brief: read one data frame from the cache in inner Can controler with the indicated ID, if Can controler has not cached the ID's Frame
	the return value is not CAN_OK.
*
* @parameter:  
		@ID:ID number.
		@len:
			the len of the data to read.
	
		@buf:
			the data out from the Can controler store into the buf.
			
*
* @return the status. if success, return MCP_OK. or this read operation is failed.
*/

INT8U MCPCAN::readMsgBufID(INT32U *ID, INT8U *len, INT8U *buf)
{
    INT8U ret;
	
    ret = readMsg();
    if (ret == CAN_OK) {
       *len = can_Dlc;
       *ID  = can_ID;
       for(int i = 0; i<can_Dlc && i < MAX_MESSAGE_LENGTH; i++) {
          buf[i] = can_Dta[i];
       }
    } else {
       *len = 0;
    }
    return ret;
}
/*!
* @brief: check whether data is cached by Can controler.
*
* @parameter:  
		@ID:ID number.
		@len:
			the len of the data to read.
	
		@buf:
			the data out from the Can controler store into the buf.
			
*
* @return: if there are some data received by Can controller. the return value is CAN_MSGAVAIL, or CAN_NOMSG.
*/

INT8U MCPCAN::checkReceive(void)
{
    INT8U res;
    res = mcp_readStatus();                                         
    if ( res & MCP_MESGE_NO_MSK ) 
    {
        return CAN_MSGAVAIL;
    }
    else 
    {
        return CAN_NOMSG;
    }
}


/*!
* @brief: check whether there is the control error on the Can bus line.
*
* @parameter:  void
			
*
* @return: if control error don't occur, return CAN_OK, or return CAN_CTRLERROR.
*/
INT8U MCPCAN::checkError(void)
{
    INT8U flag = mcp_readRegister(MCP_EFLG);

    if ( flag & MCP_EFLG_ERRORMASK ) 
    {
        return CAN_CTRLERROR;
    }
    else 
    {
        return CAN_OK;
    }
}

/*!
* @brief: get the id of the data cached in Can controller currently.
*
* @parameter: void 
			
*
* @return: return the id number.
*/

INT32U MCPCAN::getCanId(void)
{
    return can_ID;
} 

/*!
* @brief: tell whether the current data frame buffered in Can controller is remote requestion frame.
*
* @parameter: void 
			
*
* @return: return the id number.
*/
INT8U MCPCAN::isRemoteRequest(void)
{
    return can_Rtr;
} 
/*!
* @brief: tell whether the current data frame buffered in Can controller is extended frame.
*
* @parameter: void 
			
*
* @return: return the id number.
*/
INT8U MCPCAN::isExtendedFrame(void)
{
    return can_ExtFlg;
} 

I also tried using I2C instead I beleive this is supported, I couldn’t find a DFRobot library for this so I used this one Logan Labs I2C CAN Library which is designed for the same CAN IC’s. The initialisation worked for this however no can messages were transmitted. Error message 2 is being output which stands for CAN_FAILTX.

/*  send a frame from can bus
    support@longan-labs.cc
    
    CAN Baudrate,
    
    #define CAN_5KBPS           1
    #define CAN_10KBPS          2
    #define CAN_20KBPS          3
    #define CAN_25KBPS          4 
    #define CAN_31K25BPS        5
    #define CAN_33KBPS          6
    #define CAN_40KBPS          7
    #define CAN_50KBPS          8
    #define CAN_80KBPS          9
    #define CAN_83K3BPS         10
    #define CAN_95KBPS          11
    #define CAN_100KBPS         12
    #define CAN_125KBPS         13
    #define CAN_200KBPS         14
    #define CAN_250KBPS         15
    #define CAN_500KBPS         16
    #define CAN_666KBPS         17
    #define CAN_1000KBPS        18
*/
   
#include <Wire.h>

#include "Longan_I2C_CAN_Arduino.h"


I2C_CAN CAN(10);                                    // Set CS pin

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

    while (CAN_OK != CAN.begin(CAN_500KBPS))    // init can bus : baudrate = 500k
    {
        Serial.println("CAN BUS FAIL!");
        delay(100);
    }
    Serial.println("CAN BUS OK!");
}

unsigned char stmp[8] = {1, 2, 3, 4, 5, 6, 7, 0};
int cnt = 0;

void loop()
{
    stmp[7] = cnt++;
    if(cnt > 100)cnt = 0;
    
    Serial.println(CAN.sendMsgBuf(0x01, 0, 8, stmp));
    delay(5);                       // send data per 100ms
}

// END FILE
2 Likes

A logic analyser and/or a multi-channel scope would be really handy here. Have you tried slowing down the SPI bus to something like 200kHz? Flipping the CAN BUS shield around so your SPI connections are much closer to your Teensy could help too.

Here’s a good Hackaday article on SPI troubleshooting:

The Core engineers did a good video on the impact of connections and wiring on high frequency circuits and signal attenuation:

The MPC2515 doesn’t support I2C. I looked up the Longan board - looks they’re using an Atmel ATMega168P to interface between SPI and I2C. TheDFRobot shield doesn’t have this, so I’m not sure how it would actually work. It seems they’ve based their library on Seeed studio’s library, so probably the board design too.

Seeed just include the I2C and UART on the PCB with Grove connectors as a nicety, to make it easier to connect other products from their ecosystem, but they don’t appear to actually have any relationship with the MCP2515? I don’t have a board though, so I can’t check.

Something else you might be running into trouble with is the SD Card, as that’s also on the SPI Bus (The CS for this is on Pin 4). It’d be worth connecting up this pin too, to make sure it’s not floating and make sure you don’t have an SD card in the SD card slot.

The 74HC4050 shown on the datasheet is just astraight logic level shifter (shifts 5v logic of the Uno to 3.3v for SD card communication).

Which reminds me, you should stick to logic level shifting your signals to 5v. The Uno is a 5v logic device, so it’s probably safest to keep your signals into the can-shield at the voltage it was designed for.

In fact - here’s the schematic:

This confirms the I2C and UART interfaces aren’t connected, and you require the following connections (at 5V Logic) to make it work:
+5V
GND
MISO (Pin 12)
MOSI (Pin 11)
SCK (Pin 13)
CS (Pin 10)
INT(Pin 2)

Also note that the Oscillator is only 16MHz - they would need to have used a 20MHz (or faster) oscillator to obtain the maximum of 10MHz - so it’s very unlikely to work at that speed.

4 Likes