Implementation of the I2C interface based on the FT2232H chip (MPSSE mode)
The interface chip supports the I2C interface (not to be confused with I2S!) In the MPSSE (Multi-Protocol Synchronous Serial Engine) mode. In addition to I2C, this mode supports a whole list of standard serial interfaces, such as SPI, JTAG, etc. It is possible to implement your own interfaces if necessary. This description talks about a number of nuances of supporting the I2C interface, and also gives an occasion to chat on related topics.
Disclaimer: This article is written on working materials and is primarily intended for the author of the article when he loses the original document. At the same time, the information below may be of interest to a narrow circle of specialists. It is not recommended for reading to a wide circle of readers, unless the very reader wants to dive briefly into the world of debugging software and hardware. The studies were conducted more than a year ago, however, this information remains relevant at the moment, since the libraries on the manufacturer’s website were not updated. Information about the detected problems was sent to the manufacturer, but no feedback was received. A post was written based on this , for which the author expresses special thanks
Independent operation of two I2C channels is supported (one channel for FT232H). An example of a switching circuit is given in AN113 - as an example, the communication between the FT2232H and the non-volatile memory chip 24LC256 is used. Only two signals are directly related to the I2C interface: SCL (clock signal, called SCC in the figure) and SDA (transmitted data). According to the specification, each of these signals can be bi-directional, however, often there is only one master device (master) on the bus, and it is this that sets the clock signal. In any case, the data is bidirectional - for every 8 bits of transmitted data, 1 confirmation bit follows.

At the software level, working with the I2C bus is possible in two ways:
Research was conducted using one of the available boards. The INA219 power meter was used as a slave device on the I2C bus. Since the board was taken at what was at hand, between the FT2232H and INA219 chips was FPGA ( as I was lucky I understood a little later ). Initially, I planned to use it only for converting a 3-wire FT2232H interface into a two-wire I2C bus interface - in a normal device, such a conversion occurs due to the circuit, see the figure above.

As already mentioned, when transmitting data for every 8 bits of transmitted information, confirmation (ACK) follows - the signal is transferred to state 0 from the receiving device. If the transmitting device sees this confirmation, it means they heard it and can continue. If there is no confirmation, then continuing to continue is useless and the exchange can be stopped.
In the process of research, it was found that the LibMPSSE-I2C library has an error that blocks the ability to read more than one byte on the bus in most cases. The error is manifested by the appearance of a glitch on the clock signal before issuing an ACK confirmation of the first read byte from the FT2232H side to the bus. The glitch length is 1 period of the frequency of 12 MHz (about 8 ns). This glitch is perceived by the slave device on the bus as a clock signal that appears at a time when the ACK flag is not yet set. After that, the slave device aborts the transaction. An example of such a transaction, in which an attempt is made to read two bytes from the device, is shown in the figures (data was captured at a frequency of 120 MHz, a glitch is present on time samples 20968-20967).here I was glad for the first time the cluttered FPGA ). The pictures show that on the DI line the first byte from the device is read, then the device falls off (having received an incorrect confirmation from the master) and 0xFF is read instead of the second byte.

In the case of filtering this pulse, the correct reading procedure on the bus was provided. In the test environment, filtering was performed digitally on FPGA ( a small module was written in VHDL, which rejects glitches on the input signals ). Another possible way is filtering using an RC chain on the SCL bus, however, this will limit the maximum bus frequency ( due to some insanity, this solution was not analyzed deeply) An example of a successful transaction (subject to glitch filtering) is shown in the following figure. Now, on the DI bus, we see the correct reading of two bytes.

