Electronic – Clock domain crossing between OV7670 interface and AXI4-Stream

cdcclockfpgavhdlxilinx

Update 1:

My first approach is to use the xpm_cdc_handshake macro in the following way:

xpm_cdc_handshake_inst : xpm_cdc_handshake
   generic map (
      DEST_EXT_HSK => 0,            -- DECIMAL; 0=internal handshake, 1=external handshake
      DEST_SYNC_FF => 4,            -- DECIMAL; range: 2-10
      INIT_SYNC_FF => 0,            -- DECIMAL; 0=disable simulation init values, 1=enable simulation init values
      SIM_ASSERT_CHK => 0,          -- DECIMAL; 0=disable simulation messages, 1=enable simulation messages
      SRC_SYNC_FF => 4,             -- DECIMAL; range: 2-10
      WIDTH => 32                   -- DECIMAL; range: 1-1024
   )
   port map (
      dest_clk => M_AXIS_ACLK,      -- 1-bit input: Destination clock.
      dest_req => AXIS_DestReq,     -- 1-bit output: Assertion of this signal indicates that new dest_out data has been
                                    -- received and is ready to be used or captured by the destination logic. When
                                    -- DEST_EXT_HSK = 1, this signal will deassert once the source handshake
                                    -- acknowledges that the destination clock domain has received the transferred
                                    -- data. When DEST_EXT_HSK = 0, this signal asserts for one clock period when
                                    -- dest_out bus is valid. This output is registered.
      dest_ack => AXIS_DestAck,     -- 1-bit input: optional; required when DEST_EXT_HSK = 1
      dest_out => AXIS_SyncData,    -- WIDTH-bit output: Input bus (src_in) synchronized to destination clock domain. This output is registered.
      src_clk => Clock,             -- 1-bit input: Source clock.
      src_rcv => OV7670_SrcRcv,     -- 1-bit output: Acknowledgement from destination logic that src_in has been
                                    -- received. This signal will be deasserted once destination handshake has fully
                                    -- completed, thus completing a full data transfer. This output is registered.
      src_send => OV7670_SrcSend,   -- 1-bit input: Assertion of this signal allows the src_in bus to be synchronized
                                    -- to the destination clock domain. This signal should only be asserted when
                                    -- src_rcv is deasserted, indicating that the previous data transfer is complete.
                                    -- This signal should only be deasserted once src_rcv is asserted, acknowledging
                                    -- that the src_in has been received by the destination logic.
       src_in => OV7670_SyncData    -- WIDTH-bit input: Input bus that will be synchronized to the destination clock domain.
);

The idea is to design some logic which fills the OV7670 receive buffer (OV7670_SyncData) and starts the domain crossing by asserting the OV7670_SrcSend signal.
The AXI4-Stream transmission logic waits for the signal AXIS_DestAck and when this signal is asserted the data are synchronized and then transmitted over the AXI4-Stream interface.


I am trying to implement an OV7670 camera interface with an AXI4-Stream interface for the data transmission. My current idea is to implement some sort of FIFO or ring buffer to store the data from the camera (i. e. one line) and when the FIFO is full a transmission of the data over the AXI4-Stream interface is started.

But I'm not sure if this is the ideal approach, because I will cross two clock domains (the clock for the camera module and the AXI clock) or is there a better approach?

Best Answer

Asynchronous FIFO

Asynchronous FIFO is an ideal approach to consider implementing between for crossing data safely across the two clock domains.

If you are doing this in Vivado, I suggest you use the dedicated Vivado IP instead of designing one.

If you are interested to design one, it would be useful to go thru this paper:

Cummings's paper on FIFOs

Choosing the depth of the FIFO

You have to choose the depth of the FIFO based on:

  1. What are the frequencies of write and read operations at the enqueue and dequeue sides respectively.
  2. How many bursts of data you are going to enqueue to the FIFO.

Here is a simple guide I used in the past for depth calculation

EDIT:

Full handshake bus synchronizer which you are trying to use has less throughput, but it serves for your purpose consuming lesser resources; especially if you don't need to send many bursts of data in one go. If I remember well, FIFO generator demands a minm. depth and hence can be an overkill when it comes to resource utilization.