基于FPGA+JESD204B 时钟双通道 6.4GSPS 高速数据采集设计(三)连续多段触发存储及传输逻辑设计
本章将完成数据速率为 80MHz 、位宽为 12bits 的 80 路并行采样数据的连续多
段触发存储。首先,给出数据触发存储的整体框架及功能模块划分。然后,简介
MIG 用户接口、设置及读写时序。最后,进行数据跨时钟域模块设计,内存控制
模块设计以实现连续多段触发存储。触发存储数据将经高速串行接口传输至 AXIe
载板,最后,本章还将完成高速串行数据传输。
4.1 连续多段触发存储
4.1.1 触发存储整体框架设计
由 2.4 小节数据触发存储方案可知,本文最终采用 DDR3 内存条实现采集数据
的触发存储。 DDR3 的触发控制不同于 FIFO ,使用 FIFO 实现触发存储的过程如
图 4-1 所示,此时假设预触发深度为存储深度一半,正弦信号的波峰为触发点。首
先开启 FIFO 写使能,写入采样数据,如图 4-1 (
a )所示;当预触发深度写满之后,
同时开启 FIFO 读写使能等待触发信号的到来,此过程新写入的数据将覆盖掉老数
据,如图 4-1 (b)所示;触发信号到来之后,仅开启 FIFO 写使能,直至数据写满
存储空间,如图 4-1 (c)所示 [33] 。

由于 DDR3 采用地址总线访问存储空间,读写操作不能同时进行,故需通过
记录触发地址的方式实现触发存储。采用 DDR3 实现触发存储的过程如图 4-2 所
示,假设 DDR3 的存储深度为 AD 段,预触发深度为存储深度的一半(图中 AB
段),触发点设置为正弦信号的波峰。 DDR3 存储器在完成初始化后便开始存储采
样数据。当存储的数据量达到预触发深度时,将继续向后续地址空间存放采样数
据,直至触发信号(图中 C 点)到来,记录此时的触发地址。触发信号既可能出
现在存储空间写满之前,也可能出现在存储空间写满之后,对应的情况分别如图
4-2 (a)及图 4-2 (b)所示。继续往 DDR3 写后存储深度数据时,两种情况都会
出现数据回写现象,图 4-2 (a)中的 AE 段,图 4-2 (b)中的 CE 段。回写 DDR3
时,新的采样数据将覆盖掉该段存储空间中原本存储的采样数据。

由上述 DDR3 实现触发存储的过程可知,使用 DDR3 进行触发存储时需管理
读写地址及操作命令。图 4-3 是触发存储细化设计框图,单片 ADC 的采样数据经
JESD204B IP 核及解映射模块并行降速处理后,数据速率为 80MHz ,并行 80 路,
DDR3 的数据速率设置为 1600MT/s 。

