CRC计算流程详解和FPGA实现

news2024/11/18 6:26:48

一、概念

        CRC校验,中文翻译过来是:循环冗余校验,英文全称是:Cyclic Redundancy Check。是一种通过对数据产生固定位数的校验码,以检验数据是否存在错误的技术。

        其主要特点是检错能力强、开销小,易于电路实现。像网络通信上,就使用了CRC32进行数据校验。

1.1 CRC的数学基础

        其数学基础是,使用除法求余数。

        1、将K位的信息码写成如下多项式形式:\sum_{n=0}^{K-1}a_{n}x^{n}

        2、将信息码左移R位,变成如下多项式形式:\sum_{n=0}^{K-1}a_{n}x^{n+R}

        3、将移位后的信息码,除以指定的生成多项式,最后得到的余数即为CRC校验值。

        转换成二进制信息表述如下:

        1、K位的信息码,右移R位,得到新的K+R位的信息码,

        2、将新的K+R位的信息码,除以指定的二进制数,得到的余数即为CRC校验值。

        当然,此处采用的是模2运算,即没有借位。实质上在运行加减法的时候,采用的是异或运算。

1.2 其他重要概念

        CRC 校验的核心是模2除法运算,但是还存在一些其他的规则,描述如下:

        初始值:给CRC一个计算初始值,可以是0,也可以为其他值,会将待计算的信息码的值与初始值进行异或。(网上大部分关于CRC的校验计算,初始值都是默认取0,但是实际应用中,比如CRC32,其初始值是0xFFFFFFFF)

        结果异或值:将计算结果与结果异或值进行异或运算后输出,目的是防止全0数据的CRC一直为0,

        数据反转:CRC中数据 反转,指的是一个字节的数据中,高bit变低bit,低bit变高bit。 比如0x55,经过数据反转后,变为0xAA。

        生成多项式:模2除法中的除数,根据多项式可以生成二进制除数,不同的CRC校验有不同的多项式。

1.3 CRC校验的标准流程

        1、初始值赋值给crc_reg;

        2、判断信息码是否需要反转,若需要则进行数据反转,不需要则保持不变,结果赋值给crc_reg;

        3、信息码(或者反转后的信息码)左移R位,即信息码后面补上R个二进制的0;(R为校验码的位宽,同时也是生成多项式的最高次幂)

        4、crc_reg与补0后的信息码(高位)进行异或运算,并赋值给crc_reg;

        5、crc_reg与信息码进行模2除法运算,运算的余数结果赋值给crc_reg;

        6、判断输出结果是否需要反转,若需要则进行数据反转,不需要则保持不变,结果赋值给crc_reg;

        7、crc_reg与结果异或值进行异或运算,得到最终的校验值。

二、CRC32

2.1 CRC32相关信息

        最近在考虑使用FPGA实现UDP协议,就研究到了CRC32校验,像赛灵思提供的MAC核内部就实现了CRC32校验方式。于是我就抱着学习的态度,研究了一下CRC32。关于CRC8、CRC16等等其余的CRC校验方式,此处就不赘述了。

        CRC32校验里面提到了几个概念:

1、生成多项式(generator polynomial)

        CRC32=X32+X26+X23+X22+X16+X12+X11+X10+X8+X7+X5+X4+X2+X1+1。

        二进制可以表示为33'b1_0000_0100_1100_0001_0001_1101_1011_0111。

        十六进制表示为32‘h104C11DB7。

        生成多项式,即为除数。

2、待校验的数据

        待校验的数据即为被除数,即上面描述的信息码。

        最终获得的结果,即为CRC校验值。

2.2 CRC32校验流程

具体的操作流程:

  1、初始值赋值给crc_reg;

 2、判断信息码是否需要反转,若需要则进行数据反转,不需要则保持不变,结果赋值给crc_reg;

3、信息码(或者反转后的信息码)左移32位,即信息码后面补上32个二进制的0;

