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
这里是如何连线的:
我仍然想知道时钟选通脉冲的用途,因为如果我想更好地了解我的电路和所有关于同步性的话,你让我看起来好像应该知道这个。
抱歉,如果这里的任何内容看起来很明显,但我开始使用这个新的 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
这里是如何连线的:
我仍然想知道时钟选通脉冲的用途,因为如果我想更好地了解我的电路和所有关于同步性的话,你让我看起来好像应该知道这个。