1

My fpga is spartan 3E-100 Cp132. I have four push buttons as my inputs and I want to increment the four digits on 7-segment of the board by using them. The VHDL code is below:

 entity main is
    port(b1,b2,b3,b4 : in STD_LOGIC;
          clk         : in STD_LOGIC;
          sseg        : out STD_LOGIC_VECTOR(0 to 6);
          anodes      : out STD_LOGIC_VECTOR(3 downto 0);
          reset           : in STD_LOGIC
          );
end main;

architecture Behavioral of main is
    signal bcd1, bcd2, bcd3, bcd4 : STD_LOGIC_VECTOR (3 downto 0);
    signal clk2 : STD_LOGIC;
    signal pushbuttons : STD_LOGIC_VECTOR(3 downto 0);
    signal db_pushbuttons : STD_LOGIC_VECTOR(3 downto 0);
    signal counter : STD_LOGIC_VECTOR(1 downto 0);
    signal clk_divider : STD_LOGIC_VECTOR(20 downto 0);
    component Debounce is
        port( cclk : in STD_LOGIC;
                inp : in STD_LOGIC_VECTOR(3 downto 0);
                cclr : in STD_LOGIC;
                db  : out STD_LOGIC_VECTOR(3 downto 0)
                );
    end component;
begin
    pushbuttons <= b4 & b3 & b2 & b1;
    Db : Debounce port map
            ( cclk => clk2,
              inp => pushbuttons,
              cclr => reset,
              db  => db_pushbuttons);

process (clk)
begin
    if rising_edge(clk) then
        if clk_divider <= "1100001101010000" then
            clk_divider <= clk_divider + 1;
            clk2 <= '0';
        else
            clk_divider <= (others => '0');
            clk2 <= '1';
        end if;
    end if;
end process;

process (clk2, reset)
begin
    if reset = '1' then
        -- do something here
        bcd1 <= "0000";
        bcd2 <= "0000";
        bcd3 <= "0000";
        bcd4 <= "0000";
    elsif rising_edge(clk2) then
        counter <= counter + 1;
        if db_pushbuttons(0) = '1' then -- db_b1
            if bcd1 <= "1000" then
                bcd1 <= bcd1 + 1;
            else
                bcd1 <= "0000";
            end if;
        elsif db_pushbuttons(1) = '1' then -- db_b2
            if bcd2 <= "1000" then
                bcd2 <= bcd2 + 1;
            else
                bcd2 <= "0000";
            end if;
        elsif db_pushbuttons(2) = '1' then -- db_b3
            if bcd3 <= "1000" then
                bcd3 <= bcd3 + 1;
            else
                bcd3 <= "0000";
            end if;
        elsif db_pushbuttons(3) = '1' then --db_b4
            if bcd4 <= "1000" then
                bcd4 <= bcd4 + 1;
            else
                bcd4 <= "0000";
            end if;
        end if;
    end if;
end process;

process (counter, bcd1, bcd2, bcd3, bcd4)
    variable display : STD_LOGIC_VECTOR(3 downto 0);
begin
    case counter is
        when "00" => anodes <= "1110"; display := bcd1;
        when "01" => anodes <= "1101"; display := bcd2;
        when "10" => anodes <= "1011"; display := bcd3;
        when "11" => anodes <= "0111"; display := bcd4;
        when others => null;
    end case;

    case display is
        when "0000" => sseg <= "0000001"; --0
        when "0001" => sseg <= "1001111"; --1
        when "0010" => sseg <= "0010010"; --2
        when "0011" => sseg <= "0000110"; --3
        when "0100" => sseg <= "1001100"; --4
        when "0101" => sseg <= "0100100"; --5
        when "0110" => sseg <= "0100000"; --6
        when "0111" => sseg <= "0001111"; --7
        when "1000" => sseg <= "0000000"; --8
        when "1001" => sseg <= "0000100"; --9
        when others => sseg <= "0010000"; --e, represents error
    end case;
end process;
end Behavioral;

Every pushbutton should increment the corresponding 7-segment digit (b1 --> rightmost digit and b4--> leftmost digit) by one. The problem is when I push the button, it does the job but not increment it by one but some arbitrary number. The reason is that it increments by one at every rising edge of the clock 2 and it happens too quickly due to the frequency of this clock. How can I manage to get rid of this problem? I tried several debouncing code for the push buttons but they weren't helpful so much. I am totally stuck here. I mean there should be a way to do it, but how? By the way, the debouncing code that I have been using with the code above is

