沐浴着帝都的热浪,不知不觉研究生生活就开始了,下午和晚上急匆匆地去赶着上课,上午就抽出时间完成实验室的培训任务。这次是要用DDS 的IP 核产生一个1k的正弦波,经历的4天的折腾,总算是整出来了。话不多说,马上进入正题。开发环境用的 vivado 2015.
1. 新建一个工程,这里就不详细展开了。
2. 生成DDS IP 核,
点击 IP catalog,
然后双击 DDS compiler,
选择 sin cos lut only , 输出数据设置为 8bit(后期AD的输入要求8bit),(记着这里的相位数据是16 bit, 后期算输出频率要用)
output selection 选择 sin(因为只需要正弦波),然后点击OK
3.编写顶层文件
因为开发板用的是 Xilinx 的Zedboard,它的系统频率为100MHz, 根据输出频率的计算公式,相位步进间隔= (fout / fdds_in) * 2^N (N 为前面相位的位宽),所以如果用系统的频率作为DDS的输入频率,相位步进间隔= (1k / 100M)* 2^16 = 0.65536,显然这在verilog 中无法实现,所以我们要设法使DDS IP 核的输入频率较小。这里我们通过对系统频率进行分频,获得 100KHz,作为DDS的输入频率,此时相位步进间隔为 655。
代码如下
module dds_top(
input rst_n,
input clk_100M,
output data_tvalid,
output [7:0] data_tdata
);
reg [9:0]cnt;
reg clk_100K;
always @(posedge clk_100M or negedge rst_n)begin
if(!rst_n)begin
cnt<=10'd0;
clk_100K<=0;
end
else if(cnt==10'd499)begin
cnt<=10'd0;
clk_100K <= ~clk_100K;
end
else begin
cnt<=cnt+1'b1;
end
end
reg [15:0] phase_tdata;
always @(posedge clk_100K or negedge rst_n)begin
if(!rst_n)begin
phase_tdata<=16'd0;
end
else if(phase_tdata < 16'b1111_1111_1111_1111)begin
phase_tdata <= phase_tdata + 10'd655; // (1k / 100k) * 2^16 =655
end
else begin
phase_tdata<=16'd0;
end
end
dds_compiler_0 dds_inst(
.aclk(clk_100K),
.s_axis_phase_tvalid(1'b1),
.s_axis_phase_tdata(phase_tdata),
.m_axis_data_tvalid(data_tvalid),
.m_axis_data_tdata(data_tdata)
);
endmodule
4.编写测试文件
module simu(
);
reg rst_n;
reg clk_100M;
wire data_tvalid;
wire [7:0] data_tdata;
dds_top dds_top_inst(
.rst_n(rst_n),
.clk_100M(clk_100M),
.data_tvalid(data_tvalid),
.data_tdata(data_tdata)
);
always #5 clk_100M = ~clk_100M;
initial begin
rst_n=0;
clk_100M=0;
#10;
rst_n=1;
#1000000;
$stop;
end
endmodule
仿真时注意要设置足够长的仿真时间,data_tdata 要设置为 模拟显示,格式是 有符号型。 仿真波形如下(漂亮的正弦波,哈哈!):
后记
一直关注EDN和面包板,这是我第一次在这里写博客,希望有个好的开端吧!
小浣熊6666 2023-5-28 23:30
eeNick 2017-7-13 01:05
本月写作操过5篇可以拿月度新人奖,抓紧机会
LoneSurvivor 2017-7-9 08:49
O(∩_∩)O谢谢!
ev711 2017-7-9 08:42
欢迎新博主
面包板博客大赛还在进行中,博文加上“博客大赛”标签就能参与活动哦