0

Cyclic redundancy checks (CRCs) can be used to check whether data quality is maintained during transmission. This can be helpful both for serial transfer and for radio transmission.

Typically, the complexity can be taken out of this, simply by using a library to calculate the CRC8 value. For example, the OneWire library can do this very effectively in Python. However, once working across platforms, for example transmitting data from a Raspberry Pi to an Arduino, things can become difficult.

Instead of relying on libraries and packages to calculate CRC values, it may be easier to do this by writing your own function. What would such a function look like for use on an Arduino (C++) and a Raspberry Pi (Python 3.5)?

Triz
  • 173
  • 2
  • 10

2 Answers2

4

Context

Parity checks are used to ensure that the integrity of data is maintained when transmitted. The simplest form of parity check is a 1-bit cyclic redundancy check (CRC-1) otherwise known as a parity bit. This adds all of the ones in the binary code being checked and returns either an odd or an even number. This is then appended to the data which is transmitted, and checked upon receipt. This gives a basic check by which to highlight if there are issues with the data transmission.

More complex checks rely on polynomial functions to carry out repeated division of a string of binary numbers using binary operators. The higher the number of bits, the more stringent the CRC is, however complexity also increases significantly as the number of bits of the CRC increases. Common variations include CRC4, CRC8, CRC16 and CRC32. These can typically be implemented using libraries, as the bitwise processing involved quickly becomes complex.

Arduino CRC8 Function

uint8_t crc8( uint8_t *addr, uint8_t len) {
      uint8_t crc=0;
      for (uint8_t i=0; i<len;i++) {
         uint8_t inbyte = addr[i];
         for (uint8_t j=0;j<8;j++) {
             uint8_t mix = (crc ^ inbyte) & 0x01;
             crc >>= 1;
             if (mix) 
                crc ^= 0x8C;
         inbyte >>= 1;
      }
    }
   return crc;
}

Python CRC8 Function

def crc8(data):
crc = 0
for i in range(len(data)):
    byte = data[i]
    for b in range(8):
        fb_bit = (crc ^ byte) & 0x01
        if fb_bit == 0x01:
            crc = crc ^ 0x18
        crc = (crc >> 1) & 0x7f
        if fb_bit == 0x01:
            crc = crc | 0x80
        byte = byte >> 1
return crc

Note that this code was adapted from the OneWire library for Arduino and the equivalent package for Python.

Any other solutions, relevant contributions on calculating CRC8 values on Arduino and Python would be welcomed!

Triz
  • 173
  • 2
  • 10
0
// 8-bit CRC using the polynomial x^8+x^6+x^3+x^2+1, 0x14D.
// Chosen based on Koopman, et al. (0xA6 in his notation = 0x14D >> 1):
// http://www.ece.cmu.edu/~koopman/roses/dsn04/koopman04_crc_poly_embedded.pdf
//
// This implementation is reflected, processing the least-significant bit of the
// input first, has an initial CRC register value of 0xff, and exclusive-or's
// the final register value with 0xff. As a result the CRC of an empty string,
// and therefore the initial CRC value, is zero.
//
// The standard description of this CRC is:
// width=8 poly=0x4d init=0xff refin=true refout=true xorout=0xff check=0xd8
// name="CRC-8/KOOP"

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

#include <stddef.h>

// Return the CRC-8 of data[0..len-1] applied to the seed crc. This permits the
// calculation of a CRC a chunk at a time, using the previously returned value
// for the next seed. If data is NULL, then return the initial seed. See the
// test code for an example of the proper usage.
unsigned crc8(unsigned crc, unsigned char const *data, size_t len)
{
    if (data == NULL)
        return 0;
    crc &= 0xff;
    unsigned char const *end = data + len;
    while (data < end)
        crc = crc8_table[crc ^ *data++];
    return crc;
}

// crc8_slow() is an equivalent bit-wise implementation of crc8() that does not
// need a table, and which can be used to generate crc8_table[]. Entry k in the
// table is the CRC-8 of the single byte k, with an initial crc value of zero.
// 0xb2 is the bit reflection of 0x4d, the polynomial coefficients below x^8.
unsigned crc8_slow(unsigned crc, unsigned char const *data, size_t len)
{
    if (data == NULL)
        return 0;
    crc = ~crc & 0xff;
    while (len--) {
        crc ^= *data++;
        for (unsigned k = 0; k < 8; k++)
            crc = crc & 1 ? (crc >> 1) ^ 0xb2 : crc >> 1;
    }
    return crc ^ 0xff;
}

#ifdef TEST
#include <stdio.h>
#define CHUNK 16384

int main(void) {
    unsigned char buf[CHUNK];
    unsigned crc = crc8(0, NULL, 0);
    size_t len;
    do {
        len = fread(buf, 1, CHUNK, stdin);
        crc = crc8(crc, buf, len);
    } while (len == CHUNK);
    printf("%#02x\n", crc);
    return 0;
}
#endif
Mark Adler
  • 101,978
  • 13
  • 118
  • 158