CRC计算流程详解和FPGA实现

一、概念

        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处理掉,相当于异或elsecrc_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 + 1assign 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) beginif(!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;
endendmodule

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

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

记录开发STM32遇到的卡死问题-串口

背景&#xff1a;以STM32作为主控&#xff0c;广州大彩显示屏显示&#xff0c;主控实时采集数据&#xff0c;串口波特率115200.设置收发频率为50Hz&#xff0c;即单片机每秒发送50帧数据&#xff0c;每秒接收50帧数据&#xff0c;每帧数据大概14字节。 问题&#xff1a;系统长…

智能优化算法 | Matlab实现牛顿-拉夫逊优化算法Newton-Raphson-based optimize(内含完整源码)

文章目录 效果一览文章概述源码设计参考资料效果一览 文章概述 智能优化算法 | Matlab实现牛顿-拉夫逊优化算法Newton-Raphson-based optimize(内含完整源码) 源码设计 % ------------------------------------------------------------------------------------------------…

鸿蒙一次开发,多端部署(十五)常见问题

如何查询设备类型 设备类型分为default&#xff08;默认设备&#xff09;、tablet、tv、wearable、2in1等&#xff0c;有多种查询设备类型的方式。 通过命令行的方式查询设备类型。 通过命令行查询指定系统参数&#xff08;const.product.devicetype&#xff09;进而确定设备…

软件设计师笔记

计算机 运算器组成&#xff1a;算术逻辑单元(ALU)、累加寄存器(AC)、数据缓冲寄存器(DR)、状态条件寄存器()等组成。 控制器组成&#xff1a;指令寄存器(IR)、程序计数器(PC)、地址寄存器(AR)、指令译码器(ID)。 最小数据单位&#xff1a;bit 最小存储单位: byte n进制 转 1…

力扣爆刷第103天之CodeTop100五连刷1-5

力扣爆刷第103天之CodeTop100五连刷1-5 文章目录 力扣爆刷第103天之CodeTop100五连刷1-5一、3. 无重复字符的最长子串二、206. 反转链表三、146. LRU 缓存四、215. 数组中的第K个最大元素五、25. K 个一组翻转链表 一、3. 无重复字符的最长子串 题目链接&#xff1a;https://l…

使用Intellij idea编写Spark应用程序(Scala+Maven)

使用Intellij idea编写Spark应用程序(ScalaMaven) 对Scala代码进行打包编译时&#xff0c;可以采用Maven&#xff0c;也可以采用sbt&#xff0c;相对而言&#xff0c;业界更多使用sbt。这里介绍IntelliJ IDEA和Maven的组合使用方法。IntelliJ IDEA和SBT的组合使用方法&#xf…

docker实践教程,mysql中使用自定义目录实现数据挂载(二)

有一些知识点在docker实践教程&#xff0c;nginx中使用数据卷映射修改前端网页&#xff08;一&#xff09;&#xff0c;就不累述了。 下载mysql的镜像 docker pull mysql创建容器 先去Docker Hub看看mysql是怎么使用的 可知&#xff0c;运行命令为&#xff1a;&#xff08;…

SpringCloud之网关组件Gateway学习

SpringCloud之网关组件Gateway学习 GateWay简介 Spring Cloud Gateway是Spring Cloud的⼀个全新项目&#xff0c;目标是取代Netflix Zuul&#xff0c;它基于Spring5.0SpringBoot2.0WebFlux&#xff08;基于高性能的Reactor模式响应式通信框架Netty&#xff0c;异步⾮阻塞模型…

2024 用CleanMyMac X为您的MAC清理提速吧

CleanMyMac X 是由 MacPaw 公司开发的一款针对 macOS 操作系统的电脑清理工具。它可以帮助用户清理电脑中的垃圾文件、卸载不需要的软件、优化电脑性能等。它的界面简洁明了&#xff0c;操作简单易懂&#xff0c;非常适合普通用户使用。 链接: https://pan.baidu.com/s/1_TFnrI…

【技巧】ChatGPT Prompt 提示语大全

转载请注明出处&#xff1a;小锋学长生活大爆炸[xfxuezhang.cn] 主要来自&#xff1a;https://github.com/f/awesome-chatgpt-prompts ChatGPT SEO提示 Contributed by: StoryChief AI Reference: 7 Powerful ChatGPT Prompts to Create SEO Content Faster 供稿人&#xff1a;…

Linux安装Nginx及配置TCP负载均衡

目录 1、安装编译工具及库文件2、下载解压Nginx压缩包3、Ngnix配置Tcp负载均衡4、配置Ngnix的文件5、Nginx启动 1、安装编译工具及库文件 yum -y install make zlib zlib-devel gcc-c libtool openssl openssl-devel pcre-devel2、下载解压Nginx压缩包 wget https://nginx.o…

【创作纪念日】1024回忆录

不知不觉中&#xff0c;从创作第一篇文章到现在&#xff0c;已经1024天了&#xff0c;两年多的时间里&#xff0c;已经从硕士到博士了&#xff0c;1024&#xff0c;对于程序员来说&#xff0c;是个特别的数字吧&#xff0c;在此回忆与记录一下这些美好的经历吧。 缘起 很早以前…

MySQL面试题--开发(最全,涵盖SQL基础、架构、事务)

MySQL面试题--事务https://mp.csdn.net/mp_blog/creation/editor/136947072 MySQL面试题--MySQL内部技术架构https://blog.csdn.net/Timebro/article/details/136946046?spm1001.2014.3001.5501 MySQL面试题--最全面-索引https://blog.csdn.net/Timebro/article/details/136…

列车票务信息管理系统设计与实现|jsp+ Mysql+Java+ B/S结构(可运行源码+数据库+设计文档)

本项目包含可运行源码数据库LW调试部署环境&#xff0c;文末可获取本项目的所有资料。 推荐阅读100套最新项目 最新ssmjava项目文档视频演示可运行源码分享 最新jspjava项目文档视频演示可运行源码分享 最新Spring Boot项目文档视频演示可运行源码分享 2024年56套包含java…

kali安装docker(亲测有效)

第一步&#xff1a;添加Docker官方的GPG密钥 curl -fsSL https://download.docker.com/linux/debian/gpg | sudo apt-key add - 第二步&#xff1a; 第二步更新源 echo deb https://download.docker.com/linux/debian stretch stable> /etc/apt/sources.list.d/docker.list…

鸿蒙Harmony应用开发—ArkTS-枚举说明

说明&#xff1a; 本模块首批接口从API version 7开始支持&#xff0c;后续版本的新增接口&#xff0c;采用上角标单独标记接口的起始版本。 Color 从API version 9开始&#xff0c;该接口支持在ArkTS卡片中使用。 颜色名称颜色值颜色示意Black0x000000 Blue0x0000ff Brown…

C#中右键通过listview来控制datagridview字段值的是否显示、显示顺序,并存储到XML中。

最终显示效果&#xff0c;如下图所示&#xff1a; datagridview开始显示通过调用XML存储的字段值及顺序来显示&#xff0c;右键调出Tools来控制显示的顺序及是否显示&#xff0c;通过加号和减号进行调整顺序。 XML存储字段值及顺序 主要代码及事件&#xff1a; 获取datagridv…

ARM CPU的总线发展

ARM架构是当今世界上最为广泛应用的嵌入式处理器架构之一&#xff0c;其CPU总线的发展对于系统性能和扩展性具有重要影响。本文将探讨ARM CPU总线的发展历程、关键技术和对系统性能的影响。 以下是我整理的关于嵌入式开发的一些入门级资料&#xff0c;免费分享给大家&#xff…

Orbit 使用指南 10|在机器人上安装传感器 | Isaac Sim | Omniverse

如是我闻&#xff1a; 资产类&#xff08;asset classes&#xff09;允许我们创建和模拟机器人&#xff0c;而传感器 (sensors) 则帮助我们获取关于环境的信息&#xff0c;获取不同的本体感知和外界感知信息。例如&#xff0c;摄像头传感器可用于获取环境的视觉信息&#xff0c…

Spring中的OAuth2

一. 什么是OAuth2 “Auth” 表示 “授权” Authorization “O” 是 Open 的简称&#xff0c;表示 “开放” 连在一起就表示 “开放授权”&#xff0c;OAuth2是一种开放授权协议。 二. OAuth2是什么 怎么用 OAuth2是目前最流行的授权协议&#xff0c;用来授权第三方应用&am…