I'm working on a project which needs to collect data from FPGA. I'm using an FTDI FT2232H UART/FIFO IC. According to the datasheet, the chip can transfer up to 40 Mbytes/s in single-channel synchronous FIFO mode. However, when I use the Linux system (Ubuntu 20.04), the transfer speed I get is only 10 Mbytes/s.
This is the C++ code I use:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <sys/time.h>
#include "ftd2xx.h"
#include <iostream>
#include <chrono>
#define BUF_SIZE 0x10
#define MAX_DEVICES 1000
#define OneSector 8
int main(int argc, char *argv[]){
system("sudo rmmod ftdi_sio");
system("sudo rmmod usbserial");
system("setserial /dev/ttyUSB0 low_latency");
system("setserial /dev/ttyUSB1 low_latency");
FT_STATUS ftStatus;
FT_HANDLE ftHandle0;
FT_HANDLE ftHandle1;
UCHAR Mask = 0xFF;
UCHAR Mode;
UCHAR LatencyTimer = 2; //our default setting is 16
int retCode = EXIT_FAILURE;
DWORD libVersion = 0;
static FT_PROGRAM_DATA Data;
char *BufPtrs[3]; // pointer to array of 3 pointers
char Buffer1[64]; // buffer for description of first device
char Buffer2[64]; // buffer for description of second device
BufPtrs[0] = Buffer1;
BufPtrs[1] = Buffer2;
BufPtrs[2] = NULL; // last entry should be NULL
UCHAR rxBuffer[65536] = {0};
// memset(rxBuffer,0,1028);
DWORD byteCount;
auto start = std::chrono::high_resolution_clock::now();
auto stop = std::chrono::high_resolution_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
double mbps;
double secondsElapsed;
// DWORD devIndex = 0; // first device
// char Buffer[64]; // more than enough room!
DWORD RxBytes = 8;
DWORD BytesReceived;
DWORD numDevs;
// char RxBuffer[OneSector];
ftStatus = FT_GetLibraryVersion(&libVersion);
if (ftStatus == FT_OK)
{
printf("D2xx Library version = 0x%x\n", (unsigned int)libVersion);
}
else
{
printf("Error reading library version.\n");
return 1;
}
ftStatus = FT_ListDevices(BufPtrs,&numDevs,FT_LIST_ALL|FT_OPEN_BY_DESCRIPTION);
if (ftStatus == FT_OK) {
// FT_ListDevices OK, product descriptions are in Buffer1 and Buffer2, and
// numDevs contains the number of devices connected
if(numDevs<=0){
goto exit;
}
printf("%s\n", Buffer1);
printf("%s\n", Buffer2);
printf("Number of ports: %d\n", numDevs);
}
else {
// FT_ListDevices failed
}
ftStatus = FT_Open(0, &ftHandle0);
if(ftStatus != FT_OK) {
printf("FT_Open(%d) failed\n", 0);}
else{
printf("Port 0 FT_Open succeeded. Handle is %p\n", ftHandle0);}
Data.Signature1 = 0x00000000;
Data.Signature2 = 0xffffffff;
Data.Manufacturer = (char *)malloc(256); /* E.g "deponce" */
Data.ManufacturerId = (char *)malloc(256); /* E.g. "FT" */
Data.Description = (char *)malloc(256); /* E.g. "USB HS Serial Converter" */
Data.SerialNumber = (char *)malloc(256); /* E.g. "FT000001" if fixed, or NULL */
if (Data.Manufacturer == NULL ||
Data.ManufacturerId == NULL ||
Data.Description == NULL ||
Data.SerialNumber == NULL)
{
printf("Failed to allocate memory.\n");
retCode = 1;
goto exit;
}
ftStatus = FT_EE_Read(ftHandle0, &Data);
if(ftStatus != FT_OK) {
printf("FT_EE_Read failed\n");
retCode = 1;
goto exit;
}
printf("FT_EE_Read succeeded.\n\n");
printf("Signature1 = %d\n", (int)Data.Signature1);
printf("Signature2 = %d\n", (int)Data.Signature2);
printf("Version = %d\n", (int)Data.Version);
printf("VendorId = 0x%04X\n", Data.VendorId);
printf("ProductId = 0x%04X\n", Data.ProductId);
printf("Manufacturer = %s\n", Data.Manufacturer);
printf("ManufacturerId = %s\n", Data.ManufacturerId);
Mode = 0x40;
if(FT_SetBitMode(ftHandle0, Mask, Mode) == FT_OK){
printf("set bit mode succeeded\n");}
else{
printf("set bit mode failed\n"); retCode=1; goto exit;}
ftStatus = FT_SetLatencyTimer(ftHandle0, LatencyTimer);
FT_SetUSBParameters(ftHandle0, 0x40000, 0x40000);
FT_SetFlowControl(ftHandle0, FT_FLOW_RTS_CTS, 0x0, 0x0);
FT_Purge(ftHandle0, FT_PURGE_RX);
ftStatus = FT_SetTimeouts(ftHandle0, 500, 500);
if(ftStatus == FT_OK){std::cout<<"set FT_SetTimeouts success."<<std::endl;}
start = std::chrono::high_resolution_clock::now();
for(int i = 0; i < 16384; i++){
std::cout<<i<<std::endl;
if(FT_Read(ftHandle0, rxBuffer, 65536, &byteCount) != FT_OK || byteCount != 65536) {
printf("Error while reading from the device. Exiting.\r\n");
goto exit;
}
}
std::cout<<std::endl;
stop = std::chrono::high_resolution_clock::now();
duration = std::chrono::duration_cast<std::chrono::microseconds>(stop - start);
std::cout << "Read 1GB from the FTDI in : "
<< duration.count()/1000000. << " seconds" << std::endl;
mbps = 1024 / (duration.count()/1000000.);
printf("Average read speed: %0.1f Mbps.\r\n", mbps);
exit:
return retCode;
}
Here is the VHDL code:
library IEEE;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity test_syn_fifo is
port
(
CLK60M: in std_logic;
CLK50M: in std_logic;
TXE : in std_logic;
DATA : buffer std_logic_vector (7 downto 0):="00000000";
WR : buffer std_logic:='1';
);
end entity;
architecture Behavioral of test_syn_fifo is
begin
process(CLK60M,TXE, WR)
begin
if(CLK60M ='1'and CLK60M'event)then
if(TXE='0')then
DATA <= DATA+1;
WR<='0';
else
DATA <= DATA;
WR<='1';
end if;
else
DATA <= DATA;
end if;
end process;
end Behavioral;
Could you give me some suggestions on how to speed up in the Linux?