每日更新教程,评论区答疑解惑,小白也能变大神!"
目录
一.循环冗余校验(CRC)
1.1 概述
循环冗余校验 (CRC) 主要应用于核实数据传输或数据存储的正确性和完整性。
CW32x030 内部集成 CRC 计算单元, 支持采用多种 CRC 算法对输入数据进行 CRC 计算。
1.2 主要特性
- 3 种输入数据位宽:8bit、16bit、32bit
- 3 种多项式: ‒ CRC-16
- 多项式 1:x16 + x15 + x2 + 1 ‒ CRC-16
- 多项式 2:x16 + x12 + x5 + 1 ‒ CRC-32
- 多项式:x32 + x26 + x23 + x22 + x16 + x12 + x11 + x10 + x8 + x7 + x5 + x4 + x2 + x +1
- 10 种常用的算法 基于多项式,初始值,结果异或值,输入 / 输出反转的组合。
1.3 功能描述
- CRC 单元通过对输入数据 ( 或输入数据的反转 ) 和选定的多项式值进行‘除’运算,得到的余数再进行反转或者 不反转,以及异或处理,得到 CRC 计算结果。
- CRC 单元在使用之前,需要设置 SYSCTRL_AHBEN.CRC 为 1,打开 CRC 单元的配置时钟及工作时钟,一般在系 统初始化时进行设置。
1.4 算法模式
- CW32x030的 CRC单元支持多种算法模式。不同的 CRC算法,对应的多项式、初始值、输入数据反转、输出数据反转、 结果异或值等参数不同,如下表所示:
- 各参数含义如下:
- 多项式值
- 多项式是码组的描述,如 CRC-16 多项式 2:x16 + x 12 + x 5 + 1,对应的码组是 1 0001 0000 0010 0001。因为 多项式码组的最高位固定为 1,且最高位的位置已知,因此一般将最高位 1 去掉后的码组称为多项式值,如 CRC-16 多项式 2 的值为 0001 0000 0010 0001,即 0x1021。
- 初始值
- 在计算 CRC 校验值之前,CRC 寄存器的初始值。
- 输入数据反转 即在计算开始前,将需要计算 CRC 校验值的数据进行高低序位反转,如数据位 1011,反转后为 1101。
- 输出数据反转 在 CRC 计算结束后,与结果异或值进行异或之前,将计算值进行高低序位反转,如计算结果为 1011,反转 后为 1101。
- 结果异或值 在 CRC 计算结束后,得到的 CRC 计算值与结果异或值进行异或操作,就得到了最终的 CRC 校验值。
1.5输入数据位宽
CRC 计算单元支持三种输入数据位宽:8bit、16bit、32bit。输入数据位宽和算法没有对应关系,但和写入的寄 存器位宽要保持一致。为保证同样一组数据采用不同的输入数据位宽计算得到的 CRC 校验码相同,需要遵循如下 原则:
● 每次输入的数据类型应与寄存器位宽一致
● 先输入低字节再输入高字节
例如,用户需要计算 0x00, 0x11, 0x22 , 0x33, 0x44, 0x55, 0x66, 0x77 这一组数据的 CRC 校验值,对应不同输入数 据位宽示例如下:
1. 8bit 输入数据位宽时,写入顺序:0x00, 0x11, 0x22 , 0x33, 0x44, 0x55, 0x66, 0x77
代码示例:
CW_CRC -> DR8 = 0x00 ;
CW_CRC -> DR8 = 0x11 ;
CW_CRC -> DR8 = 0x22 ;
CW_CRC -> DR8 = 0x33 ;
CW_CRC -> DR8 = 0x44 ;
CW_CRC -> DR8 = 0x55 ;
CW_CRC -> DR8 = 0x66 ;
CW_CRC -> DR8 = 0x77 ;
2. 16bit 输入数据位宽时,写入顺序:0x1100, 0x3322, 0x5544, 0x7766
代码示例:
CW_CRC -> DR16 = 0x1100 ;
CW_CRC -> DR16 = 0x3322 ;
CW_CRC -> DR16 = 0x5544 ;
CW_CRC -> DR16 = 0x7766 ;
3. 32bit 输入数据位宽时,写入顺序: 0x3322 1100, 0x7766 5544
代码示例:
CW_CRC -> DR32 = 0x3322 1100 ;
CW_CRC -> DR32 = 0x7755 6644 ;
1.6编程示例
CRC16_CCITT 算法模式
步骤 1:设置 CRC_CR.MODE 为 0x04,选择 CRC16_CCITT 算法模式,硬件自动配置 CRC 寄存器初始值为 0x0000;
步骤 2:将待编码的原始数据依次写入数据寄存器 CRC_DR ,输入数据位宽可选择 8bit、16bit、32bit 。请参见 10.3.2 输入数据位宽中的代码示例;
步骤 3:读取 CRC_RESULT[15:0] 获取 CRC 校验值。
代码示例:
tempdata = CW_CRC -> RESULT16 ;
1.7CRC32 算法模式
步骤 1:设置 CRC_CR.MODE 为 0x08,选择 CRC32 算法模式,硬件自动配置 CRC 寄存器初始值为 0xFFFF FFFF;
步骤 2:将待编码的原始数据依次写入数据寄存器 CRC_DR,输入数据位宽可选择 8bit、16bit、32bit 。请参见 10.3.2 输入数据位宽中的代码示例;
步骤 3:读取 CRC_RESULT[31:0] 获取 CRC 校验值。
代码示例:
tempdata = CW_CRC -> RESULT32 ;
1.8寄存器列表
二.案例-10种不同CRC算法
uint32_t tmp1, tmp2, tmp3; // 定义三个临时变量用于存储CRC计算结果
//=========================================================================
// 主函数入口
int32_t main(void)
{
// 定义测试数据:8位、16位、32位数组,内容相同但存储格式不同
uint8_t Raw08[8] = { 0x00, 0x11, 0x22, 0x33, 0x44, 0x55, 0x66, 0x77 }; // 字节数组
uint16_t Raw16[4] = { 0x1100, 0x3322, 0x5544, 0x7766 }; // 半字数组(小端模式)
uint32_t Raw32[2] = { 0x33221100, 0x77665544 }; // 字数组(小端模式)
//=========================================================================
// 启用CRC模块时钟(通过系统控制寄存器配置)
CW_SYSCTRL->AHBEN_f.CRC = 1;
//=========================================================================
// CRC16_IBM算法测试:验证不同位宽计算结果的正确性
tmp1 = CRC16_Calc_8bit(CRC16_IBM, Raw08, 8); // 按字节计算CRC16
tmp2 = CRC16_Calc_16bit(CRC16_IBM, Raw16, 4); // 按半字计算CRC16
tmp3 = CRC16_Calc_32bit(CRC16_IBM, Raw32, 2); // 按字计算CRC16
__asm("BKPT 0"); // 断点调试,观察tmp1/tmp2/tmp3是否相等
// CRC16_MAXIM算法测试(同上)
tmp1 = CRC16_Calc_8bit(CRC16_MAXIM, Raw08, 8);
tmp2 = CRC16_Calc_16bit(CRC16_MAXIM, Raw16, 4);
tmp3 = CRC16_Calc_32bit(CRC16_MAXIM, Raw32, 2);
__asm("BKPT 0");
// CRC16_USB算法测试(同上)
tmp1 = CRC16_Calc_8bit(CRC16_USB, Raw08, 8);
tmp2 = CRC16_Calc_16bit(CRC16_USB, Raw16, 4);
tmp3 = CRC16_Calc_32bit(CRC16_USB, Raw32, 2);
__asm("BKPT 0");
// CRC16_MODBUS算法测试(同上)
tmp1 = CRC16_Calc_8bit(CRC16_MODBUS, Raw08, 8);
tmp2 = CRC16_Calc_16bit(CRC16_MODBUS, Raw16, 4);
tmp3 = CRC16_Calc_32bit(CRC16_MODBUS, Raw32, 2);
__asm("BKPT 0");
// CRC16_CCITT算法测试(同上)
tmp1 = CRC16_Calc_8bit(CRC16_CCITT, Raw08, 8);
tmp2 = CRC16_Calc_16bit(CRC16_CCITT, Raw16, 4);
tmp3 = CRC16_Calc_32bit(CRC16_CCITT, Raw32, 2);
__asm("BKPT 0");
// CRC16_CCITTFALSE算法测试(同上)
tmp1 = CRC16_Calc_8bit(CRC16_CCITTFALSE, Raw08, 8);
tmp2 = CRC16_Calc_16bit(CRC16_CCITTFALSE, Raw16, 4);
tmp3 = CRC16_Calc_32bit(CRC16_CCITTFALSE, Raw32, 2);
__asm("BKPT 0");
// CRC16_X25算法测试(同上)
tmp1 = CRC16_Calc_8bit(CRC16_X25, Raw08, 8);
tmp2 = CRC16_Calc_16bit(CRC16_X25, Raw16, 4);
tmp3 = CRC16_Calc_32bit(CRC16_X25, Raw32, 2);
__asm("BKPT 0");
// CRC16_XMODEM算法测试(同上)
tmp1 = CRC16_Calc_8bit(CRC16_XMODEM, Raw08, 8);
tmp2 = CRC16_Calc_16bit(CRC16_XMODEM, Raw16, 4);
tmp3 = CRC16_Calc_32bit(CRC16_XMODEM, Raw32, 2);
__asm("BKPT 0");
//=========================================================================
// CRC32_DEFAULT算法测试:验证不同位宽计算结果的正确性
tmp1 = CRC32_Calc_8bit(CRC32_DEFAULT, Raw08, 8); // 按字节计算CRC32
tmp2 = CRC32_Calc_16bit(CRC32_DEFAULT, Raw16, 4); // 按半字计算CRC32
tmp3 = CRC32_Calc_32bit(CRC32_DEFAULT, Raw32, 2); // 按字计算CRC32
__asm("BKPT 0");
// CRC32_MPEG2算法测试(同上)
tmp1 = CRC32_Calc_8bit(CRC32_MPEG2, Raw08, 8);
tmp2 = CRC32_Calc_16bit(CRC32_MPEG2, Raw16, 4);
tmp3 = CRC32_Calc_32bit(CRC32_MPEG2, Raw32, 2);
__asm("BKPT 0");
// 主循环(保持程序运行)
while (1)
{
;
}
}
关键点
-
数据格式
Raw08
、Raw16
、Raw32
存储相同数据,但分别以8位、16位、32位形式组织,用于测试不同位宽的CRC计算兼容性。
-
CRC算法类型
- 测试了多种标准CRC算法(如IBM、MODBUS、XMODEM等),每种算法通过8/16/32位接口计算,预期结果应一致。
-
调试机制
__asm("BKPT 0")
为嵌入式调试断点,用于观察变量值,验证不同计算方式的结果一致性。
-
硬件依赖
CW_SYSCTRL->AHBEN_f.CRC = 1
启用硬件CRC模块时钟