8-bit CRC calcuation in micropython

1.1k Views Asked by At

I'm trying to implement and use an 8-bit CRC in micropython, to be used together with an ADC (ADS1235 Texas Instruments).

I've tried for some time now to rewrite existing programs (mainly implemented in C) and code this function from the bottom up but to no avail.

The functions bellow are the closest I could find to what I'm seeking. The CRC I'm using has the polynomial 0x07.

Functions taken from PM 2Ring comment "1

def crc_16_CCITT(msg):
    poly = 0x8408
    crc = 0xffff
    for byte in msg:
        for _ in range(8):
            if (byte ^ crc) & 1:
                crc = (crc >> 1) ^ poly
            else:
                crc >>= 1
            byte >>= 1
    return crc ^ 0xffff 

I've tried to use PM 2Ring table based implementation but that doesn't work either

def make_crc_table():
    poly = 0x8408
    table = []
    for byte in range(256):
        crc = 0
        for bit in range(8):
            if (byte ^ crc) & 1:
                crc = (crc >> 1) ^ poly
            else:
                crc >>= 1
            byte >>= 1
        table.append(crc)
    return table

table = make_crc_table()

def crc_16_fast(msg):
    crc = 0xffff
    for byte in msg:
        crc = table[(byte ^ crc) & 0xff] ^ (crc >> 8)
    return crc ^ 0xffff

My modifications to the first function can be seen bellow:

def crc_8_CCITT(msg):
    poly = 0x07
    crc = 0x00
    for byte in msg:
        for _ in range(8):
            if (byte ^ crc) & 1:
                crc = (crc >> 1) ^ poly
            else:
                crc >>= 1
            byte >>= 1
    return crc ^ 0x55 
2

There are 2 best solutions below

6
Mark Adler On

For the CRC it appears that you are trying to implement, which is a reflected CRC, you need to reflect the polynomial. You need poly = 0xe0.

The code can be simplified some. The for loop over the message can be:

for byte in msg:
    crc ^= byte
    for _ in range(8):
        if crc & 1:
            crc = (crc >> 1) ^ poly
        else:
            crc >>= 1

As to whether that is the CRC you actually need, I have no idea. Is the CRC you need reflected? Is the initial value zero? Where did the 0x55 come from? Do you have a specification of the CRC that you are not revealing to us? Do you have any example data for which you know the correct CRC value?

Update:

Based on the comment below, the OP needs to implement CRC-8/I-432-1. It is not a reflected CRC, so the shifts are up, not down, has polynomial 0x07, an initial value of zero, and a final exclusive or of 0x55. The implementation for that would be:

def crc8_itu(msg):
    crc = 0
    for byte in msg:
        crc ^= byte
        for _ in range(8):
            crc = (crc << 1) ^ 7 if crc & 0x80 else crc << 1
        crc &= 0xff
    return crc ^ 0x55
0
Jakobs On

Turns out that the CRC had other parameters than I expected.

Reading the C-code section in the TI Application Report I see that the initial CRC-value is 0xFF and the final XOR-value is 0x00.

Using an online calculator with this setup, I'm able to get the same CRC-result as the ADS1235.

Rewriting @Mark Adler's code:

def crc8_8_atm(msg):
    crc = 0xFF
    for byte in msg:
        crc ^= byte
        for _ in range(8):
            crc = (crc << 1) ^ 0x07 if crc & 0x80 else crc << 1
        crc &= 0xff
    return crc ^ 0x00

Gives me the expected result.

Big thanks to @Mark Adler