Reputation: 45
I am new to VHDL and I am trying to implement a counter that counts up from 0 to its maximum value, then automatically starts counting down once it reached the max value. This is my entity and architecture:
entity Rev_Counter is -- self-reverting counter
generic (
counter_steps: integer:=256; -- number of steps of the counter
counter_output_size: integer:=8 -- smallest nr of bits to represent the biggest value of the counter
);
port (
clock: in std_logic; -- input clock signal
output: out std_logic_vector (counter_output_size-1 downto 0)
);
end Rev_Counter;
architecture Arh_Rev_Counter of Rev_Counter is
signal count_sig: std_logic_vector (counter_output_size-1 downto 0) := (others => '0');
signal count_dir: std_logic := '0'; -- 0 = count up, 1 = count down
begin
Count: process (clock)
begin
if (clock'event and clock = '1') then
if (count_sig = counter_steps-1) then -- revert the counting direction
count_dir <= '1'; -- reached highest value, count down
count_sig <= count_sig - 1;
elsif (count_sig = 0) then -- revert the counting direction
count_dir <= '0'; -- reached lowest value, count up
count_sig <= count_sig + 1;
end if;
if (count_dir = '0') then -- perform count up
count_sig <= count_sig + 1;
elsif (count_dir = '1') then -- preform count down
count_sig <= count_sig - 1;
end if;
end if;
end process;
output <= count_sig;
end architecture;
My problem is: when simulating this code, my counter counts up to FF normally, then it starts acting strange. After counting up to FF, it goes straight to 00, then FF, then 00 and so on, without the numbers in between. I would appreciate some help figuring out why it acts this way.
I found an alternative way to do it. I edited the Count
process to look like this. However, I don't exactly understand what was wrong in the first place, therefore I'd still appreciate some insight.
Count: process (clock)
begin
if (clock'event and clock = '1') then
if (count_dir = '0') then
count_sig <= count_sig + 1;
if (count_sig = counter_steps - 1) then
count_sig <= count_sig - 1;
count_dir <= '1';
end if;
elsif (count_dir = '1') then
count_sig <= count_sig - 1;
if (count_sig = 0) then
count_dir <= '0';
end if;
end if;
end if;
end process;
Upvotes: 0
Views: 959
Reputation: 26
You are changing count_dir
one tick too late at either end.
Since it is a registered value, the effects of changing it have a 1 clock period delay. As a result, on reaching 0xFF count_sig
will increment one more time (0x00) before reversing the direction. It will then count 'down' to 0xFF, reversing the direction again, resulting in the value constantly flicking between 0x00 and 0xFF.
Altering your conditions to change direction to count_sig = counter_steps - 2
and count_sig = 1
respectively gives you the behaviour you want.
Upvotes: 1