Gated Clock in Clock Divider for a Square Wave - time

I recently have been designing a clock divider for my system - which I redesigned, and now has an asynchronous reset, which generates a synchronous reset for the rest of the system. To do this, I followed the answers & advice to my own question and used a clock enable to toggle an output, thus generating clock with a 50% duty cycle (which is desired).
However, this has thrown up the error when generating the bitstream of
PhysDesignRules:372 - Gated clock. Clock net ... is sourced by a combinatorial pin. This is not good design practice. Use the CE pin to control the loading of data into the flip-flop.
Reading into this question about using the clock enable, it appears when creating a clock enable is correct, however, because I need a square wave (and not just a 1/200MHz pulse), and thus using the enable to toggle another signal, it appears in this question that this is an intentional gated clock.
So my questions are; is this gated clock warning significant? Both in simulation, and on an oscilloscope it appears to function correctly (so I'm inclined to ignore it), but am I storing problems for later? Is there a way of getting a very slow 50% duty cycle pulse without a gated clock?
I've put my code below!
Thanks very much (especially to the handful of people who have collectively given a lot of time to my recent non-stop questions)
David
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;
library UNISIM;
use UNISIM.VComponents.all;
ENTITY CLK_DIVIDER IS
GENERIC(INPUT_FREQ : INTEGER;
OUT1_FREQ : INTEGER;
OUT2_FREQ : INTEGER
);
PORT(SYSCLK : IN STD_LOGIC;
RESET_N : IN STD_LOGIC;
RESET_N_OUT : OUT STD_LOGIC;
OUT1 : OUT STD_LOGIC;
OUT2 : OUT STD_LOGIC);
END CLK_DIVIDER;
architecture Behavioral of Clk_Divider is
constant divider1 : integer := INPUT_FREQ / OUT1_FREQ / 2;
constant divider2 : integer := INPUT_FREQ / OUT2_FREQ / 2;
signal counter1 : integer := 0;
signal counter2 : integer := 0;
signal output1 : std_logic := '0';
signal output2 : std_logic := '0';
signal reset : boolean;
begin
reset_proc : process(RESET_N, SYSCLK)
variable cycles : integer := 0;
variable reset_counter : integer := 0;
begin
if rising_edge(SYSCLK) then
if cycles < 2 then
if reset_counter >= divider1 then
cycles := cycles + 1;
reset_counter := 0;
else
reset_counter := reset_counter + 1;
end if;
reset <= true;
else
reset <= false;
end if;
end if;
if RESET_N = '0' then
cycles := 0;
reset_counter := 0;
reset <= true;
end if;
end process;
output1_proc : process(SYSCLK)
begin
if rising_edge(SYSCLK) then
if counter1 >= divider1 - 1 then
output1 <= not output1;
counter1 <= 0;
else
counter1 <= counter1 + 1;
end if;
if RESET_N = '0' then
counter1 <= 0;
output1 <= '1';
end if;
end if;
end process;
output2_proc : process(SYSCLK)
begin
if rising_edge(SYSCLK) then
if counter2 >= divider2 - 1 then
output2 <= not output2;
counter2 <= 0;
else
counter2 <= counter2 + 1;
end if;
if RESET_N = '0' then
counter2 <= 0;
output2 <= '1';
end if;
end if;
end process;
OUT1 <= output1;
OUT2 <= output2;
RESET_N_OUT <= '0' when reset else '1';
end Behavioral;

The comments suggest, that the clock-divider is instantiated in a larger design.
If you want to use the generated clock there, you must add a BUFG between signal output2 and the output out2 like this:
out2_bufg : BUFG port map(I => output2, O => out2);
The component BUFG is defined in the library unisim.vcomponents. Same applies to output out1.
The BUFG ensures, that the generated clock is distributed using a clock-tree, so that the clock signal arrives at all destination flip-flops at the same time. This minimizes hold-time violations and gives more room for the setup of data signals.
If you still get the warning/error, then you combined the generated clock signal with another signal elsewhere in the larger design.

The reset_proc process is written with a elsif cycles > 1 then outside the clocked part, and with the condition derived from cycles which is also assigned as part of reset. It is unclear what hardware is actually described here, but it makes the synthesis tool unhappy.
If you want to use RESET_N as asynchronous reset, then just make a simple if RESET_N = '0' then ... end if;, and assign whatever signals or variables required to be reset. Other assignments should be moved to the clocked part.
NOTE: Code was changed after the above update... which may have removed the reason for the question.
Btw. RESET_N is used as asynchronous reset in the reset_proc, but as synchronous reset in the other processes, and this inconsistent use looks like there may be a potential problem with the reset scheme.

Related

Would like someone to double check code for 8bit up counter with enable

I am a novice coder and don't know if what I did was correct so I would appreciate if someone could double check it for me.
So im trying to make an 8-bit up counter with an active-low count enable control signal. The counter should advance to the next count if cten = 0 and stops at the current count if cten = 1. The counter resets into a state that outputs binary 0 and progresses upward on each clock edge when counting is enabled until it reaches 255. It locks in the state producing output 255. I also tried to change the clock to 1Hz clock from a 50MHz clock the is on a FPGA board that will be used to run some instructions (with there being no more than 255 instructions, hence wanting to lock at that number) based off the count value of int_q.
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity counter is
port(
clk, rst, cten: in std_logic;
q: out std_logic_vector(7 downto 0)
);
end entity counter;
architecture moore of counter is
signal d,int_q: std_logic_vector(7 downto 0);
signal cnt: integer range 0 to 25000;
signal clk1Hz: std_logic;
begin
-- drive internal Q signal to output signal
q <= int_q;
-- next-state logic: add 1 unless 255, lock at 255
d <= int_q+1 when int_q < 255;
d <= int_q when int_q = 255;
process(clk)
begin
if rising_edge(clk) then
cnt <= cnt+1;
if cnt = 25000 then
clk1Hz <= not clk1Hz;
cnt <= 0;
end if;
end if;
end process;
-- register process
process(all)
begin
if rising_edge(clk1Hz) then
if rst ='1' then int_q <= "00000000";
elsif cten = '0' then int_q <= int_q+1;
else int_q <= int_q;
end if;
end if;
end process;
end architecture moore;
Several issues:
If rst is unasserted on the rising edge of clk1Hz, then int_q will remain in an unknown state.
clk1Hz is never initialized, so the not operation does nothing.
cnt is never initialized, so incrementing it does nothing.
int_q is being driven in 2 places: both inside and outside a process.
signal d is unused, did you want to connect it to q?
You're only counting to 25_000, but if your source clock is 50 MHz, you need to count to 25_000_000.
If you want a synchronous reset, (which given the name "Moore", I bet this is homework), it's good practice to create a new process specifically to internally synchronize that async reset signal to the system clock, maybe through a 2FF synchronizer for one idea.
If I understood the question correctly, this should get you in the ballpark:
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_unsigned.all;
use ieee.numeric_std.all;
entity counter is
port(
clk, rst, cten: in std_logic;
q: out std_logic_vector(7 downto 0)
);
end entity counter;
architecture moore of counter is
signal int_q: std_logic_vector(7 downto 0);
signal cnt: integer range 0 to 25_000_000;
signal clk1Hz: std_logic;
begin
-- indicate when at 255
q <= '1' when int_q = 255 else '0';
process(rst, clk)
begin
if rst = '1' then
-- need to assign initial values
clk1Hz <= '0';
cnt <= 0;
elsif rising_edge(clk) then
if cnt = 25_000_000 then
clk1Hz <= not clk1Hz;
cnt <= 0;
else
cnt <= cnt+1;
end if;
end if;
end process;
-- register process
process(rst, clk1Hz)
begin
if rst = '1' then
int_q <= (others => '0');
elsif rising_edge(clk1Hz) then
if cten = '0' then
int_q <= int_q+1; -- rolls over
end if;
end if;
end process;
end architecture moore;
If you want to map this in an FPGA you cannot generate a clock like you do. Clocks are very special signals with strict electrical requirements. If you need a 1Hz frequency clock and the frequency of your master clock is 50MHz there are basically two options:
Use a clock manager/generator hard macro of your FPGA if it has some, and configure it to generate a 1Hz clock from your master clock. Explicitly pass the output through a clock buffer if your tools don't do it automatically.
Do not generate a 1Hz clock, use an enable signal that you assert high once every 50M clock periods. Or use a rescaler and increment your counter only when the rescaler reaches a predefined value.
As the first option depends on your FPGA, your tools, etc. let's investigate the second:
library ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
entity counter is
generic(freqHz: positive := 50000000);
port(clk, rst, cten: in std_ulogic;
q: out std_ulogic_vector(7 downto 0));
end entity counter;
architecture moore of counter is
signal rescaler: integer range 0 to freqHz - 1;
signal cnt: integer range 0 to 255;
begin
q <= std_ulogic_vector(to_unsigned(cnt, 8));
process(clk)
begin
if rising_edge(clk) then
if rst = '1' then
rescaler <= freqHz - 1;
cnt <= 0;
elsif cnt /= 255 then
if rescaler /= 0 then
rescaler <= rescaler - 1;
else
rescaler <= freqHz - 1;
cnt <= cnt + 1;
end if;
end if;
end if;
end process;
end architecture moore;
Remarks:
Use ieee.std_logic_unsigned or ieee.numeric_std but not both. And as noted by #JHBonarius, do not use ieee.std_logic_unsigned at all. It is not standard and deprecated. Use ieee.numeric_std_unsigned, instead.
I added a generic parameter (freqHz) with a default value such that you can easily adapt to different clock frequencies.
The 50Mhz to 1Hz rescaler is decremented instead of incremented because a hardware zero detector is frequently slightly smaller and faster than an arbitrary value detector.
If you do not know the difference between std_logic and std_ulogic, always use std_ulogic, never std_logic (and use std_ulogic_vector instead of std_logic_vector, u_unsigned instead of unsigned...) One day or another you will really need std_logic and this day you will understand the difference, and why you should (almost) never use it. And do not listen to people who tell you that std_logic is more standard or better supported by the tools or whatever. They are wrong. The only exception is your teacher or your boss: even if they are wrong, it might be better to obey.

Why does the output signals post-synthesis not work as usual?

I had written a small VHD file for simulating the behavior of a quadrature decoder, enclosed below. Simulating the design with a generic testbench works as expected. But after generating a synthesizable design with Quartus, I run into one of two problems (while playing with using unsigned, for example)
1. The position and direction signal are always at a constant 0 value throughout the post-synthesis simulation.
2. The position value seems to jump 10 values every 3-4 clock cycles, which I attribute to some jitter in data.
Does anyone have any recommendations to solve this issue? Is this mainly a timing problem or is there a major flaw in my design?
LIBRARY ieee;
USE ieee.std_logic_1164.ALL;
USE ieee.NUMERIC_STD.ALL;
entity quad_decoder is
port(rst : in std_logic;
clk : in std_logic;
a : in std_logic;
b : in std_logic;
direction : out std_logic;
position : out std_logic_vector(8 DOWNTO 0));
end quad_decoder;
architecture behavioral of quad_decoder is
begin
process(clk)
variable counter : integer range 0 to 360 := 0;
variable chanA,chanB : std_logic;
variable int_direction : std_logic;
begin
if (rst = '0') then
int_direction := '0';
counter := 0;
elsif (rising_edge(clk)) then
chanA := a;
chanB := b;
if (chanA = '1') and (chanB = '0') then
if (counter = 360) then
counter := 0;
else
counter:= counter + 1;
end if;
int_direction := '1';
elsif (chanA = '0') and (chanB = '1') then
if (counter = 0) then
counter := 360;
else
counter := counter-1;
end if;
int_direction := '0';
else
counter := counter;
int_direction := int_direction;
end if;
position <= std_logic_vector(to_unsigned(counter,9));
direction <= int_direction;
end if;
end process;
end behavioral;
The expected pre-synthesis snap is here.
I've linked an example snap of the post-synthesis simulation here. As seen, no change to position nor direction in multiple clock cycles.
If anyone is inquisitive, doing assignments right at the clock edge as well as turning the reset signal high proved to introduce all kinds of timing issues, which passed the multi-corner timing analysis test, but failed other tests in Quartus that I had failed to notice.
I can go into more details if my answer is vague.

Quartus II : simple counter but weird behaviour

First of all I'm sorry to bother you guys with my very noob question, but I can't find any sense to what's happening with my (ModelSim simulated) circuit.
Here's my code, simple as can be :
LIBRARY ieee;
use ieee.std_logic_1164.all;
use ieee.numeric_std.all;
ENTITY Counter IS
PORT(
enable : in std_logic;
clk : in std_logic;
count : out integer range 0 to 255);
END Counter;
ARCHITECTURE LogicFunction OF Counter IS
signal count_i : integer range 0 to 255;
begin
cnt : process(clk, enable, count_i)
begin
count <= count_i;
if (enable = '0') then
count_i <= 0;
else
count_i <= count_i + 1;
end if;
end process;
end LogicFunction;
My problem is : when I perform a timing simulation with ModelSim, with a clock signal, "enabled" is first '0' and then '1', the output ("count") stays at zero all the time. I tried a lot of different things, like setting the "count" out as a vector, doing all sorts of casts, but it still stays the same.
The increment "count_i <= count_i + 1;" seems to be the problem : I tried to replace it with something like "count_i <= 55", and then the output changes (to "55" in the previous example).
I've seen the exact same increment in the code on that webpage for example :
http://surf-vhdl.com/how-to-connect-serial-adc-fpga/
I've created a project, simulated it and... it works ! I really don't get what the guy did that I didn't, excepted for a bunch of "if" that I don't need in my code.
Any help would be greatly appreciated, I've spent like 3 hours of trial and errors...
Thanx in advance !
In addition to not using a clock edge to increment i_count you're using enable as a clear because it's both in the sensitivity list and encountered first in an if statement condition.
library ieee;
use ieee.std_logic_1164.all;
-- use ieee.numeric_std.all;
entity counter is
port(
enable : in std_logic;
clk : in std_logic;
count : out integer range 0 to 255);
end counter;
architecture logicfunction of counter is
signal count_i : integer range 0 to 255;
begin
cnt : process (clk) -- (clk, enable, count_i)
begin
-- count <= count_i; -- MOVED
-- if (enable = '0') then -- REWRITTEN
-- count_i <= 0;
-- else
-- count_i <= count_i + 1;
-- end if;
if rising_edge(clk) then
if enable = '1' then
count_i <= count_i + 1;
end if;
end if;
end process;
count <= count_i; -- MOVED TO HERE
end architecture logicfunction;
Your code is modified to using the rising edge of clk and require enable = '1' before i_count increment. The superfluous use clause referencing package numeric_std has been commented out. The only numeric operation you're performing is on an integer and those operators are predefined in package standard.
Note the replacement if statement doesn't surround it's condition with parentheses. This isn't a programming language and they aren't needed.
The count assignment is moved to a concurrent signal assignment. This removes the need of having i_count in the sensitivity list just to update count.
Throw in a testbench to complete a Miminal Complete and Verifiable Example:
library ieee;
use ieee.std_logic_1164.all;
entity counter_tb is
end entity;
architecture foo of counter_tb is
signal enable: std_logic := '0';
signal clk: std_logic := '0';
signal count: integer range 0 to 255;
begin
DUT:
entity work.counter
port map (
enable => enable,
clk => clk,
count => count
);
CLOCK:
process
begin
wait for 5 ns; -- 1/2 clock period
clk <= not clk;
if now > 540 ns then
wait;
end if;
end process;
STIMULUS:
process
begin
wait for 30 ns;
enable <= '1';
wait for 60 ns;
enable <= '0';
wait for 30 ns;
enable <= '1';
wait;
end process;
end architecture;
And that gives:
Which shows that the counter doesn't counter when enable is '0' nor does enable = '0' reset the value of i_count.
The Quartus II Handbook Volume 1 Design and Synthesis doesn't give an example using a clock edge and an enable without an asynchronous clear or load signal.
The secret here is anything inside the if statement condition specified using a clock edge will be synchronous to the clock. Any condition outside will be asynchronous.
The form of synthesis eligible sequential logic is derived from the now withdrawn IEEE Std 1076.6-2004 IEEE Standard for VHDL Register
Transfer Level (RTL) Synthesis. Using those behavioral descriptions guarantees you can produce hardware through synthesis that matches simulation.

VHDL state machine with several delays - best approach?

This is a generic question that has bugged me since I was able to understand the Basics of a finite state machine. Suppose I have four states s0 - s3, where
the FSM will automatically start at 's0' after power is applied. After some defined delay, the FSM shall enter 's1' - the same goes for the other states.
The delay between the different states is not the same.
For example:
Power up -> 's0' -> 100 ms -> 's1' -> 50 us -> 's2' -> 360 us -> 's3' -> 's3'
In a procedural language as C, I'd just call a delay routine with one parameter being the required delay and be done with it.
How do I implement this sort of FSM elegantly ?
best,
Chris
My pattern : a delay counter which each state transition can program as and when required, i.e. at the start of each new delay.
It's all synthesisable, though some tools (notably Synplicity) have trouble with accurate Time calculations unless your clock period is an integer number of nanoseconds. For more information on this bug, see this Q&A. If you run into this situation, magic numbers (32000 instead of Synplicity's calculated 32258 in that question) may be the simplest workaround.
Wrapping it in an entity/architecture left as an (easy) exercise.
-- first, some declarations for readability instead of magic numbers
constant clock_period : time := 10 ns;
--WARNING : Synplicity has a bug : by default it rounds to nanoseconds!
constant longest_delay : time := 100 ms;
subtype delay_type is natural range 0 to longest_delay / clock_period;
constant reset_delay : delay_type := 100 ms / clock_period - 1;
constant s1_delay : delay_type := 50 us / clock_period - 1;
constant s2_delay : delay_type := 360 us / clock_period - 1;
-- NB take care to avoid off-by-1 error!
type state_type is (s0, s1, s2, s3);
-- now the state machine declarations:
signal state : state_type;
signal delay : delay_type;
-- now the state machine itself:
process(clock, reset) is
begin
if reset = '1' then
state <= s0;
delay <= reset_delay;
elsif rising_edge(clock) then
-- default actions such as default outputs first
-- operate the delay counter
if delay > 0 then
delay <= delay - 1;
end if;
-- state machine proper
case state is
when s0 =>
-- do nothing while delay counts down
if delay = 0 then
--start 50us delay when entering S1
delay <= s1_delay;
state <= s1;
end if;
when s1 =>
if delay = 0 then
delay <= s2_delay;
state <= s2;
end if;
when s2 =>
if delay = 0 then
state <= s3;
end if;
when others =>
null;
end case;
end if;
end process;
You could use a combination of a clock divider and counters. Find out what the clock speed on your device is. All the delays you mentioned are factorable by 10us so I'll use a clock divider to get to that speed. Let's assume your original clock speed of your device is 50MHz. You'll need to find out how many cycles you'll need to count to 10us. The following calculation does that:
# of cycles = 10ms * 50MHz = 5000 cycles
So you're going to need a counter that counts to 5000. A rough example would be the following:
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
entity new_clk is
Port (
clk_in : in STD_LOGIC; -- your 50MHZ device clock
reset : in STD_LOGIC;
clk_out: out STD_LOGIC -- your new clock with a 10us period
);
end clk200Hz;
architecture Behavioral of new_clk is
signal temporal: STD_LOGIC;
signal counter : integer range 0 to 4999 := 0;
begin
clk_div: process (reset, clk_in) begin
if (reset = '1') then
temporal <= '0';
counter <= 0;
elsif rising_edge(clk_in) then
if (counter = 4999) then
temporal <= NOT(temporal);
counter <= 0;
else
counter <= counter + 1;
end if;
end if;
end process;
clk_out <= temporal;
end Behavioral;
Note how the counter goes from 0 to 4999. The signal clk_out will now have a period of 10us. You can use this to generate your delays now.
For example, for your 360us delay, count 36 periods of the clk_out signal. The code will be roughly similar to what is above but this time you're counting clk_out and your counter is only going from 0 to 35.
(I can add more later but this should get you started.)
Check chapters 8-9 of "Finite State Machines in Hardware: Theory and Design (with VHDL and SystemVerilog)" MIT Press, 2013, for a detailed discussion covering any case and many complete examples.
a Little Ode To Brian Drummond's Splendid Answer : Thanks Brian ! :)
The Main Difference is The Removal of The Fixed Upper Limit To The Delay's Length : It's Now Only Limited By The 'delay' SIGNAL Type's Length - Which Can, Generally, Be As Long As Needed.
LIBRARY IEEE;
USE IEEE.STD_LOGIC_1164.ALL;
USE IEEE.NUMERIC_STD.ALL;
ENTITY Test123 IS
PORT (
clk_in1 : IN std_logic := '0';
rst1, en1 : IN std_logic;
);
END ENTITY Test123;
ARCHITECTURE Test123_Arch OF Test123 IS
-- first, some declarations for readability instead of magic numbers
CONSTANT clock_period : TIME := 20 ns; -- 50 MHz
--WARNING : Synplicity has a bug : by default it rounds to nanoseconds!
CONSTANT reset_delay : TIME := 100 ms - clock_period;
CONSTANT s1_delay : TIME := 50 us - clock_period;
CONSTANT s2_delay : TIME := 360 us - clock_period;
-- NB take care to avoid off-by-1 error!
-- now the state machine declarations:
TYPE state_type IS (s0, s1, s2, s3);
SIGNAL state : state_type;
--
--signal delay : unsigned(47 downto 0) := (others => '0'); -- a 48-Bit 'unsigned' Type, Along a 50-MHz Clock, Evaluates To an Upper-Limit of ~90,071,992.5474 Seconds.
SIGNAL delay : NATURAL := 0; -- a 'natural' Type, Along a 50-MHz Clock, Evaluates To an Upper-Limit of ~85.8993459 Seconds.
--
FUNCTION time_to_cycles(time_value : TIME; clk_period : TIME) RETURN NATURAL IS
BEGIN
-- RETURN TO_UNSIGNED((time_value / clk_period), 48); -- Return a 48-Bit 'unsigned'
RETURN (time_value / clk_period); -- Return a 32-Bit 'natural'
END time_to_cycles;
--
BEGIN
-- now the state machine itself:
sm0 : PROCESS (clk_in1, rst1)
BEGIN
IF (rst1 = '1') THEN
state <= s0;
delay <= time_to_cycles(reset_delay, clock_period);
ELSIF rising_edge(clk_in1) THEN
-- default actions such as default outputs first
-- operate the delay counter
IF (delay > 0) THEN
delay <= delay - 1;
END IF;
-- state machine proper
CASE state IS
WHEN s0 =>
-- do nothing while delay counts down
IF (delay = 0) THEN
--start 50us delay when entering S1
delay <= time_to_cycles(s1_delay, clock_period);
state <= s1;
END IF;
WHEN s1 =>
IF (delay = 0) THEN
delay <= time_to_cycles(s2_delay, clock_period);
state <= s2;
END IF;
WHEN s2 =>
IF (delay = 0) THEN
state <= s3;
END IF;
WHEN OTHERS =>
NULL;
END CASE;
END IF;
END PROCESS;
END ARCHITECTURE Test123_Arch;

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

