FPGA学习笔记. DDS

DDS原理

  直接数字式频率合成器(Direct Digital Synthesizer)

频率计算公式

  Fout = FW * Fclk / 2^N

Fout 输出频率, Fw 频率控制字, N 位数 精度 Fclk / 2^N

 

设计思路

设置一个计数cnt作累加,Fw频率控制字,作为计数步长。

时钟clk下,cnt <= cnt + Fw.

设输入时钟是100mHz,目标Fo为115200Hz,计数器为32位,据上面的公式可以得出

Fw = Fo * 2^32  /  Fc = 115200 * 2^32 / (100*10^6) = 4947802.3249992

取整 Fw = 4947802,

占空比为50%,cnt <= 2^N ,Fo = 0 ; cnt > 2^N ,Fo = 1。

添加一个block menery IP,存放 正弦波相位-幅度 表,由相位累加来查询地址。

 

生成COE文件

位宽32bit 深度2^12,code

clear;
close all;
%%
width = 32; %data width
N = 12;     %addr witdh
depth = 2^N;%memery depth
x = linspace(0,2*pi,depth);
y_sin = sin(x)+1;
y_sin_q=round(y_sin*(2^(width-1)));
fid = fopen('CosWaveWid32Def2e12.coe','w');
%write header
fprintf(fid,'MEMORY_INITIALIZATION_RADIX=16;\n');
fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=\n');
%write data
if(fid>0)
    fprintf(fid,'%x,\n',y_sin_q);
end
fclose(fid);

 

verilog 程序

累加与查询地址

 1 /*
 2 fc = 100MHz
 3 fo = 1kHz 
 4 N  = 32 (width)
 5 fw = (fo * 2^N) / fc = 42949.67296 => 42950 
 6 
 7 */
 8 module DdsTopV
 9 #(
10     parameter COUNTWIDTH = 32,
11     parameter FW = 32'd429497 
12 )
13 (
14     input  wire clk,
15     input  wire rst_n,
16     output reg  clk_out,
17 //    output wire [11:0] addr,
18     output wire [31:0] phase,
19     output wire [31:0] sin_o
20     );
21 
22 //wire [31:0] phase;
23 wire [11:0] addr;
24 reg [COUNTWIDTH-1:0] cnt;
25  
26 //相位累加
27 always @(posedge clk or posedge rst_n) 
28 begin
29     if(!rst_n)
30         cnt <= 0;
31     else
32         cnt <= cnt + FW;  //计数器步长FW
33 end
34 //clk_out 
35 always @(posedge clk or posedge rst_n)
36 begin
37     if(!rst_n)
38         clk_out <= 1'b0;
39     else if(cnt < 32'h7FFF_FFFF)
40         clk_out <= 1'b0;
41     else
42         clk_out <= 1'b1;
43 end   
44 
45 assign phase = cnt;
46 assign addr = {phase[31:20]};
47 
48 blk_mem_gen_0 blk_mem_gen_0(
49     .clka(clk),
50     .addra(addr),
51     .douta(sin_o)
52     );
53 
54 endmodule

TestBench

 1 module testbench();
 2 
 3 reg clk;
 4 reg rst_n;
 5 wire clk_out;
 6 //wire [11:0] addr;
 7 wire [31:0] phase;
 8 wire [31:0] sin_o;
 9 
10 
11 /*
12 Fo = 115200Hz
13 Fw = 4947802.3
14 */
15 DdsTopV 
16 #(
17 //    .COUNTWIDTH(32'd32),
18     .FW(32'd4947802) 
19 )
20 uut
21 (
22     .clk(clk),
23     .rst_n(rst_n),
24     .phase (phase),
25 //    .addr(addr),
26     .clk_out(clk_out),
27     .sin_o(sin_o)
28     );
29 
30     initial begin
31     clk = 0;
32     rst_n = 0;
33     #15 rst_n=1; 
34     end
35     
36     always  #10 clk=~clk; 
37 
38 endmodule

 

设置Block Memery

 

 

仿真结果

 

via

https://www.cnblogs.com/christsong/p/5536995.html

posted @ 2018-11-30 16:51  写蛋炒饭的Bug  阅读(722)  评论(0编辑  收藏  举报