STM32CubeMX:配置硬件CRC 对比软件CRC计算

 关键词: CRC,STM32硬件CRC

调试环境:Keil

编译器:Keil

驱动生成:STM32CubeMX

开发板:STM32F334C8T6 核心开发板

测试目的:

1:记录硬件CRC的使用方法;

2:对比硬件、软件 CRC16 的计算耗时;

一、STM32硬件CRC功能配置

1.1按如下选项配置:

注意:以下配置是为了硬件计算结果与软件计算模式相同。实际硬件配置方式多样,这里仅取如下方式作为对比。

配置参数放大截图

1.2生成代码,并找到 crc.c ,crc.h 文件,里面有crc的初始化代码

代码如下:

#include "crc.h"

/* USER CODE BEGIN 0 */

/* USER CODE END 0 */

CRC_HandleTypeDef hcrc;

/* CRC init function */
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_DISABLE;
  hcrc.Init.DefaultInitValueUse = DEFAULT_INIT_VALUE_DISABLE;
  hcrc.Init.GeneratingPolynomial = 32773;
  hcrc.Init.CRCLength = CRC_POLYLENGTH_16B;
  hcrc.Init.InitValue = 0xFFFF;
  hcrc.Init.InputDataInversionMode = CRC_INPUTDATA_INVERSION_BYTE;
  hcrc.Init.OutputDataInversionMode = CRC_OUTPUTDATA_INVERSION_ENABLE;
  hcrc.InputDataFormat = CRC_INPUTDATA_FORMAT_BYTES;
  if (HAL_CRC_Init(&hcrc) != HAL_OK)
  {
    Error_Handler();
  }
  /* USER CODE BEGIN CRC_Init 2 */

  /* USER CODE END CRC_Init 2 */

}

void HAL_CRC_MspInit(CRC_HandleTypeDef* crcHandle)
{

  if(crcHandle->Instance==CRC)
  {
  /* USER CODE BEGIN CRC_MspInit 0 */

  /* USER CODE END CRC_MspInit 0 */
    /* CRC clock enable */
    __HAL_RCC_CRC_CLK_ENABLE();
  /* USER CODE BEGIN CRC_MspInit 1 */

  /* USER CODE END CRC_MspInit 1 */
  }
}

void HAL_CRC_MspDeInit(CRC_HandleTypeDef* crcHandle)
{

  if(crcHandle->Instance==CRC)
  {
  /* USER CODE BEGIN CRC_MspDeInit 0 */

  /* USER CODE END CRC_MspDeInit 0 */
    /* Peripheral clock disable */
    __HAL_RCC_CRC_CLK_DISABLE();
  /* USER CODE BEGIN CRC_MspDeInit 1 */

  /* USER CODE END CRC_MspDeInit 1 */
  }
}

1.3 STM32 库函数的 CRC 计算代码

uint32_t HAL_CRC_Accumulate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength) //累计模式,每次计算都以上一次的结果做初始值
uint32_t HAL_CRC_Calculate(CRC_HandleTypeDef *hcrc, uint32_t pBuffer[], uint32_t BufferLength)  //单次计算模式

二、软件CRC16计算代码

2.1 计算方式1

/* CRC16 余式表 */
static uint16_t crctalbeabs[] =
{
    0x0000, 0xCC01, 0xD801, 0x1400, 0xF001, 0x3C00, 0x2800, 0xE401,
    0xA001, 0x6C00, 0x7800, 0xB401, 0x5000, 0x9C01, 0x8801, 0x4400
};

/*!
 *  功  能: CRC16校验
 *  param1: 指向要校验的数据的指针
 *  param2: 要校验的数据的长度
 *  retval: 校验所得到的值,uint16_t 类型
 *
 *  说  明: 本次CRC校验为查表法,多项式为 x16+x15+x2+1(0x8005),CRC的初始值为0xFFFF
 */
uint16_t Crc16_C(uint8_t *ptr, uint32_t len)
{
    uint16_t crc = 0xffff;
    uint32_t i;
    uint8_t ch;

    for (i = 0; i < len; i++)
    {
        ch = *ptr++;
        crc = crctalbeabs[(ch ^ crc) & 15] ^ (crc >> 4);
        crc = crctalbeabs[((ch >> 4) ^ crc) & 15] ^ (crc >> 4);
    }

    return crc;
}

2.1 计算方式2

#define CRC16_Modbus
static uint16_t yl_crc16(unsigned char *buffer, uint16_t len)
{
#if defined  CRC16_XModem

    int i;
    uint16_t cksum;

    cksum = 0;
    for (i = 0; i < len; i++)
    {
        cksum = crc16_tab[((cksum>>8) ^ *buffer++) & 0xFF] ^ (cksum << 8);
    }
    return cksum;
#endif

#if defined  CRC16_Modbus
    uint16_t wcrc = 0XFFFF;         //16位crc寄存器预置
    uint8_t temp;
    uint16_t i = 0, j = 0;          //计数
    for (i = 0; i < len; i++)       //循环计算每个数据
    {
        temp = *buffer & 0X00FF;    //将八位数据与crc寄存器亦或
        buffer++;                   //指针地址增加,指向下个数据
        wcrc ^= temp;               //将数据存入crc寄存器
        for (j = 0; j < 8; j++)     //循环计算数据的
        {
            if (wcrc & 0X0001)      //判断右移出的是不是1,如果是1则与多项式进行异或。
            {
                wcrc >>= 1;         //先将数据右移一位
                wcrc ^= 0XA001;     //与上面的多项式进行异或
            }
            else                    //如果不是1,则直接移出
            {
                wcrc >>= 1;         //直接移出
            }
        }
    }

    return wcrc;

#endif
}

三、计算对比

测试环境 stm32f334c8t6  72M 超频到 96M.

测试用计算数据:AB 00 00 12 9A 2F B4 00 00 00 1D 00

CRC16值:93 8D 

软件CRC16计算 耗时:16uS

硬件CRC16计算 耗时:1.44uS

在线CRC计算工具:http://www.ip33.com/crc.html

四、结论 

在本次的测试环境下,硬件的计算耗时不到软件的1/10.

软件CRC16计算 耗时:16uS

硬件CRC16计算 耗时:1.44uS