MCP2515 using coryjfowler library on ESP32

Hi.
I have self made circuit board for reading data from CAN buses in my car.
It's based on ESP32. I'm using two CAN interfaces on this board.
First, built in ESP32, is using to obtain data via UDS. Everything is working fine here.
Second CAN interface, it's MCP2515 connected via SPI to ESP32, and purpose is to read frames from PT-CAN.
Generally everything works well, but I can't make filtering to work as I want, or I don't fully understand how filtering works in this driver.
So, I need to filter few CAN IDs from among many (without filtering I'm not able to capture desired frames, there is so many frames on the bus). Here are IDs: 0x0A5, 0x0F3, 0x1A1, 0x202, 0x281, 0x3F9.
I configured filters like below:

    CAN0.init_Mask(0, 0, 0x07FF0000);
    CAN0.init_Filt(0, 0, 0x03F90000);
    CAN0.init_Filt(1, 0, 0x02020000);

    CAN0.init_Mask(1, 0, 0x07FF0000);
    CAN0.init_Filt(2, 0, 0x02810000);
    CAN0.init_Filt(3, 0, 0x01A10000);
    CAN0.init_Filt(4, 0, 0x00A50000);
   CAN0.init_Filt(5, 0, 0x00F30000);

And in this configuration, receiving of frames works in odd way. Frames 0x3F9, 0x202, 0x281 are received periodically. Frames 0x1A1 and 0x0A5 sometimes are received, sometimes not. 0x0F3 is not received.
I'm wondering if it's filtering problem or my code (receiving is working in task in FreeRTOS), or maybe I should put 16MHz quartz instead of 8MHz.

Best regards,
Karol

This sounds familiar.
I recall testing filter just recently without success.
Allow me to do a few tests here.

@karolp1993 How is your MCP_CAN.begin clause? Do you have your full code?

Have you noted what is in the Standard_MaskFilter.ino example?

/* Data bytes are ONLY checked when the MCP2515 is in 'MCP_STDEXT' mode via the begin
   function, otherwise ('MCP_STD') only the ID is checked. */
#include "mcp2515.h"

MCP_CAN CAN0(15); // CS PIN



MCP_CAN init_mcp2515(){
    if(CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_8MHZ) == CAN_OK)
        Serial.println("MCP2515 Initialized Successfully!");
    else
        Serial.println("Error Initializing MCP2515...");
    
    
    pinMode(CAN0_INT, INPUT);                            // Configuring pin for /INT input
    
    CAN0.init_Mask(0, 0, 0x07FF0000);
    CAN0.init_Filt(0, 0, 0x03F90000);
    CAN0.init_Filt(1, 0, 0x02020000);

    CAN0.init_Mask(1, 0, 0x07FF0000);
    CAN0.init_Filt(2, 0, 0x02810000);
    CAN0.init_Filt(3, 0, 0x01A10000);
    CAN0.init_Filt(4, 0, 0x00A50000);
    CAN0.init_Filt(5, 0, 0x00F30000);


    CAN0.setMode(MCP_NORMAL);                     // Set operation mode to normal so the MCP2515 sends acks to received data.

    
    return CAN0;
}

I'm using STDEXT mode due STD is not working - there is a comment in the library about silicon error.

I give up for now @karolp1993

@coryjfowler : Care to pitch in?


Send code (working well) on Longan Labs CANBED V1:
Analog pin A0 connected to a servo tester.

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

#define CAN_CS_PIN 17
#define THRESHOLD 500
int CAN_ID = 94;
const int ANALOG_PIN = A0;

MCP_CAN CAN0(CAN_CS_PIN);
unsigned long prevMillis = 0;
const unsigned long interval = 100;
int pulseWidth = 0;
bool isAboveThreshold = false;
uint32_t riseTime = 0;

void setup() {
  Serial.begin(115200);
  while ((!Serial) && (millis() < 3000));  // Wait for Serial connection
  if (CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ) == CAN_OK) Serial.println("MCP2515 Initialized");
  else Serial.println("Error Initializing MCP2515");
  CAN0.setMode(MCP_NORMAL);
}

