cephal
cephal

Reputation: 15

VHDL My timer does not work

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

Answers (2)

user1155120
user1155120

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:

tbcount for q in range 0 to 250 (clickable)

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

Jonathan Drolet
Jonathan Drolet

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

Related Questions