cancel
Showing results for 
Search instead for 
Did you mean: 

STM32F4 CRC32 algorithm headache

AT38
Associate III

I am developing a serial comms protocol between two STM32F407s.

I am using the hardware CRC module to generate checksums for some of the data.

I am also writing a test script in python to aid development.

All has gone well until now.

Now I need my test script to generate a checksum that agrees with the F4's CRC module.

I have been unsuccessful.

Reading around, it seems that all I should need to do is reverse the bit order going in and reverse and invert the bits read out.

I have done this in my script and in the firmware. No joy.

I have tried 7 variants on CRC32 in my script, using crccheck lib. No joy.

I have tried implementing my own CRC32 function using the flow chart in Application Note AN4187. No joy.

I have systematically inverted and reversed bits, byte wise, word wise, and swapped endianness before, after and both, and compared against inverted, reversed and endianness swapped checksums with each of the above 8 algorithms, even fed the CRC modules byte by byte (2224 combinations). No fricking joy.

The source data was simply 0x01020304

F4's CRC output was: 0xA18723BA

bits reversed and inverted: 0xA02843B5

Does anyone have a proven concrete software implementation of the F4's hardware CRC module, either in c-like or python, that I can use to validate the firmware's output and complete my test script?

Or if not, check that your own F4 produces the same output for the source data?

Cheers

(Here's my attempted implementation:)

def dothething(inbytes, le=True, rr=False, xx=False, init=0xffffffff):
    POLY = 0x4c11db7
    crc = init
    inbytes = bytes(inbytes)
    
    for n in range(0,len(inbytes),4):
        if le:
            x = inbytes[n]<<0 | inbytes[n+1]<<1 | inbytes[n+2]<<2 | inbytes[n+3]<<3
        else:
            x = inbytes[n]<<3 | inbytes[n+1]<<2 | inbytes[n+2]<<1 | inbytes[n+3]<<0
 
        if rr:
            x = rev_bits_in_word(x)
 
        crc = crc^x            
        
        for n in range(32):
            crc = (crc<<1)
            if crc&(1<<31):
                crc = crc^POLY
            crc=crc&0xffffffff #clamp to 32 bits
 
        if rr:
            crc = rev_bits_in_word(crc)
            
        if xx:
            crc = crc^0xffffffff
                
    return crc

1 ACCEPTED SOLUTION

Accepted Solutions

>>Does anyone have a proven concrete software implementation of the F4's hardware CRC module, either in c-like or python, that I can use to validate the firmware's output and complete my test script?

I've posted dozens of working examples over the years

//****************************************************************************
//
// STM32TST - CRC32 Computation on the ST Micro STM32 Test Module
//            Copyright (C) 2014-2018, All rights reserved
//
//                            sourcer32@gmail.com
//
//****************************************************************************
 
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
 
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
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 Crc32Fast(uint32_t Crc, uint32_t Data)
{
  static const uint32_t CrcTable[16] = { // Nibble lookup table for 0x04C11DB7 polynomial
    0x00000000,0x04C11DB7,0x09823B6E,0x0D4326D9,0x130476DC,0x17C56B6B,0x1A864DB2,0x1E475005,
    0x2608EDB8,0x22C9F00F,0x2F8AD6D6,0x2B4BCB61,0x350C9B64,0x31CD86D3,0x3C8EA00A,0x384FBDBD };
 
  Crc = Crc ^ Data; // Apply all 32-bits
 
  // Process 32-bits, 4 at a time, or 8 rounds
 
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28]; // Assumes 32-bit reg, masking index to 4-bits
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28]; //  0x04C11DB7 Polynomial used in STM32
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
 
  return(Crc);
}
 
//****************************************************************************
 
uint32_t Crc32FastBlock(uint32_t Crc, uint32_t Size, uint32_t *Data)
{
  while(Size--)
    Crc = Crc32Fast(Crc, *Data++); // 32-bit at a time
 
  return(Crc);
}
 
//****************************************************************************
 
int main(int argc, char **argv)
{
  uint32_t test[] = { 0x11223344, 0xB14257CC };
 
  printf("%08X (0xB14257CC) Slow\n",Crc32(0xFFFFFFFF, 0x11223344)); // 0xB14257CC
  printf("%08X (0xB14257CC) Fast\n",Crc32Fast(0xFFFFFFFF, 0x11223344)); // 0xB14257CC
  printf("%08X (0x00000000) Block\n", Crc32FastBlock(0xFFFFFFFF, sizeof(test)/sizeof(uint32_t), test) );
 
// B14257CC (0xB14257CC) Slow
// B14257CC (0xB14257CC) Fast
// 00000000 (0x00000000) Block
 
  return(0);
}
 
