Continue to Site

Welcome to EDAboard.com

Welcome to our site! EDAboard.com is an international Electronics Discussion Forum focused on EDA software, circuits, schematics, books, theory, papers, asic, pld, 8051, DSP, Network, RF, Analog Design, PCB, Service Manuals... and a whole lot more! To participate you need to register. Registration is free. Click here to register now.

Synchronous programmable counter

Status
Not open for further replies.

jonnybgood

Full Member level 4
Joined
Dec 28, 2010
Messages
214
Helped
3
Reputation
6
Reaction score
1
Trophy points
1,298
Activity points
3,011
I implemented an 8-bit Synchronous programmable counter with;

-asynchronous active low reset
-Synchronous enable
-Count up or down (with rising edge)
-Terminal counter up (for overflow)
-Terminal Counter down (underflow)
-Asynch load


-8-bit parallel load:

--counter.vhd
LIBRARY ieee;
-- STD_LOGIC and STD_LOGIC_VECTOR types, and relevant functions
use ieee.std_logic_1164.all;
-- SIGNED and UNSIGNED types, and relevant functions
use ieee.numeric_std.all;

ENTITY counter IS
PORT (
dir, cnt_en, clk : in std_logic := '0';
Reset, load : in std_logic;
p : in INTEGER RANGE 0 TO 255;
qd : inout INTEGER RANGE 0 TO 255;
TCU, TCD : out std_logic;
cnt_in : inout std_logic_vector (7 downto 0) := (others => '0');
cnt_out : out std_logic_vector (7 downto 0) := (others => '0'));
END counter;

ARCHITECTURE RTL OF counter IS
signal cnt : INTEGER RANGE 0 TO 255;
signal NotCPU : std_logic := '0';
BEGIN


