USB Host Board – Flash Drive Software

 

This software download is for our USB Host Boards and chips. It allows you to connect a USB Flash Memory Stick to the Host Board and read/write files via a serial TTL interface or I2C. Ideal for data logging applications.

This is a free software download for our USB Host Board and USB Host IC’s (SOICDIPSSOP).

Please note: This software is free to download but only works on one of our USB boards or chips which must be bought separately.
To order, simply select which of our boards or IC products you wish to have the software loaded onto. See the USB Host Board and IC product pages for details onĀ pricingĀ and installing this software.

Features
  • Supports both the FAT16 and FAT32 file systems so can access large capacity memory sticks.
  • Does not support Long File Names
  • Serial TTL interface
  • Basic I2C interface
Serial TTL Interface

The flash drive can be accessed via a PC Terminal Program (serial TTL connection required) or directly from a Microcontroller using standard TTL Serial at the following baud rates

  • 2400
  • 4800
  • 9600
  • 14400
  • 19200
  • 38400
  • 57600
  • 115200

The following Commands are available.

All commands should be terminated with a carriage return character (ascii 13 or 0x0D)

<parameter>Required parameter (don’t enter the brackets) E.g. WRITE TEST.TXT
[option]Optional parameter (don’t enter the brackets) E.g. WRITE TEST.TXT B

COMMAND 
WRITE <file> [B]Create [file] from input. Type input (or send from microcontroller). Terminate data entry with Control-Z
Optional [B] Binary Mode (see below)
APPEND <file> [B]Append input to end of existing file. Type input (or send from microcontroller). Terminate data entry with Control-Z
Optional [B] Binary Mode (see below)
TYPE <file>Print contents of file, current dir only
READ <file> [LINENO]Print a single line of file, current dir only. Useful for reading a configuration file.
[LINENO] can be a number or the character ‘n’
Use the character ‘n’ to select the next line

Example

READ test.txt 1
READ test.txt n
READ test.txt n

This would read the first 3 lines of file test.txt

READ <file> [START] [LEN]Print a section of a file, current dir only. Useful when reading in a complete file, but splitting it into smaller chunks.
[START] is the start byte from the beginning of the file (starting at 0). It can also be the character ‘n’ which starts from the last read position.
[LEN] is the number of bytes to read

Example 1

READ test.txt 0 20
This would read the first 20 bytes of the file

Example 2

READ test.txt 0 20
READ test.txt n 20
This would read the first 20 bytes of the file, then the next 20 bytes (using n).

COPY <file1> <file2>Copy [file1] to [file2]
DEL <file>Delete file, current dir only
REN <file1> <file2>Rename [file1] to [file2]
SIZE <file> [BYTE|LINE]Return size of [file] in bytes or number of lines. The number of lines is useful when reading a configuration file.
DIR [/F] <filename>Display list of files matching filename. Filename can be left blank to display all files
E.g.

DIR *.TXT
2007-08-15 04:23:46             525 M1.TXT
2007-08-15 04:22:32             651 M2.TXT


The /F flag can be used to force only the filename to be printed
E.g.

DIR /F *.TXT
M1.TXT
M2.TXTR
CD <name>Change directory
MD <name>Make directory
RD <name>Remove directory
DATE [yyyy-mm-dd]Display or set the date
TIME [hh:mm:ss]Display or set the time (24 hr format)
BAUD <value>Set Serial Port Baud Rate (default 9600)
[2400|4800|9600|14400|19200|38400|57600|115200]
  
HELP or ?Display help
WHODisplay the VID and PID of the attached device. This is useful if you only want to read/write to a specific flash drive.

The follwing screen capture is the output from the HELP (?) command in terminal mode (see below)

