0

I'm trying to design a traffic light controller and for this I need a number of different timers. Thus, I designed this generic timer in VHDL:

library IEEE;
use IEEE.std_logic_1164.all, IEEE.numeric_std.all;

entity timer is
generic (n: NATURAL :=20);
    port (clk, reset : in std_logic;
            count : buffer std_logic);
end entity timer;


architecture behavioural of timer is
begin
    o0: process (clk, reset) IS
    variable cnt : unsigned (n-1 downto 0);
    begin
        if reset = '0' then
            cnt := (others => '0');
        elsif rising_edge(clk) then
            cnt := cnt + 1;
        end if;
        if cnt = n-1 then
            count <= '1';
        else
            count <= '0';
        end if;
    end process;
end architecture behavioural;

However, when I run the timer it outputs 0 and never changes (I've tested this by mapping count to an LED on an Altera MAX II EMP240T100C5) and thus the states in my controller don't progress. I have no idea why this happens?

The General
  • 1,239
  • 2
  • 17
  • 28
  • 1
    If you fix this per David's suggestion and map to LED as you suggest above, then the LED will only lit for 1 clock once every 2**n-1 clocks and it is unlikely you will see the LED on. It will be on so briefly that it will be a very low intensity if at all. – Jim Lewis Apr 01 '14 at 05:13
  • @JimLewis Thanks, is there a way to make it sit on the value of 1 until it is reset? I really need to counter to stop after it has counted to the number specified. – The General Apr 01 '14 at 14:19

1 Answers1

1

Where n is the number of bits in cnt, this:

    if cnt = n-1 then
        count <= '1';

Should be:

    if cnt = 2**n-1 then
        count <= '1';

count is only '1' for one clock. Did you blink and miss it? You didn't specify clock rate. I set clk to 25 MHz for purposes of demonstrating the counter.

This is with the correction above and n set to 3 so it would fit in a short waveform display:

enter timer with n equal 3

Without the above correction the count 'pulse' would have occurred after 19 clocks. Why your traffic light controller didn't respond to it is another question.

Making count sticky

After your comment stating you wanted to use the timer as a 19 clock delay and you asked Jim how to latch count.

Assuming n-1 is the trigger value for count:

    elsif rising_edge(clk) and cnt /= n-1 then
        cnt := cnt + 1;
    end if;

This essentially uses the same n wide gate output as count with an inverter to provide and enable to the cnt counter. It will only get out of the latched trigger value for cnt by reset.

And why is cnt specified as an n bit value in it's declaration when it only needs to be 5 bits long in this case?

Are you planning on supplying a trigger count separately for generalizing your timer? In which case I'd suspect a synchronous reset would in order.

The simplest overall solution might be to -

Make cnt and integer type:

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

entity timer is
    generic (
        trigger_cnt:    natural := 19
    );
    port (
        clk:        in      std_logic;
        reset:      in      std_logic;
        count:      buffer  std_logic
    );
end entity timer;


architecture behavioural of timer is

begin
o0: process (clk, reset) IS
    variable cnt : natural range 0 to trigger_cnt;
    begin
        if reset = '0' then
            cnt := 0;
        elsif rising_edge(clk) and count = '0' then
            cnt := cnt + 1;
        end if;
        if cnt = trigger_cnt then
            count <= '1';
        else
            count <= '0';
        end if;
    end process;

end architecture;

library ieee;
use ieee.std_logic_1164.all;

entity tb_timer is
end entity;

architecture foo of tb_timer is
    signal clk:     std_logic := '0';
    signal reset:   std_logic;
    signal count:   std_logic;
begin 

DUT:  
    entity work.timer
    generic map (
        trigger_cnt =>  7
    )
    port map (
    clk => clk,
    reset => reset,
    count => count
    );

CLOCK:
    process

    begin
        wait for 20 ns;
        clk <= not clk;
        if Now > 360 ns then
            wait;
        end if;
    end process;

STIMULUS:
    process 
    begin
        reset <= '0';
        wait for 40 ns;
        reset <= '1';
        wait;
    end process;
end architecture;

Note this has the sticky count:

timer with integer type trigger count

Instead of n as a generic a value trigger_cnt (compatible with an integer type) is presented as a generic.

In the process trigger_cnt is used to limit the range of cnt which will get you a synthesized counter of the right number of bits.

Because the counter stops until reset you don't have any pesky errors based on an integer type cnt exceeding it's range.

This will only work for a trigger count that falls within the VHDL implementation's integer range (natural range shown here, subtype NATURAL is INTEGER range 0 to INTEGER'HIGH; where INTEGER'HIGH is implementation defined and at least 2**31-1 (+2147483647, See Predefined integer types, IEEE Std 1076).

  • Thanks. However, the intention is for the 'pulse' to occur after 19 clocks as it needs to trigger a change in the traffic light controller after n number of clock ticks. So does this mean that the code should be working as-is? – The General Apr 01 '14 at 13:59
  • Thanks, I've written that up and I'll test it shortly :). The reason its specified as 'n' bit value is because the timer needs to count to different sizes (e.g. at one point it's initialised as 'timer3 : timer generic map (n => 3) port map(clk,reset3,count3);') and I assumed that was how I'd make the number it counts to variable? – The General Apr 01 '14 at 19:25
  • 1
    I'd suggest either algorithmically (a function) relating the size of counter (`cnt`) to the trigger value and just provide it, or provide two generics. A count of 19 fits in a 5 bit counter while `(n-1 downto 0)` is 20 bits. A function could march up powers of 2 until it surpasses a trigger count (which wouldn't need to be a power of 2), providing the left value for the range of `cnt`. –  Apr 01 '14 at 19:53
  • Thanks, that works :). I assume this method is more efficient then my `(n-1 downto 0)` assigment? – The General Apr 10 '14 at 19:09
  • Making cnt just big enough with an unsigned cnt implementation it will be somewhat more efficient, not traversing bits you don't use for the + 1 operation. They'd naturally get pared during synthesis (producing warnings). Using a natural (integer) cnt is the most efficient. Instead of a function "+" with a loop traversing 'bits', it's a single operation for integer "+". When using a natural cnt the range tells synthesis how many bits to use. –  Apr 10 '14 at 19:28