Speaking SPI & I2C With The FT-2232

For a while now I’ve been looking for an easy way to interface with external SPI and I2C devices over USB in a manner that can be easily integrated into future projects as well as used in a simple stand-alone system.

Although there are many existing SPI/I2C interface solutions, most of them are microcontroller based and connect to the PC though a USB to serial converter. This works fine, but I wanted something with a bit more speed while also remaining simple, cheap, and readily available.

After some searching, the FTDI FT-2232 family of chips seemed to fit the bill nicely. Although they are more commonly used to interface with JTAG devices, the FT-2232′s Multi-Protocol Synchronous Serial Engine (MPSSE) also supports the SPI and I2C protocols, clock rates of up to 30MHz, and a full-speed USB interface. Development boards are also cheap – the UM232H is $20 from DigiKey or Mouser in single quantities.

I’ve written libmpsse, a Linux wrapper library around libftdi that provides an easy to use API for interfacing with SPI and I2C devices using C and Python.

So how does this relate to hacking embedded systems you ask? Let’s take a look…

Although convenient, firmware update files are not always sufficient for performing code analysis on an embedded device. The firmware update file may be encrypted/obfuscated, or it may only be a partial update for the embedded system. In some cases, there may be no firmware update available at all. In these situations, being able to dump the firmware directly from the target device’s flash storage is invaluable.

SPI flash chips are increasingly replacing parallel flash chips, in both embedded devices as well as traditional PCs, and using libmpsse we can easily read and modify their contents.

As an example, let’s read the entire contents of a 1MB SPI flash chip. After making the appropriate hardware connections between the target flash chip and the FTDI chip, we can use the following Python script to dump the flash contents:


from mpsse import *

MPSSE(SPI0, THIRTY_MHZ, MSB)

Start()
Write("\x03\x00\x00\x00")
data = Read(0x100000)
Stop()

Close()

open('flash.bin', 'wb').write(data)

Although simple, the above script can read data from the flash chip very quickly:

eve@eve:~/libmpsse/src/examples$ time sudo python spiflash.py 
FT232H Future Technology Devices International, Ltd initialized at 30000000Hz (SPI mode 0)
Dumped 1048576 bytes to flash.bin

real	0m0.556s
user	0m0.020s
sys	0m0.016s

With the data extracted from the flash chip, we can now analyze it using our standard tools and techniques.

Of course libmpsse can be used to interface with other SPI/I2C devices such as data sensors, frequency synthesizers and EEPROM chips. It can be an easy way to add USB functionality to existing or future hardware designs, or to just have a simple SPI/I2C interface for development and testing.

The libmpsse source, documentation and examples are available from the Google Code project page.

Bookmark the permalink.

18 Responses to Speaking SPI & I2C With The FT-2232

  1. Pingback: FT-2232 bridges Python and I2C/SPI - Hack a Day

  2. Pingback: FT-2232 bridges Python and I2C/SPI | ro-Stire

  3. Pingback: FT-2232 bridges Python and I2C/SPI | HackDom | The Hacking Kingdom

  4. Pingback: FT-2232 bridges Python and I2C/SPI « Gadgets « The Depot of Talk

  5. kiran says:

    what is that ft2232 breakout board in the picture? from where did you buy that?

    • Craig says:

      It’s actually an FT-232H eval board (not to be confused with the FT-232R, which does not support MPSSE!), and I bought it from DigiKey. They also sell one built into a USB cable, which is quite handy. Mouser carries both of these products as well.

  6. molli123 says:

    which chip did you actually use in your example? When do I have to use i2ceeprom and when spiflash when connecting to 8 pin chips?

  7. molli123 says:

    is it AT24XX is needs I2C and AT25XX SPI, but with different wiring?

    • Craig says:

      Yes, the wiring for the SPI and I2C EEPROMs will be different. You will need to consult the EEPROM chip’s datasheet to determine which pins do what. The AN135 PDF included in the libmpsse docs folder has examples of connecting the FTDI chip to various devices, such as EEPROMs.

      You will likely need to modify the example applications as well to ensure that they are reading the right number of bytes from your EEPROM chip.

  8. Paul says:

    I tried to configure and install this with –prefix set to a location where I could install without being root, but the makefile install rule seems to not really support that. It was still trying to create things in /usr/local/….

    • Craig says:

      I just checked in a change to the Makefile so that it doesn’t try to create symlinks in /usr/lib. With –prefix and PYLIB properly specified, it should now install fine to wherever you point it.

  9. edo says:

    did you see flashroom project?
    it implement spi over libftdi and support many EEPROM chips

    • Craig says:

      Yes, I’m familiar with the flashrom project. Although there is some overlap in capabilities with libmpsse, they really are very different.

      Flashrom specifically targets reading/writing flash chips, including SPI chips as mentioned here, particularly things like BIOS chips.

      libmpsse provides a generic SPI/I2C library, letting you talk not only to flash chips, but EEPROMs, real time clocks, I/O expanders, and pretty much anything else that has an SPI/I2C interface.

  10. roboknight says:

    So, I’ve been using libmpsse to successfully interface to I2C rheostats from microchip (MCP42xx). The problem I’m having now is that data is sent during a write cycle… I can’t see how libmpsse actually handles this. It appears you have write, then read and that you can’t actually write/read in one operation. Am I missing something? I looked through at the libftdi library, and it seems that this is pretty much the way it works too. Since SPI can actually clock bytes in during all write operations, it seems to be an oversight. But as, I asked, am I missing something?

    • Craig says:

      Yes, this is a limitation in the libmpsse API. In theory it should be possible to do an SPI write and then read back the contents of the FTDI chip’s read buffer, but AFAIK libftdi doesn’t expose this functionality. One solution would be to bypass libftdi and have libmpsse do the usb bulk reads itself, but I’ll have to look into it further.

      • roboknight says:

        I was afraid of that. I was trying to find the info on the MPSSE commands that I had run across (I think they are buried on FTDIs website somewhere, but it isn’t obvious if I remember correctly), so that I could maybe hack some functionality into libftdi and expose that back to libmpsse… but I can’t find the command set anywhere for some reason now. All I can find are the FTDI API interfaces into D2XX. Maybe it was buried in their data sheets… I just don’t remember now.

      • roboknight says:

        I think I might have fixed it. I created a WriteRead command. It doesn’t output the data like the read command does yet, but at least I can do a regular read and see the data from the buffer. It has to do with how you implement the rx/tx commands. You need one that supports clocking in on rx AND tx. At any rate I might have a patch soon.

Leave a Reply

Your email address will not be published. Required fields are marked *

*

You may use these HTML tags and attributes: <a href="" title=""> <abbr title=""> <acronym title=""> <b> <blockquote cite=""> <cite> <code> <del datetime=""> <em> <i> <q cite=""> <strike> <strong>