Faster MCP2515 Interface using I/O - Embedded Micro Software [emicros.com]

Embedded Micro Software [emicros.com]
Title
Go to content

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

CAN2USB : $100

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 Using I/O
In the last episode I reduced the SPI interface time between the XIAO ESP32C3 and the MCP2515 Controller Area Network IC. The time to send a CAN message using the "mcp_can" library was around 350 microseconds and the reduced time was down to aroung 34 microseconds. This is to speed up the interface between the Seeed Development XIAO ESP32C3 module and the MicroChip MCP2515 Controller Area Network (CAN) interface IC that is used in the CanWiser Lite module or you can use with your interface to the MCP2515.

Using the I/O on the MCP2515 the CAN message send time is reduced further from 34 microseconds to 22 microseconds and the read CAN message function is introduced reducing the original read time from 124 to 50 microseconds.

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 and in part 2 the function was developed.

When I laid out the CanWiser Lite board there were 5 unused I/O pins on the Seeed Development XIAO ESP32C3 module. Just by chance I decided to connect the 3 TXnRTS and 2 RXnBF pins on the MCP2515 device to the XIAO. The 3 TXnRTS signal (n=0,1,2) are input signals when toggled low tells the MCP2515 to transmit that particular transmit buffer. The 2 RXnBF (n=0,1) indicates if the receive buffer is full.

These signals are used to further reduce the SPI transmission times.



mcp_can Library Update

In order to use the MCP2515 hardware signals the mcp_can library needs to be changed from general purpose I/O pins. In the mcp_can.cpp file in the mcp2515_init() function the statements shown to the right are changed.

//Sets BF pins as GPO
//mcp2515_setRegister(MCP_BFPCTRL,MCP_BxBFS_MASK | MCP_BxBFE_MASK);
mcp2515_setRegister(MCP_BFPCTRL,MCP_BxBFS_MASK | MCP_BxBFE_MASK | MCP_BxBFM_MASK);
//Sets RTS pins as GPI
//mcp2515_setRegister(MCP_TXRTSCTRL,0x00);
mcp2515_setRegister(MCP_TXRTSCTRL,MCP_RTS_ALL);


The XIAO pins are #defined in the first part of the file.
#define USE_CANWISER_ADDON
//#define USE_CANWISER_HWIO

#ifdef USE_CANWISER_ADDON
 #ifdef USE_CANWISER_HWIO
   #define TX0RTS   D7
   #define TX1RTS   D1
   #define TX2RTS   D2
   #define RX0INT   D3
   #define RX1INT   D4
 #endif
 #include "CanwiserLite.hpp"
 CanWiserLite canwiser(CAN0_CS); // Set CS to pin 6
#endif
In the setup() function the TXnRTS pins are configured as outputs and the RXnINT pins are configured as inputs. The TXnRTS pins are set HIGH also.
#ifdef USE_CANWISER_HWIO
 pinMode( TX0RTS, OUTPUT );
 pinMode( TX1RTS, OUTPUT );
 pinMode( TX2RTS, OUTPUT );
 pinMode( RX0INT, INPUT );
 pinMode( RX1INT, INPUT );
 digitalWrite( TX0RTS, HIGH );
 digitalWrite( TX1RTS, HIGH );
 digitalWrite( TX2RTS, HIGH );
 #endif
In the sendCanMessage() function in CanwiserLite.hpp file instead of sending the CAN message via SPI writing to the register the hardware signal is set low and then HIGH again to initiate the transmission.

// request to send
   #ifndef USE_CANWISER_HWIO
 writeCanRegister( txnum, 0x0c );
   #else
   if( tx == 0 )
   {
 digitalWrite( TX0RTS, LOW );
 digitalWrite( TX0RTS, LOW );
 digitalWrite( TX0RTS, HIGH );
   }
   else if( tx == 1 )
   {
 digitalWrite( TX1RTS, LOW );
 digitalWrite( TX1RTS, LOW );
 digitalWrite( TX1RTS, HIGH );
   }
   else if( tx == 2 )
   {
 digitalWrite( TX2RTS, LOW );
 digitalWrite( TX2RTS, LOW );
 digitalWrite( TX2RTS, HIGH );
   }
   #endif
This reduced the CAN message send time on the CanWiser Lite down to 22 microseconds.





Now let's focus on receiving CAN messages. The MCP_CAN::readMsgBuf() functions takes around 124 microseconds to read the receive buffer.



The readCanData() function shown to the right reduces the read CAN buffer time to 50 microseconds.




void readCanData( uint8_t *buffer, uint8_t len )
{
   #ifndef CANWISER_USEHWIO
   uint8_t stat = readStatus();
   if( stat & MCP_STAT_RX0IF )
   #else
   if( digitalRead( RX0INT ) == LOW )
   #endif
   {
  SPI.beginTransaction(SPISettings(SPI_RATE, MSBFIRST, SPI_MODE0));
  SELECT();
  SPI.transfer(MCP_READ);
  SPI.transfer(MCP_RXBUF_0);
  SPI.transferBytes( NULL, buffer, len );
  UNSELECT();
  SPI.endTransaction();

     SPI.beginTransaction(SPISettings(SPI_RATE, MSBFIRST, SPI_MODE0));
     SELECT();
     SPI.transfer(MCP_BITMOD);
     SPI.transfer(MCP_CANINTF);
     SPI.transfer(MCP_RX0IF);
     SPI.transfer(0);
     UNSELECT();
     SPI.endTransaction();
   }
   #ifndef CANWISER_USEHWIO
   else if( stat & MCP_STAT_RX1IF )
   #else
   if( digitalRead( RX1INT ) == LOW )
   #endif
   {
     SPI.beginTransaction(SPISettings(SPI_RATE, MSBFIRST, SPI_MODE0));
     SELECT();
     SPI.transfer(MCP_READ);
     SPI.transfer(MCP_RXBUF_1);
     SPI.transferBytes( NULL, buffer, len );
     UNSELECT();
     SPI.endTransaction();

     SPI.beginTransaction(SPISettings(SPI_RATE, MSBFIRST, SPI_MODE0));
     SELECT();
     SPI.transfer(MCP_BITMOD);
     SPI.transfer(MCP_CANINTF);
     SPI.transfer(MCP_RX1IF);
     SPI.transfer(0);
     UNSELECT();
     SPI.endTransaction();
   }
 }


Here's the links to the software....
Files last updated 3/18/2023

Thanks for your interest! This is Ron from emicros.com.







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