//****************************************************************************

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

8 REPLIES 8

>>Does anyone have a proven concrete software implementation of the F4's hardware CRC module, either in c-like or python, that I can use to validate the firmware's output and complete my test script?

I've posted dozens of working examples over the years

//****************************************************************************
//
// STM32TST - CRC32 Computation on the ST Micro STM32 Test Module
//            Copyright (C) 2014-2018, All rights reserved
//
//                            sourcer32@gmail.com
//
//****************************************************************************
 
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
 
typedef unsigned char uint8_t;
typedef unsigned short uint16_t;
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 Crc32Fast(uint32_t Crc, uint32_t Data)
{
  static const uint32_t CrcTable[16] = { // Nibble lookup table for 0x04C11DB7 polynomial
    0x00000000,0x04C11DB7,0x09823B6E,0x0D4326D9,0x130476DC,0x17C56B6B,0x1A864DB2,0x1E475005,
    0x2608EDB8,0x22C9F00F,0x2F8AD6D6,0x2B4BCB61,0x350C9B64,0x31CD86D3,0x3C8EA00A,0x384FBDBD };
 
  Crc = Crc ^ Data; // Apply all 32-bits
 
  // Process 32-bits, 4 at a time, or 8 rounds
 
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28]; // Assumes 32-bit reg, masking index to 4-bits
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28]; //  0x04C11DB7 Polynomial used in STM32
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
  Crc = (Crc << 4) ^ CrcTable[Crc >> 28];
 
  return(Crc);
}
 
//****************************************************************************
 
uint32_t Crc32FastBlock(uint32_t Crc, uint32_t Size, uint32_t *Data)
{
  while(Size--)
    Crc = Crc32Fast(Crc, *Data++); // 32-bit at a time
 
  return(Crc);
}
 
//****************************************************************************
 
int main(int argc, char **argv)
{
  uint32_t test[] = { 0x11223344, 0xB14257CC };
 
  printf("%08X (0xB14257CC) Slow\n",Crc32(0xFFFFFFFF, 0x11223344)); // 0xB14257CC
  printf("%08X (0xB14257CC) Fast\n",Crc32Fast(0xFFFFFFFF, 0x11223344)); // 0xB14257CC
  printf("%08X (0x00000000) Block\n", Crc32FastBlock(0xFFFFFFFF, sizeof(test)/sizeof(uint32_t), test) );
 
// B14257CC (0xB14257CC) Slow
// B14257CC (0xB14257CC) Fast
// 00000000 (0x00000000) Block
 
  return(0);
}
 
//****************************************************************************

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

>The source data was simply 0x01020304

 >F4's CRC output was: 0xA18723BA

How *exactly* did you produce that?

Besides Clive's program, the srecord package embeds also a STM32 CRC calculation (arguably it's not the easiest to use though). This is my favourite CRC online calculator http://www.zorc.breitbandkatze.de/crc.html with Clive's data (note the tickboxes' settings):

0690X000006DRrDQAW.png

and your data:

0690X000006DRr8QAG.png

One way how to check if your CRC calculation is not completely failed is to append the result to the checksummed data and perform the CRC again; the result should be 0 - this is what Clive did in hist last example.

JW

 printf("%08X (B5E8B5CD) Slow\n",Crc32(0xFFFFFFFF, 0xF407A5C2)); // 0xB5E8B5CD AM I STM32 TEST

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

Awesome, thankyou. Apparently I lost my mind yesterday 🙂

"One way how to check if your CRC calculation is not completely failed is to append the result to the checksummed data and perform the CRC again; the result should be 0 - this is what Clive did in hist last example."

Thankyou, I'd completely forgotten about this!

I was able to prove my CRC function was in error, and then located the fault in fairly short order. (It was a daft typo mucking up the last word of the input data. Yesterday was a no brain day.)

> daft typo

Sometimes, those are the hardest to find. And there's also nobody to blaim! 🙂

JW

Pavel A.
Evangelist III

​Also, note how the parameter x in your python function is destroyed before use...

-- pa

Thanks. Yes, I completely lost the plot and had two variables with the same name. 🙂

Also, param x should be false to match STM32CRC.

Corrected.

Though now the code I use looks like this:

from crccheck import crc
 
def crc32stm(inbytes):    
    inbytes = rev_bits_in_words(inbytes)    #words bit reversed
    crc32 = crc.Crc32.calc(inbytes)^0xffffffff
    crc32 = rev_bits_in_word(crc32)
    return crc32

Must have been Thursday. Never could get the hang of Thursdays.