之前的文章对dds ip 的结构、精度、参数、接口进行了详细的说明,本文通过例化仿真对该IP的实际使用进行演示。本文例化固定模式和可配置模式两种模式分别例化ip并仿真,说明该IP的应用。
1、固定模式:
该模式下IP的参数设置如下图,时钟频率设置为100Mhz,两个通道时分复用,SFDR 60dB.
然后相位、相位偏差全部选择固定模式,
输出频率配置为1Mhz和2Mhz:
设置完之后再summary这里可以看到该IP的实现细节,输出位宽10bit,2ch,没ch的时钟速率是50Mhz,使用一个M18K的BROM实现查找表等等的一些细节。
在additional summary里边可以看到相应的频率控制字和实际精度,因为当前设置的时标准模式不是栅格(rasterized)模式,所以输出是有频偏的。
上述设置生成的IP端口如下,输入端口为时钟复位信号,输出sin cos和phase值。
dds_compiler_0 your_instance_name (
.aclk(aclk), // input wire aclk
.aresetn(aresetn), // input wire aresetn
.m_axis_data_tvalid(m_axis_data_tvalid), // output wire m_axis_data_tvalid
.m_axis_data_tdata(m_axis_data_tdata), // output wire [31 : 0] m_axis_data_tdata
.m_axis_phase_tvalid(m_axis_phase_tvalid), // output wire m_axis_phase_tvalid
.m_axis_phase_tdata(m_axis_phase_tdata) // output wire [31 : 0] m_axis_phase_tdata
);
这个IP的tb就非常简单了,只有提供时钟复位即可,但是输出时时分复用的,所以tb对输出信号进行了处理将两路输出分开了,方便波形观察,如下:
`timescale 1ns/100ps
module tb_dds_fix_normal ;
reg aclk = 'd0;
reg aresetn = 'd0;
wire m_axis_data_tvalid ;
wire [31 : 0] m_axis_data_tdata ;
wire m_axis_phase_tvalid ;
wire [31 : 0] m_axis_phase_tdata ;
always #1 aclk = ~aclk;
initial
begin
#100;
aresetn =1'b1;
end
dds_compiler_0 dds_compiler_0 (
.aclk (aclk ), // input wire aclk
.aresetn (aresetn ), // input wire aresetn
.m_axis_data_tvalid (m_axis_data_tvalid ), // output wire m_axis_data_tvalid
.m_axis_data_tdata (m_axis_data_tdata ), // output wire [31 : 0] m_axis_data_tdata
.m_axis_phase_tvalid (m_axis_phase_tvalid ), // output wire m_axis_phase_tvalid
.m_axis_phase_tdata (m_axis_phase_tdata ) // output wire [31 : 0] m_axis_phase_tdata
);
reg S_ch0_valid ;
reg [15:0] S_ch0_cos ;
reg [15:0] S_ch0_sin ;
reg [31:0] S_ch0_pha ;
reg [15:0] S_ch1_cos ;
reg [15:0] S_ch1_sin ;
reg [31:0] S_ch1_pha ;
always @(posedge aclk)
if(!aresetn)
S_ch0_valid <= 1'b1;
else if(m_axis_data_tvalid)
S_ch0_valid <= ~S_ch0_valid;
always @(posedge aclk)
if(S_ch0_valid)
begin
S_ch0_cos <= m_axis_data_tdata[15:0] ;
S_ch0_sin <= m_axis_data_tdata[31:16] ;
S_ch0_pha <= m_axis_phase_tdata ;
S_ch1_cos <= S_ch1_cos ;
S_ch1_sin <= S_ch1_sin ;
S_ch1_pha <= S_ch1_pha ;
end
else
begin
S_ch0_cos <= S_ch0_cos ;
S_ch0_sin <= S_ch0_sin ;
S_ch0_pha <= S_ch0_pha ;
S_ch1_cos <= m_axis_data_tdata[15:0] ;
S_ch1_sin <= m_axis_data_tdata[31:16] ;
S_ch1_pha <= m_axis_phase_tdata ;
end
endmodule
仿真波形如下:
2、相位可配置模式:
该模式将相位偏差和相位步进设置为axi配置模式,如下图,其它配置保持不变:
生成的端口如下,该模式下增加了config端口,用于phase信息的配置:
dds_compiler_cfg your_instance_name (
.aclk(aclk), // input wire aclk
.aresetn(aresetn), // input wire aresetn
.s_axis_config_tvalid(s_axis_config_tvalid), // input wire s_axis_config_tvalid
.s_axis_config_tdata(s_axis_config_tdata), // input wire [31 : 0] s_axis_config_tdata
.s_axis_config_tlast(s_axis_config_tlast), // input wire s_axis_config_tlast
.m_axis_data_tvalid(m_axis_data_tvalid), // output wire m_axis_data_tvalid
.m_axis_data_tdata(m_axis_data_tdata), // output wire [31 : 0] m_axis_data_tdata
.m_axis_phase_tvalid(m_axis_phase_tvalid), // output wire m_axis_phase_tvalid
.m_axis_phase_tdata(m_axis_phase_tdata), // output wire [15 : 0] m_axis_phase_tdata
.event_s_config_tlast_missing(event_s_config_tlast_missing), // output wire event_s_config_tlast_missing
.event_s_config_tlast_unexpected(event_s_config_tlast_unexpected) // output wire event_s_config_tlast_unexpected
);
这时,需要对tb进行相应的修改,增加config的配置,如下,新增一个11bit的计数器,计满后对两个通道的phase值进行翻倍:
reg aclk = 'd0;
reg aresetn = 'd0;
reg s_axis_config_tvalid= 'd0;
reg [31 : 0] s_axis_config_tdata = {{16'd1310},{16'd1310}};
reg s_axis_config_tlast = 'd0;
wire m_axis_data_tvalid ;
wire [31 : 0] m_axis_data_tdata ;
wire m_axis_phase_tvalid ;
wire [15 : 0] m_axis_phase_tdata ;
always #1 aclk = ~aclk;
initial
begin
#100;
aresetn =1'b1;
end
reg [10:0] S_clk_cnt ;
always @(posedge aclk)
if(!aresetn)
S_clk_cnt <= 'd3;
else
S_clk_cnt <= S_clk_cnt + 'd1;
always @(posedge aclk)
s_axis_config_tvalid <= ((S_clk_cnt==0)||(S_clk_cnt==1));
always @(posedge aclk)
s_axis_config_tlast <= (S_clk_cnt==1);
always @(posedge aclk)
if(s_axis_config_tvalid)
s_axis_config_tdata <= s_axis_config_tdata + s_axis_config_tdata;
dds_compiler_cfg your_instance_name (
.aclk (aclk ), // input wire aclk
.aresetn (aresetn ), // input wire aresetn
.s_axis_config_tvalid (s_axis_config_tvalid ), // input wire s_axis_config_tvalid
.s_axis_config_tdata (s_axis_config_tdata ), // input wire [31 : 0] s_axis_config_tdata
.s_axis_config_tlast (s_axis_config_tlast ), // input wire s_axis_config_tlast
.m_axis_data_tvalid (m_axis_data_tvalid ), // output wire m_axis_data_tvalid
.m_axis_data_tdata (m_axis_data_tdata ), // output wire [31 : 0] m_axis_data_tdata
.m_axis_phase_tvalid (m_axis_phase_tvalid ), // output wire m_axis_phase_tvalid
.m_axis_phase_tdata (m_axis_phase_tdata ), // output wire [15 : 0] m_axis_phase_tdata
.event_s_config_tlast_missing (event_s_config_tlast_missing ), // output wire event_s_config_tlast_missing
.event_s_config_tlast_unexpected (event_s_config_tlast_unexpected) // output wire event_s_config_tlast_unexpected
);
仿真结果如下如,可以看到随着phase步进的不断累加,两个通道的输出频率也在不断增加.
好了,本文就写的这里,希望通着这一系列的文章能帮助大家深入理解并正确使用DDS IP,详细的仿真过程可参考B站视频。
全部0条评论
快来发表一下你的评论吧 !