Demo 31: How to use Arduino ESP32 CAN interface - IoT Sharing

Hot

Saturday, September 2, 2017

Demo 31: How to use Arduino ESP32 CAN interface

1. Introduction
- CAN stands for Controller Area Network (CAN bus). This protocol is very popular in automotive domain. In order to understand more about history, benefits, characteristics, message format of CAN, you can refer:
http://www.ni.com/white-paper/2732/en/
http://www.ti.com/lit/an/sloa101b/sloa101b.pdf
- As you knew in Introduction to ESP32, ESP32 also supports CAN interface. So I am going to make a demo for this with Arduino.
- In this demo, 2 ESP32 modules will be used: first module will send the string "hellocan" to second module. The second module will convert the string to upper case and respond it back to first module and first module will show the result in theTerminal.
2. Hardware
- ESP32 only supplies CAN controller. So you need CAN transceiver for this demo. I bought 2 CAN trasceivers here.
 Figure: ESP32 CAn transceiver
- ESP32 GPIO5 will act as CAN_Tx.
- ESP32 GPIO4 will act as CAN_Rx.
- So you can connect pins belows (ESP32_X: module ESP32 X, CAN_X: module CAN X, where X is 1 or 2 since we have 2 modules):
ESP32_1 IO5 - CAN_1 CTX 
ESP32_1 IO4 - CAN_1 CRX
CAN_1 CANH - CAN_2 CANH
CAN_1 CANL - CAN_2 CANL
ESP32_2 IO5 - CAN_2 CTX 
ESP32_2 IO4 - CAN_2 CRX
3. Software
- In order to make this demo, I used CAN driver which is made by Thomas Barth (Thanks Thomas :))
- Download the CAN library for ESP32 here. Unzip it and copy to "Arduino/libraries" folder.
- Source code for first ESP32 module: receiving string, converting to upper case and respond back:
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <ESP32CAN.h>
#include <CAN_config.h>

/* the variable name CAN_cfg is fixed, do not change */
CAN_device_t CAN_cfg;

void setup() {
    Serial.begin(115200);
    Serial.println("iotsharing.com CAN demo");
    /* set CAN pins and baudrate */
    CAN_cfg.speed=CAN_SPEED_1000KBPS;
    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
    ESP32Can.CANInit();
}

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

      //do stuff!
      if(rx_frame.FIR.B.FF==CAN_frame_std)
        printf("New standard frame");
      else
        printf("New extended frame");

      if(rx_frame.FIR.B.RTR==CAN_RTR)
        printf(" RTR from 0x%08x, DLC %d\r\n",rx_frame.MsgID,  rx_frame.FIR.B.DLC);
      else{
        printf(" from 0x%08x, DLC %d\n",rx_frame.MsgID,  rx_frame.FIR.B.DLC);
        /* convert to upper case and respond to sender */
        for(int i = 0; i < 8; i++){
          if(rx_frame.data.u8[i] >= 'a' && rx_frame.data.u8[i] <= 'z'){
            rx_frame.data.u8[i] = rx_frame.data.u8[i] - 32;
          }
        }
      }
      //respond to sender
      ESP32Can.CANWriteFrame(&rx_frame);
    }
}
- Source code for second ESP32 module: sending the string that need to be converted to upper case, receiving response and show it to Terminal
 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
#include <ESP32CAN.h>
#include <CAN_config.h>

/* the variable name CAN_cfg is fixed, do not change */
CAN_device_t CAN_cfg;

