软件环境:vivado 2019.1 硬件平台:XC7Z020
对于自产生的正余弦数据源最常用的一般有两种办法,一种是通过matlab生成coe存到ram里,使用的时候播出来,另一种就是通过自带的DDS核来产生,今天就来说说DDS_Compiler这个IP核的用法和需要注意的事项,以下内容参考手册pg141,喜欢原汁原味儿的朋友可以下载查阅。
核内部结构如下所示。
接下来就对DDS参数配置相关含义进行说明。
parameter selection中,共有两项可以选择, 分别为system parameters和hardware parameters,当选择不同参数配置方式时,下方的配置项会有所不同,主要是为了方便更关心频域方面的系统设计师或者更关心硬件部分的设计工程师而设置。
当选择system parameters时,下方参数包括动态杂散范围、频率分辨率和添加噪声形状,其中,SFDR与所选噪声形状有关,其与输出位宽之间的关系如下表所示:
频率分辨率这里有个例子,如果系统时钟是120MHz,相位累加器位宽为32位,那么,对应的频率分辨率为0.0279396Hz。
当parameter selection选择为hardware parameters时,下方参数变为数据位宽和相位位宽。
接下来是第二页的配置项。
首先是相位增量和相位偏移,也就是手册上说的PINC和POFF,none和fixed自然不用说,为不使用和固定值,当选择programmable时,左侧会多出s_axis_config配置口,当选择streaming时,左侧会多出s_axis_phase配置口,接下来会主要对PINC、POFF以及这两个配置口进行说明。
PINC即相位累加器在每次系统时钟到来时的增加量,当系统时钟为100MHz,输出位宽为18,此时如果想输出19M的波形,则PINC增量计算方法如下:
由于PINC的值只能为正数,所以当PINC为49807时,当前DDS的实际输出频率为:
至于POFF,虽然手册上并未直接给出计算公式,但是由PINC的计算方法以及仿真,大致也能够推出计算方法,这里假设想要偏移的角度值为:
最终在第n个系统时钟周期输出的相位为:
解释完了PINC与POFF,接下来对s_axis_config与s_axis_phase配置口的要求进行说明。首先是在选择了programmable之后的s_axis_config通道:
当包含有多个通道时,依次进行通道配置,且在最后一个通道配置时,置位tlast信号,此时所有的配置才能被视为有效,否则如上图中第一次配置传输,在倒数第二个通道配置时就拉高了tlast信号,导致unexpected信号与missing信号置位,配置失败。
当phase_width为11时,配置通道的数据格式如下所示:
在选择了streaming之后的s_axis_phase通道,每一个valid有效的phase_data输入,都会对应一个data的输出,可用于动态调整输出波形频率,当phase_width为11时,phase_data格式如下:
说完了PINC、POFF这些要注意的之后,说下数据输出格式,同样是在输出11位宽数据条件下,其中<<<<<<是符号位的扩充:
接下来有关于配置页的其余项,我用的都是默认的参数:
在最后的summary中可以看到配置及资源的使用情况:
接下来仿真下试试,仿真文件如下。
module dds_tb();
reg clk;
reg rst_n;
reg [31:0] phase_pinc;
reg [31:0] phase_poff;
reg phase_tvalid;
reg [31:0] phase_tdata;
wire data_valid;
wire [15:0] cos_out;
wire [15:0] sin_out;
wire phase_valid;
wire [15:0] phase_out;
initial begin
#0 clk = 0;
rst_n = 1'b0;
phase_pinc = 32'd0;
phase_poff = 32'd0;
phase_tvalid = 1'b0;
phase_tdata = 32'd0;
#1000 rst_n = 1'b1;
phase_tvalid = 1'b1;
phase_pinc = 32'd1311;
phase_poff = 32'h0000_0000;
phase_tdata = phase_poff + phase_pinc;
end
always #5 clk = ~clk;
dds_compiler_0 dds_compiler_0 (
.aclk(clk), // input wire aclk
.aresetn(rst_n), // input wire aresetn
.s_axis_phase_tvalid(phase_tvalid), // input wire s_axis_phase_tvalid
.s_axis_phase_tdata(phase_tdata), // input wire [31 : 0] s_axis_phase_tdata
.m_axis_data_tvalid(data_valid), // output wire m_axis_data_tvalid
.m_axis_data_tdata({sin_out,cos_out}), // output wire [31 : 0] m_axis_data_tdata
.m_axis_phase_tvalid(phase_valid), // output wire m_axis_phase_tvalid
.m_axis_phase_tdata(phase_out) // output wire [15 : 0] m_axis_phase_tdata
);
endmodule
sys_clk 100M,输出2M,仿真结果如下。
接下来将POFF设置为16‘h’4000_0000使相位偏移90°后,仿真结果如下。
实际上板结果如下,通过实时调整PINC值,来动态调整输出波形频率,从2M调整到10M。
最后,补充说明一下:
1.根据采样定律,输出波形的频率最好不要大于输入时钟的1/2,否则输出频率不正确
2.由仿真的结果来看, 在POFF为0,输出data_tvalid有效时对应的第一个点,并不是sin波形起始时的0点,只是一个偶然的小发现,对于连续波形应该没什么影响