(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 Xilinx ISE 14.4 (webpack).
I stumbled upon the dreaded "PhysDesignRules:372 - Gated clock" warning today, and I see there's a LOT of discussion out there concerning that in general. The consensus seems to be to use one of the DCMs on the FPGA to do clock division but... my DCM doesn't appear to be capable of going from 32 MHz to 4.096 KHz (per the wizard it bottoms out at 5MHz based on 32MHz... and it seems absurd to try to chain multiple DCMs for this low-frequency purpose).
My current design uses clk_in to count up to a specified value (15265), resets that value to zero and toggles the clk_out bit (so I end up with a duty cycle of 50%, FWIW). It does the job, and I can easily use the rising edge of clk_out to drive the next stage of my design. It seems to work just fine, but... gated clock (even though it isn't in the range where clock skew would IMHO be very relevant). (Note: All clock tests are done using the rising_edge() function in processes sensitive to the given clock.)
So, my questions:
If we're talking about deriving a relatively slow clk_out from a much faster clk_in, is gating still considered bad? Or is this sort of "count to x and send a pulse" thing pretty typical for FPGAs to generate a "clock" in the KHz range and instead some other unnecessary side-effect may be triggering this warning instead?
Is there a better way to create a low KHz-range clock from a MHz-range master clock, keeping in mind that using multiple DCMs appears to be overkill here (if it's possible at all given the very low output frequency)? I realize the 50% duty cycle may be superfluous but assuming one clock in and not using the on-board DCMs how else would one perform major clock division with an FPGA?
Edit: Given the following (where CLK_MASTER is the 32 MHz input clock and CLK_SLOW is the desired slow-rate clock, and LOCAL_CLK_SLOW was a way to store the state of the clock for the whole duty-cycle thing), I learned that this configuration causes the 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;
Whereas this configuration does NOT cause the 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 it was all for lack of an else (like I said, the 50% duty cycle was originally interesting but wasn't a requirement in the end, and the toggle of the "local" clock bit seemed quite clever at the time...) I was mostly on the right track it appears.
What's not clear to me at this point is why using a counter (which stores lots of bits) isn't causing warnings, but a stored-and-toggled output bit does cause warnings. Thoughts?
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 use 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.
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;
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';
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;

Resources