Two SPI Networks - Different Modes For Devices

Hi there,

I am currently working on a project that has two SPI devices. One is a CAN controller and the other is an A/D. My idea is to read two thermocouples from a ADS1118 and send the data out on CAN via a MCP2515. Separately, they both work fine (as in – separate test programs). However, I am struggling to get them to work in the same block of code due to the SPI modes being different for each of the devices. So:

A/D: ADS1118 – SPI mode 1 (from the data sheet).

CAN: MCP2515 – SPI mode 0 or 3 (from the data sheet).

I am setting up the ADS1118 as a normal SPI device – as in:

SPISettings thermocouple(500000, MSBFIRST, SPI_MODE1);

However, I’m using a library to drive the CAN (from Seeed Technology Inc):

#include <mcp_can.h>

Is there a way I can keep changing the SPI mode before I talk to each device? A bit like having two RS232 circuits? As in calling the ‘SPISettings’ line of code? I’ve looked through the #include <mcp_can.h> file and its associated files but I can’t see anything in there that appears to set the SPI up so I’ve not been able to try it (perhaps it uses ‘bit banging?). I’m only calling the CAN device once to send out the data:

CAN0.sendMsgBuf(0x610, 0, 8, stmp);

Any help would be much appreciated – I’m sure that someone else must have come across this issue before. Ultimately, I have no issue with the actual code – it’s calling the SPI functions at different intervals to alter the SPI mode that I’m struggling with.

Here's the code:


// software calculates internal and external temperatures
// further deatils are listed withing the code


#include <mcp_can.h> // used for sending the data out on the can bus
#include <SPI.h> // used for the communication between the can module and the ads1118

const int csThermocouple = 7; // set cs to pin 7 for the ads1118 board
MCP_CAN CAN0(6); // Set cs to pin 6 for the can board

// mcp2515 has a spi mode of 0 (cpol = 0, cpha = 0) or mode 3 (cpol = 1, cpha = 1)
// this is different from the ads1118 - which is purely mode 1

// can frame data configuration - note - the dyno uses 'little endian':
//      16 bits          16 bits          16 bits
//    lsb     msb      lsb     msb      lsb     msb
//     0       1   :    2       3    :   4       5    :   6       7
//    ch0     ch0  :   ch1     ch1   :  int     int   :  n/a     n/a

// note - in the can software display as a decimal so we can read it easier (well for positive values anyway)

// mapping locations:     
// location / input         1  2  3  4  5  6  7  8
// array value              0  1  2  3  4  5  6  7
// unsigned char stmp[8] = {0, 0, 0, 0, 0, 0, 0, 0};


// set up the speed, data order and data mode

// SPISettings mySettting(speedMaximum, dataOrder, dataMode)

// speedMaximum: up to 5000000

// dataOrder: MSBFIRST or LSBFIRST

// dataMode : SPI_MODE0, SPI_MODE1, SPI_MODE2, or SPI_MODE3:

// Mode       Clock Polarity  Clock Phase  Output Edge  Data Capture
// SPI_MODE0  0               0            Falling      Rising
// SPI_MODE1  0               1            Rising       Falling // correct for the ads1118 - see datasheet page 28
// SPI_MODE2  1               0            Rising       Falling
// SPI_MODE3  1               1            Falling      Rising

SPISettings thermocouple(500000, MSBFIRST, SPI_MODE1); // spi configuration for the ads1118

// config register set ups - only need three main ones - two for external and one for internal temperature

// channel 0 internal temperature
unsigned int configInt = 0x8fdb; // 1 000 111 1 110 1 1 01 1     0.256v, power-down and single-shot mode, pull ups enabled, port 0, 8sps, internal temperature
//unsigned int configInt = 0x8fdb; // 1 000 111 1 110 1 1 01 1     0.256v, power-down and single-shot mode, pull ups enabled, port 0, 8sps, internal temperature

// channel 0 external temperature
//unsigned int configCh0 = 0x8fc3; // 1 000 111 1 110 0 1 01 1     0.256v, power-down and single-shot mode, pull ups enabled, port 0, 8sps, external temperature
unsigned int configCh0 = 0x8fcb; // 1 000 111 1 110 0 1 01 1     0.256v, power-down and single-shot mode, pull ups enabled, port 0, 8sps, external temperature

// channel 1 external temperature
//unsigned int configCh1 = 0xbfc3; // 1 011 111 0 110 0 1 01 1     0.256v, power-down and single-shot mode, pull ups enabled, port 1, 8sps, external temperature
unsigned int configCh1 = 0xbfcb; // 1 011 111 0 110 0 1 01 1     0.256v, power-down and single-shot mode, pull ups enabled, port 1, 8sps, external temperature

boolean entryFlag = false; // entry flat set by timer interrupt

int intTemperature = 0; // internal temperature
int ch0Temperature = 0; // ch0 temperature
int ch1Temperature = 0; // ch1 temperature

float intTemperatureFloat = 0; // internal temperature
float ch0TemperatureFloat = 0; // ch0 temperature
float ch1TemperatureFloat = 0; // ch1 temperature

float intVoltage = 0; // internal temperature voltage

