Checksums and CRC
What a CRC is, how to read Width/Poly/Init/RefIn/RefOut/XorOut/Check, how CRC differs from SUM/XOR/LRC and why the Modbus CRC is sent low byte first.
Why a checksum
The sender computes a short value from the data and appends it to the message. The receiver repeats the calculation: if the result differs, the message is corrupted and discarded. A checksum detects errors; it does not correct them and does not protect against deliberate tampering.
Simple sums
| Algorithm | Calculation | Typical use |
|---|---|---|
| SUM-8 | sum of bytes modulo 256 | simple instrument protocols |
| SUM-16 | sum of bytes modulo 65,536 | bootloaders, firmware files |
| XOR-8 | exclusive OR of all bytes | NMEA 0183, simple protocols |
| LRC | two's complement of the byte sum | Modbus ASCII |
Simple sums miss swapped bytes and many double errors. A CRC of the same length is far stronger.
CRC
A CRC is the remainder of dividing the message, treated as a polynomial over GF(2), by a generator polynomial. In practice an algorithm is fully described by the Rocksoft parameter model (Ross Williams), used by the RevEng catalogue and most calculators:
| Parameter | Meaning |
|---|---|
| Width | result size: 8, 16, 32 bit |
| Poly | generator polynomial without the top bit, in normal (MSB-first) notation |
| Init | initial register value |
| RefIn | whether the bits of each input byte are reflected (processed LSB first) |
| RefOut | whether the final result is reflected |
| XorOut | value XORed with the result at the end |
| Check | CRC of the ASCII string 123456789 — reference value for verifying an implementation |
The same polynomial with different parameters gives different CRCs: CRC-16/ARC and CRC-16/MODBUS both use 0x8005, but with Init 0x0000 and 0xFFFF. So always name the algorithm fully, not just "CRC16".
Common variants
| Name (RevEng) | Width | Poly | Init | RefIn/Out | XorOut | Check |
|---|---|---|---|---|---|---|
| CRC-16/MODBUS | 16 | 8005 | FFFF | true | 0000 | 4B37 |
| CRC-16/ARC | 16 | 8005 | 0000 | true | 0000 | BB3D |
| CRC-16/IBM-3740 (CCITT-FALSE) | 16 | 1021 | FFFF | false | 0000 | 29B1 |
| CRC-16/XMODEM | 16 | 1021 | 0000 | false | 0000 | 31C3 |
| CRC-16/KERMIT | 16 | 1021 | 0000 | true | 0000 | 2189 |
| CRC-32/ISO-HDLC | 32 | 04C11DB7 | FFFFFFFF | true | FFFFFFFF | CBF43926 |
| CRC-32/ISCSI (CRC-32C) | 32 | 1EDC6F41 | FFFFFFFF | true | FFFFFFFF | E3069283 |
CRC value vs bytes in the frame
A CRC value is a number. The frame carries it as bytes in the order defined by the protocol. Modbus RTU sends the CRC low byte first:
Request: 01 03 00 00 00 02
CRC-16/MODBUS = 0x0BC4
In the frame: 01 03 00 00 00 02 C4 0B
If the calculator shows 0x0BC4 and the frame contains C4 0B, they are the same thing. This is the most common source of "my CRC doesn't match": comparing the value with bytes in the other order.
A useful property: CRC-16/MODBUS computed over the whole frame including a correctly appended CRC is zero.
Verifying your implementation
- Compute the CRC of
123456789— the result must equal Check from the catalogue. - Compare a real frame against an independent source (RevEng catalogue, crccalc.com, a language library).
- Make sure the bytes are appended in the protocol's order.
Tools
- Checksum Calculator — all variants at once, parameters, custom CRC.
- Modbus CRC16 and RTU Frame Parser — CRC check on a real frame.
Connections
Open in Knowledge Graph →Loading the map…
Sources
- CRC RevEng — Catalogue of parametrised CRC algorithms — Greg Cook
- Ross N. Williams — A Painless Guide to CRC Error Detection Algorithms — zlib.net (mirror)
- MODBUS over Serial Line Specification and Implementation Guide V1.02 — Modbus Organization
Updated 2026-10-01