1.IP设置里面的系统频率为DDS的输入频率。可以使testbench的频率,也可以是分频后的频率
2.相位步进间隔= (fout / fdds_in) * 2^N (N 为上图中相位的位宽,fdds_in为上图中的0.1KHz),也就是根据需要的输出频率,计算出步进间隔,比如步进间隔655,将其转换为二进制填入下图IP核设置中。
注意:(1.)在之前的程序实例中,例如,相位累加器的宽度是8bit,前4位作为RAM地址,也即三角函数的相位,RAM中存储三角函数的采样点数值。而在此处,相位累加器16bit即三角函数的相位,没有所谓的前几位此情况。
(2.)在之前的程序实例中,相位累加器的累加频率是采样频率,此处累加频率就是上图中每个通道的Fs也等于dds的系统频率。
3.下图中的DSP48 USE为fpga专有的高性能逻辑资源,如果用的最少,那么近就占用LUT逻辑资源多。
**实例:**此处采用testbench产生1MHz频率时钟,分频获得100KHz作为DDS时钟频率。DDS输出为1KHz正弦波,相位步进655,转为二进制为1010001111.
**代码:
module dds_ip(
input wire sclk,
input wire rst_n,
output wire [7:0] o_wave_1k
);
reg [8:0] div_cnt;
reg clk_ip;
//reg div_flag;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
div_cnt <= 'd0;
else if (div_cnt == 'd4)
div_cnt <= 'd0;
else
div_cnt <= div_cnt + 1'b1;
always @(posedge sclk or negedge rst_n)
if(rst_n == 1'b0)
clk_ip<= 1'b0;
else if (div_cnt == 'd4)
clk_ip<= ~clk_ip;
dds_ip_1m dds_ip_1m_1k_inst (
.clk(clk_ip), // input clk
.rdy(), // output rdy
.cosine(), // output [7 : 0] cosine
.sine(o_wave_1k) // output [7 : 0] sine
);
endmodule
testbench代码:
`timescale 1ns/1ns
module tb_dds_ip;
reg sclk;
reg rst_n;
wire [7:0] o_wave;
initial begin
sclk = 0;
rst_n = 0;
#1000;
rst_n = 1;
end
always #500 sclk <= ~sclk;
dds_ip dds_ip_inst(
.sclk(sclk),
.rst_n(rst_n),
.o_wave_1k(o_wave)
);
endmodule
使用ISE调用modelsim仿真结果:
可以看出输出频率为1KHz
附:一开始直接使用modelsim,通过rundo脚本文件仿真,但总是显示缺少定义,仿真错误。估计是需要查阅相关tcl文件,将其中部分语句写入rundo文件才可。所以最终放弃,直接使用ISE调用modelsim仿真,成功了。
参考链接:
使用ISE DDS IP核产生正弦信号
重温FPGA设计流程(五、调用DDS IP核产生正弦波)
待学习链接:
FPGA设计心得(9)基于DDS IP核的任意波形发生器设计
ISE14.7无法生成DDS IP核的解决办法