Most people associate the ESP family of microcontrollers with WiFi, which makes sense, as they�ve become the go-to solution for getting your project online quickly and easily. However, while WiFi capability might be the star of the show, the ESP32 is also equipped with a CAN controller. It�s just that we don�t see it being used as frequently.
Learning how to read and parse CAN messages on your ESP32 can be incredibly useful. For instance, you can obtain data from your car, such as coolant temperature, throttle position, vehicle speed, and engine rpm, and display them on a self-hosted web page, accessible over WiFi. Or, you can create your own CAN network.
In this tutorial, we�re going to cover the essentials. You�ll learn about the basics of the CAN bus system, how to configure the ESP32�s integrated CAN bus controller, how to connect the ESP32 with the TJA1050 external CAN transceiver, and importantly, how to make two ESP32 boards communicate via the CAN bus.
Basics of CAN Bus System
In the old days, cars had more than 2,000 meters of cable in them, connecting switches on the dashboard directly to the headlights and taillights, for instance. As cars became more complex, this simple logic would no longer work.
In 1986, Bosch introduced the CAN bus system, which solved this problem and made car manufacturing cheaper and easier. CAN is now the industry standard and is used in everything from cars and trucks to buses and tractors, and even airplanes and ships.
To better understand the CAN bus, think of your car as a human body. In this context, the CAN bus is the nervous system.
Similar to how the nervous system allows communication between different parts of the body, the CAN bus allows communication between different CAN bus Nodes, also known as Electronic Control Units (or ECUs).
A modern car has over 70 ECUs, each of which is responsible for performing a specific task. Although these ECUs can perform a single task efficiently, they must share information with one another. For example, the engine control module sends the current engine speed to the instrument cluster, where it is displayed on a tachometer; similarly, the driver�s door controller sends a message to the passenger�s door controller to actuate the window.
ECUs are connected to the bus in a multi-master configuration. Meaning, each ECU can take control of the bus and broadcast information (such as sensor data) over it. The broadcasted data is accepted by all other ECUs on the CAN bus. Each ECU can then read the data and decide whether to accept it or ignore it.
CAN Bus Topology
The physical communication happens via the CAN bus wiring harness, consisting of two wires, CAN low and CAN high. Both wires are twisted tightly together so that electromagnetic interference affects the signal in both wires uniformly, thereby minimizing errors.
The far ends of the cable are terminated with 120-ohm resistors. Because the CAN bus is a high-speed data bus, if the bus is not terminated, the signal will reflect back and interfere with the next data signal coming down the line, potentially disrupting communications and causing the bus to fail.
CAN Signaling
To enable data transmission on these wires, their voltage levels are changed. These changes in voltage levels are then translated to logic levels enabling nodes on the network to communicate with one another.
To transmit a �logic 1� on the CAN bus, the voltage on both lines is set to 2.5 volts (i.e. there is no voltage difference). This state is known as the Recessive State, and it indicates that the CAN bus is available for use by any node.
In contrast, to transmit �logic 0�, the CAN high line is set to 3.5 volts and the CAN low line to 1.5 volts (i.e. there is a 2V voltage difference). This state of the bus is known as the Dominant State, which tells every node on the bus that another node is transmitting and that it should wait until the transmission is finished before transmitting its message.
CAN Bus Node
Each CAN node contains a CAN transceiver, a CAN controller, and a microcontroller.
A CAN transceiver
- When receiving: It converts the voltage levels on the CAN bus to levels that the CAN controller can understand.
- When transmitting: It converts the data stream from the CAN controller to CAN bus levels.
A CAN controller
- When transmitting: It transmits the message from the microcontroller serially onto the bus when the bus is free.
- When receiving: It stores the received serial bits from the bus until an entire message is available, and instructs the microcontroller to retrieve it (usually by triggering an interrupt).
A microcontroller
It decides what the received messages mean and what messages it wants to transmit. Sensors, actuators and control devices are connected to it.
A Standard CAN Frame
Communication over the CAN bus is done via CAN frames. Here is a standard CAN frame with an 11 bit identifier. Let�s take a quick look at each of the eight message fields:
- SOF: The Start of Frame is a �dominant 0� to tell the other nodes that a CAN node intends to talk.
- ID: The ID is the frame identifier. It is used to specify what the message means, and who�s sending it. The ID also defines the priority: the lower the ID, the higher the message�s priority.
- RTR: The Remote Transmission Request indicates whether a node sends data or requests data from another node.
- Control: The Control contains the Identifier Extension Bit (IDE) which is a �dominant 0� for 11-bit. It also contains the 4 bit Data Length Code (DLC) that specifies how many bytes of data will be in the message.
- Data: The 8 bytes of data contain the actual information.
- CRC: The Cyclic Redundancy Check is for error detection.
- ACK: The ACK slot indicates if the node has acknowledged and received the data correctly.
- EOF: The EOF marks the end of the CAN frame.
The CAN bus is unique in that it is a message-based protocol. Typically, on a distributed network, each device has a unique ID to distinguish it from other devices on the same bus, and messages are sent from device A to device B based on their IDs.
On the contrary, nodes on the CAN Bus do not have IDs. Rather, each message is assigned a unique CAN ID that indicates what the message is about. All nodes receive all messages, and each node filters the messages that are relevant to it.
ESP32 CAN Controller a.k.a. TWAI Controller
Espressif Systems refers to its CAN bus-compatible controller as TWAI, which stands for Two-Wire Automotive Interface.
Now, you might wonder why they made this change from the more familiar term CAN to TWAI. It�s a common question many have asked since Espressif decided to rename it.
Previously, Espressif used the term CAN in all its documentation to describe this feature. However, in their most recent documentation, they have begun to use the term TWAI. This change might seem a bit confusing at first, but keep in mind that TWAI and CAN basically mean the same thing when it comes to the ESP32.
The TWAI controller is designed to be compatible with the CAN 2.0 protocol. It supports both Standard Frame Format (11-bit ID) and Extended Frame Format (29-bit ID).
It includes features for error detection and handling, ensuring robust communication in noisy environments, which is particularly crucial in automotive applications.
The TWAI controller also supports interrupt-driven communication, which allows for efficient handling of messages and events on the CAN bus without needing to continuously poll the status.
Block Diagram
The diagram below shows the major functional blocks of the TWAI Controller.
Signal Lines
The TWAI controller�s interface consists of four signal lines: TX, RX, BUS-OFF, and CLKOUT. A nice thing about the ESP32 is that all four signals can be mapped to any GPIO pin.
- TX and RX: The TX and RX signal lines must be connected to an external transceiver. Both signal lines represent/interpret a dominant bit as a low logic level (0 V), and a recessive bit as a high logic level (3.3 V).
- BUS-OFF: The BUS-OFF signal line is not always necessary, but it�s useful in certain situations. This line is set to a low logic level (0 V), when the TWAI controller enters a bus-off state, indicating a disruption in communication. In normal operation, the BUS-OFF line maintains a high logic level (3.3 V).
- CLKOUT: The CLKOUT signal line is another optional feature. It provides an output of a prescaled version of the controller�s source clock.
Operating Modes
The TWAI supports the following modes of operations:
- Normal Mode: In this mode, the TWAI controller can participate in bus activities such as transmitting and receiving messages/error frames. When transmitting a message, acknowledgement from another node is required.
- No Ack Mode: This mode is similar to the normal mode, with one key difference: transmissions are considered successful without the need for an acknowledgement. This mode is particularly useful for self-testing the TWAI controller, as it allows for loopback of transmissions without external confirmations.
- Listen Only Mode: In this mode, the TWAI controller takes a passive role. It does not influence the bus, meaning it will not transmit any messages, acknowledgements, or error frames. The controller can still receive messages but will not acknowledge them. This mode is suited for bus monitoring applications.
Features
The main features of the ESP32 TWAI controller are:
- Compatible with ISO 11898-1 protocol (CAN Specification 2.0)
- Supports Standard Frame Format (11-bit ID) and Extended Frame Format (29-bit ID)
- Bit rates:
- from 25 Kbit/s to 1 Mbit/s in chip revision v0.0/v1.0/v1.1
- from 12.5 Kbit/s to 1 Mbit/s in chip revision v3.0/v3.1
- Multiple modes of operation
- Normal
- Listen Only (no influence on the bus)
- Self Test (transmissions do not require acknowledgment)
- 64-byte Receive FIFO
- Special transmissions
- Single-shot transmissions (does not automatically re-transmit upon error)
- Self-Reception (the TWAI controller transmits and receives messages simultaneously)
- Acceptance Filter (supports single and dual filter modes)
- Error detection and handling
- Error counters
- Configurable Error Warning Limit
- Error Code Capture
- Arbitration Lost Capture
An excellent resource for learning about the ESP32 TWAI controller is the ESP32 Technical Reference Manual. It includes a section that is dedicated to the TWAI, providing extensive information and guidance.
TJA1050 High-Speed CAN Transceiver
Although the ESP32 has a built-in CAN bus-compatible controller, it doesn�t have a built-in CAN transceiver, so we must use an external one to connect to a CAN network.
The type of external transceiver you�ll need depends on the specific requirements of your project. For example, if you need compatibility with ISO 11898-2 standards, then something like the TJA1050 High-Speed CAN transceiver from NXP or SN65HVD23x from Texas Instruments would be excellent choices.
In this tutorial, we�ll be using the TJA1050 CAN bus transceiver module.
This module serves as an interface between the ESP32 and the physical two-wire CAN bus, and meets the automotive requirements for high-speed (up to 1Mb/s), low quiescent current, electromagnetic compatibility, and electrostatic discharge.
For more information about the TJA1050 CAN transceiver, please refer to the datasheet below.
Hardware Hookup
Now that we know everything about the TWAI controller, let�s construct our own CAN network.
Example 1: Simple two-node CAN Network
In this example, a simple two-node CAN bus network is constructed�one node transmits a message, the other receives it.
To begin, take the TJA1050 CAN transceiver module and connect its VCC pin to the VIN on your ESP32. Then, connect the GND pin to the ground. Next, connect the TX to GPIO5 and the RX to GPIO4 on the ESP32.
You�ll need to create two of these circuits. They�ll be identical in wiring. One will function as the transmitter, sending out messages, and the other will serve as the receiver, picking up those messages.
Connecting the modules is straightforward: CAN L connects to CAN L and CAN H connects to CAN H. The wires should ideally be twisted pair, but for simple breadboard testing or other short runs, this is not required.
It�s important to keep in mind that as the bus length increases or environmental electrical noise increases, using twisted pair and adding shielding becomes more important.
Construct the network as shown.
Example 2: Multi-Node CAN Network
In this example, a larger CAN network is constructed�multiple nodes send messages and one node relays them to a PC over a serial port.
Other nodes can be added between the two end nodes. These can be spliced in-line or attached to the main bus using a short stub cable, as long as the length is kept under 12 inches.
One important note about the TJA1050 CAN transceiver module is that it comes with a 120 Ohm terminating resistor already soldered on. So for these additional nodes in your network, you�ll need to remove this resistor.
Construct the network as shown.
Library Installation
The Arduino CAN library by Sandeep Mistry is really an excellent library for working with the TWAI controller. You will need to download and install it in your Arduino IDE.
To install the library, navigate to Sketch > Include Library > Manage Libraries� Wait for the Library Manager to download the library index and update the list of installed libraries.
Filter your search by entering �mcp2515�. Look for CAN by Sandeep Mistry. Click on that entry and then choose Install.
Example Code
In this simple test, we�ll attempt to transmit a �Hello World� message on the CAN bus to see if it can be decoded. It will help you learn how to use the modules and can serve as the foundation for more practical experiments and projects.
Code for the Transmitter Node
Upload this sketch to the transmitter node.
If you have multiple nodes on a CAN bus, upload this sketch to each of the transmitter nodes. Make sure to change the message IDs to unique values for each node.
#include <CAN.h>
#define TX_GPIO_NUM 5
#define RX_GPIO_NUM 4
void setup() {
Serial.begin (115200);
while (!Serial);
delay (1000);
Serial.println ("CAN Sender");
// Set the pins
CAN.setPins (RX_GPIO_NUM, TX_GPIO_NUM);
// start the CAN bus at 500 kbps
if (!CAN.begin(500E3)) {
Serial.println("Starting CAN failed!");
while (1);
}
}
void loop() {
// send packet: id is 11 bits, packet can contain up to 8 bytes of data
Serial.print("Sending packet ... ");
CAN.beginPacket(0x12);
CAN.write('h');
CAN.write('e');
CAN.write('l');
CAN.write('l');
CAN.write('o');
CAN.endPacket();
Serial.println("done");
delay(1000);
// send extended packet: id is 29 bits, packet can contain up to 8 bytes of data
Serial.print("Sending extended packet ... ");
CAN.beginExtendedPacket(0xabcdef);
CAN.write('w');
CAN.write('o');
CAN.write('r');
CAN.write('l');
CAN.write('d');
CAN.endPacket();
Serial.println("done");
delay(1000);
}
Code for the Receiver Node
Upload this sketch to the receiver node.
#include <CAN.h>
#define TX_GPIO_NUM 5
#define RX_GPIO_NUM 4
void setup() {
Serial.begin (115200);
while (!Serial);
delay (1000);
Serial.println ("CAN Receiver");
// Set the pins
CAN.setPins (RX_GPIO_NUM, TX_GPIO_NUM);
// start the CAN bus at 500 kbps
if (!CAN.begin(500E3)) {
Serial.println("Starting CAN failed!");
while (1);
}
}
void loop() {
// try to parse packet
int packetSize = CAN.parsePacket();
if (packetSize) {
// received a packet
Serial.print ("Received ");
if (CAN.packetExtended()) {
Serial.print ("extended ");
}
if (CAN.packetRtr()) {
// Remote transmission request, packet contains no data
Serial.print ("RTR ");
}
Serial.print ("packet with id 0x");
Serial.print (CAN.packetId(), HEX);
if (CAN.packetRtr()) {
Serial.print (" and requested length ");
Serial.println (CAN.packetDlc());
} else {
Serial.print (" and length ");
Serial.println (packetSize);
// only print packet data for non-RTR packets
while (CAN.available()) {
Serial.print ((char) CAN.read());
}
Serial.println();
}
Serial.println();
}
}
Demonstration
After uploading the sketch, open the serial monitor at a baud rate of 115200. The transmitter node sends a standard CAN packet and an extended CAN packet every second.
The receiver node receives it and passes it on to the PC over the serial port.