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 2
In this part 2 of the project the following functions to speed up the interface between the Seeed Development XIAO ESP32C3 module and the MicroChip MCP2515 Controller Area Network (CAN) interface IC. In part 1 I laid out the basis of the challenge to myself to reduce the time it takes to talk to the MCP2515 IC via SPI.
I created the CanWiserLite class that has 2 private variables and 6 public functions.
Private Variables
INT8U CWCS; // Chip Select pin number
const uint8_t ctrl[3] = {MCP_TXB0CTRL, MCP_TXB1CTRL, MCP_TXB2CTRL};
Public Functions
CanWiserLite(uint8_t _CS)
uint8_t readStatus(void)
void readCanData( uint8_t *buffer, uint8_t len )
void writeCanData( uint8_t addr, uint8_t *buffer, uint8_t len )
void writeCanRegister( uint8_t addr, uint8_t data )
void sendCanMessage( uint8_t tx, const uint8_t ext, const uint32_t id, uint8_t *buffer, uint8_t len)
The constructor CanWiserLite() is called with the chip select pin as the argument. This sets the pin as an output and sets it high.
CanWiserLite(uint8_t _CS)
{
CWCS = _CS;
UNSELECT();
pinMode(CWCS, OUTPUT);
}
SELECT() and UNSELECT() are #defines and just set the chip select pin HIGH or LOW.
#define UNSELECT() digitalWrite( CWCS, HIGH )
#define SELECT() digitalWrite( CWCS, LOW )
Add the class to your main program and make sure you have the CanwiserLite.hpp file.
#include "CanwiserLite.hpp"
#define CAN0_CS D6
CanWiserLite canwiser(CAN0_CS); // Set CS to pin 6
Since there a 3 transmit buffers in the MCP2515 we use this to our advantage to speed up the CAN message send function.
The arguments for the sendCanMessage() method are;
uint8_t tx; // This is one of the 3 transmit buffers 0,1, or 2
const uint8_t ext; // 0=standard or 1=extended ID
const uint32_2 id; // CAN messaage ID
uint8_t *buffer; // pointer to where the message data is
uint8_t len; // message length
The code highlighted in green converts the CAN ID into the correct register format.
The code highlighted in yellow set the DLC and copies the CAN message data.
The last bit of code copies the local data structure into the appropriate MCP2515 transmit buffer and the last statement tells the MCP2515 to transmit the message.
void sendCanMessage( uint8_t tx, const uint8_t ext, const uint32_t id, uint8_t *buffer, uint8_t len)
{
cms canMessage;
uint16_t canid;
uint8_t txnum = ctrl[tx];
canid = (uint16_t)(id & 0x0FFFF);
if ( ext == 1)
{
canMessage.id[MCP_EID0] = (INT8U) (canid & 0xFF);
canMessage.id[MCP_EID8] = (INT8U) (canid >> 8);
canid = (uint16_t)(id >> 16);
canMessage.id[MCP_SIDL] = (INT8U) (canid & 0x03);
canMessage.id[MCP_SIDL] += (INT8U) ((canid & 0x1C) << 3);
canMessage.id[MCP_SIDL] |= MCP_TXB_EXIDE_M;
canMessage.id[MCP_SIDH] = (INT8U) (canid >> 5 );
}
else
{
canMessage.id[MCP_SIDH] = (INT8U) (canid >> 3 );
canMessage.id[MCP_SIDL] = (INT8U) ((canid & 0x07 ) << 5);
canMessage.id[MCP_EID0] = 0;
canMessage.id[MCP_EID8] = 0;
}
canMessage.dlc = len;
for( uint8_t x=0; x<len; x++ )
{
canMessage.d[x] = buffer[x];
}
writeCanData( txnum+1, (uint8_t *)&canMessage, len+5 );
// request to send
writeCanRegister( txnum, 0x0c );
}
Now if we go to the loop() function in our program and comment out the Can0.sendMsgBuf() and add the canwiser.sendCanMessaage() statement we go from it taking around 350 microseconds to 36 microseconds a HUGE difference.
void loop() {
pinMode( LED, OUTPUT );
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);
canwiser.sendCanMessage( 0, 0, 0x23, &data[0], 8 );
digitalWrite( LED, LOW );
}
}
}
The first scope plot shows the faster function taking 34 microseconds and the second plot is the original. This is a good start now in the next episode I'll add a couple of tweaks I have in mind using the hardware signals from the MCP2515. Thanks for your interest.