State Machine for the Spartan 3E Knob

The following code is a simple state machine that determines the direction that the knob on the Spartan 3E is turning and outputs a clock signal (Count) as it turns. A & B are the inputs from the encoders on the knob, RST & CLK are the reset and clock obviously. Count is the clock signal that goes two cycle for each click of the knob. Dir is the current direction of the knob, 0 for clockwise and 1 for counter-clockwise. Be sure to de-bounce the A & B inputs from the knob as they will have lots of noise and cause the state machine to be unstable.

module StateMachine(Dir, Count, A, B, RST, CLK);
  output reg Dir;
  output reg Count;
  input A;
  input B;
  input RST;
  input CLK;

  reg [1:0]PS, NS;

  parameter [1:0] ST_NORM = 'b00,
                  ST_A = 'b01,
                  ST_B = 'b11,
                  ST_C = 'b10;

  initial
    begin
      PS <= ST_NORM;
      Count = 0;
    end

  always @(negedge RST or posedge CLK)
    if (!RST)
      PS <= ST_NORM;
    else if (CLK)
      PS <= NS;

  always @(A or B)
    begin
      case (PS)
        ST_NORM:
          if (A & !B)
            begin
              Dir = 0;
              Count = 1;
              NS = ST_A;
            end
          else if (!A & B)
            begin
              Dir = 1;
              Count = 1;
              NS = ST_C;
            end
          else
            NS = ST_NORM;
        ST_A:
          if (A & B)
            begin
              Dir = 0;
              Count = 0;
              NS = ST_B;
            end
          else if (!A & !B)
            begin
              Dir = 1;
              Count = 0;
              NS = ST_NORM;
            end
          else
            NS = ST_A;
        ST_B:
          if (!A & B)
            begin
              Dir = 0;
              Count = 1;
              NS = ST_C;
            end
          else if (A & !B)
            begin
              Dir = 1;
              Count = 1;
              NS = ST_A;
            end
          else
            NS = ST_B;
        ST_C:
          if (!A & !B)
            begin
              Dir = 0;
              Count = 0;
              NS = ST_NORM;
            end
          else if (A & B)
            begin
              Dir = 1;
              Count = 0;
              NS = ST_B;
            end
          else
            NS = ST_C;
      endcase
    end
endmodule

Leave a Reply