【问题标题】:Fastest way to react to an external trigger signal对外部触发信号做出反应的最快方式
【发布时间】:2019-04-30 21:33:55
【问题描述】:

外部触发信号被发送到 FPGA。只有当and1 和and2 在接收到触发时也为高电平时,才应接受触发信号。如果触发被接受,则应创建一个持续时间为 10 微秒的触发输出脉冲。目标是尽量减少 FPGA 接受/拒绝这个外部触发信号的时间。

module trigger(
input CLK, 
input trigger,
input and1,
input and2,

output triggerOut, 
);

解决方案的第一次尝试如下;

assign triggerOut = trigger & and1 & and2;

反应时间很快,但我认为这不允许实现 10 微秒的触发持续时间。

目前的解决方案如下;

always @(posedge CLK) begin

  if(trigger & and1 & and2)
    triggerOut <= 1;

end

此解决方案允许添加一个计数器,从而实现 10 微秒触发脉冲。需要注意的是,现在对外部触发器的反应时间与 CLK 的频率有关。提高 CLK 频率可以提高反应时间,但提高 CLK 的频率是有限度的。

另一种可能的解决方案可能是对不断变化的触发输入敏感;

always @(posedge trigger) begin

  if(trigger & and1 & and2)
    triggerOut <= 1;

end

我已经读到这可能是不好的做法。我不清楚为什么使用@(posedge CLK) 优于@(posedge 触发器)。什么定义了 FPGA 对@(posedge trigger) 等灵敏度的反应时间?我想这仍然必须以某种方式与 CLK 相关联 - 这种方法可能更快吗?

有没有更好的方法来提高对触发器输入的反应时间?

【问题讨论】:

  • 如果触发器是 FPGA 内部的时钟,这是一个不错的做法。也就是说,它绑定到时钟输入焊盘,和/或分配给 FPGA 内的全局缓冲区。需要注意的是,10us 计数器仍应绑定到 clk,这将导致跨域时钟问题,其中由 CLK 控制的顺序块必须接受与 CLK 不同步但与 TRIGGER 同步的输入。
  • 无论如何,无论您检测到 TRIGGER 的速度有多快。只要将 10us 计数器绑定到 CLK,反应时间就可以慢到一个完整的 CLK 周期。

标签: verilog fpga


【解决方案1】:

如果不采用异步逻辑,就很难达到这个目标。幸运的是,最近的 FPGA 将电平触发锁存器作为原语,因此不完整的组合总是块并不总是一个不好的做法。

OTOH,10us 宽度的 triggerOutput 信号需要一个同步时钟来计算时间,但是这个定时器首先会被异步输入触发。这肯定会带来跨域时钟的问题,而简单的解决方案(与两个触发器同步)会引入一些延迟,因此 10us 脉冲可能不会在内部接受触发器的同时开始,和/或正好是 10us 宽度.为避免 triggerOutput 的亚稳态问题,可将其用作 1 到 10 计数器的异步复位信号。

总而言之,这个模块是对触发检测器和接受器的异步方法的实现:

module detect_trigger (
  input wire clk,  // let's say it's 1 MHz (period = 1us)
  input wire trigger,
  input wire and1,
  input wire and2,
  output reg triggerOut
  );

  reg [3:0] cnt = 4'd0;
  initial triggerOut = 1'b0;
  always @* begin
    if (cnt >= 4'd11)
      triggerOut = 1'b0;
    else if (trigger && and1 && and2)
      triggerOut = 1'b1;
  end

  always @(posedge clk or negedge triggerOut) begin
    if (triggerOut == 1'b0)
      cnt <= 4'd0;
    else if (cnt < 4'd11)
      cnt <= cnt + 4'd1;
  end
endmodule

一个测试台模块可以是这样的:

module tb;
  reg clk;
  reg trigger;
  reg and1, and2;
  wire triggerOut;

  detect_trigger uut (
    .clk(clk),
    .trigger(trigger),
    .and1(and1),
    .and2(and2),
    .triggerOut(triggerOut)
  );

  initial begin
    $dumpfile ("dump.vcd");
    $dumpvars(1, tb);
    clk = 1'b0;
    and1 = 1'b0;
    and2 = 1'b0;
    trigger = 1'b0;

    repeat (5) begin
      #3023;
      and1 = 1'b1;
      #2419;
      and2 = 1'b1;
      #1865;
      and1 = 1'b0;
      and2 = 1'b0;
    end
    $finish;
  end

  always begin
    clk = #500 ~clk;
  end

  always begin
    trigger = 1'b0;
    #1753;
    trigger = 1'b1;
    #2;
  end
endmodule

这个测试台的输出如下:

您可以在此处使用 EDA Playground 修改和运行上述设计: https://www.edaplayground.com/x/3SGs

【讨论】:

    猜你喜欢
    • 2017-08-19
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2019-05-27
    • 2021-09-26
    相关资源
    最近更新 更多