Search the Community: Showing results for tags 'FPGA Pipistrello PIA USB'.



More search options

  • Search By Tags

    Type tags separated by commas.
  • Search By Author

Content Type


Forums

  • GadgetBox Universal IoT Hardware
    • GadgetBox General Discussion
  • Papilio Platform
    • Papilio General Discussion
    • Papilio Pro
    • Papilio One
    • Papilio DUO
    • Papilio Wings
    • DesignLab IDE
    • DesignLab Libraries
    • RetroCade Synth
    • Papilio Arcade
    • Papilio Loader Application
    • Papilio Logic Sniffer
    • Retired
  • Electronics
    • Modules
  • Soft Processors
    • ZPUino
    • J1 Forth
    • AVR8 Soft Processor
  • Community
    • Gadget Factory
    • Documentation
    • FPGA Discussions
    • Community Projects
    • Pipistrello
  • Open Bench
    • Open Bench Logic Sniffer at Dangerous Prototypes
    • OpenBench Logic Sniffer at Gadget Factory
  • Gadget Factory Internal Category

Categories

  • Papilio Platform
    • Papilio One
    • Papilio Plus
    • Papilio Wings
    • LogicStart MegaWing
    • ZPUino
    • Papilio Pro
  • Papilio Arcade
  • RetroCade Synth
  • Logic Sniffer
  • FPGAs
  • DesignLab
    • Example Projects
    • Libraries

Categories

  • Papilio FPGA
    • Papilio UCF (User Constraint) Files
    • Papilio Bit Files
  • Papilio Arcade
  • RetroCade Synth
  • General
  • Beta (Test) Releases
  • Books