float ch0Voltage = 0; // ch0 voltage
float ch0TotalVoltage = 0; // internal and ch0 voltage

float ch1Voltage = 0; // ch1 voltage
float ch1TotalVoltage = 0; // internal and ch1 voltage

unsigned char stmp[8] = {0, 0, 0, 0, 0, 0, 0, 0}; // used for the can frame data


void setup()
{

  Serial.begin(9600); // set up the serial monitor for debugging

  SPI.begin(); // kick start the spi

  // baudrate 500k and crystal 8mhz (see header file)
  if(CAN0.begin(CAN_500KBPS, MCP_8MHz) == CAN_OK) Serial.print("can init ok!!\r\n");
  else Serial.print("Can init fail!!\r\n");

 
  // chip select as an output
  pinMode (csThermocouple, OUTPUT);
  
  // 16 bit register - hence the large tcnt1 value (approx half of 65536)
  TCCR1A = 0; // clear timer / counter control register a
  TCCR1B = 0; // clear timer / counter control register b 

  // transpose the formaula to give us hz to calculate the preload - several options available:
  //TCNT1 = 3036; // preload timer = 65536-16MHz/256/1Hz - must load that value int a and b
  //TCNT1 = 34286; // preload timer = 65536-16MHz/256/2Hz - must load that value int a and b
  //TCNT1 = 49911; // preload timer = 65536-16MHz/256/4Hz - must load that value int a and b
  TCNT1 = 57724; // preload timer = 65536-16MHz/256/8Hz - must load that value int a and b
  
  TCCR1B |= (1 << CS12); // 256 prescaler - see above calculation
  TIMSK1 |= (1 << TOIE1); // enable timer overflow interrupt

/*

  // send internal temperature config to get things started
  SPI.beginTransaction(thermocouple);
  //SPI.beginTransaction();

  digitalWrite (csThermocouple, LOW); // activate
    
  SPI.transfer16(configInt);
    
  digitalWrite (csThermocouple, HIGH); // deactivate 
    
  SPI.endTransaction(); // all done
 
 */
}


ISR(TIMER1_OVF_vect)
{
  // check out tcnt in the data sheet
  TCNT1 = 57724; // 8hz / 125ms
     
  entryFlag = 1; // set the entry flag
}


void loop()
{

  // wait here until the overflow has been triggered
  if(entryFlag == 1)
  {

    entryFlag = 0; // clear the entry flag
 
    // get int data and send ch0 config
    int intSpiData = dataTransmission(configCh0);

    // * * * shifting the bits bt 2 here * * *
    intSpiData = intSpiData >> 2; // shift accross by 2 - we are only usng 14 bits

    // function to convert spi data into a int data
    //int intData = convertData(intSpiData);
    float intData = convertData(intSpiData);


    delay(15); // small delay between next read


    // next get the ch0 data and send out ch1 config
    int ch0SpiData = dataTransmission(configCh1);
   

    // function to convert spi data into a ext data
    int ch0Data = convertData(ch0SpiData);


   delay(15); // small delay between next read


    // next get the ch1 data and send out int config
    int ch1SpiData = dataTransmission(configInt); // correct - reads back the internal temperature


    // function to convert spi data into a ext data
    int ch1Data = convertData(ch1SpiData);


    delay(15); // small delay between next read


    // * * * calculations and displaying results - perhaps use a function(s) for part of this * * *

    // Convert internal data into a tempertature - >>2 has been done after spi function - see above
    //intSpiData = intSpiData >> 2; // shift accross by 2 - we are only usng 14 bits
    intData = intData * 0.03125; // one 14 bit lsb = 0.03125 degrees so multiply intData for temperature
    intTemperatureFloat = intData; // load value into intTemperature for display )keep intData for conversion below)


    // function to calculate the external temperature from the internal and external thermocouple voltages
    ch0TemperatureFloat = calculateExtTemperature(intData, ch0Data);


    delay(15); // small delay between next read


    // function to calculate the external temperature from the internal and external thermocouple voltages
    ch1TemperatureFloat = calculateExtTemperature(intData, ch1Data);


    delay(15); // small delay between next read


    // print the three calculated temperatures (dp)
    Serial.print("  Int: ");
    Serial.print(intTemperatureFloat);
    
    Serial.print("  Ch0: ");
    Serial.print(ch0TemperatureFloat);
    
    Serial.print("  Ch1: ");
    Serial.print(ch1TemperatureFloat);

    intTemperature = intTemperatureFloat;
    ch0Temperature = ch0TemperatureFloat;
    ch1Temperature = ch1TemperatureFloat;

/*
    // print the three calculated temperatures (dp)
    Serial.print("Int Temperature: ");
    Serial.println(intTemperatureFloat);
    
    Serial.print("Ch0 Temperature: ");
    Serial.println(ch0TemperatureFloat);
    
    Serial.print("Ch1 Temperature: ");
    Serial.println(ch1TemperatureFloat);

    intTemperature = intTemperatureFloat;
    ch0Temperature = ch0TemperatureFloat;
    ch1Temperature = ch1TemperatureFloat;



    // can data ready (no dp)
    Serial.print("Int Temperature: ");
    Serial.println(intTemperature);
    
    Serial.print("Ch0 Temperature: ");
    Serial.println(ch0Temperature);
    
    Serial.print("Ch1 Temperature: ");
    Serial.println(ch1Temperature);

*/

    Serial.println(); // apply a space between each readout

    //stmp[7] = analogRead(input5); // read the voltage on the potentiometer

    // lnow send out the data on can - note - the dyno uses 'little endian':
    stmp[0] = intTemperature;
    stmp[1] = intTemperature >> 8;

    stmp[2] = ch0Temperature;
    stmp[3] = ch0Temperature >> 8;
    
    stmp[4] = ch1Temperature;
    stmp[5] = ch1Temperature >> 8;



    // send data:  id = 0x610, standrad flame, data len = 8, stmp: data buf
    CAN0.sendMsgBuf(0x610, 0, 8, stmp);
    
  } // end of entry loop

} // end void loop


