Programmable Devices
CPLDs, FPGAs, SoC FPGAs, Configuration, and Transceivers
20693 Discussions

Varible clock rate

Altera_Forum
Honored Contributor II
2,728 Views

Hello together 

 

I have a verilog-module that is working with an external 25 MHz clock. Now in my application I would like to work with a variable clock rate. Some other logic modules in the FPGA shoule still work with 25 MHz 

 

The idea:  

A DDS (e.g. AD9834) would create a clock rate between 0 Hz to 25 Mhz with 1 Hz steps. The Clock rate can change during program execution. For example a sweep from 1Mhz to 10 Mhz in 5 seconds. 

 

An example application could be a bit pattern generator. 

 

Will this approach work in general? 

Is there an easier solution without a DDS? 

 

Best regards and thank you for your help 

 

Geri
0 Kudos
10 Replies
Altera_Forum
Honored Contributor II
625 Views

The DDS chip is well known solution for clk generation. But it is only justified if you want a clean clk every time. Alternatively you can design a dds-like module in your rtl. This can generate any rate which can be applied as clk enable for a fixed 25MHz.  

The idea is very simple: just a free running 2^n accummulator with variable increment. use its overflow pulse signal as enable. for example if your accum. is 32 bits wide then run it on 25MHz. if the increment value is say 2345 then the enable rate = 2345/2^32 of clk rate.  

i.e. freq = 25000000 * incr/2^32 in Hz. 

 

This is the very idea used by commercial DDS... 

make sure that the pulse is one clk short. the easiest way for this is to use 33 bits for 32 bit accum. to let it overflow without loss of count.
0 Kudos
Altera_Forum
Honored Contributor II
625 Views

There are two possible variants of using DDS techniques for digital clock generation: 

 

- The basic variant is to use only the fractional frequency divider of the DDS designs. You get an effectively unlimited frequency resolution, but the output clock has a jitter. 

 

- The extended variant uses the low pass filtered sine output of the DDS and a comparator to generate an interpolated digital clock. To be able to reduce output jitter in the low pass filter, the maximum generated frequency must be considerably lower than the DDS clock. 

 

In practise, a DDS design is the only simple way to generate a stepwise variable frequency. Alternatively a PLL with a reference frequency of 1 Hz can do, but it would be rather slow. Or a PLL with e.g. 32 or 64 Hz reference frequency and a post divider.
0 Kudos
Altera_Forum
Honored Contributor II
625 Views

Thanks to all of you for the fast response and the approaches! 

 

@Kaz: Thats sounds very fine and simple and no DDS is necessary.  

 

Attached my understanding. Does this piece of code reflect your approach? 

 

// Verilog module for clock variable clock generation of logic module DDS(clk, ClkEnable); input clk; output ClkEnable; // Binary counter, 16-bits wide parameter ClockGeneratorAccWidth = 33; // plus overflow bit parameter ClockGeneratorAccIncWidth = 32; reg ClockGeneratorAcc; reg ClockGeneratorAccInc = 2345; // any value for frequency setting e.g. 2345 always @(posedge clk) begin ClockGeneratorAcc <= ClockGeneratorAcc + ClockGeneratorAccInc; if (ClockGeneratorAcc == 1) ClockGeneratorAcc <= 0; end // Use the highest bit of the counter (MSB) to enable clock assign ClkEnable = ClockGeneratorAcc; endmodule  

 

@FvM 

The AD9834 has an integrated comparator that can be conected to the sin wave output to create a rectangular signal. So if I understand you right, the approach with the external DDS could work but what percentage do 

you estimate has it lower than the DDS frequency? 

 

Friendly regards and thank you again 

 

Geri
0 Kudos
Altera_Forum
Honored Contributor II
625 Views

I am currently not good at reading verilog but let me suggest my algorithm in vhdl: 

 

signal accum : unsigned(32 downto 0) := (others => '0'); -- on a clked process accum <= accum(31 downto 0) + increment; end process; enable <= accum(32);  

 

The main idea is adding 31:0 to 32:0 freely as this wraps up the result back and so the overflow should be one pulse. Please let me know if it works. Remember all your clked staements and clked components must have clk enable added to them.
0 Kudos
Altera_Forum
Honored Contributor II
625 Views

Hello kaz 

 

Thank you very much for your help. Your code looks similar for me, mine is a little bit more cosmectic. 

 

 

--- Quote Start ---  

Remember all your clked staements and clked components must have clk enable added to them. 

--- Quote End ---  

Yes, I will implement it as code block 

always @(posedge clk or ClkEnable rst) begin // do something end I am currently struggeling a little bit if e.g. a 20 Mhz clock can be realized using a clock rate of 25 MHz because the enable signal itself is derived from the 25 MHz clock  

 

I will let you know if it works! 

 

Best regards and thank you again 

 

