I have to generate a 78MHz clock (duty cycle 0.5 or 0.7) from a 100MHz base clock (duty cycle 0.5) using VHDL language (so the ratio is 200/156). I know that I can use DCM, PLL or similar, but at this moment (unfortunately) I just can't.
Therefore I thought to use (excluding any DCM or PLL) a simple frequency divider, but in this case I also know that the frequency can be divided only by integer numbers (and minimum 2, because I would use counters to do that - and In my case I have to divide the base clock by 1,2820512820512820512820512820513...).
So I have no idea how to realize that without using any DCM or other stuff... I thought to divide the 100MHz clock in smaller frequencies (like 50MHz, 25MHz etc.) and adding them (50+25+3 for example), but is this the right way (logically I don't think so)?
Here is a generic fractional M/D clock divider design that should solve your problem. I wrote this for my own use a few years ago. You might want to use std_logic instead of bit depending on what device you are targeting.
The basic idea is to use an accumulator keep track of the fractional clock phase. This is very similar to how you implement a direct-digital synthesizer (DDS) but only has to worry about clocks.
Enjoy! =)
In case it's not clear how to use this, the parameters you'd use for a multiplier of 39 and a divisor of 50, as 100 * 39/100 = 78
, so the required operand width is 6 (because 2**6 = 64
). Note that because this is more than half the input clock rate, no synchronous logic can generate an output clock signal, so this block's only valid output at that rate will be the clock enable.
Also note that the worst case for any possible divisor value is 33%/66% duty-cycle for any one cycle. Your particular choices of multiplier and divisor may be better (I'd need to do some math to tell), but you can't get any better that than in the worst case in general with any algorithm that uses rational division. You could clean up the output of this block with a real hardware PLL or DLL to filter the phase noise and get the duty cycle into your target range.
-- Copyright © 2010 Wesley J. Landaker <[email protected]>
--
-- This program is free software: you can redistribute it and/or modify
-- it under the terms of the GNU General Public License as published by
-- the Free Software Foundation, either version 3 of the License, or
-- (at your option) any later version.
--
-- This program is distributed in the hope that it will be useful,
-- but WITHOUT ANY WARRANTY; without even the implied warranty of
-- MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-- GNU General Public License for more details.
--
-- You should have received a copy of the GNU General Public License
-- along with this program. If not, see <http://www.gnu.org/licenses/>.
library ieee;
use ieee.numeric_bit.all;
-- Clock Divider
-- =============
--
-- Fractionally divides the input clock using simultaneous frequency
-- multiplication and division.
--
-- Outputs both a clock enable and a balanced duty-cycle clock. The clock's
-- duty-cycle is as always close to 50% as possible, worst case is 33%/66%.
--
-- Details
-- =======
--
-- Given:
--
-- Fi = input frequency Hz
-- M = multiplier
-- D = divisor
-- Fo = output frequency Hz
--
-- Where:
--
-- M ≤ D
--
-- Then:
--
-- ⎧ M
-- ⎪ Fi·— if M <= D
-- Fo = ⎨ D
-- ⎪
-- ⎩ undefined if M > D
--
--
-- If (M/D) is greater than 0.5, only the clock enable is valid.
-- If (M/D) is greater than 1.0, both outputs are invalid.
entity Clock_Divider is
generic (
operand_width : positive
);
port (
clock : in bit;
reset : in bit;
multiplier : in unsigned(operand_width-1 downto 0);
divisor : in unsigned(operand_width-1 downto 0);
out_enable : buffer bit;
out_clock : buffer bit
);
end entity;
architecture any of Clock_Divider is
signal enable_2x : bit;
begin
-- Divide the clock by accumulating phase using the mulitplier and
-- subtracting when we pass the divisor value.
proc_enable : process is
variable phase : unsigned(operand_width downto 0);
begin
wait until rising_edge(clock);
phase := phase + multiplier;
if phase >= divisor then
phase := phase - divisor;
out_enable <= '1';
else
out_enable <= '0';
end if;
if reset = '1' then
phase := (others => '0');
out_enable <= '0';
end if;
end process;
proc_enable : process is
variable phase : unsigned(operand_width downto 0);
begin
wait until rising_edge(clock);
phase := phase + (multiplier & '0');
if phase >= divisor then
phase := phase - divisor;
enable_2x <= '1';
else
enable_2x <= '0';
end if;
if reset = '1' then
phase := (others => '0');
enable_2x <= '0';
end if;
end process;
proc_out_clock : process is
begin
wait until rising_edge(clock);
if enable_2x = '1' then
out_clock <= not out_clock;
end if;
end process;
end architecture;
Thoroughly off-the-wall idea, somewhat technology specific so may not suit your goals, and quite quite horrible...
it is obvious that you cannot do this without any of (a) PLL, (b) DLL, (c) a much higher frequency clock or (d) 5ns p-p jitter.
You need many more clock edges available to you, but (assuming) you have no more clock edges, you will have to generate your own. One tech specific (Xilinx) way would be to feed your clock out, and back in via multiple pins, with different IBUFDELAY settings on each. Actual settings might be calibrated by experiment (or even on power up) and would be subject to drift with temperature, naturally.
Another way might be a chain of LUTs successively delaying the clock, with logic to detect that the n'th was delayed longer than a half cycle. (Or a whole cycle) Then tap n/2 is roughly 90 degrees late, n/4 is 45 degrees late, etc. (You cannot ensure consistency in these timings. Still, floorplanning and locking down this core will help to an extent.)
Either way, once you have multiple phases of 100MHz clock, you can apply them to the DDS (fractional divider) described above. Performance is unlikely to be stable, but ought to be better than the current best 5ns...
(And yes I am aware that this is tantamount to rolling your own (and inferior) DLL. Does that count as cheating?)
For a lower complexity approach, you can try Peter Alfke's delay/XOR trick to get 200MHz out of your 100MHz clock. There are no guarantees on its M/S ratio, but it does give you 4 edges to play with...
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With