15
votes

I am trying to generate CRC with STM32L4 hardware modul. I would like to validate fatfs files so basically I have byte arrays. I am using this CRC generator.

Unfortunately I cannot figure out how to set STM32L4 to generate the same result. I need CRC32 and I have

configuration:

hcrc.Instance = CRC;

/* The default polynomial is not used. It is required to defined it in CrcHandle.Init.GeneratingPolynomial*/
hcrc.Init.DefaultPolynomialUse    = DEFAULT_POLYNOMIAL_DISABLE;
/* Set the value of the polynomial */
hcrc.Init.GeneratingPolynomial    = 0x4C11DB7;
//hcrc.Init.GeneratingPolynomial    = 0xFB3EE248;
hcrc.Init.CRCLength= CRC_POLYLENGTH_32B;
/* The default init value is used */
/* The default init value is not used */
hcrc.Init.DefaultInitValueUse     = DEFAULT_INIT_VALUE_ENABLE;

/* User init value is used instead */
//hcrc.Init.InitValue               = 0;
hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;
//hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_BYTE;
/* The input data are inverted by word */
//hcrc.Init.InputDataInversionMode  = CRC_INPUTDATA_INVERSION_WORD;

//hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_ENABLE;
hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE;
hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
HAL_CRC_Init(&hcrc);

testing:

uint8_t test[] = {49,50,51,52};
uint32_t uwCRCValue = HAL_CRC_Calculate(&hcrc,(uint32_t *) test, 4);

result: A695C4AA

I am out of ideas. There is one way that I am succeeded with it to have uint32_t test[] and input is set to hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES; Unfortunately I have uint8_t...

5
Did you remember to enable the CRC peripheral clock? Your code doesn't show it.rost0031
Have you read appropriate reference manual? CRC module have advanced settings for different endianness cases. If you have right result with uint32_t test[], so problem only in endianness settings.imbearr
Thank you for your answer. Yes I have checked them (I used CubeMX code generator). I have read the reference manual. Unfortunately no combination of settings give me any of the CRC32 calculated by standard algorithms.David Molnar
You've gotta mention people if you want them to see your comment. You're the opener, so you receive your posts' comments without being mentioned. To mention people, add @ before their name.Mohammad Kholghi

5 Answers

9
votes

Using CubeMX, I generated with these settings:

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;

Calculate the CRC like so:

uint32_t crc = HAL_CRC_Calculate(&hcrc, (uint32_t *)address, length);

And finally invert:

crc = ~crc;
4
votes

This works for me.

static CRC_HandleTypeDef hcrc = { 
    .Instance = CRC, 
    .Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE,
    .Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE,
    .Init.CRCLength = CRC_POLYLENGTH_32B,
    .Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE,
    .Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE,
    .InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES,
};

And the manual method

