ESP32 + CAN Comm

Posts: 2
Joined: Sat Nov 30, 2019 2:31 am

ESP32 + CAN Comm

Postby gabrieldp3 » Sat Nov 30, 2019 2:53 am

Hello, i have an device that transmit message using CAN protocol. I am trying to comunicate with the ESP32, but i am having troubles to recieve the message.

The way that the device send the data is using an data package of 64 bits see the attachment please!

In this 64 bits, the first 8 bits are a CODE number, the next 16 bits are a real number but i can only recieve the right message for the package that come with 8 bits.

Instead of recieveing 1.3 , i am receiving 1 0, i dont know how to take the 16 bits messages together, or how the real number 1.3 is sent using CAN protocol.

The message that i receive : 102 1 0 39 69 0 0 0
The message that i think that i should receive : 102 1 3 39 69 0 0 0

The code that i am using:

#include <ESP32CAN.h>
#include <CAN_config.h>
#include <driver/can.h>
/* the variable name CAN_cfg is fixed, do not change */
CAN_device_t CAN_cfg;

void setup() {
Serial.println(" CAN demo");
/* set CAN pins and baudrate */
CAN_cfg.tx_pin_id = GPIO_NUM_5;
CAN_cfg.rx_pin_id = GPIO_NUM_4;
/* create a queue for CAN receiving */
CAN_cfg.rx_queue = xQueueCreate(10,sizeof(CAN_frame_t));
//initialize CAN Module

void loop() {
CAN_frame_t rx_frame;
can_message_t message;
//receive next CAN frame from queue
if(xQueueReceive(CAN_cfg.rx_queue,&rx_frame, 3*portTICK_PERIOD_MS)==pdTRUE){

//do stuff!
printf("New standard frame");
printf("New extended frame");

printf(" RTR from 0x%08x, DLC %d\r\n",rx_frame.MsgID, rx_frame.FIR.B.DLC);
printf(" from 0x%08x, DLC %d\n",rx_frame.MsgID, rx_frame.FIR.B.DLC);
for(int i = 0; i < 8; i++){



can_DRAFT.png (149.48 KiB) Viewed 2021 times

Posts: 13
Joined: Mon Oct 07, 2019 4:55 pm

Re: ESP32 + CAN Comm

Postby MStackoverflow » Mon Dec 02, 2019 9:38 pm


Do you have control over the device that is sending the CAN messages?
The reason why you don't receive 1.3 is because the sender is not sending 1.3

Usually, REAL numbers in CAN protocols have 32 bits (4-bytes), unless there is a "per bit" value like in J1939/OBDII protocols.

16-bits "REAL" are referred as "Half-precision floating point" and you will have to do the arithmetic yourself with this documentation : ... int_format

If you want to encode/decode 4-bytes REAL numbers, it is pretty easy to do so with UNION structures.


Code: Select all

//Declaration of union structure
union BytesToNumbers
    byte bytes[4] = {0,0,0,0};
    float floatVal;
} bytesToNumbers;   

// Load received bytes into the union. Let's say "rx" is our received buffer
bytesToNumbers.bytes[0] = rx[0];
bytesToNumbers.bytes[1] = rx[1];
bytesToNumbers.bytes[2] = rx[2];
bytesToNumbers.bytes[3] = rx[3];

//Print the resullting float number
Serial.println( bytesToNumbers.floatVal );

In an UNION, all the variables share the same memory space. By assigning the 4 bytes of the CANbus messages into the byte array of the bytesToNumbers union, you can read the merged bytes using the floatVal variable.

Posts: 2
Joined: Sat Nov 30, 2019 2:31 am

Re: ESP32 + CAN Comm

Postby gabrieldp3 » Fri Dec 06, 2019 4:44 pm


Thanks for the answer,

Actually i think that the protocol that this module is using is the J1939, so what this per bit value means?


Posts: 13
Joined: Mon Oct 07, 2019 4:55 pm

Re: ESP32 + CAN Comm

Postby MStackoverflow » Mon Dec 16, 2019 9:32 pm

Learning how the J1939 protocol works would be benificial for you.
Documentation is pretty hard to find, but here's some basics :

J1939 has extended bit addresses (29-bit) compare to CANOpen or OBDII.
Each address contains a standardized type of information for vehicle. The address contains a PGN number (Parameter Group Numbers) and the sub address is called the SPN (Suspect Parameter Numbers) which the number is no where in the canbus message, only in the documentation.

For example, this is the documentation for the engine speed :
spn190 - Engine Speed - Actual engine speed which is calculated over a minimum crankshaft angle of 720 degrees divided by
the number of cylinders.
Data Length: 2 bytes
Resolution: 0.125 rpm/bit , 0 offset
Data Range: 0 to 8,031.875 rpm
Type: Measured
Suspect Parameter Number: 190
Parameter Group Number: [61444]
The J1939 address is 0x18F00400 (0xF004 is the PGN 61444).
The message is on 2 bytes (byte 4-5 in this case, not mentionned).
Because the engine speed will never reach 65535 (maximum of 2 bytes combined), we can give the engine more precision by saying that each bit is 0.125 rpm. So the maximum on 2 bytes would be 8191.875 RPM (they set the max at 8031.875)

Posts: 18
Joined: Mon Apr 16, 2018 11:38 pm

Re: ESP32 + CAN Comm

Postby CollinK » Tue Dec 17, 2019 1:27 am

As Mstackoverflow was basically saying: what you have is NOT J1939. Such traffic would have extended ID frames (29 bit) and the data byte format would be different too. What you actually have doesn't even appear to be ISO-TP or anything else somewhat standard. Instead it looks kind of like it might just be something simple yet maybe non-standard.

But, if you think you should be receiving one thing but receive something else then you should suspect that the sending side is not sending what you thought it was. CAN frames have 15 bit CRC so if you get erroneous bits it will fail CRC and you just plain won't receive the frame. So, you must be getting what the other side is actually sending.

As for what a "per bit" value would mean, that's something like this:

The value on CAN is sent as a 16 bit integer but each number in that integer is really 0.0045V. So, let's say there's a scheme like I just mentioned and it wants to send a real number value of 14.63 volts. Well, 14.63 / 0.0045 = 3251 (throw away any fractional numbers. So, the sent value is 3251 which is 0x0CB3 so the CAN data could be 0C B3 or B3 0C depending on whether it is sent little or big endian. This scaling value is essentially arbitrary and chosen by the person who wrote the standard (like OBDII PID codes) or by the programmer who created the CAN specification and coded it. So, you'd have to find out what scaling factor they used in this case. That's what's meant by a per-bit value. Each discrete integer value passed is multiplied by a specific ratio to yield the "real" result.

Who is online

Users browsing this forum: No registered users and 24 guests