Arduino Playground is read-only starting December 31st, 2018. For more info please look at this Forum Post

Writing data to USB Memory Stick

The FTDI Viniculum chip will write to USB memory
FTDI VDIP1

The commands are all here

http://www.ftdichip.com/Firmware/Precompiled/UM_VinculumFirmware_V205.pdf

It uses DOS commands to navigate around the disk and create and add to files.

It can interface in various ways, but I used serial. You only need to hook up 5V, 0V and serial in and out to interface with it. It uses the CTS and RTS lines to control flow - so I just connected them to each other so that every time the VDIP says it is ready to send, it gets a clear to send message.

If you write info to it too quickly then it could possibly lose info as it won't be able to pause the sending of info, but for my app I will be doing occasional short messages - letter and 4 numbers, so hope that it will be fine.

I'm using an Arduino mini for my app., and have a USB to serial board for programming it. While I am debugging it I have the serial out of the Arduino going to the serial in of the VDIP, and the serial out from the VDIP going to an additional serial in lead that I am monitoring with Z term on the mac. This means I can send messages to the Arduino from the serial monitor in Arduino, and see the response I get in ZTerm.

I wrote a simple program that would execute various of the commands on receiving numbers from serial monitor.

One important note - do not use a memory stick with important files on it as while perfecting your code it is possible to render the disk unreadable (I did it a few times). It is important to carry out the commands in the correct order - you must open a file to write before writing to it, and you must close a file after you have finished writing to it (although you can do multiple writes to it before closing it, but each one needs to specify how much info it is going to write).

int incomingByte=0;
int fileNumber=1;
int noOfChars;
long int valToWrite;
char activityToLog;
long int x;
long int startLogTime = 0;

void setup() {
	Serial.begin(9600);	              // opens serial port, sets data rate to 9600 bps
        Serial.print("IPA");                  // sets the vdip to use ascii numbers 
                                              //(so I can read them in the code easily!)
        Serial.print(13, BYTE);               // return character to tell vdip its end of message
}

void loop() {              
	if (Serial.available() > 0) {        // read the incoming byte
		incomingByte = Serial.read();

if (incomingByte=='1'){                      // if it receives a 1
  Serial.print("OPW LOG%");                  // open to write creates a file - named
  Serial.print(fileNumber);                  // LOG%1.TXT first time round - .TXT is for the computer
  Serial.print(".TXT");                      // I have used the % sign in the name so I can 
                                             //search the disk for log files that it has created 
                                             //so as not to overwrite any that may be on already
  Serial.print(13, BYTE);                    // return character

}

if (incomingByte=='2'){                      // if it receives a 2
               Serial.print("CLF LOG%");     // it closes the file
               Serial.print(fileNumber);     // LOG%1.TXT
               Serial.print(".TXT");
               Serial.print(13, BYTE);       // return character

	}

if (incomingByte=='3'){                      // if it receives 3
               Serial.print("DIR");          // lists the directory on the memory stick
               Serial.print(13, BYTE);       // which will now include the file LOG%1.TXT
	}                                    


if (incomingByte=='5'){
               activityToLog='P';                  // I will be using different letters to label my time stamps
               valToWrite=millis() - startLogTime; // time since we started logging
               noOfChars=1;
               x=valToWrite;                       // need to copy valToWrite as getting no of characters will consume it
               while (x>= 10){                     // counts the characters in the number
                 noOfChars++;                      // thanks to D Mellis for this bit
                 x/=10;     
               }
               noOfChars +=2;                      //add 2 to the num as will also write the letter P and a return character

               Serial.print("WRF ");               //write to file (file needs to have been opened to write first)
               Serial.print(noOfChars);            //needs to then be told how many characters will be written
               Serial.print(13, BYTE);             //return to say command is finished
               Serial.print(activityToLog);        //followed by the info to write
               Serial.print(valToWrite);
               Serial.print(13, BYTE);             //write a return to the contents of the file (so each entry appears on a new line)
	}

if (incomingByte=='6'){                          
  fileNumber++;                                    //so we can create other files
}

if (incomingByte=='7'){ 
  if (fileNumber>0){                               //and look at previous ones
    fileNumber--;
  }
}

if (incomingByte=='8'){                        
               Serial.print("RD LOG%");            //reads the contents of named file
               Serial.print(fileNumber);           
               Serial.print(".TXT");
               Serial.print(13, BYTE);
	}}


if (incomingByte=='9'){   
  startLogTime=millis();                          // reset timing
}

}

