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.
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)