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:
- 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;
- 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:
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:
And the new RTL generated is:
Thanks to Brian Drummond for his comment.