您好,欢迎来到61ic! | [登录] [注册] 忘记密码 | 设为首页 帮助
 . 网站首页 . 业界新闻 . 设计中心 . 移动技术 . TI专栏 . ADI专栏 . FPGA专栏 . 代码工厂 . 官方商城 . 
 . 活动专区 . 新品快递 . 解决方案 . 前沿科技 . TI资源 . ADI资源 . FPGA资源 . 下载中心 . 产品展示 . 
加入收藏
付款方式
联系我们
您现在的位置: 61IC电子在线 >> FPGA专栏 >> Xilinx >> 正文
  [组图]FPGA实现dds(ISE实现)           ★★★ 【字体:
FPGA实现dds(ISE实现)
作者:梦想家    文章来源:梦想家    点击数:    更新时间:2014-7-10    
上次说了dds的原理,这次我们用FPGA来实现dds。

      因为dds在da之前都是数字器件,所以我们可以用FPGA来实现dds的前两个部分。

      首先要先规定一下:rom的地址输入是12位,输出时8位。

      对于第一部分:

                                           clip_image002

      这里看出,功能是将寄存器输出的值与频率控制字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

        第二部分:

                                     clip_image004

           可以看出,就是将第一部分的输出值加上一个相位控制字。所以代码也很简单:

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

              第三部分:

                                 clip_image006

           这里就只实现查找表,因为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

clip_image008

        文件结构如上所示:

       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仿真。采用模拟显示波形。

clip_image010

波形选择正弦波情况下,可以看到不同的k的值,输出的正弦波的频率是不一样的。K越大,输出频率越大。

clip_image012

方波也是和正弦波一样的效果。

clip_image014

      三角波也是一样的情况。

      大家可以将k的值改大一些,比如超过2000,大家观察下波形,看看会发生什么奇怪的现象。

      其实当k的值变得比较大的时候,会发现输出的波形已经失真了,所以k的值不能取很大。所以在程序中,k的位数其实是不需要12位的,同理相位phase也不需要12位的。

      将输出接一个告高速的da,就可以得到真正的模拟波形了。

文章录入:admin    责任编辑:admin 
  • 上一篇文章:

  • 下一篇文章: 没有了
  • 发表评论】【加入收藏】【告诉好友】【打印此文】【关闭窗口
    最新热点 最新推荐 相关文章
    Xilinx采用最新SDNet环境实现…
    (updated)在xilinx的FPGA系统…
    XILINX SERDES SI仿真中抖动…
    XILINX SERDES SI仿真中抖动…
    Xilinx ISE 12.4的简单应用
    ZED zynq板子到了,启动信息…
    Zynq交叉编译环境搭建
    ZED 完整启动信息,可以分析…
    Xilinx Zynq 操作系统的选择
    2012年行业展会研讨会中的XI…
      网友评论:(只显示最新10条。评论内容只代表网友观点,与本站立场无关!)
    站长:61 湘ICP备13001086号-2