I am using the ModBus RTU, and I'm trying to figure out how to calculate the CRC16. I don't need a code example. I am simply curious about the mechanism. I have learned that a basic CRC is a polynomial division of the data word, which is padded with zeros, depending on the length of the polynomial. The following test example is supposed to check if my basic understanding is correct:
- data word: 0100 1011
- polynomial: 1001 (x3+1)
- padded by 3 bits because of highest exponent x3
- calculation: 0100 1011 000 / 1001 -> remainder: 011
Calculation.
01001011000
1001
0000011000
1001
01010
1001
0011
Edit1: So far verified by Mark Adler in previous comments/answers.
Searching for an answer I have seen a lot of different approaches with reversing, dependence on little or big endian, etc., which alter the outcome from the given 011
.
Modbus RTU CRC16
Of course I would love to understand how different versions of CRCs work, but my main interest is to simply understand what mechanism is applied here. So far I know:
- x16+x15+x2+1 is the polynomial: 0x18005 or 0b11000000000000101
- initial value is 0xFFFF
- example message in hex: 01 10 C0 03 00 01
- CRC16 of above message in hex: C9CD
I did calculate this manually like the example above, but I'd rather not write this down in binary in this question. I presume my transformation into binary is correct. What I don't know is how to incorporate the initial value -- is it used to pad the data word with it instead of zeros? Or do I need to reverse the answer? Something else?
1st attempt: Padding by 16 bits with zeros. Calculated remainder in binary would be
1111 1111 1001 1011
which isFF9B
in hex and incorrect for CrC16/Modbus, but correct for CRC16/Bypass2nd attempt: Padding by 16 bits with ones, due to initial value. Calculated remainder in binary would be
0000 0000 0110 0100
which is0064
in hex and incorrect.
It would be great if someone could explain, or clarify my assumptions. I honestly did spent many hours searching for an answer, but every explanation is based on code examples in C/C++ or others, which I don't understand. Thanks in advance.
EDIT1: According to this site, "1st attempt" points to another CRC16-method with same polynomial but a different initial value (0x0000), which tells me, the calculation should be correct. How do I incorporate the initial value?
EDIT2: Mark Adlers Answer does the trick. However, now that I can compute CRC16/Modbus there are some questions left for clearification. Not needed but appreciated.
A) The order of computation would be: ... ?
- 1st applying RefIn for complete input (including padded bits)
- 2nd
xor
InitValue with (in CRC16) for the first 16 bits - 3rd applying RefOut for complete output/remainder (remainder maximum 16 bits in CRC16)
B) Referring to RefIn and RefOut: Is it always reflecting 8 bits for input and all bits for output nonetheless I use CRC8 or CRC16 or CRC32?
C) What do the 3rd (check) and 8th (XorOut) column in the website I am referring to mean? The latter seems rather easy, I am guessing its apllied by computing the value xor
after RefOut just like the InitValue?