Search code examples
c++crccan-buscrc16

How CRC16 using bytes data is woking ? (for CAN bus implementation)


I have some trouble implementing a CRC16 for can message, I followed the instructions given by this website https://barrgroup.com/embedded-systems/how-to/crc-calculation-c-code and http://www.sunshine2k.de/articles/coding/crc/understanding_crc.html#ch5, plus other implention I have seen in here ( for example Function to Calculate a CRC16 Checksum).

I don't understand how it is processed. My message here is in form of bytes, for example char message[4] = {0x12, 0x34, 0x56, 0x78}. When I go through the first loop I just take the first byte, shift it by 8 and calculate the remainder with a POLYNOME of 16 bits. That means we have 0x1200 and we go through the second loop with it, which mean I do a XOR with the POLYNOME that I store in the remainder but I don't quite understand why this works, especially when I look at this code, the 2nd, 3rd and 4th bytesof my message which should get XORed by the 8 first bits of the POLYNOME at some points aren't going through it at all. According to the wikipedia explanation https://en.wikipedia.org/wiki/Cyclic_redundancy_check the polynome goes through the whole message at once and not byte by byte. I don't know how that translates to doing the CRC of 0x12345678 byte by byte.

uint16_t Compute_CRC16_Simple(char* message, int nbOfBytes)
{
    uint16_t POLYNOME = 0xC599; 
    uint16_t remainder = 0; 
    for (int byte = 0;byte < nbOfBytes; byte++)
    {
        remainder ^= (message[byte] << 8); 

        for (int i = 0; i < 8; i++)
        {
            if (remainder  & 0x8000) 
            {
                remainder = (remainder << 1) ^ POLYNOME ;
            }
            else
            {
                remainder <<= 1;
            }
        }
    }
    return remainder;
}

Solution

  • I don't understand how it is processed.

    Maybe it will help to describe the bit by bit operations for 8 bits of data:

    crc[bit15] ^= data[bit7]
    if(crc[bit15] == 1) crc = (crc << 1) ^ poly
    else crc = crc << 1
    crc[bit15] ^= data[bit6]
    if(crc[bit15] == 1) crc = (crc << 1) ^ poly
    else crc = crc << 1
    ...
    crc[bit15] ^= data[bit0]
    if(crc[bit15] == 1) crc = (crc << 1) ^ poly
    else crc = crc << 1
    

    Note that the if statement only depends on the bit value in crc[bit15], so the fixed part of the XOR with data could be done in one step:

    crc[bit15 .. bit8] ^= data[bit7 .. bit0]
    if(crc[bit15] == 1) crc = (crc << 1) ^ poly
    else crc = crc << 1
    if(crc[bit15] == 1) crc = (crc << 1) ^ poly
    else crc = crc << 1
    ...
    if(crc[bit15] == 1) crc = (crc << 1) ^ poly
    else crc = crc << 1
    

    The cycling of the CRC 8 times using those if ... then (shift + xor poly) else (just shift) could be precomputed for all 256 possible values in crc[bit15 .. bit8], and stored in a table for table lookup to cycle the CRC 8 times.