【问题标题】:ModelSim simulation works but FPGA fails. What am I missing?ModelSim 仿真有效,但 FPGA 失败。我错过了什么?
【发布时间】:2020-04-19 05:30:20
【问题描述】:

对不起,如果这里的任何东西看起来很明显,但我开始使用这个新的 FPGA 东西,到目前为止我真的很喜欢它,但这让我发疯了。 这是一个块的 Verilog 代码,原则上应该对 8 位寄存器执行以下操作:

00000001

00000010

00000100

.....

01000000

10000000

01000000

00100000

module bit_bouncer(clock, enable, bouncer_out);
//INPUTS PORTS
input clock;
input enable;
//OUTPUTS PORTS
output bouncer_out;
//INPUT DATA TYPE
wire clock;
wire enable;
//OUTPUT DATA TYPE
reg [7:0] bouncer_out = 8'b00000001;
//Register to store data
reg direction = 0;

//CODE STARTS HERE
always @ (posedge clock) begin
    if(enable) begin
        bouncer_out = direction ? (bouncer_out >> 1) : (bouncer_out << 1);
        direction <= (bouncer_out == 8'b00000001 || bouncer_out == 8'b10000000) ? ~direction : direction;
    end
end

endmodule

这在模拟中完美运行,但在 FPGA(DE10-Nano 板,如果有兴趣)上失败。 我还应该指出,这是由通过 FPGA 上的 PLL 传递的时钟驱动的,然后 通过了 divideByN 块。 这里是 divideByN 块的代码:

module clk_divn #(
parameter WIDTH = 20,
parameter N = 1000000)

(clk,reset, clk_out);

input clk;
input reset;
output clk_out;

