Faster MCP2515 Interface - Part 1 - Embedded Micro Software []

Embedded Micro Software []
Go to content

.: Order using our PayPal powered shopping cart (PayPal account not required).

CAN2USB : $100

BareCAN : $80

CAN232 : $100
I2C232 : $90

U.S. Shipping Addresses Only.
Sorry we do not ship Internationally.

View Online Shopping Cart

Faster MCP2515 Interface - Part 1

In this project we're adding a few functions to speed up the interface to the MCP2515 Controller Area Network (CAN) IC from Microchip. This is part 1 of a 2 part series.

In the last episode I laid out and had built for me the CanWiser Lite module which uses the Seeed Development XIAO ESP32C3 module connected to a MicroChip MCP2515 CAN IC. When I started writing software for it using the "mcp_can" library I realized that some new functions could be added to speed up the communications via the SPI channel.

This project details the faster functions.

The board I had built and assembled had a couple of defects. I forgot the pull up resistor on the reset line and also found out the ESP32C3 doesn't like 5 volt inputs. So I redid the board adding a pullup resistor and changed the MCP2515 voltage from 5 volts to 3.3 volts. It worked!
Now let's get to the software.

Start with a new sketch and add a timer highlighted in yellow.

Next add the timer code to the setup() function.

// timerInterrupt to run every 100 microseconds
// Use 1st timer of 4 (counted from zero).
// Set 80 divider for prescaler (see ESP32 Technical Reference Manual for more
// info).
timer = timerBegin(0, 80, true);

// Attach onTimer function to our timer.
timerAttachInterrupt(timer, &onTimer, true);

// Set alarm to call onTimer function every .1 milliseconds (value in microseconds).
// Repeat the alarm (third )
timerAlarmWrite(timer, 100, true);

timerAlarmEnable( timer );
And then add the timer interrupt ISR function before the setup() function.

uint8_t timer1ms;
volatile uint8_t timer1msTriggered;

void ARDUINO_ISR_ATTR onTimer( void )
 // ----------------------------------------------------
 // 1 millisecond timer count
 // ----------------------------------------------------
 if( timer1ms >= 10 )
    timer1ms = 0;
    timer1msTriggered = true;

Notice in the onTimer() function the timer1ms counter is incremented until it reaches 10, then reset to 0, and a 1 millisecond flag is set. This is used in the loop() function as a scheduler.

In the loop() function the 1 millisecond flag is checked and if set it is reset to false and for now the LED pin is toggled.

Using a scope there appears to be "something" causing the 1 millisecond timer to be held off.
I'm not sure what causes this but if the loop() function is prevented from returning with a for loop the issue goes away.

Now we'll add the mcp_can library. The interface to the MCP2515 uses the SPI so both the mcp_can.h and SPI.h header files are included. The chip select pin for talking to the MCP2515 is D6 and the "interrupt" pin is D5. The MCP_CAN class is used and we use it as Can0. The following is added to the beginning of the file.

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

#define CAN0_INT D5   // Set INT to pin 5
#define CAN0_CS  D6
MCP_CAN Can0(CAN0_CS);     // Set CS to pin 6

Next we add the following to the setup() function. Notice that the serial channel has been added as well.

 while(!Serial) { }
 /* Setup SPI access */
 SPI.setClockDivider( SPI_CLOCK_DIV2 );
 pinMode(CAN0_INT, INPUT);
 // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
 if(Can0.begin(MCP_ANY, CAN_500KBPS, MCP_8MHZ) == CAN_OK) Serial.println("MCP2515 Initialized Successfully!");
 else Serial.println("Error Initializing MCP2515...");


In the loop() function when the 1 millisecond timer triggers a CAN message is sent using the Can0.sendMsgBuf() function. The LED is set high before this function is executed and then set low afterwards so we can use a scope plot to measure how long this function takes.

for(;; )
 if( timer1msTriggered == true )
   timer1msTriggered = false;
   uint8_t data[] = {1,2,3,4,5,6,7,8};
   digitalWrite( LED, HIGH );
   byte sndStat = Can0.sendMsgBuf(0x23, 0, 8, data);
   digitalWrite( LED, LOW );

From the scope plot the time to send a CAN message using the mcp_can library is 360 microseconds. This is fine of course but I challenged myself to improve on this which will be discussed in Part 2. Stay tuned and thanks for showing an interest in this!

Embedded Micro Software
Created by Ron
Send us an email.
Back to content