ESP32 with MCP2515 Not Receiving BMS CANBUS Data (ID 0x100)

**hey please help me **

i am work/using JBD BMS

I’m trying to collect data (total voltage, current, remaining capacity) from a BMS using an ESP32 and an MCP2515 CAN module over CANBUS, but I’m not getting consistent data. I’m following the BMS’s CANBUS protocol and using the mcp_can library. Any help debugging this would be greatly appreciated!

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

#define CAN_CS 5  // Chip Select pin (connect to ESP32 GPIO5)

MCP_CAN CAN(CAN_CS);  // Create CAN object

// CRC-16 MODBUS check (polynomial 0xA001)
uint16_t crc16_modbus(const uint8_t *data, uint8_t len) {
  uint16_t crc = 0xFFFF;
  for (uint8_t i = 0; i < len; i++) {
    crc ^= data[i];
    for (uint8_t j = 0; j < 8; j++) {
      if (crc & 1)
        crc = (crc >> 1) ^ 0xA001;
      else
        crc >>= 1;
    }
  }
  return crc;
}

void setup() {
  Serial.begin(115200);
  delay(1000);

  // Try initializing CAN
  if (CAN.begin(MCP_ANY, 500000, MCP_8MHZ) == CAN_OK) {
    Serial.println("CAN BUS Initialized Successfully");
  } else {
    Serial.println("CAN BUS Init Failed. Check wiring or crystal frequency!");
    while (1);  // Stop program here
  }

  CAN.setMode(MCP_NORMAL);  // Set to normal CAN mode
  delay(100);

  sendRemoteRequest(0x100, 8);  // Request Total Voltage, Current, Capacity
}

void loop() {
  long unsigned int rxId;
  byte len = 0;
  byte buf[8];

  if (CAN.checkReceive() == CAN_MSGAVAIL) {
    if (CAN.readMsgBuf(&rxId, &len, buf) == CAN_OK) {
      if (rxId == 0x100 && len == 8) {
        Serial.print("Received from ID: 0x");
        Serial.print(rxId, HEX);
        Serial.print(" Data: ");
        for (byte i = 0; i < len; i++) {
          Serial.print(buf[i], HEX);
          Serial.print(" ");
        }
        Serial.println();

        // CRC check (NOTE: CRC is LSB first in protocol)
        uint16_t receivedCRC = (buf[6]) | (buf[7] << 8);  // Little-endian
        uint16_t calculatedCRC = crc16_modbus(buf, 6);

        if (receivedCRC != calculatedCRC) {
          Serial.println("CRC mismatch! Data invalid.");
          return;
        }

        // Extract and convert values
        uint16_t voltage_raw = (buf[0] << 8) | buf[1];   // 10mV units
        int16_t current_raw = (buf[2] << 8) | buf[3];    // 10mA units, signed
        uint16_t capacity_raw = (buf[4] << 8) | buf[5];  // 10mAh units

        float voltage = voltage_raw / 100.0;     // → Volts
        float current = current_raw / 100.0;     // → Amps
        float capacity = capacity_raw / 100.0;   // → Ah

        // Display parsed values
        Serial.print("Total Voltage: ");
        Serial.print(voltage, 2);
        Serial.println(" V");

        Serial.print("Current: ");
        Serial.print(current, 2);
        Serial.println(" A");

        Serial.print("Remaining Capacity: ");
        Serial.print(capacity, 2);
        Serial.println(" Ah");

        delay(500);  // Wait before requesting again
        sendRemoteRequest(0x100, 8);
      }
    }
  }
}

// Function to send a remote request frame
void sendRemoteRequest(uint16_t can_id, uint8_t dlc) {
  byte dummyData[0];  // Remote frame has no data
  if (CAN.sendMsgBuf(can_id, 0, dlc | 0x40, dummyData) == CAN_OK) {
    Serial.print("Remote frame sent to 0x");
    Serial.println(can_id, HEX);
  } else {
    Serial.println("Failed to send remote frame");
  }
}

Hardware:

  • Board: ESP32 Dev Module ([SPECIFY IF DIFFERENT, e.g., DOIT ESP32 DEVKIT V1])
  • CAN Module: MCP2515 (with TJA1050 transceiver, 8 MHz crystal)
  • BMS: [SPECIFY BMS MODEL, e.g., JBD 4S 100A or generic BMS]
  • Wiring:
    • ESP32 GPIO5 to MCP2515 CS
    • ESP32 SCK (GPIO18) to MCP2515 SCK
    • ESP32 MOSI (GPIO23) to MCP2515 SI
    • ESP32 MISO (GPIO19) to MCP2515 SO
    • ESP32 3.3V to MCP2515 VCC
    • Common GND between ESP32, MCP2515, and BMS
    • MCP2515 CANH/CANL to BMS CANH/CANL
    • BMS powered by JBD 24V 4S LiFePO4 battery pack
  • components: 120Ω termination resistor

