cancel
Showing results for 
Search instead for 
Did you mean: 

How is CRC value calculated, how to determine CRC algorithm in embedded applications?

LauraCx
ST Employee

How is CRC value calculated, how to determine CRC algorithm in embedded applications?

1.  Cyclic Redundancy Check

Cyclic Redundancy Check (CRC) is an error detection method for digital data based on binary division.
CRC algorithm generates a fixed checksum code length.
 

2. How is CRC value calculated, how to determine CRC algorithm in embedded applications?

CRC algorithm embedded within the STM32 peripherals computes shift and XOR operations of a subsequent input data in functions of a Generator polynomial (POLY) and a programmable Initial CRC value.
Algorithm Input parameters:
 
  •  Input data also called “Dividend”. This is the data being transmitted or content of Flash for example.
  •  Generator polynomial or “Divisor”:
Algebraic polynomial represented as a bit pattern: the power of each term gives the position on the bit and the coefficient gives the value of the bit.
The order of the generator polynomial must not exceed the CRC length.
For a 32-bits CRC calculation, polynomial highest exponent must be 32.
By default, the standard generator polynomial used by the STM32 CRC peripheral is the Ethernet CRC-32 polynomial 0x04C11DB7. The mathematical representation according to this polynomial is x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x + 1. This presentation is obtained from the binary format of coefficients, where the 32-bit term is always present while the other terms are present only if the coefficient is equal to 1.
 
  •  Initial CRC value
Initial CRC value gives more security to CRC. It is fixed to 0xFFFFFFFF or programmable by user.
At start up, algorithm sets CRC to the initial CRC value XOR with the dividend.
Once CRC MSB is equal to one, algorithm shifts CRC one bit to the left and XORs it with the generator polynomial.
Otherwise, it only shifts CRC one bit to the left.
Figure below describes the algorithm used in STM32 MCUs.
1537.png
You can refer to AN4187 CRC peripheral overview and its firmware to understand the computation process:
 (https://www.st.com/content/st_com/en/products/embedded-software/mcu-mpu-embedded-software/stm32-embedded-software/stm32-standard-peripheral-library-expansion/stsw-stm32an4187.html#overview).

The equivalent embedded software implementation for the computation example of CRC is given in the function CrcSoftwareFunc below
1538.png
We can also use the STM32Cube HAL library to compute CRC-32 using the STM32 CRC hardware using the following APIs
HAL_CRC_Accumulate(): compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer using combination of the previous CRC value and the new one.
HAL_CRC_Calculate() compute the 7, 8, 16 or 32-bit CRC value of an 8, 16 or 32-bit data buffer independently of the previous CRC value.
To determine if your CRC is correct, you can calculate it with 3 different methods and compare the results.
There are different ways to compute CRC:
  • With your own algorithm implementation like CrcSoftwareFunc function (FW embedded in user application code)
  • With STM32Cube HAL library (STM32 CRC peripheral at user application level)
  • With an online calculator to check flash data integrity during the link step[YL1] 

 
Comments
_andreas
Senior

Once you computed the CRC, append it to the message [data|CRC] and transmit everything. To check whether the received data is correct,

calculate the CRC over [data|CRC] and check whether the newly calculated CRC is 0 - in which case the data is intact.

(For the mathematically inclined: this follows from the idea of a CRC: "multiply" a "number" such that it can be "divided" by the polynom without remainder.)

MKing
Associate III

Hi,

here is an example to show how the HAL_CRC_Calculate is working (STM32F407,STM32F107,...) and how to do the same calculation by yourself:

 

 

 

uint32_t Crc32(uint32_t Crc, uint32_t Data)
{
 uint8_t 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);
}


void test_crc(void)
{
uint8_t i;
uint8_t amountofdata;
uint32_t data[4]={
		0x12345678,
		0x23456789,
		0x3456789A,
		0x456789AB,
};
uint32_t crc_polynom;
uint32_t crc_cal1 = 0;
uint32_t crc_cal2 = 0;


//---------------------------------------------------------------- 1x4bytes
amountofdata = 1;
crc_polynom = 0xFFFFFFFF;
crc_cal1 = HAL_CRC_Calculate(&hcrc, &data[0], amountofdata);
crc_cal2 = Crc32(crc_polynom, data[0]);
//crc_cal1 = crc_cal2 = 0xdf8a8a2b
if (crc_cal1 != crc_cal2)
	Error_Handler();


//---------------------------------------------------------------- 2x4bytes
amountofdata = 2;
crc_polynom = 0xFFFFFFFF;
crc_cal1 = HAL_CRC_Calculate(&hcrc, &data[0], amountofdata);

for (i=0;i<amountofdata;i++)
	crc_polynom = Crc32(crc_polynom, data[i]);
crc_cal2 = crc_polynom;
//crc_cal1 = crc_cal2 = 0x78151f4d
if (crc_cal1 != crc_cal2)
	Error_Handler();

//---------------------------------------------------------------- 4x4bytes
amountofdata = 4;
crc_polynom = 0xFFFFFFFF;
crc_cal1 = HAL_CRC_Calculate(&hcrc, &data[0], amountofdata);

for (i=0;i<amountofdata;i++)
	crc_polynom = Crc32(crc_polynom, data[i]);
crc_cal2 = crc_polynom;
//crc_cal1 = crc_cal2 = 0xf62cb9eb
if (crc_cal1 != crc_cal2)
	Error_Handler();

//---------------------------------------------------------------- 2x4bytes
uint8_t rxbuff[8] = {
		0x01,
		0x02,
		0x0c,
		0x0a,
		0x1a,
		0x01,
		0x03,
		0x01,
};

amountofdata = 2;
crc_polynom = 0xFFFFFFFF;
crc_cal1 = HAL_CRC_Calculate(&hcrc, (uint32_t*)&rxbuff[0], amountofdata);

for (i=0;i<amountofdata*4;)
{
	crc_polynom = Crc32(crc_polynom, *(uint32_t*)&rxbuff[i]);
	i += 4;
}
crc_cal2 = crc_polynom;
//crc_cal1 = crc_cal2 = 0x50b5c7df
if (crc_cal1 != crc_cal2)
	Error_Handler();




}

 

 

 

 

