CanWiser Lite : $25

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
// ----------------------------------------------------
timer1ms++;
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.
Serial.begin(115200);
while(!Serial) { }
/* Setup SPI access */
SPI.begin();
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...");
Can0.setMode(MCP_NORMAL);
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!
