FTDI Community

Please login or register.

Login with username, password and session length.
Advanced Search  

News:

Welcome to the FTDI Community!

Please read our Welcome Note

Technical Support enquires
please contact the team
@ FTDI Support


New Bridgetek Community is now open

Please note that we have created the Bridgetek Community to discuss all Bridgetek products e.g. EVE, MCU.

Please follow this link and create a new user account to get started.

Bridgetek Community

Author Topic: FT4222: Very high CPU load and gaps between bytes  (Read 2615 times)

a4711

  • Newbie
  • *
  • Posts: 7
    • View Profile
FT4222: Very high CPU load and gaps between bytes
« on: November 06, 2021, 06:41:40 AM »

We are using a FT4222 with libFT4222 1.4.4.44 to communicate to an I2C peripheral at 400 KHz. Our communication involves a mix of writes and reads, but mainly we are reading out chunks of 128-256 bytes. We are facing two problems:
  • The CPU load caused by libft4222 is extremely high. On a Raspberry Pi Zero this is becoming a bottleneck.
  • There a gaps between bytes on all platforms.

Here you can see the gaps:

As you can see, there is no gap between address byte and the first data byte, but every subsequent byte. On a modern x86 processor and Windows the gaps are at least 8µs long, on a Raspberry PI3 and Linux they are 17µs large. One byte takes about 23µs which means we are wasting 40% of our bandwidth. On a FT232H we don't see these kind of gaps and the CPU load is much better.

We are using the FT4222_I2CMaster_Read() function as shown in the example, nothing else.

  • How can we avoid having such gaps in the transfer?
  • How can we achieve a lower CPU load?
Logged

FTDI Community

  • Administrator
  • Hero Member
  • *****
  • Posts: 775
    • View Profile
Re: FT4222: Very high CPU load and gaps between bytes
« Reply #1 on: November 08, 2021, 03:44:23 PM »

Hello,

We have a technical note about USB data transfer efficiency that can help you: https://ftdichip.com/wp-content/uploads/2020/08/TN_103_FTDI_USB_Data_Transfer_EfficiencyFT_000097.pdf.

The main points are:

• Send as much data to the IC from the host application as possible in a single write. This will
maximize the size of the data packets being sent to the device and hence minimize the number of
packets required and time to transfer an amount of data.

• Set the latency timer to a value appropriate for the application. Note that a low latency timer
value may result in many short incoming USB packets rather than a single large packet, thus
diminishing performance.

you should also refer to section 5.3 of the FT4222 datasheet: https://ftdichip.com/wp-content/uploads/2020/07/DS_FT4222H.pdf

This section outlines the I2C bus interface.

also which example are you referring to? the one shown in the LibFT4222 user guide or the one included in the library download?

Best Regards

FTDI Community
Logged

a4711

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: FT4222: Very high CPU load and gaps between bytes
« Reply #2 on: November 08, 2021, 10:45:50 PM »

Thank You for your reply.

Quote
Set the latency timer to a value appropriate for the application. Note that a low latency timer
value may result in many short incoming USB packets rather than a single large packet, thus
diminishing performance.

The latency timer is set to 16 ms (the default). Changing the value has only a very small effect on the gaps and and absolutely no effect on the CPU load on Linux.

Quote
you should also refer to section 5.3 of the FT4222 datasheet: https://ftdichip.com/wp-content/uploads/2020/07/DS_FT4222H.pdf
This section outlines the I2C bus interface.

I do not understand how this relates to the problem I am reporting here.

Quote
also which example are you referring to? the one shown in the LibFT4222 user guide or the one included in the library download?

From the library download. To illustrate my problem I modified the contained I2C example like this:

