背景
某项目用到了IC卡刷卡启动功能,程序中对读取IC卡的相关数据后要进行CRC校验,本文介绍如何在STM32F4 GD32F4 平台上使用标准库函数进行CRC硬件校验。
摘要
本文介绍如何在STM32F4、GD32F4 平台上使用标准库函数进行CRC硬件校验。包括容易出现的问题和解决方法。涉及STM32F4、GD32F4硬件CRC计算错误等问题的解决方法。
运行开发环境介绍
硬件环境 | GD32F407 J-LINK V11 |
软件开发环境 | IAR 8.32.1 VSCODE |
软件支持包 | ST官方标准库 |
上代码:
硬件CRC相关的函数在如下文件中
stm32f2xx_crc.c
工程中通过 引用
#include "stm32f2xx.h"
来实现间接引用
#include "stm32f2xx_crc.h"
因为stm32f2xx.h 中有关于
#include "stm32f2xx_conf.h "
的引用
而 stm32f2xx_conf.h 又引用了 stm32f2xx_crc.h
可以打开 "stm32f2xx_crc.c"文件查看一下 代码不是很多,
主要是一下部分,下面是我个人加的注释。
//复位CRC计算数据寄存器 DR
void CRC_ResetDR(void);
//计算32位CRC校验数据,支持传入参数为u32数据
uint32_t CRC_CalcCRC(uint32_t Data);
//计算32位CRC校验数据,支持传入参数为u32数组
uint32_t CRC_CalcBlockCRC(uint32_t pBuffer[], uint32_t BufferLength);
//返回当前的CRC数值
uint32_t CRC_GetCRC(void);
//设置8位数据到独立的数据寄存器(ID)
void CRC_SetIDRegister(uint8_t IDValue);
//返回独立数据寄存器(ID)中保存的8为数据
uint8_t CRC_GetIDRegister(void);
下面是完整的 stm32f2xx_crc.c 代码
/**
******************************************************************************
* @file stm32f2xx_crc.c
* @author MCD Application Team
* @version V1.1.0
* @date 07-October-2011
* @brief This file provides all the CRC firmware functions.
******************************************************************************
* @attention
*
* THE PRESENT FIRMWARE WHICH IS FOR GUIDANCE ONLY AIMS AT PROVIDING CUSTOMERS
* WITH CODING INFORMATION REGARDING THEIR PRODUCTS IN ORDER FOR THEM TO SAVE
* TIME. AS A RESULT, STMICROELECTRONICS SHALL NOT BE HELD LIABLE FOR ANY
* DIRECT, INDIRECT OR CONSEQUENTIAL DAMAGES WITH RESPECT TO ANY CLAIMS ARISING
* FROM THE CONTENT OF SUCH FIRMWARE AND/OR THE USE MADE BY CUSTOMERS OF THE
* CODING INFORMATION CONTAINED HEREIN IN CONNECTION WITH THEIR PRODUCTS.
*
* <h2><center>© COPYRIGHT 2011 STMicroelectronics</center></h2>
******************************************************************************
*/
/* Includes ------------------------------------------------------------------*/
#include "stm32f2xx_crc.h"
/** @addtogroup STM32F2xx_StdPeriph_Driver
* @{
*/
/** @defgroup CRC
* @brief CRC driver modules
* @{
*/
/* Private typedef -----------------------------------------------------------*/
/* Private define ------------------------------------------------------------*/
/* Private macro -------------------------------------------------------------*/
/* Private variables ---------------------------------------------------------*/
/* Private function prototypes -----------------------------------------------*/
/* Private functions ---------------------------------------------------------*/
/** @defgroup CRC_Private_Functions
* @{
*/
/**
* @brief Resets the CRC Data register (DR).
* @param None
* @retval None
*/
void CRC_ResetDR(void)
{
/* Reset CRC generator */
CRC->CR = CRC_CR_RESET;
}
/**
* @brief Computes the 32-bit CRC of a given data word(32-bit).
* @param Data: data word(32-bit) to compute its CRC
* @retval 32-bit CRC
*/
uint32_t CRC_CalcCRC(uint32_t Data)
{
CRC->DR = Data;
return (CRC->DR);
}
/**
* @brief Computes the 32-bit CRC of a given buffer of data word(32-bit).
* @param pBuffer: pointer to the buffer containing the data to be computed
* @param BufferLength: length of the buffer to be computed
* @retval 32-bit CRC
*/
uint32_t CRC_CalcBlockCRC(uint32_t pBuffer[], uint32_t BufferLength)
{
uint32_t index = 0;
for(index = 0; index < BufferLength; index++)
{
CRC->DR = pBuffer[index];
}
return (CRC->DR);
}
/**
* @brief Returns the current CRC value.
* @param None
* @retval 32-bit CRC
*/
uint32_t CRC_GetCRC(void)
{
return (CRC->DR);
}
/**
* @brief Stores a 8-bit data in the Independent Data(ID) register.
* @param IDValue: 8-bit value to be stored in the ID register
* @retval None
*/
void CRC_SetIDRegister(uint8_t IDValue)
{
CRC->IDR = IDValue;
}
/**
* @brief Returns the 8-bit data stored in the Independent Data(ID) register
* @param None
* @retval 8-bit value of the ID register
*/
uint8_t CRC_GetIDRegister(void)
{
return (CRC->IDR);
}
/**
* @}
*/
/**
* @}
*/
/**
* @}
*/
/******************* (C) COPYRIGHT 2011 STMicroelectronics *****END OF FILE****/
下面是我工程里用到的CRC 计算函数,主要调用了 CRC_ResetDR 和 CRC_CalcBlockCRC
getCalc 中保存的是收到的CRC数值, crcCalc 是硬件CRC计算后的CRC数值。
uint8_t Class_Card::Alg_CardID_Verify(void)
{
uint32_t crcCalc = 0;
uint32_t getCalc = m_u32_idCardCRC;
CRC_ResetDR();
crcCalc = CRC_CalcBlockCRC((uint32_t*)&m_u8_idCardUID[0],(sizeof(m_u8_idCardUID) / 4));
crcCalc = CRC_CalcBlockCRC((uint32_t*)&m_u8_idCardNum[0],(sizeof(m_u8_idCardNum) / 4));
crcCalc = CRC_CalcBlockCRC((uint32_t*)&m_u8_idCardCode[0],(sizeof(m_u8_idCardCode) / 4));
if(crcCalc == getCalc)
{
return 1;
}
else
{
return 0;
}
}
容易踩的坑:
注意 硬件CRC使用一定要打开时钟!!!
否则计算的数据一定是有问题的。
在使用CRC之前调用下面的代码,一般是在工厂BSP级初始化里干这个事儿。
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_CRC, ENABLE); //MD5CLK
老规矩,上图! 养眼~~