触发存储实现包括了两个部分,一个是基于 MIG 核存储逻辑设计,另一个是
触发存储控制模块设计。基于 MIG 核存储逻辑设计包括了 MIG 核的读写逻辑设计
及跨时钟域模块设计,触发存储控制模块设计则包括了存储状态机设计、触发存
储设计及分段存储设计:
1 ) MIG 核读写逻辑设计,通过对 MIG ( Memory Interface Generator )核提供
的用户接口进行读写操作实现数据存储,读写操作需满足用户接口读写时序。 MIG
核参数的正确配置与否,将决定 MIG 核是否能正常工作。
2 )跨时钟域模块设计,采用异步 FIFO 实现数据的跨时钟域处理。解决 MIG
核工作时钟、数据位宽与采样数据、上传数据模块时钟、数据位宽不匹配的问题。
确保数据存储时,每段触发存储数据正确且连续。
3 )存储状态机设计,通过状态机方式实现不同工作模式的切换,工作模式将
由命令接收模块解析。命令接收模块接收的内容除工作模式外,还有每段存储空
间的存储深度以及读地址等。无论工作在哪种工作模式下,存储状态机都是读过
程及写过程组合。读写过程将通过读输入、输出 FIFO 的标志信号及用户接口信号
实现存储状态机的跳转。
4 )触发存储设计,基于存储状态机的设计,具体完成写过程触发地址登记以
便于后续能根据触发地址读取某段存储空间里的数据。完成读写地址计数器设计,
预触发深度满判断,触发地址登记及后触发深度满判断。触发信号来自触发管理
模块,触发管理模块主要实现触发源的选择及触发脉冲的产生。
5 )分段存储设计,基于存储状态机及触发存储的设计,具体完成大容量存储
空间的分段存储。根据命令接收模块解析的存储深度实现存储空间分段,各段存
储空间的存储深度可任意设置为 2 n ,具有灵活性。各段存储空间的写起始地址也
由存储深度设置。
4.1.2 基于 MIG 核的存储逻辑设计
MIG 核设置及读写逻辑
为简化用户对 DDR3 的读写操作 Xilinx 公司提供了一种内存接口解决方案—
— MIG IP 核 [34] ,用户可通过对 MIG IP 核进行读写操作实现对 DDR3 设备的操作。
MIG 核结构框图如图 4-4 所示,由用户接口模块( User Interface Block )、内存控
制器( Memory Controller )及物理层( Physical Layer )三个部分组成。其中用户接
口模块既要与用户设计模块交互又要与内存控制器交互。在用户接口模块这一侧,
提供了 AXI4 从机接口、用户接口两种方案方便用户控制逻辑设计: AXI4 从机接
口要求用户控制逻辑遵照 AXI4 总线协议;用户接口通过平面地址空间及读写数据
缓存实现对本地接口的简单代替,对用户控制逻辑要求简单。

本文采用用户接口实现 DDR3 存储控制,下面介绍用户接口的关键信号及读
写操作时序要求。用户接口关键信号如表 4-1 所示:

表 4-1 中读写地址总线、读写数据总线位宽与 DDR3 参数有关,读写地址与
物理寄存器空间的映射关系、用户接口时钟频率与 MIG 核设置有关。在 MIG 核中
与时钟相关的设置尤为重要,因此有必要了解 MIG 核内部时钟结构。图 4-5 为 MIG
核内部时钟结构图,按照功能分为 FPGA 内部逻辑时钟、写路径(输出)端口逻
辑时钟、读路径(输入)端口逻辑时钟及 IDELAY 参考时钟。除 IDELAY 参考时
钟以外,其余时钟均由 PLL 模块产生, PLL 输入时钟又称为系统时钟。与 PLL 位
于同一 Bank 的 MMCM 模块用于产生 IDLEAY 参考时钟, MMCM 输入时钟称为
参考时钟,该时钟频率为 200MHz [35] 。当系统时钟频率同参考时钟频率一致时,参
考时钟可由系统时钟代替,从而减少一对外部参考时钟输入。 FPGA 内部逻辑时钟
同控制器时钟使用同一个时钟,该时钟与物理层时钟(频率由外部存储设备工作
频率决定)有 1:4 及 1:2 两种比例关系,两种比例关系对应的数据宽度分别为内存
接口的 4 倍及 8 倍。因此,当本文将 DDR3 内存条数据速率设置为 1600MT/s 时,
物理层时钟频率为 800MHz 。此时,控制器时钟与物理层时钟的比例关系只能设置
为 1:4 ,即控制器时钟与 FPGA 内部逻辑时钟的频率为 200MHz ,读写数据宽度为
DDR3 内存条数据宽度的 8 倍。

从表 4-1 可知,用户接口所定义的信号可分为命令信号、写操作信号、读操作
信号三类,相应的用户接口的时序路径也可分为命令路径、写路径及读路径。下
文介绍各路径时序要求,以突发长度取 8 为例。
命令路径仿真时序如图 4-6 所示,这里为了往地址 0x0000_0e30 发送写地址命
令,将 app_en 拉高。由于 app_rdy 有一段时间为低电平,写地址命令不能成功被
接收。因此需要保持地址不变且 app_en 一直为高,直至 app_rdy 信号也拉高。