static const uint32_t crc_table[0x100] = {
  0x00000000, 0x04C11DB7, 0x09823B6E, 0x0D4326D9, 0x130476DC, 0x17C56B6B, 0x1A864DB2, 0x1E475005, 0x2608EDB8, 0x22C9F00F, 0x2F8AD6D6, 0x2B4BCB61, 0x350C9B64, 0x31CD86D3, 0x3C8EA00A, 0x384FBDBD, 
  0x4C11DB70, 0x48D0C6C7, 0x4593E01E, 0x4152FDA9, 0x5F15ADAC, 0x5BD4B01B, 0x569796C2, 0x52568B75, 0x6A1936C8, 0x6ED82B7F, 0x639B0DA6, 0x675A1011, 0x791D4014, 0x7DDC5DA3, 0x709F7B7A, 0x745E66CD, 
  0x9823B6E0, 0x9CE2AB57, 0x91A18D8E, 0x95609039, 0x8B27C03C, 0x8FE6DD8B, 0x82A5FB52, 0x8664E6E5, 0xBE2B5B58, 0xBAEA46EF, 0xB7A96036, 0xB3687D81, 0xAD2F2D84, 0xA9EE3033, 0xA4AD16EA, 0xA06C0B5D, 
  0xD4326D90, 0xD0F37027, 0xDDB056FE, 0xD9714B49, 0xC7361B4C, 0xC3F706FB, 0xCEB42022, 0xCA753D95, 0xF23A8028, 0xF6FB9D9F, 0xFBB8BB46, 0xFF79A6F1, 0xE13EF6F4, 0xE5FFEB43, 0xE8BCCD9A, 0xEC7DD02D, 
  0x34867077, 0x30476DC0, 0x3D044B19, 0x39C556AE, 0x278206AB, 0x23431B1C, 0x2E003DC5, 0x2AC12072, 0x128E9DCF, 0x164F8078, 0x1B0CA6A1, 0x1FCDBB16, 0x018AEB13, 0x054BF6A4, 0x0808D07D, 0x0CC9CDCA, 
  0x7897AB07, 0x7C56B6B0, 0x71159069, 0x75D48DDE, 0x6B93DDDB, 0x6F52C06C, 0x6211E6B5, 0x66D0FB02, 0x5E9F46BF, 0x5A5E5B08, 0x571D7DD1, 0x53DC6066, 0x4D9B3063, 0x495A2DD4, 0x44190B0D, 0x40D816BA, 
  0xACA5C697, 0xA864DB20, 0xA527FDF9, 0xA1E6E04E, 0xBFA1B04B, 0xBB60ADFC, 0xB6238B25, 0xB2E29692, 0x8AAD2B2F, 0x8E6C3698, 0x832F1041, 0x87EE0DF6, 0x99A95DF3, 0x9D684044, 0x902B669D, 0x94EA7B2A, 
  0xE0B41DE7, 0xE4750050, 0xE9362689, 0xEDF73B3E, 0xF3B06B3B, 0xF771768C, 0xFA325055, 0xFEF34DE2, 0xC6BCF05F, 0xC27DEDE8, 0xCF3ECB31, 0xCBFFD686, 0xD5B88683, 0xD1799B34, 0xDC3ABDED, 0xD8FBA05A, 
  0x690CE0EE, 0x6DCDFD59, 0x608EDB80, 0x644FC637, 0x7A089632, 0x7EC98B85, 0x738AAD5C, 0x774BB0EB, 0x4F040D56, 0x4BC510E1, 0x46863638, 0x42472B8F, 0x5C007B8A, 0x58C1663D, 0x558240E4, 0x51435D53, 
  0x251D3B9E, 0x21DC2629, 0x2C9F00F0, 0x285E1D47, 0x36194D42, 0x32D850F5, 0x3F9B762C, 0x3B5A6B9B, 0x0315D626, 0x07D4CB91, 0x0A97ED48, 0x0E56F0FF, 0x1011A0FA, 0x14D0BD4D, 0x19939B94, 0x1D528623, 
  0xF12F560E, 0xF5EE4BB9, 0xF8AD6D60, 0xFC6C70D7, 0xE22B20D2, 0xE6EA3D65, 0xEBA91BBC, 0xEF68060B, 0xD727BBB6, 0xD3E6A601, 0xDEA580D8, 0xDA649D6F, 0xC423CD6A, 0xC0E2D0DD, 0xCDA1F604, 0xC960EBB3, 
  0xBD3E8D7E, 0xB9FF90C9, 0xB4BCB610, 0xB07DABA7, 0xAE3AFBA2, 0xAAFBE615, 0xA7B8C0CC, 0xA379DD7B, 0x9B3660C6, 0x9FF77D71, 0x92B45BA8, 0x9675461F, 0x8832161A, 0x8CF30BAD, 0x81B02D74, 0x857130C3, 
  0x5D8A9099, 0x594B8D2E, 0x5408ABF7, 0x50C9B640, 0x4E8EE645, 0x4A4FFBF2, 0x470CDD2B, 0x43CDC09C, 0x7B827D21, 0x7F436096, 0x7200464F, 0x76C15BF8, 0x68860BFD, 0x6C47164A, 0x61043093, 0x65C52D24, 
  0x119B4BE9, 0x155A565E, 0x18197087, 0x1CD86D30, 0x029F3D35, 0x065E2082, 0x0B1D065B, 0x0FDC1BEC, 0x3793A651, 0x3352BBE6, 0x3E119D3F, 0x3AD08088, 0x2497D08D, 0x2056CD3A, 0x2D15EBE3, 0x29D4F654, 
  0xC5A92679, 0xC1683BCE, 0xCC2B1D17, 0xC8EA00A0, 0xD6AD50A5, 0xD26C4D12, 0xDF2F6BCB, 0xDBEE767C, 0xE3A1CBC1, 0xE760D676, 0xEA23F0AF, 0xEEE2ED18, 0xF0A5BD1D, 0xF464A0AA, 0xF9278673, 0xFDE69BC4, 
  0x89B8FD09, 0x8D79E0BE, 0x803AC667, 0x84FBDBD0, 0x9ABC8BD5, 0x9E7D9662, 0x933EB0BB, 0x97FFAD0C, 0xAFB010B1, 0xAB710D06, 0xA6322BDF, 0xA2F33668, 0xBCB4666D, 0xB8757BDA, 0xB5365D03, 0xB1F740B4, 
};

uint32_t CalcCRC(uint8_t * pData, uint32_t DataLength)
{
    uint32_t Checksum = 0xFFFFFFFF;
    for(unsigned int i=0; i < DataLength; i++)
    {
        uint8_t top = (uint8_t)(Checksum >> 24);
        top ^= pData[i];
        Checksum = (Checksum << 8) ^ crc_table[top];
    }
    return Checksum;
}
3
votes