4、crc_reg与补0后的信息码(高32位)进行异或运算,并赋值给crc_reg;

 5、crc_reg与信息码进行模2除法运算,运算的余数结果赋值给crc_reg;

 6、判断输出结果是否需要反转,若需要则进行数据反转,不需要则保持不变,结果赋值给crc_reg;

7、crc_reg与结果异或值进行异或运算,得到最终的校验值。

        按照C语言编写了此CRC32校验流程,在VScode中进行测试。设置不同的反转信息、初始值、结果异或值,输出结果与CRC计算工具相一致。

CRC计算器工具:

CRC(循环冗余校验)在线计算_ip33.comicon-default.png?t=N7T8http://www.ip33.com/crc.html

//8位数据反转
uint8_t invertuint8(uint8_t data) 
{
    uint8_t tmp;
    tmp = 0;

    for(int i = 0; i<8;i++){
        if(data & (1<<i) ){
            tmp |= 1<< (7-i);
        }
    }

    return tmp;
}

//32位数据反转
uint32_t invertuint32(uint32_t data)
{
    uint32_t tmp;
    tmp = 0;

    for(int i = 0; i<32;i++){
        if(data &(1<<i) ){
            tmp |= 1<< (31-i);
        }
    }

    return tmp;
}


uint32_t CRC32(uint8_t& data)
{
    uint8_t in_reverse_en = 1; //输入数据是否反转
    uint8_t out_reverse_en = 1;//输出数据是否反转



    uint32_t poly = 0x04C11DB7; //生成多项式0x1_04C11DB7 ,仅取低32位,最高为1通过左移直接处理
    uint32_t init_value = 0xFFFFFFFF;//初始值
    uint32_t out_xor_value = 0xFFFFFFFF;//结果异或值

    uint32_t crc_reg;
    uint32_t data_reg;
    uint32_t data_shift;

//第一步,赋初值
    crc_reg = init_value;
//第二步,输入是否反转
    if(in_reverse_en == 1)
        data_reg = invertuint8(data);
    else    
        data_reg = data;
    printf("data:%x\n",data);
    printf("data_reg:%x\n",data_reg);

//第三步,信息码左移32位,赋值。由于字宽限制,仅左移24位,实际上8次移位异或运算后,其余数与原有运算相一致。
    data_shift = (data_reg <<24);
//第四步,初始值与数据异或操作
    crc_reg = crc_reg ^ data_shift;
//第五步,模2除法
    for(int i=0;i<8;i++){
        if(crc_reg & 0x80000000)//最高位是1时
            crc_reg = (crc_reg << 1) ^ poly; //左移将生成多项式的第32bits处理掉,相当于异或
        else
            crc_reg = crc_reg << 1;
    }
//
//第六步,输出是否反转

    if(out_reverse_en == 1)
        crc_reg = invertuint32(crc_reg);
//第七步,与结果异或值进行异或运算

    crc_reg = crc_reg^out_xor_value;


    return crc_reg;
}


int main(int argc, char *argv[])
{

    uint8_t data = 0x55;
    uint32_t CRC_result;


    CRC_result = CRC32(data);

    printf("CRC_result:%x\n",CRC_result);

    getchar();

    return 0;
}

       

三、CRC32的FPGA实现

         原理已经清楚了,按照上述流程就可以实现CRC32。但是FPGA有更简易的实现形式。就属于找规律的范畴了。对于CRC32,上一个校验值(或者初始值)进行CRC校验的时候,CRC校验的单个bits的校验结果固定与上一个校验值的某几个bits有关。

        所以可以直接采用bit运算的方式输出CRC校验结果。具体找规律这里不再分析,直接上示例代码(正点原子的代码)。也有现成的CRC FPGA代码生成工具,可以直接调用。

CRC代码生成工具一:Easics CRC Toolicon-default.png?t=N7T8http://crctool.easics.be/

CRC代码生成工具二:OutputLogic.com » CRC Generatoricon-default.png?t=N7T8http://outputlogic.com/?page_id=321

