Skip to main content
MFuch.3
Associate II
June 20, 2025
Solved

Unexpected results with iterative use of STM32H5 CRC unit

  • June 20, 2025
  • 3 replies
  • 592 views

Hi,

I am trying to use the STM32H5 CRC unit via HAL to calculate a CRC32 (ISO-HDLC) over multiple chunks.

This works correctly via:

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;
if (HAL_CRC_Init(&hcrc) != HAL_OK)
{
Error_Handler();
}

// calculate CRC32 over two identical chunks, HCRC keeps state!
temp = HAL_CRC_Calculate(&hcrc, (uint32_t *)data, strlen(data));	// 0x444a273c
crc = ~temp;							// 0xbbb5d8c3 OK
temp = HAL_CRC_Accumulate(&hcrc, (uint32_t *)data, strlen(data));	// 0x405e36b1
crc = ~temp;						// 0xbfa1c94e OK

Now I need to do something similiar as in https://community.st.com/t5/stm32-mcus-products/hal-function-crc-accumulate-re-init-and-calculate/td-p/672395: the CRC unit is shared for different things and I need to reinitialize it between the chunks. Where is the missed trick in that solution?

hcrc.Instance->INIT = 0xffffffff;
temp = HAL_CRC_Calculate(&hcrc, (uint32_t *)data, strlen(data));	// 0x444a273c
crc = ~temp;							// 0xbbb5d8c3 OK

// ...

// restart with former DR register content
hcrc.Instance->INIT = temp;
temp = HAL_CRC_Calculate(&hcrc, (uint32_t *)data, strlen(data)); 	// 0x3ce52cc3 unexpected!
crc = ~temp;							// 0xc31ad33c

For the 2nd chunk I do not invert the prior result. What am I missing? I want both code snippets to give the same results.

This is my reference:

import crcmod

# Create CRC function with HDLC parameters
crc32_hdlc = crcmod.mkCrcFun(0x104C11DB7, initCrc=0, rev=True, xorOut=0xFFFFFFFF)

crc = crc32_hdlc(chunk)
print(f"CRC32/HDLC: {crc:08X}")

crc = crc32_hdlc(chunk,crc)
print(f"CRC32/HDLC: {crc:08X}")

#Prints:
#CRC32/HDLC: BBB5D8C3
#CRC32/HDLC: BFA1C94E

Thanks!

Matthias

Best answer by Tesla DeLorean

I did this with a STM32U5, but is illustrative

void CRCTest(void)
{
 uint32_t temp, crc, goodcrc;
 CRC_HandleTypeDef hcrc = {0};
 char data[] = "test";

 __HAL_RCC_CRC_CLK_ENABLE();

 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;

 hcrc.Init.CRCLength = CRC_POLYLENGTH_32B;

 if (HAL_CRC_Init(&hcrc) != HAL_OK)
 {
 Error_Handler();
 }

 // calculate CRC32 over two identical chunks, HCRC keeps state!
 temp = HAL_CRC_Calculate(&hcrc, (uint32_t *)data, strlen(data));
 crc = ~temp;
 printf("%08X-%08X\n", crc, temp);
 printf("%08X DR\n", hcrc.Instance->DR); // Same as temp going into second phase
 temp = HAL_CRC_Accumulate(&hcrc, (uint32_t *)data, strlen(data));
 crc = ~temp;
 printf("%08X-%08X\n", crc, temp);
 putchar('\n');

 goodcrc = crc;

 // Alternate, reinitialize method

 hcrc.Instance->INIT = 0xffffffff;
 temp = HAL_CRC_Calculate(&hcrc, (uint32_t *)data, strlen(data));
 crc = ~temp;
 printf("%08X-%08X\n", crc, temp);

// ...

 // restart with former DR register content
 hcrc.Instance->INIT = __RBIT(temp); // Reverse bit order of value
 printf("%08X %08X INIT,DR\n", hcrc.Instance->INIT, hcrc.Instance->DR); // To understand the bit reversal/mirroring

 temp = HAL_CRC_Calculate(&hcrc, (uint32_t *)data, strlen(data));
 crc = ~temp;
 printf("%08X-%08X\n", crc, temp);

 if (crc == goodcrc)
 puts("== PASS ==");
 else
 puts("** FAIL **");
} // sourcer32@gmail.com

3 replies

Tesla DeLorean
Guru
June 20, 2025

How's "data" defined? Provide complete test patterns

Initialized as 0x00000000 or 0xFFFFFFFF

Might need to bit reverse, not invert, to push in intermediate context.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
Tesla DeLorean
Tesla DeLoreanBest answer
Guru
June 20, 2025

I did this with a STM32U5, but is illustrative

void CRCTest(void)
{
 uint32_t temp, crc, goodcrc;
 CRC_HandleTypeDef hcrc = {0};
 char data[] = "test";

 __HAL_RCC_CRC_CLK_ENABLE();

 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;

 hcrc.Init.CRCLength = CRC_POLYLENGTH_32B;

 if (HAL_CRC_Init(&hcrc) != HAL_OK)
 {
 Error_Handler();
 }

 // calculate CRC32 over two identical chunks, HCRC keeps state!
 temp = HAL_CRC_Calculate(&hcrc, (uint32_t *)data, strlen(data));
 crc = ~temp;
 printf("%08X-%08X\n", crc, temp);
 printf("%08X DR\n", hcrc.Instance->DR); // Same as temp going into second phase
 temp = HAL_CRC_Accumulate(&hcrc, (uint32_t *)data, strlen(data));
 crc = ~temp;
 printf("%08X-%08X\n", crc, temp);
 putchar('\n');

 goodcrc = crc;

 // Alternate, reinitialize method

 hcrc.Instance->INIT = 0xffffffff;
 temp = HAL_CRC_Calculate(&hcrc, (uint32_t *)data, strlen(data));
 crc = ~temp;
 printf("%08X-%08X\n", crc, temp);

// ...

 // restart with former DR register content
 hcrc.Instance->INIT = __RBIT(temp); // Reverse bit order of value
 printf("%08X %08X INIT,DR\n", hcrc.Instance->INIT, hcrc.Instance->DR); // To understand the bit reversal/mirroring

 temp = HAL_CRC_Calculate(&hcrc, (uint32_t *)data, strlen(data));
 crc = ~temp;
 printf("%08X-%08X\n", crc, temp);

 if (crc == goodcrc)
 puts("== PASS ==");
 else
 puts("** FAIL **");
} // sourcer32@gmail.com
Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
MFuch.3
MFuch.3Author
Associate II
June 23, 2025

Cool! That did it. 

THX

waclawek.jan
Super User
June 20, 2025

And if you avoid Cube/HAL? Using the CRC unit at register level is easy, just mind the endianness and written data width. For a few-words experiment, doing it entirely in debugger with no code is sufficient and fun.

JW

waclawek.jan
Super User
June 22, 2025

Ooooh, I see it now, CRC_CR.REV_OUT does nothing else just inserts a bit swapper between the real internal data register and the APB readout interface!

Logical, but the consequence is somewhat surprising.

JW

Tesla DeLorean
Guru
July 2, 2025

Yes, they have the CRC always LEFT shifting internally, and either flip the register on read, or flip the data upon injection.

When I did the 5-bit, 24-bit, etc hacks I'd push the most significant bits of the register and polynomial up there, and then shift back the DR at the end to recover the bits of interest.

Now ST does say that poly's need to be ODD, ie .. + x + 1, but that's not really how the HW works, and they can be shifted to fit provided the feed-back term does it's thing

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..