FShah.1
Associate III

@MKing 

Hi, I am following a video to write a bootloader that transfers the application code serially into the STM32F446 controller. The video originally presents the STM32F7xx series controller, but I am applying it to the F4xxx series. I have modified the code as needed, such as assigning the proper flash areas for the bootloader and application code. See the GitHub link for this tutorial.

https://github.com/Embetronicx/STM32-Bootloader/tree/ETX_Bootloader_3.0/Bootloader_Example

This link also provides a PC tool that transfers the code from the host to the controller once the handshaking is complete.

What are the recommendations if I want to calculate the CRC32 on a PC that matches the CRC32 calculated on the STM32F446 using HAL_CRC_Calculate()?

My code gives 0x08b329c8 and host calculated CRC is 0x4e08bfb4?

MKing
Associate III

For STM32H745IIKx I use:

void __MX_CRC_Init__(void)
{

  /* USER CODE BEGIN CRC_Init 0 */

  /* USER CODE END CRC_Init 0 */

  /* USER CODE BEGIN CRC_Init 1 */

  /* USER CODE END CRC_Init 1 */
	  hcrc.Instance = CRC;
	  hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE;
	  hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE;
	  //hcrc.Init.GeneratingPolynomial = 79764919;
	  hcrc.Init.CRCLength = CRC_POLYLENGTH_32B;
	  //hcrc.Init.InitValue = 0;
	  hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;
	  hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE;
	  hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_WORDS;
	  if (HAL_CRC_Init(&hcrc) != HAL_OK)
	  {
	    Error_Handler();
	  }

  /* USER CODE BEGIN CRC_Init 2 */

  /* USER CODE END CRC_Init 2 */

}

 Functioncall to calculate a CRC of internal FlashData:

test_CRC = HAL_CRC_Calculate(&hcrc, (uint32_t*)APL_BASE_ADDR, (BufferLength)/sizeof(uint32_t));

 

 

 

FShah.1
Associate III

Hi, I am stuck with a problem that I am getting a same value from hal_crc_calculate, => 0x20020000

I changed inputs  0x05060708, but no change in crc calculation. Do you please help me to solve this issue? It looks to me that DR register is not resetting to 0xFFFFFFFF.

 

static inline uint32_t combine_bytes(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4) {

return ((uint32_t)byte1 << 24) | ((uint32_t)byte2 << 16) | ((uint32_t)byte3 << 8) | (uint32_t)byte4;

}

uint8_t data8bit[4] = {5,6,7,8};

uint32_t crcInput[0] = combine_bytes(data8bit[0], data8bit[1], data8bit[2], data8bit[3]);

printf("CRC Input 0x%08lx \n",crcInput[0]);//output = 0x05060708

//Calculate and verify the CRC

__HAL_CRC_DR_RESET(&hcrc);

cal_crc = HAL_CRC_Calculate( &hcrc,(uint32_t*)crcInput, 1);//ota_fw_total_size/4

printf("MCU CRC 0x%08lx \n",cal_crc);

Not sure I like zero dimension arrays

 

static inline uint32_t combine_bytes(uint8_t byte1, uint8_t byte2, uint8_t byte3, uint8_t byte4)
{
  return ((uint32_t)byte1 << 24) | ((uint32_t)byte2 << 16) | ((uint32_t)byte3 << 8) | (uint32_t)byte4;
}

{
  uint32_t cal_crc;
  uint8_t data8bit[4] = {5,6,7,8};
  uint32_t crcInput = combine_bytes(data8bit[0], data8bit[1], data8bit[2], data8bit[3]);

  printf("CRC Input 0x%08lx \n",crcInput);//output = 0x05060708

//Calculate and verify the CRC

  __HAL_CRC_DR_RESET(&hcrc);

  cal_crc = HAL_CRC_Calculate( &hcrc,(uint32_t*)&crcInput, 1);//ota_fw_total_size/4

  printf("MCU CRC 0x%08lx \n",cal_crc);
}

 

https://github.com/cturvey/RandomNinjaChef/blob/main/stm32crc.c

#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <math.h>

typedef unsigned char uint8_t;
typedef unsigned int uint32_t;

uint32_t crc32(uint32_t crc, size_t size, uint32_t *buffer)
{
  int i;

  while(size--)
  {
    crc = crc ^ *buffer++;
    for(i=0; i<32; i++)
      if (crc & 0x80000000)
        crc = (crc << 1) ^ 0x04C11DB7;
      else
        crc <<= 1;
  }

  return(crc);
}

int main(int argc, char **argv)
{
  uint8_t data1[] = { 0x05,0x06,0x07,0x08 };
  uint8_t data2[] = { 0x08,0x07,0x06,0x05 };

  printf("%08X\n", crc32(0xFFFFFFFF, sizeof(data1)/sizeof(uint32_t), (uint32_t *)data1)); // 0xC9F6D629
  printf("%08X\n", crc32(0xFFFFFFFF, sizeof(data2)/sizeof(uint32_t), (uint32_t *)data2)); // 0x72887319

  return(1);
}
Version history
Last update:
‎2022-07-26 05:48 AM
Updated by: