参考:https://blog.csdn.net/weixin_45303812/article/details/123704440
新人第一次写文档,有错误的地方请大佬指点。
文档:Xilinx官网搜DDS
Configuration 可配置参数:
1.Configuration Options,有如下三种模式
Phase Generator and SIN/COS LUT (DDS):相位和sin和cos的数据都是IP核自己产生
Phase Generator only:只要相位输出
SIN/COS LUT only模式:只需要sin/cos模块输出,但此模式需要外部不断的输入累加的相位
2.System clock 系统时钟频率,同样也是采样率
3.Number of channels 通道数,本次用的是四通道,单通道设置为1
4.Mode of operation 不太懂,没涉及到,一般选择standard
5.Parameter selection分为两种模式,Hardware Parameter 和 System Parameter
Hardware Parameter模式没用过,看起来是设置输出的数据位宽和相位位宽就可以了。
System Parameter模式:
SFDR:无杂散动态范围
简单来说就是每增加6dB,数据位宽增加1位,16位宽,就是96dB
Frequency Resolution:频率分辨率
这个决定了数据的精度,用时钟频率除以2的n次方,n为位宽,如果是多通道,需要再除以通道数
比如我这里设置是32位宽,4通道,时钟是491.52MHz,491.52*10^6 / (2^32*4),那么可以算出来这个大约设置在0.029-0.06之间,这边写个0.04,然后左边可以看到数config_tdata的位宽变成32位,位宽更大这样输入的频率精度就更精确。
Implementation可配置参数:
1.Phase Increment Programmability:相位增量(即频率控制字)控制模式选择,一般选择固定或者可编程模式,如果是固定模式,可以通过第四个配置页Output Frequencies配置输出的频率,这里选择可编程模式,该模式下在valid有效时可对相位增量进行配置。
如图,也就是congfig配置这个,我们需要4通道,那么valid就需要持续四个时钟周期,然后每个时钟周期输入我们需要的tdata,这个参数是根据我们之前设置的精度和时钟来算。具体下面tb用到时讲。
2.Phase Offset Programmability:相位偏移量(即相位控制字)控制模式选择,暂时没用到,用法应该和频率控制字类似。
3.Output 输出: sin、cos、sin&cos字面意思,这里选sin&cos。
4.Has Phase Out :本实验不需要相位输出,不选。
其他的默认。
Detailed Implementation:设置输入输出的一些格式,需不需要ready,last等,根据需要选择即可。
Output Frequencies:输出频率,固定模式的时候设置这个,此处不需要。
最终配置如下:
代码部分:
直接调用IP核。
module dds_test(
input aclk ,
input aresetn ,
input s_axis_config_tvalid ,
output s_axis_config_tready ,
input [31: 0] s_axis_config_tdata ,
input s_axis_config_tlast ,
output m_axis_data_tvalid ,
input m_axis_data_tready ,
output [31: 0] m_axis_data_tdata ,
output m_axis_data_tlast ,
output event_s_config_tlast_missing ,
output event_s_config_tlast_unexpected
);
dds_compiler_0 dds_0 (
.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_tready(s_axis_config_tready), // output wire s_axis_config_tready
.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_tready(m_axis_data_tready), // input wire m_axis_data_tready
.m_axis_data_tdata(m_axis_data_tdata), // output wire [31 : 0] m_axis_data_tdata
.m_axis_data_tlast(m_axis_data_tlast), // output wire m_axis_data_tlast
.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
);
endmodule
tb部分,生成了四路正余弦IQ信号。
其中最重要的是上文提到的设置输出信号频率的参数设置。
以生成10M信号为例,我们的时钟采用的是491.52MHz,一共4路信号,那么实际采样率就是122.88MHz,我们设置的精度为32位,因此,10M信号的参数计算如下:
10/122.88 * 2^32 ≈ 32‘h 14D55555;
如果是-10M信号,由于频谱翻转,位置是122.88M-10M,计算如下
112.88/122.88 * 2^32 ≈ 32‘h EB2AAAAB
或者用2^32 - 10/122.88 * 2^32 ≈ 32‘h EB2AAAAB都可以,一个意思。
此外,DDS多通道的配置是,每个时钟周期VALID有效时,输入的参数才有效,因此多通道必须一个输入时钟一个参数,同时拉高valid,最后一个数据加last。
`timescale 1ns/1ps
module dds_tb();
reg aclk ;
reg aresetn ;
reg s_axis_config_tvalid ;
wire s_axis_config_tready ;
reg [31: 0] s_axis_config_tdata ;
reg s_axis_config_tlast ;
wire m_axis_data_tvalid ;
reg m_axis_data_tready ;
wire [31: 0] m_axis_data_tdata ;
wire m_axis_data_tlast ;
wire event_s_config_tlast_missing ;
wire event_s_config_tlast_unexpected ;
reg [1 : 0] cnt_chan ;
reg [31: 0] m_dout_0 ;
reg [31: 0] m_dout_1 ;
reg [31: 0] m_dout_2 ;
reg [31: 0] m_dout_3 ;
always @(posedge aclk) begin
if (!aresetn) begin
cnt_chan <= 2'b0;// reset
end
else begin
cnt_chan <= cnt_chan + 1'b1;
end
end
always @(posedge aclk) begin
if (cnt_chan == 2'b0) begin
m_dout_0 <= m_axis_data_tdata;
end
else if(cnt_chan == 2'b01)begin
m_dout_1 <= m_axis_data_tdata;
end
else if(cnt_chan == 2'b10)begin
m_dout_2 <= m_axis_data_tdata;
end
else if(cnt_chan == 2'b11)begin
m_dout_3 <= m_axis_data_tdata;
end
end
parameter fre_ch0 = 32'h14D55555 ,//10M
//fre_ch0 = 873813333 ,
fre_ch1 = 32'hEB2AAAAB ,//-10M
fre_ch2 = 32'h29AAAAAA ,//20M
fre_ch3 = 32'hD6555556 ;//-20M
initial aclk = 1'b0;
always #(500/491.52) aclk = ~aclk;
initial begin
aresetn = 1'b0;s_axis_config_tvalid=0;s_axis_config_tdata = 0;s_axis_config_tlast=0;m_axis_data_tready=1'b0;
#(1000*100/491.52) aresetn = 1'b1;
#(1000*100/491.52) s_axis_config_tvalid = 1;s_axis_config_tdata = fre_ch0;m_axis_data_tready=1'b1;
#(1000/491.52) s_axis_config_tvalid = 1;s_axis_config_tdata = fre_ch1;
#(1000/491.52) s_axis_config_tvalid = 1;s_axis_config_tdata = fre_ch2;
#(1000/491.52) s_axis_config_tvalid = 1;s_axis_config_tdata = fre_ch3;s_axis_config_tlast=1;
#(1000/491.52) s_axis_config_tvalid = 0;s_axis_config_tdata = 0;s_axis_config_tlast=0;
end
dds_test tb (
.aclk(aclk),
.aresetn(aresetn),
.s_axis_config_tvalid(s_axis_config_tvalid),
.s_axis_config_tready(s_axis_config_tready),
.s_axis_config_tdata(s_axis_config_tdata),
.s_axis_config_tlast(s_axis_config_tlast),
.m_axis_data_tvalid(m_axis_data_tvalid),
.m_axis_data_tready(m_axis_data_tready),
.m_axis_data_tdata(m_axis_data_tdata),
.m_axis_data_tlast(m_axis_data_tlast),
.event_s_config_tlast_missing(event_s_config_tlast_missing),
.event_s_config_tlast_unexpected(event_s_config_tlast_unexpected)
);
endmodule
仿真结果:
输出的四路信号分别为10M,-10M,20M,-20M的IQ信号,图片仿真的结果没把IQ拆出来,大概看个波形,可以看出得到了想要的结果。