To Remove Debounce from MicroJoystick installed on LogicStart MegaWing (FPGA) and read input correctly

debouncefpgaverilog

I am working on an FPGA board and coding in Verilog. I am trying to use the MicroJoystick installed on LogicStartMegaWing, the shield with Papilio-One 500k (my FPGA board).
I have to do simple tasks like increment or decrement a reg variable on different movements of the joystick.
Initially I was running the above code in an alwaya @ (SWITCH) block i.e. the block will be running whenever there is a movement in joystick (on this board joystick shares the pins with five switches). This led to complete loss of control of the cursor on the VGA display (very fast multiple increments or decrements), even on slightest movement of the joystick.

Then I ran the same code in an always @ (slowclk) block where 'slowclk' is a 1Hz clock. This led to improvement as there were finite, slower increments or decrements.
However, the problem is not completely resolved i.e. on one move of the joystick there are multiple increments to the reg.

How can I remove this debounce from the input through the joystick? Need some help on this. I am also putting my code to generate the slowclk and to use the joystick.

THE COMPLETE REVISED CODE:

 //This increments/decrements number and displays on seven segment display on
 //up/down movement of joystick; in an array of 8 LEDS shifts the glowing LED to
 //right or left on left/right movement of joystick

 //joystick (i.e. [4:0] SWITCH here) by default gives all ones

 // input clock is at 32 Mhz

module Display(

input clk,
input [4:0] SWITCH,
output reg [3:0] Seg7_AN,
output reg Seg7_A,
output reg Seg7_B,
output reg Seg7_C,
output reg Seg7_D,
output reg Seg7_E,
output reg Seg7_F,
output reg Seg7_G,
output Seg7_DP,
output reg [7:0] LED
);

reg [3:0] number;
wire [4:0] clean;

Debounce stable(.clk(clk), .SWITCH(SWITCH), .clean(clean));

initial
begin
LED = 8'b00000001;
end

assign Seg7_DP = 1;

always @ (clean)
begin
if(clean[0]==0)
  begin
  if (number==9)
    number <= 0;
  else
    number <= number+1;
  end
else if (clean[1]==0)
begin
if (number==0)
   number <= 9;
else
   number <= number -1;
