Diana Vrabie
Diana Vrabie

Reputation: 45

Implementing a reversing counter in VHDL

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

Answers (1)

NextHendrix
NextHendrix

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

Related Questions