Electronic – 3 digit BCD Counter in VHDL and Quartus II

counterfpgaprogrammable-logicquartusvhdl

I'm trying to make a 3 digits BCD counter in VHDL for Cyclone V FPGA from intel. I have an module-k counter design and I instantiate four counters in top level module (structural design):

  • One counter acts as frequency divider to get 1Hz signal for the enable of the first digit counter.
  • The remaining counts the three digits.

The problem is that for example when test the circuit, I get the sequence: 018 -> 019 -> 010 -> 021 instead of 018 -> 019 -> 020 -> 021.
Listings of code:

  1. counter_modK.vhd
    library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity counter_modK is
    generic(
        N : integer := 5;
        K : integer :=  20
    );
    port(
        clk, reset, en : in std_logic;
        Q   : out std_logic_vector(N-1 downto 0);
        rollover : out std_logic
    );
end counter_modK;

architecture behavioral of counter_modK is
    
    signal counter_state : unsigned(N-1 downto 0);
    
begin

    process (clk, reset)
    begin
        if reset = '0' then
            counter_state <= (others => '0');
            rollover <= '0';
        elsif rising_edge(clk) then
            if en = '1' then
                if counter_state = K-1 then
                    counter_state <= (others => '0');
                    rollover <= '1';
                else
                    counter_state <= counter_state + 1;
                    rollover <= '0';
                end if;
            end if;
        end if;
    end process;
    Q <= std_logic_vector(counter_state);

end behavioral;
  1. BCD_Counter.vhd

library ieee;
use ieee.std_logic_1164.all;

entity BCD_counter is
    port(
        clk, reset, en : in std_logic;
        HEX0, HEX1, HEX2 : out std_logic_vector(6 downto 0)
    );
end BCD_counter;

architecture structural of BCD_counter is
    
    component counter_modK is
    generic(
        N : integer := 5;
        K : integer :=  20
    );
    port(
        clk, reset, en : in std_logic;
        Q   : out std_logic_vector(N-1 downto 0);
        rollover : out std_logic
    );
    end component;
    
    component dec7segment is
    port(
        bin : in std_logic_vector(3 downto 0);
        seg : out std_logic_vector(6 downto 0)
    );
    end component;
    
    signal clk_1sec, enable0, enable1, enable2 : std_logic;
    signal bcd_digit0, bcd_digit1, bcd_digit2 : std_logic_vector(3 downto 0);
    signal dec_out0, dec_out1, dec_out2 : std_logic_vector(6 downto 0);
    signal registered_output0, registered_output1, registered_output2 : std_logic_vector(6 downto 0);

begin

    prescaler: counter_modK 
    generic map(N => 26, K => 50000000) 
    port map(
        clk => clk,
        reset => reset,
        en => en,
        Q => open,
        rollover => clk_1sec
    );
    
    count_first_digit: counter_modK 
    generic map(N => 4, K => 10) 
    port map(
        clk => clk,
        reset => reset,
        en => clk_1sec,
        Q => bcd_digit0,
        rollover => enable1
    );
    
    count_second_digit:
    counter_modK 
    generic map(N => 4, K => 10) 
    port map(
        clk => clk,
        reset => reset,
        en => enable1 and clk_1sec,
        Q => bcd_digit1,
        rollover => enable2
    );
    
    count_third_digit:
    counter_modK 
    generic map(N => 4, K => 10) 
    port map(
        clk => clk,
        reset => reset,
        en => enable2 and enable1 and clk_1sec,
        Q => bcd_digit2,
        rollover => open
    );
    
    disp0:
    dec7segment port map(bin => bcd_digit0, seg => dec_out0);
    
    disp1:
    dec7segment port map(bin => bcd_digit1, seg => dec_out1);
    
    disp2:
    dec7segment port map(bin => bcd_digit2, seg => dec_out2);
    
    -- synchronized outputs
    process (clk, reset)
    begin
        if reset='0' then
            registered_output0 <= (others => '0');
            registered_output1 <= (others => '0');
            registered_output2 <= (others => '0');
        elsif rising_edge(clk) then
            registered_output0 <= dec_out0;
            registered_output1 <= dec_out1;
            registered_output2 <= dec_out2;
        end if;
    end process;
    
    HEX0 <= registered_output0;
    HEX1 <= registered_output1;
    HEX2 <= registered_output2;
    
end structural;

This glitched behaviour is due to Quartus register the output rollover with a flip-flop in counter_modK entity, as shown in the next picture:
enter image description here

I think that if rollover was a combinational output the problem will be solved because when the counter reach ninth value rollover will get high in the same clock cycle and not in the next cycle how it does now.

Does anyone know how to correct this failed behavior, without reimplement all as a behavioral description in a whole process ?

Thanks.

Best Answer

The problem is solved. I fix the code for counter_modK.vhd. Now instead of puts rollover signal to high when the counter state is K-1, rollover gets high when counter state is K-2 and I use rollover to increment the counter or reset its internal state. The code is:

  • counter_modK.vhd:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity counter_modK is
    generic(
        N : integer := 5;
        K : integer :=  20
    );
    port(
        clk, reset, en : in std_logic;
        Q   : out std_logic_vector(N-1 downto 0);
        rollover : out std_logic
    );
end counter_modK;

architecture behavioral of counter_modK is
    
    signal counter_state : unsigned(N-1 downto 0);
    signal rollover_state : std_logic;
    
begin

    process (clk, reset)
    begin
        if reset = '0' then
            counter_state <= (others => '0');
            rollover_state <= '0';
        elsif rising_edge(clk) then
            if en = '1' then
            
                if counter_state = K-2 then
                    -- set rollover in advance
                    rollover_state <= '1';
                else
                    rollover_state <= '0';
                end if;
                
                if rollover_state = '1' then
                    counter_state <= (others => '0');
                else
                    counter_state <= counter_state + 1;
                end if;
                
            end if;
        end if;
    end process;
    Q <= std_logic_vector(counter_state);
    rollover <= rollover_state;

end behavioral;

And the new RTL generated is: enter image description here

Thanks to Brian Drummond for his comment.

Related Topic