0
\$\begingroup\$

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
\$\endgroup\$
2
  • \$\begingroup\$ So - in your revised code - where are you setting "clean" ? \$\endgroup\$
    – Majenko
    Commented Jun 21, 2014 at 23:50
  • \$\begingroup\$ I talk about denouncing in the second half of this answer: electronics.stackexchange.com/a/112454/16047 \$\endgroup\$
    – stanri
    Commented Jun 22, 2014 at 12:04

3 Answers 3

2
\$\begingroup\$

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.

\$\endgroup\$
7
  • \$\begingroup\$ well, this is the code i am running after what you said should be done... \$\endgroup\$
    – Kanupriya
    Commented Jun 21, 2014 at 22:20
  • \$\begingroup\$ well, i have edited the post and added the code i am running after what you said should be done... this module takes input SWITCH 5bit reg vector and returns 'clean' signal (also 5bit reg vector) running on slowclock, this clean signal goes to code that increments or decrements on input... that code remains the same except that it is in always @ (SWITCH) block now problem persists!! \$\endgroup\$
    – Kanupriya
    Commented Jun 21, 2014 at 22:27
  • \$\begingroup\$ But... you don't want to increment WHILE it is pressed, do you? You want to increment WHEN it is pressed. \$\endgroup\$
    – Majenko
    Commented Jun 21, 2014 at 22:29
  • \$\begingroup\$ i have to increment/decrement once every movement of joystick... say it is moved up and back => one operation, it is moved right and back => one operation \$\endgroup\$
    – Kanupriya
    Commented Jun 21, 2014 at 22:46
  • \$\begingroup\$ what change do i make to make WHEN it is pressed from WHILE it is pressed?? further, since sensitivity list contains SWITCH, the block would run only once every time SWITCH incurs a change... hence only one time increment i assume...so isnt it already WHEN it is pressed! \$\endgroup\$
    – Kanupriya
    Commented Jun 21, 2014 at 22:53
2
\$\begingroup\$

Your problem is not about debouncing at all. It's actually about how you've coded the second part of your listing. Instead of looking for edge events on the switches, you're simply testing their state once per clock edge. This means that insetad of one increment or decrement per switch operation (which is what I think you want), you get one increment or decrement per clock edge, as long as the switch is held.

\$\endgroup\$
2
  • \$\begingroup\$ do you mean to say it should have been posedge slowclk in the sensitivity list of always@? if yes, then i have tried dat... in fact leads to no change at all... despite any switch operation.. i dont have any explanation to this behaviour though... \$\endgroup\$
    – Kanupriya
    Commented Jun 21, 2014 at 22:35
  • \$\begingroup\$ 1) it is indeed per clock edge,but i had slowed down my clock to 1Hz... and joystick isnt held for longer than that... hence it should be one operation per clock edge should be same as one operations per change in switch However, i have modified the code now... 2) i have changed it to always @ (SWITCH) block.... where SWITCH comes in through the debounce code that i have added... problem persists! \$\endgroup\$
    – Kanupriya
    Commented Jun 21, 2014 at 22:43
0
\$\begingroup\$

image if you had a signal sequence in time like this 0000000000000000000010101010111111011111111111111 how might you detect the transition from 0 to 1 once, but since it could eventially go back to 0 some time, this must be only ignored within a given window.

Think of the signal changing as an "event". You might also have a "hardware input" and a "debounced input" were the second is the accepted signal that was not just switch noise.

The first thing that happens is you might detect the event, regardless of weather it occures multiple times. I imagine this may be done by "saving" the last "debounced" input that was accepted and assigned and comparing against the present input to the system.

Basically you are checking weather your input one clock cycle ago is your current input, from here, you can generate a trigger signal that is used by the remaining debounce logic that determines the "real" input.

An implimentation could for example be a state machine were the hardware idles in a state waiting for the trigger above and transitions to a waiting state for some period of time before going back to the idling. This can be implimented with a known clock rate and a counter, by checking the counter value you can choose when to return from the second state to the first and repeat.

If you only assign the "hardware input" to the "debounced input" when in the first state you will find that the signal only changes as fast the the state machine can change to the second state, count, and then return to sampling.

I think if you have multiple inputs (different buttons) they may require that they are handeled individually by instances of a circuit like this.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.