01signal.com

将 01-signal sampling 与 source-synchronous inputs结合使用

介绍

本页介绍 01-signal sampling 作为与 source-synchronous input连接的方法。有关 source-synchronous inputs 的页面概述了与此类数据源交互的其他策略。该页面还解释了 source-synchronous input 是什么。

01-signal sampling 背后的想法是将外部 clock 视为 data signal: 因此, clock 由 register采样。该 register 使用内部 clock ,稳定且独立于外部 clock。

data signals 由额外的 registers采样。相同的内部 clock 用于此目的。该内部 clock 也用于实现 01-signal sampling的所有 logic 。

该 logic 检测对外部 clock进行采样的 register 上的变化。当这个 register 从 '0' 变成 '1'的时候,这意味着外接的 clock上多了一个 rising edge 。 logic 通过将另一个 registers 的值写入 FIFO来响应此事件。这些 registers 包含外部 clock 的 rising edge 发生时存在的 data signals 的值。

该 logic 实现的结果与 FIFO的 clock 是外部 clock 并且 FIFO的 data inputs 直接连接到 data signals相同。区别在于 logic使用的是哪个 clock : 外部 clock 或内部 clock。 01-signal sampling 的优点是所有 logic 只依赖于内部的 clock。这款 clock 稳定可靠。即使外部 clock 行为不当, logic 仍会继续以合理的方式运行。

下图展示了 01-signal sampling:

Example of 01-signal sampling

在此图中, @stable_clk 是 FPGA的内部 clock。 @data_clk 和 @data 是到达 FPGA的信号。 @data_clk_samp 和 @data_samp 是 FPGA内部的 registers 。外部信号 @data_clk 用 @data_clk_samp表示。 @data_samp 相对于 @data也是如此。

该图说明当“0 1”模式出现在 @data_clk_samp中时, @data_samp 的值被写入 FIFO。这就是该方法被称为“01-signal sampling”的原因。

此处以 FIFO 为例,说明如何处理到达的数据。这通常是一个合适的解决方案,因为内部 clock 的频率明显高于数据速率。因此,通常使用基于较低 clock 频率的 logic 继续处理数据会比较方便。 FIFO 是一种将数据移交给不同 clock domain中的 logic 的便捷方法。

尽管如此,仍可以使用与 01-signal sampling相同的内部 clock 来实现 logic 的其余部分。使用 FIFO 只是一种可能性。

Verilog中的示例

这个 Verilog 代码说明了这个想法。外部 clock 为 @data_clk。

module top (
   input stable_clk,

   input data_clk,
   input [7:0] data
);

   reg [7:0] data_guard, data_samp;
   reg       data_clk_guard, data_clk_samp, data_clk_samp_d;
   wire      fifo_wr_en;

   always @(posedge stable_clk)
     begin
        data_guard <= data;
        data_clk_guard <= data_clk;

        data_samp <= data_guard;
        data_clk_samp <= data_clk_guard;

        data_clk_samp_d <= data_clk_samp;
     end

   assign fifo_wr_en = data_clk_samp && !data_clk_samp_d;

   data_fifo fifo_i
     (
      .wr_clk(stable_clk),
      .din(data_samp),
      .wr_en(fifo_wr_en),

       [ ... other ports connected here ... ]
      );
endmodule

重要的部分是FIFO的 wr_en: @fifo_wr_en。此 signal 等于“data_clk_samp && !data_clk_samp_d”。因此,由于在 @data_clk_samp上检测到“0 1”模式,该 signal 处于高电平。这会导致 @data_samp 的值被写入 FIFO。

请注意, logic仅将 @stable_clk 用作 clock 。 @data_clk 被视为普通的 I/O input。

@data_guard 和 @data_clk_guard 的 timing 要求不保证: input ports 相对于 @stable_clk是异步的。 @data_guard 和 @data_clk_guard 因此是 metastability guards。 logic 不直接依赖于这两个 registers的值。另一方面, @data_samp 和 @data_clk_samp 直接被 logic使用,因为这些 registers 是 metastability guard的第二步。

但这真的有效吗?答案就在 timing analysis中。

Timing analysis