// * * functions * * *

int dataTransmission(int thermocoupleConfig)
{

    int returnData = 0;
  
    SPI.beginTransaction(thermocouple);
    //SPI.beginTransaction();

    digitalWrite (csThermocouple, LOW); // activate
    
    returnData = SPI.transfer16(thermocoupleConfig); // send out new config / get previous config temperature data
    
    digitalWrite (csThermocouple, HIGH); // deactivate 
    
    SPI.endTransaction(); // all done
    
    return returnData; // sent the data back for calculation

}


int convertData(int thermocoupleData)
{
    //float returnConvertedData = 0;
    int returnConvertedData = 0;

    //float positiveThermocoupleData = 0;
    int positiveThermocoupleData = 0;

    
    // Bit-14 is the sign - copy the 13 bits accross from 'thermocoupleData' and delete the 14th bit
    positiveThermocoupleData = (thermocoupleData & 0x00001FFF);
 
      // Check for negative temperature using the original thermocoupleData that still holds the 14th bit
      if (thermocoupleData & 0x00002000) // 10 0000 0000 0000
      {

        // 2's complement operation -> invert
        thermocoupleData = ~thermocoupleData;
        
        // Ensure operation involves lower 13-bit only
        positiveThermocoupleData = thermocoupleData & 0x00001FFF;
      
        // Add 1 to obtain the positive number
        //thermocoupleTemperature += 1;
        positiveThermocoupleData = positiveThermocoupleData + 1;
      
        // Make temperature negative
        //thermocoupleTemperature *= -1;
        positiveThermocoupleData = positiveThermocoupleData * -1;
      
      }
      
      returnConvertedData = positiveThermocoupleData; // load value for return
      
      return returnConvertedData; // to load into the can frame (no decimal place - see int)

}


float calculateExtTemperature(int intData, int extData)
{
    float intVoltage = 0;

    float extVoltage = 0;

    float totalVoltage = 0;

    float extTemperature = 0;
    
    intVoltage = intData * 41e-6; // 41xe-6 is he best conversion figure available for the non linear scale
                                  // eg: 20 degrees * 41e-6 = 0.82mv (0.798mv on the k type conversion table)


    //extVoltage = float(7.82e-6 * extData); // not sure if the float makes a difference?
    extVoltage = (7.82e-6 * extData); // convert adc reading to a voltage - fsr = 256mv, 15 bits = 32767/6
                                      // 256mv / 32767 = 7.82e-6
                                      
    totalVoltage = intVoltage + extVoltage; // add the hot and cold junction voltages together
    extTemperature = totalVoltage / 41e-6; // now convert to a temperature

    return extTemperature; // return calculated temperature for displa / can frame
}

With just a quick look, it seems like it should work as is. All SPI operations by the mcp_can library are preceded by 'SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));' and all SPI accesses in main .ino file are preceded by 'SPI.beginTransaction(thermocouple);'.

What problem are you having? If were my project, I'd slap a logic analyzer on the SPI bus and see what's actually going on.

FWIW, SPI_MODE0 is probably considered more "normal" than SPI_MODE1.

Hi gfvalvo,

Thank you so much for your reply - the problem is now solved.

I looked for the line of code you posted:

SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));

And I couldn't find it? Perhaps I looked in the wrong file? Or - maybe I just need to declare it as a matter of fact? Either way I placed it before my CAN frame send command and all is fine:

    SPI.beginTransaction(SPISettings(10000000, MSBFIRST, SPI_MODE0));

    // send data:  id = 0x610, standrad flame, data len = 8, stmp: data buf
    CAN0.sendMsgBuf(0x610, 0, 8, stmp);

Which is exactly what I was after - thanks!

Post a GitHub link to the mcp_can library you're using. The SPI usage is correct Here and several other places in the same file.

Ah, mine is fairly old - I have just looked at the same section and the line of code isn't there - apologies for the whole mcp_can.cpp file but here we go:


/*
  mcp_can.cpp
  2012 Copyright (c) Seeed Technology Inc.  All right reserved.

  Author:Loovee
  Contributor: Cory J. Fowler
  2014-1-16
  This library is free software; you can redistribute it and/or
  modify it under the terms of the GNU Lesser General Public
  License as published by the Free Software Foundation; either
  version 2.1 of the License, or (at your option) any later version.

  This library is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  Lesser General Public License for more details.

  You should have received a copy of the GNU Lesser General Public
  License along with this library; if not, write to the Free Software
  Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-
  1301  USA
  */