void setup() {
    Serial.begin(115200);
    Serial.println("iotsharing.com CAN demo");
    /* set CAN pins and baudrate */
    CAN_cfg.speed=CAN_SPEED_1000KBPS;
    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
    ESP32Can.CANInit();
}

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

      //do stuff!
      if(rx_frame.FIR.B.FF==CAN_frame_std)
        printf("New standard frame");
      else
        printf("New extended frame");

      if(rx_frame.FIR.B.RTR==CAN_RTR)
        printf(" RTR from 0x%08x, DLC %d\r\n",rx_frame.MsgID,  rx_frame.FIR.B.DLC);
      else{
        printf(" from 0x%08x, DLC %d\n",rx_frame.MsgID,  rx_frame.FIR.B.DLC);
        for(int i = 0; i < 8; i++){
          printf("%c\t", (char)rx_frame.data.u8[i]);
        }
        printf("\n");
      }
    }
    else
    {
      rx_frame.FIR.B.FF = CAN_frame_std;
      rx_frame.MsgID = 1;
      rx_frame.FIR.B.DLC = 8;
      rx_frame.data.u8[0] = 'h';
      rx_frame.data.u8[1] = 'e';
      rx_frame.data.u8[2] = 'l';
      rx_frame.data.u8[3] = 'l';
      rx_frame.data.u8[4] = 'o';
      rx_frame.data.u8[5] = 'c';
      rx_frame.data.u8[6] = 'a';
      rx_frame.data.u8[7] = 'n';

      
      ESP32Can.CANWriteFrame(&rx_frame);
    }
}
4. Result
Figure: ESP32 CAN demo

26 comments:

Unknown said...

ESP32 Software Serial library or exampale please.

Tech It Yourself said...

esp32 has 3 serial interfaces so you need not SoftSerial.

Tech It Yourself said...

here is it:

Demo 2: How to use multiple Serial ports on Arduino ESP32

http://www.iotsharing.com/2017/05/how-to-use-serial-arduino-esp32-print-debug.html

Hippydipsynakedrunner said...

Can you test it using MCP2551 ?

Tech It Yourself said...

