I would use a completely separate block of code to debounce any button signals, allowing your state machine process to focus on just the state machine, without having to worry about anything else.
You could use a process like this to debounce the input. You could of course exchange variables for signals in this example (with associated assignment operator replacements).
process (clk)
constant DEBOUNCE_CLK_PERIODS : integer := 256; -- Or whatever provides enough debouncing
variable next_button_state : std_logic := '0'; -- Or whatever your 'unpressed' state is
variable debounce_count : integer range 0 to DEBOUNCE_CLK_PERIODS-1 := 0;
begin
if (rising_edge(clk)) then
if (bouncy_button_in /= next_button_state) then
next_button_state := bouncy_button_in;
debounce_count := 0;
else
if (debounce_count /= DEBOUNCE_CLK_PERIODS-1) then
debounce_count := debounce_count + 1;
else
debounced_button_out <= next_button_state;
end if;
end if;
end if;
end process;
Another option would be to sample the bouncy_button_in
at a slow rate:
process (clk)
constant DEBOUNCE_CLK_DIVIDER : integer := 256;
variable debounce_count : integer range 0 to DEBOUNCE_CLK_DIVIDER-1 := 0;
begin
if (rising_edge(clk)) then
if (debounce_count /= DEBOUNCE_CLK_DIVIDER-1) then
debounce_count := debounce_count + 1;
else
debounce_count := 0;
debounced_button_out <= bouncy_button_in;
end if;
end if;
end process;
The advantage of the first method is that it will reject glitches in the input. In either case, you would use the debounced_button_out
(or whatever you want to call it, perhaps rst
) in your state machine, whose code then contains only the core state machine functionality.
If you wanted even more debouncing, you could use another counter to create an enable signal for the processes above, to effectively divide down the clock rate. This could be better than setting the division constant to a very high number, because you may not be able to meet timing if the counter gets beyond a certain size.
You could even create a debounce entity in a separate file, which could be instantiated for each button. It could have a generic for the constant in the above process.
There's also hardware debouncing, but I suppose that's outside the scope of this question.