In my current project I want to interface the FT220x over 1-bit SPI with an TI piccolo TMS320F28027. After some trouble and various cups of coffee I managed the whole thing by implementing the SPI in pure software.

I wasn’t able to get it working with the built in tri-wire hardware SPI as the FT uses MIOSIO and MISO to send/receive data and status respectively.

Because there is no sample code available on the web concerning this problem I decided to publish my library here. Take a look into the datasheet for further information!

Sending data over SPI to the FT1248/FT220x is quite easy: Just send a WRITE_REQ (0x00) followed by the payload on MIOSIO.

Reading is a bit more complicated: We need to know how many chars to read. Well, send a READ_REQ (0x02), evaluate MISO and read data on MIOSIO if the FIFO is not empty. If MISO returns 0xFF, the FT’s FIFO is empty, cancel transmission immediately! If MISO returns 0xFE while sending READ_REQ, there is data in the FIFO ready to be shifted out. If MISO returns 0x7F while reading data, there is more data in the FIFO.

In my project there are other 4-wire SPI slaves, that’s why I need to toggle MIOSIO’s direction and MIOSIO/MOSI. Therefor I use the functions setSoftSpi4wire3wireOut() and setSoftSpi3wireIn().

libft220x.h

/*
* libft220x.h
*
* Created on: 29.05.2013
* Author: Dennis Schuett, dev.shyd.de
*/

#ifndef LIBFT220X_H_
#define LIBFT220X_H_

#include "main.h"
#define uint8_t unsigned char

#define READ_REQ 0x02
#define WRITE_REQ 0x00

void FTwrite(uint8_t *buf, uint8_t len);
int FTread(uint8_t *buf, uint8_t len);
uint8_t spi3_write(uint8_t value);
uint8_t spi3_read(uint8_t *value);

#endif /* LIBFT220X_H_ */

libft220x.c

/*
 * libft220x.c
 *
 *  Created on: 29.05.2013
 *      Author: Dennis Schuett, dev.shyd.de
 */

#include "libft220x.h"

void FTwrite(uint8_t *buf, uint8_t len)
{
  setSoftSpi4wire3wireOut(); // MIOSIO as output
  FT_CE_EN;
  spi3_write(WRITE_REQ);
  while (len--)
    spi3_write(*(buf++));
  FT_CE_DIS;
}

int FTread(uint8_t *buf, uint8_t len)
{
  uint8_t i = 0;
  uint8_t err = 0;
  setSoftSpi4wire3wireOut(); // MIOSIO as output
  FT_CE_EN;
  err = spi3_write(READ_REQ);
  if ((err & 0xFF) == 0xFE) // check for data in fifo
  {
    setSoftSpi3wireIn(); // MIOSIO as input
    for (i = 0; i < len; i++)
    {
      err = spi3_read(&buf[i]);
      if ((err & 0xFF) == 0xFF) // break if no more data in fifo
        break;
    }
  }
  FT_CE_DIS;
  return i;
}

uint8_t spi3_write(uint8_t value)
{
  uint8_t bit_ctr;
  for (bit_ctr=0; bit_ctr<8; bit_ctr++)   // output 8-bit
  {
    if(value & 0x80)
      MOSI_1;
    else
      MOSI_0;

    value = (value << 1);   // shift next bit into MSB..
        asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop");
    SCK_1;          // Set SCK high..
        asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop");
       value |= MISO;          // capture current MISO bit
        asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop");
    SCK_0;                // ..then set SCK low again
  }
  return value;
}

uint8_t spi3_read(uint8_t *value)
{
  uint8_t bit_ctr;
  uint8_t err; // error from MISO
  for (bit_ctr=0; bit_ctr<8; bit_ctr++)   // output 8-bit
  {
    *value = (*value << 1);  // shift next bit into MSB..
    err = (err << 1);
        asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop");
    SCK_1;          // Set SCK high..
        asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop");
        *value |= MOSI;      // capture current MIOSIO bit
       err |= MISO;            // capture current error bit on MISO
        asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop"); asm (" nop");
    SCK_0;                // ..then set SCK low again
  }
  return err;
}