Fast and slow clocks

I'm wondering what the correct way to handle the following situation is. Sorry this is a bit long winded. BTW, it's not homework, all that was 40+ years ago.

I have two clocks, clk which is the FPGA clock rate, and sclk which I create using a simple divide by n counter. Typically, sclk is 1024 times slower than clk.

An event occurs that sets a reg, DR, for one clk cycle.

There is a register, calcreg [7:0] which is to be incremented slowly, but reset to zero on DR.

There are two sections, one triggered by clk and one by sclk, ie:

// Fast section always @ (posedge clk) begin .... end

// Slow section always @ (posedge sclk) begin if (DR) calcreg

Reply to
Bruce Varley
Loading thread data ...

Hi,

I would put it all into a single clk block. I.e.

reg [9:0] count = 0; always @(posedge clk) begin count

Reply to
mnentwig

.. you could also resynchronize the slow "clock" on the event. Maybe the difficulty is to define how exactly the circuit is going to behave, not so much coding it in RTL.

Multiple clocks might be used on an ASIC where it allows use of smaller cells for the slow part.

For a simple FPGA project, my main goal would be to keep the code as readable as possible.

--------------------------------------- Posted through

formatting link

Reply to
mnentwig

If you're really just dividing one clock to make another, then you're probably better off using a single clock and generating a count enable for your slow process. On the other hand your problem of using a fast signal to reset a slow process is also applicable to situations where the two clocks are not related and are both necessary for the design. In that case I would normally have an intermediate variable in the fast clock domain that gets set by DR and cleared by a signal returned from the slow process. Something like:

reg DR_hold = 0; reg DR_seen = 0; always @ (posedge clk) begin if (DR) DR_hold

Reply to
Gabor

Oops, in the previous post I started with "DR_seen" but then went to "DR_resync" for the same signal. But you get the idea...

--
Gabor
Reply to
Gabor

Okay, you ain't going to like VHDL, but here is a solution based on a Johns on ring divider:

---------------------------------------------------------------------------

---------------------------------------------------------------------------

----------

-- File : wrapper_SPI_Master.vhd

-- Author : David Greig (email : snipped-for-privacy@ieee.org)

-- Revision :

-- Description :

---------------------------------------------------------------------------

---------------------------------------------

-- Notes :

--======================== ========================= ========================= ========================= ========================= ========================= =======-- library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all;

--======================== ========================= ========================= ========================= ========================= ========================= =======-- entity wrapper_SPI_Master is port( arstn : in std_logic; clk : in std_logic; spi_rst_i : in std_logic; clken : in std_logic;

cpol_i : in std_logic; cpha_i : in std_logic;

spi_wr_i : in std_logic;-----------------------------------------------

---------------------------------------------------------------------------

--------------------------------------

-- File : wrapper_SPI_Master.vhd

-- Author : David Greig (email : snipped-for-privacy@ieee.org)

-- Revision :

-- Description :

---------------------------------------------------------------------------

---------------------------------------------

-- Notes :

--======================== ========================= ========================= ========================= ========================= ========================= =======-- library IEEE; use IEEE.std_logic_1164.all; use IEEE.numeric_std.all;

--======================== ========================= ========================= ========================= ========================= ========================= =======-- entity wrapper_SPI_Master is port( arstn : in std_logic; clk : in std_logic; spi_rst_i : in std_logic; clken : in std_logic;

cpol_i : in std_logic; cpha_i : in std_logic;

spi_wr_i : in std_logic; spi_tx_data_i : in std_logic_vector(16-1 downto 0); spi_tx_empty_o : out std_logic; spi_tx_full_o : out std_logic; spi_tx_ovf_o : out std_logic; spi_tx_unf_o : out std_logic; spi_tx_done_o : out std_logic;

spi_rd_i : in std_logic; spi_rx_data_o : out std_logic_vector(16-1 downto 0); spi_rx_empty_o : out std_logic; spi_rx_full_o : out std_logic; spi_rx_ovf_o : out std_logic; spi_rx_unf_o : out std_logic;

sck_o : out std_logic; ssn_o : out std_logic; mosi_o : out std_logic; miso_i : in std_logic ); end entity wrapper_SPI_Master;

--======================== ========================= ========================= ========================= ========================= ========================= =======--

--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~-- architecture rtl of wrapper_SPI_Master is

---------------------------------------------------------------------------

--------------------------------------------- component SPI_Master generic( Gram_pref : string; Gfifo_depth : natural; Gdwidth : natural; Gspi_clk_div : natural ); port( arstn : in std_logic; clk : in std_logic; spi_rst_i : in std_logic; clken : in std_logic;

cpol_i : in std_logic; cpha_i : in std_logic;

spi_wr_i : in std_logic; spi_tx_data_i : in std_logic_vector(Gdwidth-1 downto 0); spi_tx_empty_o : out std_logic; spi_tx_full_o : out std_logic; spi_tx_ovf_o : out std_logic; spi_tx_unf_o : out std_logic; spi_tx_done_o : out std_logic;

spi_rd_i : in std_logic; spi_rx_data_o : out std_logic_vector(Gdwidth-1 downto 0); spi_rx_empty_o : out std_logic; spi_rx_full_o : out std_logic; spi_rx_ovf_o : out std_logic; spi_rx_unf_o : out std_logic;

sck_o : out std_logic; ssn_o : out std_logic; mosi_o : out std_logic; miso_i : in std_logic ); end component SPI_Master;

---------------------------------------------------------------------------

--------------------------------------------- begin

---------------------------------------------------------------------------

--------------------------------------------- inst_SPI_Master : SPI_Master generic map( Gram_pref => "logic", Gfifo_depth => 2, Gdwidth => 16, Gspi_clk_div => 4 ) port map( arstn => arstn , clk => clk , spi_rst_i => spi_rst_i , clken => clken ,

cpol_i => cpol_i , cpha_i => cpha_i ,

spi_wr_i => spi_wr_i , spi_tx_data_i => spi_tx_data_i , spi_tx_empty_o => spi_tx_empty_o , spi_tx_full_o => spi_tx_full_o , spi_tx_ovf_o => spi_tx_ovf_o , spi_tx_unf_o => spi_tx_unf_o , spi_tx_done_o => spi_tx_done_o ,

spi_rd_i => spi_rd_i , spi_rx_data_o => spi_rx_data_o , spi_rx_empty_o => spi_rx_empty_o , spi_rx_full_o => spi_rx_full_o , spi_rx_ovf_o => spi_rx_ovf_o , spi_rx_unf_o => spi_rx_unf_o ,

sck_o => sck_o , ssn_o => ssn_o , mosi_o => mosi_o , miso_i => miso_i );

---------------------------------------------------------------------------

--------------------------------------------- end architecture rtl;

--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~--

spi_tx_data_i : in std_logic_vector(16-1 downto 0); spi_tx_empty_o : out std_logic; spi_tx_full_o : out std_logic; spi_tx_ovf_o : out std_logic; spi_tx_unf_o : out std_logic; spi_tx_done_o : out std_logic;

spi_rd_i : in std_logic; spi_rx_data_o : out std_logic_vector(16-1 downto 0); spi_rx_empty_o : out std_logic; spi_rx_full_o : out std_logic; spi_rx_ovf_o : out std_logic; spi_rx_unf_o : out std_logic;

sck_o : out std_logic; ssn_o : out std_logic; mosi_o : out std_logic; miso_i : in std_logic ); end entity wrapper_SPI_Master;

