前言
本实验是带FIFO的ADDA实验,具体的要求、注意事项以及开发流程如下。
带FIFO的ADDA实验流程 |
1.本实验在DAC FIFO实验的基础上完成。
2.把DAC输出模拟信号自环给ADC的模拟输入。
3.ADC使用25MHz的时钟信号采样。
4.ADC的输出的数据信号,用ILA抓取观察波形。
5.用VIO配置频率字,分别生成1MHz和3MHz的DDS正弦波形,用Matlab分析频谱,验证频率的正确性。
本实验是在DAC FIFO实验的基础上完成的,实验中与之相关的内容可以参考博文:ZYNQ FPGA实验——DAC FIFO实验。
一、IP核的添加
本实验中AXI4-Stream Data FIFO IP核、DDS IP核和VIO IP核的添加与DAC FIFO实验相同,这里不再详细说明。PLL IP核和 ILA IP核的添加稍有不同,具体见下。
PLL IP核在添加时多添加一个25MHz的输出时钟,因为本实验中ADC使用25MHz的时钟信号进行采样。
本实验添加一个 ILA,设置5个探针,分别用来监测频率字控制位(2位)、dds的输出(8位)、fifo的输出(8位)、ad接收端(8位)以及da接收端(8位)。
各个探针位数的设置如下图所示。
二、编写测试程序
本实验的文件目录结构如下图所示。
在文件fifo_adda.v中写入的代码如下。
//该代码参考自博客:vivado VIO IP的用法、DAC FIFO实验,以及正点原子官方文件,见总结
`timescale 1ns / 1ps
module fifo_adda(
input sys_clk, //系统时钟 50MHz T=20ns
input rst_n, //系统复位
//DA芯片接口
output da_clk, //DA(AD9708)驱动时钟,最大支持125Mhz时钟
output [7:0] da_data, //输出给DA的数据
//AD芯片接口
input [7:0] ad_data, //AD输入数据
//模拟输入电压超出量程标志(本次试验未用到)
//input ad_otr , //0:在量程范围 1:超出量程
output ad_clk //AD(AD9280)驱动时钟,最大支持32Mhz时钟
);
//----------VIO按键控制频率控制字(key_PINC)--------------//
wire [1:0] key_PINC;
vio_0 vio_0_inst (
.clk(sys_clk), // input wire clk
.probe_out0(key_PINC) // output wire [1 : 0] probe_out0
);
//---------------信号频率控制模块--------------//
wire [23:0] Fword ; //频率字
Fword_set Fword_set_inst(
//input
.clk (sys_clk),
.rst_n (rst_n),
.key_PINC (key_PINC),
//output
.Fword (Fword)
);
//---------------PLL模块--------------//
wire clk_100M;
clk_wiz_0 pll_inst
(
// Clock out ports
.clk_out1(clk_100M), // output clk_out1
.clk_out2(ad_clk), // output clk_out2
// Status and control signals
.reset(~rst_n), // input reset
.locked(locked), // output locked
// Clock in ports
.clk_in1( sys_clk) // input clk_in1
);
//---------------DDS模块--------------//
//input
wire [0:0] fre_ctrl_word_en;
wire m_axis_data_tready;
wire m_axis_phase_tready;
//output
wire [0:0] m_axis_data_tvalid;
wire [7:0] m_axis_data_tdata;
wire [0:0] m_axis_phase_tvalid;
wire [23:0] m_axis_phase_tdata;
wire [0:0] s_axis_config_tready;
assign fre_ctrl_word_en=1'b1;
//---------------AXIS模块--------------//
//output
wire fifo_s_axis_tready;
wire fifo_m_axis_tvalid;
wire da_m_axis_tready;
wire [7:0] fifo_m_axis_tdata;
wire [31:0] fifo_axis_wr_data_count;
wire [31:0] fifo_axis_rd_data_count;
assign s_axis_aresetn = 1'b1;
//例化DDS
dds_compiler_0 dds_compiler_0_inst (
.aclk(clk_100M), // input wire aclk 给DDS的工作频率为100MHz
.s_axis_config_tvalid(fre_ctrl_word_en), // input wire s_axis_config_tvalid
.s_axis_config_tready(s_axis_config_tready), // output wire s_axis_config_tready
.s_axis_config_tdata(Fword), // input wire [23 : 0] s_axis_config_tdata
.m_axis_data_tvalid(m_axis_data_tvalid), // output wire m_axis_data_tvalid
.m_axis_data_tready(fifo_s_axis_tready), // input wire m_axis_data_tready
.m_axis_data_tdata(m_axis_data_tdata), // output wire [15 : 0] m_axis_data_tdata
.m_axis_phase_tvalid(m_axis_phase_tvalid), // output wire m_axis_phase_tvalid
.m_axis_phase_tready(fifo_s_axis_tready), // input wire m_axis_phase_tready
.m_axis_phase_tdata(m_axis_phase_tdata) // output wire [23 : 0] m_axis_phase_tdata
);
//例化AXIS
axis_data_fifo_0 axis_data_fifo_inst (
.s_axis_aresetn(s_axis_aresetn), // input wire s_axis_aresetn
.s_axis_aclk(clk_100M), // input wire s_axis_aclk 给100MHz
.s_axis_tvalid(m_axis_data_tvalid), // input wire s_axis_tvalid
.s_axis_tready(fifo_s_axis_tready), // output wire s_axis_tready
.s_axis_tdata(m_axis_data_tdata), // input wire [7 : 0] s_axis_tdata
.m_axis_aclk(sys_clk), // input wire m_axis_aclk 给系统时钟频率50MHz
.m_axis_tvalid(fifo_m_axis_tvalid), // output wire m_axis_tvalid
.m_axis_tready(s_axis_config_tready), // input wire m_axis_tready
.m_axis_tdata(fifo_m_axis_tdata), // output wire [7 : 0] m_axis_tdata
.axis_wr_data_count(fifo_axis_wr_data_count), // output wire [31 : 0] axis_wr_data_count
.axis_rd_data_count(fifo_axis_rd_data_count) // output wire [31 : 0] axis_rd_data_count
);
//DA数据发送
da_wave_send u_da_wave_send(
.clk (sys_clk),
.rst_n (rst_n),
.rd_data (fifo_m_axis_tdata),
.da_clk (da_clk),
.da_data (da_data),
.da_m_axis_tready (da_m_axis_tready)
);
//ILA采集数据
ila_0 ila_0_inst (
.clk(sys_clk), // input wire clk
.probe0(key_PINC), // input wire [1:0] probe0
.probe1(m_axis_data_tdata), // input wire [7:0] probe1
.probe2(fifo_m_axis_tdata), // input wire [7:0] probe2
.probe3(da_data), // input wire [7:0] probe3
.probe4(ad_data) // input wire [7:0] probe4
);
endmodule
文件Fword_set.v中写入的代码如下。
//该代码来自博客:vivado VIO IP的用法,见总结
`timescale 1ns / 1ps
module Fword_set(
input clk ,
input rst_n ,
input [1:0] key_PINC ,
output reg [23:0] Fword
);
always@(*)
begin
case(key_PINC)
0: Fword <= 'h51eb; //1Mhz 20971.52 取整20971
1: Fword <= 'ha3d7; //2Mhz 41943.04 取整41943
2: Fword <= 'hf5c2; //3Mhz 62914.56 取整62914
//3: Fword <= 'h33333; //10Mhz 209715.2 取整209715
endcase
end
endmodule
文件da_wave_send.v中写入的代码如下。
//本代码来自正点原子
module da_wave_send(
input clk , //时钟
input rst_n , //复位信号,低电平有效
input [7:0] rd_data, //读出的数据
//DA芯片接口
output da_clk , //DA(AD9708)驱动时钟,最大支持125Mhz时钟
output [7:0] da_data, //输出给DA的数据
output da_m_axis_tready // 由于DAC的工作频率小于DDS工作频率,所以DAC接口控制器给FIFO的RDY信号应该一直为高
);
//parameter 频率调节控制
parameter FREQ_ADJ = 8'd5; //频率调节,FREQ_ADJ的值越大,最终输出的频率越低,范围0~255
//reg define
reg [7:0] freq_cnt ; //频率调节计数器
//数据rd_data是在clk的上升沿更新的,所以DA芯片在clk的下降沿锁存数据是稳定的时刻
//而DA实际上在da_clk的上升沿锁存数据,所以时钟取反,这样clk的下降沿相当于da_clk的上升沿
assign da_clk = ~clk;
assign da_data = rd_data; //将读到的数据赋值给DA数据端口
assign da_m_axis_tready = 1'b1;
//频率调节计数器
always @(posedge clk or negedge rst_n) begin
if(rst_n == 1'b0)
freq_cnt <= 8'd0;
else if(freq_cnt == FREQ_ADJ)
freq_cnt <= 8'd0;
else
freq_cnt <= freq_cnt + 8'd1;
end
endmodule
本实验中管脚分配与ZYNQ FPGA实验——DAC FIFO实验完全相同,这里不再赘述。
三、连接开发板测试
连接开发板,点击Generate Bitstream生成比特流文件,将其下载到开发板上。
这时候会出现hw_ila_1和hw_vios两个窗口,其中hw_vios窗口是用来调节频率字的,其中00对应1MHz,01对应2MHz,10对应3MHz,hw_ila_1窗口是用来查看输出波形的。
1MHz输出频率在ILA下观察到的输出波形如下图所示。
2MHz输出频率在ILA下观察到的输出波形如下图所示。
3MHz输出频率在ILA下观察到的输出波形如下图所示。
通过上面各频率输出图可以看出,信号ad_data_IBUF[7:0]输出的正弦波不是特别的规则,但是大体的轮廓还是比较接近正弦波。
四、Matlab中分析输出波形
将上面ILA下的不同输出频率所对应的正弦波导出为CSV文件,然后在Matlab中依次进行分析。
新建脚本文件并写入如下代码。
%这是1MHz的代码,2MHz和3MHz的代码稍加改动即可
csv_row8 = iladata1{
:,8}; %取出csv文件中的第八列数据
fs=50000000; %设置采样频率为50MHz
N=4096; %采样点
n=0:N-1;
t=n/fs;
f=n*fs/N; %频率序列
subplot(2,1,1);plot(t,csv_row8);grid on;title('1MHz-时域波形');
y=abs(fft(csv_row8,N));
subplot(2,1,2);plot(f,y,'r');grid on;title('1MHz-频谱');
输出频率为1MHz的运行结果如下图所示。
输出频率为2MHz的运行结果如下图所示。
输出频率为3MHz的运行结果如下图所示。
通过Matlab验证ILA抓取的ADC输出数据可知,各波形所对应的频率都是正确的。
总结
以上就是ZYNQ FPGA实验——带FIFO的ADDA实验的所有内容了,本实验是在ZYNQ FPGA实验——DAC FIFO实验的基础上进行的,之前已经做过AD/DA测试实验,该实验就是在DAC FIFO实验的基础上加入ADDA模块,进一步验证带有FIFO的AD/DA测试结果。本文中所参考的文章都在下面进行了罗列。
参考资料:
正点原子–course_s1_ZYNQ那些事儿-FPGA实验篇V1.06.pdf
ALINX黑金AX7020开发板用户手册V2.2.pdf
领航者ZYNQ之FPGA开发指南_V2.0 .pdf
参考博文:
vivado VIO IP的用法
详解XILINX IP AXI4 STREAM DATA FIFO
AXI4 STREAM DATA FIFO
DAC FIFO实验(AXI-stream FIFO IP核配置)
AXI总线协议时序