写数据操作也可以在成功写入写命令之前的一个周期或者之后的两个周期
以内。仿真时序图如图 4-7 所示,将写数据操作与写命令放在同一时钟周期内完
成,即 app_en 与 app_wdf_wren 同时置位为高,对应 app_rdy 与 app_wdf_rdy 信
号都为高说明写数据操作成功,反之则写数据操作失败。

读数据操作相对于写数据操作简单,仿真时序图如图 4-8 所示,只需保证将命
令与读地址成功写入 MIG 核即可。 MIG 核使用 app_rd_data_valid 信号指示输出数
据是否为有效数据。

跨时钟域设计
解映射后的采样数据数据速率为 80MHz ,数据位宽为 80*12bits ,而 MIG 核
的用户接口时钟为 200MHz ,突发 8 次读写的数据位宽为 64*8bits ,所以在采样数
据写入内存之前需要将其数据速率同步到用户接口时钟域。不仅如此,之后的数
据上传模块也需要跨时钟域,该模块的工作时钟为 40MHz ,数据位宽为 32bits 。
高速数据在进行跨时钟域传输时,常因为源寄存器时钟域与目的寄存器时钟
的相位关系未知,导致数据到达目的端寄存器时无法满足建立保持时间,从而出
现数据不确定状态的情况,我们把这种现象称为亚稳态。为减少亚稳态发生,需
采取一定的同步策略。常用的跨时钟域同步方法有:一位同步器、握手协议、异
步 FIFO 等。一位同步器通常应用于单 bit 信号,握手协议与异步 FIFO 则常用于多
bit 信号。由于握手协议需要协议双方不断对关键指令进行反馈,故其处理时间相
较于异步 FIFO 更长。所以,基于处理速度及位宽考虑,数据存入内存及从内存读
出都采用异步 FIFO 进行跨时钟域设计。则整个跨时钟域设计的关键在于对 FIFO
读写使能的控制及深度的配置 [36-37] 。图 4-9 是数据存入内存并从内存读出的跨时钟
域处理模块图。

采样数据在触发存储控制模块的控制下,首先进入输入 FIFO 进行跨时钟域处
理。采样数据为并行 80 路,数据位宽为 12bits ,则总的数据位宽为 960bits 。为了
使 FIFO 输出数据位宽等于用户接口数据位宽 512bits (包含 40 个 12bits 采样点),
将异步 FIFO 输入数据位宽设置为 1024bits (包含有 80 个 12bits 采样点)。 FIFO
输入端、输出端时钟频率分别为 80MHz 、 200MHz ,持续对 FIFO 进行读写操作,
FIFO 的读出速率(
200MHz × 512bits )将大于写入速率( 80MHz × 1024bits=160MHz
× 512bits )。然而 DDR3 内存条在预充电刷新阶段是不可操作的, MIG 核的 app_rdy
信号也会因此每隔几个用户接口时钟周期拉低,写操作时 app_rdy 信号会更为频繁
地拉低。持续对 FIFO 进行读写操作时, app_rdy 的频繁拉低会使 FIFO 读出速率在
某段时间内小于写入速率。若 FIFO 深度设置不合理,有可能会造成 FIFO 溢出,
采样数据丢失。为避免上述情况,需设置 FIFO 的深度以缓存 app_rdy 无效时的采
样数据。经过实验分析,本文 FIFO 深度设置为 256 时已能满足要求。在 MIG 核
设置及读写逻辑部分对 MIG 核的命令通道时序进行了分析,据此可知只有当
app_rdy 有效时,地址及命令才能进入 MIG 核,读写操作才可能有效。因此 app_rdy
无效的同时需关闭 FIFO 的读使能信号( fifo_rd_en 为低电平),这样才能保证 FIFO
此时输出的数据不被下一次读出的数据覆盖。不仅如此,当 FIFO 为空时 FIFO 的
读使能信号也需要为低电平,只有这样才保证存入 MIG 核的数据连续。故只有当
异步 FIFO 非空并且 app_rdy 信号有效时,才能拉高 FIFO 的读使能信号。当 FIFO
为空或者 app_rdy 信号无效时, FIFO 读使能拉低, FIFO 读出数据保持不变,仿真
时序如图 4-10 所示。