01-signal sampling 的 timing analysis 与通常的做法不同: 通常情况下, clock edge 和 data signals 被采样的时刻之间存在恒定的时间差。这是因为用于采样的 clock 与 data signals是同步的。但是对于 01-signal sampling, @data 的采样是用 @stable_clk完成的。因此采样时刻与 data signals自带的 timing无关。相反, logic 仅选择接近 rising clock edge的 @data_clk_samp 值。

因此, data clock、 rising edge 的时刻与实际采样发生的时刻之间存在随机时间差。这个方法怎么可能可靠呢?

logic design中有一个单独的页面介绍 timing 的基础知识。该页面解释了 tsu 和 thold的含义。长话短说, flip-flop的 input port 必须在 clock 的 rising edge 之前和之后保持稳定(假设 flip-flop 在 rising edge上激活)。 tsu 定义了 input port 必须在 rising edge之前稳定的时间。 thold 定义了 input port 在 rising edge之后必须保持稳定的时间。如果违反这些条件之一, flip-flop对 rising edge 的响应将不可预测。

可以用另一种方式来看待这个问题: input port 必须在 rising edge周围的特定时间段内保持稳定。我们称这个时间段为 Δt = tsu + thold。基于 Δt 和其他参数,我们现在应该找到保证可靠运行的 timing requirements 。

整个 timing analysis 是基于 @data_clk_guard 为高、 @data_clk_samp 为低的情况。发生这种情况时, clock cycle 后会检测到“0 1”模式。换句话说,在下一个 clock cycle上, @data_clk_samp_d 将是“0”, @data_clk_samp 将是“1”。 @fifo_wr_en 将因此而变高,因此 @data_samp 必须包含数据源预期的值。

因此,分析将集中在这个问题上: 当 @data_clk_guard 为高电平、 @data_clk_samp 为低电平时,对 @data 有什么要求才能保证信息正确到达?

分析将分两部分进行: 在这两个部分中,我都假设 @data_clk_guard 为高电平, @data_clk_samp 为低电平。在第一部分中,问题是: 在不打破这个假设的情况下, @data_clk 可以从低到高变化的最新时刻是什么?然后我将找到关于 @data 的 timing requirement ,以确保 @data_samp 包含正确的值。

在分析的第二部分,我会问相反的问题: 在不打破 @data_clk_guard 和 @data_clk_samp假设的情况下, @data_clk 最早能从低电平变为高电平的时刻是多少?接下来我会对 timing requirements做类似的分析。

但首先,让我们定义一些符号:

第一部分分析

这个 timing diagram 展示了 @stable_clk的两个 clock cycles 。在下面的讨论中, @data_clk_guard 将其新值从 rising edge 上的 @data_clk 复制到右侧。同样, @data_guard 将其新值从 @data 复制到同一 clock edge上。

同样的原理, @data_clk_samp 和 @data_samp 与左边的 @stable_clk的 rising clock edge 相关。

Timing diagram for late @data_clk scenario

在这种情况下, @data_clk 恰好在黄色区域的末端变为高电平。 flip-flop的 timing requirements 被侵犯,所以结果不可预测。但有可能 @data_clk_guard 会高, @data_clk_samp 会低。

然而,如果 @data_clk 稍后改变其值, @data_clk_guard 肯定会很低,因为 flip-flop的行为是可以预测的: 在这种情况下, input port 在整个黄色期间都处于低电平。这就是为什么我们可以这样说: 如果 @data_clk_guard 为高且 @data_clk_samp 为低,则 @data_clk 从低到高的变化于上面 timing diagram 中所示的情况。因此, timing diagram 显示了 @data_clk 在最晚可能时刻发生变化的场景。

为了确保 @data_guard 包含可靠的值, @data 必须在黄色区域之前保持稳定。这给了我们第一个 timing requirement: @data 必须在 @data_clk的 rising edge之前稳定 Δt 的时间段。

注意,如果 @data_clk 提前从低电平变为高电平,这个 timing requirement 仍然可以保证 @data_guard的 tsu 要求。因此, flip-flops的 tsu 在 @data_clk_guard 为高、 @data_clk_samp 为低的所有场景下都有保证。

上面的 timing diagram 没有显示任何与 skew相关的内容。为了考虑到 skew , timing requirement 为: @data 必须在 @data_clk的 rising edge之前稳定 Δt + tskew 的时间段。

本场景无需考虑 jitter ,因为讨论中只涉及一台 clock edge 。

第二部分分析

这是针对此场景的 timing diagram :

