CRC计算流程详解和FPGA实现

这篇具有很好参考价值的文章主要介绍了CRC计算流程详解和FPGA实现。希望对大家有所帮助。如果存在错误或未考虑完全的地方,请大家不吝赐教,您也可以点击"举报违法"按钮提交疑问。

一、概念

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

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

1.1 CRC的数学基础

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

        1、将K位的信息码写成如下多项式形式:

        2、将信息码左移R位,变成如下多项式形式:CRC计算流程详解和FPGA实现,FPGA,fpga开发

        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.comhttp://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 Toolhttp://crctool.easics.be/

CRC代码生成工具二:OutputLogic.com » CRC Generatorhttp://outputlogic.com/?page_id=321文章来源地址https://www.toymoban.com/news/detail-848906.html

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

到了这里,关于CRC计算流程详解和FPGA实现的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处: 如若内容造成侵权/违法违规/事实不符,请点击违法举报进行投诉反馈,一经查实,立即删除!

领支付宝红包 赞助服务器费用

相关文章

  • 记一次基于FPGA的VGA显示四操作数计算器工程的开发流程——(1)从顶层设计说起

    首先值得说明的是,在这个项目几乎完成之际,笔者才愈发体会到了硬件思维和软件思维的云泥之别。不幸的是,在此项目的实现过程中,绝大部分代码的思维仍然是软件思维,因此该项目主要模块的设计部分可能并不能体现硬件操作的独到之处,不符合硬件工程师的基本设

    2024年02月04日
    浏览(43)
  • 【FPGA】FPGA入门 —— 基本开发流程

    快速上手verilog语法 状态机,线性序列机 FPGA常见的设计方法 自己写代码,下载代码进行使用,使用厂家/第三方提供的IP核 常见接口设计 等等。。 学习时间:基础内容的学习 - 20*8h,啊啊啊我可以我能行,看来这个月我给把时间砸这上面了~~ 仿真两大作用:检查验证设计功能

    2024年02月11日
    浏览(53)
  • 【FPGA】高云FPGA之科学的FPGA开发流程

    项目需要做什么,了解系统的功能,如果是大型的项目还会划分模块 通过使用verilog、VHDL、成熟的IP核或者通过画原理图的方式进行逻辑输入设计 当逻辑输入设计完成后需要对其进行验证,该部分由软件部分进行验证,如果逻辑输入有问题需要检查语法错误或则重新设计设计

    2024年02月04日
    浏览(50)
  • FPGA学习笔记-1 FPGA原理与开发流程

    注:笔记主要参考: B站 正点原子 教学视频“正点原子手把手教你学FPGA-基于达芬奇Pro开发板 Artix-7 XC7A35T/XC7A100T”。 小梅哥爱漂流 教学视频“【零基础轻松学习FPGA】小梅哥Xilinx FPGA基础入门到项目应用培训教程”。 B站搬运 “特权同学2020版《深入浅出玩转FPGA视频教程》

    2024年02月05日
    浏览(54)
  • FPGA的基本开发流程

    FPGA是一种可编程逻辑器件,与传统的硬连线电路不同,它具有高度的可编程性和灵活性。FPGA的设计方法包括硬件设计和软件设计两部分,硬件设计包括FPGA芯片电路、存储器、输入输出接口电路等等,软件设计则是HDL程序开发,以及软硬件的联调。 本文主要介绍FPGA设计的基

    2024年04月13日
    浏览(47)
  • 02体验FPGA开发流程

    标准的 FPGA 开发流程主要有以下几个步骤: 需求分析:做一个项目之前,首先需要对项目需求进行详细分析,弄明白项目所需要实现的功能 系统设计:根据项目所需的功能进行系统架构设计,架构设计主要是确定将系统分为子模块,模块之间数据流怎么走,控制流怎么走,

    2024年01月24日
    浏览(48)
  • FPGA verilog设计的MODBUS CRC算法

    已经测试通过。 `timescale 1ns / 1ps // // Company: // Engineer: // // Create Date: 20:14:12 05/18/2023 // Design Name: // Module Name: Modbus_CRC // Project Name: // Target Devices: // Tool versions: // Description: // // Dependencies: // // Revision: // Revision 0.01 - File Created // Additional Comments: // // module Modbus_CRC( input clk, input rst

    2024年02月06日
    浏览(45)
  • SOC FPGA介绍及开发设计流程

    目录 一、SoC FPGA简介 二、SoC FPGA开发流程 2.1 硬件开发 2.2 软件开发          SOC FPGA是在FPGA架构中集成了基于ARM的硬核处理器系统(HPS),包括处理器、外设和存储器控制器。 相较于传统的仅有ARM处理器或 FPGA 的嵌入式芯片,SOC FPGA既拥有ARM处理器灵活高效的数据运算和事务

    2024年02月15日
    浏览(43)
  • 【FPGA】Vivado开发流程(基于2018.3版本)

    基本流程:①设计定义 ②设计输入 ③分析综合 ④功能仿真 ⑤布局布线 ⑥分析性能   双击 Vivado图标即可启动 Vivado 软件。 ①Quick Start 组包含有 Create Project(创建工程) Open Project(打开工程)OpenExample Project(打开实例工程)。 ②Tasks 组包含有 Manage IP(管理 IP) Open Hardw

    2024年02月14日
    浏览(41)
  • Xilinx FPGA开发环境vivado使用流程

    第一步:点击Add Sources按钮 第二步:选择add or create design sources按钮,即添加设计文件 第三步:选择create file 文件新建完成后: 此时可以定义I/O端口,我们选择自己在程序中编写。 第四步:在编辑器中编写verilog程序 XDC文件里主要是完成管脚的约束,时钟的约束,以及组的约

    2024年02月03日
    浏览(63)

觉得文章有用就打赏一下文章作者

支付宝扫一扫打赏

博客赞助

微信扫一扫打赏

请作者喝杯咖啡吧~博客赞助

支付宝扫一扫领取红包,优惠每天领

二维码1

领取红包

二维码2

领红包