end
else if (clean[3] == 0)
begin
   if (LED == 8'b00000001)
      LED <= 8'b10000000;
   else
      LED <= LED >> 1;
   end
   else if (clean[4]==0)
   begin
     if (LED == 8'b10000000)
        LED <= 8'b00000001;
     else
        LED <= LED << 1;
end
end

always @ (*)
begin

   Seg7_AN <= 4'b0111;

case (number)
0 : begin Seg7_A<=0; Seg7_B<=0 ; Seg7_C<=0 ; Seg7_D<=0 ; Seg7_E<=0 ; Seg7_F<=0 ; Seg7_G<=1 ; end
1 : begin Seg7_A<=1; Seg7_B<=0 ; Seg7_C<=0 ; Seg7_D<=1 ; Seg7_E<=1 ; Seg7_F<=1 ; Seg7_G<=1 ; end
2 : begin Seg7_A<=0; Seg7_B<=0 ; Seg7_C<=1 ; Seg7_D<=0 ; Seg7_E<=0 ; Seg7_F<=1 ; Seg7_G<=0 ; end
3 : begin Seg7_A<=0; Seg7_B<=0 ; Seg7_C<=0 ; Seg7_D<=0 ; Seg7_E<=1 ; Seg7_F<=1 ; Seg7_G<=0 ; end
4 : begin Seg7_A<=1; Seg7_B<=0 ; Seg7_C<=0 ; Seg7_D<=1 ; Seg7_E<=1 ; Seg7_F<=0 ; Seg7_G<=0 ; end
5 : begin Seg7_A<=0; Seg7_B<=1 ; Seg7_C<=0 ; Seg7_D<=0 ; Seg7_E<=1 ; Seg7_F<=0 ; Seg7_G<=0 ; end
6 : begin Seg7_A<=0; Seg7_B<=1 ; Seg7_C<=0 ; Seg7_D<=0 ; Seg7_E<=0 ; Seg7_F<=0 ; Seg7_G<=0 ; end
7 : begin Seg7_A<=0; Seg7_B<=0 ; Seg7_C<=0 ; Seg7_D<=1 ; Seg7_E<=1 ; Seg7_F<=1 ; Seg7_G<=1 ; end
8 : begin Seg7_A<=0; Seg7_B<=0 ; Seg7_C<=0 ; Seg7_D<=0 ; Seg7_E<=0 ; Seg7_F<=0 ; Seg7_G<=0 ; end
9 : begin Seg7_A<=0; Seg7_B<=0 ; Seg7_C<=0 ; Seg7_D<=0 ; Seg7_E<=1 ; Seg7_F<=0 ; Seg7_G<=0 ; end
default : begin Seg7_A<=0; Seg7_B<=0 ; Seg7_C<=0 ; Seg7_D<=0 ; Seg7_E<=0 ; Seg7_F<=0 ; Seg7_G<=1 ; end 
endcase

end



endmodule





module Debounce(

     clk, SWITCH, clean
    );

input wire clk;
input wire [4:0] SWITCH;
output reg [4:0] clean = 0;

reg [18:0] count = 0;
reg [4:0] new = 0;

SlowClock OneKHz (.clk(clk), .slowclk(slowclk));

always @(posedge slowclk)
begin

    if (SWITCH != new)
    begin                                
        new <= SWITCH;
        count <= 0;
    end
    else if (count == 20) 
     begin
             clean <=new;  
             count <=0; 
     end        
    else                                 
        count <= count+1;
end

 endmodule


module SlowClock(
    input clk,
    output reg slowclk
    );

reg [63:0] i;

parameter delay = 32000;

initial
begin
    slowclk = 0;
    i = 64'd0;
end

always @ (posedge clk)
begin
if (i<delay)
    begin
    i= i+1;
    end
else
    begin
    i = 64'd0;
    slowclk = ~slowclk;
    end
end


endmodule

Best Answer

Bouncing, as I am sure you are aware, occurs when the contacts of a switch or button literally bounce off each other when you activate it. This causes, when working digitally, in a rapid succession of on-off-on-off-on signals, ending up finally with the steady state that is intended.

There are two basic methods of debouncing (lit: removing the bounce) - software and hardware. Hardware methods can be broken down into two types - RC filters and flip-flops. The latter requires a two-pole input that is used to toggle the inputs to a bistable flipflop, and the former effectively treats the switch signal as an AC waveform and low-pass filters it (filters out the high frequency switching noise and leaves the basic HIGH/LOW signals intact).

Neither of those are really applicable for writing in Verilog, as you don't have capacitors, and your joystick isn't a two-pole switch, but it's useful to know the hardware options so you can see how they relate to software.

Software debouncing basically involves emulating a low-pass filter in software. The most common way of doing it is to look at the input and say "How long has the input been at this state?", and that of course requires some form of timing.

The simplest method is to do the following:

  1. Notice when the input has changed state
  2. Flag that it has changed and clear a counter.

At the same time, driven by the clock, for any inputs with the "changed" flag set:

  1. Increment the input's counter
  2. If the counter exceeds a certain limit then clear the "changed" flag and set an output variable to the state of the switch.

That means that every time the switch changes state, which will be multiple times during the pressing of that switch, the counter is cleared, but the changed flag is only set once. Only when the last bounce has happened will the counter be able to count high enough (as it keeps getting reset by the bouncing) to exceed the threshold, and only then will the switches state be passed on to the rest of your code.

The clock wants to be considerably faster than 1Hz. It is generally accepted that any two events that happen faster than 20ms apart appear (to us) to occur at the same time. 50ms starts to become really noticeable, so a debounce period of 10-20ms is usually quite good. So your clock needs to go much faster than that to increment the counter and give good press response resolution. To keep things simple a 1KHz clock is good. That gives a 1ms tick, so when your counter reaches 20 that will be 20ms and a good threshold to have.