这些小活动你都参加了吗?快来围观一下吧!>>
电子产品世界 » 论坛首页 » 嵌入式开发 » STM32 » NUCLEO-U083RC学习历程32-硬件CRC校验及软件CRC校验知识分享

共2条 1/1 1 跳转至

NUCLEO-U083RC学习历程32-硬件CRC校验及软件CRC校验知识分享

助工
2025-02-18 08:47:42     打赏

一:常见的校验方式知识分享:

在工业控制中,通信之间为了保证数据传输的准确性或者是完整性,都会存在校验。

常见的校验方式有以下几种方式:

1. 奇偶校验(Parity Check)

原理:在数据后添加一个校验位,使数据中1的个数为奇数或偶数。

类型:奇校验:1的个数为奇数。偶校验:1的个数为偶数。

特点:简单,但只能检测奇数个错误。常用于串口之间的通讯。

2. 校验和(Checksum)

原理:将数据分段求和,结果作为校验和附加在数据后。

特点:实现简单,适合低错误率环境,但检测能力有限。

一般用于PC机与下位机之间的通讯方式。

3. 循环冗余校验(CRC, Cyclic Redundancy Check)

原理:通过多项式除法生成校验码,附加在数据后。

特点:检测能力强,适合高可靠性要求的场合。

4. MD5 和 SHA 校验

原理:使用哈希算法生成固定长度的校验值。

特点:主要用于验证数据完整性,抗碰撞性强。

5. Reed-Solomon 码

原理:通过添加冗余数据,检测并纠正多个错误。

特点:广泛应用于通信和存储系统,纠错能力强。

6. 前向纠错(FEC, Forward Error Correction)

原理:发送冗余信息,接收方直接纠正错误。

特点:无需重传,适合实时性要求高的场景。

7. 异或校验(XOR Check)

原理:对数据逐字节异或运算,结果作为校验值。

特点:简单,但检测能力有限。

二:STM32的硬件CRC 知识分享:

今天我们讨论一下,STM32的硬件CRC校验方式:

2.1:我们查看一下官方的手册:

CRC(循环冗余校验)计算单元用于使用可配置的生成器多项式值和大小来获取CRC代码。

在其他应用中,基于CRC的技术用于验证数据传输或存储的完整性。在EN/IEC60335-1标准的范围内,它们提供了一种验证闪存完整性的方法。CRC计算单元有助于在运行时计算软件的签名,以便与在链接时生成并存储在给定存储器位置的引用名进行比较。

STM32 微控制器内置了 CRC(循环冗余校验)模块,用于计算数据的 CRC 校验值。CRC 是一种常用的数据校验方法,用于检测数据传输或存储过程中的错误。STM32 的 CRC 模块支持多种 CRC 标准,并且可以通过硬件加速计算,提高效率

2.2:STM32 CRC 模块的特点

支持多种 CRC 标准:STM32 的 CRC 模块支持多种 CRC 多项式,包括 CRC-32、CRC-16 等。

硬件加速:CRC 计算由硬件完成,速度快,不占用 CPU 资源。

可配置的初始值和输入输出反转:用户可以根据需要配置 CRC 计算的初始值,以及是否对输入和输出数据进行反转。

32 位数据宽度:STM32 的 CRC 模块通常支持 32 位数据宽度的计算。

2.3:STM32 CRC 模块的使用步骤

启用 CRC 时钟:在使用 CRC 模块之前,需要先启用 CRC 模块的时钟。

配置 CRC 模块(可选):根据需要配置 CRC 的初始值、多项式、输入输出反转等参数。

计算 CRC:将数据写入 CRC 数据寄存器,CRC 模块会自动计算 CRC 值。

读取 CRC 结果:计算完成后,从 CRC 数据寄存器中读取 CRC 值。

三:STM32 cubeMX 软件配置如下:

0218-1.png

硬件CRC校验代码如下:

  hcrc.Instance = CRC;   //CRC示例
  hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_DISABLE; //失能默认的多项式
  hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE;   //使用默认的初始值
  hcrc.Init.GeneratingPolynomial = 101;
  hcrc.Init.CRCLength = CRC_POLYLENGTH_7B;    //数据长度为7个字节
  hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE;      //输入数据不反转
  hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE; //输出数据不反转
  hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES; //输入数据格式为32位字
  if (HAL_CRC_Init(&hcrc) != HAL_OK)
  {
    Error_Handler();
  }

CRC (循环冗余校验) 计算单元计算从 8 位数据(字节)缓冲区派生的 7 位 CRC 码。用户定义的生成多项式被手动设置为 0x65,即 X^7 + X^6 + X^5 + X^2 + 1,如列车通信网络 IEC 60870-5[17] 中使用的那样。

宏定义一些变量:

static const uint8_t CRC7_DATA8_TEST5[5]   = {0x12, 0x34, 0xBA, 0x71, 0xAD};
static const uint8_t CRC7_DATA8_TEST17[17] = {0x12, 0x34, 0xBA, 0x71, 0xAD,
                                              0x11, 0x56, 0xDC, 0x88, 0x1B,
                                              0xEE, 0x4D, 0x82, 0x93, 0xA6,
                                              0x7F, 0xC3
                                             };