reg [WIDTH-1:0] pos_count = {WIDTH{1'b0}};
reg [WIDTH-1:0] neg_count = {WIDTH{1'b0}};
wire [WIDTH-1:0] r_nxt = {WIDTH{1'b0}};

 always @(posedge clk)
 if (reset)
 pos_count <=0;
 else if (pos_count ==N-1) pos_count <= 0;
 else pos_count<= pos_count +1;

 always @(negedge clk)
 if (reset)
 neg_count <=0;
 else  if (neg_count ==N-1) neg_count <= 0;
 else neg_count<= neg_count +1; 

assign clk_out = ((pos_count > (N>>1)) | (neg_count > (N>>1))); 
endmodule

divideByN 也已经过模拟测试并且工作正常。 我实际上做了一个模拟,如果可以的话,divideByN 连接到“bouncer_block” 这样称呼它,它也可以工作。

一切都是模拟的,但在现实生活中没有任何效果......但不是总是这样吗:P

我希望有人能帮我解决这个问题,因为我真的很想了解更多关于 FPGA 和使用 他们在未来的项目中。

如果您阅读了所有这些内容,您会很棒,祝您有美好的一天:)

【问题讨论】:

  • 您需要更详细地解释“失败”的含义。我们看不到您的 FPGA 板。
  • 我连接输出的 8 个 LED 以不可预知的方式一次点亮一个(它跳得非常快并停在一个 LED 上,然后又快速跳到另一个 LED 点亮 LED在它的路径中非常短暂)
  • 您使用的是我们所说的'派生时钟'。由另一个时钟加逻辑生成的时钟。昨天有一个问题here。看看那里的cmets。如果可能的话,在整个设计中使用一个主时钟。 (直到您在几年内获得多个时钟域和时钟域交叉)
  • 我已经按照你说的做了,并使用了来自 FPGA 的直接时钟,我只通过了 divideByN 而不是 PLL。现在我唯一得到的是一个永远亮着的 LED,什么也没有发生(也没有按钮按下会影响它,因为你可能会认为我的逻辑与我的启用相反)。这是我的示意图,向您展示我的实际设置仍然无法正常工作(仍然使用与以前相同的代码,但我将 divideByN 调整为 50 000 000 以尝试从输入时钟获取 1Hz 信号):imgur.com/tegPQLg跨度>
  • 我还编辑了 divideByN 的宽度为 26 以解释 50 000 000 的 N (不是 5 000 000 ......愚蠢的我......)。但它仍然不起作用。现在 LED 像以前一样跳来跳去,但似乎受到了 divideByN 宽度的影响,即使缓冲区对于使用的 N 来说足够大。

标签: verilog fpga modelsim quartus intel-fpga


【解决方案1】:

您的位弹跳器没有与系统时钟同步运行,也没有重置条件,这是一个麻烦的秘诀。

更好的方法是使用时钟选通并在主系统时钟的边缘对其进行测试。此外,触觉按钮的所有输入都应与系统时钟同步并消除抖动。像这样的:

示意图

RTL

BitBouncer

module BitBouncer
(
    input wire clock,
    input wire reset,
    input wire enable,
    input wire clock_strobe,
    output reg[7:0] bouncer_out
);

    // Register to store data
    reg direction = 0;

    // CODE STARTS HERE
    always @(posedge clock)
    begin
        if (reset)
        begin
            bouncer_out = 1;
            direction = 0;
        end
        else if (enable && clock_strobe)
        begin
            bouncer_out = direction ? (bouncer_out >> 1) : (bouncer_out << 1);
            direction <= (bouncer_out == 8'b00000001 || bouncer_out == 8'b10000000) ? ~direction : direction;
        end
    end

endmodule

时钟频闪

module ClockStrobe
#(
    parameter MAX_COUNT = 50000000
)
(
    input wire clock,
    input wire reset, 
    output reg clock_strobe
);

    reg [$clog2(MAX_COUNT) - 1: 0] counter;

    always @(posedge clock)
    begin
        if (reset)
        begin
            counter <= 0;
        end
        else
        begin
            counter <= counter + 1;
            if (counter == MAX_COUNT)
            begin
                clock_strobe <= 1;
                counter <= 0;
            end
            else
            begin
                clock_strobe <= 0;
            end
        end
    end

endmodule

同步

module Sync
(
    input wire clock,
    input wire in,
    output reg out
);

    reg [2:0] sync_buffer;

    initial
    begin
        out = 0;
        sync_buffer = 3'd0;
    end

    always @*
    begin
        out <= sync_buffer[2];
    end

    always @(posedge clock)
    begin
        sync_buffer[0] <= in;
        sync_buffer[2:1] <= sync_buffer[1:0];
    end

endmodule

去抖

module Debounce
#(
    parameter MAX_COUNT = 2500000
)
(
    input wire clock,
    input wire in,
    output reg out
);

    reg previous_in;

    reg [$clog2(MAX_COUNT) - 1:0] counter;

    initial begin
        previous_in = 0;
        counter = 0;
        out = 0;
    end

    always @(posedge clock)
    begin
        counter <= counter + 1;
        if (counter == MAX_COUNT)
        begin
            out <= previous_in;
            counter <= 0;
        end
        else if (in != previous_in)
        begin
            counter <= 0;
        end
        previous_in <= in;
    end

endmodule

【讨论】:

  • 您在我写这篇文章的答案时确实发布了这个 XD 让我现在阅读它:P
  • 好的,如果我没弄错,你就是在去抖我的开关,但我忘了提到它们已经在硬件上去抖了(抱歉)。但是您能否解释一下时钟频闪灯的功能以及它的用途(当然如果您有时间的话)。并且感谢那个 clog2 函数,从昨天开始我一直想删除那些讨厌的 WIDTH 参数:P
  • 关于去抖动,我的开发板手册声称他们已经被去抖动了,但是根据我的经验,我的开发板按钮已经受到了这样的打击,我做了额外的去抖动只是为了当然。
  • 关于时钟选通,它每MAX_COUNT个产生一个时钟周期的脉冲宽度。然后 BitBouncer 在系统时钟的每个上升沿测试选通脉冲的值。这使逻辑与系统时钟保持同步,因此只有一个时钟域。通过尝试与时钟分频器同步,它会因大量传播延迟而滞后,因此极不可能与系统时钟边缘对齐并成为另一个质量差的时钟域。
  • 我会注意的:P 你有同样的板子吗?
【解决方案2】:

我尝试添加重置但没有成功,但我自己做了divideByN并保留了Charles建议的重置,现在它可以完美地工作。我认为我在网上获取的 divideByN 代码可能无法正确合成。这是我的 divideByN 新代码:

module my_div_n #(parameter N = 1_000_000, parameter WIDTH = 20) (clock_in, 

clock_out);
input wire clock_in;
output reg clock_out;
reg[WIDTH-2:0] counter; //WIDTH-2 because the last bit is taken care of by the fact that we flip the output (it acts as the last bit)

always @ (posedge clock_in) begin
    counter <= counter + 19'b1;
    if(counter == N>>1) begin
        counter <= 0;
        clock_out <= !clock_out;
    end
end

endmodule

还有我的 bit_bouncer 的代码:

module bit_bouncer(clock, enable, reset, bouncer_out);
//INPUTS PORTS
input clock;
input enable;
input reset;
//OUTPUTS PORTS
output [7:0] bouncer_out;
//INPUT DATA TYPE
wire clock;
wire enable;
wire reset;
//OUTPUT DATA TYPE
reg [7:0] bouncer_out;
//Register to store data
reg direction;

//CODE STARTS HERE
always @ (posedge clock) begin
    if(reset) begin
        bouncer_out <= 8'b00000001;
        direction <= 0;
    end
    else if(enable) begin
        bouncer_out = direction ? (bouncer_out >> 1) : (bouncer_out << 1);
        direction <= (bouncer_out == 8'b00000001 || bouncer_out == 8'b10000000) ? ~direction : direction;
    end
end

endmodule

这里是如何连接的:

我仍然想知道时钟频闪的用途,因为如果我想更好地了解我的电路以及所有关于同步性的信息,我似乎应该知道这一点。

【讨论】:

    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2022-01-13
    • 1970-01-01
    • 2015-11-15
    • 2023-03-19
    • 2017-02-06
    • 1970-01-01
    相关资源
    最近更新 更多