Menu Close

Xilinx FPGA DDR 接口及Verilog实现

DDR(double data rate)是指相对于时钟频率,data的吞吐率是普通IO接口的双倍,即在时钟的上升沿可以读写一笔数,在时钟的下降沿也可以读写一笔数。

标准的应用中Vivado提供向导生成DDR2,DDR3控制器,DDR控制器也将DDR接口等设置做好,因此无需单独设置DDR接口,但还有许多应用场景还是需要单独设置,单独使用DDR接口已满足与其它设备的接口,如RGMII接口等。Xilinx FPGA DDR接口有输入接口和输出接口两种,下面将分开介绍。

1. DDR接口只用在端口上

尽管在FPGA内部通过Verilog语言描述也可以实现DDR的方式,但与数据相关的IP core都是单边沿操作,因此对于DDR的使用都是用在FPGA端口上。IDDR输入使用端口寄存器,将DDR双边沿数据变成两个单边沿寄存器输出。同样如果使用ODDR,则将FPGA内部单边沿的两个时钟的数据Q1,Q2变成双边沿的一个时钟内输出,即上升沿输出Q1,下降沿输出Q2。通过DDR接口在时钟频率不变的情况下,将端口的数据吞吐率提高一倍,著名的DDR存储器系列就是通过这种方式实现的。

2. DDR输入接口(IDDR)

DDR输入接口是指数据或时钟输入是以DDR接口实现的,即输入数据是双边沿的,输出将数据还原回单边沿的方式。

  • DDR输入接口Verilog原语


这个原语可以复制到Verilog程序中直接使用,虽然这个原语是ARTIX器件的相关器件原语,但整个7系列的所有器件的IDDR原语都相同。下面就各个部分作简单介绍,IDDR分为两个部分,参数化(属性)部分以及IP核实体例化部分。

  • IDDR参数化(属性)部分

    • 时钟边沿属性

对于IDDR时钟边沿属性分为OPPOSITE_EDGE,SAME_EDGE和SAME_EDGE_PIPELINED三种模式。

    • OPPOSITE_EDGE模式

.DDR_CLK_EDGE(“OPPOSITE_EDGE”), // “OPPOSITE_EDGE”, “SAME_EDGE”

// or “SAME_EDGE_PIPELINED”   

      “OPPOSITE_EDGE”属性是指,Q1上升沿输出,Q2下降沿输出,即Q1,Q2分别同步在相反的时钟边沿上,如图1所示。

图1  IDDR OPPOSITE_EDGE模式

图1可以看出Q1,Q2交错输出,Q1与Q2相差1800,在FPGA内部可以利用时钟再次锁存,统一到同一个边沿上,如:

always@(posedge c) //统一到上升沿,此时D0A,D1A 为一对,D2A,D3A 为一对。

begin

Q3 <= Q1;

Q4 <= Q2;

end

此时Q3,Q4统一在时钟上升沿输出,锁存后Q3,Q4的数据成对并列出现,如在同一个上升沿锁存后Q3,Q4的值(D0A,D1A),(D2A,D3A),(D4A,D5A)……。但在对时钟C进行约束时应将时钟的约束频率翻倍。 “OPPOSITE_EDGE”属性适合并行数据与串行数据的转换。

或利用下降沿锁存

always@(negedge c) //统一到下降沿,第一个下降沿Q5 = D0A, 第二下降沿Q5 = D2A,Q6 = D1A。

begin

Q5 <= Q1; 

Q6 <= Q2;

end

此时Q5,Q6统一在时钟下降沿输出,Q5,Q6的数据奇偶交错,Q6的数据比Q5滞后一个时钟周期。但在对时钟C进行约束时应将时钟的约束频率翻倍。 “OPPOSITE_EDGE”属性适合高速数据流与DDR数据的转换。

    • SAME_EDGE模式

“SAME_EDGE” 属性是指,双边沿数据D经过IDDR后,输出Q1、Q2相差一个时钟周期,都同步在上升沿上,如图2.

图2 “SAME_EDGE” 属性IDDR

“SAME_EDGE” 属性适合前后相差一个时钟周期的串行数据合并成DDR数据,以降低端口时钟频率。

    • SAME_EDGE_PIPELINED模式

“SAME_EDGE_PIPELINED” 是指双边沿数据D经过IDDR后,延时一个时钟周期,Q1,Q2输出统一合并到上升沿,如图3所示。