--======================== ========================= ========================= ========================= ========================= ========================= =======--

--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~-- architecture rtl of wrapper_SPI_Master is

---------------------------------------------------------------------------

--------------------------------------------- component SPI_Master generic( Gram_pref : string; Gfifo_depth : natural; Gdwidth : natural; Gspi_clk_div : natural ); port( arstn : in std_logic; clk : in std_logic; spi_rst_i : in std_logic; clken : in std_logic;

cpol_i : in std_logic; cpha_i : in std_logic;

spi_wr_i : in std_logic; spi_tx_data_i : in std_logic_vector(Gdwidth-1 downto 0); spi_tx_empty_o : out std_logic; spi_tx_full_o : out std_logic; spi_tx_ovf_o : out std_logic; spi_tx_unf_o : out std_logic; spi_tx_done_o : out std_logic;

spi_rd_i : in std_logic; spi_rx_data_o : out std_logic_vector(Gdwidth-1 downto 0); spi_rx_empty_o : out std_logic; spi_rx_full_o : out std_logic; spi_rx_ovf_o : out std_logic; spi_rx_unf_o : out std_logic;

sck_o : out std_logic; ssn_o : out std_logic; mosi_o : out std_logic; miso_i : in std_logic ); end component SPI_Master;

---------------------------------------------------------------------------

--------------------------------------------- begin

---------------------------------------------------------------------------

--------------------------------------------- inst_SPI_Master : SPI_Master generic map( Gram_pref => "logic", Gfifo_depth => 2, Gdwidth => 16, Gspi_clk_div => 4 ) port map( arstn => arstn , clk => clk , spi_rst_i => spi_rst_i , clken => clken ,

cpol_i => cpol_i , cpha_i => cpha_i ,

spi_wr_i => spi_wr_i , spi_tx_data_i => spi_tx_data_i , spi_tx_empty_o => spi_tx_empty_o , spi_tx_full_o => spi_tx_full_o , spi_tx_ovf_o => spi_tx_ovf_o , spi_tx_unf_o => spi_tx_unf_o , spi_tx_done_o => spi_tx_done_o ,

spi_rd_i => spi_rd_i , spi_rx_data_o => spi_rx_data_o , spi_rx_empty_o => spi_rx_empty_o , spi_rx_full_o => spi_rx_full_o , spi_rx_ovf_o => spi_rx_ovf_o , spi_rx_unf_o => spi_rx_unf_o ,

sck_o => sck_o , ssn_o => ssn_o , mosi_o => mosi_o , miso_i => miso_i );

---------------------------------------------------------------------------

--------------------------------------------- end architecture rtl;

