The OBD-II diagnostic protocol is well defined and information about it can be found in On-board Diagnostics. It’s a mish-mash of many diffrerent standards, both physical and electrical, that I’ll refer to as OBD-II. There’s also a complete breakdown of the Services and PIDs (see below) that can be found in On-board Diagnostic PIDs.
I’ll talk a little bit about the protocol here but the main point of this post is to say what OBD-II data the Catheram MBE 9A4 ECU supports and what that looks like on the CAN bus.
OBD-II can be broken down into three main data types:
- Services (previously called “modes”),
- Parameter IDentifiers (PIDs) and,
- OBD-II data
You can find all the relevant standards defined in the first link above… but many of them are behind a pay-wall. So unless you’re prepared to pay for the documents then you have to glean what you can from Google searches like I did.
Fundamentally, the bog-standard OBD-II diagnostic protocol uses a single CAN bus frame (max 8 bytes, but usually less), to request, and then get a response, for a single data value (variable) from the car’s ECU. It is a request response protocol, meaning a scanner, or active device, requests a data value and the ECU responds with the result. Both request and response take up one CAN bus frame.
The basics of the protocol request and response are as follow:
OBD-II CAN Bus Request Frame | |||||||
Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 |
LENGTH | SERVICE ID | Data 0 | Data 1 | Data 2 | Data 3 | Data 4 | Data 5 |
OBD-II CAN Bus Response Frame | |||||||
Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 |
LENGTH | SERVICE ID + 0x40 | Data 0 | Data 1 | Data 2 | Data 3 | Data 4 | Data 5 |
The important points here, from a 9A4 perspective, are:
- LENGTH: First byte of request or response is the number of additional bytes in the message. Note that this is “additional” bytes, in addition to the length byte itself. So, for instance a request for engine coolant temp (PID = 0x05, byte 2) and service ID of 0x01 (byte 1) requires a length of 2, i.e. two bytes (Service ID + PID) in addition to the length byte (byte 0).
- SERVICE ID: See OBD-II and OBD-II PIDs for a list of possible service ID’s. I’ve only verified that a 9A4 only responds to a service ID of 1 so far
- SERVICE ID + 0x40: When responding to a request, 0x40 is added to the service ID, so a request with service ID of 0x01 will get a response service ID of 0x41.
- The ECU always responds with 8 bytes (seems to pad with 0xff)
- 9A4 ECU responds with a CAN ID of 0x18daf101
- Only 15 PIDs are supported by our ECUs, see below for a list
An example request and response for coolant temp might be:
OBD-II CAN Bus Request Frame : Coolant Temp | |||||||
Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 |
0x02 | 0x01 | 0x05 |
… and the response:
OBD-II CAN Bus Response Frame : Coolant Temp | |||||||
Byte 0 | Byte 1 | Byte 2 | Byte 3 | Byte 4 | Byte 5 | Byte 6 | Byte 7 |
0x03 | 0x41 | 0x05 | 0x3d |
We can see here that the ECU responded with a coolant temperature of 0x3d. We then need to refer to the offset and scaling algorithm found again here. For a PID of 0x05, Coolant Temp, the formula is ( Result-40 ), i.e.
Coolant Temp = 0x3d – 40 = 61 -40 = 21 C
There’s not a lot of resolution there, just an integer. That’s one of the reason’s we might like to use either of the MBE Broadcast or MBE ISOTP diagnostic protocols, with the later providing a lot more detail.
PID Discovery
With all these PIDs documented in the standard and cars not having to support them all, there needs to be a way of figuring out what each car can is capable of responding with. This is done with PIDs 0x01, 0x20, 0x40, 0x60, 0x80, 0xA0 and 0xc0.
When a request is made to each of these PIDs, the ECU responds with a bit-field showing which of the next 32 (0x20) PIDs are supported in the 4 data bytes returned in the response, including whether the next+1 set of 32 PIDs are supported at all.
So for our ECUs we get the following communication at the start of a scanning cycle:
1672 16.267925833 0x18db33f1 02 01 00 ff ff ff ff ff 1673 16.269274940 0x18daf101 06 41 00 d8 36 80 19 ff 1724 16.776437588 0x18db33f1 02 01 20 ff ff ff ff ff 1726 16.778090875 0x18daf101 06 41 20 20 00 20 01 ff 1777 17.284954491 0x18db33f1 02 01 40 ff ff ff ff ff 1778 17.287421616 0x18daf101 06 41 40 40 10 00 00 ff
Decoding that a bit, we can see that the 9A4 ECU supports:
PID=0x00 ->; 0x01-0x20: 0xd8368019 PID=0x20 ->; 0x21-0x40: 0x20002001 PID=0x40 ->; 0x41-0x60: 0x40100000
And if we unwrangle all the bits then we’re shown that these ECUs support the following PIDs (definitions reproduced from Wikipedia):
PID (hex) | Data bytes returned | Description | Min value | Max value | Units | Formula |
---|---|---|---|---|---|---|
00 | 4 | PIDs supported [01 – 20] | Bit encoded | |||
4 | Monitor status since DTCs cleared. | Bit encoded | ||||
02 | 2 | Freeze DTC | ||||
04 | 1 | Calculated engine load | 0 | 100 | % | (or ) |
05 | 1 | Engine coolant temperature | -40 | 215 | °C | |
0B | 1 | Intake manifold absolute pressure | 0 | 255 | kPa | |
0C | 2 | Engine RPM | 0 | 16,383.75 | rpm | |
0E | 1 | Timing advance | -64 | 63.5 | ° before TDC | |
0F | 1 | Intake air temperature | -40 | 215 | °C | |
11 | 1 | Throttle position | 0 | 100 | % | |
1C | 1 | OBD standards this vehicle conforms to | Bit encoded | |||
1D | 1 | Oxygen sensors present (in 4 banks) | Similar to PID 13, but [A0..A7] == [B1S1, B1S2, B2S1, B2S2, B3S1, B3S2, B4S1, B4S2] | |||
20 | 4 | PIDs supported [21 – 40] | Bit encoded | |||
23 | 2 | Fuel Rail Gauge Pressure (diesel, or gasoline direct injection) | 0 | 655,350 | kPa | |
33 | 1 | Absolute Barometric Pressure | 0 | 255 | kPa | |
40 | 4 | PIDs supported [41 – 60] | Bit encoded | |||
42 | 2 | Control module voltage | 0 | 65.535 | V | |
4C | 1 | Commanded throttle actuator | 0 | 100 | % |
Example OBD-II Communications
Here’s one full cycle of output that my scanner pulled from my car. Obviously, the scanner is attempting to show “real time” data and so repeatedly sends requests for each of the data values that the ECU supports, then repeats again and again to give the impression of “real time” output.
Here’s the Raw CAN bus frames first, followed by what Wireshark decodes the packets as.
# Time CAN ID Data 1891 18.384234117 0x18db33f1 02 01 02 ff ff ff ff ff 1892 18.386480284 0x18daf101 04 41 02 22 26 ff ff ff 1948 18.932752338 0x18db33f1 02 01 04 ff ff ff ff ff 1949 18.933708266 0x18daf101 03 41 04 00 ff ff ff ff 2004 19.480255834 0x18db33f1 02 01 05 ff ff ff ff ff 2006 19.482689349 0x18daf101 03 41 05 3d ff ff ff ff 2061 20.029324990 0x18db33f1 02 01 0b ff ff ff ff ff 2062 20.031880206 0x18daf101 03 41 0b c8 ff ff ff ff 2118 20.578419385 0x18db33f1 02 01 0c ff ff ff ff ff 2119 20.581109100 0x18daf101 04 41 0c 00 00 ff ff ff 2175 21.127303969 0x18db33f1 02 01 0e ff ff ff ff ff 2176 21.128371192 0x18daf101 03 41 0e 80 ff ff ff ff 2231 21.674841186 0x18db33f1 02 01 0f ff ff ff ff ff 2233 21.676107628 0x18daf101 03 41 0f 38 ff ff ff ff 2288 22.222260164 0x18db33f1 02 01 11 ff ff ff ff ff 2289 22.224313834 0x18daf101 03 41 11 39 ff ff ff ff 2345 22.771129266 0x18db33f1 02 01 1c ff ff ff ff ff 2346 22.773691168 0x18daf101 03 41 1c 06 ff ff ff ff 2402 23.320629505 0x18db33f1 02 01 1d ff ff ff ff ff 2403 23.323019928 0x18daf101 03 41 1d 01 ff ff ff ff 2459 23.869724288 0x18db33f1 02 01 23 ff ff ff ff ff 2460 23.872168914 0x18daf101 04 41 23 00 f0 ff ff ff 2515 24.419230119 0x18db33f1 02 01 33 ff ff ff ff ff 2517 24.421439008 0x18daf101 03 41 33 00 ff ff ff ff 2572 24.968236310 0x18db33f1 02 01 42 ff ff ff ff ff 2573 24.969567270 0x18daf101 04 41 42 2d ad ff ff ff 2629 25.516453162 0x18db33f1 02 01 4c ff ff ff ff ff 2630 25.518540406 0x18daf101 06 41 4c 00 ff ff ff ff
… and here’s how Wireshark decodes those raw CAN bus frames:
# Time ID Info 1891 18.384234117 [18db33f1] Freeze DTC 1892 18.386480284 [18daf101] Freeze DTC: < 22 26 > 1948 18.932752338 [18db33f1] Calculated engine load 1949 18.933708266 [18daf101] Calculated engine load: 0.00 % 2004 19.480255834 [18db33f1] Engine coolant temperature 2006 19.482689349 [18daf101] Engine coolant temperature: 21 °C 2061 20.029324990 [18db33f1] Intake manifold absolute pressure 2062 20.031880206 [18daf101] Intake manifold absolute pressure: 200 kPa 2118 20.578419385 [18db33f1] Engine RPM 2119 20.581109100 [18daf101] Engine RPM: 0.00 rpm 2175 21.127303969 [18db33f1] Timing advance 2176 21.128371192 [18daf101] Timing advance: 0.00 °BTDC 2231 21.674841186 [18db33f1] Intake air temperature 2233 21.676107628 [18daf101] Intake air temperature: 16 °C 2288 22.222260164 [18db33f1] Throttle position 2289 22.224313834 [18daf101] Throttle position: 22.35 % 2345 22.771129266 [18db33f1] OBD standards 2346 22.773691168 [18daf101] OBD standards: EOBD 2402 23.320629505 [18db33f1] Oxygen sensors present (4 banks) 2403 23.323019928 [18daf101] Oxygen sensors present (4 banks): Bank1 sensors: 1 , Bank2 sensors: None, Bank3 sensors: None, Bank4 sensors: None 2459 23.869724288 [18db33f1] Fuel Rail Gauge Pressure 2460 23.872168914 [18daf101] Fuel Rail Gauge Pressure: 2400 kPa 2515 24.419230119 [18db33f1] Absolute Barometric Pressure 2517 24.421439008 [18daf101] Absolute Barometric Pressure: 0 kPa 2572 24.968236310 [18db33f1] Control module voltage 2573 24.969567270 [18daf101] Control module voltage: 11.693 V 2629 25.516453162 [18db33f1] Commanded throttle actuator 2630 25.518540406 [18daf101] Commanded throttle actuator: 00
So, the MBE 94A’s support the OBD-II diagnostic protocol. It’s not a huge amount of info that can be gleaned from the car, just 15 data points, but it’s more than is available from the default MBE Broadcast protocol.
Leave a Comment