Skip to main content
BPort.2
Associate II
February 16, 2021
Solved

Which 32 bit CRC does the CRC calculation unit on the stm32f429 calculate?

  • February 16, 2021
  • 6 replies
  • 8081 views

The documentation I have says the Ethernet calculation with 0x4C11DB7... but I don't get results matching what I get from any other calculator. To remove any endianess or mirroring questions I've tried 0x00000000 and 0x66666666 (e.g.). All calculators I have produce 2144_DF1C and E425_C810 for those 2 inputs. From the CRC unit I get 6904_BB59 and 7B91_8196 (which don't seem to be related by combinations -- on the final value -- of bit flipping and reflection).

Yes I asked what the results are -- because I can't imagine what I' don't see in the 1 -> CR; XXXX -> DR; Result <- DR sequence.

TIA,

Brett

Best answer by Tesla DeLorean
//****************************************************************************
//
// CRCSTM32 - Forward and Reverse CRC32 Computation on the ST Micro STM32
// Copyright (C) 2010-2021 C Turvey, All rights reserved
//
// sourcer32@gmail.com
//
//****************************************************************************
 
#include <windows.h>
 
#include <stdio.h>
#include <stdlib.h>
 
typedef unsigned long uint32_t;
 
//****************************************************************************
 
uint32_t Crc32(uint32_t Crc, uint32_t Data)
{
 int i;
 
 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);
}
 
//****************************************************************************
 
uint32_t Crc32Rev(uint32_t CurrentCrc, uint32_t DesiredCrc)
{
 uint32_t Data;
 int i;
 
 for(i=0; i<32; i++)
 if (DesiredCrc & 0x00000001)
#if 1
 DesiredCrc = ((DesiredCrc ^ 0x04C11DB7) >> 1) | 0x80000000; // Long form
#else // or
 DesiredCrc = (DesiredCrc >> 1) ^ 0x82608EDB; // Back feeding polynomial
#endif
 else
 DesiredCrc = (DesiredCrc >> 1);
 
 Data = DesiredCrc ^ CurrentCrc;
 
 return(Data); // Data Pattern to get Desired CRC from Current CRC
}
 
//****************************************************************************
 
int main(int argc, char **argv)
{
 printf("%08X (0x2608EDB8)\n\n",Crc32(0, 0x00000008)); // 0x2608EDB8
 
 printf("%08X (0x490D678D)\n\n",Crc32(0, 0x04C11DB7)); // 0x490D678D
 
 printf("%08X (0x00000000)\n\n",Crc32(0x04C11DB7, 0x04C11DB7));
 
 printf("%08X (0x2F69E5B4)\n\n",Crc32Rev(0xAAAAAAAA, 0x12345678));
 
 printf("%08X (0x12345678)\n\n",Crc32(0xAAAAAAAA, 0x2F69E5B4));
 
 printf("%08X (0x80E886A3)\n\n",Crc32(0, 0x66666666));
 
 printf("%08X (0x84299B14)\n\n",Crc32(1, 0x66666666));
 
 printf("%08X (0x47EC5BD8)\n\n",Crc32(0xFFFFFFFF, 0x66666666));
 
 printf("%08X (0xC704DD7B)\n\n",Crc32(0xFFFFFFFF, 0));
 
 printf("%08X (0x04C11DB7)\n\n",Crc32(0, 1));
 
 return(0);
}
 
//****************************************************************************

 __CRC_CLK_ENABLE();
 CRC->CR = 1;
 printf("%08X\n", CRC->DR);
 CRC->DR = 0x66666666;
 printf("%08X\n", CRC->DR);
FFFFFFFF
47EC5BD8

6 replies

Tesla DeLorean
Guru
February 16, 2021

The standard STM32 implementation is 32-bit at a time, MSB first, left-shifting. Awkward for sure..

0x00000000 into 0xFFFFFFFF should yield 0xC704DD7B

