Master the "Heavyweight Champion" of automotive and heavy industry; CAN Bus protocol, with deep dives into ESP32 TWAI hardware, hardware filtering, and OBD-II diagnostics.
UART, I2C, or SPI are gentle protocols; they love clean desktop environments. CAN Bus (Controller Area Network) is like a battle tank. It is designed to work flawlessly amidst electric motor noise, high magnetic fields, and meters of cable mess.
This guide aims to teach the ESP32 TWAI (Two-Wire Automotive Interface) hardware, Mask/Code filtering logic, and Arbitration (Collision Avoidance) rules in great detail, without hiding behind simplified Arduino libraries.
- 🔌 Physical Layer: Why do we use an external Transceiver (SN65HVD230)?
- ⚖️ Arbitration: Why is data never lost if two devices talk simultaneously? (Democracy Logic).
- 🎭 Hardware Filter: How to capture only relevant messages without burdening the processor?
- 🚗 OBD-II Hack: How to read your car's engine RPM and speed?
This guide consists of 4 main chapters taking you from zero to hero:
| Chapter | Title | Summary |
|---|---|---|
| 01 | 🔌 Physical Layer | TWAI vs CAN difference, Dominant/Recessive voltages, and 120 Ohm termination resistor. |
| 02 | ⚖️ Protocol & Arbitration | Message priorities, ID structure, and "Non-Destructive Arbitration" mechanism. |
| 03 | 💻 Integration & Code | ESP32 TWAI driver setup, data queuing, and Mask/Code filters. |
| 04 | 🕵️♂️ Error & OBD-II | Recovering from Bus Off errors and reading data from the vehicle diagnostic port (OBD-II). |
To practice the examples in this guide, the following hardware is recommended:
- Microcontroller: ESP32 (Contains internal TWAI controller).
- Transceiver: SN65HVD230 (3.3V compatible) or TJA1050 (5V - Requires Level Shifter).
- Cable: Twisted Pair cable.
- Resistor: 2x 120 Ohm resistors (For the start and end of the bus).
The most confusing yet powerful part of CAN Bus is filtering. Here is how to say "Accept only IDs starting with 0x100":
// 1. Configuration
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();
// 2. Filter: Accept only range 0x100 - 0x10F
// Code: Ideal ID, Mask: Don't Care Bits (1 = Ignore)
twai_filter_config_t f_config = {
.acceptance_code = (0x100 << 21),
.acceptance_mask = ~(0xF << 21),
.single_filter = true
};
// 3. Start
twai_driver_install(&g_config, &t_config, &f_config);
twai_start();Did you spot a mistake or want to add some "Field Experience"?
- Fork this repo.
- Make your fix.
- Submit a Pull Request.
This project is open-source under the MIT License. Knowledge grows as it is shared.
