Automotive
UDS Diagnostics
UDS — Unified Diagnostic
Services, ISO 14229 — is the protocol a diagnostic
tool speaks to an ECU: "what's your fault code?", "give me your
VIN", "let me reprogram you." It rides on top of
CAN as a request/response
protocol built on one very literal rule: a response's first byte is
either your request's Service ID plus 0x40 (success), or
0x7F (failure, with a specific reason attached).
- What it is
- A request/response diagnostic protocol riding on CAN, letting a tool query or command an ECU — read fault codes, read live data, reprogram firmware, unlock protected functions.
- Mental model
- A literal question-and-answer protocol: every request is a Service ID plus parameters; every response is either "yes, and here's your answer" or "no, and here's exactly why."
- Key numbers
- Positive response = request SID +
0x40(request0x22→ positive response0x62); negative response is always0x7F. - Reach for it when
- Reading/clearing fault codes, reading live ECU data, unlocking protected diagnostic or programming functions, or building any diagnostic tool integration.
Why a dedicated diagnostic protocol?
A raw CAN frame's meaning is fixed at design time — an identifier always means the same signal, agreed on by every node ahead of time. Diagnostics needs the opposite: an open-ended way for an external tool, from any vendor, to ask an ECU an arbitrary question it wasn't necessarily hardwired to answer. UDS solves this with a standard service catalog and message format every compliant ECU and every compliant tool both understand, without needing a bespoke message design per query.
The request/response pattern and the +0x40 rule
Checking a response is almost embarrassingly simple once you know the rule:
bool uds_is_positive_response(uint8_t request_sid, const uint8_t *response) {
return response[0] == (uint8_t)(request_sid + 0x40);
}
// response[0] == 0x7F means a negative response instead —
// see "Negative responses and NRCs" below for what comes next.
Common UDS services
| SID | Service | Purpose |
|---|---|---|
| 0x10 | Diagnostic Session Control | Switch sessions (default, extended, programming) — some services only work outside the default session. |
| 0x11 | ECU Reset | Request the ECU reset itself (soft or hard reset). |
| 0x14 | Clear Diagnostic Information | Clear stored fault codes. |
| 0x19 | Read DTC Information | Read stored/pending fault codes and their status. |
| 0x22 | Read Data By Identifier | Read a specific data value by its Data Identifier (DID) — VIN, live sensor values, calibration data. |
| 0x27 | Security Access | Seed-key handshake to unlock protected services — see below. |
| 0x2E | Write Data By Identifier | Write a value by DID — calibration, configuration. |
| 0x31 | Routine Control | Start/stop/check a defined ECU routine (a self-test, an actuator test, an erase routine). |
| 0x34 / 0x36 / 0x37 | Request Download / Transfer Data / Request Transfer Exit | The three-step sequence that carries a new firmware image into the ECU during reflashing. |
| 0x3E | Tester Present | A keep-alive so the ECU doesn't time out of a non-default session while the tool is momentarily idle. |
Negative responses and NRCs
A negative response is always three bytes: 0x7F, the
original request's SID (so the tool knows which request failed), and
a Negative Response Code (NRC) saying exactly why.
| NRC | Meaning |
|---|---|
| 0x11 | Service not supported |
| 0x12 | Sub-function not supported |
| 0x13 | Incorrect message length or invalid format |
| 0x22 | Conditions not correct (e.g. wrong session, engine running when it shouldn't be) |
| 0x31 | Request out of range |
| 0x33 | Security access denied |
| 0x78 | Request correctly received, response pending — "still working, don't give up on me yet" |
0x78 is worth calling out specifically: it's not a
failure at all, it's the ECU explicitly buying itself more time on a
slow operation. A tool that doesn't recognize this and extend its
timeout will misread a perfectly successful long-running operation as
a failure.
Security access: the seed-key handshake
Many services (reflashing, calibration writes, certain routines) are locked behind a challenge-response handshake so an arbitrary tool can't invoke them without proving it knows a manufacturer secret:
- Tool requests a seed:
0x27with an odd sub-function (e.g.0x01). - ECU returns a pseudo-random seed value.
- Tool computes a key from that seed using a manufacturer-specific algorithm (often involving a shared secret).
- Tool sends the key back:
0x27with the next even sub-function (e.g.0x02). - ECU validates the key and unlocks the protected services on success, or returns
securityAccessDenied— and counts the failure toward a lockout, on failure.
Carrying UDS on CAN: ISO-TP segmentation
A classical CAN frame carries at most 8 data bytes, but plenty of UDS messages (a VIN, a chunk of firmware) are longer than that. ISO-TP (ISO 15765, the Transport Protocol layer) segments a longer message across multiple CAN frames, using the first byte (or nibble) of each frame's data as a PCI (Protocol Control Information) field that tells the receiver which of four frame types it's looking at:
For a message longer than one frame, the tool and ECU actually coordinate the transfer:
Scan tools and CAN analyzers
- OBD-II scan tool
- A consumer/technician-level tool reading standardized emissions-related fault codes and live data — a narrower, older, legally-mandated sibling of full UDS.
- Professional/OEM diagnostic tool
- Full UDS access — manufacturer-specific DIDs and routines, security access, and firmware reflashing via the download/transfer service sequence.
- CAN analyzer / bus analyzer
- Tools like Vector CANoe/CANalyzer or PCAN-View capture and display every frame on the bus, not just a curated diagnostic session — used for development and debugging, not just repair. See SocketCAN for the Linux-side equivalent.
- J2534 pass-through
- A standardized PC-to-vehicle interface API letting general-purpose PC software (not just a dedicated handheld tool) send and receive diagnostic messages — heavily used by OEM reprogramming software.
Real-world applications
- Repair shop diagnostics — reading and clearing fault codes is the single most common real-world UDS interaction.
- ECU reflashing — the Request Download / Transfer Data / Request Transfer Exit sequence is exactly how new firmware gets into a production ECU, closely related to the staged loading ideas in the boot process.
- End-of-line manufacturing — factory test stations use UDS routines and Write Data By Identifier to calibrate and validate every unit before it ships.
- Automotive security research — understanding UDS's request/response structure, security access, and session model is foundational to any legitimate automotive security assessment.
Gotchas
- Security access lockout is deliberate anti-brute-force protection — repeated failed key attempts trigger a real, sometimes lengthy, time-delay lockout. Mashing "retry" makes it worse, not better.
- A tool that doesn't specifically handle NRC
0x78(response pending) with an extended timeout will misread a slow-but-successful operation as a failure. - Mismatched ISO-TP flow-control timing (block size, minimum separation time) between tool and ECU is a classic real-world cause of "the diagnostic tool just times out for no reason" — it's a pacing bug, not a broken ECU.
- Diagnostic session state matters: a perfectly well-formed request can still fail with
conditionsNotCorrectif the ECU isn't currently in the session (extended, programming) that service requires.