Mastering ESP32 CAN Bus | Complete Guide for Sending and Receiving Data


In modern embedded systems, the Controller Area Network Bus (CAN Bus ) is a crucial communication protocol, particularly in automotive electronics and industrial control systems. This article explores how to develop a CAN Bus driver using the ESP32 microcontroller and the ESP-IDF (Espressif IoT Development Framework), providing both hardware interfacing and software implementation details.

CAM Bus

Introduction

In the ESP32, CAN communication is driven by the TWAI (Two-Wire Automotive Interface) hardware module, which is fully compatible with the CAN 2.0 protocol standard. This allows the ESP32 to not only participate in data exchange on a CAN Bus network but also to act as a gateway, data logger, or node controller, taking advantage of its built-in processing power. Additionally, the flexibility of the ESP32 enables developers to combine CAN with Wi-Fi or Bluetooth, facilitating remote monitoring and diagnostics as advanced functions.

What is CAN Bus?

CAN Bus (Controller Area Network Bus) is an efficient serial communication protocol that was originally designed by Bosch in the 1980s for automotive applications. Over the years, it has become widely adopted across various industries, including industrial automation, robotics, medical equipment, and home automation.

Key Features of CAN Bus

  • Multi-master architecture: This allows multiple devices to be interconnected, where any node can initiate communication.
  • High reliability: It includes built-in error detection and fault tolerance features, ensuring stable data transmission.
  • Differential signaling: Using the CANH (CAN High) and CANL (CAN Low) lines, CAN Bus is highly resistant to electromagnetic interference.
  • Priority mechanism: Data with higher priority is transmitted first, ensuring time-sensitive messages are delivered promptly.
  • Support for multiple nodes: Up to 120 devices can be connected to the same CAN network.

Each device (such as ESP32, sensor, or MCU) will be equipped with a CAN transceiver (like the SN65HVD230), which interfaces with the bus via the CAN_H and CAN_L signals.

      +--------+           +--------+           +--------+
      | CAN    |           | CAN    |           | CAN    |
      | Device |           | Device |           | Device |
      | (e.g., |           | (e.g., |           | (e.g., |
      | ESP32) |           | Sensor)|           | MCU)   |
      +--------+           +--------+           +--------+
           |                   |                   |
     +---------+          +---------+          +---------+
     | CAN_H   |----------| CAN_H   |----------| CAN_H   |
     +---------+          +---------+          +---------+
           |                   |                   |
     +---------+          +---------+          +---------+
     | CAN_L   |----------| CAN_L   |----------| CAN_L   |
     +---------+          +---------+          +---------+

Development Environment

Before you start programming, make sure to set up the following:

  • Install ESP-IDF (version 4.4 or higher): ESP-IDF is the official development framework for programming the ESP32, and it supports multiple operating systems such as Windows, macOS, and Linux.
  • ESP32 Development Board: You’ll need an ESP32 board, which has built-in capabilities for CAN communication.
  • CAN Transceiver Module: A CAN transceiver like the MCP2551 or SN65HVD230 is required to connect the ESP32 to the CAN bus network.
  • CAN Devices or Simulator (Optional): You may need additional CAN devices or a simulator to test your setup.

Wiring Diagram with SN65HVD230

Here is a simple wiring diagram using ASCII art:

+------------+          +-------------------+         +---------+
|   ESP32    |          | SN65HVD230 (CAN)  |         |   CAN   |
|            |          |                   |         | Device  |
|   GPIO4 ---+--------->| TXD               |         |         |
|   GPIO5 ---+--------->| RXD               |         |         |
|    GND  ---+--------->| GND               |         |         |
|    3V3  ---+--------->| VCC               |         |         |
|            |          | CANH --- CAN Bus  |---------|  CANH   |
|            |          | CANL --- CAN Bus  |---------|  CANL   |
+------------+          +-------------------+         +---------+

Signal Connections between ESP32 and SN65HVD230:

  • GPIO4 on ESP32TXD on SN65HVD230 (Data Transmission)
  • GPIO5 on ESP32RXD on SN65HVD230 (Data Reception)

Ensure that the baud rate of the ESP32 and other CAN bus nodes are the same for proper communication.

Power and Ground Connections:

  • 3V3 on ESP32VCC on SN65HVD230 (Power Supply)
  • GND on ESP32GND on SN65HVD230 (Ground)

The ESP32 operates at 3.3V, so VCC on SN65HVD230 must also be connected to 3.3V to avoid damaging the module.

CANH and CANL:

  • CANH on SN65HVD230CAN High on CAN Bus
  • CANL on SN65HVD230CAN Low on CAN Bus

If the CAN network requires termination resistors, place a 120Ω resistor between CANH and CANL to ensure stable data transmission.

Code

The ESP-IDF includes a built-in CAN driver (referred to as TWAI, for Two-Wire Automotive Interface), which supports CAN 2.0. Here’s a simple implementation to initialize and use the CAN Bus:

#include "driver/twai.h"  // Include the TWAI (CAN) driver library
#include "esp_log.h"      // Include ESP logging library

#define TAG "CAN_DRIVER"  // Define a tag for logging messages

