← Back to Autonomy
An interactive primer · Vol. I Diagnostics for the Electrified Vehicle

Listening to the Vehicle:
UDS, DTC & the EV diagnostic stack.

A modern car is a parliament of fifty-odd computers, each with its own grievances. This primer is the protocol they answer to — what UDS asks, how a DTC is shaped, and what changes when the powertrain runs on electrons instead of gasoline.

§ IWhy diagnostics exist at all

Imagine a doctor with a stethoscope. Now imagine fifty patients in one room, each with its own heartbeat, each capable of failing silently. That is, more or less, the situation inside a modern car. The diagnostic system is the stethoscope — and more importantly, the language each patient agrees to answer in.

A modern vehicle contains anywhere from 30 to 150 ECUs (Electronic Control Units) — each a small computer with its own firmware, memory, sensors and faults. When something goes wrong, the technician needs to ask, in a uniform way:

To make this possible, the industry standardized one common diagnostic protocol that runs on top of whatever bus the ECU happens to be on. That protocol is UDS — Unified Diagnostic Services, defined in ISO 14229. core idea One language, fifty ECUs, every workshop on Earth.

EV twist. An electrified powertrain adds new patients to the room: a high-voltage battery, an inverter driving a permanent-magnet machine, a DC/DC converter, an on-board charger, an insulation monitor, contactors, a thermal loop. Each speaks UDS too — but with a fault vocabulary your gasoline-era tester never had to learn.

§ IIThe diagnostic stack

UDS doesn't run alone. It sits on top of a transport, which sits on a network, which sits on a wire. Think of it as a letter: UDS is the language inside the envelope, the transport is how the envelope is sealed and segmented, the network decides how envelopes get routed.

UDS
The request/response language. Services like "read this DID", "clear DTCs", "run routine 0x0203".
ISO 14229-1
Transport
Cuts long UDS messages into bus-sized frames and reassembles them. Adds flow control.
ISO-TP (15765-2)
DoIP (13400-2)
Network
The data-link layer — addressing, arbitration, error detection.
CAN, CAN-FD
Automotive Ethernet
Physical
The actual differential pair on copper.
ISO 11898 (CAN)
100/1000BASE-T1
Fig. 1 — The four-layer envelope. UDS is identical regardless of what carries it.

For most of the last twenty years, the wire was a classical CAN bus at 500 kbps, the transport was ISO-TP, and CAN identifiers were assigned in pairs (one for request, one for response) per ECU. EVs and modern domain controllers increasingly use CAN-FD (up to 8 Mbps payload) and, for high-bandwidth or zonal architectures, DoIP (Diagnostics over IP) — the same UDS payload, just inside Ethernet/TCP frames.

Practical. The application layer is identical across all of these. A request like 22 F1 90 ("read the VIN") looks the same whether it travels on CAN, CAN-FD or DoIP. Only the envelope changes. This is what makes UDS such a durable standard.

§ IIIUDS in one breath

Every UDS conversation has the same skeleton: tester sends a request, ECU sends back either a positive response or a negative response. That's it. The shape is brutally simple:

Request
22SID
F1DIDhi
90DIDlo
Positive response (SID + 0x40)
62SID+40
F1DIDhi
90DIDlo
57'W'
44'D'
42'B'
VIN
Negative response
7FNRC marker
22orig SID
31NRC = 0x31

NRC 0x31 = requestOutOfRange. The ECU is saying "I understood you, but that DID is not one I serve."

Fig. 2 — Anatomy of a UDS exchange (here: read DID 0xF1 90, the VIN).

Three patterns to memorize and you can read most UDS traces:

Common NRCs you'll see in the wild: 0x11 service not supported, 0x12 sub-function not supported, 0x13 incorrect message length, 0x22 conditions not correct (often: ECU is not in the right session or the high-voltage system is interlocked), 0x31 request out of range, 0x33 security access denied, 0x7E sub-function not supported in active session, 0x7F service not supported in active session, and the famous 0x78 — "requestCorrectlyReceived, responsePending" — the ECU's way of saying hold on, I'm working on it.

§ IVOBD — the regulated subset

If UDS is a private conversation between the OEM and its workshop, OBD is a public broadcast in a language every emissions inspector on Earth has to speak. It predates UDS by a decade — but today it's best understood as a fixed, legally-mandated subset of UDS, exposing only what the regulator needs to see.

OBD stands for On-Board Diagnostics. It is the part of a vehicle's diagnostic system that is required by law to be present, accessible without special tools, and answer in a standardized way regardless of manufacturer. The 16-pin connector under your dashboard is its physical face. Every $20 scanner from a hardware store talks to it. So does your state's emissions inspection station.

A two-minute history

OBD vs UDS in one table

