Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers

VHDL Counter

Altera_Forum
Honored Contributor II
8,529 Views

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 

rjrodrig@yahoo.com 

 

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;
0 Kudos
16 Replies
Altera_Forum
Honored Contributor II
4,711 Views

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;
0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

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;
0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

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;
0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

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

0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

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;
0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

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;
0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

I suggest you try the code I posted, without the enable = '0' reset condition. 

 

For the bit you dont understand, you have to remember that what you are trying to do is describe hardware, not write code. For what I posted, the enable_r signal will always be what enable was 1 clock cycle ago. This way you can check to see if enable has changed since the last clock cycle. The "if" statement I put in detects a falling edge on the enable signal. This is the only way to detect falling/rising edges in logic (clocks are a special case). 

 

With the variable you added, you never actually set the value of X to anything other than 0, so r_reg will always be 1.
0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

I tried it, and even the simulator and hardware predict the same... I gets zeros out... not counts at all. I don't know how to do this... It can't be that difficult.

0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

have you connected the clock?

0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

Yes...I have connected everything. i think the way i am going to approach this problem will be the dumb way. I will let the counter run and use a d-ff to latch only the last value so the fifo only gets the largest count. 

 

I don't know how to make counter that resets itself on an enable trigger and only provides the last count... thanks for your help though
0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

VHDL is so complex!!

0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

I figured out a work around I just created a simple counter. I created a separate unit which provide a reset signal so I can reset the counters. I also made sure the counter counts only when enable is true.  

 

This works fine 

 

 

 

use IEEE.STD_LOGIC_1164.ALL; use IEEE.STD_LOGIC_ARITH.ALL; use IEEE.STD_LOGIC_UNSIGNED.ALL; --Entry port entity Counter is generic(N: integer :=16); --Scale it to 20 bits 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: std_logic_vector (N-1 downto 0) := (others =>'0'); BEGIN PCntr: process(clk,reset,enable) begin if(reset='1') then r_reg <= (others => '0'); elsif(rising_edge(clk)) then if(enable='1') then r_reg <= r_reg + 1; else r_reg <=(others => '0'); end if; end if; end process PCntr; --Output logic max_ticks <= '1' when r_reg = (2**N-1) else '0'; --Overflow counter indicator cnts_out <= r_reg; end Behavioral;
0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

Usually is a bad Idea to make the process sensitive to enable. 

Just remove enable from the sensitivity list.
0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

I know I am posting in an Altera Website... I am using Xilinx ISE... It complains if it is not in the sensitivity list. Also, as I understand it, the reason why you put it in the sensitivity list is so that the "event" when any of the signals within the process(*) changes state, the process block will execute. 

 

So I would think if the enable happens to change, as it is in my case of a random signal, I need to be able to start and stop my counter. If I don't put it there, there is a chance my counter will neither stop or start its counting process. So I don't completely agree with your statement, but I have been proven wrong other times. 

 

I am not very experienced VHDL writer. I only do glue logic with CPLDS...
0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

 

--- Quote Start ---  

I know I am posting in an Altera Website... I am using Xilinx ISE... It complains if it is not in the sensitivity list. Also, as I understand it, the reason why you put it in the sensitivity list is so that the "event" when any of the signals within the process(*) changes state, the process block will execute. 

 

So I would think if the enable happens to change, as it is in my case of a random signal, I need to be able to start and stop my counter. If I don't put it there, there is a chance my counter will neither stop or start its counting process. So I don't completely agree with your statement, but I have been proven wrong other times. 

 

I am not very experienced VHDL writer. I only do glue logic with CPLDS... 

--- Quote End ---  

 

 

If it is complaining, it is a bug with ISE. Nothing will happen unless there is a clock event, so having the process execute when enable changes is pointless. You only care about the state of the enable signal when there is an event on "clk". 

 

Adding extra signals to sensitivity lists reduces the performance of your code inside a simulator as it makes the simulator evaluate the process unneccesarily.
0 Kudos
Altera_Forum
Honored Contributor II
4,711 Views

Proof of what I am saying, this code: 

if(enable='1') then r_reg <= r_reg + 1; else r_reg <=(others => '0'); end if; Will only get executed at posedge clk NO MATTER what. 

 

And that means: adding "enable" to the sensitivity list will only confuse your code (for both humans and compilers). 

 

Besides that, when enable changes, surely there will be a clk posedge shortly after that (after all clk is a PERIODIC signal), and at that point your code WILL get evaluated (have no fear). 

 

Besides that I also know ISE tools and I know what I'm saying here :)
0 Kudos
Reply