2
\$\begingroup\$

So, I have an FT232H chip, specifically this breakout.

I'm trying to read data as fast as possible from it, so I've set it to synchronous 245 FIFO mode, which the datasheet says should yield up to 40 Mbytes/s. I've wired AC3 = WR# to ground, on the assumption that constantly signaling the intent to write won't slow it down, assuming it works at all. Which it does - I have a raspberry pico counting down on 8 pins at a rate of 60Mhz, confirmed by an oscilloscope, and the data I get from the FTDI chip (which has a data clock of 60MHz) DOES match up (not perfectly, since the clocks aren't actually synchronized) - I get a stream of bytes counting down one by one, and changing frequencies or count step sizes yields the expected behavior, skipping or duplicating entries, etc. The end of one read lines up with the start of the next, too. BUT, measuring the total data read vs time it took to read, I'm only actually reading at a rate of about 9 Mbyte/s. (In this setup, MHz = Mbyte/s.) I infer that it periodically skips large segments of data, transmitting contiguous chunks of about 1/7th the total data. I'd be fine with SOME dropout, sure, since 60 Mbyte/s is higher than what the spec claims, but 9 Mbyte/s is a lot smaller, and less than my application calls for.

Here's (part of) my code, using the D2XX api, adapted from the LargeRead example included in the linux x64 driver download. I also have a Rust project, which is my main code, but the C code seems better for baseline sanity checks, and for sharing. I'm using Ubuntu 20.04.

#include <stdio.h>
#include <stdlib.h>
#include "../ftd2xx.h"

#define BUF_SIZE 0x10000*3 // If I do *4 or higher, the read hangs

int main(int argc, char *argv[]) {
    char * pcBufRead;
    DWORD dwBytesRead;
    FT_HANDLE ftHandle;
    FT_STATUS ftStatus;
    int iport;
    
    if(argc > 1) {
        sscanf(argv[1], "%d", &iport);
    }
    else {
        iport = 0;
    }
            
    ftStatus = FT_Open(iport, &ftHandle);
    if(ftStatus != FT_OK) {
        printf("FT_Open(%d) failed\n", iport);
        return 1;
    }

    FT_ResetDevice(ftHandle);
    FT_Purge(ftHandle, FT_PURGE_RX || FT_PURGE_TX);
    FT_SetChars(ftHandle, 0, 0, 0, 0);
    FT_SetFlowControl(ftHandle, FT_FLOW_RTS_CTS, 0, 0); //CHECK ???
    FT_SetTimeouts(ftHandle, 0, 0);             // infinite timeouts    
    FT_SetBitMode(ftHandle, 0xFF, 0x040);
    printf("start\n");

    struct timespec tstart={0,0}, tend={0,0};
    clock_gettime(CLOCK_MONOTONIC, &tstart);
    long totalBs = 0;
    int n = BUF_SIZE;
    pcBufRead = (char *)malloc(n);
    for (int i = 1; i <= 0x100; i++) {
        FT_Read(ftHandle, pcBufRead, n, &dwBytesRead);
        totalBs += dwBytesRead;
    }
    clock_gettime(CLOCK_MONOTONIC, &tend);
    double us = (((double)tend.tv_sec + 1.0e-9*tend.tv_nsec)*1000000) - (((double)tstart.tv_sec + 1.0e-9*tstart.tv_nsec)*1000000);
    printf("%ld @ %.0f = %ld B/s\n", totalBs, us, (long)(totalBs / (us/1000000)));
 
    free(pcBufRead);
    FT_Close(ftHandle);
    
    return 0;
}

And I get:

$ ./largeread 
start
50331648 @ 5483920 = 9178041 B/s

I tested reading a large file from a USB stick in case the socket was slow - got 18 Mbyte/s, so seems like 9 isn't the cap.

Anybody know why this FTDI chip is reading data so much slower than the datasheet says it should?

Edit: I've now tried it on Windows, too - the same code, the same circuit configuration plugged into Linux gives like 8.5MB/s, but on Windows gives like 45MB/s. So I guess now the question becomes, are their Linux drivers just slow, or is there some way of fixing it, perhaps some setting I've missed?

\$\endgroup\$
3
  • 1
    \$\begingroup\$ did you try it on a windows pc as well? Not sure what happens if WR is pulled low if TXE is still high. "set it to synchronous 245 FIFO mode" = means wrote the EEPROM accordingly? \$\endgroup\$ Commented Jul 28, 2023 at 7:58
  • \$\begingroup\$ Not yet, though I can try (Windows). Yeah, set 245 FIFO in EEPROM with FTDI's programmer, and also set the bit mode to synchronous fifo in the code. \$\endgroup\$
    – Erhannis
    Commented Jul 28, 2023 at 16:00
  • \$\begingroup\$ @ChristianB. Huh. Yeah, the same code, the same circuit configuration plugged into windows gives like 45MB/s but on Linux gives like 8.5MB/s. \$\endgroup\$
    – Erhannis
    Commented Aug 1, 2023 at 6:42

2 Answers 2

1
\$\begingroup\$

A little internet search yielded that this is a well known issue. Just search for "However, one of our Linux customers has used a third party FTDI library called LibFTDI to get 40 MByte/sec performance with Sync FIFO with the latest Linux kernels" for details.

Bottom line is, that FTDI seems to know about this issue but did not fix it for several years. It is recommended to switch to libftdi. There is a stream_test.c which should allow you quickly to check for the speed.

\$\endgroup\$
1
  • \$\begingroup\$ Yeah, libftid seems to do better; thanks! \$\endgroup\$
    – Erhannis
    Commented Aug 5, 2023 at 19:03
0
\$\begingroup\$

Their Linux "driver" is an old piece of code compiled with an old version of libusb. I'd been considering it junk for what, a decade now? Forget about their driver on non-Windows systems is all I can suggest.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.