一、 文章简述
CRC算法在通讯和数据传输领域中有着广泛的应用,关于CRC的原理本文档不做阐述,本文档将将重点放在Verilog CRC代码生成工具的使用和如何修改代码使其满足我们的要求两个方面来CRC算法Verilog实现的进行讲解。本教程包含以下方面的内容:
1.CRC类型简介
2.CRC参数简介
3.crc-gen代码生产工具的使用
4.CRC 校验代码的移植
5.CRC校验代码的测试
二、 CRC算法中参数的简介
2.1 CRC类型
简单来讲,CRC分为CRC-4、CRC-5、CRC-6、CRC-7、CRC-8、CRC-16、CRC-32;但是又可以进行更细节的分类,如图1所示,同样是CRC-8却有四种不同的计算方法,如CRC-8、CRC-8/ITU、CRC-8/ROHC、CRC-8/MAXIM。因此在进行CRC检验时,要根据实际情况进行选择,并且在双方进行通讯时,校验方式务必一致。

图1 CRC类型图
2.2 CRC参数:
从图1中可以看出,每一种CRC都有多个参数,这个参数用来确定检验算法具体如何实现,如图2所示。

图2 CRC参数图
CRC Name:CRC算法的名称,也是在CRC校验使用过程中很重要的参数,使用时通讯双方使用同一种检验方式进行检验、对比才有意义
CRC Width:CRC输出结果的位宽,与CRC名称中的-X相对应。
CRC Poly:该参数是CRC校验的核心参数,它与CRC校验公式有关。例如:CRC-5/ITC的公式为x5+x4+x2+1,该公式等效为x5×1+x4×1+x3×0+x2×1+x1×0+x0×1,二进制表示其阶数关系:10101(必须去掉最高阶数),二进制的10101等于十六进行的0x15。同理其他检验的Poly也可以以同样的方式进行确定。
CRC Init:该参数为CRC校验的结果的初始值。
CRC RefIn:该参数确定输入的数据是否进行字节的反转,如果是true则需要反转,若为false则不需要反转。
CRC RefOut:该参数确定CRC初步校验结果是否进行字节的反转,如果是true则需要反转,若为false则不需要反转。
CRC XorOut:该参数确定CRC校验结果输出时的异或值。
2.3 CRC检验的过程的理解:
关于CRC校验,我的理解是,首先有一个最基本的CRC的算法,它是CRC的主干,它需要的参数是Width、Poly、Init;还有一些外围的算法,例如输入输出是否反转,输出结果需要异或的值,它的参数包括:RefIn、RefOut、XorOut。
三、CRC算法Verilog代码生产工具的使用
3.1 crc-gen工具简介
crc-gen是一款基于命令行操作的crc校验代码生成工具,可以生成VHDL和Verilo HDL语言的CRC算法的基础代码。生成基础代码之后,我们只需要根据自己所使用的CRC校验算法的参数要求在进行参数上的修改,就可以写出符合要求的CRC校验的VHDL或Verilog HDL的代码。本人学习的是Verilog HDL语言,本文将以该语言进行讲解。
Crc-gen工具可以在网上进行下载,也可以使用下面的链接进行下载。
crc-gen下载链接:https://pan.baidu.com/s/1BuH7LmCB7x2gd1tJAuPCYA
提取码:rt2z
3.2 crc-gen 的使用
在进行使用前,请先看一下crc-gen文件夹中的说明文档。以免下面的操作有不好理解的地方。本例采用CRC-8/MAXIM校验方式,CRC多项式为:x8+x5+x4+1。
首先打开电脑cmd命令行,并进入crc-gen文件夹,如图3所示:

图3 crc-gen初始界面
crc-gen的命令格式如下:
crc-gen language data_width poly_width poly_string
language: verilog or vhdl
data_width : 数据数据位宽,1-1024。
poly_width : CRC多项式宽度,1-1024。
poly_string : CRC多项式描述,即CRC Poly参数,16进制表示。
CRC-8/MAXIM的多项式为x8+x5+x4+1,通过多项式可以得到Poly值为0x31。我们要生成的代码,编程语言采用Verlog,数据输入为8位,输入以下命令:
crc-gen Verilog 8 8 31,如图4所示:

