VW Transport Protocol 2.0 (TP 2.0)

While most diagnostic protocols on CAN use ISO-TP to transfer payloads larger than 8 bytes, Volkswagen uses a custom protocol on older models. This protocol is called VW Transport Protocol 2.0 (TP 2.0). It's usually used to transfer KWP2000 diagnostic messages, but can also be used to transfer other data.

TP 2.0 uses the concept of channels to communicate data between the tester and the ECU. Once a channel is opened, data can be exchanged. There is no official specification of TP 2.0, so the protocol description here is based on reverse engineering work by Jared Wiltshire.

VW TP 2.0 uses four types of packets: channel setup, channel parameters, data packets, and broadcast.

Channel Setup

The first step in opening a channel is sending a channel setup request message. It's sent on Arbitration ID 0x200, and the response will be sent on 0x200 + logical address of the ECU. For example, the engine control unit has a logical address of 0x01, so the response will be on 0x201.

The channel setup message is 7 bytes long. Each of the RX and TX IDs is split across two bytes: a low byte holding the lower 8 bits of the 11-bit CAN ID, and a "validity + prefix" byte where the high nibble is the validity flag (0x0 = valid, 0x1 = invalid) and the low nibble is the upper nibble of the CAN ID. Read together as a little-endian 16-bit value, this gives V·ID with V in the top nibble.

Opcode

  • 0xC0 — Setup Request
  • 0xD0 — Positive Response
  • 0xD60xD8 — Negative Response

Example

In the example below the tester opens a channel to the ECU with logical address 0x09. The RX ID is set to invalid to let the ECU decide where it listens. The TX ID is set to 0x300 to request that the ECU transmit on 0x300. The ECU responds with a positive response, acknowledges that it will listen on 0x300, and tells the tester to send to 0x7A8.

Channel setup

TesterECU
09C00010000301
FieldMnemonicValueDescription
DestinationDest09Logical address of the ECU. 0x09 here.
OpcodeOpC00xC0 = Setup Request.
RX ID low byteRX00Low 8 bits of the RX ID (CAN ID the ECU should listen on).
RX V & prefixRXVP10
High
Validity (1 = invalid, "ECU you decide")
Low
Upper nibble of RX ID (0)
TX ID low byteTX00Low 8 bits of the TX ID (CAN ID the ECU should transmit on).
TX V & prefixTXVP03
High
Validity (0 = valid)
Low
Upper nibble of TX ID (0x3) — full ID = 0x300.
ApplicationApp01Always 0x01 for KWP2000.
ECUTester
00D00003A80701
FieldMnemonicValueDescription
DestinationDest00Logical address of the tester (always 0x00).
OpcodeOpD00xD0 = Positive Response. 0xD6–0xD8 indicate a negative response.
RX ID low byteRX00ECU confirms it will listen on this CAN ID.
RX V & prefixRXVP03
High
Validity (0 = valid)
Low
Upper nibble of RX ID (0x3) — ECU listens on 0x300.
TX ID low byteTXA8Tester should send to this CAN ID.
TX V & prefixTXVP07
High
Validity (0 = valid)
Low
Upper nibble of TX ID (0x7) — full ID = 0x7A8.
ApplicationApp01Echoed.

Channel Parameters

After opening the channel, some timing parameters need to be negotiated. The tester sends a parameters request message, and the ECU responds with a parameters response message. The parameters are used to determine the timing of the channel.

Opcode

  • 0xA0 — Parameters request (6 bytes)
  • 0xA1 — Parameters response (6 bytes)
  • 0xA3 — Channel test (1 byte). The ECU responds with an 0xA1 message. Used to keep the channel alive.
  • 0xA4 — Break (1 byte). The receiver discards all data since last ACK.
  • 0xA8 — Disconnect (1 byte). Closes the channel. Receiver responds with a disconnect.

Timing Parameters

T1, T2, T3, T4 are each one byte. Bits 7–6 encode the time units and bits 5–0 encode a multiplier. The unit values are:

  • 0x0 — 0.1 ms
  • 0x1 — 1 ms
  • 0x2 — 10 ms
  • 0x3 — 100 ms

The total time is units × multiplier. For example 0x8A = 10 001010 = 10 ms × 10 = 100 ms.

Example

Example of the tester exchanging the timing parameters. Recall the ECU listens on 0x7A8 and will transmit on 0x300. The tester requests a block size of 15, T1 of 100 ms, and T3 of 1 ms. The ECU responds with a block size of 15, T1 of 100 ms, and T3 of 10 ms.

Channel parameters

