平台:Vivado2018
官方相关文档,ug471_7Series_SelectIO.pdf
关于IDDR与ODDR
Input DDR Resource(IDDR)
外部的数据在时钟的上下沿同时传输数据,我们可以使用IDDR原语将输入的单bit数据转化为2bit的数据输出。同时数据速率变为原来的二分之一。
端口介绍
|-------|------------|
| Q1,Q2 | 数据输出 |
| C | 时钟输入 |
| CE | 时钟使能 |
| D | 数据输入(DDR) |
| S/R | 同步、异步和复位引脚 |
IDDR属性
|-----------------|------------------------------------------------------------------------------------|
| DDR_CLK_EDGE | 设置相对于时钟边沿的 IDDR 工作模式,拥有OPPOSITE_EDGE (default), SAME_EDGE, SAME_EDGE_PIPELINED三种模式 |
| INIT_Q1、INIT_Q2 | 设置Q1、Q2初始值 |
| SRTYPE | 相对于时钟 (C) 的设置/复位类型 |
模式介绍
OPPOSITE_EDGE Mode模式
通过时钟上升沿输出Q1下降沿输出Q2。
SAME_EDGE模式
数据呈现到同一时钟边沿上的FPGA逻辑中。先输出D0A,在输出一对D1A和D2A。
SAME_EDGE_PIPELINED模式
数据呈现到相同时钟边沿的FPGA逻辑中。与SAME_EDGE模式不同的是,数据在第二个时钟周期输出一对数据。
Output DDR Overview (ODDR)
与IDDR相反的是,ODDR将内部的2bit数据,转换为单bit数据输出。数据速率变为原来的二倍。
端口介绍
|-----|------------|
| Q | 数据输出(DDR) |
| C | 时钟输入 |
| CE | 时钟使能 |
| D | 数据输入 |
| S/R | 同步、异步和复位引脚 |
ODDR属性
|--------------|-----------------------------------------------------------------|
| DDR_CLK_EDGE | 设置相对于时钟边沿的 ODDR 工作模式,拥有O OPPOSITE_EDGE (default), SAME_EDGE两种模式 |
| INIT | 设置 Q 端口的初始值 |
| SRTYPE | 相对于时钟 (C) 的设置/复位类型 |
模式介绍
OPPOSITE_EDGE Mode
时钟的两个边沿 (CLK) 都用于以两倍的吞吐量从 FPGA 逻辑捕获数据。
SAME_EDGE Mode
数据可以呈现给同一时钟边沿。
参考代码IDDR
// *********************************************************************************/
// Project Name :
// Author : i_huyi
// Email : i_huyi@qq.com
// Creat Time : 2024/3/27 11:27:39
// File Name : .v
// Module Name :
// Called By :
// Abstract :
//
// CopyRight(c) 2020, xxx xxx xxx Co., Ltd..
// All Rights Reserved
//
// *********************************************************************************/
// Modification History:
// 1. initial
// *********************************************************************************/
// *************************
// MODULE DEFINITION
// *************************
`timescale 1 ns / 1 ps
module adc_interface_iob_dly#(
parameter U_DLY = 1
)
(
//
input wire adc_data_n ,
input wire adc_data_p ,
output wire adc_data_rise ,
output wire adc_data_fall ,
output wire data_lvds_out ,
//system
input wire adc_clock ,
input wire adc_reset
);
//--------------------------------------
// localparam
//--------------------------------------
//--------------------------------------
// register
//--------------------------------------
//--------------------------------------
// wire
//--------------------------------------
//--------------------------------------
// assign
//--------------------------------------
//------------------------------------------------------------
//------------------------------------------------------------
IBUFDS #(
.DIFF_TERM ("TRUE" ),// Differential Termination
.IBUF_LOW_PWR ("FALSE" ),// Low power="TRUE", Highest performance="FALSE"
.IOSTANDARD ("LVDS" )// Specify the input I/O standard
) IBUFDS_inst (
.O (data_lvds_out ),// Buffer output
.I (adc_data_p ),// Diff_p buffer input (connect directly to top-level port)
.IB (adc_data_n )// Diff_n buffer input (connect directly to top-level port)
);
//------------------------------------------------------------
//------------------------------------------------------------
IDDR #
(
.DDR_CLK_EDGE ("SAME_EDGE_PIPELINED" ),// "OPPOSITE_EDGE", "SAME_EDGE"
// or "SAME_EDGE_PIPELINED"
.INIT_Q1 (1'b0 ),// Initial value of Q1: 1'b0 or 1'b1
.INIT_Q2 (1'b0 ),// Initial value of Q2: 1'b0 or 1'b1
.SRTYPE ("SYNC" )// Set/Reset type: "SYNC" or "ASYNC"
)
IDDR_i
(
.Q1 (adc_data_rise ),// 1-bit output for positive edge of clock
.Q2 (adc_data_fall ),// 1-bit output for negative edge of clock
.C (adc_clock ),// 1-bit clock input
.CE (1'b1 ),// 1-bit clock enable input
.D (data_lvds_out ),// 1-bit DDR data input
.R (adc_reset ),// 1-bit reset
.S (1'b0 )// 1-bit set
);
//------------------------------------------------------------
//------------------------------------------------------------
endmodule
参考代码ODDR
// *********************************************************************************/
// Project Name :
// Author : i_huyi
// Email : i_huyi@qq.com
// Creat Time : 2024/3/27 11:40:24
// File Name : .v
// Module Name :
// Called By :
// Abstract :
//
// CopyRight(c) 2020, xxx xxx xxx Co., Ltd..
// All Rights Reserved
//
// *********************************************************************************/
// Modification History:
// 1. initial
// *********************************************************************************/
// *************************
// MODULE DEFINITION
// *************************
`timescale 1 ns / 1 ps
module adc_interface_out#(
parameter U_DLY = 1
)
(
//
input wire adc_data_n ,
input wire adc_data_p ,
output wire adc_dq_p ,
output wire adc_dq_n ,
//system
input wire adc_clock ,
input wire adc_reset
);
//--------------------------------------
// localparam
//--------------------------------------
//--------------------------------------
// register
//--------------------------------------
//--------------------------------------
// wire
//--------------------------------------
wire Q ;
//--------------------------------------
// assign
//--------------------------------------
OBUFDS #(
.IOSTANDARD ("LVDS18" ),// Specify the output I/O standard
.SLEW ("SLOW" )// Specify the output slew rate
) OBUFDS_inst (
.O (adc_dq_p ),// Diff_p output (connect directly to top-level port)
.OB (adc_dq_n ),// Diff_n output (connect directly to top-level port)
.I (Q )// Buffer input
);
//------------------------------------------------------------
//------------------------------------------------------------
ODDR #(
.DDR_CLK_EDGE ("SAME_EDGE" ),// "OPPOSITE_EDGE" or "SAME_EDGE"
.INIT (1'b0 ),// Initial value of Q: 1'b0 or 1'b1
.SRTYPE ("SYNC" )// Set/Reset type: "SYNC" or "ASYNC"
) ODDR_inst (
.Q (Q ),// 1-bit DDR output
.C (adc_clock ),// 1-bit clock input
.CE (1'b1 ),// 1-bit clock enable input
.D1 (adc_data_p ),// 1-bit data input (positive edge)
.D2 (adc_data_n ),// 1-bit data input (negative edge)
.R (adc_reset ),// 1-bit reset
.S (1'b0 )// 1-bit set
);
//------------------------------------------------------------
//------------------------------------------------------------
//------------------------------------------------------------
//------------------------------------------------------------
endmodule
仿真tb
`timescale 1ns / 1ps
//
// Company:
// Engineer:
//
// Create Date: 2024/03/27 10:25:26
// Design Name:
// Module Name: vtf_adc_interface_iob_dly
// Project Name:
// Target Devices:
// Tool Versions:
// Description:
//
// Dependencies:
//
// Revision:
// Revision 0.01 - File Created
// Additional Comments:
//
//
module vtf_adc_interface_iob_dly;
reg adc_clock ;
reg adc_reset ;
wire [11:0] ADC_A_I_P ;
wire [11:0] ADC_A_I_N ;
wire [11:0] ADC_A_I_r ;
wire [11:0] ADC_A_I_f ;
reg data_clk ;
wire [11:0] adc_dq_p ;
wire [11:0] adc_dq_n ;
//-----------------------------------------------------------
//-----------------------------------------------------------
parameter WIDTH = 12;
//-----------------------------------------------------------
//-----------------------------------------------------------
genvar i;
generate
for (i = 0; i<=(WIDTH-1); i = i +1) begin : adc_ch_di
adc_interface_iob_dly u_iddr(
.adc_clock ( adc_clock ),
.adc_reset ( adc_reset ),
.adc_data_n ( ADC_A_I_N[i] ),
.adc_data_p ( ADC_A_I_P[i] ),
.adc_data_rise ( ADC_A_I_r[i] ),
.adc_data_fall ( ADC_A_I_f[i] )
);
end
endgenerate
genvar j;
generate
for (j = 0; j<=(WIDTH-1); j = j +1) begin : adc_ch_do
adc_interface_out u_oddr(
.adc_data_n (ADC_A_I_f[j] ),
.adc_data_p (ADC_A_I_r[j] ),
.adc_dq_p (adc_dq_p[j] ),
.adc_dq_n (adc_dq_n[j] ),
.adc_clock (adc_clock ),
.adc_reset (adc_reset ));
end
endgenerate
//-----------------------------------------------------------
//-----------------------------------------------------------
initial
begin
adc_clock =0;
adc_reset =1;
data_clk =0;
#100;
adc_reset =0;
end
reg [11:0] data_cnt;
always@(posedge data_clk or posedge adc_reset)
begin
if(adc_reset == 1'b1)begin
data_cnt <= 12'h0;
end
else begin
data_cnt <= data_cnt + 11'h1;
end
end
//-----------------------------------------------------------
//-----------------------------------------------------------
//产生数据
assign ADC_A_I_P[0] = data_cnt[0];
assign ADC_A_I_P[1] = data_cnt[1];
assign ADC_A_I_P[2] = data_cnt[2];
assign ADC_A_I_P[3] = data_cnt[3];
assign ADC_A_I_P[4] = data_cnt[4];
assign ADC_A_I_P[5] = data_cnt[5];
assign ADC_A_I_P[6] = data_cnt[6];
assign ADC_A_I_P[7] = data_cnt[7];
assign ADC_A_I_P[8] = data_cnt[8];
assign ADC_A_I_P[9] = data_cnt[9];
assign ADC_A_I_P[10] = data_cnt[10];
assign ADC_A_I_P[11] = data_cnt[11];
assign ADC_A_I_N[0] =~ADC_A_I_P[0];
assign ADC_A_I_N[1] =~ADC_A_I_P[1];
assign ADC_A_I_N[2] =~ADC_A_I_P[2];
assign ADC_A_I_N[3] =~ADC_A_I_P[3];
assign ADC_A_I_N[4] =~ADC_A_I_P[4];
assign ADC_A_I_N[5] =~ADC_A_I_P[5];
assign ADC_A_I_N[6] =~ADC_A_I_P[6];
assign ADC_A_I_N[7] =~ADC_A_I_P[7];
assign ADC_A_I_N[8] =~ADC_A_I_P[8];
assign ADC_A_I_N[9] =~ADC_A_I_P[9];
assign ADC_A_I_N[10] =~ADC_A_I_P[10];
assign ADC_A_I_N[11] =~ADC_A_I_P[11];
//时钟
always #2 adc_clock = ~adc_clock;
always #1 data_clk = ~data_clk;
endmodule
关于IDDR的模式
SAME_EDGE_PIPELINED
SAME_EDGE
OPPOSITE_EDGE
关于ODDR
输出adc_dq_p,adc_dq_n。