CCP / XCP on CAN Explained - A Simple Intro [2025]
Need a simple intro to CCP/XCP on CAN bus?
In this practical tutorial, we introduce the basics of the CAN Calibration Protocol (CCP) and the Universal Measurement and Calibration Protocol (XCP) on CAN. In particular, we'll focus on the CCP/XCP frame structures, trace examples and A2L files.
We also cover practical ECU data logging via polling/DAQ - and how to decode the data.
Tip: See also our simple intro to A2L files.
What is CCP/XCP?
The CAN Calibration Protocol (CCP) is an interface that enables read/write access to an Electronic Control Unit (ECU). It enables calibration, data measurement, flashing and more.
The Universal Measurement and Calibration Protocol (XCP) is the successor to CCP with various improvements - including support for more transport layers such as Ethernet, FlexRay and SxL.
The CCP/XCP protocols have extensive overlaps, but also important differences. To avoid confusion, we will first focus on covering the CCP protocol - and subsequently go through XCP on CAN with explicit clarification on important differences.
To understand the motivation for CCP/XCP, let's revisit our simple intro to CAN bus. As explained here, CAN enables communication of data between different ECUs in a vehicle/machine. Inputs and outputs of every ECU will be broadcast on the CAN bus. However, the inner workings of an ECU is a blackbox.
Here, CCP/XCP provides direct access to the inner workings of an ECU. This lets you request high-frequency parameter data that may otherwise only be known to the ECU. Further, it also lets you modify the ECU algorithms and variables, making it easy to test and calibrate ECUs. Importantly, CCP/XCP enables these interfaces in a standardized way across ECU manufacturers.
History of CCP/XCP
The CAN Calibration Protocol (CCP) was originally developed by a calibration systems company, Helmut Kleinknecht. Within a few years, it was improved by a working group, ASAP (Arbeitskreis zur Standardisierung von Applikationssystemen) that included Audi, BMW, VW and others. Later ASAP was renamed to ASAM (Association for Standardization of Automation and Measuring Systems).
Below are the key milestones:
- 1992: CCP 1.0 initial release by Helmut Kleinknecht
- 1995: CCP 1.01 standardized by ASAP
- 1996: CCP 2.0 released by ASAP
- 1998: Drafts of CCP 2.01 and CCP 2.1 were prepared
- 1999: CCP 2.1 was released in February
- 2003: XCP 1.0 incl. support for CAN, Ethernet, SPI, USB
- 2008: XCP 1.1 incl. support for FlexRay
- 2013: XCP 1.2 incl. ECU description file updates + CAN FD
- 2015: XCP 1.3 incl. ECU states, bypass handling, time correlation
- 2017: XCP 1.4 incl. Improvements and new DAQ mode
- 2017: XCP 1.5 incl. software debugging without a debug adapter
Today, XCP (aka ASAM MCD-1 XCP) is the successor to CCP (aka ASAM MCD-1 CCP). However, in practice many ECUs still use CCP, which makes it relevant to understand both protocols and key differences.
Master-slave architecture
The CCP/XCP protocol is based on a single-master/multi-slave concept. An external measurement & calibration tool (e.g. a PC/device/data logger) serves as the master and is able to read/write from one or more ECUs aka slaves.
The interface between the master and slave is called ASAP1 or ASAM MCD-1. The CCP/XCP standard also describes the ASAP2 or ASAM MCD-2 MC interface between the master and an ECU description file. In practice, this database describes all relevant information about an ECU in a standardized file format called A2L (ECU Description Files) - which we will cover shortly.
CCP/XCP use cases
The CCP/XCP protocol enables multiple use cases:
- Plug & play ECU measurement and calibration
- Recording of ECU data at microsecond resolution
- Access to data internal to the ECU (not broadcast on CAN)
- Measurement via polling or based on events (time, triggers)
- Real-time calibration/adjustment of ECU algorithm variables
- Flash programming of ECUs
- Optional authentication for secure access
- Mainly for OEM development - rarely used post production
Major changes in XCP vs. CCP
- XCP adds support for CAN FD, Ethernet, FlexRay, SxL and more
- Less interpretation - more consistent implementations
- New 'stimulation' (STIM) mode for bypassing ECU calculations
- Predefined/dynamic DAQ lists for efficient communication
- Support for synchronous use of different DAQ modes
- ECU auto detection (master can poll slaves for information)
- More precise data acquisition by measuring ECU timestamps
- More data throughput via new optional commands
CCP/XCP vs. UDS
Before we deep-dive further on CCP/XCP, it can be useful to understand the role of these communication protocols vs. a slightly similar protocol, Unified Diagnostic Services (UDS).
As evident from the illustration, CCP/XCP is designed specifically for pre-launch measurement and calibration by the OEMs. Typically, the CCP/XCP access to ECUs is disabled once vehicles are ready for launch. In contrast, UDS is typically not available in early stage prototype development and only later added - also being available for communication post launch.
UDS focuses on diagnostics, whereas the diagnostics capabilities of CCP/XCP are light-weight. UDS may also be used by e.g. field technicians and in OEM specific scan tools.
The two protocols do share similarities, though - e.g. in their support for polling/cyclic data acquisition, ECU flashing and read/write access by address (CCP/XCP) or ID (UDS).
CCP - the basics
To understand how CCP communication works we will first review the CCP message types.
Overall, CCP communication is done through a request/response logic using specific CAN IDs and data payloads - similar to OBD2 and UDS. Two types of messages are used: The Command Receive Object (CRO) and the Data Transmission Object (DTO).
CCP CAN frame identifiers
In CCP, two CAN identifiers are used: One for messages sent by the master (e.g. 0x701) and one for messages sent by the slave (e.g. 0x702). These are specified in the A2L (ECU Description File).
Note: In CCP, the master does not address specific ECUs via the CAN IDs - but rather through a connect sequence (more below).
CRO - Command Receive Object
The Command Receive Object (CRO) is a CAN frame sent by the master to an ECU. The 1st byte of the data payload is the command byte (CMD). This controls what command is being issued by the master to the ECU as per the table overview.
To track the commands issued, the 2nd byte is a counter (CTR). It is indented by +1 for every command sent by the master and is mirrored in the response from the slave ECU. The remaining 6 bytes depend on the command.