Naturally, I want to get to the true reasons for this behavior. Unfortunately, the source code of the LibMPSSE-I2C library is not available, binary disassembly is not our specialty. But to analyze the USB data exchange in the presence of an open protocol description is a matter of 5 minutes. Well, an hour. Well, no more than a day.
A detailed study showed a problem in generating commands for the MPSSE controller generated by the LibMPSSE-I2C library. The following is a set of instructions used to read 2 bytes on the bus (the stop bit is not set at the end). The highlighted commands show the location of the problem and the method of solution (prohibiting the transition to 1 or changing the phase of the supplied clock signal for the ACK flag):
Thus, the problem is localized, a solution is found and all the afflicted are divided into 3 flows:
In the research process, two test software projects were created based on examples supplied by FTDI. The project based on the LibMPSSE-I2C library is called i2c_direct (the main file is i2c_direct.cpp). The project programming the MPSSE mode independently is I2CTEST (the main file is I2CTEST.cpp). Those who wish will find examples of source files in the archive like rarjpeg in the first picture of the post.
Links:
AN108 Command Processor For MPSSE and MCU Host Bus Emulation Modes
AN113 Interfacing FT2232H Hi-Speed Devices To I2C Bus
AN177 User Guide For LibMPSSE-I2C
Example of interface FT2232H Hi-Speed devices to I2C bus (via D2XX)
LibMPSSE-I2C Examples
Disclaimer: This article is written on working materials and is primarily intended for the author of the article when he loses the original document. At the same time, the information below may be of interest to a narrow circle of specialists. It is not recommended for reading to a wide circle of readers, unless the very reader wants to dive briefly into the world of debugging software and hardware. The studies were conducted more than a year ago, however, this information remains relevant at the moment, since the libraries on the manufacturer’s website were not updated. Information about the detected problems was sent to the manufacturer, but no feedback was received. A post was written based on this , for which the author expresses special thanks
Independent operation of two I2C channels is supported (one channel for FT232H). An example of a switching circuit is given in AN113 - as an example, the communication between the FT2232H and the non-volatile memory chip 24LC256 is used. Only two signals are directly related to the I2C interface: SCL (clock signal, called SCC in the figure) and SDA (transmitted data). According to the specification, each of these signals can be bi-directional, however, often there is only one master device (master) on the bus, and it is this that sets the clock signal. In any case, the data is bidirectional - for every 8 bits of transmitted data, 1 confirmation bit follows.

At the software level, working with the I2C bus is possible in two ways:
- Directly through the D2XX driver. In this case, it is necessary to carry out manual programming of the MPSSE mode in accordance with the set of commands described in AN108. All work goes through the FT_Read () and FT_Write () functions, as well as the related functions of opening / closing the device, etc.
- Using the LibMPSSE-I2C library. This library solves all the programming issues of the MPSSE mode and allows you to read and write the specified number of bytes on the I2C bus using the I2C_DeviceWrite () and I2C_DeviceRead () calls. A description of the library is given in AN177.
Research was conducted using one of the available boards. The INA219 power meter was used as a slave device on the I2C bus. Since the board was taken at what was at hand, between the FT2232H and INA219 chips was FPGA ( as I was lucky I understood a little later ). Initially, I planned to use it only for converting a 3-wire FT2232H interface into a two-wire I2C bus interface - in a normal device, such a conversion occurs due to the circuit, see the figure above.

As already mentioned, when transmitting data for every 8 bits of transmitted information, confirmation (ACK) follows - the signal is transferred to state 0 from the receiving device. If the transmitting device sees this confirmation, it means they heard it and can continue. If there is no confirmation, then continuing to continue is useless and the exchange can be stopped.
In the process of research, it was found that the LibMPSSE-I2C library has an error that blocks the ability to read more than one byte on the bus in most cases. The error is manifested by the appearance of a glitch on the clock signal before issuing an ACK confirmation of the first read byte from the FT2232H side to the bus. The glitch length is 1 period of the frequency of 12 MHz (about 8 ns). This glitch is perceived by the slave device on the bus as a clock signal that appears at a time when the ACK flag is not yet set. After that, the slave device aborts the transaction. An example of such a transaction, in which an attempt is made to read two bytes from the device, is shown in the figures (data was captured at a frequency of 120 MHz, a glitch is present on time samples 20968-20967).here I was glad for the first time the cluttered FPGA ). The pictures show that on the DI line the first byte from the device is read, then the device falls off (having received an incorrect confirmation from the master) and 0xFF is read instead of the second byte.

