一、前言
最近忙于硕士毕业设计和论文,没有太多时间编写博客,现总结下之前在某个项目中用到的一个高速ADC接口设计部分。ADC这一器件经常用于无线通信、传感、测试测量等领域。目前数字系统对高速数据采集的需求与日俱增,本文使用了米联客的一款速率较高的AD/DA模块ADQ9481来阐述利用FPGA设计高速ADC接口的技术要点。
二、ADC硬件特性分析
首先必须通过datasheet分析其核心参数、接口定义和时序要求。ADC9481的采样率为250MSPS,精度8bit。其原理结构图如下:
主要引脚说明:
CLK+-:差分时钟输入,信号频率为250MHz
VIN+-:模拟信号输入,范围是1Vpp
VREF:电压参考输入/输出,这里使用内部固定参考电压模式
SENSE:参考模式选择
D7A~D0A:通道A数字信号输出
D7B~D0B:通道B数字信号输出
DCO+-:数字差分时钟输出,信号频率为125MHz
S1:数据格式选择,该接口电压决定数格式时原码还是补码
PDWN:低功耗选通
接下来看看接口时序:
很容易看出A和B两个数字输出通道是交替输出的,通道A在DCO+上升沿输出,B在DCO-上升沿输出。DCO+-的频率仅是采样率250MHz的一半,也就是降低了对数字系统处理速率的要求。
三、ADC接口设计
根据上述时序关系可知,FPGA端需要在DCO+上升沿采集通道B数据,在DCO-上升沿采集通道A数据。并且由于在DCO+-同一变化沿时刻,通道A为前一个数据,因此要注意数据的采集顺序。这类数据采集的普遍做法是将数据存入到RAM中,然后利用本地时钟同步。具体方法是:按照两通道的数据顺序对数据进行拼接,之后缓存到异步FIFO中。本地PLL生成的125MHz时钟作为读侧和后续处理时钟信号。这里就要利用Xilinx FPGA的“原语”中的IBUFDS+BUFG,依次是差分输入缓冲器和全局缓冲器。前者可将差分信号转变为单端信号,后者则可让时钟信号到达FPGA内部逻辑引脚的时延和抖动最小。综上,ADC接口硬件架构如图:
四、HDL代码编写
根据前文所述的硬件架构,ADC接口HDL代码如下:
![](https://i-blog.csdnimg.cn/blog_migrate/8f900a89c6347c561fdf2122f13be562.gif)
![](https://i-blog.csdnimg.cn/blog_migrate/961ddebeb323a10fe0623af514929fc1.gif)
1 `timescale 1ns / 1ps 2 3 module adc_interface#(parameter WIDTH = 8, 4 FRAME_LEN = 512 5 //WAIT_CYC = 125_000_000//1s = 1000_000_000ns 1000_000_000/8 = 125_000_000 6 ) 7 ( 8 input clk0, //125MHZ 9 input clk1, 10 11 input [WIDTH-1:0] da, 12 input [WIDTH-1:0] db, 13 output adc_pd,//省电模式选择 14 15 output pll_ce, 16 output pll_rst_n, 17 output pen, 18 19 input user_clk,//125MHZ 20 input rst_n, 21 input en, 22 output reg [WIDTH*2-1:0] dout = 0, 23 output reg dout_vld = 0 24 ); 25 26 function integer clogb2 (input integer bit_depth); 27 begin 28 for(clogb2=0; bit_depth>0; clogb2=clogb2+1) 29 bit_depth = bit_depth >> 1; 30 end 31 endfunction 32 33 localparam DATA_CNT_W = clogb2(FRAME_LEN-1); 34 35 (*DONT_TOUCH = "true"*)reg setup_flag = 0; 36 reg [WIDTH-1:0] data_a = 0,data_b = 0; 37 reg data_a_vld = 0,data_b_vld = 0; 38 reg wr_en = 0; 39 reg [WIDTH*2-1:0] wr_data = 0; 40 reg rd_en = 0; 41 wire empty; 42 wire full; 43 wire [WIDTH*2-1:0] rd_data; 44 (*DONT_TOUCH = "true"*)wire