Communication and location
CAN bus (SN65HVD230) with ESP32
The ESP32 has a built-in CAN controller, called TWAI in Espressif's documents, but no physical CAN driver. Add a 3.3 V transceiver such as the SN65HVD230 and two pins connect to a real CAN bus. It suits vehicles, machines and robots, where several devices share one twisted pair.
Wiring is short: TX and RX to the transceiver's TXD and RXD, 3.3 V, ground, then CANH and CANL to the bus. Use 3.3 V only, because the logic pins are not 5 V tolerant. A bus needs a 120 Ω resistor at both ends. Many modules have one fitted, and if yours sits in the middle of a bus, it should come off.
The ESP32 and ESP32-S3 support classic CAN, not CAN FD. A device alone on the bus cannot finish sending, because nobody acknowledges its frames, so test with two nodes or a CAN adapter. The code below uses the driver in the ESP32 core, without a library. Check the board page first: boards such as Waveshare's Touch LCD 7 already have a transceiver and a terminal. Connecting to a car's bus can interfere with safety systems, so listen only unless you know the network.

Specifications
| Controller | ESP32 TWAI, classic CAN only |
|---|---|
| Transceiver supply | 3.3 V |
| Bus wires | CANH, CANL |
| Termination | 120 Ω at both ends |
| Logic pins | Not 5 V tolerant |
Power and logic levels
3.3 V: safe to connect directly
| Supply | 3.3 V |
|---|---|
| Signal level | 3.3 V |
| On an ESP32 | This is a 3.3 V transceiver, so no shifting is needed. Do not feed it 5 V. |
ESP32 pins, including those on a display board's connectors, work at 3.3 V and are not 5 V tolerant. Modules differ, so if in doubt, measure the signal before you connect it.
Wiring
| CAN bus (SN65HVD230) | Connect to | Note |
|---|---|---|
| VCC | 3V3 | Never 5 V |
| GND | GND | |
| TXD / CTX | GPIO 5 | |
| RXD / CRX | GPIO 6 | |
| CANH, CANL | CAN bus | Twisted pair |
Arduino code
#include "driver/twai.h"
const gpio_num_t TX_PIN = GPIO_NUM_5, RX_PIN = GPIO_NUM_6;
void setup() {
Serial.begin(115200);
twai_general_config_t g = TWAI_GENERAL_CONFIG_DEFAULT(TX_PIN, RX_PIN, TWAI_MODE_NORMAL);
twai_timing_config_t t = TWAI_TIMING_CONFIG_500KBITS();
twai_filter_config_t f = TWAI_FILTER_CONFIG_ACCEPT_ALL();
twai_driver_install(&g, &t, &f);
twai_start();
}
void loop() {
twai_message_t tx = {};
tx.identifier = 0x123;
tx.data_length_code = 2;
tx.data[0] = 0x11;
tx.data[1] = 0x22;
twai_transmit(&tx, pdMS_TO_TICKS(100));
twai_message_t rx;
if (twai_receive(&rx, pdMS_TO_TICKS(1000)) == ESP_OK) {
Serial.printf("ID %03lX, %d bytes\n", (unsigned long)rx.identifier, rx.data_length_code);
}
}
No extra library needed. Compiled for ESP32-S3 with arduino-esp32 3.x. Not yet tested by us on a physical sensor. Change the pins to match your board.
On a display
Read the value in your sketch and pass it to a label, or send it over MQTT and show it with an MQTT value in the editor.
Design a display for CAN bus (SN65HVD230)Boards with a ready connector
Only boards whose connectors we have surveyed. Others may still work on free GPIOs.
| Elecrow CrowPanel ESP32 HMI 2.4" | GPIO_D port: GPIO 25, 32 |
| Elecrow CrowPanel ESP32 HMI 2.8" | GPIO_D port: GPIO 25, 32 |
| Elecrow CrowPanel ESP32 HMI 3.5" | GPIO_D port: GPIO 25, 32 |
| Elecrow CrowPanel ESP32-S3 HMI 4.3" | GPIO_D port: GPIO 37, 38 |
| LilyGO T-Display (classic) 1.14" | Left pin header: GPIO 21, 22 |
| LilyGO T-Display-S3-Pro 2.33" | QWIIC LEFT: GPIO 43, 44 |
| LilyGO T-Deck 2.8" | Grove connector: GPIO 43, 44On the T-Deck Plus this port is taken by the built-in GPS |
| M5Stack AtomS3 0.85" | Grove port: GPIO 2, 1 |
| M5Stack M5StickC Plus2 1.14" | Grove port: GPIO 32, 33 |
| Sunton ESP32-2432S028R 2.8" | GPIO / I2C header (CN1): GPIO 22, 27 |
| Sunton ESP32-4827S043R/C 4.3" | GPIO header (P4): GPIO 17, 18P3 carries the same two pins |
| Sunton ESP32-8048S043C 4.3" | GPIO header (P4): GPIO 17, 18P3 carries the same two pins |
| Sunton ESP32-8048S050C 5.0" | GPIO header (P4): GPIO 17, 18P5 carries the same pins. Shared with the I2S amplifier of the speaker output (P6). |
| Sunton ESP32-8048S070C 7.0" | GPIO header (P4): GPIO 17, 18P5 carries the same pins. Shared with the I2S amplifier of the speaker output (P6). |
| Waveshare ESP32-S3 Touch LCD 1.28" round | SH1.0 GPIO header: GPIO 15, 16Six GPIOs led out per the wiki pin table |
| Waveshare ESP32-S3 Touch LCD 1.28" round (CNC metal housing) | SH1.0 GPIO header: GPIO 15, 16Six GPIOs led out per the wiki pin table |
Good to know
- A lone node gets no acknowledge. Test with two devices.
- Use 3.3 V only on the transceiver.
- ESP32 and ESP32-S3 support classic CAN, not CAN FD.
- Keep off a car's bus unless you know what you are doing. Listen only.
- Some display boards already have CAN.
What it is good for
- Machine panels
- Vehicle data displays
- Robot and sensor networks
FAQ
Does the ESP32 have CAN?
It has a CAN controller called TWAI, but needs an external transceiver.
Why does my CAN send fail?
With one node, nobody acknowledges the frame. Add a second node and check termination.
Does the ESP32 support CAN FD?
ESP32 and ESP32-S3 support classic CAN only.
Sources
Related parts
Use this information at your own risk. It is for general guidance only: the example code compiles, but it has not been tested on every part, and modules differ between sellers. Check the manufacturer's data before you build. Product names belong to their owners, and LCD Ultra Pro is not affiliated with them. See our Terms.