Found 1 result

  1. FPGA as USB PIA

    I recently needed to bitbang some data on several IO pins and was considering my options. I didn't want to write HDL code and run it on a FPGA, I didn't even want to write C code and compile it and then run it under a soft processor on a FPGA. What I wanted was to write code on a PC, compile it, run it on the PC and quickly see the the results on a bunch of IO pins, kind of like the old days of the parallel port. My first thought was to use a FT2232H breakout board, the FTDI chip has a bunch of ports and several operation modes: However none of these modes would give me more than two 8-bit ports, one for channel A and one for channel B. Then I remembered that on a Pipistrello, Magnus had connected the entire port B to the FPGA allowing parallel data transfer. My thought was, why not use the FPGA's 48 IO pins as a PIA chip (Peripheral Interface Adaptor) and read/write them programmatically from the PC via the FTDI chip. After reading the FTDI datasheet cover to cover as well as the FTDI Programmer's Guide I still had questions as to how to enable the various modes. For example the ftd2xx.h file contains only the following modes that can be set via the FT_SetBitMode function: #define FT_BITMODE_RESET 0x00#define FT_BITMODE_ASYNC_BITBANG 0x01#define FT_BITMODE_MPSSE 0x02#define FT_BITMODE_SYNC_BITBANG 0x04#define FT_BITMODE_MCU_HOST 0x08#define FT_BITMODE_FAST_SERIAL 0x10#define FT_BITMODE_CBUS_BITBANG 0x20#define FT_BITMODE_SYNC_FIFO 0x40So how does one set the "245 FIFO" mode from the datasheet? Note that this isn't the same as the "245 FIFO SYNC" which is a special fast mode that uses channel A (connected to JTAG on the Pipi) and also uses all the resources on the FTDI chip which makes channel B become inactive. After much googling it turns out that the answer is easy and a little weird. "245 FIFO" mode is not set programmatically by calling the FT_SetBitMode function, instead this mode is programmed in the FTDI's eeprom chip for channel B, with a free FTDI Utility program, then on powerup, the chip will use "245 FIFO" mode for that channel. With the programming side sorted, it was a simple matter to come up with some HDL code to run on the FPGA that would allow the user to set and read pins. It is a simple state machine that receives commands from the PC and executes them. Each transfer is two bytes, a command and data byte. The 48 pins on the FPGA are treated as six 8-bit ports AL, AH, BL, BH, CL, CH just like the wing groupings. Each pin can be individually set as an output (direction bit = 0) or an input (direction bit = 1). When the pin is an input it is tristated but has a pullup (in the .ucf file) so this can be changed as required. On the PC side the programming is easy, you need to check the FTDI programming manual in the link above which has example code in it for every function call. Here's a quick guide to get something minimal up and running. This is written for Windows (minGW environment) and should therefore apply equally well to Linux. Grab ftd2xx.h and ftd2xx.lib from the drivers package on the FTDI web site. You can drop these into your include and lib directories respectively in your minGW installation. To compile you need a line similar to gcc -o your_program your_program.c -lftd2xx Inside your program you then need to #include "ftd2xx.h" Some useful defines would be:#define PORT0 0x00#define PORT1 0x01#define PORT2 0x02#define PORT3 0x03#define PORT4 0x04#define PORT5 0x05#define GET_VAL 0x00#define SET_VAL 0x08#define SET_DIR 0x10Then you need to open the FTDI port with: ftStatus = FT_OpenEx("Pipistrello LX45 B", FT_OPEN_BY_DESCRIPTION, &ftHandle);if (ftStatus != FT_OK) { printf("Failure\n");} else { printf("Success\n");}For the above to work you should make sure that your Pipistrello's board FTDI chip EEPROM is programmed with the name string "Pipistrello LX45", if you have changed it you need to adjust accordingly. Every function call in the FTDI library returns an FT_OK on success so you need to check that for error handling. To set port 0 to all inputs you would use something like this: buffer[0] = SET_VAL | PORT0;buffer[1] = 0xFF;ftStatus = FT_Write(ftHandle, buffer, 2, &BytesWritten);To read 1 byte from port 1 you could do this: buffer[0] = GET_VAL| PORT1;ftStatus = FT_Write(ftHandle, buffer, 1, &BytesWritten);ftStatus |= FT_Read (ftHandle, buffer, 1, &BytesReceived);Each USB transaction (call to FT_Read / FT_Write) introduces latency because the data has to be packaged into a USB packet and transferred complete with USB protocol overhead such as handshaking. A trick you could use is to package multiple write commands into just one packet. For example suppose you want to write a value to port 0 and then strobe low a pin on port 1 to indicate to some attached circuit that new data is available. You could do this in three USB calls, write data to port 0, write to port 1 to bring pin low, write to port 1 to bring pin high, or you could just do this in one call: buffer[0] = SET_VAL | PORT0;buffer[1] = 0x12; // output data on port 0buffer[2] = SET_VAL | PORT1;buffer[3] = 0xFE; // drop bit 0buffer[4] = SET_VAL | PORT1;buffer[5] = 0xFF; // raise bit 0ftStatus = FT_Write(ftHandle, buffer, 6, &BytesWritten);Finally, always be a good boy or girl and close the door when you leave. ftStatus = FT_Close(ftHandle);This is of course the bare minimum to get you going, you simply must read the FTDI programmer's manual to get a feel of all the functions available to you. I recommend you check out FT_SetUSBParameters, FT_SetTimeouts and FT_SetLatencyTimer. Also a very useful command is FT_Purge to clear the FIFO's. Oh this reminds me. The FTDI chip uses FIFO's on both the read and write channels. This means of course that you don't have to read each data byte immediately if you don't have to. For example suppose you want to read all six ports. You may think you'd have to write the read command for port 0 then read the value returned then repeat for all the other ports meaning you have to call the FTDI procedures in this order: read, write, read, write, read, write, read, write, read, write, read, write. Because of the FIFOs however you could simply send six read commands packaged into one USB packet then simply read six bytes for a total of two function calls, one read and one write as below: buffer[0] = GET_VAL | PORT0;buffer[1] = GET_VAL | PORT1;buffer[2] = GET_VAL | PORT2;buffer[3] = GET_VAL | PORT3;buffer[4] = GET_VAL | PORT4;buffer[5] = GET_VAL | PORT5;ftStatus = FT_Write(ftHandle, buffer, 6, &BytesWritten);ftStatus |= FT_Read (ftHandle, buffer, 6, &BytesReceived);Below is the source code of the project. It's very small and very simple. Pipistrello_fifo.zip