Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
16 years ago

VHDL Counter

I am new to VHDL, and I am trying to create a counter that will count up from 0 to X when a signal called enable will be true.

I get errors like Latches are generated for incomplete case or if statements. I don't know how to code it.

A signal called enable will drop low and before it goes low the counter is incrementing. What I want ideally is to use this counter and get the counts at the point where enable goes low.

A second counter picks up the ball (same counter instantiated twice) in the mean time I want to the counts of the first count to be zero before I use it.

The error I get is this

Found 16-bit latch for signal <cnts_out>. Latches may be generated from incomplete case or if statements. We do not recommend the use of latches in FPGA/CPLD designs, as they may lead to timing problems.

I don't know what to put on the else statement of this process...

can someone help please write a counter:

1. Count up

2. transfer the counts only when enable goes low

3. next time it is used it should start from zero up!

Help

[email protected]

pOut: process(enable,r_reg)

begin

if(enable ='0') then -- If the enable drops low then transfer the counts

cnts_out<= std_logic_vector(r_reg); --Typecast into bus vector

--temp <= std_logic_vector(r_reg); -- Keep the last counts

--else

-- cnts_out <= temp;

end if;

end process;


--Entry port 
entity Counter is
     generic(N: integer :=16);                   --Scale it to 20bits counter
    port ( clk         : in  STD_LOGIC;
           enable        : in     STD_LOGIC;        --Enable this counter
              reset        : in  STD_LOGIC;
              max_ticks    : out std_logic;
              cnts_out     : out  STD_LOGIC_VECTOR (N-1 downto 0));