Code: [Select]
static int exercise4222(DWORD locationId)
{
    int                  success = 0;
    FT_STATUS            ftStatus;
    FT_HANDLE            ftHandle = (FT_HANDLE)NULL;
    FT4222_STATUS        ft4222Status;
    FT4222_Version       ft4222Version;
    const uint16         slaveAddr = 0x58;
    uint16               bytesToRead ;
    uint16               bytesRead = 0;
    uint16               bytesToWrite;
    uint16               bytesWritten = 0;
    char                *writeBuffer;
    uint8_t              pageBuffer[BYTES_PER_PAGE + 1];
    int                  page;


    ftStatus = FT_OpenEx((PVOID)(uintptr_t)locationId,
                         FT_OPEN_BY_LOCATION,
                         &ftHandle);
    if (ftStatus != FT_OK)
    {
        printf("FT_OpenEx failed (error %d)\n",
               (int)ftStatus);
        goto exit;
    }

    ft4222Status = FT4222_GetVersion(ftHandle,
                                     &ft4222Version);
    if (FT4222_OK != ft4222Status)
    {
        printf("FT4222_GetVersion failed (error %d)\n",
               (int)ft4222Status);
        goto exit;
    }

    printf("Chip version: %08X, LibFT4222 version: %08X\n",
           (unsigned int)ft4222Version.chipVersion,
           (unsigned int)ft4222Version.dllVersion);

    // Configure the FT4222 as an I2C Master
    ft4222Status = FT4222_I2CMaster_Init(ftHandle, 400);
    if (FT4222_OK != ft4222Status)
    {
        printf("FT4222_I2CMaster_Init failed (error %d)!\n",
               ft4222Status);
        goto exit;
    }

    // Reset the I2CM registers to a known state.
    ft4222Status = FT4222_I2CMaster_Reset(ftHandle);
    if (FT4222_OK != ft4222Status)
    {
        printf("FT4222_I2CMaster_Reset failed (error %d)!\n",
               ft4222Status);
        goto exit;
    }

    for (;;) {

        // Sequential read from slave EEPROM's current word address.
        uint8_t content[512];
        bytesToRead = sizeof(content);
        ft4222Status = FT4222_I2CMaster_Read(ftHandle,
                                             slaveAddr,
                                             content,
                                             bytesToRead,
                                             &bytesRead);
        if (FT4222_OK != ft4222Status)
        {
            printf("FT4222_I2CMaster_Read failed (error %d)\n",
                   (int)ft4222Status);
            goto exit;
        }

        if (bytesRead != bytesToRead)
        {
            printf("FT4222_I2CMaster_Read read %u of %u bytes.\n",
                   bytesRead,
                   bytesToRead);
            goto exit;
        }

        usleep(100000);
    }

    success = 1;

exit:
    if (ftHandle != (FT_HANDLE)NULL)
    {
        (void)FT4222_UnInitialize(ftHandle);
        (void)FT_Close(ftHandle);
    }

    return success;
}

It reads out 512 byte chunks in a loop with 100ms sleep in between transfers.

  • There are still gaps between 8µs and 17µs between each byte
  • The CPU load on a RPi3b is >50% which is unexpectedly high. On a RPi0 it is even higher due to the slower CPU.

I found the following note in the errata (3.1.2):
Quote
The FT4222H doesn’t support the latency timer feature and causes the USB scheduler to be busy and
uses too much CPU resource.

This looks exactly like what I am seeing, but I have chip revision D.

Can you reproduce this issue? How to solve it?
Logged

FTDI Community

  • Administrator
  • Hero Member
  • *****
  • Posts: 775
    • View Profile
Re: FT4222: Very high CPU load and gaps between bytes
« Reply #3 on: November 09, 2021, 02:26:23 PM »

Hello,

As we are working from home at the moment, I do not have the required hardware to see if I can recreate your issue. However, I have sent your code to my colleague who does have access to the required hardware, so they can test it. I'll let you know what they find.

In the mean time, have you tried running the example as is? Just to see if the hardware is functioning properly?

Best Regards

FTDI Community
Logged

a4711

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: FT4222: Very high CPU load and gaps between bytes
« Reply #4 on: November 09, 2021, 04:09:50 PM »

Quote
In the mean time, have you tried running the example as is? Just to see if the hardware is functioning properly?

My original code is much more complex. Therefore I thought I would strip it down and fit it into the "official" example.
 
Just copy-paste this function into the example file i2cm.c and run it on Linux and include <unistd.h>. On Windows you will have to replace usleep by Sleep. It works on my end. If you could run it on a Raspberry Pi you could see how high the CPU load is. But the gaps are visible on any platform I have checked.
Logged

FTDI Community

  • Administrator
  • Hero Member
  • *****
  • Posts: 775
    • View Profile
Re: FT4222: Very high CPU load and gaps between bytes
« Reply #5 on: November 15, 2021, 09:27:45 AM »

Hi,

we were able to recreate the high CPU load on the raspberry pi. you can add the following setting at the beginning of your code which will resolve this issue: ftStatus = FT_SetTimeouts(ftHandle, 5000,0);

concerning the gaps between bytes, sorry this is a firmaware limitation so there is no way to resolve it.

Best Regards

FTDI Community
Logged

a4711

  • Newbie
  • *
  • Posts: 7
    • View Profile
Re: FT4222: Very high CPU load and gaps between bytes
« Reply #6 on: November 23, 2021, 08:01:01 PM »

Thank you for your suggestion. I confirm that the CPU load is now a bit lower, but it is still higher than I would expect.

Could you explain the consequence of setting the timeout to 0?

Thanks.
« Last Edit: November 23, 2021, 10:10:41 PM by a4711 »
Logged

FTDI Community

  • Administrator
  • Hero Member
  • *****
  • Posts: 775
    • View Profile
Re: FT4222: Very high CPU load and gaps between bytes
« Reply #7 on: November 30, 2021, 09:27:35 AM »

Hi,

Setting the timeout to 0 just means that the timeout is infinite, or until the task has been completed. There should be no real consequences to dong this.

Best Regards,

FTDI Community 
Logged