STM32的硬件CRC32使用

最近用到STM32的CRC32模块,看一下官网的Lib,感觉用起来十分简单.但是,你会发现直接使用起来会出现,与很多在线CRC32的网站或者PC端的CRC32校验工具计算结果不一致!

简直就是无语......

搜索了一下,在21IC的论坛上面有关使用STM32的CRC32的大讨论,不过是09年的帖子.主要定论是STM32的CRC32与目前大多数的PC端软件使用的一些数据顺序及方法不一致.这里主要推荐看一下这个链接: STM32内置CRC模块的使用 讨论的很火.

如果真如,那帖子说的那样.那么作为MCU这端,是有必要进行转换,要适应潮流.当然这里不是说ST不好.

按照帖子的结论:

1、每个字节的位序相反。stm32f是按32位,高位在先。而主流实例每字节里面是从低位起的。
2、结果出来后,主流实例与0xffffffff异或了。而stm32f没有。

那么我们可以大概贴出以下代码.

 

 
 /*******************************************************************************
* Function Name  : CRC32_ForWords
* Description    :输入的是32bit buffer的指针及长度
* Input          : 
* Output         : 
* Return         : 
* 说明           :
*******************************************************************************/
u32 CRC32_ForWords(u32 *pData,u32 uLen)
{
	u32 i = 0,uData = 0;
	if((RCC->AHB1ENR & RCC_CRC_BIT) == 0)
	{
		RCC->AHB1ENR |= RCC_CRC_BIT;
	}

	/* Reset CRC generator */
	CRC->CR = CRC_CR_RESET;
	for (i = 0;i < uLen;i++)
	{
#ifdef USED_BIG_ENDIAN		
		uData = __REV(*(pData + i));
#else
		uData = *(pData + i);
#endif		
		CRC->DR = revbit(uData);
	}
	return revbit(CRC->DR)^0xFFFFFFFF;
}

说明:__REV()函数功能是将数据按指节大小反向取 ,如原来的数据为0x41424344,经过这个函数之后变成0x44434241

 

其中,数据反向的代码(由于是GCC编译器所以不知道为什么不支持)别人的代码:

 

crc_16_32 revbit(crc_16_32 data)
{
  asm("rbit r0,r0");
  return data;
};


自己修改的代码如下:

 

 

/*******************************************************************************
* Function Name  : revbit
* Description    :对入参uData 按位倒序。如:0111-->1110
* Input          : uData:被转的数据
* Output         : None
* Return         : 转换好的数据
*******************************************************************************/
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;
 }


经过测试,确认能得到与PC端的代码一致的结果.

 

 

那接着又有问题了,那如果我传入的buffer非4字节对其能否使用STM32 CRC32能.

当然,答案是肯定的.但是需要软件配合.这里直接推荐一下,我的代码参考的帖子: 实现非4字节对其的CRC32方法

我的代码如下:

 

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

//#define	USED_BIG_ENDIAN

/*==================================================================
* Function	: CRC32_ForBytes
* Description	: CRC32输入为8bits buffer的指针及长度
* Input Para	: 
* Output Para	: 
* Return Value: 
==================================================================*/
u32 CRC32_ForBytes(u8 *pData,u32 uLen)
{
	u32 uIndex= 0,uData = 0,i;
	uIndex = uLen >> 2;
	
	if((RCC->AHB1ENR & RCC_CRC_BIT) == 0)
	{
		RCC->AHB1ENR |= RCC_CRC_BIT;
	}

	/* Reset CRC generator */
	CRC->CR = CRC_CR_RESET;
	  
	while(uIndex--)
	{
#ifdef USED_BIG_ENDIAN	
		uData = __REV((u32*)pData);
#else
		memcpy((u8*)&uData,pData,4);
#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;
	}
	return uData^0xFFFFFFFF;
}


测试一下,"Hello World"得到的结果为0x4A17B156,确认与PC的软件一致.

 

 

难道CRC32这样就结束了吗?非也,还有问题.

那就是数据大小端的问题.从我的代码中,我认为如果大端的话需要将数据反一下,然后再送入到STM32 CRC32的硬件里面做运算.这样就可以得到跟PC同样的结果.

但是由于我用keil的gcc编译器,目前这个无法支持大端.所以只能当作留给有心人去帮手做剩下我结论的验证。

