Modicon Modbus Protocol Guide (PI-MBUS-300) RTU CRC calculation description correction

There are many correct 'C' routines published for Modbus RTU CRC calculation. However if for you want to implement the procedure in another language (Power Basic for example) and implement it from the documented description of Modbus RTU CRC calculation in the Modicon Modbus Protocol guide PI-MBUS-300 (Rev J for example) you will find it gives the wrong result

The description is wrong because in its loop, testing CRC LSB and shifting through 8 bits, it examines the LSB value of the CRC register after a shift of the register and not before. Whether or not to XOR the CRC with the polynomial after the shift depends on the CRC LSB value before the shift. Below the description of it is modified to an order which gives the correct result.

1. Load a 16-bit register with FFF hex (all 1's) Call this the CRC register

2. Exclusive OR the first 8 bit byte of the message with the low-order byte of the CRC register

3. Extract and examine the LSB

4. (If the LSB was 1): Shift the CRC one bit to the right towards the LSB, zero-filling the MSB
Exclusive OR the CRC register with the polynomial value A001 hex (1010 0000 0000 0001)

(if the LSB was 0): Just shift the CRC one bit to the right towards the LSB, zero-filling the MSB.

5. Repeat Steps 3 and 4 until 8 shifts have been performed. When this is done a complete 8-bit byte will have been processed

6. Repeat Steps 2 through 5 for the next 8-bit byte of the message.

Continue doing this until all bytes have been processed

7. The final contents of the CRC register is the CRC value

8. When the CRC is placed in the message its upper and lower bytes must be swapped as described below

Placing the CRC in the Message

When the 16-bit CRC (two 8 bit bytes) is transmitted in the message, the low-order byte will be transmitted first, followed by the high order byte. For example, if the CRC value is 1241 hex (0001 0010 0100 0001):

Addr​
Func​
Data Count​
Data​
Data​
Data​
Data​
Data​
CRCLo
41​
CRCHi
12​
 
I don't think the spec is necessarily wrong, you may just not be interpreting it the way it was intended.

The line in question is
3. Shift the CRC register one bit to the right (toward the LSB), zero–filling the MSB. Extract and examine the LSB.

The intended interpretation of the above is that the LSB referred to is the bit that is right-shifted out of the CRC register (I believe this is why the the term "extract" is used and in the later instructions the wording "If the LSB was" is used instead of "If the LSB is"). For example, right shifting a byte-value of 0x15, in binary is 00010101. Shifting one bit to the right gives 00001010. The LSB that is extracted (shifted out) is a 1.

In addition, please note that the PI-MBUS-300 spec you're referring to is over 25 years old (from 1996) and is obsolete. Although the CRC description is identical in the latest spec (Modbus Serial Line Protocol and Implementation Guide V1.02).
 
I don't think the spec is necessarily wrong, you may just not be interpreting it the way it was intended.

The line in question is
3. Shift the CRC register one bit to the right (toward the LSB), zero–filling the MSB. Extract and examine the LSB.

The intended interpretation of the above is that the LSB referred to is the bit that is right-shifted out of the CRC register (I believe this is why the the term "extract" is used and in the later instructions the wording "If the LSB was" is used instead of "If the LSB is"). For example, right shifting a byte-value of 0x15, in binary is 00010101. Shifting one bit to the right gives 00001010. The LSB that is extracted (shifted out) is a 1.

In addition, please note that the PI-MBUS-300 spec you're referring to is over 25 years old (from 1996) and is obsolete. Although the CRC description is identical in the latest spec (Modbus Serial Line Protocol and Implementation Guide V1.02).
OK thanks, that defence makes sense. In the old days the bit shifted out could well have ended up in a carry bit easy to test in assembly code. I realise it is a pretty academic and obscure point after all this time but I couldn't see what was wrong with my implementation (which tested the LSB remaining in the byte after the shift) until I read someone else's written in C. I made my post in case it should help someone else. Thanks for responding.
 
Top