On-board diagnostics (OBD-II)
OBD (On-Board Diagnostics) is a standardized way of accessing vehicle data. It was first required in 1988 in California, and has since been revised several times. OBD-II was introduced in 1996 and became mandatory in the United States; Europe introduced similar EOBD requirements later.
OBD-I was introduced as a means to ensure emission control systems would function during the whole life of the vehicle. The goal was to read out emissions-related data from the vehicle every year during an annual inspection. However, because the reporting of emissions-specific data was not standardized, it wasn't very successful. It also didn't help that every manufacturer used its own connector and own set of DTCs.
To solve OBD-I's problems, OBD-II was introduced. In the new standard, the connector, electrical signaling, and DTCs were specified.
Europe followed in 2001 when they introduced EOBD for petrol cars, and in 2004 for diesel cars. EOBD is essentially the European implementation of the same emissions-focused diagnostics concept.
History
- 1988 — OBD-I is required in California.
- 1996 — OBD-II is made mandatory in the United States for cars and light trucks.
- 2001 — EOBD is made mandatory in Europe for petrol cars.
- 2004 — EOBD is made mandatory in Europe for diesel cars.
- 2005 — OBD-II is made mandatory in the United States for medium duty vehicles.
- 2008 — OBD-II must use CAN in the United States.
- 2010 — OBD-II is made mandatory in the United States for heavy duty vehicles.
SAE J1962 Connector
The connector used for OBD-II is the SAE J1962 diagnostic link connector. There is a Type A connector for 12 V vehicles, and a Type B for 24 V vehicles. The connector has 16 pins, some of which are part of the standard while others can be used at the manufacturer's discretion.
On newer vehicles that expose DoIP on the OBD-II connector, some of the manufacturer-specific pins are used for Ethernet. There are two possible pinouts, Option 1 and Option 2 — by measuring the voltage on pin 8 (the DoIP Activation Line), the tester can determine which pinout is in use.
OBD-II — J1962 Type A
| Function | Mnemonic | Pins | Description |
|---|---|---|---|
| SAE J1850 Bus | J1850 | 2, 10 | Two-wire J1850 PWM/VPW bus. |
| Chassis Ground | CGND | 4 | Chassis ground reference. |
| Signal Ground | SGND | 5 | Signal ground reference. |
| CAN Bus | CAN | 6, 14 | ISO 15765 CAN bus. Mandatory in the US since 2008. |
| ISO 9141 K/L-Line | K/L | 7, 15 | K-Line and L-Line for ISO 9141-2 / KWP2000. |
| Battery (+) | +VB | 16 | +12 V (Type A) or +24 V (Type B), permanent. |
| Manufacturer-specific | — | 1, 3, 8, 9, 11, 12, 13 | OEM-defined functions. Not part of the standard. |
Signal Protocols
The OBD-II standard allows for implementing one or more of the following signaling protocols. Since 2008, CAN is mandatory in the United States.
- SAE J1850 PWM — Two-wire PWM-based signal running at 41.6 kbit/s. Most commonly used in older Ford vehicles.
- SAE J1850 VPW — One-wire VPW-based signal. After every bit the level on the bus changes. The length of the high pulse determines the value of the bit: 64 µs for a logical 1, 128 µs for a logical 0. Due to the variable length of each bit there is no fixed data rate. Most commonly used in older General Motors vehicles.
- ISO 9141 (K-Line) — UART-based signal running at 10.4 kbit/s. Used in EU, Chrysler, and Asian cars from 2000 until 2004.
- ISO 14230 (KWP2000) — Same physical layer as ISO 9141. Common after 2003.
- ISO 15765 (CAN) — Mandatory in the United States since 2008. Uses ISO-TP as a transport layer.
Service IDs (SIDs)
The protocol itself was standardized as SAE J1979 (also published as ISO 15031-5) and defines a set of services that must be supported. These "services" used to be called "modes". A successful response starts with the SID ORed with 0x40 (e.g. SID 0x01 becomes a response of 0x41). On error, the reply starts with 0x7F, followed by the SID and a UDS-style negative response code.
The PID, OBDMID, TID and INFOTYPE values referenced below are catalogued in the SAE J1979-DA digital annex.
0x01 — Show current data
Reads a live emissions-related parameter. The request carries a 1-byte PID; the response echoes the PID followed by 1 to 4 data bytes (named A, B, C, D). PID 0x00 is special: it reports a bitmap of which PIDs in the range 0x01–0x20 the ECU supports. The same trick (PID 0x20, 0x40, 0x60, …) walks the rest of the table.
0x01 — Request current powertrain diagnostic data
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Service ID | SIDRQ | 01 | Request current powertrain diagnostic data SID. |
| parameterIdentifier | PID | PID | 1-byte PID (see SAE J1979-DA). |
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Response SID | SIDPR | 41 | Request SID ORed with 0x40. |
| parameterIdentifier | PID | PID | Echoed PID. |
| dataRecord | DREC | 1–4 bytes (Data A–D) | PID-specific value. Format and length depend on the PID. |
0x02 — Show freeze frame data
Reads emissions data captured at the moment a DTC was stored. Same shape as Service 0x01, but with an extra "frame number" byte. Frame 0x00 is the freeze frame associated with the DTC that triggered storage.
0x02 — Request powertrain freeze frame data
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Service ID | SIDRQ | 02 | Request powertrain freeze frame data SID. |
| parameterIdentifier | PID | PID | 1-byte PID. |
| frameNumber | FRNO | frame | Freeze frame number. 0x00 = freeze frame stored when the DTC was set. |
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Response SID | SIDPR | 42 | Request SID ORed with 0x40. |
| parameterIdentifier | PID | PID | Echoed PID. |
| frameNumber | FRNO | frame | Echoed frame number. |
| dataRecord | DREC | 1–4 bytes (Data A–D) | PID-specific value captured at freeze-frame time. |
0x03 — Show stored diagnostic trouble codes
Reads "confirmed" emission-related DTCs. The request has no payload. On CAN (ISO 15765-4) the response starts with a count byte; on the older protocols the count comes from PID 0x01 instead. Each DTC takes two bytes; see the DTC encoding section below.
0x03 — Request stored emission-related DTCs
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Service ID | SIDRQ | 03 | Request stored DTCs SID. No payload. |
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Response SID | SIDPR | 43 | Request SID ORed with 0x40. |
| numberOfDTCs | #OFDTC | count | Number of DTCs that follow (CAN only). 0x00 = no DTCs stored. |
| dtcRecord | DTC | 2 bytes per DTC | Two bytes per DTC, repeated for each stored code. |
0x04 — Clear diagnostic trouble codes and stored values
Clears confirmed and pending DTCs, freeze frame data, on-board monitor results, MIL state, distance/time-with-MIL counters, etc. Permanent DTCs (Service 0x0A) are not affected. The request and response have no payload. Most ECUs require ignition ON with the engine off and otherwise return NRC 0x22 conditionsNotCorrect.
0x04 — Clear/reset emission-related diagnostic information
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Service ID | SIDRQ | 04 | Clear/reset SID. No payload. |
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Response SID | SIDPR | 44 | Request SID ORed with 0x40. The clear was accepted. |
0x05 — Oxygen sensor monitoring test results (non-CAN only)
Reports oxygen sensor test results addressed by a Test ID. Defined for ISO 9141-2, ISO 14230-4 and SAE J1850 only — on CAN this functionality is folded into Service 0x06.
0x05 — Request oxygen sensor monitoring test results
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Service ID | SIDRQ | 05 | Request oxygen sensor monitoring test results SID. |
| testIdentifier | TID | TID | Test ID identifying the oxygen sensor parameter. |
| o2SensorId | O2S | O2 sensor | Oxygen sensor identifier (bank/sensor). Optional depending on Test ID. |
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Response SID | SIDPR | 45 | Request SID ORed with 0x40. |
| testIdentifier | TID | TID | Echoed Test ID. |
| o2SensorId | O2S | O2 sensor | Echoed sensor identifier. |
| dataRecord | DREC | test value bytes | Test result, format defined per Test ID. |
0x06 — On-board monitoring test results
Reports test values, minimum and maximum limits for on-board monitors (catalyst, EVAP, misfire, oxygen sensors on CAN, …). Each monitor is addressed by an OBDMID; each monitor can have multiple Test IDs. The Unit and Scaling ID tells the tester how to interpret the 16-bit value and limits.
0x06 — Request on-board monitoring test results
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Service ID | SIDRQ | 06 | Request on-board monitoring test results SID. |
| monitorIdentifier | OBDMID | OBDMID | On-Board Diagnostic Monitor ID. |
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Response SID | SIDPR | 46 | Request SID ORed with 0x40. |
| monitorIdentifier | OBDMID | OBDMID | Echoed OBDMID. |
| testIdentifier | TID | TID | Standardized or manufacturer-defined Test ID. |
| unitAndScalingId | UASID | UAS ID | Encodes the unit and scaling for the test value and limits. |
| testValue | TV | 2 bytes | Test result, 16-bit big-endian. |
| minTestLimit | MINTL | 2 bytes | Minimum test limit, 16-bit big-endian. |
| maxTestLimit | MAXTL | 2 bytes | Maximum test limit, 16-bit big-endian. |
0x07 — Pending DTCs
Reads "pending" DTCs detected during the current or last completed driving cycle, before the MIL is illuminated. Useful to verify a repair after clearing DTCs without waiting for several driving cycles. Same wire format as Service 0x03.
0x07 — Request pending DTCs from current/last driving cycle
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Service ID | SIDRQ | 07 | Request pending DTCs SID. No payload. |
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Response SID | SIDPR | 47 | Request SID ORed with 0x40. |
| numberOfDTCs | #OFDTC | count | Number of DTCs that follow (CAN only). |
| dtcRecord | DTC | 2 bytes per DTC | Two bytes per DTC, same format as Service 0x03. |
0x08 — Control on-board component / system
Drives an on-board component or test routine — for example, commanding an EVAP leak test. Each TID has its own request/response data layout, defined in SAE J1979-DA.
0x08 — Request control of on-board system, test or component
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Service ID | SIDRQ | 08 | Request control SID. |
| testIdentifier | TID | TID | Test ID identifying the system, test or component. |
| dataRecord | DREC | 0–5 bytes (Data A–E) | Optional Test ID-specific parameters (e.g. ON/OFF, duration). |
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Response SID | SIDPR | 48 | Request SID ORed with 0x40. |
| testIdentifier | TID | TID | Echoed Test ID. |
| dataRecord | DREC | 0–5 bytes (Data A–E) | Test ID-specific status / test result. |
0x09 — Request vehicle information
Reads identification data such as the VIN, Calibration ID(s), Calibration Verification Number(s) and the in-use performance tracking (IPT) counters. The INFOTYPE selects what to read; the response includes a "number of data items" byte so the tester knows how many records (e.g. multiple Calibration IDs) follow.
0x09 — Request vehicle information
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Service ID | SIDRQ | 09 | Request vehicle information SID. |
| infoType | INFTYP | INFOTYPE | 1-byte INFOTYPE (e.g. 0x02 = VIN, 0x04 = Calibration ID, 0x06 = CVN). |
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Response SID | SIDPR | 49 | Request SID ORed with 0x40. |
| infoType | INFTYP | INFOTYPE | Echoed INFOTYPE. |
| numberOfDataItems | NODI | count | Number of data items in the response. |
| dataRecord | DREC | INFOTYPE-specific bytes | For INFOTYPE 0x02 (VIN), 17 ASCII bytes. Other INFOTYPEs use their own format. |
0x0A — Permanent DTCs
Reads DTCs with "permanent" status — confirmed DTCs that the ECU stores in non-volatile memory. They cannot be cleared by Service 0x04 or by disconnecting the battery; only the ECU's own monitor can clear them, after observing the fault is no longer present. This is intended to stop drivers from passing emissions inspections by clearing codes right before the test. Same wire format as Service 0x03.
0x0A — Request DTCs with permanent status
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Service ID | SIDRQ | 0A | Request permanent DTCs SID. No payload. |
| Field | Mnemonic | Value | Description |
|---|---|---|---|
| Response SID | SIDPR | 4A | Request SID ORed with 0x40. |
| numberOfDTCs | #OFDTC | count | Number of permanent DTCs that follow. |
| dtcRecord | DTC | 2 bytes per DTC | Two bytes per DTC, same format as Service 0x03. |
Parameter IDs (PIDs)
PIDs identify the values readable through Service 0x01 (current data) and 0x02 (freeze frame data). The full list lives in the SAE J1979-DA digital annex; a small selection is shown below.
Each PID has a fixed response format. The data bytes are conventionally named A, B, C, D and combined per PID into a physical value via a fixed formula. Most PIDs return 1 to 4 data bytes; a few return larger records.
PIDs 0x00, 0x20, 0x40, … are markers: each returns a 4-byte bitmap of which PIDs in the next 32-PID block the ECU supports. Walking these markers lets a tester enumerate every supported PID without prior knowledge of the ECU.
| PID | Bytes | Description | Min | Max | Unit | Formula |
|---|---|---|---|---|---|---|
0x00 | 4 | PIDs supported (0x01 – 0x20) | Bit encoded | |||
0x04 | 1 | Calculated Engine Load | 0 | 100 | % | A / 2.55 |
0x05 | 1 | Engine coolant temperature | -40 | 215 | °C | A − 40 |
0x0C | 2 | Engine speed | 0 | 16383.75 | rpm | (256·A + B) / 4 |
0x0D | 1 | Vehicle speed | 0 | 255 | km/h | A |
0x20 | 4 | PIDs supported (0x21 – 0x40) | Bit encoded | |||
0xA6 | 4 | Odometer | 0 | 429496729.5 | km | (A·2²⁴ + B·2¹⁶ + C·2⁸ + D) / 10 |
Diagnostic Trouble Codes (DTCs)
Another important part of the OBD-II standard are the Diagnostic Trouble Codes (DTCs). These are a standardized way of reporting issues with a vehicle. Each DTC is encoded as a two-byte value. A list of stored DTCs is requested using service 0x03 without any payload.
The first two bits of the 2-byte value indicate the type of DTC: 0b00 for P(owertrain), 0b01 for C(hassis), 0b10 for B(ody), and 0b11 for U (Network). The next two bits encode the first digit of the DTC. The final three sets of 4 bits encode the second, third, and fourth digit of the DTC. For example, the value 0xC158 decodes to the DTC U0158. The DTC U0158 means "Lost Communication With Head Up Display".
CAN Arbitration IDs
For OBD-II over CAN, the Arbitration ID 0x7DF is used, which acts as a broadcast address. ECUs both listen to the broadcast address and to their own address in the range 0x7E0 through 0x7E7. They respond on their own address + 8, so 0x7E8 through 0x7EF.
Some cars use 29-bit Arbitration IDs for OBD-II instead of the standard 11-bit Arbitration ID. The 29-bit broadcast address is 0x18DB33F1, and the ECU addresses are in the range 0x18DAF1xx, responding on 0x18DAxxF1 (swap last two bytes).