How to avoid derived clock domains (i.e. ripple counter)

@DrPi, Josy
In a earlier post you mentioned the following:

“Unless you have good reasons, you should not create derived clocks but use one clock and strobe signals”

Now i would like to follow that advice and change my previous code, for instance:

@always_seq(CLK.posedge, reset=RESET)   #CLK is 16MHz
def clocks():
	pwmcounter.next=pwmcounter+1
	CLK4M.next = pwmcounter[1]		#8MHz for edge delay is output
	CLK8K.next = pwmcounter[10]		#8kHz control loop clock is output

# control loop at approx. 8kHz
@always_seq(CLK8K.posedge, reset=RESET)
def control_loop():
	if ~DISABLE:
		LEDLat.next=not LEDLat
		LED.next=LEDLat     #control loop runs and output ENABLEd: indicate with led

etc. …

Upon reading for instance “Alteras recommended design practices” - which is very informative -
I still can’t code this accordingly…

Would you kindly indicate how that would be done?

Something like this should be ok :

    strobe_counter_8khz  : Signal(intbv(0, min=0, max=2000))
    strobe_counter_16Mhz : Signal(intbv(0, min=0, max=2))
    enable_8khz  : Signal(bool(0))
    enable_16Mhz : Signal(bool(0))

    @always_seq(CLK.posedge, reset=RESET)   # CLK is 16MHz
    def strobes():
        enable_8khz.next  = False
        enable_16Mhz.nest = False

        if strobe_counter_8khz == strobe_counter_8khz.max-1 :
            strobe_counter_8khz.next = 0
            enable_8khz.next = True
        else :
            strobe_counter_8khz.next = strobe_counter_8khz + 1

        if strobe_counter_16Mhz == strobe_counter_16Mhz.max-1 :
            strobe_counter_16Mhz.next = 0
            enable_16Mhz.next = True
        else :
            strobe_counter_16Mhz.next = strobe_counter_16Mhz + 1

    # control loop at 8kHz
    @always_seq(CLK.posedge, reset=RESET)
    def control_loop():
        if enable_8khz :
            if not DISABLE:
                LEDLat.next = not LEDLat
                LED.next = LEDLat     #control loop runs and output ENABLEd: indicate with led


Using separate strobe counters makes the design much easier to understand and, this way, you can get the exact frequencies you need in your design.
Using a single counter is an option when the design is missing resources.
Or when all strobe frequencies are a power of 2. However, for clarity of the design, the strobe generator should be located near its use. Creating a strobe_generator component is a good idea.

Allright, - I see the mechanism.

Thank you!

I said, “unless you have good reasons…”.

Here are the good reasons (I’ll try to be clear).

  • CLK is (very) high frequency : When using strobes, the full design needs to meet the timing requirements of CLK. If the high frequency domain concerns a small amount of logic and most of the logic is in a low frequency domain, it might be a good idea to use a separate low frequency clk (and clk synchronization techniques). In a FPGA, it can be difficult for the tool to achieve timing requirements when the clk is high frequency. How much high depends on the FPGA (and the tool).

  • Lack of resources : The strobe signal is used everywhere in the low frequency domain. Its use adds logic to the functional logic. You may know, in a FPGA, logic in instantiated through LUTs. When the functional logic does not use all LUT inputs, adding a strobe signal has no impact on the resources used. When the functional logic uses all the LUT entries, adding the strobe signal to the equation triggers the use of another LUT. How many more LUTs are used in the design is… design and FPGA dependent. Imagine you have a counter and you do if counter == 0 : reset.next = True . With a 3 bit counter and 4 inputs LUTs, adding a strobe signal has no impact. With a 4 bit counter and 4 input LUTs, adding a strobe signal will need a second LUT. With a 4 bit counter and 6 input LUTs, adding a strobe signal will have no impact.

  • Timing (again) : When LUTs are added because of the use of a strobe signal (see previous point), this adds one level of logic with the consequence that timings are harder to achieve by the tool. This can be a problem with a high frequency CLK.

These points can be hard to understand since they require a good understanding of FPGA internals. But it is worth mentioning them.

Not hard to understand. You describe clearly whats going on.
That helps!

On the cross-clock synchronization side, there are many things to speak about(the meta-stable problem is not the only one).
Here is a link quickly describing the main problems and solutions.
And here is The link exploring many CDC techniques in details. The language used in this paper is System Verilog but it is easy to transpose to MyHDL. On the same site, there are many other interesting papers to explore.

Very concise, and a source for further studies - thank you