CAN Calibration Protocol (CCP)

CCP is another diagnostic protocol on CAN. It's used during debugging and final tuning or calibration of an ECU. Therefore, it mostly contains commands to read and write memory on the ECU. Even though it's not supposed to be used post-production, it's sometimes left enabled on production cars, or can be enabled using UDS. CCP is therefore a very useful protocol to know about.

History

  • 1992 — CCP 1.0 initial release
  • 1995 — CCP 1.01 standardized
  • 1996 — CCP 2.0 standardized
  • 1999 — CCP 2.1 standardized

Protocol

The CCP protocol defines two types of messages, one for each direction between the tester and the ECU. Messages from tester to ECU are called CRO (Command Receive Object). Messages from ECU to tester are called DTO (Data Transfer Object).

Command Receive Object (CRO)

The CRO is used to send commands from the Tester to the ECU. It's an 8-byte message. The first byte is the command. The command is followed by a one-byte counter. The counter increases by one after each command and wraps after reaching 255. The counter is used to match the CRO with the DTO. The rest of the message is command-specific data.

TesterECUCRO frame layout
commandcounter6 bytes, command-specific
FieldMnemonicValueDescription
Command CodeCMDcommandIdentifies the requested command (e.g. 0x01 CONNECT, 0x03 DNLOAD).
Command CounterCTRcounterIncrements per command, wraps at 0xFF → 0x00. The DTO echoes this value.
Parameters & dataDATA6 bytes, command-specificLayout depends on the command. Unused bytes are "don't care".

Data Transfer Object (DTO)

There are three different options for the DTO. All types of DTO start with a PID indicating the type of DTO.

  • Command Return Message (PID = 0xFF) — Response to a CRO from the tester. The second byte of the message is the Command Return Code, which is 0x0 for a successful command, or non-zero in case of an error. The rest of the message is command-specific data. The DTO is always 8 bytes in size, padded if needed.
  • Event Message (PID = 0xFE) — Sent based on a status change in the ECU. The second byte is the event code, and the rest of the message is event-specific data. Since the DTO is not sent as a response to a CRO, the CTR value is not defined. Always 8 bytes, padded if needed.
  • Data Acquisition Message (0x0 ≤ PID ≤ 0xFD) — Frame containing data as a response to a (periodic) Data Acquisition Request. The PID is used to identify the data and matches the entry in the ODT. The message can have a variable length and should not be padded.
ECUTesterDTO — Command Return / Event Message
0xFF / 0xFEcodecounter5 bytes, command-specific
FieldMnemonicValueDescription
Packet IDPID0xFF / 0xFE0xFF = Command Return. 0xFE = Event Message.
Return / Event codeERRcode0x00 = acknowledge for Command Returns. Non-zero values are error or event codes.
Command CounterCTRcounterFor Command Returns, echoes the CTR from the matching CRO. Don't-care for Event Messages.
Parameters & dataDATA5 bytes, command-specificLayout depends on the command or event. Always padded to 8 bytes total.
ECUTesterDTO — Data Acquisition Message
0x00 – 0xFDup to 7 bytes
FieldMnemonicValueDescription
Packet IDPID0x00 – 0xFDIdentifies the Object Descriptor Table (ODT) within the DAQ list.
DAQ dataDATAup to 7 bytesPeriodic data from the ECU. Variable length, not padded.

Commands

A few interesting commands are described below. For the full list see the CCP standard.

0x01CONNECT

The CONNECT command is the first step in establishing a connection with the ECU. The CONNECT command has a single two-byte parameter (little-endian), the Station Address. By adding a Station Address to the connect step, it's possible to have multiple ECUs listen for CCP on the same Arbitration ID. The Station Address parameter might also be ignored by the ECU, in which case it will respond to any Station Address.

Example of connecting to an ECU with Station Address 0x0040. The command counter is 0x00:

CONNECT — open a session with station 0x0040

TesterECU
0100400000000000
FieldMnemonicValueDescription
Command CodeCMD010x01 = CONNECT.
Command CounterCTR00First command in the session.
Station addressSTA40 00Little-endian station address (0x0040).
Don't care00 00 00 00Unused. Padded to 8 bytes.
ECUTester
FF00000000000000
FieldMnemonicValueDescription
Packet IDPIDFF0xFF = Command Return Message.
Return CodeERR000x00 = acknowledge.
Command CounterCTR00Echoed CTR from the CRO.
Don't care00 00 00 00 00Padded to 8 bytes.

0x02SET_MTA

The SET_MTA command sets the Memory Transfer Address (MTA) pointer to a user-specified address. This data pointer is then used in subsequent commands. There are two data pointers, MTA0 and MTA1. The MTA number is specified in the CRO. MTA0 is used for DNLOAD, UPLOAD, DNLOAD_6, SELECT_CAL_PAGE, CLEAR_MEMORY, PROGRAM, and PROGRAM_6 commands. MTA1 is used as the destination pointer for the MOVE command.

SET_MTA — point MTA0 at 0x34002000 (extension 0x02)