cnt_out <= std_logic_vector(to_unsigned(cnt, cnt_out'length));

PROCESS (clk, Reset, p, qd, dir, cnt_en, cnt, load)



BEGIN
IF (Reset = '0') THEN
cnt <= 0;


ELSIF (load = '1' and Reset = '1') THEN --load is activated
cnt <= p;


ELSE
IF (rising_edge(clk)) THEN
IF (dir = '1' and cnt_en = '1') THEN
cnt <= cnt + 1;
TCD <= '1';
TCU <= '1';

ELSIF (dir = '0' and cnt_en = '1') THEN
cnt <= cnt - 1;
TCD <= '1';
TCU <= '1';

END IF;

END IF;
END IF;
qd <= cnt;
if cnt = 0 then
if (dir = '1') then
TCD <= '1';
TCU <= '1';
elsif (dir = '0') then
TCD <= '0';
TCU <= '1';
end if;
elsif (cnt = 255) then
if (dir = '1') then
TCD <= '1';
TCU <= '0';
elsif (dir = '0') then
TCD <= '1';
TCU <= '1';
end if;
end if;

END PROCESS;
END RTL;
_____________________________________________________________________________________________________

When I simulated with the following test bench I got results that match the Truth table in the 74HC193 data sheet. What do you think? The only problem is that although I am declaring an integer with a range, when the integer (cnt) is exceeding the maximum upper limit 255, the simulation stops instead of resetting the this integer (cnt) automatically. Do I have to take care of resetting it my self in the vhdl code?

Also, the 74HC193 implements the counters slightly different from mine. It uses two separate clocks for count up or count down. Each one is clocked while the other is held high;
HTML:
http://www.nxp.com/documents/data_sheet/74HC_HCT193.pdf

I tried to follow this method but there seems to be issue when considering two possible clocks;


ELSE
IF (CPU = '1' and CPD = '1') THEN
IF (rising_edge(CPU)) THEN
cnt <= cnt + 1;
TCD <= '1';
TCU <= '1';


ELSIF (rising_edge(CPD)) THEN
cnt <= cnt - 1;
TCD <= '1';
TCU <= '1';

END IF;
END IF;

I get this error: ..behavior depends on the edges of multiple distinct clocks ..

What can be a possible solution for this?

task2_sim.pngtask2_sim.png
--counter_test.vhd

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

use ieee.std_logic_unsigned.all;

entity counter_test is
end Entity counter_test;


Architecture behavioral of counter_test is

Signal dir, cnt_en, clk, TCU, TCD : std_logic := '0';
Signal Reset, load : std_logic := '1';
signal p, qd : integer range 0 to 255 ;
Signal Endsim : std_logic := '0';
Signal cnt_in, cnt_out : std_logic_vector (7 downto 0) := (others => '0');

begin

UUT : entity work.counter
port map ( clk => clk,
Reset => Reset,
load => load,
p => p,
dir => dir,
qd => qd,
TCU => TCU,
TCD => TCD,
cnt_en => cnt_en,
cnt_in => cnt_in,
cnt_out => cnt_out);

CLK_process :process
begin
if(EndSim = '0') then
clk <= NOT clk;
wait for 2ns;
else wait;
end if;
end process;

Signals : process

Begin

wait for 0.5 ns;

Reset <= '1';
dir <= '1';
cnt_en <= '1';
load <= '0';

wait for 1020ns;

cnt_en <= '0';

wait for 50ns;
cnt_en <= '1';
dir <= '0';

wait for 1020ns;
cnt_en <= '0';

wait for 50ns;
load <= '1';
p <= 100;

wait for 4ns;
load <= '0';
cnt_en <= '1';

wait for 200ns;
Reset <= '0';

wait for 100ns;
EndSim <= '1';
wait;
end process;

end Architecture behavioral;
 

You are using 2 clocks in 1 process... in the 2nd code
in the 1st code you can make the code better by putting all statements inside the clock. you are including too much of combinatorial logic.
 

With reference to 1st code; I put the asynchronous elements outside the clock conditions etc.. Does this cause any problem?
 

The best way is to completely separate your asyncronous elements outside the process or include in another combinatorial process.
I think you should consider spending some time on, how your code would look like after hardware implementation.
And how can you make a down counter asyncronous ?
 

I will try to make a separate process for combinational. Regarding the down counter, actually it is synchronous. It is my fault because of my bad indentation;

IF (rising_edge(clk)) THEN

IF (dir = '1' and cnt_en = '1') THEN
cnt <= cnt + 1;
TCD <= '1';
TCU <= '1';

ELSIF (dir = '0' and cnt_en = '1') THEN
cnt <= cnt - 1;
TCD <= '1';
TCU <= '1';

END IF;

END IF;
 

This should work fine.. provided you are not using multiple clock ( if using multiple clock then the you are meeting timing requirements )

Also , either you need to use std_logic_unsigned.all package ( not a standard package) or you should make the counter unsigned integer or signed to perform arithmetic operation under ieee.std.numeric.all package.
try this --
HTML:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;

-- Uncomment the following library declaration if using
-- arithmetic functions with Signed or Unsigned values
use IEEE.std_logic_unsigned.all;

entity up_down is
    Port ( clk : in  STD_LOGIC;
            clr : in  STD_LOGIC;
	    dir : in  STD_LOGIC;
           count_out : out  STD_LOGIC_VECTOR (3 downto 0)
           );
end up_down;

architecture rtl of up_down is
  signal cnt_en : std_logic := '0';
  signal cnt : STD_LOGIC_VECTOR (3 downto 0) := "0000";
begin
process (clk, clr)
begin

  If clr = '1' then 
    cnt <= (others => '0');
  ElsIF (rising_edge(clk)) THEN
    IF (dir = '1' and cnt_en = '1') THEN
       if cnt = "1111" then 
          cnt <= "0000";
       else
          cnt <= cnt + 1;
       end if;
    ElsIF (dir = '0' and cnt_en = '1') THEN
       if cnt = "0000" then 
          cnt <= "1111";
       else
          cnt <= cnt - 1;
       end if;
   END IF;
 END IF;
end process;
count_out <= cnt ;
end rtl;
I am using unsigned package bcoz of laziness..
 
Last edited:
Status
Not open for further replies.

Part and Inventory Search

Welcome to EDABoard.com

Sponsor

Back
Top