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