5.e. Cyclic Redundancy Check (CRC) Error Detection

For certain applications, verifying the integrity of the data you’re sending and receiving can be very important. Because of this, the TReX has optional 7-bit cyclic redundancy checking, which is similar to a standard checksum but somewhat more robust as it can detect duplicated and out-of-order bytes.

When bit 6 of the serial settings parameter is cleared and bit 5 is set, cyclic redundancy checking is enabled. In CRC mode, the TReX expects an extra byte to be tacked onto the end of every command packet. The lower seven bits of this byte must be the 7-bit CRC for that packet, or else the TReX will set its CRC Error bit in the UART Error Byte and ignore the command. The TReX will also transmit an additional byte every time it returns data; the lower seven bits of this byte will be the 7-bit CRC for the packet of data the TReX is sending you.

A detailed account of how cyclic redundancy checking works is beyond the scope of this document, but you can find a wealth of information using Wikipedia. The quick version is that a CRC computation is basically a carryless long division of a CRC “polynomial” into your message, where all you care about is the remainder. The TReX uses CRC-7, which means it uses an 8-bit polynomial (whose MSB must always be 1) and, as a result, produces a 7-bit remainder. This remainder is the lower 7 bits of the CRC byte you tack onto the end of your command packets.

The CRC-7 algorithm is as follows:

  1. Express your 8-bit CRC-7 polynomial (TReX default is 0x89) and message in binary.
  2. Add 7 zeroes to the end of your message.
  3. Write your CRC-7 polynomial underneath the message so that the MSB of your polynomial is directly below the MSB of your message.
  4. If the MSB of your CRC-7 is aligned under a 1, XOR the CRC-7 with the message to get a new message; if the MSB of your CRC-7 is aligned under a 0, do nothing.
  5. Shift your CRC-7 right one bit. If all 8 bits of your CRC-7 polynomial still line up underneath message bits, go back to step 4.
  6. What’s left of your message is now your CRC-7 result (transmit these seven bits as your CRC byte when talking to the TReX with CRC enabled).

If you’ve never encountered CRCs before, this probably sounds a lot more complicated than it really is. Allow me to demonstrate a sample CRC-7 calculation so you can see how this actually works. Our CRC-7 polynomial will be 0x89 (the default TReX CRC-7 polynomial) and our message will be a two-byte sequence: 0x86, 0x1F (the command packet to get raw channel input values for all five channels).


Steps 1 & 2 (write as binary, add 7 zeroes to the end of the message):

    CRC-7 Polynomial = [1 0 0 0 1 0 0 1]
    message = [1 0 0 0 0 1 1 0] [0 0 0 1 1 1 1 1] 0 0 0 0 0 0 0

Steps 3, 4, & 5:
                    _______________________________________________
    1 0 0 0 1 0 0 1 ) 1 0 0 0 0 1 1 0 0 0 0 1 1 1 1 1 0 0 0 0 0 0 0
                  XOR 1 0 0 0 1 0 0 1 | | | | | | | | | | | | | | |
                      --------------- | | | | | | | | | | | | | | |
                        0 0 0 1 1 1 1 0 0 0 1 | | | | | | | | | | |
                 shift  ----> 1 0 0 0 1 0 0 1 | | | | | | | | | | |
                              _______________ | | | | | | | | | | |
                                1 1 1 1 0 0 0 1 | | | | | | | | | |
                                1 0 0 0 1 0 0 1 | | | | | | | | | |
                                _______________ | | | | | | | | | |
                                  1 1 1 1 0 0 0 1 | | | | | | | | |
                                  1 0 0 0 1 0 0 1 | | | | | | | | |
                                  _______________ | | | | | | | | |
                                    1 1 1 1 0 0 0 1 | | | | | | | |
                                    1 0 0 0 1 0 0 1 | | | | | | | |
                                    _______________ | | | | | | | |
                                      1 1 1 1 0 0 0 1 | | | | | | |
                                      1 0 0 0 1 0 0 1 | | | | | | |
                                      _______________ | | | | | | |
                                        1 1 1 1 0 0 0 0 | | | | | |
                                        1 0 0 0 1 0 0 1 | | | | | |
                                        _______________ | | | | | |
                                          1 1 1 1 0 0 1 0 | | | | |
                                          1 0 0 0 1 0 0 1 | | | | |
                                          _______________ | | | | |
                                            1 1 1 1 0 1 1 0 | | | |
                                            1 0 0 0 1 0 0 1 | | | |
                                            _______________ | | | |
                                              1 1 1 1 1 1 1 0 | | |
                                              1 0 0 0 1 0 0 1 | | |
                                              _______________ | | |
                                                1 1 1 0 1 1 1 0 | |
                                                1 0 0 0 1 0 0 1 | |
                                                _______________ | |
                                                  1 1 0 0 1 1 1 0 |
                                                  1 0 0 0 1 0 0 1 |
                                                  _______________ |
                                                    1 0 0 0 1 1 1 0
                                                    1 0 0 0 1 0 0 1
                                                    _______________
                                                      0 0 0 0 1 1 1 = 0x07

So the full command packet we would send to retrieve the raw channel inputs for all five channels with CRC enabled is: 0x86, 0x1F, 0x07

There are some tricks you can use in your programs to make the CRC calculation much more efficient from a speed perspective. You can find an example of this Section 5.f.