0

I am new to VHDL and currently working on a clock generator that generates two different clock speeds. Everything is working, except the switch between the slow and fast speed_status. There seems to be a problem with the "speed button" because sometimes I have to press it more than once to change the current set speed. The "reset button" is always working as expected. Is there something wrong with my VHDL Code or do I need to add some sort of software debouncing? If so, why is the reset button working? And could you give me some advice which parts of my clock generator I could improve (code/logic)?

entity clk_gen is
Port ( clk_in : in  STD_LOGIC;
       clk_btn_in : in STD_LOGIC_VECTOR (3 DOWNTO 0);
       clk_out : out  STD_LOGIC);
end clk_gen;

architecture Behavioral of clk_gen is
    signal temp : STD_LOGIC := '0';
    begin
    clock: process(clk_in,clk_btn_in)
        variable counter : integer range 0 to 49999999 := 0;
        constant freq_cnt_slow : integer := 49999999;
        constant freq_cnt_fast : integer := 4999999;
        type speed is (slow, fast);
        variable speed_status : speed := slow;
        begin
            if rising_edge(clk_in) then
                -- RESET BUTTON PRESSED
                if (clk_btn_in = "1000") then
                    temp <= '0';
                    counter := 0;
                    speed_status := slow;

                -- SPEED BUTTON
                elsif (clk_btn_in = "0100") then
                    if (speed_status = fast) then
                    speed_status:= slow;
                elsif (speed_status = slow) then
                     speed_status := fast;
                end if;
            end if;

            if ((counter = freq_cnt_fast) and (speed_status = fast)) then
                temp <= NOT(temp);
                counter := 0;
            elsif ((counter = freq_cnt_slow) and (speed_status = slow)) then
                temp <= NOT(temp);
                counter := 0;
            else
                counter := counter + 1;
            end if;

        end if;
    end process clock;

    clk_out <= temp;
end Behavioral;

I use Xilinx ISE 13.4 and the XC5VLX110T based on Xilinx Virtex 5.

evolved
  • 1,850
  • 19
  • 40

1 Answers1

2

It looks like your speed mode will toggle any time the button is in the 'pressed' state. Unless you can guarantee that your button is only 'pressed' for one clock period, the state is likely to toggle many times, making the state after you pressed the button essentially random (depending on the exact timing of the button press).

Firstly, you need a debouncing circuit on the button. This can be implemented externally, or within the FPGA. I will not go into switch debouncing in detail here, but you can easily find information on this elsewhere. Secondly, you need to convert the button into a synchronous signal, that is, one that has a fixed relationship to your clock. An example synchroniser for your example would be:

signal button_reg1 : std_logic_vector(3 downto 0) := (others => '0');
signal button_reg2 : std_logic_vector(3 downto 0) := (others => '0');

...

process (clk_in)    
begin
    if (rising_edge(clk_in)) then
        button_reg2 <= button_reg1;
        button_reg1 <= clk_btn_in;
    end if;
end process;

button_reg2 will then have a fixed relationship to the clock. Without this, you could violate the setup/hold constraints on the speed_status register. Lastly, you need to convert the pressing of the button into a pulse that is one clock period in length. Example:

signal speed_button_reg : std_logic := '0';
signal speed_button_pressed : std_logic := '0';

...

process (clk_in)    
begin
    if (rising_edge(clk_in)) then
        speed_button_reg <= button_reg2(2);
        if (speed_button_reg = '0' and button_reg2(2) = '1') then
            -- The button has just been pressed (gone from low to high)
            -- Do things here, or set another signal e.g.
            speed_button_pressed <= '1';
        else
            speed_button_pressed <= '0';
        end if;
    end if;
end process;
scary_jeff
  • 4,314
  • 13
  • 27