Geri
0 Kudos
Altera_Forum
Honored Contributor II
625 Views

Hi Geri, 

 

for whatever rate value you choose, the final rate will tend to be correct over time despite the irregular nature of enable. This is a matter of accum. resolution and design toloerances but 32 bits is pretty high for most. 

 

You can if you wish use a dedicated accum for a given ratio e.g. for 20MHz on 25MHz you have two choices: 

 

generic high resolution accum: modulo 2 above then: 

20 = 25 * incr/2^32 then incr = 2^32 * 20/25 = 2^32 * 0.80000... 

 

option 2: 

dedicated accum: i.e. incr = 20, accum 0~24 

or incr = 4, accum = 0~4 (in effect a divider)
0 Kudos
Altera_Forum
Honored Contributor II
625 Views

Hello  

 

Now I did some tests with the following code and measuring output frequency with an oscillosope. 

 

fOsc = 24 MHz 

 

 

// Verilog module for variable clock generation of logic // fOut = fclk * ClockGeneratorAccInc/2^32 module DDS(clk, ClkEnable); input clk; output ClkEnable; parameter ClockGeneratorAccWidth = 32; // plus overflow bit reg ClockGeneratorAcc; always @(posedge clk) begin ClockGeneratorAcc <= ClockGeneratorAcc + 178956971; // if (ClockGeneratorAcc == 1) ClockGeneratorAcc <= 0; end // Use the highest bit of the counter (MSB) to enable clock assign ClkEnable = ClockGeneratorAcc; endmodule // test logic module TestDDS(clk, fOut); input clk; output fOut; wire cEn; reg ClkOut; DDS ClockGenerator(.clk(clk),.ClkEnable(cEn)); always @(posedge clk) begin if (cEn) ClkOut = ~ClkOut; end assign PWM = ClkOut; endmodul Results:  

Using this design without reset on overflow: 

There is a periodical signal on the output but the output signal  

has area of 12 Mhz clock output and an area with output level 0. 

The freuquency of the total signal follows the formula 

 

fOut = 24 Mhz * Increment / 2^32  

 

Using this design with reset on overflow: 

There is a periodical signal, the high-low changes are evenly distributed. 

I think it works a standard frequency divider. 

 

On higer frequencies e.g. a set value of 18 Mhz I think the output is always 12 MHz 

 

So the logic is not working as expected. 

 

Does anybody have an idea?
0 Kudos
Altera_Forum
Honored Contributor II
625 Views

Hi, 

 

First you shouldn't reset the accumulator and second you shouldn't add accum to itself. see my previous post: 

add bits 31:0 of accum to increment and assign result to accum 32:0 

 

The binary counter should be allowed free running without reset once it starts. The increment value can be changed on the fly.
0 Kudos
Altera_Forum
Honored Contributor II
625 Views

Hello kaz 

 

Wow, now it works fine.  

 

For others, that are interested in the working code, it looks like:  

 

// Verilog module for variable clock generation triggering logic // fOut = fclk * ClockGeneratorAccInc/2^32 // Accumulator increment value = fout/fOsc * 2^32; // e.g. value = 19123456/24000000 * 2^32 = 3422275754 module DDS(clk, ClkEnable); input clk; output ClkEnable; parameter ClockGeneratorAccWidth = 32; // plus overflow bit reg ClockGeneratorAccWidth:0] ClockGeneratorAcc; always @(posedge clk) begin ClockGeneratorAcc <= ClockGeneratorAcc + 3422275754; // 19123456 MHz end // Use the highest bit of the counter (MSB) to enable clock assign ClkEnable = ClockGeneratorAcc; endmodule // Example of use // because ClkOut is toggeling we have the half frequency on output pin:) module TestDDS(clk, fOut); input clk; output fOut; wire cEn; reg ClkOut; DDS ClockGenerator(.clk(clk),.ClkEnable(cEn)); always @(posedge clk) begin if (cEn) ClkOut = ~ClkOut; end assign PWM = ClkOut; endmodule Thank you very much for your help again 

 

Geri
0 Kudos
Altera_Forum
Honored Contributor II
625 Views

Hi Geri, 

 

I'm glad that I found your code. But when I cut & pasted and attempted to simulate it with Fclk = 24 MHz, the clockout didn't come out as expected. First, the ModelSim gave a warning that the number 3422275754 will be a signed integer and will cause overflow. Second, without any hard reset at the beginning to set the accumulator to a default value (all 0's in this case), the subsequent accumulations resulted in all red in ModelSim. 3rd, the clock enable pulse is not a single pulse when FOut (~19 MHz) is so close to the sampling clock, Fclk, at 24 MHz. I've noticed when the sampling clock, Fclk, is at least 10 times the generated clock, FOut, then it would work! Can you/anyone provide some inputs into how to generate a variable clock with fine resolution. Thank you.
0 Kudos
Reply