How to configure STM32H7 hardware CRC to match zlib CRC32 in Python

You can configure the STM32 CRC32 peripheral to match the CRC32 algorithm used by zlib (which is available in Python’s zlib module):

According to crccalc.com, the zlib CRC32 (there called CRC-32/ISO-HDLC) uses Init=0xFFFFFFFF, XorOut=0xFFFFFFFF and byte-wise reversal of input & output.

On the STM32H7, you can use the HAL to configure the CRC peripheral to match this:

void Init_CRC32() {
    __HAL_RCC_CRC_CLK_ENABLE();
    // Reset CRC
    _hcrc.Instance = CRC;
    _hcrc.Init.DefaultPolynomialUse    = DEFAULT_POLYNOMIAL_ENABLE;
    _hcrc.Init.DefaultInitValueUse     = DEFAULT_INIT_VALUE_ENABLE;
    _hcrc.Init.InputDataInversionMode  = CRC_INPUTDATA_INVERSION_BYTE;
    _hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_ENABLE;
    _hcrc.InputDataFormat              = CRC_INPUTDATA_FORMAT_BYTES;

    HAL_CRC_Init(&_hcrc);
}

uint32_t CalculateCRC32(void* data, size_t length)
{
    // Compute the CRC
    uint32_t crc_result = HAL_CRC_Calculate(&_hcrc, reinterpret_cast<uint32_t*>(data), length);
    
    // Invert to obtain ZLIB CRC32
    return crc_result ^ 0xFFFFFFFF;
}

The following test code can be used to validate the result

void TestCRC32() {
    uint32_t crc = CalculateCRC32((void*)"DEADBEEF", 8);
    printf("CRC32 of 'DEADBEEF': %08X", crc);

    // When testing, always include a non-divisible-by-4 number of bytes
    crc = CalculateCRC32((void*)"Hello, World!", 13);
    SendLogMessageF("CRC32 of 'Hello, World!': %08X", crc);
}

Output:

CRC32 of 'DEADBEEF': E24CEE98
CRC32 of 'Hello, World!': EC4AC3D0

Equivalent Python code

The python code for this is extremely simple as it uses the built-in zlib module:

import zlib

def calculate_crc32(data: bytes) -> int:
    return zlib.crc32(data)

print(f"CRC32 of 'Hello, World!': {calculate_crc32(b'Hello, World!'):08X}")
print(f"CRC32 of 'DEADBEEF': {calculate_crc32(b'DEADBEEF'):08X}")

Output:

CRC32 of 'DEADBEEF': E24CEE98
CRC32 of 'Hello, World!': EC4AC3D0

You can even do it inline:

import zlib

print(f'{zlib.crc32(b"DEADBEEF"):08X}') # E24CEE98