Author Topic: [FPGA][clocking] Reset a counter on a fast clock domain from a slow clock domain  (Read 2908 times)

0 Members and 1 Guest are viewing this topic.

Offline gauravmpTopic starter

  • Regular Contributor
  • *
  • Posts: 77
  • Country: us
Hi all,

Is there a way i could run a counter on a fast clock domain (say 100MHz) and a slow clock domain (say 10MHz) and have the rising edge of the 10MHz clock reset a counter which counts up every positive edge on the 100MHz? I'll have both these clocks coming out of PLL which has phase alignment, so they should be synchronous for the most part.

Sorry if I've avoided any info. I'm more so asking a general question

Thanks.
 

Offline kc8apf

  • Regular Contributor
  • *
  • Posts: 103
  • Country: us
Sample the 10Mhz clock on every 100Mhz clock. Shift the samples through two registers so you have the current and previous samples cleanly aligned to the 100Mhz clock. Look for the rising edge by comparing the two samples.

Sent from my K88 using Tapatalk

 
The following users thanked this post: gauravmp

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
You can't directly use 10MHz clock to reset the 100MHz counter. The flipflops can only be sensitive to one clock  edge (although the can drive the async set or reset signals)

Why not just run everything in the 100MHz domain?

The other option is to toggle a flipflop in the slow domain, and watch that from the fast domain - when it changed 9 cycles ago you know it is about to change.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Online ataradov

  • Super Contributor
  • ***
  • Posts: 11238
  • Country: us
    • Personal site
You can't directly use 10MHz clock to reset the 100MHz counter.
Why not? 10 MHz will be a reset signal, not another counting signal.
Alex
 

Offline Someone

  • Super Contributor
  • ***
  • Posts: 4525
  • Country: au
    • send complaints here
You can't directly use 10MHz clock to reset the 100MHz counter.
Why not? 10 MHz will be a reset signal, not another counting signal.
Exactly, when the clocks have a known relationship the timing tools will happily cross signals between them while keeping the timing happy. Though this seems to be rather similar to the previous question:
https://www.eevblog.com/forum/microcontrollers/(fpga)(verilog)-how-to-detect-synchronized-edges-of-two-different-signals/
 
The following users thanked this post: gauravmp

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
You can't directly use 10MHz clock to reset the 100MHz counter.
Why not? 10 MHz will be a reset signal, not another counting signal.

The important bit of the OP's question is:
Quote
...and have the rising edge of the 10MHz clock reset a counter ...

That implies this VHDL:

Code: [Select]
  if rising_edge(a) then
     if rising_edge(b) then
        count_out <= counter;
        counter <= (others =>'0');
     else
        counter <= counter + 1;
     end if;
  end if;

You can look at it a few different ways:

- Outside of simulation, two different clocks cannot be guaranteed to rise at exactly the same time, so something like this can't be guaranteed to work.

- In FPGA fabrics (and in general), the flip-flops have a single clock input. So you can't physically wire both signals to the same flipflop,so code like this can't be made implemented in such a fabric (unless 'a' and 'b' are aliases of the same signal):
Code: [Select]
  if rising_edge(a) then
     if rising_edge(b) then
        ....
     end if;
  end if;

- If you connect signals to the async resets of the flipflops then it is level sensitive, not edge sensitive, which is not what the OP wants.

I can't see why you would want to do this, but the best way I see would be something like this:
Code: [Select]
   -- Might need to be 10 bits long
   -- simulate to double check!
   signal shift_reg : std_logic_vector(8 downto 0) := (others => '0');
   signal toggle : std_logic := '0';

process(clk10Mhz)
  begin
     if rising_edge(clk10MHz) then
        -- toggle a single flip-flop so the the fast domain can sync with the 10MHz clock
        toggle <= not toggle;
     end if;
   end process;