TesterECU
A00F8AFF0AFF
FieldMnemonicValueDescription
OpcodeOpA00xA0 = Parameters request.
BlockSizeBS0F15 packets between ACKs.
T1T18A
High
Units (bits 7–6 = 10₂ → 10 ms)
Low
Multiplier (bits 5–0 = 10) — total 100 ms
Time to wait for ACK. Should satisfy T1 > 4 × T3.
T2T2FFAlways 0xFF (unused).
T3T30A
High
Units (bits 7–6 = 00₂ → 0.1 ms)
Low
Multiplier (bits 5–0 = 10) — total 1 ms
Interval between packets requested by the tester.
T4T4FFAlways 0xFF (unused).
ECUTester
A10F8AFF4AFF
FieldMnemonicValueDescription
OpcodeOpA10xA1 = Parameters response.
BlockSizeBS0FECU agrees to 15 packets per block.
T1T18A100 ms (same encoding as request).
T2T2FFAlways 0xFF.
T3T34A
High
Units (bits 7–6 = 01₂ → 1 ms)
Low
Multiplier (bits 5–0 = 10) — total 10 ms
ECU bumps the inter-packet gap to 10 ms.
T4T4FFAlways 0xFF.

Data Transmission

After opening a channel, data can be transmitted. Up to 7 bytes of payload can be sent at a time. During channel setup, a block size was negotiated; after this many data transmission packets, an ACK is required. The first nibble of the first byte contains the opcode, and the second is used as a counter. Note that this counter behaves in a counterintuitive way: both tester and ECU have their own counter that persists between transmissions. The counter is incremented after each data transmission. An ACK does not increment any counter, but is expected to use the counter value of the last data transmission that is being acknowledged plus one.

Opcode

  • 0x0 — Waiting for ACK, more packets follow (max block size reached)
  • 0x1 — Waiting for ACK, last packet
  • 0x2 — Not waiting for ACK, more packets to follow
  • 0x3 — Not waiting for ACK, last packet
  • 0xB — ACK, ready for more data
  • 0x9 — ACK, not ready for more data
TesterECUData frame — last packet, expecting ACK
1200021A9B
FieldMnemonicValueDescription
Op & SequenceOp|Seq12
High
Op (1 = waiting for ACK, last packet)
Low
Sequence number (2)
LengthLen00 02Big-endian total payload length (2 bytes). Only present in the first frame of a message.
PayloadData1A 9BKWP2000 service ID (0x1A read ECU identification) and parameter (0x9B).
ECUTesterACK frame
B3
FieldMnemonicValueDescription
Op & SequenceOp|SeqB3
High
Op (B = ACK, ready for next)
Low
Sequence number (last data Seq + 1 = 3)

Example

In this example the tester has some KWP2000 communication with the ECU. There are some short packets to enter a diagnostics mode, then a larger payload is requested using service 0x1A (Read ECU Identification) to get the firmware version.

  1. Tester0x7A8
    1000021089
    Payload 10 89 — enter diag mode 0x89
  2. ECU0x300
    B1
    ACK
  3. ECU0x300
    1000025089
    Payload 50 89 — mode 0x89 entered
  4. Tester0x7A8
    B1
    ACK
  5. Tester0x7A8
    1100021089
    Payload 10 89 — enter diag mode 0x89
  6. ECU0x300
    B2
    ACK
  7. ECU0x300
    1100025089
    Payload 50 89 — mode 0x89 entered
  8. Tester0x7A8
    B2
    ACK
  9. Tester0x7A8
    1200021A9B
    Payload 1A 9B — Read ECU Identification
  10. ECU0x300
    B3
    ACK
  11. ECU0x300
    2200305A9B314B30
    Payload "Z.1K0"
  12. ECU0x300
    2339303931343445
    Payload "909144E"
  13. ECU0x300
    2420203235303100
    Payload " 2501."
  14. ECU0x300
    2500000000064016
    Payload ".....@."
  15. ECU0x300
    26054D4550535F5A
    Payload ".MEPS_Z"
  16. ECU0x300
    27464C53204B6C2E
    Payload "FLS Kl."
  17. ECU0x300
    2820313834202020
    Payload " 184. "
  18. ECU0x300
    1920
    Payload " "
  19. Tester0x7A8
    BA
    ACK

Broadcast

For diagnostics requests, it might be useful to quickly send a message without needing a (long) response, and without needing to open a channel first. The broadcast packets have no form of ACK, so they are sent 5 times.

Opcode

  • 0x23 — Broadcast request
  • 0x24 — Broadcast response
TesterECUBroadcast frame
01234 KWP2000 bytes00
FieldMnemonicValueDescription
DestinationDest01Logical address of the destination module.
OpcodeOp230x23 = Broadcast request, 0x24 = Broadcast response.
KWP2000 dataData4 KWP2000 bytesService ID and parameters.
Response flagResp000x00 = response expected. 0x55 or 0xAA = no response expected.