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:
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.