Example: CCP CRO CONNECT message
Below is an example of a CRO used for initializing communication with a specific ECU:

Here, the CAN ID reflects the ID used by the CCP master for communication. The 1st byte is 0x01, corresponding to the CONNECT command as evident from the previous table. The 2nd byte is the CTR value. The 3rd and 4th bytes are specific to the CONNECT command and correspond to the target ECU's station address in Intel byte order. In other words, the above CRO is used by the master to establish a connection with ECU 0x0139. All subsequent communication will in this case be with this specific ECU until the master terminates the connection or connects to another ECU.
DTO - Data Transmission Object
The Data Transmission Object (DTO) is a CAN frame sent by the ECU to the master. Three types of DTOs exist as outlined below:
#1 CRM-DTO: Command Response Message
The CRM-DTO is sent by the ECU in response to a CRO from the master. The ID reflects the CAN ID used by the ECU (e.g. 0x702).
The data payload for the CRM can be broken down as follows:
- The 1st byte is the Packet Identifier (PID). For the CRM-DTO, the PID always equals 0xFF
- The 2nd byte is the error code (ERR), which can be used to e.g. inform the master of an invalid request.
- The 3rd byte is the counter (CTR), which will match the CTR value from the master's CRO
- The remaining 5 bytes depend on the CRO request
Note that error codes can be sent in both CRM-DTOs (if they happen in direct response to a CRO from the master) or in EV-DTOs (if they happen asynchronously to the master's CRO commands).

Example: CCP CRO CONNECT message (incl. response CRM)
Below is the previous connection example trace, including a positive response CRM.

The trace shows a connection to the ECU with station address 0x0139, which responds to the initialization command sent by the master. As evident, the 1st byte is 0xFF (as the message is a CRM). The 2nd byte shows that no errors occurred, while the 3rd byte matches the CTR of the CRO. With this sequence, the connection between the master and ECU 0x0139 is established.
#2 EV-DTO: Event Message
The EV-DTO is sent by the ECU in response to an internal event causing a status change in the ECU. This can be used to inform the master of errors that occurred since the last CRO.
The EV-DTO is identical to the CRM-DTO, but with the PID always equal to 0xFE. Note that the CTR has no relevance for EV-DTOs.
#3 DAQ-DTO: Data Acquisition Message
The DAQ-DTO is used by the ECU to send data to the master in response to an event (e.g. a cyclic counter or button).
In DAQ communication, the master starts out by 'configuring' the ECU for a measurement sequence. Once initiated, the ECU outputs DAQ-DTOs without further CROs from the master.
In the DAQ-DTO the PID refers to an 'Object Descriptor Table' (ODT), while up to 7 bytes carry data related to the ODT.
Example: CCP DAQ-DTO
Below is an example of a DAQ-DTO message sent by an ECU to a master.

The trace shows the DAQ-DTO communication from a slave following an initial configuration sequence. The data relates to ODT list #37 (0x25) with a payload of 5 bytes. Note how we do not pad the unused bytes (as this is not required for DAQ-DTOs). Note also how a new CAN ID is introduced for this DAQ response (more on this later).
CRO, CRM-DTO and EV-DTO messages must have a payload length of 8. Any unused bytes are padded with arbitrary values (we use 0xAA in this intro). DAQ-DTO messages may use the actual payload size.
Next, we consider XCP on CAN (and compare it to CCP), after which we cover CCP/XCP data logging.
XCP on CAN - the basics
We have now gone through the basics of CCP. In this section, we cover XCP on CAN with focus on message structures.
XCP on CAN - CAN frame identifiers
XCP communication requires at least two CAN bus identifiers: One for the master (e.g. 0x551) and one for the ECU (e.g. 0x552). If the master needs to communicate via XCP with more than one ECU, an additional set of identifiers will be required. This is in contrast to CCP, where ECU addressing is not linked to the CAN ID, but instead set up in the session connection.
XCP CTO - Command Transfer Object
In XCP on CAN, the CTO is a CAN frame for transferring control commands, incl. commands (CMD), command responses (RES), errors (ERR), events (EV) and service requests (SERV).
In contrast to the CRO in CCP, the CTO is used by both the master and ECU. Note also that a CMD packet from the master must be answered with a RES or ERR packet from the ECU, while the other packet types are sent asynchronously.
If we look at the CTO payload, the 1st byte reflects a Packet Identifier (PID). The remaining 7 bytes in an XCP on CAN CTO payload consists of data, specific to the type of CTO packet.
If we compare this structure to the CCP CRO, it is similar, except for the exclusion of the counter byte in XCP.
The actual values of the CMD byte across XCP and CCP differ as well. For example, CCP uses 0x01 for the CONNECT command, while XCP uses 0xFF. See also the table overview for the assignment of CTO PIDs depending on whether messages are sent from the master or slave. See also the comparison of CCP vs. XCP CMD codes in the table above.

XCP CONNECT + GET_STATUS response tables
Below we show how to interpret the ECU responses to two core XCP commands.


Example 1: XCP CTO CONNECT message
As in CCP, let's look at how a CONNECT sequence may look in XCP on CAN:

Note that the example does not use the 0xAA padding, as this is optional in XCP on CAN.
In the trace, the master sends a CONNECT CMD (0xFF) to the ECU with the communication mode set to normal (0x00). Note that, in contrast to CCP, the master does not need to specify a station address in the payload of the CONNECT frame. This is because the CAN identifiers already uniquely identify which ECU the master is communicating with.
The ECU responds with a CAN frame that can be decoded as per the CONNECT table above:
- The 1st byte equals the positive response PID 0xFF (RES)
- The 2nd byte is the resource availability (0x04 = 0b00000100 means that DAQ is available)
- The 3rd byte relates to the 'communication mode' (0x80 = 0b10000000 e.g. tells us that Intel byte order is used)
- The 4th byte is the maximum CTO size (here 8 bytes, meaning we are limited to Classical CAN CTOs)
- The 5th and 6th byte equal the maximum DTO size (here 8 bytes, meaning we are limited to Classical CAN DTOs)
- the 7th and 8th bytes equal the XCP protocol layer version and transport layer version respectively (both 1 in this case)
Example 2: XCP CTO GET_STATUS message
Below is another example, showing an XCP GET_STATUS request/response:

As before, we can interpret the response based on the table:
- The 1st byte equals the positive response PID 0xFF (RES)
- The 2nd byte is the session status (0x00 means that everything is reset and no active DAQs are running)
- The 3rd byte relates to the seed & key protection status (0x00 means that no commands are protected)
- The 5th and 6th byte equal the session config ID (0x00 means no active session)
The GET_STATUS command is particularly useful for obtaining information about whether certain commands (e.g. related to data acquisition via DAQ lists) are protected via seed & key authentication. Note that basic XCP polling via SHORT_UPLOAD commands is never protected via seed & key authentication.
XCP DTO: Data Transfer Object
The XCP DTO is used for sending synchronous data. In particular, the DTO is used in DAQ measurement (similar to the role of the DAQ-DTO in CCP). In XCP, it also enables the transfer of 'stimulation' (STIM) data that can be used in bypassing the normal algorithm within an ECU.
The XCP DTO timestamp
One important thing to note about XCP DAQ measurement, however, is that it enables the ECU to write the measurement time in the XCP DTO packets. The implication is that the master is able to correctly sync ECU data split across multiple frames by utilising the ECU measurement timestamp, rather than the master's own internal timestamp.
The XCP DTO timestamp is optional and is implemented as an incrementing counter, with the incrementation logic specified in the A2L file. If a timestamp is to be included for a specific DAQ list, it will be written into the 1st ODT list (but not subsequent ones if more ODT lists exist within the same DAQ list).
It is also worth noting that multiple methods exist for packing the DAQ list # and ODT list # information in the DAQ DTOs. The simplest case is 'absolute ODT numbers', where the ODT list # is unique across all DAQ lists. Here, the PID (i.e. ODT #) is sufficient for globally identifying an ODT list. In the section on data logging we showcase this in action.
Another method exists, however, where relative ODT list numbers are used across DAQ lists. Thus, you could e.g. have two ODT lists with PID = 0x00, meaning that they cannot be uniquely identified as the CAN ID is identical across the two DTOs. Here, a 1 or 2 byte DAQ list identifier can be added in the 2nd to 3rd bytes of the CAN frame payload. With this, one can again uniquely identify a specific ODT list.
The A2L file and ECU will provide information on what method is used.
A 1-byte counter field may optionally be used in the communication of XCP DTOs. If a CTR field is used in XCP DTO DAQ packets, the slave will only insert the value of the CTR in the 1st frame of a DAQ list, i.e. in the 1st ODT list.
Most of our XCP on CAN overview assumes that the lower layer is Classical CAN. However, since v1.2, XCP can also be based on CAN FD, which adds a number of opportunities for optimization. If an ECU supports XCP on CAN FD, it may support longer CTO/DTO payloads beyond 8 bytes, which will then be evident from the CONNECT response by the ECU as per the table.
Support for CAN FD CTOs enables the master to leverage longer CAN FD frames when initializing DAQ lists, which can reduce the number of separate CAN messages significantly. Further, support fro CAN FD DTOs may allow for encoding much more ECU signal values into the same CAN frame data payload. This is powerful because it reduces busload, but also because it allows for better time synchronization of the data (as will become evident in the data logging section).
CCP/XCP of course contain numerous more topics that we have not taken the time to discuss here. Deliberately, we have focused on the basic topics and concepts related to data logging. However, below you'll find useful links for further reading.
- Vector's XCP Book v1.5: A detailed overview of the XCP 1.5 protocol
- XCP (Wikipedia): The basics on the XCP protocol
- ASAM MCD-1 XCP overview: Also provides a detailed overview of the XCP protocol
- ASAM ASAM MCD-2 MC overview: Provides an overview of the ECU description file standard
- Seed & key details (Vector): A useful intro to the basics on authorization
XCP on CAN vs CCP: Message structure comparison
Below we summarize the structural message differences in XCP on CAN vs. CCP:
An alternative way to illustrate the role of the CCP vs. XCP messages is via below architecture comparison:
How to record ECU data via CCP/XCP
Let us imagine that you are an engineer working at an automotive OEM. You have been tasked to extract the value of a specific parameter from an ECU over an extended period. How do you do it? Below we will outline two methods: Polling and DAQ.
Data acquisition via CCP/XCP polling
The simplest solution is CCP/XCP polling. Here, the master requests data on an ECU signal and the ECU responds with the data. This is done via CRO/CRM-DTO messages (CCP) or CTO messages (XCP). Let us illustrate this method with two examples:
Example 1: CCP polling (CRO/CRM-DTO)
Assuming the CCP master has connected to an ECU, it can poll data as below:

Here, the master sends a request to the slave for 0x04 bytes of data stored at the 'source address' 0x12345678 (Motorola byte order) - corresponding to a specific ECU signal. The 4th byte 0x00 reflects the source address 'extension', which may correspond to a certain memory segment. The slave responds with the current ECU signal value (4 bytes of data, 0xF12A712F).
This can be repeated to e.g. extract real-time parameter data, such as an RPM signal - similarly to how you request RPM via an OBD2 request/response flow in most cars.
Effectively, 'polling' is simply a sequence of CRO/CRM-DTOs with the master using a command called SHORT_UP (short upload).
Example 2: XCP on CAN polling (CTO)
Assuming the XCP master has connected to an ECU, it can poll data as below:

As before, the master sends a SHORT_UPLOAD CMD (PID 0xF4) for 2 bytes of data. The 3rd byte is reserved, while the 4th byte of the CTO is the address extension (in this case 0). The remaining 4 bytes equal the source address 0x12345678 (Intel byte order). In response to the command CTO, the ECU sends a response CTO with the value of the 2 bytes of data.
For CCP/XCP communication, incl. polling, the byte order is ECU specific and described in the A2L file. In the examples above we therefore provide both an Intel and Motorola example, though the selection here is arbitrary and not linked to whether the protocol is CCP or XCP. You can also identify the byte order based on the XCP CONNECT response by interpreting the 3rd byte (communication mode).
One restriction, however, is that in CCP communication the CONNECT message 2-byte station address is always Intel byte order.
Downsides to CCP/XCP polling
Polling is simple to set up - just establish an ECU connection and send the correct request message every X ms. For many practical use cases this can be a perfectly viable solution. However, polling has two significant downsides.
#1 Polling is inefficient
Polling requires a request message for every response. If you e.g. need to measure a 2-byte signal at 100 Hz, that increases the busload by 200 frames/second.
The inefficiency is both due to the need for requesting every single response - but also the fact that response messages are forced to be 8 bytes long, with 3 bytes spent on overhead.
#2 Polling is asynchronous
When polling for multiple signals, the request/responses need to be sent sequentially with a small delay between each request.
As a result, the signal observations are not time synchronized. This makes data analysis more difficult and less precise.
Beyond the above downsides, there can also be more subtle issues with CCP/XCP polling. For example, if your goal is to poll 50 signals with a device that is restricted to sending 1 transmit message per 10 ms (e.g. for safety reasons), the 'cycle period' of each signal would become 50 x 10 ms = 500 ms. In other words, you'd only be able to get a refresh rate of 2 Hz on each signal, which is rarely sufficient for XCP data acquisition purposes.
Data acquisition via CCP/XCP DAQ
CCP/XCP offers an alternative data measurement technique called DAQ (Synchronous Data Acquisition).
How DAQ works + key benefits
DAQ is more complex, but solves the downsides of polling.
The master specifies which ECU signals to record from the slave, what event should trigger the communication of data and how to package the signals. In terms of events, the master may e.g. request that signals A and B are broadcast every 10 ms, while signal C is broadcast every 100 ms - or when a button is pushed.
Once the DAQ configuration is complete, the master 'starts' the sequence and the slave now autonomously broadcasts the requested signals using DAQ-DTO messages.
This eliminates the request messages from the master. In addition, the signal data is packaged more efficiently in the DAQ-DTOs vs. the CCP CRM-DTOs or XCP CTOs, reducing busload.
Further, with DAQ it is possible to package related signals in the same DAQ-DTO frames to enable time synced analysis.
To use DAQ, the master has to first configure the ECU accordingly. Two concepts are key in this regard: Object Descriptor Tables (ODT) and DAQ lists.
Object Descriptor Table
The Object Descriptor Table (ODT) is a list of references to data elements from the ECU memory.
If we take the 'short upload' example used in CCP/XCP polling, the master sends a request specifying three elements: The data length (in bytes), address extension and source address. With this info, the ECU finds the data and sends it to the master.
The concept of an ODT is similar: An ODT is simply a list of 'element references'. Each entry in the ODT reflects an ECU source address (and optionally an address extension and length). The ODT thus describes how ECU signals are 'packaged' in a DAQ-DTO payload.
The master defines ODTs during DAQ initialization - and therefore also knows how to decode the DAQ-DTOs.
Let us consider an example: We wish to record 7 signals, each of them with a length of 1 byte. To do so, we define a new ODT #0 (PID 0x00) with 7 element entries. Element 1 refers to signal 1 with a specific ECU source address. Element 2 refers to signal 2 with another source address etc.
When we use the DAQ mode for data measurement, we can now refer to ODT #0 in order to get the ECU to provide us with time synced data on all 7 signals - within a single DAQ-DTO CAN frame. In other words: The ODT we defined describes the structure of a DAQ-DTO message, meaning that the ECU will now know how to package the 7 signal bytes in a single CAN frame - and the master knows how to extract the 7 signal bytes from that CAN frame.
Notice the impact on the busload: If we were to poll all 7 signals, it would require 14 CRO/CRM-DTO CAN frames per cycle - now it only requires 1 DAQ-DTO CAN frame. Further, we can easily plot these 7 signals together as they share the same CAN frame timestamp - making it much easier to perform analysis. For the same reason, ODT lists are typically defined to group related signals together.
In practice, a master will often define multiple ODT lists and assign PIDs for each of them in the range of 0x00 to 0xFD. Each ODT then defines the structure of a separate DAQ-DTO.
DAQ lists
When working with multiple ODTs, it is useful to group them based on sampling method (e.g. every 10 ms, 100 ms, on-event). These groups of ODTs are referred to as DAQ lists. DAQ list #0 may e.g. contain ODT #0, ODT #1 and ODT #2. The ECU A2L file specifies the supported DAQ lists (aka events) and which signals/measurements can be assigned to each event type.
How to initialize a DAQ sequence
We have now looked at both the ODT and DAQ lists - but how do we define these over CAN?
In simple terms, the configuration of DAQ lists is done through a (potentially long) sequence of CCP CRO/CRM-DTO or XCP CTO frames. Here, the master essentially specifies the entire DAQ/ODT/element structure element-by-element. To define a new signal (aka element), the master specifies the address, length and address extension. Next, the master informs informs the ECU how to package the element in DAQ-DTOs by linking the element to an ODT# and DAQ#.
To understand this in detail, consider below trace examples/explanations:
Example 1: CCP DAQ - initialization
The below shows a basic CCP DAQ initialization sequence.

So we have quite a bit going on here, but let's break it down:
We start by using the CRO command GET_DAQ_SIZE. This has two purposes: It informs us about the size of the specified DAQ list in terms of ODT lists - and it clears the current list. Essentially, this works like a 'reset' command for the DAQ list, in this case DAQ list #5.
As part of the GET_DAQ_SIZE command we also provide the 11-bit CAN ID 0x712 in the last 4 bytes. This informs the ECU that it should use CAN ID 0x712 to broadcast the subsequent DAQ-DTOs. This is subtle, but an important aspect: Essentially, the master is able to specify the CAN ID for every DAQ list, which in turn also enables the master to initiate DAQ measurement across multiple ECUs in parallel.
The ECU confirms the CRO from the master and informs us that the DAQ list #5 has 3 ODTs with the first PID being 0x07.
Next, the master starts populating DAQ list #5 and ODT list #7 with the source address information for 7 x 1-byte signals. This is done through a simple loop consisting of 7 repetitions of two commands: SET_DAQ_PTR and WRITE_DAQ.
First, the master uses SET_DAQ_PTR to "select" DAQ list #5, ODT list #7 and element #0 of the ODT list. Next, the master uses WRITE_DAQ to write the contents of this element reference: A length of 1, an address extension of 0 and a source address of 0x00001000.
Basically, we have now told the ECU to "package" the value of our 1st signal (which is stored in the specified source address) into the 2nd byte of the DAQ-DTO that corresponds to DAQ list #5 and ODT list #7 (the 1st byte of the DAQ-DTO being the PID 0x07).
After this, we repeat the process for the remaining 6 signals until the ODT #7 has been completed.
In this simplistic case we only care about this particular DAQ and ODT list. Therefore, the final step is to start the DAQ measurement via the START_STOP command. Here, we specify that we wish to start DAQ list #5 and ODT list #7. As part of this, we specify the timing parameters, namely that event channel 0x03 should be used with a prescaler of 10. The ECU specific event channel details are specified in the ECU description file.
As evident, the ECU will now start broadcasting data from DAQ list #5 and ODT list #7 at the specified frequency. The CAN frame payloads include the ODT PID 0x05 in the 1st byte and the 7 'element' signal values in the remaining payload.
Note also that you can alternatively use the START_STOP command to 'prepare' multiple DAQ lists and ODT lists for measurement and then use the START_STOP_ALL command to simultaneously start or stop all of them.
Below example trace shows an already initiated DAQ sequence:

In this example, the target ECU is broadcasting data across three ODTs in total, as evident from the 1st bytes spanning from 0x00 to 0x02. While it's not explicitly clear from the trace, the three ODTs are split into two DAQ lists: One DAQ list contains ODT #0 with a sampling frequency of 10 ms - while DAQ list #1 contains the remaining ODT lists #1 to #2 with a sampling frequency of 100 ms. This is why the DAQ-DTO with PID 0x00 is observed more frequently in the trace vs. the other DAQ-DTOs.
Example 2: XCP on CAN DAQ - initialization (Classical CAN CTOs/DTOs)
The below shows a basic XCP on CAN DAQ initialization sequence for 1 DAQ list and 4 ODTs. The master uses Classical CAN frames for both the initialization and the subsequent DAQ-DTOs that carry the ECU signal data.

In this trace, we explicitly show the initial CONNECT and GET_STATUS command, which are typically used prior to starting a DAQ initialization sequence. The ECU responses to these commands can yield useful information about DAQ-related capabilities of the ECU as explained in the XCP CTO section - see also the related 'response tables' for these commands. In particular, note that the CONNECT response tells us that the client supports 0x40 (64) byte CTOs and DTOs, though for exposition we use Classical CAN frames in this example only. The CONNECT response also informs us that the ECU uses Intel byte order. The GET_STATUS response tells us that the ECU does not use seed & key authentication for any commands, including DAQ.
Let us outline the rest of the example:
- The master starts by clearing any dynamic DAQ lists via the FREE_DAQ command
- Next, the master uses ALLOC_DAQ to allocate a single DAQ list
- Next, the master uses ALLOC_ODT to allocate 4 ODTs to the DAQ list 0x0000
- After this the master uses ALLOC_ODT_ENTRY for each of the 4 ODTs to specify the number of elements/signals
- Now that the basic allocations are done, the master uses SET_DAQ_PTR to target a specific DAQ list (0x0000) and ODT (0x00). Subsequently the master uses WRITE_DAQ commands to allocate specific ECU signals to the target. Notice how each WRITE_DAQ specifies the byte length of the signal, but not the payload position (this is handled by the ECU). Note also that with Classical CAN, the payload per ODT is limited to 7 data bytes. This process is repeated for each of the 4 ODTs
- Once the signal writing is done, the master uses SET_DAQ_LIST_MODE to 'configure' the targeted DAQ list 0x0000. The 2nd byte, MODE, is set to 0x00, which means the 'direction' is slave-to-master (for data acquisition), timestamps are not included in the DAQ-DTO payloads - and the ODT PID is not disabled, meaning that the 1st byte of the DAQ-DTOs will reflect the ODT identifier field. The EVENT_CHANNEL_NUMBER 0x0002 is linked to a specific 'trigger event' in the ECU, in this case implying that the DAQ list is broadcast periodically every 5 ms. The prescaler value is set to 1, meaning we do not downscale the frequency of the DAQ list
- Finally, the master uses the START_STOP_DAQ_LITS to 'select' DAQ list 0x0000 for synced startup - and then uses START_STOP_SYNCH to actually trigger the start of the DAQ-DTO communication from the ECU
At the end of the trace we see how the ECU starts producing the four separate DAQ-DTOs, each linked to the relevant ODT via the PID in the 1st byte. Note also how the length of the DAQ-DTOs corresponds to the total byte length of the signals assigned to the respective ODTs during the WRITE_DAQ step.
Example 3: XCP on CAN DAQ - initialization (multiple DAQ lists + CAN FD DTOs)
The below shows a more advanced XCP on CAN DAQ initialization sequence using Classical CAN frames for the initialization of 2 DAQ lists carrying a total of 3 ODTs. Notice how one of the DAQ-DTOs is a CAN FD frame with 32 bytes.

This trace is very similar to the previous one, but now includes multiple separate DAQ lists. A few highlights:
- In DAQ list 0x0000 ODT 0x01 the master assigns 0x0F (15) elements, which requires 15 x WRITE_DAQ commands because the master uses Classical CAN frames for the initialization. The total byte length of these 15 elements is 24 bytes as evident from the final DAQ-DTO related to this ODT. When accounting for the PID, that means 25 bytes are required in total. In CAN FD, it is necessary to 'round up' to the closest supported data length, which in this case is 32 bytes - meaning that some padding is included
- Notice also how we include the ECU slave responses to the two START_STOP_DAQ_LIST commands. This is to show how the ECU responds with the FIRST_PID value, telling the master what the first PID is for each DAQ list (related to absolute PID numbering)
- The example also shows how the two DAQ lists use separate event channels (0x0002 = 5 ms and 0x0003 = 10 ms periodic broadcast)
Example 4: XCP on CAN DAQ - initialization (CAN FD CTOs via WRITE_MULTIPLE_DAQ + CAN FD DTOs)
This example leverages the XCP command 'WRITE_MULTIPLE_DAQ' to write 7 signals in a single CAN FD frame - thus reducing initialization time and overhead. The DAQ-DTO also leverages CAN FD to pack the 7 signals (14 data bytes) in a single frame.

In this example, the master fully leverages CAN FD in both the XCP CTOs (for the initialization) and DTOs (for the subsequent DAQ-DTO communication).
Specifically, the master uses the WRITE_DAQ_MULTIPLE to add 7 elements to a single DAQ list and ODT within a single write command. As evident, this command requires specifying the number of elements (0x07) and then essentially parsing a similar structure as in the regular WRITE_DAQ commands, though with the extension and ECU address field order reversed.
The resulting DAQ-DTO contains all 7 elements (14 data bytes). As the required data length incl. the PID is 14 + 1 = 15 bytes, the closest CAN FD frame length is 16 bytes and therefore 1 byte of padding is added.
How to disconnect from an ECU
Once the data acquisition has completed, the master may disconnect from the ECU via the DISCONNECT command.
Example 1: CCP DISCONNECT

Here, the 3rd byte 0x01 means that we end the session entirely (in contrast to a temporary disconnection). This effectively resets the ECU including our previous configuration. To target the specific ECU of interest, we specify the station address (Intel format) of the ECU, i.e. 0x702.
As evident, DAQ is more convoluted to set up - but enables efficient time synced communication of ECU data.
Example 2: XCP on CAN - stop DAQ + DISCONNECT

In this example, the master first stops the existing DAQ communication via the START_STOP_SYNCH command (with the 2nd byte set to 0x00). After this, the master disconnects the overall XCP session. Notice how this command is simpler vs. CCP as the XCP master does not need to target a specific ECU address (as this is implicit from the CAN IDs used).
1: Decoding CCP/XCP signal data from ECUs
In CCP/XCP polling/DAQ, you are in practice recording raw CAN frames with specific signal encoding structures.
In order to make sense of the recorded data, you need to decode it to human-readable form aka physical values. This is the same concept as we've explained in several other CAN-related intros, incl. our intro to CAN bus, J1939, OBD2 and DBC files.
However, CCP/XCP decoding involves some extra complexities that we will explain below.
2: Decoding CCP/XCP polling data
Let us review an extended version of the CCP polling request/response from before:

This reflects a decoding challenge: The ECU sends different signals with the same CAN ID - with no way to identify them in the payload.
In the above example, the master is requesting two different 4-byte signal values from the ECU, namely from source addresses 0x12345678 and 0xABCDEF00. In both cases, the ECU responds with CAN ID 0x702.
In most CAN bus decoding scenarios, you would be able to simply lookup the response CAN ID and find the 'start bit' and 'bit length' of a given signal to extract the raw data from the payload.
However, that is not possible here as the ECU uses the same CAN ID across two different signals. In other words, the CAN ID is not sufficient to distinguish between the signal coming from 0x12345678 and the one coming from 0xABCDEF00.
To some extent, this is similar to how OBD2 responses from an ECU use the same CAN ID (typically 0x7E8) across different signals like speed and RPM. In the case of OBD2 we can, however, easily solve this because the OBD2 PID (Parameter Identifier) is included in the payload. Together with the CAN ID, this serves as a unique identifier within the response frame - enabling us to view the response as a case of multiplexing.
We cannot directly do this in CCP polling because the response payload does not include the ECU source address. In other words: In use cases with multiple CCP polling signals we need to combine information from the request & response message.
In simplistic terms, we can solve this by "repackaging" the payloads as follows:

By doing so, we can process this using multiplexing logic - similar to how we handle OBD2 and UDS decoding. Here, the CAN ID to look up is 0x702 and the multiplexor is found in the 5th to 8th byte, while the signal value is found in the 12th to 15th byte. Two separate decoding rules can now be specified, with the relevant one dependent on the value of the 4-byte multiplexor.
In practice such a reconstruction of CAN frames can be done in e.g. a Python script, assuming the CAN trace includes both the request and response data. Once the CAN frames are reconstructed, it is possible to use DBC files for decoding the data via multiplexing. Alternatively, the data can be loaded into a software tool supporting CCP/XCP decoding directly.
Decoding CCP/XCP DAQ data
Let's briefly review a snippet of the post-initialization DAQ trace from before:

As evident, the DAQ-DTO messages have a pre-specified CAN identifier (0x712 above) and a payload in which the 1st byte equals the ODT list identifier aka ODT PID (0x07 above). As a result, it is not necessary to "combine" the DAQ-DTO response frames to uniquely identify which frames contain which signals - this can directly be identified through a combination of the CAN ID and the ODT PID.
This makes decoding of DAQ-DTO messages simpler than polling messages. In fact, you can directly create a DBC file with multiplexing if you know the encoding of all the bytes in each ODT list. This is exactly what we do in our canedge-xcp Python tool, where a DBC is auto-generated based on a specific dynamic DAQ initialization (more on this further below). However, while DBC files can be useful for decoding, the primary file format used in CCP/XCP is the A2L file format.
A2L - ECU Description Files
In the prior sections, we have occasionally referred to 'ECU description files'. An ECU description file contains everything a master tool needs to know to communicate with an ECU. From a data measurement perspective, this includes information on CAN identifiers, available signals, signal decoding rules, DAQ/ODT information etc.
In practice, the ASAP2 description format (*.A2L) is used to structure this information. The ASAP2 data definition was standardized by ASAM in the ASAM MCD-2 MC, with the first version 1.3.1 being released June 15 1999, i.e. the same year that the CCP 2.1 standard was released. The latest version of the standard, 1.7.1, was released in 2018.
In practice, the A2L file is used to 'configure' the master device, enabling communication with the ECU. This includes protocol layer details (e.g. what CAN IDs are used for requests/responses, if FD is supported etc) - and details on the measurements of interest (e.g. ECU addresses and decoding rules).
For details, see our intro to A2L files, which covers the main syntax - and how to use them in XCP on CAN data acquisition.
A2L files introSeed & key authorization
As explained previously, CCP/XCP communication is typically used by automotive OEM engineers to facilitate communication with ECUs in pre-production applications.
In some cases all it takes to communicate with an ECU is the A2L file and a suitable CAN tool. As evident, one can also simply extract a subset of the A2L file to configure a device e.g. for measurement of specific signals. However, without the A2L file, it is practically impossible to perform communication and hence many OEMs do not require any additional security measures beyond keeping the A2L file under lock.
However, some use cases warrant additional security.
CCP/XCP supports this via a concept called 'seed & key' authorization. Here, the master requests a random seed from the ECU as part of the initialization of the ECU communication. The master receives the seed from the ECU and uses it as input for an internal security algorithm to calculate a key. The master then sends the key to the ECU via CAN - and if it matches the key calculated internally by the ECU, authorization is provided for further communication.
Example: CCP seed & key authentication

In this example, the master requests the seed via the GET_SEED command 0x12, specifying a 'resource mask' of 0x02 in the 3rd byte. The resource mask references the level of access requested - with 0x02 being DAQ access only (see the CCP 2.1 standard for details).
The ECU responds with a frame in which the 4th byte is 0x01, implying that DAQ access is protected (in contrast to 0x00 which would imply that authentication would not be required). The ECU provides the requested seed in the remaining 4 bytes.
Based on the seed, the ECU calculates the key and provides it via the UNLOCK command, 0x13. The key is in this case 4 bytes long. The ECU responds positively including the requested resource mask 0x02, meaning that DAQ access is now unlocked.
The most common implementation of the security algorithm is via a *.dll file, since the master device is frequently a Windows PC with a GUI tool and a CAN interface. The use of a *.dll file also enables standardization across CCP tools, while eliminating the need for the master tool to know the underlying algorithm used.
It is, however, challenging to use *.dll files in standalone CAN bus data loggers and telematics devices (as they do not run Windows), hence some companies use alternative solutions - e.g. proprietary file formats better suited for embedded devices.
The CANedge does not support seed & key authentication - though this is not necessarily an issue in regards to data acquisition.
As evident from the XCP GET_STATUS command, authentication may apply to calibration/pagination, DAQ, stimulation and programming commands. However, authentication is not required for basic commands like e.g. CONNECT, GET_STATUS and SHORT_UPLOAD. If your goal is to perform data acquisition wtih the CANedge, you can use the GET_STATUS command to determine if DAQ is an option or not. If it is not, you can 'fall back' to using CCP/XCP polling.
Further, if you prefer to use DAQ rather than polling, it may also be possible for your team to simply disable authentication for DAQ in the ECU for the purpose of your data logging use case.
Using the CANedge for CCP/XCP data acquisition
The CANedge lets you easily record raw CCP/XCP data to an 8-32 GB SD card - and optionally offload it via WiFi/LTE to your own server. The device can be configured to poll data or use DAQ lists. You can decode the data via free software/APIs.
The device is used by many automotive OEM engineers for this purpose - see e.g. Vitesco's case study on creating XCP on CAN cloud data lakes.
canedge-xcp Python tool
In particular, the CANedge is well-suited for XCP on CAN data acquisition using dynamic DAQ lists. This is enabled by our 100% open source 'canedge-xcp' Python tool. The tool lets you provide your A2L and a CSV with your requested measurements and event channels. The tool then generates a CANedge transmit list and DBC file based on this.
In turn, this lets you easily log your ECU data with the CANedge and analyze it with e.g. the asammdf GUI, Grafana dashboards, python-can, Vector tools, MATLAB and more.
Learn more in our intro to A2L files - or contact us.
CCP/XCP data logging - applications
In this section we provide brief examples of how CCP/XCP data logging may be useful in practice.
XCP telematics for prototype vehicle fleet
As an OEM, you may need to collect data internal to an ECU, which can only be measured via XCP on CAN. Here, a CAN logger like the CANedge can be configured using our canedge-xcp Python tool to initialize dynamic DAQ lists. The CANedge records the resulting raw XCP on CAN data in log files and uploads them via WiFi/LTE to your own cloud server. The raw data can be easily DBC decoded via the canedge-xcp DBC file, enabling you to visualize/analyze the measurements in e.g. Grafana dashboards, Vector tools or Python.
Remote CCP/XCP calibration via OTA updates
As a more sophisticated use case, an OEM could utilize a CANedge3 to perform over-the-air updates to an ECU. For example, a CANedge3 may be deployed in a prototype vehicle in which an OEM engineer would like to re-calibrate certain variables in the ECU. To achieve this, the engineer constructs the relevant sequence of single-shot CAN frames in a new configuration file for the CANedge. Next, the engineer deploys the new configuration file on the CANedge S3 server, thus triggering an OTA update - allowing the CANedge3 to transmit the sequence into the vehicle remotely.
For more intros, see our guides section - or download the 'Ultimate Guide' PDF.
Ready to log your CCP/XCP data?
Get your CANedge today!