How is CRC value calculated, how to determine CRC algorithm in embedded applications?
- Subscribe to RSS Feed
- Mark as New
- Mark as Read
- Bookmark
- Subscribe
- Email to a Friend
- Printer Friendly Page
- Report Inappropriate Content
on 2022-07-26 5:48 AM
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”:
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
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.
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
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]
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Email to a Friend
- Report Inappropriate Content
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.)
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Email to a Friend
- Report Inappropriate Content
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();
}
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Email to a Friend
- Report Inappropriate Content
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?
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Email to a Friend
- Report Inappropriate Content
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));
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Email to a Friend
- Report Inappropriate Content
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);
- Mark as Read
- Mark as New
- Bookmark
- Permalink
- Email to a Friend
- Report Inappropriate Content
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);
}