Skip to content

Instantly share code, notes, and snippets.

@jblang jblang/
Last active Apr 12, 2019

What would you like to do?
TPM2 Protocol Description

TPM2 Protocol Implementation


Frame data is transferred inside packets (similar to DMX, for example). A frame is an image representing a matrix or a light scene.

The packets start and end with one-byte characters. In between are a few control bytes followed by the payload. There is no set size for a payload; it is transmitted with each packet. This makes the protocol quite flexible. There are enough bytes in a single packet for an RGB matrix with 21,845 pixels, but if you just want to control an RGBW lamp, that only requires 9 bytes. The variable frame size means there is no overhead, allowing for maximum transfer speed.

TPM2 Packet Structure

Section Value
Packet start byte 0xC9
Packet type 0xDA = Data frame or
0xC0 = Command or
0xAA = Requested response (from the data receiver to the sender)
Payload size (16 bits) High-Byte first, then
User data 1 - 65,535 bytes of data or command with parameters
Packet end byte 0x36


At this point, the commands are not yet standardized, nor are possible responses. If such commands are used, they should be uniform so the user's software and hardware can cooperate. Commands could be used make adjustments from a distance, automatically configure the control software by asking the matrix on how big it is and then adjusting to accommodate it, or tell the controller to save the following frames to sd card, for example.


The receiver can respond with an acknowledgement byte 0xAC after each correctly received frame. It is possible for the transmission software to only send the next frame when 0xAC comes back from the receiver. However, acknowedgment is not mandatory, and transmission software can keep sending packets even if no acknowledgement is received.


It is possible to have automatic addressing of daisy-chained devices. For example, the transmitter sends 2,048 bytes, the first receiver takes the first 512 bytes out, decreases the frame size by 512 bytes, then sends the rest on, and so on until there is nothing left. It is also possible (as with DMX) for multiple receivers to receive the same data on a parallel bus, and each only takes the bytes that are addressed to them.

Hardware Independence

No special hardware requirements (physical layer, connectors, etc.) are standardized by the protocol. It only specifies the format of the packets. It doesn't matter whether these packets are then transmitted via RS232, TTL, USB, RS485, Ethernet or wireless; it is up to each user to decide themselves.

Transmission Rates

Likewise, the transmission rate may be very different depending on the requirements. For a 128x128 pixel matrix with 30fps or more, 100 megabit Ethernet may be required. For a 16x16 matrix, 250 to 500 kbps could be sent via USB. For building light control, where here and there, single lamps are turned on or off, 2400 baud would suffice. Protocol


The original TPM2 protocol was intended to be independent of underlying hardware. This does not quite apply to Ethernet/WiFi/UDP because the size of user data in each packet should not exceed 1500 bytes (the Ethernet frame size). The IP protocol states that the transmitter should break up, and the receiver should reassemble packets larger than 1500 bytes; however, many embedded TCP/IP implementations do not handle reassembly of packets. Therefore, it is useful to divide the TPM2 frames with larger datasets into corresponding portions. In this case, the individual packets should be numbered so that these portions can be put back together.

For this reason, introduces an additional packet number byte immediately after the frame size in bytes. To distinguish between "normal TPM2" and, the start code for has been changed to 0x9C. Packet Structure

Section Value
Packet start byte 0x9C
Packet type 0xDA = Data frame or
0xC0 = Command or
0xAA = Requested response (from the data receiver to the sender)
Frame size in 16 bits High-Byte first, then
Packet number 1-255
Number of packets 1-255
User data 1 - 1,490 bytes of data or command with parameters
Packet end byte 0x36

UDP Ports

These packets will be sent via UDP to port 65506 / 0xFFE2. The port for responses from the receiver to transmitter is 65442 / 0xFFA2.

Backwards Compatibility

The receive routine can reference the start code (0xC9 or 0x9C) to determine whether a packet is "normal TPM2", then look for the frame size bytes equal to the payload, or if is, read the packet number and number of packets.


The packet number goes from 1 to 255 in decimal, so there are a maximum of 255 packets, each around 1,490 bytes. This allows for 379,950 bytes per frame sent by, which would amount to 126,650 RGB LEDs.

Splitting Packets

The number of packets issent along to help control automatic memory allocation on the receiver. It may be convenient to have the number of packets can vary in each case, but keep all packets the same size. Otherwise, it is much more complicated for the receiver to put the packets back together again.

For example, if you have an RGB matrix with 32x32 = 1024 pixels or 3,072 bytes, you can then send 3 packets of 1,024 bytes. If you build a larger array of modules with 16x16 = 256 RGB pixels to build, then it could be useful to send a packet with 768 bytes per module. The transmission software must be configured to assemble the packets as the receiver expects. Usually you have to configure it anyway to set the number of pixels.

Temporal numbering is not provided, since it is assumed that is used in small networks without a router, so the packets arrive in the order in which they were sent.


The original protocol description, in German, is here:

I translated it using Google Translate and then cleaned up the mangled English. Hopefully it is still true to the spirit of the original text.


This comment has been minimized.

Copy link

commented Aug 12, 2017

Thanks! Unfortunately, the table is not properly formatted. I fixed it here.


This comment has been minimized.

Copy link
Owner Author

commented Sep 10, 2017

I'm not sure what happened there. It used to display properly. Maybe github got stricter on markdown rendering. Anyway I fixed it now.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.