0x66666666 into 0xFFFFFFFF should yield 0x47EC5BD8

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
February 16, 2021
(gdb) set CRC->CR=1
(gdb) p /x *CRC
$7 = {DR = 0xffffffff, IDR = 0x0, RESERVED0 = 0x0, RESERVED1 = 0x0, CR = 0x0,
 RESERVED2 = 0x0, INIT = 0xffffffff, POL = 0x4c11db7}
(gdb) set CRC->DR=0x12345678
(gdb) p /x *CRC
$8 = {DR = 0xdf8a8a2b, IDR = 0x0, RESERVED0 = 0x0, RESERVED1 = 0x0, CR = 0x0,
 RESERVED2 = 0x0, INIT = 0xffffffff, POL = 0x4c11db7}
(gdb)

0693W000008GLGTQA4.pngJW

Tesla DeLorean
Tesla DeLoreanBest answer
Guru
February 16, 2021
//****************************************************************************
//
// CRCSTM32 - Forward and Reverse CRC32 Computation on the ST Micro STM32
// Copyright (C) 2010-2021 C Turvey, All rights reserved
//
// sourcer32@gmail.com
//
//****************************************************************************
 
#include <windows.h>
 
#include <stdio.h>
#include <stdlib.h>
 
typedef unsigned long uint32_t;
 
//****************************************************************************
 
uint32_t Crc32(uint32_t Crc, uint32_t Data)
{
 int i;
 
 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);
}
 
//****************************************************************************
 
uint32_t Crc32Rev(uint32_t CurrentCrc, uint32_t DesiredCrc)
{
 uint32_t Data;
 int i;
 
 for(i=0; i<32; i++)
 if (DesiredCrc & 0x00000001)
#if 1
 DesiredCrc = ((DesiredCrc ^ 0x04C11DB7) >> 1) | 0x80000000; // Long form
#else // or
 DesiredCrc = (DesiredCrc >> 1) ^ 0x82608EDB; // Back feeding polynomial
#endif
 else
 DesiredCrc = (DesiredCrc >> 1);
 
 Data = DesiredCrc ^ CurrentCrc;
 
 return(Data); // Data Pattern to get Desired CRC from Current CRC
}
 
//****************************************************************************
 
int main(int argc, char **argv)
{
 printf("%08X (0x2608EDB8)\n\n",Crc32(0, 0x00000008)); // 0x2608EDB8
 
 printf("%08X (0x490D678D)\n\n",Crc32(0, 0x04C11DB7)); // 0x490D678D
 
 printf("%08X (0x00000000)\n\n",Crc32(0x04C11DB7, 0x04C11DB7));
 
 printf("%08X (0x2F69E5B4)\n\n",Crc32Rev(0xAAAAAAAA, 0x12345678));
 
 printf("%08X (0x12345678)\n\n",Crc32(0xAAAAAAAA, 0x2F69E5B4));
 
 printf("%08X (0x80E886A3)\n\n",Crc32(0, 0x66666666));
 
 printf("%08X (0x84299B14)\n\n",Crc32(1, 0x66666666));
 
 printf("%08X (0x47EC5BD8)\n\n",Crc32(0xFFFFFFFF, 0x66666666));
 
 printf("%08X (0xC704DD7B)\n\n",Crc32(0xFFFFFFFF, 0));
 
 printf("%08X (0x04C11DB7)\n\n",Crc32(0, 1));
 
 return(0);
}
 
//****************************************************************************

 __CRC_CLK_ENABLE();
 CRC->CR = 1;
 printf("%08X\n", CRC->DR);
 CRC->DR = 0x66666666;
 printf("%08X\n", CRC->DR);