entity Debounce is
    port(cclk       :   in STD_LOGIC;
          inp    :  in STD_LOGIC_VECTOR(3 downto 0);
          cclr  :  in STD_LOGIC;
          db     :  out STD_LOGIC_VECTOR(3 downto 0)
         );
end Debounce;

architecture Behavioral of Debounce is
    signal delay1, delay2, delay3 : STD_LOGIC_VECTOR(3 downto 0);
begin
    process (cclk, cclr)
    begin
        if cclr = '1' then
            delay1 <= "0000";
            delay2 <= "0000";
            delay3 <= "0000";
        elsif rising_edge(cclk) then
            delay1 <= inp;
            delay2 <= delay1;
            delay3 <= delay2;
        end if;
    end process;
    db <= delay1 and delay2 and delay3;
end Behavioral;

So any help will be appreciated, thanks in advance!

user3100463
  • 15
  • 2
  • 4

2 Answers2

1

If the intended function of the button is that you will only increment once, no matter how long you hold it down, you need to implement an "edge detect" on the debounced switch output. That is, only allow the bcd count to increment/update on the rising edge of the debounced switch signal. For example:

...
elsif rising_edge(clk2) then
    counter <= counter + 1;
    db_pushbuttons_previous <= db_pushbuttons;
    if db_pushbuttons(0) = '1' and db_pushbuttons_previous(0) = '0' then --rising edge detect
        if bcd1 <= "1000" then
            bcd1 <= bcd1 + 1;
        else
            bcd1 <= "0000";
        end if;
...

This way, no matter how long db_pushbuttons(0) is asserted, the bcd value will only be incremented once.

Josh
  • 3,627
  • 26
  • 37
  • But if I do that, I create a FSM, right? I am not sure where can put the signal assignment in your code? Do I need to create another process or just move it into the existing ones? – user3100463 Dec 14 '13 at 12:43
  • You sir, finally put an end to my misery. Thanks a lot! – user3100463 Dec 14 '13 at 13:30
0

Testing with GHDL I have the following code. file: sevensegns.vhdl

-----------------------------------------
---- SevenSegNS.vhdl
---- Seven segment driver with 4 input
---- buttons

---- Author: Derby Russell
---- Date: 12-13-2013
-----------------------------------------
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.ALL;

entity main_7_seg is
     port(b1,b2,b3,b4 : in std_logic;
          clk         : in std_logic;
          sseg        : out std_logic_vector(0 to 6);
          anodes      : out std_logic_vector (3 downto 0);
          reset       : in std_logic
          );
end main_7_seg;

architecture behavioral of main_7_seg is
    signal bcd1, bcd2, bcd3, bcd4 : unsigned (3 downto 0) := "0000";
    signal clk2 : std_logic := '0';
    signal pushbuttons : std_logic_vector(3 downto 0) := "0000";
    signal db_pushbuttons : std_logic_vector(3 downto 0) := "0000";
    signal counter : unsigned (1 downto 0) := "00";
    component Debounce is
        port( cclk : in std_logic;
                inp : in std_logic_vector(3 downto 0);
                cclr : in std_logic;
                db  : out std_logic_vector(3 downto 0)
                );
    end component;
begin
    pushbuttons <= b4 & b3 & b2 & b1;
    Db : Debounce port map
            ( cclk => clk2,
              inp => pushbuttons,
              cclr => reset,
              db  => db_pushbuttons);
process (clk)
begin
    if rising_edge(clk) then
        clk2 <= '1';
    else
        clk2 <= '0';

    --  FOR RUNNING ON ACTUAL HARDWARE:
    --  RESTORE NEXT 6 LINES AND COMMENT OUT ABOVE 4 LINES.

    --    if clk_divider <= "1100001101010000" then
    --        clk_divider <= clk_divider + 1;
    --        clk2 <= '0';
    --    else
    --        clk_divider <= (others => '0');
    --        clk2 <= '1';


    end if;
end process;