图3  IDDR SAME_EDGE_PIPELINED模式

属性为”SAME_EDGE_PIPELINED”的IDDR的输出Q1,Q2成对同步在时钟的上升沿上,这与 “OPPOSITE_EDGE”属性的IDDR输出后,再经过上升沿锁存的效果相同,如Q3,Q4

    • INIT属性

INIT属性用来初始化输出Q1,Q2 的初始值,一般为1’b0或1’b1。

.INIT_Q1(1’b0), // Initial value of Q1: 1’b0 or 1’b1

描述输出端Q1的初始值,也就是输入数据没有到来,或DDR在没有完全接受控制之前的数据,一般0或1都可以,IDDR在数据分解之前可以使用R或S输入端进行复位或置位。

.INIT_Q2(1’b0), // Initial value of Q2: 1’b0 or 1’b1

描述输出端Q2的初始值,也就是输入数据没有到来,或DDR在没有完全接收控制之前的数据,一般0或1都可以,IDDR在数据分解之前可以使用R或S输入端进行复位或置位。

    • SRTYPE属性

SRTYPE属性可以指定复位端R、置位端S是否与时钟同步。

.SRTYPE(“SYNC”) // Set/Reset type: “SYNC” or “ASYNC”

描述S,R置位/复位输入端的特性,有同步(SYNC)和异步(ASYNC)两种,同步就是置位或复位位为高电平时复位或置位并不能立即生效,而是在时钟上升沿时才会生效,而异步行为将立即生效。

  • 实体例化部分端口

输入时钟 C:IDDR寄存器的输入时钟,时钟C与数据D在双边沿同步。

输入端D:DDR数据输入,在输出端口将被分离出Q1,Q2。

输出Q1 :从输入端D分离出的数据 ,D端对应时钟的上升沿的数据。

输出Q2 :从输入端D分离出的数据 ,D端对应时钟的下降沿的数据。

输入CE:时钟使能,高电平有效。

输入R: 复位端,高电平时Q1,Q2为0,R为0,IDDR正常工作。

输入S: 置位端,高电平时 Q1, Q2为1, S为0时,IDDR正常工作。

注: R,S不能同时为高电平。

3. DDR输出接口(ODDR)

ODDR的原语如下,


 

  • ODDR属性部分(参数)

ODDR属性部分(参数),仅有 “OPPOSITE_EDGE” 与 “SAME_EDGE” 两种,因为ODDR是将D1,D2两个数据合并到双边沿输出,因此没有 “SAME_EDGE_PIPELINED” 选项。

    • OPPOSITE_EDGE模式:

当输入参数为OPPOSITE_EDGE模式时,要求输入数据D1,D2在时钟CLK的相位上差1800,即D1满足上升沿采样条件(如 setup time,hold time),也可与上升沿对齐。D2满足下降沿采样条件或与下降沿对齐,输出OQ的上升沿对应D1 对应的数据(D1A),下降沿对应D2的数据(D2A),如图4。

图4 ODDR 的OPPOSITE_EDGE模式

OPPOSITE_EDGE 模式一般用在串行数据流,可以降低端口的时钟频率。

  • SAME_EDGE 模式:

ODDR的SAME_EDGE模式要求输入数据D1,D2满足CLK的上升沿采样条件或与CLK的上升沿对齐。

图5 ODDR的SAME_EDGE模式

    • SAME_EDGE模式一般用在并行数据转成DDR的方式输出。
    • INIT 初始化Q的值为INIT的值,将Q初始化为0或1。
    • STYPE 属性参数为“SYNC ”,“ASYNC”用来设置R,S 是否与时钟同步。
  • ODDR例化的实体部分,

D1,D2 对应的输入数据,Q为DDR输出。CE为时钟使能,当CE为低电平时ODDR进入低功耗模式。R,S分别为复位和置位端,R为1时,Q = 0,S为1时Q = 1。R,S不能同时为1.

4. DDR接口的使用与仿真

由于DDR接口在FPGA端口实现,因此实时DEBUG工具很难观测到端口上的具体行为,但仿真可以看到具体细节,因此对于DDR接口学习和使用,仿真是一个很有效的办法。后续IDDR,ODDR的部分主要以实例的方式介绍高速数据流到DDR的转换,以及并行数据交替在DDR接口串行输出,以及多IDDR,ODDR并行数据的接口实现。

