CRC (Cyclic Redundancy Check) 原理
CRC 是一种基于二进制除法的错误检测方法,广泛应用于数字网络和存储设备中,以检测数据传输或存储过程中的错误。以下是 CRC 的基本原理和步骤:
- 基本概念
CRC 使用一个多项式生成器对数据进行编码和校验。该多项式通常称为生成多项式,表示为 𝐺(𝑥)G(x)。多项式的阶数决定了 CRC 的位数(例如,CRC-32 表示多项式阶数为 32)。 - 生成多项式
生成多项式 𝐺(𝑥)G(x) 是一个二进制多项式,如 CRC-32 的生成多项式为: 𝐺(𝑥)=𝑥32+𝑥26+𝑥23+𝑥22+𝑥16+𝑥12+𝑥11+𝑥10+𝑥8+𝑥7+𝑥5+𝑥4+𝑥2+𝑥+1G(x)=x32+x26+x23+x22+x16+x12+x11+x10+x8+x7+x5+x4+x2+x+1 - 数据处理步骤
- 附加零位:
• 在数据后面附加 𝑛n 个零位,𝑛n 是生成多项式的阶数。例如,对于 CRC-32,附加 32 个零位。 - 二进制除法:
• 使用生成多项式 𝐺(𝑥)G(x) 对扩展后的数据进行二进制除法。除法的结果是余数,不使用商。
• 二进制除法中,减法操作等同于异或 (XOR) 操作。 - CRC 码生成:
• 余数就是 CRC 校验码。将余数附加到原始数据的末尾,形成传输数据。 - 接收端校验:
• 接收端使用相同的生成多项式对接收到的数据进行二进制除法。如果余数为零,则表示数据没有错误;否则,数据存在错误。 - 具体示例
假设数据为 11010110111101011011,生成多项式为 𝑥4+𝑥+1x4+x+1,表示为 1001110011。 - 数据附加零位: 1101011011→110101101100001101011011→11010110110000
- 二进制除法:
11010110110000−10011010011−00011100001−000011000000−0000011100000011−110−00101−1000001−01000000111110000011100000011000100010100100100
继续此过程,直到数据处理完毕,得到最终余数。 - CRC 码生成: 余数即为 CRC 码。
- 优点与应用
• 优点:
• 高效的错误检测能力。
• 硬件和软件实现都非常简单和快速。
• 应用:
• 数据通信协议(如 Ethernet、USB)。
• 存储设备的数据校验(如硬盘、SSD)。
• 文件传输和压缩格式(如 ZIP 文件)。 - 总结
CRC 是一种有效的错误检测机制,通过使用生成多项式进行二进制除法,生成并验证数据的校验码,确保数据的完整性。它在各种数字通信和存储系统中得到了广泛应用。
matlab仿真程序:
function crc = crc32(data)
% 输入数据转换为二进制向量
data_bin = de2bi(data, 8, 'left-msb');
data_bin = data_bin';
data_bin = data_bin(:)';
% CRC 多项式定义
poly = [1 1 1 0 1 0 1 1 0 1 1 1 0 0 0 1 0 0 0 0 0 1 0 0 0 1 0 0 0 1];
poly_length = length(poly);
% 在数据末尾附加多项式长度减1的零
data_padded = [data_bin zeros(1, poly_length-1)];
% 初始化CRC寄存器
crc = zeros(1, poly_length);
% CRC 计算
for i = 1:length(data_bin)
if xor(data_padded(i), crc(1))
crc = xor(crc, [poly zeros(1, length(crc)-poly_length)]);
end
crc = [crc(2:end) 0];
end
% 最终CRC值
crc = crc(1:poly_length-1);
crc = bi2de(crc, 'left-msb');
end
% 测试数据
data = uint8('123456789');
crc_value = crc32(data);
disp(['CRC-32 值: ', num2str(crc_value)]);
verilog实现CRC:
//-----------------------------------------------------------------------------
// CRC module for data[7:0] , crc[31:0]=1+x^1+x^2+x^4+x^5+x^7+x^8+x^10+x^11+x^12+x^16+x^22+x^23+x^26+x^32;
//-----------------------------------------------------------------------------
module crc(
input [7:0] data_in,
input crc_en,
output [31:0] crc_out,
input rst,
input clk);
reg [31:0] lfsr_q,lfsr_c;
assign crc_out = lfsr_q;
always @(*) begin
lfsr_c[0] = lfsr_q[24] ^ lfsr_q[30] ^ data_in[0] ^ data_in[6];
lfsr_c[1] = lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[0] ^ data_in[1] ^ data_in[6] ^ data_in[7];
lfsr_c[2] = lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[6] ^ data_in[7];
lfsr_c[3] = lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[31] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[7];
lfsr_c[4] = lfsr_q[24] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[30] ^ data_in[0] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[6];
lfsr_c[5] = lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[29] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[0] ^ data_in[1] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7];
lfsr_c[6] = lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[28] ^ lfsr_q[29] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[1] ^ data_in[2] ^ data_in[4] ^ data_in[5] ^ data_in[6] ^ data_in[7];
lfsr_c[7] = lfsr_q[24] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[29] ^ lfsr_q[31] ^ data_in[0] ^ data_in[2] ^ data_in[3] ^ data_in[5] ^ data_in[7];
lfsr_c[8] = lfsr_q[0] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[27] ^ lfsr_q[28] ^ data_in[0] ^ data_in[1] ^ data_in[3] ^ data_in[4];
lfsr_c[9] = lfsr_q[1] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[28] ^ lfsr_q[29] ^ data_in[1] ^ data_in[2] ^ data_in[4] ^ data_in[5];
lfsr_c[10] = lfsr_q[2] ^ lfsr_q[24] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[29] ^ data_in[0] ^ data_in[2] ^ data_in[3] ^ data_in[5];
lfsr_c[11] = lfsr_q[3] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[27] ^ lfsr_q[28] ^ data_in[0] ^ data_in[1] ^ data_in[3] ^ data_in[4];
lfsr_c[12] = lfsr_q[4] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[28] ^ lfsr_q[29] ^ lfsr_q[30] ^ data_in[0] ^ data_in[1] ^ data_in[2] ^ data_in[4] ^ data_in[5] ^ data_in[6];
lfsr_c[13] = lfsr_q[5] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[29] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[1] ^ data_in[2] ^ data_in[3] ^ data_in[5] ^ data_in[6] ^ data_in[7];
lfsr_c[14] = lfsr_q[6] ^ lfsr_q[26] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[2] ^ data_in[3] ^ data_in[4] ^ data_in[6] ^ data_in[7];
lfsr_c[15] = lfsr_q[7] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[29] ^ lfsr_q[31] ^ data_in[3] ^ data_in[4] ^ data_in[5] ^ data_in[7];
lfsr_c[16] = lfsr_q[8] ^ lfsr_q[24] ^ lfsr_q[28] ^ lfsr_q[29] ^ data_in[0] ^ data_in[4] ^ data_in[5];
lfsr_c[17] = lfsr_q[9] ^ lfsr_q[25] ^ lfsr_q[29] ^ lfsr_q[30] ^ data_in[1] ^ data_in[5] ^ data_in[6];
lfsr_c[18] = lfsr_q[10] ^ lfsr_q[26] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[2] ^ data_in[6] ^ data_in[7];
lfsr_c[19] = lfsr_q[11] ^ lfsr_q[27] ^ lfsr_q[31] ^ data_in[3] ^ data_in[7];
lfsr_c[20] = lfsr_q[12] ^ lfsr_q[28] ^ data_in[4];
lfsr_c[21] = lfsr_q[13] ^ lfsr_q[29] ^ data_in[5];
lfsr_c[22] = lfsr_q[14] ^ lfsr_q[24] ^ data_in[0];
lfsr_c[23] = lfsr_q[15] ^ lfsr_q[24] ^ lfsr_q[25] ^ lfsr_q[30] ^ data_in[0] ^ data_in[1] ^ data_in[6];
lfsr_c[24] = lfsr_q[16] ^ lfsr_q[25] ^ lfsr_q[26] ^ lfsr_q[31] ^ data_in[1] ^ data_in[2] ^ data_in[7];
lfsr_c[25] = lfsr_q[17] ^ lfsr_q[26] ^ lfsr_q[27] ^ data_in[2] ^ data_in[3];
lfsr_c[26] = lfsr_q[18] ^ lfsr_q[24] ^ lfsr_q[27] ^ lfsr_q[28] ^ lfsr_q[30] ^ data_in[0] ^ data_in[3] ^ data_in[4] ^ data_in[6];
lfsr_c[27] = lfsr_q[19] ^ lfsr_q[25] ^ lfsr_q[28] ^ lfsr_q[29] ^ lfsr_q[31] ^ data_in[1] ^ data_in[4] ^ data_in[5] ^ data_in[7];
lfsr_c[28] = lfsr_q[20] ^ lfsr_q[26] ^ lfsr_q[29] ^ lfsr_q[30] ^ data_in[2] ^ data_in[5] ^ data_in[6];
lfsr_c[29] = lfsr_q[21] ^ lfsr_q[27] ^ lfsr_q[30] ^ lfsr_q[31] ^ data_in[3] ^ data_in[6] ^ data_in[7];
lfsr_c[30] = lfsr_q[22] ^ lfsr_q[28] ^ lfsr_q[31] ^ data_in[4] ^ data_in[7];
lfsr_c[31] = lfsr_q[23] ^ lfsr_q[29] ^ data_in[5];
end // always
always @(posedge clk, posedge rst) begin
if(rst) begin
lfsr_q <= {32{1'b1}};
end
else begin
lfsr_q <= crc_en ? lfsr_c : lfsr_q;
end
end // always
endmodule // crc