P2: process (clk2, reset)
begin
    if reset = '1' then
        -- do something here
        bcd1 <= "0000";
        bcd2 <= "0000";
        bcd3 <= "0000";
        bcd4 <= "0000";
    elsif rising_edge(clk2) then
        counter <= counter + 1;
        if db_pushbuttons(0) = '1' then -- db_b1
            if bcd1 <= "0010" then
                if bcd1 = "0000" then
                    bcd1 <= bcd1 + 1;
                end if;
            else
                bcd1 <= "0000";
            end if;
        elsif db_pushbuttons(1) = '1' then -- db_b2
            if bcd2 <= "0010" then
                if bcd2 = "0000" then
                    bcd2 <= bcd2 + 1;
                end if;
            else
                bcd2 <= "0000";
            end if;
        elsif db_pushbuttons(2) = '1' then -- db_b3
            if bcd3 <= "0010" then
                if bcd3 = "0000" then
                    bcd3 <= bcd3 + 1;
                end if;
            else
                bcd3 <= "0000";
            end if;
        elsif db_pushbuttons(3) = '1' then --db_b4
            if bcd4 <= "0010" then
                if bcd4 = "0000" then
                    bcd4 <= bcd4 + 1;
                end if;
            else
                bcd4 <= "0000";
            end if;
        end if;
    end if;
end process P2;

P3: process (counter, bcd1, bcd2, bcd3, bcd4)
    -- variable display : std_logic_vector(3 downto 0);
    variable display : unsigned (3 downto 0);
begin
    case counter is
        when "00" => anodes <= "1110"; display := bcd1;
        when "01" => anodes <= "1101"; display := bcd2;
        when "10" => anodes <= "1011"; display := bcd3;
        when "11" => anodes <= "0111"; display := bcd4;
        when others => null;
    end case;

    case display is
        when "0000" => sseg <= "0000001"; --0
        when "0001" => sseg <= "1001111"; --1
        when "0010" => sseg <= "0010010"; --2
        when "0011" => sseg <= "0000110"; --3
        when "0100" => sseg <= "1001100"; --4
        when "0101" => sseg <= "0100100"; --5
        when "0110" => sseg <= "0100000"; --6
        when "0111" => sseg <= "0001111"; --7
        when "1000" => sseg <= "0000000"; --8
        when "1001" => sseg <= "0000100"; --9
        when others => sseg <= "0010000"; --e, represents error
    end case;
end process P3;
end behavioral;

file: debounce.vhdl

library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use ieee.numeric_std.ALL;

entity Debounce is
    port(cclk       :   in std_logic;
          inp    :  in std_logic_vector(3 downto 0);
          cclr  :  in std_logic;
          db     :  out std_logic_vector(3 downto 0)
         );
end Debounce;

architecture behavioral_2 of Debounce is
    signal delay1, delay2, delay3 : std_logic_vector(3 downto 0);
begin
    process (cclk, cclr)
    begin
        if cclr = '1' then
            delay1 <= "0000";
            delay2 <= "0000";
            delay3 <= "0000";
        elsif rising_edge(cclk) then
            delay1 <= inp;
            delay2 <= delay1;
            delay3 <= delay2;
        end if;
    end process;
    db <= delay1 and delay2 and delay3;
end behavioral_2;

I processed these two files with a data file sevensegns_tb.vhdl Then I ran the files and observed the data with gtkwave here is the output: gtkwave output
(source: googlecode.com)

And I have posted all the code and results to: Google Code sevenseg
Click on the Source tab to see all the files created.

Community
  • 1
  • 1
user2737761
  • 115
  • 7
  • Thanks for the reply! Maybe I am wrong but, It seems in the simulation that bcd's are incremented when the corresponding pushbutton is released. And I don't understand why you don't divide clk to get the clk2 with 50 KHz frequency (since otherwise you cannot observe nothing on the seven segment). But instead, you use two identical clock. When I tried to run your code, the Xilinix gave an error that indicated clk2 is not synthesizable because of the bad synchronous description. Maybe I am doing something wrong, but if you could explain a little bit, I would be very glad. – user3100463 Dec 14 '13 at 13:18
  • Oh, I changed the clock so that my test bed would not be 20 pages long. The clock can be put back with no harm. – user2737761 Dec 14 '13 at 19:50
  • Restore the clock to the code you had, I left that code commentted in my code. – user2737761 Dec 14 '13 at 20:06