VHDL - Debounce Button Press - switch-statement

I have the following button press logic in my code. I have tried debouncing it using a wait delay, but the compiler will not allow this. I have four push buttons on my FPGA, which the "key" array below reflects:
process(clock)
begin
if rising_edge(clock) then
if(key(3)/='1' or key(2)/='1' or key(1)/='1' or key(0)/='1') then --MY ATTEMPT AT DEBOUNCING
wait for 200 ns; ----MY ATTEMPT AT DEBOUNCING
if (key(3)='1' and key(2)='1' and key(1)='0' and last_key_state="1111" and key(0)='1') then
...
elsif (key(3)='1' and key(2)='1' and key(1)='1' and key(0)='0' and last_key_state="1111") then
...
elsif (key(3)='0' and key(2)='1' and key(1)='1' and key(0)='1' and last_key_state="1111") then
...
elsif (key(3)='1' and key(2)='0' and key(1)='1' and key(0)='1' and last_key_state="1111") then
...
end if;
last_key_state<=key;
end if;
end if;
end process;
Can anyone give some really simple example code showing how I could debounce a setup like the one I have above?

Well if you think about how you would do this with real electronics you would probably use a capacitor.. which has a charging time. Same idea applies here, just figure out the time your switch is bouncing (usually a function of clock speed) and then actually set the register.
Simple Example With a 4-Bit Shift Register
So you'd put this between your switch and any other logic blocks
process
begin
if rising_edge(clock) then --You're clock
SHIFT_PB(2 Downto 0) <= SHIFT_PB(3 Downto 1); --Shifting each cycle
SHIFT_PB(3) <= NOT PB; --PB is the pre-bounced signal
If SHIFT_PB(3 Downto 0)="0000" THEN --once the bounce has settled set the debounced value
PB_DEBOUNCED <= '1';
ELSE
PB_DEBOUNCED <= '0';
End if;
end process;
Its basically delaying your signal 4 clock cycles (what you were trying to do with the wait).

Others have shown the way with counters... you also need to synchronise the signal to the clock before feeding it to the counter, otherwise occasionally, the signal will get to different parts of the counter at different times, and the counter will count incorrectly.
Whether this matters depends on the application - if correct operation is important, it is important to synchronise correctly!

You get the error because of wait ... wait is not synthesizeable.
I would do it with a simple counter. So you can use the same code for different clock speeds by adjusting the counter.
-- adjust the counter to you special needs
-- depending on how good your buttons are hardware debounced
-- you can easily think in ms
signal counter : std_logic_vector(7 DOWNTO 0) := "10000000";
process
begin
if rising_edge(clock) then --You're clock
if(key(3) = '0') or (key(2) = '0') or (key(1) = '0') or (key(0) = '0') then
start_debouncing <= '1';
key_vector_out <= key(3) & key(2) & key(1) & key(0);
end if;
if(start_debouncing = '1') then
key_vector_out <= "0000";
counter <= std_logic_vector(unsigned(counter) - 1);
end if;
if(counter = "00000000") then
counter <= "10000000";
start_debouncing <= '0';
end if;
end process;
Your code can produce another problem.
What will happen if you button is released so your input is .. key = "0000" .. right you never get you output. Perhaps it will work 99 out of 100 times but you can get an really hard to find error.

Related

Verilog - incrementing variable using buttons