Timing diagram for early @data_clk scenario

在这种情况下, @data_clk 恰好在 @stable_clk的前一个 clock edge的黄色区域的开始处变为高电平。

毫无疑问, @data_clk_guard 在这种情况下会很高。然而, @data_clk_samp 的价值是不可预测的,因为之前的 clock cycle违反了 timing 。和以前一样, @data_clk_samp 有可能会很低。但如果 @data_clk 早于这个改变数值的话, @data_clk_samp 肯定会高。

因此,如果 @data_clk_guard 为高且 @data_clk_samp 为低,则 @data_clk 从低到高的变化于上面 timing diagram 中所示的时间。因此, timing diagram 尽早展现了 @data_clk 发生变化的场景。

为了确保 @data_guard 包含正确的值, @data 必须稳定在黄色区域向右之后

根据上面的 timing diagram , @data_clk的 rising edge 与第二个黄色区域结束的时间差为 Δt + tclk。但我们还需要考虑 skew 和 jitter 。因此, @data 必须在 @data_clk之后的 Δt + tclk + tskew + tj 时间内保持稳定。

请注意,如果 @data_clk 较早地从低变为高,则此 timing requirement 仍然覆盖 @data_guard的 hold 要求。因此, flip-flops的 thold 在 @data_clk_guard 为高、 @data_clk_samp 为低的所有场景下都有保证。

timing requirements

总结上面的 timing analysis ,这是保证 01-signal sampling可靠运行的两个 timing requirements :

这些要求可能看起来很复杂,但通常很容易确保实现它们。例如,如果 @data 随着 @data_clk的 falling edge一起改变,通常很容易保证这些要求。如果 @stable_clk 的速度是 @data_clk的三倍,通常就足够了。

在大多数情况下,无需知道 Δt、 tskew 或 tj的准确值。根据上述两个要求,计算 Δt 和 Δt + tskew + tj 允许的大小通常就足够了。如果 @stable_clk的频率足够高,这两个表达式的值通常会大于 FPGA的实际可能值。

IOB registers应该用于最小化 FPGA和 input ports (tskew) 之间的 timing 差异。另外, timing constraints 应该与这些 input ports 相关联地编写,以确保使用IOB registers

01-signal sampling的变体

在到目前为止的讨论中,我假设 @data 与 data_clk的 falling edge一起变化。如果 @data 与 @data_clk的 rising edge一起变化,则应调整 logic ,使其在 @data_clk_guard 为低电平且 @data_clk_samp 为高电平时变为活动状态。换句话说, logic 应该通过查找“1 0”模式来检测 @data_clk 的 falling edge 。

还可以选择不同的标准来确定何时获取 @data的值。例如,将 @fifo_wr_en 延迟几个 clock cycles可能会更好。有时, @fifo_wr_en 的激活时间最好早于上述建议。这取决于 @data_clk 和 @data之间的时序关系。参考信号源的数据表,按照上图分析 timing 。

如果 @data_clk的频率比较高,可以使用 DDR registers 来采样 @data_clk 和 @data。实现此解决方案的 logic 稍微复杂一些,但原理相同。

@data_guard 真的是 metastability guard吗?

这个问题的简短答案是肯定的。 @data 与 @stable_clk异步,因此 @data_guard的 timing requirements 不保证。

但让我们将讨论范围缩小到实际使用 @data_guard内容的 clock cycles : 请注意,上面的两个 timing requirements 确保实现 @data_guard 的 flip-flops 可靠运行。这些 flip-flops 的 tsu 和 thold 都是有保障的。

因此, @data_guard 并不是真正用作 metastability guard。从这个 register 的使用方式来看,它的功能仅相当于 delay register。但如果物理信号 (@data) 出现异常,额外的 register 可以防止 timing violations 发生,这并没有什么坏处。当信号通过连接器连接到 FPGA 时,这一点尤其重要。

一个现实生活中的例子

不同的页面上有一个 logic 与 OV7670 camera sensor 连接的示例。 logic 通过 01-signal sampling从该相机传感器获取像素数据。 inputs 的摄像头传感器如下:

input       pclk_in;
   input [7:0] D_in;
   input       hsync_in, vsync_in;

执行 01-signal sampling 的 logic 如下:

