cancel
Showing results for 
Search instead for 
Did you mean: 

Unexpected results with iterative use of STM32H5 CRC unit

MFuch.3
Associate II

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

1 ACCEPTED SOLUTION

Accepted Solutions

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
View more
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..

View solution in original post

6 REPLIES 6

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 Venmo
Up vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User

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

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
View more
Tips, Buy me a coffee, or three.. PayPal Venmo
Up vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User

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

Cool! That did it. 

THX

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 Venmo
Up vote any posts that you find helpful, it shows what's working..