module crc32_d8(
    input                 clk     ,  //时钟信号
    input                 rst_n   ,  //复位信号,低电平有效
    input         [7:0]   data    ,  //输入待校验8位数据
    input                 crc_en  ,  //crc使能,开始校验标志
    input                 crc_clr ,  //crc数据复位信号            
    output   reg  [31:0]  crc_data,  //CRC校验数据
    output        [31:0]  crc_next   //CRC下次校验完成数据
    );

//*****************************************************
//**                    main code
//*****************************************************

//输入待校验8位数据,需要先将高低位互换
wire    [7:0]  data_t;

assign data_t = {data[0],data[1],data[2],data[3],data[4],data[5],data[6],data[7]};

//CRC32的生成多项式为:G(x)= x^32 + x^26 + x^23 + x^22 + x^16 + x^12 + x^11 
//+ x^10 + x^8 + x^7 + x^5 + x^4 + x^2 + x^1 + 1

assign crc_next[0] = crc_data[24] ^ crc_data[30] ^ data_t[0] ^ data_t[6];
assign crc_next[1] = crc_data[24] ^ crc_data[25] ^ crc_data[30] ^ crc_data[31] 
                     ^ data_t[0] ^ data_t[1] ^ data_t[6] ^ data_t[7];
assign crc_next[2] = crc_data[24] ^ crc_data[25] ^ crc_data[26] ^ crc_data[30] 
                     ^ crc_data[31] ^ data_t[0] ^ data_t[1] ^ data_t[2] ^ data_t[6] 
                     ^ data_t[7];
assign crc_next[3] = crc_data[25] ^ crc_data[26] ^ crc_data[27] ^ crc_data[31] 
                     ^ data_t[1] ^ data_t[2] ^ data_t[3] ^ data_t[7];
assign crc_next[4] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28] 
                     ^ crc_data[30] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[4] 
                     ^ data_t[6];
assign crc_next[5] = crc_data[24] ^ crc_data[25] ^ crc_data[27] ^ crc_data[28] 
                     ^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[0] 
                     ^ data_t[1] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[6] 
                     ^ data_t[7];
assign crc_next[6] = crc_data[25] ^ crc_data[26] ^ crc_data[28] ^ crc_data[29] 
                     ^ crc_data[30] ^ crc_data[31] ^ data_t[1] ^ data_t[2] ^ data_t[4] 
                     ^ data_t[5] ^ data_t[6] ^ data_t[7];
assign crc_next[7] = crc_data[24] ^ crc_data[26] ^ crc_data[27] ^ crc_data[29] 
                     ^ crc_data[31] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5] 
                     ^ data_t[7];
assign crc_next[8] = crc_data[0] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27] 
                     ^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];
assign crc_next[9] = crc_data[1] ^ crc_data[25] ^ crc_data[26] ^ crc_data[28] 
                     ^ crc_data[29] ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5];
assign crc_next[10] = crc_data[2] ^ crc_data[24] ^ crc_data[26] ^ crc_data[27] 
                     ^ crc_data[29] ^ data_t[0] ^ data_t[2] ^ data_t[3] ^ data_t[5];
assign crc_next[11] = crc_data[3] ^ crc_data[24] ^ crc_data[25] ^ crc_data[27] 
                     ^ crc_data[28] ^ data_t[0] ^ data_t[1] ^ data_t[3] ^ data_t[4];
assign crc_next[12] = crc_data[4] ^ crc_data[24] ^ crc_data[25] ^ crc_data[26] 
                     ^ crc_data[28] ^ crc_data[29] ^ crc_data[30] ^ data_t[0] 
                     ^ data_t[1] ^ data_t[2] ^ data_t[4] ^ data_t[5] ^ data_t[6];
assign crc_next[13] = crc_data[5] ^ crc_data[25] ^ crc_data[26] ^ crc_data[27] 
                     ^ crc_data[29] ^ crc_data[30] ^ crc_data[31] ^ data_t[1] 
                     ^ data_t[2] ^ data_t[3] ^ data_t[5] ^ data_t[6] ^ data_t[7];
