Home > Enterprise >  Is there a difference in how crc8-atm and crc8-maxim are calculated?
Is there a difference in how crc8-atm and crc8-maxim are calculated?

Time:08-26

I want to implement CRC8 generator. CRC8-ATM works without problems. However, when using the polynomial of CRC8-MAXIM, the calculation result is different. Did I calculate the wrong way?

==============================
CRC8-ATM
dat: "AB" = 01000001 01000010
ply: 0x107 = 100000111
res: 0x87
==============================
01000001 01000010 00000000
 1000001 11
----------------------------
         10000010 00000000
         10000011 1
----------------------------
                1 1000000
                1 00000111
----------------------------
my_res:           10000111 => 0x87 (OK)
==============================
CRC8-MAXIM
dat: "AB" = 01000001 01000010
ply: 0x131 = 100110001
res: 0xA5
==============================
01000001 01000010 00000000
 1001100 01
----------------------------
    1101 00000010 00000000
    1001 10001
----------------------------
     100 10001010 00000000
     100 110001
----------------------------
          1001110 00000000
          1001100 01
----------------------------
               10 01000000
               10 0110001
----------------------------
my_res :          00100010 => 0x22 (Must be 0xA5)

For the calculation results, refer to the site below.

https://crccalc.com

If anyone is familiar with the implementation of CRC8, please help.

CodePudding user response:

Yes, there is.
Regular CRC-8 and CRC-8/MAXIM have different RefIn and RefOut configurations :

  • RefIn parameter indicates if the data byte should be reversed before being used.
  • RefOut parameter indicates if the computed CRC should be reversed before appling the final XorOut operation.

Here is a piece of code computing CRC8 algorithms:

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

uint8_t uint8_reverse(uint8_t val)
{
    uint8_t ret = 0;
    for (size_t i = 0; i < 8; i  )
    {
        if (val & 0x80)
        {
            ret |= (1 << i);
        }
        val <<= 1;
    }
    return ret;
}

uint8_t crc8(uint8_t const * data, size_t data_size, uint8_t poly, uint8_t init,
             bool refin, bool refout, uint8_t xor_out)
{
    uint8_t crc = init;
    for (size_t i = 0; i < data_size; i  )
    {
        crc = crc ^ (refin ? uint8_reverse(data[i]) : data[i]);
        for (size_t j = 0; j < 8; j  )
        {
            if (crc & 0x80)
            {
                crc = (crc << 1) ^ poly;
            }
            else
            {
                crc <<= 1;
            }
        }
    }
    return (refout ? uint8_reverse(crc) : crc) ^ xor_out;
}

int main(void)
{
    printf("--- Check data ---\n");
    const uint8_t check[9] = "123456789";
    printf("crc8:          0xx\n", crc8(check, 9, 0x07, 0x00, 0, 0, 0x00));
    printf("crc8-cdma2000: 0xx\n", crc8(check, 9, 0x9b, 0xff, 0, 0, 0x00));
    printf("crc8-darc:     0xx\n", crc8(check, 9, 0x39, 0x00, 1, 1, 0x00));
    printf("crc8-itu:      0xx\n", crc8(check, 9, 0x07, 0x00, 0, 0, 0x55));
    printf("crc8-maxim:    0xx\n", crc8(check, 9, 0x31, 0x00, 1, 1, 0x00));

    printf("--- 'AB' data ---\n");
    const uint8_t ab_data[2] = "AB";
    printf("crc8:          0xx\n", crc8(ab_data, 2, 0x07, 0x00, 0, 0, 0x00));
    printf("crc8-itu:      0xx\n", crc8(ab_data, 2, 0x07, 0x00, 0, 0, 0x55));
    printf("crc8-maxim:    0xx\n", crc8(ab_data, 2, 0x31, 0x00, 1, 1, 0x00));

    return 0;
}

It outputs:

--- Check data ---
crc8:          0xf4
crc8-cdma2000: 0xda
crc8-darc:     0x15
crc8-itu:      0xa1
crc8-maxim:    0xa1
--- 'AB' data ---
crc8:          0x87
crc8-itu:      0xd2
crc8-maxim:    0xa5

Note that most of the time RefIn and RefOut have the same value, and code optimization is possible (i.e. avoiding all byte reversing operations).

CodePudding user response:

As noted by @lrntgr, the CRC-8/MAXIM defintion has the input bits and the resulting CRC bits reflected. Re-doing your notation with the input and output reflected:

==============================
CRC8-MAXIM
dat: "AB" reflected = 10000010 01000010
ply: 0x131 = 100110001
res: 0xA5
==============================
10000010 01000010 00000000
10011000 1
----------------------------
   11010 11000010 00000000
   10011 0001
----------------------------
    1001 11010010 00000000
    1001 10001
----------------------------
          1011010 00000000
          1001100 01
----------------------------
            10110 01000000
            10011 0001
----------------------------
              101 01010000
              100 110001
----------------------------
                1 10010100
                1 00110001
----------------------------
my_res :          10100101 => reflected 10100101 = 0xA5

For this particular example, 0xA5 reflected is 0xA5! So, unfortunately, you cannot see that the final reflection of the CRC is needed. But, it is. Do another example to see that.

Also as noted, the actual calculation does not need to reflect the input and output bits, but instead can have the exact same effect by instead reflecting the polynomial and shifting down instead of up. The code then is:

unsigned crc8maxim(unsigned char const *dat, size_t len) {
    unsigned crc = 0;
    for (size_t i = 0; i < len; i  ) {
        crc ^= dat[i];
        for (unsigned k = 0; k < 8; k  )
            crc = crc & 1 ? (crc >> 1) ^ 0x8c : crc >> 1;
    }
    return crc;
}

where the 0x8c is the reflection of 0x31, the polynomial bits excluding x8.

  • Related