#include "mcp_can.h"

#define spi_readwrite SPI.transfer
#define spi_read() spi_readwrite(0x00)

/*********************************************************************************************************
** Function name:           mcp2515_reset
** Descriptions:            reset the device
*********************************************************************************************************/
void MCP_CAN::mcp2515_reset(void)
{
	MCP2515_SELECT();
	spi_readwrite(MCP_RESET);
	MCP2515_UNSELECT();
	delay(10);
}

/*********************************************************************************************************
** Function name:           mcp2515_readRegister
** Descriptions:            read register
*********************************************************************************************************/
INT8U MCP_CAN::mcp2515_readRegister(const INT8U address)
{
	INT8U ret;

	MCP2515_SELECT();
	spi_readwrite(MCP_READ);
	spi_readwrite(address);
	ret = spi_read();
	MCP2515_UNSELECT();

	return ret;
}

/*********************************************************************************************************
** Function name:           mcp2515_readRegisterS
** Descriptions:            read registerS
*********************************************************************************************************/
void MCP_CAN::mcp2515_readRegisterS(const INT8U address, INT8U values[], const INT8U n)
{
	INT8U i;
	MCP2515_SELECT();
	spi_readwrite(MCP_READ);
	spi_readwrite(address);
	// mcp2515 has auto-increment of address-pointer
	for (i = 0; i < n; i++)
	{
		values[i] = spi_read();
	}
	MCP2515_UNSELECT();
}

/*********************************************************************************************************
** Function name:           mcp2515_setRegister
** Descriptions:            set register
*********************************************************************************************************/
void MCP_CAN::mcp2515_setRegister(const INT8U address, const INT8U value)
{
	MCP2515_SELECT();
	spi_readwrite(MCP_WRITE);
	spi_readwrite(address);
	spi_readwrite(value);
	MCP2515_UNSELECT();
}

/*********************************************************************************************************
** Function name:           mcp2515_setRegisterS
** Descriptions:            set registerS
*********************************************************************************************************/
void MCP_CAN::mcp2515_setRegisterS(const INT8U address, const INT8U values[], const INT8U n)
{
	INT8U i;
	MCP2515_SELECT();
	spi_readwrite(MCP_WRITE);
	spi_readwrite(address);

	for (i = 0; i < n; i++)
	{
		spi_readwrite(values[i]);
	}
	MCP2515_UNSELECT();
}

/*********************************************************************************************************
** Function name:           mcp2515_modifyRegister
** Descriptions:            set bit of one register
*********************************************************************************************************/
void MCP_CAN::mcp2515_modifyRegister(const INT8U address, const INT8U mask, const INT8U data)
{
	MCP2515_SELECT();
	spi_readwrite(MCP_BITMOD);
	spi_readwrite(address);
	spi_readwrite(mask);
	spi_readwrite(data);
	MCP2515_UNSELECT();
}

/*********************************************************************************************************
** Function name:           mcp2515_readStatus
** Descriptions:            read mcp2515's Status
*********************************************************************************************************/
INT8U MCP_CAN::mcp2515_readStatus(void)
{
	INT8U i;
	MCP2515_SELECT();
	spi_readwrite(MCP_READ_STATUS);
	i = spi_read();
	MCP2515_UNSELECT();

	return i;
}

/*********************************************************************************************************
** Function name:           mcp2515_setCANCTRL_Mode
** Descriptions:            set control mode
*********************************************************************************************************/
INT8U MCP_CAN::mcp2515_setCANCTRL_Mode(const INT8U newmode)
{
	INT8U i;

	mcp2515_modifyRegister(MCP_CANCTRL, MODE_MASK, newmode);

	i = mcp2515_readRegister(MCP_CANCTRL);
	i &= MODE_MASK;

	if (i == newmode)
	{
		return MCP2515_OK;
	}

	return MCP2515_FAIL;

}

