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

XCP: reading and writing ECU memory over CAN

XCP (the Universal Measurement and Calibration Protocol, ASAM MCD-1) is how calibration tools peek and poke an ECU's RAM/flash live: read a memory address, write a calibration constant, or stream signal values at high rate (DAQ). It runs over many transports; this page covers XCP-on-CAN, which the sloppyCAN XCP tab decodes and can actively drive.

CRO and DTO

XCP-on-CAN uses exactly two CAN identifiers, configured from the ECU's A2L file. There's no standard pair, every project picks its own, so always check the A2L:

CRO: master → slave (e.g. 0x7E0)
F4SHORT_UPLOAD
08#bytes
00rsvd
00addr ext
00 10 00 20address (per byte order)
DTO: slave → master (e.g. 0x7E8)
FFRES (positive)
12 34 56 78 9A BC DEuploaded bytes

DTO first byte: the packet class

Byte 0ClassMeaning
0xFFRESPositive command response, decode it in the context of the command you sent
0xFEERRError. Byte 1 is the error code (e.g. 0x20 ERR_CMD_UNKNOWN)
0xFDEVEvent packet (DAQ overload, session terminated, …)
0xFCSERVService request packet
0x00–0xFBDAQMeasurement data: the first byte is the PID (ODT number); the rest is sampled signal data

Why pairing matters: a bare FF RES carries no hint of what it answers. The same FF … means resources+versions after CONNECT, but raw memory bytes after UPLOAD. The XCP tab remembers the last command and decodes the response in that context, which is what makes the log readable.

CONNECT and byte order

Everything starts with CONNECT (0xFF). The positive response tells the master what the slave can do:

CONNECT response: 0xFF …
FFRES
15resource
00COMM_MODE_BASIC
08MAX_CTO
08 00MAX_DTO
01proto ver
01transport ver

Don't hardcode little-endian. Byte order is per-slave and only known after CONNECT. The XCP tab learns it from the response and offers a manual override for decoding traffic you captured before the CONNECT.

Reading and writing memory

CmdNameWhat it does
0xF6SET_MTASet the Memory Transfer Address (addr ext + 32-bit address)
0xF5UPLOADRead N bytes from the MTA; MTA auto-advances
0xF4SHORT_UPLOADOne-shot read: #bytes + address in one frame, no prior SET_MTA needed. The easiest read
0xF0DOWNLOADWrite N bytes to the MTA. Changes ECU memory

The XCP tab's Read memory form sends a single SHORT_UPLOAD and hex-dumps the response. Write memory sends SET_MTA then DOWNLOAD, behind a second explicit confirm, because it modifies the ECU.

Active XCP is not read-only by nature. DOWNLOAD writes real calibration/RAM. The tab gates every transmit on a live bus, the listen-only checkbox being off, and a one-time session confirm; writes add their own confirm. Only point it at a bench ECU you control.

DAQ: streaming measurements

DAQ (Data AcQuisition) is XCP's high-rate measurement mode: instead of polling addresses, the master configures DAQ lists (which signals, how often) and the slave then pushes DTO packets autonomously. Each DAQ DTO's first byte is a PID identifying the ODT (object descriptor table), and the rest is packed signal data.

DAQ data DTO: first byte is the PID (ODT number)
00PID / ODT
E8 03signal A (u16 LE)
5Csignal B
07counter
00 00 00-

Full DAQ authoring is a sequence: FREE_DAQ → ALLOC_DAQ → ALLOC_ODT → ALLOC_ODT_ENTRY → SET_DAQ_PTR → WRITE_DAQ → SET_DAQ_LIST_MODE → START_STOP_DAQ_LIST. The XCP tab covers the read-capability + start/stop end of this (GET_DAQ_PROCESSOR_INFO 0xDA, START_STOP_SYNCH 0xDD) and passively classifies incoming DAQ DTOs by PID; building DAQ lists from an A2L is left as future work.

The active session

1 CONNECT → 2 GET_STATUS / GET_COMM_MODE_INFO → 3 SHORT_UPLOAD (read) / DOWNLOAD (write) → 4 DAQ start → stream → stop → 5 DISCONNECT

Single transaction in flight. XCP is request/response: send one CRO, wait for its RES/ERR before the next. The tab enforces this (like the ISO-TP/UDS tab) and times out if the slave goes quiet. Turn on Demo mode to drive the whole flow against a simulated slave, including a live DAQ stream, with no hardware.

Common error codes

CodeName
0x10ERR_CMD_BUSY
0x11ERR_DAQ_ACTIVE
0x20ERR_CMD_UNKNOWN, command not implemented
0x21ERR_CMD_SYNTAX, malformed command
0x22ERR_OUT_OF_RANGE, parameter out of range
0x23ERR_WRITE_PROTECTED
0x24ERR_ACCESS_DENIED
0x25ERR_ACCESS_LOCKED, Seed & Key required
0x32ERR_VERIFY, slave's verify routine failed