#### CRC verification experiment of Modbus

formulation

```
Name : "CRC-16/MODBUS"
Width : 16
Poly : 8005
Init : FFFF
RefIn : True
RefOut : True
XorOut : 0000
Check : ?
```

First, refer to the Modbus calibration program given by some manufacturers

`const unsigned char auchCRCHi[] = {`

From the above program, we can see that the method used is the direct drive table method, but the generated table is inconsistent with the table generated by direct calculation of forward poly.

The reason is that MODBUS uses the option of inverting input bytes, so the generated tables are different

So how is this table generated?

`poly 18005`

Because the CRC in MODBUS has selected the option “find”, let’s see how this table is generated

```
unsigned short crcTable[256] = {0};
unsigned short poly = 0xa001;
void crcTableCreate(void)
{
int i = 0;
for(i = 0; i < 256; i++)
{
unsigned short crc = i;
for(int j = 0; j < 8; j++)
{
if(crc & 0x0001)
{
crc = (crc >> 1) ^ poly;
}
else
{
crc = crc >> 1;
}
}
crcTable[i] = crc;
}
}
0000,c0c1,c181,0140,c301,03c0,0280,c241,c601,06c0,0780,c741,0500,c5c1,c481,0440,
cc01,0cc0,0d80,cd41,0f00,cfc1,ce81,0e40,0a00,cac1,cb81,0b40,c901,09c0,0880,c841,
d801,18c0,1980,d941,1b00,dbc1,da81,1a40,1e00,dec1,df81,1f40,dd01,1dc0,1c80,dc41,
1400,d4c1,d581,1540,d701,17c0,1680,d641,d201,12c0,1380,d341,1100,d1c1,d081,1040,
f001,30c0,3180,f141,3300,f3c1,f281,3240,3600,f6c1,f781,3740,f501,35c0,3480,f441,
3c00,fcc1,fd81,3d40,ff01,3fc0,3e80,fe41,fa01,3ac0,3b80,fb41,3900,f9c1,f881,3840,
2800,e8c1,e981,2940,eb01,2bc0,2a80,ea41,ee01,2ec0,2f80,ef41,2d00,edc1,ec81,2c40,
e401,24c0,2580,e541,2700,e7c1,e681,2640,2200,e2c1,e381,2340,e101,21c0,2080,e041,
a001,60c0,6180,a141,6300,a3c1,a281,6240,6600,a6c1,a781,6740,a501,65c0,6480,a441,
6c00,acc1,ad81,6d40,af01,6fc0,6e80,ae41,aa01,6ac0,6b80,ab41,6900,a9c1,a881,6840,
7800,b8c1,b981,7940,bb01,7bc0,7a80,ba41,be01,7ec0,7f80,bf41,7d00,bdc1,bc81,7c40,
b401,74c0,7580,b541,7700,b7c1,b681,7640,7200,b2c1,b381,7340,b101,71c0,7080,b041,
5000,90c1,9181,5140,9301,53c0,5280,9241,9601,56c0,5780,9741,5500,95c1,9481,5440,
9c01,5cc0,5d80,9d41,5f00,9fc1,9e81,5e40,5a00,9ac1,9b81,5b40,9901,59c0,5880,9841,
8801,48c0,4980,8941,4b00,8bc1,8a81,4a40,4e00,8ec1,8f81,4f40,8d01,4dc0,4c80,8c41,
4400,84c1,8581,4540,8701,47c0,4680,8641,8201,42c0,4380,8341,4100,81c1,8081,4040,
```

The tables generated by this method are consistent with those given by the government, but the high and low bits are reversed. How to understand this? It is because the low bit first XOR method, then the byte filling method is inconsistent with the forward direction, and the reverse mode is equivalent to that the data is filled on the left side of the data string. Therefore, the last 8 bits of the CRC generated are instead advanced with the last in data Line XOR.

The formula of direct drive table method in this way is also different from poly

```
unsigned short crcUpdate3(unsigned short crcIn, unsigned char data)
{
unsigned short result = 0;
//result = (crcIn << 8) ^ crcTable[(crcIn >> 8) ^ data]; // poly
result = (crcIn >> 8) ^ crcTable[(crcIn & 0xff) ^ data]; // reversed poly
return result;
}
unsigned short crcCheck3(unsigned char *pData, unsigned char size)
{
unsigned short crcResult = 0xffff;//Initial Value
for(int i = 0; i < size; i++)
{
crcResult = crcUpdate3(crcResult, *(pData+i));
}
return crcResult;
}
```

If you want to get the same result from the three methods, the initial register value of the direct drive table method must be 0 to achieve the same output results of the three methods. Otherwise, the direct drive table method can get the same result as the other two methods, because the direct drive table method is a variation of the direct counting method.

The following is the specific implementation of three consistent results for Modbus,The initial value of the register is set to 0

```
unsigned short crcUpdate(unsigned short crcIn, unsigned char data)
{
unsigned short result = 0;
unsigned int poly = (0xa001 << 1) + 1;
unsigned int tmp = crcIn;
for(int i = 0; i < 8; i++)
{
if(data & 0x01)
{
tmp += 0x10000;
}
data >>= 1;
if(tmp & 0x0001)
{
tmp ^= poly;
}
tmp >>= 1;
}
result = tmp & 0xffff;
return result;
}
unsigned short crcCheck(unsigned char *pData, unsigned char size)
{
unsigned short crcResult = 0x0000;//Initial Value
for(int i = 0; i < size; i++)
{
crcResult = crcUpdate(crcResult, *(pData+i));
}
for(int i = 0; i < 2; i++)
{
crcResult = crcUpdate(crcResult, 0x00);
}
return crcResult;
}
unsigned short crcUpdate2(unsigned short crcIn, unsigned char data)
{
unsigned short result = 0;
result = (crcIn >> 8 | data << 8) ^ crcTable[(crcIn & 0xff)];
return result;
}
unsigned short crcCheck2(unsigned char *pData, unsigned char size)
{
unsigned short crcResult = 0x0000;//Initial Value
for(int i = 0; i < size; i++)
{
crcResult = crcUpdate2(crcResult, *(pData+i));
}
for(int i = 0; i < 2; i++)
{
crcResult = crcUpdate2(crcResult, 0x00);
}
return crcResult;
}
unsigned short crcUpdate3(unsigned short crcIn, unsigned char data)
{
unsigned short result = 0;
result = (crcIn >> 8) ^ crcTable[(crcIn & 0xff) ^ data];
return result;
}
unsigned short crcCheck3(unsigned char *pData, unsigned char size)
{
unsigned short crcResult = 0x0000;//Initial Value
for(int i = 0; i < size; i++)
{
crcResult = crcUpdate3(crcResult, *(pData+i));
}
return crcResult;
}
```

The byte is inverted and the small bit is calculated first because some hardware circuits are sent by LSB first. If the calculation of small bits is started, CRC calculation can be started directly for the data entered by hardware, which is convenient for the implementation of hardware circuit.