AI-generated text still pending human review/editing.
ISO-TP transport ↗

UDS & ISO 14229

Unified Diagnostic Services is the standard diagnostic language of modern vehicles. It's what a dealer scan tool, a flashing tool, or an end-of-line tester speaks to read fault codes, log data, run actuator tests, unlock security, and reprogram ECUs. On CAN it rides the same ISO-TP (ISO 15765-2) transport sloppyCAN already speaks. UDS just defines the application layer on top.

Request / response grammar

Every exchange follows the same convention. Learn it once and every service reads the same way:

Tester → ECU
22 F1 90
ReadDataByIdentifier, DID 0xF190 (VIN)
→
ECU → tester
62 F1 90 …
positive response (0x22 + 0x40), DID echoed, then data

For the transport mechanics, how a long response splits into First Frame + Flow Control + Consecutive Frames, see the ISO-TP Explainer.

Services you'll actually use

There are dozens of services in ISO 14229, but a handful cover most day-to-day work. These are exactly the buttons in sloppyCAN's UDS palette:

SIDServiceWhat it does
10DiagnosticSessionControlSwitch session: default / programming / extended. Unlocks the rest.
11ECUResethardReset / keyOffOn / softReset.
19ReadDTCInformationRead fault codes by a sub-function + status mask.
22ReadDataByIdentifierRead a value by 16-bit DID (e.g. F190 VIN).
14ClearDiagnosticInformationClear DTCs for a group (FFFFFF = all).
27SecurityAccessSeed/key challenge to unlock protected services.
28CommunicationControlEnable/disable normal Rx/Tx messaging.
2EWriteDataByIdentifierWrite a value by DID.
31RoutineControlStart / stop / get results of an on-ECU routine.
3ETesterPresentHeartbeat that keeps a non-default session alive.
85ControlDTCSettingTurn DTC logging on/off during a test.

Sessions & security

At power-up an ECU is in the default session, where it answers only safe, read-only requests. Anything intrusive, writing data, running actuators, flashing, first needs an extended or programming session (10 03 / 10 02), and usually a SecurityAccess unlock (27). You request a seed, compute a key with the manufacturer's secret algorithm, and send it back.

StepRequestMeaning
110 03Enter extended diagnostic session
227 01SecurityAccess, request seed (response: 67 01 <seed>)
327 02 <key>Send computed key (response: 67 02 = unlocked)
42E F1 90 …Now a protected WriteDataByIdentifier is accepted
53E 00TesterPresent, keep the session alive while you work

TesterPresent matters. If the tester goes quiet for the session timeout (typically ~5 s), the ECU drops back to the default session and you lose your unlock, so tools send 3E 00 on a heartbeat.

Negative response codes (NRCs)

When an ECU rejects a request it replies 7F <sid> <nrc>. The most common NRCs you'll meet:

NRCNameUsually means
11serviceNotSupportedThis ECU doesn't implement that service
12subFunctionNotSupportedService exists, that sub-function doesn't
22conditionsNotCorrectWrong session/state for this request
31requestOutOfRangeBad DID / parameter value
33securityAccessDeniedNeed a SecurityAccess unlock first
7E / 7F…InActiveSessionService/sub-function not allowed in the current session

Common diagnostic IDs

Most ECUs use a fixed pair of CAN IDs for diagnostics: one the tester transmits requests on, one the ECU replies on. The exact numbers vary by OEM, but these are the conventions you'll see most often:

Request IDResponse IDConvention
7E07E8OBD-II / UDS, ECU #1 (engine), classic "7E0-7E7 / 7E8-7EF" physical addressing range
7E17E9ECU #2 (often transmission)
7DF- (multiple)OBD-II functional request, every ECU that supports the PID may answer
18DA xx F118DA F1 xxExtended (29-bit) UDS addressing, xx is the ECU's source address

These pairs are just convention, not part of the UDS standard itself. The actual IDs are configured per ECU and per OEM. sloppyCAN's UDS palette defaults to 7E0/7E8, but you can change them to match the bus you're on.

Broadcast IDs and their limits

A few IDs are deliberately heard by every node on the bus instead of one. They're useful, but they come with a catch: there's no single device to talk back to you.

IDStandardWhat it doesLimitation
7DFOBD-IIFunctional request, "whoever supports this PID, answer"Multiple ECUs may all reply, staggered by the stack. Fine for polling, unusable for anything needing a single deterministic response
18DB33F1UDS (extended)Functional addressing equivalent of 7DF for 29-bit UDSSame multi-responder problem; also can't carry a SecurityAccess-gated unlock meant for one ECU
PDU1 to DA 0xFFJ1939Global destination address 0xFF in a PDU1 message (and every PDU2 broadcast), "all nodes," used for things like time/date broadcastsNothing tells you who received it: the Acknowledgment PGN (59392) is only sent by a node that was addressed specifically, so a global request may get many answers, or none

Broadcast isn't acknowledged by anyone in particular. CAN does have a wired-AND ACK slot, and it is filled on a broadcast frame just like any other, but it only means "at least one node on the bus received this frame intact". It names nobody, and a node that heard the frame but doesn't implement the service still ACKs it. So both UDS functional requests and J1939 global PGNs are fire-and-forget at the application layer. If you need confirmation that a specific ECU received something, address it physically (UDS request ID, or a J1939 destination-specific PGN) and wait for its actual reply, not the CAN ACK bit.

UDS vs OBD-II vs KWP2000

All three ride ISO-TP on CAN. OBD-II (SAE J1979) is the legally-mandated, emissions-only subset: fixed PIDs, no sessions, no security. KWP2000 (ISO 14230) is UDS's older cousin; same grammar, a few service IDs collide and mean different things. UDS is the full modern toolbox. sloppyCAN switches between all three from the protocol toggle on the ISO-TP tab.

Try it

On the ISO-TP tab select UDS and turn on Demo. The palette buttons each transmit a real request. The ones with a ▾ caret open a small panel where you pick a sub-function (e.g. session type) or type a hex argument (e.g. a DID), then Send. A simulated ECU answers, and unknown services come back as 7F <sid> 11 (serviceNotSupported). You can also type any hex into the input directly, e.g. 22 F1 90 or 10 03.