相比于数据存储过程,数据读取过程设计实现简单,仅需要保证地址及读命
令信号在 app_rdy 信号有效时送入 MIG 核,当然开启读 DDR3 数据时,输出 FIFO
要为空状态。 DDR3 输出数据位宽为 512bits ,为方便上位机处理将采样数据位宽
拓宽至 16bits ,输出 FIFO 输入数据位宽设置为 640bits 。输出 FIFO 输出数据位宽
由上传模块及 FIFO 特性决定,这里设置为 160bits 。
4.1.3 触发存储控制模块
存储状态机设计
为实现大容量数据存储及传输,首先需要上位机设置存储参数及工作模式,
并启动存储状态机,在接收到参数及写工作模式后,将开始存储采样数据,直至
触发信号到来并完成后触发深度存储。完成大容量数据存储之后,可由用户设置
读起始地址读取存储的采样数据,并将读取的数据传输至 AXIe 载板,并由 AXIe
载板将数据最终上传至上位机。则存储模块需要一个初始化的过程(初始态 IDLE ),
一个实现波形数据写入 DDR3 中的写过程(写状态 WRITE ),一个实现波形数据
从 DDR3 中读出的读过程(读状态 READ )以及一个工作模式判断过程(工作模
式选择装填 CMD )。存储模块定义了三种工作模式,分别为只写,只读及先写后
读。在先写后读的工作模式下,写过程与读过程之间定义了一个延迟状态(延迟
态 DELAY )。图 4-11 为存储模块的状态跳转示意。

当复位情况下,即条件 1 ,存储状态机将从当前状态回到初始 IDLE 态。
在 IDLE 状态检测 MIG 核初始化校准信号 init_calib_complete 是否有效,以确
保读写操作时 DDR3 能够正常工作,同时监测输入异步 FIFO 是否为空,以确保下
一次开始写入 DDR3 的数据不包含上一次写过程中未读出的数据。在 IDLE 状态还
将完成存储相关参数的初始化,如初始写地址、初始读地址、初始命令等。当满
足条件 2 ,即 MIG 核初始化校准信号有效且输入异步 FIFO 空标志拉高,状态机将
从 IDLE 状态进入工作模式选择 CMD 状态。
在工作模式 CMD 状态,使能接收命令,并根据命令类型进入读状态还是写状
态,同时完成写地址、读地址等的初始化。当满足条件 3 ,即工作模式命令为只写
或先写后读模式,状态机将首先进入 WRITE 状态;当满足条件 5 ,即工作模式命
令为只读模式,状态机将进入 READ 状态。只有在 CMD 状态才能接收命令。
在 WRITE 状态,完成数据的触发存储,并登记触发地址,之后会根据工作模
式命令进入不同的状态。当条件 6 满足,即工作模式命令为只写命令且写过程完
成,状态机将返回 CMD 状态,接收新的命令;当条件 4 满足,即工作模式命令为
先写后读命令且写过程完成,状态机将进入延迟状态,完成读过程相关参数的初
始化,并进入 READ 状态。
在 READ 状态,根据触发地址,计算读起始地址,之后会根据工作模式命令
进入不同的状态。当条件 7 满足,即完成读过程后,状态机将返回 CMD 状态。
在具体实现存储状态机时采用易于综合且资源消耗较少的三段式状态机。
触发存储设计
触发存储整体框图设计小节已经介绍了使用 FIFO 和使用 DDR3 内存条实现触
发存储的最大不同在于触发的控制。 FIFO 在预触发深度满至触发信号到来的这段
时间内边读边写,在触发信号到来之后仅需使关闭读使能,保持写使能。而 DDR3
在实现触发存储时只能写数据,并且触发信号到来时需记录此时的地址信息。
DDR3 读数据时需根据触发地址计算读起始地址。下面将具体展开采集数据的触发
存储功能设计。
由于 DDR3 实现触发存储时不能边读边写,且可能会出现数据回写的情况,
故可用图 4-12 所示的环形结构示意 DDR3 触发存储实现的过程。图 4-12 中的 AA’
段为存储深度所对应的内存空间, AB 段为预触发深度所对应的内存空间,此处设
置为存储深度的一半, C 点为触发信号到达时刻。内存状态机进入写数据状态后将
从写起始地址 A 点开始存储数据。只有在写入的数据量填满预触发深度 AB 段之
后,触发信号才能触发后触发深度 CD 段的写入,数据在 AD 段发生了回写。当触
发信号到来后写入的数据量等于后触发深度时,一次触发存储完成。

