CRC手推过程及FPGA简单实现

目录

1. CRC介绍

2. CRC手推过程(以CRC 6为例)

Step1: 获得除数

Step 2: 数据末位补0

Step 3: 开始模2除运算,即异或运算

Step 4: 增加循环校验位

Step 5: 接收端反向验证

3. FPGA实现手推结果


1. CRC介绍

        在进行信息传输时,收发双方可制定特定规则,在数据后增加一些冗余位,以增加接收端的检错能力。该冗余位即为本文介绍的循环冗余校验码(Cyclic Redundancy Check, CRC),CRC是一种差错校验码,用来检测信息传输过程中可能出现的错误。其中信息位的长度和校验位的长度可以任意指定。

        在发送方,利用生成多项式对数据多项式做2生成校验位,在接收方利用同样的多项式对收到的编码多项式做2检错。其基本思想是将要传送的数据D(X)表示为一个多项式L,用预先确定的多项式G(X)除以L,得到的余式就是所需的循环冗余校验码。

CRC的生成多项式应符合如下规律:

a. n位的生成多项式中,应包含Xn和X0;

b. 当信息流出现误码时,数据多项式被生成多项式除后余数不为0;

根据5G协议“R15 38.212”,通信中常用的CRC生成多项式包含以下几种:

{\color{DarkGreen} gcrc_{24A} (X) = X^{24} + X^{23} + X^{18} + X^{17} + X^{14} + X^{11}+ X^{10} + X^{7} + X^{6}+ X^{5}+ X^{4} + X^{3} + X + 1;}

{\color{DarkGreen} gcrc_{24B} (X) = X^{24} + X^{23} + X^{6}+ X^{5}+ X + 1;}

{\color{DarkGreen} gcrc_{16} (X) = X^{16} + X^{12} + X^{5} + 1;}

{\color{DarkGreen} gcrc_{11} (X) = X^{11} + X^{10} + X^{9} + X^{5} + 1;}

{\color{DarkGreen} gcrc_{6} (X) = X^{6 }+ X^{5} + 1;}

2. CRC手推过程(以CRC 6为例)

由于手推过程比较繁琐,为方便各位理解,以校验位最短的CRC6为例进行推导。

Step1: 获得除数

CRC16的生成多项式{\color{DarkGreen} gcrc_{6} (X) = X^{6 }+ X^{5} + 1;}

还可以写成

gcrc6 (X) = 1 * X^{6} + 1* X^{5} + 0 * X^{4} + 0 * X^{3} + 0 * X^{2} + 0 * X^{1} + 1 * 1;

故多项式系数即为需要进行模2除运算的除数(0~6)71 1 0 0 0 0 1

Step 2: 数据末位补0

根据生成多项式最高位的阶数在数据的末位补相应位数的“0故本实例应补6个“0

数据串范例:1 0 0 1 0 1 0 0 1 0

0之后范例1 0 0 1 0 1 0 0 1 0 0 0 0 0 0 0

Step 3: 开始模2除运算即异或运算

        计算时需将补0后的数据串和除数对齐按位进行“异或”操作相同取“0相异取“1将前7位异或的结果计算结束后再将未作计算的数据直接下移形成新的数据串重复以上操作每进行一次操作均需将除数左移至与第一个“1对齐再继续表示跳过无需操作的“0”位。进行多次循环异或运算后得到的余数,舍掉无效位0后就是CRC循环校验码的结果“ 1 1 0 1 1 1” 

Step 4: 增加循环校验位

将计算得到的循环校验位加在数据末位形成新的数据流

新数据流1 0 0 1 0 1 0 0 1 0 1 1 0 1 1 1

Step 5: 接收端反向验证

        接收端接收到数据流后重复Step 3,进行CRC验证如下计算后得到结果为全0,表示在传输过程中无误码完成了一个完整的CRC校验过程

3. FPGA实现手推结果

根据CRC 的公式可得到如下通用CRC电路,由CRC 6公式和电路图可知:

{\color{DarkGreen} gcrc_{6} (X) = X^{6 }+ X^{5} + 1;}

D0 <= data_in ^ D5;

D1 <= D0;          D2< = D1;                D3 <= D2;

D5 <= data_in ^ D5^ D4;

 FPGA程序、测试TB文件、和最后波形如下,仅供参考。