Issue:

  • The Serial Monitor shows [DESCRIBE PROBLEM, e.g., “no data received at all”, “random hex values that don’t make sense”, “CRC mismatch errors every time”, or “voltage reads 0V”].
  • Expected behavior: I want to reliably read total voltage, current, and remaining capacity from ID 0x100 every 500ms, as per the BMS protocol (6 data bytes + 2 CRC bytes, high byte first for data, little-endian for CRC).
  • The ESP32 and MCP2515 work for a simple CAN loopback test, but not with the BMS.

What I’ve Tried:

  • Verified wiring with a multimeter for continuity between ESP32, MCP2515, and BMS.
  • Confirmed MCP2515 crystal is 8 MHz, matching the code.
  • Added a 120Ω termination resistor between CANH and CANL (or confirmed BMS has one built-in, [SPECIFY WHICH]).
  • Tested with different CAN IDs (e.g., 0x101) to check if the BMS responds to other frames.
  • Searched the forum for “ESP32 MCP2515 BMS CANBUS” but didn’t find a matching issue.
  • Checked BMS manual, which specifies CAN2.0B, 500 kHz baud rate, and 11-bit IDs with CRC-16 (0xA001 polynomial).

Topic moved !! Please do not post in "Uncategorized"; see the sticky topics in Uncategorized - Arduino Forum.

What part of the section's description that says "DO NOT POST HERE", are you having trouble in understanding?

You might want to look at this How to get the best out of this forum before you proceed any further.

Is this an official Arduino branded ESP32 or a clone?

Run the library examples between two Arduinos with 2515’s to get that aspect working .

Check you can serial print ok.

Then add print statements into you code , printing variable values so you can home in on the issue .

Are you running one of the eBay type 2515 boards, if not and it’s a home made 2515 setup you need the bus driver chip to go with it (2550 ?)

agree with @hammy test the CANbus with other modules which you know communicate OK
when that works attach your BMS Canbus
I find it useful to have a USB-CAN module so a PC can monitor the traffic

when using CANbus with the ESP32 I tend to use the onboard Two-Wire Automotive Interface (TWAI) interface
the ESP32 directly drives a CAN transceiver, e.g. cjmcu-1051

photo showing two ESP32s one using a MCP2515 the other using TWAI

EDIT: try checking the crystal on the MCP2515 module matches the setting

 if (CAN0.begin(MCP_ANY, CAN_125KBPS, MCP_8MHZ) == CAN_OK)

I sometimes find it worth using an oscilloscope to check the canbus baudrate

1 Like

no all thing are work
14:22:39.573 -> CAN BUS Initialized Successfully
14:22:39.639 -> Remote frame sent to 0x100
14:25:00.561 -> Received from ID: 0x100 Data: 0 0 D C0 1 48 0 0
14:25:00.561 -> CRC mismatch! Data invalid. but agin i got this output

14:22:39.573 -> CAN BUS Initialized Successfully
14:22:39.639 -> Remote frame sent to 0x100
14:25:00.561 -> Received from ID: 0x100 Data: 0 0 D C0 1 48 0 0
14:25:00.561 -> CRC mismatch! Data invalid. but agin i got this output

CANBUS communication protocol.pdf (235.0 KB)
this is the offcial document

Good point about the can speed - the modules usually have the 8Mhz crystal - I got caught on that one .
Unlikely issue ….There is also some stuff on there being two buffers on the 2515 and most modules only consider one and you can set how these deal with incoming data .

You do need the 2550 driver , even I think in using the ESP 32 for the CAN

I would use a transceiver such as the cjmcu-1051 which has dual supply voltages

  1. VCC 5V for the transceiver section
  2. VIO for the interface logic - this can be 3.3V making it suitable for interfacing with 3.3V logic microcontrollers such as the ESP32, RP2040, STM32, etc

Yes I have checked everything that you have told me, but the actual problem is in the code development because the official PDF there is no mention about the remote frame, so confusion in code only other thing i have checked

Without an annotated schematic I can only take a SWAG: Check your module, mine have a 5V not A 3V3 transceiver mounted. From my experience they are flaky at 3V3, some even work others do not.

I can confirm this

I have two MCP2515 modules the first operates only at 5V
the second appears to work at 3.3V transmitting and receiving packets
however, examination of results shows it is intermittent - missing some packets - works OK at 5V

with 3.3V logic microcontollers one can

  1. use onboard CAN controllers if available, e.g. ESP32, some STM32, etc, with an external CAN transceiver with dual power supplies - one for the CAN transceiver (5V) the second for the interface logic (3.3V), e.g. cjmcu-1051
  2. use software CAN controller, e.g. CAN2040 library for RPi PICO RP2040
  3. use a level shifter
  4. use a CAN module such as the MCP25625 which has dual power supplies - used in the Adafruit RP2040 CAN Bus Feather

some microcontrollers have (some) 5V tolerant inputs - check data sheets, e.g. PIC24FJ1024GB610, STM32H747xI/G (used in the Arduino GIGA)

I use a level translating chip on my WeMos R1 D1 (ESP8266) without any problems. Pull up resistors are very important to make this work. I have also replaced the TJA1050 with a SN65HVD230, this works fine as well. The MCP2515 is 3V3 and 5V.

This topic was automatically closed 180 days after the last reply. New replies are no longer allowed.