图4 crc-gen 命令输入及代码生成界面
从图中可以看出CRC的代码已经生成,并且公式与我们所要求的公式是一致的。
将代码赋值到文件中,复制的代码如下:

// CRC module for
//       data[7:0]
//       crc[7:0]=1+x^4+x^5+x^8;
//
module crc(input [7:0] data_in,input        crc_en,output [7:0] crc_out,input        rst,input        clk);reg [7:0] lfsr_q,lfsr_c;assign crc_out = lfsr_q;always @(*) beginlfsr_c[0] = lfsr_q[0] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[6] ^ data_in[0] ^ data_in[3] ^ data_in[4] ^ data_in[6];lfsr_c[1] = lfsr_q[1] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[7] ^ data_in[1] ^ data_in[4] ^ data_in[5] ^ data_in[7];lfsr_c[2] = lfsr_q[2] ^ lfsr_q[5] ^ lfsr_q[6] ^ data_in[2] ^ data_in[5] ^ data_in[6];lfsr_c[3] = lfsr_q[3] ^ lfsr_q[6] ^ lfsr_q[7] ^ data_in[3] ^ data_in[6] ^ data_in[7];lfsr_c[4] = lfsr_q[0] ^ lfsr_q[3] ^ lfsr_q[6] ^ lfsr_q[7] ^ data_in[0] ^ data_in[3] ^ data_in[6] ^ data_in[7];lfsr_c[5] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[3] ^ lfsr_q[6] ^ lfsr_q[7] ^ data_in[0] ^ data_in[1] ^ data_in[3] ^ data_in[6] ^ data_in[7];lfsr_c[6] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[4] ^ lfsr_q[7] ^ data_in[1] ^ data_in[2] ^ data_in[4] ^ data_in[7];lfsr_c[7] = lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[5] ^ data_in[2] ^ data_in[3] ^ data_in[5];end // alwaysalways @(posedge clk, posedge rst) beginif(rst) beginlfsr_q  <= {8{1'b1}};endelse beginlfsr_q  <= crc_en ? lfsr_c : lfsr_q;endend // always
endmodule // crc

四、Verilog代码移植与修改
4.1参数要求
CRC-8/MAXIM的参数如图5右侧所示,其中Poly为0x31,初始值为0x00,输入输出需要数据位翻转,输出值要异或0x00(相当于不进行异或)。在生成的代码中我们要进行初始值的设置,数据输入输出的翻转。

图5 CRC-8/MAXIM的参数
4.2 代码修改
从参数身上可以看出,我们需要进行三处的修改(输出结果异或0x00相当于不异或):

  1. CRC结果初始值,即每次CRC计算的起始值,需设置为0x00。
  2. 对输入数据的进行位数的翻转。
  3. 对输出的CRC校验值进行翻转。
    修改后的代码如下:
// CRC module for
//       data[7:0]
//       crc[7:0]=1+x^4+x^5+x^8;
//
module crc(input [7:0] data_in,input        crc_en,output [7:0] crc_out,input        rst,input        clk);reg [7:0] lfsr_q,lfsr_c;//输入数据的翻转/*1.定义一个8位的data2.将data_in 翻转赋值给data3.将always @(*)语句块中的data_in替换为data*/wire [7:0]data;assign data = {data_in[0],data_in[1],data_in[2],data_in[3],data_in[4],data_in[5],data_in[6],data_in[7]};//输出数据的翻转assign crc_out = {lfsr_q[0],lfsr_q[1],lfsr_q[2],lfsr_q[3],lfsr_q[4],lfsr_q[5],lfsr_q[6],lfsr_q[7]};always @(*) beginlfsr_c[0] = lfsr_q[0] ^ lfsr_q[3] ^ lfsr_q[4] ^ lfsr_q[6] ^ data[0] ^ data[3] ^ data[4] ^ data[6];lfsr_c[1] = lfsr_q[1] ^ lfsr_q[4] ^ lfsr_q[5] ^ lfsr_q[7] ^ data[1] ^ data[4] ^ data[5] ^ data[7];lfsr_c[2] = lfsr_q[2] ^ lfsr_q[5] ^ lfsr_q[6] ^ data[2] ^ data[5] ^ data[6];lfsr_c[3] = lfsr_q[3] ^ lfsr_q[6] ^ lfsr_q[7] ^ data[3] ^ data[6] ^ data[7];lfsr_c[4] = lfsr_q[0] ^ lfsr_q[3] ^ lfsr_q[6] ^ lfsr_q[7] ^ data[0] ^ data[3] ^ data[6] ^ data[7];lfsr_c[5] = lfsr_q[0] ^ lfsr_q[1] ^ lfsr_q[3] ^ lfsr_q[6] ^ lfsr_q[7] ^ data[0] ^ data[1] ^ data[3] ^ data[6] ^ data[7];lfsr_c[6] = lfsr_q[1] ^ lfsr_q[2] ^ lfsr_q[4] ^ lfsr_q[7] ^ data[1] ^ data[2] ^ data[4] ^ data[7];lfsr_c[7] = lfsr_q[2] ^ lfsr_q[3] ^ lfsr_q[5] ^ data[2] ^ data[3] ^ data[5];end // always//校验初始化/*将always @(posedge clk, posedge rst) 中的 lfsr_q  <= {8{1'b1}}改为 lfsr_q  <= {8{1'b0}}.*/always @(posedge clk, posedge rst) beginif(rst) beginlfsr_q  <= {8{1'b0}};endelse beginlfsr_q  <= crc_en ? lfsr_c: lfsr_q;endend // always
endmodule // crc

