文章目录
1 产生原理
循环冗余校验码Cyclic Redundancy Check(CRC)
简介:在发送端根据要传送的K位二进制码序列,以一定的规则产生一个校验用的r位监督码(CRC码),附在信息后面组成n=k+r位的码发出去。这种编码也叫(n,k)码。对于一个给定的(n,k)码,存在一个高次幂为r的多项式G(x),根据多项式G(x)可以生成k位信息的校验码,G(x)叫做这个CRC码的生成多项式, 生成多项式的最高位和最低位必是1。
1.1 CRC可检测的错误?
- 突发长度小于n-k+1的突发错误;
- 大部分突发长度等于n-k+1的突发错误,其中不可检出的占2-(n-k-1);
- 大部分突发长度大于n-k+1的突发错误,其中不可检出的占2-(n-k);
- 所有与许用码组 码距 小于dmin-1的错误及所有奇数个错误。
1.2 CRC生成过程?
生成过程:发送信息C(x)左移r位,表示为C(x)×2r,C(x)右边空出的r位就是校验码的位置。通过C(x)×2r模2除以生成多项式G(x)得到的余数就是校验码。
1.3 接收过程?
接收过程:
- 计算CRC比较。
- 收到的二进制序列(信息码+循环码)除以多项式,如果余数为0,则说明传输过程无错误发生。
2 CRC 的计算
以输入数据0x5a,G(x)=x^8+x^2+x+1计算为例。
2.1 手算
首先了解模2运算:
模2加:0+0=0,0+1=1,1+1=0 -> a(模2加)b = a⊕b
模2减:0-0=0,0-1=1,1-0=1,1-1=0 -> a(模2减)b = a⊕b
模2乘:0×0=0,0×1=0,1×1=1
模2除:0/1=0,1/1=1
根据生成过程:C(x)×2^r模2除以生成多项式G(x)得到的余数就是校验码。
G(x)对应:0x107
运算过程减法为模2减,即异或运算。
设余数为R[8:0],注意的是,当 R[7] 为1,下一商位为1,当 R[7] 为0,下一商位为0。
其他规则与正常二进制除法一致。
可以看到每次运算的结果:
输入位 | 商 | 余数 |
---|---|---|
0 | 0 | 0_0000_0000 |
1 | 1 | 0_0110_1111 |
0 | 0 | 0_0110_1111 |
1 | 1 | 0_1011_1011 |
1 | 1 | 0_0111_0001 |
0 | 0 | 0_0111_0001 |
1 | 1 | 0_1100_0011 |
0 | 1 | 0_1000_0001 |
最终的到的余数为:0x81,即我们需要的CRC码,0x5a编码之后为 0x5a|0x81。
2.1 在线计算器
网页就有各参数的介绍。
需要注意的是
- POLY:生成项的简写,以16进制表示。忽略了最高位的"1"。
- INIT:这是算法开始时寄存器(crc)的初始化预置值,十六进制表示。手动计算过程初始值是0x00。
3 Verilog 实现
3.1 线性反馈移位寄存器(LFSR)循环码编码
以上的计算过程很多文章都有介绍,但是都没有介绍为什么是题目中的结构?
比如为什么 Verilog实现串行CRC-8,G(D)=D8+D2+D+1,电路结构如下?
其实这是线性反馈移位寄存器(LFSR)循环码编码。
引用《数字通信(第四版)John G.Proakis著.张力军译》8.1.3 循环码的内容:
对于CRC-8进行信源0x5a的校验,移位运算过程为:
信源数据的逐个输入等效于把0x5a(8’b01011010)移位后的 16’b0101_1010_0000_0000 拆分为:
-
16’b0000_0000_0000_0000 模2除 9’b1_0000_0111 = 商0…余 R1:0000_0000
0 ________________________ 8’b1_0000_0111|16'b0000_0000_0000_0000 /- 0000_0000_0 ____________ =R1: 0000_0000_0
这一步比较直观。所以在这我们就知道为什么在线计算器需要设置初始值?嘿嘿
-
16’b0100_0000_0000_0000 模2除 9’b1_0000_0111 ⊕ R1 = 商1…余 R2: 0000_0111
01 ________________________ 8’b1_0000_0111|16'b0100_0000_0000_0000 /- 100_0001_11 +R1: 0000_0000_0 ____________ =R2: 0000_0011_1
这一步值得注意的是生成多项式为0的位可以想象有一个C_(i-1) ⊕ 0,只不过与结果为C_(i-1)省略了,因为加减都是等效于异或,以此实现加上上一步的余数减去因式。
-
16’b0000_0000_0000_0000 模2除 9’b1_0000_0111 ⊕ R2 = 商0…余 R3:0000_1110:
-
16’b0001_0000_0000_0000 模2除 9’b1_0000_0111 ⊕ R3 = 商1…余 R4:0001_1011:
-
16’b0000_1000_0000_0000 模2除 9’b1_0000_0111 ⊕ R4 = 商1…余 R5:1000_1100:
-
16’b0000_0000_0000_0000 模2除 9’b1_0000_0111 ⊕ R5 = 商0…余 R6:0110_0010:
-
16’b0000_0010_0000_0000 模2除 9’b1_0000_0111 ⊕ R6 = 商1…余 R7:1100_0001:
-
16’b0000_0000_0000_0000 模2除 9’b1_0000_0111 ⊕ R7 = 商1…余 R8:1000_0001:
输入 | 移位 | 移位寄存器值C7~C0 |
---|---|---|
0 | 0000_0000 | |
0 | 0 | 0000_0000 |
1 | 1 | 0000_0111 |
0 | 0 | 0000_1110 |
1 | 1 | 0001_1011 |
1 | 1 | 1000_1100 |
0 | 0 | 0110_0010 |
1 | 1 | 1100_0001 |
0 | 1 | 1000_0001 |
可以看到,这其实就是对应我们模2除运算的过程。
3.2 Verilog代码
OutputLogic可以在线生成CRC代码,我们在生成的基础上改就好了。