2
\$\begingroup\$

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.

\$\endgroup\$
2
  • \$\begingroup\$ Your counter_modK module will be confused with its en input pin. The rollover signal is changed in sync with clk, it goes to zero when rising clk (as defined in counter_modk codes). and then u use it like this enable2 and enable1 and clk_1sec as an en signal for other modules. There's times when en has a falling edge and Clk has a rising edge at the same time. This can be the cause of problem. \$\endgroup\$ – Hamid R. Tanhaei Oct 23 '20 at 1:21
  • \$\begingroup\$ Why it happens is obvious : Rollover becomes active right when Counter_state is reset to 0. This is too late to affect the next digit. You want the next digit to count and this one to clear at the same time. One solution is to set Rollover in advance; i.e when Counter state becomes N-1. Then use Rollover=1 as the cue for clearing the counter next time... \$\endgroup\$ – user_1818839 Oct 23 '20 at 12:01
4
\$\begingroup\$

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.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.