module crc_serial(
input    wire           clk       ,
input    wire           rst       ,
input    wire           i_data    ,  //输入的串行数据 
input    wire           i_data_vld , //数据有效标志

output   reg [5:0]     o_crc_data ,  //输出的CRC结果
output   reg          o_crc_vld      //CRC 有效标志
    );
reg   [5:0]    crc_reg;
reg   [3:0]    data_cnt;
//为输出计数,可计0 ~ (输入数据数量-1)个数
always @(posedge clk) begin
    if(rst)
        data_cnt <= 4'd0;
    else if(i_data_vld)
        data_cnt <= data_cnt + 4'h1;
    else
        data_cnt <= 4'd0;
end
always @(posedge clk) begin
    if(rst)
        crc_reg <= 6'h0;
    else if(i_data_vld) begin
        crc_reg [5]    <= crc_reg[5]^crc_reg[4]^i_data;
        crc_reg [4:1]  <= crc_reg [3:0];
        crc_reg [0]    <= crc_reg [5] ^ i_data;
    end
    else
        crc_reg <= crc_reg;
end
//计数输入数据数量个时钟周期,最后一比特计算完成后输出计算结果
always @(posedge clk) begin
    if(rst)
        o_crc_data <= 6'd0;
    else if(data_cnt ==4'd10)
        o_crc_data <= crc_reg;
    else
        o_crc_data <= 6'd0;
end
always @(posedge clk) begin
    if(rst)
        o_crc_vld <= 1'd0;
    else if(data_cnt ==4'd10)
        o_crc_vld <= 1'd1;
    else
        o_crc_vld <= 1'd0;
end
endmodule
module crc_serial_tb();

reg           clk       ;
reg           rst       ;
reg           i_data    ;  
reg           i_data_vld ;
wire [5:0]    o_crc_data ;
wire          o_crc_vld  ;

parameter    CLK_74_25 = 6.734;
initial begin
    clk = 1'b0;
    forever begin
        #CLK_74_25 clk = ~clk;
    end
end
//生成数据时钟和传入模块的时钟反相
wire clk_data_gen;
assign clk_data_gen = ~clk;
initial begin
    rst = 1'b1; 
    i_data = 10'b0;
    i_data_vld = 1'b0;
    #1000
    rst = 1'b0;
//根据电路图,高位先进入逻辑,低位后进入逻辑
    @(posedge clk_data_gen) begin  //9
    //i_data = 10'b1001010010;
    i_data = 1'b1;
    i_data_vld = 1'b1;end
   @(posedge clk_data_gen) begin  //8
    i_data = 1'b0;
    i_data_vld = 1'b1; end
   @(posedge clk_data_gen) begin  //7
    i_data = 1'b0;
    i_data_vld = 1'b1; end
   @(posedge clk_data_gen) begin  //6
    i_data = 1'b1;
    i_data_vld = 1'b1; end
   @(posedge clk_data_gen) begin  //5
    i_data = 1'b0;
    i_data_vld = 1'b1; end
   @(posedge clk_data_gen) begin  //4
    i_data = 1'b1;
    i_data_vld = 1'b1; end
    @(posedge clk_data_gen) begin  //3
    i_data = 1'b0;
    i_data_vld = 1'b1; end
    @(posedge clk_data_gen) begin  //2
    i_data = 1'b0;
    i_data_vld = 1'b1; end
    @(posedge clk_data_gen) begin  //1
    i_data = 1'b1;
    i_data_vld = 1'b1; end
    @(posedge clk_data_gen) begin  //0
    i_data = 1'b0;
    i_data_vld = 1'b1;end
   @(posedge clk_data_gen) begin
    i_data = 10'b0;
    i_data_vld = 1'b0;
    end
end

crc_serial crc_serial_test(
.clk        (clk)         ,
.rst        (rst)         ,
.i_data     (i_data )      ,  
.i_data_vld  (i_data_vld)   ,

.o_crc_data  (o_crc_data)  ,
.o_crc_vld   (o_crc_vld)
    );
endmodule

以上均为个人总结,如有错误之处欢迎留言讨论,如果对您有帮助,欢迎点赞收藏,谢谢可爱的小哥哥小姐姐们!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值