Search code examples
verilogfsm

FSM Verilog - 1 pushbutton for both start&stop


So I am pretty new to Verilog and I am trying to write a simple FSM.

Input a is a push button and by pushing it starts the machine. But every other next state, after initially pressing a, causes to go back to the start/initial state.

input clk, reset;
input a,b,c;

reg [1:0] state;
reg [1:0] nextstate;

parameter = START=2b'0,
            STATE1=2b'1,
            STATE2=2b'11;

always @(posedge clk)
 if(reset) state <= START;
 else state<=nextstate;

always @(state, a)
 case (state)
   START: begin if(a) nextstate<=STATE1; else nextstate<=START; end
   STATE1: begin if(a) nextstate<=START; else if(b) nextstate<=STATE2; else nextstate<=STATE1; end
   STATE2: begin if(a) nextstate<=START; else if(c) nextstate<=STATE1; else nextstate<=STATE2; end
 endcase

Keeping your finger on a now means my state is alternating between STATE1 and START every positive edge of clk. How do I fix this?


Solution

  • A simple solution is to track the "edge" of the button, rather than the current state. For example:

    reg aPressed, aPrev;
    always @(posedge clk)
        aPrev<=a;
    
    always@(*)
        if (a&&!aPrev) // a is high now, but was low last cycle
            aPressed = 1;
        else
            aPressed = 0;
    

    In this code, aPressed is asserted only when a was low last cycle, and is high now (i.e. it was just pressed). If you replace a with aPressed in your next state logic, the user will be required to release a for a least one cycle before aPressed will trigger again.

    always @(*)
        case (state)
            START: begin 
                if(aPressed) nextstate=STATE1; 
                else nextstate=START;
             end
            STATE1: begin 
                if(aPressed) nextstate=START; 
                else if(b) nextstate=STATE2;
                else nextstate=STATE1; 
            end
            STATE2: begin 
                if(aPressed) nextstate=START; 
                else if(c) nextstate=STATE1; 
                else nextstate=STATE2; 
            end
         endcase
    

    Side note: it's good practice to use always@(*) for combinational logic, rather than specifying the sensitivity list (always@(state,a))