《基于软核技术的嵌入式系统设计》Word格式文档下载.docx
《《基于软核技术的嵌入式系统设计》Word格式文档下载.docx》由会员分享,可在线阅读,更多相关《《基于软核技术的嵌入式系统设计》Word格式文档下载.docx(32页珍藏版)》请在冰豆网上搜索。
![《基于软核技术的嵌入式系统设计》Word格式文档下载.docx](https://file1.bdocx.com/fileroot1/2022-10/17/b7743087-ab2d-49e9-8ed5-a9ce32ead418/b7743087-ab2d-49e9-8ed5-a9ce32ead4181.gif)
使用其他开发板的同学在设置时需要做相应的改动)
CRC原理及实现方法
CRC的全称为CyclicRedundancyCheckcode,中文名称为循环冗余校验码。
它是一类重要的线性分组码,编码和解码方法简单,检错和纠错能力强,在通信领域广泛地用于实现差错控制。
实际上,除数据通信外,CRC在其它很多领域也是大有用武之地的。
循环冗余校验码(CRC)的基本原理是:
在K位信息码后再拼接R位的校验码,整个编码长度为N位,因此,这种编码又叫(N,K)码。
对于一个给定的(N,K)码,可以证明存在一个最高次幂为N-K=R的多项式G(x)。
根据G(x)可以生成K位信息的校验码,而G(x)叫做这个CRC码的生成多项式。
校验码的具体生成过程为:
假设发送信息用信息多项式C(X)表示,将C(x)左移R位,则可表示成C(x)*2R,这样C(x)的右边就会空出R位,这就是校验码的位置。
通过C(x)*2R除以生成多项式G(x)得到的余数就是校验码。
在代数编码理论中,将一个码组表示为一个多项式,码组中各码元当作多项式的系数。
例如1100101表示为:
1·
x6+1·
x5+0·
x4+0·
x3+1·
x2+0·
x+1,即x6+x5+x2+1。
设编码前的原始信息多项式为P(x),P(x)的最高幂次加1等于k;
生成多项式为G(x),G(x)的最高幂次等于r;
CRC多项式为R(x);
编码后的带CRC的信息多项式为T(x)。
发送方编码方法:
将P(x)乘以xr(即对应的二进制码序列左移r位),再除以G(x),所得余式即为R(x)。
用公式表示为:
T(x)=xrP(x)+R(x)
接收方解码方法:
将T(x)除以G(x),如果余数为0,则说明传输中无错误发生,否则说明传输有误。
举例来说:
设信息码为1100,生成多项式为1011,即P(x)=x3+x2,G(x)=x3+x+1,计算CRC的过程为
XrP(x)x3(x3+x2)x6+x5x
————=—————=—————=(x3+x2+x)+————
G(x)x3+x+1x3+x+1x3+x+1
即:
R(x)=x。
注意到G(x)最高幂次r=3,得出CRC为010。
如果用竖式除法,计算过程为
1110
-------
1011/1100000(1100左移3位)
1011
----
1110
-----
1010
0010
0000
010
因此,T(x)=(x6+x5)+(x)=x6+x5+x,即1100000+010=1100010。
如果传输无误,
T(x)x6+x5+x
————=——————=x3+x2+x,
G(x)x3+x+1无余式。
再看一下前述的竖式除法,如果被除数是1100010,显然在商第三个1时,就能除尽。
下面是一个典型的PPP帧。
最后两个字节称为FCS(FrameCheckSequence),是前面11个字节的CRC。
FF03C021040300070D0306D03A
我们来计算这个PPP帧的CRC,并验证它。
byteppp[13]={0xFF,0x03,0xC0,0x21,0x04,0x03,0x00,0x07,0x0D,0x03,0x06,0x00,0x00};
inti,j;
u16result;
///////////以下计算FCS
//初始化
crcInitRegisters();
//逐位输入,每个字节低位在先,不包括两个FCS字节
for(i=0;
i<
11;
i++)
{
for(j=0;
j<
8;
j++)
crcInputBit((ppp[i]>
>
j)&
1);
}
//得到CRC:
将寄存器组的值求反
result=~crcGetRegisters();
//填写FCS,先低后高
ppp[11]=result&
0xff;
ppp[12]=(result>
8)&
///////////以下验证FCS
//逐位输入,每个字节低位在先,包括两个FCS字节
13;
//得到验证结果
result=crcGetRegisters();
可以看到,计算出的CRC等于0x3AD0,与原来的FCS相同。
验证结果等于0。
初始化为全"
1"
,以及将寄存器组的值求反得到CRC,都是CRC-ITU的要求。
事实上,不管初始化为全"
还是全"
0"
,计算CRC取反还是不取反,得到的验证结果都是0。
实现方式一:
软件方法
在本实验中我们使用的CRC-ITU的生成多项式为G(x)=x16+x12+x5+1
,简记式为1021。
生成多项式的最高幂次项系数是固定的1,故在简记式中,将最高的1统一去掉了。
CRC-ITU的计算算法如下:
a.寄存器组初始化为全"
(0xFFFF)。
b.寄存器组向右移动一个字节。
c.刚移出的那个字节与数据字节进行异或运算,得出一个指向查找表值(注:
本实验是利用函数来产生查找表)的索引。
d.索引所指的表值与寄存器组做异或运算。
e.数据指针加1,如果数据没有全部处理完,则重复步骤b。
f.寄存器组取反,得到CRC,附加在数据之后。
CRC-ITU的验证算法如下:
c.刚移出的那个字节与数据字节进行异或运算,得出一个指向查找表值的索引。
e.数据指针加1,如果数据没有全部处理完,则重复步骤b(数据包括CRC的两个字节)。
f.寄存器组的值是否等于0xF0B8(CRC-ITU定义),若相等则通过,否则失败。
实现方式二:
用户指令的使用
在Altera的NiosII嵌入式处理器中,用户可以在NiosII指令系统中增加用户自定义指令,以增强对强实时软件算法的处理能力。
用户自定义指令可以通过单周期或多周期操作来完成复杂的处理任务。
采用用户自定义指令是一个把复杂的标准指令序列简化为一条用硬件实现的单个指令的方法,最多可以定制256个用户指令。
定制指令处理器还是处理复杂的算术运算和加速逻辑的最佳途径。
完整的用户自定义指令包括:
用户自定义逻辑——完成用户操作的硬件部分;
软件宏——提供软件接口使用户能够访问用户自定义逻辑。
本实验将一个CRC-ITU算法的逻辑块(包含了4个子逻辑块)作为一个用户定制指令,将它们添加到NiosIICPU的指令中,可以比用软件实现快几倍。
4个子逻辑快分别实现字位转换、数据相乘、数据寄存和移位异或的功能。
向NiosIIALU中增加用户自定义指令
由于用户自定义指令需要直接连到ALU上,所以NiosII提供一套预先定义好名称和功能的接口如下图:
NiosII配置向导会扫描用户自定义指令,搜索需要的端口,把这些端口连到ALU上。
因此用户自定义指令必须指定所有需要的端口类型(如单周期或多周期),必须使用预先定义的端口名称,端口才能连到正确的接口上。
例如,在本实验中自定义指令逻辑快的顶层文件CRC的原理图如下,可以看到所定义的端口符合上面提到的原则(本实验未使用prefix端口)。
这样只用一个函数就可实现CRC。
unsignedshortcrcCompute(unsignedshort*data_block,unsignedintnWords)
{
unsignedshort*pointer;
unsignedshortword;
word=ALT_CI_CRC(0xFFFF,1);
//initialisecrcregto0xFFFF
for(pointer=data_block;
pointer<
(data_block+nWords);
pointer++)
word=ALT_CI_CRC(*pointer,0);
return(word);
}/*crcCompute()*/
其中的ALT_CI_CRC函数就是调用自定义指令的C语言的宏定义。
实现方式三:
用户添加外设IPCORE
Altera公司提供了CRC校验码的IPcore,此core是基于CRC-ITU的,用户可以使用SOPCBuilder中的用户逻辑接口向导,将其集成到NiosII处理器系统中。
这种自动化工具能够校验Verilog或VHDL源代码,识别顶层端口并将这些端口连接到合适的处理器总线信号上,整个过程用户介入很少。
SOPCBuilder也会为该外设生成定制的C和汇编函数库,方便用户直接在IDE中使用与该外设相关的函数操作。
添加外设之后,再用SOPCBuilder中的添加向导,把加速逻辑和DMA通道添加到系统中,可以比用软件实现快数百倍。
CRC的IPcore的源文件为crc_peripheral.v(vhd)。
通过SOPCBuilder的用户定义逻辑接口向导可以把该程序编译生成为在SOPCBuilder中能够调用的外设器件文件,添加到NiosIICPU之后就可以利用对应的C函数库,再配合DMA模块我们就能够用自定义外设实现CRC。
以下就是调用自定义外设的函数。
volatilealt_u16crcCompute(unsignedlong*data_block,unsignedintnWords,inthex)
alt_u16word;
IOWR(CRC_PERIPH_BASE,0,0x0000FFFF);
//通过对外设写数据,实现初始化
alt_dma_txchan_ioctl(tx,
ALT_DMA_RX_STREAM_ON,
(void*)(CRC_PERIPH_BASE+0x4));
alt_avalon_dma_send(tx,
data_block,
nWords,
//dma_done,
NULL,
NULL);
while(IORD_A