keil的gcc编译器编译出来的错误信息也贴上,看看有没有高手支持解决一下:

 

我认为目前该编译器不支持大端编译的原因是以下链接:讨论gcc大端问题 也许是支持的,自己鸡肠不够好理解错了,欢迎大家纠正.

 

 

来自:http://blog.csdn.net/lan120576664

 

 

å¨è¿éæå¥å¾çæè¿°

### STM32硬件CRC功能概述 STM32微控制器内置了一个专门用于循环冗余校验(CRC)计算的模块,该模块能够显著提高数据传输和存储过程中的可靠性。与传统的软件实现相比,硬件CRC具有更高的效率和更低的CPU负载[^1]。 #### 硬件CRC的特点 STM32硬件CRC的主要特点如下: - **高速性能**:硬件CRC利用专用电路完成计算,无需消耗MCU的核心处理能力,因此速度极快[^2]。 - **灵活性**:尽管硬件CRC提供了快速的计算能力,但在某些情况下可能需要特定配置才能匹配常见的标准算法。 - **易用性**:通过ST官方提供的HAL库函数`HAL_CRC_Calculate()`可以直接调用并获取CRC值,简化了开发者的工作流程[^3]。 以下是基于STM32 HAL库的一个典型CRC计算实例: ```c #include "stm32f1xx_hal.h" // 初始化CRC句柄结构体 CRC_HandleTypeDef hcrc; void MX_CRC_Init(void) { hcrc.Instance = CRC; hcrc.Init.DefaultPolynomialUse = DEFAULT_POLYNOMIAL_ENABLE; // 默认多项式启用 hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_ENABLE; // 默认初始值启用 hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_NONE; // 输入数据反转模式关闭 hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_DISABLE; // 输出数据反转禁用 hal_status = HAL_CRC_Init(&hcrc); } uint32_t Calculate_CRC(uint32_t *data_buffer, uint32_t length) { return HAL_CRC_Calculate(&hcrc, data_buffer, length); // 调用HAL库函数进行CRC计算 } ``` 上述代码展示了如何初始化CRC外设以及执行具体的CRC计算操作。需要注意的是,在实际应用中应根据具体需求调整输入/输出数据反转模式以及其他参数设置。 --- ### 数据流与结果解析 当使用`HAL_CRC_Calculate()`函数时,传入的数据缓冲区会被逐字节送入CRC单元进行累加运算,最终返回一个32位的结果值。如果希望将此数值转换为便于观察的形式,则可以将其拆分为四个8位部分分别存放到一个字符数组里以便后续处理或发送至其他设备显示。 例如下面这段程序片段演示了怎样把得到的CRC值分解成单独字节形式并通过UART接口上传给计算机终端打印出来: ```c uint32_t Data_buffer[5] = {0x00000001, 0x00000002, 0x00000003, 0x00000004, 0x00000005}; uint32_t CRC_Value = 0; uint8_t CRC_Result[4] = {0}; CRC_Value = HAL_CRC_Calculate(&hcrc, (uint32_t*)Data_buffer, 5); CRC_Result[3] = CRC_Value & 0xFF; CRC_Result[2] = (CRC_Value >> 8) & 0xFF; CRC_Result[1] = (CRC_Value >> 16) & 0xFF; CRC_Result[0] = (CRC_Value >> 24) & 0xFF; HAL_UART_Transmit(&huart2, CRC_Result, 4, 500); ``` 这里我们先调用了`HAL_CRC_Calculate()`来获得整个数据块对应的CRC检验码,接着按照低位到高位顺序依次提取每一位放入准备好的临时变量组内最后经由串口传递出去供调试工具捕获分析。 --- ### 配置注意事项 为了确保正确无误地运用好这个强大的特性,有几个方面值得特别留意: - 正确设定逆变选项以适应不同协议的要求; - 如果遇到不一致的情况,请核查当前使用的生成多项式是否符合预期标准; - 对于初次使用者来说建议优先采用默认配置作为起点逐步探索更多可能性. 综上所述,借助STM32自带的硬件支持配合简单直观的应用层API可以让原本复杂耗时的任务变得轻松快捷许多同时也极大提升了系统的整体表现力.
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值