五、测试及分析
5.1测试代码
测试输入数据位0x01、0x02、0x03、0x04,测试代码如下:

module CRC(
input CLK
);//对时钟进行分频,用于运算reg [1:0]cnt = 2'd0;reg CLK_DIV = 1'd0;always@(posedge CLK)beginif(cnt == 2'd3)beginCLK_DIV <= ~CLK_DIV;cnt <= 2'd0;endelsebegincnt <= cnt + 1'd1;endend//进行CRC模块的测试reg [7:0]crc_data_test[3:0];reg [7:0]crc_cnt = 8'd0;reg [7:0]crc_data_in;wire [7:0]crc_data_out;reg crc_en;reg crc_rst;//crc-8实例化crc(.data_in(crc_data_in),.crc_en(crc_en),.crc_out(crc_data_out),.rst(crc_rst),.clk(~CLK_DIV));//测试状态机always@(posedge CLK_DIV)begincase(crc_cnt)8'd0:begin//测试数据赋初值crc_data_test[0] <= 8'h01;crc_data_test[1] <= 8'h02;crc_data_test[2] <= 8'h03;crc_data_test[3] <= 8'h04;//关闭crccrc_en <= 1'd0;//复位crccrc_rst <= 1'd1;//状态计数器加1crc_cnt <= crc_cnt + 1'd1;end8'd1:begin//使能crccrc_en <= 1'd1;//停止复位crccrc_rst <= 1'd0;//输入数据初值crc_data_in <= crc_data_test[0];//状态计数器加1crc_cnt <= crc_cnt + 1'd1;end8'd2:begin//输入数据初值crc_data_in <= crc_data_test[1];//状态计数器加1crc_cnt <= crc_cnt + 1'd1;end8'd3:begin//输入数据初值crc_data_in <= crc_data_test[2];//状态计数器加1crc_cnt <= crc_cnt + 1'd1;end8'd4:begin//输入数据初值crc_data_in <= crc_data_test[3];//状态计数器清零crc_cnt <= 8'd0;enddefault:begincrc_cnt <= 8'd0;endendcaseend
endmodule

5.2测试结果
CRC计算机计算结果如图6所示。

图6 CRC计算机计算结果
FPGA 测试结果如图7所示。

图7 FPGA 测试结果
从图中可以看到,输入数据相同的情况下,在数据输入结束后的,CRC校验输出值与CRC计算器计算的结果是一样。

