emFile User Guide & Reference Manual
CPU-independent file system for embedded applications.
Introduction to emFile
This section presents an overview of emFile, its structure,
and its capabilities.
What is emFile
emFile is a file system design for embedded applications which supports
NAND, DataFlash, NOR and SPI Flash, SD and MMC Memory Cards, RAM and USB mass
storage devices. emFile is a high performance library optimized for high
speed, versatility and a minimal memory footprint of both RAM and ROM.
It is written in ANSI C and can be used on any CPU.
Features
The main features of emFile are:
- Two file systems variants: FAT or SEGGER’s proprietary Embedded File System (EFS).
- FAT supports MS DOS/MS Windows-compatible FAT12, FAT16 and FAT32.
- EFS natively supports Long File Name (LFN). Add-on for FAT LFN available.
- Multiple device driver support; the same driver can support multiple storage media.
- Multiple media support; device drivers allow concurrent access to different storage media types.
- Cache support via RAM for optimized performance.
- Fail-safe and Task-safe, works with any operating system.
- ANSI C stdio.h-like API. Applications using standard C I/O library can easily be ported to emFile.
- Simple device driver structure, sample code trial versions and extensive API documentation.
- NAND Flash driver for SLC and MLC NAND and DataFlash with ECC and wear leveling.
- NOR Flash driver for NOR, SPI and QSPI Flash with wear leveling.
- Driver for Memory Card devices such as MMC, SD, SDHC, eMMC using bus and SPI mode.
- IDE Driver, Compact Flash, True-IDE and memory mapped mode.
- Journaling, RAID1 and RAID5 options to enhance data integrity.
- FAT Long File Name (LFN).
- Encryption (DES) and Extra Strong Encryption (DES and AES.)
- Profiling via SEGGER SystemView.
- Image creator tools for NOR and NAND.
- NAND flash evaluation board available.
- SQLite integration is available as sample upon request.
- MISRA C:2012 compliant.
- Support for Shift-JIS encoded Japanese file names.
- Support for GBK and Big5 encoded Chinese file names.
- Support for UHC encoded Korean file names.
- Support for files larger than 4 GBytes via BigFAT component.
Basic concepts
This section describes the software structure of emFile as well as
other general concepts such as fail safety and wear leveling.
emFile structure
emFile is organized in different layers as illustrated in the following
diagram. A short description of each layer’s functionality follows below.