void app_main() {
    // Configure the CAN driver parameters
    twai_general_config_t g_config = TWAI_GENERAL_CONFIG_DEFAULT(GPIO_NUM_21, GPIO_NUM_22, TWAI_MODE_NORMAL);
    twai_timing_config_t t_config = TWAI_TIMING_CONFIG_500KBITS();
    twai_filter_config_t f_config = TWAI_FILTER_CONFIG_ACCEPT_ALL();

    // Initialize the CAN driver
    if (twai_driver_install(&g_config, &t_config, &f_config) == ESP_OK) {
        ESP_LOGI(TAG, "TWAI driver installed successfully");
    } else {
        ESP_LOGE(TAG, "Failed to install TWAI driver");
        return; // Exit the function if driver installation fails
    }

    // Start the CAN driver
    if (twai_start() == ESP_OK) {
        ESP_LOGI(TAG, "TWAI driver started successfully");
    } else {
        ESP_LOGE(TAG, "Failed to start TWAI driver");
        return; // Exit the function if driver start fails
    }

    // Prepare a message to send
    twai_message_t tx_message;          
    tx_message.identifier = 0x100;     
    tx_message.data_length_code = 8;   
    for (int i = 0; i < 8; i++) {      
        tx_message.data[i] = i;        
    }

    // Transmit the message
    if (twai_transmit(&tx_message, pdMS_TO_TICKS(1000)) == ESP_OK) {
        ESP_LOGI(TAG, "Message transmitted");
    } else {
        ESP_LOGE(TAG, "Failed to transmit message");
    }

    // Receive a message
    twai_message_t rx_message;  // Declare a message structure for receiving
    if (twai_receive(&rx_message, pdMS_TO_TICKS(1000)) == ESP_OK) {
        ESP_LOGI(TAG, "Message received");
        ESP_LOGI(TAG, "ID: 0x%x, DLC: %d, Data:", rx_message.identifier, rx_message.data_length_code);
        for (int i = 0; i < rx_message.data_length_code; i++) {
            ESP_LOGI(TAG, "Data[%d]: 0x%x", i, rx_message.data[i]);
        }
    } else {
        ESP_LOGE(TAG, "Failed to receive message");
    }

    // Stop and uninstall the CAN driver
    twai_stop();                         
    twai_driver_uninstall();             
    ESP_LOGI(TAG, "TWAI driver uninstalled");
}

Code Explanation

Configuration:

  • TWAI_GENERAL_CONFIG_DEFAULT: Sets the basic settings for CAN communication, like which GPIO pins to use and the mode (normal mode).
  • TWAI_TIMING_CONFIG_500KBITS: Sets the CAN bus speed to 500 kbps, ensuring all devices on the bus communicate at the same speed.
  • TWAI_FILTER_CONFIG_ACCEPT_ALL: Configures the system to accept all incoming CAN messages, without filtering.

Initialization:

  • twai_driver_install: Initializes the CAN driver to prepare for communication.
  • twai_start: Starts the CAN communication, enabling the ESP32 to send and receive messages.

Message Transmission and Receiving:

  • twai_message_t: This structure holds the message details, such as ID and data.
  • twai_transmit: Sends the message on the CAN bus to other devices.
  • twai_receive: Function to receive messages.

Clean-up:

  • twai_stop: Stops CAN communication.
  • twai_driver_uninstall: Cleans up resources and stops the driver.

Result Output

Here is a simulation of what you might see in the serial monitor when the code executes successfully:

I (10) CAN_DRIVER: TWAI driver installed successfully
I (20) CAN_DRIVER: TWAI driver started successfully
I (30) CAN_DRIVER: Message transmitted
I (40) CAN_DRIVER: Message received
I (40) CAN_DRIVER: ID: 0x100, DLC: 8, Data:
I (40) CAN_DRIVER: Data[0]: 0x0
I (40) CAN_DRIVER: Data[1]: 0x1
I (40) CAN_DRIVER: Data[2]: 0x2
I (40) CAN_DRIVER: Data[3]: 0x3
I (40) CAN_DRIVER: Data[4]: 0x4
I (40) CAN_DRIVER: Data[5]: 0x5
I (40) CAN_DRIVER: Data[6]: 0x6
I (40) CAN_DRIVER: Data[7]: 0x7
I (50) CAN_DRIVER: TWAI driver uninstalled

Explanation of each message:

  • TWAI driver installed successfully: This indicates that the CAN driver was successfully initialized. The hardware is now set up correctly and is ready for communication.
  • TWAI driver started successfully: This confirms that the CAN communication has been started, meaning the device is now capable of sending and receiving CAN messages.
  • Message transmitted: This shows that the message has been sent successfully to the CAN bus.
  • Message received: Signals that a CAN message was successfully received by the ESP32. This demonstrates that both transmission and reception are functioning.
  • ID: 0x100: The message identifier (standard ID 0x100 in this case). This is often used to distinguish different types of messages in a CAN system.
  • DLC: 8: Data Length Code, specifying that the message contains 8 bytes of data.
  • Data:: Payload, Each byte of data is printed line by line.
  • TWAI driver uninstalled: This indicates that the driver has been stopped and uninstalled, cleaning up the resources and making sure the system is reset properly.

Possible Error Messages:

If there is an issue at any stage, you might see error messages like:

E (10) CAN_DRIVER: Failed to install TWAI driver

This means the CAN driver could not be installed, which could be due to a configuration issue or a hardware problem.

E (20) CAN_DRIVER: Failed to start TWAI driver

This indicates that the CAN driver failed to start, preventing the system from communicating on the CAN bus. This could be due to incorrect wiring or configuration.

Conclusion

CAN Bus is an efficient and reliable serial communication protocol initially developed by Bosch in the 1980s for the automotive industry. Today, it is widely used across various fields such as industrial control, medical equipment, and robotics. Thanks to its interference resistance, real-time communication capabilities, and cost-effectiveness, CAN Bus has become a key technology for connecting different devices in modern electronic systems.

As a decentralized communication system, CAN Bus allows multiple devices to communicate over the same bus, offering high speeds (up to 1 Mbps), robust error detection, and automatic retransmission mechanisms. It remains stable even in harsh electromagnetic environments, making it ideal for applications requiring high reliability and continuous operation.