void loop() {
  if (millis() - prevMillis >= interval) {
    prevMillis = millis();
    byte data[] = {(byte)(pulseWidth >> 8), (byte)pulseWidth};
    char buffer[50];
    sprintf(buffer, "%02X Data: %02X %02X %s", CAN_ID, data[0], data[1], CAN0.sendMsgBuf(CAN_ID, 0, 2, data) == CAN_OK ? "Sent" : "Error");
    Serial.println(buffer);
    CAN_ID++;
    if (97 < CAN_ID) CAN_ID = 94;
  }

  int analogVal = analogRead(ANALOG_PIN);
  if (analogVal > THRESHOLD) {
    if (!isAboveThreshold) isAboveThreshold = true, riseTime = micros();
  } else if (isAboveThreshold) {
    isAboveThreshold = false;
    pulseWidth = micros() - riseTime;
  }
}

Receive code on Arduino Nano 33 IoT:
Note, example uses custom MCP_CAN_lib to fit MIKROE CAN SPI Click 3.3V with 10MHz crystal, code can be found at MCP_CAN_lib / Pull requests #33.

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

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];

#define CAN0_INT_PIN 9
#define CAN0_CS_PIN 10

MCP_CAN CAN0(CAN0_CS_PIN);

void setup()
{
  Serial.begin(115200);
  while ((!Serial) && (millis() < 3000));  // Wait for Serial connection
  if (CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_10MHZ) == CAN_OK)
    Serial.print("MCP2515 Init Okay!!\r\n");
  else
    Serial.print("MCP2515 Init Failed!!\r\n");
  pinMode(CAN0_INT_PIN, INPUT);  // Setting pin for /INT input

  setCANFilterConfig();
  CAN0.setMode(MCP_NORMAL);  // Exit configuration mode
}

void loop()
{
  if (CAN_MSGAVAIL == CAN0.checkReceive())
  {
    CAN0.readMsgBuf(&rxId, &len, rxBuf);  // Read data: len = data length, buf = data byte(s)
    Serial.print("ID: ");
    Serial.print(rxId, HEX);
    Serial.print(" Data: ");
    for (int i = 0; i < len; i++)  // Print each byte of the data
    {
      if (rxBuf[i] < 0x10) Serial.print("0");
      Serial.print(rxBuf[i], HEX);
      Serial.print(" ");
    }
    Serial.println();
  }
}

// Function to set mask and filter configuration
void setCANFilterConfig() {
    CAN0.init_Mask(0, 0x07FF);  // Full mask for ID
    CAN0.init_Mask(1, 0x07FF);  // Full mask for ID
    CAN0.init_Filt(0, 0x05E);   // Filter for ID 0x5E (standard ID 94)
    CAN0.init_Filt(1, 0x061);   // Filter for ID 0x61 (standard ID 97)
    Serial.println("Config 1: Standard IDs 0x5E and 0x61 only");
}

Serial Monitor output:

Entering Configuration Mode Successful!
Setting Baudrate Successful!
MCP2515 Init Okay!!
Starting to Set Mask!
Setting Mask Successful!
Starting to Set Mask!
Setting Mask Successful!
Starting to Set Filter!
Setting Filter Successful!
Starting to Set Filter!
Setting Filter Successful!
Config 1: Standard IDs 0x5E and 0x61 only

void setCANFilterConfig() {
      // **Config 2: Allow a range of IDs by using partial mask**
      CAN0.init_Mask(0, 0x07F0);  // Only check the first 8 bits of ID
      CAN0.init_Mask(1, 0x07F0);
      CAN0.init_Filt(0, 0x050);   // Accept IDs 0x50 to 0x5F
      Serial.println("Config 2: Allow IDs in range 0x50-0x5F");
}

Serial Monitor output:

