8

I have seen multiple implementation of crc8 implementation in C, but I am unable to figure out for polynomial(x8,x5,x4,1) i.e. 0x31 and initialization 0xFF.

Also reflect input = False, reflect output = False and final XOR = 0x00.

I tried several of them, and I expect such that CRC(0x00)=0xAC and CRC(0xBEEF)=0x92.

I have seen similar implementations, but nothing really worked out. I saw the exact functionality in here http://www.sunshine2k.de/coding/javascript/crc/crc_js.html where I could give initialization, reflect input, reflect output, and final XOR. But can somebody point to me implementation in C. I do understand that initially we need to give crc as 0xFF, but nothing worked out for me so far.

Please find the sample code that I tried attached:

#include <stdio.h>
#include <stdint.h>

uint8_t crc8(uint16_t input);

int main()
{
    uint8_t temp1;
    uint16_t temp2 = 0xBEEF;

    printf("CRC input is 0x%X\n", temp2);

    temp1 = crc8(temp2);

    printf("CRC output is 0x%X\n", temp1);

    return 0;
}

uint8_t crc8(uint16_t input)
{
    uint8_t crc[8] = { };
    uint8_t i;
    uint8_t inv;
    uint8_t output = 0;

    for(i = 0; i < 16; i++)
    {
        inv = ((((input >> i) & 1) ^ crc[7]) & 1);

        crc[7] = (crc[6] & 1);
        crc[6] = (crc[5] & 1);
        crc[5] = (crc[4] ^ inv & 1);
        crc[4] = (crc[3] ^ inv & 1);
        crc[3] = (crc[2] & 1);
        crc[2] = (crc[1] & 1);
        crc[1] = (crc[0] & 1);
        crc[0] = (inv & 1);
    }

    for(i = 0; i < 8; i++){
        output |= ((crc[i] << i) & (1 << i));
    }


    return output;
}

I am seeing

CRC input is 0xBEEF
CRC output is 0x2 //instead of 0x92
Kami Kaze
  • 2,069
  • 15
  • 27
arnab dasgupta
  • 219
  • 2
  • 3
  • 9

5 Answers5

14

