Search code examples
verilogfpgamodelsimquartusintel-fpga

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


Sorry if anything in here seems obvious but I am starting out in this new FPGA thing and I really enjoy it so far but this is driving me crazy. Here is the Verilog code for a block that should in principle do the following to an 8 bit register:

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

This works perfectly in simulation but fails on the FPGA (DE10-Nano board, if interested). I should also point out that this gets driven by a clock passed trough a PLL on the FPGA that is then passed trough a divideByN block. Here is the code for the divideByN block:

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

The divideByN has also been tested in simulation and works fine. I actually made a simulation in which the divideByN is connected to the "bouncer_block" if I can call it like that and it also works.

Everything simulates but nothing works in real life....but isn't it always like that :P

I hope someone can help me figure this out because I really want to learn more about FPGA and use them in future projects.

If you read all this you are awesome and I wish you an amazing day :)


Solution

  • Your bit bouncer is not operating synchronously to the system clock and neither does it have a reset condition, which is a recipe for trouble.

    A better approach is to use a clock strobe and test for it on edges of the main system clock. Also, all inputs from tactile buttons should be synchronised to the system clock and debounced. Something like this:

    Schematic

    enter image description here

    RTL

    enter image description here

    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
    

    ClockStrobe

    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
    

    Sync

    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
    

    Debounce

    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