assign crc_next[14] = crc_data[6] ^ crc_data[26] ^ crc_data[27] ^ crc_data[28] 
                     ^ crc_data[30] ^ crc_data[31] ^ data_t[2] ^ data_t[3] ^ data_t[4]
                     ^ data_t[6] ^ data_t[7];
assign crc_next[15] =  crc_data[7] ^ crc_data[27] ^ crc_data[28] ^ crc_data[29]
                     ^ crc_data[31] ^ data_t[3] ^ data_t[4] ^ data_t[5] ^ data_t[7];
assign crc_next[16] = crc_data[8] ^ crc_data[24] ^ crc_data[28] ^ crc_data[29] 
                     ^ data_t[0] ^ data_t[4] ^ data_t[5];
assign crc_next[17] = crc_data[9] ^ crc_data[25] ^ crc_data[29] ^ crc_data[30] 
                     ^ data_t[1] ^ data_t[5] ^ data_t[6];
assign crc_next[18] = crc_data[10] ^ crc_data[26] ^ crc_data[30] ^ crc_data[31] 
                     ^ data_t[2] ^ data_t[6] ^ data_t[7];
assign crc_next[19] = crc_data[11] ^ crc_data[27] ^ crc_data[31] ^ data_t[3] ^ data_t[7];
assign crc_next[20] = crc_data[12] ^ crc_data[28] ^ data_t[4];
assign crc_next[21] = crc_data[13] ^ crc_data[29] ^ data_t[5];
assign crc_next[22] = crc_data[14] ^ crc_data[24] ^ data_t[0];
assign crc_next[23] = crc_data[15] ^ crc_data[24] ^ crc_data[25] ^ crc_data[30] 
                      ^ data_t[0] ^ data_t[1] ^ data_t[6];
assign crc_next[24] = crc_data[16] ^ crc_data[25] ^ crc_data[26] ^ crc_data[31] 
                      ^ data_t[1] ^ data_t[2] ^ data_t[7];
assign crc_next[25] = crc_data[17] ^ crc_data[26] ^ crc_data[27] ^ data_t[2] ^ data_t[3];
assign crc_next[26] = crc_data[18] ^ crc_data[24] ^ crc_data[27] ^ crc_data[28] 
                      ^ crc_data[30] ^ data_t[0] ^ data_t[3] ^ data_t[4] ^ data_t[6];
assign crc_next[27] = crc_data[19] ^ crc_data[25] ^ crc_data[28] ^ crc_data[29] 
                      ^ crc_data[31] ^ data_t[1] ^ data_t[4] ^ data_t[5] ^ data_t[7];
assign crc_next[28] = crc_data[20] ^ crc_data[26] ^ crc_data[29] ^ crc_data[30] 
                      ^ data_t[2] ^ data_t[5] ^ data_t[6];
assign crc_next[29] = crc_data[21] ^ crc_data[27] ^ crc_data[30] ^ crc_data[31] 
                      ^ data_t[3] ^ data_t[6] ^ data_t[7];
assign crc_next[30] = crc_data[22] ^ crc_data[28] ^ crc_data[31] ^ data_t[4] ^ data_t[7];
assign crc_next[31] = crc_data[23] ^ crc_data[29] ^ data_t[5];

always @(posedge clk or negedge rst_n) begin
    if(!rst_n)
        crc_data <= 32'hff_ff_ff_ff;
    else if(crc_clr)                             //CRC校验值复位
        crc_data <= 32'hff_ff_ff_ff;
    else if(crc_en)
        crc_data <= crc_next;
	else;
end

endmodule

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1540573.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

YOLOv8-ROS-noetic+USB-CAM目标检测

环境介绍 Ubuntu20.04 Ros1-noetic Anaconda-yolov8虚拟环境 本文假设ROS和anaconda虚拟环境都已经配备&#xff0c;如果不知道怎么配备可以参考&#xff1a; https://blog.csdn.net/weixin_45231460/article/details/132906916 创建工作空间 mkdir -p ~/catkin_ws/srccd ~/ca…