And here's the result once its plugged back into the computer.

As you can see the files creation date is wrong. Below is the code to use a realtime clock to create files with the correct creation date. This could be adapted to use real time stamps rather than time since logging started, but I don't need that at the moment.

I used the Dallas real time clock DS1307, starting with code from here in the forum.

I'm using a mini, so had to solder to pins 4 and 5 on the end of the chip to get the lines for i2c.

You need to check the firmware that your VDIP is running if you want to set the creation date of the file to make sure this will work. Writing date info to the file meta data was only enabled in V03.50 25-Apr-2007 of the firmware. Mine were bought in May 2007 and were running V2.56, so adding a date stamp was not working at all.

To check what version you are running, the VDIP prints out its current firmware value on power up, so hook it up to a serial port and give it power while watching with z term or the like. This is also a handy way to learn the commands - I learned to do what I wanted to do with ZTerm first, and then worked out how to get the Arduino to send the same messages.

To update the firmware, just download the file from http://www.ftdichip.com/Firmware/Precompiled.htm rename the file ftrfb.ftd (removing version number) and put it on a memory stick. Plug that into the VDIP, and it will find the file and upgrade itself.

On to the code to do this-

add these lines to the earlier code

#include <Wire.h>;
unsigned long datestamp;

to the declarations at the beginning.

add

Wire.beginTransmission(104); // transmit to device #104, the ds 1307

to the Setup code

add this function between setup and loop

unsigned long dateStampForUSB()
  {
    // Below required to reset the register address to 0.
  Wire.beginTransmission(104); // transmit to device #104, the ds 1307
  Wire.send(0x00);             // resets ds1307 to beginning of its registers -could be in setup, 
                               //but this just makes sure that whenever you are going to do 
                               //a reading it is starting from the right point
  Wire.endTransmission();      // stop transmitting

  Wire.requestFrom(104, 7);    // request 7 bytes from slave ds1307, we'll assume it'll send them all
                               // even though it doesn't have to
  int second = Wire.receive();      //I have declared all these in here so that the
  int minute = Wire.receive();      //function is self contained
  int hour = Wire.receive();        //you could declare them at the top and then get at
  int day_of_week=Wire.receive();   //the bits individually elsewhere in the code
  int day = Wire.receive();         //but this could make the code less logical and
  int month = Wire.receive();       //more difficult to debug
  int year = Wire.receive();  

  // Convert all the BCD values that might have "tens" to decimal
  hour=hour/16* 10 + hour % 16;
  minute=minute/16 * 10 + minute % 16;
  second=(second/16 * 10 + second % 16)/2;         //USB drive only works to 2s accuracy 
                                                  // and takes number between 0 - 30
  day=day/16 * 10 + day % 16;
  month=month/16 * 10 + month % 16;
  year=20 + year/16 * 10 + year % 16;              //VDIP dates start 0=1980, rtc0=2000, so we need to add 20 first

// shift and or values to get one number in format needed for VDIP
// doing it in 2 chunks as ints were going wrong if shifted for upper
// values, and didn't want to make all the variables long in case space became an issue
// so create one unsigned long, shift the ints that need to go into the top half into 
// the lower half of it, and move them along inside the long var, then or it with the 
// lower half values

  unsigned long datecalc=(year<<9)|(month<<5)|(day);
  unsigned int lsdatecalc=(hour<<11)|(minute<<5)|(second);    
  datecalc=(datecalc<<16);
  datecalc=(datecalc)|(lsdatecalc);

   return datecalc;

} 

Now just add 3 lines to the if block that creates the file

if (incomingByte=='1'){
  dateStamp=dateStampForUSB();       //gets value for datestamp
  Serial.print("OPW LOG%");
  Serial.print(fileNumber);
  Serial.print(".TXT ");             //make sure there is a space at the end here
  Serial.print("0x");                //tells vdip it is a hex value
  Serial.print(dateStamp, HEX);      //sends datestamp as hex value                   
  Serial.print(13, BYTE);      

}

Hope this makes sense.

I may rewrite this as a single example that includes the datestamp stuff if people think that would be better, but thought I would get it up quick for now.

Cheers

Nick