Search code examples
vhdlcounterbcd

Binary Coded Decimal Counter in VHDL


I have written this BCD-Counter in VHDL but the 10th place counter counts up every clock cylce instead of once, so instead of going from 09 to 10, the output is 09,19,29,39,... until bcd1_overflow is '0' again as you can see in the screenshot.

library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity Counter7Segments is
  port(
    clk : in std_logic;
    reset : in std_logic;
    segments_1 : out std_logic_vector(6 downto 0);
    segments_10 : out std_logic_vector(6 downto 0)
  );
end Counter7Segments;

architecture rtl of Counter7Segments is

component ClockEnableGenerator is
  generic(
    DIVIDE_BY : integer
  );

  port(
    clk_in : in std_logic;
    clk_en_out : out std_logic;
    reset : in std_logic
  );
end component;

component GenericBCDCounter is
  generic(
    COUNT_MAX : integer
  );

  port(
    clk : in std_logic;
    enable : in std_logic;
    reset : in std_logic;
    count : out std_logic_vector(3 downto 0);
    overflow : out std_logic
  );
end component;

component BCDDecoder is
  port(
    digit : in std_logic_vector(3 downto 0);
    segments : out std_logic_vector(6 downto 0)
  );
end component;

signal clock_seconds : std_logic;
signal count_1 : std_logic_vector(3 downto 0);
signal count_10 : std_logic_vector(3 downto 0);
signal bcd1_overflow : std_logic;

begin

Clock : ClockEnableGenerator
  generic map(
    DIVIDE_BY => 13
  )

  port map(
    clk_in => clk,
    clk_en_out => clock_seconds,
    reset => reset
  );

Counter_1 : GenericBCDCounter
  generic map(
    COUNT_MAX => 9
  )

  port map(
    clk => clk,
    enable => clock_seconds,
    reset => reset,
    count => count_1,
    overflow => bcd1_overflow
  );

Counter_10 : GenericBCDCounter
  generic map(
    COUNT_MAX => 5
  )

  port map( 
    clk => clk,
    enable => bcd1_overflow,
    reset => reset,
    count => count_10,
    overflow => open
  );

Decoder_1 : BCDDecoder
  port map(
    digit => count_1,
    segments => segments_1
  );

Decoder_10 : BCDDecoder
  port map(
    digit => count_10,
    segments => segments_10
  );

end architecture rtl;

The simulation output

I tried having a synchronous bcd1_overflow_pulse, but it was off by some clock cyles, also I tried making the condition for Counter_10 to count up "bcd1_overflow and clock_seconds" but that didn't work either.

If you want to try something out with my code, here is the code for the components I used:

library ieee;
use ieee.std_logic_1164.all;

entity BCDDecoder is

port(
  digit : in std_logic_vector(3 downto 0);
  segments : out std_logic_vector(6 downto 0)
);

end BCDDecoder;

architecture rtl of BCDDecoder is

begin

process(digit)
begin
  if(digit = "0000") then
    segments <= "1111110";
  elsif(digit = "0001") then
    segments <= "0110000";
  elsif(digit = "0010") then
    segments <= "1101101";
  elsif(digit = "0011") then
    segments <= "1111001";
  elsif(digit = "0100") then
    segments <= "0110011";
  elsif(digit = "0101") then
    segments <= "1011011";
  elsif(digit = "0110") then
    segments <= "1011111";
  elsif(digit = "0111") then
    segments <= "1110000";
  elsif(digit = "1000") then
    segments <= "1111111";
  elsif(digit = "1001") then
    segments <= "1111011";
  end if;
end process;

end architecture rtl;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity ClockEnableGenerator is

generic(
  DIVIDE_BY : integer
);

port(
  clk_in : in std_logic;
  reset : in std_logic;
  clk_en_out : out std_logic
);

end ClockEnableGenerator;

architecture rtl of ClockEnableGenerator is

signal counter : unsigned(3 downto 0) := "0000";

begin

process(clk_in, reset)
begin
  if(reset = '1') then
    clk_en_out <= '0';
    counter <= "0001";
  elsif(rising_edge(clk_in)) then
    if(counter = DIVIDE_BY - 1) then
      counter <= (others => '0');
      clk_en_out <= '1';
    else
      clk_en_out <= '0';
      counter <= counter + 1;
    end if;
  end if;
end process;

end architecture rtl;
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;

entity GenericBCDCounter is

generic(
  COUNT_MAX : integer
);

port(
  clk : in std_logic;
  reset : in std_logic;
  enable : in std_logic;
  count : out std_logic_vector(3 downto 0);
  overflow : out std_logic
);

end GenericBCDCounter;

architecture rtl of GenericBCDCounter is

signal value : unsigned(3 downto 0);

begin

process(clk)
begin
  if(reset = '1') then
    value <= (others => '0');
    overflow <= '0';
  elsif(rising_edge(clk)) then
    if(enable = '1') then
      if(value = COUNT_MAX) then
        value <= (others => '0');
      else
        value <= value + 1;
      end if;

      if(value + 1 = COUNT_MAX) then
        overflow <= '1';
      else
        overflow <= '0';
      end if;
    else
      if(value = COUNT_MAX) then
        overflow <= '1';
      else
        overflow <= '0';
      end if;
    end if;
  end if;
end process;

count <= std_logic_vector(value);

end architecture rtl;

Solution

  • The error is that you clock the tens' counter Counter_10 with clk and enable it with bcd1_overflow, which is 1 during multiple clock cycles. With each clock it advances, as you observed.

    One possible solution is to AND clock_seconds and bcd1_overflow before using it to enable Counter_10.