OBD-IIUDS
StandardSAE J1979, ISO 15031ISO 14229
PurposeEmissions compliance, mandated by regulatorsOEM service, calibration, flashing — anything the OEM wants
Service IDs used0x01 – 0x0A (called "Modes")0x10 – 0x3E, 0x80+ (called "Services")
Parameter space1-byte PIDs (≈256 values, SAE-managed)2-byte DIDs (≈65,536 values, OEM-managed)
Connector accessMandated, tool-free, near steering wheelSame connector physically, but session-locked
SecurityNone — publicSeed/key (0x27), session-gated
DTC scopeEmissions-related onlyEverything (powertrain, chassis, body, network)
Read by a $20 dongle?YesGenerally no (needs OEM tester or known DIDs)
Fig. 3 — OBD-II is a small, public subset of the same diagnostic ecosystem.
Mental model. On a modern CAN-bus car, when you send the byte 0x01 the ECU recognizes it as "OBD-II Mode 01". When you send 0x22 the ECU recognizes it as "UDS Read Data By Identifier". They share the same physical wires and the same response patterns — the OBD modes are simply a reserved low-numbered slice of the service ID space.

The ten modes of OBD-II (SAE J1979)

ModeNameWhat it does
0x01Show current dataReal-time sensor values via PIDs (RPM, speed, coolant temp, MAF, O2 voltage, …). The mode most consumer scanners spend 95% of their time in.
0x02Show freeze-frame dataSnapshot of the PIDs at the moment the most recent emissions DTC was set.
0x03Show stored DTCsList of confirmed emissions-related fault codes.
0x04Clear DTCs & stored dataWipes the emissions DTC list, freeze frames, and resets readiness monitors.
0x05O2 sensor test resultsLegacy — non-CAN only. Replaced by Mode 06 on CAN-based OBD-II.
0x06On-board test resultsNon-continuous monitor test results, indexed by TID (Test ID) and CID (Component ID).
0x07Show pending DTCsFaults seen once but not yet confirmed across cycles.
0x08Control on-board systemsBidirectional control — rare on light-duty, used in heavy-duty/EOBD for component activation.
0x09Vehicle infoVIN, calibration IDs, calibration verification numbers, ECU name.
0x0APermanent DTCs"Sticky" DTCs that cannot be cleared by Mode 04. Only erased when the ECU itself confirms the fault is gone over several drive cycles. Defeats the "clear codes before inspection" trick.
Fig. 4 — The ten OBD-II modes. Service IDs 0x01–0x0A; positive response = mode + 0x40.

So a complete OBD-II read of engine RPM looks like this on the wire:

Request (Mode 01, PID 0x0C — engine RPM)
01Mode
0CPID
Response (Mode + 0x40)
41Mode+40
0CPID
1AA
F8B

Engine RPM is encoded as (256·A + B) / 4. So 1A F8 = 6904/4 = 1726 RPM. Every PID has its own encoding formula in the J1979 spec — most are simple linear scales.

Fig. 5 — Anatomy of an OBD-II PID read.

Mode 01 PID 01 — the "MIL byte" (interactive)

The single most-read piece of OBD-II data is PID 0x01: a 4-byte status word that tells you whether the Check Engine Light is on, how many emissions DTCs are stored, and how many readiness monitors have run. The very first byte ("Byte A") is the part everyone cares about.

Configure the byte
Number of emissions DTCs
0
Byte A on the wire
0x00
0000 0000
Bit 7 = MIL (off). Bits 6–0 = DTC count (0).
Fig. 6 — Mode 01 PID 01, Byte A. The "is your check engine light on" byte.

Bytes B, C, D of the PID 01 response encode readiness monitor status — 11 emissions monitors that must each run to completion before an emissions inspection station will pass the vehicle. The monitors split into:

EV note. For a battery-electric vehicle, almost every readiness monitor is N/A. There is no catalyst, no evap system, no O2 sensor. The vehicle reports those monitors as "not supported" in PID 01. This is also why most BEVs sail through US emissions inspection in seconds — there is no monitor state to evaluate, and the MIL byte is almost always 0x00.

OBD-II on EVs — what's actually required

Until very recently, "OBD for BEVs" was almost a contradiction. With no engine, no catalyst, no evaporative emissions, the entire J1979 framework barely applied. The regulatory situation is changing fast:

EV-relevant PIDs added to SAE J1979 (and J1979-DA / J1979-2 amendments) include:

Practical & reverse-engineering notes for EVs

Don't confuse OBD with ISO 15118. OBD-II is diagnostic communication between a tester and the vehicle, on the 16-pin DLC, over CAN/DoIP. ISO 15118 is communication between the vehicle and an EVSE (charging station) for smart charging, plug-and-charge authentication, and V2G — entirely different physical interface (CP-line PLC or WLAN), entirely different message set. Both are vehicle communication standards, but they speak in different rooms.