Hobbytronics Flash Drive Explorer v1.17

  WRITE <file> [B]        - create [file] from input (B-Binary mode)
  APPEND <file> [B]       - append input to file (B-Binary mode)
  TYPE <file>             - print contents of file, current dir only
  READ <file> [LINENO|n]  - print single line of file, current dir only
  READ <file> [ST] [LEN]  - print bytes of file, from byte [ST] length [LEN]
  COPY <file1> <file2>    - copy [file1] to [file2]
  DEL <file>              - delete file, current dir only
  REN <file1> <file2>     - rename [file1] to [file2]
  SIZE <file> [BYTE|LINE] - Return size of [file] in bytes or num lines
  DIR [/F] <name>         - display directory/files
  CD <name>               - change directory
  MD <name>               - make directory
  RD <name>               - remove directory

  DATE [yyyy-mm-dd]       - display or set the date
  TIME [hh:mm:ss]         - display or set the time (24 hr format)
  BAUD <value>            - Set Serial Port Baud Rate
                            [2400|4800|9600|14400|19200|38400|57600|115200]
  I2C <value>             - Set I2C Address
   (41 )                    [1 - 127]
  HELP or ?               - display help
  WHO                     - display the VID and PID of the attached device

Connections required for Flash Drive

  • 5V power in
  • 0V
  • TX out
  • RX in
  • SS pin goes high when Flash drive inserted, low when removed

Real Time Clock

The USB Host Board has a real time clock on-board. When you have set the date and time the real time clock will keep track of the correct date and time. Files created will have the correct time and date stamp. The time and date can also be read in to your controller and then used in your output string.

The Real Time Clock is maintained by the main crystal oscillator and not by a dedicated watch crystal. It should be accurate to within a few seconds per day.

There is no battery backup for the clock. If you remove power to the Host board the clock will lose its settings.

Binary File Write Mode

In the default mode for writing to a file, we assume the file is text based and the file is closed by sending the Control-Z character.

In the optional Binary mode (V1.10+), any character can be sent and will be written to the file, including the Control-Z character; so we need a different method of closing the file write. This is done using the unused SDO (A)  pin on the board.

This pin is HIGH by default and should be briefly pulled LOW to terminate the file write.

Note: You can use the [B]inary method for normal text files as well as binary files.

Modes of Operation

There are two modes of operation for issuing commands and receiving responses

  1. Terminal Mode. Type as you would on your computer. All instructions and results are echoed back. This mode is best used when connected via a serial connection to a computer.
  2. Silent Mode. Designed for microcontroller applications. Silent mode is enabled by prefixing any command with a $ symbol. The command will not be echoed back, only the results (if any) returned

Silent mode is best explained with an example. Here we have an arduino sketch which sets the date and time and then writes to a file, all in silent mode. No data is echo’d back to the microcontroller.

/*
  USB HOST BOARD - Flash Drive Example
  
  Works with Arduino 1.0 and previous versions
  Basic use of Flash Drive in Silent Mode.
  Sets Date and Time and Creates a file ARDUINO.TXT
  Writes and Appends data to the file, then closes file.
  Prefix all commands with $ for silent mode

  Uses SoftwareSerial so as not to interfere with the Serial port
  
  Commands need a little time to be processed before the next command
  is sent, so we create a little function "flash_data" to save us
  having to do it each time 
 
 */
 
int i;
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX

// Create a printing function which has a built-in delay
void flash_data(char *pstring)
{
  mySerial.println(pstring); 
  delay(50); 
}  

void setup() 
{ 
  delay(2000);
  mySerial.begin(9600); 
  // Set the DATE and TIME 
  flash_data("$TIME 09:00:00"); 
  flash_data("$DATE 2012-01-01"); 

  // Create the file ARDUINO.TXT
  flash_data("$WRITE ARDUINO.TXT");   
  delay(1000);        // Needs extra time to create the file. 
                      // Depends on flash drive used
  
  // Write ten lines to the file
  for(i=0;i<10;i++)
  {
    flash_data("This is a test file");      
  }
  // Close the file by sending Control-Z (note the use of "print" not "println"
  #if ARDUINO >= 100
     mySerial.write(26);  // 26 is Control-Z character
  #else
     mySerial.print(26,BYTE);  // 26 is Control-Z character
  #endif  
  delay(500);              // Give time for the file to be saved and closed

  // Now re-open file and append data to it
  flash_data("$APPEND ARDUINO.TXT");   
  delay(1000);    
  
  // Write ten lines to the file  
  for(i=0;i<10;i++)
  {
    flash_data("Appended line to file.");      
  }
  #if ARDUINO >= 100
     mySerial.write(26);  // 26 is Control-Z character
  #else
     mySerial.print(26,BYTE);  // 26 is Control-Z character
  #endif   

} 