由上述可知,触发存储实现的关键在于写地址的产生、对写预触发深度阶段
写入数据量的计数、对写后触发深度阶段写入数据量的计数、数据回写阶段写地
址的产生及触发时刻触发地址的登记。
在存储过程中,采用计数器 cnt_wr_addr 产生写地址。本文采用的 DDR3 内存
条在 MIG 核用户接口模块中的地址位宽为 30bits ,最高位为 RANK 位,由于该内
存条仅有一个 RANK ,则可访问的存储空间数量为 2 29 ,即地址位宽为 29bits 。又
由于内存突发模式的突发长度为 8 ,则计数器 cnt_wr_addr 位宽仅需设置为 26bits
便能访问所有内存空间,计数器 cnt_wr_addr 计数值左移三位后即是内存地址值。
写预触发深度阶段及写后触发深度阶段也采用了计数器对写入数据量进行计数,
分别定义为 cnt_pre 、 cnt_post ,位宽都为 26bits 。当写入数据量超过存储深度即计
数器 cnt_pre 的计数值等于存储深度时,将发生数据回写,此时需将计数器
cnt_wr_addr 及 cnt_pre 设置为初始值以使写入地址从写起始地址开始。触发地址的
登记将结合写过程状态机及计数器介绍,写过程实现的状态机如图 4-13 所示。

这里的 IDLE 状态即前面所述的初始化状态,在该状态分别给预触发深度计数
器 cnt_pre 、后触发深度计数器 cnt_post 及写起始地址计数器 cnt_init 赋初值。 CMD
状态即为前面所述工作模式选择状态,该状态在只写及先写后读工作模式下将进
入预触发深度写 PRE_WRITE ,同时完成计数器 cnt_wr_addr 初始化。在预触发深
度写状态将启动计数器 cnt_wr_addr 及 cnt_pre 计数,每成功写入一次数据,计数
器加一,计数器 cnt_post 处于关闭状态,图 4-14 为此过程计数器计数仿真时序。

当 cnt_pre 的计数值与预触发深度 pre_depth 值相等时,写预触发深度满标志
pre_full 为高,状态机将从预触发深度写状态跳转至等待触发 WAIT_TRIG 。在
WAIT_TRIG 状态,计数器 cnt_wr_addr 及 cnt_pre 继续计数,等待触发信号的到来。
若触发信号迟迟未到,此时 cnt_pre 的计数值已超过存储深度,需要将 cnt_wr_addr
及 cnt _pre 值设置为初始值。当触发信号到来后,将从 WAIT_TRIG 进入后触发深
度写状态 POS_WRITE ,并记录下此时计数器 cnt_wr_addr 的值,该值所对应的地
址即为触发地址。如图 4-15 所示为等待触发过程计数器计数及触发地址登记仿真
时序。

在 POS_WRITE 状态,计数器 cnt_wr_addr 及 cnt_pre 仍将继续计数,并且启
动计数器 cnt_post 计数。若在 POS_WRITE 状态,出现了数据回写的情况,同
WAIT_TRIG 状态的处理方式一样,需要将 cnt_wr_addr 及 cnt_pre 值设置为初始值。
当计数器 cnt_post 的计数值等于后触发深度 pos_depth 时,写后触发深度满标志
post_full 为高时,状态机将从后触发深度写状态进入 IDLE 状态或存储模块状态机
中的 DELAY 状态,结束数据写过程。图 4-16 为写后触发深度过程计数器仿真时
序。