§ VThe service catalog (interactive)

UDS defines ~25 services, but in practice you'll touch maybe a dozen. Click any tile to see its request shape, an example, and where it shows up in EV work.

Select a service above

The catalog covers the services you'll actually wire up in CDD/ODX files.

Fig. 7 — Interactive service catalog. Click a tile.

§ VISessions & the seed/key dance

An ECU is not a single piece of cooperative software — it has modes. By default, in defaultSession, it will answer basic identification questions and report DTCs but refuse to change anything important. To unlock dangerous operations, the tester escalates the ECU into a different session, and for the truly dangerous ones, also passes a security check.

The three sessions every ECU has

Fig. 8 — Session state machine. Click a button to transition.

Sessions matter because UDS services are session-gated. You can't write a DID in default session. You can't erase flash unless you're in programming session. The ECU will return NRC 0x7F if you try.

Security access — the seed and the key

For services that touch real state (writing calibration DIDs, erasing flash, unlocking developer routines), UDS layers in service 0x27: a challenge-response handshake.

  1. Tester asks for a seed: 27 01 → ECU replies 67 01 <seed>.
  2. Tester computes a key by running the seed through a secret algorithm (a polynomial, a CMAC, a HSM-backed signature — depends on the OEM and the ECU's ASIL/SecOC level).
  3. Tester sends 27 02 <key>. If the key matches what the ECU computed independently, it replies 67 02 and you're unlocked.
Reality check. In modern EV ECUs the seed/key algorithm is usually held in an OEM-controlled HSM and delivered over signed certificates — not a static XOR mask like in early-2000s diagnostics. The protocol shape is the same; the cryptography behind it is much more serious.

§ VIIThe shape of a DTC

A DTC — Diagnostic Trouble Code — is the receipt the ECU prints when a monitored condition fails. The familiar form P0420 on a scanner screen is a human gloss; on the wire it is three bytes.

Decode any DTC

Try: P0AA6 · P0D2A · U1A14 · C0561

Fig. 9 — DTC decoder. Five-character codes map onto three bytes.

Every five-character DTC encodes into two bytes (plus a third byte for the failure type byte, see below). The mapping:

On the bus, a DTC is always reported as 3 bytes: the 2-byte code above, then a failure type byte (FTB) — an SAE J2012 sub-classification telling you what kind of fault it was (open circuit, short to ground, signal out of range high, signal stuck, performance, etc.). So a complete DTC reference is e.g. C0 5C 12 = "C05C-12" = "HV Battery Cell 12 Voltage — circuit short to battery".

EV note. The SAE J2012 dictionary added a large block of P0Axx–P0Dxx codes specifically for hybrids and EVs: motor/generator faults, inverter faults, traction battery cell faults, charger faults. If a DTC starts with P0A, P0B, P0C, P0D — it almost certainly belongs to your high-voltage or e-machine domain.

§ VIIIThe DTC status byte — a one-byte history

A DTC alone is not very informative — has it just happened? Is it confirmed? Is it intermittent? UDS attaches an 8-bit status byte to every DTC report, where each bit is a flag from ISO 14229-1 Annex D. The status byte is how an ECU compresses an entire diagnostic history into 8 bits.

Click bits to toggle. Bit 0 is rightmost.

Status byte
0x00
In plain English
No bits set — the ECU has never seen this fault.
Fig. 10 — Interactive status byte. The same eight bits every ECU on Earth has to set correctly.

Reading DTCs with 0x19

Service 0x19 has many sub-functions — they all ask "tell me about your DTCs" but slice the set differently. The five you'll use most:

And of course 14 FF FF FFclearDiagnosticInformation with the wildcard group "everything". After a fault is repaired, this is how you reset the DTC memory.

§ IXEV subsystem fault atlas

This is where EVs diverge from ICE diagnostics. Click each subsystem to see what kinds of faults it reports — and what's actually happening physically when those DTCs fire.

Fig. 11 — EV subsystem DTC atlas. Generic / illustrative codes — actual codes vary by OEM.
Cross-cutting EV practical. Many EV ECUs implement a derate ladder before they raise a hard fault. A cell that drifts 80 mV from its neighbors won't immediately throw a DTC — it will first reduce charge power, then reduce discharge power, then warn the driver, and only finally latch a DTC and open contactors. When debugging a "vehicle felt slow" complaint, always read the extended data records (sub-function 0x06), not just the active DTC list: the derate counters and fault occurrence counters tell the real story.

§ XFlashing an ECU — the bootloader handshake

Software updates over UDS are not a single command — they are a choreographed sequence. The basic shape, used by virtually every OEM (with variations), is:

  1. Enter extended session. 10 03 — needed before you can elevate further.
  2. Disable communication. 28 03 01 — stop non-diagnostic CAN traffic so the ECU isn't getting hammered with periodic messages during the flash.
  3. Disable DTC setting. 85 02 — flashing causes legitimate DTCs to fire all over the network; suppress them.
  4. Enter programming session. 10 02 — this typically reboots the ECU into the bootloader. You'll lose the link briefly.
  5. Security access. 27 01 → seed; 27 02 <key> → key. Bootloader has its own seed/key, often stronger than the application's.
  6. Write the fingerprint. 2E F1 5A <tester ID, date> — leaves a forensic record of who flashed this part.
  7. Erase memory. 31 01 FF 00 <addr> <len> — routine 0xFF00, eraseMemory. The ECU returns 0x78 (pending) for several seconds while it actually erases the flash sectors.
  8. Request download. 34 <format> <addr> <len> — ECU answers with the max block size it can accept.
  9. Transfer data. Repeated 36 <blockSeq> <data…> until the whole image is sent. The block sequence counter wraps 01→FF→00→01…
  10. Exit transfer. 37 — "I'm done sending."
  11. Check programming dependencies. 31 01 FF 01 — routine 0xFF01, checkProgrammingDependencies. The ECU verifies the new image's CRC/signature.
  12. ECU reset. 11 01 — hardReset. The ECU reboots into the new application.
  13. Re-enable everything. 85 01 to allow DTCs again, 28 00 01 to re-enable communication.
Field reality. Steps 7 and 8 are where most flash failures happen. If the tester's block size assumption disagrees with what the ECU advertised in step 8, the ECU will NRC every 0x36 with 0x73 (wrongBlockSequenceCounter) or 0x71 (transferDataSuspended). Always parse the response to 0x34 before sending the first 0x36.

§ XITools, files & field notes

The file formats you'll meet

The benches you'll see

EV field notes

§ XIIReferences & further reading

ISO 14229-1 — Unified Diagnostic Services (UDS) — specification and requirements. The canonical UDS document. Annex D defines the status byte bits. Annex A enumerates NRCs.

ISO 14229-3 — UDS on CAN (UDSonCAN). Application-layer specifics for CAN-bound implementations.

ISO 15765-2 — Network & transport layer for CAN (ISO-TP). Defines how UDS messages longer than 7 bytes are segmented across CAN frames with flow control.

ISO 15765-4 — Requirements for emissions-related systems (the CAN-based OBD-II profile). What an ELM327 dongle actually speaks. Constrains baud rate, message format, and ECU response timing.

ISO 15031 (parts 1–7) — Communication between vehicle and external test equipment for emissions-related diagnostics. The umbrella ISO framework that wraps J1979/J2012/J1962 into a single normative reference.

ISO 13400-2 — Diagnostics over Internet Protocol (DoIP). The Ethernet/TCP transport for UDS.

ISO 27145 (parts 1–6) — World-wide Harmonized On-Board Diagnostics (WWH-OBD). The modern UDS-based replacement for the J1979 "modes" framework, mandated for heavy-duty and increasingly extending to light-duty & BEVs.

SAE J1979 / J1979-DA / J1979-2 — E/E Diagnostic Test Modes. The OBD-II PIDs and modes (01–0A). The "-2" amendment adds extensive hybrid and EV PIDs.

SAE J1962 — Diagnostic connector. Defines the 16-pin DLC, pinout, mounting location and accessibility requirements.

SAE J1850 / ISO 9141-2 / ISO 14230-4 (KWP2000) — Legacy pre-CAN OBD-II physical/transport protocols. Phased out for new US vehicles after model year 2008.

SAE J2012 — Diagnostic Trouble Code Definitions. The official DTC dictionary including the P0Axx–P0Dxx hybrid/EV expansion.

SAE J2534 — Pass-thru programming. The US EPA-mandated interface that lets independent shops reflash emissions-related ECUs.

CARB Title 13 CCR §1968.2 & §1962.5 — California OBD-II regulation and the new BEV battery durability monitoring rule (effective 2026 MY).

ISO 15118 (parts 1–20) — Vehicle-to-grid (V2G) communication interface. Not diagnostics — it covers charging-station handshake, plug-and-charge, smart charging. Listed here to disambiguate; OBD and 15118 are often conflated.

ISO 26262 — Road vehicles — Functional safety. Not a diagnostic standard per se, but it's why your fault detection has confirmation counters and why some DTCs are tagged ASIL-relevant.

AUTOSAR Dem & Dcm SWS — Diagnostic Event Manager & Diagnostic Communication Manager software specifications. If your ECU runs AUTOSAR Classic, these two modules are your UDS stack.

ASAM MCD-2 D / ODX — open data format for diagnostic descriptions.

ASAM MCD-2 NET / FIBEX — network description format, often paired with ODX for the dealer tooling chain.