In the case of filtering this pulse, the correct reading procedure on the bus was provided. In the test environment, filtering was performed digitally on FPGA ( a small module was written in VHDL, which rejects glitches on the input signals ). Another possible way is filtering using an RC chain on the SCL bus, however, this will limit the maximum bus frequency ( due to some insanity, this solution was not analyzed deeply) An example of a successful transaction (subject to glitch filtering) is shown in the following figure. Now, on the DI bus, we see the correct reading of two bytes.

Naturally, I want to get to the true reasons for this behavior. Unfortunately, the source code of the LibMPSSE-I2C library is not available, binary disassembly is not our specialty. But to analyze the USB data exchange in the presence of an open protocol description is a matter of 5 minutes. Well, an hour. Well, no more than a day.
A detailed study showed a problem in generating commands for the MPSSE controller generated by the LibMPSSE-I2C library. The following is a set of instructions used to read 2 bytes on the bus (the stop bit is not set at the end). The highlighted commands show the location of the problem and the method of solution (prohibiting the transition to 1 or changing the phase of the supplied clock signal for the ACK flag):
0x80, 0x03, 0x13, 0x80, 0x03, 0x13, 0x80, 0x03, 0x13, 0x80, 0x03, 0x13, 0x80, 0x03, 0x13, // SDA, SCL high
0x80, 0x03, 0x13, 0x80, 0x03, 0x13, 0x80, 0x03, 0x13, 0x80, 0x03, 0x13, 0x80, 0x03, 0x13,
0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, // SDA low: START
0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13,
0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13,
0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13, 0x80, 0x01, 0x13,
0x80, 0x00, 0x13, // SDA, SCL low
0x80, 0x02, 0x13, // SDA high, SCL low
0x13, 0x07, 0x81, // Write address
0x80, 0x00, 0x11, // SDA, SCL low
0x22, 0x00, // Read ACK from slave
0x80, 0x00, 0x11, // SDA, SCL low
0x22, 0x07, // Read 8 bits
0x80, 0x02, 0x13, // SDA high, SCL low
//0x80, 0x00, 0x13, // Optional fix (use instead prev. command) to avoid SDA to go High
//0x12, 0x00, 0x00, // Write 1 bit: ACK - error here in LibMPSSE-I2C
0x13, 0x00, 0x00, // Write 1 bit: ACK - fixed version *************************************
0x80, 0x00, 0x11,
0x22, 0x07,
0x80, 0x02, 0x13,
0x12, 0x00, 0x00
Thus, the problem is localized, a solution is found and all the afflicted are divided into 3 flows:
- Communicate with FTDI regarding the above described pending clarification.
- The binary library is disassembled in search of the place where the corresponding teams are formed and govern it.
- They write without using the LibMPSSE-I2C library, directly sending control sequences like the above, thereby programming the MPSSE mode bypassing the library.
In the research process, two test software projects were created based on examples supplied by FTDI. The project based on the LibMPSSE-I2C library is called i2c_direct (the main file is i2c_direct.cpp). The project programming the MPSSE mode independently is I2CTEST (the main file is I2CTEST.cpp). Those who wish will find examples of source files in the archive like rarjpeg in the first picture of the post.
Links:
AN108 Command Processor For MPSSE and MCU Host Bus Emulation Modes
AN113 Interfacing FT2232H Hi-Speed Devices To I2C Bus
AN177 User Guide For LibMPSSE-I2C
Example of interface FT2232H Hi-Speed devices to I2C bus (via D2XX)
LibMPSSE-I2C Examples