Forum Discussion

Altera_Forum's avatar
Altera_Forum
Icon for Honored Contributor rankHonored Contributor
9 years ago

Generate a pulse by using a counter/timer

Hello,

I just started with FPGAs and thus I am trying to improve my VHDL skills. Recently I am building a design that generates a pulse which is meant to start a ADC conversion. My idea is to use a counter which controls the pulse length. Unfortunately, the counter seems to start but never reaches the value at which the pulse should end. After several hours of trying I have no clue what is going wrong. May you could have a look at my code.

So this is my counter:

library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity counter is
    generic
    (
        n : natural := 1
    );
    
    port
    (
        clock : in std_logic;
        clock_enable : in std_logic;
        reset : in std_logic;
        output : out std_logic_vector((n-1) downto 0)
    );
end;
architecture behaviour of counter is
    signal counter_value : std_logic_vector((n-1) downto 0) := (others => '0');
    
begin
    
    process(clock, reset)
    begin
        if (reset = '1') then
            counter_value <= (others => '0');
        elsif (rising_edge(clock)) then
            if (clock_enable = '1') then
                counter_value <= counter_value + 1;
            end if;
        end if;
    end process;
    output <= counter_value;
end behaviour;

And here is my ADC design file, which uses the counter:

library ieee;
    use ieee.std_logic_1164.all;
    use ieee.std_logic_arith.all;
    use ieee.std_logic_unsigned.all;
    
entity ti_ads1675 is
    port
    (
        -- ports required by the TI ADS1675
        start : out std_logic;
        
    
        -- ports required by the avalon-mm interface
        clock : in std_logic;
        reset_n : in std_logic;
        
        read : in std_logic;
        write: in std_logic;
        
        address: in std_logic;
        
        writedata : in std_logic_vector(31 downto 0);
        readdata : out std_logic_vector(31 downto 0)
    );
end ti_ads1675;
architecture rtl of ti_ads1675 is
    
    component counter is
        generic
        (
            n : natural := 1
        );
        port
        (
            clock                : in            std_logic;
            clock_enable    : in            std_logic;
            reset                : in            std_logic;
            output            :         out    std_logic_vector(n downto 0)
        );
    end component;
    
    -- counter related signals
    signal counter_clock_enable : std_logic := '0';
    signal counter_reset : std_logic := '1';
    signal counter_value : std_logic_vector(31 downto 0);
    
    -- general signals
    signal control_register : std_logic_vector(31 downto 0) := x"00000000";
    signal data_register : std_logic_vector(31 downto 0);
begin
    counter_inst : component counter
        generic map
        (
            n => 32
        )
        port map
        (
            clock    => clock,
            clock_enable => counter_clock_enable,
            reset => counter_reset,
            output => counter_value        
        );
    registers : process (clock)
    begin
        if (rising_edge(clock)) then
            -- reset registers
            if (reset_n = '0') then
                data_register <= x"00000000";
                control_register <= x"00000000";
                readdata <= x"00000000";
            -- read register contents
            elsif (read = '1') then
                if (address = '0') then
                    readdata <= data_register;
                elsif (address = '1') then
                    readdata <= control_register;
                end if;
            -- write register contents
            elsif (write = '1') then
                if (address = '0') then
                    data_register <= writedata;
                elsif (address = '1') then
                    control_register <= writedata;
                end if;
            end if;
        end if;
    end process registers;
    
    
    --------------------------
    -- gererate start pulse --
    --------------------------
    process (control_register(2), counter_value)
    begin
        if (rising_edge(control_register(2))) then
            counter_reset <= '0';
            counter_clock_enable <= '1';
            start <= '1';
        elsif (counter_value = x"0000ffff") then
            start <= '0';
            counter_clock_enable <= '0';
            counter_reset <= '1';
            control_register(2) <= '0';
        end if;
    end process;
end rtl;

I have absolutely no clue what is wrong here. The counter itself works, so I think I made a (logic?) fault in my ADC design file. I am thankful for any tips or hints.

Regards Michael

3 Replies

  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi,

    At least one problem is in line:

    if (rising_edge(control_register(2))) then

    do not use rising_edge function to detect rising edge of general signal of your design. rising_edge function ment to be used for CLOCK edge detection.

    Regards,
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    This is the culprit code:

    
    --------------------------
        -- gererate start pulse --
        --------------------------
        process (control_register(2), counter_value)
        begin
            if (rising_edge(control_register(2))) then
                counter_reset <= '0';
                counter_clock_enable <= '1';
                start <= '1';
            elsif (counter_value = x"0000ffff") then
                start <= '0';
                counter_clock_enable <= '0';
                counter_reset <= '1';
                control_register(2) <= '0';
            end if;
        end process;
    

    This is not good code, so I have no idea what the synthesisor made of it. Did you look at the RTL and technology diagram?

    You should clock this with "clock", and make an edge detector circuit with control_register(2) -

    
    process(clock)
    begin
    if rising_edge(clk) then
      control_register2_r <= control_register(2);
      if control_register2_r = '0' and control_register(2) = '1' then -- you have a rising_ege on the signal
    

    Do you have a testbench to test this code in the simualtor?

    And as you're trying to improve your VHDL skills - stop using std_logic_arith and std_logic_unsigned. They are non-standard VHDL libraries. Use numeric_std instead.
  • Altera_Forum's avatar
    Altera_Forum
    Icon for Honored Contributor rankHonored Contributor

    Hi, thank you for your fast replies. I'll have a closer look at your suggestions and try to change my code accordingly. I'll report the outcome...

    ... with your help I just go the design running. I build an edge detector an used it to start my counter. Here is the code:

    library ieee;
        use ieee.std_logic_1164.all;
    entity edge_detector is
        port
        (
            clock         : in     std_logic;
            signal_in : in     std_logic;
            output     :   out std_logic
        );
    end edge_detector;
    architecture behavioral of edge_detector is
        signal signal_delayed : std_logic;
        
    begin
        process (clock)
        begin
            if (rising_edge(clock)) then
                signal_delayed <= signal_in;
            end if;
        end process;
        output <= signal_in and (not signal_delayed);
    end behavioral;

    And following the updated code snippet of the ADC-Design:

        process(control_register_start_edge, counter_value)
        begin
            if (control_register_start_edge = '1') then
                counter_reset <= '0';
                counter_clock_enable <= '1';
                start <= '1';
            elsif (counter_value = x"00000004") then
                start <= '0';
                counter_clock_enable <= '0';
                counter_reset <= '1';
            end if;
        end process;

    I was able to verify the design with ModelSim and even used the 'start' signal to blink an LED on my BeMicro CV ;)

    No I am looking for a intelligent way to reset my register bit to '0' again. My first idea was to use a reset signal which would be detected in my r/w register process...

    So after all, thank you for your help!