FT2232HQ synchronous FIFO mode is much slower than it should be in Ubuntu

152 views Asked by At

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?

0

There are 0 answers