Long Smith
Long Smith

Reputation: 1401

Make CRC on stm32 match with software implementation

Upd. See the end of post for working code

I'm already mad with this. How can I make checksum from CRC unit on stm32f103 match with software implementation? Stm has polynom 0x04C11DB7 and reset value 0xFFFFFFFF. So I've tried to calculate it in python.

Code for stm:

uint32_t crc32_hard_block(uint32_t *buf, uint32_t len)
{
    CRC_ResetDR();
    uint32_t crc = CRC_CalcBlockCRC(buf, len);
    return crc;
}

uint32_t buf[4] = {50, 10, 243, 147};
uint32_t crc_hard_block = crc32_hard_block(buf, 4);

Code for python:

custom_crc_table = {}

def int_to_bytes(i):
    return [(i >> 24) & 0xFF, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF]

def reverse_int(i, w):
    b = '{:0{width}b}'.format(i, width=w)
    return int(b[::-1], 2)


def generate_crc32_table(_poly):

    global custom_crc_table

    for i in range(256):
        c = i << 24

        for j in range(8):
            c = (c << 1) ^ _poly if (c & 0x80000000) else c << 1

        custom_crc_table[i] = c


def custom_crc32(buf, _poly):

    global custom_crc_table
    crc = 0xFFFFFFFF

    for integer in buf:
        b = int_to_bytes(integer)

        for byte in b:
            top = (crc >> 24) & 0xFF
            crc = (crc << 8) | byte
            crc = crc ^ custom_crc_table[top]

    return crc, reverse_int(crc, 32)

poly = 0x04C11DB7
buf = [50, 10, 243, 147]

generate_crc32_table(poly)
custom_crc, rev = custom_crc32(buf, poly)

print("Custom rev src      " + hex(rev))
print("Custom crc          " + hex(custom_crc))

Testing on array [50, 10, 243, 147] gives me output:

In python:

Custom rev src      0x344a9514f010200020100010100020301000203
Custom crc          0x3010002030100020200020100010203ca2a548b #reversed

It's definetly something wrong with my crc.

In stm:

0x491b3bf3

UPDATE

Here is working code for software crc as on stm32f103 and code for stm32f103.

Python:

def generate_crc32_table(_poly):

    global custom_crc_table

    for i in range(256):
        c = i << 24

        for j in range(8):
            c = (c << 1) ^ _poly if (c & 0x80000000) else c << 1

        custom_crc_table[i] = c & 0xffffffff


def crc32_stm(bytes_arr):

    length = len(bytes_arr)
    crc = 0xffffffff

    k = 0
    while length >= 4:

        v = ((bytes_arr[k] << 24) & 0xFF000000) | ((bytes_arr[k+1] << 16) & 0xFF0000) | \
        ((bytes_arr[k+2] << 8) & 0xFF00) | (bytes_arr[k+3] & 0xFF)

        crc = ((crc << 8) & 0xffffffff) ^ custom_crc_table[0xFF & ((crc >> 24) ^ v)]
        crc = ((crc << 8) & 0xffffffff) ^ custom_crc_table[0xFF & ((crc >> 24) ^ (v >> 8))]
        crc = ((crc << 8) & 0xffffffff) ^ custom_crc_table[0xFF & ((crc >> 24) ^ (v >> 16))]
        crc = ((crc << 8) & 0xffffffff) ^ custom_crc_table[0xFF & ((crc >> 24) ^ (v >> 24))]

        k += 4
        length -= 4

    if length > 0:
        v = 0

        for i in range(length):
            v |= (bytes_arr[k+i] << 24-i*8)

        if length == 1:
            v &= 0xFF000000

        elif length == 2:
            v &= 0xFFFF0000

        elif length == 3:
            v &= 0xFFFFFF00

        crc = (( crc << 8 ) & 0xffffffff) ^ custom_crc_table[0xFF & ( (crc >> 24) ^ (v ) )];
        crc = (( crc << 8 ) & 0xffffffff) ^ custom_crc_table[0xFF & ( (crc >> 24) ^ (v >> 8) )];
        crc = (( crc << 8 ) & 0xffffffff) ^ custom_crc_table[0xFF & ( (crc >> 24) ^ (v >> 16) )];
        crc = (( crc << 8 ) & 0xffffffff) ^ custom_crc_table[0xFF & ( (crc >> 24) ^ (v >> 24) )];

    return crc

poly = 0x04C11DB7
buf = [50, 10, 243, 147]

generate_crc32_table(poly)
crc_stm = crc32_stm(bytearray(buf))

Stm32f103:

#include <stm32f10x_crc.h>    

uint32_t crc32_native(char *bfr, int len, int clear) {

    uint32_t crc;
    int l = len / 4;
    uint32_t *p = (uint32_t*)bfr;
    uint32_t x = p[l];

    if(clear)
    {
        CRC_ResetDR();
    }

    while(l--)
    {
        crc = CRC_CalcCRC(*p++);
    }

    switch(len & 3)
    {
        case 1: crc = CRC_CalcCRC(x & 0x000000FF); break;
        case 2: crc = CRC_CalcCRC(x & 0x0000FFFF); break;
        case 3: crc = CRC_CalcCRC(x & 0x00FFFFFF); break;
    }

    return crc;
}

Upvotes: 5

Views: 7316

Answers (3)

user50619
user50619

Reputation: 353

I have C code in STM32G which gives the same results as the srec utility and the internal STM CRC engine when fed WORDS

// This is C code that gives the same results
// as sending words to the STM32 CRC engine.
// Most online calculators apply CRC's to bit reversed
// streams and will therefore, not give the same results.
// Optimally this would be done via DMA in the background.
//

uint32_t stm32_crc32(uint32_t crc, uint32_t data) {

    int i;
    // Adapted from python from Clive's suggestion from STMicro forum
    crc = crc ^ data;
    for (i = 0; i < 32; i++) {
        if (crc & 0x80000000)
            crc = ((crc << 1) ^ 0x04C11DB7); // Polynomial used in STM32
        else
            crc = (crc << 1);
    }
    return crc;
}

Upvotes: 0

Satake
Satake

Reputation: 883

I have tried many approaches to get a CRC32 python implementation that mimics the HAL STM32f407 implementation and I finally came across that it uses the crc32 mpeg2 algorithm. For anyone like me stuck, here is a python implementation of it.

def crc32mpeg2(buf, crc=0xffffffff):
    for val in buf:
        crc ^= val << 24
        for _ in range(8):
            crc = crc << 1 if (crc & 0x80000000) == 0 else (crc << 1) ^ 0x104c11db7
    return crc

Upvotes: 2

Mark Adler
Mark Adler

Reputation: 112374

custom_crc_table = {}

def int_to_bytes(i):
    return [(i >> 24) & 0xFF, (i >> 16) & 0xFF, (i >> 8) & 0xFF, i & 0xFF]


def generate_crc32_table(_poly):

    global custom_crc_table

    for i in range(256):
        c = i << 24

        for j in range(8):
            c = (c << 1) ^ _poly if (c & 0x80000000) else c << 1

        custom_crc_table[i] = c & 0xffffffff


def custom_crc32(buf):

    global custom_crc_table
    crc = 0xffffffff

    for integer in buf:
        b = int_to_bytes(integer)

        for byte in b:
            crc = ((crc << 8) & 0xffffffff) ^ custom_crc_table[(crc >> 24) ^ byte]

    return crc

poly = 0x04C11DB7
buf = [50, 10, 243, 147]

generate_crc32_table(poly)
custom_crc = custom_crc32(buf)

print("Custom crc          " + hex(custom_crc))

Upvotes: 5

Related Questions