Industrial systems do not have the right to give a "Blue Screen". If one sensor fails, the whole factory must not stop. CAN Bus has the ability to detect a faulty device and kick it off the network (Bus Off).
Also in this chapter, we will see how to read your car's engine RPM and speed via the OBD-II port.
Every CAN controller has an internal "Error Counter".
- TEC: Transmit Error Counter
- REC: Receive Error Counter
The system goes through 3 stages:
- Error Active (Healthy): Error counter < 127. The device works normally. If it finds an error, it sends an "Error Flag" (6 Dominant bits) to warn everyone.
- Error Passive (Yellow Card): Error counter > 127. The device is now considered so unreliable that even if it finds an error, it is not allowed to scream. It just takes notes silently.
- Bus Off (Red Card): Error counter > 255.
- The controller shuts itself down completely.
- It disconnects electrically from the bus (Stays in Logic 1 / Recessive mode).
- It cannot speak again without software intervention (Reset).
🛠️ Field Scenario: If your device works intermittently (starts and stops), it is probably falling into the "Bus Off" state. You can bring it back to life with the
twai_initiate_recovery()command.
OBD (On-Board Diagnostics) is a protocol standard on all cars since 2001. It is essentially a "Question-Answer" layer running on top of CAN Bus.
- Request ID:
0x7DF(The engine ECU listens to messages sent to this ID). - Response ID:
0x7E8(Usually the response from the engine ECU).
| Byte 0 | Byte 1 | Byte 2 | Byte 3-7 |
|---|---|---|---|
| Length | Service (Mode) | PID (Code) | Empty |
0x02 |
0x01 (Current Data) |
0x0C (RPM) |
0x55 (Don't Care) |
To read engine RPM, PID 0x0C is used.
ID: 0x7DF -> Data: 02 01 0C 00 00 00 00 00
The car replies with something like this:
ID: 0x7E8 -> Data: 04 41 0C 1A F8 00 00 00
04: 4 Bytes of valid data.41: Response to Service 01 (01 + 40 = 41).0C: The requested PID (RPM).1A F8: Actual Value (Hex).
Formula:
sequenceDiagram
participant ESP32 as ESP32 (Tester)
participant ECU as Vehicle Brain (ECU)
Note over ESP32: Request: Service 01, PID 0C (RPM)
ESP32->>ECU: ID: 0x7DF [02 01 0C 00...]
Note over ECU: Calculates Data
ECU-->>ESP32: ID: 0x7E8 [04 41 0C 1A F8...]
Note over ESP32: Apply Formula: ((A*256)+B)/4
Note over ESP32: Result: 1726 RPM
The code below asks the vehicle "What is your speed?" every second. (Speed PID: 0x0D)
void getVehicleSpeed() {
// 1. Prepare Request
twai_message_t tx_msg;
tx_msg.identifier = 0x7DF; // Broadcast Request ID
tx_msg.extd = 0; // Standard 11-bit
tx_msg.data_length_code = 8;
tx_msg.data[0] = 0x02; // Data Length (Mode + PID)
tx_msg.data[1] = 0x01; // Service 01 (Show Current Data)
tx_msg.data[2] = 0x0D; // PID 0D (Vehicle Speed)
// Fill the rest with 0x55 (Padding)
for(int i=3; i<8; i++) tx_msg.data[i] = 0x55;
// 2. Transmit
twai_transmit(&tx_msg, pdMS_TO_TICKS(100));
// 3. Wait for Response (Timeout: 100ms)
twai_message_t rx_msg;
if (twai_receive(&rx_msg, pdMS_TO_TICKS(100)) == ESP_OK) {
// Did the response come from 0x7E8? And is it PID 0x0D?
if (rx_msg.identifier == 0x7E8 && rx_msg.data[2] == 0x0D) {
int speed = rx_msg.data[3]; // Formula for speed is just 'A'
printf("Vehicle Speed: %d km/h\n", speed);
}
}
}Congratulations! You have mastered the world of CAN Bus.
- Physical: Don't forget the 120 Ohm resistor. Differential signals are immune to noise.
- Arbitration: Small ID (0x000) always wins, big ID shuts up.
- Filter: Use Mask and Code to save the processor from unnecessary load.
- Error: Recover a device that went "Bus Off" using
initiate_recovery. - OBD-II: Ask
0x7DF, get answer from0x7E8, apply formula.