Talking to the car
The port is a gateway, and it is silent
With the engine running and the car moving, a listen-only connection on the OBD-II port’s CAN pins (6 and 14) sees nothing at all. The car’s own traffic stays behind a gateway; the port only carries diagnostic requests and their answers. So:
- Passive sniffing gets you nothing here. Whatever reads this car must transmit requests.
- The bus runs at 500 kbit/s, standard 11-bit ids. (Auto-detecting the speed on a silent bus fails; just open it at 500k.)
- Every frame sent is 8 bytes, padded with
00.
| You send to | It answers on | Who |
|---|---|---|
7DF |
7E8, 7E9 |
everyone (standard OBD-II, functional address) |
7E0 |
7E8 |
engine |
7E1 |
7E9 |
transmission |
784 |
785 |
ABS / stability control |
763 |
764 |
likely the instrument cluster |
| others | see Modules | 15 modules in all |
Standard OBD-II: service 01
Single frame both ways. Ask everyone (7DF) or the engine (7E0):
7DF 02 01 0C 00 00 00 00 00 request: 2 bytes follow, service 01, PID 0C (rpm)
7E8 04 41 0C 0D 44 00 00 00 answer: 41 = "here is 01", PID 0C, A=0D B=44
rpm = (A·256 + B) / 4 = (0x0D·256 + 0x44) / 4 = 849. (Frames copied from a capture, as are the others on this page.)
Asked of 7DF, the transmission (7E9) answers some PIDs too, a millisecond
after the engine. Which PIDs each supports, and how they decode, is on
Standard OBD-II.
Mitsubishi’s own: KWP2000 service 21
“Read data by local identifier”. One byte picks a block; the module answers with the whole block.
784 02 21 56 00 00 00 00 00 ABS: read local id 56
785 04 61 56 00 00 FF FF FF 61 = "here is 21", id 56, data 00 00; padded with FF
Data bytes are numbered from the first byte after 61 <id>. Here byte 0
is 00: the brake pedal switch is released (it reads 82 while pressed).
Some modules pad with FF, others with 00; the length byte says where the
answer ends.
The modules here speak KWP2000 on CAN; only 7F1 speaks UDS. Service 22
(UDS “read data by identifier”) is refused by every KWP module.
Answers longer than 7 bytes: ISO-TP
Most blocks do not fit in one frame. The answer starts with a first frame
(1L LL = total length), then waits for a flow control from you before
sending the rest as consecutive frames (21, 22, … 2F, 20, …).
784 02 21 02 00 00 00 00 00 ABS: read local id 02 (brake pressure)
785 10 0A 61 02 00 51 00 00 first frame: 0x00A = 10 bytes in all
784 30 00 00 00 00 00 00 00 flow control: send the rest, no gaps
785 21 00 00 00 00 FF FF FF consecutive frame 1: the last 4 bytes
Put together, the answer is 61 02 then 00 51 00 00 00 00 00 00; brake
pressure is bytes 3–4, 00 00, foot off the brake. The transmission’s
local id 08 (the gear) is 52 bytes: a first frame and seven consecutive
frames.
Send the flow control to the id the request went to (784 here), not to
the answer id. 30 00 00 means: continue, no block limit, no separation time.
The modules here never needed anything else.
Refusals
A refusal is 7F <service> <code>. What this car sent back:
| Code | Meaning | Seen when |
|---|---|---|
78 |
busy, answer to follow | Some modules, 718 most of all, before answering a block. Keep waiting (a second is plenty) |
12 |
sub-function not supported / bad format | A local id the module does not have. Most of the 256 asked |
33 |
security access denied | A handful of local ids on 73A, 763, 773 and 77B |
11 |
service not supported | 22 on the engine, transmission and ABS; 21 and 1A on 7F1 (UDS) |
80 |
service not supported in this session | 22 on the other KWP modules |
31 |
request out of range | 22 ids other than F190 on 7F1 |
Nothing used here needs a diagnostic session change or security access: every value on this site comes from the default session.
Requests used
All of them are reads.
| Service | What | Used for |
|---|---|---|
01 |
current data (OBD-II) | rpm, boost, coolant, pedal, battery… |
21 <id> |
read local identifier (KWP2000) | gear, brake, odometer, everything Mitsubishi-specific |
1A 87 |
ECU identification (KWP2000) | part numbers |
1A 90 |
VIN (KWP2000) | which modules hold the VIN |
22 F190 |
VIN (UDS) | 7F1 |
3E |
tester present | finding who is there (most refuse it with 12, which still proves they exist) |
To find the modules, every request id from 700 to 7FF was sent 3E 00,
then 22 F1 90, then 1A 90; any answer, even a refusal, gave away a module
and its answer id.
How fast it answers
Time from a request leaving to the first frame of its answer, measured on the bus:
| Asked | Median | 90th percentile |
|---|---|---|
Engine, OBD-II 01 (via 7DF) |
1.7 ms | 3.5 ms |
Transmission 7E1, service 21 |
3.5 ms | 4.7 ms |
ABS 784, service 21 |
4.8 ms | 7.1 ms |
773, service 21 |
4.6 ms | 14.6 ms |
763, 728, service 21 |
14 ms | 15 ms |
In practice, asking one request at a time from a laptop over USB: five standard PIDs in turn came back about 13 times a second each; with the gear and brake blocks added to each round, about 8. A reader on the bus itself, sending the flow control without a round trip to a computer, does better.
Hardware used
- ESP32 DevKit V1 on a MrDIY ESP32 CAN Bus Shield v1.3, plugged into the OBD-II port. The ESP32’s own CAN controller (TWAI), RX on GPIO4, TX on GPIO5.
- The shield’s switch: R makes it physically unable to transmit, RW lets it. This car needs RW for everything.
- Frames went to a laptop over USB, each stamped with its arrival time; captures are in candump format, which SavvyCAN reads.
- The car has to be on: engine running, or ignition ON.