I have a problem with the FT232HL FTDI ic.

Windows application send data to the chip via USB and the chip send the data out with one SPI channel.

I did check with a logic analyser, the bytes are correctly sent out and the SPI clock match the settings. However, between each byte, there is a 64uS delay so it means that no matter how high is the SPI clock, the data transfer takes minutes instead of seconds.

I imagined maybe playing with the channelConf.LatencyTimer would help, but it shows no difference no matter the value used (10, 128, 255), delay remain 64uS between consecutive bytes.

There must be something to fix because there are numerous examples of people reaching high transfer rates. Also, delay between bytes should be a setting somewhere.

I've used sample code provided with sample-dynamic.c The byte stream is sent with a single call to p_SPI_Write() with total length of 2048 bytes. I've tried other length (256, 8192, etc) no change. Here is the configuration used:

channelConf.ClockRate = 5000*1000; 
channelConf.LatencyTimer= 10; 
channelConf.configOptions = SPI_CONFIG_OPTION_MODE0| SPI_CONFIG_OPTION_CS_DBUS3/*|*/ ;
channelConf.Pin = 0x00000000; /* FinalVal-FinalDir-InitVal-InitDir (for dir: 0=in, 1=out) */

OS: windows7 X64 Compiler: GCC Library and code from: http://www.ftdichip.com/Support/SoftwareExamples/MPSSE/LibMPSSE-SPI.htm

FYI: I've contacted FTDI support, they asked me to update the libraries to latest one (which I did), then they would not provide further support.

Any help appreciated. Thank you.

  • \$\begingroup\$ How are you delivering the data to the drivers? In what size chunks? USB peripherals can slow to a crawl if they only get a byte or few moved per frame. Back in the early days before people understood the issues, adding a USB serial converter to something that worked fine on a local bus serial port could completely break its usability. That's often now understood, but SPI can involve coordination with other signals like selects, so it's easy to imagine being hobbled by bus framing and unable to leverage the theoretical data rate that would apply to larger transfers. \$\endgroup\$ – Chris Stratton Jun 19 '18 at 2:25
  • \$\begingroup\$ Hello. As written on the message, no matter how many bytes sent at once, the delay is same. I typically send 2048 bytes per p_SPI_Write() call. Also, I use master spi mode, write-only, there shouldn't be any handshaking involved. Thank you. \$\endgroup\$ – ggadde29 Jun 19 '18 at 5:14
  • \$\begingroup\$ Are you sure that USB side is sending data fast enough? Why are you looking only at SPI side of your bridge? \$\endgroup\$ – Ale..chenski Jun 19 '18 at 23:44
  • \$\begingroup\$ I have no idea how fast the USB transmit the data. I check the SPI side because that's the end of the line and I can easily check with logic analyzer. I don't see how USB transfer could be slower than 16KByte/sec anyway. I heard back from FTDI guys, they suggest I don't use their library (but they didn't clearly say that their lib was bugged). I'm still surprised some people can reach high transfer speeds out of the box and using the provided lib. Starts to be over-complicated for a simple USB<>SPI transfer job. \$\endgroup\$ – ggadde29 Jun 20 '18 at 3:52
  • \$\begingroup\$ I am in the same situation. The SPI_ToggleCS() is definitely slow due to the sleep but having refactored to just Ft_Write calls there is still a long lag between seen on logic analyser between the Cs pin going low to clock + data of around 100us in my case. Very annoyed and frustrated! \$\endgroup\$ – Crog Dec 11 '19 at 20:19

I usually work with the FT2232H chip, but I dug out an FT232HQ chip out just so I could check out this issue you were having. It's the same chip as the FT232HL chip you have, just in a QFN package instead of a QFP.

I tried to recreate the problem you describe, but I wasn't able to exactly. This is what it looked like on my logic analyzer when I output 6 bytes at once at a clock rate of 5MHz. There is is a small delay between bytes, but nowhere near as large as 64us.

Example 5MHz Multibyte Transmission

Here are some things to check.

  • Latency timer really shouldn't matter because that is simply a timeout before USB will send an incomplete packet. I have it set to 255, but often for timing sensitive stuff, I have it lower (2 -10)
  • Try a slower clockrate first just to test and make sure the device is communicating correctly (I assume you did, I'm just adding this in case someone else hasn't tried that yet).
  • The pin directions don't matter except for GPIO since they get overwritten by the SPI lib.
  • Instead of p_SPI_Write(), use SPI_Write(). If you make a single call, add the appropriate chip select enable and disable flags (see below). If you make multiple calls, make sure to add the chip select flags to the first and last calls in the series.
  • Make sure you pass the number of bytes to transmit, and set the SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES flag.
  • If this is a custom board design, or you bought a discount FT232H adapter board, make sure it has the correct system clock frequency. That delay between bytes is based on how long it takes the chip to move the next byte from its internal buffer to the output shift registers. If the chip is clocked slowly, then this will show at the higher frequencies as a larger gap between bytes. Note that for SPI it doesn't matter if the clock is stretched a little bit here and there since it is based on the edges of the clock signal (read on one edge, propagate on the other). Probe the crystal or CMOS crystal chip and make sure it is getting 12MHz.

Here is some quick example code on how to send multiple data bytes in case it helps.

uint32 sizeToTransfer = 0;
uint32 sizeTransfered = -1;
uint8 buffer[256]; //Must be large enough for what you are sending.
FT_STATUS status;

//add data
buffer[sizeToTransfer++] = 0x20; //First data byte (can be what you need)
 * More bytes added....
buffer[sizeToTransfer++] = 0x00; //Last data byte (can be what you need)

status = SPI_Write(*handle, buffer, sizeToTransfer, &sizeTransfered,

//Don't forget to check status. It should equal FT_OK if everything went well

Disclaimer: I use the FT2232H and I am not 100% sure if all statements can be transferred to this case.

To the best of my knowledge ftdi mpsse spi is not really optimized for high data throughput. This becomes obvious if one takes a closer look into the source. In the current version (checked out 24.04.2019) there is a INFRA_SLEEP(2) call within SPI_ToggleCS function which leads to a 2 ms delay everytime the state of CS line is changed. Soif you need to pulse CS for every single word you are doomed. Even without the sleep call usb latency will mostlikely severely slow things down. Even without this call the maximum throughput falls off expectations during my tests. I assume that the reason for this is the architecture of mpsse itself. So personally I would recommend to stick with the natively supported protocols like UART, fast opto or FIFO for high throughput application if possible.

Out of curiosity (if this case is still open): did you check for different drivers as well? Can you observe the same behavior for a different pc as well?


Behind each libMPSSE call is a call to FT_Write() which actually writes a data-frame to hi-speed USB. When using the library functions you are therefore restricted by the USB communication layer (As reported by FTDI support).

The solution to get full speed is to go lower level and buffer you commands together into a large FT_Write() so that the data is packed into a USB transmission frame:

Add to buffer: GPIO Write for CS lo
Add to buffer: Clock N bytes command
Add to buffer: N bytes of data
Add to buffer: GPIO write for CS hi
Add to buffer: Send immediate command (0x87) – only if you read bytes from the LTC device, not if you only write them
++ Repeat for other commands as much as possible for your use-case …
FT_Write of the above buffer

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

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