end Counter;
architecture Behavioral of Counter is
signal r_reg: unsigned(N-1 downto 0):=x"0000";
begin
    
    pCntr: process(clk,reset,enable)                        --Counter process
        begin
            if(reset = '1') then
                r_reg <= (others => '0');
            elsif (clk'event and clk='1' and enable ='1') then          
                    r_reg <= r_reg + 1;                        --Increment 
            end if;
    end process;
    
    --Output logic
    --Only transfer the last count when enable goes low!   
 pOut: process(enable,r_reg)
    begin
        if(enable ='0') then                                    -- If the enable drops low then transfer the counts
            cnts_out<= std_logic_vector(r_reg);            --Typecast into bus vector
        end if;
    end process;
--Set an overflow Flag in due case we reach the maximum counts
    max_ticks <= '1' when r_reg = (2**N-1) else '0';    --Overflow counter indicator    
end Behavioral;

16 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Guys,

    I have modified the code you provided in an effort to get my counter to count up, and to reset it before it starts again based on the Enable signal = '1'. One thing I didn't mention is that the counter will not reach its rollover point, so I have to reset it some how before I reuse it.

    I am not sure the changes are correct but all the stuff I added is in RED, and comments are in green Would this work?

    
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
     
     
    entity Counter is
         generic(N: integer :=16);                   --Scale it to 20bits counter
        port ( clk         : in  STD_LOGIC;
               enable        : in     STD_LOGIC;        --Enable this counter
                  reset        : in  STD_LOGIC;
                  max_ticks    : out std_logic;
                  cnts_out     : out  STD_LOGIC_VECTOR (N-1 downto 0));
    end Counter;
     
     
    architecture Behavioral of Counter is
     
      signal r_reg: unsigned(N-1 downto 0):= to_unsigned(0, N);  --use to_unsigned function so that it works with the generic N
      signal q_reg: unsigned(N-1 downto 0):= to_unsigned(0,N); 
     signal enable_r : std_logic;   --enable register
     
    begin
     
      pCntr: process(clk,reset)   --no need for enable in here
      Variable X: integer range 0 to ((2**N)-1);    -- Will this work?
      begin
        if(reset = '1') then
          r_reg <= (others => '0');
        elsif rising_edge(clk) then          
          if enable = '1' then
            r_reg <= X + 1;     --Increment - this rolls over back to 0
          end if;
        end if;
     
    -- I need to start counting from zero next time I come back into the counter
    -- A signal controller is toggling the enable back High/low, but the r_reg
    -- will hold the previous value unless it sees a reset coming in which I don't
    -- available.  I am trying to clear out the r_reg so that after is sent
     
    -- How does this change detect the edge? If I am not mistaken (bear with
    -- me I am new to VHDL) it seems to me enable_r stores the state in the 
    -- first rising edge, since everything executes sequentially, the second time
    -- in the previous state will get over-written and the if() will not fire!  What
    -- is the explanation of this code so I understand why this works?
     
         --Register enable so we can detect falling edge
          enable_r <= enable;
     
     
    -- This code may generate the same warning since it does not have
    -- the else condition on it, unless I add this...
     
    --    if ((enable_r = '1') and (enable = '0')) then  --falling edge of enable
     
    if(enable = '0') then
      cnts_out <= std_logic_vector (r_reg);  --Changed to this since unsigned is different type than cnts_out right!
      X := 0;  --Reset the counter
    else
      cnts_out <= std_logic_vector(q_reg)   --Does this work?
    end if;
     
      end process;
     
      --Set an overflow Flag in due case we reach the maximum counts
      max_ticks <= '1' when r_reg = (2**N-1) else '0';    --Overflow counter indicator    
    end Behavioral;
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    LogicallyRed and Tricky... thank you so much for your help...

    Tricky: I want to start always at zero after I transfer the counts. I added the second comment to this code is this correct?

    
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
     
     
    entity Counter is
         generic(N: integer :=16);                   --Scale it to 20bits counter
        port ( clk         : in  STD_LOGIC;
               enable        : in     STD_LOGIC;        --Enable this counter
                  reset        : in  STD_LOGIC;
                  max_ticks    : out std_logic;
                  cnts_out     : out  STD_LOGIC_VECTOR (N-1 downto 0));
    end Counter;
     
     
    architecture Behavioral of Counter is
     
      signal r_reg: unsigned(N-1 downto 0):= to_unsigned(0, N);  --use to_unsigned function so that it works with the generic N
      signal enable_r : std_logic;   --enable register
     
    begin
     
      pCntr: process(clk,reset)   --no need for enable in here
      begin
        if(reset = '1') then
          r_reg <= (others => '0');
     
        elsif rising_edge(clk) then          
          if enable = '1' then
            r_reg <= r_reg + 1;     --Increment - this rolls over back to 0
          else
            r_reg <= to_unsigned(0, N);  --reset when enable is low
          end if;
     
          --Register enable so we can detect falling edge
          enable_r <= enable;
     
          if enable_r = '1' and enable = '0' then  --falling edge of enable
            cnts_out   <= r_reg;
          end if;
        end if;
      end process;
     
      --Set an overflow Flag in due case we reach the maximum counts
      max_ticks <= '1' when r_reg = (2**N-1) else '0';    --Overflow counter indicator    
    end Behavioral;
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Tricky, as usual, thank you for helping wash off all the newb on my shirt.

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    also - if you want the counter to reset after an enable burst:

    
    if enable = '1' then
      r_reg <= r_reg + 1;     --Increment - this rolls over back to 0
    else
      r_reg <= to_unsigned(0, N);  --reset when enable is low
    end if;
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Logically red:your code will work in a simulator, but wont work on an FPGA because you're trying to use the enable signal as a clock, which is not allowed.

    This is a much tidier version that wont give you any warnings about latches:

    
    library ieee;
    use ieee.std_logic_1164.all;
    use ieee.numeric_std.all;
    entity Counter is
         generic(N: integer :=16);                   --Scale it to 20bits counter
        port ( clk         : in  STD_LOGIC;
               enable        : in     STD_LOGIC;        --Enable this counter
                  reset        : in  STD_LOGIC;
                  max_ticks    : out std_logic;
                  cnts_out     : out  STD_LOGIC_VECTOR (N-1 downto 0));
    end Counter;
    architecture Behavioral of Counter is
      signal r_reg: unsigned(N-1 downto 0):= to_unsigned(0, N);  --use to_unsigned function so that it works with the generic N
      signal enable_r : std_logic;   --enable register
    begin
        
      pCntr: process(clk,reset)   --no need for enable in here
      begin
        if(reset = '1') then
          r_reg <= (others => '0');
          
        elsif rising_edge(clk) then          
          if enable = '1' then
            r_reg <= r_reg + 1;     --Increment - this rolls over back to 0
            
          end if;
            
          --Register enable so we can detect falling edge
          enable_r <= enable;
          
          if enable_r = '1' and enable = '0' then  --falling edge of enable
            cnts_out   <= r_reg;
          end if;
        end if;
      end process;
      
      --Set an overflow Flag in due case we reach the maximum counts
      max_ticks <= '1' when r_reg = (2**N-1) else '0';    --Overflow counter indicator    
    end Behavioral;
    
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hola Homie,

    I believe this code will do what you want.

    Cheers

    
    Library ieee;
    Use ieee.std_logic_1164.all;
    Use ieee.numeric_std.all;
    ----------------------------------->
    Entity YourCount is
      Generic( n: integer := 16);
      Port(
            clk : in std_logic ;
            rst : in std_logic;
            enable : in std_logic;
            max_ticks : out std_logic;
            Cnts_out : out Unsigned (N-1 downto 0)
            );
    End YourCount;
    ----------------------------------------->
    Architecture Count of YourCount is
    Begin
      
      ------------- CountBe quick ---------------------------
      CountBeQuick : Process(clk,rst,enable)
        Variable count : integer range 0 to ((2**N)-1);                -- integer range 0 to 65,535
      Begin
        if(rst = '1') then
          count := 0;            -- clear count
          max_ticks <= '0';     -- clear max ticks
        elsif (clk'EVENT and clk ='1' and enable = '1') then
          count := count + 1; 
          if (count = ((2**N)-1)) then
            max_ticks <= '1';     -- max_ticks stays high till reset
           end if;
        end if;
        
        if (enable'Event and enable ='0') then     -- this transfers count value and clears count
          Cnts_out <= TO_UNSIGNED(count,N);  -- converts count to unsigned of length N
          count := 0;
        end if;
       End Process CountBeQuick;
       ----------------------------------------------------------
    End Count;