I'm trying to design a two digit counter the counts between 00 and 99 in a circular fashion both up and down. I have it working for the most part, however, no matter what I try I can't get the decade digit to stay in synch with the first digit. My results right now give me stuff like this:
08 -> 09 -> 00 -> 11 ... 18 -> 19 -> 10 -> 21
and
21 -> 20 -> 29 -> 18 ... 11 -> 10 -> 19 -> 08
From this it seems that the overflow from the first digit is delayed in reaching the decade digit. I've tried several things to try and fix this. The only thing to provide any beneficial result was to add an additional if statement that sent the overflow a state early, but that was only a supperficial fix. If I stopped the counter while the first digit was 8 or 0, and started it again, I'd be back to the same problem as before.
I also tried making an additional 'synchronizer' module, thinking maybe I could set it up, so even though they're out of sync, they'd be displayed as if they were in sync, but it didn't change anything.
I've been working on trying to fix this for over two weeks and I'm at my wits end.
Here's my code for the counter, and the synchronizer if anyone wants to check that out, any and all help is appreciated.
**I'm using VHDL, programming the Zybo Digilent Board with Vivado 2015.2
Counter Module for single digit, the overflow becomes the enable of the decade digit.
library IEEE;
use IEEE.STD_LOGIC_1164.all;
use ieee.numeric_std.all;
entity counter is
generic(N : positive := 4);
port(
AR : in STD_LOGIC;
clk : in STD_LOGIC;
ld : in STD_LOGIC;
en : in STD_LOGIC;
up_dn : in STD_LOGIC;
D : in STD_LOGIC_VECTOR(N - 1 downto 0);
overflow : out STD_LOGIC;
Q : out STD_LOGIC_VECTOR(N - 1 downto 0);
sync_in : in STD_LOGIC;
sync_out : out STD_LOGIC
);
end counter;
architecture counter of counter is
signal Qt : std_logic_vector(N - 1 downto 0);
signal OvrFlw : std_logic;
signal sync : std_logic;
begin
process(clk, AR)
begin
if (AR = '1') then
Qt <= (others => '0');
OvrFlw <= '0';
sync <= sync_in;
elsif (clk = '1' and clk'event) then
if ld = '1' then
Qt <= D;
sync <= sync_in;
elsif en = '1' then
if up_dn = '0' then -- if counting down
if (unsigned(Qt) = 0) then
Qt <= "1001";--(others => '1');
OvrFlw <= '1';
sync <= sync_in and en;
--elsif (unsigned(Qt) = 1) then
-- Qt <= std_logic_vector(unsigned(Qt) - 1);
-- OvrFlw <= '1';
else
Qt <= std_logic_vector(unsigned(Qt) - 1);
OvrFlw <= '0';
sync <= sync_in and en;
end if;
else -- if counting up
if (unsigned(Qt) = 2**N-7) then
Qt <= (others => '0');
OvrFlw <= '1';
sync <= sync_in and en;
--elsif (unsigned(Qt) = 2**N-8) then
-- Qt <= std_logic_vector(unsigned(Qt) + 1);
-- OvrFlw <= '1';
else
Qt <= std_logic_vector(unsigned(Qt) + 1);
OvrFlw <= '0';
sync <= sync_in and en;
end if;
end if;
end if;
end if;
end process;
sync_out <= sync;
Q <= Qt;
overflow <= OvrFlw;
end counter;
Here's the code for the synchronizer I tried to put together. Don't know if it's really relevant but I thought I'd put it up just in case.
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity Synchronizer is
generic(N : positive := 4);
Port (
MSB_Sync : in STD_LOGIC;
LSB_Sync : in STD_LOGIC;
MSB_Q : in STD_LOGIC_VECTOR(N-1 downto 0);
LSB_Q : in STD_LOGIC_VECTOR(N-1 downto 0);
MSB_Out : out STD_LOGIC_VECTOR(N-1 downto 0);
LSB_Out : out STD_LOGIC_VECTOR(N-1 downto 0));
end Synchronizer;
architecture Behavioral of Synchronizer is
begin
process (MSB_Sync, LSB_Sync)
begin
if ((MSB_Sync and LSB_Sync) = '1') then
MSB_Out <= MSB_Q;
LSB_Out <= LSB_Q;
end if;
end process;
end Behavioral;
The apparent basic problem you had resulting in the sync stuff is that your 'overflow' signal is registered, it's assignment found in the if statement conditional on a rising clock edge.
I dumped the sync stuff and removed the overflow register in the following example:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity bcd_ud_ctr is
port (
AR: in std_logic;
clk: in std_logic;
ld: in std_logic;
en: in std_logic;
up_dn: in std_logic;
D: in std_logic_vector (3 downto 0);
overflow: out std_logic;
Q: out std_logic_vector (3 downto 0)
);
end entity;
architecture off of bcd_ud_ctr is
signal Qt: unsigned (3 downto 0);
signal nine: std_logic;
signal zero: std_logic;
begin
-- Count recognizers
nine <= '1' when Qt = "1001" else
'0';
zero <= '1' when Qt = "0000" else
'0';
COUNT:
process (clk, AR)
begin
if AR = '1' then
Qt <= (others => '0');
elsif rising_edge(clk) then
if ld = '1' then
Qt <= unsigned(D);
elsif en = '1' then
if up_dn = '0' then -- up
if nine = '1' then
Qt <= (others => '0');
else
Qt <= Qt + 1;
end if;
else -- down
if zero = '1' then
Qt <= "1001";
else
Qt <= Qt - 1;
end if;
end if;
end if;
end if;
end process;
BUFFERED_OUT:
Q <= std_logic_vector(Qt);
CARRY_BORROW:
overflow <= (en and up_dn and zero) or
(en and not up_dn and nine);
end architecture;
Notice I also ANDed the enable into the overflow signal so it could be used as an enable to the next stage:
library ieee;
use ieee.std_logic_1164.all;
entity bcd_2digit_tb is
end entity;
architecture foo of bcd_2digit_tb is
signal AR: std_logic;
signal clk: std_logic := '0';
signal ld: std_logic := '0';
signal en: std_logic := '0';
signal up_dn: std_logic := '1';
signal rollover: std_logic;
signal Q: std_logic_vector (7 downto 0);
constant DIG_PAR: std_logic_vector(3 downto 0) := "0010"; -- 2
constant TEN_PAR: std_logic_vector(3 downto 0) := "0100"; -- 4 (42)
begin
CLOCK:
process
begin
wait for 10 ns;
clk <= not clk;
if Now > 500 ns then
wait;
end if;
end process;
DIGITS:
entity work.bcd_ud_ctr
port map (
AR => AR,
clk => clk,
ld => ld,
en => en,
up_Dn => up_dn,
D => DIG_PAR,
overflow => rollover,
Q => Q(3 downto 0)
);
TENS:
entity work.bcd_ud_ctr
port map (
AR => AR,
clk => clk,
ld => ld,
en => rollover,
up_Dn => up_dn,
D => TEN_PAR,
overflow => open,
Q => Q(7 downto 4)
);
STIMULUS:
process
begin
wait for 10 ns;
AR <= '1';
wait for 10 ns;
AR <= '0';
up_dn <= '0'; -- up
en <= '1';
wait for 260 ns;
up_dn <= '1';
wait;
end process;
end architecture;
And this gives:
While this simply shows the one's digit rolling over then down counting and rolling under the testbench can be extended.