/*********************************************************************************************************
** Function name:           mcp2515_configRate
** Descriptions:            set boadrate
*********************************************************************************************************/
INT8U MCP_CAN::mcp2515_configRate(const INT8U canSpeed, const INT8U clock)
{
	INT8U set, cfg1, cfg2, cfg3;
	set = 1;
	switch (clock)
	{
		case (MCP_16MHz) :
			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_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_100KBPS) :                                             /* 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:
					set = 0;
					break;
			}
			break;

		case (MCP_8MHz) :
			switch (canSpeed)
			{
				case (CAN_5KBPS) :
					cfg1 = MCP_8MHz_5kBPS_CFG1;
					cfg2 = MCP_8MHz_5kBPS_CFG2;
					cfg3 = MCP_8MHz_5kBPS_CFG3;
					break;

				case (CAN_10KBPS) :
					cfg1 = MCP_8MHz_10kBPS_CFG1;
					cfg2 = MCP_8MHz_10kBPS_CFG2;
					cfg3 = MCP_8MHz_10kBPS_CFG3;
					break;

				case (CAN_20KBPS) :
					cfg1 = MCP_8MHz_20kBPS_CFG1;
					cfg2 = MCP_8MHz_20kBPS_CFG2;
					cfg3 = MCP_8MHz_20kBPS_CFG3;
					break;

				case (CAN_31K25BPS) :
					cfg1 = MCP_8MHz_31k25BPS_CFG1;
					cfg2 = MCP_8MHz_31k25BPS_CFG2;
					cfg3 = MCP_8MHz_31k25BPS_CFG3;
					break;

				case (CAN_40KBPS) :
					cfg1 = MCP_8MHz_40kBPS_CFG1;
					cfg2 = MCP_8MHz_40kBPS_CFG2;
					cfg3 = MCP_8MHz_40kBPS_CFG3;
					break;

				case (CAN_50KBPS) :
					cfg1 = MCP_8MHz_50kBPS_CFG1;
					cfg2 = MCP_8MHz_50kBPS_CFG2;
					cfg3 = MCP_8MHz_50kBPS_CFG3;
					break;

				case (CAN_80KBPS) :
					cfg1 = MCP_8MHz_80kBPS_CFG1;
					cfg2 = MCP_8MHz_80kBPS_CFG2;
					cfg3 = MCP_8MHz_80kBPS_CFG3;
					break;

				case (CAN_100KBPS) :                                             /* 100KBPS                  */
					cfg1 = MCP_8MHz_100kBPS_CFG1;
					cfg2 = MCP_8MHz_100kBPS_CFG2;
					cfg3 = MCP_8MHz_100kBPS_CFG3;
					break;

				case (CAN_125KBPS) :
					cfg1 = MCP_8MHz_125kBPS_CFG1;
					cfg2 = MCP_8MHz_125kBPS_CFG2;
					cfg3 = MCP_8MHz_125kBPS_CFG3;
					break;

				case (CAN_200KBPS) :
					cfg1 = MCP_8MHz_200kBPS_CFG1;
					cfg2 = MCP_8MHz_200kBPS_CFG2;
					cfg3 = MCP_8MHz_200kBPS_CFG3;
					break;

				case (CAN_250KBPS) :
					cfg1 = MCP_8MHz_250kBPS_CFG1;
					cfg2 = MCP_8MHz_250kBPS_CFG2;
					cfg3 = MCP_8MHz_250kBPS_CFG3;
					break;

				case (CAN_500KBPS) :
					cfg1 = MCP_8MHz_500kBPS_CFG1;
					cfg2 = MCP_8MHz_500kBPS_CFG2;
					cfg3 = MCP_8MHz_500kBPS_CFG3;
					break;

				case (CAN_1000KBPS) :
					cfg1 = MCP_8MHz_1000kBPS_CFG1;
					cfg2 = MCP_8MHz_1000kBPS_CFG2;
					cfg3 = MCP_8MHz_1000kBPS_CFG3;
					break;

				default:
					set = 0;
					break;
			}
			break;

		default:
			set = 0;
			break;
	}

	if (set) {
		mcp2515_setRegister(MCP_CNF1, cfg1);
		mcp2515_setRegister(MCP_CNF2, cfg2);
		mcp2515_setRegister(MCP_CNF3, cfg3);
		return MCP2515_OK;
	}
	else {
		return MCP2515_FAIL;
	}
}

/*********************************************************************************************************
** Function name:           mcp2515_initCANBuffers
** Descriptions:            init canbuffers
*********************************************************************************************************/
void MCP_CAN::mcp2515_initCANBuffers(void)
{
	INT8U i, a1, a2, a3;

	INT8U std = 0;
	INT8U ext = 1;
	INT32U ulMask = 0x00, ulFilt = 0x00;


	mcp2515_write_id(MCP_RXM0SIDH, ext, ulMask);			/*Set both masks to 0           */
	mcp2515_write_id(MCP_RXM1SIDH, ext, ulMask);			/*Mask register ignores ext bit */

	/* Set all filters to 0         */
	mcp2515_write_id(MCP_RXF0SIDH, ext, ulFilt);			/* RXB0: extended               */
	mcp2515_write_id(MCP_RXF1SIDH, std, ulFilt);			/* RXB1: standard               */
	mcp2515_write_id(MCP_RXF2SIDH, ext, ulFilt);			/* RXB2: extended               */
	mcp2515_write_id(MCP_RXF3SIDH, std, ulFilt);			/* RXB3: standard               */
	mcp2515_write_id(MCP_RXF4SIDH, ext, ulFilt);
	mcp2515_write_id(MCP_RXF5SIDH, std, ulFilt);

	/* Clear, deactivate the three  */
	/* transmit buffers             */
	/* TXBnCTRL -> TXBnD7           */
	a1 = MCP_TXB0CTRL;
	a2 = MCP_TXB1CTRL;
	a3 = MCP_TXB2CTRL;
	for (i = 0; i < 14; i++) {                                          /* in-buffer loop               */
		mcp2515_setRegister(a1, 0);
		mcp2515_setRegister(a2, 0);
		mcp2515_setRegister(a3, 0);
		a1++;
		a2++;
		a3++;
	}
	mcp2515_setRegister(MCP_RXB0CTRL, 0);
	mcp2515_setRegister(MCP_RXB1CTRL, 0);
}

