In this blog post, we explain how to test CAN bus communication between two ESP32 PLC 14 units using the CAN SPI 5V click module and Arduino IDE.
Hardware setup: connecting the CAN SPI click
The ESP32 PLC 14 has one additional communication slot compatible with the CAN SPI click. Connect the H and L pins between the two units. A two-wire connection works, but a 3-point CAN bus cable is recommended for better signal integrity.
Software setup: libraries and pin definitions
Install the industrialshields-esp32 board on the Arduino IDE: go to Tools > Board > Boards Manager and search for "industrialshields-esp32". Then select Tools > Board > Industrial Shields ESP32 > 14 IOS PLC Family.
Download and install the MCP_CAN library: Sketch > Include Library > Add .ZIP Library. The library is available at github.com/coryjfowler/MCP_CAN_lib.
Create a defs.h file inside a new folder in your Arduino Libraries folder, paste the following definitions, and restart the Arduino IDE.
#include "MCP23017.h" #define In0 11 #define In1 10 #define In2 12 #define In3 13 #define In4 4 #define In5 6 #define In6 5 #define S0_24v 15 #define S1_24v 14 #define S2_24v 1 #define S3_24v 0 #define Relay 7 #define PWM_click 9 #define INT_click 8 #define INTA 13 // Expander interrupt #define Out0 32 #define Out1 25 #define Out2 26 #define Out3 27 #define CS0 14 // Ethernet #define CS1 4 // Click #define A0420 32 // Analog 4..20mA #define A1420 33 #define A0010 34 // Analog 0..10v #define A1010 35 #define pwrPin 2 #define resetPin 3 #define INT_click 8 #define PWM_click 9 #define INTA 13 // Expander interrupt #define CS0 14 // Ethernet #define CS1 4 // Click #define UART1 0x78 #define Bit0 0x00 // MCP I2C CONFIG const uint8_t sda = 21; const uint8_t scl = 22; uint8_t mcp_i2c_address = 0x20; MCP23017 mcp(mcp_i2c_address);
CAN send sketch
Upload the following sketch to the sender ESP32 PLC 14:
#include "defs.h"
#include "Wire.h"
#include <mcp_can.h>
MCP_CAN CAN0(CS1);
byte data[8] = {0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07};
void setup() {
Serial.begin(115200UL);
delay(1000);
pinMode(CS1, OUTPUT);
delay(100);
digitalWrite(CS1, LOW);
delay(1000);
if (!mcp.begin(sda, scl)) {
Serial.print(-1);
while (1);
}
delay(1000);
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);
}
void loop() {
uint8_t sndStat = CAN0.sendMsgBuf(0x111, 0, 8, data);
if (sndStat == CAN_OK) {
Serial.println("Message sent successfully!");
} else {
Serial.println("Error sending message...");
}
delay(3000);
}
CAN receive sketch
Upload the following sketch to the receiver ESP32 PLC 14:
#include "defs.h"
#include "Wire.h"
#include <mcp_can.h>
MCP_CAN CAN0(CS1);
long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128];
void setup() {
Serial.begin(115200UL);
delay(1000);
pinMode(CS1, OUTPUT);
delay(100);
digitalWrite(CS1, LOW);
delay(1000);
if (!mcp.begin(sda, scl)) {
Serial.print(-1);
while (1);
}
delay(1000);
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);
}
void loop() {
CAN0.readMsgBuf(&rxId, &len, rxBuf);
if ((rxId & 0x80000000) == 0x80000000)
sprintf(msgString, "Extended ID: 0x%.8lX DLC: %1d Data:", (rxId & 0x1FFFFFFF), len);
else
sprintf(msgString, "Standard ID: 0x%.3lX DLC: %1d Data:", rxId, len);
Serial.print(msgString);
if ((rxId & 0x40000000) == 0x40000000) {
sprintf(msgString, " REMOTE REQUEST FRAME");
Serial.print(msgString);
} else {
for (byte i = 0; i < len; i++) {
sprintf(msgString, " 0x%.2X", rxBuf[i]);
Serial.print(msgString);
}
}
Serial.println();
delay(500);
}
Once both sketches are running on separate ESP32 PLC 14 units, open the Serial Monitor on the receiver to confirm that CAN messages are arriving correctly.

Testing CAN/SPI communication on the ESP32 PLC 14