logo资料库

FPGA实现dds(ISE实现).pdf

第1页 / 共9页
第2页 / 共9页
第3页 / 共9页
第4页 / 共9页
第5页 / 共9页
第6页 / 共9页
第7页 / 共9页
第8页 / 共9页
资料共9页,剩余部分请下载后查看
FPGA实现实现dds((ISE实现)实现) 上次说了dds的原理,这次我们用FPGA来实现dds。因为dds在da之前都是数字器件,所以我们可以用FPGA来 实现dds的前两个部分。 首先要先规定一下:rom的地址输入是12位,输出时8位。 对于第一部分: 这里看出,功能是将寄存器输出的值与频率控制字M的值相加,然后在时钟的上升沿,将相加后的数据通过寄存器输出。所以 这里的verilog代码也很简单。 + 查看代码 module frequency_tiaozhi( input clk, //输入时钟 input rst_n, //复位信号,用来给寄存器初始复位 input [11:0] k, //频率控制字k output reg [11:0] result //相加后的寄存器输出结果 ); wire [11:0] sum; //相加后的值 assign sum = k + result; always@( posedge clk or negedge rst_n) begin if( !rst_n ) result <= 0; else result <= sum; end endmodule 第二部分:
可以看出,就是将第一部分的输出值加上一个相位控制字。所以代码也很简单: + 查看代码 module phase_tiaozhi( input clk, //输入时钟 input rst_n, //输入复位信号,给寄存器复位 input [11:0] phase, //相位控制字 input [11:0] result, //第一部分的输出结果的输入 output [11:0] address //输出给rom的地址 ); reg [11:0] phase_reg; always@( posedge clk or negedge rst_n ) begin if( !rst_n ) phase_reg <= 0; else phase_reg <= phase; end assign address = result + phase_reg; endmodule 第三部分: 这里就只实现查找表,因为da是模拟器件,FPGA实现不了。 查找表其实是一个rom。所以这里用ISE自带的rom的ip核。既然用到了rom,那么就要对rom里面的值要写入我们需要的值。 这里就用ise的rom的ip核的固定初始化文件coe文件。 Coe文件格式是: 第一行是: MEMORY_INITIALIZATION_RADIX=10; 后面的10表示数据是以什么进制表示,这里是10进制,所以是10.如果 是16就是16进制表示。
第二行是:MEMORY_INITIALIZATION_VECTOR= 这个是固定的。 接下来第三行就是数据,数据以逗号相隔,最后一个数据以分号结束。 这里我们是要产生正弦波,方波,三角波,所以需要三个rom。这里方便统一,直接将方波的数据也放进rom里面。 那就要对正弦波,方波,三角波分别生成rom初始化文件coe。用matlab来生成。 这里要注意,由于da只能转换正数值,所以要将sin的负值部分要处理一下,使之数据范围在0到1之间。 生成正弦波matlab代码: + 查看代码 t=0:2*pi/2^12:2*pi y=0.5*sin(t)+0.5; r=ceil(y*(2^8-1)); %将小数转换为整数,ceil是向上取整。 fid = fopen('sin.coe','w'); %写到sin.coe文件,用来初始化sin_rom fprintf(fid,'MEMORY_INITIALIZATION_RADIX=10;\n'); fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=\n'); for i = 1:1:2^12 fprintf(fid,'%d',r(i)); if i==2^12 fprintf(fid,';'); else fprintf(fid,','); end if i%15==0 fprintf(fid,'\n'); end end fclose(fid); 生成方波matlab代码: + 查看代码 t=1:1:2^12; y=(t<=2047); r=ceil(y*(2^8-1)); fid = fopen('square.coe','w'); %写到square.coe,用来初始化rom_square fprintf(fid,'MEMORY_INITIALIZATION_RADIX=10;\n'); fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=\n'); for i = 1:1:2^12 fprintf(fid,'%d',r(i)); if i==2^12 fprintf(fid,';');
else fprintf(fid,','); end if i%15==0 fprintf(fid,'\n'); end end fclose(fid); 最后是生成三角波matlab + 查看代码 t=1:1:2^12; y=[0.5:0.5/1024:1-0.5/1024, 1-0.5/1024:-0.5/1024:0, 0.5/1024:0.5/1024:0.5]; r=ceil(y*(2^8-1)); fid = fopen('triangular.coe','w'); %写到triangular.coe,初始化三角波rom fprintf(fid,'MEMORY_INITIALIZATION_RADIX=10;\n'); fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=\n'); for i = 1:1:2^12 fprintf(fid,'%d',r(i)); if i==2^12 fprintf(fid,';'); else fprintf(fid,','); end if i%15==0 fprintf(fid,'\n'); end end fclose(fid); 生成coe文件后,接下来,就要调用ise的rom ip,进行rom的创建。这里,就不说明怎么创建rom了。可自行百度。 这下,我们的模块就都做好了。但是发现,我们没有编写波形选择的模块。输出的波形有三种,所以要选择输出是哪一种。 代码如下: + 查看代码 module wave_select( input [1:0] wave, //波形选择 input [7:0] sin_data, input [7:0] square_data, input [7:0] triangular_data,
output reg [7:0] dds_data ); parameter sin = 2'b00; parameter square = 2'b01; parameter triangular = 2'b10; always@(*) begin case(wave) sin: dds_data = sin_data; square: dds_data = square_data; triangular: dds_data = triangular_data; default: dds_data = sin_data; endcase end endmodule 接下来,就是将刚刚设计好的模块连接在一起即可。顶层top代码如下: + 查看代码 module dds_top( input clk, //clock input rst_n, //reset input [1:0] wave, //wave select 00 sin 01 square 10 triaangular input [11:0] k, //adjust frequency input [11:0] phase, //adjust phase output [7:0] dds_data //dds output data ); wire [11:0] result; //frequency add result wire [11:0] address; //phase add result wire [7:0] sin_data; //sin data output wire [7:0] square_data; //square data output wire [7:0] triangular_data; //triangular data output frequency_tiaozhi u1 ( .clk(clk), .rst_n(rst_n), .k(k), .result(result[11:0]) ); phase_tiaozhi u2
( .clk(clk), .rst_n(rst_n), .phase(phase[11:0]), .result(result[11:0]), .address(address[11:0]) ); wave_select u3 ( .wave(wave), .sin_data(sin_data[7:0]), .square_data(square_data[7:0]), .triangular_data(triangular_data[7:0]), .dds_data(dds_data[7:0]) ); loop_up_table_sin u4 ( .clk(clk), .address(address[11:0]), .sin_data(sin_data[7:0]) ); look_up_table_square u5 ( .clk(clk), .address(address[11:0]), .square_data(square_data[7:0]) ); look_up_table_triangular u6( .clk(clk), .address(address[11:0]), .triangular_data(triangular_data[7:0]) ); endmodule
文件结构如上所示: dds_top为顶层文件。U4到u6为正弦波,方波,三角波的rom例化模块。 接下来就是测试了: + 查看代码 module dds_top_tb; // Inputs reg clk; reg rst_n; reg [1:0] wave; reg [11:0] k; reg [11:0] phase; // Outputs wire [7:0] dds_data; // Instantiate the Unit Under Test (UUT) dds_top uut ( .clk(clk), .rst_n(rst_n), .wave(wave), .k(k), .phase(phase), .dds_data(dds_data) ); always #1 clk = ~clk; integer i; initial begin // Initialize Inputs clk = 0; rst_n = 0; wave = 0;
i = 0; k = {$random}%256; //随机产生频率控制字 phase = 0; // Wait 100 ns for global reset to finish #100 rst_n = 1; repeat(300) begin @(uut.address >3800) //。可以是引用模块内部信号 i = i+1; if(i==40) begin k = {$random}%256; end if(i==80) begin k = {$random}%256; end if(i==120) begin k = {$random}%256; wave = 1; end if(i==160) begin k = {$random}%256; end if(i==200) begin k = {$random}%256; wave = 2; end if(i==250) begin k = {$random}%256; end end end endmodule 用modelsim仿真。采用模拟显示波形。
分享到:
收藏