Getting Started With FPGA

FTDI Asynchronous FIFO Interfacing with Waxwing

2032 views March 23, 2018 admin 2

Introduction:

The FTDI FT2232H USB 2.0 chip on-board Waxwing provides users with a FIFO interface for data transfer between FPGA and host PC. The FT2232H chip features two channels or ports, which can be configured into various modes like UART, FIFO, JTAG etc. On Waxwing, channel A is used for FPGA configuration and flash programming, whereas Channel B is available for custom usage.This article demonstrates communication between host and the board using Asynchronous FIFO mode via Channel B of FT2232H. The Channel B of FT2232H, when configured as FIFO, acts as a USB-FIFO bridge between host and FPGA. This article is applicable for Waxwing Spartan 6 FPGA Development Board. Let’s get started!

Prerequisites:

Step 1:

Open Xilinx ISE. Go to File Menu -> New Project.

Step 2:

Enter a project name and select a convenient project location.

Step 3:

In ‘Project Settings’ tab, select ‘Family’, ‘Device’, ‘Package’ and ‘Speed’ as shown below. Click Next and then Finish to create project

Step 4:

Right-Click ‘xc6slx45-2csg324’ and select ‘Add Source…’

Step 5:

Download and extract the RTL source files from here and add them to the project.

Here, FTDI’s Asynchronous FIFO interface is used to perform data transfer between FPGA and host PC. As the operation is asynchronous, the data transfers is not synchronous to any common clock between FPGA and FTDI. The design is simpler but has relatively lower speed than synchronous FIFO interface. To use the asynchronous FIFO transfer mode available on FT2232H, its hardware and driver must be configured as 245 FIFO and D2XX respectively. In this article, Channel B of FT2232H (Channel A for Styx) is configured as FIFO, which provides the following signals: 

data: It is bi-directional bus carrying the 8-bit FIFO data. 

rxf_n: It is an active low signal. When de-asserted, does not read data from FIFO. When it is enabled, it indicates that there is some data available in FIFO, the data is read after asserting rd_n. 

txe_n: It is an active low signal. When de-asserted, does not write data to FIFO. When it is asserted, data can be written to FIFO if wr_n is asserted. 

rd_n: It is an active low signal. When asserted, data is driven onto ‘data’ bus from FIFO. 

wr_n: It is an active low signal. When asserted, data from ‘data’ bus is driven into FIFO. 

In the RTL code, FSM is implemented which checks if there is some data available for reading (indicated by pending_read), then the data is read by enabling rd_n signal. When there is some data to be written (indicated by pending_write), wr_n signal is asserted and incoming data is driven into FIFO.

Step 6:

Right-Click ‘ft2232h_phy_top-rtl’ and select ‘New Source’.

Step 7:

Select ‘Implementation Constraints File’ as source type, enter a file name and click Next.

Step 8:

Copy-paste the following constraints to the newly created constraints file and save it.

CONFIG VCCAUX = "3.3" ;

NET "clk" LOC = V10 | IOSTANDARD = LVCMOS33 | PERIOD = 100MHz | SLEW = FAST ;
 
 NET "data[0]" LOC = "N11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
 NET "data[1]" LOC = "M11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
 NET "data[2]" LOC = "T14" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
 NET "data[3]" LOC = "V14" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
 NET "data[4]" LOC = "N18" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
 NET "data[5]" LOC = "N17" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
 NET "data[6]" LOC = "V11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
 NET "data[7]" LOC = "U11" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
 
 NET "rxf_n" LOC = "V13" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
 NET "txe_n" LOC = "U13" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
 NET "rd_n" LOC = "V15" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
 NET "wr_n" LOC = "U15" | IOSTANDARD = LVCMOS33 | SLEW = FAST | DRIVE = 8 ;
 NET "rst" LOC = "B4" | IOSTANDARD = LVCMOS33 | DRIVE = 8 | SLEW = FAST | PULLUP = TRUE;

Step 9:

Select ‘ft2232h_phy_top-rtl’ and Click ‘Synthesize-XST’, followed by ‘Implement Design’ and ‘Generate Programming File’.

Step 10:

Once the programming file is generated, double-Click ‘Configure Target Device’ and click ‘OK’. It will open iMPACT. Double Click ‘Boundary Scan’ to scan Waxwing Board. Make sure it is connected to power source and JTAG.

Step 11:

Right-click on the text ‘Right click to Add device or Initialize Chain’ and Click ‘Initialize Chain’. It will display device details. Click OK to add the device. It will display a message ‘Identity Succeeded’.

Step 12:

Right-Click on the device and select ‘Assign New Configuration File’. Locate the .bit file inside the project directory and select it for programming.

Step 13:

Once the file is selected, double-click ‘Program’ option to program the FPGA onboard Waxwing. It will display a success message if the programming is done successfully.

Step 14:

Once the device is programmed, we need to configure FTDI FT2232H’s channel settings for FIFO mode.

Open FTDI FT Prog. Go to Device:0 -> Hardware Specific -> Port B -> Hardware and select RS245 FIFO. Go to Hardware Specific -> Port B -> Driver and select D2XX.  The process is very similar to that of Saturn and details are available here.

Step 15:

To check if Asynchronous FIFO is working as expected, write some data through FIFO, read it back and compare it. If the data written matches the data that is read then it means that the design is working fine.

To check this, copy the following python code in text editor and save it as ‘async_test.py’

from __future__ import print_function

import time
import random

import ftd2xx

dev = ftd2xx.openEx(b'Waxwing Spartan 6 FPGA Board B', 2) 
dev.setTimeouts(5000, 5000)
dev.purge(ftd2xx.defines.PURGE_TX|ftd2xx.defines.PURGE_RX)
print("\nDevice Details :")
print("Serial : " , dev.getDeviceInfo()['serial'])
print("Type : " , dev.getDeviceInfo()['type'])
print("ID : " , dev.getDeviceInfo()['id'])
print("Description : " , dev.getDeviceInfo()['description'])

BLOCK_LEN = 2048 * 10

tx_data = bytes(bytearray([ random.randrange(0, 256) for i in range(BLOCK_LEN) ]))
print("\nWriting %d KB of data to the deivce..." % (BLOCK_LEN / 1024))
ts = time.time()
written = dev.write(tx_data)

rx_data = dev.read(BLOCK_LEN)
te = time.time()
print("\nReading %d KB of data from the deivce..." % (BLOCK_LEN / 1024))
p = te - ts

print("\nComparing data...\n")
if (tx_data == rx_data):
 print("Data written matches the data read\n")
else:
 print("Data verification failed\n") 
 
dev.close()
print("Transfer Time = %.3f seconds" % p)
speed = (BLOCK_LEN / 1024./1024 / p)
print("Transfer Rate = %.3f MB/s" % speed)

print("\nAsynchronous Test Finished Successfully!\nThank You!!")

Open command prompt. Change to the directory of the file async_test.py and enter the following command:

python async_test.py

Was this helpful?

Leave A Comment
*
*