|
COMPACTFLASH MEMORY CARD
FAT16 / FAT32 DRIVER
TECHNICAL MANUAL
V1.02
|


Index. 2
CompactFlash Memory Cards & FAT Filing System.. 5
CompactFlash Memory Card FAT16/ FAT32 Driver 6
Introduction. 6
Features. 6
Driver Technical Overview. 7
Specifications. 7
Code Size. 7
Variables Memory Space. 7
CompactFlash Card Mode. 8
Files Included In The Project 8
Driver Source Code Files. 8
Sample Project Source Code Files. 8
Notes About Our Source Code Files. 8
How We Organise Our Project Files. 8
Modifying Our Project Files. 9
The Driver Functions & Defines. 9
Pin Defines. 9
512 Byte Buffer Define. 10
Bus Access Delay Defines. 10
Watchdog Timer Define. 10
User Options. 10
Standard Type And Function Names. 10
Open File. 11
Move File Byte Pointer 11
Get The Current Position In The File. 12
Set File Byte Pointer To Start Of File. 12
Write Byte To File. 12
Read Byte From File. 12
Write String To File. 12
Read String From File. 13
Write Data Block To File. 13
Read Data Block From File. 13
Store Any Unwritten Data To The Card. 13
Close File. 13
Delete File. 14
Rename File. 14
Clear Error & End Of File Flags. 14
Has End Of File Been Reached. 14
Has An Error Occurred During File Access. 14
Is A Compact Flash Card Inserted And Available. 14
Do Background Tasks. 14
The Driver Sub Functions. 14
Find File. 14
Convert File Name To Dos Filename. 15
Read Next Directory Entry. 15
Overwrite The Last Directory File Name. 15
Get The Start Cluster Number For A File. 16
Create A New File. 16
Find Next Free Cluster In FAT Table. 16
Get Next Cluster Value From FAT Table. 16
Modify Cluster Value In FAT Table. 16
Read Sector To Buffer 16
Write Sector From Buffer 16
Is CompactFlash Card Present 16
Set CompactFlash Card Reset Pin. 17
Set CompactFlash Card Address. 17
Write Byte To CompactFlash Card. 17
Read Word From CompactFlash Card. 17
Read Byte From CompactFlash Card. 17
Using The Driver In A Project 18
General Requirements. 18
Checking If A CompactFlash Card Is Available. 18
CompactFlash Card Operations. 18
Characters That May Be Used In DOS Compatible File Names. 18
Directories. 18
Partitions. 18
Long Filenames. 18
Working With Multiple Files. 18
Ensure Data Is Saved For Write Operations. 19
Reading & Writing A Text File. 19
Reading & Writing A Spreadsheet File. 19
Fast Reading Of Bulk File Data. 19
Fast Writing Of Bulk File Data. 20
Using CompactFlash Cards For Firmware Updates. 20
Deleting Files. 20
Searching In The Directory. 20
Disk Viewing & Editing Utilities. 20
CompactFlash And FAT Licensing. 20
Additional Information. 21
What is CompactFlash, CF Type I, CF Type II and CF I/O?. 21
Where can I get a free copy of the CompactFlash
Specification?. 21
Sample Project 21
Troubleshooting. 21
Project PCB Module. 23
Features. 23
PIC Microcontroller 23
Disabling The PIC Microcontroller 24
RS232 Port 24
RS422 / RS485 Port 24
I2C Port 24
DC Power 25
Voltage Regulator 25
Switches. 25
LEDs. 25
Stripboard Prototyping Area. 25
PIC Microcontroller Spare Pins. 25
D Connector Spare Pins. 25
Development Connection Header 25
Running Current 25
Enclosure. 25
Layout Of A CompactFlash Card With FAT. 26
Terms used for hard disks and therefore CompactFlash
memory cards. 26
Byte Ordering. 27
Disk Information Block. 27
The Layout of a FAT16 Volume. 28
The Layout of a FAT32 Volume. 29
CompactFlash Identify Drive Instruction. 30
The Master Boot Record. 32
The Boot Record. 34
The FAT Tables. 36
FAT16 FAT Table. 36
FAT32 FAT Table. 37
Location & Size. 37
Root Directory & Other Directories. 38
Special Markers. 38
Location & Size. 39
Date and Time Formats. 39
Data Area. 39
Start Address. 39
FAT32 File System Information Sector 40
Support 41
Revision History. 42
CompactFlash memory cards provide embedded
devices with a very inexpensive and convenient way of storing anything from
very small to very large amounts of data. Applications are endless and may
include devices that use CompactFlash cards to store their own data, or to
exchange data between other embedded devices or to exchange data between
embedded devices and a PC.
Mechanically CompactFlash cards are small,
but with enough size to provide very large capacities at low cost. They are
low power and may be used with both 3V3 (+-5%) or 5V (+-10%) systems with no
requirements for external power switching or interface circuitry (just power
the card with either voltage). They use a parallel interface to allow fast
data transfers with relatively few additional control connections required. Data
reliability is also provided by built-in dynamic defect management and error
correction technologies.
At the simplest level a CompactFlash card
is just a large memory array which may be used in a similar way to a standard
parallel memory IC. Very simple applications may just use a CompactFlash card
like any other memory device, storing data on it as required by the
application. However this has the obvious limitation that the contents of the
card is only readable and writable by the device that is using it. To allow
other devices to easily read and write data to the card requires the use of a
standardised file system. If a filing system is chosen that is also used by
PC’s then sharing data with PC applications is made very simple.
There are 3 flavours of FAT (File
Allocation Table):- FAT12, FAT16 and FAT32. FAT12 has now effectively become
obsolete as the very small memory sizes of card this was useful for (<=16MB)
are no longer generally available. This leaves FAT16 and FAT32. The 16 and 32
simply refer to the size of the cluster value in bits, although FAT32 is
actually only 28 bits as 4 bits are reserved (see below for an explanation of
clusters etc). This simply means that a FAT32 table takes up more space on a
disk (or memory card), as each entry uses more bytes, but it allows addressing
of larger memory sizes with smaller cluster sizes, resulting in less wastage of
disk space. This use of smaller cluster sizes can quickly pay off in terms of
efficiency as less space wastage at the end of each file frees up more space
than the larger FAT32 table uses up.
Limits of FAT16
Maximum volume size is 2GB
Maximum file size is 2GB
Maximum number of files is
65,517
Maximum of 512
files or folders per folder
Limits of FAT32
Maximum volume
size is 2TB
Maximum file size is 4GB
Maximum number of files is
268,435,437
Maximum of
65,534 files or folders per folder
You may think that you don’t need anything
more than FAT16 for your application if you don’t plan to store more than 2GB
of data on a CompactFlash card. After all, many embedded applications only need
to store relatively small amounts of data. However CompactFlash cards with
capacities greater than 256MB are typically supplied pre-formatted with FAT32.
Also Windows XP will typically format a CompactFlash card with a capacity
greater than 32MB as FAT32 by default. This is because FAT32 uses larger
volumes more efficiently than FAT16 and is also less susceptible to a single
point of failure due to the use of a backup copy of critical data structures in
the boot record. Therefore if you use a driver that only supports FAT16 for
your application your users will need to find a PC with a CompactFlash adaptor
to re-format larger capacity cards to be FAT16 before they can be used with
your device. You also run the risk of increased technical support demands from
users who haven’t read your instructions or don't understand how to format a
card as FAT16 instead of the default FAT32 and can’t work out why their new
CompactFlash card won’t work in your device. Using a driver that supports
FAT16 and FAT32 doesn't result in a large amount of additional code space by
today’s standards, as the two systems are very similar, and it makes life a lot
easier for you and your users.
See the ‘Layout Of A Compact Flash Card
With FAT’ section later in this manual for detailed information of the FAT16
and FAT32 filing system.
Using a CompactFlash card in your embedded
device with the FAT filing system allows you to very easily read and write
multiple files and exchange this data with other embedded devices and PC’s.
Apart from the convenience of such a powerful and flexible filing system, being
able to read and write PC compatible files can add huge benefits to your
product. However writing a CompactFlash FAT filing system driver is a complex
and daunting task. This driver removes that complexity for you and allows you
to read and write files with ease.
This driver has been specifically designed
from the ground up for embedded applications using 8, 16 or 32 bit processors
or microcontrollers. Whilst the code has been kept as small as possible, it
hasn’t been reduced to such a point that the driver becomes difficult to use.
Instead great importance has been put on being able to use as many of the
standard ANSI-C file system functions as possible and with as many of each of
their features as possible.
The CompactFlash card FAT16 / FAT32 driver
code has been designed and tested using the Microchip MPLAB C18 ANSI compliant
C complier for the Microchip PIC18 8bit series of microcontrollers. Using the
driver with other ANSI compliant C compliers and with other processors /
microcontrollers should not present significant problems, but you should ensure
that you have sufficient programming expertise to carry out any modifications
that may be required to the source code. Embedded-code.com source code is
written to be very easy to understand by programmers of all levels. The code
is very highly commented with no lazy programming techniques. All function,
variable and constant names are fully descriptive to help you modify and expand
the code with ease.
The CompactFlash card FAT16 / FAT32 driver
and associated files are provided under a licence agreement. Please see
www.embedded-code.com\licence.php for
full details.
The remainder of this manual provides a
wealth of technical information about the driver as well as useful guides to
get you going. We welcome any feedback on this manual and the driver.
As with any development project you
should ensure that backup copies are made of any files stored on a CompactFlash
card that is used with the driver until you have completed your development and
thoroughly tested the operation of the driver in your application.
Designed for both FAT16 and FAT32 formatted
CompactFlash cards with an 8bit hardware interface to a microcontroller or
processor.
Optimised for embedded designs. Only a
single 512 data buffer is required for all operations. (It is not possible to
write to CompactFlash cards without a 512 byte buffer as sectors have to be
read to local memory, modified and written back as a whole).
Intelligent use of the local ram sector
buffer. Read and writes of sector data only occur when necessary, avoiding
unnecessary and slow repeated read or write operations to the CompactFlash
card.
Optimised file delete function for fast deleting
of large files. Instead of altering each FAT table entry one at a time, a
complete sector of FAT table entries are altered in one operation before
writing back to the card, resulting in a large speed improvement.
Provides the following standard ANSI-C functions:
fopen, fseek,
ftell, fgetpos, fsetpos, ffs_rewind, fputc, putc, fgetc, getc, fputs, fgets,
fwrite, fread, fflush, fclose, remove, rename, clearer, feof and ferror
Standard DOS ‘*’ and ‘?’ wildcard
characters may be used in file operations.
Multiple files may be opened at the same
time.
The data area of CompactFlash memory cards
is accessed through the use of a 512 byte sector buffer. (Actually this buffer
may be less than 512 bytes and this is supported by the driver, but it is very
unlikely you will come across a card that doesn’t have 512 bytes per sector).
All data read and write operations work through the reading and writing a 512
byte block of sector data. Therefore to modify a single byte, a complete sector
of data must be read to local ram, modified and then the complete sector
written back to the card.
|
Other flash memory devices, such as flash
memory IC’s also basically use the same system whereby a complete block of
data must be erased to reset all of the bytes in that block back to 0xFF
ready for writing again, as typically flash memory can only write by turning
high bits to low, not low to high).
|
This 512 byte buffer is an issue when it
comes to designing a driver to provide fast read and write access. The reason
is that as a programmer you want to be able to access individual bytes of a
file without worrying about sectors, but you don’t want the driver continuously
reading and writing 512 bytes of data every time you modify a byte, resulting in
painfully slow access. This driver overcomes these problems by only reading
and writing when an operation needs to access a byte that is contained in a
different sector on the card. Whilst this requires some instances of quite complex
driver code, this complexity is worthwhile due to the massive speed
improvements this approach provides.
If you want to gain an understanding of
exactly how the driver works then this manual contains a thorough description
of the layout of FAT based CompactFlash cards. Once you understand this each
of the driver functions are relatively easy to understand. However you don’t
need to do this and if you just want to read and write FAT16 or FAT32
CompactFlash cards then you can skip these in-depth parts of the manual.
Finally you should also note that different
CompactFlash memory cards can take different amounts of time to complete
internal operations, such as preparing to read or writing a new sector of
data. If your application is very time sensitive you may need to consider
using some processor RAM memory to act as some sort of FIFO buffer for read and
write operations. For example say you are designing a MP3 player that needs to
send MP3 file data to a MP3 decoder IC within a certain response time when it
requests it. You may find that a slow CompactFlash card might not be able to
provide the next byte of data fast enough when it moves from one sector to the
next, resulting in your MP3 decoder IC temporarily running out of data. By
using some form of circular FIFO RAM buffer in your application you could read
data from the CompactFlash as one process, always trying to fill the data
buffer so its full, and read data from the buffer to send to the MP3 decoder IC
when it requests it as a separate interrupt based process.
Approximately 13460
program memory words (16 bit) compiling just the driver functions with the
Microchip C18 compiler for a PIC18F4620 with all optimisations turned off.
This may vary depending on your compiler etc.
Approximately 9080
program memory words (16 bit) compiling the complete PIC18 project PCB sample
project (including the driver) using the Microchip C18 compiler with all
optimisations turned on.
Approximately
566 bytes of static RAM. This includes a continuous 512 byte buffer that is
required by the driver (it is possible to share this buffer with other parts of
an application – see the 512 Byte Buffer Define section of this manual).
An additional 22
bytes of static RAM are required for each file that may be opened
simultaneously (set by the FFS_FOPEN_MAX define).
The driver
requires a moderate amount of variable storage space from the stack for its
functions.
The driver
accesses a CompactFlash card in common memory mode (not IDE mode).
The driver source code files:
mem-ffs.c The
FAT16/32 file system driver functions
mem-ffs.h
mem-cf.c The
lower level CompactFlash card driver functions
mem-cf.h
The sample project source code files, with
a few basic functions ready for you to try and modify as required:
ap-main.c
ap-main.h
The embedded-code.com generic global file
main.h
The Microchip MPLAB C18 compiler project
files
cf_demo.cod
cf_demo.cof
cf_demo.hex (The executable code which may be
imported into MPLAB and programmed into the PIC without needing to open the
whole project, if desired)
cf_demo.lst
cf_demo.map
cf_demo.mcp
cf_demo.mcw
cf_demo.mptags
cf_demo.tagsrc
untitled.mcw
18f4620i-ffs.lkr (A
modified version off the microchip standard linker script for the PIC18F4620)
There are many different ways to organise
your source code and many different opinions on the best method! We have
chosen the following as a very good approach that is widely used, well suited
to both small and large projects and simple to follow.
Each .c source code file has a matching .h
header file. All function and memory definitions are made in the header file.
The .c source code file only contains functions. The header file is separated
into distinct sections to make it easy to find things you are looking for. The
function and data memory definition sections are split up to allow the defining
of local (this source code file only) and global (all source code files that
include this header file) functions and variables. To use a function or
variable from another .c source code file simply include the .h header file.
Variable types BYTE, WORD, SIGNED_WORD,
DWORD, SIGNED_DWORD are used to allow easy compatibility with other compilers.
Our projects include a ‘main.h’ global header file which is included in every
.c source code file. This file contains the typedef statements mapping these
variable types to the compiler specific types. You may prefer to use an
alternative method in which case you should modify as required. Our main.h
header file also includes project wide global defines.
This is much easier to see in use than to
try and explain and a quick look through the included sample project will show
you by example.
Please also refer to the resources section
of the embedded-code.com web site for additional documentation which may be
useful to you.
We may issue new versions of our source
code files from time to time due to improved functionality, bug fixes,
additional device / compiler support, etc. Where possible you should try not
to modify our source codes files and instead call the driver functions from
other files in your application. Where you need to alter the source code it is
a good idea to consider marking areas you have changed with some form of
comment marker so that if you need to use an upgraded driver file its as easy
as possible to upgrade and still include all of the additions and changes that
you have made.
FFS_DATA_BUS_IP CompactFlash D7:0 data bus read
register
FFS_DATA_BUS_OP CompactFlash D7:0 data bus write
register (same as read register if your microcontroller / processor doesn't
have separate registers for input and output)
FFS_DATA_BUS_TO_INPUTS Set the data bus pins to inputs
FFS_DATA_BUS_TO_OUTPUTS Set the data bus pins to outputs
FFS_CE The CompactFlash Chip
Enable pin (output)
FFS_WE The CompactFlash
Write Enable pin (output)
FFS_OE The CompactFlash
Output Enable pin (output)
FFS_REG The CompactFlash
Register pin (output)
FFS_RDY The CompactFlash Ready
pin (input)
FFS_WAIT The CompactFlash Wait
pin (input)
The CompactFlash address pins are assigned
using several defines to make it easy to use direct microcontroller / processor
pins or an external latch IC:-
FFS_ADDRESS_REGISTER The register that should be updated when
changing an address pin state (e.g. the port register, or a ram register that
gets written to a latch IC).
FFS_ADDRESS_BIT_0 The bit of the register that is
CompactFlash address pin 0 (must be one of 0x80, 0x40, 0x20, 0x10, 0x08, 0x04,
0x02 or 0x01).
FFS_ADDRESS_BIT_1 The bit of the register that is
CompactFlash address pin 1.
FFS_ADDRESS_BIT_2 The bit of the register that is
CompactFlash address pin 2.
FFS_ADDRESS_FUNCTION Optional function to call to output the FFS_ADDRESS_REGISTER. Just comment this out if its not required (i.e. if your not using
an external latch IC).
The CompactFlash reset pin is assigned
using several defines to make it easy to use a direct microcontroller /
processor pin or an external latch IC:-
FFS_RESET_PIN_REGISTER The register that should be updated when changing the
reset pin state (e.g. the port register, or a ram register that gets written to
a latch IC).
FFS_RESET_PIN_BIT The bit of the register that is reset pin
(must be one of 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02 or 0x01).
FFS_RESET_PIN_FUNCTION Optional function to call to output the FFS_RESET_PIN_REGISTER. Just comment this out if its not required (i.e. if your not using
an external latch IC).
The CompactFlash card detect pin is
assigned using several defines to make it easy to use a direct microcontroller
/ processor pin or an external input buffer IC:-
FFS_CD_PIN_REGISTER The register that should be read when reading
the card detect pin state (e.g. the port register, or a ram register that gets
read from a buffer IC).
FFS_CD_PIN_BIT The bit of the register that is card
detect pin (must be one of 0x80, 0x40, 0x20, 0x10, 0x08, 0x04, 0x02 or 0x01).
FFS_CD_PIN_FUNCTION Optional function to call to read the FFS_CD_PIN_REGISTER. Just comment this out if its not required (i.e. if your not using
an external buffer IC).
FFS_DRIVER_GEN_512_BYTE_BUFFER The microcontroller / processor ram buffer that is used to buffer
a complete sector of CompactFlash data. A define is used as some compilers may
have special requirements to create a large data buffer. The driver only
accesses the buffer using pointers, in case your compiler requires this. This
buffer may also be shared with other functions in your application if you call
the ffs_fflush() function for each open file and set ffs_buffer_contains_lba = 0xFFFFFFFF first.
FFS_DELAY_FOR_WAIT_SIGNAL() Needs to be minimum 35nS. Use one or more null instructions
to provide the required delay based on your processor speed. This define may also
have additional null instructions to allow data bus signals to stabilise during
read or write access. 2 layer PCB’s (no ground plane) and PCB’s with long
track lengths are more likely to require this. If you are experiencing read or
write problems try using this define to give a reasonable delay and then drop
it later once all is working.
FFS_DELAY_FOR_RDY_SIGNAL() Needs to be minimum 400nS. Use one or more null
instructions to provide the required delay based on your processor speed.
CLEAR_WATCHDOG_TIMER Use this if you have a watchdog
timer that needs to be reset for operations that can take a long time. Just
comment this out if its not required.
FFS_FOPEN_MAX The maximum number of files that
may be opened simultaneously (1 - 254). 22 bytes of memory are required per
file.
For ease of interoperability this driver
uses modified version of the standard ANSI-C function names and FILE data types.
To avoid conflicting with your compilers stdio.h definitions you can comment
out this section and use the modified ffs_ (flash filing system) names in your
code. If you want to use the ANSI-C standard names then un-comment this
section:-
#define fopen ffs_fopen
#define fseek ffs_fseek
#define ftell ffs_ftell
#define fgetpos ffs_fgetpos
#define fsetpos ffs_fsetpos
#define rewind ffs_rewind
#define fputc ffs_fputc
#define fgetc ffs_fgetc
#define fputs ffs_fputs
#define fgets ffs_fgets
#define fwrite ffs_fwrite
#define fread ffs_fread
#define fflush ffs_fflush
#define fclose ffs_fclose
#define remove ffs_remove
#define rename ffs_rename
#define clearerr ffs_clearerr
#define feof ffs_feof
#define ferror ffs_ferror
#define putc ffs_putc
#define getc ffs_getc
#define EOF FFS_EOF
#define SEEK_SET FFS_SEEK_SET
#define SEEK_CUR FFS_SEEK_CUR
#define SEEK_END FFS_SEEK_END
FFS_FILE*
ffs_fopen (const char *filename, const char *access_mode)
This function opens
a file for read and or write access.
For ease of use
this driver does not differentiate between text and binary mode. You may open
a file in either mode (or neither) and all file operations will be exactly the
same (basically is if the file was opened in binary mode. LF characters will
not be converted to a pair CRLF characters and vice versa. This makes using
functions like fseek much simpler and avoids operating system difference
issues. (If you are not aware there is no difference between a binary file and
a text file – the difference is in how the operating system chooses to handle
text files)
filename Only
8 character DOS compatible root directory filenames are allowed. Format is F.E
where F may be between 1 and 8 characters and E may be between 1 and 3
characters, null terminated, non-case sensitive. The '*' and '?' wildcard
characters may be used.
access_mode "r" Open
a file for reading. The file must exist.
"r+" Open a file for reading and writing. The file
must exist.
"w" Create an empty file for writing. If a file with
the same name already exists its content is erased.
"w+" Create an empty file for writing and reading. If
a file with the same name already exists its content is erased before it is
opened.
"a" Append to a file. Write operations append data
at the end of the file. The file is created if it doesn't exist.
"a+" Open a file for reading and appending. All
writing operations are done at the end of the file protecting the previous
content from being overwritten. You can reposition (fseek) the pointer to
anywhere in the file for reading, but writing operations will move back to the
end of file. The file is created if it doesn't exist.
Return value. If the file has been
successfully opened the function will return a pointer to the file. Otherwise a
null pointer is returned (0x00).
int
ffs_fseek (FFS_FILE *file_pointer, long offset, int origin)
This function
allows you to change the byte location in the file which the next read or write
access will address. The function is quite complex as it looks to see if the
new location is in the same cluster as the current location to avoid having to
read all of the FAT table entries for the file from the file start where
possible, which results in a large speed improvement.
file_pointer Pointer
to the open file to use.
origin The
initial position from where the offset is applied
FFS_SEEK_SET (0) Beginning of file
FFS_SEEK_CUR (1) Current position of the file pointer
FFS_SEEK_END
(2) End of file
offset Signed
offset from the position set by origin
returns 0
if successful, 1 otherwise
int
ffs_fsetpos (FFS_FILE *file_pointer, long *position)
This function is
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.
long
ffs_ftell (FFS_FILE *file_pointer)
This function
returns the current position within the file (the next byte that will be read
or written).
int
ffs_fgetpos (FFS_FILE *file_pointer, long *position)
This function is
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.
Returns 0
if successful, 1 otherwise
void
ffs_rewind (FFS_FILE *file_pointer)
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.
file_pointer Pointer
to the open file to use.
int
ffs_fputc (int data, FFS_FILE *file_pointer)
or
ffs_putc(int
data, FFS_FILE *file_pointer)
file_pointer Pointer
to the open file to use.
data The
data byte to write which is converted to a byte before writing (the int type is
specified by ANSI-C)
Returns If there are no errors
the written character is returned. If an error occurs FFS_EOF is returned.
int
ffs_fgetc (FFS_FILE *file_pointer)
or
int ffs_getc
(FFS_FILE *file_pointer)
file_pointer Pointer
to the open file to use.
Returns The byte read is
returned as an int value (int type is specified by ANSI-C). If the End Of File
has been reached or there has been an error reading FFS_EOF is returned.
int
ffs_fputs (const char *string, FFS_FILE *file_pointer)
or
int
ffs_fputs_char (char *string, FFS_FILE *file_pointer)
This function writes
a string to the file until a null termination is reached. The null termination
is not written to the file. If a new line character (\n) is required it should
be included at the end of the string
The alternative ffs_fputs_char function is not part of the ANSI-C standard but may be needed writing
a string from ram with compilers that won't deal with converting the ram string
to a constant string.
Returns Non-negative
value if successful. If an error occurs FFS_EOF is returned.
char*
ffs_fgets (char *string, int length, FFS_FILE *file_pointer)
This function reads
characters from file and stores them into the specified buffer until a newline
(\n) or EOF character is read or (length - 1) characters have been read. A newline
character (\n) is not discarded. A null termination is added to the string
Returns Pointer to the buffer if
successful. A null pointer (0x00) if there is an error of the end-of-file is
reached (use ffs_ferror or ffs_feof to check what happened).
int
ffs_fwrite (const void *buffer, int size, int count, FFS_FILE *file_pointer)
Writes count
number of items, each one with a size of size bytes, from the
specified buffer.
No translation
occurs for files opened in text mode. The total number of bytes to be written
is (size x count).
Returns The number of full items
(not bytes) successfully written. This may be less than the requested number if
an error occurred.
(For a very
fast method of reading complete sectors at a time see the ‘Using The Driver In
A Project’ section later in this manual).
int
ffs_fread (void *buffer, int size, int count, FFS_FILE *file_pointer)
Reads count
number of items each one with a size of size bytes from the
file to the specified buffer.
Total amount of
bytes read is (size x count).
Returns The number of items (not
bytes) read is returned. If this number differs from the requested amount (count) an
error has occurred or the End Of File has been reached (use ffs_ferror or
ffs_feof to check what happened).
int ffs_fflush (FFS_FILE *file_pointer)
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.
Returns 0
if successful, 1 otherwise
int
ffs_fclose (FFS_FILE *file_pointer)
Closes an open
file, saving any unsaved data to the card and updating the file filesize value
if it has changed.
Returns 0
if successful, 1 otherwise
int
ffs_remove (const char *filename)
This function is
optimised to avoid unnecessary read and writes of the FAT table to greatly
improve its speed.
Returns 0 if the file is successfully
deleted, 1 if there was an error (the file doesn't exist or can't be deleted
as its currently open.
int
ffs_rename (const char *old_filename, const char *new_filename)
Return value 0 if the file is successfully
renamed, 1 if there was and error (the file doesn't exist or can't be renamed
as its currently open)
void
ffs_clearerr (FFS_FILE *file_pointer)
int
ffs_feof (FFS_FILE *file_pointer)
int
ffs_ferror (FFS_FILE *file_pointer)
BYTE
ffs_is_card_available (void)
void
ffs_process (void)
This function
needs to be called regularly from your applications main loop to detect a new
card being inserted so that it can be initialised ready for access.
These functions are used by the driver but
should not be used by your application.
DWORD
ffs_find_file (const char *filename, DWORD *file_size, BYTE *attribute_byte,
DWORD *directory_entry_sector,
BYTE *directory_entry_within_sector,
BYTE *read_file_name, BYTE
*read_file_extension)
This function
searches for a specified filename. If wildcard characters are used then the
first file that matches with the standard and wildcard characters will be
found.
filename Only
8 character DOS compatible root directory filenames are allowed. Format is F.E
where F may be between 1 and 8 characters and E may be between 1 and 3
characters, null terminated. The '*' and '?' wildcard characters are allowed.
*file_size Pointer
where the file size (bytes) will be written to.
*attribute_byte Pointer
where the attribute byte will be written to.
*directory_entry_sector Pointer where the sector number that contains the files directory
entry will be written to.
*directory_entry_within_sector
Pointer where
the file directory entry number within the sector that contains the file will
be written to.
*read_file_name Pointer to a 8 character
buffer where the filename read from the directory entry will be written to (this
may be needed if using this function with wildcard characters)
*read_file_extension Pointer to a 3 character buffer where the filename extension
read from the directory entry will be written to (this may be needed if using
this function with wildcard characters)
Returns The
file start cluster number (0xFFFFFFFF = file not found)
BYTE
ffs_convert_filename_to_dos (const char *source_filename, BYTE *dos_filename,
BYTE *dos_extension)
Used by
functions to convert the application supplied filename to a driver specific DOS
type filename. The source_filename is a case insensitive string with between 1 and 8 filename
characters, a period (full stop) character, between 1 and 3 extension
characters and a terminating null.
Returns 1 if the filename
contained any wildcard characters, 0 if not (this allow calling functions to detect
invalid names if they are creating a new file)
BYTE
ffs_read_next_directory_entry (BYTE *file_name, BYTE *file_extension,
BYTE *attribute_byte, DWORD *file_size,
DWORD *cluster_number,
BYTE start_from_beginning,
DWORD
*directory_entry_sector,
BYTE
*directory_entry_within_sector)
*file_name Pointer
where the 8 character array filename will be written to.
*file_extension Pointer
where the 3 character array filename extension will be written to.
*attribute_byte Pointer
where the file attribute byte will be written to.
*file_size Pointer
where the file size will be written to.
*cluster_number Pointer
where the start cluster for the file will be written to.
start_from_beginning Set to cause routine to start from 1st directory entry (this
must be set if the drivers data buffer has been modified since the last call)
*directory_entry_sector Pointer where the sector number that contains the files directory
entry will be written to.
*directory_entry_within_sector
Pointer where
the file directory entry number within the sector that contains the file will
be written to.
Returns 1
if a file entry was found, 0 if not (marks the end of the directory
void
ffs_overwrite_last_directory_entry (BYTE *file_name, BYTE *file_extension,
BYTE *attribute_byte, DWORD
*file_size
DWORD *cluster_number)
*file_name Pointer
to an 8 character filename (must be DOS compatible - uppercase and any trailing
unused characters set to 0x20)
*file_extension Pointer to 3 character filename extension (must be
DOS compatible - uppercase and any trailing unused characters set to 0x20)
*attribute_byte Pointer
to the file attribute byte
*file_size Pointer
to the file size
*cluster_number Pointer
to the start cluster number for the file
DWORD
get_file_start_cluster(FFS_FILE *file_pointer)
Returns the cluster number of
the start of the file. Further cluster numbers are read from the FAT table.
BYTE
ffs_create_new_file (const char *file_name, DWORD *write_file_start_cluster,
DWORD *directory_entry_sector,
BYTE
*directory_entry_within_sector)
*file_name Pointer
to an 8 character filename
*write_file_start_cluster The
cluster number that contains the start of the file.
*directory_entry_sector Pointer where the sector number that contains the files directory entry
will be written to.
*directory_entry_within_sector
Pointer where
the file directory entry number within the sector that contains the file will
be written to.
Return value 1
if successful, 0 if not
DWORD
ffs_get_next_free_cluster (void)
Find the next
available free cluster from the FAT table. The last found free cluster number
is stored to help speed up successive calls to this function.
Returns The cluster number, or
0xFFFFFFFF if no free cluster found (card is full)
DWORD
ffs_get_next_cluster_no (DWORD current_cluster)
This function
looks up the current_cluster number in the FAT table and returns the FAT table entry which will
be the next cluster number or the end of file marker.
void
ffs_modify_cluster_entry_in_fat (DWORD cluster_to_modify,
DWORD cluster_entry_new_value)
The cluster_to_modify FAT
table entry is overwritten with cluster_entry_new_value.
void ffs_read_sector_to_buffer
(DWORD sector_lba)
Reads a sector of data (usually
512 bytes) to the microcontroller / processor ram buffer.
sector_lba The
‘Logical Block Address’ / sector number to read.
void
ffs_write_sector_from_buffer (DWORD sector_lba)
Write a sector of data (usually
512 bytes) from the microcontroller / processor ram buffer.
sector_lba The
‘Logical Block Address’ / sector number to read.
BYTE
ffs_is_card_present (void)
Returns 1
if present, 0 if not
void
ffs_card_reset_pin (BYTE pin_state)
void
ffs_set_address (BYTE address)
address The
low 3 bits are the address to set
BYTE
ffs_write_byte (BYTE data)
WORD
ffs_read_word (void)
BYTE
ffs_read_byte (void)
Add the mem-ffs.c, mem-ffs.h, mem-cf.c and
mem.cf.h files to your project. Check the definitions in the mem-ffs.h and mem-cf.h
file for the microcontroller / processor you are using and your hardware
connections. In each .c file in your application that will use the driver
functions include the ‘mem-fffs.h’ file.
You will need to provide some form of timer
for the driver. Typically this can be done in your applications general
heartbeat timer if you have one. Do the following every 10mS:-
//-----
FAT FILING SYSTEM DRIVER TIMER -----
if
(ffs_10ms_timer)
ffs_10ms_timer--;
If you do not have a matching
timer then using a time base that is slightly greater than 10mS is fine.
You will need to periodically call the
drivers background processing function. Typically this can be done as part of
your applications main loop. This function looks to see if a CompactFlash card
has been inserted or removed and updates the driver appropriately. Add the
following call:-
//-----
PROCESS FAT FILING SYSTEM -----
ffs_process();
The following example checks to see if a
CompactFlash card is available to use:-
//IS
A FAT FORMATTED COMPACTFLASH CARD INSERTED AND READY TO USE?
if
(ffs_card_ok)
{
}
The included sample application contains several
examples of using the driver.
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
This driver supports reading and writing of
files in a CompactFlash cards root directory only.
This driver does not support multiple
partitions. It will access the first partition of a CompactFlash card. Other
partitions will not be damaged, but they cannot be accessed.
This driver does not support long file
names. Adding long filename support would use additional code space which is
not desirable in many embedded applications, and is also subject to patent /
licence restrictions as Microsoft holds patents for the long filename
specification.
You 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
CompactFlash 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.
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 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 CompactFlash 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 CompactFlash 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.
.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 product, 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 CompactFlash card which a user can then email you for remote analysis.
.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. 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, 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.
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. 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.
A CompactFlash 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
CompactFlash 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 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)
;
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.
If you want to be able to view the contents
of a CompactFlash card on your PC, which can be very useful when debugging or
just learning about how disks are structured, then the WinHex application is
very good. This is available from http://www.x-ways.net.
The implementation and use of the FAT file
system and CompactFlash specification may require a license from various
entities, including, but not limited to Microsoft® Corporation, IBM and the
CompactFlash Association. It is your responsibility to obtain information
regarding any applicable licensing requirements.
Microsoft offers licensing for the use of
its FAT filing system on a per unit sold basis. However it is generally viewed
that this only applies to applications that implement the patented long file name
system (LFN). It is our understanding that if long filenames are not used then
no licence fee is due, however you should ascertain if you agree with this view
yourself (to our knowledge Microsoft have not stated this but others have
determined this based on original releases of the FAT standard by Microsoft).
IBM patents may also apply to technology
supporting extended attributes within the file system.
We have checked with the CompactFlash
Association and have been told that providing a CompactFlash card interface in
a product does not require a licence from their association. If you use the
CompactFlash logo trademark on your product or in your literature then they ask
that you indicate that they are trademarks of the CompactFlash Association.
The only difference between CF Type I and
CF Type II cards is the card thickness. Type I cards are 3.3 mm thick and Type
II cards are 5mm thick. A Type I card will operate in a Type I or Type II slot.
A Type II card will only fit in a Type II slot. The electrical interfaces are
identical. CompactFlash memory is predominantly available as Type I cards.
http://www.compactflash.org/specdl1.htm.
A sample project is included which is
designed to be used with the project PCB module available from
embedded-code.com. The project is ready to be used with the Microchip MPLAB
IDE and the Microchip C18 compiler.
When run the 2 LED’s on the project PCB
operate as follows:-
Red LED indicates that PCB is
powered
Green LED indicates that a
CompactFlash card is inserted and is ready for use.
The 2 buttons on the project PCB trigger 2
different operations:-
Left edge switch When pressed all files in the root
directory are deleted, and a new file called test.txt is created containing
example test data. The red LED blinks to confirm the operation.
Middle switch When pressed a new Excel compatible spreadsheet
file called test.csv is created containing test data from the test.txt file if
it is present on the CompactFlash card. The green LED blinks to confirm the
operation.
The project may be used as a starting point
to write a new application or just as a reference for including the driver in
your own project. A description of each of the sample project files is given
in the ’Files Included In The Project’ section of this manual.
Note that this project uses a modified
version off the microchip standard linker script for the PIC18F4620. This is
required as the C18 compiler does not support data buffers over 256 bytes without
a modification to the linker script to define a larger bank of microcontroller
ram. A 512 byte buffer is required by the driver.
If you are experiencing problems using the
driver in your project the following tips may help:-
Double check IO
pin definitions in the driver header file.
Verify with a
scope that all of the control and data pins to the CompactFlash card are
working correctly.
Add additional
null execution steps to the FFS_DELAY_FOR_WAIT_SIGNAL
define in the mem-cf.h file in case more time is required for signals to
stabilise on your PCB. This is more likely to be an issue for 2 layer PCB’s
(no ground plane) with long tack lengths.
Check that no
other device on the data bus is outputting while the driver is trying to communicate
with the CompactFlash card.
Single step
through the initialise new card part of the ffs_process
function. There are several points at which the driver
verifies the correct value is returned by the CompactFlash card and if the
correct value is not being returned this may point to the cause of a problem.
Try using a
different CompactFlash card made by a different manufacturer. We have
occasionally come across faulty cards or cards that do not properly conform to
the CompactFlash standard, even from reputable manufacturers.
If you’re using
output latches for some of the control pins, instead of pins connected directly
to your processor, check your output latch function restores the previous
output on the data bus when it exits, to avoid destroying the data the driver function
is writing to a CompactFlash card.
Check that your
microcontroller is not resetting due to a watchdog timer timeout. Read and
write operations to CompactFlash cards can sometimes take time to complete that
may exceeded your watchdog timer setting?
Check that you
have enough stack space allocated. This driver uses a moderate amount of ram
from the stack and if your application is already using large amounts of the
stack before calling driver functions this may be causing a stack overrun?
A PCB module is available from
embedded-code.com which the CompactFlash driver is already configured for. It
may be used as a development board to evaluate the driver, or as OEM (other end
manufacturer) module to build into your own equipment.
PIC18 8bit PCB Module

Device
PIC18F4620
powered at 5V
Memory
64K bytes / 32K single word
instructions of flash program memory.
3986 bytes of RAM data memory
1K bytes of eeprom data memory
(Note that when
using an in-circuit debugger a small amount of program and RAM memory is not
available).
Oscillator Speed
40MHz (10
million instructions per second).
Programming and in-circuit debugging
Several
debuggers/programmers are available for the Microchip PIC18 series. We
recommend the Microchip ICD2.
A 5 pin ‘SIL’ programming header
is provided for programming and in-circuit debugging:
|
SIL 5
|
Function
|
|
1
|
MCLR/Vpp
|
|
2
|
Vdd
|
|
3
|
Gnd
|
|
4
|
PGD
|
|
5
|
PGC
|
A special link
cable is available from embedded-code.com to connect the Microchip ICD2
debugger to our project PCB’s, or if you wish to make you own:
|
SIL 5
|
Function
|
ICD2 RJ12
|
|

|
|
1
|
MCLR/Vpp
|
6
|
|
2
|
Vdd
|
5
|
|
3
|
Gnd
|
4
|
|
4
|
PGD
|
3
|
|
5
|
PGC
|
2
|
Special Notes
If working with
a particular PIC device for the first time it is a good idea to check the
Microchip ‘errata’ document for the device which will list any known issues and
suggested workarounds.
The latest data sheet for this PIC
microcontroller may be found on the Microchip web site at http://www.microchip.com.
If you want to use the PCB module with an
alternative processor / microcontroller, or want to connect it as a slave board
to another of our Project PCB Modules the PIC microcontroller may be disabled
by simply linking pins 1 and 3 on the 5 pin programming header (pin 1 is
indicated by a square pad and 2 arrows on the silkscreen). This forces the PIC
microcontroller into a reset state and all of its IO pins are set to high
impedance inputs.
Note that the PIC microcontroller may be
configured to disable the MCLR input which would stop this disabling method
working. However the PCB module is supplied with the MCLR pin enabled and our
sample projects set the pin as enabled.
The PCB includes a RS232 driver IC for
linking to a PC or other RS232 devices. The PIC microcontroller only provides
one USART peripheral so a jumper is provided to allow selection of the RS232 or
the RS485 receive signal to be connected to the microcontroller.
Making a RS232 Serial Cable To Connect The
Module To A PC
|
D15 line male
|
|
D9 line female
|
Function
|
|
3
|
>
|
5
|
Ground
|
|
4
|
>
|
2
|
TX
> RX
|
|
5
|
>
|
3
|
RX
< TX
|
(If your PC
application needs to use hardware flow control / handshaking then link pins
4>6 and pins 7>8 on the D9 connector).
The PCB includes a 2 wire bi-directional
RS485 driver IC, suitable for RS422 or RS485 communications. The PIC
microcontroller only provides one USART peripheral so a jumper is provided to
allow selection of the RS232 or the RS485 receive signal to be connected to the
microcontroller.
If you have not used a RS422 or RS485
interface before you should search the web for details of the requirements of
this type of bus. The main requirements are that the cable connection must be
‘daisy chain’ (i.e. from device to device in one long line, with no ‘Y’ splits,
and that twisted pair screen cable should be used if connecting more than a
very short distance. The cable type is important and it is the twisting of the
pair that carries the ‘D-‘ and ‘D+’ data signals that provides the excellent
interference rejection of this type of interface (much more so than the cable
screen in fact).
Resistor footprints are provided for a
terminate resistor and bus pull resistors which may be fitted if required.
Normally a RS422 or RS495 bus is terminated at each end using a 120ohm
resistor.
In applications where multiple devices
transmit on the bus at different times you may wish to avoid the bus giving a
bad low signal when no device is driving it by fitting pull up and pull down resistors.
We recommend fitting 750R pull up and pull down resistors on just one device,
typically the bus ‘master’ device if you have one, and 56K pull up and pull
down resistors on all other devices. The device at each end of the bus should
then use a 130R terminate resistor. These values are not part of any
specification and you may find others recommend different values, but we have
found these values to work very well in applications with fast data rates and
long cable lengths.
The PIC microcontroller has a built in I2C
port which you may use or simply use these pins as additional IO pins if
required. Note that if using an I2C bus there should be pull up resistors
fitted at one point on the bus and the PCB includes 0805 resistor footprints to
allow these to be fitted if needed. The I2C bus may be used to connect local
I2C devices, or to connect to other equipment or PCB modules using a short
cable link.
A 2.5mm mini power connector is provided to
power the PCB. Note that a power supply is not supplied. A suitable DC power
supply should be used with an output voltage of between 9 and 12V. An
unregulated DC power supply may be used.
The PCB voltage regulator may be used to
power additional electronics. The IC is rated up to 800mA total load although
you should check that the IC does not become too hot with additional load
connected. If it does reduce the load or reduce the input supply voltage to
reduce the heat output.
2 push buttons are provided for use in your
application.
1 red and 1 green LED are provided for use
in your application. The red LED is next to left edge switch and the green LED
is next to middle switch.
This PCB module includes a stripboard
prototyping area for you to add additional electronics if required. Note that
the pads are connected in lines on the bottom layer of the PCB in the same way
as standard stripboard.
There are 3 spare PIC pins which are
connected to pads next to the stripboard prototyping area. These may be
configured as analog inputs if required.
The D connector has 6 spare pins which are
connected to pads next to the stripboard prototyping area.
A SIL header type connection is provided on
the PCB containing all of the connections made to the CompactFlash memory
card. This may be used when testing signals or to connect an alternative
microcontroller or processor, or to connect additional electronics to the data
bus.
With no CompactFlash card inserted the PCB
module draws approximately 60mA. Standard CompactFlash memory cards may draw
up to an additional 75mA average current.
A high quality machined enclosure is also available.
Note – this
section of the manual is for information only. You do not need to read and
understand this large and in depth section to use the driver! However you may
want to if you wish to gain an understanding of disk access, the FAT filing
system and how this driver works.
Remember when understanding these terms
that hard disks uses multiple disks of magnetic material with a read/write head
for each side of each disk. Bytes are read from and written to a disks surface
in circular paths.
Track
The circular
track on one surface of a disk (numbered 0 - #). This is not usually referred
to.
Cylinder
All of the
tracks in the same position on all of the surfaces (numbered 0 - #). This is
not usually referred to other than when determining the parameters of a disk
during initialisation.
Head
Each side of a
disk has a read / write head (numbered 0 - #). This is not usually referred to
other than when determining the parameters of a disk during initialisation.
Sector
This is the
fundamental unit of disk mapping - all reading and writing to disks is carried
out in sectors. A sector is usually 512 bytes in size, but can be 128 – 1024
bytes.
(Numbered as 1 -
# (0 is reserved for identification purposes)).
Cluster
A cluster is a
specified group of sectors. It is clusters that are the addressing unit when
reading and writing files using the FAT system (i.e. a directory will point to
a particular file using the cluster number that contains the start of the
file). A cluster may only be used by one file, and large files will use
multiple clusters to hold their data. A disk with a large cluster size (lots
of sectors per cluster) will mean that disk space is wasted as any unused bytes
after the end of a file in its final cluster will not be available for anything
else. A disk with a small cluster size means less wastage. However, a small
cluster size means a larger FAT table as a FAT table contains an entry for
every cluster on a disk (or in the partition if the disk is partitioned), hence
the need to FAT32 instead of FAT16 for larger volumes.
The valid range
is 1 – 64 sectors per cluster. The first cluster that may be used is number 2
(clusters 0 & 1 are reserved).
The FAT filing system was developed for DOS
and DOS thinks of a disk as a linear object, not as it is actually
constructed. This means that DOS treats the sectors of a disk as a sequential
list of sectors, from the first on the disk to the last. Whilst this made
things more complex when writing drivers for hard disks, it makes things easier
when dealing with modern flash memory cards as these are linear memory objects.
The FAT file system uses ‘little endian’. That is that the
first byte read is the least significant byte of a large value, the next byte
read is more significant than the last and so on. For example this is how a
32bit value would be stored (with the bit numbers shown):-
byte[3] 3 3 2 2 2 2 2 2 //This is the
last byte read from the disk
1 0 9 8 7 6 5 4
byte[2] 2 2 2 2 1 1 1 1
3 2 1 0 9 8 7 6
byte[1] 1 1 1 1 1 1 0 0
5 4 3 2 1 0 9 8
byte[0] 0 0 0 0 0 0 0 0 //This is the
first byte read from the disk
7 6 5 4 3 2 1 0
This block of data is not part of the disk
space, but is read from a Compact Flash Card using the ‘Identify Drive’ command
before accessing the disk. See the following section for an in depth
description.
|
No Start Address
|
255 bytes
|
‘Identify Drive’ command drive parameter
information block.
|
The following show how the different
sections of a disk are organised for FAT16 and FAT32, looking at the disk as a
linear memory object (which is how it is addressed). See the following
sections for an in depth description of each block.
|
Start Address
|
Size
|
Contents
|
|
0x00000000
|
512
bytes
|
Master Boot Record
(Amongst other things this specifies the
address of each of the main partitions).
|
|
Partition
Start Address + 0
|
512
bytes
|
Partition 1
|
The Boot Record. Located in the first
sector of a partition.
|
|
Partition
Start Address + 512
|
As
specified in the Boot Record
|
FAT table 1
|
|
Partition
Start Address + 512
+
(Size of FAT Table x (FAT table # - 1))
|
As
specified in the Boot Record
|
FAT table # (specified by ‘Number of
Copies of FAT’ in master boot record. A value of 2 is normal)
|
|
Partition
Start Address + 512 + (Size of FAT Table x Number of Copies of FAT)
|
As
specified in the Boot Record
|
Root directory
|
|
Partition
Start Address + 512 + (Size of FAT Table x Number of Copies of FAT)
+
Size of Root Directory
|
Calculated
from the Master Boot Record Total Partition Size
|
Data area for files and other directories.
(This area occupies the remainder of the
disk, or the space to the start of the next partition).
|
Then follows further partitions if
present:-
|
Start Address
|
Size
|
Contents
|
|
Partition
Start Address + 0
|
512
bytes
|
Partition 2
|
The Boot Record. Located in the first
sector of a partition.
|
|
Partition
Start Address + 512
|
As
specified in the Boot Record
|
FAT table 1
|
|
Partition
Start Address + 512
+
(Size of FAT Table x (FAT table # - 1))
|
As
specified in the Boot Record
|
FAT table # (specified by ‘Number of
Copies of FAT’ in master boot record. A value of 2 is normal)
|
|
Partition
Start Address + 512 + (Size of FAT Table x Number of Copies of FAT)
|
As
specified in the Boot Record
|
Root directory
|
|
Partition
Start Address + 512 + (Size of FAT Table x Number of Copies of FAT)
+
Size of Root Directory
|
Calculated
from the Master Boot Record Total Partition Size
|
Data area for files and other directories.
(This area occupies the remainder of the
disk, or the space to the start of the next partition).
|
Repeated for each partition
Note - Shaded
cells may repeat or not be present at all.
This is basically the same as for a FAT16
volume, but without the root directory included (and with each block using a
different amount of space).
|
Start Address
|
Size
|
Contents
|
|
0x00000000
|
512
bytes
|
Master Boot Record
(Amongst other things this specifies the
address of each of the main partitions).
|
|
Partition
Start Address + 0
|
512
bytes
|
Partition 1
|
The Boot Record. Located in the first
sector of a partition.
|
|
Partition
Start Address + 512
|
As
specified in the Boot Record
|
FAT table 1
|
|
Partition
Start Address + 512
+
(Size of FAT Table x (FAT table # - 1))
|
As
specified in the Boot Record
|
FAT table # (specified by ‘Number of
Copies of FAT’ in master boot record. A value of 2 is normal)
|
|
Partition
Start Address + 512 + (Size of FAT Table x Number of Copies of FAT)
|
Calculated
from the Master Boot Record Total Partition Size
|
Data area for files and other directories.
(This area occupies the remainder of the
disk, or the space to the start of the next partition).
|
Then if there is more than 1 partition, the
additional partitions follow:-
|
Start Address
|
Size
|
Contents
|
|
Partition
Start Address + 0
|
512
bytes
|
Partition 2
|
The Boot Record. Located in the first
sector of a partition.
|
|
Partition
Start Address + 512
|
As
specified in the Boot Record
|
FAT table 1
|
|
Partition
Start Address + 512
+
(Size of FAT Table x (FAT table # - 1))
|
As
specified in the Boot Record
|
FAT table # (specified by ‘Number of
Copies of FAT’ in master boot record. A value of 2 is normal)
|
|
Partition
Start Address + 512 + (Size of FAT Table x Number of Copies of FAT)
|
Calculated
from the Master Boot Record Total Partition Size
|
Data area for files and other directories.
(This area occupies the remainder of the
disk, or the space to the start of the next partition).
|
Repeated for each partition
Note - Shaded
cells may repeat or not be present at all.
When initialising a new CompactFlash card
the ‘Identify Drive’ command is used to determine the cards setup. Note that
this is not part of the disk space, but is drive specific data. This command
returns the following data:-
|
Word
|
Value
|
|
0
|
0x00
|
= 0x848A . General configuration word
which indicates that this is a CompactFlash storage card
|
|
1
|
0x01
|
Default number of cylinders
|
|
2
|
0x02
|
Reserved (0x0000)
|
|
3
|
0x03
|
Default number of heads (0x00## where #
is the value)
|
|
4
|
0x04
|
Number of unformatted bytes per track
(0x#### where # is the value)
|
|
5
|
0x05
|
Number of unformatted bytes per sector
(0x#### where # is the value)
|
|
6
|
0x06
|
Default number of sectors per track
(0x#### where # is the value)
|
|
7
|
0x07
|
Number of sectors per card (Word 7 = most
significant word, Word 8 = least significant word)
(0x######## where # is the value)
|
|
8
|
0x08
|
|
9
|
0x09
|
Vendor Unique
|
|
10
|
0x0A
|
20 bytes of serial number in ASCII (right
justified and padded with spaces (0x20))
|
|
||
|
||
|
|
19
|
0x13
|
|
20
|
0x14
|
Buffer type (0x#### where # is the value)
|
|
21
|
0x15
|
Buffer size in 512 byte increments
(0x#### where # is the value)
|
|
22
|
0x16
|
# of ECC bytes passed on Read/Write Long
Commands (= 0x0004)
|
|
23
|
0x17
|
8 bytes of firmware revision in ASCII. (Big
Endian)
|
|
||
|
||
|
|
26
|
0x1A
|
|
27
|
0x1B
|
40 bytes of model number in ASCII (Left
Justified, Big Endian)
|
|
||
|
||
|
|
46
|
0x2E
|
|
47
|
0x2F
|
Maximum number of sectors on Read/Write
Multiple command. (0x#### where # is the value)
|
|
48
|
0x30
|
Double Word not supported (= 0x0000,
double word transfers not possible)
|
|
49
|
0x31
|
Capabilities:-
|
Bit 13
|
Standby Timer (1 = Standby timer is
supported (defined by the IDLE command), 0 = Standby timer operation is
defined by the vendor)
|
|
Bit 11
|
IORDY Support (1 = device supports
IORDY operation, 0 = device may support IORDY operation)
|
|
Bit 9
|
LBA support (CompactFlash storage cards
support LBA mode addressing)
|
|
Bit 8
|
DMA Support (Should be set to 0 as DMA
mode is not supported)
|
|
|
50
|
0x32
|
Reserved (= 0x0000)
|
|
51
|
0x33
|
PIO data transfer cycle timing mode
(0x0#00 where # is the value)
|
|
52
|
0x34
|
DMA data transfer cycle timing mode (=
0x0000)
|
|
53
|
0x35
|
Translation parameters are valid (=
0x0001)
|
|
54
|
0x36
|
Current numbers of cylinders (0x####
where # is the value)
|
|
55
|
0x37
|
Current numbers of heads (0x#### where #
is the value)
|
|
56
|
0x38
|
Current sectors per track (0x#### where #
is the value)
|
|
57
|
0x39
|
Current capacity in sectors (LBAs)(Word
57 = LSW, Word 58 = MSW)
(0x######## where # is the value)
|
|
58
|
0x3A
|
|
59
|
0x3B
|
Multiple sector setting (0x010# where #
is the value)
|
|
60
|
0x3C
|
Total number of sectors addressable in
LBA Mode
(0x######## where # is the value)
|
|
61
|
0x3D
|
|
62
|
0x3E
|
Reserved (138 bytes)
|
|
||
|
||
|
|
127
|
0x7F
|
|
128
|
0x80
|
Security status (0x#### where # is the
value)
|
|
129
|
0x81
|
Vendor unique bytes (64 bytes)
|
|
||
|
||
|
|
159
|
0x9F
|
|
160
|
0xA0
|
Power requirement description (0x####
where # is the value)
|
Bit 15
|
VLD (1 = this word contains a valid
power requirement description)
|
|
Bit 14
|
RSV (This bit is reserved and must be
0)
|
|
Bit 13
|
-XP (1 = the CompactFlash Storage Card
does not have Power Level 1 commands, 0 = has Power Level 1 commands_
|
|
Bit 12
|
-XE (1 = Power Level 1 commands are
disabled, 0 - Power Level 1 commands are enabled)
|
|
Bit 0-11
|
Maximum current. This field contains
the CompactFlash Storage Card’s maximum current in mA.
|
|
|
161
|
0xA1
|
Reserved
|
|
||
|
||
|
|
255
|
0xFF
|
This driver only reads the first section of
this data to retrieve essential disk setup information and the rest is dumped.
However you may want to modify the driver to include reading of additional data
such as the ‘Power Requirement Description’ etc.
The first sector of a hard disk is set
aside for the Master Boot Record. This is operating system independent. It is
located on the first Sector of the disk, at Cylinder 0, Head 0, Sector 1. It
contains the partition table, which defines the different sections of your hard
drive and if this section of a disk is corrupted it can mean that the disk is
dead!
Note – if trying to view the master boot
record using PC disk viewing software ensure that you have selected the correct
section of the disk. Some software will show you the contents of the first
partition by default, not the first sector containing the master boot record.
|
Byte
(0x00000000 + #)
|
Value
|
|
0
|
0x0000
|
446 bytes of boot up executable code and
data.
|
|
||
|
||
|
|
445
|
0x01BD
|
|
446
|
0x01BE
|
Partition 1
|
Offset 0x00
|
Current State of Partition (00h=Inactive, 80h=Active)
|
|
447
|
0x01BF
|
Offset 0x01
|
Beginning of Partition – Head
|
|
448
|
0x01C0
|
Offset 0x02
|
Beginning of Partition – Cylinder/Sector
|
15
|
14
|
13
|
12
|
11
|
10
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
|
Cylinder Bits 7 to 0
|
Cylinder Bits 9+8
|
Sector Bits 5 to 0
|
|
|
449
|
0x01C1
|
Offset 0x03
|
|
450
|
0x01C2
|
Offset 0x04
|
Type of Partition:
|
0x00
|
Unknown or Nothing
|
|
0x01
|
12-bit FAT
|
|
0x04
|
16-bit FAT (Partition Smaller than
32MB)
|
|
0x05
|
Extended MS-DOS Partition
|
|
0x06
|
16-bit FAT (Partition Larger than 32MB)
|
|
0x0B
|
32-bit FAT (Partition Up to 2048GB)
|
|
0x0C
|
Same as 0x0B, but uses LBA 0x13
extensions
|
|
0x0E
|
Same as 0x06, but uses LBA 0x13
extensions
|
|
0x0F
|
Same as 0x05, but uses LBA 0x13
extensions
|
The above values relate
to Microsoft operating systems – there are others.
LBA = Logical
Block Addressing which uses the Int 0x13 extensions built into newer BIOS’s
to access data above the 8GB barrier, or to access strictly in LBA mode,
instead of CHS (Cylinder, Head, Sector).
|
|
451
|
0x01C3
|
Offset 0x05
|
End of Partition – Head
|
|
452
|
0x01C4
|
Offset 0x06
|
End of Partition – Cylinder/Sector
|
15
|
14
|
13
|
12
|
11
|
10
|
9
|
8
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
|
Cylinder Bits 7 to 0
|
Cylinder Bits 9+8
|
Sector Bits 5 to 0
|
|
|
453
|
0x01C5
|
Offset 0x07
|
|
454
|
0x01C6
|
Offset 0x08
|
Number of sectors between the master boot
record and the first sector in the partition.
|
|
455
|
0x01C7
|
Offset 0x09
|
|
456
|
0x01C8
|
Offset 0x0A
|
|
457
|
0x01C9
|
Offset 0x0B
|
|
458
|
0x01CA
|
Offset 0x0C
|
Number of sectors in the partition
|
|
459
|
0x01CB
|
Offset 0x0D
|
|
460
|
0x01CC
|
Offset 0x0E
|
|
461
|
0x01CD
|
Offset 0x0F
|
|
462
|
0x01CE
|
Partition 2
|
Offset 0x00
|
Current State of Partition (00h=Inactive, 80h=Active)
|
|
463
|
0x01CF
|
Offset 0x01
|
Beginning of Partition - Head
|
|
464
|
0x01D0
|
Offset 0x02
|
Beginning of Partition - Cylinder/Sector
(Format as per partition 1)
|
|
465
|
0x01D1
|
Offset 0x03
|
|
466
|
0x01D2
|
Offset 0x04
|
Type of Partition (Format as per partition 1)
|
|
467
|
0x01D3
|
Offset 0x05
|
End of Partition - Head
|
|
468
|
0x01D4
|
Offset 0x06
|
End of Partition - Cylinder/Sector
(Format as per partition 1)
|
|
469
|
0x01D5
|
Offset 0x07
|
|
470
|
0x01D6
|
Offset 0x08
|
Number of sectors between the master boot
record and the first sector in the partition.
|
|
471
|
0x01D7
|
Offset 0x09
|
|
472
|
0x01D8
|
Offset 0x0A
|
|
473
|
0x01D9
|
Offset 0x0B
|
|
474
|
0x01DA
|
Offset 0x0C
|
Number of sectors in the partition
|
|
475
|
0x01DB
|
Offset 0x0D
|
|
476
|
0x01DC
|
Offset 0x0E
|
|
477
|
0x01DD
|
Offset 0x0F
|
|
478
|
0x01DE
|
Partition 3
|
Offset 0x00
|
Current State of Partition (00h=Inactive, 80h=Active)
|
|
479
|
0x01DF
|
Offset 0x01
|
Beginning of Partition - Head
|
|
480
|
0x01E0
|
Offset 0x02
|
Beginning of Partition - Cylinder/Sector
(Format as per partition 1)
|
|
481
|
0x01E1
|
Offset 0x03
|
|
482
|
0x01E2
|
Offset 0x04
|
Type of Partition (Format as per partition 1)
|
|
483
|
0x01E3
|
Offset 0x05
|
End of Partition - Head
|
|
484
|
0x01E4
|
Offset 0x06
|
End of Partition - Cylinder/Sector
(Format as per partition 1)
|
|
485
|
0x01E5
|
Offset 0x07
|
|
486
|
0x01E6
|
Offset 0x08
|
Number of sectors between the master boot
record and the first sector in the partition.
|
|
487
|
0x01E7
|
Offset 0x09
|
|
488
|
0x01E8
|
Offset 0x0A
|
|
489
|
0x01E9
|
Offset 0x0B
|
|
490
|
0x01EA
|
Offset 0x0C
|
Number of sectors in the partition
|
|
491
|
0x01EB
|
Offset 0x0D
|
|
492
|
0x01EC
|
Offset 0x0E
|
|
493
|
0x01ED
|
Offset 0x0F
|
|
494
|
0x01EE
|
Partition 4
|
Offset 0x00
|
Current State of Partition (00h=Inactive, 80h=Active)
|
|
495
|
0x01EF
|
Offset 0x01
|
Beginning of Partition - Head
|
|
496
|
0x01F0
|
Offset 0x02
|
Beginning of Partition - Cylinder/Sector
(Format as per partition 1)
|
|
497
|
0x01F1
|
Offset 0x03
|
|
498
|
0x01F2
|
Offset 0x04
|
Type of Partition (Format as per partition 1)
|
|
499
|
0x01F3
|
Offset 0x05
|
End of Partition - Head
|
|
500
|
0x01F4
|
Offset 0x06
|
End of Partition - Cylinder/Sector
(Format as per partition 1)
|
|
501
|
0x01F5
|
Offset 0x07
|
|
502
|
0x01F6
|
Offset 0x08
|
Number of sectors between the master boot
record and the first sector in the partition.
|
|
503
|
0x01F7
|
Offset 0x09
|
|
504
|
0x01F8
|
Offset 0x0A
|
|
505
|
0x01F9
|
Offset 0x0B
|
|
506
|
0x01FA
|
Offset 0x0C
|
Number of sectors in the partition
|
|
507
|
0x01FB
|
Offset 0x0D
|
|
508
|
0x01FC
|
Offset 0x0E
|
|
509
|
0x01FD
|
Offset 0x0F
|
|
510
|
0x01FE
|
Boot signature (= 0xAA55)
|
|
511
|
0x01FF
|
The first sector of a partition contains a
boot record. There are differences between the FAT16 and FAT32 boot records.
(Greyed out FAT32 entries indicate that
the contents is the same as for FAT16)
|
FAT16
|
|
|
FAT32
|
|
|
Offset
|
Description
|
|
Offset
|
Description
|
|
0x0000
|
Jump Code + NOP
|
|
0x0000
|
Jump Code + NOP
|
|
0x0001
|
|
0x0001
|
|
0x0002
|
|
0x0002
|
|
0x0003
|
8 byte OEM Name
|
|
0x0003
|
8 byte OEM Name
|
|
||
|
|
||
|
|
0x000A
|
|
0x000A
|
|
0x000B
|
Bytes Per Sector
|
|
0x000B
|
Bytes Per Sector
|
|
0x000C
|
|
0x000C
|
|
0x000D
|
Sectors Per Cluster (Restricted to powers of 2 (1, 2, 4, 8, 16, 32…))
|
|
0x000D
|
Sectors Per Cluster (Restricted to
powers of 2 (1, 2, 4, 8, 16, 32…))
|
|
0x000E
|
Reserved Sectors
|
|
0x000E
|
Reserved Sectors
|
|
0x000F
|
|
0x000F
|
|
0x0010
|
Number of Copies of FAT. (A value of 2
is recommended – values other than 2 are possible by are not recommended by
Microsoft)
|
|
0x0010
|
Number of Copies of FAT. (A value of 2 is recommended – values other
than 2 are possible by are not recommended by Microsoft)
|
|
0x0011
|
Maximum Root Directory Entries
|
|
0x0011
|
Maximum Root Directory Entries (not applicable for FAT32)
|
|
0x0012
|
|
0x0012
|
|
0x0013
|
Number of Sectors in Partition Smaller
than 32MB
|
|
0x0013
|
Number of Sectors in Partition Smaller than 32MB (not
applicable for FAT32)
|
|
0x0014
|
|
0x0014
|
|
0x0015
|
Media Descriptor (F8h for Hard Disks)
|
|
0x0015
|
Media Descriptor (F8h for Hard
Disks)
|
|
0x0016
|
Sectors Per FAT
|
|
0x0016
|
Sectors Per FAT (not applicable for FAT32 – bigger field
below)
|
|
0x0017
|
|
0x0017
|
|
0x0018
|
Sectors Per Track
|
|
0x0018
|
Sectors Per Track
|
|
0x0019
|
|
0x0019
|
|
0x001A
|
Number of Heads
|
|
0x001A
|
Number of Heads
|
|
0x001B
|
|
0x001B
|
|
0x001C
|
Number of Hidden Sectors in Partition
|
|
0x001C
|
Number of Hidden Sectors in
Partition
|
|
0x001D
|
|
0x001D
|
|
0x001E
|
|
0x001E
|
|
0x001F
|
|
0x001F
|
|
0x0020
|
Number of Sectors in Partition
|
|
0x0020
|
Number of Sectors in Partition
|
|
0x0021
|
|
0x0021
|
|
0x0022
|
|
0x0022
|
|
0x0023
|
|
0x0023
|
From this point the boot records are not
the same – continued on next page...
|
0x0024
|
Logical Drive Number of Partition
|
|
0x0025
|
|
0x0026
|
Extended Signature (29h)
|
|
0x0027
|
Serial Number of Partition
|
|
0x0028
|
|
0x0029
|
|
0x002A
|
|
0x002B
|
11 bytes of volume name of the
partition
|
|
||
|
|
0x0035
|
|
0x0036
|
FAT Name (FAT16)
|
|
0x003E
|
448 bytes of executable code and data
|
|
||
|
|
0x01FD
|
|
0x01FE
|
Boot signature (= 0xAA55)
|
|
0x01FF
|
|
|
0x0024
|
Number of Sectors Per FAT
|
|
0x0025
|
|
0x0026
|
|
0x0027
|
|
0x0028
|
Flags:
|
15:8
|
Reserved
|
|
Bit 7
|
1 = FAT Mirroring is Disabled, only 1 FAT is active as
specified in bits 3:0
0 = FAT Mirroring is Enabled into all FATs
|
|
6:4
|
Reserved
|
|
Bits
3:0
|
Number of active FAT (0-#). Only valid if mirroring
disabled.
|
|
|
0x0029
|
|
0x002A
|
Version of FAT32 Drive (high byte = major version, low
byte = minor version)
|
|
0x002B
|
|
0x002C
|
Cluster Number of the Start of the Root Directory
(Usually 2, but not required to be)
|
|
0x002D
|
|
0x002E
|
|
0x002F
|
|
0x0030
|
Sector Number of the File System Information Sector
(Referenced from the start of the partition)
|
|
0x0031
|
|
0x0032
|
Sector Number of the Backup Boot Sector (Referenced from
the start of the partition)
|
|
0x0033
|
|
0x0034
|
Reserved (12 bytes)
|
|
||
|
|
0x003F
|
|
0x0040
|
Logical Drive Number of Partition
|
|
0x0041
|
Unused
|
|
0x0042
|
Extended Signature (29h)
|
|
0x0043
|
Serial Number of Partition
|
|
0x0044
|
|
0x0045
|
|
0x0046
|
|
0x0047
|
11 byte volume name of the partition
|
|
||
|
|
0x0051
|
|
0x0052
|
8 byte FAT Name (FAT32)
|
|
||
|
|
0x0059
|
|
0x005A
|
420 bytes of executable code and data
|
|
||
|
|
0x01FD
|
|
0x01FE
|
Boot Signature (= 0xAA55)
|
|
0x01FF
|
|
The FAT table (whether FAT16 or FAT32)
contains an entry for every cluster on the disk (or partition if the disk is
partitioned). Each entry is either 16 bits in size for FAT16, or 32bits in
size for FAT32. The contents of an entry may be as follows:-
FAT16 Table Entry Values:-
0x0000 The
cluster is free.
0x0001 Reserved
0x0002 – 0xFFF0 This cluster is used. The
value indicates the next cluster number for the file.
0xFFF7 Cluster
is bad
0xFFF8 – 0xFFFF EOC
(End Of Clusterchain) (typically you should use 0xFFFF)
FAT32 Table Entry Values:-
0x#0000000 The
cluster is free.
0x0001 Reserved
0x0002 – 0xFFF0 This cluster is used. The
value indicates the next cluster number for the file.
0x#FFFFFF7 Cluster
is bad
0x#FFFFFF8 –
0x#FFFFFFF EOC (End Of Clusterchain) (typically you should use 0x#FFFFFFF
(The top 4 bits
are reserved and will not necessarily be zero. They must be ignored when
reading a cluster number but maintained when writing a new value to an entry)
When a file is stored the first available
free cluster is found from the FAT table and stored in the files directory
entry (see later in this manual). The file is written to the cluster. If it
doesn’t fit within the cluster then the next free cluster is found and the new
cluster number is written in the previous clusters FAT table entry. This
continues until the last cluster that is required for the file (which may be
the first cluster if the file will fit within one cluster). The EOC marker is
written to the FAT tables for the last cluster to indicate that no further
clusters are used.
Therefore when reading a file the start
cluster number is determined from the files entry in the directory the file is
located in. Then the FAT table is used to find the next cluster that holds the
next block of the files data, then the next etc. Whilst the EOC marker
indicates that a cluster is the last cluster used to store a file, the exact
file size is stored in the files directory entry so that the last used byte
number of the file can be determined.
|
Byte
(Partition Start Address + 512
+ #)
|
FAT Entry
|
Value
|
|
0
|
0x0000
|
1
|
Reserved. Contains the media type value
in the low 8 bits and all other bits are set to 1
|
|
1
|
0x0001
|
|
2
|
0x0002
|
2
|
Reserved – set on format to the EOC
marker. The top 2 bits may be used as ‘dirty volume’ flags:
|
Bit 15
|
1 = volume is ‘clean’. 0 = volume is
‘dirty’ (the file system driver did not complete its last task properly and
it would be good idea to run a disk checking program.
|
|
Bit 14
|
1 =no disk read/write errors were
encountered. 0 = the file system driver encountered a disk I/O error on
the volume the last time it was used, which indicates that some sectors may
have gone bad on the volume. It would be a good idea to run a disk checking
program.
|
|
|
3
|
0x0003
|
|
4
|
0x0004
|
3
|
The FAT entry for the 1st cluster in the
data area of the disk / partition
|
|
5
|
0x0005
|
|
6
|
0x0006
|
4
|
The FAT entry for the 2nd
cluster in the data area of the disk / partition
|
|
7
|
0x0007
|
|
||
|
||
|
|
|
|
#
|
0x####
|
#
|
The FAT entry for the last cluster in the
data area of the disk / partition
|
|
#
|
0x####
|
|
Byte
(Partition Start Address + 512
+ #)
|
FAT Entry
|
Value
|
|
0
|
0x0000
|
1
|
Reserved. Contains the media type value
in the low 8 bits and all other bits are set to 1
|
|
1
|
0x0001
|
|
2
|
0x0002
|
|
3
|
0x0003
|
|
4
|
0x0004
|
2
|
Reserved – set on format to the EOC
marker. The top 2 bits may be used as ‘dirty volume’ flags:
|
Bit 27
|
1 = volume is ‘clean’. 0 = volume is
‘dirty’ (the file system driver did not complete its last task properly and
it would be good idea to run a disk checking program.
|
|
Bit 26
|
1 =no disk read/write errors were
encountered. 0 = the file system driver encountered a disk I/O error on
the volume the last time it was used, which indicates that some sectors may
have gone bad on the volume. It would be a good idea to run a disk checking
program.
|
|
|
5
|
0x0005
|
|
6
|
0x0006
|
|
7
|
0x0007
|
|
8
|
0x0008
|
3
|
The FAT entry for the 1st cluster in the
data area of the disk / partition
|
|
9
|
0x0009
|
|
10
|
0x000A
|
|
11
|
0x000B
|
|
12
|
0x000C
|
4
|
The FAT entry for the 2nd
cluster in the data area of the disk / partition
|
|
13
|
0x000D
|
|
14
|
0x000E
|
|
15
|
0x000F
|
|
||
|
||
|
|
|
|
#
|
0x####
|
#
|
The FAT entry for the last cluster in the
data area of the disk / partition
|
|
#
|
0x####
|
|
#
|
0x####
|
|
#
|
0x####
|
FAT16 uses 2 FAT tables, one after the
other, and FAT32 uses up to 4 FAT tables. This provides a backup in case of
corruption of one of the tables. If you change the contents of the FAT table,
ensure that all copies are updated (checking for FAT32 to see which tables
should be updated).
The first FAT table starts straight after
the Boot Record. Therefore the start address of the first FAT table:
= Start
address of partition + No of reserved sectors
Each additional FAT table follows straight
on after the last. The number of FAT tables is recommended to be 2 due to old
systems that assume a value of 2. However the number of FAT tables does not
have to be 2 and for flash drives where a backup of the FAT table is redundant
only a single table may be used. It is also possible to have more than 2 FAT
tables.
A FAT directory is simply a ‘file’
containing a linear list of 32 byte entries. The only special directory, which
must always be present, is the root directory. For FAT16 volumes the root
directory is located in a fixed location on the disk immediately following the
last FAT and is a fixed size in sectors as specified in the Boot Record.
For FAT16 the first sector of the root directory
is sector number relative to the first sector of the FAT volume:
For FAT32 the root directory can be of
variable size and is a cluster chain just like any other directory. The first
cluster of the root directory is specified in the Boot Record.
Each directory entry is 32 bytes and
formatted as follows:
|
Byte
|
Value
|
|
0
|
0x00
|
Name
(The 8 character filename)
|
|
1
|
0x01
|
|
2
|
0x02
|
|
3
|
0x03
|
|
4
|
0x04
|
|
5
|
0x05
|
|
6
|
0x06
|
|
7
|
0x07
|
|
8
|
0x08
|
Extension
(The 3 character filename extension)
|
|
9
|
0x09
|
|
10
|
0x0A
|
|
11
|
0x0B
|
Attributes
|
Bit:
|
7
|
6
|
5
|
4
|
3
|
2
|
1
|
0
|
|
Value:
|
0
|
0
|
Archive
|
Directory
|
Volume Label
|
System
|
Hidden
|
Read Only
|
|
|
12
|
0x0C
|
NT
(Reserved for WindowsNT always 0)
|
|
13
|
0x0D
|
Created time – mS (0 if not used)
|
|
14
|
0x0E
|
Created time - hour and minute (0 if not
used)
|
|
15
|
0x0F
|
|
16
|
0x10
|
Created date (0 if not used)
|
|
17
|
0x11
|
|
18
|
0x12
|
Last accessed date (0 if not used)
|
|
19
|
0x13
|
|
20
|
0x14
|
Extended Attribute
(reserved for OS/2, always 0)
High word of cluster for FAT32 volumes
|
|
21
|
0x15
|
|
22
|
0x16
|
Time of last write to file
|
|
23
|
0x17
|
|
24
|
0x18
|
Date of last write to file
|
|
25
|
0x19
|
|
26
|
0x1A
|
Start cluster (referenced from the start
of the data area of the volume)
|
|
27
|
0x1B
|
|
28
|
0x1C
|
File size
|
|
29
|
0x1D
|
|
30
|
0x1E
|
|
31
|
0x1F
|
(Shaded bytes we’re unused in the original
DOS specification and may still be left unused if desired)
If the first byte of a directory entry is
0xE5 then the entry has been erased. If the first byte is 0x00 then the entry
has never been used (this can be used to detect the end of the table as all
following entries will also be 0x00).
For FAT16 the root directory is located
directly after the 2nd FAT table:
= Start address
of partition + No of reserved sectors + (Number of FAT tables x FAT table size)
Its size is specified by the boot record:
= maximum number
of root directory entries x 32 bytes per entry
The data area starts straight after the
root directory. The only difference between the root folder and any other
folders is that the root folder is at a specified location and has a fixed
number of entries.
For FAT32 the root directory can be of
variable size and is a cluster chain, just like any other directory is. The
first cluster of the root directory on a FAT32 volume is stored in the sector
specified in the boot record.
For both FAT16 and FAT23, unlike other
directories, the root directory itself does not have any date or time stamps,
does not have a file name (other than the implied file name “\”), and does not
contain “.” and “..” files as the first two directory entries in the directory.
The only other special aspect of the root directory is that it is the only
directory on the FAT volume for which it is valid to have a file that has only
the ‘Volume ID’ attribute bit set.
If date and time are not supported then
they should be written as zero. Bytes 22 – 25, time of last write and date of
last write, must be supported according to the FAT specification but if a
device has no real time clock then this isn’t possible.
Date field
A 16-bit field
that is a date relative to 01/01/1980:-
Bits 15:9 Count
of years from 1980, valid range 0 – 127 (=1980–2107).
Bits 8:5 Month
of year, valid range 1–12 (1 = January)
Bits 4:0 Day
of month, valid range 1-31
Time Format.
A 16-bit field
with a valid range from Midnight 00:00:00 to 23:59:58:-
Bits 15:11 Hours,
valid range 0 – 23
Bits 10:5 Minutes,
valid range 0 – 59
Bits 4:0 2-second
count, valid range 0–29 (= 0 – 58 seconds)
The remainder of the volume is the data
area, which may contain files and directories. It is this area that the FAT
tables relate to.
For FAT16 the start address of the data
area is:-
Start address of
partition + Number of reserved sectors + (Number of FAT tables x FAT table size)
+ Number of root directory sectors
For FAT32 the start address of the data
area is:-
Start address of
partition + Number of reserved sectors + (Number of FAT tables x FAT table
size)
For a given cluster number in the FAT
table, the start address of that sector is:-
data area start address + ((FAT
table cluster number – 2) x sectors per cluster)
Because sectors per cluster is restricted
to powers of 2 (1, 2, 4, 8, 16, 32…), division and multiplication by sectors
per cluster can actually be performed via shift operations which is often
faster than multiply or divide instructions
(Not applicable to FAT16)
The partition boot record specifies the
sector that contains this information block, which can be utilised by a FAT
driver to speed up write operations.
|
Byte
(Sector Start
+ #)
|
Value
|
|
0
|
0x0000
|
Signature = 0x41615252.
This validates that this is a File System Information
Sector.
|
|
1
|
0x0001
|
|
2
|
0x0002
|
|
3
|
0x0003
|
|
4
|
0x0004
|
480 reserved bytes
|
|
||
|
||
|
|
483
|
0x01E3
|
|
484
|
0x01E4
|
Signature = 0x61417272.
Another signature that is more localized in the sector to
the location of the fields that are used.
|
|
485
|
0x01E5
|
|
486
|
0x01E6
|
|
487
|
0x01E7
|
|
488
|
0x01E8
|
Number of Free Clusters on the volume.
Set to 0xFFFFFFFF if unknown and needs computing.
This should be range checked at least to make sure it is
<= volume cluster count.
|
|
489
|
0x01E9
|
|
490
|
0x01EA
|
|
491
|
0x01EB
|
|
492
|
0x01EC
|
It indicates the cluster number at which the driver should
start looking for free clusters – it is a hint for the FAT driver. Because a FAT32
FAT is large, it can be rather time consuming if there are a lot of allocated
clusters at the start of the FAT and the driver starts looking for a free
cluster starting at cluster 2. Typically this value is set to the last
cluster number that the driver allocated. If the value is 0xFFFFFFFF, then
there is no hint and the driver should start looking at cluster 2. Any other
value can be used, but should be checked first to make sure it is a valid
cluster number for the volume.
|
|
493
|
0x01ED
|
|
494
|
0x01EE
|
|
495
|
0x01EF
|
|
496
|
0x01F0
|
12 reserved bytes
|
|
||
|
||
|
|
507
|
0x01FB
|
|
508
|
0x01FC
|
Trailing signature = 0x000055AA
Used to validate that this is a File System Information
Sector.
|
|
509
|
0x01FD
|
|
510
|
0x01FE
|
|
511
|
0x01FF
|
Please visit the support section of the
embedded-code.com web site if you have any queries regarding this driver.
Please note that our support covers the use of this driver with the reference
designs in this manual. Where possible we will try to help solve any problems if
the code is used with other devices or compilers, but given the huge number of
devices and compilers available we are unable to guarantee 'out of the box'
compatibility. If you plan to use the source code with a different processor,
microcontroller and/or compiler you should ensure that you have sufficient
programming expertise to carry out any modifications that may be required to
the source code.
If you do encounter issues using the driver
with other compilers or devices and are able to give us details of the issue you
encountered we will try and include changes or notes across our range of
drivers to help other programmers avoid similar issues in the future. Please use the contact us page of our web site to report any such issues discovered.
V1.00
Original release
V1.01
Minor modifications for V1.02
firmware.
V1.02
Added sections on ‘Fast Reading
Of Bulk File Data’ and ‘Fast Writing Of Bulk File Data’.
Added ‘Searching
In The Directory’ section to demonstrate how it is possible to search in the
root directory for files.

Web: www.embedded-code.com
© Copyright embedded-code.com, United Kingdom
The information contained in this document
is subject to change without notice. Embedded-code.com makes no warranty of
any kind with regard to this material, including, but not limited to, the
implied warranties of fitness for a particular purpose.
Embedded-code.com shall not be liable for
errors contained herein or for incidental or consequential damages in
conjunction with the furnishing, performance or use of this material.