Sorry I do not have MCP2551 :(

Anonymous said...

can I use different esp32 pins for can tx/rx ? or they must be gpio5 gpio4

Tech It Yourself said...

Hi

Proposed connection:
ESP32 VP231 Description
GPIO5 / GPIO12 / GPIO25 D CAN TX
GPIO4 / GPIO14 / GPIO35 R CAN RX

Anonymous said...

It work with MCP2551 to, but use 5V for supply not 3.3 V.

martii said...

I was wondering how code would look like if I wanted to send 3 messages, each with different ID in one go. I was trying to do 3x the same code ending with ESP32Can.CANWriteFrame(&rx_frame); but it seems only one first ID is being sent not the following 2 with different IDs.

Anonymous said...

Can you please explain what's the difference between the CAN driver and the Arduino library and where you use each one of them ?

Hippydipsynakedrunner said...

what do i need yo change to read data from car CAN BUS ?

Tech It Yourself said...

Hi it used: xQueueReceive to receive data

Hippydipsynakedrunner said...

can you explain all the parameters in

(xQueueReceive(CAN_cfg.rx_queue,&rx_frame, 3*portTICK_PERIOD_MS)==pdTRUE) ?

Unknown said...

Just tested with both ESP32 it's works. But using Logic Analyzer, it's unreadable. It's looks has wrong speed

sixweb said...

Hello, tested with ESP32 + SN65HVD230 module. It wasn't worked for my Astra H because the middle speed bus in GM models uses an unusual 95kbps speed. However I could figure out, in ESP32SJA1000.cpp this snipped can be added in begin() at the section "switch (baudRate)":

case (long)95E3:
modifyRegister(REG_BTR1, 0x0f, 0x0c);
modifyRegister(REG_BTR0, 0x3f, 25);
break;


Now this works.

sixweb

Anonymous said...

Hello guys,

I flashed the ESP32 with the example code provided. However, it is not working. Nothing outs from the GPIO5 and GPIO4 pins. The library is not working.

Has someone successfully made it worked?

Dinesh said...

How to use cjmcu 1051 instead of the cjmcu 230. I cant get it to work with the same wiring schematic.

Thank you.

Dinesh said...

Got it to work with cjmcu 1051. Just have set the s pin in the transceiver low or ground. Preferably low.

Thank you.

Unknown said...

Hey there,
I followed your step. it works. If I plug the Can bus line to real Vehicle. I cannot receive any data. Does the code work for real vehicle

Unknown said...

I Don't get it working. I conected the ESP32(DOIT DEVKITV1) to SN65HVD230 by GPIO5 to CTX and GPIO4 to CRX. I downloaded the Library as ZIP and loaded it into Arduino by ZIP-Bibliothek hinzufügen. I uploaded to the first ESP32 the ESP32CAN example and to the second ESP32 the ESP32CANSEND example. But i dont get only feedback in the serial monitor with this message:

ets Jun 8 2016 00:22:57

rst:0x1 (POWERON_RESET),boot:0x17 (SPI_FAST_FLASH_BOOT)
configsip: 0, SPIWP:0xee
clk_drv:0x00,q_drv:0x00,d_drv:0x00,cs0_drv:0x00,hd_drv:0x00,wp_drv:0x00
mode:DIO, clock div:1
load:0x3fff0018,len:4
load:0x3fff001c,len:808
load:0x40078000,len:6084
load:0x40080000,len:6696
entry 0x400802e4
E (106) spiram: SPI RAM enabled but initialization failed. Bailing out.
iotsharing.com CAN demo


No things are written like "HELLOCAN".

What is the problem, what did I wrong?

Unknown said...

I am having trouble tranmitting the CAN frame using ESP32 with cjmcu-1051 board (PIN S is grounded) .Is there a way to know the if there is a TX error or Tx err que status ? Do i need to terminate both ends using 120 Ohm ?It is rather a very short CAN wire your example didnt talk about terminations .So i assume may be this is not requied.Any helpis appreciated

Anonymous said...

Hi there,

I am only having the first CAN message. Where's the rest?
ID: 0x80 DLC: 0 Data: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
ID: 0x80 DLC: 0 Data: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
ID: 0x80 DLC: 0 Data: 0x00 0x00 0x00 0x00 0x00 0x00 0x00 0x00
...

Should be like:
" 80";"0";"";""
"286";"8";"00 00 00 00 12 00 FE FF"
"339";"8";"00 00 00 00 00 00 9A 03"
"173";"8";"D4 7D 2A 01 25 02 24 00"
"156";"7";"FD 05 21 00 00 00 00"
"279";"8";"00 00 00 00 00 00 00 00"
" 80";"0";"";""
"286";"8";"00 00 00 00 FC FF F8 FF"
"339";"8";"00 00 00 00 00 00 9A 03"
"173";"8";"D4 7D 2A 01 25 02 24 00"
"156";"7";"FD 05 21 00 00 00 00"
"279";"8";"00 00 00 00 00 00 00 00"

Here is the simple code:
void loop() {
CAN_frame_t rx_frame;
if(xQueueReceive(CAN_cfg.rx_queue, &rx_frame, 3*portTICK_PERIOD_MS) == pdTRUE){

sprintf(msgString, "ID: 0x%.2X DLC: %1d Data: ", rx_frame.MsgID, rx_frame.FIR.B.DLC);
Serial.print(msgString);

for(int i = 0; i < 8; i++){
sprintf(dataString, "0x%.2X ", rx_frame.data.u8[i]);
Serial.print(dataString);
}
Serial.println();
}
}

Any ideas?

Dustin said...

I wish there were a way to do this in MicroPython, but only the PyBoard version seems to have a CAN class. Unsupported on ESP32... [sadface]

TonySK said...

is it possible to use 2 can lines at same time? I need to receive from 2 separate lines

mhtalha07 said...

Thanks, it works fine for me! (with SN65HVD230 CAN Board + ESP32 DOIT layout board).
The resistance across the wires was 60Ω.

Anonymous said...

Which CAN Transceiver are you using?

Thường mất vài phút để quảng cáo xuất hiện trên trang nhưng thỉnh thoảng, việc này có thể mất đến 1 giờ. Hãy xem hướng dẫn triển khai mã của chúng tôi để biết thêm chi tiết. Ðã xong