CRC校验学习文档

1.简介

在数字通信的传输过程中, 由于信道存在的噪声、线路间的串扰等各种因素的影响, 造成所传输的信号失真。
为了提高通信的可靠性和减少误码率, 通常采用信道编码技术来进行差错控制。循环冗余校验(Cyclic Redundancy Code, CRC) 由于其误码检测能力强, 抗干扰性能优异, 在众多的信道编码方法中得到广泛的应用。
CRC是最常用的一种查错校验码,其特征是信息字段和校验字段的长度可以任意选定。

2.原理

CRC码是由两部分组成的,前部分是信息码,就是需要校验的信息,后部分是校验码,如果CRC码长共n bit,信息码长k bit,就称为(n,k)码,剩余的r bit即为校验位。如:(7,3)码:110 1001,前三位110为信息码,1001为校验码。
在这里插入图片描述
这个校验码不是随意的,是需要经过计算得出,这里需要引进一个生成多项式的概念。

2.1 生成多项式g(x)

在产生CRC校验码时,要用到除法运算,一般来说,这是比较麻烦的,因此,把二进制信息预先转换成一定的格式,这就是CRC的多项式表示。二进制数表示为生成多项式的系数,如下:
在这里插入图片描述
 所有二进制数均被表示为一个多项式,x仅是码元位置的标记,因此我们并不关心x的取值,称之为码多项式。(我没研究过CRC代数推理过程,没体会到用多项式计算的方便之处,这里要学会的就是给出生成多项式g(x),能写出对应的二进制即可)

常见的生成多项式如下:
  在这里插入图片描述

2.2校验码计算

假定生成多项式的位数为n,则在原信息码的后面加上(n-1)为0,并将生成的新的信息码作为被除数,与生成多项式的二进制进行模二除法,得到的余数就是校验码。
例子:
在这里插入图片描述

3.CRC校验分类

CRC校验有两种方式,一种是串行计算CRC,一种是并行。

  • 串行CRC
    如果用时序电路串行实现,则8 bit数据要移位8次,就需要8个clk,效率低下,为了能在一个时钟周期输出结果,必须采用组合电路,当然,这是以空间换时间的方法,由于使用了for循环8次,直观的讲电路规模将扩大8倍。
  • 并行CRC
    以8bit数据为例,并行计算一次性输入8bit数据,相当于一次并行运算就得到了串行运算需要8位移位所得的结果。

4.串行CRC校验码计算

通常CRC 的串行实现是通过线性反馈移位寄存器 (L FSR s) 来实现的。移位寄存器L FSR s 由m (设生成多项
式的最高阶是m ) 个D 触发器, 加上一些异或门和一条反馈回路组成。线性反馈移位寄存器(L FSR s) 有2 种可能
结构, 分别如图2、图3 所示。本文中把图2 所示的结构称为L FSR, 而把图3 的结构称为L FSR2。
在这里插入图片描述
串行编码实现如图2 所示, 开始时, 寄存器初始化为全0 (或全1) , 数据流码字按高位到低位(或反之) 的顺
序, 依次通过L FSR s。当数据的一位码字从右边移出寄存器时, 就通过反馈回路并根据生成多项式相应位的值(1
表示通路, 0 表示断路) , 和后续输入数据进行异或运算, 从左边反馈进入移位寄存器。当所有位数据移入寄存
器后, 移位寄存器中所形成的结果即为CRC 校验码。需要指出的是, 利用L FSR 进行CRC 编码时, 应在信息码后面
加上m 位的0 序列, 而利用L FSR2 进行编码则不需要。
串行译码使用的电路与编码电路一样, 通常利用L FSR 作为译码电路。与编码不同的是, 利用L FSR 进行译码时, 不需要在信息码后面添加零序列。

4.1 L FSR的伪随机数

