第十八章 CRC
目录
4 CRC寄存器CRC 计算单元包括 2 个数据寄存器和 1 个控制寄存器
1 CRC简介
循环冗余校验(CRC)计算单元是根据固定的生成多项式得到任一 172 位全字的 CRC 计算结果。在其他的应用中,CRC 技术主要应用于核实数据传输或者数据存储的正确性和完整性。标准EN/IEC60335-1 即提供了一种核实闪存存储器完整性的方法。CRC 计算单元可以在程序运行时计算出软件的标识,之后与在连接时生成的参考标识比较,然后存放在指定的存储器空间。
2 CRC主要特性
- 使用 CRC-32(以太网)多项式:0x4C11DB7
- X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X4+X2+X+1
- 一个 32 位数据寄存器用于输入/输出
- CRC 计算时间:4 个 AHB 时钟周期(HCLK)
- 通用 8 位寄存器(可用于存放临时数据)
下图为 CRC 计算单元框图:
CRC 计算单元框图
3 CRC功能描述
CRC 计算单元含有 1 个 32 位数据寄存器:
- 对该寄存器进行写操作时,作为输入寄存器,可以输入要进行 CRC 计算的新数据。
- 对该寄存器进行读操作时,返回上一次 CRC 计算的结果。
每一次写入数据寄存器,其计算结果是前一次 CRC 计算结果和新计算结果的组合(对整个 32 位字进行 CRC 计算,而不是逐字节地计算)。
在 CRC 计算期间会暂停 CPU 的写操作,因此可以对寄存器 CRC_DR 进行背靠背写入或者连续地写-读操作。可以通过设置寄存器 CRC_CR 的 RESET 位来重置寄存器 CRC_DR 为0xFFFF FFFF。该操作不影响寄存器 CRC_IDR 内的数据。
4 CRC寄存器CRC 计算单元包括 2 个数据寄存器和 1 个控制寄存器
4.1 数据寄存器(CRC_DR)
地址偏移:0x00
复位值:0xFFFF FFFF
4.2 独立数据寄存器(CRC_IDR)
地址偏移:0x04
复位值:0x0000 0000
4.3 控制寄存器(CRC_CR)
地址偏移:0x08
复位值:0x0000 0000
4.4 CRC 寄存器映像
下表列出了 CRC 的寄存器映像和复位值:
CRC 计算单元寄存器映像和复位值
5 例程设计
5.1 CRC_DifferentCrcMode例程
1.宏定义与结构体:定义了不同 CRC 模式的预期结果,创建了CRC_ResultInfo结构体用于存储 CRC 模式名称和预期结果,同时定义了待计算 CRC 的数据缓冲区Buff。
2.UART 模块:UART_Configuration函数:使能 USART1 和 GPIOA 时钟,配置 GPIO 引脚,初始化 USART 参数(波特率、数据位、停止位等),最后使能 USART1。
- 重定向printf函数:通过SER_PutChar和fputc函数将printf输出重定向到 USART1,方便输出调试信息。
3.CRC 测试模块:CRC_DifferentModeTest函数:遍历不同的 CRC 模式,对Buff缓冲区的数据进行 CRC 计算。每次计算前重置 CRC 数据寄存器,将计算结果与预期结果比较,若一致则输出 “Right”,不一致则输出 “Error” 并显示预期结果。
// CRC多模式测试函数
void CRC_DifferentModeTest(void)
{
uint32_t crcresult = 0; // 存储实际计算结果
uint8_t i;
// 遍历所有CRC测试用例
for (i = 0; i < sizeof(CRCResult) / sizeof(CRC_ResultInfo); i++)
{
CRC_ResetDR(); // 重置CRC数据寄存器(清除之前的计算结果)
// 计算CRC值(参数:CRC模式、数据缓冲区、数据长度(字计数))
crcresult = CRC_CalcBlockCRC(CRC_16_IBM + i, Buff, sizeof(Buff) / 4);
// 比较实际结果与预期结果
if (CRCResult[i].CRCResultData == crcresult)
{
printf("%s Right.\n", CRCResult[i].Str); // 输出测试通过信息
}
else
{
// 输出测试失败信息及预期结果
printf("%s Error.\n", CRCResult[i].Str);
printf("%s Error Result is 0x%x\n", CRCResult[i].Str, CRCResult[i].CRCResultData);
}
}
}
4.主函数模块:使能 CRC 时钟,初始化延时函数和 UART。
int main(void)
{
RCC_ClocksTypeDef clocks; // 系统时钟结构体
// 1. 使能CRC时钟(AHB总线)
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_CRC, ENABLE);
// 2. 基础初始化:延时函数、串口
delay_init();
UART_Configuration(115200);
// 3. 获取并打印系统时钟信息
RCC_GetClocksFreq(&clocks);
printf("\nSYSCLK: %3.1fMhz, HCLK: %3.1fMhz, PCLK1: %3.1fMhz, PCLK2: %3.1fMhz, ADCCLK: %3.1fMhz\n",
(float)clocks.SYSCLK_Frequency / 1000000,
(float)clocks.HCLK_Frequency / 1000000,
(float)clocks.PCLK1_Frequency / 1000000,
(float)clocks.PCLK2_Frequency / 1000000,
(float)clocks.ADCCLK_Frequency / 1000000);
// 4. 打印测试提示
printf("CRC Different Mode Test.\n");
// 5. 执行CRC测试
CRC_DifferentModeTest();
// 6. 主循环(保持程序运行)
while (1);
}
- 获取并输出系统时钟频率信息。
- 输出测试提示信息。
- 调用CRC_DifferentModeTest函数进行 CRC 测试。
- 进入无限循环,保持程序运行。
6 下载验证
6.1 CRC_DifferentCrcMode例程
程序启动阶段
- 串口输出系统时钟信息:程序启动后,会通过串口输出系统时钟的相关频率信息,包括 SYSCLK、HCLK、PCLK1、PCLK2 和 ADCCLK 的频率,帮助确认系统时钟配置是否正确。
- 显示测试提示信息:紧接着输出测试提示信息,表明开始进行不同模式的 CRC 测试。
CRC 测试阶段
- 遍历不同 CRC 模式进行测试:程序会依次对多种 CRC 模式(如 CRC_16_IBM、CRC_16_MAXIM 等)进行测试。
- 输出测试结果:对于每种 CRC 模式,会计算给定数据(Buff数组)的 CRC 值,并将其与预设的预期结果进行比较。
- 计算结果正确:若计算得到的 CRC 值与预期结果一致,串口会输出相应模式的测试结果为 “Right”。
- 计算结果错误:若计算得到的 CRC 值与预期结果不一致,串口会输出相应模式的测试结果为 “Error”,并显示该模式下的预期结果。
程序持续运行
- 进入无限循环:完成所有 CRC 模式的测试后,程序会进入无限循环,保持运行状态。