Checking If A MMC or SD Card Is Available
The following example checks to see if a MMC or SD card is available to use:-
//IS A FAT FORMATTED MMC/SD CARD INSERTED AND READY TO USE?
if (ffs_card_ok)
{
}
MMC / SD Card Operations
Below is a list of the available functions and a detailed description of each is provided later in this manual. The included sample projects contain examples of using many of the driver functions.
ffs_fopen
Opens a file for read and or write access.
ffs_fseek
Change the byte location in the file which the next read or write access will address.
ffs_fsetpos
An alternative to ffs_seek. The value used is intended to be file system specific and obtained using the ffs_getpos function. However as the type is recommended to be a long and this doesn’t provide enough space to store everything needed for the low level file position this function calls the ffs_fseek function.
ffs_ftell
Returns the current position within the file (the next byte that will be read or written).
ffs_fgetpos
An alternative to ffs_tell. The value returned is intended to be file system specific and only to be used with fsetpos. However as the position type is recommended to be a long and this doesn’t provide enough space to store everything needed for the low level file position this function calls the ffs_tell function.
ffs_rewind
The file byte pointer is set to the first byte of the file and the file access error flag is cleared if it has been set.
ffs_fputc or ffs_putc
Write byte to file
ffs_fgetc or ffs_getc
Read Byte From File
ffs_fputs or ffs_fputs_char
Writes a string to the file until a null termination is reached.
ffs_fgets
Reads characters from file and stores them into the specified buffer until a newline (\n) or EOF (end of file) character is read or (length – 1) characters have been read.
ffs_fwrite
Writes count number of items, each one with a size of size bytes, from the specified buffer.
ffs_fread
Reads count number of items each one with a size of size bytes from the file to the specified buffer.
ffs_fflush
Write any data that is currently held in microcontroller / processor ram that is waiting to be written to the card. Update the file filesize value if it has changed. This function does not need to be called by your application, but may be called if your application opens a file for a long period of time to avoid data loss if your device suddenly looses power.
ffs_fclose
Closes an open file, saving any unsaved data to the card and updating the file filesize value if it has changed.
ffs_remove
Delete file
ffs_rename
Rename file
ffs_clearerr
Clear Error & End Of File Flags
ffs_feof
Has End Of File Been Reached
ffs_ferror
Has An Error Occurred During File Access
ffs_is_card_available
Is A Card Inserted and Available
ffs_change_file_size
Fast method to increase or decrease a files size.
Characters That May Be Used In DOS Compatible File Names
Upper case letters A-Z (lowercase will be modified to uppercase).
Numbers 0-9
Space (though trailing spaces are considered to be padding and not a part of the file name)
! # $ % & ( ) – @ ^ _ ` { } ~ ‘
Values 128-255
Partitions
This driver does not support multiple partitions. It will access the first partition of a MMC or SD card. Other partitions will not be damaged, but they cannot be accessed.
Working With Multiple Files
You are able to open multiple files at the same time and perform any operation on any of these files at any time. However all read and write operations involve reading a complete 512 byte block of data from the MMC or SD card and storing the complete block back to the card if any of the data has been modified before moving onto another block of data. The driver deals with this block requirement in an intelligent way, only reading and writing a block when it has to. If working on more than one file best speed will be achieved by working on one file as much as possible before working on another file. This is because each time you swap to a different file the driver has to save or dump the block of data currently being written or read and then load the data block being written or read for the other file. Therefore if doing an operation such as copying data from one file to another try and copy as much data as possible to processor ram before starting writing it to the other file. You don’t have to, but doing this will significantly increase the speed of your application.
Ensure Data Is Saved For Write Operations
Files may be opened and kept open indefinitely. However you should try and carry out file write operations in one process and close the file again when it is not required in case your product should loose power. If power is lost while a file is open the file will always remain usable, but any data that has been written since the last close of the file may be lost, as the current file size value may not have been written back to directory entry for the file. Whilst the data may have already been stored to the MMC or SD card, without the file size value the next time the file is accessed by the driver or another device the data will effectively not exist and the sectors that contain it will be lost on the card (until it is formatted or a disk repair utility is run). In theory the file size value could be updated every time a new block of data is written to the card, however the driver does not do this as it would significantly slow down bulk write operations. If you need to keep a file open for a long period of time then you should periodically call the ffs_fflush function to ensure that the most recent data is saved.
Reading & Writing A Text File
.txt files are as simple as it gets. They are simply comprised of ASCII bytes with a CR (carriage return) & LF (line feed) character at the end of each line of text.
In addition to being a great way of storing and retrieving configuration and operating data for your project, writing text files can be a really useful way of debugging complex problems with an application, by being able to write large quantities of text and then analysing this with any standard text application on a PC. In addition, if your designing a product that may experience problems in certain installations it is typically quite a simple matter to write some code to provide logging of the products operation, such as communications sent and received, to a .txt file on a MMC or SD card which a user can then email you for remote analysis.
Reading & Writing A Spreadsheet File
.csv files are a great way of reading and writing spreadsheet data. They are exactly the same as a text file, except that the comma ‘,’ character is used to mark moving on to the next column. Every time the CF and LF characters are used the next row is started.
.csv files may be directly read and written by Microsoft Excel™.
Fast Reading Of Bulk File Data
The ANSI-C fread function is provided to allow blocks of data to be read but this can be too slow for some applications. This is because of the overhead the C library functions require which is fine and very useful on systems with enough processor power so it doesn’t notice, but can waste huge amounts of clock cycles in speed sensitive embedded applications. The following is a simple method that will allow complete sectors (512 bytes) to be read as a data block, used by your application as required and then the next sector read.
Open a file for reading using fopen as normal and then use the fgetc function to read the first byte (you must start this from the first byte of the file). In reading the first byte the driver will actually read the first sector of file data into the drivers sector buffer FFS_DRIVER_GEN_512_BYTE_BUFFER. Subsequent calls to the fgetc or other read functions will simply read data from this buffer without accessing the card, but with all of the background checks the driver has to do for each byte read. Instead you can simply access the buffer directly in your application. When you are ready to read the next sector do the following:-
your_file_name->current_byte_within_file += 511;
your_file_name->current_byte += 511;
That’s it. In modifying the 2 above values you reposition the drivers internal processes into thinking that it last accessed the last byte in the current sector. To load the next sector call the fgetc function again and repeat the process. When using this method just bear in mind that you will need to detect the end of file yourself as the last sector read for a file will contain unused data bytes unless the file size is an exact multiple of 512 bytes.
An example:
our_file_1 = ffs_fopen(filename_test_txt, read_access_mode);
while( ) //Repeat this as many times as you wish
{
i_temp = ffs_fgetc(our_file_1);
//The FFS_DRIVER_GEN_512_BYTE_BUFFER has been loaded with
//the next 512 bytes which you can now read directly from
// the buffer without calling any ffs functions.
//Then do this:
our_file_1->current_byte_within_file += 511;
our_file_1->current_byte += 511;
}
//This example doesn’t check for file end – remember to check for this if you need to
Fast Writing Of Bulk File Data
This can be achieved in the same was as fast reading of bulk data above. Use the fputc function to write the first byte of a new sector (you must start this from the first byte of a new file). Then write the rest of the data directly to the buffer. When you are ready to write the next sector do the following:-
your_file_name->current_byte_within_file += 511;
your_file_name->current_byte += 511;
your_file_name->file_size += 511;
In modifying the 3 above values you reposition the drivers internal processes into thinking that it last wrote to the last byte in the current sector. To write the next sector call the fputc function again and repeat the process.
An example:
our_file_1 = ffs_fopen(filename_test_txt, write_access_mode);
while( ) //Repeat this as many times as you wish
{
ffs_fputc((int)b_temp, our_file_1);
//The FFS_DRIVER_GEN_512_BYTE_BUFFER has been prepared for
//a write of 511 further bytes which you can now write
//directly to the buffer without calling any ffs functions.
//Then do this:
our_file_1->current_byte_within_file += 511;
our_file_1->current_byte += 511;
our_file_1->file_size += 511;
}
//This example doesn’t check for a file write error – remember to do this if you wish to check for errors
N.B. For even faster writing of large quantities of data it may be helpful to combine this technique with the use of the ffs_change_file_size function (see the ffs_change_file_size section of this manual for details).
Using MMC or SD Cards For Firmware Updates
A MMC or SD card may be used to allow new firmware files to be read off a card and programmed into your devices memory. You could use a standard raw .hex format or your own encrypted format. Remember that if reading the file directly off the card and into program memory you will need to allow sufficient boot loader program memory space for the MMC / SD card driver. If space is at a premium the driver could be ‘hacked’ down to the bare bones of just reading files with no writing or file re-positioning capabilities to reduce its size.
Deleting Files
Deleting a single file
const char filename_1[] = {"test.txt"};
ffs_remove(filename_1);
Deleting all files in the root directory:-
const char filename_all[] = {"*.*"};
while (ffs_remove(filename_all) == 0)
;
Searching In The Directory
There is no function that directly provides this, as its not provided by the standard ANSI-C functions. However, a relatively simple way of achieving this is to add a global variable to the driver that is usually zero, or add an additional variable to the ffs_find_file function declaration. In the ffs_find_file function use this variable so that if it is greater than zero the function does not return when it finds a matching file, but instead decrements the value and looks for the next match. When used with wildcard characters in the file name this allows you to find each matching file in turn, by setting the variable to zero and then every time the function returns with a cluster number for a match you set it to the last value +1, continuing until the functions returns with the not found value.


