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

Show Posts

You can view here all posts made by this member. Note that you can only see posts made in areas to which you currently have access.

Messages - allenhuffman

Pages: [1] 2
1
Discussion - Software / Re: I2C Master Read in multiple read requests.
« on: November 14, 2022, 08:03:16 PM »
Update: I have done tests, and verified under a Saleae logic analyzer, that this does work. There's just a huge gap between the reads on my Windows system.

Without full error checking (because this is bad code you shouldn't use for production):

Code: [Select]
uint8_t buffer[128];
memset (buffer, 0x0, sizeof(buffer));

ft4222Status = FT4222_I2CMaster_ReadEx (ftHandle, UNIVERSAL_BOARD_ADDRESS, START, &buffer[0], 2, &sizeTransferred);

if (ft4222Status == FT4222_OK)
{
    uint16_t numDataBytes = 0;

    printf ("Read %d bytes.\n", sizeTransferred);

    // buffer[0] is our Start Code, and we'd error check that here.

    // buffer[1] is the number of data bytes in our payload (if any)

    numDataBytes = buffer[1];

    printf ("Repsonse num data bytes %d.\n", numDataBytes);

    ft4222Status = FT4222_I2CMaster_ReadEx (ftHandle, UNIVERSAL_BOARD_ADDRESS, STOP, &buffer[2], 3+numDataBytes+2, &sizeTransferred);

In our case, our message format is a 5-byte header (starting with a Star Code, # of PayLoad Data Byters, and three other items), then payload bytes (if any), then a 2-byte CRC.

In testing, we took out all error checking and just did the two reads back to back.  This works, but will have a 150uS-300uS gap between reading the first two bytes and reading the rest, due to overhead of Windows and such. We haven't benchmarked it under Linux yet, but that's on the list.

Hope this helps others.

2
Discussion - Software / I2C Master Read in multiple read requests.
« on: November 14, 2022, 05:27:55 PM »
UPDATE: Next post has confirmation this works, with a Saleae capture showing the start and stop bits are handled properly.

We use a custom protocol over I2C that embeds message length in our messages. In our PIC24 firmware, we have one board that will read the first two bytes (to get our protocol start code, and the number of data bytes in the message) and then it will read only the expected number of bytes. (Our actual protocol does more - having CRC and other things we validate, but I am simplyfing it here for example and removing most error checking.)

Code: [Select]
i2c_start (I2C_SUBNET_BUS);

i2c_write (I2C_SUBNET_BUS, I2CSlaveAddress + 1);

// Read the message on the I2C bus.
startCode = i2c_read (I2C_SUBNET_BUS, 1); // Start Code

numDataBytes = i2c_read (I2C_SUBNET_BUS, 1); // Num Data Bytes

for (int idx = 0; idx<(numDataBytes-1); idx++)
{
    RXBuffer[idx] = i2c_read (I2C_SUBNET_BUS, 1);
}

// Read the last byte, but don't ACK.
RXBuffer[idx] = i2c_read (I2C_SUBNET_BUS, ZERO);

i2c_stop (I2C_SUBNET_BUS);

Our system is fairly complex with as many as 27 different boards in communication over I2C.

On our FTDI Windows host program side, we hard code the expected response message size. We do something like:

Code: [Select]
FT4222_I2CMaster_Write(ftHandle, slaveAddress, buffer, bytesToWrite, &sizeTransferred);
...
FT4222_I2CMaster_Read(ftHandle, slaveAddress, responseBufferPtr, ExpectedResponseSizeForThatMessage, &sizeTransferred);

This is fine, but if we are writing something that has a large message expected, and there is a problem, the slave board will return a NACK message (7 bytes in our case) and the Master reads that and keeps reading up to the expected size.

No big deal, since our firmware zeros out the response buffer so if the Master reads 10 bytes at any time, it just gets back 10 0s.

BUT, I wanted to make our messages more flexible and maybe speeds things up. It looks like I could recreate what I want using ReadEx(), since I see:

Quote
The I2C condition will be sent with this I2C transaction
 START = 0x02
 Repeated_START = 0x03
 Repeated_START will not send master code in HS mode
 STOP = 0x04
 START_AND_STOP = 0x06

It looks like I would do a ReadEx of 2 bytes, with the flag set to START, then I can error check our start code (byte 0) and number of data bytes (byte 1) and then issue a ReadEx of that many bytes with flag set to Repeated_Start (for one less byte) then read the final byte using STOP.

I thought I'd ask if this was worth trying, or if there was a better way. Perhaps the driver handles doing a read with just STOP and I can save a step.

I plan to experiment on this before the end of the year, but thought I'd ask in case I couldn't even do this.

Thanks, much.



3
Sorry to bump such an old topic, but we'd still like to find examples of how to properly detect and recover from an I2C bus lock. There was an API call added that does appear to send the clock pulses, but we haven't found any examples of what process to follow to shut down/recover when issues happen.

4
Hello,

This will be included in the LibFT422 release notes in future releases.

I will also check if anything can be done in the driver or library to help improve this.

Best Regards,
FTDI Community

Thank you. A simple blocking option (don't return until all bytes have been sent) would be great.

5
Since there is a separate byte for the address, and since there are 9 pulses for each byte (ack/nak bit), a formula probably needs to take that in to consideration. Something like:

Code: [Select]
#define I2C_KHZ 400

ms = ((8+1) /*bits*/ * (1000/(I2C_KHZ)) /*us*/ * (bytesTransferred+1)) / 1000;

if (ms < 1) ms = 1;

Sleep (ms);

When looking at the FTDI Master (Windows 11) in a Salae capture, I also see gaps between each byte that range from 10us to 14us, so I added some worst-case extra bits (6 for my case) to that to cover it:

ms = ((8+1+6) ....etc...

I am not sure what the FTDI driver does that causes those gaps, but I expect the reason they vary in length is due to Windows not being a realtime OS.  Perhaps the gaps are even larger when using more CPU time or running more stuff.  That would throw all these calculations off.

There really should be a way to query the driver and find out if it's done writing.

6
Thank you for the reply. Please consider to update the wording in the errata sheet and mention the affected libFT4222 APIs explicitly.

Having just ran in to this on our project, yes, please.

7
Discussion - Software / msvcp100.dll and msvcr100.dll dependencies?
« on: March 29, 2022, 03:04:51 PM »
We have a large LabWindows program and the only external component it uses is the FTDI drivers:

ftd2xx.lib
LibFT4222-64.lib and LibFT4222-64.dll

When we first ran it under Windows 10 LTSC, it complained about missing msvcp100.dll and msvcr100.dll. These come from the Visual C++ 2010 redistributable. These files are included with Windows 10, but are not part of LTSC and have to be installed separately.

Are these FTDI files what is needing them? A simple LabWindows U.I. program that does not use the FTDI code seems to work.

It appears the dependency is either in the FTDI software, or some library item that LabWindows is pulling in for our product (FTDI is the only component we use that is not built-in to LabWindows).

Hopefully someone can confirm whether or not these DLLs are used by FTDI. That would greatly help me know where to focus my research in to this issue.

Thanks, much!

8
Discussion - Software / Re: FT260 - Pauses in I2C comunication.
« on: August 26, 2021, 08:28:50 PM »
This may not help, but...

Using the FT4222, we noticed timing gaps between groups of data (I seem to recall odd spacing every 3 bytes).

Somewhere (support? random internet searching?) we were told to look at the SetClock speed and set it to SYS_CLK_24.

FT4222_SetClock (ftHandle, clock);

I do not know if this changed anything.

9
We make use of LibFT4222.dll for I2C Master communication on a Windows PC.

I would like to make our error detection much more robust. For example, I want to be able to detect issues such as:
  • USB cable disconnected.
  • I2C bus lock up.
  • ? ? ?
I get back an FT4222_STATUS from all read/write operations, but I am not real sure which errors are "best practice" to try to detect and handle.  I expect we can put in things like:

If we think I2C bus is locked, try an FT4222_I2CMaster_ResetBus().

If we think the USB connection is bad, un-init, close and try to re-open and init.

Library functions such as FT_CyclePort() may also be useful.

Could someone point me to some documention on "best practices" for a robust I2C system?

Thanks, much.

10
We use Windows and the FT4222 driver to talk to a variety of boards over I2C. Over the years, we have seen many issues with I2C bus locks and have tried to mitigate them in software/firmware.

I thought I'd ask here if folks had any elegant solutions for detecting an I2C bus lock and attempting recovery.

The last release of the library (1.4.4) added FT4222_I2CMaster_ResetBus(); and finally allowed sending the 9 clock pulses to try to unstick a stuck I2C slave device. Before this function was added, we tried doing it manually but found you could not access the GPIO pins when in I2C mode.

I believe we may have been able to just uninitialized from I2C and initialize in GPIO mode to do this:

Code: [Select]
FT_HANDLE ftHandle = NULL;

ftStatus = FT_OpenEx ("PrecisePower B", FT_OPEN_BY_DESCRIPTION,
                      &ftHandle);

if (ftStatus == FT_OK)
{
     GPIO_Dir gpioDir[4] = { GPIO_OUTPUT, GPIO_OUTPUT, GPIO_OUTPUT, GPIO_OUTPUT };
     
     ft4222Status = FT4222_GPIO_Init(ftHandle, gpioDir);

     //disable suspend out , enable gpio 2
     ft4222Status = FT4222_SetSuspendOut(ftdiInfoPtr->ftHandle, false);
     
     //disable interrupt , enable gpio 3
     ft4222Status = FT4222_SetWakeUpInterrupt(ftdiInfoPtr->ftHandle, false);
     
     // set gpio0/gpio1/gpio2/gpio3 output level high
     for (int pulse=0; pulse<9; pulse++)
     {
        ft4222Status = FT4222_GPIO_Write(ftHandle, GPIO_PORT0, 1); // Clock pin
        ft4222Status = FT4222_GPIO_Write(ftHandle, GPIO_PORT0, 0); // Clock pin
     }
     Sleep (1);
     
     FT4222_UnInitialize(ftHandle);

    // Re-init as I2C and use it...           
}
FT_Close (ftHandle);

(Untested; not sure the timing from within Windows toggling that pin on/off would do the trick.)

I wondered if anyone had any clever ways of detecting an I2C stuck bus condition (like when a slave device is using clock stretching, and the master doesn't do a read).

I'll do another post about our experiments with ACK/NACK.

Cheers.

11
During some early testing, I noticed that Write worked even if nothing was on the other side (no address ACK). Today, I am doing the write, and if it returns OK, I am checking controller status looking to see if the write was acknowledged.

But, I also saw the errata saying reading that register while a write was in progress could corrupt data.

12
Thanks. I am still trying to work through best practices. In this case, nothing could be done, but I often find the
c program gets stuck doing an FTDI library call. You can’t kill it with task manager, and have to reboot Windows, or unplug the USB cable. It releases when that is done.

How can I detect if a bus is stuck?

13
*** UPDATE ***

I switched over to GPIO mode and notice I can toggle the data line, but not clock.  At this point, I believe one of the devices on my bus is holding it low and this "unstick trick" will not work for me.

I have learned about FT4222_UnInitialize() which lets me open the device, initialize it for GPIO, unitialize it, the initialize it for I2C. I did not know about that, back then, or I would have tried this trick before the library had ResetBus.

My test code:

Code: [Select]
    FT_HANDLE ftHandle = NULL;
   
    ftStatus = FT_OpenEx ("PrecisePower B", FT_OPEN_BY_DESCRIPTION,
                          &ftHandle);
   
    if (ftStatus == FT_OK)
    {
         GPIO_Dir gpioDir[4] = { GPIO_OUTPUT, GPIO_OUTPUT, GPIO_OUTPUT, GPIO_OUTPUT };
         
         ft4222Status = FT4222_GPIO_Init(ftHandle, gpioDir);

         //disable suspend out , enable gpio 2
         //ft4222Status = FT4222_SetSuspendOut(ftdiInfoPtr->ftHandle, false);
         
         //disable interrupt , enable gpio 3
         //ft4222Status = FT4222_SetWakeUpInterrupt(ftdiInfoPtr->ftHandle, false);
         
         // set gpio0/gpio1/gpio2/gpio3 output level high
         for (int pulse=0; pulse<9; pulse++)
         {
            ft4222Status = FT4222_GPIO_Write(ftHandle, GPIO_PORT0, 1); // Clock pin
            Sleep (1);
            ft4222Status = FT4222_GPIO_Write(ftHandle, GPIO_PORT0, 0); // Clock pin
            Sleep (1);
         }
         Sleep (1);
         
         FT4222_UnInitialize(ftHandle);           
    }
    FT_Close (ftHandle);

14
FTDI added FT4222_I2CMaster_ResetBus() in the 1.4.4 release (I believe).  It is supposed to send 9 I2C clock pulses to unstick the I2C bus. I recall testing this when I first received this version, and saw it work.

But today, I am noticing it is not sending clock pulses.  Attached is a screen shot of the Saleae capture.

To verify my Saleae was working, I swapped my two input probes and saw the pulses move to the other input.

My code is very simple and is doing this:

Code: [Select]
    ftStatus = FT_OpenEx ("MyDeviceNameHere", FT_OPEN_BY_DESCRIPTION,
                          &ftdiInfoPtr->ftHandle);
   
    if (ftStatus == FT_OK)
    {
        ResetDevice ();
        // Need to wait for the FTDI device to complete the reset.
        Sleep (ONE_THOUSAND);

        // Set the device timeouts.
        ftStatus = FT_SetTimeouts (ftdiInfoPtr->ftHandle,
                                   FT_DEFAULT_RX_TIMEOUT,
                                   FT_DEFAULT_TX_TIMEOUT);

        // Initialize the I2C master.
        if (ftStatus == FT_OK)
        {
            // Initialize the FTDI device chosen.
            ft4222Status = I2CMasterInit (ftdiInfoPtr->ftHandle, I2C_SPECIAL_FAST_CLK);

            // Initialization is done.
            if (ft4222Status == FT4222_OK)
            {
                for (int idx=0; idx < 10; idx++)
                {
                    // Send nine clock pulses to reset a stuck Slave device.
                    ft4222Status = I2CMasterResetBus (ftdiInfoPtr->ftHandle);
                    Sleep (1);
                }

We have wrappers for the different functions, so I2CMasterResetBus is just:

Code: [Select]
FT4222_STATUS I2CMasterResetBus (FT_HANDLE ftHandle)
{
    return FT4222_I2CMaster_ResetBus (ftHandle);
}

And ResetDevice() is just calling FT_ResetDevice ();

Anyone used this? It's new, and wasn't even documented at first (beyond header file entries).

Thanks, much.

15
I do not think it was actually resolved in 1.4.3, but it definitely works in 1.4.4.

Pages: [1] 2