Reputation: 15
I have a 25MHz clock in my FPGA and I would like to make a timer which returns '1' when it counts for 60 seconds. But I have two problems:
Here are my VHDL files:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.STD_LOGIC_ARITH.all;
use IEEE.STD_LOGIC_UNSIGNED.all;
entity count is
Port ( clk : in STD_LOGIC;
count_entree : in STD_LOGIC;
count_sortie : out STD_LOGIC
);
end count;
architecture Behavioral of count is
signal q : integer range 0 to 30000000 :=0;
begin
process(clk)
begin
if (clk'event and clk='1')
then
while ((count_entree = '1') and (q < 25000000)) loop
if (q < 25000000) then
q := q + 1;
count_sortie <= '0';
else
count_sortie <= '1';
end if;
end loop;
end if;
end process;
end Behavioral;
And the testbench file:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
ENTITY tbcount IS
END tbcount;
ARCHITECTURE behavior OF tbcount IS
-- Component Declaration for the Unit Under Test (UUT)
COMPONENT count
PORT(
clk : in STD_LOGIC;
count_entree : in STD_LOGIC;
count_sortie : out STD_LOGIC
);
END COMPONENT;
--Inputs
signal clk : std_logic := '0';
signal count_entree : std_logic;
--Outputs
signal count_sortie : std_logic;
--Clock
constant clk_period : time := 40 ns;
BEGIN
-- Instantiate the Unit Under Test (UUT)
uut: count PORT MAP (
clk => clk,
count_entree => count_entree,
count_sortie => count_sortie
);
-- Clock process definitions
clk_process :process
begin
clk <= '0';
wait for clk_period/2;
clk <= '1';
wait for clk_period/2;
end process;
-- Stimulus process
stim_proc: process
begin
count_entree <= '1';
wait;
end process;
END;
Thank you for your support.
Upvotes: 1
Views: 804
Reputation:
No one has actually answered your question:
- I don't understand why my outpout signal "count_sortie" is undefined in Vivado when I simulate it.
- To force to define my signal count_sortie, I add ":= 0" in the testbench file to simulate but "count_sortie" stays equal to '0' after the 60 seconds delay.
As written with the variable assignment :=
your design description isn't valid VHDL.
It may be worth revisiting warning messages, what's going on should be apparent there. Instantiated count
labelled uut
is unbound in testbench tbcount
and it's output signal not driven. As far as the testbench is concerned there is not instantiation of count
.
As far as the unasked question 'how to get it work'
And as Jonathan has pointed out your code can't do what you want it to in any event. Jonathan's explanation of what the while loop does is essentially correct, you process won't work as intended even if uut
is instantiated.
The basic idea is to is to count until q
reaches 25,000,000 and set the output count_sortie
. Note that evaluating for 25000000 will actual add an extra clock delay to count_sortie
.
if clk'event and clk = '1' then
if q /= 24999999 and count_entree = '1' then
q <= q + 1;
end if;
if q = 24999999 then
count_sortie <= '1';
else
count_sortie <= '0';
end if;
end if;
This would count to 24999999 and stop counting. One clock later count_sortie
would be set (1
).
It has the property that if you were to clear or load q
back to 0 to retrigger the timer there'd be a one clock delay before count_sortie
went to '0'.
If that could be detrimental you could restore the comparison to 25000000 and move the if statement with the assignment to count_sortie
outside the bounds of the if statement evaluating the rising edge of clk
, or even make it a concurrent conditional signal assignment statement.
Keeping the assignment in the process might be more frugal, it share the same comparison for count
in synthesis, guaranteed.
That code in this answer above would then look something like this:
if clk'event and clk = '1' then
if q /= 25000000 and count_entree = '1' then
q <= q + 1;
end if;
end if;
if q = 25000000 then
count_sortie <= '1';
else
count_sortie <= '0';
end if;
And q
should be in the sensitivity list. Note also the range of integer q
only needs to extend from it's lefmost to it's rightmost assigned value.
To demonstrate this I've divides all the count values by 100,000 (for demo purposes, the numeric literal 250 can be set to 25000000 in all three places):
architecture behavioral of count is
signal q: integer range 0 to 250 ;
begin
timer:
process (clk,q)
begin
if clk'event and clk = '1' then
if q /= 250 and count_entree = '1' then
q <= q + 1;
end if;
end if;
if q = 250 then
count_sortie <= '1';
else
count_sortie <= '0';
end if;
end process;
end architecture;
Scaling q was about waiting for all those clocks needlessly just to
demonstrate count_sortie
worked with your testbench:
So now we've not only answered your question directly but shown how to make it work correctly.
And if you were intending to use count_sortie
as a clock you'd want to use the first method (using 24999999).
Upvotes: 1
Reputation: 3388
In addition to my comment on your syntax being invalid, i.e. there is a confusion wether q
is a signal or a variable, the following code will not do what you expect:
while ((count_entree = '1') and (q < 25000000)) loop
if (q < 25000000) then
q := q + 1;
count_sortie <= '0';
else
count_sortie <= '1';
end if;
end loop;
This loop is either an infinite loop if it's entered while count_entree = '1'
and q
is a signal, or resolves to the single statement count_sortie <= '0'
if q
is a variable.
Your loop doesn't have any wait statement. If q
is a signal, it will never be updated to a new value since this happens when a process ends or encounters a wait statement, you then get an infinite loop.
If q
is a variable, the loop is unrolled and only the last assignment is effective. Note that since you exit your loop if q < 25000000
, the else
statements are never executed.
Finally, note that this kind of structure would not be synthesizable, if it is your end goal.
Upvotes: 2