(* IOB = "TRUE" *) reg [7:0] D_guard;
   (* IOB = "TRUE" *) reg       pclk_guard, hsync_guard, vsync_guard;

   reg [7:0]  D;
   reg 	      pclk, hsync, vsync;

   wire       sample_valid;
   reg 	      previous_pclk;

   always @(posedge stable_clk)
     begin
	// Metastability guards on asynchronous inputs
	D_guard <= D_in;
	pclk_guard <= pclk_in;
	hsync_guard <= hsync_in;
	vsync_guard <= vsync_in;

	D <= D_guard;
	pclk <= pclk_guard;
	hsync <= hsync_guard;
	vsync <= vsync_guard;

        previous_pclk <= pclk;
     end

   assign sample_valid = pclk && !previous_pclk;

为了清楚起见,此处提供的 Verilog 代码与有关 OV7670的页面上的 Verilog 代码之间存在细微差别。这些差异对 logic 的工作方式没有影响。

让我们将此 Verilog 代码与我在本页顶部提供的 Verilog 代码进行比较。 signals 的名称不同,但含义相同: 我们现在有 @D_in、 @hsync_in 和 @vsync_in,而不是 @data。我们现在有 @pclk_in,而不是 @data_clk。我们现在有 @sample_valid,而不是 @fifo_wr_en。名称的变化可能会令人困惑,但上面的 Verilog 代码没有变化。

请注意 registers声明之前的“(* IOB = "TRUE" *)”部分。使用 Vivado时,这是请求将 registers 插入 IOBs的可能方法。

在此示例中,未显示 FIFO 。这是因为我们不想将所有数据写入 FIFO: 当 @sample_valid 为高电平时,意味着 @D、 @hsync 和 @vsync 包含来自相机传感器的正确值。但这并不意味着我们要将 @D 写入 FIFO: 取决于 @hsync 和 @vsync。因此, OV7670 的示例中还有额外的 logic ,可确保仅将像素写入 FIFO。

但让我们进入有趣的部分: timing 计算。

本例中 @stable_clk 的频率为 100 MHz。 @pclk_in 的频率是 25 MHz。根据 OV7670的datasheet,在 @pclk_in 由高变低(falling edge)后的 5 ns 期间,信号 @D_in、 @hsync_in 和 @vsync_in 保证稳定。

@pclk_in的 clock cycle 是 40 ns。因此,从 falling edge 到 rising edge 的距离是 20 ns。现在我们来与 timing requirements进行比较。

第一个 timing requirement 是 @D_in、 @hsync_in 和 @vsync_in 必须在 @pclk_in的 rising edge之前稳定 Δt 的时间段。实际上,这些信号从 falling edge之后 5 ns 开始就稳定了。因此,这些信号至少在下一个 rising edge之前的 15 ns 是稳定的。回想一下 Δt = tsu + thold。所以 timing requirement 其实就是 tsu + thold 比 15 ns小。对于每台 FPGA都是如此。

第二个要求是这些信号在 @pclk_in的 rising edge之后至少在 Δt + tclk + tskew + tj 的时间段内保持稳定。但这些信号仅因 falling edge而改变。所以要求是 Δt + tclk + tskew + tj 比 20 ns小。 tclk 等于 10 ns ,因为 @stable_clk的频率是 100 MHz。因此实际的要求是 Δt + tskew + tj 比 10 ns小。这对于每台 FPGA来说都是显而易见的。

此示例演示了如何在不了解 FPGA的确切 timing parameters的情况下轻松确保 timing requirements 。

结论

当 data rate 相对于 FPGA 可支持的 clock 频率较低时,01-signal sampling 是一个出色的解决方案: data clock 不必稳定。此外,不必提前知道 data clock 的确切频率。保证两台 timing requirements就足够了。

此方法还有其他优点: 如果此 clock 短暂处于非活动状态,唯一的结果是在该特定时间段内不会收集 data 。 clock 的任何故障造成的损害仅限于 data flow的中断。这会导致系统出现明显的故障,但这种故障看起来像是 clock 的问题(而不是FPGA 被鬼魂困扰)。

因此,尽管 data signals 的 sampling 具有固有的随机性,但 01-signal sampling 是 source synchronous input的可靠且稳健的解决方案。唯一真正的缺点是 data rate的限制。

此页面由英文自动翻译。 如果有不清楚的地方,请参考原始页面
Copyright © 2021-2024. All rights reserved. (6f913017)