--~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ ~~~~~~~~--

---------------------------------------------------------------------------

---------------------------------------------------------------------------

----------

-- File : SPI_Master.vhd

-- Author : David Greig (email : snipped-for-privacy@ieee.org)

-- Revision :

-- Description : SPI master with individual fifo buffers on RX and TX

---------------------------------------------------------------------------

---------------------------------------------

-- Notes :

-- Verified conforming with "Freescale Semiconductor, Inc." SPI Block Guide V4 S12SPIV4.pdf

-- cpha 0 means "sample on 1st edge", cpha = 1 means "sample on 2nd edge" .

-- cpol simply changes the effective polarity of the clock

-- Tranfer latency - ssn goes low 2 clk cycles after first spi_wr

-- One complete sck period is inserted between ssn falling edge to data sta rt, and again from data end to ssn rising edge, and again at the end to giv e minimum

-- ssn high of one sck period

-- Illustration for 8 bit data :- overall time = (nbits + 3) * sck period s

____________~

-- cpha=0 sdo ~-------------------X=======X==== ===X=======X=======X======= X=======X=======X=======X--------

-----~

-- cpha=0 sdo ~-------------------X=======X==== ===X=======X=======X======= X=======X=======X=======X--------

-----~

--
____________~ 


-- cpha=1  sdo  ~-------------------X=======X==== 
 Click to see the full signature
Reply to
s2z.domain

You have a CDC (clock-domain-crossing) situation going from a fast clock domain to a slow clock domain. Some others have already mentioned solutions:

Reply to
Grao

+1. Using the DR_resync (who looks at 'reg' declarations, anyway) should work even if sclk isn't generated from clk.
--
Tim Wescott 
Wescott Design Services 
 Click to see the full signature
Reply to
Tim Wescott

You have a CDC (clock-domain-crossing) situation going from a fast to slow domain. Are you sure those clocks are synchronous?Some solutions have alrea dy been mentioned:

1) Use a single clock domain for everything and just capture the event in t he fast clock domain and clear it when you enable the slow domain (count= =1024). This will consume more power as you are using the same clock for all logic but you have a fully synchronous design (easier for timing).

2) Use handshake to pass the signal across the CDC boundary but be sure to double-register signals to avoid metastability (asynchronous clock crossing ). i.e. Gabor's code with synchronizing flops.

It really depends on the relationship between the clocks in your design. St aying synchronous keeps things a lot simpler.

-Ganesh

On Saturday, October 18, 2014 3:53:31 AM UTC-4, snipped-for-privacy@googlegroups.com wro te:

Reply to
Grao

Bruce Varley:

A good question, and it sounds like you're already analysing the problems correctly.

In terms of electronic circuit complexity (however), the problem you describe scales down to what single design primitives of the hardware deliver.

So it'll be best to start with taking a look at what kind of design primitives are supported by the hardware platform (so in case of an FPGA, the interesting information would be about which "slice"-FlipFlop-Types are available).

To me it seems like at least all Xilinx FPGA support both, synchroneous and asychroneous (re)set for clocked data paths.

If I got your pronlem description correcty, a simple solution would be to use async reset FlipFlops for calcreg:

always @(posedge sclk or posedge DR) begin if (DR) calcreg

Reply to
Jan Bruns

Your problem is a hair underdefined here. Is it imperative that calcreg be reset to zero at the exact time of DR, or is it good enough that the DR ensure that calcreg go to zero on the next sclk edge?

"Bad practice" is a bit of a blanket statement, but in this instance yes. The two clock domains are causing you unnecessary grief and probably can't be justified. mnentwig already provided example code for how to do it synchronously; the /1024 counter becomes a "count up" enable input, and DE becomes a synchronous reset.

In an FPGA, any time you find yourself with multiple clock domains you should always ask "What is the technical reason that _requires_ it be this way?" Sometimes that question will have a good answer, but when it doesn't keep it all on the same clock.

Various forms of asynchronous horribleness. Gabor gave you one, Jan's use of the async clear is another, and I'll present you a third by saying to Google "flancter" (a clever little arrangement with two cross-coupled flops and an XOR gate).

All these will work. All of them will require you to get creative with your design's timing constraints if you want the tools to really analyze the path and make _sure_ that it works over process/temp/voltage variations. Timing analysis and async logic go hand in hand, and both have the exciting feature that, unlike synchronous logic, you'll never have a simulation that can tell you that you've got it right. You just design it very hard, then sit there digging through the report outputs of your timing analysis to make sure that it actually got constrained, and that the constraint actually does what you want, and then you hope that on subsequent recompiles key signals don't get renamed and break it. Then you too can know the joy of wasting an hour or two trying to get the tools to work properly on a chunk of code that's only 20 lines long.

Or you can do it synchronously.

--
Rob Gaddi, Highland Technology -- www.highlandtechnology.com 
Email address domain is currently out of order.  See above to fix.
Reply to
Rob Gaddi

ElectronDepot website is not affiliated with any of the manufacturers or service providers discussed here. All logos and trade names are the property of their respective owners.