Search code examples
verilogfpgaintel-fpgaquartus

Why does this code work only partially?


This code is supposed to increment a counter (outputting to LEDs) when one button is pushed and decrement it when the other one is pushed. It works OK with decrementing but on incrementing it changes LEDs to random configuration instead.

module LED_COUNTER( CLK_50M, LED, Positive, Negative );
input wire CLK_50M;
input wire Positive;
input wire Negative;
output reg[7:0] LED;

always@( posedge Positive or posedge Negative )
begin
    if(Positive == 1)
        LED <= LED + 1;
    else
        LED <= LED - 1; 
end

endmodule

I am using this board: http://www.ebay.com/itm/111621868286. The pin assignment is:

The connections:

After swapping pin assignments for buttons the behavior stays the same.


Solution

  • As others have already pointed out, you should be clocking with the CLK_50M and you should de-bounce your inputs (some FPGAs do it for you automatically, check your manual).

    The reason you see partial functionality is from the way the synthesizer interprets the RTL. If the sensitivity list is edge triggered and that signal is referenced in the body of the always block, then the synthesizer will think it is an asynchronous level sensitive signal. This is intend for asynchronous reset & set (sometimes named clear & preset). ASIC design typically use flops with asynchronous reset in most the design. FPGAs tend to have a limited number of flops with asynchronous set or rest, so check your manual and use sparingly.

    With your code, Negative is the clock and Positive is treated as an active high asynchronous input.

    Modify the code to a functional behavioral equivalent (in simulation) seen below, then Positive will be the clock and Negative will be the active high asynchronous input.

    always@( posedge Positive or posedge Negative )
    begin
        if(Negative == 1)
            LED <= LED - 1;
        else
            LED <= LED + 1; 
    end
    

    There are several resource for learning Verilog available online (use your favorite search engine), and I have some resources posted on my profile though more aimed at SystemVerilog.
    Here is some pseudo code to point you in the correct direction for your project:

    always @(posedge CLK_50M)
    begin
      past_Positive <= Positive;
      // ...
      case({/* ... , */ past_Positive,Positive})
        4'b0001 : LED <= LED + 1;
        4'b0100 : LED <= LED - 1;
        // ...
      endcase
    end