I'm actually trying for 3 days to make my code works. I have an dev board with multiplexed 7-seg display - it's working. The problem is, when I'm trying to increment a variable. I written code below:
assign buttons = debouncedL | debouncedR;
always #(posedge buttons or negedge RES) begin
if(~RES) number <= 0;
else if(debouncedL) number <= (number + 10);
else if(debouncedR) number <= (number + 1);
end
And it's not working. When I'm pressing R button, variable is incremented by 1, but when I'm pressing L nothing happens. After changing positions of both else if, L button still not work and displayed number is toggling between 0000 and 0001 after pressing R button. It might be newbie question, but I can't find solution in book and on Internet. Can you help me? Thank you in advance.
Your design is asynchronous, you have metastability on buttons signal.
In synchronous design (and all FPGA design should be synchronous) only clock can be used for always #posedge() process. In your design you are using button signal as a clock.
To detect raising edge on button you have to save the old state of button signal and compare it to current state like this :
always #(posedge clock or posedge rst) begin
// detect rising edge
if (button_old != button && button == 1'b1)
button_raise <= 1'b1
button_old <= button;
// increment number
if(button_raise == 1b'1)
begin
if(~RES) number <= 0;
else if(debouncedL) number <= (number + 10);
else if(debouncedR) number <= (number + 1);
end
end

Combining Blocking and NonBlocking in Verilog

If I want statements to happen in parallel and another statement to happen when all other statements are done with, for example:
task read;
begin
if (de_if==NOP) begin
dp_op <= 3'b000;
dp_phase = EXEC;
end
else begin
if (de_if==EXEC_THEN) begin
dp_const <= de_src3[0];
dp_src <= de_src3;
dp_op <= {NOP,de_ctrl3};
dp_dest <= de_dest1;
end
else if (get_value(de_ctrl1,de_src1)==dp_mem[de_src2]) begin
dp_const <= de_src3[0];
dp_src <= de_src3;
dp_op <= {NOP,de_ctrl3};
dp_dest <= de_dest1;
end
else begin
dp_const <= de_src4[0];
dp_src <= de_src4;
dp_op <= {NOP,de_ctrl4};
dp_dest <= de_dest2;
end
#1 dp_phase=READ;
end
end
endtask
In this code I want the statement dp_phase = READ to only be executed after all other assignments are done, how do I do it?
As you can see what I did is wait 1 clock before the assignment but i do not know if this is how its done ...
You need a state machine. That's the canonical way to make things happen in a certain sequence. Try to remember that using a hardware description language is not like a regular programming language...you are just describing the kind of behavior that you would like the hardware to have.
To make a state machine you will need a state register, one or more flip-flops that keep track of where you are in the desired sequence of events. The flip-flops should be updated on the rising clock edge but the rest of your logic can be purely combinational.

How to use two switches in vhdl

I want to control the value of a variable using two switches. One for incrementing the value, whereas the other one for decrementing the value. How should i shange this code.
error says that the variable counting is unsynthesisable.
I have tried a lot but could not figure out what exactly the problem is.
ERROR:Xst:827 - line 34: Signal counting0 cannot be synthesized, bad synchronous description. The description style you are using to describe a synchronous element (register, memory, etc.) is not supported in the current software release.
library IEEE;
use IEEE.std_logic_1164.ALL;
use IEEE.numeric_std.ALL;
entity counts is
port(
btn_up : in std_logic;
reset : IN STD_LOGIC;
btn_dn : in std_logic;
counted : out std_logic_vector(8 downto 0)
);
end entity counts;
architecture behaviour of counts is
signal counter : std_logic_vector(8 downto 0);
begin
btupprocess : process(btn_up,reset,counter)
variable counting : unsigned(8 downto 0);
begin
counting := unsigned(counter);
if(reset = '1') then
counting := (others => '0');
elsif (rising_edge(btn_up)) then
if(counting > 399) then
counting := counting - 1;
else
counting := counting + 1;
end if;
end if;
counter <= std_logic_vector(counting);
end process;
btndnprocess : process(btn_dn,counter)
variable counting : unsigned(8 downto 0);
begin
counting := unsigned(counter);
if (falling_edge(btn_dn)) then
if(counting < 200) then
counting := counting + 1;
else
counting := counting - 1;
end if;
end if;
counter <= std_logic_vector(counting);
end process;
counted <= counter;
end behaviour;
Although in some cases it is possible to drive a signal from two different processes, there are better approaches in this case.
A possible solution to your problem is:
add a clock input to your entity; you should probably use a synchronous design
rewrite your architecture to use three processes, with each process driving a single signal:
one process will debounce and detect a rising edge on btn_up; this process will generate the signal btn_up_rising_edge
one process will debounce and detect a rising edge on btn_dn; this process will generate the signal btn_dn_rising_edge
a third process will read btn_up_rising_edge and btn_dn_rising_edge, and increment or decrement the count as appropriate
in all three processes, your sensitiviy list should contain clock and reset only
You can find an example of an edge detector with a debouncer here: https://electronics.stackexchange.com/questions/32260/vhdl-debouncer-circuit

Why a delay of 1 clock period in simple counter

Below is a simple 3-bit counter.
When reset(rst) is 0, counter value is "000", else it increments by 1 for rising edge of each clock.
LIBRARY ieee;
USE ieee.std_logic_1164.all;
use IEEE.std_logic_unsigned.all;
use IEEE.numeric_std.all;
---------------------------------------------
ENTITY counter IS
PORT (clk : IN STD_LOGIC;
rst : in std_logic;
digit : out std_logic_vector (2 downto 0)
);
END counter;
---------------------------------------------
ARCHITECTURE counter OF counter IS
BEGIN
count: PROCESS(clk,rst)
VARIABLE temp : std_logic_vector(2 downto 0);
BEGIN
IF (clk'EVENT AND clk='1') THEN
if (rst = '1') then
temp := temp + "001";
else
temp := "000";
END IF;
END IF;
digit <= temp;
END PROCESS count;
END counter;
Below is the simulation result I got :
In the result, output is correct. But there is an one clock delay between the time rst = 1 and output='001'. ie counter doesn't increment instantaneously when rst = '1'.
As per my understanding, whenever a change in clk or rst happens, process is executed. So when rst changes from low to high, an event occurs. Process checks if rising edge of clk, YES. Then check if rst = 1, YES. So normally counter has to increment in that clk itself. But it doesn't.
Questions:
Why one clock period delay between reset = 1 and output = 001?
And what is wrong in my understanding?
The most likely cause in that "rst" is generated by a clocked process, clocked by the same "clk" signal.
So "rst" occurs one delta cycle after "clk". When "rst" changes it will wake the process up, but "clk'event" was on the previous delta cycle, therefore the "if" statement will not execute.
On the next clock edge, rst = 1 so the counter works as expected.
Three minor points:
it would be worth naming the reset signal rst_n to make it clearer that it is an
active-low reset!
rst really doesn't need to be in the sensitivity list
there is no need for parentheses around the boolean expressions
(Disclaimer: It's been long time since I programmed in VHDL, so this only answers to generic logic design.)
Anyway, one can't expect the result of addition to be ready immediately when a process is triggered. The point is, that calculating even the first bit of 000 + 001 is affected by the propagation delay equivalent to one xor operation. The second bit is calculated from the first bit's carry (if both bits were 1) and xor operation of the second bits. And so on.
If one would probe the 'temp' variable asynchronously, one would see something like this:
^ ________________
result_bit_0 __________|
0123456789
_____________
result_bit_1 ^ |____________
0123456789
____________ _____
result_bit_2 ^ |_| |________
0123456789abcde
________
clock: ________| |______|
The figure tries to illustrate in more detail the waveforms of a generic add operation.
At time 0 the process of adding is started.
After a small delay '2' the first bit stabilizes to 1.
At time '5' the second bit stabilizes to 0 and at time '9' the third bit stabilizes to 0.
But also it's quite common, that as in result_bit_2, the output toggles between various states.
It's the total / maximum delay of each temporary variable to take to stabilize, that determines the minimum clock period. At this case the time instant 'e' is that one, where we have decided that the result of counter increment is available.
Still, from the perspective result (which is a vector), everything happens instantly at the next clock cycle.
the "issue" is in the way you have described your "rst".
The way you did it would result in a "synchronous" reset, i.e. the reset would take effect only after a rising edge of the clock.
In general this is just a matter of coding style/preferences.
I usually prefer asynchronous reset (with maybe a reset synchronizer at top-level to avoid meta-stability when releasing the reset), but there is nothing wrong in adopting a synchronous reset approach.
In case of an asynchronous reset, you would need to change your code to something like this:
PROCESS (clk, rst_n) BEGIN
IF rst_n = '0' THEN
...
ELSIF rising_edge(clk) THEN
...
END IF;
END PROCESS;

Delay a signal in vhdl

I would like to delay a signal several cycles in vhdl, but I have problems using how to delay a signal for several cycles in vhdl
Wouldn't I need a registered signal? I mean, something like:
a_store and a_store_registered would be std_logic_vector(cycles_delayed-1 downto 0)
process(clk)
begin
if rising_edge(clk) then
a_store_registered <= a_store;
end if;
end process;
a_out <= a_store_registered(cycles_delayed-1);
process(a_store_registered, a)
begin
a_store <= a_store_registered(size-2 downto 0) & a;
end process;
The solution you link to is a registered signal - the very act of writing to a signal inside a process with a rising_edge(clk) qualifier creates registers.
An even simpler implementation of a delay-line can be had in one line of code (+ another one if you want to copy the high bit to an output)
a_store <= (a_store(a_store'high-1 downto 0) & a) when rising_edge(clk);
a_out <= a_store(a_store'high);
Not sure why I didn't mention this in my answer to the linked question!
I am not sure why you are approaching the problem as you are; there is no need for a second process here. What is wrong with the method suggested in the linked question?
if rising_edge(clk) then
a_store <= a_store(store'high-1 downto 0) & a;
a_out <= a_store(a_store'high);
end if;
In this case your input is a and your output is a_out. If you want to make the delay longer, increase the size of a_store by resizing the signal declaration.
If you want to access the intermediate signal for other reasons, you could do this:
a_store <= a_store_registered(cycles_delayed-2 downto 0) & a;
process(clk)
begin
if rising_edge(clk) then
a_store_registered <= a_store;
end if;
end process;
a_out <= a_store_registered(cycles_delayed-1);
Remember that you can use the foo'delayed(N ns) attribute or foo <= sig after N ns in simulations.

Resources