4.1.  串行数据流到DDR的收发转换

    • ODDR 的使用与仿真

例1: 利用ODDR将串行数据流转成DDR的方式输出,并将端口时钟频率降低1倍。假设数据流以11010011_10111100为基本单位进行循环。

由于ODDR的D1,D2对应的是串行数据,因此选用OPPOSITE_EDGE属性比较合适。

ODDR实体程序:


仿真程序:


 

    • 仿真程序解释如下:

(1)利用PLL生成了两个时钟分别为系统时钟sys_clk(200MHz)与DDR_IN_CLK(ODDR时钟输入时钟,100MHz),sys_clk与DDR_IN_CLK在相位上相差00。

(2)利用移位寄存器shift_reg在sys_clk的控制下, 将初始化的数据16’b11010011_10111100循环左移,并将最高位赋值给寄存器shift_r。

(3)生成HL控制信号,高(1)、低(0)交替,同步于sys_clk。

(4)根据HL选择将shift_r的值赋值给D1或D2。

(5)将PLL生成的DDR_IN_CLK 作为ODDR的输入时钟。

仿真结果如图6,

 

图6  ODDR  OPPOSITE _EDGE 模式的仿真结果

例1实现了200Mbps的串行数据流,如何利用ODDR实现100M上下边沿实现数据发送,从波形上可以看出DDR_IN_CLK在上升沿采样D1,在下降沿采样D2,数据合并从上升沿开始。注意由于DDR是同步数据传输,因此端口需要数据端Q和时钟一起传送。

也可以修改DDR_IN_CLK与sys_clk在相位上差900关系,如图6。可以预测DDR_IN_CLK的相位滞后sys_clk  900,最终的仿真结果就与图4显示的结果基本一致。

图6,设置clk_out2相对于输入时钟偏移900

 

图7    DDR_IN_CLK偏移900的仿真结果

 

例2  将IDDR输入的数据按照先后顺序统一到数据上升沿上,并检测数据包,假设线路状态如下:

(1)IDLE 状态 ,输入数据D的上升沿和下降沿都为1,

(2)Preamble    10101010

(3)SFD             10101011

(4)DATA       8位数据0-255循环,  8’h00, 8’h01, 8’h02, 8’h03, 8’h04, 8’h05, 8’h06, 8’h07…。

根据以上提供的信息解出数据包,并给出数据包的包络线(RX _DV )。

    • 解题思路如下:

(1)在例1的基础上改进的ODDR能按照例2的要求实现线路状态,以提供实验环境。

(2)在输入端添加PLL2,输入时钟为IDDR数据伴随时钟IDDR_IN_CLK,输出时钟为IDDR_CLK(100M,偏移900),IDDR_SYS_CLK(200M,偏移900)以提供IDDR 对应的2倍频率的时钟,如图8所示。

图8

对于IDDR双边沿数据合并成单边沿的快速数据流,应该采用OPPOSITE_EDGE模式,如图1所示。

IDDR的实体程序IDDR_decomposition.v如下:


 

  • 仿真激励程序sim_ODDR.v,

仿真激励程序将快速时钟产生的数据流,采用ODDR的方式输出,对外时钟降低1倍, ODDR与例1一样采用OPPOSITE_EDGE  模式。程序如下:


 

仿真波形如图9所示,

 

图9-1  IDDR数据

图9-2  采用ODDR/IDDR实现高速数据流到DDR的转换

图9显示利用ODDR/IDDR可以将线路时钟频率降低一倍,并能正确将数据包还原,在例2中双方约定收发数据长度,如果利用8b/10b编码也可以利用K28.5和K28.1作为起始和结束进行包头、包尾的判断。

例2 工程代码下载   DDR_int erface

4.2  并行数据实现DDR串行化

例3,采用ODDR与IDDR实现8位并行数据串行化,在保持时钟频率不变的情况下,将输出端口降低一半。数据包的测试数据与例2相同。

解题思路如下:

(1)数据包的构成:

    •  IDLE    11111111…
    • Preamble   8’b10101010
    • SFD             8’b10101011
    • data           0-255 循环

(2)系统时钟采用125Mhz, DDR的时钟同样为125Mhz,端口由8-bit降低为4-bit,实现1000Mbps 的收发。