通过一定的算法对事先选定的随机种子(seed)做一定的运算可以得到一组人工生成的周期序列,在这组序列中以相同的概率选取其中一个数字,该数字称作伪随机数,由于所选数字并不具有完全的随机性,但是从实用的角度而言,其随机程度已足够了。这里的“伪”的含义是,由于该随机数是按照一定算法模拟产生的,其结果是确定的,是可见的,因此并不是真正的随机数。伪随机数的选择是从随机种子开始的,所以为了保证每次得到的伪随机数都足够地“随机”,随机种子的选择就显得非常重要,如果随机种子一样,那么同一个随机数发生器产生的随机数也会一样。
产生伪随机数的方法最常见的是利用一种线性反馈移位寄存器(LFSR),它是由n个D触发器和若干个异或门组成的,如下图:
在这里插入图片描述
其中,gn为反馈系数,取值只能为0或1,取为0时表明不存在该反馈之路,取为1时表明存在该反馈之路;n个D触发器最多可以提供2^n-1个状态(不包括全0的状态),为了保证这些状态没有重复,gn的选择必须满足一定的条件。下面以n=3,g0=1,g1=1,g2=0,g3=1为例,说明LFSR的特性,具有该参数的LFSR结构如下图:
在这里插入图片描述
从图可以看出,正好有2^3-1=7个状态,不包括全0;

如果您理解了上图,至少可以得到三条结论:

1)初始状态是由SEED提供的;

2)当反馈系数不同时,得到的状态转移图也不同;必须保证gn===1,否则哪来的反馈?

3)D触发器的个数越多,产生的状态就越多,也就越“随机”;

通过CRC的生成原理知道CRC的检验码生成是通过除法得到,由此联想到可以通过LFSR来产生校验码。

假设原信息码子多项式为

在这里插入图片描述

生成多项式为
在这里插入图片描述
那么CRC的码字为为LFSR的工作原理以及LFSR在CRC上的应用 ,使用LFSR电路来进行实现,将M(x)向左移r位在电路中的意义即为输入完信息码后再输入r个0,所以在电路上的表现就如图5所示。
在这里插入图片描述
将这个时刻产生的寄存器输入添加到原信息码的后边就进行完了CRC编码,同样接收端可以使用LFSR来进行CRC检验。

4.2 串行计算CRC verilog实现

module CRC_GEN(
    input            rst,     /*async reset,active low*/
    input            clk,     /*clock input*/
    input     [7:0]  data_in, /*parallel data input pins */
    input            d_valid, /* data valid,start to generate CRC, active high*/
    output reg[15:0] crc
);

integer i;
reg feedback;
reg [15:0] crc_tmp;
/*
*  sequential process
*/
always @(posedge clk or negedge rst)
begin
    if(!rst) 
        crc <= 16'b0;          /*触发器中的初始值十分重要 */
    else if(d_valid==1'b0)
        crc <= 16'b0;
    else
        crc <= crc_tmp;
end

/*
*   combination process
*/
always@( data_in or crc)
begin
    crc_tmp = crc;
    for(i=7; i>=0; i=i-1)
    begin
        feedback    = crc_tmp[15] ^ data_in[i];
        crc_tmp[15]  = crc_tmp[14];
        crc_tmp[14]  = crc_tmp[13];
        crc_tmp[13]  = crc_tmp[12];
        crc_tmp[12]  = crc_tmp[11] ^ feedback;
        crc_tmp[11]  = crc_tmp[10] ;
        crc_tmp[10]  = crc_tmp[9];
        crc_tmp[9]   = crc_tmp[8];
        crc_tmp[8]   = crc_tmp[7];
        crc_tmp[7]   = crc_tmp[6];
        crc_tmp[6]   = crc_tmp[5];
        crc_tmp[5]   = crc_tmp[4] ^ feedback;
        crc_tmp[4]   = crc_tmp[3];
        crc_tmp[3]   = crc_tmp[2];
        crc_tmp[2]   = crc_tmp[1];
        crc_tmp[1]   = crc_tmp[0];
        crc_tmp[0]   = feedback;
     end
end

endmodule

5.并行CRC校验码计算

并行计算CRC校验码推导公式有点难懂,放上网址,以后在学
https://dspace.xmu.edu.cn/bitstream/handle/2288/157622/%e4%b8%80%e7%a7%8d%e5%b9%b6%e8%a1%8cCRC%e7%ae%97%e6%b3%95%e7%9a%84%e5%ae%9e%e7%8e%b0%e6%96%b9%e6%b3%95.pdf?sequence=1&isAllowed=y

5.1 并行verilog实现

https://www.cnblogs.com/kingstacker/p/9848191.html

1)并行计算crc用verilog语言描述是复杂繁琐的,所以可以使用在线工具生成verilog或者VHDL模板:http://www.easics.com/webtools/crctool,模板生成的代码稍加修改即可使用。

(2)本次校验模型为G(x) = X16+X12+X5+1。在在线工具中操作相关选项生成模板。
这是生成的代码