Assuming your running on a PC or other little endian processor, temp2 is stored in memory as {0xEF, 0xBE}. Unoptimized example code (doesn't use a table). For a faster version, the inner loop using j could be replaced with a 256 byte table lookup: crc = table[crc ^ data[i]];

#include <stdio.h>

typedef unsigned char uint8_t;

uint8_t gencrc(uint8_t *data, size_t len)
{
    uint8_t crc = 0xff;
    size_t i, j;
    for (i = 0; i < len; i++) {
        crc ^= data[i];
        for (j = 0; j < 8; j++) {
            if ((crc & 0x80) != 0)
                crc = (uint8_t)((crc << 1) ^ 0x31);
            else
                crc <<= 1;
        }
    }
    return crc;
}

int main()
{
uint8_t data[8] = {0xBE,0xEF,0,0,0,0,0,0};
uint8_t crc;
    crc = gencrc(data, 2);   /* returns 0x92 */
    printf("%1x\n", crc);
    crc = gencrc(data+2, 1); /* returns 0xac */
    printf("%1x\n", crc);
    return 0;
}
rcgldr
  • 27,407
  • 3
  • 36
  • 61
9

You call these with mem equal to NULL to get the initial CRC value. Then call with chunks of your data, updating the CRC value by feeding it the previous value.

#include <stddef.h>

unsigned crc8x_simple(unsigned crc, void const *mem, size_t len) {
    unsigned char const *data = mem;
    if (data == NULL)
        return 0xff;
    while (len--) {
        crc ^= *data++;
        for (unsigned k = 0; k < 8; k++)
            crc = crc & 0x80 ? (crc << 1) ^ 0x31 : crc << 1;
    }
    crc &= 0xff;
    return crc;
}

static unsigned char const crc8x_table[] = {
    0x00, 0x31, 0x62, 0x53, 0xc4, 0xf5, 0xa6, 0x97, 0xb9, 0x88, 0xdb, 0xea, 0x7d,
    0x4c, 0x1f, 0x2e, 0x43, 0x72, 0x21, 0x10, 0x87, 0xb6, 0xe5, 0xd4, 0xfa, 0xcb,
    0x98, 0xa9, 0x3e, 0x0f, 0x5c, 0x6d, 0x86, 0xb7, 0xe4, 0xd5, 0x42, 0x73, 0x20,
    0x11, 0x3f, 0x0e, 0x5d, 0x6c, 0xfb, 0xca, 0x99, 0xa8, 0xc5, 0xf4, 0xa7, 0x96,
    0x01, 0x30, 0x63, 0x52, 0x7c, 0x4d, 0x1e, 0x2f, 0xb8, 0x89, 0xda, 0xeb, 0x3d,
    0x0c, 0x5f, 0x6e, 0xf9, 0xc8, 0x9b, 0xaa, 0x84, 0xb5, 0xe6, 0xd7, 0x40, 0x71,
    0x22, 0x13, 0x7e, 0x4f, 0x1c, 0x2d, 0xba, 0x8b, 0xd8, 0xe9, 0xc7, 0xf6, 0xa5,
    0x94, 0x03, 0x32, 0x61, 0x50, 0xbb, 0x8a, 0xd9, 0xe8, 0x7f, 0x4e, 0x1d, 0x2c,
    0x02, 0x33, 0x60, 0x51, 0xc6, 0xf7, 0xa4, 0x95, 0xf8, 0xc9, 0x9a, 0xab, 0x3c,
    0x0d, 0x5e, 0x6f, 0x41, 0x70, 0x23, 0x12, 0x85, 0xb4, 0xe7, 0xd6, 0x7a, 0x4b,
    0x18, 0x29, 0xbe, 0x8f, 0xdc, 0xed, 0xc3, 0xf2, 0xa1, 0x90, 0x07, 0x36, 0x65,
    0x54, 0x39, 0x08, 0x5b, 0x6a, 0xfd, 0xcc, 0x9f, 0xae, 0x80, 0xb1, 0xe2, 0xd3,
    0x44, 0x75, 0x26, 0x17, 0xfc, 0xcd, 0x9e, 0xaf, 0x38, 0x09, 0x5a, 0x6b, 0x45,
    0x74, 0x27, 0x16, 0x81, 0xb0, 0xe3, 0xd2, 0xbf, 0x8e, 0xdd, 0xec, 0x7b, 0x4a,
    0x19, 0x28, 0x06, 0x37, 0x64, 0x55, 0xc2, 0xf3, 0xa0, 0x91, 0x47, 0x76, 0x25,
    0x14, 0x83, 0xb2, 0xe1, 0xd0, 0xfe, 0xcf, 0x9c, 0xad, 0x3a, 0x0b, 0x58, 0x69,
    0x04, 0x35, 0x66, 0x57, 0xc0, 0xf1, 0xa2, 0x93, 0xbd, 0x8c, 0xdf, 0xee, 0x79,
    0x48, 0x1b, 0x2a, 0xc1, 0xf0, 0xa3, 0x92, 0x05, 0x34, 0x67, 0x56, 0x78, 0x49,
    0x1a, 0x2b, 0xbc, 0x8d, 0xde, 0xef, 0x82, 0xb3, 0xe0, 0xd1, 0x46, 0x77, 0x24,
    0x15, 0x3b, 0x0a, 0x59, 0x68, 0xff, 0xce, 0x9d, 0xac};

unsigned crc8x_fast(unsigned crc, void const *mem, size_t len) {
    unsigned char const *data = mem;
    if (data == NULL)
        return 0xff;
    crc &= 0xff;
    while (len--)
        crc = crc8x_table[crc ^ *data++];
    return crc;
}

Either version gives your check values for 0x00 and 0xbe 0xef.

Mark Adler
  • 101,978
  • 13
  • 118
  • 158
2

To implement the initial value for the CRC you just have to set crc in the beginning to what you want to have. So either

uint8_t crc[8] = {1,1,1,1, 1,1,1,1};

or

memset(crc,1,8);

But you have a flaw in your logic and that is the reason why you do not get the right values (even without the init value). It is quite a small error, you read the input in the wrong direction:

inv = ((((input >> i) & 1) ^ crc[7]) & 1);

should be

inv = ((((input >> 15-i) & 1) ^ crc[7]) & 1);

after this your algorithm should work fine and you can set the init value like written above.

If you are looking for an implementation in C there is a big tutorial on the website you linked, also with code. It think it is written in C++ or maybe Java, but there are not many changes necessary to make this valid C code.

Kami Kaze
  • 2,069
  • 15
  • 27
  • thanks a lot, but for 0x00 it should be 0xAC, its reporting 0x81 after the changes, but thanks a lot for the help. – arnab dasgupta Aug 09 '18 at 16:39
  • I think it has gotto do with the polynomial, whiich is x8+x5+x4+1, dont know how to use this.. – arnab dasgupta Aug 09 '18 at 16:44
  • @arnabdasgupta your polynominal is correct. You mistake your input for 8 bit on the website, you have to enter 0000 for the correct calculation. For different length you would have to add a length parameter other wise your input is always 2bytes – Kami Kaze Aug 10 '18 at 05:57
0

I had to solve the same problem as you today. The answer from @rcgldr was great and a good help, thanks for that.

I implemented both versions with and without the table. I also used your link (http://www.sunshine2k.de/coding/javascript/crc/crc_js.html) to calculate the table.

Here is the code I used:

const uint8_t crc8x_table[256] = {
0x00,0x31,0x62,0x53,0xC4,0xF5,0xA6,0x97,0xB9,0x88,0xDB,0xEA,0x7D,0x4C,0x1F,0x2E,
0x43,0x72,0x21,0x10,0x87,0xB6,0xE5,0xD4,0xFA,0xCB,0x98,0xA9,0x3E,0x0F,0x5C,0x6D,
0x86,0xB7,0xE4,0xD5,0x42,0x73,0x20,0x11,0x3F,0x0E,0x5D,0x6C,0xFB,0xCA,0x99,0xA8,
0xC5,0xF4,0xA7,0x96,0x01,0x30,0x63,0x52,0x7C,0x4D,0x1E,0x2F,0xB8,0x89,0xDA,0xEB,
0x3D,0x0C,0x5F,0x6E,0xF9,0xC8,0x9B,0xAA,0x84,0xB5,0xE6,0xD7,0x40,0x71,0x22,0x13,
0x7E,0x4F,0x1C,0x2D,0xBA,0x8B,0xD8,0xE9,0xC7,0xF6,0xA5,0x94,0x03,0x32,0x61,0x50,
0xBB,0x8A,0xD9,0xE8,0x7F,0x4E,0x1D,0x2C,0x02,0x33,0x60,0x51,0xC6,0xF7,0xA4,0x95,
0xF8,0xC9,0x9A,0xAB,0x3C,0x0D,0x5E,0x6F,0x41,0x70,0x23,0x12,0x85,0xB4,0xE7,0xD6,
0x7A,0x4B,0x18,0x29,0xBE,0x8F,0xDC,0xED,0xC3,0xF2,0xA1,0x90,0x07,0x36,0x65,0x54,
0x39,0x08,0x5B,0x6A,0xFD,0xCC,0x9F,0xAE,0x80,0xB1,0xE2,0xD3,0x44,0x75,0x26,0x17,
0xFC,0xCD,0x9E,0xAF,0x38,0x09,0x5A,0x6B,0x45,0x74,0x27,0x16,0x81,0xB0,0xE3,0xD2,
0xBF,0x8E,0xDD,0xEC,0x7B,0x4A,0x19,0x28,0x06,0x37,0x64,0x55,0xC2,0xF3,0xA0,0x91,
0x47,0x76,0x25,0x14,0x83,0xB2,0xE1,0xD0,0xFE,0xCF,0x9C,0xAD,0x3A,0x0B,0x58,0x69,
0x04,0x35,0x66,0x57,0xC0,0xF1,0xA2,0x93,0xBD,0x8C,0xDF,0xEE,0x79,0x48,0x1B,0x2A,
0xC1,0xF0,0xA3,0x92,0x05,0x34,0x67,0x56,0x78,0x49,0x1A,0x2B,0xBC,0x8D,0xDE,0xEF,
0x82,0xB3,0xE0,0xD1,0x46,0x77,0x24,0x15,0x3B,0x0A,0x59,0x68,0xFF,0xCE,0x9D,0xAC };

uint8_t calculate_cr8x_fast(uint8_t* data, size_t len) {
    uint8_t crc = 0xFF; // init value
    for (size_t i = 0; i < len; i++) {
         crc = crc8x_table[data[i] ^ crc];
     }
   return crc;
}

uint8_t calculate_cr8x_slow(uint8_t* data, size_t len)
{
   uint8_t crc = 0xff; // init value
   size_t i, j;
   for (i = 0; i < len; i++) {
      crc ^= data[i];
      for (j = 0; j < 8; j++) {
          if ((crc & 0x80) != 0)
              crc = (uint8_t)((crc << 1) ^ 0x31);
          else
              crc <<= 1;
      }
  }
  return crc;
 }

// Function call in main
int main()
{
uint8_t data[2] = {0xBE,0xEF};
uint8_t crc;
crc = calculate_cr8x_fast(data, 2);   /* returns 0x92 */ // calculate_cr8x_slow is the same call
std::cout << std::hex << std::uppercase << static_cast<int>(crc)) << std::endl;
    return 0;
}
blitzmax
  • 11
  • 3
  • Hey harper, I checked with 255 and it didn’t compile. There are 256 byte needed. – blitzmax Jun 30 '22 at 10:26
  • Hey harper, yeah sure, you are right. I didn't read your comment correct. --> EDIT: value crc8x_table[255] is 0xAC not 0xA --> I changed it in the code – blitzmax Jul 01 '22 at 11:32
0

For anyone thinking of using Sunshine's CRC Calculator consider the following:

The default CRC8 has Polynomial: 0x7; Initial Value: 0x0; Final Xor Value: 0x0

Consider the CRCs generated by the following strings: 0x00

0x00 0x00

0x00 0x00 0x00 0x00

0x01 0x07 0x00

0x01 0x07 0x00 0x00

Notice that they all result in a crc of 0x0. The redundancy of successive 0x00 is not resulting in a changed CRC - which is, of course, what the 'redundancy check' is supposed to identify.

Change to CRC8_SAE_J1850 for Polynomial: 0x1D; Initial Value: 0xFF; Final Xor Value: 0xFF; prepend 0xff to the strings above - and the result is always 0xff

Why is this so? I think (I'm not bothering to investigate the details) that the author is fixated on using xor's to derive successive values. Forgetting that a CRC is a division process, and the string being divided has an implicit 0x1 prepended, and the divisor also having that x8 bit turned on.

The lookup table that sunshine uses for these CRCs has 0x00 at offset zero. Carefully ensuring that I have xor'ed my way to 0x00, means that any number of 0x00 following results in the same resulting CRC.

  • That particular CRC calculator web page is not to blame for the properties of CRCs. Any CRC with an initial value of zero will continue to have its register contain all zeros with inputs of zeros. For any CRC, even with an initial value that is non-zero, there exists inputs of the CRC's degree or greater in bits that will bring the register to all zeros. From there on, inputs of zeros will leave the register equal to all zeros. That's just the math. – Mark Adler Apr 16 '23 at 02:40