CRC校验算法的Verilog实现相关推荐

  1. 【FPGA】CRC校验算法从数学原理到代码实现

    老规矩,转b站 [[FPGA]CRC校验算法从数学原理到代码实现-哔哩哔哩]

  2. CRC校验算法的数学原理(上)

    介绍   CRC是Cyclic Redundancy Check的缩写,用中文来讲,就是 循环冗余校验.是一种通过对数据产生固定位数校验码以备侦测数据错误的数据校验技术,主要用来侦测数据传输错误,也可 ...

  3. modbus c语言校验算法,Modbus CRC校验算法

    终于找到了 Modbus CRC 校验算法 算法一: unsigned int calccrc(uchar crcbuf,uint crc) { uchar i; crc=crc ^ crcbuf; ...

  4. c# 如何编写CRC校验算法

    在C#中编写CRC校验算法,可以使用以下步骤: 首先需要确定CRC校验的多项式和初始值.根据具体的需求和应用场景,选择合适的CRC多项式和初始值. 定义一个计算CRC校验值的函数,函数的输入参数为待校 ...

  5. CRC-16原理及通用的16位CRC校验算法代码

    CRC-16原理及通用的16位CRC校验算法代码 循环冗余码校验英文名称为Cyclical Redundancy Check,简称CRC.它是利用除法及余数的原理来作错误侦测(Error Detect ...

  6. CRC校验算法的解析,暨对网上的CRC详解的补充

    一.CRC的形象理解 本文面向对CRC校验有一定基础的读者,如果你不懂,请戳这里.维基百科还有图解版的. 在CRC的具体实现中,如果要计算CRC的数据很长,一般都会用到寄存器,用来保存当前的计算到的C ...

  7. 16位CRC校验算法,16进制crc校验

    在CRC计算时只用8个数据位,起始位及停止位,如有奇偶校验位也包括奇偶校验位,都不参与CRC计算. CRC计算方法是: 1. 加载一值为0XFFFF的16位寄存器,此寄存器为CRC寄存器. 2. 把第 ...

  8. 基于verilog的CRC校验(汇总)

    目录 原理 计算 检错与纠错 纠错实现 Verilog实现 本来想整理一下关于CRC校验的内容,但是发现前辈们写的都很好,本文对内容进行整理汇总. 原理 crc为什么能够检错和纠错,这背后有着深刻的数 ...

  9. 【Verilog】CRC校验码生成器原理及verilog实现

    目录 一.CRC的基本原理 二.CRC生成步骤 2.1举个栗子 三.Verilog实现 四.参考资料 4.1 CRC在线计算器 一.CRC的基本原理 CRC :Cyclic Redundancy Ch ...

  10. CRC校验原理和推导过程及Verilog实现(一文讲透)

    目录 一.CRC简介 1.1 CRC可检测的错误 1.2 CRC需要知道的基本名称 1.2.1 多项式公式 1.2.2 多项式简记式 1.2.3 数据宽度 1.2.4 初始值与结果异或值 1.2.5 ...

最新文章

  1. drx功能开启后_简单实用!小米手机中这些新功能真香
  2. RabbitMq install on Centos
  3. linux 下 用户与用户组
  4. 文件流下载到本地 - 待完成
  5. LIKE语句也可以这样写
  6. Android中解析XML
  7. angular HttpClient 配置
  8. mysql+keepalived必须要lvs吗_Mysql双主热备+LVS+Keepalived高可用操作记录
  9. linux系统日志_Linux系统学习系列——Linux系统日志管 理(下 )
  10. 2017济南北大青鸟accp和学士后课程的真实情况
  11. win10任务栏卡死的靠谱解决方法
  12. 5G网络结构核心网侧接口介绍
  13. 怎么设置电脑的固定IP地址?
  14. Android TV 认证简介
  15. MAC压缩文件 密码 加密ZIP
  16. MFC修改界面图标时,已导入.ico文件,但是程序运行后,界面不显示更新后的新图标
  17. 外呼系统四大功能,助力企业进入智能电销时代
  18. 角位移/倾角/角度传感器如何安装
  19. 实现简单的直播互动功能,直播软件源码是如何做的
  20. what is VC维

热门文章

  1. 机器学习视频课程(超清完整11周)分享给大家!
  2. axure怎么转换成html文件,AxureRP教程AxureRP如何生成HTML文件
  3. Golang优化之内存对齐
  4. 音乐播放小程序demo
  5. 大一微积分笔记整理_大学数学-微积分学笔记.pdf
  6. 数据挖掘领头人韩家炜教授:如何从无结构文本到有用的知识?
  7. mysql语句怎么拼接字符串_mysql字符串拼接
  8. HOOK大神用c++制作绝地求生自瞄物品透视,源码仅供娱乐!
  9. nuxt SSR部署到iis7方案
  10. VSCode使用eclipse快捷键