// Copyright (C) 1999-2008 Easics NV.
// This source file may be used and distributed without restriction
// provided that this copyright statement is not removed from the file
// and that any derivative work contains the original copyright notice
// and the associated disclaimer.
//
// THIS SOURCE FILE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS
// OR IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
// WARRANTIES OF MERCHANTIBILITY AND FITNESS FOR A PARTICULAR PURPOSE.
//
// Purpose : synthesizable CRC function
//   * polynomial: x^16 + x^12 + x^5 + 1
//   * data width: 16
//
// Info : tools@easics.be
//        http://www.easics.com

module CRC16_D16;

  // polynomial: x^16 + x^12 + x^5 + 1
  // data width: 16
  // convention: the first serial bit is D[15]
  function [15:0] nextCRC16_D16;

    input [15:0] Data;
    input [15:0] crc;
    reg [15:0] d;
    reg [15:0] c;
    reg [15:0] newcrc;
  begin
    d = Data;
    c = crc;

    newcrc[0] = d[12] ^ d[11] ^ d[8] ^ d[4] ^ d[0] ^ c[0] ^ c[4] ^ c[8] ^ c[11] ^ c[12];
    newcrc[1] = d[13] ^ d[12] ^ d[9] ^ d[5] ^ d[1] ^ c[1] ^ c[5] ^ c[9] ^ c[12] ^ c[13];
    newcrc[2] = d[14] ^ d[13] ^ d[10] ^ d[6] ^ d[2] ^ c[2] ^ c[6] ^ c[10] ^ c[13] ^ c[14];
    newcrc[3] = d[15] ^ d[14] ^ d[11] ^ d[7] ^ d[3] ^ c[3] ^ c[7] ^ c[11] ^ c[14] ^ c[15];
    newcrc[4] = d[15] ^ d[12] ^ d[8] ^ d[4] ^ c[4] ^ c[8] ^ c[12] ^ c[15];
    newcrc[5] = d[13] ^ d[12] ^ d[11] ^ d[9] ^ d[8] ^ d[5] ^ d[4] ^ d[0] ^ c[0] ^ c[4] ^ c[5] ^ c[8] ^ c[9] ^ c[11] ^ c[12] ^ c[13];
    newcrc[6] = d[14] ^ d[13] ^ d[12] ^ d[10] ^ d[9] ^ d[6] ^ d[5] ^ d[1] ^ c[1] ^ c[5] ^ c[6] ^ c[9] ^ c[10] ^ c[12] ^ c[13] ^ c[14];
    newcrc[7] = d[15] ^ d[14] ^ d[13] ^ d[11] ^ d[10] ^ d[7] ^ d[6] ^ d[2] ^ c[2] ^ c[6] ^ c[7] ^ c[10] ^ c[11] ^ c[13] ^ c[14] ^ c[15];
    newcrc[8] = d[15] ^ d[14] ^ d[12] ^ d[11] ^ d[8] ^ d[7] ^ d[3] ^ c[3] ^ c[7] ^ c[8] ^ c[11] ^ c[12] ^ c[14] ^ c[15];
    newcrc[9] = d[15] ^ d[13] ^ d[12] ^ d[9] ^ d[8] ^ d[4] ^ c[4] ^ c[8] ^ c[9] ^ c[12] ^ c[13] ^ c[15];
    newcrc[10] = d[14] ^ d[13] ^ d[10] ^ d[9] ^ d[5] ^ c[5] ^ c[9] ^ c[10] ^ c[13] ^ c[14];
    newcrc[11] = d[15] ^ d[14] ^ d[11] ^ d[10] ^ d[6] ^ c[6] ^ c[10] ^ c[11] ^ c[14] ^ c[15];
    newcrc[12] = d[15] ^ d[8] ^ d[7] ^ d[4] ^ d[0] ^ c[0] ^ c[4] ^ c[7] ^ c[8] ^ c[15];
    newcrc[13] = d[9] ^ d[8] ^ d[5] ^ d[1] ^ c[1] ^ c[5] ^ c[8] ^ c[9];
    newcrc[14] = d[10] ^ d[9] ^ d[6] ^ d[2] ^ c[2] ^ c[6] ^ c[9] ^ c[10];
    newcrc[15] = d[11] ^ d[10] ^ d[7] ^ d[3] ^ c[3] ^ c[7] ^ c[10] ^ c[11];
    nextCRC16_D16 = newcrc;
  end
  endfunction
endmodule

这是经过修改的

