算法简介:
一种信道编码技术,用来检测数据传输或者保存后可能出现的错误,其使用模2除法进行校验,计算速度快,检错能力强,有不同的标准参数模型,标准越高则检错能力和精度越好。
算法实现:
(以CRC-5为例(初值00)):其生成多项式为X5+X3+1 输入输出无需翻转。设数据串为100101
- 根据生成多项式不同幂次的系数得到其二进制为:101001(除数),由于首位和末尾必为1,所以省略首位为01001 = 0x099 (POLY)
- 给数据串后补上省略首位后的系数位数的0,得到新数据串100101 00000(被除数).
- 将新数据串和除数进行模2除法运算,得到5位余数即CRC校验码10111.
- 将得到的余数拼接在数据串末尾,得到新数据串,
- 用该数据串模2除以除数,若无余数,说明无误码。
实现电路:
根据多项式画出标准电路
列出表达式:
D0 <= data_in ^ D4 ;
D1 <= D0 ;
D2 <= D1 ;
D3 <= data_in ^ D4 ^D2 ;
D4 <= D3 ;
Data-in | D0 | D1 | D2 | D3 | D4 |
0 | 0 | 0 | 0 | 0 | 0 |
1 | 1 | 0 | 0 | 1 | 0 |
0 | 0 | 1 | 0 | 0 | 1 |
0 | 1 | 0 | 1 | 1 | 0 |
1 | 1 | 1 | 0 | 0 | 1 |
0 | 1 | 1 | 1 | 1 | 0 |
1 | 1 | 1 | 1 | 0 | 1 |
当6个时钟周期结束后,D4-D0的值即是CRC校验码10111
verilog实现:(.V文件)
module crc (
input [5:0] data_in , //输入待检测数据
output [4:0] crc_data , //CRC校验码输出
input rst ,
input clk ,
output wire [4:0] result , // 最后用来检验的余数
output wire [10:0] string_data // 定义输出的CRC数据串
) ;
reg [4:0] reminder_1 , reminder_2 , //两组中间变量, 用来储存电路现态和次态的值
mod1 , mod2 ;
wire [5:0] data ;
integer i =0 ;
integer j = 0;
assign string_data = {crc_data[0],crc_data[1],crc_data[2],crc_data[3],crc_data[4],data_in[0],data_in[1],data_in[2],data_in[3],data_in[4],data_in[5]} ; //将输入数据和CRC校验码拼接
assign data = {data_in[0],data_in[1],data_in[2],data_in[3],data_in[4],data_in[5]} ; //储存输入数据100101
assign crc_data= {reminder_2[4],reminder_2[3],reminder_2[2],reminder_2[1],reminder_2[0]} ; //将中间变量数据传入CRC值
assign result = {mod2[4],mod2[3],mod2[2],mod2[1],mod2[0]} ; //余数
always @ (*) begin
reminder_1[0] <= data [i] ^ reminder_2 [4] ; //根据电路图写出关系式
reminder_1[1] <= reminder_2 [0] ; //D0 <= data_in ^ D4
reminder_1[2] <= reminder_2 [1] ; //D1 <= D0
reminder_1[3] <= data [i] ^ reminder_2 [4] ^ reminder_2 [2] ; //D2 <= D1
reminder_1[4] <= reminder_2 [3] ; //D3 <= data_in ^ D4 ^D2
//D4 <= D3
mod1[0] <= string_data [j] ^ mod2 [4] ;
mod1[1] <= mod2 [0] ;
mod1[2] <= mod2 [1] ;
mod1[3] <= string_data [j] ^ mod2 [4] ^ mod2 [2] ;
mod1[4] <= mod2 [3] ;
end
always @ (posedge clk or posedge rst ) begin
if(rst) begin
reminder_2 <= {5{1'b0}} ; //复位使电路状态清0
mod2 <= {5{1'b0}};
end
else if (i <= 5 && j<=10)begin
mod2 <= mod1 ;
reminder_2 <= reminder_1 ; // i递增,控制data_in的顺序进入 (LSB)
i = i +1 ; // j递增,控制string_data的顺序进入 (LSB)
j = j + 1;
end
else if (i > 5 && j>10)begin
mod2 <= mod2 ;
reminder_2 <=reminder_2 ;
end
else begin
reminder_2 <=reminder_2 ;
mod2 <= mod1 ;
j = j+1 ;
end
end
endmodule
(测试文件)
`timescale 1 ps/ 1 ps
module crc_vlg_tst();
reg clk;
reg [5:0] data_in;
reg rst;
wire [4:0] crc_data;
wire [4:0] result ;
wire [10:0] string_data ;
crc i1 (
.clk(clk),
.crc_data(crc_data),
.data_in(data_in),
.rst(rst) ,
.string_data(string_data) ,
.result(result)
);
always #10 clk = ~clk ;
initial
begin
clk = 0;
rst = 1 ;
data_in <= 6'b100101 ;
#20
rst = 0 ;
$display("Running testbench");
end
endmodule
波形验证:
可以看到对于拼接CRC校验码后的数据串,通过电路,最后留下的余数为00000,证明数据无误,且通过在线计算得到CRC校验码无误。
刚开始研究,代码较为繁琐,如有错误,欢迎大神沟通指正!