process(clk100Mhz)
  begin
     if rising_edge(clk100MHz) then
        -- Detect a clock edge in the 10MHz domain 9 cycles ago.
        if  shift_reg(shift_reg'high) XOR shift_reg(shift_reg'high-1) ='1' then
           --------------------------------------
           -- Detected the cycle where the 10MHz
           -- domain's clock edge will be aligned
           -- with the rising edge of the 100MHz clock
           -----------------------------------------
           .... do the tricky stuff that needs to be aligned in both domains.....
        end if;
        shift_reg <= shiftreg(shift_reg'high-1 downto 0) & toggle;
     end if;
   end process;

It will give the impression of the tricky stuff happening on both edges.

However, I can see almost no reason WHY you would want to do this - why not just use the 100MHz clock with a 1-in-10 clock enable for the 10MHz logic. The only reason I can see is to maybe allow the fast domain to have its clock gated off when not is use, reducing power.
« Last Edit: November 13, 2016, 06:23:40 am by hamster_nz »
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline Someone

  • Super Contributor
  • ***
  • Posts: 4525
  • Country: au
    • send complaints here
You can't directly use 10MHz clock to reset the 100MHz counter.
Why not? 10 MHz will be a reset signal, not another counting signal.

The important bit of the OP's question is:
Quote
...and have the rising edge of the 10MHz clock reset a counter ...
Yes, and?

Code: [Select]
process (clock100M)
begin
if rising_edge(clock100M) then
  clock_10M_d <= clock10M;
  if (clock10M = '1' and clock_10M_d = '0') then
    counter <= (others =>'0');
  else
    counter <= counter + 1;
  end if;
end if;
end process
Its still possible to route clocks onto general logic resources and the timing will be safe, but you won't be sure exactly which side of the rising edge your counter will reset on and it may vary from build to build.
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
You can't directly use 10MHz clock to reset the 100MHz counter.
Why not? 10 MHz will be a reset signal, not another counting signal.

The important bit of the OP's question is:
Quote
...and have the rising edge of the 10MHz clock reset a counter ...
Yes, and?

Code: [Select]
process (clock100M)
begin
if rising_edge(clock100M) then
  clock_10M_d <= clock10M;
  if (clock10M = '1' and clock_10M_d = '0') then
    counter <= (others =>'0');
  else
    counter <= counter + 1;
  end if;
end if;
end process
Its still possible to route clocks onto general logic resources and the timing will be safe, but you won't be sure exactly which side of the rising edge your counter will reset on and it may vary from build to build.

If you look a it very closely, or simulate it, your counter is getting incremented one cycle *after* the rising edge of clock10M, as clock10M is already '1'.
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Offline Someone

  • Super Contributor
  • ***
  • Posts: 4525
  • Country: au
    • send complaints here
You can't directly use 10MHz clock to reset the 100MHz counter.
Why not? 10 MHz will be a reset signal, not another counting signal.

The important bit of the OP's question is:
Quote
...and have the rising edge of the 10MHz clock reset a counter ...
Yes, and?

Code: [Select]
process (clock100M)
begin
if rising_edge(clock100M) then
  clock_10M_d <= clock10M;
  if (clock10M = '1' and clock_10M_d = '0') then
    counter <= (others =>'0');
  else
    counter <= counter + 1;
  end if;
end if;
end process
Its still possible to route clocks onto general logic resources and the timing will be safe, but you won't be sure exactly which side of the rising edge your counter will reset on and it may vary from build to build.

If you look a it very closely, or simulate it, your counter is getting incremented one cycle *after* the rising edge of clock10M, as clock10M is already '1'.
And now you're getting into terse arguments about the intent of the OPs vague request. So a sequence of 1,2,3..,8,9,10 vs 0,1,2..,7,8,9 which can be chosen by changing the preload of the counter, they're synchronous clocks so no trickery is needed. But the real answer is to do it all in a single domain, there should be no need for a 10MHz clock domain that is aligned and synchronous to a 100MHz clock domain.
 

Offline hamster_nz

  • Super Contributor
  • ***
  • Posts: 2803
  • Country: nz
Agreed that it shouldn't be needed, but I have no idea of the OP's requirement either - here is something that resets the 100MHz counter on the rising edge of a synchronous 10MHz clock:

Code: [Select]
library IEEE;
use IEEE.STD_LOGIC_1164.ALL;
use IEEE.NUMERIC_STD.ALL;

entity mixed_clocks is
    Port ( clk10Mhz    : in STD_LOGIC;
           clk100Mhz   : in STD_LOGIC;
           counter_out : out STD_LOGIC_VECTOR (4 downto 0));
end mixed_clocks;

architecture Behavioral of mixed_clocks is
    signal shift_reg : std_logic_vector(9 downto 0) := (others => '0');
    signal toggle    : std_logic                    := '0';
    signal counter   : unsigned(4 downto 0)         := (others => '0');
begin


process(clk10Mhz)
  begin
     if rising_edge(clk10MHz) then
        toggle <= not toggle;
     end if;
   end process;


process(clk100Mhz)
  begin
     if rising_edge(clk100MHz) then
        -- Detect a clock edge in the 10MHz domain 9 cycles ago.
        if (shift_reg(shift_reg'high) XOR shift_reg(shift_reg'high-1)) = '1' then
           --------------------------------------
           -- This will run when the 10MHz
           -- domain's clock edge will be aligned
           -- with the rising edge of the 100MHz clock
           -----------------------------------------
           counter     <= (others => '0');
           counter_out <= std_logic_vector(counter + 1);
        else
            counter <= counter +1;
        end if;
        shift_reg <= shift_reg(shift_reg'high-1 downto 0) & toggle;
     end if;
   end process;
   
end Behavioral;

And snap of the simulation output is attached.
« Last Edit: November 13, 2016, 08:13:53 am by hamster_nz »
Gaze not into the abyss, lest you become recognized as an abyss domain expert, and they expect you keep gazing into the damn thing.
 

Online nctnico

  • Super Contributor
  • ***
  • Posts: 26895
  • Country: nl
    • NCT Developments
You can't directly use 10MHz clock to reset the 100MHz counter. The flipflops can only be sensitive to one clock  edge (although the can drive the async set or reset signals)

Why not just run everything in the 100MHz domain?

The other option is to toggle a flipflop in the slow domain, and watch that from the fast domain - when it changed 9 cycles ago you know it is about to change.
Having multiple clock domains is a good thing to do in an FPGA because slower logic is easier to route and you'll get better device utilisation. If the clocks come from the same PLL the FPGA routing software will automatically setup timing constraints between the two of them so you don't need extra clock domain crossing logic. A bigger problem will be using the 10MHz clock as an input. The FPGA logic usually doesn't allow this and the solution is to make a flip-flop toggle (output rate 5MHz) and use both edges to reset the counter in the 100MHz domain.
There are small lies, big lies and then there is what is on the screen of your oscilloscope.
 


Share me

Digg  Facebook  SlashDot  Delicious  Technorati  Twitter  Google  Yahoo
Smf