VHDL: creating a very slow clock pulse based on a very fast clock

前端 未结 4 1463
悲哀的现实
悲哀的现实 2021-01-02 22:35

(I\'d post this in EE but it seems there are far more VHDL questions here...)

Background: I\'m using the Xilinx Spartan-6LX9 FPGA with the

相关标签:
4条回答
  • 2021-01-02 22:49

    Note for this example to work this line,

    signal clk_enable_counter : std_logic_vector(9 downto 0);

    must be changed to

    signal clk_enable_counter : unsigned(9 downto 0);

    and you'll need to include this library,

    library ieee; use ieee.numeric_std.all;

    0 讨论(0)
  • 2021-01-02 22:52

    Both your samples create a signal, one of which toggles at a slow rate, and one of which pulses a narrow pulse at a "slow-rate". If both those signals go to the clock-inputs of other flipflops, I would expect warnings about clock routing being non-optimal.

    I'm not sure why you get a gated clock warning, that usually comes about when you do:

    gated_clock <= clock when en = '1' else '0';
    
    0 讨论(0)
  • 2021-01-02 22:53

    Here's a Complete Sample Code :

    LIBRARY IEEE;
    USE IEEE.STD_LOGIC_1164.ALL;
    USE IEEE.NUMERIC_STD.ALL;
    
    ENTITY Test123 IS
    
        GENERIC (
            clk_1_freq_generic : unsigned(31 DOWNTO 0) := to_unsigned(0, 32); -- Presented in Hz
            clk_in1_freq_generic : unsigned(31 DOWNTO 0) := to_unsigned(0, 32) -- Presented in Hz, Also
        );
    
        PORT (
            clk_in1 : IN std_logic := '0';
            rst1 : IN std_logic := '0';
            en1 : IN std_logic := '0';
            clk_1 : OUT std_logic := '0'
        );
    
    END ENTITY Test123;
    
    ARCHITECTURE Test123_Arch OF Test123 IS
        --
        SIGNAL clk_en_en : std_logic := '0';
        SIGNAL clk_en_cntr1 : unsigned(31 DOWNTO 0) := (OTHERS => '0');
        --
        SIGNAL clk_1_buffer : std_logic := '0';
        SIGNAL clk_1_freq : unsigned(31 DOWNTO 0) := (OTHERS => '0'); -- Presented in Hz, Also
        SIGNAL clk_in1_freq : unsigned(31 DOWNTO 0) := (OTHERS => '0'); -- Presented in Hz
        --
        SIGNAL clk_prescaler1 : unsigned(31 DOWNTO 0) := (OTHERS => '0'); -- Presented in Cycles (Relative To The Input Clk.)
        SIGNAL clk_prescaler1_halved : unsigned(31 DOWNTO 0) := (OTHERS => '0');
        --
    
    BEGIN
        clk_en_gen : PROCESS (clk_in1)
        BEGIN
            IF (clk_en_en = '1') THEN
    
                IF (rising_edge(clk_in1)) THEN
                    clk_en_cntr1 <= clk_en_cntr1 + 1;
    
                    IF ((clk_en_cntr1 + 1) = clk_prescaler1_halved) THEN   -- a Register's (F/F) Output Only Updates Upon a Clock-Edge : That's Why This Comparison Is Done This Way !
    
                        clk_1_buffer <= NOT clk_1_buffer;
                        clk_1 <= clk_1_buffer;
                        clk_en_cntr1 <= (OTHERS => '0');
    
                    END IF;
    
                END IF;
    
            ELSIF (clk_en_en = '0') THEN
    
                clk_1_buffer <= '0';
                clk_1 <= clk_1_buffer;
                clk_en_cntr1 <= (OTHERS => '0'); -- Clear Counter 'clk_en_cntr1'
    
            END IF;
    
        END PROCESS;
    
        update_clk_prescalers : PROCESS (clk_in1_freq, clk_1_freq)
        BEGIN
            clk_prescaler1 <= (OTHERS => '0');
            clk_prescaler1_halved <= (OTHERS => '0');
            clk_en_en <= '0';
    
            IF ((clk_in1_freq > 0) AND (clk_1_freq > 0)) THEN
    
                clk_prescaler1 <= (clk_in1_freq / clk_1_freq); -- a Register's (F/F) Output Only Updates Upon a Clock-Edge : That's Why This Assignment Is Done This Way !
                clk_prescaler1_halved <= ((clk_in1_freq / clk_1_freq) / 2); -- (Same Thing Here)
    
                IF (((clk_in1_freq / clk_1_freq) / 2) > 0) THEN -- (Same Thing Here, Too)
                    clk_en_en <= '1';
                END IF;
    
            ELSE
                NULL;
            END IF;
    
        END PROCESS;
    
        clk_1_freq <= clk_1_freq_generic;
        clk_in1_freq <= clk_in1_freq_generic;
    
    END ARCHITECTURE Test123_Arch;
    
    0 讨论(0)
  • 2021-01-02 23:01

    If you just need a clock to drive another part of your logic in the FPGA, the easy answer is to use a clock enable.

    That is, run your slow logic on the same (fast) clock as everything else, but us a slow enable for it. Example:

    signal clk_enable_200kHz  : std_logic;
    signal clk_enable_counter : std_logic_vector(9 downto 0);
    
    --Create the clock enable:
    process(clk_200MHz)
    begin
      if(rising_edge(clk_200MHz)) then
        clk_enable_counter <= clk_enable_counter + 1;
        if(clk_enable_counter = 0) then
          clk_enable_200kHz <= '1';
        else
          clk_enable_200kHz <= '0';
        end if;
      end if;
    end process;
    
    
    --Slow process:
    process(clk_200MHz)
    begin
      if(rising_edge(clk_200MHz)) then
        if(reset = '1') then
          --Do reset
        elsif(clk_enable_200kHz = '1') then
          --Do stuff
        end if;
      end if;
    end process;
    

    The 200kHz is approximate though, but the above can be extended to basically any clock enable frequency you need. Also, it should be supported directly by the FPGA hardware in most FPGAs (it is in Xilinx parts at least).

    Gated clocks are almost always a bad idea, as people often forget that they are creating new clock-domains, and thus do not take the necessary precautions when interfacing signals between these. It also uses more clock-lines inside the FPGA, so you might quickly use up all your available lines if you have a lot of gated clocks.

    Clock enables have none of these drawbacks. Everything runs in the same clock domain (although at different speeds), so you can easily use the same signals without any synchronizers or similar.

    0 讨论(0)
提交回复
热议问题