Embedded systems / 2026
OBD-II Diagnostic Logger
An ESP32 logger I built to read engine data, diagnostic trouble codes, and CAN traffic from my 2007 Honda Accord.
Why I built it
I do my own maintenance on my 2007 Honda Accord LX. I wanted more detail than I was getting from a generic OBD-II scanner, so I built an ESP32 logger to read live engine data, diagnostic trouble codes, and raw CAN bus traffic.
Hardware
The ESP32’s TWAI controller handles CAN communication. I connected it to the vehicle’s bus through an SN65HVD230 transceiver.
A J1962 OBD-II to DB9 cable connects to CAN High on pin 6 and CAN Low on pin 14. The board draws 12V from the diagnostic port, with a buck converter supplying power to the ESP32.
Reading engine data
I wrote the firmware in C++ using SAE J1979 diagnostic requests. The logger sends requests to CAN ID 0x7DF for parameters such as engine RPM (0x0C), vehicle speed (0x0D), and coolant temperature (0x05).
The receiver handles the ECU’s reply at 0x7E8 and converts the returned bytes into readable measurements. For RPM, it combines two data bytes and divides the result by four.
This excerpt shows the RPM request and response parsing.
/*Simplified example of req and pars Engine RPM over CAN*/
void request_rpm() {
can_message_t tx_msg;
tx_msg.identifier = 0x7DF;
tx_msg.extd = 0;
tx_msg.data_length_code = 8;
tx_msg.data[0] = 0x02; //Number of additional bytes
tx_msg.data[1] = 0x01; //Service 01 (Show current data)
tx_msg.data[2] = 0x0C; //PID 0C (Engine RPM)
//Pad remaining bytes to complete the frame
for(int i = 3;i < 8; i++) tx_msg.data[i] = 0xAA;
twai_transmit(&tx_msg, pdMS_TO_TICKS(1000));
}
void parse_rpm_response(can_message_t *rx_msg) {
//Check if response is from ECU and matches the RPM PID
if (rx_msg->identifier == 0x7E8 && rx_msg->data[2] == 0x0C) {
uint8_t a = rx_msg->data[3];
uint8_t b = rx_msg->data[4];
//Standard OBD-II formula for RPM
float rpm = ((a * 256.0) + b) / 4.0;
printf("Current RPM: %.2f\n", rpm);
}
}