/*********************************************************************************************************
** Function name:           mcp2515_init
** Descriptions:            init the device
*********************************************************************************************************/
INT8U MCP_CAN::mcp2515_init(const INT8U canSpeed, const INT8U clock)                       /* mcp2515init                  */
{

	INT8U res;

	mcp2515_reset();

	res = mcp2515_setCANCTRL_Mode(MODE_CONFIG);
	if (res > 0)
	{
#if DEBUG_MODE
		Serial.print("Enter setting mode fall\r\n");
#endif
		return res;
	}
#if DEBUG_MODE
	Serial.print("Enter setting mode success \r\n");
#endif

	/* set boadrate                 */
	if (mcp2515_configRate(canSpeed, clock))
	{
#if DEBUG_MODE
		Serial.print("set rate fall!!\r\n");
#endif
		return res;
	}
#if DEBUG_MODE
	Serial.print("set rate success!!\r\n");
#endif

	if (res == MCP2515_OK) {

		/* init canbuffers              */
		mcp2515_initCANBuffers();

		/* interrupt mode               */
		mcp2515_setRegister(MCP_CANINTE, MCP_RX0IF | MCP_RX1IF);

#if (DEBUG_RXANY==1)
		/* enable both receive-buffers  */
		/* to receive any message       */
		/* and enable rollover          */
		mcp2515_modifyRegister(MCP_RXB0CTRL,
			MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK,
			MCP_RXB_RX_ANY | MCP_RXB_BUKT_MASK);
		mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK,
			MCP_RXB_RX_ANY);
#else
		/* enable both receive-buffers  */
		/* to receive messages          */
		/* with std. and ext. identifie */
		/* rs                           */
		/* and enable rollover          */
		mcp2515_modifyRegister(MCP_RXB0CTRL,
			MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK,
			MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK);
		mcp2515_modifyRegister(MCP_RXB1CTRL, MCP_RXB_RX_MASK,
			MCP_RXB_RX_STDEXT);
#endif
		/* enter normal mode            */
		res = mcp2515_setCANCTRL_Mode(MODE_NORMAL);
		if (res)
		{
#if DEBUG_MODE        
			Serial.print("Enter Normal Mode Fall!!\r\n");
#endif           
			return res;
		}


#if DEBUG_MODE
		Serial.print("Enter Normal Mode Success!!\r\n");
#endif

	}
	return res;

}

/*********************************************************************************************************
** Function name:           mcp2515_write_id
** Descriptions:            write can id
*********************************************************************************************************/
void MCP_CAN::mcp2515_write_id(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;
	}
	mcp2515_setRegisterS(mcp_addr, tbufdata, 4);
}

/*********************************************************************************************************
** Function name:           mcp2515_read_id
** Descriptions:            read can id
*********************************************************************************************************/
void MCP_CAN::mcp2515_read_id(const INT8U mcp_addr, INT8U* ext, INT32U* id)
{
	INT8U tbufdata[4];

	*ext = 0;
	*id = 0;

	mcp2515_readRegisterS(mcp_addr, tbufdata, 4);

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

	if ((tbufdata[MCP_SIDL] & MCP_TXB_EXIDE_M) == MCP_TXB_EXIDE_M)
	{
		/* extended id                  */
		*id = (*id << 2) + (tbufdata[MCP_SIDL] & 0x03);
		*id = (*id << 8) + tbufdata[MCP_EID8];
		*id = (*id << 8) + tbufdata[MCP_EID0];
		*ext = 1;
	}
}

/*********************************************************************************************************
** Function name:           mcp2515_write_canMsg
** Descriptions:            write msg
*********************************************************************************************************/
void MCP_CAN::mcp2515_write_canMsg(const INT8U buffer_sidh_addr)
{
	INT8U mcp_addr;
	mcp_addr = buffer_sidh_addr;
	mcp2515_setRegisterS(mcp_addr + 5, m_nDta, m_nDlc);                  /* write data bytes             */
	if (m_nRtr == 1)                                                   /* if RTR set bit in byte       */
	{
		m_nDlc |= MCP_RTR_MASK;
	}
	mcp2515_setRegister((mcp_addr + 4), m_nDlc);                        /* write the RTR and DLC        */
	mcp2515_write_id(mcp_addr, m_nExtFlg, m_nID);                     /* write CAN id                 */

}

/*********************************************************************************************************
** Function name:           mcp2515_read_canMsg
** Descriptions:            read message
*********************************************************************************************************/
void MCP_CAN::mcp2515_read_canMsg(const INT8U buffer_sidh_addr)        /* read can msg                 */
{
	INT8U mcp_addr, ctrl;

	mcp_addr = buffer_sidh_addr;

	mcp2515_read_id(mcp_addr, &m_nExtFlg, &m_nID);

	ctrl = mcp2515_readRegister(mcp_addr - 1);
	m_nDlc = mcp2515_readRegister(mcp_addr + 4);

	if ((ctrl & 0x08)) {
		m_nRtr = 1;
	}
	else {
		m_nRtr = 0;
	}

	m_nDlc &= MCP_DLC_MASK;
	mcp2515_readRegisterS(mcp_addr + 5, &(m_nDta[0]), m_nDlc);
}