static const uint8_t CRC7_DATA8_TEST1[1]   = {0x19};
static const uint8_t CRC7_DATA8_TEST2[2]   = {0xAB, 0xCD};

uint32_t * CRC7_DATA8_PTR_TEST1 = (uint32_t *)CRC7_DATA8_TEST1;
uint32_t * CRC7_DATA8_PTR_TEST2 = (uint32_t *)CRC7_DATA8_TEST2;

/* Expected CRC Values */
/* The 7 LSB bits are the 7-bit long CRC */
uint32_t uwExpectedCRCValue_1 = 0x00000057;    /* First byte stream CRC  */
uint32_t uwExpectedCRCValue_2 = 0x0000006E;    /* Second byte stream CRC */
uint32_t uwExpectedCRCValue_3 = 0x0000004B;    /* Third byte stream CRC  */
uint32_t uwExpectedCRCValue_4 = 0x00000027;    /* Fourth byte stream CRC */

测试代码如下所示:

 uwCRCValue = HAL_CRC_Accumulate(&hcrc, (uint32_t *)&CRC7_DATA8_TEST5, BUFFER_SIZE_5);

  /* Compare the CRC value to the expected one */
  if (uwCRCValue != uwExpectedCRCValue_1)
  {
    /* Wrong CRC value: enter Error_Handler */
    Error_Handler();
  }

  uwCRCValue = HAL_CRC_Accumulate(&hcrc, (uint32_t *)&CRC7_DATA8_TEST17, BUFFER_SIZE_17);

  /* Compare the CRC value to the expected one */
  if (uwCRCValue != uwExpectedCRCValue_2)
  {
    /* Wrong CRC value: enter Error_Handler */
    Error_Handler();
  }

  uwCRCValue = HAL_CRC_Accumulate(&hcrc, (uint32_t *)CRC7_DATA8_PTR_TEST1, BUFFER_SIZE_1);

  /* Compare the CRC value to the expected one */
  if (uwCRCValue != uwExpectedCRCValue_3)
  {
    /* Wrong CRC value: enter Error_Handler */
    Error_Handler();
  }

  uwCRCValue = HAL_CRC_Calculate(&hcrc, (uint32_t *)CRC7_DATA8_PTR_TEST2, BUFFER_SIZE_2);

  /* Compare the CRC value to the expected one */
  if (uwCRCValue != uwExpectedCRCValue_4)
  {
    /* Wrong CRC value: enter Error_Handler */
    Error_Handler();
  }
  else
  {
    /* Right CRC value: Turn LED4 on */
    BSP_LED_On(LED4);
  }

代码测试图如下所示:

0218-2.png

程序执行的过程如下所示:

首先,处理一个 5 字节长的缓冲区以产生第一个 CRC。

接下来,从 17 字节长的缓冲区计算第二个 CRC。对于后者,CRC 计算器不会重新初始化,而是使用先前计算的 CRC 作为初始值。

然后,从 1 字节长的缓冲区计算第三个 CRC。同样,CRC 计算器不会重新初始化,而是将先前计算的 CRC 用作初始值。

最后,从 2 字节长的缓冲区计算第四个 CRC。这一次,CRC 计算器使用为 7 位 CRC 0x7F的 IP 默认值重新初始化。这是通过调用 HAL_CRC_Calculate() 而不是 HAL_CRC_Accumulate() 来完成的。

后记:CRC校验在使用过程中的注意事项

数据对齐:STM32 的 CRC 模块通常要求输入数据是 32 位对齐的。如果数据不是 32 位对齐的,可能需要手动处理。

多项式选择:默认情况下,STM32 使用 CRC-32 多项式(0x04C11DB7)。如果需要使用其他多项式,可以通过配置寄存器来实现。

初始值:默认初始值为 0xFFFFFFFF,可以根据需要修改。

第二部分:软件CRC-8校验方式:

/**
  * @brief  计算CRC8校验值
  * @param  *pdat:数据首地址
  * @param  len:计算数据长度
  * @retval 无
  */
unsigned char calcCRC(unsigned char *pdat, unsigned int len)
{
	unsigned char i; 
	unsigned char crc=0x00; /* 计算的初始crc值 */ 

	while(len--)
	{
    			crc ^= *pdat++;  /* 每次先与需要计算的数据异或,计算完指向下一数据 */  
    			for (i=8; i>0; --i)   /* 下面这段计算过程与计算一个字节crc一样 */  
    			{ 
    					if (crc & 0x80)
    							crc = (crc << 1) ^ 0xD5;
    					else
    							crc = (crc << 1);
    			}
	} 
	return (crc); 
}

到这里:STM32硬件CRC校验方式和软件CRC-8校验方式,基本上就是这样,大家可以根据自己项目需求,自行取舍。




关键词: NUCLEO-U083RC     硬件CRC校验     软件C    

专家
2025-02-18 09:03:08     打赏
2楼

谢谢分享


共2条 1/1 1 跳转至

回复

匿名不能发帖!请先 [ 登陆 注册 ]