TesterECU
0223000234002000
FieldMnemonicValueDescription
Command CodeCMD020x02 = SET_MTA.
Command CounterCTR23Per-command counter.
MTA numberMTA#000x00 = MTA0 (used for downloads/uploads). 0x01 = MTA1 (MOVE destination).
Address extensionEXT02Memory device / page selector. Implementation-specific.
AddressADDR34 00 20 0032-bit big-endian address. 0x34002000 here.
ECUTester
FF00230000000000
FieldMnemonicValueDescription
Packet IDPIDFF0xFF = Command Return Message.
Return CodeERR000x00 = acknowledge.
Command CounterCTR23Echoed CTR.
Don't care00 00 00 00 00Padded to 8 bytes.

0x03DNLOAD

The DNLOAD command is used to write data to the ECU. The data is written to the address specified by the MTA0 pointer. The length of the data is specified in the CRO. The CRO can contain up to 5 bytes of data. The MTA0 pointer is automatically increased by the amount of data written, so multiple DNLOAD commands can be issued in a row to write a large amount of data. The acknowledgment response from the ECU contains the value of the new MTA0 pointer.

DNLOAD — write 5 bytes at MTA0

TesterECU
0323051011121314
FieldMnemonicValueDescription
Command CodeCMD030x03 = DNLOAD.
Command CounterCTR23Per-command counter.
SizeSIZE05Number of data bytes that follow (1–5).
DataDATA10 11 12 13 14Up to 5 bytes to write at MTA0. MTA0 is post-incremented by `size`.
ECUTester
FF00230234002005
FieldMnemonicValueDescription
Packet IDPIDFF0xFF = Command Return Message.
Return CodeERR000x00 = acknowledge.
Command CounterCTR23Echoed CTR.
New MTA0 ext.EXT02MTA0 address extension after post-increment.
New MTA0 addressADDR34 00 20 05MTA0 after post-increment by `size` (0x34002000 + 5).

0x23DNLOAD_6

Using the DNLOAD command, one byte of payload is lost to the length byte. If large batches of data need to be written, the DNLOAD_6 command can be used to download data in fixed chunks of 6 bytes.

DNLOAD_6 — write a fixed 6-byte block

TesterECU
2325101112131415
FieldMnemonicValueDescription
Command CodeCMD230x23 = DNLOAD_6.
Command CounterCTR25Per-command counter.
DataDATA10 11 12 13 14 15Always exactly 6 bytes. MTA0 is post-incremented by 6.
ECUTester
FF00250234002006
FieldMnemonicValueDescription
Packet IDPIDFF0xFF = Command Return Message.
Return CodeERR000x00 = acknowledge.
Command CounterCTR25Echoed CTR.
New MTA0 ext.EXT02MTA0 address extension after post-increment.
New MTA0 addressADDR34 00 20 06MTA0 after post-increment by 6.

0x04UPLOAD

The UPLOAD command can be used to read data from the ECU. This can be useful to dump the flash or RAM contents of the ECU for reverse engineering. The ECU will reply with the requested size of data. The MTA0 pointer is incremented automatically.

UPLOAD — read 4 bytes from MTA0

TesterECU
0423040000000000
FieldMnemonicValueDescription
Command CodeCMD040x04 = UPLOAD.
Command CounterCTR23Per-command counter.
SizeSIZE04Number of bytes to read (1–5). MTA0 is post-incremented by `size`.
Don't care00 00 00 00 00Unused.
ECUTester
FF00231011121300
FieldMnemonicValueDescription
Packet IDPIDFF0xFF = Command Return Message.
Return CodeERR000x00 = acknowledge.
Command CounterCTR23Echoed CTR.
DataDATA10 11 12 13Requested bytes from MTA0.
Don't care00Padded to 8 bytes.

0x0FSHORT_UP

While the UPLOAD command can be used to read data from the ECU, it first requires setting the MTA0 pointer using the SET_MTA command. If you only want to read data from the ECU and want to keep track of the current pointer on the tester side, the SHORT_UP command can be used. This command requests up to 5 bytes from an address specified in the CRO. The MTA0 pointer is not changed by this command.

SHORT_UP — read 4 bytes from 0x12345678

TesterECU
0F23040012345678
FieldMnemonicValueDescription
Command CodeCMD0F0x0F = SHORT_UP.
Command CounterCTR23Per-command counter.
SizeSIZE04Number of bytes to read (1–5).
Address extensionEXT00Memory device / page selector.
AddressADDR12 34 56 7832-bit big-endian source address.
ECUTester
FF00231011121300
FieldMnemonicValueDescription
Packet IDPIDFF0xFF = Command Return Message.
Return CodeERR000x00 = acknowledge.
Command CounterCTR23Echoed CTR.
DataDATA10 11 12 13Requested bytes. MTA0 is unchanged.
Don't care00Padded to 8 bytes.

Error Codes

CodeDescription
0x00Acknowledge / no error
0x01DAQ processor overload
0x10Command processor busy
0x11DAQ processor busy
0x12Internal timeout
0x18Key request
0x19Session status request
0x20Cold start request
0x21Cal. data init. request
0x22DAQ list init. request
0x23Code update request
0x30Unknown command
0x31Command syntax
0x32Parameter(s) out of range
0x33Access denied
0x34Overload
0x35Access locked
0x36Resource / function not available

Scanning for CCP

The CONNECT command is a great way to scan for ECUs that accept CCP connections. You have to iterate over all possible Arbitration IDs and Station Addresses, which is quite a large space to search. However, most of the time the Arbitration ID will be between 0x600 and 0x7FF, and the Station Address will be between 0x0 and 0x40. Sometimes the Station Address is ignored by the ECU.