Embedded & Electronics Toolkit
← All guides

Why Your CRC Does Not Match

Two devices compute "CRC-16" over the same bytes and get different answers. Neither has a bug in the usual sense. "CRC-16" names a width, not an algorithm, and there are dozens of 16-bit CRCs in use that differ in four other settings. This guide explains those settings, gives reference values to test against, and ends with a procedure for finding which one is wrong.

Five parameters define a CRC

ParameterMeaning
WidthSize of the result in bits: 8, 16, 32
PolynomialThe divisor, written without its top bit, for example 0x8005 or 0x1021
InitValue of the register before the first byte
ReflectionWhether bytes are processed least significant bit first, and whether the result is bit-reversed
XOR-outValue XORed onto the result at the end

A mismatch in any one of them gives a completely different result, not a nearly right one. That is by design: a CRC spreads every input bit across the whole output.

Reference values

The standard way to identify a CRC is its check value: the result for the nine ASCII bytes 123456789. If your implementation returns the check value, all five parameters are right.

NamePolynomialInitReflectedXOR-outCheck value
CRC-80x070x00no0x000xF4
CRC-16/MODBUS0x80050xFFFFyes0x00000x4B37
CRC-16/ARC0x80050x0000yes0x00000xBB3D
CRC-16/CCITT-FALSE0x10210xFFFFno0x00000x29B1
CRC-16/XMODEM0x10210x0000no0x00000x31C3
CRC-16/KERMIT0x10210x0000yes0x00000x2189
CRC-320x04C11DB70xFFFFFFFFyes0xFFFFFFFF0xCBF43926
CRC-32/MPEG-20x04C11DB70xFFFFFFFFno0x000000000x0376E6E7

Look at the three rows with polynomial 0x1021. Same polynomial, three different results, and all three are called "CCITT" somewhere. The same holds for MODBUS and ARC, which differ only in the initial value. A specification that says "CRC-16 CCITT" without stating init and reflection has not told you which CRC to use.

Reflection, and the two faces of a polynomial

A reflected CRC processes each byte starting from its least significant bit. This matches how a UART puts bits on the wire, which is why serial protocols such as Modbus use reflected CRCs. Software implementations of reflected CRCs shift right instead of left, and to make that work they use the bit-reversed polynomial:

Polynomial as specifiedBit-reversed form used in right-shifting code
0x80050xA001
0x10210x8408
0x04C11DB70xEDB88320

So 0x8005 and 0xA001 are the same polynomial in two notations. Seeing 0xA001 in Modbus code and 0x8005 in the Modbus specification is not a contradiction. Mixing them up, by using 0xA001 in left-shifting code, gives a valid but different CRC that matches nothing.

Why the initial value is not zero

With an initial value of zero, leading zero bytes do not change the register. A message of four zero bytes and a message of five zero bytes both produce a CRC of zero under CRC-16/XMODEM, so a dropped or extra leading zero goes undetected. Starting from 0xFFFF fixes this: the same two messages give 0x84C0 and 0x110C. This is the reason most modern protocols use a non-zero initial value, and a good reason to choose one when designing your own.

Byte order on the wire

The CRC is a number; the protocol decides in which order its bytes are sent. Modbus RTU sends the low byte first. For the check string the CRC is 0x4B37, and the bytes appended to the frame are 37 4B. For the common request 01 03 00 00 00 0A the CRC is 0xCDC5 and the frame ends in C5 CD. Getting this backwards is the single most common Modbus CRC mistake, and it shows up as a CRC that looks right in the debugger and is rejected by the other device.

The residue trick

There is a neat way for a receiver to check a frame without separating the CRC from the data: run the CRC over the whole frame, including the received CRC bytes. If the frame is intact and the CRC was appended in the natural byte order for that algorithm, the result is a fixed constant.

This also works as a test of byte order. If the CRC over message plus CRC is not the expected constant, but the separately computed CRC matches, the two CRC bytes are swapped.

What a CRC does and does not guarantee

An n-bit CRC detects every single-bit error and every burst of errors no longer than n bits. For random corruption beyond that, a fraction of about 1 in 2n goes undetected: 1 in 65,536 for a 16-bit CRC, 1 in about 4.3 billion for a 32-bit one. A 16-bit CRC is appropriate for short frames on a serial link. For a firmware image of several hundred kilobytes, use 32 bits.

A CRC is not a security measure. Anyone who can change the data can recompute the CRC. To detect deliberate modification, use a cryptographic hash or a message authentication code.

Bitwise or table-driven

The bitwise algorithm needs no table and eight shift-and-XOR steps per byte. The table-driven version replaces those eight steps with one lookup, at the cost of a 256-entry table: 512 bytes of flash for a 16-bit CRC, 1 kB for a 32-bit one. On a small microcontroller checking a 20-byte frame, bitwise is fine. For megabytes of data, such as an image check at boot, the table pays for itself. Either way, keep the table in flash by declaring it const.

Some microcontrollers have a hardware CRC unit. Before relying on it, feed it 123456789 and compare with the table above. Hardware units often implement the non-reflected 32-bit variant and consume whole 32-bit words, so the result differs from the reflected CRC-32 used by zip, Ethernet and most PC tools unless the unit is configured, or the data pre-processed, to match.

Finding the wrong parameter

  1. Compute the CRC of 123456789 with your code. Compare with the check value of the variant you believe you are implementing.
  2. If it differs, compare against the other rows of the table. A match there tells you which variant you have actually implemented, and therefore which parameter is off.
  3. If your check value is right but the other device still disagrees, the algorithm is fine. Look at what is being fed in: the range of bytes covered, whether an address or length byte is included, and the byte order of the appended CRC.
  4. Capture one real frame from the other device and run your CRC over it, with and without the trailing CRC bytes. Use the residue constants above to check the byte order.

Step 3 is where most real problems are. The arithmetic is rarely wrong for long; the disagreement is usually about which bytes are covered.

Run the numbers: CRC Calculator does this calculation for your own values.

More guides