Author Topic: VHDL question - making a slower clock from a faster one...  (Read 5028 times)

0 Members and 1 Guest are viewing this topic.

Offline alank2Topic starter

  • Super Contributor
  • ***
  • Posts: 2196
VHDL question - making a slower clock from a faster one...
« on: August 09, 2016, 09:10:30 pm »
Let's say you have a 50 Mhz clock - can you make a 40 MHz clock from it with VHDL?  or will it have to be half or slower?

I did this to half a clock:

process (clk50M)
begin
if rising_edge(clk50M) then
clk <= not clk;
end if;
end process;

Could you do something whe nthe clk50M changes (low->high, or high_low) so that something occurs on both transitions?  Could that something then be addition into a std_logic_vector that could drop a 50 Mhz clock down close to 40 MHz ?  Something like defining a 16 bit one and then using the highest bit for the 40 Mhz clock?  If you added 8192 to it each clk50m transition, the top bit would toggle at 50 Mhz , right?  8192*40/50 would be 6553.6, or rounded up to 6554.  Would that yield a 40 MHz clock even though it is jittery?
 

Offline Siwastaja

  • Super Contributor
  • ***
  • Posts: 8789
  • Country: fi
Re: VHDL question - making a slower clock from a faster one...
« Reply #1 on: August 10, 2016, 06:14:56 am »
You can only divide by integer (25 MHz, 16.67MHz...), otherwise you need a specialized analog hardware, namely PLL. But practically every device you program with VHDL includes a bunch of PLLs, so learn how to instantiate those on your chip of choice.

Of course you could do horribly jittery kludges, but I think the jitter is too much.
 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9935
  • Country: us
Re: VHDL question - making a slower clock from a faster one...
« Reply #2 on: August 10, 2016, 01:53:15 pm »
Most devices have some form of DCM (Digital Clock Manager) which is a very sophisticated phase lock loop.  Yes, you can generate 40 MHz from a 50 MHz clock but you'll have to wait for hamster_nz to jump in.  I can't recall that I have ever used the gadget.  Or, if I did, it was a canned solution to something I was playing with.

 

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9935
  • Country: us
Re: VHDL question - making a slower clock from a faster one...
« Reply #3 on: August 10, 2016, 03:28:13 pm »
Wouldn't this thread be better over in the FPGA forum?
 

Offline aandrew

  • Frequent Contributor
  • **
  • Posts: 277
  • Country: ca
Re: VHDL question - making a slower clock from a faster one...
« Reply #4 on: August 10, 2016, 08:56:18 pm »
Generally speaking, do not create new clocks in logic. Use the clock hardware within the FPGA to do it for you. Using a signal that is generated from logic as a clock input for another bit of logic is all kinds of janky; the synthesizer now has to route a logic signal around to a clock network and you might have more issues meeting timing since the delays on the general routing fabric aren't as tight as on the clock networks. From one run to the next you may end up with enough of a variation that your logic won't work. Your generated clock will also be more jittery than one generated with hardware designed to generate clocks.

Having said that, if you need some kind of slower timing, use clock enables. This helps to keep all your logic tied to your "core" clocks (i.e. no need to worry about clock domain crossing if the logic all uses the same clock) and utilizes the FPGA fabric better, since pretty much every ALM/LUT/LAB/whatever has clock enables just waiting to be used.

An example. Let's say you've got logic that you want to run every 100ms. You've got a 24MHz clock. You don't create a 10Hz clock, you generate a 10Hz clock enable and gate the logic that must run every 100ms with the clock enable.

Code: [Select]
-- generates a 1T clock enable pulse every 100ms
process gen_100ms_ce (clk, rst)
variable ctr: integer range 0 to 2399999;

begin
    if rst = '1' then
        ctr := 0;
        onehundred_ms <= '0';
    elsif rising_edge(clk) then
        if ctr = ctr'high then
            onehundred_ms <= '1';
            ctr := 0;
        else
            onehundred_ms <= '0';
            ctr := ctr + 1;
        end if;
    end if;
