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

(I would post this in EE, but there seem to be even more VHDL questions here ...)

Background: I am using Xilinx Spartan-6LX9 FPGA with Xilinx ISE 14.4 (webpack).

I came across the scary warning "PhysDesignRules: 372 - Gated clock" today, and I see there a lot of discussion about this in general. The consensus seems to be to use one of the DCMs on the FPGA to do the clock separation, but ... my DCM doesn't seem to be able to switch from 32 MHz to 4.096 kHz (it goes to each master at 5 MHz based on 32 MHz ... and it seems absurd to try to bind multiple DCMs for this low-frequency purpose).

My current project uses clk_in to count to the specified value (15265), resets this value to zero and switches the clk_out bit (so I finish the 50% duty cycle, FWIW). It does the job, and I can easily use the cutting edge clk_out to control the next phase of my project. It seems that everything works fine, but ... closed hours (even if it is not in the range where the skew time will be very important). (Note: All watch tests are performed using the rising_edge () function in processes sensitive to that watch.)

So my questions are:

  • If we are talking about inferring a relatively slow clk_out from a faster clk_in, is gating still considered bad? Or is it the type of “count to x and send the pulse”, which is pretty typical for FPGAs to generate “clocks” in the KHz band, and instead some other unnecessary side effect can cause this warning instead?

  • Is there a better way to create a low kHz clock from the main MHz clock, bearing in mind that using multiple DCMs seems to be excessive (if possible with a very low output frequency)? I understand that a 50% duty cycle may be superfluous, but assuming that there is one clock input and no use of built-in DCMs, how else can you perform basic clock division using FPGA?

Edit: given the following (where CLK_MASTER is the 32 MHz input clock, and CLK_SLOW is the desired slow cycle, and LOCAL_CLK_SLOW is the way to save the clock state for the entire duty cycle), I found out that this configuration triggers a warning:

architecture arch of clock is constant CLK_MASTER_FREQ: natural := 32000000; -- time := 31.25 ns constant CLK_SLOW_FREQ: natural := 2048; constant MAX_COUNT: natural := CLK_MASTER_FREQ/CLK_SLOW_FREQ; shared variable counter: natural := 0; signal LOCAL_CLK_SLOW: STD_LOGIC := '0'; begin clock_proc: process(CLK_MASTER) begin if rising_edge(CLK_MASTER) then counter := counter + 1; if (counter >= MAX_COUNT) then counter := 0; LOCAL_CLK_SLOW <= not LOCAL_CLK_SLOW; CLK_SLOW <= LOCAL_CLK_SLOW; end if; end if; end process; end arch; 

While this configuration does NOT raise a warning:

 architecture arch of clock is constant CLK_MASTER_FREQ: natural := 32000000; -- time := 31.25 ns constant CLK_SLOW_FREQ: natural := 2048; constant MAX_COUNT: natural := CLK_MASTER_FREQ/CLK_SLOW_FREQ; shared variable counter: natural := 0; begin clock_proc: process(CLK_MASTER) begin if rising_edge(CLK_MASTER) then counter := counter + 1; if (counter >= MAX_COUNT) then counter := 0; CLK_SLOW <= '1'; else CLK_SLOW <= '0'; end if; end if; end process; end arch; 

So, in this case everything was due to the lack of another (as I said, the 50% duty cycle was initially interesting, but in the end it was not a requirement, and the switch of the “local” clock bit seemed pretty smart at that time ...) I was mostly on the right track, he appears.

What is not clear to me at the moment is why using a counter (which stores many bits) does not cause warnings, but a stored and output bit of the output causes warnings. Thoughts

+6
source share
4 answers

If you just need a clock to control another part of your logic in FPGA, the simple answer is to use clock resolution.

That is, run the slow logic on the same (fast) clock as everything else, but we will turn it on slowly. 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; 

200 kHz is approximate, but the above can be extended to, in principle, use any clock frequency. In addition, it must be supported directly by the FPGA equipment in most FPGAs (it is, at least in parts of Xilinx).

Closed watches are almost always a bad idea, as people often forget that they create new clock domains and, therefore, do not take the necessary precautions when signals interact between them. It also uses more hours in FPGA, so you can quickly use all available lines if you have many built-in clocks.

A clock does not have any of these drawbacks. Everything works in the same clock domain (although at different speeds), so you can easily use the same signals without any synchronizers or the like.

+7
source

Note for this example, to work with this line,

signal clk_enable_counter: std_logic_vector (9 to 0);

need to change to

signal clk_enable_counter: unsigned (9 downto 0);

and you will need to enable this library,

ieee library; use ieee.numeric_std.all;

+2
source

Both of your samples create a signal, one of which switches at a slow pace, and one of them gives a narrow impulse at a "slow speed". If both of these signals arrive at the clock inputs of other triggers, I would expect that the clock routing warnings would be suboptimal.

I'm not sure why you get a closed-clock warning that usually occurs when you do:

 gated_clock <= clock when en = '1' else '0'; 
0
source

Here is the full 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 (F/F) Output Only Updates Upon a Clock-Edge : That 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 (F/F) Output Only Updates Upon a Clock-Edge : That 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; 
-2
source

All Articles