API layer
The API layer is the interface between emFile and the user application.
It is divided in two parts storage API and file system API. The file system API
declares file functions in ANSI C standard I/O style, such as FS_FOpen(),
FS_FWrite() etc. The API layer transfers any calls to these functions
to the file system layer. Currently the FAT file system or an optional
file system, called EFS, are available for emFile. Both file systems
can be used simultaneously. The storage API declares the functions which
are required to initialize and access a storage medium. The storage API allows
sector read and write operations. The API layer transfers these calls to the
storage layer. The storage API is optimized for applications which do not
require file system functionality like file and directory handling.
A typical application which uses the storage API could be a USB mass storage
device, where data has to be stored on a medium, but all file system
functionality is handled by the host PC.
File system layer
The file system layer translates file operations to logical block (sector)
operations. After such a translation, the file system calls the logical block
layer and specifies the corresponding device driver for a device.
Storage layer
The main purpose of the Storage Layer is to synchronize accesses to a device
driver. Furthermore, it provides a simple interface for the File System API.
The Storage Layer calls a device driver to perform a block operation.
It also contains the cache mechanism.
Driver layer
Device drivers are low-level routines that are used to access sectors of the
device and to check status. It is hardware independent but depends
on the storage medium.
Hardware layer
These layer contains the low-level routines to access your hardware.
These routines simply read and store fixed length sectors. The structure
of the device driver is simple in order to allow easy integration
of your own hardware.
Choice of file system type: FAT vs. EFS
Within emFile, there is a choice among two different file systems.
The first, the FAT file system, is divided into three different sub types,
FAT12, FAT16 and FAT32. The other file system EFS, is a proprietary file system
developed by SEGGER. The choice of the suitable file system depends
on the environment in which the end application is to operate.
The FAT file system was developed by Microsoft to manage file segments, locate
available clusters and reassemble files for use. Released in 1976, the first
version of the FAT file system was FAT12, which is no longer widely used.
It was created for extremely small storage devices. (The early version of FAT12
did not support managing directories).
FAT16 is good for use on multiple operating systems because it is supported
by all versions of Microsoft Windows, including DOS and Linux. The newest
version, FAT32, improves upon the FAT16 file system by utilizing
a partition/disk much more efficiently. It is supported by all Microsoft Windows
versions newer than Windows 98 and as well on Linux based systems.
The EFS file system was added to emFile as an alternative to the FAT
file system and was specifically designed for embedded devices. This file system
uses the storage space dedicated to the file and directory names more efficiently
while still offering faster access to embedded storage devices. Another benefit
of EFS is that there are no issues concerning long file name (LFN) support.
The FAT file system was not designed for long file name support, limiting names
to twelve characters (8.3 format). LFN support may be added to any of the FAT
file systems. Long file names are inherent to this proprietary file system.
Fail safety
Fail safety is the feature of emFile that ensures the consistency of data
in case of unexpected loss of power during a write access to a storage medium.
emFile will be fail-safe only when both the file system (FAT/EFS) and the
device driver are fail-safe. The journaling add-on of emFile makes
the FAT/EFS file systems fail-safe. The device drivers of emFile are all
fail-safe by design. You can find detailed information about how the fail-safety
works in chapter Journaling and as part of the description
of individual device drivers.
Wear leveling
This is a feature of the NAND and NOR flash device drivers that increase
the lifetime of a storage medium by ensuring that all the storage blocks
are equally well used. The flash storage memories have a limited number
of program/erase cycles, typically around 100,000. The manufacturers do not
guarantee that the storage device will work properly once this limit
is exceeded. The wear leveling logic implemented in the device drivers tries
to keep the number of program-erase cycles of a storage block as low
as possible. You can find additional information in the description of the
respective device drivers.
Implementation notes
This section provides information about the implementation of emFile
File system configuration
The file system is designed to be configurable at runtime. This has various
advantages. Most of the configuration is done automatically; the linker builds
in only code that is required. This concept allows to put the file system in a
library. The file system does not need to be recompiled when the configuration
changes, e.g. a different driver is used. Compile time configuration is kept to
a minimum, primarily to select the level of multitasking support and the level
of debug information. For detailed information about configuration
of emFile, refer to Configuration of emFile.
Runtime memory requirements
Because the configuration is selected at runtime the amount of memory required
is not known at compile-time. For this reason a mechanism for runtime memory
assignment is required. Runtime memory is typically allocated when required
during the initialization and in most embedded systems never freed.
Initializing the file system
The first thing that needs to be done after the system start-up and before any
file system function can be used, is to call the function FS_Init(). This
routine initializes the internals of the file system. While initializing the
file system, you have to add your target device to the file system. The function
FS_X_AddDevices() adds and initializes the device.
FS_Init()
|
+-> FS_X_AddDevices()
|
+-> FS_AssignMemory()
|
+-> FS_AddDevice()
|
+-> Optional: Other configuration functions
Development environment (compiler)
The CPU used is of no importance; only an ANSI-compliant C compiler complying
with at least one of the following international standards is required:
- ISO/IEC/ANSI 9899:1990 (C90) with support for C++ style comments (//)
- ISO/IEC 9899:1999 (C99)
- ISO/IEC 14882:1998 (C++)
If your compiler has some limitations, let us know and we will inform you if
these will be a problem when compiling the software. Any compiler for
16/32/64-bit CPUs or DSPs that we know of can be used; most 8-bit compilers
can be used as well. A C++ compiler is not required, but can be used.
The application program can therefore also be programmed in C++ if desired.
Getting started
This chapter provides an introduction to using emFile. It explains how to
use the Windows sample, which is an easy way to get a first project with
emFile up and running.
Package content and installation
emFile is provided in source code and contains everything needed to compile
it on any platform. The following table shows the contents of the emFile package:
Files | Description |
Application | Sample applications. |
BSP | Support files for different evaluation boards |
Config | Configuration header files. |
Doc | emFile documentation. |
FS | emFile source code. |
Inc | Global header files. |
Linux | Utility applications for Linux. |
Sample | Sample drivers and applications. |
SEGGER | Utility source code. |
Simulation | Support files for PC simulation. |
Windows | Utility applications for Windows. |
FS_Start.* | PC simulation project MS Visual Studio / C++ and FAT. |
FS_EFS_Start.* | PC simulation project MS Visual Studio / C++ and EFS. |
FS_STORAGE_Start.* | PC simulation project MS Visual Studio / C++ and storage layer. |
emFile is shipped in electronic form in a .zip file. In order to
install it, extract the .zip file to any folder of your choice,
preserving the directory structure of the .zip file.
Using the Windows sample application
If you have MS Visual C++ 6.00 or any later version available, you will be able
to work with a Windows sample project using emFile. Even if you do not have the
Microsoft compiler, you should read this chapter in order to understand how an
application can use emFile.
Building the sample application
Open the workspace FS_Start.sln with MS Visual Studio (for example
double-clicking it). There is no further configuration necessary. You should
be able to build the application without any error or warning message.
Overview of the sample application
The sample project uses the RAM disk driver for demonstration. The main function
of the sample application Start.c calls the function MainTask().
MainTask() initializes the file system and executes some basic file system
operations. The sample application Start.c step-by-step:
void main(void);
void main(void) {
MainTask();
}
void MainTask(void) {
U32 v;
FS_FILE * pFile;
char ac[256];
char acFileName[32];
const char * sVolumeName = "";
FS_X_Log("Start\n");
//
// Initialize file system
//
FS_Init();
//
// Check if low-level format is required
//
FS_FormatLLIfRequired(sVolumeName);
//
// Check if volume needs to be high level formatted.
//
if (FS_IsHLFormatted(sVolumeName) == 0) {
FS_X_Log("High-level format\n");
FS_Format(sVolumeName, NULL);
}
sprintf(ac, "Running sample on \"%s\"\n", sVolumeName);
FS_X_Log(ac);
v = FS_GetVolumeFreeSpaceKB(sVolumeName);
if (v < 0x8000) {
sprintf(ac, " Free space: %lu KBytes\n", v);
} else {
v >>= 10;
sprintf(ac, " Free space: %lu MBytes\n", v);
}
FS_X_Log(ac);
sprintf(acFileName, "%s\\File.txt", sVolumeName);
sprintf(ac, " Write test data to file %s\n", acFileName);
FS_X_Log(ac);
pFile = FS_FOpen(acFileName, "w");
if (pFile) {
FS_Write(pFile, "Test", 4);
FS_FClose(pFile);
} else {
sprintf(ac, "Could not open file: %s to write.\n", acFileName);
FS_X_Log(ac);
}
v = FS_GetVolumeFreeSpaceKB(sVolumeName);
if (v < 0x8000) {
sprintf(ac, " Free space: %lu KBytes\n", v);
} else {
v >>= 10;
sprintf(ac, " Free space: %lu MBytes\n", v);
}
FS_X_Log(ac);
FS_Unmount(sVolumeName);
FS_X_Log("Finished\n");
while (1) {
;
}
}
Application start
main.c calls MainTask().
File system initialization
MainTask() initializes and adds a device to emFile.
Low-level formatting
Checks if volume is low-level formatted and formats if required.
High-level formatting
Checks if volume is high-level formatted and formats if required.
Volume name
Outputs the volume name.
Free space before operation
Calls FS_GetVolumeFreeSpace() and outputs the return value - the available
free space of the RAM disk - to console window.
File creation
Creates and opens a file test with write access (File.txt) on the device.
File write
Writes 4 bytes into the file and closes the file handle or outputs an error
message.
Free space after operation
Calls FS_GetVolumeFreeSpace() and outputs the return value - the available
free space of the RAM disk - again to console window.
End of application
Outputs a quit message and runs into an endless loop.
Stepping through the sample application
Application start
After starting the debugger by stepping into the application, your screen should
look like the screenshot below. The main function calls MainTask().

File system initialization
The first thing called from MainTask() is the emFile function
FS_Init(). This function initializes the file system and calls FS_X_AddDevices().
The function FS_X_AddDevices() is used to add and configure the used device
drivers to the file system. In the example configuration only the RAM disk
driver is added. FS_Init() must be called before using any other emFile
function. You should step over this function.

Low-level formatting
If the initialization was successful, FS_FormatLLIfRequired() is called.
It checks if the volume is low-level formatted and formats the volume if
required. You should step over this function.
High-level formatting
Afterwards FS_IsHLFormatted() is called. It checks if the volume is high-level
formatted and formats the volume if required. You should step over this function.
Volume name
The volume name is printed in the console window.
Free space before operation
The emFile function FS_GetVolumeFreeSpace() is called and the return
value is written into the console window.
File creation
Afterwards, you should get to the emFile function call FS_FOpen().
This function creates a file named File.txt in the root directory
of your RAM disk. Stepping over this function should return the address
of an FS_FILE structure. In case of any error, it would return 0, indicating
that the file could not be created.

File write
If FS_FOpen() returns a valid pointer to an FS_FILE structure, the sample
application will write a small ASCII string to this file by calling the
emFile function FS_Write(). Step over this function. If a problem occurs,
compare the return value of FS_Write() with the length of the ASCII string,
which should be written. FS_Write() returns the number of elements which have
been written. If no problem occurs the function emFile function
FS_FClose() should be reached. FS_FClose() closes the file handle for
File.txt. Step over this function.
Free space after operation
Continue stepping over until you reach the place where the function
FS_GetVolumeFreeSpace() is called. The emFile function
FS_GetVolumeFreeSpace() returns available free drive space in bytes.
After you step over this function, the variable v should have a value
greater than zero.
End of application
The return value is written in the console window.

Further source code examples
Further source code examples which demonstrate directory operations and
performance measuring are available. All emFile source code examples are
located in the Sample/FS/Application folder of the emFile shipment.
Recommended project structure
We recommend keeping emFile separate from your application files.
It is good practice to keep all the program files (including the
header files) together in the FS subdirectory of your project’s
root directory. This practice has the advantage of being very easy to
update to newer versions of emFile by simply replacing the FS
directory. Your application files can be stored anywhere.
Note
When updating to a newer emFile version as files may have been
added, moved or deleted, the project directories may need to be
updated accordingly.
Note
Always make sure that you have only one version of each file!
It is frequently a major problem when updating to a new version of emFile
if you have old files included and therefore mix different versions. If you keep
emFile in the directories as suggested (and only in these), this type of
problem cannot occur. When updating to a newer version, you should be able to
keep your configuration files and leave them unchanged. For safety reasons,
we recommend backing up (or at least renaming) the FS directories before
updating.
Running emFile on target hardware
This chapter explains how to integrate and run emFile on your target
hardware. It explains this process step-by-step.
Integrating emFile
The default configuration of emFile contains a single storage device:
a RAM disk. This should always be the first step to check if emFile
functions properly on your target hardware. We assume that you are familiar
with the tools you have selected for your development (compiler,
project manager, linker, etc.). You should therefore be able to add files,
add directories to the include search path, and so on. It is also assumed that
you are familiar with the OS that you will be using on your target system
(if you are using one). The SEGGER Embedded Studio IDE
(https://www.segger.com/embedded-studio.html)
is used in this document for all examples and screenshots, but every other
ANSI C toolchain can also be used. It is also possible to use makefiles;
in this case, when we say “add to the project”, this translates into
“add to the makefile”.
Procedure to follow
Integration of emFile is a relatively simple process, which consists of
the following steps:
- Step 1: Creating a start project without emFile.
- Step 2: Adding emFile to the start project.
- Step 3: Adding the device driver.
- Step 4: Activating the driver.
- Step 5: Adjusting the RAM usage.
Step 1: Creating a simple project without emFile
We recommend that you create a small “hello world” program for your system.
That project should already use your OS and there should be a way to display
text on a screen or serial port. If you are using the SEGGER embOS
(https://www.segger.com/products/rtos/embos/),
you can use the start project shipped with the embOS for this purpose.

Step 2: Adding emFile to the start project
Add all source files from the following directories (and their subdirectories)
to your project:
- Application (Only one file located in this directory has to be included)
- Config
- FS
- Sample/FS/OS (Only one file located in this directory has to be included
and only if the application uses an RTOS. The included file
must be compatible with the RTOS used).
- SEGGER
It is recommended to keep the provided folder structure.

Configuring the include path
The include path is the path in which the compiler looks for include files.
In cases where the included files (typically header files, .h)
do not reside in the same directory as the C file to compile, an include path
needs to be set. In order to build the project with all added files,
you will need to add the following directories to your include path:

Select the start application
For quick and easy testing of your emFile integration, start with the code
found in the Application folder of the shipment. Exclude all files in the
Application folder of your project except the supplied main.c
and FS_Start.c files.
The application performs the following steps:
- main.c calls MainTask().
- MainTask() initializes and adds a device to file system.
- Checks if volume is low-level formatted and formats if required.
- Checks if volume is high-level formatted and formats if required.
- Outputs the volume name.
- Calls FS_GetVolumeFreeSpace() and outputs the return value -- the available
total space of the RAM disk -- to console window.
- Creates and opens a file test with write access (File.txt)
on the storage device
- Writes 4 bytes of data into the file and closes the file handle
or outputs an error message.
- Calls FS_GetVolumeFreeSpace() and outputs the return value
-- the available free space of the RAM disk -- again to console window.
- Outputs a quit message and runs into an endless loop.
Build the project and test it
Build the project. It should compile without errors and warnings. If you
encounter any problem during the build process, check your include path and
your project configuration settings. The start application should print out
the storage space of the device twice, once before a file has been written
to the device and once afterwards.
Step 3: Adding the device driver
To configure emFile with a device driver, two modifications have to be performed:
- Adding device driver source to project.
- Adding hardware routines to project.
Each step is explained in the following sections. For example,
the implementation of the MMC/SD driver is shown, but all steps can easily be
adapted to every other device driver implementation.
Adding the device driver source to project
Add the driver sources to the project and add the directory to the include path.

Most drivers require additional hardware routines to work with the specific hardware.
If your driver requires low-level I/O routines to access the hardware, you will have to
provide them.
Drivers which require hardware routines are:
- NAND flash
- NOR flash with serial devices
- MMC/SD cards
- Compact flash / IDE
Drivers which do not require hardware routines are:
- NOR flash with CFI compliant devices
- RAM disk
Nearly all drivers have to be configured before they can be used. The runtime
configuration functions which specify for example the memory addresses and
the size of memory are located in the configuration file of the respective
driver. All required configurations are explained in the configuration section
of the respective driver. If you use one of the drivers which do not require
hardware routines skip the next section and refer to
Step 4: Activating the driver.
Adding hardware routines to project
A template with empty function bodies and in most cases one ore more sample
implementations are supplied for every driver that requires hardware routines.
The easiest way to start is to use one of the ready-to-use samples.
The ready-to-use samples can be found in the subfolders
Sample/FS/Driver/<DRIVER_DIR> of the emFile shipment where
DRIVER_DIR is the type of the device driver. You should check the
Readme.txt file located in the driver directory to see which samples
are included. If there is one which is a good or close match for your hardware,
it should be used. Otherwise, use the template to implement the hardware routines.
The template is a skeleton driver which contains empty implementations of the
required functions and is the ideal base to start the implementation of hardware
specific I/O routines.
What to do
Copy the compatible hardware function sample or the template into a subdirectory of
your work directory and add it to your project. The template file is located in the
Sample/FS/Driver/<DRIVER_DIR> folder; the example implementations are
located in the respective directories. If you start the implementation
of hardware routines with the hardware routine template, refer to
Device drivers for detailed information about the implementation
of the driver specific hardware functions, else refer to section
Step 4: Activating the driver.
Note
You cannot run and test the project with the new driver on your hardware
as long as you have not added the proper configuration file for the driver
to your project. Refer to section Step 4: Activating the driver
for more information about the activation of the driver with
the configuration file.
Step 4: Activating the driver
After adding the driver source, and if required the hardware function
implementation, copy the FS_Config<DRIVER_NAME>.c file (for example,
FS_ConfigMMC_CardMode.c for the MMC/SD card driver using card mode)
into the Config folder of your emFile work directory
and add it to your project.

The configuration files contain, all the runtime configuration functions of
the file system. The configuration files include a start configuration which
allows a quick and easy start with every driver. The most important function
for the beginning is FS_X_AddDevices(). It activates and configures the driver,
if required. A driver which does not require hardware routines has to be
configured before it can be used.
Modifying the runtime configuration
The following example a single CFI compliant NOR flash chip with a 16-bit
interface and a size of 256 Mbytes to the file system. The base address,
the start address and the size of the NOR flash are defined using the macros
FLASH0_BASE_ADDR, FLASH0_START_ADDR and FLASH0_SIZE.
Normally, only the “Defines, configurable” section of the configuration files
requires changes for typical embedded systems. The “Public code” section which
includes the time and date functions and FS_X_AddDevices() does not require
modifications on most systems.
/*********************************************************************
*
* Defines, configurable
*
* This section is the only section which requires changes for
* typical embedded systems using the NOR flash driver with a
* single device.
*
**********************************************************************
*/
#define ALLOC_SIZE 0x10000 // Size of memory dedicated to the file
// system. This value should be fine-tuned
// according for your system.
#define FLASH0_BASE_ADDR 0x40000000 // Base address of the NOR flash device
// to be used as storage
#define FLASH0_START_ADDR 0x40000000 // Start address of the first sector
// to be used as storage. If the entire
// device is used for file system,
// it is identical to
// the base address.
#define FLASH0_SIZE 0x200000 // Number of bytes to be used for storage
/*********************************************************************
*
* Static data.
*
* This section does not require modifications in most systems.
*
**********************************************************************
*/
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for semi-dynamic
// allocation in FS_AssignMemory().
/*********************************************************************
*
* Public code
*
* This section does not require modifications in most systems.
*
**********************************************************************
*/
/*********************************************************************
*
* FS_X_AddDevices
*
* Function description
* This function is called by the FS during FS_Init().
* It is supposed to add all devices, using primarily FS_AddDevice().
*/
void FS_X_AddDevices(void) {
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Add driver the NOR driver.
//
FS_AddDevice(&FS_NOR_Driver);
//
// Configure the NOR flash interface.
//
FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
FS_NOR_Configure(0, FLASH0_BASE_ADDR, FLASH0_START_ADDR, FLASH0_SIZE);
//
// Configure a read buffer for the file data.
//
FS_ConfigFileBufferDefault(512, 0);
}
After the driver has been added, the configuration functions (in this example
FS_NOR_SetPhyType() and FS_NOR_Configure()) should be called.
Detailed information about the driver configuration can be found
in the configuration section of the respective driver.
Refer to section Runtime configuration for detailed
information about the other runtime configurations of the file system.
Before compiling and running the sample application with the added driver,
you have to exclude FS_ConfigRAMDisk.c from the project.
Note
For the drivers which required hardware access routines, if you have only
added the template with empty function bodies until now, the project should
compile without errors or warning messages. But you can only run the project
on your hardware if you have finished the implementation of the hardware
functions.
Step 5: Adjusting the RAM usage
The file system needs RAM for management purposes in various places. The amount
of RAM required depends primarily on the configuration, especially the drivers
used. The drivers which have their own level of management
(such as NOR / NAND drivers) require in general more RAM than the “simple”
drivers such as for hard drives, compact flash or MMC/SD cards.
Every driver needs to allocate RAM. The file system allocates RAM in the
initialization phase and holds it while the file system is running. The macro
ALLOC_SIZE which is located in the respective driver configuration file
specifies the size of RAM used by the file system. This value should be
fine-tuned according to the requirements of your target system.
Per default, ALLOC_SIZE is set to a value which should be appropriate
for most target systems. Nevertheless, you should adjust it in order to avoid
wasting too much RAM. Once your file system project is up and running, you can
check the real RAM requirement of the driver via the public variable
FS_Global.MemManager.NumBytesAllocated. Check the value of
FS_Global.MemManager.NumBytesAllocated after the initialization
of the file system and after a volume has been mounted. At this point
FS_Global.MemManager.NumBytesAllocated can be used as reference for
the dynamic memory usage of emFile. You should reserve a few more bytes
for emFile as the value of FS_Global.MemManager.NumBytesAllocated
is at this point, since every file which is opened needs dynamic memory
for maintenance information. For more information about resource usage
of the file handlers, please refer to Dynamic RAM usage.
Note
If you define ALLOC_SIZE with a value which is smaller than the appropriate
size, the file system will run into FS_X_Panic(). If you define ALLOC_SIZE
with a value which is above the limits of your target system, the linker will
give an error during the build process of the project.
API functions
This chapter provides a detailed description of emFile API layer.
Any functions or data structures that are not described in this chapter but
are exposed through inclusion of the FS.h header file must be considered
private and subject to change.
Volume, file and directory names
A volume, file or directory name is a 0-terminated string the application can
use as a parameter to an API function (such as FS_FOpen()) to identify a volume,
file or directory the API function has to operate on.
A file or directory name contains the following mandatory and optional elements
where the optional elements are surrounded by []:
[VolumeName:[UnitNo:]][DirPath]FileName|DirName
- VolumeName is the name of the volume on which the file or directory
is located. If not specified, the first configured volume is assumed.
- UnitNo is the index of the volume on which the file or directory
is located. If not specified, the index 0 is assumed. It is not allowed to
specify a unit number if volume name has not been specified.
- DirPath is the complete directory path to an already existing
subdirectory. DirPath has to start and end with a directory delimiter
character. The names of directories in the path are also separated by directory
delimiter. The directory delimiter character can be configured at compile time
via FS_DIRECTORY_DELIMITER configuration define. The default directory delimiter
is the ’\’ character. The root directory is assumed if DirPath is not
specified. emFile does not support relative file or directory names
therefore the application has to always specify the full path a to a file or
directory.
- FileName or DirName is the name of the file or directory that
has to be accessed by the file system. If volume is formatted as FAT and the
support for long file name is not enabled, all file and directory names
directory names have to follow the standard FAT 8.3 naming convention.
The same applies to the directory names in DirPath.
EFS comes with native support for long file names. The length of a file
or directory name is limited to 235 valid characters.
A volume name contains the following mandatory and optional elements
where the optional elements are surrounded by []:
VolumeName:[UnitNo:]
VolumeName and UnitNo have the same meaning as described above.
Examples
The following examples specify the same file name assuming that the first driver
added to file system is the NAND driver.
- “DirName\FileName.txt”
- “nand:\DirName\FileName.txt”
- “nand:0:\DirName\FileName.txt”
The following examples specify the same volume name assuming that the first
driver added to file system is the NOR driver.
API function overview
The table below lists the available API functions within their respective categories.
File system control functions
FS_Init()
Description
Starts the file system.
Prototype
void FS_Init(void);
Additional information
FS_Init() initializes the file system and creates resources
required for the access of the storage device in
a multi-tasking environment. This function has to be called
before any other file system API function.
Example
#include "FS.h"
void SampleInit(void) {
FS_Init();
//
// Access file system
//
}
FS_DeInit()
Description
Frees allocated resources.
Prototype
void FS_DeInit(void);
Additional information
This function is optional. FS_DeInit() frees all resources
that are allocated by the file system after initialization.
Also, all static variables of all file system layers
are reset in order to guarantee that the file system remains
in a known state after deinitialization.The application can
call this function only after it called FS_Init().
This function has to be used when the file system is reset at
runtime. For example this is the case if the system uses a
software reboot which reinitializes the target application.
This function is available if the emFile sources are compiled
with the FS_SUPPORT_DEINIT configuration define set to 1.
Example
#include "FS.h"
void SampleDeInit(void) {
FS_Init();
//
// Access the file system...
//
FS_DeInit();
//
// The file system cannot be accessed anymore.
//
}
FS_Mount()
Description
Initializes a volume in default access mode.
Prototype
int FS_Mount(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | The name of a volume. If the empty string is specified, the first device in the volume table is used. |
Return value
= 0 | Volume is not mounted. |
= FS_MOUNT_RO | Volume is mounted read only. |
= FS_MOUNT_RW | Volume is mounted read/write. |
< 0 | Error code indicating the failure reason. Refer to FS_ErrorNo2Text(). |
Additional information
The storage device has to be mounted before being accessed for the
first time after file system initialization. The file system is
configured by default to automatically mount the storage device
at the first access in read / write mode. This function can be used to
explicitly mount the storage device if the automatic mount behavior
has been disabled via FS_SetAutoMount(). Refer to FS_SetAutoMount()
for an overview of the different automatic mount types.
Example
#include "FS.h"
void SampleMount(void) {
FS_Init();
//
// Mount default volume in read / write mode.
//
FS_Mount("");
//
// Access the data stored on the file system.
//
}
FS_MountEx()
Description
Initializes a volume in a specified access mode.
Prototype
int FS_MountEx(const char * sVolumeName,
U8 MountType);
Parameters
Parameter | Description |
sVolumeName | The name of the volume. If the empty string is specified, the first device in the volume table is used. |
MountType | Indicates how the volume has to be mounted. FS_MOUNT_RO Read only access. FS_MOUNT_RW Read / write access. |
Return value
= 0 | Volume is not mounted. |
= FS_MOUNT_RO | Volume is mounted read only. |
= FS_MOUNT_RW | Volume is mounted read/write. |
< 0 | Error code indicating the failure reason. Refer to FS_ErrorNo2Text(). |
Additional information
Performs the same operation as FS_Mount() while it allows the
application to specify how the storage device has to be mounted.
Example
#include "FS.h"
void SampleMountEx(void) {
FS_Init();
//
// Mount default volume in read-only mode.
//
FS_MountEx("", FS_MOUNT_RO);
//
// Access the data stored on the file system.
//
}
FS_SetAutoMount()
Description
Sets the automatic mount behavior.
Prototype
void FS_SetAutoMount(const char * sVolumeName,
U8 MountType);
Parameters
Parameter | Description |
sVolumeName | Pointer to a string containing the name of the volume. If the empty string is specified, the first device in the volume table is used. |
MountType | Indicates how the volume has to be mounted. FS_MOUNT_RO Allows to automatically mount the volume in read only mode. FS_MOUNT_RW Allows to automatically mount the volume in read / write mode. 0 Disables the automatic mount operation for the volume. |
Additional information
By default, the file system is configured to automatically mount
all volumes in read / write mode and this function can be used to
change the default automatic mount type or to disable the automatic
mounting.
Example
#include "FS.h"
void SampleSetAutoMount(void) {
FS_SetAutoMount("", FS_MOUNT_R); // Mount default volume in read-only mode.
}
FS_Sync()
Description
Saves cached information to storage.
Prototype
int FS_Sync(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Pointer to a string containing the name of the volume to be synchronized. If the empty string is specified, the first configured volume is used. |
Return value
= 0 | OK, volume synchronized |
≠ 0 | Error code indicating the failure reason. Refer to FS_ErrorNo2Text() for more information. |
Additional information
The function write the contents of write buffers and updates
the management information of all opened file handles to storage
device. All the file handles are left open. If configured,
FS_Sync() also writes to storage the changes present in the write
cache and in the journal. FS_Sync() can be called from the same
task as the one writing data or from a different task.
Example
#include "FS.h"
void SampleSync(void) {
FS_Sync(""); // Synchronize the default volume.
}
FS_Unmount()
Description
Synchronizes the data and marks the volume as not initialized.
Prototype
void FS_Unmount(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Pointer to a string containing the name of the volume to be unmounted. If the empty string is specified, the first device in the volume table is used. Can not be NULL. |
Additional information
This function closes all open files and synchronizes the volume,
that is writes all cached data to storage device.
FS_Unmount() hast to be called before a storage device is removed
to make sure that all the information cached by the file system
is updated to storage device. This function is also useful when
shutting down a system.
The volume is initialized again at the next call to any other
file system API function that requires access to storage device.
The application can also explicitly initialize the volume via
FS_Mount() or FS_MountEx().
Example
#include "FS.h"
void SampleUnmount(void) {
FS_Unmount(""); // Unmount the default volume.
}
FS_UnmountForced()
Description
Marks the volume as not initialized.
Prototype
void FS_UnmountForced(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Pointer to a string containing the name of the volume to be unmounted. If the empty string is specified, the first device in the volume table is used. |
Additional information
This function performs the same operations as FS_Unmount().
FS_UnmountForced() has to be called if a storage device has been
removed before it could be regularly unmounted. When using
FS_UnmountForced() there is no guarantee that the information
cached by the file system is updated to storage.
The volume is initialized again at the next call to any other
file system API function that requires access to storage device.
The application can also explicitly initialize the volume via
FS_Mount() or FS_MountEx().
Opened file handles are only marked as invalid but they are not
closed. The application has to close them explicitly by calling
FS_FClose().
Example
#include "FS.h"
#include "FS_OS.h"
void SampleUnmountForced(void) {
int IsPresentNew;
int IsPresent;
IsPresent = FS_GetVolumeStatus("");
while (1) {
IsPresentNew = FS_GetVolumeStatus("");
//
// Check if the presence status of the storage device has been changed.
//
if (IsPresentNew != IsPresent) {
if (IsPresentNew == FS_MEDIA_IS_PRESENT) {
FS_Mount("");
} else {
FS_UnmountForced("");
}
IsPresent = IsPresentNew;
}
FS_X_OS_Delay(500);
}
}
Volume mounting modes
Description
Modes for mounting a volume.
Definition
#define FS_MOUNT_RO FS_MOUNT_R
#define FS_MOUNT_RW (FS_MOUNT_R | FS_MOUNT_W)
Symbols
Definition | Description |
FS_MOUNT_RO | Read-only. Data can only be read from storage device. |
FS_MOUNT_RW | Read / Write. Data can be read form and written to storage device. |
File system configuration functions
The file system control functions listed in this section can only be used
in the runtime configuration phase. This means in practice that they can only
be called from within FS_X_AddDevices().
FS_AddDevice()
Description
Adds a driver to file system.
Prototype
FS_VOLUME *FS_AddDevice(const FS_DEVICE_TYPE * pDevType);
Parameters
Parameter | Description |
pDevType | in Pointer to a function table identifying the driver that has to be added. |
Return value
≠ 0 | OK, driver added. |
= 0 | An error occurred. |
Additional information
This function can be used to add a device or a logical driver
to file system. The application has to add at least one driver
to file system.
The function performs the following operations:
- Adds a physical device. This initializes the driver, allowing the driver to identify the storage device if required and to allocate memory for driver level management of the storage device. This makes sector operations possible.
- Assigns a logical volume to physical device. This makes it possible to mount the storage device, making it accessible for the file system and allowing file operations to be performed on it.
Example
#include "FS.h"
void FS_X_AddDevices(void) {
//
// Basic configuration of the file system...
//
//
// Add and configure a device driver for NAND flash.
//
FS_AddDevice(&FS_NAND_UNI_Driver);
//
// Additional configuration of the file system...
//
}
FS_AddPhysDevice()
Description
Adds a device to file system without assigning a volume to it.
Prototype
int FS_AddPhysDevice(const FS_DEVICE_TYPE * pDevType);
Parameters
Parameter | Description |
pDevType | in Pointer to a function table identifying the driver that has to be added. |
Return value
= 0 | OK, storage device added. |
≠ 0 | An error occurred. |
Additional information
This function can be used to add a device or a logical driver
to file system. It works similarly to FS_AddDevice() with the
difference that it does not assign a logical volume to storage
device. This means that the storage device is not directly
accessible by the application via the API functions of the file
system. An additional logical driver is required to be added
via FS_AddDevice() to make the storage device visible
to application.
FS_AddPhysDevice() initializes the driver, allowing the driver
to identify the storage device as far as required and allocate
memory required for driver level management of the device.
This makes sector operations possible.
FS_AssignMemory()
Description
Assigns a memory pool to the file system.
Prototype
void FS_AssignMemory(U32 * pData,
U32 NumBytes);
Parameters
Parameter | Description |
pData | in A pointer to the start of the memory region assigned to file system. |
NumBytes | Size of the memory pool assigned. |
Additional information
emFile comes with a simple semi-dynamic internal memory manager
that is used to satisfy the runtime memory requirements of the
file system. FS_AssignMemory() can be used to provide a memory
pool to the internal memory manager of the file system.
If not enough memory is assigned, the file system calls
FS_X_Panic() in debug builds which by default halts the execution
of the application. The actual number of bytes allocated is
stored in the global variable FS_Global.MemManager.NumBytesAllocated.
This variable can be used to fine-tune the size of the memory pool.
emFile supports also the use of an external memory manager
(e.g. via malloc() and free() functions of the standard C library).
The selection between the internal and the external memory
management has to be done at compile time via the
FS_SUPPORT_EXT_MEM_MANAGER define. The configuration of the
memory management functions is done via FS_SetMemHandler().
This function has to be called in the initialization phase
of the file system; typically in FS_X_AddDevices().
The support for internal memory management has to be enabled
at compile time by setting the FS_SUPPORT_EXT_MEM_MANAGER define
to 0. FS_AssignMemory() does nothing if the FS_SUPPORT_EXT_MEM_MANAGER
define is set to 1.
Example
#include "FS.h"
#define ALLOC_SIZE 0x1000
static U32 _aMemBlock[ALLOC_SIZE / 4];
void FS_X_AddDevices(void) {
FS_AssignMemory(_aMemBlock, sizeof(_aMemBlock));
//
// Perform additional file system configuration.
//
}
FS_ConfigFileBufferDefault()
Description
Configures the size and flags for the file buffer.
Prototype
int FS_ConfigFileBufferDefault(int BufferSize,
int Flags);
Parameters
Parameter | Description |
BufferSize | Size of the file buffer in bytes. |
Flags | File buffer operating mode. 0 Read file buffer. FS_FILE_BUFFER_WRITE Read / write file buffer. FS_FILE_BUFFER_ALIGNED Logical sector boundary alignment. |
Return value
= 0 | OK, the file buffer has been configured. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The function has to be called only once, in FS_X_AddDevices().
If called after FS_Init() the function does nothing and generates
a warning.
The file system allocates a file buffer of BufferSize bytes for
each file the application opens. The operating mode of the file
buffer can be changed at runtime via FS_SetFileBufferFlags().
If file buffers of different sizes are required
FS_SetFileBuffer() should be used instead.
For best performance it is recommended to set the size of the
file buffer to be equal to the size of the logical sector.
Smaller file buffer sizes can also be used to reduce the RAM
usage.
FS_SetFileBuffer() is available if the emFile sources are
compiled with the FS_SUPPORT_FILE_BUFFER configuration
define set to 1.
Example
#include "FS.h"
#define ALLOC_SIZE 0x1000
static U32 _aMemBlock[ALLOC_SIZE / 4];
void FS_X_AddDevices(void) {
FS_AssignMemory(_aMemBlock, sizeof(_aMemBlock));
//
// Set the file buffer of 512 bytes for read and write operations.
// The file buffer is allocated at runtime for each opened file
// from _aMemBlock.
//
#if (FS_USE_FILE_BUFFER || FS_SUPPORT_FILE_BUFFER)
FS_ConfigFileBufferDefault(512, FS_FILE_BUFFER_WRITE);
#endif
}
FS_LOGVOL_Create()
Description
Creates a driver instance.
Prototype
int FS_LOGVOL_Create(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to create. |
Return value
= 0 | OK, volume has been created. |
≠ 0 | An error occurred. |
Additional information
This function creates an instance of a logical volume.
A logical volume is the representation of one or more physical devices
as a single device. It allows treating multiple physical devices as one
larger device. The file system takes care of selecting the correct
location on the correct physical device when reading from or writing to
the logical volume. Logical volumes are typically used if multiple flash
devices (NOR or NAND) are present, but they should be presented
to the application in the same way as a single device with the combined
capacity of both.
sVolumeName is the name that has to be assigned to the logical
volume. This is the volume name that is passed to some of
the FS API functions and that has to be used in a file path.
FS_LOGVOL_Create() does nothing if the module is configured
to work in driver mode by setting the FS_LOGVOL_SUPPORT_DRIVER_MODE
define option to 1. In this case a logical driver is created
by adding it via FS_AddDevice() to file system.
Normally, all devices are added individually using FS_AddDevice().
This function adds the devices physically as well as logically to the file system.
In contrast to adding all devices individually, all devices can be combined
in a logical volume with a total size of all combined devices.
To create a logical volume the following steps have to be performed:
1. The storage device has to be physically added to the file system using
FS_AddPhysDevice().
2. A logical volume has to be created using FS_LOGVOL_Create().
3. The devices which are physically added to the file system have to be
added to the logical volume using FS_LOGVOL_AddDevice().
FS_LOGVOL_AddDevice()
Description
Adds a storage device to a logical volume.
Prototype
int FS_LOGVOL_AddDevice(const char * sVolumeName,
const FS_DEVICE_TYPE * pDeviceType,
U8 DeviceUnit,
U32 StartSector,
U32 NumSectors);
Parameters
Parameter | Description |
sVolumeName | Name of the logical volume. |
pDeviceType | Type of the storage device that has to be added. |
DeviceUnit | Index of the storage device that has to be added (0-based). |
StartSector | Index of the first sector that has to be used as storage (0-based). |
NumSectors | Number of sectors that have to be used as storage. |
Return value
= 0 | OK, storage device added. |
≠ 0 | An error occurred. |
Additional information
Only devices with an identical sector size can be combined to a logical volume.
All additionally added devices need to have the same sector size as the first
physical device of the logical volume.
This function does nothing if FS_LOGVOL_SUPPORT_DRIVER_MODE is set to 1.
FS_SetFileBufferFlags()
Description
Changes the operating mode of the file buffer.
Prototype
int FS_SetFileBufferFlags(FS_FILE * pFile,
int Flags);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
Flags | File buffer operating mode. 0 Read file buffer. FS_FILE_BUFFER_WRITE Read / write file buffer. FS_FILE_BUFFER_ALIGNED Logical sector boundary alignment. |
Return value
= 0 | OK, file buffer flags changed. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function can only be called immediately after FS_FOpen(),
to change the operating mode of the file buffer (read or
read / write).
FS_SetFileBufferFlags() is available if the emFile sources are
compiled with the FS_SUPPORT_FILE_BUFFER configuration define set to 1.
Example
#include "FS.h"
void SampleSetFileBufferFlags(void) {
FS_FILE * pFile;
U8 abData[16];
pFile = FS_FOpen("Test.txt", "w");
if (pFile != NULL) {
memset(abData, 'a', sizeof(abData));
FS_SetFileBufferFlags(pFile, FS_FILE_BUFFER_WRITE);
FS_Write(pFile, abData, sizeof(abData));
FS_FClose(pFile);
}
}
FS_SetFileBufferFlagsEx()
Description
Changes the operating mode of the file buffer.
Prototype
int FS_SetFileBufferFlagsEx(const char * sVolumeName,
int Flags);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which to set the flags. |
Flags | File buffer operating mode. 0 Read file buffer. FS_FILE_BUFFER_WRITE Read / write file buffer. FS_FILE_BUFFER_ALIGNED Logical sector boundary alignment. |
Return value
= 0 | OK, operating mode changed. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function can be used to change the operating mode of
the file buffer for the files that are located on a specific
volume.
FS_SetFileBufferFlagsEx() is available if the emFile sources are
compiled with the FS_SUPPORT_FILE_BUFFER configuration define
set to 1.
FS_SetFileWriteMode()
Description
Configures the file write mode.
Prototype
void FS_SetFileWriteMode(FS_WRITEMODE WriteMode);
Parameters
Parameter | Description |
WriteMode | Specifies how to write to file: FS_WRITEMODE_SAFE Updates the allocation table and the directory entry at each write to file operation. FS_WRITEMODE_MEDIUM Updates the allocation table at each write to file operation. FS_WRITEMODE_FAST The allocation table and directory entry are updated when the file is closed. |
Additional information
This function can be called to configure which mode the file system
has to use when writing to a file. The file system uses by default
FS_WRITEMODE_SAFE which allows the maximum fail-safe behavior,
since the allocation table and the directory entry is updated on
every write operation to file.
If FS_WRITEMODE_FAST is set, the update of the allocation table
is performed using a special algorithm. When writing to the file
for the first time, the file system checks how many clusters in series
are empty starting with the first one occupied by the file.
This cluster chain is remembered, so that if the file grows and
needs an additional cluster, the allocation doesn’t have to be
read again in order to find the next free cluster. The allocation table
is only modified if necessary, which is the case when:
- All clusters of the cached free-cluster-chain are occupied.
- The volume or the file is synchronized that is when FS_Sync(), FS_FClose(), or FS_SyncFile() is called.
- A different file is written.
Especially when writing large amounts of data, FS_WRITEMODE_FAST allows
maximum performance, since usually the file system has to search for
a free cluster in the allocation table and link it with the last one
occupied by the file. In worst case, multiple sectors of the allocation
table have to be read in order to find a free cluster.
Example
#include "FS.h"
void FS_X_AddDevices(void) {
//
// Configure the file system to write as fast as possible
// to all files on all volumes.
//
FS_SetFileWriteMode(FS_WRITEMODE_FAST);
//
// Perform other file system configuration...
//
}
FS_SetFileWriteModeEx()
Description
Configures the write mode of a specified volume.
Prototype
int FS_SetFileWriteModeEx( FS_WRITEMODE WriteMode,
const char * sVolumeName);
Parameters
Parameter | Description |
WriteMode | Specifies how to write to file: FS_WRITEMODE_SAFE Updates the allocation table and the directory entry at each write to file operation. FS_WRITEMODE_MEDIUM Updates the allocation table at each write to file operation. FS_WRITEMODE_FAST The allocation table and directory entry are updated when the file is closed. |
sVolumeName | Identifies the volume for which the write mode has to be changed. |
Return value
= 0 | OK, write mode set. |
≠ 0 | Error code inidicating the failure reason. |
Additional information
When not explicitly set using this function the write mode of a
volume is the write mode set via FS_SetFileWriteMode() or the
default write mode (FS_WRITEMODE_SAFE). FS_SetFileWriteModeEx()
is typically on file system configurations using multiple volumes
that require different write modes. For example on a file system
configured to use two volumes where one volume has to be configured
for maximum write performance (FS_WRITEMODE_FAST) while on the other
volume the write operation has to be fail-safe (FS_WRITEMODE_SAFE).
Refer to FS_SetFileWriteMode() for detailed information about
the different write modes.
Example
#include "FS.h"
void FS_X_AddDevices(void) {
//
// Configure the file system to write as fast as possible
// to all files on the "nand:0:" volume.
//
FS_SetFileWriteModeEx(FS_WRITEMODE_FAST, "nand:0");
//
// Perform other file system configuration...
//
}
FS_SetMemHandler()
Description
Configures functions for memory management.
Prototype
void FS_SetMemHandler(FS_MEM_ALLOC_CALLBACK * pfAlloc,
FS_MEM_FREE_CALLBACK * pfFree);
Parameters
Parameter | Description |
pfAlloc | Pointer to a function that allocates memory (e.g. malloc()). It cannot be NULL. |
pfFree | Pointer to a function that frees memory (e.g. free()). It cannot be NULL. |
Additional information
The application can use this function to configure functions
for the memory management. The file system calls pfAlloc
to allocate memory and pfFree to release the allocated memory.
This function has to be called in the initialization phase
of the file system; typically in FS_X_AddDevices().
The support for external memory management has to be enabled
at compile time by setting the FS_SUPPORT_EXT_MEM_MANAGER define
to 1. FS_SetMemHandler() does nothing if FS_SUPPORT_EXT_MEM_MANAGER
is set to 0 (default).
Example
#include <stdlib.h>
#include "FS.h"
void FS_X_AddDevices(void) {
#if FS_SUPPORT_EXT_MEM_MANAGER
//
// Configure functions for dynamic memory allocation.
//
FS_SetMemHandler((FS_MEM_ALLOC_CALLBACK *)malloc, free);
#endif // FS_SUPPORT_EXT_MEM_MANAGER
//
// Configure the file system...
//
}
FS_SetMaxSectorSize()
Description
Configures the maximum size of a logical sector.
Prototype
int FS_SetMaxSectorSize(unsigned MaxSectorSize);
Parameters
Parameter | Description |
MaxSectorSize | Number of bytes in the logical sector. |
Return value
= 0 | OK, the sector size had been set. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The file system uses internal RAM buffers to store the data of
logical sectors it accesses. The storage devices added to file
system can have different logical sector sizes. Since the size
of the logical sectors is not known at the time the internal RAM
buffers are allocated the application has to call
FS_SetMaxSectorSize() to specify the size of the largest logical
sector used by the configured drivers.
The default value for the maximum size of a logical sector
is 512 bytes. The size of the logical sector supported by a
driver can be found in the section that describes the specific
driver.
FS_SetMaxSectorSize() can be called only at file system
initialization in FS_X_AddDevices().
Example
#include "FS.h"
void FS_X_AddDevices(void) {
//
// This function call is typically required when
// a NAND flash with 2048 byte pages is used as
// storage device.
//
FS_SetMaxSectorSize(2048);
}
FS_MEM_ALLOC_CALLBACK
Description
Type of function called by the file system to allocate memory
dynamically.
Type definition
typedef void * FS_MEM_ALLOC_CALLBACK(U32 NumBytes);
Parameters
Parameter | Description |
NumBytes | Number of bytes to be allocated. |
Return value
≠ NULL | OK, pointer to the allocated memory block. |
= NULL | Error, could not allocate memory. |
Additional information
The callback function has the same signature as the malloc() standard C
function. The application can register the callback function via
FS_SetMemHandler().
FS_MEM_FREE_CALLBACK
Description
Type of function called by the file system to release dynamically
allocated memory.
Type definition
typedef void FS_MEM_FREE_CALLBACK(void * pData);
Parameters
Parameter | Description |
pData | Memory block to be released. |
Additional information
The callback function has the same signature as the free() standard C
function. The application can register the callback function via
FS_SetMemHandler(). pMem points to a memory block that was allocated
using a call to pfAlloc callback function registered via FS_SetMemHandler().
FS_WRITEMODE
Description
Modes of writing to file.
Type definition
typedef enum {
FS_WRITEMODE_SAFE,
FS_WRITEMODE_MEDIUM,
FS_WRITEMODE_FAST,
FS_WRITEMODE_UNKNOWN
} FS_WRITEMODE;
Enumeration constants
Constant | Description |
FS_WRITEMODE_SAFE | Allows maximum fail-safe behavior. The allocation table and the directory entry are updated after each write access to file. This write mode provides the slowest performance. |
FS_WRITEMODE_MEDIUM | Medium fail-safe. The allocation table is updated after each write access to file. The directory entry is updated only if file is synchronized that is when FS_Sync(), FS_FClose(), or FS_SyncFile() is called. |
FS_WRITEMODE_FAST | This write mode provided the maximum performance. The directory entry is updated only if the file is synchronized that is when FS_Sync(), FS_FClose(), or FS_SyncFile() is called. The allocation table is modified only if necessary. |
FS_WRITEMODE_UNKNOWN | End of enumeration (for internal use only) |
File access functions
The functions in this section can be used to access the data stored in a file.
FS_FClose()
Description
Closes an opened file.
Prototype
int FS_FClose(FS_FILE * pFile);
Parameters
Parameter | Description |
pFile | Handle to the file to be closed. |
Return value
= 0 | OK, file handle has been successfully closed. |
≠ 0 | Error code indicating the failure reason. Refer to FS_ErrorNo2Text(). |
Example
#include "FS.h"
void SampleFClose(void) {
FS_FILE * pFile;
pFile = FS_FOpen("Test.txt", "r");
if (pFile) {
//
// Access file.
//
FS_FClose(pFile);
}
}
FS_FGets()
Description
Reads a line of text from file.
Prototype
char *FS_FGets(char * sData,
int SizeOfData,
FS_FILE * pFile);
Parameters
Parameter | Description |
sData | out Buffer that receives the data read from file. It cannot be NULL. |
SizeOfData | Number of bytes in sData. It cannot be 0. |
pFile | Handle to opened file. It cannot be NULL. |
Return value
≠ NULL | OK, data read successfully. The returned value is sData buffer. |
= NULL | An error occurred. |
Additional information
This function starts reading from the current position in the file
and advances the current file position by the number of bytes read.
FS_FGets() returns when either a line terminator is read from file
and stored to sData, SizeOfData - 1 bytes are stored to sData
or the end of file is reached. The data stored to sData is 0-terminated.
A line terminator can be either a single Line Feed character (0x0A),
a single Carriage Return character (0x0D) or a Carriage Return
and Line Feed character sequence (0x0D 0x0A).
The file to read from has to be opened with read permissions.
For more information about open modes refer to FS_FOpen().
The application can check for the actual error using FS_FError().
Example
#include "FS.h"
void SampleFGets(void) {
FS_FILE * pFile;
char ac[128];
char * s;
pFile = FS_FOpen("Test.txt", "r");
if (pFile != NULL) {
for (;;) {
s = FS_FGets(ac, sizeof(ac), pFile);
if (s == NULL) {
break;
}
}
FS_FClose(pFile);
}
}
FS_FOpen()
Description
Opens an existing file or creates a new one.
Prototype
FS_FILE *FS_FOpen(const char * sFileName,
const char * sMode);
Parameters
Parameter | Description |
sFileName | Name of the file to be opened or created. It is a 0-terminated string that cannot be NULL. |
sMode | Indicates how the file should be opened. It is a 0-terminated string that cannot be NULL. |
Return value
≠ 0 | OK, pointer to a file handle that identifies the opened file. |
= 0 | Error, unable to open the file. |
Additional information
The sMode parameter can take one of the following values:
sMode | Description |
“r” or “rb” | Open files for reading. |
“w” or “wb” | Truncates to zero length or creates file for writing. |
“a” or “ab” | Appends; opens / creates file for writing at end of file. |
“r+”, “r+b” or “rb+” | Opens file for update (reading and writing). |
“w+”, “w+b” or “wb+” | Truncates to zero length or creates file for update. |
“a+”, “a+b” or “ab+” | Appends; opens / creates file for update, writing at end of file. |
For more details about FS_FOpen(), refer to the ANSI C
documentation of the fopen() function.
The file system does not distinguish between binary and text mode;
the files are always accessed in binary mode.
In order to use long file names with FAT, the FS_FAT_SupportLFN()
has to be called before after the file system is initialized.
FS_FOpen() accepts file names encoded in UTF-8 format. This feature
is disabled by default. To enable it the file system has to be compiled
with the FS_FAT_SUPPORT_UTF8 configuration define to 1. Additionally,
the support for long file names has to be enabled for volumes
formatted as FAT.
Example
#include "FS.h"
void SampleOpenFile(void) {
FS_FILE * pFile;
//
// Opens for reading a file on the default volume.
//
pFile = FS_FOpen("Test.txt", "r");
//
// Opens for writing a file on the default volume.
//
pFile = FS_FOpen("Test.txt", "w");
//
// Opens for reading a file in folder "SubDir" on the default volume.
// The directory delimiter is the '\' character.
//
pFile = FS_FOpen("\\SubDir\\Test.txt", "r");
//
// Opens for reading a file on the first RAM disk volume.
//
pFile = FS_FOpen("ram:Test.txt", "r");
//
// Opens for reading a file on the second RAM disk volume.
//
pFile = FS_FOpen("ram:1:Test.txt", "r");
//
// Opens for writing a file with a long name for writing.
//
FS_FAT_SupportLFN();
pFile = FS_FOpen("Long file name.text", "w");
//
// Opens for writing a file with a name encoded in UTF-8 format.
// The file system has to be compiled with FS_FAT_SUPPORT_UTF8 define
// set to 1. The name contains the following characters:
// small a, umlaut mark
// small o, umlaut mark
// small sharp s
// small u, umlaut mark
// '.'
// 't'
// 'x'
// 't'
//
FS_FAT_SupportLFN();
pFile = FS_FOpen("\xC3\xA4\xC3\xB6\xC3\x9F\xC3\xBC.txt", "w");
}
FS_FOpenEx()
Description
Opens an existing file or creates a new one.
Prototype
int FS_FOpenEx(const char * sFileName,
const char * sMode,
FS_FILE ** ppFile);
Parameters
Parameter | Description |
sFileName | Name of the file to be opened or created. It is a 0-terminated string that cannot be NULL. |
sMode | Indicates how the file should be opened. It is a 0-terminated string that cannot be NULL. |
ppFile | Pointer to a file handle pointer that receives the opened file handle. |
Return value
= 0 | OK, file opened. |
≠ 0 | Error code indicating the failure reason. |
Additional information
For additional information about the sMode parameter refer
to FS_FOpen().
Example
#include <stdio.h>
#include "FS.h"
FS_FILE * pFile;
/*********************************************************************
*
* SampleFOpenEx
*
* Function description
* Opens for reading a file on the default volume.
*/
void SampleFOpenEx(void) {
int r;
char ac[100];
r = FS_FOpenEx("Test.txt", "r", &pFile);
if (r) {
SEGGER_snprintf(ac, sizeof(ac), "Could not open file (Reason: %s)\n",
FS_ErrorNo2Text(r));
FS_X_Log(ac);
}
}
FS_FPrintf()
Description
Writes a formatted string to a file.
Prototype
int FS_FPrintf( FS_FILE * pFile,
const char * sFormat,
...);
Parameters
Parameter | Description |
pFile | Opened file handle. It cannot be NULL. |
sFormat | Format of the data to be written (0-terminated string). It cannot be NULL. |
Return value
≥ 0 | OK, number of bytes written to file. |
< 0 | Error code indicating the failure reason. |
Additional information
This function works in the same way as the fprintf() standard C
library function. It formats the data according to sFormat
and then writes the formatted string to pFile. The format
specification is identical to that of fprintf(). FS_FPrintf()
relies on SEGGER_vsnprintfEx() to perform the actual formatting.
The file position is advanced by the number of bytes written.
FS_FPrintf() uses a buffer allocated on the stack for the
formatting of the data. The size of this buffer can be configured
via FS_BUFFER_SIZE_FILE_PRINT and it has to be at least 1 byte large.
Example
#include "FS.h"
void SampleFPrintf(void) {
FS_FILE * pFile;
int i;
pFile = FS_FOpen("Test.txt", "w");
if (pFile != NULL) {
for (i = 0; i < 10; ++i) {
FS_FPrintf(pFile, "Counter value: %d\n", i);
}
FS_FClose(pFile);
}
}
FS_FPuts()
Description
Writes a 0-terminated string to a file.
Prototype
int FS_FPuts(const char * sData,
FS_FILE * pFile);
Parameters
Parameter | Description |
sData | Data to be written (0-terminated string). It cannot be NULL. |
pFile | Opened file handle. It cannot be NULL. |
Return value
= 0 | OK, data written successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function works in the same way as the fputs() standard C
library function. It writes the 0-terminated string sData to
the file pFile. The 0-terminator is not written to file.
The file position is advanced by the number of bytes written.
Example
#include "FS.h"
const char acText[] = "Hello world\n";
void SampleFPuts(void) {
FS_FILE * pFile;
pFile = FS_FOpen("Test.txt", "w");
if (pFile != NULL) {
FS_FPuts(acText, pFile);
FS_FClose(pFile);
}
}
FS_FRead()
Description
Reads data from file.
Prototype
U32 FS_FRead(void * pData,
U32 ItemSize,
U32 NumItems,
FS_FILE * pFile);
Parameters
Parameter | Description |
pData | Buffer that receives the data read from file. |
ItemSize | Size of one item to be read from file (in bytes). |
NumItems | Number of items to be read from the file. |
pFile | Handle to opened file. It cannot be NULL. |
Return value
Number of items read.
Additional information
The file has to be opened with read permissions.
For more information about open modes refer to FS_FOpen().
The application has to check for possible errors using FS_FError()
if the number of items actually read is different than the number
of items requested to be read by the application.
The data is read from the current position in the file that is
indicated by the file pointer. FS_FRead() moves the file pointer
forward by the number of bytes successfully read.
Example
#include "FS.h"
char acBuffer[100];
void SampleFRead(void) {
FS_FILE * pFile;
U32 NumItems;
int ErrCode;
pFile = FS_FOpen("Test.txt", "r");
if (pFile) {
NumItems = FS_FRead(acBuffer, 1, sizeof(acBuffer), pFile);
if (NumItems != sizeof(acBuffer)) {
ErrCode = FS_FError(pFile);
if (ErrCode) {
//
// An error occurred during the read operation.
//
}
}
FS_FClose(pFile);
}
}
FS_FSeek()
Description
Sets the current position in file.
Prototype
int FS_FSeek(FS_FILE * pFile,
FS_FILE_OFF Offset,
int Origin);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
Offset | Byte offset for setting the file pointer position. |
Origin | Indicates how the file pointer has to be moved. |
Return value
= 0 | OK, file pointer has been positioned according to the specified parameters. |
≠ 0 | Error code indicating the failure reason. |
Additional information
FS_FSeek() moves the file pointer to a new location by a number
of bytes relative to the position specified by the Origin
parameter. The Origin parameter can take the values specified
by the FS_SEEK_… defines
The file pointer can be repositioned anywhere in the file.
It is also possible to reposition the file pointer beyond
the end of the file. This feature is used together with
FS_SetEndOfFile() to reserve space for a file
(preallocate the file).
Alternative name
FS_SetFilePos
Example
#include "FS.h"
const char acText[]="Some text will be overwritten";
void SampleFTell(void) {
FS_FILE * pFile;
pFile = FS_FOpen("Test.txt", "w");
if (pFile) {
//
// Write the data to file.
//
FS_FWrite(acText, 1, strlen(acText), pFile);
//
// Move the file pointer back 4 bytes from the current
// position in file. The data stored in the file looks
// like this: "Some text will be overwritten"
//
FS_FSeek(pFile, -4, FS_SEEK_CUR);
//
// The write operation overwrites the last
// 4 characters that is "tten" of the data
// written in the previous call to FS_FWrite().
//
FS_FWrite(acText, 1, strlen(acText), pFile);
//
// The data in the file looks now like this:
// "Some text will be overwriSome text will be overwritten"
//
FS_FClose(pFile);
}
}
FS_FWrite()
Description
Writes data to file.
Prototype
U32 FS_FWrite(const void * pData,
U32 ItemSize,
U32 NumItems,
FS_FILE * pFile);
Parameters
Parameter | Description |
pData | Data to be written to file. |
ItemSize | Size of an item to be written to file (in bytes). |
NumItems | Number of items to be written to file. |
pFile | Handle to opened file. It cannot be NULL. |
Return value
Number of elements written.
Additional information
The file has to be opened with write permissions.
For more information about open modes refer to FS_FOpen().
The application has to check for possible errors using FS_FError()
if the number of items actually written is different than
the number of items requested to be written by the application.
The data is written at the current position in the file that is
indicated by the file pointer. FS_FWrite() moves the file pointer
forward by the number of bytes successfully written.
Example
#include "FS.h"
const char acText[] = "Hello world\n";
void SampleFWrite(void) {
FS_FILE * pFile;
pFile = FS_FOpen