Crossing Clock Boundaries

When working with FPGAs, it is common for signals to operate on different clock signals. If more than a byte or two of data needs to cross clock boundaries, you should use a synchronization technique capable of handling large amounts of data.

Using a FIFO to cross clock boundaries is one of the most reliable methods of synchronizing data across clock boundaries. The following software example streams a short string of data to the board, then streams it back from the board. The HDL example pipes in the streaming data, uses a Xilinx-generated FIFO to cross from the ti_clk domain to the clk1 domain, then uses another Xilinx FIFO to reverse the clock conversion so the data can be piped back off the board. Note that the FIFO in this example is two bytes wide, which is the transfer size for a USB 2.0 device. In a USB 3.0 device, a pipe transfer consists of four bytes and should be handled with a four byte-wide FIFO.

In this example, the length of data is being ignored. It is assumed here that the HDL extracts data from the FIFO as available and has no expectation on transfer length.

Note: This section contains both software and HDL portions. The software and HDL must work in tandem if FrontPanel is to be used on the PC end to perform tasks on the FPGA. The HDL in this section is designed to be set within the FrontPanel Framework HDL, available on the HDL Framework page for USB 2.0 and USB 3.0. For specific information about the FrontPanel methods or modules, consult the FrontPanel User’s Manual, the FrontPanel API guide, and the samples and README files provided with the FrontPanel download.

C/C++

okCFrontPanel dev; okCFrontPanel::ErrorCode error; unsigned char dataout[128]; unsigned char datain[128]; int i; long written; dev.OpenBySerial(); error = dev.ConfigureFPGA("example.bit"); // It’s a good idea to check for errors here! // Send brief reset signal to initialize the FIFO dev.SetWireInValue(0x10, 0xff, 0x01); dev.UpdateWireIns(); dev.SetWireInValue(0x10, 0x00, 0x01); dev.UpdateWireIns(); for (i = 0; i < sizeof(dataout); i++){ // Fill buffer with data } // Send buffer to PipeIn at endpoint 0x80 written = dev.WriteToPipeIn(0x80, sizeof(dataout), dataout); // Read from PipeOut at endpoint 0x80 written = dev.ReadFromPipeOut(0xA0, sizeof(datain), datain);
Code language: PHP (php)

C#

okCFrontPanel dev = new okCFrontPanel(); okCFrontPanel.ErrorCode error = new okCFrontPanel.ErrorCode(); int n = 128; byte[] dataout = new byte[n]; byte[] datain = new byte[n]; int i; long written; dev.OpenBySerial(""); error = dev.ConfigureFPGA("example.bit"); // It’s a good idea to check for errors here! // Send brief reset signal to initialize the FIFO dev.SetWireInValue(0x10, 0xff, 0x01); dev.UpdateWireIns(); dev.SetWireInValue(0x10, 0x00, 0x01); dev.UpdateWireIns(); for (i = 0; i < (n * sizeof(byte)); i++) { // Fill buffer with data } // Send buffer to PipeIn at endpoint 0x80 written = dev.WriteToPipeIn(0x80, n* sizeof(byte), dataout); // Read from PipeOut at endpoint 0x80 written = dev.ReadFromPipeOut(0xA0, n * sizeof(byte), datain);
Code language: JavaScript (javascript)

Python

dev = ok.okCFrontPanel() # In Python, the buffer (mutable type bytearray) must be initialized upon declaration dataout = bytearray('abcdefghijklmnopqrstuvwxyz') datain = bytearray('00000000000000000000000000') dev.OpenBySerial("") error = dev.ConfigureFPGA("example.bit") # It’s a good idea to check for errors here!! # Send brief reset signal to initialize the FIFO dev.SetWireInValue(0x10, 0xff, 0x01); dev.UpdateWireIns(); dev.SetWireInValue(0x10, 0x00, 0x01); dev.UpdateWireIns(); # Send buffer to PipeIn at endpoint 0x80 data = dev.WriteToPipeIn(0x80, dataout) # Read from PipeOut at endpoint 0x80 data = dev.ReadFromPipeOut(0xA0, datain)
Code language: PHP (php)

Java

