ModelSim 仿真有效,但 FPGA 失败。我错过了什么?

ModelSim simulation works but FPGA fails. What am I missing?

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

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和使用 他们在未来的项目中。

如果您阅读了所有这些内容,那您真是太棒了,祝您度过美好的一天:)

您的 bit bouncer 未与系统时钟同步运行,也没有重置条件,这很容易出问题。

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

示意图

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

我曾尝试添加重置但没有成功,但我已经创建了自己的 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

这里是如何连线的:

我仍然想知道时钟选通脉冲的用途,因为如果我想更好地了解我的电路和所有关于同步性的话,你让我看起来好像应该知道这个。