end process gen_100ms_ce;

And now to use it, you still use the normal (fast) clock:

Code: [Select]
-- does something every 100ms, uses a clock enable to gate the logic
process do_100ms(clk, rst)
begin
    if rising_edge(clk) then
        if onehundred_ms = '1' then
            ...
        end if;
    end if;
end process do_100ms;
 
The following users thanked this post: Kilrah

Offline rstofer

  • Super Contributor
  • ***
  • Posts: 9935
  • Country: us
Re: VHDL question - making a slower clock from a faster one...
« Reply #5 on: August 10, 2016, 10:05:58 pm »
It seems to me that the approach above works well when the divisor is huge.  But getting 40 MHz out of 50 MHz using counters probably doesn't work.  You can't even divide by 2.

The manual gets to the meat of the situation around page 71:
http://www.xilinx.com/support/documentation/user_guides/ug472_7Series_Clocking.pdf

The gist of it might be to multiply the 50 MHz by 8 and divide by 10.  There are certain ranges for the VCO so a bit of studying is required.
« Last Edit: August 10, 2016, 10:08:39 pm by rstofer »
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2812
  • Country: nz
Re: VHDL question - making a slower clock from a faster one...
« Reply #6 on: August 11, 2016, 03:08:39 am »
If you are using Xilinx 7 series, this should work....

Code: [Select]

Library UNISIM;
use UNISIM.vcomponents.all;
....

   -------------------------------------------------------
   -- Generate a 40MHz from 50Mhz clock
   -------------------------------------------------------
clocking : PLLE2_BASE
   generic map (
      BANDWIDTH          => "OPTIMIZED",
      CLKFBOUT_MULT      => 24,  -- VCO freq is 1.2GHz - needs to be between 800MHz and 1600MHz
      CLKFBOUT_PHASE     => 0.0,
      CLKIN1_PERIOD      => 10.0,

      -- CLKOUT0_DIVIDE - CLKOUT5_DIVIDE: Divide amount for each CLKOUT (1-128)
      CLKOUT0_DIVIDE     => 30,  CLKOUT1_DIVIDE     => 16, CLKOUT2_DIVIDE      => 16,
      CLKOUT3_DIVIDE     => 16,  CLKOUT4_DIVIDE     => 16, CLKOUT5_DIVIDE      => 16,

      -- CLKOUT0_DUTY_CYCLE - CLKOUT5_DUTY_CYCLE: Duty cycle for each CLKOUT (0.001-0.999).
      CLKOUT0_DUTY_CYCLE => 0.5, CLKOUT1_DUTY_CYCLE => 0.5, CLKOUT2_DUTY_CYCLE => 0.5,
      CLKOUT3_DUTY_CYCLE => 0.5, CLKOUT4_DUTY_CYCLE => 0.5, CLKOUT5_DUTY_CYCLE => 0.5,

      -- CLKOUT0_PHASE - CLKOUT5_PHASE: Phase offset for each CLKOUT (-360.000-360.000).
      CLKOUT0_PHASE      => 0.0, CLKOUT1_PHASE      => 0.0, CLKOUT2_PHASE      => 0.0,
      CLKOUT3_PHASE      => 0.0, CLKOUT4_PHASE      => 0.0, CLKOUT5_PHASE      => 0.0,

      DIVCLK_DIVIDE      => 1,
      REF_JITTER1        => 0.0,
      STARTUP_WAIT       => "FALSE"
   )
   port map (
      CLKIN1   => CLK50MHz,
      CLKOUT0 => CLK40MHz, CLKOUT1 => open,
      CLKOUT2 => open,     CLKOUT3  => open,
      CLKOUT4 => open,     CLKOUT5 => open,
      LOCKED   => open,
      PWRDWN   => '0',
      RST      => '0',
      CLKFBOUT => clkfb,
      CLKFBIN  => clkfb
   );

On the latest releases of Vivado you may need to add a clock buffer on the input clock - it doesn't do it automatically during the implementation phase any more.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf