Recently I have been working on trying to store information to some form of on-board storage – either a flash drive or SD card. This has been a frustrating process as there are many options, but none with easy to find information on how to implement it exactly how I wanted – on a PIC18F4550 microcontroller chip using C18 compiler. This is a bit of a technical article, mainly to put up the info for others who might be in a similar position to myself.
I had been told about an easy-to-use module called the VDIP1 from FTDI Vicculum. This is an all-in-one USB controller with what is meant to be a very easy to use interface – either in UART, SPI or Parallel FIFO modes. I already used the SPI interface for controlling a display so I thought it would be a very simple matter of just using the same interface. VDIP1 has now been around for quite a while and they now stock a range of really interesting products.
I use a PIC18F4550 microcontroller IC for most of my designs at the moment. This has on-board USB facility, but only as a slave (i.e. you can plug it into a host, such as a computer, but you cannot plug in a USB drive which would also be a slave). I upload programs via the USB interface from a computer. I also use the C18 ‘C’ compiler from Microchip and the MPLAB IDE environment, also from Microchip – these are both free to download programs, but to get full optimisation then you must pay for the C18 compiler.
Here are some photos of my test SPI set-up:
I wanted to make a stand-alone data-logger which would store the data onto a readily available format, such as a USB flash drive. The VDIP1 can be used as a USB host (so can some PIC chips now). So I had the VDIP and got started….
It turns out that it is not quite as easy as I had thought. There was a lot of talk on the web about the fact that these devices are a bit funny in their implementation (note to self: do more research before buying things). The SPI interface is not what it would seem: while it is a serial peripheral interface, it does not work with the standard C18 SPI libraries. Rather you must implement the SPI code yourself. FTDI do supply some sample code for use of the device in SPI mode, but they use a different C compiler (SourceBoost) hence it does not build in C18 and my C and compiler knowledge was not good enough to get the example (called VMUSIC on the FTDI website) working directly.
I should add that I got a lot of useful information from google searches. Useful websites included:
So first things first:
Not much is needed – I used the same SPI interface wires but a 180pF capacitor is required between SDO and GND on the VDIP1. A wiring array is shown here:
PIC (18F4550) VDIP1
GND ———————————-> GND (Pin 18, 7)
5V ———————————–> 5V (Pin 1)
SDI (Port B0, Pin 33) ————> SDO (Pin 9) must have 180pf cap to ground
SDO (Port C7, Pin 26) ———–> SDI (Pin 8)
SCLK (Port B1, Pin 34) ———-> SCLK (Pin 6)
CS (Port D2, Pin 21) ————-> CS (Pin 10)
I wired this up on breadboard, connected to my PIC development board.
I also uploaded the latest version of the firmware for the VDIP1. This can be downloaded from the FTDI website. It took me a while to realise that the firmware is for the VNC1L IC, which is used in the VDIP1 module. I used the VDAP firmware (for Disk and Peripherals) (version 3.66 in my case). You then put this onto the home directory of a flash drive and rename it to be ‘FTRFB.FTD’. Plug the flash drive into the VDIP1 and then power it up and the new firmware will be uploaded. This worked first time for me, but there is no indication that it has been successful, causing me to doubt myself a bit.
This is where things got interesting (i.e. hours and hours of head banging). I eventually ended up using the bulk of the code written for the VMUSIC application, but with some tweeks to get it to work (at least to prove it works – making the code better is more of a long term goal).
I used the SPI.c and SPI.h files from the VMUSIC application and included them in a blank 18F4550 project. This did not compile. Eventually I found that you must remove the first line of code and add the next three lines to the top of the SPI.c file, as shown here:
I also had to change the pin definitions (although that was pretty obvious):
// Pin definitions for SPI
// NOTE: pin names are relative to the VMusic device
#define PORT_SDI PORTCbits.RC7 // SDI (on VMusic) is RC1 (Port C bit 1)
#define TRIS_SDI TRISCbits.TRISC7
#define PORT_SDO PORTBbits.RB0 // SDO (on VMusic) is RC0 (Port C bit 0)
#define TRIS_SDO TRISBbits.TRISB0
#define PORT_SCLK PORTBbits.RB1 // SCLK is RC5 (Port C bit 5)
#define TRIS_SCLK TRISBbits.TRISB1
#define PORT_CS PORTDbits.RD2 //Chip-Select Pin (change as needed)
#define TRIS_CS TRISDbits.TRISD2
I also had to change the spiDelay routine to:
After these changes the code compiled without error. I made no changes to SPI.h. I presume these changes are all related to syntax difference between SourceBoost and C18.
Now we needed to make the PIC and VDIP1 talk to each other. I presumed I could just read/write using the four spi functions – spiInit, spiWrite, spiRead, spiReadWait. But I kept getting rubbish back. After looking on the ‘scope I realised that the correct message was being sent, I just did not know what was being sent back. This is where the fun begins.
The most important document you need is the Vinculum Firmware Manual which explains the codes and command set.
In the VMUSIC program there is a routine where the code sends out the echo command (either ‘E’ or ‘e’), which you send and wait for the same character to be returned.This is called the synchronisation routine. In truth, when the VDIP1 is turned on it has a message waiting to be sent out. This message is the firmware version in the format (where ‘CR’ means carriage return):
This message changes depending upon the firmware version. I presume it also changes length.If you try and send ‘E’ chars then you will get rubbish (well the above code) returned until this message has been taken out of the read buffer.
To get things working I included an spiReadWait in the initialisation routine. This is done 25 times (in a ‘for’ loop) to get the above data read out.
Once this has been done you can then send commands and wait for data to be returned, such as the echo command shown here:
spiWrite(0x0D); // This sends the carriage return value
data=spiReadWait(); // Reads the data comming back (should be an ‘E’ – echo) Waits until it is read….
The data will contain the read back data, ‘E’ (the second spiReadWait will contain the carriage return value).
At the moment I have got to the stage where I can send and read commands. I will improve the initialization routine, as it should do synchronisation not matter how much data is in the read buffer. But for now I thought I would write this up to remind myself and to help others. I will add the full spi.c and spi.h for FTDI routines here when I have finished them.
I had been having a problem where, if you inserted and then removed the flash disk a few times (4 to be precise) then the VDIP1 would hang at the spiReadWait command. The SDO output was telling me that there was an internal buffer overflow – but I could not find out how large that buffer was (any ideas anyone?).
It turns out (2 days work…) that I had been sending commands when I really should have been waiting for the previous command data to be returned. Hence there were unserviced commands in the buffer which filled up until it could do no more.This is not explicit in the VDIP1 datasheets and firmware manual I think (obviously someone will tell me to RTFM, but I did, honest).
So in the end I wrote a code which does something a bit like this:
If the data_flag is high, write the command to the VDIP1.
Set a data_flag low.
Read all the data from the device.
Only when the VDIP1 returns the ‘prompt’ line (which is ‘>’ in the short command set) then set the data_flag high again.
I will work on getting a few routines going in some libraries so I can use this interface much more quickly in future applications.
Hope this saves someone more headbanging than I have had.