Search code examples
if-statementvhdlfpgapulse

How can i generate a pulse train to give output in common way?


I am working on generating a 40 bit length pulse train. I also must be able to adjust the frequency. I tried to make a new low frequency clock and i make a new counter which counts on it's rising edges and give an high output and terminating after 40 bit. It's not working. I tried some other methods. They are not, too.

For example;

    library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.all;

entity con40 is port(clk:in std_ulogic; q:out std_ulogic); 
end entity con40; 

architecture Behaviour of con40 is 
    constant s:std_ulogic_vector:="11111111111111111111111111111111"; 
    signal i:unsigned(4 downto 0):="00000"; 
     signal en:std_logic:='1';
     signal reset:std_logic:='0';
begin 
    q<=s(to_integer(i)); 

    process(reset,clk) is begin 
        if reset='1' then 
          i<=(others=>'0'); 
        elsif rising_edge(clk) then 
            if en='1' then 
                i<=i+1; 
                end if; 
        end if; 
    end process; 
end architecture Behaviour;

There is 32-bit length in this code but i wanna make 40 bit but whatever, this is not working too. I think methods for such a pulse train must be common and they are being used widely. But hey! unluckily i can find nothing useful.


Solution

  • I took the liberty of moving en and reset to port signals, also changed your constant to a recognizable 40 bit value, and specified the range to make it a locally static constant.

    The issue with your counter is that it isn't big enough to address 40 bits. You have i specified as a 5 bit value while 40 bits requires a 6 bit counter.

    I also added a second architecture here with i as an integer type signal. With i as either an unsigned value or an integer type you likely need to roll over the i counter at 39 ("100111") when the first position is 0 ("000000").

    library ieee;
    use ieee.std_logic_1164.all;
    
    entity con40 is 
        port(
            reset:  in  std_ulogic;
            clk:    in  std_ulogic;
            en:     in  std_ulogic;
            q:      out std_ulogic
        ); 
    end entity con40; 
    
    architecture foo of con40 is 
        constant s: std_ulogic_vector (0 to 39) := x"feedfacedb"; 
        signal i:   natural range 0 to 39;
    begin 
        q <= s(i); 
    
        process (reset, clk) 
        begin     
            if reset = '1' then 
              i <= 0; 
            elsif rising_edge(clk) and en = '1' then 
                if i = 39 then 
                    i <= 0;
                else
                    i <= i + 1; 
                end if; 
            end if; 
        end process; 
    end architecture;
    
    library ieee;
    use ieee.numeric_std.all;
    
    architecture behave of con40 is 
        constant s: std_ulogic_vector (0 to 39) := x"feedfacedb"; 
        signal i:   unsigned (5 downto 0);
    begin 
        q <= s(to_integer(i)); 
    
        process (reset, clk) 
        begin     
            if reset = '1' then 
              i <= "000000"; 
            elsif rising_edge(clk) and en = '1' then 
                if i = "100111" then 
                    i <= "000000";
                else
                    i <= i + 1; 
                end if; 
            end if; 
        end process; 
    end architecture;
    

    I also did a quick and dirty test bench:

    library ieee;
    use ieee.std_logic_1164.all;
    
    entity tb_con40 is
    end entity;
    
    architecture foo of tb_con40 is
        signal clk:     std_ulogic := '0';
        signal reset:   std_ulogic := '1';
        signal en:      std_ulogic := '0';
        signal q:       std_ulogic;
    begin
    
    DUT:
        entity work.con40
            port map  (
                reset => reset,
                clk => clk,
                en => en,
                q => q
            );
    
    CLOCK:
    process
    begin
        for i in 0 to 46 loop
            wait for 20 ns;
            clk <= not clk;
            wait for 20 ns;
            clk <= not clk;
        end loop;
        wait;
    end process;
    
    STIMULUS1:
        reset <= '0' after 40 ns;
    
    STIMULUS2:
        en <= '1' after 60 ns;
    
    end architecture;
    

    Which can demonstrate the correct output:

    enter image description here

    addendum in response to comment question

    The pattern X"FEEDFACEDB" is 40 bits long and was substituted for the 32 all '1's value for constant s to demonstrate that you are actually addressing individual elements of the s array value.

    To stop the pulse train fro recurring:

    For architecture foo (using an integer type for i):

        elsif rising_edge(clk) and en = '1' then 
            -- if i = 39 then
            --     i <= 0;
            -- else
            if i /= 39 then  -- added
                i <= i + 1; 
            end if; 
    

    This stops the counter from operating when it reaches 39.

    For architecture behave (using an unsigned type for i):

        elsif rising_edge(clk) and en = '1' then 
            -- if i = "100111" then
            --     i <= "000000";
            -- else
            if i /= "100111" then  -- added
                i <= i + 1; 
            end if; 
        end if; 
    

    Both architectures behave identically stopping the i counter at 39 ("100111").

    The counter can be shown to have stopped by simulating:

    enter image description here

    Without adding an additional control input the only way to get the pulse stream to occur a second time would be by invoking reseet.