FFFFFFFF
47EC5BD8

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
BPort.2
BPort.2Author
Associate II
February 16, 2021
Thanks for the replies.
Apologies for my mis-reporting one of the values I have gotten – too many scraps of hex digit floating around.
Tesla (or do you prefer DeLorean :smiling_face_with_smiling_eyes:), thanks for the details and the code. I was pulled away from this issue all day today, but tonight I’ll try adding this calculation to the tool I’m assembling (which I hope will making the calculation that is needed outside the device simpler).
BTW, is this a (relatively) standard CRC, and is there a way I might have found it outside of asking ‘ST Community’ (documentation I have seems misleading, and searches are annoying and never get to the relevant info?
Tesla DeLorean
Guru
February 17, 2021

It is a standard polynomial, but I feel that is misapplied here, due to the shift direction, byte/endian order and width. Some of the other STM32 parts have a more programmable CRC, but again they've made a bit of a dogs-breakfast of the whole thing, making it slower and more complicated than necessary. I say this as a guy who did IC design, and has built CRC and Reed-Solomon ECC engines at the gate level, and with significantly less resources than ST Micro.

With a more intelligent design and polynomial choice they could have done CRC-32 properly in a byte centric form compatible with PKZIP, etc. We can use the STM32 one for that, but it requires bit-reversal, inversion, and special handling of trailing bytes. I've posted an example of that to prior iterations of the forum, but as you observe the search here is somewhat pitiful.

I did post an app to CRC binaries. I should probably put that on github. Here I tend to package binaries, compress, encrypt and sign, depending on what's needed.

Tips, Buy me a coffee, or three.. PayPal VenmoUp vote any posts that you find helpful, it shows what's working..
waclawek.jan
Super User
March 17, 2021

Without answering your final question - why would it be difficult to skip that one position while performing the checksumming?

JW

BPort.2
BPort.2Author
Associate II
March 17, 2021
That would almost certainly be the next best thing (the skip at runtime would be no problem), the scripts (batch files using srec_cat and related tool) is a bit messier at the moment – and not doing the entire job… but should be fixable.
waclawek.jan
Super User
March 17, 2021

With srecord, I believe you would need to use the -exclude filter, to exclude the CRC's position from calculation. I did not try,though.

JW

BPort.2
BPort.2Author
Associate II
March 25, 2021
These 2 lines of bash muck the hex file just right:
read c1 c2 < <(awk -n '/^[ ]*CHECKSUM / {printf "0x%X 0x%X\n", $2, $2+4}' $Build_Map)
srec_cat $Build_Hex -intel -exclude $c1 $c2 -STM32 $c1 -output wcrc.hex -intel
Would rather get the CHECKSUM from the executable – but the mapfile was just too handy.
srec_cat warns mightily that I could not really want to run the checksum over a file with a hole in it – but it
works just right. It is a well done tool… examples I’ve seen don’t get its flexibility – kind of understandable… a bit more of how-it-works documentation would help folks take better advantage.
I can’t say “well done�? about any of the Keil ARM toolchain – in this case the linker (and the documentation maybe more so) is sadly confused and confusing…. but I found the Load$$LR$$LR_IROM1$$xxxx names to give the load region boundaries to the embedded application code.
MGeri.1
Associate II
April 9, 2025

In order to use the generated code from CubeMX one has to configure the CRC peripheral accordingly:

Basic Parameters:
* Default Polynomial State: Enable
* Default Init Value State: Enable
Advanced Parameters:
* Input Data Inversion Mode: Byte
* Output Data Inversion Mode: Enable
* Input Data Format: Bytes

The you can use the following functions:

uint32_t crc32_ieee(const uint8_t* data, size_t len)
{
uint32_t crc;

crc = HAL_CRC_Calculate(&hcrc, (uint32_t*)data, len);

return ~crc;
}

uint32_t crc32_ieee_update(uint32_t crc, const uint8_t* data, size_t len)
{
crc = ~crc;

__HAL_CRC_INITIALCRCVALUE_CONFIG(&hcrc, __RBIT(crc));

crc = HAL_CRC_Accumulate(&hcrc, (uint32_t*)data, len);

return ~crc;
}