标签:
图1 DDS原理框图
首先谈一下DDS(直接数字式频率合成器)的原理,如图1所示。 由相位累加器、ROM查找表、高速DAC、低通滤波器(LPF)组成。 设频率控制字的宽度为 N bits,则频率控制字的取值范围:0~2^N。 相位累加器是一个计数器,宽度一般要超过N+1位(抽样定理),在参考时钟Fref 的上升沿,计数器自增一次,步长为频率控制字对应的值。
相位累加器的输出 作为 R0M查找表的 “地址输入”,ROM查找表中存储了任意波形的 “ 幅值 - 相位 ” 对应表,相位累加器提供相位,ROM查找表根据这个相位输出对应的幅值。 设相位累加器的宽度为M位,即将2*pi 等分成 2^M 份,频率控制字为 K,即累加器步长为 K。则输出频率 Fout = Fref / (2^M) * K。 当K=1时,是最小输出频率,Fout = Fref / (2^M);其他输出频率都是这个频率的整倍数。
后面的高速DA和LPF就不是FPGA所做的事情了,就不赘述了。
下面我们通过VIVADO仿真一个简单的DDS工程:
1 建立一个VIVADO工程
2 设计相位累加器,Verilog HDL代码如下:
module PhaseAdder(
input clk,
input rst,
input [10:0]FreqCtrl, //频率控制字,相位累加步长
output [11:0]phase
);
reg [11:0]phase_reg = 0;
assign phase = phase_reg;
always@(posedge rst or posedge clk)
begin
if(rst)
phase_reg <= 12‘d0;
else
phase_reg <= phase_reg + FreqCtrl; //溢出循环
end
endmodule
说明:clk就是框图的Fref,可以连接FPGA板载晶振,或通过晶振分频后倍频后的时钟
rst是复位引脚,因为basys3板上的按键接的是下拉电阻,所以这边的复位信号是高电平有效
FreqCtrl是频率控制字,可以通过MCU提供,在程序中,作为计数器的累加步长。
phase是相位累加器的实时输出,作为ROM查找表的地址,因为本工程将正弦信号经4096点抽样,所以相位累加器的地址为12位(2^12 = 4096)
3 设计ROM查找表
通过Matlab将正弦信号作4096点抽样,并生成" .coe "文件(Quartus II是要求“ .mif ”文件,VIVADO是要求" .coe "文件,但最终还是要转换成“ .mif ”文件),
用于初始化ROM。
Matlab代码如下:
n = 0:4095 ;
yn = sin(2*pi/4096*n) ;
yn = round((yn+1)*2047);
plot(n,yn);
fid = fopen(‘rom.coe‘,‘wt‘);
fprintf(fid,‘memory_initialization_radix = 10;\nmemory_initialization_vector = ‘);
for i = 1 : 4096
if mod(i-1,16) == 0
fprintf(fid,‘\n‘);
end
fprintf(fid,‘%4d,‘,yn(i));
end
生成COE文件之后,在VIVADO软件中添加IP核,如下图,双击Distributed Memory Generator
出现下列界面,设置ROM的深度(抽样点数)和数据的宽度(根据高速DA的数据口宽度而定!!!)
然后点击第3个选项卡(RST & Initialization),添加刚才由matlab生成的COE文件,Radix可以选择 2 , 10 , 16,代表COE文件中的数据进制。设置完成后点击OK即可。
至此,我们已经成功 生成 并 初始化 了 ROM查找表,其vhd端口声明如下。我们可以在顶层文件中直接例化这个ROM查找表。
4 设计顶层文件,串接相位累加器,代码如下:
module DDS(
input clk,
input rst,
input [10:0]FreqCtrl,
output [11:0]waveform
);
wire [11:0]phase;
PhaseAdder u_PhaseAdder
(
.clk (clk),
.rst (rst),
.FreqCtrl (FreqCtrl),
.phase (phase)
);
DDS_ROM u_DDS_ROM
(
.a (phase[11:0]),
.spo (waveform)
);
endmodule
至此,我们整个的工程设计完毕,Sources结构图如下图所示:
RTL Analysis 如下:
5 添加仿真文件,编写testbench,代码如下:
module simu(
);
reg clk = 0;
always #5 clk <= ~clk; //100 MHz
reg rst = 0;
reg [10:0]FreqCtrl = 1;
wire [11:0]waveform;
DDS u_DDS
(
.clk (clk),
.rst (rst),
.FreqCtrl (FreqCtrl),
.waveform (waveform)
);
endmodule
点击 Run Simulation 观察波形图:可见频率控制字FreqCtrl = 1时,在40960ns中输出 1个 正弦周期。
修改频率控制字FreqCtrl = 2,重新仿真,如下图:可见频率控制字FreqCtrl = 2时,在40960ns中输出 2个 正弦周期。
实验完毕!谢谢阅读!
标签:
原文地址:http://blog.csdn.net/u011964923/article/details/51232670