代码库_CRC校验

代码库_CRC校验

  • 前言
  • README
  • 附源代码

前言

CRC 循环校验码 是一种用于通信双方保证传输数据和接收数据正确和完整的一种算法。
网上的资料很多,但还是意料之中的杂而乱,看着三篇就好,我记得还有个可以生成CRC verilog的网页,试了一下,emmm
概念:https://www.cnblogs.com/94cool/p/3559585.html
C:https://blog.csdn.net/wanyongtai/article/details/79472882
软件:http://www.ip33.com/crc.html
几个要点,
1、生成多项式是要通讯双方约定好的,有许多不同格式,常见的CRC-16、MODBUS、USB,分别具有不同的模型参数
2、完整的多项式位宽比校验码位宽多1位,比如校验码4位,完整的生成多项式可以为X^4+X+1,即1 0011,循环迭代过程中,因为最高位1和待校验序列的1异或为0,所以计算过程中最高位相当于不参与运算,通过移位处理替代
3、模2除即异或 ^

README

核心代码:2字节数据,2字节校验接收完成后构成一帧,第一个if-else是循环校验,切记,此时的生成多项式CRC_POLY已经去除最高位;第二个if-else是循环控制,CRC_cnt 是定时器!

			4:begin								//CRC校验
				if(CRC_frame[31] == 1'b1)begin
					CRC_frame[31:16] <= CRC_frame[30:15]^CRC_POLY;
					CRC_frame[15:0] <= {CRC_frame[14:0],1'b0}; //CRC_frame[15:0]<<1'b1;
				end
				else 
					CRC_frame[31:0] <= {CRC_frame[30:0],1'b0};
					
				if(CRC_cnt == 15)begin
					CRC_cnt <= 0;
					i <= i+1'b1;
				end
				else 
					CRC_cnt <= CRC_cnt+1'b1;
			end

校验过程和校验码可以通过以下过程生成,也很好理解,因为CRC就是那个多项式除法的余数嘛
代码库_CRC校验_第1张图片
代码库_CRC校验_第2张图片
时序图如下,高亮的线分别为校验结果DATA_VALID和数据帧,可以看到5a 5a 1a cb校验正确,1a ca跟软件不同,感觉这个软件又将余数00010000循环了一遍

0000 0000 0000 0001 0000 0000 0000 0000
					0001 0000 0010 0001
-----------------------------------------
		            0001 0000 0010 0001 == 16'h1021

//1021
代码库_CRC校验_第3张图片
代码库_CRC校验_第4张图片

0000 0000 0000 0010 0000 0000 0000 0000
				  0 0010 0000 0100 001
-----------------------------------------
		            001 0000 0010 0001 0 ==  2042

//2042
代码库_CRC校验_第5张图片

代码库_CRC校验_第6张图片

附源代码

CRC function module

module CRC_16(
	input 			sys_clk,     
	input 			sys_rst,
	
	input  [7:0] 	data_in,	//

CRC TB

module CRC_16_tb();


reg CLK;
reg RSTn;

initial
begin
	RSTn = 0; #10 RSTn = 1;
	CLK = 0; forever #5 CLK = ~CLK;
end

////////////////////////////////function module inst
reg [7:0] DATA_UART;
reg        DATA_EN;
reg        CRC_16_EN;

wire [15:0] CRC_out;
wire CRC_flag;
wire CRC_DONE;
wire DATA_VALID;

CRC_16 CRC_16_inst(
	.sys_clk(CLK),
	.sys_rst(RSTn),
	
	.data_in(DATA_UART),	
	.data_en(DATA_EN),
	.CRC_out(CRC_out),
	//.CRC_flag(CRC_flag),
	
	.isEN(CRC_16_EN),
	.oDone(CRC_DONE)
);


assign DATA_VALID = (CRC_DONE && (CRC_out == 16'h0))?1:0;

////////////////////////////core operation
reg [3:0] i;

always@(posedge CLK or negedge RSTn)begin
	if(!RSTn)begin
		DATA_UART <= 8'b0;
        DATA_EN	<= 1'b0;
        CRC_16_EN <= 1'b0;
		
		i <= 0;
	end
	else 
		case(i)
			0:begin
				i <= i+1'b1;
				CRC_16_EN <= 1'b1; //使能功能模块
			end
			1:begin
				DATA_UART <= 8'h5a;
                DATA_EN	<= 1'b1;
				i <= i+1'b1;
			end	
			2:begin
				DATA_UART <= 8'h5a;
                DATA_EN	<= 1'b1;
				i <= i+1'b1;
			end	
			3:begin
				DATA_UART <= 8'h1a;
                DATA_EN	<= 1'b1;
				i <= i+1'b1;
			end	
			4:begin
				DATA_UART <= 8'hcb;
                DATA_EN	<= 1'b1;
				i <= i+1'b1;
			end	
			5:begin
			 if(CRC_DONE)begin
				CRC_16_EN <= 1'b0;//复位功能模块
				DATA_EN <= 1'b0;
				i <= i+1'b1;
			end
			else
			    i <= i;	
			end
			6:begin
				i <= i+1'b1;
				CRC_16_EN <= 1'b1; //使能功能模块
			end
			7:begin
				DATA_UART <= 8'h5a;
                DATA_EN	<= 1'b1;
				i <= i+1'b1;
			end	
			8:begin
				DATA_UART <= 8'h5a;
                DATA_EN	<= 1'b1;
				i <= i+1'b1;
			end	
			9:begin
				DATA_UART <= 8'h1a;
                DATA_EN	<= 1'b1;
				i <= i+1'b1;
			end	
			10:begin
				DATA_UART <= 8'hca;
                DATA_EN	<= 1'b1;
				i <= i+1'b1;
			end	
			11:begin
			   if(CRC_DONE)
				    CRC_16_EN <= 1'b0;//复位功能模块
				    //i <= 0;			  //循环 
				    i <= i;			//停止			  
			end
		endcase
end		
	


endmodule

你可能感兴趣的:(代码库)