Electronic – Generation of non overlapping clocks on FPGA using VHDL

hdltimingtiming-analysisvhdl

I am trying to implement switched capacitor circuits and I hence need to generate a two-phase non-overlapping clock. I have been trying to use an FPGA for the same. Unfortunately, my synthesis tool- Quartus II is throwing timing warnings. Further, when I dump the code onto the FPGA (Altera MAX7000S series FPGA), I clearly observe metastable levels and unpredictable outputs.

The code that I've written to implement this is given below:

architecture clock_gen_integrator_arch of clock_gen_integrator is
signal counter_15 : STD_LOGIC_VECTOR(3 downto 0);
signal phi1_sig, phi2_sig: STD_LOGIC;
signal counter : STD_LOGIC_VECTOR(14 downto 0);

begin
phi1     <= phi1_sig;
phi2     <= phi2_sig;

signal_gen: process (reset, clock25M) begin
    if(reset = '0') then
        counter_15    <= (others => '0');
        counter       <= (others => '0');
        phi1_sig      <= '1';
        phi2_sig      <= '0';
        reset_int     <= '1';
    elsif(clock25M = '1' and clock25M'EVENT) then
              if(counter < "000010000000000" and counter_15 < "1111") then
              phi1_sig      <= '0';
              phi2_sig      <= '0';
              counter       <= counter + 1;
              reset_int     <= '0';
          elsif (counter < "011100000000000" and counter_15 < "1111") then
              phi1_sig      <= '1';
              phi2_sig      <= '0';
              counter       <= counter + 1;
              reset_int     <= '0';
          elsif (counter < "100010000000000" and counter_15 < "1111") then
              phi1_sig      <= '0';
              phi2_sig      <= '0';
              counter       <= counter + 1;
              reset_int     <= '0';
          elsif (counter < "111100000000000" and counter_15 < "1111") then
              phi1_sig      <= '0';
              phi2_sig      <= '1';
              counter       <= counter + 1;
              reset_int     <= '0';
          elsif (counter < "111111111111111" and counter_15 < "1111") then
              phi1_sig      <= '0';
              phi2_sig      <= '0';
              counter       <= counter + 1;
              reset_int     <= '0';
          elsif (counter = "111111111111111" and counter_15 < "1111") then
              counter_15    <= counter_15 + 1;
              counter       <= counter + 1;
              reset_int     <= '0';
          else 
              phi1_sig      <= phi1_sig;
              phi2_sig      <= phi2_sig;
              reset_int     <= '0';
          end if;

        end if;
    end process;
end architecture;

Unforunately, I'm not able to include the entire code here, I'm having formatting issues. However, since it's just the entity decleration, I have left it out. phi1(out), phi2(out), reset(in), reset_int(out), clock25M(in) are present in the port list.

In this code, I'm arbitrarily choosing the frequency and duty cycles of the required clocks. I specifically want 15 pulses of phi1 and 15 pulses of phi2 and counter_15 helps me achieve this.

I am being told by QuartusII that I have setup time violations.
Setup time violations reported by QuartusII. There are 100 of them in total

This is the output

Sorry for the greyscale image, I had to reduce the size of the image somehow in order to upload it. The first channel is the phi1 output and the second channel is the phi2 output.
Being new to the tool as well as timing analysis, I'd be grateful if someone could point out what I am doing wrong and how I can fix the timing violation. Also, any tips on how to avoid these issues in general are welcome.

Best Answer

One general method for improving timing is to split logic over multiple cycles by registering results.

You could try something like this...

signal_gen: process (reset, clock25M) begin
    if(reset = '0') then
        counter_15    <= (others => '0');
        counter       <= (others => '0');
        phi1_sig      <= '1';
        phi2_sig      <= '0';
        reset_int     <= '1';
        counter_15_not_done <= true;
        count_lt_000010000000000 <= false;
        count_lt_011100000000000 <= false;
        count_lt_100010000000000 <= false;
        count_lt_111100000000000 <= false;
        count_lt_111111111111111 <= false;
        count_eq_111111111111111 <= false;
    elsif(clock25M = '1' and clock25M'EVENT) then
          --the comparisons are computed in parallel and registered
          counter_15_not_done <= counter_15 < "1111";
          count_lt_000010000000000 <= count < "000010000000000";
          count_lt_011100000000000 <= count < "011100000000000";
          count_lt_100010000000000 <= count < "100010000000000";
          count_lt_111100000000000 <= count < "111100000000000";
          count_lt_111111111111111 <= count < "111111111111111";
          count_eq_111111111111111 <= count = "111111111111111";
          --the logic now only depends on the registered results.
          --The registered results are only 7 bits rather than 19 bits
          --this should have much better timing
          if(count_lt_000010000000000 and counter_15_not_done) then
              phi1_sig      <= '0';
              phi2_sig      <= '0';
              counter       <= counter + 1;
              reset_int     <= '0';
          elsif (count_lt_011100000000000 and counter_15_not_done) then
              phi1_sig      <= '1';
              phi2_sig      <= '0';
              counter       <= counter + 1;
              reset_int     <= '0';
          elsif (count_lt_100010000000000 and counter_15_not_done) then
              phi1_sig      <= '0';
              phi2_sig      <= '0';
              counter       <= counter + 1;
              reset_int     <= '0';
          elsif (count_lt_111100000000000 and counter_15_not_done) then
              phi1_sig      <= '0';
              phi2_sig      <= '1';
              counter       <= counter + 1;
              reset_int     <= '0';
          elsif (count_lt_111111111111111 and counter_15_not_done) then
              phi1_sig      <= '0';
              phi2_sig      <= '0';
              counter       <= counter + 1;
              reset_int     <= '0';
          elsif (count_eq_111111111111111 and counter_15_not_done) then
              counter_15    <= counter_15 + 1;
              counter       <= counter + 1;
              reset_int     <= '0';
          else 
              phi1_sig      <= phi1_sig;
              phi2_sig      <= phi2_sig;
              reset_int     <= '0';
          end if;

        end if;
    end process;
end architecture;

Note that the registered results will lag the actual counts by 1 clock cycle so you may need to adjust the comparison points back 1 cycle.

Related Topic