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?
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:
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.
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.
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
:
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).