/*********************************************************************************************************
** Function name:           sendMsg
** Descriptions:            send message
*********************************************************************************************************/
void MCP_CAN::mcp2515_start_transmit(const INT8U mcp_addr)              /* start transmit               */
{
	mcp2515_modifyRegister(mcp_addr - 1, MCP_TXB_TXREQ_M, MCP_TXB_TXREQ_M);
}

/*********************************************************************************************************
** Function name:           sendMsg
** Descriptions:            send message
*********************************************************************************************************/
INT8U MCP_CAN::mcp2515_getNextFreeTXBuf(INT8U *txbuf_n)                 /* get Next free txbuf          */
{
	INT8U res, i, ctrlval;
	INT8U ctrlregs[MCP_N_TXBUFFERS] = { MCP_TXB0CTRL, MCP_TXB1CTRL, MCP_TXB2CTRL };

	res = MCP_ALLTXBUSY;
	*txbuf_n = 0x00;

	/* check all 3 TX-Buffers       */
	for (i = 0; i < MCP_N_TXBUFFERS; i++) {
		ctrlval = mcp2515_readRegister(ctrlregs[i]);
		if ((ctrlval & MCP_TXB_TXREQ_M) == 0) {
			*txbuf_n = ctrlregs[i] + 1;                                   /* return SIDH-address of Buffe */
			/* r                            */
			res = MCP2515_OK;
			return res;                                                 /* ! function exit              */
		}
	}
	return res;
}

/*********************************************************************************************************
** Function name:           set CS
** Descriptions:            init CS pin and set UNSELECTED
*********************************************************************************************************/
MCP_CAN::MCP_CAN(INT8U _CS)
{
	SPICS = _CS;
	pinMode(SPICS, OUTPUT);
	MCP2515_UNSELECT();
}

/*********************************************************************************************************
** Function name:           init
** Descriptions:            init can and set speed
*********************************************************************************************************/
INT8U MCP_CAN::begin(INT8U speedset, const INT8U clockset)
{
	INT8U res;

	SPI.begin();
	res = mcp2515_init(speedset, clockset);
	if (res == MCP2515_OK) return CAN_OK;
	else return CAN_FAILINIT;
}

/*********************************************************************************************************
** Function name:           init_Mask
** Descriptions:            init canid Masks
*********************************************************************************************************/
INT8U MCP_CAN::init_Mask(INT8U num, INT8U ext, INT32U ulData)
{
	INT8U res = MCP2515_OK;
#if DEBUG_MODE
	Serial.print("Begin to set Mask!!\r\n");
#endif
	res = mcp2515_setCANCTRL_Mode(MODE_CONFIG);
	if (res > 0){
#if DEBUG_MODE
		Serial.print("Enter setting mode fall\r\n");
#endif
		return res;
	}

	if (num == 0){
		mcp2515_write_id(MCP_RXM0SIDH, ext, ulData);

	}
	else if (num == 1){
		mcp2515_write_id(MCP_RXM1SIDH, ext, ulData);
	}
	else res = MCP2515_FAIL;

	res = mcp2515_setCANCTRL_Mode(MODE_NORMAL);
	if (res > 0){
#if DEBUG_MODE
		Serial.print("Enter normal mode fall\r\n");
#endif
		return res;
	}
#if DEBUG_MODE
	Serial.print("set Mask success!!\r\n");
#endif
	return res;
}

/*********************************************************************************************************
** Function name:           init_Filt
** Descriptions:            init canid filters
*********************************************************************************************************/
INT8U MCP_CAN::init_Filt(INT8U num, INT8U ext, INT32U ulData)
{
	INT8U res = MCP2515_OK;
#if DEBUG_MODE
	Serial.print("Begin to set Filter!!\r\n");
#endif
	res = mcp2515_setCANCTRL_Mode(MODE_CONFIG);
	if (res > 0)
	{
#if DEBUG_MODE
		Serial.print("Enter setting mode fall\r\n");
#endif
		return res;
	}

	switch (num)
	{
	case 0:
		mcp2515_write_id(MCP_RXF0SIDH, ext, ulData);
		break;

	case 1:
		mcp2515_write_id(MCP_RXF1SIDH, ext, ulData);
		break;

	case 2:
		mcp2515_write_id(MCP_RXF2SIDH, ext, ulData);
		break;

	case 3:
		mcp2515_write_id(MCP_RXF3SIDH, ext, ulData);
		break;

	case 4:
		mcp2515_write_id(MCP_RXF4SIDH, ext, ulData);
		break;

	case 5:
		mcp2515_write_id(MCP_RXF5SIDH, ext, ulData);
		break;

	default:
		res = MCP2515_FAIL;
	}

	res = mcp2515_setCANCTRL_Mode(MODE_NORMAL);
	if (res > 0)
	{
#if DEBUG_MODE
		Serial.print("Enter normal mode fall\r\nSet filter fail!!\r\n");
#endif
		return res;
	}
#if DEBUG_MODE
	Serial.print("set Filter success!!\r\n");
#endif

	return res;
}