Entering Configuration Mode Successful!
Setting Baudrate Successful!
MCP2515 Init Okay!!
Starting to Set Mask!
Setting Mask Successful!
Starting to Set Mask!
Setting Mask Successful!
Starting to Set Filter!
Setting Filter Successful!
Config 2: Allow IDs in range 0x50-0x5F
ID: 5E Data: 08 58 
ID: 5F Data: 08 58 
ID: 60 Data: 08 58 
ID: 61 Data: 08 58 
ID: 5F Data: 08 58 
ID: 60 Data: 08 58 
ID: 61 Data: 08 58 
ID: 5E Data: 08 58 
ID: 5E Data: 08 58

I would also suggest using hardware interrupts to read the buffers instead of polling the state of the interrupt like most examples do in the library. It is entirely likely stuff is happening too fast to capture with a polled MCP2515. I experienced similar when I was reverse engineering a DeviceNET bus.

There is also a hardware overflow bit in the MCP2515 that will push a received message in buffer 1 to buffer 2 overwriting buffer 2. I am pretty sure that is enabled by default in the library. You should try disabling that.

Thanks! :slightly_smiling_face:

Receive code on Arduino Nano 33 IoT:

This should probably work for you @karolp1993

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

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128];                        // Array to store serial string

#define CAN0_INT_PIN 9
#define CAN0_CS_PIN 10
MCP_CAN CAN0(CAN0_CS_PIN);                               // Set CS to pin 10

void setup()
{
  Serial.begin(115200);
  while ((!Serial) && (millis() < 3000));  // Wait for Serial connection
  pinMode(21, INPUT_PULLUP);
  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if(CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_10MHZ) == CAN_OK)
    Serial.println("MCP2515 Initialized Successfully!");
  else
    Serial.println("Error Initializing MCP2515...");

  CAN0.init_Mask(0, 0x7FF0000);
  CAN0.init_Mask(1, 0x7FF0000);
  CAN0.init_Filt(0, 0x0A50000);
  CAN0.init_Filt(1, 0x0F30000);
  CAN0.init_Filt(2, 0x1A10000);
  CAN0.init_Filt(3, 0x2020000);
  CAN0.init_Filt(4, 0x2810000);
  CAN0.init_Filt(5, 0x3F90000);

  CAN0.setMode(MCP_NORMAL);                     // Set operation mode to normal so the MCP2515 sends acks to received data.

  pinMode(CAN0_INT_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(CAN0_INT_PIN), CAN0INTE, FALLING);
  
  Serial.println("MCP2515 Library Receive Example...");
}

void loop()
{
  delay(1);
}

