FPGA学习之DDS

什么是DDS

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

调频原理(任意频率)

(1)事先波形数据存储在ROM里,每一个ROM地址对应一个波形数据(假设地址位宽8位,总共2^8=256)。DDR就是循环读取ROM里的数据。
(2)假设系统时钟为50MHZ,每个时钟地址+1,则获得频率   f o u t = 50 M h z 256 = 195.3 k h z   \ fout=\frac{50Mhz}{256}=195.3khz \,  fout=25650Mhz=195.3khz.因此可以产生两种想法来改变频率

	(a)改变采样时钟,即每两个时钟到来,地址+1,达到分频效果。
	(b)改变地址采样间隔,即每个时钟地址+2,到底倍频效果(采样定理的存在,采样点数减少,容易使波形失真)
缺点:只能达到整数倍频或者分数分频。

(3)改变地址位宽实现任意分频:将原来地址[0:7]拓展成32位,读取数据时,只读取与之对应的原8位所对应的值,这样可达到 50 M h z 2 3 2 = 0.01164 h z   . \frac{50Mhz}{2^32}=0.01164hz\,. 23250Mhz=0.01164hz.假设此时需要1KHZ的频率,则每个时钟来临时地址+1000/0.01164=85911。
总结公式为

  f o u t = f c l k 2 N ∗ K   \ fout=\frac{fclk}{2^N}*K\,  fout=2NfclkK
K为频率控制字,N为位宽。

调相原理

假设ROM地址为8位
  地 址 初 值 = 256 ∗ ( 初 始 相 位 / 360 ) \ 地址初值=256*(初始相位/360)  =256/360

代码讲解

matlab程序产生波形数据(vivado支持.coe文件)

x=linspace(0,2*pi,4096);		%一个周期采样点取4096(2^12)个,数据量
y=sin(x)+1;					   	%将函数平移到纵轴的正半轴。

​y1=ceil(y*(2^8-1))				%将数据转化为整数,方便ROM存储
								%matlab取整函数:
								%fix(x)向零取整
								%floor(x)向左取整
								%ceil(x)向右取整	

fid = fopen('cos_coe.coe','wt');			%生成cos函数coe文件
fprintf(fid,'MEMORY_INITIALIZATION_RADIX=10;\n');%并不明白为什么要加这两句话
fprintf(fid,'MEMORY_INITIALIZATION_VECTOR=\n');

for i = 1:1:2^12
    fprintf(fid,'%16.0f',y3(i));
    if i==2^12
        fprintf(fid,';');
    else
        fprintf(fid,',');
    end
    if i%15==0
        fprintf(fid,'\n');
    end
end
fclose(fid);

ROM IP设置

FPGA学习之DDS_第1张图片
FPGA学习之DDS_第2张图片
FPGA学习之DDS_第3张图片

dds_top代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2018/04/11 09:42:14
// Design Name: 
// Module Name: dds_top
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module dds_top(
    input           clk_50MHz, //输入时钟
    input           rst,//复位信号
    input [31:0]    freq_data,//频率控制字:就是多少个单位1,一般85899对应1KHz,
    input [11:0]    phase_data,//相位控制字
    output [9:0]    douta//输出
    );

//dds rom
reg     [31:0]  fcnt;//拓展地址
wire     [11:0]  addra;//十二位数据地址(原理中使用的是8位)
wire   [11:0]  cos;



always @(posedge clk_50MHz or negedge rst)begin
	if(!rst)
		fcnt <= 32'd0;
	else
		fcnt <= fcnt + freq_data;
end

assign addra = fcnt[31:20] + phase_data;//说白了就是每隔[19:0]次位才发生地址变化,否则输出地址addra保持不变

//sin
blk_mem_sin blk_mem_sin_inst (
  .clka(clk_50MHz),     // input wire clka
  .addra(addra),        // input wire [11 : 0] addra
  .douta(douta)           // output wire [11 : 0] douta
);
endmodule

dds仿真代码

`timescale 1ns / 1ps
//
// Company: 
// Engineer: 
// 
// Create Date: 2019/04/14 21:48:50
// Design Name: 
// Module Name: my_sim
// Project Name: 
// Target Devices: 
// Tool Versions: 
// Description: 
// 
// Dependencies: 
// 
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
// 
//


module my_sim(

    );
reg clk_50MHz=0;
reg rst=0;
reg [31:0] freq_data;
reg [11:0] phase_data;
wire [9:0] douta;
dds_top dds_top_u1(
    .clk_50MHz(clk_50MHz),
    .rst(rst),
    .freq_data(freq_data),
    .phase_data(phase_data),
    .douta(douta));
 initial 
 begin
 rst=0;
 #10
 rst=1;
freq_data=50000;
phase_data=0;
 end   
 always #10 clk_50MHz=~clk_50MHz;
endmodule

仿真结果

FPGA学习之DDS_第4张图片

你可能感兴趣的:(FPGA学习之DDS)