【javascript】原型继承

在编程中&#xff0c;我们经常会想获取并扩展一些东西。 例如&#xff0c;我们有一个 user 对象及其属性和方法&#xff0c;并希望将 admin 和 guest 作为基于 user 稍加修改的变体。我们想重用 user 中的内容&#xff0c;而不是复制/重新实现它的方法&#xff0c;而只是在其之…

黑马程序员:C++核心编程——2.引用

引用的作用是给变量起别名&#xff0c;本名和别名都可以操作同一块地址的数据。 注意事项 1&#xff09;引用必须初始化且在初始化后不可改变。大白话是创建时不能不说是谁的别名&#xff0c;更不能在创建之后修改为其他人的别名。 2&#xff09;*重点&#xff1a;函数传参的…

蓝桥杯b组C语言组一个月怎么准备?

蓝桥杯b组C语言组一个月怎么准备&#xff1f; C/C程序设计组其中主要的是C算法竞赛选手 1.面对算法竞赛C语言缺少很多便捷性的数据结构&#xff0c;应该快速了解并掌握C的stl。 2.蓝桥杯俗称篮球杯&#xff0c;含金量大海捞针&#xff0c;其中练好dfs的暴力搜索能够骗取相当的…

从信号完整性角度看电容应用与计算

从信号完整性的角度来看&#xff0c;电容在电子电路中具有关键的应用。电容是一种被用来存储电荷并在电路中传递电流的被动元件&#xff0c;它对信号完整性有着重要的影响。 1. 去耦电容的选择 电容类型总结表格 实际的电容并不是理想&#xff0c;表现为&#xff1a; a.电…

网页无插件视频播放器,支持录像、截图、音视频播放,多路播放等,提供源码下载

前言 本播放器内部采用jessibuca插件接口&#xff0c;支持录像、截图、音视频播放等功能。播放器播放基于ws流&#xff0c;分屏操作支持1分屏、4分屏、6分屏、9分屏方式。 jessibuca工作原理是通过Emscripten将音视频解码库编译成Js&#xff08;WebAssembly&#xff0c;简称was…

人工智能的迷惑行为:AI世界的隐秘角落

人工智能迷惑行为大赏 在当今数字化时代&#xff0c;人工智能技术的飞速发展给我们的生活带来了诸多便利和可能性&#xff0c;但同时也伴随着一些令人困惑的现象和行为。本文将深入探讨人工智能的迷惑行为&#xff0c;揭示AI世界中的隐秘角落&#xff0c;让我们一同探寻这个充…

鸿蒙Harmony应用开发—ArkTS-if/else:条件渲染

ArkTS提供了渲染控制的能力。条件渲染可根据应用的不同状态&#xff0c;使用if、else和else if渲染对应状态下的UI内容。 说明&#xff1a; 从API version 9开始&#xff0c;该接口支持在ArkTS卡片中使用。 使用规则 支持if、else和else if语句。 if、else if后跟随的条件语句…

框架结构模态分析/动力时程分析Matlab有限元编程 【Matlab源码+PPT讲义】|梁单元|地震时程动画|结果后处理|地震弹性时程分析| 隐式动力学

专栏导读 作者简介&#xff1a;工学博士&#xff0c;高级工程师&#xff0c;专注于工业软件算法研究本文已收录于专栏&#xff1a;《有限元编程从入门到精通》本专栏旨在提供 1.以案例的形式讲解各类有限元问题的程序实现&#xff0c;并提供所有案例完整源码&#xff1b;2.单元…

上位机图像处理和嵌入式模块部署(qmacvisual之ROI设定)

【 声明&#xff1a;版权所有&#xff0c;欢迎转载&#xff0c;请勿用于商业用途。 联系信箱&#xff1a;feixiaoxing 163.com】 ROI&#xff0c;全称是region of interest&#xff0c;也就是感兴趣区域。这里面一般分成两种情况&#xff0c;一种是所有的算法都依赖于这个ROI&a…