void CAN0INTE() {
  CAN0.readMsgBuf(&rxId, &len, rxBuf);      // Read data: len = data length, buf = data byte(s)
  Serial.print("ID: ");
  if (rxId < 256) Serial.print("0");
  Serial.print(rxId, HEX);
  Serial.print(" Data: ");
  for (int i = 0; i < len; i++)  // Print each byte of the data
  {
    if (rxBuf[i] < 0x10) Serial.print("0");
    Serial.print(rxBuf[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
}

CAN0_INT Low pulse width: ~85µs

Testing with

void loop() {
  if (CAN_MSGAVAIL == CAN0.checkReceive())
  {
    // ... 

CAN0_INT Low pulse width: x̄ 94µs (average, assuming the microcontroller does not do any other work)

Rollover

Had a look here at RXB0CTRL receive buffer 0 control register. And it seems to me that the overwrite is disabled when MCP_STDEXT is used.

//mcp_can.cpp
INT8U MCP_CAN::mcp2515_init(const INT8U canIDMode, const INT8U canSpeed, const INT8U canClock)
{
  // ...
            case (MCP_STDEXT): 
            mcp2515_modifyRegister(MCP_RXB0CTRL,
            MCP_RXB_RX_MASK | MCP_RXB_BUKT_MASK,
            MCP_RXB_RX_STDEXT | MCP_RXB_BUKT_MASK );
//mcp_can_dfs.h
#define MCP_RXB_RX_STDEXT   0x00
#define MCP_RXB_RX_MASK     0x60

bit 6-5   RXM[1:0]: Receive Buffer Operating mode bits
          11 = Turns mask/filters off; receives any message
          10 = Reserved
          01 = Reserved
          00 = Receives all valid messages using either Standard or Extended 
               Identifiers that meet filter criteria; Extended ID Filter registers, 
               RXFnEID8:RXFnEID0, are applied to the first two bytes of data 
               in the messages with standard IDs

Send code updated for Longan Labs CANBED V1:

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

#define CAN_CS_PIN 17
const int ANALOG_PIN = A0;
MCP_CAN CAN0(CAN_CS_PIN);
unsigned long prevMillis = 0;
const unsigned long interval = 100;
uint32_t riseTime = 0;
int pulseWidth = 0, analogVal = 0;
bool isAboveThreshold = false;
const int canIds[] = {0xA5, 0x51, 0xF3, 0x53, 0x1A1, 0x55, 0x202, 0x57, 0x281, 0x59, 0x3F9, 0x5B};
int idIndex = 0;

void setup() {
  Serial.begin(115200);
  while ((!Serial) && (millis() < 3000));
  CAN0.begin(MCP_ANY, CAN_500KBPS, MCP_16MHZ);
  CAN0.setMode(MCP_NORMAL);
}

void loop() {
  if (millis() - prevMillis >= interval) {
    prevMillis = millis();
    byte data[] = {(byte)(pulseWidth >> 8), (byte)pulseWidth};
    CAN0.sendMsgBuf(canIds[++idIndex % 12], 0, 2, data);
    Serial.print("ID: ");
    if (canIds[idIndex % 12] < 256) Serial.print("0");
    Serial.print(canIds[idIndex % 12], HEX);
    Serial.print(" Data: ");
    Serial.print(data[0], HEX);
    Serial.print(" ");
    Serial.println(data[1], HEX);
  }

  analogVal = analogRead(ANALOG_PIN);
  if (analogVal > 500) {
    if (!isAboveThreshold) isAboveThreshold = true, riseTime = micros();
  } else if (isAboveThreshold) {
    isAboveThreshold = false;
    pulseWidth = micros() - riseTime;
  }
}

Hi guys. Receiving in interrupt do the trick, filtering is working as expected now, big thanks to both of you!
Right now I need to spend some time with my freertos code, receiving stops after a while, I think some queues may be overloaded.

1 Like

I understand you are busy, but I would greatly appreciate it if I could ask you a question.

I am using an ESP32 and MCP2515 and was able to receive by polling using the same library. However, when I ran the interrupt program, the INT did not respond at all and did not show up on the serial monitor. Normally it should go from 5V to 0V and the interrupt should be recognized, but it stays at 5V all the time.

I would appreciate it if you could tell me if there is a way to fix this.

Code? Wiring?
I am not too familiar with the ESP32, are all interrupt pins?
Have you maybe connected the INT pin to a non interrupt input pin?

Do you have this in your setup?

  pinMode(CAN0_INT_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(CAN0_INT_PIN), CAN0INTE, FALLING);

the ESP32 uses 3.3V logic - inputting 5V can damage the device
All ESP32 GPIOs can be configured as interrupts.

using a MCP2515 with an ESP32 I used GPIOs

// MCP2515 INT to ESP32 GPIO22
// MCP2515 SCK to ESP32 GPIO18 CLK
// MCP2515  SI to ESP32 GPIO23 MOSI
// MCP2515  SO to ESP32 GPIO19 MISO
// MCP2515  CS to ESP32 GPIO5  CS
// MCP2515 GND to ESP32 GND
// MCP2515 VCC to ESP32 3.3V

the ESP32 has an onboard CANBUS controller - see Two-Wire Automotive Interface (TWAI) just requires an external CAN transceiver such as the TJA1051

Thank you for your reply.

The code we are currently using is a modified version of the code you created, with the pin number and bit rate changed.

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

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128];                        // Array to store serial string

#define CAN0_INT_PIN 16
#define CAN0_CS_PIN 12
MCP_CAN CAN0(CAN0_CS_PIN);                               // Set CS to pin 10

void setup()
{
  Serial.begin(115200);
  while ((!Serial) && (millis() < 3000));  // Wait for Serial connection
  pinMode(CAN0_INT_PIN, INPUT_PULLUP);
  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if(CAN0.begin(MCP_STDEXT, CAN_500KBPS, MCP_8MHZ) == CAN_OK)
    Serial.println("MCP2515 Initialized Successfully!");
  else
    Serial.println("Error Initializing MCP2515...");

  CAN0.init_Mask(0, 0x7FF0000);
  CAN0.init_Mask(1, 0x7FF0000);
  CAN0.init_Filt(0, 0x0A50000);
  CAN0.init_Filt(1, 0x0F30000);
  CAN0.init_Filt(2, 0x1A10000);
  CAN0.init_Filt(3, 0x2020000);
  CAN0.init_Filt(4, 0x2810000);
  CAN0.init_Filt(5, 0x3F90000);

  CAN0.setMode(MCP_NORMAL);                     // Set operation mode to normal so the MCP2515 sends acks to received data.

  pinMode(CAN0_INT_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(CAN0_INT_PIN), CAN0INTE, FALLING);
  
  Serial.println("MCP2515 Library Receive Example...");
}

void loop()
{
  delay(1);
}

void CAN0INTE() {
  CAN0.readMsgBuf(&rxId, &len, rxBuf);      // Read data: len = data length, buf = data byte(s)
  Serial.print("ID: ");
  if (rxId < 256) Serial.print("0");
  Serial.print(rxId, HEX);
  Serial.print(" Data: ");
  for (int i = 0; i < len; i++)  // Print each byte of the data
  {
    if (rxBuf[i] < 0x10) Serial.print("0");
    Serial.print(rxBuf[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
}

ESP32 is a module that can be developed with ArduinoIDE and used with the same programs as Arduino.

ESP32 can use interrupt on all GPIOs.
The current pin assignments are as follows.

MISO 19
MOSI 23
SCK 18
CS 12
INT 16

I am confident that wiring is not a problem.
The reason for this is that I tried the example sketch code included in the mcp_can library and it displayed 8 bytes of data continuously on the serial printout with no problems. Here is the code

// CAN Receive Example
//

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

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128];                        // Array to store serial string

#define CAN0_INT 16                              // Set INT to pin 2
MCP_CAN CAN0(12);                               // Set CS to pin 12


void setup()
{
  Serial.begin(115200);
  
  // 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);                     // Set operation mode to normal so the MCP2515 sends acks to received data.

  pinMode(CAN0_INT, INPUT);                            // Configuring pin for /INT input
  
  Serial.println("MCP2515 Library Receive Example...");
}

void loop()
{
  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
  {
    CAN0.readMsgBuf(&rxId, &len, rxBuf);      // Read data: len = data length, buf = data byte(s)
    
    if((rxId & 0x80000000) == 0x80000000)     // Determine if ID is standard (11 bits) or extended (29 bits)
      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){    // Determine if message is a remote request frame.
      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();
  }
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/

With this in mind, we considered that the lack of interrupts was not a wiring problem, but something wrong with the setting.

We then verified that the voltage does not change from 5V to 0V. As a verification method, I tried using another Arduino's digital input to have the serial monitor display only the moment it changed, but it did not. I do not have an oscilloscope.

Any advice on what this information can tell me would be appreciated.
Thank you in advance for your time.

1 Like

In the first code you have

Does that even compile?
Are you also using a custom version of the MCP CAN library?
As opposed to the second code / example you refer to:

Note the "" vs <> ?

What ID frames that you're trying to receive has? INT doesn't go low if you don't read buffer (according to documentation). If your frames are outside filter and you did receive nothing, interrupt will not work. I've got similar problems when my buffer is running out of space.

@horace Thanks for your reply.
In the first stage I tried many things to use the MCP2562+ESP32's built-in CAN controller, but in the end I gave up.
Because the processor of the Freenove_ESP32_WROOM_ I bought is the ESP32WROOM32E and the dedicated library on Github seems to support the ESP32WROOM32D which has not been updated for 5 years and the bit rate is half the set value! I'm trying to find out if this is a Bug? Specification change?

As a beginner I found it difficult and decided to use the MCP2515 module which has a CAN controller with it.

I'll put the Github link below in case you are interested.
There is a lot written about the problems with esp32 in the issue section.

MCP2562 CAN Library

I also knew that the esp32 was 3.3V driven, so I knew that a 5V input would not be good. So I connected 3.3V to Vcc and the POW light went dark. Also, using the same program as with the 5V input, I could not receive the signal the moment I connected it to 3.3V.
I know the risk, but I am now using the 5V one which I can receive. Thanks for the advice.

Thanks for the reply.
I was not aware of that point. Thank you, I will try to get it to work.

I tried to fix it but there is no change and it does not show up on the serial monitor.

@karolpThanks for your reply.

Now I keep sending the same CAN pseudo signal from Arduino Nano + MCP2515 and trying to receive ESP32 + MCP2515.

When using CAN_receive in the mcp_can sketch example, it is displayed on the serial monitor without any problem. The source of CAN_receive is shown below.

// CAN Receive Example
//

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

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128];                        // Array to store serial string

#define CAN0_INT 16                              // Set INT to pin 2
MCP_CAN CAN0(12);                               // Set CS to pin 12


void setup()
{
  Serial.begin(115200);
  
  // 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);                     // Set operation mode to normal so the MCP2515 sends acks to received data.

  pinMode(CAN0_INT, INPUT);                            // Configuring pin for /INT input
  
  Serial.println("MCP2515 Library Receive Example...");
}

void loop()
{
  if(!digitalRead(CAN0_INT))                         // If CAN0_INT pin is low, read receive buffer
  {
    CAN0.readMsgBuf(&rxId, &len, rxBuf);      // Read data: len = data length, buf = data byte(s)
    
    if((rxId & 0x80000000) == 0x80000000)     // Determine if ID is standard (11 bits) or extended (29 bits)
      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){    // Determine if message is a remote request frame.
      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();
  }
}

/*********************************************************************************************************
  END FILE
*********************************************************************************************************/


At this time, the serial monitor displayed the following image.

Reception is working fine. Here I thought that if I am receiving, the buffer could accumulate at least once and change int.

However, when I tried a program with interrupt handling, not a single one appeared on the serial monitor. I think this is because the int processing is not well done, so it is removed from the condition and not displayed.

I don't know what I should change, though it doesn't seem to be filtering by ID.

If you have any advice I would appreciate it.

Could it be you forgot to remove the filtering?

1 Like

We were able to communicate without any problems!
Thanks!
@wittrup for answering my questions and everyone else who responded. They were really helpful.
Thank you from the bottom of my heart.
From a Japanese university student

Sorry . I'm back again. I hope you can answer my question again.

I have to receive at 1000KBPS, but when I received with the following code, the memory overflowed and stopped receiving.
The following is almost identical to the code created by @wittrap.

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

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128];                        // Array to store serial string

#define CAN0_INT_PIN 16
#define CAN0_CS_PIN 12
MCP_CAN CAN0(CAN0_CS_PIN);                               // Set CS to pin 10

void setup()
{
  Serial.begin(9600);
  while ((!Serial) && (millis() < 3000));  // Wait for Serial connection
  pinMode(CAN0_INT_PIN, INPUT_PULLUP);
  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if(CAN0.begin(MCP_STDEXT, CAN_1000KBPS, MCP_8MHZ) == CAN_OK)
    Serial.println("MCP2515 Initialized Successfully!");
  else
    Serial.println("Error Initializing MCP2515...");

  

  CAN0.setMode(MCP_NORMAL);                     // Set operation mode to normal so the MCP2515 sends acks to received data.

  pinMode(CAN0_INT_PIN, INPUT_PULLUP);
  attachInterrupt(digitalPinToInterrupt(CAN0_INT_PIN), CAN0INTE, FALLING);
  
  Serial.println("MCP2515 Library Receive Example...");
}

void loop()
{
  delay(1);
}

void CAN0INTE() {
  CAN0.readMsgBuf(&rxId, &len, rxBuf);      // Read data: len = data length, buf = data byte(s)
  Serial.print("ID: ");
  if (rxId < 256) Serial.print("0");
  Serial.print(rxId, HEX);
  Serial.print(" Data: ");
  for (int i = 0; i < len; i++)  // Print each byte of the data
  {
    if (rxBuf[i] < 0x10) Serial.print("0");
    Serial.print(rxBuf[i], HEX);
    Serial.print(" ");
  }
  Serial.println();
}

However, after displaying about 10 pieces of 8-byte data as it was, a mysterious string of characters appeared on the serial monitor and was not updated thereafter. I examined the string and discovered that it was a memory overflow.

As a solution, the ISR content needed to be as lightweight as possible, so the ISR content was moved into the loop function. The code is as follows.

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

long unsigned int rxId;
unsigned char len = 0;
unsigned char rxBuf[8];
char msgString[128];  // Array to store serial string

#define CAN0_INT_PIN 16
#define CAN0_CS_PIN 12
MCP_CAN CAN0(CAN0_CS_PIN);  // Set CS to pin 12

volatile bool canMessageReceived = false;  

void setup()
{
  Serial.begin(115200);
  while ((!Serial) && (millis() < 3000));  // Wait for Serial connection

  pinMode(CAN0_INT_PIN, INPUT_PULLUP);
  

  // Initialize MCP2515 running at 16MHz with a baudrate of 500kb/s and the masks and filters disabled.
  if (CAN0.begin(MCP_STDEXT, CAN_1000KBPS, MCP_8MHZ) == CAN_OK)
    Serial.println("MCP2515 Initialized Successfully!");
  else
    Serial.println("Error Initializing MCP2515...");

  CAN0.setMode(MCP_NORMAL);  // Set operation mode to normal so the MCP2515 sends acks to received data.

  attachInterrupt(digitalPinToInterrupt(CAN0_INT_PIN), CAN0INTE, FALLING);

  Serial.println("MCP2515 Library Receive Example...");
}

void loop()
{
  if (canMessageReceived)  
  {
    canMessageReceived = false;  // clear flag
    if (CAN0.readMsgBuf(&rxId, &len, rxBuf) == CAN_OK)  // receive message
    {
      Serial.print("ID: ");
      if (rxId < 256) Serial.print("0");
      Serial.print(rxId, HEX);
      Serial.print(" Data: ");
      for (int i = 0; i < len; i++)  // Print each byte of the data
      {
        if (rxBuf[i] < 0x10) Serial.print("0");
        Serial.print(rxBuf[i], HEX);
        Serial.print(" ");
      }
      Serial.println();
    }
    else
    {
      Serial.println("Error reading CAN message");
    }
  }

delay(1);  // timing
}

void CAN0INTE()//ISR
{
  canMessageReceived = true;  // Flag
}

After doing this, the mysterious string was no longer displayed on the serial monitor, but eventually it stopped receiving immediately.

Serial monitor when acquired by polling.
A dozen data are received in 0.03 seconds.

Serial monitor in case of interrupt processing

↑After receiving these 8 frames, it stops and receives nothing.

Supplementary information: Currently, the device we want to acquire CAN is from the 2010s and uses a communication method that combines RS232 and CAN. 176 bytes of data are divided into 22 frames and sent at once at a communication rate of 1000KBPS.

The picture shown on the serial monitor acquired by polling is an example.

However, since all data cannot be acquired by polling, we would like to acquire 22 frames of information continuously by interrupting. But at present, it overflows.

Any advice on this issue would be appreciated.