数据读过程的实现相对于写过程简单,关键在于正确给定读数据起始地址。
读起始地址值为触发地址与预触发深度的差值,计算公式如式(
4-1 )所示。计算
读起始地址时,有可能出现 trig_addr 的值小于 pre_depth 的情况。因此,在实现的
时候,会根据触发地址与预触发地址的大小关系分别讨论读起始地址的计算。

在读过程设计了两个计数器 cnt_rd_addr 及 cnt_rd , cnt_rd_addr 用于产生读地
址, cnt_rd 用于对读出数据量进行计数。读过程可能会出现读地址超过存储空间地
址范围的情况,因此需要在读地址等于最大地址之后将读地址赋值为初始值。当
cnt_rd 值等于存储深度时,结束数据读过程。
分段存储设计
分段存储结构如图 4-17 所示,存储器被等分为 N 个独立的存储空间,各段存
储空间的大小确定,触发条件即可以相同也可以不同 [38] ,这里将各段触发条件设
置为波形下降沿,预触发深度设置为存储深度的一半。
首先将波形数据写入第一段存储空间,写满预存储区域后等待触发信号。在
捕获到的第一个触发信号之后,写满第一段存储空间并将之后的波形数据写入第
二段存储空间。在写满第二段存储空间预存储区域后捕获触发信号,完成后触发
深度数据量写入。每当一段存储空间写满采集数据后便开启往下一段存储空间写
入数据的过程,如此反复,直至划分的最后一段存储空间也写满数据。写满存储
器之后可根据每段存储空间的地址范围、触发地址及预触发深度计算起始地址,
逐帧读取显示或叠加映射波形数据。
采用 DDR3 分段存储写过程的流程图如图 4-18 所示。首先完成存储模块上电
或复位初始化,设置模块的初始工作状态及各种参数的初始值,主要是写起始地
址计数器 cnt_init 值及写地址计数器 cnt_wr_addr 值。写起始地址用于写地址初始
化,在写过程中写地址 cnt_wr_addr 将持续加一。上电及复位完成后,写起始地址
cnt_init 设置为零。完成上电、复位初始化后,将接受上位机操作命令及存储深度
depth 的值。由于上电或复位状态后,写起始地址计数器 cnt_init 为 0,在首次接收
到写命令之后,将启动往 DDR3 的第一段存储空间写数据的过程。每段存储空间
的写数据过程都采用触发方式实现波形数据存储,因此每段存储空间都会有对应
的触发地址,可采用 FPGA 内部的 RAM 或 FIFO 存储器存储这些触发地址。每完
成一段存储空间的波形数据存储,需要将写初始地址计数器 cnt_init 设置为下一段
存储空间起始地址对应的计数值,即此时的 cnt_init 值加上存储深度计数值
cnt_depth 。完成一次存储后将返回接收命令状态,再次判断工作模式。
当工作模式为写模式时,将根据上一段存储完成后计算的 cnt_init 设置此时写
地址计数器 cnt_wr_addr 的值;无论工作模式切换为何种模式, cnt_init 将保持在上
一段存储完成后设置值状态,以保证下一次写过程,能从上次存储段后的一段存
储空间开始,连段存储之间 cnt_init 计数器计数仿真时序如图 4-19 所示。在实现时,
这里的初始化状态指的是 IDLE 状态,接收命令指的是 CMD 状态,写数据过程指
WRITE 状态。

在实现连续多段写时,总是会出现写地址超出某段存储空间的情况,需将写
地址计数器 cnt_wr_addr 设置为此段存储空间写起始地址计数器 cnt_init 值。可通
过将工作模式设置为只读模式,读取每段存储空间对应的数据。读过程中也可能
出现读地址计数器 cnt_rd_addr 大于存储空间对应的计数器值,同理也需要将读地
址计数器 cnt_rd_addr 值设置为写起始地址计数器 cnt_init 值。