Counter with push button switch design using VHDL and Xilinx

Varaquilex picture Varaquilex · Mar 18, 2013 · Viewed 11.8k times · Source

I'm very new to VHDL and XILINX ISE. I use the version 13.2 for Xilinx ISE.

I want to design a very simple counter with the following inputs:

  • Direction
  • Count

The count input will be assigned to a button and I want the counter to count up or down according to direction input when the button is pressed. I have written a sample VHDL before this one. It had a clock input and It was counting according to the clock input. Now I want it to count when I press the button instead of counting synchronously.

Here's my VHDL code (please tell me if my code have a logical or any other flaw):

entity counter is
    Port ( COUNT_EN : in  STD_LOGIC;
           DIRECTION : in  STD_LOGIC;
           COUNT_OUT : out  STD_LOGIC_VECTOR (3 downto 0));
end counter;

architecture Behavioral of counter is

signal count_int : std_logic_vector(3 downto 0) := "0000";
begin
process 
begin
    if COUNT_EN='1' then
        if DIRECTION='1' then   
            count_int <= count_int + 1;
        else
            count_int <= count_int - 1;
        end if;
    end if;
end process;
COUNT_OUT <= count_int;
end Behavioral;

I use Spartan xc3s500e and I placed the inputs accordingly. Below is my .ucf file:

#Created by Constraints Editor (xc3s500e-fg320-5) - 2013/03/18
NET "COUNT_EN" LOC = K17;
NET "COUNT_OUT[0]" LOC = F12;
NET "COUNT_OUT[1]" LOC = E12;
NET "COUNT_OUT[2]" LOC = E11;
NET "COUNT_OUT[3]" LOC = F11;
NET "DIRECTION" LOC = L13;
#Created by Constraints Editor (xc3s500e-fg320-5) - 2013/03/18
NET "COUNT_EN" CLOCK_DEDICATED_ROUTE = FALSE;

I needed to change the last line because I was getting the error:

This will not allow the use of the fast path between the IO and the Clock...

After having this error gone, I programmed the device. But the output (leds) acted crazy. They sometimes stood still for a few seconds, sometimes just flashed very fast. I could not figure out where my mistake is. I would appreciate any help, some beginner tutorials are greatly appreciated (the links i found directed me to xilinx's documentations and they seemed quite complicated for a beginner).

Answer

darron picture darron · Mar 18, 2013

You don't have a clock. Once the COUNT_EN and DIRECTION conditions are satisfied, the count_int variable is going to increase as fast as it possibly can... in fact the timing of when individual bits change will probably make the entire thing completely unstable and incorrect.

You should always use a clock... just to allow the FPGA to get the timing right.

In this case, put the clock back... then add a new signal COUNT_EN_LAST. Save the old COUNT_EN each pass through the clocked process. Only increment when COUNT_EN = '1' and COUNT_EN_LAST = '0'.

In fact, you'll next find that you need to "debounce" the input. Physical buttons/switches "bounce" and give you multiple off-on events per single button press. For that, you'd simply make COUNT_EN_LAST a vector (say 5 long), shift new values into it each time ("COUNT_EN_LAST <= COUNT_EN_LAST(3 downto 0) & COUNT_EN;"), and only increment when COUNT_EN_LAST = "01111", or right before they're all 1's. The length of the vector you need will change depending on how fast your clock is and how long the switch can bounce before settling down to the new state.