FTDI LibMPSSE SPI

0

I recently purchased the FTDI C232HM-DDHSL-0 USB cable for use with SPI and I2C devices; my goal is to read the memory from an SPI memory chip that I removed from a router. However, I am having issues getting the libMPSSE library & 2xx drivers to send signals to a connected device.I hooked the leads of the C232 up to a Saleae logic analyzer and saw that no signals were being output!

Useful links for this question:

I am using a Debian x86_64 machine. The MPSSE SPI download only had the i386 version of the library, so I downloaded the MPSSE SPI source (https://www.ftdichip.com/Support/SoftwareExamples/MPSSE/LibMPSSE-SPI.htm) and built the x86_64 bit version. There were no build errors or warnings.

I copied libftd2xx.so and libMPSSE.so to /usr/local/lib.

I plugged the cable in, then removed the following kernel modules:

  • ftdi_sio <-- Readme says to take take out
  • usbserial <-- Readme says to take out
  • usb_wann <-- Needed to remove to take out usbserial
  • qcserial <-- Needed to remove to take out usbserial

At this point I was hoping that my set up was done correctly.

I connected 6x cables to the 8 pin memory chip:

  • VCC <--> red lead
  • Ground <--> black lead
  • Chip select <--> brown lead
  • Data in <--> green
  • serial clock <--> orange
  • Data out <--> yellow

I did not connect hold and write protect pins on the memory chip. Recall my goal is to read the memory out of the chip, and the waveform for the read did not show those pins were necessary.

I am using this program:

/* Standard C libraries */
#include<stdio.h>
#include<stdlib.h>
#include<string.h>

#include "ftd2xx.h"
#include "libMPSSE_spi.h"

FT_HANDLE ftHandle;

uint8 tx_buffer[4096] = {0};
uint8 rx_buffer[4096] = {0};

int main()
{
    uint8 i = 0;
    int sizeToTransfer = 0;
    int sizeTransfered = 0;
    FT_STATUS status = FT_OK;
    FT_DEVICE_LIST_INFO_NODE devList = {0};
    ChannelConfig channelConf = {0};

    channelConf.ClockRate = 30000000; // 30Mhz
    channelConf.LatencyTimer = 75;
    channelConf.configOptions = SPI_CONFIG_OPTION_MODE0 | SPI_CONFIG_OPTION_CS_DBUS3 | SPI_CONFIG_OPTION_CS_ACTIVELOW;
    channelConf.Pin = 0x00000000;/*FinalVal-FinalDir-InitVal-InitDir (for dir 0=in, 1=out)*/


    //
    // Open the channel and dump some information
    //
    status = SPI_GetChannelInfo(0,&devList);
    if (status != FT_OK)
    {
        printf("SPI_GetChannelInfo failed, status = %d\n", status);
        return -1;
    }
    printf("Flags=0x%x\n",devList.Flags);
    printf("Type=0x%x\n",devList.Type);
    printf("ID=0x%x\n",devList.ID);
    printf("LocId=0x%x\n",devList.LocId);
    printf("SerialNumber=%s\n",devList.SerialNumber); // TODO: Why blank?
    printf("Description=%s\n",devList.Description);
    printf("ftHandle=0x%p\n",devList.ftHandle);/*is 0 unless open*/


    //
    // Open channel 0 
    //
    status = SPI_OpenChannel(0,&ftHandle);
    if (status != FT_OK)
    {
        printf("SPI_OpenChannel failed, status = %d\n", status);
        return -1;
    }

    //
    // Initialize the channel: See configuration structure at top of main()
    //
    status = SPI_InitChannel(ftHandle,&channelConf);
    if (status != FT_OK)
    {
        printf("SPI_InitChannel failed, status = %d\n", status);
        return -1;
    }

    //
    // Send the read command (0x03), and read what we get in our receive buffer
    //
    sizeToTransfer=8;
    sizeTransfered=0;
    tx_buffer[0] = 0x03;
    status = SPI_ReadWrite(ftHandle, rx_buffer, tx_buffer, sizeToTransfer, &sizeTransfered, 
            SPI_TRANSFER_OPTIONS_SIZE_IN_BYTES|SPI_TRANSFER_OPTIONS_CHIPSELECT_DISABLE|SPI_TRANSFER_OPTIONS_CHIPSELECT_ENABLE);
    if (status != FT_OK)
    {
        printf("SPI_ReadWrite failed, status = %d\n", status);
        return -1;
    }

    //
    // Dump the receive buffer to see if we got anything.
    //
    printf("Size transfered = %d\n", sizeTransfered);
    i = 0;
    while (i < sizeTransfered)
    {
        printf("%02x",rx_buffer[i]);
        i++;
    }   
    printf("\n");

    //
    // Cleanup
    //
    status = SPI_CloseChannel(ftHandle);
    if (status != FT_OK)
    {   
        printf("SPI_CloseChannel failed, ret = %d\n", status);
    }

    return 0;
}

To make and run the program:

To compile: gcc read_memory.c -lMPSSE -ldl
To run: sudo ./a.out

My output is:

// The driver can at least detect the cable.
Flags=0x2
Type=0x8
ID=0x4036001
LocId=0x204
SerialNumber=
Description=USB <-> Serial
ftHandle=0x(nil)
Size transfered = 8

// Junk in the receive buffer
ff037fffffffffff

Whether I keep the memory chip connected or disconnected I get the same junk in the receive buffer. I see no LEDs light up on the cable or anything to indicate it is "working." I have tried SPI_Write() and SPI_Read() and get similar behavior. I tested on an Ubuntu VM (running on Windows host) and saw the exact same behavior.

I am really excited to get this to work so if anyone can help me with what I am doing wrong it would be greatly appreciated! Thanks!

linux
x86-64
reverse-engineering
ftdi
asked on Stack Overflow Oct 20, 2019 by donsiuch • edited Oct 20, 2019 by donsiuch

1 Answer

0

Set device first to MPSSE mode, and it should work. See quite minimum (Python) example below based on FTD2XX library only (tested in Windows). LibMPSSE is not required to run simple SPI. Data can be read by s = dev.read(nbytes), where nbytes is byte count. Find more information in nice tutorial: Driving an SPI device using MPSSE

import ftd2xx
OPS = 0x03                                  # Bit mask for SPI clock and data out
OE = 0x08                                   # CS

dev = ftd2xx.open(0)                        # open first available device
if dev:
    dev.setTimeouts(1000, 1000)
    dev.setBitMode(OPS, 2)                  # bit mask, MPSSE mode
    dev.write(bytes((0x86, 59, 0)))         # set SCK to 100kHz
    dev.write(bytes((0x80, 0, OE + OPS)))   # CS low
    data = 0x55,
    n = len(data) - 1
    dev.write(bytes(((0x11, n % 256, n // 256) + data))) # write SPI data
    dev.write(bytes((0x80, OE, OE + OPS)))  # CS high
    dev.close()
answered on Stack Overflow Jan 23, 2020 by juha • edited Jan 29, 2020 by juha

User contributions licensed under CC BY-SA 3.0