-1

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.

  • 1
    For starters, `q <= s(to_integer(i));` when `s` is a constant vector that's all `'1'`s guarantees that your output will never be anything other than `'1'`, ever, at all. – fru1tbat Sep 11 '14 at 10:33
  • but that's not the answer. – Mehmet Salih Cüvelek Sep 11 '14 at 11:30
  • No, just a comment. It's not exactly clear to me from your question what your parameters are, but if you at least fix some of the glaring problems, you might be able to make some progress. – fru1tbat Sep 11 '14 at 12:14
  • I have 2 options in my mind to achieve this. First, generating a new slow clock (adjustable one) and generating a signal from leading edges of the slow clock, and doing this job 40 times and quit. – Mehmet Salih Cüvelek Sep 11 '14 at 12:51
  • Second one is that share in my post. Making a constant which consists 40-bit length 1s. And giving that to output with some adjustable speed. And making this only once and stop. I think question is clear. Why are these ways not working and isn't there a common way to achieve this? – Mehmet Salih Cüvelek Sep 11 '14 at 12:56
  • 1
    You say you want a pulse train (by which I assume you mean you want a 40-pulse sequence, i.e. 40 `'1'`/`'0'` cycles), but shifting out a vector of just 40 `'1'`s will give you a single 40-clock long pulse (since you're never shifting out a `'0'`). That's what's not exactly clear. Which do you want? – fru1tbat Sep 11 '14 at 13:07
  • You're right. That one is not correct, ok. I want 1-0-1-0.. like a clock. – Mehmet Salih Cüvelek Sep 12 '14 at 20:19

3 Answers3

0

The following code could be a simple implementation to generate pulse trains. This module requires a start impulse (StartSequence) and acknowledges the generated sequence with 'SequenceCompleted'.

Instead of an state machine I use a basic RS flip flop with set = StartSequence and rst = SequenceCompleted_i. I also broke up the process into two processes:

  1. state control - this can be extended to a full FSM if needed
  2. used for counter(s)

Initially, the module emits PULSE_TRAIN(0) by default and also after each sequence generation. So if you want to emit 40 ones otherwise zero set PULSE_TRAIN := (0 => '0', 1 to 40 => '1')

This module is variable in the bit count of PULSE_TRAIN, so I needed to include a function called log2ceil, which calculates the 2s logarithm aka needed bits from PULSE_TRAIN's length attribute. So in case of 'length = 41 bits Counter_us has a range of (5 downto 0).

entity PulseTrain is
  generic (
    PULSE_TRAIN       : STD_LOGIC_VECTOR
  );
  port (
    Clock             : in  STD_LOGIC;
    StartSequence     : in  STD_LOGIC;
    SequenceCompleted : out STD_LOGIC;
    Output            : out STD_LOGIC
  ); 
end entity; 

architecture rtl of PulseTrain is
  function log2ceil(arg : POSITIVE) return NATURAL is
    variable tmp : POSITIVE := 1;
    variable log : NATURAL  := 0;
  begin
    if arg = 1 then  return 0; end if;
    while arg > tmp loop
      tmp := tmp * 2;
      log := log + 1;
    end loop;
    return log;
  end function;

  signal State               : STD_LOGIC                                           := '0';
  signal Counter_us          : UNSIGNED(log2ceil(PULSE_TRAIN'length) - 1 downto 0) := (others => '0');
  signal SequenceCompleted_i : STD_LOGIC;

begin 
  process(Clock) is
  begin 
    if rising_edge(Clock) then
      if (StartSequence = '1') then
        State <= '1';
      elsif (SequenceCompleted_i = '1') then
        State <= '0';
      end if;
    end if;
  end process;

 SequenceCompleted_i <= '1' when (Counter_us = (PULSE_TRAIN'length - 1)) else '0';
 SequenceCompleted   <= SequenceCompleted_i;

  process(Clock)
  begin
    if rising_edge(Clock) then
      if (State = '0') then
        Counter_us <= (others => '0');
      else
        Counter_us <= Counter_us + 1;
      end if;
    end if;
  end process;

  Output <= PULSE_TRAIN(to_integer(Counter_us));
end;
Paebbels
  • 15,573
  • 13
  • 70
  • 139
0

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.

  • But your if statement provides an endless loop. When the number is 39 it returns to start and runs on. I just want a 40 times of 1-0 and stop. In addition i don't understand "feedfacedb". What's that, how is it work? – Mehmet Salih Cüvelek Sep 12 '14 at 20:34
  • See the addendum to the answer for stopping the pulse train after one occurrence. The pattern `X"FEEDFACEDB"` was selected to demonstrate the constant was being output in the correct order. –  Sep 12 '14 at 22:27
  • Thanks for response. There is one more question. Why does your test bench simulation show that q is arbitrary, not a forty times of square wave? Because the code about that shows that you use equal delays. Why does this occur? – Mehmet Salih Cüvelek Sep 16 '14 at 13:29
  • Your original design shows a counter selecting bits (`q<=s(to_integer(i))`) from a constant that are all '1's. The `X"FEEDFACEDB"` isn't all '1's, it's `"1111111011101101111110101100111011011011"`. Each bit selected one at a time by the `i` counter. The pattern was whimiscally picked to show the addressing was in the correct order - it's not a palindrome. If you check in the waveform they all come out, `i` is left pointing to the last one, a '1'. It's also 40 bits long. –  Sep 16 '14 at 19:13
0

As what @fru1tbat mentioned, it's not really clear what is "not working" and what you really intend to do. If you would really just want to generate a pulse train, one would think you want to generate a series of alternating '1' and '0', not all '1's like in the code you posted.

Also, the i counter just counts up, and can only be reset to '0' by use of the reset signal, which is fine as long as you intended it that way.

If you'd like to generate a train of '1's and '0's, you'd need something like this (not tested, but should be along these lines):

architecture behaviour of con40 is
    constant trainLength:positive:=80;
    signal i:unsigned(6 downto 0):=(others=>'0');
    ...
begin
    process(reset,clk) is begin 
        if reset then 
            i<=(others=>'0');
            q<='0';
        elsif rising_edge(clk) then
            q<='0';    -- default assignment.
                       -- Defaults to '0' when if-statement fails.

            if i<trainLength then
                i<=i+1;
                q<=not q;
            end if;
        end if;
    end process;
end architecture behaviour;

This gives you a single-shot pulse train, means there is no way to repeat generation of the pulse train unless you assert the reset signal again. This is fine if it's what you want, otherwise, you'll need more signals to cater for cases where you'd like to re-generate the pulse train without resetting.

Here, I'm assuming you'd like 40 HIGH pulses, which essentially makes the train length 80 clock cycles, not 40. Also, I'm assuming you want a 50% duty cycle, i.e. the HIGH and LOW times are equal. Depending on your requirements, you may need a pulse width that is longer or shorter.

With these assumptions in mind, you'd need at least a 7-bit counter to count 80 clocks. You may think of other better ways to do this as well, but this just comes off the top of my head, and is probably a good place to start.

If your tool doesn't yet support VHDL-2008's enhanced port modes (e.g. ability to read from out-mode ports), then you could declare q as having a buffer mode instead of out. If your tool doesn't support buffer port modes, then you can declare an internal signal and use it for your logic. E.g.:

signal i_q: std_ulogic;
...
i_q<=not i_q;  -- use internal signal for logic instead.
q<=i_q;        -- drive output from internal signal.

To adjust the frequency, simply supply a higher or lower frequency into your clk input. This can be generated from another PLL, or a frequency divider, or any other oscillating circuitry you have available. Just supply its output into your clk.

Hope this helps.

Daniel Kho
  • 96
  • 1
  • 3
  • 1
    I just want 40 times 1-0-1-0 like a clock and stop and sure with 50% duty cycle. I analyzed your code. Something called my attention: q<=not q; if we make it that way q becomes inout and i know that way strongly unrecommended. And i heard that it's not syntetizable. And how i adjust frequency with your code? – Mehmet Salih Cüvelek Sep 12 '14 at 20:46
  • Alright, seems like my assumption was correct then. My code assumes a 40 times "10" repeating pattern. Yes, traditionally q would have to be declared as inout, but VHDL-2008 now allows "out"-mode ports to be read. Tool support for this may be lacking though. So, use "buffer" in place of "out". It's synthesizable, depending on which tool you use - I've used it for many designs in Quartus, and have not faced any problems as yet. You should re-test the "strongly unrecommended" advise you've been hearing again when new tools or standards emerge, especially when the style or technique is good. – Daniel Kho Sep 13 '14 at 14:20
  • If your tool doesn't support the "buffer" mode, then declare an internal signal, and drive q from that internal signal. I'll edit my answer to include this example. – Daniel Kho Sep 13 '14 at 14:22
  • 1
    I'm using ISE 14.5 and i am not able to read from out port. And i did what u said, assigned q is a buffer and it is now syntetizable. I can not try it on the board at this time. But i don't understand how the loop turns 80 times. Because "q<=not q;" is out of the "if i – Mehmet Salih Cüvelek Sep 16 '14 at 14:03
  • Great. At least you've reached this stage. To stop generating the pulse train after 80 times, just make your 'en' go low after the counter 'i' reaches 79. i<=i+1 will count from zero till 79 ( – Daniel Kho Sep 23 '14 at 17:23
  • While working on this, I thought there was a simpler way. I'll use the 'i – Daniel Kho Sep 23 '14 at 17:31