Visual Studio - Platform Toolset

Visual Studio - Platform Toolset 1. Microsoft Visual Studio 2013 - Platform Toolset2. Microsoft Visual Studio 2015 - Platform ToolsetReferences 1. Microsoft Visual Studio 2013 - Platform Toolset (right mouse click on the project) -> 属性 -> 配置属性…

鸿蒙Harmony应用开发—ArkTS-应用级变量的状态管理

状态管理模块提供了应用程序的数据存储能力、持久化数据管理能力、UIAbility数据存储能力和应用程序需要的环境状态。 说明&#xff1a; 本模块首批接口从API version 7开始支持&#xff0c;后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 本文中T和S的含义…

41-Vue-webpack基础

webpack基础 前言什么是webpackwebpack的基本使用指定webpack的entry和output 前言 本篇开始来学习下webpack的使用 什么是webpack webpack: 是前端项目工程化的具体解决方案。 主要功能&#xff1a;它提供了友好的前端模块化开发支持&#xff0c;以及代码压缩混淆、处理浏览…

Unity:2D

目录 1. 简介 2. 2D Sorting 3. 9-slicing Sprites 3.1 9-slicing and Colliders 4. Sprite Renderer 5. Sprite Creator 6. Sprite Editor 6.1 Slice 6.1 Resize polygons 6.2 Custom Outline 6.3 Custom Physics Shape 6.4 Secondary Textures 6.5 Data Provider…

AI在融媒体领域的应用探讨

AI在融媒体领域的应用探讨 ChatGPT是人工智能的一种应用形式&#xff0c;它属于自然语言处理&#xff08;NLP&#xff0c;Nature Language Process&#xff09;领域。 2022年11月30日&#xff0c;由人工智能实验室OpenAI发布的对话式大型语言模型ChatGPT一夜爆火&#xff0c;…

BUUCTF-Misc12

[BJDCTF2020]纳尼1 1.打开附件 一张打不开的图片和一个没什么用的文本文档 2.010 Editor 用010 Editor 打开6.gif这个文件 发现文件头缺少 .gif 的文件头是47 49 46 38 添加文件头并保存 得到一个动图&#xff0c;由四张图片组成 得到一串看似像base64的编码&#xff1a;Q…

解析SpringBoot自动装配原理前置知识:解析条件注释的原理

什么是自动装配&#xff1f; Spring提供了向Bean中自动注入依赖的这个功能&#xff0c;这个过程就是自动装配。 SpringBoot的自动装配原理基于大量的条件注解ConditionalOnXXX&#xff0c;因此要先来了解一下条件注解相关的源码。 以ConditionalOnClass为例 首先来查看Conditi…

本地运行环境工具UPUPWANK(win)和Navicat数据库管理工具

UPUPWANK安装地址&#xff1a;https://www.upupw.net 1.进入UPUPWANK后点击一键开启 2.新增项目 这里请千万注意80端口&#xff0c;如果80端口被占用了&#xff0c;请记住去任务管理器关闭占用80端口的进程。不然就不会成功显示。&#xff08;笔者含泪警告&#xff0c;一晚上的…

Python Qt Designer 初探

代码下载在最下面 #开发环境安装# 本示例在Windows11下, 使用VSCode开发, Python 3.12.2, Qt Designer 5.11 VSCode插件Python、Python Debugger、PYQT Integration、Pylance (准备) VSCode自行官网下载 Visual Studio Code - Code Editing. Redefined (准备) Python 直接…

Linux进程的管理和进程的状态

进程的基本概念&#xff1a; 程序的一个执行实例 &#xff0c;正在执行的程序等等 ——— 课本概念 担当分配系统资源的实体&#xff0c;例如cpu时间&#xff0c;内存 -----内核的观点 一、进程的管理 processbar 存储在磁盘中的可执行文件 可执行文件在启动/运行的同时&…