赞
踩
1.需求:利用FPGA与DDS技术的结合输出14位的双路波形,因为位数高能提高输出的精度。
首先,注意精度和速度的问题:DDS引用IP核的mif文件中,文本输出的波形纵坐标是由输出位数决定的(0~2^14),横坐标是采样点个数width(也叫深度)。因此AD驱动时钟只能决定输出频率越高(输出频率f=clk/width),不能说明速度越快,因此尽量满足采样时钟的情况下,提高采样精度是必须的。
一句话总结:FPGA的时钟是50M,AD驱动时钟要比这个高,才能获得相应高输出频率,而mif纵坐标与输出位数有关,输出位数越高,输出精度越高。
问题:mif文件在rom核里面必须是手动输入(否则rom的q无法输出数据);mif文件必须核工程文件在同一个目录下(否则rom无法识别mif文件)。
2.以quartus为平台的fpga代码(之前代码是没根据AD9767时序,硬件输出有问题,现在更改了):
- module DACout(
- input clk , //时钟
- input rst, //复位信号,低电平有效
-
-
-
- output da_clk1 , //DA(AD9767)驱动时钟
- output [13:0] da_data1, //输出给 DA 的数据
- output da_wrt1,
- output da_clk2 , //DA(AD9767)驱动时钟
- output [13:0] da_data2, //输出给 DA 的数据
- output da_wrt2
- );
-
- reg [8:0] rd_addr1; //rom的地址位数,也是采样点深度
- wire [13:0] rd_data1;//rom的q,输出给da的数据
-
- reg [8:0] rd_addr2;//rom的地址位数,也是采样点深度
- wire [13:0] rd_data2;//rom的q,输出给da的数据
-
-
- //*****************************************************
- //** main code
- //*****************************************************
-
- //数据 rd_data 是在 clk 的上升沿更新的,所以 DA 芯片在 clk 的下降沿锁存数据是稳定的时刻
- //而 DA 实际上在 da_clk 的上升沿锁存数据,所以时钟取反,这样 clk 的下降沿相当于da_clk 的上升沿
- assign da_clk1 = clk;
- assign da_wrt1 = clk;
-
- assign da_clk2 = clk;
- assign da_wrt2 = clk;
-
- assign da_data1 = rd_data1+rd_data2; //将读到的 ROM 数据赋值给 DA 数据端口,14位正弦和锯齿的叠加波
- assign da_data2 = rd_data2; // 幅度是10%锯齿波的32.55k正弦波
-
- //例化rom
- rom1 u_rom1(
- .address (rd_addr1),
- .clock (clk),
- .q (rd_data1)
- );
-
-
- rom2 u_rom2 (
- .address (rd_addr2),
- .clock (clk),
- .q (rd_data2)
- );
-
- //parameter
- //频率调节控制
- parameter FREQ_ADJ1 =8'd9765; //频率调节,FREQ_ADJ 的越大,最终输出的频率越低,范围 0~512
- //reg define
- reg [7:0] freq_cnt1 ; //频率调节计数器
- //频率调节计数器
- always @(posedge clk or negedge rst) begin
- if(rst == 1'b0)
- freq_cnt1 <= 8'd0;
- else if(freq_cnt1 == FREQ_ADJ1)
- freq_cnt1 <= 8'd0;
- else
- freq_cnt1 <= freq_cnt1 + 8'd1;
- end
-
- //读 ROM 地址
- always @(posedge clk or negedge rst) begin
- if(rst == 1'b0)
- rd_addr1 <= 8'd0;
- else begin
- if(freq_cnt1 == FREQ_ADJ1) begin
- rd_addr1 <= rd_addr1 + 8'd1;
- end
- end
- end
-
-
- //parameter
- //频率调节控制
- parameter FREQ_ADJ2 =8'd0; //频率调节,FREQ_ADJ 的越大,最终输出的频率越低,范围 0~1024
- //reg define
- reg [7:0] freq_cnt2 ; //频率调节计数器
- always @(posedge clk or negedge rst) begin
- if(rst == 1'b0)
- freq_cnt2 <= 8'd0;
- else if(freq_cnt2 == FREQ_ADJ2)
- freq_cnt2 <= 8'd0;
- else
- freq_cnt2 <= freq_cnt2 + 10'd1;
- end
-
-
-
- //读 ROM 地址
- always @(posedge clk or negedge rst) begin
- if(rst == 1'b0)
- rd_addr2 <= 8'd0;
- else begin
- if(freq_cnt2 == FREQ_ADJ2) begin
- rd_addr2 <= rd_addr2 + 8'd1;
- end
- end
- end
- endmodule
3.测试代码:
- `timescale 1 ns/ 1 ns
- module DACout_vlg_tst();
- // constants
- // general purpose registers
- //reg eachvec;
- // test vector input registers
- reg clk;
- reg rst;
- // wires
- wire da_clk1;
- wire da_clk2;
- wire [13:0] da_data1;
- wire [13:0] da_data2;
-
- // assign statements (if any)
- DACout i1 (
- // port map - connection between master ports and signals/registers
- .clk(clk),
- .da_clk1(da_clk1),
- .da_clk2(da_clk2),
- .da_data1(da_data1),
- .da_data2(da_data2),
- .rst(rst)
- );
- initial
- begin
- // code that executes only once
- // insert code here --> begin
- clk =0;
- rst =0;
- #20 rst =1;
- // --> end
- $display("Running testbench");
- end
- always
- // optional sensitivity list
- // @(event1 or event2 or .... eventn)
- begin
- // code executes for every event on sensitivity list
- // insert code here --> begin
- # 10 clk =~clk;
- //@eachvec;
- // --> end
- end
- endmodule
4.matlab对正弦波的编程:
- clc;
- clear;
- depth =512; %存储器的深度
- widths = 14; %数据宽度为10位
- % L = 0:2047; %把一个周期的正弦信号分为2048份
- % s =sin(2*pi *L/2048); %计算0 ~2*pi之间的sin值
- qqq = fopen('sine.mif','wt'); %使用fopen函数生成sine.mif
- fprintf(qqq, 'depth = %d;\n',depth); %使用fprintf打印depth = 2048;
- fprintf(qqq, 'width = %d;\n',widths); %使用fprintf打印width = 10;
- fprintf(qqq, 'address_radix = UNS;\n'); %使用fprintf打印address_radix = UNS; 表示无符号显示数据
- fprintf(qqq,'data_radix = UNS;\n'); %使用fprintf打印data_radix = UNS; 表示无符号显示数据
- fprintf(qqq,'content begin\n'); %使用fprintf打印content begin
- for(x = 1 : depth) %产生正弦数据
- fprintf(qqq,'%d:%d;\n',x-1,round(819.2*sin(2*pi*(x-1)/512)+819.2));
- fplot(@(x)round(819.2.*sin(2.*pi.*(x)./512)+819.2),[0,511]);
- end
- fprintf(qqq, 'end;'); %使用fprintf打印end;
- fclose(qqq);
5.功能仿真效果图(实际硬件输出噪声有点大,初步认为杜邦线连接原因,也可能示波器不行):
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。