Although computing a checksum isn't specific to I2C, it is another common task. The datasheet explains that the polynomial used is:
X8 + X5 + X4 + 1
Once you have this information you can work out the divisor by writing a binary number with a one in each location corresponding to a power of X in the polynomial. In this case the 8th, 5th, 4th and 1st bit. Hence the divisor is:
0x0131
What you do next is roughly the same for all CRCs. First you put the data that was used to compute the checksum together with the checksum value as the low order bits:
Now you have three bytes, i.e 24 bits in a 32-bit value. Next you adjust the divisor so that its most significant non-zero bit aligns with the most significant bit of the three bytes. As this divisor has a 1 at bit eight it needs to be shifted 15 places to the right to move it to be the 24th bit:
uint32_t divisor = 0x988000;
Now that you have both the data and the divisor aligned, you step through the top-most 16 bits, i.e. you don't process the low order eight bits which is the received checksum. For each bit you check to see if it is a 1 - if it is you replace the data with the data XOR divisor. In either case you shift the divisor one place to the right:
for (int i = 0; i < 16; i++) {
if (data32 & (uint32_t) 1 << (23 - i)) data32 ^= divisor;
divisor >>= 1;
};
When the loop ends, if there was no error, the data32 should be zeroed and the received checksum is correct and as computed on the data received.
Are you ready for Thanksgiving, when overeating remorse and a surfeit of being thankful causes the unsettling thought that there are only four weeks till the Xmas break? So here is a mix of weird [ ... ]