Use the following code to calc cc32. CRC32 calc by STM32 CRC unit is not the same as our standard CRC32, it did use big endian, and it will not XOR with 0xFFFFFFFF.

u32 CRC32_ForBytes(u8 *pData, u32 uLen);

#define UNUSED(x) ((void)(x))

/**
 * @brief  CRC functions
 */
#define __HAL_RCC_CRC_CLK_ENABLE()   do { \
                                        __IO uint32_t tmpreg; \
                                        SET_BIT(RCC->AHBENR, RCC_AHBENR_CRCEN);\
                                        /* Delay after an RCC peripheral clock enabling */\
                                        tmpreg = READ_BIT(RCC->AHBENR, RCC_AHBENR_CRCEN);\
                                        UNUSED(tmpreg); \
                                      } while(0)

#define __HAL_RCC_CRC_CLK_DISABLE()       (RCC->AHBENR &= ~(RCC_AHBENR_CRCEN))

#define CRC32_POLYNOMIAL                        ((u32)0xEDB88320)  
#define RCC_CRC_BIT                             ((u32)0x00001000)


/**
 * @brief  Calc CRC32 for data in bytes
 * @param  pData Buffer pointer
 * @param  uLen  Buffer Length
 * @retval CRC32 Checksum
 */
u32 CRC32_ForBytes(u8 *pData,u32 uLen)  
{  
    u32 uIndex= 0,uData = 0,i;  
    uIndex = uLen >> 2;  

    __HAL_RCC_CRC_CLK_ENABLE();

    /* Reset CRC generator */  
    CRC_ResetDR();

    while(uIndex--)  
    {  
#ifdef USED_BIG_ENDIAN    
        uData = __REV((u32*)pData);  
#else
        ((u8 *)&uData)[0] = pData[0];
        ((u8 *)&uData)[1] = pData[1];
        ((u8 *)&uData)[2] = pData[2];
        ((u8 *)&uData)[3] = pData[3];
#endif        
        pData += 4;  
        uData = revbit(uData);  
        CRC->DR = uData;  
    }  
    uData = revbit(CRC->DR);  
    uIndex = uLen & 0x03;  
    while(uIndex--)  
    {  
        uData ^= (u32)*pData++;  
        for(i = 0;i < 8;i++)  
          if (uData & 0x1)  
            uData = (uData >> 1) ^ CRC32_POLYNOMIAL;  
          else  
            uData >>= 1;  
    }

    __HAL_RCC_CRC_CLK_DISABLE();

    return uData^0xFFFFFFFF;  
}

static u32 revbit(u32 uData)
{  
    u32 uRevData = 0,uIndex = 0;  
    uRevData |= ((uData >> uIndex) & 0x01);  
    for(uIndex = 1;uIndex < 32;uIndex++)  
    {  
        uRevData <<= 1;  
        uRevData |= ((uData >> uIndex) & 0x01);  
    }  
    return uRevData;  
}

Calc your CRC32 like this:

u32 uwCRCValue = CRC32_ForBytes(&test, 4);
0
votes

This is a small note if you are wondering what polynomial hcrc.Init.GeneratingPolynomial and hcrc.Init.CRCLength means. In your initial example, your polynomial settings will give:

> polyviz(0x4C11DB7, 32)
x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 + x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1

If you got node.js installed, you can use the below function I written to convert from stm32 crc generator polynomial to crc polynomial formula ...+x^2+x^1+1 form.

function polyviz(Pol, PolyLength)
{
  var msb = 31;

  process.stdout.write(" x^"+(PolyLength));
  while (msb-- > 0)
  {
    if ((Pol & (1 << msb)))
    {
      if (msb == 0)
      process.stdout.write(" + 1");
      else
      process.stdout.write(" + x^"+(msb));
    }
  }
  process.stdout.write("\r\n");
}

// Examples from HAL_CRCEx_Polynomial_Set():
// * for a polynomial of degree 16, X^16 + X^12 + X^5 + 1 is written 0x1021 (Bin: 0001 0000 0010 0001 )
polyviz(0x1021, 16)
// * for a polynomial of degree 7, X^7 + X^6 + X^5 + X^2 + 1 is written 0x65 (Bin: 0110 0101)
polyviz(0x65, 7)

Using this method, you can confirm if you set your polynomial correctly. (Since many crc standards uses polynomial representation)

0
votes

I found this tutorial (for STM32F746) and use it with STM32F407VGT6,

There are a lot of IDE configurations and it will probably be better to access them directly, I'm sorry I don't embed all the content directly here:

Hands-on: CRC Checksum Generation

Note: In this case, the file to be written is ROM.hex (you will need to configure the STM32CubeIDE to be able to do this operation automatically, the IDE uses the *.elf file, see how to do it in the tips below):

Some tips and solutions about this CRC usage (Windows/Linux)