/*********************************************************************************************************
** Function name:           setMsg
** Descriptions:            set can message, such as dlc, id, dta[] and so on
*********************************************************************************************************/
INT8U MCP_CAN::setMsg(INT32U id, INT8U ext, INT8U len, INT8U *pData)
{
	int i = 0;
	m_nExtFlg = ext;
	m_nID = id;
	m_nDlc = len;
	for (i = 0; i < MAX_CHAR_IN_MESSAGE; i++)
		m_nDta[i] = *(pData + i);
	return MCP2515_OK;
}

/*********************************************************************************************************
** Function name:           clearMsg
** Descriptions:            set all message to zero
*********************************************************************************************************/
INT8U MCP_CAN::clearMsg()
{
	m_nID = 0;
	m_nDlc = 0;
	m_nExtFlg = 0;
	m_nRtr = 0;
	m_nfilhit = 0;
	for (int i = 0; i < m_nDlc; i++)
		m_nDta[i] = 0x00;

	return MCP2515_OK;
}

/*********************************************************************************************************
** Function name:           sendMsg
** Descriptions:            send message
*********************************************************************************************************/
INT8U MCP_CAN::sendMsg()
{
	INT8U res, res1, txbuf_n;
	uint16_t uiTimeOut = 0;

	do {
		res = mcp2515_getNextFreeTXBuf(&txbuf_n);                       /* info = addr.                 */
		uiTimeOut++;
	} while (res == MCP_ALLTXBUSY && (uiTimeOut < TIMEOUTVALUE));

	if (uiTimeOut == TIMEOUTVALUE)
	{
		return CAN_GETTXBFTIMEOUT;                                      /* get tx buff time out         */
	}
	uiTimeOut = 0;
	mcp2515_write_canMsg(txbuf_n);
	mcp2515_start_transmit(txbuf_n);
	do
	{
		uiTimeOut++;
		res1 = mcp2515_readRegister(txbuf_n);  			                /* read send buff ctrl reg 	*/
		res1 = res1 & 0x08;
	} while (res1 && (uiTimeOut < TIMEOUTVALUE));
	if (uiTimeOut == TIMEOUTVALUE)                                       /* send msg timeout             */
	{
		return CAN_SENDMSGTIMEOUT;
	}
	return CAN_OK;

}

/*********************************************************************************************************
** Function name:           sendMsgBuf
** Descriptions:            send buf
*********************************************************************************************************/
INT8U MCP_CAN::sendMsgBuf(INT32U id, INT8U ext, INT8U len, INT8U *buf)
{
	setMsg(id, ext, len, buf);
	sendMsg();
}

/*********************************************************************************************************
** Function name:           readMsg
** Descriptions:            read message
*********************************************************************************************************/
INT8U MCP_CAN::readMsg()
{
	INT8U stat, res;

	stat = mcp2515_readStatus();

	if (stat & MCP_STAT_RX0IF)                                        /* Msg in Buffer 0              */
	{
		mcp2515_read_canMsg(MCP_RXBUF_0);
		mcp2515_modifyRegister(MCP_CANINTF, MCP_RX0IF, 0);
		res = CAN_OK;
	}
	else if (stat & MCP_STAT_RX1IF)                                   /* Msg in Buffer 1              */
	{
		mcp2515_read_canMsg(MCP_RXBUF_1);
		mcp2515_modifyRegister(MCP_CANINTF, MCP_RX1IF, 0);
		res = CAN_OK;
	}
	else
	{
		res = CAN_NOMSG;
	}
	return res;
}

/*********************************************************************************************************
** Function name:           readMsgBuf
** Descriptions:            read message buf
*********************************************************************************************************/
INT8U MCP_CAN::readMsgBuf(INT8U *len, INT8U buf[])
{
	readMsg();
	*len = m_nDlc;
	for (int i = 0; i < m_nDlc; i++)
	{
		buf[i] = m_nDta[i];
	}
}

/*********************************************************************************************************
** Function name:           checkReceive
** Descriptions:            check if got something
*********************************************************************************************************/
INT8U MCP_CAN::checkReceive(void)
{
	INT8U res;
	res = mcp2515_readStatus();                                         /* RXnIF in Bit 1 and 0         */
	if (res & MCP_STAT_RXIF_MASK)
	{
		return CAN_MSGAVAIL;
	}
	else
	{
		return CAN_NOMSG;
	}
}

/*********************************************************************************************************
** Function name:           checkError
** Descriptions:            if something error
*********************************************************************************************************/
INT8U MCP_CAN::checkError(void)
{
	INT8U eflg = mcp2515_readRegister(MCP_EFLG);

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

/*********************************************************************************************************
** Function name:           getCanId
** Descriptions:            when receive something ,u can get the can id!!
*********************************************************************************************************/
INT32U MCP_CAN::getCanId(void)
{
	return m_nID;
}
/*********************************************************************************************************
  END FILE
  *********************************************************************************************************/

Perhaps I should have updated the file - but it worked just fine when I downloaded some time ago.

Personally, I'd update the whole library from the GitHub. But if you're OK with the way it works after adding the hack ... it is your project.

I agree with you gfvalvo - I will update - I just didn't realise it would cause an issue using an older version that worked prior to this project.

Appreciate your help - update required - thanks.