public class example{ okCFrontPanel dev; okCFrontPanel.ErrorCode error; byte[] dataout; byte[] datain; long written; int i; int n = 128; public void Pipes(){ dev = new okCFrontPanel(); dev.OpenBySerial(""); error = dev.ConfigureFPGA("example.bit"); // It’s a good idea to check for errors here!! dataout = new byte[n]; for(i = 0; i < dataout.length; i++){ // Fill buffer with data } // Send brief reset signal to initialize the FIFO dev.SetWireInValue(0x10, 0xff, 0x01); dev.UpdateWireIns(); dev.SetWireInValue(0x10, 0x00, 0x01); dev.UpdateWireIns(); // Send buffer to PipeIn at endpoint 0x80 written = dev.WriteToPipeIn(0x80, dataout.length, dataout); datain = new byte[dataout.length]; // Read from PipeOut at endpoint 0x80 written = dev.ReadFromPipeOut(0xA0, datain.length, datain); } }
Code language: PHP (php)

Verilog

// Wire declarations wire fifowrite; wire fiforead; wire [15:0] wireout; wire [15:0] datain; wire [15:0] dataout; wire [15:0] datatrans; wire fifo_en; wire reset; wire n_fifo_em; wire fifofull1; wire fifofull2; //Circuit behavior assign fifo_en = ~n_fifo_em; assign reset = wireout[0]; FIFO_16bit_dual_port fifo_in ( .rst(reset), // input rst .wr_clk(ti_clk), // input wr_clk .rd_clk(clk1), // input rd_clk .din(datain), // input [15 : 0] din .wr_en(fifowrite), // input wr_en .rd_en(fifo_en), // input rd_en .dout(datatrans), // output [15 : 0] dout .full(fifofull1), // output full .empty(n_fifo_em) // output empty ); FIFO_16bit_dual_port fifo_out ( .rst(reset), // input rst .wr_clk(clk1), // input wr_clk .rd_clk(ti_clk), // input rd_clk .din(datatrans), // input [15 : 0] din .wr_en(fifo_en), // input wr_en .rd_en(fiforead), // input rd_en .dout(dataout), // output [15 : 0] dout .full(fifofull2), // output full .empty(fifoem) // output empty ); //FrontPanel endpoint instantiations okPipeIn pipe80( .ok1(ok1), .ok2(ok2x[0*17 +: 17]), .ep_addr(8'h80), .ep_write(fifowrite), .ep_dataout(datain) ); okPipeOut pipeA0( .ok1(ok1), .ok2(ok2x[1*17 +: 17]), .ep_addr(8'hA0), .ep_read(fiforead), .ep_datain(dataout) );
Code language: PHP (php)

VHDL

-- Signal declarations signal fifowrite : STD_LOGIC; signal fiforead : STD_LOGIC; signal datain : STD_LOGIC_VECTOR(15 downto 0); signal dataout : STD_LOGIC_VECTOR(15 downto 0); signal datatrans : STD_LOGIC_VECTOR(15 downto 0); signal reset : STD_LOGIC; signal wireout : STD_LOGIC_VECTOR(15 downto 0); signal n_fifo_em : STD_LOGIC; signal fifo_en : STD_LOGIC; signal fifofull1 : STD_LOGIC; signal fifofull2 : STD_LOGIC; signal fifoem : STD_LOGIC; --Component declaration goes in architecture portion of VHDL body COMPONENT FIFO_16bit PORT ( rst : IN STD_LOGIC; wr_clk : IN STD_LOGIC; rd_clk : IN STD_LOGIC; din : IN STD_LOGIC_VECTOR(15 DOWNTO 0); wr_en : IN STD_LOGIC; rd_en : IN STD_LOGIC; dout : OUT STD_LOGIC_VECTOR(15 DOWNTO 0); full : OUT STD_LOGIC; empty : OUT STD_LOGIC ); END COMPONENT; --Circuit behavior reset <= wireout(0); fifo_en <= not n_fifo_em; --Instantiate FIFO Xilinx Core IP fifo_in : FIFO_16bit PORT MAP ( rst => reset, wr_clk => ti_clk, rd_clk => clk1, din => datain, wr_en => fifowrite, rd_en => fifo_en, dout => datatrans, full => fifofull1, empty => n_fifo_em ); fifo_out : FIFO_16bit PORT MAP ( rst => reset, wr_clk => clk1, rd_clk => ti_clk, din => datatrans, wr_en => fifo_en, rd_en => fiforead, dout => dataout, full => fifofull2, empty => fifoem ); --End FIFO instantiation --FrontPanel endpoint instantiation wire10 : okWireIn port map( ok1=>ok1, ep_addr=>x"10", ep_dataout=>wireout ); pipe80 : okPipeIn port map( ok1=>ok1, ok2=>ok2s(1*17-1 downto 0*17), ep_addr=>x"80", ep_write=>fifowrite, ep_dataout=>datain ); pipeA0 : okPipeOut port map( ok1=>ok1, ok2=>ok2s(2*17-1 downto 1*17), ep_addr=>x"A0", ep_read=>fiforead, ep_datain=>dataout );
Code language: PHP (php)