void loop() 
{ 

  // Nothing to do here

Here is another example program. It reads the number of lines in a files, then reads each line in one at a time. It uses software serial to talk to the USB Host board so that the file data can been seen on the Arduino Serial Monitor. This is useful for reading in data files or config files.

/* USB Host - Flash Drive software
   Demo Arduino sketch to show how to read number of lines in a file
   and to individually read each line.
   Useful for data or config files
   
   Hobbytronics Ltd 2013 (www.hobbytronics.co.uk)
*/   
#include <stdio.h>
#include <SoftwareSerial.h>
SoftwareSerial mySerial(2, 3); // RX, TX

int file_lines, i;
byte serial_char;
char filename[] = "1.txt";  // File name
char mystring[40];          // String to hold commands to be sent
void setup() {
  delay(2000);
  Serial.begin(9600);  
  mySerial.begin(9600);
  
  // Issue command to return number of lines in file
  // Note: Use silent mode ($) as we don't want the command echo'ed back
  sprintf(mystring,"$size %s line\r",filename);
  mySerial.write(mystring);  
  
  while(!mySerial.available());        // Wait for data to be returned
  
  // Number of lines in file returned as ascii chars, so convert to number
  file_lines = 0;  
  while (mySerial.available() > 0) {
     file_lines*=10;
     file_lines+=mySerial.parseInt();
  }  
  // Print filesize information
  sprintf(mystring,"Lines in file = %d",file_lines);  
  Serial.println(mystring);
  
  // Loop through each line
  for(i=1;i<=file_lines;i++){
    // Print line number we are reading
    sprintf(mystring,"Line %d = ",i);  
    Serial.print(mystring);     
   
    // send command to read specific line 
    sprintf(mystring,"$read %s %d\r",filename,i);  
    mySerial.write(mystring); 
    
    while(!mySerial.available());        // Wait for data to be returned
  
    // Read and display contents of line returned 
    while (mySerial.available() > 0) {
      Serial.write(mySerial.read());
    }  
  }  
  
}  
  
void loop(){
}  

I2C Interface

We have added basic read/write functionality using the I2C interface. This is still a work in progress but if you need to use an I2C interface rather than a serial connection then this section is for you. We shall describe the functionality then show an example program to show how it all works in practice.

As with most I2C devices, there are a number of ‘registers’ or commands that can be sent

// I2C Register Addresses
#define I2C_FILENAME        0
#define I2C_WRITE           1
#define I2C_APPEND          2
#define I2C_READ            3
#define I2C_READ_SETLINE    4
#define I2C_FLASH_READY     99

So, starting with I2C_FILENAME; we use this to transmit the filename to be used in the read/write operations. This only needs to be done once, unless you want to change the filename or if you are writing to one file, but reading from another.
The I2C_WRITE and I2C_APPEND commands do what they suggest, I2C_WRITE overwrites the file with data, while I2C_APPEND appends to the end of the file.

Now, read operations are trickier. Because flash drives can take some time to read the data, we can’t simply request some data and expect it to be returned in a timely fashion suitable for I2C communication. So we have split reading into 2 operations. First we tell the flash drive what data we want; then we wait for the flash drive to read the data, then retrieve the data and store it in a buffer. When the data is fully received the data can be read from the buffer.

The I2C_READ function returns a specified line of data from the file. This is generally more useful than simply reading x amount of characters, especially if you are reading from a configuration file for example. Lines must be terminated with a carriage return.
So to read a line from a file, we first use the I2C_READ_SETLINE function to tell the host board which line number we want, it can then fetch the data, and when ready we use the I2C_READ function to read the data.

The I2C_FLASH_READY command is used to determine whether the flash drive is available for read/write operation and is not currently busy.

The example Arduino program below shows how data can be written to and read from a Flash drive using the I2C interface.

Please note that the Arduino code library “Wire” limits the amount of data that can be send/received in one go to 32 bytes. This is defined in Wire.h with the line

#define BUFFER_LENGTH 32

You can change this value to allow more data to be written or read.

/*
** Wire Master for Hobbytronics USB Host Flash Drive
** Created 16 Oct 2014
**
** This example code is in the public domain.
** www.hobbytronics.co.uk
*/

#include <Wire.h>

// I2C Register Addresses
#define I2C_FILENAME		0
#define I2C_WRITE		1
#define I2C_APPEND		2
#define I2C_READ		3
#define I2C_READ_SETLINE	4
#define I2C_FLASH_READY		99

const char  flash_address=41;   // I2C Address

void setup()
{
  delay(2000);
  Serial.begin(9600);
  Wire.begin();              // join i2c bus (address optional for master) 
  
  flash_write(flash_address, I2C_FILENAME, "i2c.txt");
  flash_write(flash_address, I2C_WRITE, "Test File\r\n");  // Overwrite file
}

void loop()
{
  // In this loop we keep writing "Hello" to the file, and we read and print 
  // the first line which should be "Test File" 
  flash_write(flash_address, I2C_APPEND, "Hello\r\n"); // Append to file
  flash_read_line(flash_address, 1);             // read line 1 of the file
  delay(5000);                                   // Wait 5 seconds

}

// Check if flash drive is available (i.e. not currently reading/writing)
byte flash_ready(char host_address)
{
  byte f_ready;
  // This function reads one byte over I2C
  Wire.beginTransmission(host_address);
  Wire.write(I2C_FLASH_READY); 
  Wire.endTransmission(false);         // restart
  Wire.requestFrom(host_address, 1);   // Request the data...
  f_ready = Wire.read();
  if(f_ready==0) delay(20);            // A small delay before we try again
  return f_ready;
}

void flash_write(char host_address, char h_command, char *pstring)
{
    unsigned char i=0;
    
    while(!flash_ready(host_address));     // Wait until Flash drive is ready 
      
    Wire.beginTransmission(host_address);  // transmit to device
    Wire.write((byte) h_command);          // send command - WRITE or APPEND
    do{ 
        Wire.write((byte) pstring[i]);
        i++;
    } while(pstring[i]);    

    Wire.endTransmission(); 
}

void flash_read_line(char host_address, unsigned char line_num){
    // Read in a line from flash drive
    // This is a 2-stage process. First we tell the host board
    // which line number we want, so it has time to fetch the data
    // Next we request the data
    unsigned char i=0;
    
    while(!flash_ready(host_address));       // Wait until Flash drive is ready 
      
    Wire.beginTransmission(host_address);    // transmit to device
    Wire.write((byte) I2C_READ_SETLINE);     // send SETLINE command
    Wire.write((byte) line_num);             // send line number    
    Wire.endTransmission(); 

    // Wait until line is fetched from flash drive into buffer
    while(!flash_ready(host_address));       // Wait until Flash drive is ready     

    Wire.beginTransmission(host_address);    // transmit to device
    Wire.write((byte) I2C_READ);             // send READ command
    Wire.endTransmission(false);             // restart
    Wire.requestFrom(host_address, 255);     // request max 255 bytes from slave 
                                             // device (Arduino wont do this many)

    while(Wire.available())    // slave may send less than requested
    {
       char c = Wire.read();    // receive a byte as character
       if(c!='\0') Serial.print(c);         // print the character
    }
}
Shopping Basket
Scroll to Top