11.begin
12.addr_r<=addr_r+8'd1;
13.source_data_valid_r<=1'b1;
14.rden<=1'b1;
15.end
16.else
17.begin
18.addr_r<='d0;
19.end
2)rom模块中的信息储存在rom_256.mif文件中,使用Quartus提供的IP核产生rom模块,配置如下:
图2-2-7ROM配置
图2-2-8端口配置,深度配置
3)初始化ROM
用mif格式文件初始化,格式如下代码。
1.WIDTH=1;
2.DEPTH=250;
3.ADDRESS_RADIX=UNS;
4.DATA_RADIX=UNS;
5.CONTENTBEGIN
6.0:
1;
7.1:
1;
8.2:
1;
9.3:
0;
10.4:
1;
11.……//后面省略共250个数
可以使用matlab程序生成随机数(注意最后六位置零,因为FEC初始相位六位)
1.closeall;
2.clearall;
3.width=1;
4.depth=250;
5.data=randn(1,250)>0;
6.data(end-5:
end)=0;
7.fid=fopen('initial_data.txt','w');
8.fprintf(fid,'%d\n',data);
9.//按照格式写入对应的深度,宽度,格式等信息
10.fid=fopen('ram_256.mif','w+');
11.fprintf(fid,'WIDTH=%d;\n',width);
12.fprintf(fid,'DEPTH=%d;\n',depth);
13.fprintf(fid,'ADDRESS_RADIX=UNS;\n');
14.fprintf(fid,'DATA_RADIX=UNS;\n');
15.fprintf(fid,'CONTENTBEGIN\n');
16.fori=1:
depth
17.fprintf(fid,'%d:
%d;\n',i-1,data(i));
18.end
19.fprintf(fid,'END;\n');
20.fclose(fid);
图2-2-9数据初始化RTL视图
4)仿真时序
图2-2-10时序仿真结果和matlab结果对比(首部)
图2-2-11时序仿真结果和matlab结果对比(尾部)
5)将仿真数据导出来和matlab对比分析
图2-2-12时序仿真结果和matlab结果对比(一帧数据)
3.卷积模块
卷积模块采用(2.1.7)码,编码效率
,约束长度
。
生成多项式为(133,171)。
卷积后进行并串转换,先输出133卷积码,后输出171卷积码。
卷积电路图如图2-3-1所示,时序仿真如图2-3-2所示。
1)Verilog代码输入
考虑到同步设计思想,尽量使用原始时钟的分频输出,故对于8kbps的信息码输入和16kbps的卷积码输出,分别采用两种速率的时钟,这样可以尽量保证产生较小的时延,更利于码片对齐。
通过对不同时钟沿的采样和输出,所得到的卷积输出结果不同,这里采用在8k时钟上升沿采样输入数据,在16k时钟下降沿输出卷积码,可以获得正确的卷积输出。
卷积模块的Verilog语言描述如下
1.always@(posedgeclk_8kornegedgerst_n)
2.if(rst_n==1'b0)
3.begin
4.fec_in<=7'd0;
5.fec_out<=2'd0;
6.end
7.elseif(in_valid_r==1'd1)
8.begin
9.fec_in<={fec_in[5:
0],in_data_r};
10.//卷积码生成
11.fec_out<={fec_in[0]+fec_in[2]+fec_in[3]+fec_in[5]+fec_in[6],fec_in[0]+fec_in[1]+fec_in[2]+fec_in[3]+fec_in[6]};
12.end
13.else
14.begin
15.fec_in<=7'd0;
16.fec_out<=2'd0;
17.end
2)卷积原理图示
(2,1,7)卷积码生成器的:
图2-3-1卷积码(2,1,7)
对应的生成多项式:
,
所以得到生成元为:
,
3)仿真结果对比
图2-3-2时序仿真结果和matlab结果对比(首部)
图2-3-3时序仿真结果和matlab结果对比(一帧数据)
4.扩频模块
扩频模块是本设计的重点,扩频码采用KASAMI码,生成多项式为m1=23(n=4),m2=435(n=8);m1和m2的初相(
):
010110100101。
扩频码产生电路如图2-4-1所示。
扩频码产生模块输出的PN序列与上一级卷积输出进行异或,为了减小毛刺,采用D触发器锁存输出,扩频后的输出波形如图2-4-3所示。
扩频码产生模块的Verilog语言描述如下
1.always@(posedgeclk_4_08Mornegedgerst_n)
2.if(rst_n==1'b0)
3.begin
4.m1<=4'b0101;
5.m2<=8'b10100101;
6.kasami_code<='d0;
7.kasami_valid<='d0;
8.count<='d0;
9.kasami_last<=1'b0;
10.End
11.//255周期
12.elseif(count==count_254)
13.begin
14.m1<=4'b0101;
15.m2<=8'b10100101;
16.count<='d0;
17.kasami_last<=1'b1;
18.kasami_code<=m1[3]+m2[7];
19.kasami_valid<=1'b1;
20.End
21.//扩频码产生
22.elseif(fec_out_valid_r[1]==1'b1)
23.begin
24.m1<={m1[2:
0],m1[0]+m1[3]};
25.m2<={m2[6:
0],m2[1]+m2[2]+m2[3]+m2[7]};
26.kasami_code<=m1[3]+m2[7];
27.kasami_valid<=1'b1;
28.count<=count+1'b1;
29.kasami_last<=1'b0;
30.end
31.else
32.begin
33.kasami_code<=1'b0;
34.kasami_valid<=1'b0;
35.kasami_last<=1'b0;
36.end
图2-4-1扩频码产生电路图
图2-4-2扩频电路模块接口
扩频后的仿真对比:
图2-4-3时序仿真结果和matlab结果对比(首部)
图2-4-4时序仿真结果和matlab结果对比(一帧数据)
5.极性变换与内插模块
极性变换是将扩频输出变为双极性码,即将0变换为001,1变换为111。
内插是在4.08m双极性码中插入7个0码片,总速率变为32.64m。
由于这两个模块并不复杂,故可以合并为一个模块。
该模块仿真波形如图2-5-1所示,其Verilog语言描述如下
1.always@(posedgeclk_32_64Mornegedgerst_n)
2.if(rst_n==1'b0)
3.begin
4.reverse_out_w<=3'b0;
5.reverse_out_valid_w<=1'b0;
6.count<='d0;
7.end
8.elseif(count==count_7)
9.begin
10.count<='d0;
11.reverse_out_valid_w<=1'b1;
12.reverse_out_w<=3'b0;
13.end
14.elseif(kpm_code_valid_r[1]==1'b1)
15.begin
16.reverse_out_valid_w<=1'b1;
17.count<=count+3'd1;
18.//计数到0做极性变换,其他计数1-7插零
19.case(count)
20.0:
reverse_out_w<=(kpm_code_r[1])?
3'b001:
3'b111;
21.default:
reverse_out_w<=3'b0;
22.endcase
23.end
24.else
25.begin
26.reverse_out_w<=3'b0;
27.reverse_out_valid_w<=1'b0;
28.end
图2-5-1极性变换与内插模块仿真波形(一帧数据)
6.FIR低通滤波模块
本模块采用老师所提供的低通滤波器即可,注意观察到上一级的输出有毛刺,为了避开毛刺,FIR模块采用上升沿检测。
、总体设计调试及结果的Matlab验证
1)联合调试采用时序仿真,选择仿真器件为CycloneIVE,引脚分配集中在bank4如下:
图3-1引脚分配
2)编译之后的资源占用
图3-2总体资源占用
3)设计RTL视图
图3-3RTL视图,六个模块
4)时序约束,主要包括四个时钟约束
主要包括时钟余量,建立时间余量和保持时间余量
图3-4时钟约束,时钟余量
图3-5建立/保持时间余量
结论:
静态时序分析正常,最高时钟可达98.04M,满足要求。
5)时序仿真结果
图3-6时序仿真各个模块输出结果
6)Matlab仿真代码
将时序仿真的结果写到txt,和matlab对比,因为只靠人手动对比开头和结尾不一定能保证数据的正确性。
1.closeall;
2.clearall;
3.
4.%初始化250个数
5.load('initial_data.txt');
6.%对比数据产生模块250个数据
7.load('source_data.txt');
8.error_source=source_data(1:
250)-initial_data;
9.
10.%fec
11.d_trellis=poly2trellis(7,[133171]);
12.d_source=convenc(initial_data,d_trellis);
13.
14.%对比fec数据
15.load('fec_out.txt');
16.index_fec=0;
17.error_fec=d_source-fec_out(1+index_fec*500:
500+index_fec*500);
18.
19.%kasami255生成多项式m1=23(n=4),m2=435(n=8)
20.%初始相位010110100101
21.m1=[0101];
22.m2=[10100101];
23.kasami_out=zeros(1,255);
24.fori=1:
255
25.kasami_out(1,i)=mod(m1
(1)+m2
(1),2);
26.x_1=mod(m1
(1)+m1(4),2);
27.m1=[m1(2:
end),x_1];
28.x_2=mod(m2
(1)+m2(5)+m2(6)+m2(7),2);
29.m2=[m2(2:
end),x_2];
30.end
31.%扩频
32.kpm_out=zeros(500,255);
33.fori=1:
500
34.forj=1:
255
35.kpm_out(i,j)=mod(kasami_out(j)+d_source(i),2);
36.end
37.end
38.kpm_out2=zeros(1,255*500);
39.kpm_out2=reshape(kpm_out',1,500*255);
40.
41.%对比matlab数据和仿真数据
42.load('kpm_code.txt');
43.kpm_code=kpm_code';
44.index_kpm=0;
45.error_kpm=kpm_out2-kpm_code(1+index_kpm*500*255:
index_kpm*500*255+500*255);
46.error_kpm_not=find(error_kpm~=0);
47.
48.%将0映射成-1,1映射成1
49.I=find(kpm_out2==0);
50.kpm_out2(I)=7;
51.
52.%插零
53.insert_out=zeros(1,8*length(kpm_out2));
54.
55.fori=1:
8*length(kpm_out2)
56.if(mod(i,8)==1)
57.insert_out(i)=kpm_out2(fix(i/8)+1);
58.else
59.insert_out(i)=0;
60.end
61.end
62.
63.%量化3bit
64.reverse_out2=dec2bin(insert_out,3);
65.
66.%验证映射和插零
67.reverse_out_matlab=insert_out;
68.J=find(reverse_out_matlab==7);
69.reverse_out_matlab(J)=111;
70.
71.load('reverse_out.txt');
72.index_reverse=2;
73.error_reverse=reverse_out_matlab'-reverse_out(1+500*255*8*index_reverse:
500*255*8*(index_reverse+1));
74.error_reverse_sum=sum(error_reverse);
仿真结果:
图3-7matlab对比数据
数据产生error_source为0,卷积error_fec为零,扩频error_kpm为零,交织和插零之后数据太多,matlab无法显示所有数据,所以对error_reverse_sum求和,结果为零,说明该模块也正确无误。
总共验证了连续三帧的数据结果正确。
7)FIR联调结果绘图
将FIR模块用上之后,16bit数据导出转换成带符号整数,matlab绘图如下:
图3-8matlab绘图
、实验中遇到的问题及解决方案
1.发射模块输出第一帧的首位缺失,后面帧正常发射
数据初始化我是同时产生读地址和读使能信号,由于初始地址是0,在地址开始加1的时候再把读使能置1,导致了读使能在地址为1的时候才开始,导致读取ROM的数据也是从地址1开始,但是不影响第二帧的输出。
评估问题,该问题可以通过把地址初始值置为-1,或者将程序最开始的触发信号作为读使能。
代码如下:
1.//产生读地址和使能信号
2.always@(posedgeclk_8kornegedgerst_n)
3.if(rst_n==1'd0)
4.begin
5.addr_r<=-8'd1;
6.rden<=1'd0;
7.source_data_valid_r<=1'd0;
8.end
9.elseif(addr_r==-8'd1||addr_r10.begin
11.addr_r<=addr_r+8'd1;
12.source_data_valid_r<=1'b1;
13.rden<=1'b1;
14.end
15.else
16.begin
17.addr_r<='d0;
18.end
这样就可以解决第一帧的第一个数为地址为1的数。
但是这样增加了组合逻辑资源,考虑到接收端接收信号不关注第一帧的第一个数,可以从第二帧开始读取,此问题可以忽略。
2.卷积码输出问题
卷积码是一个bit输入,两个bit输出,我才用的办法是在8k时钟下产生的两个bit写入到两位的寄存器变量中,然后在16K时钟下读取0、1、0、1的地址来实现。
但是这种读取方式依赖于8K和16K时钟对齐,而且地址0或者1开始需要有触发信号。
最后可以实现的方式是,在16K时钟下采8K时钟的值实现0、1、0、1的地址读取,采样开始的触发信号使用上一级的输出有效信号(8K时钟下),不然涉及到跨时钟传输多位信号的同步问题。
3.扩频PN码与卷积输出码的对齐问题
这