`timescale 1ns/1ps
module crc16_test (
    input     wire              i_clk                 , //时钟;
    input     wire              i_rst_n               , //同步复位;
    input     wire              i_din_valid           , //输入数据有效;
    input     wire    [15:0]    i_din                 , //输入数据;
    output    wire              o_dout_valid          , //输出CRC值有效;
    output    wire    [15:0]    o_dout                  //输出CRC;         
);
reg [15:0] r_dout;
wire [15:0] d;
wire [15:0] c;
assign d = i_din;
assign c = r_dout;
always @(posedge i_clk) begin
    if (~i_rst_n) 
        r_dout <= 16'hffff; //初始值为ffff;
    else if (i_din_valid) 
    begin //计算逻辑;
        r_dout[0]  = d[12] ^ d[11] ^ d[8] ^ d[4] ^ d[0] ^ c[0] ^ c[4] ^ c[8] ^ c[11] ^ c[12];
        r_dout[1]  = d[13] ^ d[12] ^ d[9] ^ d[5] ^ d[1] ^ c[1] ^ c[5] ^ c[9] ^ c[12] ^ c[13];
        r_dout[2]  = d[14] ^ d[13] ^ d[10] ^ d[6] ^ d[2] ^ c[2] ^ c[6] ^ c[10] ^ c[13] ^ c[14];
        r_dout[3]  = d[15] ^ d[14] ^ d[11] ^ d[7] ^ d[3] ^ c[3] ^ c[7] ^ c[11] ^ c[14] ^ c[15];
        r_dout[4]  = d[15] ^ d[12] ^ d[8] ^ d[4] ^ c[4] ^ c[8] ^ c[12] ^ c[15];
        r_dout[5]  = d[13] ^ d[12] ^ d[11] ^ d[9] ^ d[8] ^ d[5] ^ d[4] ^ d[0] ^ c[0] ^ c[4] ^ c[5] ^ c[8] ^ c[9] ^ c[11] ^ c[12] ^ c[13];
        r_dout[6]  = d[14] ^ d[13] ^ d[12] ^ d[10] ^ d[9] ^ d[6] ^ d[5] ^ d[1] ^ c[1] ^ c[5] ^ c[6] ^ c[9] ^ c[10] ^ c[12] ^ c[13] ^ c[14];
        r_dout[7]  = d[15] ^ d[14] ^ d[13] ^ d[11] ^ d[10] ^ d[7] ^ d[6] ^ d[2] ^ c[2] ^ c[6] ^ c[7] ^ c[10] ^ c[11] ^ c[13] ^ c[14] ^ c[15];
        r_dout[8]  = d[15] ^ d[14] ^ d[12] ^ d[11] ^ d[8] ^ d[7] ^ d[3] ^ c[3] ^ c[7] ^ c[8] ^ c[11] ^ c[12] ^ c[14] ^ c[15];
        r_dout[9]  = d[15] ^ d[13] ^ d[12] ^ d[9] ^ d[8] ^ d[4] ^ c[4] ^ c[8] ^ c[9] ^ c[12] ^ c[13] ^ c[15];
        r_dout[10] = d[14] ^ d[13] ^ d[10] ^ d[9] ^ d[5] ^ c[5] ^ c[9] ^ c[10] ^ c[13] ^ c[14];
        r_dout[11] = d[15] ^ d[14] ^ d[11] ^ d[10] ^ d[6] ^ c[6] ^ c[10] ^ c[11] ^ c[14] ^ c[15];
        r_dout[12] = d[15] ^ d[8] ^ d[7] ^ d[4] ^ d[0] ^ c[0] ^ c[4] ^ c[7] ^ c[8] ^ c[15];
        r_dout[13] = d[9] ^ d[8] ^ d[5] ^ d[1] ^ c[1] ^ c[5] ^ c[8] ^ c[9];
        r_dout[14] = d[10] ^ d[9] ^ d[6] ^ d[2] ^ c[2] ^ c[6] ^ c[9] ^ c[10];
        r_dout[15] = d[11] ^ d[10] ^ d[7] ^ d[3] ^ c[3] ^ c[7] ^ c[10] ^ c[11];
    end
end 
reg r_dout_valid = 0; 
always @(posedge i_clk) //输入数据在一个时钟内完成CRC计算,下一个时钟输出;
begin
    r_dout_valid <= i_din_valid;
end

assign o_dout_valid = r_dout_valid;
assign o_dout = r_dout ;

endmodule // end the crc16_test model;
  • 1
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值