CRC check code generator
Error detection
In the process of data transmission, no matter how perfect the design of the transmission system is, errors will always exist . This error may cause one or more frames transmitted on the link to be destroyed (bit errors occur, 0 becomes 1, or 1 becomes 0), so that the receiver receives the wrong data. In order to improve the accuracy of the data received by the receiver as much as possible, it is necessary to perform error detection on the data before the receiver receives the data , and the receiver actually accepts the data if and only when the detection result is correct.
A [r-bit binary check code] is appended after a [p-bit binary data sequence] to form a binary sequence with a total length of [p+r] . There is a specific relationship between the check code attached to the data sequence and the p-bit binary sequence. If errors occur in some bits in the data sequence due to interference or other reasons, this characteristic relationship will be destroyed. Therefore, the correctness of the received data can be verified by checking the specific relationship .
There are many ways to detect, the common ones are parity check, accumulation and check, and cyclic redundancy check.
(1) Parity check, the detection error probability is about 50%, which is simple but low in transmission efficiency. Parity is mostly used for low-speed data communication, such as RS232.
(2) Accumulation and verification, the detection error probability is about 1/256, simple to implement and widely used.
(3) CRC verification, as long as the number of divisor polynomials selected is large enough, the probability of detection error is almost non-existent.
Cyclic redundancy check
CRC check code generator
Different generator polynomials have different error detection capabilities. Choose CRC-16 generator polynomial:
G(X) = x 16 + x 15 + x 2 + 1
There are two types of CRC check code generators: serial CRC check code generator and parallel CRC check code generator.
Generally, the value of the CRC check code can be obtained through a linear shift register and an XOR gate . The linear shift register shifts one bit at a time to complete the division function, and the XOR gate completes the subtraction function without carry. If the quotient is 1, the divisor is XORed from the higher-order bits of the dividend, and the shift register is shifted to the right by one bit, ready to perform operations on the lower bits of the dividend; if the quotient is 0, the shift register is shifted to the right by one Bit.
The circuit structure diagram is as follows:
The serial CRC check code generator shifts 1 bit per clock, and the parallel CRC check code generator shifts 16 bits per clock cycle (implemented by combinational logic).
CRC can be calculated online at the following website:
http://www.ip33.com/crc.html
00AA -> 03FC
AA89 -> 7F3F
2853 -> F1EA
Parallel CRC-16 check code generator
parallelCRC16.v
`timescale 1ns / 1ps
// Company:
// Engineer:
//
// Create Date: 2020/12/14
// Author Name: Sniper
// Module Name: parallelCRC16
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
module parallelCRC16
#(
parameter DATA_WIDTH = 16
)
(
input clk,
input rst_n,
input [DATA_WIDTH-1:0] data,
output reg [15:0] crc_out
);
reg [15:0] crc_temp;
reg temp;
integer i;
//CRC out
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
crc_out <= 0;
else
crc_out <= crc_temp;
end
//CRC temp
//G(X) = x16 + x15 + x2 + 1
always@(*)
begin
if(!rst_n)
begin
crc_temp = 0;
temp = 0;
end
else
begin
crc_temp = 0;//init
for(i=DATA_WIDTH-1; i>=0; i=i-1)
begin
temp = data[i] ^ crc_temp[15];
crc_temp[15] = temp ^ crc_temp[14];
crc_temp[14:3] = crc_temp[13:2];
crc_temp[2] = temp ^ crc_temp[1];
crc_temp[1] = crc_temp[0];
crc_temp[0] = temp;
end
end
end
endmodule
tb_parallelCRC16.v
`timescale 1ns / 1ps
// Company:
// Engineer:
//
// Create Date: 2020/12/14
// Author Name: Sniper
// Module Name: tb_parallelCRC16
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
module tb_parallelCRC16;
//parameter
parameter DATA_WIDTH = 16;
//input
reg clk;
reg rst_n;
reg [DATA_WIDTH-1:0] data;
//output
wire [15:0] crc_out;
initial
begin
clk = 0;
rst_n = 0;
data[DATA_WIDTH-1:0] = 0;
#100;
rst_n = 1;
@(posedge clk);
data <= 16'h00AA;
@(posedge clk);
data <= 16'hAA89;
@(posedge clk);
data <= 16'h2853;
end
//clock
always #5 clk = ~clk;
//DUT
parallelCRC16
#(
.DATA_WIDTH(DATA_WIDTH)
)
DUT
(
.clk(clk),
.rst_n(rst_n),
.data(data),
.crc_out(crc_out)
);
initial
begin
$dumpfile("tb_parallelCRC16.vcd");
$dumpvars(0,tb_parallelCRC16);
end
initial #1000 $finish;
endmodule
operation result
vcs -R parallelCRC16.v tb_parallelCRC16.v
The CRC result is generated in the next clock cycle of data input.
Serial CRC-16 check code generator
serialCRC16.v
`timescale 1ns / 1ps
// Company:
// Engineer:
//
// Create Date: 2020/12/14
// Author Name: Sniper
// Module Name: serialCRC16
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
module serialCRC16
#(
parameter DATA_WIDTH = 16
)
(
input clk,
input rst_n,
input clear,
input data,
output reg [15:0] crc_out
);
wire temp;
assign temp = data ^ crc_out[15];
//CRC out
//G(X) = x16 + x15 + x2 + 1
always@(posedge clk or negedge rst_n)
begin
if(!rst_n)
crc_out <= 0;
else if(clear)
crc_out <= 0;
else
begin
crc_out[15] <= temp ^ crc_out[14];
crc_out[14:3] <= crc_out[13:2];
crc_out[2] <= temp ^ crc_out[1];
crc_out[1] <= crc_out[0];
crc_out[0] <= temp;
end
end
endmodule
tb_serialCRC16.v
`timescale 1ns / 1ps
// Company:
// Engineer:
//
// Create Date: 2020/12/15
// Author Name: Sniper
// Module Name: tb_serialCRC16
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
module tb_serialCRC16;
//parameter
parameter DATA_WIDTH = 16;
//input
reg clk;
reg rst_n;
reg clear;
reg data;
//output
wire [15:0] crc_out;
task write_data(input [DATA_WIDTH-1:0] data_all);
begin
@(posedge clk);
clear <= 1;
for(int i=DATA_WIDTH-1;i>=0;i=i-1)
begin
@(posedge clk);
data <= data_all[i];
clear <= 0;
end
repeat(3) @(posedge clk) clear <= 1;
end
endtask
initial
begin
clk = 0;
rst_n = 0;
clear = 0;
data = 0;
#100;
rst_n = 1;
repeat(3) @(posedge clk);
write_data(16'h00AA);
write_data(16'hAA89);
write_data(16'h2853);
end
//clock
always #5 clk = ~clk;
//DUT
serialCRC16
#(
.DATA_WIDTH(DATA_WIDTH)
)
DUT
(
.clk(clk),
.rst_n(rst_n),
.clear(clear),
.data(data),
.crc_out(crc_out)
);
initial
begin
$dumpfile("tb_serialCRC16.vcd");
$dumpvars(0,tb_serialCRC16);
end
initial #1000 $finish;
endmodule
operation result
vcs -R -sverilog serialCRC16.v tb_serialCRC16.v
The CRC result is generated in the next clock cycle after the last bit of the data is input.