quartus II 与AD9767(双路14位输出)的fpga主要代码,测试代码,matlab调幅度代码以及遇到的问题。

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.功能仿真效果图(实际硬件输出噪声有点大,初步认为杜邦线连接原因,也可能示波器不行):

  • 8
    点赞
  • 14
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值