(3)收、发双方采用握手信号

    • 发送端 tx_en, txd[3:0], tx_clk(125M ), 将tx_data[7:0],按照低半字节(上升沿),高半字节(下降沿)的顺序发出。
    • 接收端 RX_DV,RXD[3:0],RX_CLK, 将收到的RXD [3:0] ,拼成一个字节的方式输出。

(4)并行数据发送与接收,ODDR采用SAME_EDGE模式, IDDR采用SAME_EDGE_PIPELINED 模式。

(5)写出收、发程序并仿真。

  • 利用ODDR实现4-bit双边沿发送数据包程序test_ODDR.v:


 

上面的程序基本上按照ODDR的SAME_EDGE 模式配置,将高4个bit和低4个bit的数据赋值给ODDR_D1 与ODDR_D2。

注意时钟输出应延时一个固定值,在接收端才能正确采样,这段程序与RGMII接口MAC端的应用一致。如:

assign #2 DDR_OUT_CLK=tx_clk; //DDR_OUT_CLK 需要延时一个固定时间,才能对上升沿和下降沿的数据正确采样。

当然这个延时也可以在接收端设计,目前延时的方法有如下几种:

(1)仿真时可以采用延迟赋值语句的方式实现,这种延时只能用来评估时钟对齐的效果,也就是只能在仿真时有效,综合后的结果无效,因为综合时会忽略延迟部分。

(2)采用IO延迟,可以采用IDELAY或ODELAY实现,有关IDEAL或ODELAY部分的相关内容,参照IO DELAY部分的相关内容。

(3)采用PLL或MMCM实现时钟的相位偏移。

(4)有些器件已经带有2 ns延迟,如RTL8211E物理层网络芯片,因此在使用时应注意正确设定,详细资料见RTL8211E的datasheet。

  • 发送端数据包生成程序


 

  • 接收端程序IDDR_decomposition.v


 

  • 仿真程序


 

  • 仿真结果:

    • 时钟没有延迟的仿真波形(assign  DDR_OUT_CLK=tx_clk;),如图10所示。

图10

从图10中可以看出,在IDDR_IN_CLK上升沿的采样第一次(如黄线位置)采样的值为f,下降沿采样为a,因此后面的拼接都是错位的。所以整个数据包无法正确解调出来。

    • 时钟带有延迟赋值语句的仿真波形(assign  #2 DDR_OUT_CLK=tx_clk;),如图11所示。

图11

图11显示,时钟经过延迟之后,可以正确恢复原数据包。

    • 在接收端利用PLL将DDR_IN_CLK延时900,如图12所示。

图12  PLL例化(输入时钟125M)

图13  输出时钟125M(延迟900)

图13中输出两个时钟,分别为125M并延迟900,另一个时钟为200M,在后续的IO delay延迟中会用到。修改IDDR_decomposition.v程序如下,


 

更新的test_ODDR.v如下:


 

仿真波形如图14所示:

图14   IDDR_CLK

       从图14可以看出,IDDR_CLK比IDDR_IN_CLK延迟900,利用IDDR_CLK可以正确恢复原数据包。缺点是当IDDR_IN_CLK的时钟频率频繁变换时应及时探测,并复位PLL2,保持PLL2及时锁定及频率跟踪。详细内容请参照网络开发中RXC测量部分。也可以利用tx_clk作为PLL的时钟输入,将输出时钟延迟900作为ODDR的输出时钟,方法与上面的方法几乎一致,感兴趣的朋友可以尝试。但需注意只能在发送端或接收端提供延迟,不能收发时钟两端都延迟。

    • 在接收端利用IDELAY将时钟延迟一定的时间,一般2ns左右(2ns对于125M时钟为1/4的时钟周期,对于双边沿相当于延迟900)。
    • 修改IDDR_decomposition.v程序如下,


 

图15 Artix-7 Idelay Tap计算

    • 仿真波形如图16所示。

图16    利用端口IDELAY将IDDR的时钟延迟900

由于测试器件为ARTIX系列不支持ODELAY, 如果选用的器件为Kintex或更高档器件,也可以用ODELAY的方式实现。关于IDELAY及ODELAY的更多的细节将会在IOdelay及应用章节中讲解。

Posted in FPGA, FPGA, FPGA 教材教案, FPGA硬件资源, Verilog, 元器件, 教材与教案, 文章, 编程语言, 资料区, 集成电路