emFile
User Guide & Reference Manual
Document: UM02001
Software Version: 5.34.0
Document revision: 0
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.
Warning
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.
Warning
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 in addition to main.c 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
NOR_BASE_ADDR, NOR_START_ADDR and NOR_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
*
**********************************************************************
*/
#define ALLOC_SIZE 0x10000 // Size of memory pool provided
// to the file system for
// semi-dynamic memory allocation.
// This value should be fine-tuned
// according for your system.
#define NOR_BASE_ADDR 0x40000000 // Base address of the NOR flash
// device to be used as storage
#define NOR_START_ADDR 0x40000000 // Address of the first NOR physical
// sector to be used as storage.
// If the entire NOR flash device
// has to be used by file system,
// then this value is identical
// to the base address.
#define NOR_SIZE 0x200000 // Number of bytes to be used
// as storage.
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for semi-dynamic
// allocation of the file system.
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* FS_X_AddDevices
*
* Function description
* Configures the file system.
*
* Additional information
* This function is called during the file system initialization.
*/
void FS_X_AddDevices(void) {
//
// Provide the file system memory to work with.
//
FS_AssignMemory(_aMemBlock, sizeof(_aMemBlock));
//
// Add and configure driver the NOR driver.
//
FS_AddDevice(&FS_NOR_Driver);
FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
FS_NOR_Configure(0, NOR_BASE_ADDR, NOR_START_ADDR, NOR_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 maximum length of a file or directory name can be configured via the
FS_MAX_PATH configuration define.
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 | Specifies 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 | Specifies 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. |
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.
Flags is a bitwise-or combination of File buffer flags.
If Flags is set to 0 then the file buffer caches only the
data read from the file.
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. |
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 the file is
opened and before performing any operation on the file.
Flags is a bitwise-or combination of File buffer flags.
If Flags is set to 0 then the file buffer caches only the
data read from the file.
FS_SetFileBufferFlags() is only available if the file system is built
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. |
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.
Flags is a bitwise-or combination of File buffer flags.
If Flags is set to 0 then the file buffer caches only the
data read from the file.
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 indicating 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” | Opens file for reading. |
“w” or “wb” | Truncates to zero length or creates file for writing. |
“a” or “ab” | Opens or creates file for writing at end of file. |
“r+”, “r+b” or “rb+” | Opens file for reading and writing. |
“w+”, “w+b” or “wb+” | Truncates file to zero length or creates file for reading and writing. |
“a+”, “a+b” or “ab+” | Opens or creates file for reading and 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,
I32 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 File positioning reference.
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 SampleFSeek(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_FSeek64()
Description
Modifies the current position in a file.
Prototype
int FS_FSeek64(FS_FILE * pFile,
I64 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
This function moves the file pointer to a new location by a number
of bytes specified via the Offset parameter and relative to a
position specified via the Origin parameter. The Origin parameter
can take the values specified by File positioning reference.
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 can be used together with
FS_SetEndOfFile() to reserve space for a file, also known as
file preallocation.
This function performs the same operation as FS_FSeek() with the
difference that the set file position can be greater than or equal
to 232. This makes FS_Seek64() suitable for setting
the position in a file that is larger than or equal to 4 GB.
This function is available only when the file system is built with
FS_SUPPORT_LARGE_FILES set to 1.
Example
#include "FS.h"
const char acText[]="Some text will be overwritten";
void SampleFSeek64(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_FSeek64(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("Test.txt", "w");
if (pFile != NULL) {
FS_FWrite(acText, 1, strlen(acText), pFile);
FS_FClose(pFile);
}
}
FS_FTell()
Description
Returns current position in file.
Prototype
I32 FS_FTell(FS_FILE * pFile);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
Return value
≠ 0xFFFFFFFF | OK, current position of the file pointer. |
= 0xFFFFFFFF | An error occurred. |
Additional information
The function returns the file position as a signed value
for compatibility reasons. The return value has to be
treated as a 32-bit unsigned with the value 0xFFFFFFFF
indicating an error.
This function simply returns the file pointer member of the
file handle structure pointed by pFile. Nevertheless, you should
not access the FS_FILE structure yourself, because that data
structure may change in the future.
In conjunction with FS_FSeek(), this function can also be used
to examine the file size. By setting the file pointer to the end
of the file using FS_SEEK_END, the length of the file can now be
retrieved by calling FS_FTell(). Alternatively the FS_GetFileSize()
function can be used.
Alternative name
FS_GetFilePos
Example
#include "FS.h"
const char acText[]="Hello world\n";
void SampleFTell(void) {
FS_FILE * pFile;
I32 FilePos;
pFile = FS_FOpen("Test.txt", "w");
if (pFile) {
FS_FWrite(acText, 1, strlen(acText), pFile);
FilePos = FS_FTell(pFile);
FS_FClose(pFile);
}
}
FS_FTell64()
Description
Returns current position in a file.
Prototype
I64 FS_FTell64(FS_FILE * pFile);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
Return value
≠ 0xFFFFFFFFFFFFFFFF | OK, current position of the file pointer. |
= 0xFFFFFFFFFFFFFFFF | An error occurred. |
Additional information
This function performs the same operation as FS_FTell() with the
difference that the returned file position can be greater than
or equal to 232. This makes FS_FTell64() suitable for getting
the position in a file that is larger than or equal to 4 GB.
This function is available only when the file system is built with
FS_SUPPORT_LARGE_FILES set to 1.
Example
#include "FS.h"
const char acText[]="Hello world\n";
void SampleFTell64(void) {
FS_FILE * pFile;
I64 FilePos;
pFile = FS_FOpen("Test.txt", "w");
if (pFile) {
FS_FWrite(acText, 1, strlen(acText), pFile);
FilePos = FS_FTell64(pFile);
FS_FClose(pFile);
}
}
FS_GetFileSize()
Description
Returns the size of a file.
Prototype
U32 FS_GetFileSize(const FS_FILE * pFile);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
Return value
≠ 0xFFFFFFFF | File size of the given file in bytes. |
= 0xFFFFFFFF | An error occurred. |
Additional information
The file has to be opened with read or write access.
Example
#include "FS.h"
void SampleGetFileSize(void) {
FS_FILE * pFile;
U32 FileSize;
pFile = FS_FOpen("Test.txt", "r");
if (pFile) {
FileSize = FS_GetFileSize(pFile);
FS_FClose(pFile);
}
}
FS_GetFileSizeEx()
Description
Returns the size of a file.
Prototype
int FS_GetFileSizeEx(FS_FILE * pFile,
U32 * pNumBytes);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
pNumBytes | out Size of the file. |
Return value
= 0 | OK, file size returned successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_GetFileSize()
with the difference that it returns an error code in case of
an error.
The file has to be opened with read or write access.
Example
#include "FS.h"
void SampleGetFileSizeEx(void) {
FS_FILE * pFile;
U32 FileSize;
pFile = FS_FOpen("Test.txt", "r");
if (pFile) {
FileSize = 0;
FS_GetFileSizeEx(pFile, &FileSize);
FS_FClose(pFile);
}
}
FS_GetFileSize64()
Description
Returns the size of a file.
pFile Handle to opened file.
pNumBytes out Size of the file.
Prototype
int FS_GetFileSize64(FS_FILE * pFile,
U64 * pNumBytes);
Return value
= 0 | OK, file size returned successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The file has to be opened with read or write access.
This function performs the same operation as FS_GetFileSize() with the
difference that the returned file size can be greater than or equal
to 232. This makes FS_GetFileSize64() suitable for getting
the size of a file that is larger than or equal to 4 GB.
This function is available only when the file system is built with
FS_SUPPORT_LARGE_FILES set to 1.
Example
#include "FS.h"
void SampleGetFileSize64(void) {
FS_FILE * pFile;
U64 FileSize;
pFile = FS_FOpen("Test.txt", "r");
if (pFile) {
FileSize = 0;
FS_GetFileSize64(pFile, &FileSize);
FS_FClose(pFile);
}
}
FS_Read()
Description
Reads data from a file.
Prototype
U32 FS_Read(FS_FILE * pFile,
void * pData,
U32 NumBytes);
Parameters
Parameter | Description |
pFile | Handle to an opened file. It cannot be NULL. |
pData | Buffer to receive the read data. |
NumBytes | Number of bytes to be read. |
Return value
Number of bytes 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 bytes actually read is different than the number
of bytes 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_Read() moves the file pointer
forward by the number of bytes successfully read.
Example
#include "FS.h"
U8 abBuffer[100];
void SampleRead(void) {
FS_FILE * pFile;
U32 NumBytesRead;
pFile = FS_FOpen("Test.txt", "r");
if (pFile) {
NumBytesRead = FS_Read(pFile, abBuffer, sizeof(abBuffer));
if (NumBytesRead != sizeof(abBuffer)) {
//
// An error occurred.
//
}
FS_FClose(pFile);
}
}
FS_SetEndOfFile()
Description
Sets the file size to current file position.
Prototype
int FS_SetEndOfFile(FS_FILE * pFile);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
Return value
= 0 | OK, new file size has been set. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The file has to be opened with write permissions.
Refer to FS_FOpen() for more information about the file open modes.
FS_SetEndOfFile() can be used to truncate as well as to extend
a file. If the file is extended, the contents of the file between
the old end-of-file and the new one are not defined. Extending
a file (preallocation) can increase the write performance when
the application writes large amounts of data to file as the
file system is not required anymore to access the allocation
table.
Example
#include "FS.h"
void SampleSetEndOfFile(void) {
FS_FILE * pFile;
//
// Reserve space for a file of 20000 bytes.
//
pFile = FS_FOpen("Test.bin", "r+");
if (pFile) {
FS_FSeek(pFile, 20000, FS_SEEK_SET);
FS_SetEndOfFile(pFile);
FS_FClose(pFile);
}
}
FS_SetFileSize()
Description
Sets the file size to the specified number of bytes.
Prototype
int FS_SetFileSize(FS_FILE * pFile,
U32 NumBytes);
Parameters
Parameter | Description |
pFile | Handle to an opened file. |
NumBytes | New file size. |
Return value
= 0 | OK, new file size has been set. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The file has to be opened with write permissions.
Refer to FS_FOpen() for more information about the file
open modes. FS_SetFileSize() can be used to extend
as well as truncate a file. The file position is preserved
if the new file size is larger than or equal to the current
file position. Else the file position is set to the end of
the file.
Example
#include "FS.h"
void SampleSetFileSize(void) {
FS_FILE * pFile;
//
// Create a file 20000 bytes large.
//
pFile = FS_FOpen("Test.bin", "r+");
if (pFile) {
FS_SetFileSize(pFile, 20000);
FS_FClose(pFile);
}
}
FS_SetFileSize64()
Description
Sets the file size to the specified number of bytes.
Prototype
int FS_SetFileSize64(FS_FILE * pFile,
U64 NumBytes);
Parameters
Parameter | Description |
pFile | Handle to an opened file. |
NumBytes | New file size. |
Return value
= 0 | OK, new file size has been set. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The file has to be opened with write permissions.
Refer to FS_FOpen() for more information about the file
open modes.
FS_SetFileSize64() can be used to extend as well as truncate a file.
The file position is preserved if the new file size is larger than
or equal to the current file position. Otherwise the file position
is set to the end of the file.
This function performs the same operation as FS_SetFileSize() with the
difference that the set file size can be greater than or equal
to 232. This makes FS_SetFileSize64() suitable for setting
a file size that is larger than or equal to 4 GB.
This function is available only when the file system is built
with FS_SUPPORT_LARGE_FILES set to 1.
Example
#include "FS.h"
void SampleSetFileSize64(void) {
FS_FILE * pFile;
//
// Create a file that is about 8GB bytes large.
//
pFile = FS_FOpen("Test.bin", "r+");
if (pFile) {
FS_SetFileSize64(pFile, 8000000000uLL);
FS_FClose(pFile);
}
}
FS_SyncFile()
Description
Synchronizes file to storage device.
Prototype
int FS_SyncFile(FS_FILE * pFile);
Parameters
Parameter | Description |
pFile | File pointer identifying the opened file. It can be NULL. |
Return value
= 0 | OK, file(s) synchronized. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The function synchronizes all the opened files if a NULL is
passed as pFile parameter.
FS_SyncFile() cleans the write buffer if configured and updates
the management information to storage device. The function
performs basically the same operations as FS_FClose() with the
only difference that it leaves the file open. FS_SyncFile() is
used typically with fast or medium file write modes to make
sure that the data cached by the file system for the file is
written to storage medium.
The function can also be called from a different task than the
one that writes to file if the support for multi-tasking is
enabled in the file system. The support for multi-tasking can
be enabled by compiling the file system sources with the
FS_OS_LOCKING define is set to value different than 0.
Example
#include "FS.h"
void SampleFileSync(void) {
FS_FILE * pFile;
FS_SetFileWriteMode(FS_WRITEMODE_FAST);
pFile = FS_FOpen("Test.txt", "w");
if (pFile) {
//
// Write to file...
//
FS_SyncFile(pFile);
//
// Write to file...
//
FS_SyncFile(pFile);
//
// Write to file...
//
FS_FClose(pFile);
}
}
FS_Truncate()
Description
Changes the size of a file.
Prototype
int FS_Truncate(FS_FILE * pFile,
U32 NumBytes);
Parameters
Parameter | Description |
pFile | Handle to an opened file. |
NumBytes | The new size of the file. |
Return value
= 0 | OK, file size successfully modified. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The file has to be opened in write mode.
For more information about open modes refer to FS_FOpen().
An error is returned if NumBytes is larger than the actual
file size and the support for POSIX operation is disabled.
If the support for POSIX operation is enabled, then this function
can also be used to increase the size of the file. The extra bytes
are initialized with 0. The application can enable the support for
POSIX operation by building the file system with FS_SUPPORT_POSIX
set to 1 and by calling at runtime FS_ConfigPOSIXSupport() with the
OnOff parameter set to 1.
FS_Truncate() allocates FS_BUFFER_SIZE_TRUNCATE bytes on the stack
with the support for the POSIX operation enabled.
Example
#include "FS.h"
void SampleTruncate(void) {
FS_FILE * pFile;
U32 FileSize;
int r;
pFile = FS_FOpen("Test.bin", "r+");
if (pFile) {
FileSize = FS_GetFileSize(pFile);
//
// Reduce the size of the file by 200 bytes.
//
r = FS_Truncate(pFile, FileSize - 200);
if (r) {
//
// An error occurred while truncating file.
//
}
}
FS_FClose(pFile);
}
FS_Truncate64()
Description
Changes the size of a file.
Prototype
int FS_Truncate64(FS_FILE * pFile,
U64 NumBytes);
Parameters
Parameter | Description |
pFile | Handle to an opened file. |
NumBytes | The new size of the file. |
Return value
= 0 | OK, file size successfully modified. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The file has to be opened in write mode.
For more information about open modes refer to FS_FOpen().
An error is returned if NumBytes is larger than the actual
file size and the support for POSIX operation is disabled.
If the support for POSIX operation is enabled, then this function
can also be used to increase the size of the file. The extra bytes
are initialized with 0. The application can enable the support for
POSIX operation by building the file system with FS_SUPPORT_POSIX
set to 1 and by calling at runtime FS_ConfigPOSIXSupport() with the
OnOff parameter set to 1.
FS_Truncate64() allocates FS_BUFFER_SIZE_TRUNCATE bytes on the stack
with the support for the POSIX operation enabled.
This function performs the same operation as FS_Truncate() with the
difference that the set file size can be greater than or equal
to 232. This makes FS_Truncate64() suitable for setting
a file size that is larger than or equal to 4 GB.
This function is available only when the file system is built
with FS_SUPPORT_LARGE_FILES set to 1.
Example
#include "FS.h"
void SampleTruncate64(void) {
FS_FILE * pFile;
U64 FileSize;
int r;
pFile = FS_FOpen("Test.bin", "r+");
if (pFile) {
r = FS_GetFileSize64(pFile, &FileSize);
if (r == 0) {
//
// Reduce the size of the file by 200 bytes.
//
r = FS_Truncate64(pFile, FileSize - 200);
if (r != 0) {
//
// An error occurred while truncating file.
//
}
}
}
FS_FClose(pFile);
}
FS_Verify()
Description
Verifies the file contents.
Prototype
int FS_Verify( FS_FILE * pFile,
const void * pData,
U32 NumBytes);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
pData | Data to be checked against. |
NumBytes | Number of bytes to be checked. |
Return value
= 0 | Verification was successful. |
≠ 0 | Verification failed. |
Additional information
The function starts checking at the current file position.
That is the byte read from file position + 0 is checked
against the byte at pData + 0, the byte read from file position + 1
is checked against the byte at pData + 1 and so on.
FS_Verify() does not modify the file position.
Example
#include "FS.h"
const U8 abVerifyData[4] = { 1, 2, 3, 4 };
void SampleVerify(void) {
FS_FILE * pFile;
int r;
//
// Open file and write data into it.
//
pFile = FS_FOpen("Test.bin", "w+");
if (pFile) {
FS_Write(pFile, abVerifyData, sizeof(abVerifyData));
//
// Set file pointer to the start of the data that has to be verified.
//
FS_FSeek(pFile, 0, FS_SEEK_SET);
//
// Verify data.
//
r = FS_Verify(pFile, abVerifyData, sizeof(abVerifyData));
if (r == 0) {
FS_X_Log("Verification was successful.\n");
} else {
FS_X_Log("Verification failed.\n");
}
FS_FClose(pFile);
}
}
FS_Write()
Description
Writes data to file.
Prototype
U32 FS_Write( FS_FILE * pFile,
const void * pData,
U32 NumBytes);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
pData | The data to be written to file. |
NumBytes | Number of bytes to be written to file. |
Return value
Number of bytes 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 bytes actually written is different than
the number of bytes 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"
void SampleWrite(void) {
FS_FILE * pFile;
const char acText[] = "Hello world\n";
pFile = FS_FOpen("Test.txt", "w");
if (pFile) {
FS_Write(pFile, acText, strlen(acText));
FS_FClose(pFile);
}
}
File positioning reference
Description
Reference point when changing the file position.
Definition
#define FS_SEEK_SET 0
#define FS_SEEK_CUR 1
#define FS_SEEK_END 2
Symbols
Definition | Description |
FS_SEEK_SET | The reference is the beginning of the file. |
FS_SEEK_CUR | The reference is the current position of the file pointer. |
FS_SEEK_END | The reference is the end-of-file position. |
Operations on files
The functions on this section can be used by an application to manipulate files.
FS_CopyFile()
Description
Copies a file.
Prototype
int FS_CopyFile(const char * sFileNameSrc,
const char * sFileNameDest);
Parameters
Parameter | Description |
sFileNameSrc | Name of the source file (fully qualified). |
sFileNameDest | Name of the destination file (fully qualified). |
Return value
= 0 | OK, the file has been copied |
≠ 0 | Error code indicating the failure reason |
Additional information
The copy process uses an internal temporary buffer of 512 bytes
that is allocated on the stack. The size of this buffer can be
configured via FS_BUFFER_SIZE_FILE_COPY. Alternatively,
FS_CopyFileEx() can be used that lets the application specify
a copy buffer of an arbitrary size.
FS_CopyFile() overwrites the destination file if it exists.
The destination file has to be writable, that is the
FS_ATTR_READ_ONLY flag is set to 0.
Example
#include "FS.h"
void SampleCopyFile(void) {
FS_CopyFile("Src.txt", "ram:\\Dest.txt");
}
FS_CopyFileEx()
Description
Copies a file.
Prototype
int FS_CopyFileEx(const char * sFileNameSrc,
const char * sFileNameDest,
void * pBuffer,
U32 NumBytes);
Parameters
Parameter | Description |
sFileNameSrc | Name of the source file (fully qualified). |
sFileNameDest | Name of the destination file (fully qualified). |
pBuffer | Buffer to temporary store the copied data. It cannot be NULL. |
NumBytes | Size of the buffer size in bytes. |
Return value
= 0 | OK, the file has been copied. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The copy process uses an external buffer provided by the
application. FS_CopyFile() overwrites the destination file
if it exists. The destination file has to be writable, that
is the FS_ATTR_READ_ONLY flag is set to 0.
The best performance is achieved when the copy buffer is a
multiple of sector size and is 32-bit aligned. For example using
a 7 KB copy buffer to copy 512 byte sectors is more efficient
than using a copy buffer of 7.2 KB therefore the function rounds
down the size of the copy buffer to a multiple of sector size.
If the application specifies a copy buffer smaller than the
sector size a warning is generated in debug builds indicating
that the performance of the copy operation is not optimal.
Example
#include "FS.h"
static U32 _aBuffer[1024 / 4]; // Buffer to be used as temporary storage.
void SampleCopyFileEx(void) {
FS_CopyFileEx("Src.txt", "Dest.txt", _aBuffer, sizeof(_aBuffer));
}
FS_GetFileAttributes()
Description
Queries the attributes of a file or directory.
Prototype
U8 FS_GetFileAttributes(const char * sName);
Parameters
Parameter | Description |
sName | Name of the file or directory to be queried. |
Return value
= 0xFF | An error occurred. |
≠ 0xFF | Bit mask containing the attributes of file or directory. |
Additional information
The return value is an or-combination of the following attributes:
FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN, FS_ATTR_SYSTEM,
FS_ATTR_ARCHIVE, or FS_ATTR_DIRECTORY.
Example
#include <stdio.h>
#include "FS.h"
void SampleGetFileAttributes(void) {
U8 Attr;
char ac[100];
Attr = FS_GetFileAttributes("Test.txt");
if (Attr == 0xFF) {
FS_X_Log("ERROR: Could not get the file attributes.\n");
} else {
SEGGER_snprintf(ac, sizeof(ac),
"File attributes: %c%c%c%c%c\n",
(Attr & FS_ATTR_READ_ONLY) ? 'R' : '-',
(Attr & FS_ATTR_HIDDEN) ? 'H' : '-',
(Attr & FS_ATTR_SYSTEM) ? 'S' : '-',
(Attr & FS_ATTR_ARCHIVE) ? 'A' : '-',
(Attr & FS_ATTR_DIRECTORY) ? 'D' : '-');
FS_X_Log(ac);
}
}
FS_GetFileBufferInfo()
Description
Obtains information about a file buffer.
Prototype
int FS_GetFileBufferInfo(FS_FILE * pFile,
FS_FILE_BUFFER_INFO * pInfo);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
pInfo | out Information about the file buffer. |
Return value
= 0 | OK, information returned successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function returns an error if the specified file does not
have a file buffer. FS_IsFileBufferSet() can be used to check
if a file buffer is configured.
FS_GetFileBufferInfo() is available only if the file system is built
with the FS_SUPPORT_FILE_BUFFER configuration define set to 1.
This function does not perform any access to the storage device.
Example
#include "FS.h"
void SampleGetFileBufferInfo(void) {
FS_FILE * pFile;
FS_FILE_BUFFER_INFO Info;
int r;
char ac[100];
pFile = FS_FOpen("Test.txt", "w");
if (pFile != 0) {
r = FS_IsFileBufferSet(pFile);
if (r > 0) {
memset(&Info, 0, sizeof(Info));
r = FS_GetFileBufferInfo(pFile, &Info);
if (r == 0) {
FS_X_Log("File buffer info:\n");
FS_X_Log(" Allocated by application: ");
if (Info.IsExternal != 0) {
FS_X_Log("yes\n");
} else {
FS_X_Log("no\n");
}
SEGGER_snprintf(ac, sizeof(ac),
" Buffer size: %d bytes\n", Info.BufferSize);
FS_X_Log(ac);
FS_X_Log(" Operating mode: READ");
if (Info.Flags & FS_FILE_BUFFER_WRITE) {
FS_X_Log(" WRITE");
}
if (Info.Flags & FS_FILE_BUFFER_ALIGNED) {
FS_X_Log(" ALIGNED");
}
FS_X_Log("\n");
}
}
FS_FClose(pFile);
}
}
FS_GetFileInfo()
Description
Returns information about a file or directory.
Prototype
int FS_GetFileInfo(const char * sName,
FS_FILE_INFO * pInfo);
Parameters
Parameter | Description |
sName | Name of the file or directory. |
pInfo | out Information about file or directory. |
Return value
= 0 | OK, information returned. |
≠ 0 | An error occurred. |
Additional information
The function returns information about the attributes, size and
time stamps of the specified file or directory. For more
information refer to FS_FILE_INFO.
Example
#include <stdio.h>
#include "FS.h"
void SampleGetFileInfo(void) {
int r;
FS_FILE_INFO FileInfo;
char ac[100];
FS_FILETIME FileTime;
r = FS_GetFileInfo("Test.txt", &FileInfo);
if (r == 0) {
FS_X_Log("File info:\n");
SEGGER_snprintf(ac, sizeof(ac), " Attributes: 0x%x\n", FileInfo.Attributes);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Size: %ld bytes\n", FileInfo.FileSize);
FS_X_Log(ac);
FS_TimeStampToFileTime(FileInfo.CreationTime, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), " Creation time: %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
FS_TimeStampToFileTime(FileInfo.LastAccessTime, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), " Access time: %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
FS_TimeStampToFileTime(FileInfo.LastWriteTime, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), " Write time: %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
}
}
FS_GetFileInfo64()
Description
Obtains information about a file or directory.
Prototype
int FS_GetFileInfo64(const char * sName,
FS_FILE_INFO64 * pInfo);
Parameters
Parameter | Description |
sName | Name of the file or directory. |
pInfo | out Information about file or directory. |
Return value
= 0 | OK, information returned. |
≠ 0 | An error occurred. |
Additional information
The function returns information about the attributes, size and
time stamps of the specified file or directory. For more
information refer to FS_FILE_INFO64.
This function performs the same operation as FS_GetFileInfo()
with the difference that the size of the queried file or directory
can be greater than or equal to 4GB.
This function is available only then the file system is built
with FS_SUPPORT_LARGE_FILES set to 1.
#include <stdio.h>
#include "FS.h"
void SampleGetFileInfo64(void) {
int r;
FS_FILE_INFO64 FileInfo;
char ac[100];
FS_FILETIME FileTime;
U32 FileSizeLow;
U32 FileSizeHigh;
r = FS_GetFileInfo64("Test.txt", &FileInfo);
if (r == 0) {
FileSizeLow = (U32)(FileInfo.FileSize % 1000000000uLL);
FileSizeHigh = (U32)(FileInfo.FileSize / 1000000000uLL);
FS_X_Log("File info:\n");
SEGGER_snprintf(ac, sizeof(ac), " Attributes: 0x%x\n", FileInfo.Attributes);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Size: %ld%ld bytes\n", FileSizeHigh, FileSizeLow);
FS_X_Log(ac);
FS_TimeStampToFileTime(FileInfo.CreationTime.TimeDate, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), " Creation time: %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
FS_TimeStampToFileTime(FileInfo.LastAccessTime.TimeDate, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), " Access time: %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
FS_TimeStampToFileTime(FileInfo.LastWriteTime.TimeDate, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), " Write time: %d-%.2d-%.2d %.2d:%.2d:%.2d\n",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
}
}
FS_GetFileName()
Description
Obtains the name of a file.
Prototype
int FS_GetFileName(FS_FILE * pFile,
char * pFileName,
unsigned SizeOfFileName);
Parameters
Parameter | Description |
pFile | Handle to the opened file. |
pFileName | out Receives the name of the file as 0-terminated string. It cannot be NULL. |
SizeOfFileName | Number of bytes in pFileName. |
Return value
> 0 | Number of bytes in the file name or number of bytes required to store the volume name. |
< 0 | Error code indicating the failure reason. |
Additional information
If pFileName is sufficiently large to store the entire file
name and the 0-terminator then the function returns the number
of bytes in the file name without the 0-terminator.
If pFileName is not sufficiently large to store the entire file
name and the 0-terminator then the function returns the minimum
buffer size required to store the entire file name including the 0-terminator.
In this case, the function does not store any data to pFileName.
FS_GetFileName() stores at most SizeOfFileName - 1
bytes to pFileName and it terminates the string by a 0.
This function is present only when the file system is built
with FS_MULTI_HANDLE_SAFE set to 1.
#include "FS.h"
void SampleGetFileName(void) {
FS_FILE * pFile;
unsigned SizeOfBuffer;
int NumBytes;
char acFileName[32];
pFile = FS_FOpen("Test.txt", "w");
if (pFile != NULL) {
memset(acFileName, 0, sizeof(acFileName));
SizeOfBuffer = sizeof(acFileName);
NumBytes = FS_GetFileName(pFile, acFileName, SizeOfBuffer);
if ((NumBytes > 0) && (NumBytes < (int)SizeOfBuffer)) {
FS_X_Log("File name: ");
FS_X_Log(acFileName);
FS_X_Log("\n");
}
FS_FClose(pFile);
}
}
FS_GetFileTime()
Description
Returns the creation time of a file or directory.
Prototype
int FS_GetFileTime(const char * sName,
U32 * pTimeStamp);
Parameters
Parameter | Description |
sName | File or directory name. |
pTimeStamp | out Receives the timestamp value. |
Return value
= 0 | OK, timestamp returned. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The date and time encoded in the timestamp using the following format:
Bit field | Description |
0--4 | Second divided by 2 |
5--10 | Minute (0--59) |
11--15 | Hour (0--23) |
16--20 | Day of month (1--31) |
21--24 | Month (1--12, 1: January, 2: February, etc.) |
25--31 | Year (offset from 1980). Add 1980 to get the current year. |
FS_TimeStampToFileTime() can be used to convert the timestamp
to a FS_FILETIME structure that can be used to easily process
the time information.
The last modification and the last access timestamps can be read via
FS_GetFileTimeEx().
Example
#include <stdio.h>
#include "FS.h"
void SampleGetFileTime(void) {
char ac[100];
U32 TimeStamp;
FS_FILETIME FileTime;
int r;
r = FS_GetFileTime("Test.txt", &TimeStamp);
if (r == 0) {
FS_TimeStampToFileTime(TimeStamp, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), "Creation time: %d-%.2d-%.2d %.2d:%.2d:%.2d",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
}
}
FS_GetFileTimeEx()
Description
Gets the timestamp of a file or directory.
Prototype
int FS_GetFileTimeEx(const char * sName,
U32 * pTimeStamp,
int TimeType);
Parameters
Parameter | Description |
sName | File or directory name. |
pTimeStamp | out Receives the timestamp value. |
TimeType | Type of timestamp to return. It can take one of the following values: FS_FILETIME_CREATE FS_FILETIME_ACCESS FS_FILETIME_MODIFY |
Return value
= 0 | OK, timestamp returned. |
≠ 0 | Error code indicating the failure reason. |
Additional information
Refer to FS_GetFileTime() for a description of the timestamp
format. FS_TimeStampToFileTime() can be used to convert the
timestamp to a FS_FILETIME structure that can be used to easily
process the time information.
EFS maintains only one filestamp that is updated when the file
is created and updated therefore the same timestamp value
is returned for all time types.
Example
#include <stdio.h>
#include "FS.h"
void SampleGetFileTimeEx(void) {
char ac[100];
U32 TimeStamp;
FS_FILETIME FileTime;
int r;
r = FS_GetFileTimeEx("Test.txt", &TimeStamp, FS_FILETIME_MODIFY);
if (r == 0) {
FS_TimeStampToFileTime(TimeStamp, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), "Modify time: %d-%.2d-%.2d %.2d:%.2d:%.2d",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
}
}
FS_IsFileBufferSet()
Description
Checks if a file buffer is configured for the specified file.
Prototype
int FS_IsFileBufferSet(FS_FILE * pFile);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
Return value
= 1 | OK, file buffer set. |
= 0 | OK, file buffer not set. |
≠ 0 | Error code indicating the failure reason. |
Additional information
FS_IsFileBufferSet() is available only if the file system is built
with the FS_SUPPORT_FILE_BUFFER configuration define set to 1.
Example
#include "FS.h"
void SampleIsFileBufferSet(void) {
FS_FILE * pFile;
int r;
pFile = FS_FOpen("Test.txt", "w");
if (pFile != 0) {
r = FS_IsFileBufferSet(pFile);
if (r < 0) {
FS_X_Log("ERROR: Could not get file buffer status.\n");
} else {
if (r != 0) {
FS_X_Log("File buffer set\n");
} else {
FS_X_Log("File buffer not set\n");
}
}
FS_FClose(pFile);
}
}
FS_ModifyFileAttributes()
Description
Sets / clears the attributes of a file or directory.
Prototype
U8 FS_ModifyFileAttributes(const char * sName,
U8 SetMask,
U8 ClrMask);
Parameters
Parameter | Description |
sName | Name of the file or directory. |
SetMask | Bit mask of the attributes to be set. |
ClrMask | Bit mask of the attributes to be cleared. |
Return value
= 0xFF | An error occurred. |
≠ 0xFF | Bit mask containing the old attributes of the file or directory. |
Additional information
This function can be used to set and clear at the same time the
attributes of a file or directory. The FS_ATTR_DIRECTORY attribute
cannot be modified using this function.
The return value is an or-combination of the following attributes:
FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN, FS_ATTR_SYSTEM,
FS_ATTR_ARCHIVE, or FS_ATTR_DIRECTORY.
The attributes that are specified in the SetMask are set to 1
while the attributes that are specified in the ClrMask are set to 0.
SetMask and ClrMask values are an or-combination of the following
attributes: FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN, FS_ATTR_SYSTEM,
or FS_ATTR_ARCHIVE. The attributes that are not specified nor
in SetMask either in ClrMask are not modified.
Example
#include <stdio.h>
#include "FS.h"
void SampleModifyFileAttributes(void) {
U8 Attr;
char ac[100];
//
// Set the read-only and the hidden flags. Clear archive flag.
//
Attr = FS_ModifyFileAttributes("Test.txt",
FS_ATTR_READ_ONLY | FS_ATTR_HIDDEN,
FS_ATTR_ARCHIVE);
SEGGER_snprintf(ac, sizeof(ac), "Old file attributes: %c%c%c%c%c\n",
(Attr & FS_ATTR_READ_ONLY) ? 'R' : '-',
(Attr & FS_ATTR_HIDDEN) ? 'H' : '-',
(Attr & FS_ATTR_SYSTEM) ? 'S' : '-',
(Attr & FS_ATTR_ARCHIVE) ? 'A' : '-',
(Attr & FS_ATTR_DIRECTORY) ? 'D' : '-');
FS_X_Log(ac);
Attr = FS_GetFileAttributes("Test.txt");
SEGGER_snprintf(ac, sizeof(ac), "New file attributes: %c%c%c%c%c\n",
(Attr & FS_ATTR_READ_ONLY) ? 'R' : '-',
(Attr & FS_ATTR_HIDDEN) ? 'H' : '-',
(Attr & FS_ATTR_SYSTEM) ? 'S' : '-',
(Attr & FS_ATTR_ARCHIVE) ? 'A' : '-',
(Attr & FS_ATTR_DIRECTORY) ? 'D' : '-');
FS_X_Log(ac);
}
FS_Move()
Description
Moves a file or directory to another location.
Prototype
int FS_Move(const char * sNameSrc,
const char * sNameDest);
Parameters
Parameter | Description |
sNameSrc | Name of the source file or directory (partially qualified). It cannot be NULL. |
sNameDest | Name of the destination file or directory (partially qualified). It cannot be NULL. |
Return value
= 0 | OK, file or directory move successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
FS_Move() can be used to change the location of a file or directory
in the directory tree of the file system.
If the source and the destination file are located on the same volume,
then only the directory entry assigned to the moved file is relocated.
Otherwise the contents of the file is copied to the destination volume
and the source file is deleted.
The function is able to move entire directory trees when
the source and destination are located on the same volume.
Moving an entire directory tree on a different volume is not supported.
This operation has to be performed in the application by iterating
over the files and directories and by copying them one-by-one.
By default, the source files and directories that have the
FS_ATTR_READ_ONLY attribute set and that are located on a volume
formatted as FAT cannot be moved. This behavior can be changed by
compiling the file system sources with FS_FAT_PERMIT_RO_FILE_MOVE
configuration define to 1. FS_FAT_ConfigROFileMovePermission()
can be used to change the behavior at runtime.
Source files and directories located on a EFS formatted volume
can be moved even if they have the FS_ATTR_READ_ONLY attribute
set.
The operation fails if the destination file or directory already exists.
FS_Move() preserves the timestamps of the moved file or directory.
Example
#include "FS.h"
void SampleMove(void) {
//
// File tree before the operation.
//
// <root>
// |
// +->SubDir2
// |
// +->SubDir3
//
FS_Move("SubDir1", "SubDir2\\SubDir3");
//
// File tree after the operation.
//
// <root>
// |
// +->SubDir1
// |
// +->SubDir2
//
}
FS_Remove()
Description
Removes a file.
Prototype
int FS_Remove(const char * sFileName);
Parameters
Parameter | Description |
sFileName | Name of the file to be removed. |
Return value
= 0 | OK, file has been removed. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The function removes also files that have the FS_ATTR_READ_ONLY
attribute set. The remove operation fails if the file to be
deleted is open.
Example
#include "FS.h"
void SampleRemove(void) {
FS_Remove("Test.txt");
}
FS_Rename()
Description
Changes the name of a file or directory.
Prototype
int FS_Rename(const char * sNameOld,
const char * sNameNew);
Parameters
Parameter | Description |
sNameOld | Old file or directory name (including the path). |
sNameNew | New file or directory name (without path). |
Return value
= 0 | OK, file or directory has been renamed. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The function can rename either a file or a directory.
By default, the files and directories that have the
FS_ATTR_READ_ONLY attribute set and that are located on a volume
formatted as FAT cannot be renamed. This behavior can be changed
by compiling the file system sources with the
FS_FAT_PERMIT_RO_FILE_MOVE configuration define to 1.
FS_FAT_ConfigROFileMovePermission() can be used to change
the behavior at runtime.
Source files and directories located on a EFS formatted volume
can be moved event if they have the FS_ATTR_READ_ONLY attribute
set.
Example
#include "FS.h"
void SampleRename(void) {
//
// File tree before the operation.
//
// <root>
// |
// +->SubDir2
// |
// +->SubDir3
//
FS_Rename("SubDir2\\SubDir3", "SubDir1");
//
// File tree after the operation.
//
// <root>
// |
// +->SubDir1
// |
// +->SubDir3
//
}
FS_SetFileAttributes()
Description
Modifies all the attributes of a file or directory.
Prototype
int FS_SetFileAttributes(const char * sName,
U8 AttrMask);
Parameters
Parameter | Description |
sName | Pointer to a name of the file/directory. |
AttrMask | Bit mask of the attributes to be set. |
Return value
= 0 | OK, attributes have been set. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The FS_ATTR_DIRECTORY attribute cannot be modified using this
function. The value of AttrMask parameter is an or-combination
of the following attributes: FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN,
FS_ATTR_SYSTEM, FS_ATTR_ARCHIVE, or FS_ATTR_DIRECTORY.
The attributes that are not set in AttrMask are set to 0.
Example
#include <stdio.h>
#include "FS.h"
void SampleFileAttributes(void) {
U8 Attr;
char ac[100];
FS_SetFileAttributes("Test.txt", FS_ATTR_HIDDEN);
Attr = FS_GetFileAttributes("Test.txt");
SEGGER_snprintf(ac, sizeof(ac), "File attributes: %c%c%c%c%c\n",
(Attr & FS_ATTR_READ_ONLY) ? 'R' : '-',
(Attr & FS_ATTR_HIDDEN) ? 'H' : '-',
(Attr & FS_ATTR_SYSTEM) ? 'S' : '-',
(Attr & FS_ATTR_ARCHIVE) ? 'A' : '-',
(Attr & FS_ATTR_DIRECTORY) ? 'D' : '-');
FS_X_Log(ac);
}
FS_SetFileBuffer()
Description
Assigns a file buffer to an opened file.
Prototype
int FS_SetFileBuffer(FS_FILE * pFile,
void * pData,
I32 NumBytes,
int Flags);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
pData | Pointer to the to memory area which should be used as buffer. |
NumBytes | Number of bytes in the buffer. |
Flags | Specifies the operating mode of the file buffer. |
Return value
= 0 | OK, buffer assigned. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function can only be called immediately after the file is
opened and before performing any operation on the file.
Flags is a bitwise-or combination of File buffer flags.
If Flags is set to 0 then the file buffer caches only the
data read from the file.
If the file buffer is configured in write mode the
data of any operation that writes less bytes at once than the
size of the file buffer is stored to file buffer. The contents
of the file buffer is written to file in the following cases:
In case of a read operation if the data is not present in the
file buffer the file system fills the entire file buffer with
the data from file.
FS_SetFileBuffer() reports an error if the file system is
configured to automatically allocate a file buffer for each
file it opens via FS_ConfigFileBufferDefault().
The data required to manage the file buffer is allocated from
pData. The FS_SIZEOF_FILE_BUFFER() define can be used to
calculate the amount of RAM required to store a specified
number of data bytes in the file buffer.
If the file is opened and closed in the same function the file
buffer can be allocated locally on the stack. Otherwise the buffer
has to be globally allocated. After the file is closed the memory
allocated for the file buffer is no longer accessed by the file
system and can be safely deallocated or used to store other data.
FS_SetFileBuffer() is available only if the file system is built
with the FS_SUPPORT_FILE_BUFFER configuration define set to 1.
Example
#include "FS.h"
void SampleSetFileBuffer(void) {
FS_FILE * pFile;
U32 aBuffer[FS_SIZEOF_FILE_BUFFER(512) / 4];
pFile = FS_FOpen("Test.txt", "w");
if (pFile != NULL) {
//
// Set the file buffer for read and write operation.
// The file buffer is allocated on the stack since the file
// is closed before the function returns.
//
FS_SetFileBuffer(pFile, aBuffer, sizeof(aBuffer), FS_FILE_BUFFER_WRITE);
//
// Data is written to file buffer.
//
FS_Write(pFile, "Test", 4);
//
// Write the data from file buffer to storage and close the file.
//
FS_FClose(pFile);
}
}
FS_SetFileTime()
Description
Sets the creation time of a file or directory.
Prototype
int FS_SetFileTime(const char * sName,
U32 TimeStamp);
Parameters
Parameter | Description |
sName | File or directory name. |
TimeStamp | The value of the timestamp to be set. |
Return value
= 0 | OK, timestamp modified. |
≠ 0 | Error code indicating the failure reason. |
Additional information
Refer to FS_GetFileTime() for a description of the timestamp
format. FS_FileTimeToTimeStamp() can be used to convert
a FS_FILETIME structure to a timestamp that can be used in a
call to FS_SetFileTime().
This function is optional. The file system updates automatically
the timestamps of file or directories.
Example
#include "FS.h"
void SampleSetFileTime(void) {
U32 TimeStamp;
FS_FILETIME FileTime;
FileTime.Year = 2005;
FileTime.Month = 03;
FileTime.Day = 26;
FileTime.Hour = 10;
FileTime.Minute = 56;
FileTime.Second = 14;
FS_FileTimeToTimeStamp (&FileTime, &TimeStamp);
FS_SetFileTime("Test.txt", TimeStamp);
}
FS_SetFileTimeEx()
Description
Sets the timestamp of a file or directory.
Prototype
int FS_SetFileTimeEx(const char * sName,
U32 TimeStamp,
int TimeType);
Parameters
Parameter | Description |
sName | File or directory name. |
TimeStamp | The value of the timestamp to be set. |
TimeType | Type of timestamp to be modified. It can take of the following values: FS_FILETIME_CREATE FS_FILETIME_ACCESS FS_FILETIME_MODIFY |
Return value
= 0 | OK, timestamp modified. |
≠ 0 | Error code indicating the failure reason. |
Additional information
Refer to FS_GetFileTime() for a description of the timestamp
format. FS_FileTimeToTimeStamp() can be used to convert
a FS_FILETIME structure to a timestamp that can be used in
a call to FS_SetFileTimeEx().
EFS maintains only one filestamp therefore the TimeType parameter
is ignored for files and directories stored on an EFS volume.
This function is optional. The file system updates automatically
the timestamps of file or directories.
Example
#include "FS.h"
void SampleSetFileTime(void) {
U32 TimeStamp;
FS_FILETIME FileTime;
FileTime.Year = 2017;
FileTime.Month = 07;
FileTime.Day = 07;
FileTime.Hour = 14;
FileTime.Minute = 48;
FileTime.Second = 14;
FS_FileTimeToTimeStamp(&FileTime, &TimeStamp);
//
// Set the access time of the file.
//
FS_SetFileTimeEx("Test.txt", TimeStamp, FS_FILETIME_ACCESS);
}
FS_UnsetFileBuffer()
Description
Frees the file buffer assigned to specified file.
Prototype
int FS_UnsetFileBuffer(FS_FILE * pFile);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
Return value
= 0 | OK, file buffer freed successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function can only be called immediately after the file is
opened and before performing any operation on the file.
An error is returned if an attempt is made to unset a file
buffer allocated by the file system with FS_SUPPORT_FILE_BUFFER_LIST
set to 0.
FS_UnsetFileBuffer() is available only if the file system is built
with the FS_SUPPORT_FILE_BUFFER configuration define set to 1.
This function does not perform any access to the storage device.
Example
#include "FS.h"
void SampleUnsetFileBuffer(void) {
FS_FILE * pFile;
int r;
U8 abData[4];
pFile = FS_FOpen("Test.txt", "w");
if (pFile != 0) {
if (FS_IsFileBufferSet(pFile)) {
FS_UnsetFileBuffer(pFile);
}
//
// The following write operation is performed
// without a file buffer.
//
memset(abData, 0, sizeof(abData));
FS_Write(pFile, abData, sizeof(abData));
FS_FClose(pFile);
}
}
FS_WipeFile()
Description
Overwrites the contents of a file with random data.
Prototype
int FS_WipeFile(const char * sFileName);
Parameters
Parameter | Description |
sFileName | Name of the file to overwrite. |
Return value
= 0 | Contents of the file overwritten. |
≠ 0 | Error code indicating the failure reason. |
Additional information
When a file is removed, the file system marks the corresponding
directory entry and the clusters in the allocation table as free.
The contents of the file is not modified and it can be in theory
restored by using a disk recovery tool. This can be a problem if
the file stores sensitive data. Calling FS_WipeFile() before
the file is removed makes the recovery of data impossible.
This function allocates FS_BUFFER_SIZE_FILE_WIPE bytes on the stack.
Example
#include "FS.h"
void SampleWipeFile(void) {
FS_FILE * pFile;
//
// Create a file and write data to it.
//
pFile = FS_FOpen("Test.txt", "w");
if (pFile) {
FS_Write(pFile, "12345", 5);
FS_FClose(pFile);
}
//
// Overwrite the file contents with random data.
//
FS_WipeFile("Test.txt");
//
// Delete the file from storage medium.
//
FS_Remove("Test.txt");
}
File attributes
Description
Attributes of files and directories.
Definition
#define FS_ATTR_READ_ONLY 0x01u
#define FS_ATTR_HIDDEN 0x02u
#define FS_ATTR_SYSTEM 0x04u
#define FS_ATTR_ARCHIVE 0x20u
#define FS_ATTR_DIRECTORY 0x10u
Symbols
Definition | Description |
FS_ATTR_READ_ONLY | The file is read-only. Applications can read the file but cannot write to it. |
FS_ATTR_HIDDEN | The file or directory is marked as hidden. Most of operating systems do not include these files in an ordinary directory listing. This flag is not evaluated by emFile. |
FS_ATTR_SYSTEM | The file or directory is part of, or is used exclusively by, the operating system. This flag is not evaluated by emFile. |
FS_ATTR_ARCHIVE | The file or directory is an archive file or directory. Applications can use this attribute to mark files for backup or removal. This flag is not evaluated by emFile. |
FS_ATTR_DIRECTORY | The file is actually a directory. |
File buffer flags
Description
File buffer operating options.
Definition
#define FS_FILE_BUFFER_WRITE (1uL << 0)
#define FS_FILE_BUFFER_ALIGNED (1uL << 1)
Symbols
Definition | Description |
FS_FILE_BUFFER_WRITE | Data written to file is cached. |
FS_FILE_BUFFER_ALIGNED | Cached data is kept aligned to logical sector boundary. |
Additional information
A file buffer always caches the data read from the file.
This operating mode is always enabled and cannot be disabled.
File buffer size
Description
Calculates the file buffer size.
Definition
#define FS_SIZEOF_FILE_BUFFER(NumBytes) (FS_SIZEOF_FILE_BUFFER_STRUCT + (NumBytes))
Symbols
Definition | Description |
FS_SIZEOF_FILE_BUFFER(NumBytes) | Calculates the file buffer size. |
Additional information
This define can be used in an application to calculate the number
of bytes that have to be allocated in order to store the specified
number of bytes in the file buffer. NumBytes is typically
a multiple of logical sector size.
FS_FILE_BUFFER_INFO
Description
Information about a file buffer.
Type definition
typedef struct {
U32 BufferSize;
U8 Flags;
U8 IsExternal;
} FS_FILE_BUFFER_INFO;
Structure members
Member | Description |
BufferSize | Maximum number of bytes that can be stored in the file buffer. |
Flags | Operating mode of the file buffer. |
IsExternal | Specifies where the file buffer was allocated. |
Additional information
The Flags member is a bitwise-or combination of File buffer flags
The IsExternal member is set to 1 if the file buffer is provided
by the application via FS_SetFileBuffer(). If the file buffer
is allocated by the file system then IsExternal is set to 0.
FS_FILE_INFO
Description
Information about a file or directory.
Type definition
typedef struct {
U8 Attributes;
U32 CreationTime;
U32 LastAccessTime;
U32 LastWriteTime;
U32 FileSize;
} FS_FILE_INFO;
Structure members
Member | Description |
Attributes | File or directory attributes. |
CreationTime | Date and time when the file was created. |
LastAccessTime | Date and time when the file was accessed last. |
LastWriteTime | Date and time when the file was written to last. |
FileSize | Size of the file in bytes. |
Additional information
The Attributes member is an bitwise-or combination of the following
flags: FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN, FS_ATTR_SYSTEM,
FS_ATTR_ARCHIVE, or FS_ATTR_DIRECTORY.
The FileSize member is always set to 0 for directories located on FAT and EFS volumes.
FS_FILE_INFO64
Description
Information about a file or directory.
Type definition
typedef struct {
U8 Attributes;
FS_TIMESTAMP CreationTime;
FS_TIMESTAMP LastAccessTime;
FS_TIMESTAMP LastWriteTime;
U64 FileSize;
} FS_FILE_INFO64;
Structure members
Member | Description |
Attributes | File or directory attributes. |
CreationTime | Date and time when the file was created. |
LastAccessTime | Date and time when the file was accessed last. |
LastWriteTime | Date and time when the file was written to last. |
FileSize | Size of the file in bytes. |
Additional information
The Attributes member is an bitwise-or combination of the following
flags: FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN, FS_ATTR_SYSTEM,
FS_ATTR_ARCHIVE, or FS_ATTR_DIRECTORY.
The FileSize member is always set to 0 for directories located on FAT and EFS volumes.
This structure can store the size of a file that is greater than
or equal to 4GB.
File time types
Description
Types of timestamps available for a file or directory.
Definition
#define FS_FILETIME_CREATE 0
#define FS_FILETIME_ACCESS 1
#define FS_FILETIME_MODIFY 2
Symbols
Definition | Description |
FS_FILETIME_CREATE | Date and time when the file or directory was created. |
FS_FILETIME_ACCESS | Date and time of the last read access to file or directory. |
FS_FILETIME_MODIFY | Date and time of the last write access to file or directory. |
Directory functions
This section describes functions that operate on directories. API functions
are provided for creating, deleting and listing directories.
FS_CopyDir()
Description
Copies a directory and its contents to a different location.
Prototype
int FS_CopyDir(const char * sDirNameSrc,
const char * sDirNameDest,
int MaxRecursionLevel);
Parameters
Parameter | Description |
sDirNameSrc | Name of the source directory (0-terminated string). |
sDirNameDest | Name of the destination directory (0-terminated string). |
MaxRecursionLevel | Maximum depth of the directory tree. |
Return value
= 0 | OK, directory copied successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The function uses recursion to process the directory tree and
it requires about 100 bytes of stack for each directory level
it processes. The MaxRecursionLevel parameter can be used to
prevent a stack overflow if the directory tree is too deep.
This function allocates on the stack two buffers of FS_MAX_PATH bytes
and one buffer of FS_BUFFER_SIZE_FILE_COPY bytes.
Following are some examples of the values that can be passed to
MaxRecursionLevel.
- MaxRecursionLevel=0 Creates an empty destination directory. If any files or directories are present in the source directory then an error is reported.
- MaxRecursionLevel=1 Copies the source directory and all the files stored in it to the destination directory. If a subdirectory is present in the source directory then the copy operation is aborted and an error is reported. In this case, the destination directory will contain an incomplete copy of the source directory.
- MaxRecursionLevel=2 Copies the source directory and all the files and subdirectories stored in it to the destination directory. If the subdirectories contain other subdirectories in them then the copy operation is aborted and an error is reported. The destination directory will contain an incomplete copy of the source directory.
If present, the destination directory including its contents is removed
before the copy operation. The destination directory is created if missing.
Example
#include "FS.h"
void SampleCopyDir(void) {
FS_CopyDir("SubDir", "CopyDir", 5);
}
FS_CreateDir()
Description
Creates a directory including any missing directories in the path.
Prototype
int FS_CreateDir(const char * sDirName);
Parameters
Parameter | Description |
sDirName | Directory name. |
Return value
= 0 | Directory path has been created. |
= 1 | Directory path already exists. |
< 0 | Error code indicating the failure reason. |
Additional information
The function creates automatically any subdirectories that are
specified in the path but do not exist on the storage.
FS_CreateDir() uses a work buffer of FS_MAX_PATH bytes that is
allocated on the stack. This buffer is used for parsing the path
to the created directory.
Example
#include "FS.h"
void SampleCreateDir(void) {
//
// File tree before the operation.
//
// <root>
// |
// +->SubDir1
//
FS_CreateDir("SubDir1\\SubDir2\\SubDir3");
//
// File tree after the operation.
//
// <root>
// |
// +->SubDir1
// |
// +->SubDir2
// |
// +->SubDir3
//
}
FS_DeleteDir()
Description
Removes a directory and its contents.
Prototype
int FS_DeleteDir(const char * sDirName,
int MaxRecursionLevel);
Parameters
Parameter | Description |
sDirName | Directory name. |
MaxRecursionLevel | Maximum depth of the directory tree. |
Return value
= 0 | OK, directory has been removed |
≠ 0 | Error code indicating the failure reason |
Additional information
The function uses recursion to process the directory tree and
it requires about 100 bytes of stack for each directory level
it processes. The MaxRecursionLevel parameter can be used to
prevent a stack overflow if the directory tree is too deep.
Following are some examples of the values that can be passed to
MaxRecursionLevel.
- MaxRecursionLevel=0 Deletes the directory only if empty else an error is reported and the directory is not deleted.
- MaxRecursionLevel=1 Deletes the directory and all the files in it. If a subdirectory is present an error is reported and the directory is not deleted.
- MaxRecursionLevel=2 Deletes the directory and all the files and subdirectories in it. If the subdirectories contain other subdirectories an error is reported and the directory is not deleted.
Example
#include "FS.h"
void SampleDeleteDir(void) {
//
// File tree before the operation.
//
// <root>
// |
// +->SubDir1
// |
// +->SubDir2
// |
// +->File1.txt
// |
// +->File2.txt
//
FS_DeleteDir("SubDir2", 1);
//
// File tree after the operation.
//
// <root>
// |
// +->SubDir1
//
}
FS_FindClose()
Description
Ends a directory scanning operation.
Prototype
void FS_FindClose(FS_FIND_DATA * pFD);
Parameters
Parameter | Description |
pFD | Context of the directory scanning operation. |
Additional information
This function has to be called at the end of the directory
scanning operation to clear the used context. After calling
this function the same context can be used for a different
directory scanning operation.
Example
#include "FS.h"
void SampleFindClose(void) {
FS_FIND_DATA fd;
int r;
char acFileName[32];
//
// List the files from the root directory.
//
r = FS_FindFirstFile(&fd, "", acFileName, sizeof(acFileName));
if (r == 0) {
do {
//
// Process file or directory...
//
} while (FS_FindNextFile(&fd));
}
FS_FindClose(&fd);
//
// List the files from the "SubDir1" directory.
//
r = FS_FindFirstFile(&fd, "SubDir1", acFileName, sizeof(acFileName));
if (r == 0) {
do {
//
// Process file or directory...
//
} while (FS_FindNextFile(&fd));
}
FS_FindClose(&fd);
}
FS_FindClose64()
Description
Ends a directory scanning operation.
Prototype
int FS_FindClose64(FS_FIND_DATA64 * pFD);
Parameters
Parameter | Description |
pFD | Context of the directory scanning operation. |
Return value
= 0 | OK, directory scanning closed successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function has to be called at the end of the directory
scanning operation to clear the used context. After calling
this function the same context can be used for a different
directory scanning operation.
This function is available only when the file system is built
with FS_SUPPORT_LARGE_FILES set to 1.
Example
#include "FS.h"
void SampleFindClose64(void) {
FS_FIND_DATA64 fd;
int r;
char acFileName[32];
//
// List the files from the root directory.
//
r = FS_FindFirstFile64(&fd, "", acFileName, sizeof(acFileName));
if (r == 0) {
for (;;) {
//
// Process file or directory...
//
r = FS_FindNextFile64(&fd);
if (r != 0) {
break;
}
}
}
(void)FS_FindClose64(&fd);
//
// List the files from the "SubDir1" directory.
//
r = FS_FindFirstFile64(&fd, "SubDir1", acFileName, sizeof(acFileName));
if (r == 0) {
for (;;) {
//
// Process file or directory...
//
r = FS_FindNextFile64(&fd);
if (r != 0) {
break;
}
}
}
(void)FS_FindClose64(&fd);
}
FS_FindFirstFile()
Description
Initiates a directory scanning operation.
Prototype
int FS_FindFirstFile( FS_FIND_DATA * pFD,
const char * sDirName,
char * sFileName,
int SizeOfFileName);
Parameters
Parameter | Description |
pFD | Context of the directory scanning operation. |
sDirName | Name of the directory to search in. |
sFileName | Buffer that receives the name of the file found. |
SizeOfFileName | Size in bytes of the sFileName buffer. |
Return value
= 0 | OK, directory scanning initialized successfully. |
= 1 | No files or directories available in directory. |
< 0 | Error code indicating the failure reason. |
Additional information
This function returns information about the first file or
directory found in the directory. This is typically the special
directory name “.” when searching in a directory other than root.
FS_FindFirstFile() and FS_FindNextFile() can be used to list
all the files and directories in a directory.
The name of the file or directory is returned in sFileName.
FS_FindFirstFile() stores at most SizeOfFileName - 1 characters
in the buffer and it terminates the name of file or directory
by a 0 character. The file or directory name is truncated if it
contains more characters than the number of characters that can
be stored in sFileName. For files or directories stored on a FAT
volume with LFN support the name is truncated by returning the
short version (8.3 format) of the file or directory name.
Alternatively, the file name can be accessed via the sFileName
member of the pFD structure. Additional information about the
file or directory such as size, attributes and timestamps are
returned via the corresponding members of pFD structure.
For more information refer to FS_FIND_DATA.
The returned file or directory does not necessarily be the
first file or directory created in the root directory. The name
of the first file or directory can change as files are deleted
and created in the root directory.
The file system is able to handle a sFileName buffer with
a maximum size of 32767 bytes.
Example
#include <stdio.h>
#include "FS.h"
void SampleFindFirstFile(void) {
FS_FIND_DATA fd;
int r;
char acFileName[32];
char ac[100];
FS_FILETIME FileTime;
//
// List the files from the "SubDir1" directory.
//
r = FS_FindFirstFile(&fd, "SubDir1", acFileName, sizeof(acFileName));
if (r == 0) {
do {
//
// Ignore "." and ".." entries.
//
if (fd.sFileName[0] == '.') {
continue;
}
//
// Show information about the file.
//
if (fd.Attributes & FS_ATTR_DIRECTORY) {
SEGGER_snprintf(ac, sizeof(ac), "Directory name: %s\n", fd.sFileName);
} else {
SEGGER_snprintf(ac, sizeof(ac), "File name: %s\n", fd.sFileName);
}
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "File size: %lu\n", fd.FileSize);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Attributes: %c%c%c%c%c\n",
(fd.Attributes & FS_ATTR_READ_ONLY) ? 'R' : '-',
(fd.Attributes & FS_ATTR_HIDDEN) ? 'H' : '-',
(fd.Attributes & FS_ATTR_SYSTEM) ? 'S' : '-',
(fd.Attributes & FS_ATTR_ARCHIVE) ? 'A' : '-',
(fd.Attributes & FS_ATTR_DIRECTORY) ? 'D' : '-');
FS_X_Log(ac);
FS_TimeStampToFileTime(fd.CreationTime, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), "Creation time: %d-%.2d-%.2d %.2d:%.2d:%.2d",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
FS_TimeStampToFileTime(fd.LastAccessTime, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), "Access time: %d-%.2d-%.2d %.2d:%.2d:%.2d",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
FS_TimeStampToFileTime(fd.LastWriteTime, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), "Write time: %d-%.2d-%.2d %.2d:%.2d:%.2d",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
FS_X_Log("--\n");
} while (FS_FindNextFile(&fd));
}
FS_FindClose(&fd);
}
FS_FindFirstFile64()
Description
Initiates a directory scanning operation.
Prototype
int FS_FindFirstFile64( FS_FIND_DATA64 * pFD,
const char * sDirName,
char * sFileName,
int SizeOfFileName);
Parameters
Parameter | Description |
pFD | Context of the directory scanning operation. |
sDirName | Name of the directory to search in. |
sFileName | Buffer that receives the name of the file found. |
SizeOfFileName | Size in bytes of the sFileName buffer. |
Return value
= 1 | OK, no files or directories available in directory. |
= 0 | OK, directory scanning initialized successfully. |
< 0 | Error code indicating the failure reason. |
Additional information
This function returns information about the first file or
directory found in the directory. This is typically the special
directory name “.” when searching in a directory other than root.
FS_FindFirstFile64() and FS_FindNextFile64() can be used to list
all the files and directories that are located in a specified directory.
The name of the file or directory is returned via sFileName.
FS_FindFirstFile64() stores at most SizeOfFileName - 1 characters
in the buffer and it terminates the name of file or directory
by a 0-character. The file or directory name is truncated if it
contains more characters than the number of characters that can
be stored in sFileName. For files or directories stored on a FAT
volume with LFN support the name is truncated by returning the
short version (8.3 format) of the file or directory name.
Alternatively, the file name can be accessed via the sFileName
member of the pFD structure. Additional information about the
file or directory such as size, attributes and timestamps are
returned via the corresponding members of pFD structure.
For more information refer to FS_FIND_DATA.
If the file name is truncated then value of the FileNameLen member
of the pFD structure is greater than the length of the 0-terminated
string stored in the sFileName member of the same structure.
The returned file or directory does not necessarily be the
first file or directory created in the root directory. The name
of the first file or directory can change as files are deleted
and created in the root directory.
The file system is able to handle a sFileName buffer with
a maximum size of 32767 bytes.
This function is available only when the file system is built
with FS_SUPPORT_LARGE_FILES set to 1.
Example
#include <stdio.h>
#include "FS.h"
void SampleFindFirstFile64(void) {
FS_FIND_DATA64 fd;
int r;
char acFileName[32];
char ac[100];
FS_FILETIME FileTime;
//
// List the files from the "SubDir1" directory.
//
r = FS_FindFirstFile64(&fd, "SubDir1", acFileName, sizeof(acFileName));
if (r == 0) {
for (;;) {
//
// Skip over system directory entries.
//
if ((fd.sFileName[0] == '.') && (fd.sFileName[1] == '\0')) {
continue;
}
if ((fd.sFileName[0] == '.') && (fd.sFileName[1] == '.') && (fd.sFileName[2] == '\0')) {
continue;
}
//
// Show information about the file.
//
if (fd.Attributes & FS_ATTR_DIRECTORY) {
SEGGER_snprintf(ac, sizeof(ac), "Directory name: %s\n", fd.sFileName);
} else {
SEGGER_snprintf(ac, sizeof(ac), "File name: %s\n", fd.sFileName);
}
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "File size: %lu\n", fd.FileSize);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Attributes: %c%c%c%c%c\n",
(fd.Attributes & FS_ATTR_READ_ONLY) ? 'R' : '-',
(fd.Attributes & FS_ATTR_HIDDEN) ? 'H' : '-',
(fd.Attributes & FS_ATTR_SYSTEM) ? 'S' : '-',
(fd.Attributes & FS_ATTR_ARCHIVE) ? 'A' : '-',
(fd.Attributes & FS_ATTR_DIRECTORY) ? 'D' : '-');
FS_X_Log(ac);
FS_TimeStampToFileTime(fd.CreationTime.TimeDate, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), "Creation time: %d-%.2d-%.2d %.2d:%.2d:%.2d",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
FS_TimeStampToFileTime(fd.LastAccessTime.TimeDate, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), "Access time: %d-%.2d-%.2d %.2d:%.2d:%.2d",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
FS_TimeStampToFileTime(fd.LastWriteTime.TimeDate, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), "Write time: %d-%.2d-%.2d %.2d:%.2d:%.2d",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
FS_X_Log("--\n");
r = FS_FindNextFile64(&fd);
if (r != 0) {
break;
}
}
}
(void)FS_FindClose64(&fd);
}
FS_FindNextFile()
Description
Returns information about the next file or directory
in a directory scanning operation.
Prototype
int FS_FindNextFile(FS_FIND_DATA * pFD);
Parameters
Parameter | Description |
pFD | Context of the directory scanning operation. |
Return value
1 | OK, information returned successfully. |
0 | Error occurred or end of directory reached. |
Additional information
FS_FindNextFile() returns information about the next file
or directory located after the file or directory returned via
a previous call to FS_FindFirstFile() or FS_FindNextFile()
within the same listing context.
The name of the file or directory is returned in sFileName
member of pFD. FS_FindNextFile() stores at most one less than the
buffer size characters in the buffer and it terminates the name of
the file or directory by a 0 character. The buffer for the file or
directory name is specified in the call to FS_FindFirstFile().
The file or directory name is truncated if it contains
more characters than the number of characters that can be stored
in sFileName. For files or directories stored on a FAT volume with
LFN support the name is truncated by returning the short version
(8.3 format) of the file or directory name.
Additional information about the file or directory such as size,
attributes and timestamps are returned via the corresponding members
of pFD structure. For more information refer to FS_FIND_DATA.
FS_FindFirstFile() has to be called first to initialize the
listing operation. It is allowed to perform operations
on files or directories (creation, deletion, etc.) within
the listing loop.
Example
Refer to the example of FS_FindFirstFile()
FS_FindNextFileEx()
Description
Returns information about the next file or directory
in a directory scanning operation.
Prototype
int FS_FindNextFileEx(FS_FIND_DATA * pFD);
Parameters
Parameter | Description |
pFD | Context of the directory scanning operation. |
Return value
= 1 | No files or directories available in directory. |
= 0 | OK, information returned successfully. |
< 0 | Error code indicating the failure reason. |
Additional information
FS_FindNextFileEx() performs the same operation as FS_FindNextFile()
with the difference that its return value is consistent with the
return value of the other emFile API functions.
FS_FindNextFile64()
Description
Returns information about the next file or directory
in a directory scanning operation.
Prototype
int FS_FindNextFile64(FS_FIND_DATA64 * pFD);
Parameters
Parameter | Description |
pFD | Context of the directory scanning operation. |
Return value
= 1 | OK, no files or directories available in directory. |
= 0 | OK, information returned successfully. |
< 0 | Error code indicating the failure reason. |
Additional information
This function can be called only after an initial call
to the FS_FindFirstFile64() with the same directory
scanning context.
This function is available only when the file system is built
with FS_SUPPORT_LARGE_FILES set to 1.
Example
Refer to the example of FS_FindFirstFile64()
FS_MkDir()
Description
Creates a directory.
Prototype
int FS_MkDir(const char * sDirName);
Parameters
Parameter | Description |
sDirName | Directory name. |
Return value
= 0 | OK, directory has been created |
≠ 0 | Error code indicating the failure reason |
Additional information
The function fails if a directory with the same name already
exists in the target directory. FS_MkDir() expects that all
the directories in the path to the created directory exists.
Otherwise the function returns with an error.
FS_CreateDir() can be used to create a directory along with
any missing directories in the path.
Example
#include "FS.h"
void SampleMkDir(void) {
FS_MkDir("SubDir1");
}
FS_RmDir()
Description
Removes a directory.
Prototype
int FS_RmDir(const char * sDirName);
Parameters
Parameter | Description |
sDirName | Directory name. |
Return value
= 0 | OK, directory has been removed |
≠ 0 | Error code indicating the failure reason |
Additional information
The function fails if the directory is not empty.
FS_DeleteDir() can be used to remove a directory and its contents.
Example
#include "FS.h"
void SampleRmDir(void) {
FS_RmDir("SubDir1");
}
FS_FIND_DATA
Description
Information about a file or directory.
Type definition
typedef struct {
U8 Attributes;
U32 CreationTime;
U32 LastAccessTime;
U32 LastWriteTime;
U32 FileSize;
char * sFileName;
U16 SizeofFileName;
FS_DIR Dir;
} FS_FIND_DATA;
Structure members
Member | Description |
Attributes | Attributes of the file or directory. |
CreationTime | Date and time when the file or directory was created. |
LastAccessTime | Date and time when the file or directory was accessed last. |
LastWriteTime | Date and time when the file or directory was modified last. |
FileSize | Size of the file in bytes. |
sFileName | Name of the file or directory as 0-terminated string. |
SizeofFileName | Internal. Not to be used by the application. |
Dir | Internal. Not to be used by the application. |
Additional information
sFileName points to the buffer passed as argument to FS_FindFirstFile().
This structure contains also the context for the file listing
operation. These members are considered internal and should
not be used by the application. FS_FIND_DATA is used as context
by the FS_FindFirstFile(), FS_FindNextFile(), FS_FindNextFileEx()
and FS_FindClose() set of functions.
FS_FIND_DATA64
Description
Information about a file or directory.
Type definition
typedef struct {
U8 Attributes;
FS_TIMESTAMP CreationTime;
FS_TIMESTAMP LastAccessTime;
FS_TIMESTAMP LastWriteTime;
U64 FileSize;
char * sFileName;
U16 FileNameLen;
U16 SizeOfFileName;
FS_DIR Dir;
} FS_FIND_DATA64;
Structure members
Member | Description |
Attributes | Attributes of the file or directory. |
CreationTime | Date and time when the file or directory was created. |
LastAccessTime | Date and time when the file or directory was accessed last. |
LastWriteTime | Date and time when the file or directory was modified last. |
FileSize | Size of the file in bytes. |
sFileName | Name of the file or directory as 0-terminated string. |
FileNameLen | Actual length of the file name in bytes. |
SizeOfFileName | Internal. Not to be used by the application. |
Dir | Internal. Not to be used by the application. |
Additional information
sFileName points to the buffer passed as argument to FS_FindFirstFile64().
This structure contains also the context for the file listing
operation. These members are considered internal and should
not be used by the application. FS_FIND_DATA64 is used as context
by the FS_FindFirstFile64(), FS_FindNextFile64() and FS_FindClose64()
set of functions.
If FileNameLen is greater than the length of the 0-terminated string
stored to sFileName then the file name was truncated.
A storage device has to be formatted before it can be used to write data to it.
SD and MMC memory cards as well as USB drives are usually already preformatted.
Normally, the NAND and NOR flash devices have to be reformatted. These storage
devices require a low-level format first, followed by a high-level format.
The low-level format is device-specific while the high-level format depends
on the type of file system.
Description
Performs a high-level format.
Prototype
int FS_Format(const char * sVolumeName,
const FS_FORMAT_INFO * pFormatInfo);
Parameters
Parameter | Description |
sVolumeName | Volume name. |
pFormatInfo | in Additional format information. It can be set to NULL. |
Return value
= 0 | OK, storage device formatted successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The high-level format operation prepares a storage device
for the access via the file system. It has to be performed once
before writing any data to the storage device.
The term “high-level” indicates that the format operation is performed
at the file system level in comparison with a low-level format
operation that is performed at the device driver level that is located
below the file system level in the file system stack. A low-level
format operation can be performed via FS_FormatLow().
The high-level format operation writes to the storage device basic
management information that is required by the file system to operate correctly.
This includes the initialization of the allocation table and
of the root directory, as well as of the BIOS Parameter Block (BPB)
for a volume formatted as FAT and of the Information Sector for a
volume formatted as EFS. The amount of data written during the
high-level format operation is typically smaller than 1 percent
of the capacity of the storage device.
The type of file system can be selected at compile time via
FS_SUPPORT_FAT and FS_SUPPORT_EFS defines. If both file systems
are enabled at compile time the type of file system can be
configured via FS_SetFSType().
pFormatInfo can be used to specify how the storage device has to
be formatted such as the cluster size and the number of entries
in the root directory.
For a typical application, this parameter can safely
be set to NULL. If set to NULL, the file system uses reasonable
format parameters that are calculated based on the capacity
of the storage device.
For increased performance it is recommended to format the storage
device with clusters as large as possible. In this way the number
of accesses to the allocation table the file system has to perform
during a read or write operation is kept to a minimum.
For more information about format parameters see FS_FORMAT_INFO.
After performing a high-level format operation all the files
and directory that were present on the storage device are lost.
An application can check if a storage device is high-level
formatted by calling FS_IsHLFormatted().
Example
#include <string.h>
#include "FS.h"
void SampleFormat(void) {
FS_FORMAT_INFO FormatInfo;
//
// Format default volume using reasonable defaults.
//
FS_Format("", NULL);
//
// Format the "mmc:0:" volume using 32 Kbyte clusters
// assuming that the size of the logical sector used
// by the storage device is 512 bytes.
//
memset(&FormatInfo, 0, sizeof(FormatInfo));
FormatInfo.SectorsPerCluster = 64;
FS_Format("mmc:0:", &FormatInfo);
}
Description
Performs a low-level format.
Prototype
int FS_FormatLLIfRequired(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be formatted. |
Return value
= 0 | OK, low-level format successful. |
= 1 | Low-level format not required. |
< 0 | Error code indicating the failure reason. |
Additional information
This function performs a low-level format of a storage device
if it is not already low-level formatted. FS_FormatLLIfRequired()
does nothing if the storage device is already low-level formatted.
A storage device has to be low-level formatted once before
the file system can perform any data access. All the data
present on the storage device is lost after a low-level format.
The low-level format operation is required only for the storage
devices that are managed by the file system such as NAND and NOR
flash devices. SD cards and e.MMC devices do not require
a low-level format.
Example
#include "FS.h"
void SampleFormatLLIfRequired(void) {
FS_Init();
//
// Perform a low-level format if required.
// Equivalent to the following sequence:
//
// if (FS_IsLLFormatted("nand:0:") == 0) {
// FS_FormatLow("nand:0:");
// }
//
FS_FormatLLIfRequired("nand:0:");
}
Description
Performs a low-level format.
Prototype
int FS_FormatLow(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be formatted. |
Return value
= 0 | OK, low-level format successful. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The low-level format operation prepares a storage device for the data access.
It has to be performed once before writing any data to the storage device.
This operation is performed by the device driver that is used to access
the storage device. The low-level format operation has to be performed only
for a storage device that is managed by the file system such as NAND
and NOR flash. SD cards and eMMC devices do not support and do not
require a low-level format.
The term “low-level” indicates that the format operation is performed
at the device driver level in comparison with a high-level format
operation that is performed at the file system level that is located
above the device driver level in the file system stack. A high-level
format operation can be performed either via FS_Format() or FS_FAT_FormatSD().
The low-level format operation writes to the storage device basic
management information that is required by the device driver to operate correctly.
A typical low-level format operation erases all the blocks in the partition
that is used as storage and then stores format information in the first block
of the partition.
The file system reports an error if an attempt is made to access
a storage device that is not low-level formatted. The application can check
if a storage device is low-level formatted by calling FS_IsLLFormatted().
All the data present on the storage device is lost after a low-level format.
Typically, a low-level format operation has to be followed by a high-level
format operation if a file system is used for accessing the storage device.
If the storage device is accessed only via the functions of the storage layer
such as when the contents of the storage device is exposed via USB Mass Storage
then a high-level format operation is not required.
Example
#include "FS.h"
void SampleFormatLow(void) {
FS_Init();
//
// Performs a low-level format of the NOR flash.
//
FS_FormatLow("nor:0:");
}
Description
Checks if a volume is high-level formatted or not.
Prototype
int FS_IsHLFormatted(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be checked. |
Return value
= 1 | Volume is formatted. |
= 0 | Volume is not formatted. |
< 0 | Error code indicating the failure reason. |
Additional information
This function can be use to determine if the format of a volume
is supported by the file system. If the volume format is unknown
the function returns 0.
Example
#include "FS.h"
void SampleIsHLFormatted(void) {
FS_Init();
//
// Perform a high-level format if required.
//
if (FS_IsHLFormatted("") == 0) {
FS_Format("", NULL);
}
}
Description
Returns whether a volume is low-level formatted or not.
Prototype
int FS_IsLLFormatted(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be checked. It cannot be NULL. |
Return value
= 1 | Volume is low-level formatted |
= 0 | Volume is not low-level formatted |
< 0 | Error code indicating the failure reason |
Example
#include "FS.h"
void SampleIsLLFormatted(void) {
FS_Init();
//
// Perform a low-level format if required.
// Equivalent to the following sequence:
//
// FS_FormatLLIfRequired("nor:0:");
//
if (FS_IsLLFormatted("nor:0:") == 0) {
FS_FormatLow("nor:0:");
}
}
Description
Parameters for the high-level format.
Type definition
typedef struct {
U16 SectorsPerCluster;
U16 NumRootDirEntries;
FS_DEV_INFO * pDevInfo;
U8 Flags;
U16 SectorsPerClusterHigh;
} FS_FORMAT_INFO;
Structure members
Member | Description |
SectorsPerCluster | Number of sectors in a cluster. |
NumRootDirEntries | Number of directory entries in the root directory. |
pDevInfo | Information about the storage device. |
Flags | Formatting options. |
SectorsPerClusterHigh | High-order 16-bits of the number of sectors in a cluster. |
Additional information
This structure can be passed to FS_Format() to specify
additional information about how the storage device has
to be formatted.
A cluster is the allocation unit of the file system that
consists of one or more consecutive logical sectors.
The size of the cluster can be specified in number of sectors via
SectorsPerCluster that has to be a power of 2 value.
Using large clusters can help improve the performance of the file
system because this reduces the number of accesses to the allocation
table. Using small clusters makes more efficient use of disk space.
Permitted values for SectorsPerCluster are:
- 0-128 for FAT
- 0-32768 for EFS
- 0-65536 for exFAT
A value of 0 means that the file system has to determine the
size of the cluster automatically.
NumRootDirEntries represents the number of directory entries in
the root directory should have. This is only a proposed value.
The actual value depends on the FAT type. This value is typically
used for FAT12 or FAT16 formatted volume that have a fixed number
of entries in the root directory. On FAT32 formatted volume the
root directory can grow dynamically. The file system uses a
default value of 256 if NumRootDirEntries is set to 0.
pDevInfo should be typically set to NULL unless some specific
information about the storage device has to be passed to
format function. The file system requests internally the
information from storage device if pDevInfo is set to NULL.
Flags is a bitwise-or combination of Formatting flags.
Description
Options for formatting a storage device.
Definition
#define FS_FORMAT_FLAG_IGNORE_PARTITIONING 0x01u
Symbols
Definition | Description |
FS_FORMAT_FLAG_IGNORE_PARTITIONING | Overwrite any existing partitioning information. |
Partitioning functions
The functions in this section can be used to manage separate volumes
on the same storage device.
FS_CreateGPT()
Description
Partitions the specified volume using a GPT (GUID Partition Table)
partition scheme.
Prototype
int FS_CreateGPT(const char * sVolumeName,
FS_GPT_INFO * pGPTInfo,
FS_PARTITION_INFO_GPT * pPartInfo,
int NumPartitions);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be partitioned. |
pGPTInfo | in Information about the GPT partitioning. It cannot be NULL. |
pPartInfo | in List of the partitions to be created. It cannot be NULL. |
NumPartitions | Number of partitions to be created. It cannot be 0 or negative. |
Return value
= 0 | OK, volume partitioned successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The partition information is stored starting with the first
logical sector of the storage device. The number of logical sectors
occupied by the partitioning information depends on the number
of partitions created. The partitioning information requires
at least three logical sectors that is one logical sector
for the protective MBR, one logical sector for the GPT header
and one logical sector for the partition table. In addition,
a copy of the GPT header and of the partition table is stored
for redundancy purposes at the end of the storage device.
For this reason, FS_CreateGPT() overwrites any information
present in these logical sectors of the specified volume.
The partition entries are stored in the order specified
in the pPartInfo array: the information found in pPartInfo[0]
is stored to first partition entry, the information found
in pPartInfo[1] is stored to the second partition entry,
and so on.
The actual number of created partition entries is calculated
as the maximum of NumPartitions and pGPTInfo::NumPartitions
If pGPTInfo::NumPartitions is greater than NumPartitions
then FS_CreateGPT() creates empty partitions for partition indexes
greater than or equal to NumPartitions.
FS_CreateGPT() calculates the values of pGPTInfo::StartSector
and pGPTInfo::NumSectors based on the capacity of the storage
device if these members are set to 0.
If pPartInfo::StartSector is set to 0 then FS_CreateGPT()
set is to the next available sector that immediately follows
the previous partition entry. pPartInfo::NumSectors can
be set to 0 only for the last partition in the list in which
case the last partition occupies the remaining free space
on the storage device. For any other partitions
pPartInfo::NumSectors must be different than 0.
FS_CreateGPT() checks the validity of values in pGPTInfo and pPartInfo.
Any misconfiguration such as overlapping partitions is reported as an
error and the partition table is not created.
The partitioning information such as the disk id and the
number of partitions can be queried via FS_GetGPTInfo().
The information about individual partitions can be obtained
via FS_GetPartitionInfoGPT().
The DISKPART logical driver can be used to access
the data of the created partitions.
Example
#include <string.h>
#include "FS.h"
static const U8 _abDiskId[FS_NUM_BYTES_GUID] = { // FB223EF0-C45C-D24A-4787-F2E856469D59
0xFB, 0x22, 0x3E, 0xF0,
0xC4, 0x5C,
0xD2, 0x4A,
0x47, 0x87,
0xF2, 0xE8, 0x56, 0x46, 0x9D, 0x59
};
static const U8 _abTypeBasicData[FS_NUM_BYTES_GUID] = { // A2A0D0EB-E5B9-3344-87C0-68B6B72699C7
0xA2u, 0xA0u, 0xD0u, 0xEBu,
0xE5u, 0xB9u,
0x33u, 0x44u,
0x87u, 0xC0u,
0x68u, 0xB6u, 0xB7u, 0x26u, 0x99u, 0xC7
};
static const U8 _abPartId0[FS_NUM_BYTES_GUID] = { // E633CD2E-2D08-7C46-5E97-7283101E324D
0xE6, 0x33, 0xCD, 0x2E,
0x2D, 0x08,
0x7C, 0x46,
0x5E, 0x97,
0x72, 0x83, 0x10, 0x1E, 0x32, 0x4D
};
static const U8 _abPartId1[FS_NUM_BYTES_GUID] = { // 6D8195A2-A800-3442-4007-999793ECE605
0x6D, 0x81, 0x95, 0xA2,
0xA8, 0x00,
0x34, 0x42,
0x40, 0x07,
0x99, 0x97, 0x93, 0xEC, 0xE6, 0x05
};
static const U8 _abPartId2[FS_NUM_BYTES_GUID] = { // 621D39CB-6DD4-6448-7539-487394C67FCF
0x62, 0x1D, 0x39, 0xCB,
0x6D, 0xD4,
0x64, 0x48,
0x75, 0x39,
0x48, 0x73, 0x94, 0xC6, 0x7F, 0xCF
};
void SampleCreateGPT(void) {
FS_PARTITION_INFO_GPT aPartInfo[3];
FS_GPT_INFO gptInfo;
//
// This example creates a GUID partition table with three partitions.
// The position and size of first partition is configured explicitly.
// The position of the second partition is calculated by FS_CreateGPT()
// and it starts right after the first partition.
// The third partition occupies the remaining of the storage device.
//
memset(aPartInfo, 0, sizeof(aPartInfo));
memset(&gptInfo, 0, sizeof(gptInfo));
//
// We fill here only the disk id. The information related to
// the partition location and the number of partitions is
// calculated by FS_CreateGPT();
//
memcpy(gptInfo.abId, _abDiskId, FS_NUM_BYTES_GUID);
//
// First partition.
//
aPartInfo[0].StartSector = 32;
aPartInfo[0].NumSectors = 5000;
memcpy(aPartInfo[0].abId, _abPartId0, FS_NUM_BYTES_GUID);
memcpy(aPartInfo[0].abType, _abTypeBasicData, FS_NUM_BYTES_GUID);
//
// Second partition.
//
aPartInfo[1].StartSector = 0;
aPartInfo[1].NumSectors = 10000;
memcpy(aPartInfo[1].abId, _abPartId1, FS_NUM_BYTES_GUID);
memcpy(aPartInfo[1].abType, _abTypeBasicData, FS_NUM_BYTES_GUID);
//
// Third partition.
//
aPartInfo[2].StartSector = 0;
aPartInfo[2].NumSectors = 0;
memcpy(aPartInfo[2].abId, _abPartId1, FS_NUM_BYTES_GUID);
memcpy(aPartInfo[2].abType, _abTypeBasicData, FS_NUM_BYTES_GUID);
//
// Create the partition table.
//
FS_CreateGPT("", &gptInfo, aPartInfo, 3);
}
FS_CreateMBR()
Description
Partitions the specified volume using a MBR (Master Boot Record)
partition scheme.
Prototype
int FS_CreateMBR(const char * sVolumeName,
FS_PARTITION_INFO_MBR * pPartInfo,
int NumPartitions);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be partitioned. |
pPartInfo | in List of the partitions to be created. |
NumPartitions | Number of partitions to be created. |
Return value
= 0 | OK, volume partitioned successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The Master Boot Record is a special logical sector that contains
information about how the storage device is partitioned.
This partitioning information is located on the first logical
sector of a storage device (sector index 0). The MBR information can
be queried via FS_GetPartitionInfoMBR().
FS_CreateMBR() overwrites any information present in the first
logical sector of the specified volume.
The partition entries are stored in the order specified in
the pPartInfo array: the information found in pPartInfo[0]
is stored to first partition entry, the information found in
pPartInfo[1] is stored to the second partition entry, and so on.
If the Type member of the FS_PARTITION_INFO_MBR structure
is set to 0 then FS_CreateMBR() automatically calculates the partition
type and the CHS (Cylinder/Head/Sector) addresses (Type,
StartAddr and EndAddr) based on the values stored
in the StartSector and NumSector members.
The data of the created partitions can be accessed using the DISKPART
logical driver.
Example
#include <string.h>
#include "FS.h"
void SampleCreateMBR(void) {
FS_PARTITION_INFO_MBR aPartInfo[2];
//
// This example creates a MBR with two partitions.
// The first partition is configured to be bootable.
// All parameters are explicitly configured.
// The second partition is configured not to be bootable.
// The partition type and CHS address are calculated
// automatically by FS_CreateMBR().
//
memset(aPartInfo, 0, sizeof(aPartInfo));
//
// First partition.
//
aPartInfo[0].IsActive = 1;
aPartInfo[0].StartSector = 10;
aPartInfo[0].NumSectors = 100000;
aPartInfo[0].Type = 6;
aPartInfo[0].StartAddr.Cylinder = 0;
aPartInfo[0].StartAddr.Head = 0;
aPartInfo[0].StartAddr.Sector = 11;
aPartInfo[0].EndAddr.Cylinder = 538;
aPartInfo[0].EndAddr.Head = 1;
aPartInfo[0].EndAddr.Sector = 10;
//
// Second partition.
//
aPartInfo[1].StartSector = 200000;
aPartInfo[1].NumSectors = 10000;
FS_CreateMBR("", aPartInfo, 2);
}
FS_GetGPTInfo()
Description
Returns information about the GPT partitioning.
Prototype
int FS_GetGPTInfo(const char * sVolumeName,
FS_GPT_INFO * pGPTInfo);
Parameters
Parameter | Description |
sVolumeName | Name of the volume on which the partition is located. |
pGPTInfo | out Information about the GPT partitioning. |
Return value
= 0 | OK, partition information read. |
≠ 0 | Error code indicating the failure reason. |
Example
#include <string.h>
#include "FS.h"
void SampleGetGPTInfo(void) {
char ac[100];
int r;
FS_GPT_INFO gptInfo;
memset(&gptInfo, 0, sizeof(gptInfo));
r = FS_GetGPTInfo("", &gptInfo);
if (r == 0) {
FS_X_Log("GPT partitioning info:\n");
SEGGER_snprintf(ac, sizeof(ac), " StartSector: %lu\n",
(U32)gptInfo.StartSector);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumSectors: %lu\n",
(U32)gptInfo.NumSectors);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumPartitions: %u\n", gptInfo.NumPartitions);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " IsValidMain: %u\n", gptInfo.IsValidMain);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " IsValidBackup: %u\n", gptInfo.IsValidBackup);
FS_X_Log(ac);
FS_X_Log(" Id: ");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X%02X%02X",
gptInfo.abId[0], gptInfo.abId[1],
gptInfo.abId[2], gptInfo.abId[3]);
FS_X_Log(ac);
FS_X_Log("-");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X",
gptInfo.abId[4], gptInfo.abId[5]);
FS_X_Log(ac);
FS_X_Log("-");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X",
gptInfo.abId[6], gptInfo.abId[7]);
FS_X_Log(ac);
FS_X_Log("-");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X",
gptInfo.abId[8], gptInfo.abId[9]);
FS_X_Log(ac);
FS_X_Log("-");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X%02X%02X%02X%02X",
gptInfo.abId[10], gptInfo.abId[11], gptInfo.abId[12],
gptInfo.abId[13], gptInfo.abId[14], gptInfo.abId[15]);
FS_X_Log(ac);
FS_X_Log("\n");
}
}
FS_GetPartitionInfoMBR()
Description
Returns information about a MBR partition.
Prototype
int FS_GetPartitionInfoMBR(const char * sVolumeName,
FS_PARTITION_INFO_MBR * pPartInfo,
U8 PartIndex);
Parameters
Parameter | Description |
sVolumeName | Name of the volume on which the partition is located. |
pPartInfo | out Information about the partition. |
PartIndex | Index of the partition to query. |
Return value
= 0 | OK, partition information read. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The function reads the information from the Master Boot Record
(MBR) that is stored on the first sector (the sector with the
index 0) of the specified volume. An error is returned if no MBR
information is present on the volume. If the Type member
of the FS_PARTITION_INFO_MBR structure is 0, the partition entry
is not valid.
Permitted values for PartIndex are 0 to 3.
Example
#include <string.h>
#include "FS.h"
void SampleGetPartitionInfoMBR(void) {
int iPart;
FS_PARTITION_INFO_MBR PartInfo;
char ac[100];
//
// Show the contents of the partition list stored in the Master
// Boot Record. Only the valid entries are displayed.
//
FS_X_Log("MBR partition list:\n");
for (iPart = 0; iPart < FS_MAX_NUM_PARTITIONS_MBR; ++iPart) {
memset(&PartInfo, 0, sizeof(PartInfo));
FS_GetPartitionInfoMBR("", &PartInfo, iPart);
if (PartInfo.Type != 0) {
SEGGER_snprintf(ac, sizeof(ac), " Index: %u\n", iPart);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " StartSector: %lu\n", PartInfo.StartSector);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumSectors: %lu\n", PartInfo.NumSectors);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Type: %u\n", PartInfo.Type);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " IsActive: %u\n", PartInfo.IsActive);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " FirstCylinder: %u\n", PartInfo.StartAddr.Cylinder);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " FirstHead: %u\n", PartInfo.StartAddr.Head);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " FirstSector: %u\n", PartInfo.StartAddr.Sector);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " LastCylinder: %u\n", PartInfo.EndAddr.Cylinder);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " LastHead: %u\n", PartInfo.EndAddr.Head);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " LastSector: %u\n", PartInfo.EndAddr.Sector);
FS_X_Log(ac);
FS_X_Log("\n");
}
}
}
Deprecated name
FS_GetPartitionInfo
FS_GetPartitionInfoGPT()
Description
Returns information about a GPT partition.
Prototype
int FS_GetPartitionInfoGPT(const char * sVolumeName,
FS_PARTITION_INFO_GPT * pPartInfo,
unsigned PartIndex);
Parameters
Parameter | Description |
sVolumeName | Name of the volume on which the partition is located. |
pPartInfo | out Information about the partition. |
PartIndex | Index of the partition to query. |
Return value
= 0 | OK, partition information read. |
≠ 0 | Error code indicating the failure reason. |
Example
#include <string.h>
#include "FS.h"
void SampleGetPartitionInfoGPT(void) {
int iPart;
FS_PARTITION_INFO_GPT PartInfo;
char ac[100];
int r;
FS_GPT_INFO gptInfo;
int IsEmpty;
unsigned i;
//
// Show the contents of a GUID partition table.
// Only the valid entries are displayed.
//
memset(&gptInfo, 0, sizeof(gptInfo));
r = FS_GetGPTInfo("", &gptInfo);
if (r == 0) {
FS_X_Log("GPT partition list:\n");
for (iPart = 0; iPart < gptInfo.NumPartitions; ++iPart) {
memset(&PartInfo, 0, sizeof(PartInfo));
r = FS_GetPartitionInfoGPT("", &PartInfo, iPart);
IsEmpty = 1;
//
// An empty partition entry has all the bytes in the GUID type set to 0;
//
for (i = 0; i < sizeof(PartInfo.abType); ++i) {
if (PartInfo.abType[i] != 0) {
IsEmpty = 0;
}
}
if (IsEmpty == 0) {
SEGGER_snprintf(ac, sizeof(ac), " Index: %u\n", iPart);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " StartSector: %lu\n",
(U32)PartInfo.StartSector);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumSectors: %lu\n",
(U32)PartInfo.NumSectors);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Attr: 0x%08X%08X\n",
(U32)(PartInfo.Attributes >> 32), (U32)(PartInfo.Attributes & 0xFFFFFFFFuL));
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Name: %s\n", PartInfo.acName);
FS_X_Log(ac);
FS_X_Log(" Type: ");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X%02X%02X",
PartInfo.abType[0], PartInfo.abType[1],
PartInfo.abType[2], PartInfo.abType[3]);
FS_X_Log(ac);
FS_X_Log("-");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X",
PartInfo.abType[4], PartInfo.abType[5]);
FS_X_Log(ac);
FS_X_Log("-");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X",
PartInfo.abType[6], PartInfo.abType[7]);
FS_X_Log(ac);
FS_X_Log("-");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X",
PartInfo.abType[8], PartInfo.abType[9]);
FS_X_Log(ac);
FS_X_Log("-");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X%02X%02X%02X%02X",
PartInfo.abType[10], PartInfo.abType[11], PartInfo.abType[12],
PartInfo.abType[13], PartInfo.abType[14], PartInfo.abType[15]);
FS_X_Log(ac);
FS_X_Log(" Unique: ");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X%02X%02X",
PartInfo.abId[0], PartInfo.abId[1],
PartInfo.abId[2], PartInfo.abId[3]);
FS_X_Log(ac);
FS_X_Log("-");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X",
PartInfo.abId[4], PartInfo.abId[5]);
FS_X_Log(ac);
FS_X_Log("-");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X",
PartInfo.abId[6], PartInfo.abId[7]);
FS_X_Log(ac);
FS_X_Log("-");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X",
PartInfo.abId[8], PartInfo.abId[9]);
FS_X_Log(ac);
FS_X_Log("-");
SEGGER_snprintf(ac, sizeof(ac), "%02X%02X%02X%02X%02X%02X",
PartInfo.abId[10], PartInfo.abId[11], PartInfo.abId[12],
PartInfo.abId[13], PartInfo.abId[14], PartInfo.abId[15]);
FS_X_Log(ac);
FS_X_Log("\n");
FS_X_Log("\n");
}
}
}
}
FS_GetPartitioningScheme()
Description
Returns information about how a storage device is partitioned.
Prototype
int FS_GetPartitioningScheme(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume on which the partition is located. |
Return value
≥ 0 | OK, partitioning type. Can be one of the Partitioning schemes values. |
≠ 0 | Error code indicating the failure reason. |
Example
#include "FS.h"
void SampleGetPartitioningScheme(void) {
int Scheme;
Scheme = FS_GetPartitioningScheme("");
if (Scheme >= 0) {
switch (Scheme) {
case FS_PARTITIONING_SCHEME_NONE:
FS_X_Log("The storage device is not partitioned.\n");
break;
case FS_PARTITIONING_SCHEME_MBR:
FS_X_Log("The storage device is partitioned via MBR.\n");
break;
case FS_PARTITIONING_SCHEME_GPT:
FS_X_Log("The storage device is partitioned via GPT.\n");
break;
default:
FS_X_Log("Unknown partitioning scheme.\n");
break;
}
}
}
FS_GPT_INFO
Description
Information about a GUID partition table.
Type definition
typedef struct {
U64 StartSector;
U64 NumSectors;
U16 NumPartitions;
U8 IsValidMain;
U8 IsValidBackup;
U8 abId[];
} FS_GPT_INFO;
Structure members
Member | Description |
StartSector | Index of the first logical sector that can be used for partition data (FirstUsableLBA field). |
NumSectors | Index of the last logical sector that can be used for partition data (LastUsableLBA field - FirstUsableLBA field + 1). |
NumPartitions | Number of partitions present on the storage device (NumberOfPartitionEntries field). |
IsValidMain | Indicates if the main partition table is valid. |
IsValidBackup | Indicates if the backup partition table is valid. |
abId | GUID that uniquely identifies the storage device (DiskGUID field) |
Additional information
The partitioning information can be obtained via FS_GetGPTInfo().
FS_PARTITION_INFO_MBR
Description
Information about a MBR partition.
Type definition
typedef struct {
U32 NumSectors;
U32 StartSector;
FS_CHS_ADDR StartAddr;
FS_CHS_ADDR EndAddr;
U8 Type;
U8 IsActive;
} FS_PARTITION_INFO_MBR;
Structure members
Member | Description |
NumSectors | Total number of sectors in the partition. |
StartSector | Index of the first sector in the partition relative to the beginning of the storage device. |
StartAddr | Address of the first sector in the partition in CHS format. |
EndAddr | Address of the last sector in the partition in CHS format. |
Type | Type of the partition. |
IsActive | Set to 1 if the partition is bootable. |
Example
For an example usage refer to FS_GetPartitionInfoMBR().
Deprecated name
FS_PARTITION_INFO_MBR
FS_PARTITION_INFO_GPT
Description
Information about a GPT partition.
Type definition
typedef struct {
U8 abType[];
U8 abId[];
U64 StartSector;
U64 NumSectors;
U64 Attributes;
char acName[];
} FS_PARTITION_INFO_GPT;
Structure members
Member | Description |
abType | Partition type as GUID (PartitionTypeGUID field). |
abId | Unique id of the partition as GUID (UniquePartitionGUID field). |
StartSector | Index of the first logical sector in the partition (StartingLBA field). |
NumSectors | Index of the last logical sector in the partition (EndingLBA field - StartingLBA field + 1). |
Attributes | Partition attributes (Attributes field). |
acName | Partition name as 0-terminated string, UTF-8 encoded (PartitionName field). |
Additional information
The name of the partition returned via acName member is a
0-terminated string encoded as UTF-8. The size of this member
can be configured via FS_MAX_NUM_BYTES_PART_NAME.
Example
For an example usage refer to FS_GetPartitionInfoGPT().
Partitioning schemes
Description
Methods for partitioning a storage device.
Definition
#define FS_PARTITIONING_SCHEME_NONE 0
#define FS_PARTITIONING_SCHEME_MBR 1
#define FS_PARTITIONING_SCHEME_GPT 2
Symbols
Definition | Description |
FS_PARTITIONING_SCHEME_NONE | The storage device is not partitioned. |
FS_PARTITIONING_SCHEME_MBR | The storage device is partitioned as MBR. |
FS_PARTITIONING_SCHEME_GPT | The storage device is partitioned as GPT. |
Example
Refer to FS_GetPartitioningScheme() for an example usage.
File system checking functions
The functions in this section can be used by an application to check
the consistency of the file system structure.
FS_CheckAT()
Description
Verifies the consistency of the allocation table.
Prototype
int FS_CheckAT(FS_CHECK_DATA * pCheckData);
Parameters
Parameter | Description |
pCheckData | in Checking context. It cannot be NULL. |
Return value
= FS_CHECKDISK_RETVAL_OK | No errors found or the callback returned FS_CHECKDISK_ACTION_DO_NOT_REPAIR. |
= FS_CHECKDISK_RETVAL_RETRY | An error has been found. The error has been corrected since the callback function returned FS_CHECKDISK_ACTION_SAVE_CLUSTERS or FS_CHECKDISK_ACTION_DELETE_CLUSTERS. FS_CheckDir() has to be called again to check for the next error. |
= FS_CHECKDISK_RETVAL_ABORT | The application requested the abort of disk checking operation through the callback returning FS_CHECKDISK_ACTION_ABORT. |
= FS_CHECKDISK_RETVAL_CONTINUE | Indicates that not all the allocation table has been checked. The entire volume has to be checked again using FS_CheckDir(). |
< 0 | Error code indicating the failure reason. |
Additional information
FS_CheckAT() has to be called in combination with FS_InitCheck()
and FS_CheckDir() to check the consistency of the file system.
pCheckData has to be initialized via a call to FS_InitCheck().
Example
Refer to FS_InitCheck() for a usage example.
FS_CheckDir()
Description
Verifies the consistency of a single directory.
Prototype
int FS_CheckDir( FS_CHECK_DATA * pCheckData,
const char * sPath);
Parameters
Parameter | Description |
pCheckData | in Checking context. It cannot be NULL. |
sPath | Path to the directory to be checked. It cannot be NULL. |
Return value
= FS_CHECKDISK_RETVAL_OK | No errors found or the callback returned FS_CHECKDISK_ACTION_DO_NOT_REPAIR. |
= FS_CHECKDISK_RETVAL_RETRY | An error has been found. The error has been corrected since the callback function returned FS_CHECKDISK_ACTION_SAVE_CLUSTERS or FS_CHECKDISK_ACTION_DELETE_CLUSTERS. FS_CheckDir() has to be called again to check for the next error. |
= FS_CHECKDISK_RETVAL_ABORT | The application requested the abort of disk checking operation through the callback returning FS_CHECKDISK_ACTION_ABORT. |
= FS_CHECKDISK_RETVAL_MAX_RECURSE | Maximum recursion level reached. The disk checking operation has been aborted. |
< 0 | Error code indicating the failure reason. |
Additional information
FS_CheckDir() has to be called in combination with FS_InitCheck()
and FS_CheckAT() to check the consistency of the file system.
pCheckData has to be initialized via a call to FS_InitCheck().
In order to check the entire file system structure, the application
will have to call FS_CheckDir() with every different directory path
present on the file system.
Example
Refer to FS_InitCheck() for a usage example.
FS_CheckDisk()
Description
Checks the consistency of the file system structure.
Prototype
int FS_CheckDisk(const char * sVolumeName,
void * pBuffer,
U32 BufferSize,
int MaxRecursionLevel,
FS_CHECKDISK_ON_ERROR_CALLBACK * pfOnError);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be checked. |
pBuffer | Work buffer to be used for checking the allocation table. |
BufferSize | Size of the work buffer in bytes. It cannot be NULL. |
MaxRecursionLevel | The maximum directory depth the function is allowed to check. |
pfOnError | Function that has to be called when an error is found. It cannot be NULL. |
Return value
= FS_CHECKDISK_RETVAL_OK | No errors found or the callback returned FS_CHECKDISK_ACTION_DO_NOT_REPAIR. |
= FS_CHECKDISK_RETVAL_RETRY | An error has been found. The error has been corrected since the callback function returned FS_CHECKDISK_ACTION_SAVE_CLUSTERS or FS_CHECKDISK_ACTION_DELETE_CLUSTERS. FS_CheckDisk() has to be called again to check for the next error. |
= FS_CHECKDISK_RETVAL_ABORT | The application requested the abort of disk checking operation through the callback returning FS_CHECKDISK_ACTION_ABORT. |
= FS_CHECKDISK_RETVAL_MAX_RECURSE | Maximum recursion level reached. The disk checking operation has been aborted. |
< 0 | Error code indicating the failure reason. |
Additional information
This function can be used to check if any errors are present
on a specific volume and, if necessary, to repair these errors.
Ideally, the work buffer has to be large enough to store the
usage information of all the clusters in the allocation table.
FS_CheckDisk() uses one bit to store the usage state of a cluster.
The typical size of the work buffer is about 2 KBytes.
Additional iterations are performed if the work buffer
is not large enough to check the whole allocation table
in one step.
FS_CheckDisk() can detect and correct the following file system
errors:
- Invalid directory entries.
- Lost clusters or cluster chains.
- Cross-linked clusters.
- Clusters are associated to a file with size of 0.
- Too few clusters are allocated to a file.
- Cluster is not marked as end-of-chain, although it should be.
The contents of a lost cluster chain is saved during the repair
operation to files named FILE<FileIndex>.CHK that are stored
in directories named FOUND.<DirIndex>. FileIndex is
a 0-based 4-digit decimal number that is incremented by one for
each cluster chain saved. DirIndex is a 0-based 3-digit
decimal number that is incremented by one each time FS_CheckDisk()
is called. For example the first created directory has the
name FOUND.000, the second FOUND.001, and so on
while the first file in the directory has the name FILE0000.CHK,
the second FILE0001.CHK, and so on.
The callback function is used to notify the application about
the errors found by FS_CheckDisk() during the disk checking
operation. FS_CheckDisk() uses the return value of the callback
function to decide if the error hast to be repaired or not.
For more information refer to FS_CHECKDISK_ON_ERROR_CALLBACK.
FS_CheckDisk() closes all opened files before it starts the
disk checking operation. The application is not allowed to
access the storage device from a different task as long as
the operation is in progress.
Example
#include <stdio.h>
#include <stdarg.h>
#include <string.h>
#include "FS.h"
static U32 _aBuffer[1024 / 4];
static int _NumErrors;
/*********************************************************************
*
* _OnError
*/
static int _OnError(int ErrCode, ...) {
va_list ParamList;
const char * sFormat;
char c;
char ac[256];
(void)memset(&ParamList, 0, sizeof(ParamList));
sFormat = FS_CheckDisk_ErrCode2Text(ErrCode);
if (sFormat) {
va_start(ParamList, ErrCode);
vsprintf(ac, sFormat, ParamList);
FS_X_Log(ac);
FS_X_Log("\n");
}
if (ErrCode != FS_CHECKDISK_ERRCODE_CLUSTER_UNUSED) {
FS_X_Log(" Do you want to repair this? (y/n/a) ");
} else {
FS_X_Log(" * Convert lost cluster chain into file (y)\n");
FS_X_Log(" * Delete cluster chain (d)\n");
FS_X_Log(" * Do not repair (n)\n");
FS_X_Log(" * Abort (a)\n");
}
_NumErrors++;
c = getchar();
FS_X_Log("\n");
if ((c == 'y') || (c == 'Y')) {
return FS_CHECKDISK_ACTION_SAVE_CLUSTERS;
} else if ((c == 'a') || (c == 'A')) {
return FS_CHECKDISK_ACTION_ABORT;
} else if ((c == 'd') || (c == 'D')) {
return FS_CHECKDISK_ACTION_DELETE_CLUSTERS;
}
return FS_CHECKDISK_ACTION_DO_NOT_REPAIR; // Do not repair anything.
}
/*********************************************************************
*
* SampleCheckDisk
*/
void SampleCheckDisk(void) {
int r;
while (1) {
r = FS_CheckDisk("", _aBuffer, sizeof(_aBuffer), 5, _OnError);
if (r != FS_CHECKDISK_RETVAL_RETRY) {
break;
}
}
if (_NumErrors == 0) {
FS_X_Log("No errors were found.\n");
} else {
FS_X_Log("Errors were found.\n");
}
}
FS_CheckDisk_ErrCode2Text()
Description
Returns a human-readable text description of a disk checking
error code.
Prototype
char *FS_CheckDisk_ErrCode2Text(int ErrCode);
Parameters
Parameter | Description |
ErrCode | Error code for which the text description has to be returned. |
Return value
Text description as 0-terminated string.
Additional information
This function can be invoked inside the callback
for FS_CheckDisk() to format the error information
in human-readable format. The text description includes
format specifiers for the printf() family of functions that
can be used to show additional information about the
file system error.
Refer to FS_CheckDisk() for more information about how
to use this function.
FS_GetATInfo()
Description
Obtains information about the allocation table.
Prototype
int FS_GetATInfo(const char * sVolumeName,
FS_AT_INFO * pATInfo);
Parameters
Parameter | Description |
sVolumeName | Name of the volume that stores the allocation table. It cannot be NULL. |
pATInfo | out Allocation table information. It cannot be NULL. |
Return value
= 0 | OK, information returned successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This is an optional function that can be used to get
information about the allocation table. The allocation
table is a data structure maintained by the file system
that stores information about how the clusters are allocated.
Example
#include "FS.h"
void SampleGetATInfo(void) {
int r;
FS_AT_INFO ATInfo;
char ac[100];
memset(&ATInfo, 0, sizeof(ATInfo));
r = FS_GetATInfo("", &ATInfo);
if (r == 0) {
FS_X_Log("Allocation table info:");
SEGGER_snprintf(ac, sizeof(ac), " First cluster: %u\n", ATInfo.FirstClusterId);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Last cluster: %u\n", ATInfo.LastClusterId);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Write count: %u\n", ATInfo.WriteCnt);
FS_X_Log(ac);
}
}
FS_GetClusterInfo()
Description
Obtains information about a storage allocation unit.
Prototype
int FS_GetClusterInfo(const char * sVolumeName,
U32 ClusterId,
FS_CLUSTER_INFO * pClusterInfo);
Parameters
Parameter | Description |
sVolumeName | Name of the volume that stores the cluster. It cannot be NULL. |
ClusterId | Id of the cluster to be queried. |
pClusterInfo | out Cluster information. It cannot be NULL. |
Return value
= 0 | OK, information returned successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This is an optional function that can be used to get detailed
information about a storage allocation unit (cluster).
The file system reserves the first entries in the allocation table for internal usage.
These entries of the allocation table do not have any associated cluster.
The id of the first and of the last valid cluster can be obtain via FS_GetATInfo().
Example
#include "FS.h"
void SampleGetClusterInfo(void) {
int r;
FS_CLUSTER_INFO ClusterInfo;
char ac[100];
memset(&ClusterInfo, 0, sizeof(ClusterInfo));
r = FS_GetClusterInfo("", 2, &ClusterInfo);
if (r == 0) {
FS_X_Log("Cluster info:");
SEGGER_snprintf(ac, sizeof(ac), " Sector index: %u\n", ClusterInfo.SectorIndex);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Status: %s\n",
ClusterInfo.IsFree ? "free" : "allocated");
FS_X_Log(ac);
if (ClusterInfo.IsFree == 0) {
if (ClusterInfo.IsEOC != 0) {
SEGGER_snprintf(ac, sizeof(ac), " Next cluster: <end of chain>\n");
} else {
SEGGER_snprintf(ac, sizeof(ac), " Next cluster: %u\n", ClusterInfo.NextClusterId);
}
FS_X_Log(ac);
}
}
}
FS_GetDiskLayout()
Description
Obtains information about the data layout of a volume.
Prototype
int FS_GetDiskLayout(const char * sVolumeName,
FS_DISK_LAYOUT * pDiskLayout);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be queried. It cannot be NULL. |
pDiskLayout | out Layout information. It cannot be NULL. |
Return value
= 0 | OK, information returned successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This is an optional function that can be used to get
detailed information about where the file system stores
the data on a volume. The information is provided in
in a form of logical sector ranges.
Example
#include "FS.h"
void SampleGetDiskLayout(void) {
int r;
FS_DISK_LAYOUT DiskLayout;
U32 aBuffer[512 / 4];
U32 SectorIndex;
memset(&DiskLayout, 0, sizeof(DiskLayout));
r = FS_GetDiskLayout("", &DiskLayout);
if (r == 0) {
//
// Read the first logical sector of the root directory.
// Works only for volumes formatted as FAT12 or FAT16.
//
if ( (DiskLayout.FSType == FS_TYPE_FAT12)
|| (DiskLayout.FSType == FS_TYPE_FAT16)) {
SectorIndex = DiskLayout.FSLayout.fat.SectorIndexRootDir;
(void)FS_STORAGE_ReadSector("", aBuffer, SectorIndex);
}
}
}
FS_GetFirstCluster()
Description
Obtains the id of the first cluster assigned to a file or directory.
Prototype
int FS_GetFirstCluster(const char * sName,
U32 * pClusterId);
Parameters
Parameter | Description |
sName | Name of the file or directory to query. |
pClusterId | out Id of the first cluster. |
Return value
= 0 | OK, cluster id returned successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This is an optional function that can be used to get the
id of the first cluster assigned to a file or directory for
analysis purposes.
Empty files do not have any cluster assigned to them.
In this case the returned cluster id is 0.
Subdirectories always have a cluster id assigned to them because
they are never empty since the system directory entries “.”
and “..” are always present and cannot be deleted.
The root directory of a FAT32 and EFS formatted storage device
always have a cluster id assigned to them that is set when
the storage device is formatted.
The root directory of a FAT12 and FAT16 formatted storage device
is allocated on a special area of the file system and has a fixed size.
For this reason the such a root directory does not have any cluster
allocated to it. FS_GetFirstCluster() returns an error in this case.
Example
#include "FS.h"
void SampleGetFirstCluster(void) {
char ac[100];
U32 ClusterId;
int r;
r = FS_MkDir("SubDir1");
if (r == 0) {
r = FS_GetFirstCluster("SubDir1", &ClusterId);
if (r == 0) {
SEGGER_snprintf(ac, sizeof(ac), "%u is the first cluster in the chain\n", ClusterId);
FS_X_Log(ac);
}
}
}
FS_InitCheck()
Description
Initializes a non-blocking disk checking operation.
Prototype
int FS_InitCheck( FS_CHECK_DATA * pCheckData,
const char * sVolumeName,
void * pBuffer,
U32 BufferSize,
FS_CHECKDISK_ON_ERROR_CALLBACK * pfOnError);
Parameters
Parameter | Description |
pCheckData | out Checking context. It cannot be NULL. |
sVolumeName | Name of the volume on which the checking is performed. It cannot be NULL. |
pBuffer | in Working buffer. It cannot be NULL. |
BufferSize | Number of bytes in pBuffer. |
pfOnError | Callback function to be invoked in case of a file system damage. It cannot be NULL. |
Return value
= FS_CHECKDISK_RETVAL_OK | OK, disk checking has been initialized. |
< 0 | Error code indicating the failure reason. |
Additional information
FS_InitCheck() has to be called in combination with FS_CheckDir()
and FS_CheckAT() to check the consistency of the file system.
These functions perform the same operation as FS_CheckDisk()
with the difference that the access to the file system is
blocked only for a limited period of time.
It is mandatory to call FS_InitCheck() before any call to
FS_CheckDir() or FS_CheckAT(). The purpose of FS_InitCheck() is to
prepare the checking context pCheckData for the operation.
This context must be passed to FS_CheckDir() and FS_CheckAT().
The parameters sVolumeName, pBuffer, BufferSize and pfOnError
have the same meaning as the corresponding parameters of FS_CheckDisk().
Refer to FS_CheckDisk() for more information about the usage of these
parameters.
In a typical usage the application calls FS_InitCheck() once followed
by multiple calls to FS_CheckDir() and FS_CheckAT(). In addition,
each time FS_CheckDir() and FS_CheckAT() find and correct an error
FS_InitCheck() has to be called again to re-initialize the operation.
Example
The following example demonstrates how the consistency of the file system
structure can be checked while the application performs normal file system
operations.
#include <stdarg.h>
#include <stdio.h>
#include <string.h>
#include "FS.h"
#define VOLUME_NAME ""
#define MAX_RECURSION 5
static U32 _aBuffer[1024 / 4];
static int _NumErrors;
/*********************************************************************
*
* _IsSystemDir
*/
static int _IsSystemDir(const char * sDirName) {
if (((*sDirName == '.') && (*(sDirName + 1) == '\0'))) {
return 1;
}
if (((*sDirName == '.') && (*(sDirName + 1) == '.') && (*(sDirName + 2) == '\0'))) {
return 1;
}
return 0;
}
/*********************************************************************
*
* _cbOnError
*/
static int _cbOnError(int ErrCode, ...) {
va_list ParamList;
const char * sFormat;
int c;
char ac[1000];
//lint --e{438} -esym(530, ParamList)
sFormat = FS_CheckDisk_ErrCode2Text(ErrCode);
if (sFormat) {
va_start(ParamList, ErrCode);
SEGGER_vsnprintf(ac, sizeof(ac), sFormat, ParamList);
va_end(ParamList);
FS_X_Log(ac);
FS_X_Log("\n");
}
if (ErrCode != FS_CHECKDISK_ERRCODE_CLUSTER_UNUSED) {
FS_X_Log(" Do you want to repair this error? (y/n/a) ");
} else {
FS_X_Log(" * Convert lost cluster chain into file (y)\n");
FS_X_Log(" * Delete cluster chain (d)\n");
FS_X_Log(" * Do not repair (n)\n");
FS_X_Log(" * Abort (a)\n");
}
++_NumErrors;
c = getchar();
FS_X_Log("\n");
if ((c == 'y') || (c == 'Y')) {
return FS_CHECKDISK_ACTION_SAVE_CLUSTERS;
} else if ((c == 'a') || (c == 'A')) {
return FS_CHECKDISK_ACTION_ABORT;
} else if ((c == 'd') || (c == 'D')) {
return FS_CHECKDISK_ACTION_DELETE_CLUSTERS;
}
return FS_CHECKDISK_ACTION_DO_NOT_REPAIR;
}
/*********************************************************************
*
* _CheckDir
*
* Function description
* Checks the consistency of a directory tree.
*
* Notes
* (1) This function calls itself recursively.
*/
static int _CheckDir(FS_CHECK_DATA * pCheckData, char * sDirPath,
unsigned SizeOfDirPath, int MaxRecursionLevel) {
int r;
int Result;
FS_FIND_DATA FindData;
char acDirName[32];
unsigned LenPath;
unsigned LenName;
char * p;
char * pEnd;
unsigned NumBytes;
r = FS_CheckDir(pCheckData, sDirPath);
if (r == FS_CHECKDISK_RETVAL_OK) {
//
// Search for subdirectories and descend into them.
//
memset(&FindData, 0, sizeof(FindData));
Result = FS_FindFirstFile(&FindData, sDirPath, acDirName, sizeof(acDirName));
if (Result == 0) {
while (1) {
//
// Descend into any directory other than "." and "..".
//
if (FindData.Attributes & FS_ATTR_DIRECTORY) {
if (_IsSystemDir(FindData.sFileName) == 0) {
if (MaxRecursionLevel == 0) {
r = FS_CHECKDISK_RETVAL_MAX_RECURSE; // Error, deepest directory
// level reached.
break;
}
//
// Create the path to the directory.
//
LenPath = strlen(sDirPath);
if (LenPath >= (SizeOfDirPath - 1)) {
r = FS_ERRCODE_BUFFER_TOO_SMALL; // Error, cannot create path
// to directory.
break;
}
NumBytes = SizeOfDirPath - LenPath;
LenName = strlen(FindData.sFileName);
if ((LenName + 1 + 1) >= NumBytes) {
r = FS_ERRCODE_BUFFER_TOO_SMALL; // Error, cannot create path
// to directory.
break;
}
pEnd = sDirPath + LenPath;
p = pEnd;
strcpy(p, FindData.sFileName); // Add the directory name.
p += LenName;
*p++ = FS_DIRECTORY_DELIMITER; // Separate the path from
// directory name.
*p = '\0';
r = _CheckDir(pCheckData, sDirPath, SizeOfDirPath, MaxRecursionLevel - 1);
*pEnd = '\0'; // Restore the path to parent
// directory.
if (r != FS_CHECKDISK_RETVAL_OK) {
break;
}
}
}
Result = FS_FindNextFile(&FindData);
if (Result == 0) {
break; // End of directory reached
// or error.
}
}
}
}
if (r == FS_CHECKDISK_RETVAL_SKIP) {
r = FS_CHECKDISK_RETVAL_OK; // Make sure that we return
// the same value as FS_CheckDisk()
}
return r;
}
/*********************************************************************
*
* _CheckDisk
*
* Function description
* Checks the consistency of the file system.
*/
static int _CheckDisk(void) {
int r;
char acDirName[FS_MAX_PATH];
FS_CHECK_DATA CheckData;
memset(&CheckData, 0, sizeof(CheckData));
for (;;) {
//
// Initialize the operation.
//
r = FS_InitCheck(&CheckData, VOLUME_NAME, _aBuffer, sizeof(_aBuffer), _cbOnError);
if (r != 0) {
break; // Error, could not initialize
// the operation.
}
for (;;) {
memset(acDirName, 0, sizeof(acDirName)); // Begin the checking with the
// root directory.
strncpy(acDirName, VOLUME_NAME, sizeof(acDirName) - 1);
//
// Check the directory structure.
//
r = _CheckDir(&CheckData, acDirName, sizeof(acDirName), MAX_RECURSION);
if (r != FS_CHECKDISK_RETVAL_OK) {
break; // An error occurred.
}
//
// Check the allocation table.
//
r = FS_CheckAT(&CheckData);
if (r != FS_CHECKDISK_RETVAL_CONTINUE) {
break; // No more checks are required
// or an error was found and corrected.
}
}
if (r != FS_CHECKDISK_RETVAL_RETRY) {
break; // Operation completed.
}
}
return r;
}
/*********************************************************************
*
* SampleCheckDiskBG
*/
void SampleCheckDiskBG(void) {
FS_CHECK_DATA CheckData;
FS_CHECK_DATA CheckDataOld;
int r;
//
// Initialize the check context.
//
memset(&CheckDataOld, 0, sizeof(CheckDataOld));
memset(&CheckData, 0, sizeof(CheckData));
for (;;) {
//
// Wait for a file system change.
//
for (;;) {
r = FS_InitCheck(&CheckData, VOLUME_NAME, _aBuffer, sizeof(_aBuffer), _cbOnError);
if (r == 0) {
r = memcmp(&CheckData, &CheckDataOld, sizeof(FS_CHECK_DATA));
if (r != 0) {
break;
}
}
//
// TBD: Delay execution using a RTOS function.
//
}
_NumErrors = 0;
//
// Check and correct file system errors.
//
r = _CheckDisk();
if (r != 0) {
FS_X_Log("Disk checking operation failed.\n");
} else {
if (_NumErrors == 0) {
FS_X_Log("File system structure is consistent.\n");
}
}
memcpy(&CheckDataOld, &CheckData, sizeof(FS_CHECK_DATA));
}
}
FS_AT_INFO
Description
Information about the allocation table.
Type definition
typedef struct {
U32 FirstClusterId;
U32 LastClusterId;
U32 WriteCnt;
} FS_AT_INFO;
Structure members
Member | Description |
FirstClusterId | Id of the first cluster used as storage. |
LastClusterId | Id of the last cluster used as storage. |
WriteCnt | Number of times the allocation table was modified since mounting the file system. |
Additional information
The information can be obtained using FS_GetATInfo().
FS_CLUSTER_INFO
Description
Information about a storage allocation unit.
Type definition
typedef struct {
U32 SectorIndex;
U32 NextClusterId;
U8 IsFree;
U8 IsEOC;
} FS_CLUSTER_INFO;
Structure members
Member | Description |
SectorIndex | Index of the first sector in the cluster. |
NextClusterId | Id of the linked cluster. |
IsFree | Usage status. |
IsEOC | End of chain status. |
Additional information
NextClusterId is valid only if IsFree and IsEOC are set to 0.
IsFree is set to 1 if the cluster is not allocated to any file or directory.
IsEOC is set to 1 if the cluster is the last in the chain.
If the cluster is linked to another cluster then IsEOC is set to 0.
In this case NextClusterId stores the index of the linked cluster.
Information about a cluster can be obtained using FS_GetClusterInfo().
FS_DISK_LAYOUT
Description
Layout of the data stored on the volume.
Type definition
typedef struct {
U32 SectorIndexPart;
U32 NumSectorsPart;
U16 FSType;
FS_FS_LAYOUT FSLayout;
} FS_DISK_LAYOUT;
Structure members
Member | Description |
SectorIndexPart | Index of the logical sector that stores the first data in the file system partition. |
NumSectorsPart | Number of logical sectors in the file system partition. |
FSType | Type of the file system stored on the volume. |
FSLayout | Information about the layout of the file system data. |
Additional information
SectorIndexPart is set to 0 if the storage device is not partitioned.
The sector indexes in the FSLayout.fat and FSLayout.efs structures
are relative to SectorIndexPart.
FSType indicates the type of file system stored on the volume.
It can be set to one of the Format types values.
If FSType is set to either FS_TYPE_FAT12, FS_TYPE_FAT16 or
FS_TYPE_FAT32 then the layout information is stored in
FSLayout.fat. If FSType is set to FS_TYPE_EFS then the layout
information is stored in FSLayout.efs.
The data layout of a volume can be obtained using FS_GetVolumeLayout().
FS_EFS_LAYOUT
Description
Data layout of an EFS partition.
Type definition
typedef struct {
U32 SectorIndexInfo;
U32 SectorIndexStatus;
U32 SectorIndexAT;
U32 NumSectorsAT;
U32 SectorIndexData;
U32 NumSectorsData;
} FS_EFS_LAYOUT;
Structure members
Member | Description |
SectorIndexInfo | Index of the logical sector that stores the format information. |
SectorIndexStatus | Index of the logical sector that stores information about the status of file system. |
SectorIndexAT | Index of the logical sector that stores the beginning of the allocation table. |
NumSectorsAT | Number of logical sectors in the allocation table. |
SectorIndexData | Index of the logical sector that stores the beginning of the area reserved for files and directories. |
NumSectorsData | Number of logical sectors available for file and directories. |
FS_FAT_LAYOUT
Description
Data layout of a FAT partition.
Type definition
typedef struct {
U32 SectorIndexBPB;
U32 SectorIndexBPBBackup;
U32 SectorIndexFSInfo;
U32 SectorIndexFSInfoBackup;
U32 NumSectorsReserved;
U32 SectorIndexAT;
U32 SectorIndexATBackup;
U32 NumSectorsAT;
U32 SectorIndexRootDir;
U32 NumSectorsRootDir;
U32 SectorIndexData;
U32 NumSectorsData;
} FS_FAT_LAYOUT;
Structure members
Member | Description |
SectorIndexBPB | Index of the logical sector that stores the format information. |
SectorIndexBPBBackup | Index of the logical sector that stores a copy of the format information. |
SectorIndexFSInfo | Index of the logical sector that stores information about the status of file system. |
SectorIndexFSInfoBackup | Index of the logical sector that stores a copy of the data stored at SectorIndexFSInfo. |
NumSectorsReserved | Number of reserved logical sectors. |
SectorIndexAT | Index of the logical sector that stores the beginning of the allocation table. |
SectorIndexATBackup | Index of the logical sector that stores the beginning of the copy of the allocation table. |
NumSectorsAT | Number of logical sectors in the allocation table. |
SectorIndexRootDir | Index of the logical sector that stores the beginning of the root directory. |
NumSectorsRootDir | Number of logical sectors allocated for the root directory. |
SectorIndexData | Index of the logical sector that stores the beginning of the area reserved for files and directories. |
NumSectorsData | Number of logical sectors available for file and directories. |
Additional information
SectorIndexBPB is typically set to 0.
SectorIndexBPBBackup is typically set to 6. This member is valid
only for FAT32 formatted volumes.
SectorIndexFSInfo is typically set to 1. This member is valid only
for FAT32 formatted volumes.
SectorIndexFSInfoBackup is typically set to 7. This member is valid
only for FAT32 formatted volumes.
NumSectorsReserved is never set to 0 because it includes at least
the BPB sector and the FSInfo sector.
SectorIndexATBackup is set to 0 if the backup AT is not present.
SectorIndexRootDir is valid only for FAT12 and FAT16 formatted volumes.
For FAT32 formatted volumes this member is set to 0 to indicate that
the root directory is dynamically allocated at runtime.
NumSectorsRootDir is valid only for FAT12 and FAT16 formatted volumes.
For FAT32 formatted volumes this member is set to 0 to indicate that
the root directory is dynamically allocated at runtime.
FS_EXFAT_LAYOUT
Description
Data layout of an exFAT partition.
Type definition
typedef struct {
U32 SectorIndexBoot;
U32 SectorIndexBootBackup;
U32 SectorIndexBootEx;
U32 SectorIndexBootExBackup;
U32 NumSectorsBootEx;
U32 SectorIndexOEMPara;
U32 SectorIndexOEMParaBackup;
U32 SectorIndexReserved;
U32 SectorIndexReservedBackup;
U32 SectorIndexCheckSum;
U32 SectorIndexCheckSumBackup;
U32 SectorIndexAT;
U32 SectorIndexATBackup;
U32 NumSectorsAT;
U32 SectorIndexData;
U32 NumSectorsData;
U32 SectorIndexRootDir;
U32 SectorIndexAB;
U32 NumSectorsAB;
U32 SectorIndexUT;
U32 NumSectorsUT;
} FS_EXFAT_LAYOUT;
Structure members
Member | Description |
SectorIndexBoot | Index of the logical sector that stores the format information. |
SectorIndexBootBackup | Index of the logical sector that stores a copy of the format information. |
SectorIndexBootEx | Index of the first logical sector that stores extended boot information. |
SectorIndexBootExBackup | Index of the first logical sector that stores a copy of the extended boot information. |
NumSectorsBootEx | Number of sectors that store extended boot information. |
SectorIndexOEMPara | Index of the logical sector that stores OEM parameters. |
SectorIndexOEMParaBackup | Index of the logical sector that stores a copy of the OEM parameters. |
SectorIndexReserved | Index of the logical sector that stores reserved information. |
SectorIndexReservedBackup | Index of the logical sector that stores a copy of the reserved information. |
SectorIndexCheckSum | Index of the logical sector that stores checksum information. |
SectorIndexCheckSumBackup | Index of the logical sector that stores a copy of the checksum information. |
SectorIndexAT | Index of the logical sector that stores the beginning of the allocation table. |
SectorIndexATBackup | Index of the logical sector that stores the beginning of the copy of the allocation table. |
NumSectorsAT | Number of logical sectors in the allocation table. |
SectorIndexData | Index of the logical sector that stores the beginning of the area reserved for files and directories. |
NumSectorsData | Number of logical sectors available for file and directories. |
SectorIndexRootDir | Index of the first logical sector of the root directory. |
SectorIndexAB | Index of the first logical sector of the Allocation Bitmap. |
NumSectorsAB | Number of logical sectors in the Allocation Bitmap. |
SectorIndexUT | Index of the first logical sector of the Up-case Table. |
NumSectorsUT | Number of logical sectors in the Up-case Table. |
Additional information
SectorIndexBoot is typically set to 0.
SectorIndexBootBackup is typically set to 12.
SectorIndexATBackup is set to 0 if the backup AT is not present.
FS_FS_LAYOUT
Description
Data layout of the file system.
Type definition
typedef union {
FS_FAT_LAYOUT fat;
FS_EFS_LAYOUT efs;
FS_EXFAT_LAYOUT exFAT;
} FS_FS_LAYOUT;
Structure members
Member | Description |
fat | Information about the layout of the FAT file system data. |
efs | Information about the layout of the EFS file system data. |
exFAT | Information about the layout of the exFAT file system data. |
File system extended functions
This section describes API functions that do not fall in any other category.
It includes function that operate on volumes, utility functions as well as
functions for locking the file system against concurrent access from different
tasks.
FS_ConfigEOFErrorSuppression()
Description
Enables / disables the reporting of end-of-file condition as error.
Prototype
void FS_ConfigEOFErrorSuppression(int OnOff);
Parameters
Parameter | Description |
OnOff | Activation status of the option. 0 EOF is reported as error. 1 EOF is not reported as error. |
Additional information
The end-of-file indicator of a file handle is set to 1 as soon
as the application tries to read more bytes than available in
the file. This function controls if an error is reported
via FS_FError() when the end-of-file indicator is set for
a file handle. The default is to report the end-of-file
condition as error. The configuration has effect on all the
opened file handles.
This function is available only when the file system is built
with FS_SUPPRESS_EOF_ERROR set to 1.
FS_ConfigPOSIXSupport()
Description
Enables / disables support for the POSIX-like behavior.
Prototype
void FS_ConfigPOSIXSupport(int OnOff);
Parameters
Parameter | Description |
OnOff | Activation status of the option. 0 POSIX behavior is disabled. 1 POSIX behavior is enabled. |
Additional information
The end-of-file indicator of a file handle is set to 1 as soon
as the application tries to read more bytes than available in
the file. This function controls if an error is reported
via FS_FError() when the end-of-file indicator is set for
a file handle. The default is to report the end-of-file
condition as error. The configuration has effect on all the
opened file handles.
FS_ConfigWriteVerification()
Description
Enables / disables the verification of the written data.
Prototype
void FS_ConfigWriteVerification(int OnOff);
Parameters
Parameter | Description |
OnOff | Activation status of the option. 0 Verification is disabled. 1 Verification is enabled. |
Additional information
If enabled, this feature requests the file system to check that
the data has been written correctly to storage device.
This operation is performed by reading back and comparing
the read with the written data. The verification is performed
one logical sector at a time. A sector buffer is allocated
from the memory pool for this operation.
FS_FileTimeToTimeStamp()
Description
Converts a broken-down date and time specification to a timestamp.
Prototype
void FS_FileTimeToTimeStamp(const FS_FILETIME * pFileTime,
U32 * pTimeStamp);
Parameters
Parameter | Description |
pFileTime | in Broken-down date and time to be converted. It cannot be NULL. |
pTimeStamp | out Converted timestamp. It cannot be NULL. |
Additional information
This function can be used to convert a broken-down date and time
specification to a timestamp used by the file system.
The converted timestamp can be directly passed to
FS_SetFileTime() or FS_SetFileTimeEx() to change the timestamps
of files and directories.
For a description of the timestamp format refer to FS_GetFileTime().
Example
#include "FS.h"
void SampleSetFileTime(void) {
U32 TimeStamp;
FS_FILETIME FileTime;
FileTime.Year = 2005;
FileTime.Month = 03;
FileTime.Day = 26;
FileTime.Hour = 10;
FileTime.Minute = 56;
FileTime.Second = 14;
FS_FileTimeToTimeStamp (&FileTime, &TimeStamp);
FS_SetFileTime("Test.txt", TimeStamp);
}
FS_FreeSectors()
Description
Informs the device driver about unused sectors.
Prototype
int FS_FreeSectors(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume on which to perform the operation. |
Return value
= 0 | OK, sectors have been freed. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The function visits each entry of the allocation table and checks
if the cluster is used to store data. If the cluster is free,
informs the storage layer that the sectors assigned to the cluster
do not store valid data. This information is used by the NAND and
NOR device drivers to optimize the internal wear-leveling process.
FS_FreeSectors() is available only when the support for the free sector
operation is enabled. The support for the free sector operation can be
enabled or disabled via FS_SUPPORT_FREE_SECTOR.
Example
#include "FS.h"
void SampleFreeSectors(void) {
FS_FreeSectors("nand:0:");
}
FS_GetAutoMount()
Description
Returns information about how a volume is automatically mounted.
Prototype
int FS_GetAutoMount(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be queried. |
Return value
= 0 | Volume is not mounted automatically. |
= FS_MOUNT_RO | Volume is mounted automatically in read only mode. |
= FS_MOUNT_RW | Volume is mounted automatically in read/write mode. |
< 0 | Error code indicating the failure reason. Refer to FS_ErrorNo2Text(). |
Additional information
After the initialization of the file system all the volumes
are configured to be automatically mounted as read/write
at the first access to the file system. The type of mount
operation can be configured via FS_SetAutoMount().
FS_GetFileId()
Description
Calculates a value that uniquely identifies a file.
Prototype
int FS_GetFileId(const char * sFileName,
U8 * pId);
Parameters
Parameter | Description |
sFileName | Name of the file for which to calculate the id. |
pId | A 16-byte array where the id is stored. |
Return value
= 0 | Id returned OK. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The calculated value is a combination of the sector number that
stores the directory entry assigned to file combined with the
index of the directory index. Typically used by USB MTP component
of SEGGER emUSB-Device to create an unique object id to the file.
FS_GetFileWriteMode()
Description
Returns the write mode.
Prototype
FS_WRITEMODE FS_GetFileWriteMode(void);
Return value
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.
- FS_WRITEMODE_UNKNOWN An error occurred.
Additional information
This function can be used to query the write mode configured
for the entire file system. The write mode for the entire file
system can be configured via FS_SetFileWriteMode().
The write mode is set by default to FS_WRITEMODE_SAFE when
the file system is initialized.
Refer to FS_SetFileWriteMode() for detailed information about
the different write modes.
FS_GetFileWriteModeEx()
Description
Returns the write mode configured for a specified volume.
Prototype
FS_WRITEMODE FS_GetFileWriteModeEx(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Identifies the volume that have to be queried. |
Return value
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.
- FS_WRITEMODE_UNKNOWN An error occurred.
Additional information
This function can be used to query the write mode configured
for the specified volume. The write mode of the volume can be
configured via FS_SetFileWriteModeEx(). If the write mode is not
explicitly configured by the application for the volume
via FS_SetFileWriteModeEx() then the write mode configured
for the entire file system is returned. The write mode for
the entire file system can be configured via FS_SetFileWriteMode().
The write mode is set by default to FS_WRITEMODE_SAFE when
the file system is initialized.
Refer to FS_SetFileWriteMode() for detailed information about
the different write modes.
FS_GetFSType()
Description
Returns the type of file system assigned to volume.
Prototype
int FS_GetFSType(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be queried. It cannot be NULL. |
Return value
≥ 0 | File system type. |
< 0 | Error code indicating the failure reason. |
Additional information
This function is optional and available only when the file system
is built with support for multiple file system types.
The support for multiple file system types is activated when
more than two of the following configuration defines are set to 1:
- FS_SUPPORT_FAT
- FS_SUPPORT_EFS
- FS_SUPPORT_EXFAT
The return value can be one of the value specified by
File system types
Example
#include "FS.h"
void SampleGetFSType(void) {
int FSType;
#if FS_SUPPORT_MULTIPLE_FS
FSType = FS_GetFSType("");
#else
FSType = FS_FAT;
#endif
FS_X_Log("File system type: ");
switch (FSType) {
case FS_FAT:
FS_X_Log("FAT");
break;
case FS_EFS:
FS_X_Log("EFS");
break;
default:
FS_X_Log("<unknown>");
break;
}
FS_X_Log("\n");
}
FS_GetMaxSectorSize()
Description
Queries the maximum configured logical sector size.
Prototype
U32 FS_GetMaxSectorSize(void);
Return value
Maximum logical sector size in bytes.
Additional information
Default value of the maximum logical sector size is 512 bytes.
Refer to FS_SetMaxSectorSize() for more information about
the maximum logical sector size.
Example
#include "FS.h"
void SampleGetMaxSectorSize(void) {
U32 MaxSectorSize;
MaxSectorSize = FS_GetMaxSectorSize();
}
FS_GetMemInfo()
Description
Returns information about the memory management.
Prototype
int FS_GetMemInfo(FS_MEM_INFO * pMemInfo);
Parameters
Parameter | Description |
pMemInfo | out Returned information. |
Return value
= 0 | OK, information returned. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The application can use this function to obtain information
about the memory management such as number of bytes allocated
by the file system, type of memory management used, etc.
FS_GetMountType()
Description
Returns information about how a volume is mounted.
Prototype
int FS_GetMountType(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be queried. |
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
sVolumeName is the name of a volume that already exists. If the
volume name is not known to file system then an error is returned.
Alternatively, the application can call FS_IsVolumeMounted()
if the information about how the volume is actually mounted
is not important. After the file system initialization all
volumes are in unmounted state.
Example
#include <stdio.h>
#include "FS.h"
void SampleGetMountType(void) {
int r;
const char * sMountType;
char ac[100];
r = FS_GetMountType("");
switch (r) {
case 0:
sMountType = "not mounted";
break;
case FS_MOUNT_RO:
sMountType = "read only";
break;
case FS_MOUNT_RW:
sMountType = "read/write";
break;
default:
sMountType = FS_ErrorNo2Text(r);
break;
}
SEGGER_snprintf(ac, sizeof(ac), "Mount type: %s\n", sMountType);
FS_X_Log(ac);
}
FS_GetNumFilesOpen()
Description
Queries the number of opened file handles.
Prototype
int FS_GetNumFilesOpen(void);
Return value
Total number of file handles that are open.
Additional information
This function counts the number of file handles that were opened
by the application via FS_FOpen() or FS_FOpenEx() and that were
not closed yet via FS_FClose().
The returned value is not the actual number of files opened
because the same file can be opened by an application more
than one time. For example, FS_GetNumFilesOpen() returns 2
if the same file is opened by the application twice.
Example
#include "FS.h"
void SampleGetNumFilesOpen(void) {
FS_FILE * pFile1;
FS_FILE * pFile2;
int NumFileHandles;
FS_Init();
//
// The number of opened files is 0 at this stage.
//
NumFileHandles = FS_GetNumFilesOpen();
//
// Open the first file.
//
pFile1 = FS_FOpen("File1.txt", "w");
//
// The number of opened files is 1 at this stage.
//
NumFileHandles = FS_GetNumFilesOpen();
//
// Open the second file.
//
pFile2 = FS_FOpen("File2.txt", "w");
//
// The number of opened files is 2 at this stage.
//
NumFileHandles = FS_GetNumFilesOpen();
//
// Close first file.
//
FS_FClose(pFile1);
//
// The number of opened files is 1 at this stage.
//
NumFileHandles = FS_GetNumFilesOpen();
//
// Close second file.
//
FS_FClose(pFile2);
//
// The number of opened files is 0 at this stage.
//
NumFileHandles = FS_GetNumFilesOpen();
}
FS_GetNumFilesOpenEx()
Description
Queries the number of opened file handles on a volume.
Prototype
int FS_GetNumFilesOpenEx(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume (0-terminated string). NULL is permitted. |
Return value
≥ 0 | Total number of file handles that are open on the volume. |
< 0 | Error code indicating the failure reason. |
Additional information
This function counts the number of file handles that were opened
by the application via FS_FOpen() or FS_FOpenEx() and that were
not closed yet via FS_FClose() on a specified volume.
The returned value is not the actual number of files opened
because the same file can be opened by an application more
than one time. For example, FS_GetNumFilesOpenEx() returns 2
if the same file is opened by the application twice.
FS_GetNumFilesOpenEx() works in the same way as
FS_GetNumFilesOpen() if sVolumeName is set to NULL.
FS_GetNumVolumes()
Description
Queries the number of configured volumes.
Prototype
int FS_GetNumVolumes(void);
Return value
Number of volumes.
Additional information
This function can be used to check how many volumes are
configured in the file system. Each call to FS_AddDevice()
creates a separate volume. Calling FS_AddPhysDevice() does
not create a volume. The maximum number of volumes is limited
only by available memory.
FS_GetNumVolumes() can be used together with FS_GetVolumeName()
to list the names of all configured volumes.
Example
#include "FS.h"
void SampleGetVolumeName(void) {
int NumVolumes;
int iVolume;
int BufferSize;
int NumBytesStored;
char acVolumeName[32];
BufferSize = sizeof(acVolumeName);
NumVolumes = FS_GetNumVolumes();
FS_X_Log("Available volumes:\n");
for (iVolume = 0; iVolume < NumVolumes; iVolume++) {
NumBytesStored = FS_GetVolumeName(iVolume, acVolumeName, BufferSize);
if (NumBytesStored < BufferSize) {
FS_X_Log(" ");
FS_X_Log(acVolumeName);
FS_X_Log("\n");
}
}
}
FS_GetVolumeAlias()
Description
Returns the alternative name of a volume.
Prototype
char *FS_GetVolumeAlias(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | in Name of the volume to be queried. It cannot be set to NULL. |
Return value
= NULL | No volume alias configure or an error occurred. |
≠ NULL | Configured volume alias. |
Additional information
This function is optional. It can be used by an application
to obtain the alternative name of a volume if configured.
For more information about the volume alias refer to FS_SetVolumeAlias().
This function is available only when FS_SUPPORT_VOLUME_ALIAS is set
to 1.
The alias of a volume can also be queried either via FS_GetVolumeInfo()
or FS_GetVolumeInfoEx(). The sAlias member of the FS_DISK_INFO structure
stores the configured alias.
FS_GetVolumeFreeSpace()
Description
Returns the free space available on a volume.
Prototype
U32 FS_GetVolumeFreeSpace(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be checked. |
Return value
≠ 0 | Number of bytes available on the volume. |
= 0 | An error occurred. |
Additional information
This function returns the free space available to application
to store files and directories.
A free space larger than four Gbytes is reported as 0xFFFFFFFF
because this is the maximum value that can be represented in
an unsigned 32-bit integer. The function
FS_GetVolumeFreeSpaceKB() can be used instead if the available
free space is larger than four Gbytes.
FS_GetVolumeFreeSpace() can sill be reliably used if the
application does not need to know if there is more than four
GBytes of free space available.
Example
#include <stdio.h>
#include "FS.h"
void SampleGetVolumeFreeSpace(void) {
U32 NumBytes;
char ac[100];
NumBytes = FS_GetVolumeFreeSpace("");
if (NumBytes < 0x8000) {
SEGGER_snprintf(ac, sizeof(ac), "Free space: %lu Kbytes\n", NumBytes);
} else {
NumBytes >>= 10;
SEGGER_snprintf(ac, sizeof(ac), "Free space: %lu Mbytes\n", NumBytes);
}
FS_X_Log(ac);
}
FS_GetVolumeFreeSpaceFirst()
Description
Initiates the search for free space.
Prototype
int FS_GetVolumeFreeSpaceFirst( FS_FREE_SPACE_DATA * pFSD,
const char * sVolumeName,
void * pBuffer,
int SizeOfBuffer);
Parameters
Parameter | Description |
pFSD | Context of the free space search. |
sVolumeName | Name of the volume to search on. |
pBuffer | Work buffer. |
SizeOfBuffer | Size of the work buffer in bytes. |
Return value
= 1 | OK, the entire allocation table has been searched. |
= 0 | OK, search is not completed. |
< 0 | Error code indicating the failure reason. |
Additional information
FS_GetVolumeFreeSpaceFirst() together with FS_GetVolumeFreeSpaceNext()
can be used to calculate the amount of available free space on a volume.
This pair of functions implement the same functionality as
FS_GetVolumeFreeSpace() with the difference that they block the access
to the file system for a very short time.
Typically, FS_GetVolumeFreeSpace() uses the information stored to
the FSInfo sector of a FAT file system or to the Status sector of
an EFS file system to get the number of free clusters on the volume.
If this information is not available then FS_GetVolumeFreeSpace()
calculates the free space by reading and evaluating the entire
allocation table. The size of the allocation table depends on the
size of the volume with sizes of a few tens of Mbytes for a volume
pf 4 Gbytes or larger. Reading such amount of data can take a
relatively long time to complete during which the application
is not able to access the file system. FS_GetVolumeFreeSpaceFirst()
and FS_GetVolumeFreeSpaceNext() can be used in such cases by
calculating the available free space while the application is
performing other file system accesses.
FS_GetVolumeFreeSpaceFirst() is used by the application to initiate
the search process followed by one or more calls to
FS_GetVolumeFreeSpaceNext(). The free space is returned in the
NumClustersFree member of pFSD. The cluster size can be determined
by calling FS_GetVolumeInfoEx() with the Flags parameter set to 0.
The specified work buffer is used by the file system for the read
operations only when FS_SUPPORT_SECTOR_BUFFER_BURST is set to 1.
The file system is able to use the work buffer for burst operations
only if pBuffer is aligned according to the value configured via
FS_DRIVER_ALIGNMENT.
Example
#include <stdio.h>
#include "FS.h"
void SampleGetVolumeFreeSpace(void) {
char ac[100];
FS_FREE_SPACE_DATA fsd;
int r;
FS_DISK_INFO VolumeInfo;
U32 BytesPerCluster;
U32 NumKBytesFree;
r = FS_GetVolumeFreeSpaceFirst(&fsd, "", NULL, 0);
if (r < 0) {
SEGGER_snprintf(ac, sizeof(ac), "Could not initiate searching (%s)\n",
FS_ErrorNo2Text(r));
FS_X_Log(ac);
} else {
if (r == 0) {
for (;;) {
r = FS_GetVolumeFreeSpaceNext(&fsd);
if (r < 0) {
SEGGER_snprintf(ac, sizeof(ac), "Could not continue searching (%s)\n",
FS_ErrorNo2Text(r));
FS_X_Log(ac);
break;
}
if (r == 1) {
// End of allocation table reached.
break;
}
}
}
}
FS_GetVolumeInfoEx("", &VolumeInfo, 0);
BytesPerCluster = (VolumeInfo.BytesPerSector * VolumeInfo.SectorsPerCluster);
NumKBytesFree = fsd.NumClustersFree * (BytesPerCluster >> 10);
SEGGER_snprintf(ac, sizeof(ac), "Free space: %lu Kbytes\n", NumKBytesFree);
FS_X_Log(ac);
}
FS_GetVolumeFreeSpaceKB()
Description
Returns the free space available on a volume.
Prototype
U32 FS_GetVolumeFreeSpaceKB(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be checked. |
Return value
≠ 0 | The space available on the volume in Kbytes. |
= 0 | An error occurred. |
Additional information
This function returns the free space available to application
to store files and directories.
Example
#include <stdio.h>
#include "FS.h"
void SampleGetVolumeFreeSpaceKB(void) {
U32 NumKBytes;
char ac[100];
NumKBytes = FS_GetVolumeFreeSpaceKB("");
SEGGER_snprintf(ac, sizeof(ac), "Free space: %lu Kbytes\n", NumKBytes);
FS_X_Log(ac);
}
FS_GetVolumeFreeSpaceNext()
Description
Continues the search for free space.
Prototype
int FS_GetVolumeFreeSpaceNext(FS_FREE_SPACE_DATA * pFSD);
Parameters
Parameter | Description |
pFSD | Context of the free space search. |
Return value
= 1 | OK, the entire allocation table has been searched. |
= 0 | OK, search is not completed. |
< 0 | Error code indicating the failure reason. |
Additional information
pFSD has to be initialized via a call to FS_GetVolumeFreeSpaceFirst().
One or more calls to FS_GetVolumeFreeSpaceNext() are required
in order to determine the available free space. For more information
refer to FS_GetVolumeFreeSpaceFirst().
Example
Refer to FS_GetVolumeFreeSpaceFirst() for an example usage.
FS_GetVolumeInfo()
Description
Obtains information about a volume.
Prototype
int FS_GetVolumeInfo(const char * sVolumeName,
FS_DISK_INFO * pInfo);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to query. It cannot be NULL. |
pInfo | out Volume information. It cannot be NULL. |
Return value
= 0 | OK, information returned. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function returns the information about a volume
such as volume size, available free space, format type, etc.
Example
#include <stdio.h>
#include <string.h>
#include "FS.h"
void SampleGetVolumeInfo(void) {
FS_DISK_INFO VolumeInfo;
int r;
char ac[100];
const char * sFSType;
memset(&VolumeInfo, 0, sizeof(VolumeInfo));
r = FS_GetVolumeInfo("", &VolumeInfo);
if (r == 0) {
SEGGER_snprintf(ac, sizeof(ac), "Total number of clusters: %lu\n",
VolumeInfo.NumTotalClusters);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Number of free clusters: %lu\n",
VolumeInfo.NumFreeClusters);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Sectors per cluster: %d\n",
VolumeInfo.SectorsPerCluster);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Bytes per sector: %d\n",
VolumeInfo.BytesPerSector);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Number of root directory entries: %d\n",
VolumeInfo.NumRootDirEntries);
FS_X_Log(ac);
switch (VolumeInfo.FSType) {
case FS_TYPE_FAT12:
sFSType = "FAT12";
break;
case FS_TYPE_FAT16:
sFSType = "FAT16";
break;
case FS_TYPE_FAT32:
sFSType = "FAT32";
break;
case FS_TYPE_EFS:
sFSType = "EFS";
break;
default:
sFSType = "<Unknown>";
break;
}
SEGGER_snprintf(ac, sizeof(ac), "File system type: %s\n",
sFSType);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Formatted acc. to SD spec.: %s\n",
VolumeInfo.IsSDFormatted ? "Yes" : "No");
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Has been modified: %s\n",
VolumeInfo.IsDirty ? "Yes" : "No");
FS_X_Log(ac);
}
}
FS_GetVolumeInfoEx()
Description
Obtains information about a volume.
Prototype
int FS_GetVolumeInfoEx(const char * sVolumeName,
FS_DISK_INFO * pInfo,
int Flags);
Parameters
Parameter | Description |
sVolumeName | The volume name. |
pInfo | out Volume information. |
Flags | Specifies what type of information the function has to return. |
Return value
= 0 | OK, information returned. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_GetVolumeInfo()
with the difference it gives the application more control about
what type of information it has to return. The type of information
that has to be returned can be controlled via the Flags parameter.
Flags is an bitwise-or combination of Volume information flags.
Example
#include <stdio.h>
#include <string.h>
#include "FS.h"
void SampleGetVolumeInfoEx(void) {
FS_DISK_INFO VolumeInfo;
int r;
char ac[100];
const char * sFSType;
memset(&VolumeInfo, 0, sizeof(VolumeInfo));
//
// Return also the available free space.
//
r = FS_GetVolumeInfoEx("", &VolumeInfo, FS_DISKINFO_FLAG_FREE_SPACE);
if (r == 0) {
SEGGER_snprintf(ac, sizeof(ac), "Number of total clusters: %lu\n",
VolumeInfo.NumTotalClusters);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Number of free clusters: %lu\n",
VolumeInfo.NumFreeClusters);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Sectors per cluster: %d\n",
VolumeInfo.SectorsPerCluster);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Bytes per sector: %d\n",
VolumeInfo.BytesPerSector);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Number of root directory entries: %d\n",
VolumeInfo.NumRootDirEntries);
FS_X_Log(ac);
switch (VolumeInfo.FSType) {
case FS_TYPE_FAT12:
sFSType = "FAT12";
break;
case FS_TYPE_FAT16:
sFSType = "FAT16";
break;
case FS_TYPE_FAT32:
sFSType = "FAT32";
break;
case FS_TYPE_EFS:
sFSType = "EFS";
break;
default:
sFSType = "<Unknown>";
break;
}
SEGGER_snprintf(ac, sizeof(ac), "File system type: %s\n",
sFSType);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Formatted acc. to SD spec.: %s\n",
VolumeInfo.IsSDFormatted ? "Yes" : "No");
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Has been modified: %s\n",
VolumeInfo.IsDirty ? "Yes" : "No");
FS_X_Log(ac);
}
}
FS_GetVolumeLabel()
Description
Returns the label of the volume.
Prototype
int FS_GetVolumeLabel(const char * sVolumeName,
char * sVolumeLabel,
unsigned SizeOfVolumeLabel);
Parameters
Parameter | Description |
sVolumeName | Identifies the volume to be queried. It cannot be NULL. |
sVolumeLabel | Buffer that receives the volume label. It cannot be NULL. |
SizeOfVolumeLabel | Number of characters in pVolumeName buffer. |
Return value
= 0 | OK, volume label read. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The function stores at most SizeOfVolumeLabel - 1 bytes
to pVolumeLabel buffer. The returned volume label is 0-terminated.
The volume label is truncated if it contains more characters
than the number of characters that can be stored to pVolumeLabel.
EFS does not have a volume label. FS_GetVolumeLabel() returns
with an error if the application tries to read the volume
label of a volume formatted as EFS.
Example
#include "FS.h"
void SampleGetVolumeName(void) {
char acVolumeLabel[16];
int r;
r = FS_GetVolumeLabel("", acVolumeLabel, sizeof(acVolumeLabel));
if (r == 0) {
FS_X_Log("Volume label: ");
FS_X_Log(acVolumeLabel);
FS_X_Log("\n");
}
}
FS_GetVolumeName()
Description
Obtains the name of a volume.
Prototype
int FS_GetVolumeName(int VolumeIndex,
char * pVolumeName,
int SizeOfVolumeName);
Parameters
Parameter | Description |
VolumeIndex | 0-based index of the volume to be queried. |
pVolumeName | out Receives the name of the volume as 0-terminated string. It cannot be NULL. |
SizeOfVolumeName | Number of bytes in pVolumeName. |
Return value
> 0 | Number of bytes in the volume name or number of bytes required to store the volume name. |
< 0 | Error code indicating the failure reason. |
Additional information
If pVolumeName is sufficiently large to store the entire volume
name and the 0-terminator then the function returns the number
of bytes in the volume name without the 0-terminator.
If pVolumeName is not sufficiently large to store the entire volume
name and the 0-terminator then the function returns the minimum
buffer size required to store the entire volume name and the 0-terminator.
In this case the function does not store any data to pVolumeName.
FS_GetVolumeName() stores at most SizeOfVolumeName - 1
bytes to pVolumeName and it terminates the string by a 0.
VolumeIndex specifies the position of the volume in the internal
volume list of the file system. The first volume added to file
system in FS_X_AddDevices() via FS_AddDevice() is stored at
index 0 in the volume list, the second volume added via
FS_AddDevice() is store at the index 1 in the volume list and
so on. The total number of volumes can be queried via
FS_GetNumVolumes().
Example
#include "FS.h"
void SampleGetVolumeName(void) {
int NumVolumes;
int iVolume;
int BufferSize;
int NumBytesStored;
char acVolumeName[32];
BufferSize = sizeof(acVolumeName);
NumVolumes = FS_GetNumVolumes();
FS_X_Log("Available volumes:\n");
for (iVolume = 0; iVolume < NumVolumes; iVolume++) {
NumBytesStored = FS_GetVolumeName(iVolume, acVolumeName, BufferSize);
if (NumBytesStored < BufferSize) {
FS_X_Log(" ");
FS_X_Log(acVolumeName);
FS_X_Log("\n");
}
}
}
FS_GetVolumeSize()
Description
Returns the size of a volume.
Prototype
U32 FS_GetVolumeSize(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be queried. |
Return value
≠ 0 | Total number of bytes available to file system. |
= 0 | An error occurred. |
Additional information
This function returns the total number of bytes available to
file system as data storage. The actual number of bytes available
to application for files and directories is smaller than
the value returned by FS_GetVolumeSize() since the file system
requires some space for the boot sector and the allocation table.
A size larger than four Gbytes is reported as 0xFFFFFFFF
because this is the maximum value that can be represented in
an unsigned 32-bit integer. The function
FS_GetVolumeSizeKB() can be used instead if the volume size is
larger than four Gbytes.
Example
#include <stdio.h>
#include "FS.h"
void SampleGetVolumeSize(void) {
U32 NumBytes;
char ac[100];
NumBytes = FS_GetVolumeSize("");
if (NumBytes < 0x8000) {
SEGGER_snprintf(ac, sizeof(ac), "Volume size: %lu Kbytes\n", NumBytes);
} else {
NumBytes >>= 10;
SEGGER_snprintf(ac, sizeof(ac), "Volume size: %lu Mbytes\n", NumBytes);
}
FS_X_Log(ac);
}
FS_GetVolumeSizeKB()
Description
Returns the size of a volume.
Prototype
U32 FS_GetVolumeSizeKB(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be queried. |
Return value
≠ 0 | Storage available to file system in Kbytes. |
= 0 | An error occurred. |
Additional information
This function returns the total number of bytes available to
file system as data storage. The actual number of bytes available
to application for files and directories is smaller than
the value returned by FS_GetVolumeSize() since the file system
requires some space for the boot sector and the allocation table.
Example
#include <stdio.h>
#include "FS.h"
void SampleGetVolumeSizeKB(void) {
U32 NumKBytes;
char ac[100];
NumKBytes = FS_GetVolumeSizeKB("");
SEGGER_snprintf(ac, sizeof(ac), "Volume size: %lu Kbytes\n", NumKBytes);
FS_X_Log(ac);
}
FS_GetVolumeStatus()
Description
Returns the presence status of a volume.
Prototype
int FS_GetVolumeStatus(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume. It cannot be NULL. |
Return value
FS_MEDIA_NOT_PRESENT | Storage device is not present. |
FS_MEDIA_IS_PRESENT | Storage device is present. |
FS_MEDIA_STATE_UNKNOWN | Presence status is unknown. |
Additional information
This function can be used to check if a removable storage device
that is assigned to a volume is present or not.
FS_GetVolumeStatus() is typically called periodically from a
separate task to handle the insertion and removal of a
removable storage device.
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);
}
}
FS_IsVolumeMounted()
Description
Checks if a volume is mounted.
Prototype
int FS_IsVolumeMounted(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be queried. |
Return value
1 | Volume is mounted. |
0 | Volume is not mounted or does not exist. |
Additional information
The function returns 1 if the volume is mounted either in
read-only mode or in read / write mode.
Example
#include "FS.h"
void SampleIsVolumeMounted(void) {
int IsMounted;
IsMounted = FS_IsVolumeMounted("");
if (IsMounted) {
FS_X_Log("Volume is mounted.\n");
} else {
FS_X_Log("Volume is not mounted.\n");
}
}
FS_Lock()
Description
Claims exclusive access to file system.
Prototype
void FS_Lock(void);
Additional information
The execution of the task that calls this function is suspended
until the file system grants it exclusive access. After the task
gets exclusive access to file system the other tasks that try to
perform file system operations are blocked until the task calls
FS_Unlock().
FS_Lock() is typically used by applications that call
device driver functions from different tasks. These functions
are usually not protected against concurrent accesses.
Additionally, FS_Lock() can be used to protect a group of file
system operations against concurrent access.
FS_Lock() is available if FS_OS_LOCKING set to 1. The function
does nothing if FS_OS_LOCKING set to 0 or 2. The calls to
FS_Lock() / FS_Unlock() cannot be nested.
The API functions of the file system are multitasking safe.
It is not required to explicitly lock these function calls
via FS_Lock() / FS_Unlock(). All API functions call internal
versions of FS_Lock() and FS_Unlock() on function
entry and exit respectively.
Example
#include "FS.h"
void SampleLock(void) {
FS_FILE * pFile;
FS_NAND_DISK_INFO DiskInfo;
//
// The device driver functions are not protected against concurrent
// access from different tasks. Make sure that only one task can access
// the file system.
//
#if (FS_OS_LOCKING == 1)
FS_Lock();
#endif // FS_OS_LOCKING == 1
FS_NAND_UNI_GetDiskInfo(0, &DiskInfo);
#if (FS_OS_LOCKING == 1)
FS_Unlock();
#endif // FS_OS_LOCKING == 1
//
// Make sure that the write operation is not interrupted
// by a different task.
//
#if (FS_OS_LOCKING == 1)
FS_Lock();
#endif // FS_OS_LOCKING == 1
pFile = FS_FOpen("Test.txt", "w");
if (pFile) {
FS_Write(pFile, "Test", 4);
FS_FClose(pFile);
}
#if (FS_OS_LOCKING == 1)
FS_Unlock();
#endif // FS_OS_LOCKING == 1
}
FS_LockVolume()
Description
Claims exclusive access to a volume.
Prototype
void FS_LockVolume(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume that has to be locked. |
Additional information
The execution of the task that calls this function is suspended
until the file system grants it exclusive access to the specified
volume. After the task gets exclusive access to volume the other
tasks that try to perform file system operations on that volume
are blocked until the task calls FS_UnlockVolume() with the
same volume name as in the call to FS_LockVolume().
FS_LockVolume() is typically used by applications that call
device driver functions from different tasks. These functions
are usually not protected against concurrent accesses.
Additionally, FS_LockVolume() can be used to protect a group
of file system operations against concurrent access.
FS_LockVolume() is available if FS_OS_LOCKING set to 2.
The function does nothing if FS_OS_LOCKING set to 0 or 1.
The calls to FS_LockVolume() / FS_UnlockVolume() cannot be
nested.
The API functions of the file system are multitasking safe.
It is not required to explicitly lock these function calls
via FS_LockVolume() / FS_UnlockVolume(). All API functions
call internal versions of FS_LockVolume() and FS_UnlockVolume()
on function entry and exit respectively.
Example
#include "FS.h"
void SampleLockVolume(void) {
FS_FILE * pFile;
FS_NAND_DISK_INFO DiskInfo;
//
// The device driver functions are not protected against concurrent
// access from different tasks. Make sure that only one task can access
// the file system.
//
#if (FS_OS_LOCKING == 2)
FS_LockVolume("nand:0:");
#endif // FS_OS_LOCKING == 2
FS_NAND_UNI_GetDiskInfo(0, &DiskInfo);
#if (FS_OS_LOCKING == 2)
FS_UnlockVolume("nand:0:");
#endif // FS_OS_LOCKING == 2
//
// Make sure that the write operation is not interrupted
// by a different task.
//
#if (FS_OS_LOCKING == 2)
FS_LockVolume("nand:0:");
#endif // FS_OS_LOCKING == 2
pFile = FS_FOpen("nand:0:\\Test.txt", "w");
if (pFile) {
FS_Write(pFile, "Test", 4);
FS_FClose(pFile);
}
#if (FS_OS_LOCKING == 2)
FS_UnlockVolume("nand:0:");
#endif // FS_OS_LOCKING == 2
}
FS_SetBusyLEDCallback()
Description
Registers a callback for busy status changes of a volume.
Prototype
int FS_SetBusyLEDCallback(const char * sVolumeName,
FS_BUSY_LED_CALLBACK * pfBusyLED);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which the callback has to be registered. It cannot be NULL. |
pfBusyLED | Function to be called when the busy status changes. It cannot be NULL. |
Return value
= 0 | OK, callback registered. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The application can use this FS_SetBusyLEDCallback() to register
a function that is called by the file system each time the busy
status of a volume changes. The volume becomes busy when it
starts an access to storage device. When the access to storage
device ends the volume becomes ready. The busy status of a volume
can change several times during a single file system operation.
FS_SetBusyLEDCallback() is available if the FS_SUPPORT_BUSY_LED
configuration define is set to 1. The function does nothing
if FS_SUPPORT_BUSY_LED is set to 0.
Example
#include "FS.h"
static void _cbBusyLED(U8 OnOff) {
if (OnOff) {
//
// Set LED on.
//
} else {
//
// Set LED off.
//
}
}
void SampleSetBusyLEDCallback(void) {
FS_FILE * pFile;
FS_SetBusyLEDCallback("nand:0:", _cbBusyLED);
pFile = FS_FOpen("nand:0:\\File.txt", "w");
FS_FClose(pFile);
}
FS_SetCharSetType()
Description
Configures the character set that is used for
the file and directory names.
Prototype
void FS_SetCharSetType(const FS_CHARSET_TYPE * pCharSetType);
Parameters
Parameter | Description |
pCharSetType | Type of character set used. |
Additional information
Permitted values of pCharSetType are:
Identifier | Description |
FS_CHARSET_CP437 | Latin characters |
FS_CHARSET_CP932 | Japanese characters encoded as Shift JIS |
FS_CHARSET_CP936 | Simplified Chinese characters encoded as GBK |
FS_CHARSET_CP949 | Korean characters encoded as UHC |
FS_CHARSET_CP950 | Chinese characters encoded as Big5 |
FS_SetFSType()
Description
Sets the type of file system a volume.
Prototype
int FS_SetFSType(const char * sVolumeName,
int FSType);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which the type of the file system has to be set. It cannot be NULL. |
FSType | Type of file system. |
Return value
= 0 | OK, file system type set. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function is optional and available only when the file system
is built with support for multiple file system types.
The support for multiple file system types is activated when
more than two of the following configuration defines are set to 1:
- FS_SUPPORT_FAT
- FS_SUPPORT_EFS
- FS_SUPPORT_EXFAT
FSType can be one of the value specified by
File system types
In a multi-volume configuration the application has to call
FS_SetFSType() before formatting a volume that was never formatted
or when the volume was formatted using a different file system type.
Example
#include "FS.h"
void SampleSetFSType(void) {
//
// Format the "nand:0:" volume as EFS.
//
#if FS_SUPPORT_MULTIPLE_FS
FS_SetFSType("nand:0:", FS_EFS);
#endif // FS_SUPPORT_MULTIPLE_FS
FS_Format("nand:0:", NULL);
//
// Format the "nor:0:" volume as FAT.
//
#if FS_SUPPORT_MULTIPLE_FS
FS_SetFSType("nor:0:", FS_FAT);
#endif // FS_SUPPORT_MULTIPLE_FS
FS_Format("nor:0:", NULL);
}
FS_SetMemCheckCallback()
Description
Registers a callback for checking of 0-copy operations.
Prototype
int FS_SetMemCheckCallback(const char * sVolumeName,
FS_MEM_CHECK_CALLBACK * pfMemCheck);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which the callback has to be registered. It cannot be NULL. |
pfMemCheck | Function to be called before a 0-copy operation is executed. It cannot be NULL. |
Return value
= 0 | OK, callback registered. |
≠ 0 | Error code indicating the failure reason. |
Additional information
FS_SetMemCheckCallback() can be used by an application to
register a function that is called by the file system before
any read or write operation to check if a data buffer can be
used in 0-copy operation. In a 0-copy operation, a pointer to
the data is passed directly to the device driver instead of
the data being copied first in an internal buffer and then being
passed it to device driver.
Example
#include "FS.h"
#if FS_SUPPORT_CHECK_MEMORY
static int _cbMemCheck(void * p, U32 NumBytes) {
if ((U32)p > 0x100000uL) {
return 1; // 0-copy allowed.
} else {
return 0; // 0-copy not allowed
}
}
#endif // FS_SUPPORT_CHECK_MEMORY
void SampleSetMemCheckCallback(void) {
FS_FILE * pFile;
#if FS_SUPPORT_CHECK_MEMORY
FS_SetMemCheckCallback("", _cbMemCheck);
#endif // FS_SUPPORT_CHECK_MEMORY
pFile = FS_FOpen("File.txt", "w");
if (pFile) {
FS_Write(pFile, "Test\n", 5);
}
FS_FClose(pFile);
}
FS_SetTimeDateCallback()
Description
Configures a function that the file system can use to get
the current time and date.
Prototype
void FS_SetTimeDateCallback(FS_TIME_DATE_CALLBACK * pfTimeDate);
Parameters
Parameter | Description |
pfTimeDate | Function to be invoked. |
Additional information
During the initialization of the file system via FS_Init()
the callback function is initialized to point to FS_X_GetTimeDate().
FS_SetVolumeAlias()
Description
Assigns an alternative name for a volume.
Prototype
int FS_SetVolumeAlias(const char * sVolumeName,
const char * sVolumeAlias);
Parameters
Parameter | Description |
sVolumeName | in Name of the volume to which the alternative name has to be assigned. It cannot be set to NULL. |
sVolumeAlias | in Alternative name as 0-terminated string. Can be set to NULL. |
Return value
= 0 | OK, the alternative name has been assigned. |
< 0 | Error code indicating the failure reason. |
Additional information
The assigned alias can be used as replacement in any path
to a file or directory that contains a volume name and
it can be passed instead of a volume name to any API function
that requires one. The alias replaces the volume and the unit number.
When used as a volume name the volume separator character (’:’)
has to be added to the end of the alias otherwise it is not recognized
as a valid volume name by the file system.
Valid characters in an alias are ASCII capital and small letters,
digits and the underscore character. The comparison applied
to alias is case sensitive and is performed after the file system
checks the real volume names.
The alias name is copied to the internal instance of the volume.
The function fails with an error if the alias is longer that the
space available in the internal buffer. The size of the internal
buffer for the alias can be configured at compile time via
FS_MAX_LEN_VOLUME_ALIAS. The alias can be removed by either
passing a NULL or an empty string as sVolumeAlias parameter.
If FS_MAX_LEN_VOLUME_ALIAS is set to 0 then only the pointer to
the volume alias is stored. The application has to make sure that
the memory region that stores the volume alias remains valid
until the file system is deinitialized via FS_DeInit().
This function is available only when FS_SUPPORT_VOLUME_ALIAS is set
to 1.
The alias of a volume can be queried either via FS_GetVolumeInfo()
or FS_GetVolumeInfoEx(). The sAlias member of the FS_DISK_INFO structure
stores the configured alias. In addition, the volume alias can be obtained
via FS_GetVolumeAlias().
Example
#include "FS.h"
void SampleSetVolumeAlias(void) {
FS_SetVolumeAlias("nor:0:", "flash");
}
FS_SetVolumeLabel()
Description
Modifies the label of a volume.
Prototype
int FS_SetVolumeLabel(const char * sVolumeName,
const char * sVolumeLabel);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which the label has to be modified. It cannot be NULL. |
sVolumeLabel | Volume label as 0-terminated ASCII string. The volume label is deleted if set to NULL. |
Return value
= 0 | OK, volume label set. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The volume label is a ASCII string that can be assigned to a
volume. It is not evaluated by the file system and it cannot
be used as volume name. A Windows PC shows the volume label
of a removable storage device in the “Computer” window when it
is mounted via USB MSD. The volume label can be read via
FS_GetVolumeLabel().
The volume label of a FAT-formatted volume can contain at
most 11 characters. The following characters are not allowed
in a volume name: ’“’, ’&’, ’*’, ’+’, ’-’, ’,’, ’.’, ’/’,
’:’, ’;’, ’<’, ’=’, ’>’, ’?’, ’[’, ’]’, ’\’.
EFS does not have a volume label. FS_GetVolumeLabel() returns
with an error if the application tries to read the volume
label of a volume formatted as EFS.
Example
#include "FS.h"
void SampleSetVolumeName(void) {
FS_SetVolumeLabel("", "SEGGER");
}
FS_TimeStampToFileTime()
Description
Converts a timestamp to a broken-down date and time specification.
Prototype
void FS_TimeStampToFileTime(U32 TimeStamp,
FS_FILETIME * pFileTime);
Parameters
Parameter | Description |
TimeStamp | Timestamp to be converted. |
pFileTime | out Converted broken-down date and time. It cannot be NULL. |
Additional information
This function can be used to convert a timestamp as used by the
file system a broken-down date and time specification.
For a description of the timestamp format refer to FS_GetFileTime().
Example
#include <stdio.h>
#include "FS.h"
void SampleGetFileTime(void) {
char ac[100];
U32 TimeStamp;
FS_FILETIME FileTime;
int r;
r = FS_GetFileTime("Test.txt", &TimeStamp);
if (r == 0) {
FS_TimeStampToFileTime(TimeStamp, &FileTime);
SEGGER_snprintf(ac, sizeof(ac), "Creation time: %d-%.2d-%.2d %.2d:%.2d:%.2d",
FileTime.Year, FileTime.Month, FileTime.Day,
FileTime.Hour, FileTime.Minute, FileTime.Second);
FS_X_Log(ac);
}
}
FS_Unlock()
Description
Releases the exclusive access to file system.
Prototype
void FS_Unlock(void);
Additional information
This function has to be called in pair with FS_Lock()
to allow other tasks to access the file system. For each
call to FS_Lock() the application has to call FS_Unlock().
FS_Unlock() is available if FS_OS_LOCKING set to 1.
The function does nothing if FS_OS_LOCKING set to 0 or 2.
The calls to FS_Lock() / FS_Unlock() cannot be nested.
Example
Refer to FS_Lock() for an example usage.
FS_UnlockVolume()
Description
Releases the exclusive access to a volume.
Prototype
void FS_UnlockVolume(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume that has to be locked. |
Additional information
This function has to be called in pair with FS_LockVolume()
to allow other tasks to access the volume. For each
call to FS_LockVolume() the application has to call
FS_UnlockVolume() with the same volume name as parameter.
FS_UnlockVolume() is available if FS_OS_LOCKING set to 2.
The function does nothing if FS_OS_LOCKING set to 0 or 1.
The calls to FS_LockVolume() / FS_UnlockVolume() cannot be
nested.
Example
Refer to FS_LockVolume() for an example usage.
Disk checking error codes
Description
Error codes reported by FS_CheckDisk() during operation.
Definition
#define FS_CHECKDISK_ERRCODE_0FILE 0x10
#define FS_CHECKDISK_ERRCODE_SHORTEN_CLUSTER 0x11
#define FS_CHECKDISK_ERRCODE_CROSSLINKED_CLUSTER 0x12
#define FS_CHECKDISK_ERRCODE_FEW_CLUSTER 0x13
#define FS_CHECKDISK_ERRCODE_CLUSTER_UNUSED 0x14
#define FS_CHECKDISK_ERRCODE_CLUSTER_NOT_EOC 0x15
#define FS_CHECKDISK_ERRCODE_INVALID_CLUSTER 0x16
#define FS_CHECKDISK_ERRCODE_INVALID_DIRECTORY_ENTRY 0x17
#define FS_CHECKDISK_ERRCODE_SECTOR_NOT_IN_USE 0x18
#define FS_CHECKDISK_ERRCODE_INVALID_FILE 0x19
Symbols
Definition | Description |
FS_CHECKDISK_ERRCODE_0FILE | A cluster chain is assigned to a file that does not contain any data. |
FS_CHECKDISK_ERRCODE_SHORTEN_CLUSTER | The cluster chain assigned to a file is longer than the size of the file. |
FS_CHECKDISK_ERRCODE_CROSSLINKED_CLUSTER | A cluster is assigned to more than one file or directory. |
FS_CHECKDISK_ERRCODE_FEW_CLUSTER | The size of the file is larger than the cluster chain assigned to file. |
FS_CHECKDISK_ERRCODE_CLUSTER_UNUSED | A cluster is marked as in use, but not assigned to any file or directory. |
FS_CHECKDISK_ERRCODE_CLUSTER_NOT_EOC | A cluster is does not have end-of-chain marker. |
FS_CHECKDISK_ERRCODE_INVALID_CLUSTER | Invalid cluster id. |
FS_CHECKDISK_ERRCODE_INVALID_DIRECTORY_ENTRY | Invalid directory entry. |
FS_CHECKDISK_ERRCODE_SECTOR_NOT_IN_USE | A logical sector that stores data is not marked as in use in the device driver. |
FS_CHECKDISK_ERRCODE_INVALID_FILE | A fragment file was found that does not belong to any big file. |
Additional information
The error codes are reported via the ErrCode parameter of
the callback function.
Example
Refer to FS_CheckDisk() for an example usage.
Disk checking return values
Description
Error codes returned by FS_CheckDisk().
Definition
#define FS_CHECKDISK_RETVAL_OK 0
#define FS_CHECKDISK_RETVAL_RETRY 1
#define FS_CHECKDISK_RETVAL_ABORT 2
#define FS_CHECKDISK_RETVAL_MAX_RECURSE 3
#define FS_CHECKDISK_RETVAL_CONTINUE 4
#define FS_CHECKDISK_RETVAL_SKIP 5
Symbols
Definition | Description |
FS_CHECKDISK_RETVAL_OK | OK, file system not in corrupted state |
FS_CHECKDISK_RETVAL_RETRY | An error has be found and repaired, retry is required. |
FS_CHECKDISK_RETVAL_ABORT | User aborted operation via callback or API call |
FS_CHECKDISK_RETVAL_MAX_RECURSE | Maximum recursion level reached, operation aborted |
FS_CHECKDISK_RETVAL_CONTINUE | FS_CheckAT() returns this value to indicate that the allocation table has not been entirely checked. |
FS_CHECKDISK_RETVAL_SKIP | FS_CheckDir() returns this value to indicate that the directory entry does not have to be checked. |
Example
Refer to FS_CheckDisk() for an example usage.
Disk checking action codes
Description
Values returned by the FS_CheckDisk() callback function.
Definition
#define FS_CHECKDISK_ACTION_DO_NOT_REPAIR 0
#define FS_CHECKDISK_ACTION_SAVE_CLUSTERS 1
#define FS_CHECKDISK_ACTION_ABORT 2
#define FS_CHECKDISK_ACTION_DELETE_CLUSTERS 3
Symbols
Definition | Description |
FS_CHECKDISK_ACTION_DO_NOT_REPAIR | The error does not have to be repaired. |
FS_CHECKDISK_ACTION_SAVE_CLUSTERS | The data stored in the clusters of a faulty cluster chain has to be saved to a file. |
FS_CHECKDISK_ACTION_ABORT | The disk checking operation has to be aborted. |
FS_CHECKDISK_ACTION_DELETE_CLUSTERS | The data stored in the clusters of a faulty cluster chain has to be deleted. |
Additional information
These values indicate FS_CheckDisk() how to handle a file
system error.
Example
Refer to FS_CheckDisk() for an example usage.
File system types
Description
Types of file systems supported.
Definition
#define FS_FAT 0
#define FS_EFS 1
#define FS_EXFAT 2
#define FS_FAT_TYPE_UNKONWN 0u
#define FS_FAT_TYPE_FAT12 12u
#define FS_FAT_TYPE_FAT16 16u
#define FS_FAT_TYPE_FAT32 32u
Symbols
Definition | Description |
FS_FAT | File Allocation Table (FAT). |
FS_EFS | SEGGER Embedded File System (EFS). |
FS_EXFAT | Extensible File Allocation Table (exFAT). |
FS_FAT_TYPE_UNKONWN | Internal use. |
FS_FAT_TYPE_FAT12 | Internal use. |
FS_FAT_TYPE_FAT16 | Internal use. |
FS_FAT_TYPE_FAT32 | Internal use. |
Description
Types of format supported.
Definition
#define FS_TYPE_FAT12 0x000Cu
#define FS_TYPE_FAT16 0x0010u
#define FS_TYPE_FAT32 0x0020u
#define FS_TYPE_EFS 0x0120u
#define FS_TYPE_EXFAT 0x0220u
Symbols
Definition | Description |
FS_TYPE_FAT12 | FAT with 12-bit allocation table entries. |
FS_TYPE_FAT16 | FAT with 16-bit allocation table entries. |
FS_TYPE_FAT32 | FAT with 32-bit allocation table entries. |
FS_TYPE_EFS | SEGGER Embedded File System (EFS) with 32-bit allocation table entries. |
FS_TYPE_EXFAT | exFAT with 32-bit allocation table entries. |
FS_BUSY_LED_CALLBACK
Description
Type of function called by the file system to report a
change in the busy status of a volume.
Type definition
typedef void FS_BUSY_LED_CALLBACK(U8 OnOff);
Parameters
Parameter | Description |
OnOff | Indicates if the volume is busy or not. 1 The volume is busy. 0 The volume is ready. |
Additional information
A function of this type can be registered with the file system
via FS_SetBusyLEDCallback(). FS_BUSY_LED_CALLBACK() is called
by the file system each time the volume changes the busy status
from busy to ready and reverse. Therefore, an application
can use FS_BUSY_LED_CALLBACK()to indicate the busy / ready
status of a volume via LED or by other means.
The file system calls FS_BUSY_LED_CALLBACK() with OnOff set to 1
when the volume goes busy. When the volume becomes ready
FS_BUSY_LED_CALLBACK() is called again with OnOff set to 0.
Example
Refer to FS_SetBusyLEDCallback() for an example usage.
FS_CHECKDISK_ON_ERROR_CALLBACK
Description
Type of function called by FS_CheckDisk() to report an error.
Type definition
typedef int FS_CHECKDISK_ON_ERROR_CALLBACK(int ErrCode,
... ...);
Parameters
Parameter | Description |
ErrCode | Code of the reported error. |
Return value
Value that indicates FS_CheckDisk() how the error should be
handled.
Additional information
ErrCode is one of the FS_CHECKDISK_ERRCODE_… defines.
The value returned by FS_CHECKDISK_ON_ERROR_CALLBACK()
can be one of the FS_CHECKDISK_ACTION_… defines.
In addition to ErrCode FS_CheckDisk() can pass other parameters
FS_CHECKDISK_ON_ERROR_CALLBACK() providing information about
the reported error. These parameters can be directly passed
to a printf()-style function along with the format returned
by FS_CheckDisk_ErrCode2Text() to create a text description
of the error in human-readable format.
Example
Refer to FS_CheckDisk() for an example usage.
FS_CHS_ADDR
Description
Address of physical block on a mechanical drive.
Type definition
typedef struct {
U16 Cylinder;
U8 Head;
U8 Sector;
} FS_CHS_ADDR;
Structure members
Member | Description |
Cylinder | Cylinder number (0-based) |
Head | Read / write head (0-based) |
Sector | Index of the sector on a cylinder. |
FS_DISK_INFO
Description
Information about a volume.
Type definition
typedef struct {
U32 NumTotalClusters;
U32 NumFreeClusters;
U16 SectorsPerCluster;
U16 BytesPerSector;
U16 NumRootDirEntries;
U16 FSType;
U8 IsSDFormatted;
U8 IsDirty;
const char * sAlias;
void * pBuffer;
int SizeOfBuffer;
U16 SectorsPerClusterHigh;
} FS_DISK_INFO;
Structure members
Member | Description |
NumTotalClusters | Total number of clusters on the storage device. |
NumFreeClusters | Number of clusters that are not in use. |
SectorsPerCluster | Number of sectors in a cluster. |
BytesPerSector | Size of the logical sector in bytes. |
NumRootDirEntries | Number of directory entries in the root directory. |
FSType | Type of file system. |
IsSDFormatted | Set to 1 if the volume was formatted according to SD Specification. |
IsDirty | Set to 1 if the volume was not unmounted correctly or the file system modified the storage. |
sAlias | Alternative name of the volume (0-terminated). |
pBuffer | Buffer to be used for the access to the storage device. |
SizeOfBuffer | Number of bytes in pBuffer. |
SectorsPerClusterHigh | High-order 16-bits of the number of sectors in a cluster. |
Additional information
IsDirty can be used to check if the volume formatted as FAT
has been correctly unmounted before a system reset. IsDirty
is set to 1 at file system initialization if the file system
was not properly unmounted.
NumRootDirEntries is valid only for volumes formatted FAT12 or FAT16.
FSType can be one of Format types.
IsSDFormatted and IsDirty are valid only for volumes formatted as FAT.
sAlias is set to NULL if the volume alias feature is disabled.
The members pBuffer and SizeOfBuffer can be used to specify
a work buffer for the operation that calculates the available
free space. This work buffer is used by the file system to read
data from the allocation table of the file system. Specifying
a work buffer larger than a logical sector size can help
increasing the performance of the operation when using a storage
device that can efficiently perform read burst operations such as
SD card, eMMC device or USB drive.
The file system is able to use the work buffer for burst operations
only if pBuffer is aligned according to the value configured via
FS_DRIVER_ALIGNMENT.
The work buffer is used only when the flag FS_DISKINFO_FLAG_WORK_BUFFER
is set in the Flags parameter passed to FS_GetVolumeInfoEx() and
the file system is built with FS_SUPPORT_SECTOR_BUFFER_BURST
set to 1. The file system uses an internal sector buffer for the
operation if either pBuffer is set to NULL or SizeOfBuffer is set to 0.
Example
Refer to FS_GetVolumeInfo() for an example usage.
FS_FILETIME
Description
Time and date representation.
Type definition
typedef struct {
U16 Year;
U16 Month;
U16 Day;
U16 Hour;
U16 Minute;
U16 Second;
} FS_FILETIME;
Structure members
Member | Description |
Year | Year (The value has to be greater than 1980.) |
Month | Month (1--12, 1: January, 2: February, etc.) |
Day | Day of the month (1--31) |
Hour | Hour (0--23) |
Minute | Minute (0--59) |
Second | Second (0--59) |
Additional information
FS_FILETIME represents a timestamp using individual members for
the month, day, year, weekday, hour, minute, and second values.
This can be useful for getting or setting a timestamp of a file
or directory. The conversion between timestamp and FS_FILETIME
can be done using FS_FileTimeToTimeStamp() and
FS_TimeStampToFileTime()
FS_FREE_SPACE_DATA
Description
Information the number of free space available on a volume.
Type definition
typedef struct {
U32 NumClustersFree;
int SizeOfBuffer;
void * pBuffer;
FS_VOLUME * pVolume;
U32 FirstClusterId;
} FS_FREE_SPACE_DATA;
Structure members
Member | Description |
NumClustersFree | Number of unallocated clusters found. |
SizeOfBuffer | Internal. Do not use. Number of bytes in the work buffer. |
pBuffer | Internal. Do not use. Work buffer. |
pVolume | Internal. Do not use. Volume information. |
FirstClusterId | Internal. Do not use. Id of the first cluster to be checked. |
Additional information
This structure stores the result and context of the operation
that calculates the amount of free space available on a volume.
The amount of free space is returned as a number of clusters
via the NumClustersFree member. The members of the search
context are considered internal and should not be used by
the application.
FS_FREE_SPACE_DATA is used by the FS_GetVolumeFreeSpaceFirst()
FS_GetVolumeFreeSpaceNext() pair of API functions.
FS_MEM_CHECK_CALLBACK
Description
Type of function called by the file system to check if a memory
region can be used in a 0-copy operation.
Type definition
typedef int FS_MEM_CHECK_CALLBACK(void * pMem,
U32 NumBytes);
Parameters
Parameter | Description |
pMem | Points to the first byte in the memory area to be checked. |
NumBytes | Size of the memory area in bytes. |
Return value
≠ 0 The memory region can be used in a 0 | copy operation. |
= 0 The memory region cannot be used in a 0 | copy operation. |
Additional information
A function of this type is called by the file system before
any read or write operation performed by the application.
The function has to check if the memory region defined
by pMem and NumBytes can be passed directly to the device
driver during a 0-copy operation.
The callback function is typically required on a system where
the device driver uses DMA to transfer data to and from the
storage device and where not all the memory regions can be
accessed by the DMA. If the memory region cannot be accessed
by DMA the callback function has to return 0. The file system
copies then the data to an internal buffer that is accessible
to DMA and performs the data transfer. The callback has to
return a value different than 0 if the DMA can access the
specified memory region. In this case the memory region is
passed directly to device driver to perform the data transfer
and the internal copy operation of the file system is skipped.
FS_MEM_INFO
Description
Information about the memory management.
Type definition
typedef struct {
U8 IsExternal;
U32 NumBytesTotal;
U32 NumBytesAllocated;
} FS_MEM_INFO;
Structure members
Member | Description |
IsExternal | Memory allocator type. |
NumBytesTotal | Size of the memory pool in bytes. |
NumBytesAllocated | Number of bytes allocated from the memory pool. |
Additional information
The information can be queried via FS_GetMemInfo().
IsExternal contains the value of the FS_SUPPORT_EXT_MEM_MANAGER
configuration define.
If the file system is configured to use the internal memory allocator
(FS_SUPPORT_EXT_MEM_MANAGER set to 0) then NumBytesTotal stores the value
passed as second parameter to FS_AssignMemory(). NumBytesTotal is set to
0 if the file system is configured to use an external memory allocator
(FS_SUPPORT_EXT_MEM_MANAGER set to 1) because this value is not known to
the file system.
The value of NumBytesAllocated stores the number of bytes allocated by the
file system at the time FS_GetMemInfo() is called. In emFile versions older
than 5.xx this information was stored in the global variable FS_NumBytesAllocated.
FS_TIME_DATE_CALLBACK
Description
Type of function called by the file system to get the actual
time an date.
Type definition
typedef U32 FS_TIME_DATE_CALLBACK(void);
Return value
Current time and date in a format suitable for the file system.
Additional information
The time and date have to be encoded as follows:
Bit 0-4: 2-second count (0-29)
Bit 5-10: Minutes (0-59)
Bit 11-15: Hours (0-23)
Bit 16-20: Day of month (1-31)
Bit 21-24: Month of year (1-12)
Bit 25-31: Count of years from 1980 (0-127)
The callback function can be registered via FS_SetTimeDateCallback().
FS_X_GetTimeDate() is set as default callback function at the
file system initialization. The application has to provide
the implementation of FS_X_GetTimeDate().
Example
Refer to FS_SetTimeDateCallback() for an example usage.
FS_TIMESTAMP
Description
Recorded time of an action performed on a file or directory.
Type definition
typedef struct {
U32 TimeDate;
U8 Milliseconds;
U8 Offset;
} FS_TIMESTAMP;
Structure members
Member | Description |
TimeDate | Local time and date. |
Milliseconds | Number of milliseconds. |
Offset | Time difference to UTC. |
Additional information
TimeDate is encoded as documented in the description of
FS_GetFileTime().
Milliseconds is stored in ten-millisecond multiples.
The valid value range for Milliseconds is 0-199.
Offset is encoded in the same way as the UtcOffset field
of an exFAT timestamp.
Description
Flags that control the information returned by FS_GetVolumeInfoEx().
Definition
#define FS_DISKINFO_FLAG_FREE_SPACE 0x01
#define FS_DISKINFO_FLAG_WORK_BUFFER 0x02
Symbols
Definition | Description |
FS_DISKINFO_FLAG_FREE_SPACE | Returns the available free space on the storage device. |
FS_DISKINFO_FLAG_WORK_BUFFER | Specifies a working buffer for the read operations. |
Storage layer functions
The functions described in this section can be used to access and to manage
the data at the logical sector level effectively bypassing the file system.
These functions are typically used when the application comes with its own
file system or when the storage device has to be mounted as mass storage
device via USB.
FS_STORAGE_Clean()
Description
Performs garbage collection on a volume.
Prototype
int FS_STORAGE_Clean(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume on which to perform the garbage collection. |
Return value
= 0 | OK, volume cleaned. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The application can call this function to convert storage blocks
that contain invalid data to free space that can be used to
store new data. This operation is supported only by storage devices
that are managed by the file system such as NAND and NOR flash.
FS_STORAGE_Clean() is optional since the device drivers perform
the garbage collection operation automatically. The function
can be used to increase the write performance by preparing the
storage device in advance of the write operation.
The actions executed by FS_STORAGE_Clean() depend on the
device driver used. For example, the Sector Map NOR driver
converts all logical blocks that contain invalid data into free
(writable) logical blocks. As a consequence, the following write
operation will run faster because physical sectors does not have
to be erased.
FS_STORAGE_Clean() can potentially take a long time to complete,
preventing the access of other tasks to the file system. How long
the execution takes depends on the type of storage device and on
the number of storage blocks that contain invalid data.
The file system provides an alternative function
FS_STORAGE_CleanOne() that completes in a shorter period of time
than FS_STORAGE_Clean(). This is realized by executing only one
sub-operation of the entire garbage collection operation
at a time. For more information refer to FS_STORAGE_CleanOne().
Additional information about the garbage collection operation
can be found in the “Garbage collection” section of the NAND
and NOR drivers of the emFile manual.
Example
#include "FS.h"
void SampleStorageClean(void) {
FS_FILE * pFile;
//
// Perform garbage collection on the storage device.
//
FS_STORAGE_Clean("nor:0:");
//
// The write to file is fast since the NOR driver does not have to perform
// any garbage collection during the write operation.
//
pFile = FS_FOpen("nor:0:\\File.txt", "w");
if (pFile) {
FS_Write(pFile, "Test", 4);
FS_FClose(pFile);
}
}
FS_STORAGE_CleanEx()
Description
Performs garbage collection on a volume.
Prototype
int FS_STORAGE_CleanEx(FS_VOLUME * pVolume);
Parameters
Parameter | Description |
pVolume | Instance of the volume on which to perform the garbage collection. |
Return value
= 0 | OK, volume cleaned. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_Clean()
with the difference that the volume is specified via a volume instance
instead of a volume name.
FS_STORAGE_CleanOne()
Description
Performs garbage collection on a volume.
Prototype
int FS_STORAGE_CleanOne(const char * sVolumeName,
int * pMoreToClean);
Parameters
Parameter | Description |
sVolumeName | Name of the storage volume on which to perform the garbage collection. |
pMoreToClean | out Indicates if the storage device has been cleaned completely or not. It can be NULL. ≠0 Not cleaned completely. =0 Completely clean. |
Return value
= 0 | OK, clean operation executed. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_Clean()
with the difference that it executes only one sub-operation of
the garbage collection operation at a time. This is practical
if other tasks of the application require access to the file
system before the garbage collection operation is completed.
The completion of the garbage collection operation is indicated
via pMoreToClean. FS_STORAGE_CleanOne() returns a value different
than 0 via pMoreToClean if the operation is not completed.
Additional information about the garbage collection operation
can be found in the “Garbage collection” section of the NAND
and NOR drivers.
Example
#include "FS.h"
void SampleStorageCleanOne(void) {
FS_FILE * pFile;
int MoreToClean;
//
// Perform garbage collection on the storage device.
//
MoreToClean = 0;
do {
FS_STORAGE_CleanOne("nand:0:", &MoreToClean);
} while (MoreToClean);
//
// The write to file is fast since the NAND driver does not have to perform
// any garbage collection during the write operation.
//
pFile = FS_FOpen("nand:0:\\File.txt", "w");
if (pFile) {
FS_Write(pFile, "Test", 4);
FS_FClose(pFile);
}
}
FS_STORAGE_CleanOneEx()
Description
Performs garbage collection on a volume.
Prototype
int FS_STORAGE_CleanOneEx(FS_VOLUME * pVolume,
int * pMoreToClean);
Parameters
Parameter | Description |
pVolume | Instance of the storage volume on which to perform the garbage collection. |
pMoreToClean | out Indicates if the storage device has been cleaned completely or not. It can be NULL. ≠0 Not cleaned completely. =0 Completely clean. |
Return value
= 0 | OK, clean operation executed. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_CleanOne()
with the difference that the volume is specified via a volume instance
instead of a volume name.
FS_STORAGE_DeInit()
Description
Frees the resources allocated by the storage layer.
Prototype
void FS_STORAGE_DeInit(void);
Additional information
This function is optional. FS_STORAGE_DeInit() frees all
resources that are allocated by the storage layer after
initialization. The application can call this function
only after it called FS_STORAGE_Init().
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 SampleStorageDeInit(void) {
FS_STORAGE_Init();
#if FS_SUPPORT_DEINIT
//
// Access the storage layer...
//
FS_STORAGE_DeInit();
#endif // FS_SUPPORT_DEINIT
//
// The storage layer cannot be accessed anymore.
//
}
FS_STORAGE_FillSectors()
Description
Writes the same sector data to one or more logical sectors.
Prototype
int FS_STORAGE_FillSectors(const char * sVolumeName,
const void * pData,
U32 SectorIndex,
U32 NumSectors);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to write to. It cannot be NULL. |
pData | in Buffer that contains the sector data to be written. It cannot be NULL. |
SectorIndex | Index of the first sector to be written. |
NumSectors | Number of sectors to be written. |
Return value
= 0 | OK, sector data modified. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function can be used to write the same sector data to multiple
consecutive logical sectors. pData has to point to a memory region
that stores the contents of a single logical sector that has to be written.
The size of the logical sector depends on the type of storage device used.
The application can query the size of the logical sector as well as
the number of logical sectors of a storage device via FS_STORAGE_GetDeviceInfo().
Typically, the size of a logical sector is 512 bytes.
SectorIndex is a 0-based index that identifies the first logical
sector to be written. The range of the logical sectors modified
by this function is SectorIndex to SectorIndex + NumSectors - 1.
FS_STORAGE_FillSectors() reports an error and does not perform
any operation if the specified range of logical sectors exceeds
the size of the storage device.
FS_STORAGE_FillSectorsEx()
Description
Writes the same sector data to one or more logical sectors.
Prototype
int FS_STORAGE_FillSectorsEx( FS_VOLUME * pVolume,
const void * pData,
U32 SectorIndex,
U32 NumSectors);
Parameters
Parameter | Description |
pVolume | Instance of the volume to write to. |
pData | in Contents of the logical sector. |
SectorIndex | Index of the logical sector to be written. |
NumSectors | Number of logical sectors to be written. |
Return value
= 0 | OK, logical sectors written successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as
FS_STORAGE_FillSectors() with the difference that the
volume is specified via a volume instance instead a volume name.
The application can get a volume instance from a volume name
by calling FS_STORAGE_FindVolume().
FS_STORAGE_FindVolume()
Description
Searches for a volume instance by name.
Prototype
FS_VOLUME *FS_STORAGE_FindVolume(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume. |
Return value
≠ NULL | Pointer to the volume instance. |
= NULL | Volume not found. |
Additional information
This function returns the volume instance assigned to the
specified volume name. The return value can be passed as
parameter to the API functions of the Storage layer that
identify a volume by instance and not by name.
The returned volume instance is no longer valid after
the file system is deinitialized via a call to FS_DeInit().
The application must call FS_STORAGE_FindVolume() to
get a new volume instance after the file system is
reinitialized.
FS_STORAGE_FindVolumeByDevice()
Description
Searches for a volume instance by index.
Prototype
FS_VOLUME *FS_STORAGE_FindVolumeByDevice(FS_DEVICE * pDevice);
Parameters
Parameter | Description |
pDevice | Device instance assigned to the volume. |
Return value
≠ NULL | Pointer to the volume instance. |
= NULL | Volume not found. |
Additional information
This function performs the same operation as FS_STORAGE_FindVolumeByIndex()
with the difference that the volume to be searched for is specified
via device instance instead of volume index.
A device index can be obtained via the callback of the function
registered via FS_STORAGE_SetOnDeviceActivityCallback() or
FS_STORAGE_SetOnDeviceActivityCallbackEx().
FS_STORAGE_FindVolumeByIndex()
Description
Searches for a volume instance by index.
Prototype
FS_VOLUME *FS_STORAGE_FindVolumeByIndex(int VolumeIndex);
Parameters
Parameter | Description |
VolumeIndex | Index of the volume. |
Return value
≠ NULL | Pointer to the volume instance. |
= NULL | Volume not found. |
Additional information
This function returns the volume instance assigned to the
volume with the specified index. The first volume added
to the file system via FS_AddDevice() has the index 0,
the second index 1 and so on. The total number of configured
volumes can be queried via FS_GetNumVolumes().
The return value of this function can be passed as
parameter to the API functions of the Storage layer that
identify a volume by instance and not by name.
The returned volume instance is no longer valid after
the file system is deinitialized via a call to FS_DeInit().
The application must call FS_STORAGE_FindVolumeByIndex() to
get a new volume instance after the file system is
reinitialized.
Description
Formats the storage device.
Prototype
int FS_STORAGE_FormatLowEx(FS_VOLUME * pVolume);
Parameters
Parameter | Description |
pVolume | Instance of the volume to be formatted. |
Return value
= 0 OK, low | level format was successful. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_FormatLow()
with the difference that the volume to be queried is identified
by a volume instance instead a volume name. The application
can get a volume instance from a volume name by calling FS_STORAGE_FindVolume().
FS_STORAGE_FreeSectors()
Description
Informs the driver about unused sectors.
Prototype
int FS_STORAGE_FreeSectors(const char * sVolumeName,
U32 SectorIndex,
U32 NumSectors);
Parameters
Parameter | Description |
sVolumeName | Name of the volume on which to perform the operation. |
SectorIndex | Index of the first logical sector to be marked as invalid (0-based). |
NumSectors | Number of sectors to be marked as invalid starting with SectorIndex. |
Return value
= 0 | OK, sectors freed. |
≠ 0 | Error code indicating the failure reason |
Additional information
Typically, this function is called by the application to inform
the driver which logical sectors are no longer used for data
storage. The NAND and NOR drivers can use this information to
optimize the internal relocation of data blocks during the
wear-leveling operation. The data of the logical sectors marked
as not in use is not copied anymore that can typically lead to
an improvement of the write performance.
FS_STORAGE_FreeSectors() performs a similar operation as the trim
command of SSDs (Solid-State Drives). The data stored to a
logical sector is no longer available to an application after
the logical sector has been freed via FS_STORAGE_FreeSectors(),
Example
#include "FS.h"
void SampleStorageFreeSectors(void) {
//
// Inform the NAND driver that the logical sectors
// with the indexes 2, 3, and 4 are no longer in use.
//
FS_STORAGE_FreeSectors("nand:0:", 2, 3);
}
FS_STORAGE_FreeSectorsEx()
Description
Informs the driver about unused sectors.
Prototype
int FS_STORAGE_FreeSectorsEx(FS_VOLUME * pVolume,
U32 SectorIndex,
U32 NumSectors);
Parameters
Parameter | Description |
pVolume | Instance of the volume on which to perform the operation. |
SectorIndex | Index of the first logical sector to be marked as invalid (0-based). |
NumSectors | Number of sectors to be marked as invalid starting with SectorIndex. |
Return value
= 0 | OK, sectors freed. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_FreeSectors()
with the difference that the volume is specified via a volume instance
instead of a volume name.
FS_STORAGE_GetAutoMountType()
Description
Returns information about how a volume is automatically mounted.
Prototype
int FS_STORAGE_GetAutoMountType(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be queried. |
Return value
= 0 | Volume is not mounted automatically. |
= FS_MOUNT_RO | Volume is mounted automatically in read only mode. |
= FS_MOUNT_RW | Volume is mounted automatically in read and write mode. |
< 0 | Error code indicating the failure reason. Refer to FS_ErrorNo2Text(). |
Additional information
This function is available only if the file system is built
with FS_STORAGE_SUPPORT_MOUNT set to 1.
FS_STORAGE_GetAutoMountTypeEx()
Description
Returns information about how a volume is automatically mounted.
Prototype
int FS_STORAGE_GetAutoMountTypeEx(FS_VOLUME * pVolume);
Parameters
Parameter | Description |
pVolume | Instance of the volume to be queried. |
Return value
= 0 | Volume is not mounted automatically. |
= FS_MOUNT_RO | Volume is mounted automatically in read only mode. |
= FS_MOUNT_RW | Volume is mounted automatically in read and write mode. |
< 0 | Error code indicating the failure reason. Refer to FS_ErrorNo2Text(). |
Additional information
This function performs the same operation as FS_STORAGE_GetAutoMountType()
with the difference that the volume is specified via a volume
instance instead of a volume name.
This function is available only if the file system is built
with FS_STORAGE_SUPPORT_MOUNT set to 1.
FS_STORAGE_GetCleanCnt()
Description
Calculates the number of garbage collection sub-operations.
Prototype
int FS_STORAGE_GetCleanCnt(const char * sVolumeName,
U32 * pCleanCnt);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be queried. |
pCleanCnt | out Number of sub-operations left. |
Return value
= 0 | OK, clean count returned. |
≠ 0 | Error code indicating the failure reason. |
Additional information
FS_STORAGE_GetCleanCnt() calculates and returns the number
of sub-operations that the application has to perform
until the garbage collection operation is completed.
The value returned via pCleanCnt is the number of times
FS_STORAGE_CleanOne() has to be called to complete
the garbage collection. FS_STORAGE_GetCleanCnt() is supported
only for volumes mounted on a storage device managed by emFile
such as NAND or NOR flash.
Example
#include "FS.h"
void SampleStorageGetCleanCnt(void) {
U32 CleanCnt;
CleanCnt = 0;
FS_STORAGE_GetCleanCnt("nor:0:", &CleanCnt);
if (CleanCnt) {
do {
FS_STORAGE_CleanOne("nor:0:", NULL);
} while (--CleanCnt);
}
}
FS_STORAGE_GetCleanCntEx()
Description
Calculates the number of garbage collection sub-operations.
Prototype
int FS_STORAGE_GetCleanCntEx(FS_VOLUME * pVolume,
U32 * pCleanCnt);
Parameters
Parameter | Description |
pVolume | Instance of the volume to be queried. |
pCleanCnt | out Number of sub-operations left. |
Return value
= 0 | OK, clean count returned. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_GetCleanCnt()
with the difference that the volume is specified via a volume instance
instead of a volume name.
FS_STORAGE_GetCounters()
Description
Returns the values of statistical counters.
Prototype
void FS_STORAGE_GetCounters(FS_STORAGE_COUNTERS * pStat);
Parameters
Parameter | Description |
pStat | out Current values of statistical counters. |
Additional information
This function returns the values of the counters that indicate
how many operations the storage layer executed since the file
system initialization or the last call to
FS_STORAGE_ResetCounters().
The statistical counters are updated only on debug builds if the
file system sources are compiled with FS_DEBUG_LEVEL greater then
or equal to FS_DEBUG_LEVEL_CHECK_PARA or FS_STORAGE_ENABLE_STAT_COUNTERS
set to 1.
Example
#include <stdio.h>
#include "FS.h"
void SampleStorageGetCounters(void) {
FS_STORAGE_COUNTERS StatCnt;
char ac[100];
FS_STORAGE_GetCounters(&StatCnt);
SEGGER_snprintf(ac, sizeof(ac), "Num. read operations: %lu\n",
StatCnt.ReadOperationCnt);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Num. sectors read: %lu\n",
StatCnt.ReadSectorCnt);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Num. sectors read (from cache): %lu\n",
StatCnt.ReadSectorCachedCnt);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Num. sectors read (alloc. table): %lu\n",
StatCnt.ReadSectorCntMan);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Num. sectors read (dir. entry): %lu\n",
StatCnt.ReadSectorCntDir);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Num. write operations: %lu\n",
StatCnt.WriteOperationCnt);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Num. sectors written: %lu\n",
StatCnt.WriteSectorCnt);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Num. sectors written (by cache): %lu\n",
StatCnt.WriteSectorCntCleaned);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Num. sectors written (alloc. table): %lu\n",
StatCnt.WriteSectorCntMan);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Num. sectors written (dir. entry): %lu\n",
StatCnt.WriteSectorCntDir);
FS_X_Log(ac);
}
FS_STORAGE_GetDeviceInfo()
Description
Returns information about the storage device.
Prototype
int FS_STORAGE_GetDeviceInfo(const char * sVolumeName,
FS_DEV_INFO * pDeviceInfo);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be queried. It cannot be NULL. |
pDeviceInfo | out Information about the storage device. It cannot be NULL. |
Return value
= 0 | OK, information returned. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function returns information about the logical organization
of the storage device such as the number of logical sectors
and the size of the logical sector supported.
FS_STORAGE_GetDeviceInfo() requests the information directly
from the device driver.
Deprecated name
FS_GetDeviceInfo
Example
#include <stdio.h>
#include "FS.h"
void SampleStorageGetDeviceInfo(void) {
FS_DEV_INFO DeviceInfo;
char ac[100];
FS_STORAGE_GetDeviceInfo("", &DeviceInfo);
SEGGER_snprintf(ac, sizeof(ac), "Total num. sectors: %lu\n",
DeviceInfo.NumSectors);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Num. bytes per sector: %d\n",
DeviceInfo.BytesPerSector);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Num. read / write heads: %d\n",
DeviceInfo.NumHeads);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Num. sectors per track: %d\n",
DeviceInfo.SectorsPerTrack);
FS_X_Log(ac);
}
FS_STORAGE_GetDeviceInfoEx()
Description
Returns information about the storage device.
Prototype
int FS_STORAGE_GetDeviceInfoEx(FS_VOLUME * pVolume,
FS_DEV_INFO * pDeviceInfo);
Parameters
Parameter | Description |
pVolume | Instance of the volume to be queried. |
pDeviceInfo | out Information about the storage device. |
Return value
= 0 | OK, volume information returned. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_GetDeviceInfo()
with the difference that the volume to be queried is identified
by a volume instance instead a volume name. The application
can get a volume instance from a volume name by calling FS_STORAGE_FindVolume().
FS_STORAGE_GetMountType()
Description
Returns information about how a volume is mounted.
Prototype
int FS_STORAGE_GetMountType(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be queried. |
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
This function is available only if the file system is built
with FS_STORAGE_SUPPORT_MOUNT set to 1.
FS_STORAGE_GetMountTypeEx()
Description
Returns information about how a volume is mounted.
Prototype
int FS_STORAGE_GetMountTypeEx(FS_VOLUME * pVolume);
Parameters
Parameter | Description |
pVolume | Instance of the volume to be queried. |
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
This function performs the same operation as FS_STORAGE_GetMountType()
with the difference that the volume is specified via a volume
instance instead of a volume name.
This function is available only if the file system is built
with FS_STORAGE_SUPPORT_MOUNT set to 1.
FS_STORAGE_GetSectorUsage()
Description
Returns information about the usage of a logical sector.
Prototype
int FS_STORAGE_GetSectorUsage(const char * sVolumeName,
U32 SectorIndex);
Parameters
Parameter | Description |
sVolumeName | Name of the volume. |
SectorIndex | Index of the sector to be queried. |
Return value
= FS_SECTOR_IN_USE | The sector contains valid data. |
= FS_SECTOR_NOT_USED | The sector contains invalid data. |
= FS_SECTOR_USAGE_UNKNOWN | The usage of the sector is unknown or the operation is not supported. |
< 0 | Error code indicating the failure reason. |
Additional information
After a low-level format all the logical sectors contain invalid
information. The data of a logical sector becomes valid after
the application performs a write operation to that sector.
The sector data can be explicitly invalidated by calling
FS_STORAGE_FreeSectors().
Example
#include "FS.h"
void SampleStorageGetSectorUsage(void) {
int SectorUsage;
SectorUsage = FS_STORAGE_GetSectorUsage("", 7);
switch (SectorUsage) {
case FS_SECTOR_IN_USE:
FS_X_Log("The sector is used to store data.\n");
break;
case FS_SECTOR_NOT_USED:
FS_X_Log("The sector is not used to store data.\n");
break;
case FS_SECTOR_USAGE_UNKNOWN:
FS_X_Log("The sector usage is unknown.\n");
break;
default:
FS_X_Log("An error occurred during the operation.\n");
}
}
FS_STORAGE_GetSectorUsageEx()
Description
Returns information about the usage of a logical sector.
Prototype
int FS_STORAGE_GetSectorUsageEx(FS_VOLUME * pVolume,
U32 SectorIndex);
Parameters
Parameter | Description |
pVolume | Instance of the volume that stores the logical sector. |
SectorIndex | Index of the sector to be queried. |
Return value
= FS_SECTOR_IN_USE | The sector contains valid data. |
= FS_SECTOR_NOT_USED | The sector contains invalid data. |
= FS_SECTOR_USAGE_UNKNOWN | The usage of the sector is unknown or the operation is not supported. |
< 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_GetSectorUsage()
with the difference that the volume is specified via a volume instance
instead of a volume name.
FS_STORAGE_GetVolumeStatusEx()
Description
Returns the presence status of a volume.
Prototype
int FS_STORAGE_GetVolumeStatusEx(FS_VOLUME * pVolume);
Parameters
Parameter | Description |
pVolume | Instance of the volume to be queried. |
Return value
FS_MEDIA_NOT_PRESENT | Volume is not present. |
FS_MEDIA_IS_PRESENT | Volume is present. |
FS_MEDIA_STATE_UNKNOWN | Volume presence state is unknown. |
Additional information
This function performs the same operation as FS_GetVolumeStatus()
with the difference that the volume to be queried is identified
by a volume instance instead a volume name. The application
can get a volume instance from a volume name by calling FS_STORAGE_FindVolume().
FS_STORAGE_Init()
Description
Initializes the storage layer.
Prototype
unsigned FS_STORAGE_Init(void);
Return value
Number of OS synchronization objects required to protect
the file system against concurrent access from different tasks.
Additional information
This function initializes the only drivers and if necessary
the OS layer. It has to be called before any other function
of the storage layer (FS_STORAGE_…) The storage layer
allows an application to access the file system at logical
sector level. The storage device is presented as an array
of logical sector that can be accessed via a 0-based index.
This can be useful when using the file system as USB mass storage
client driver.
FS_STORAGE_Init() is called internally at the initialization
of the file system. The return value of this function is used
by FS_Init() to calculate the number of internal buffers the
file system has to allocate for the read and write operations.
The application is not required to call FS_STORAGE_Init() if
it already calls FS_Init().
FS_STORAGE_DeInit() is the counterpart of FS_STORAGE_Init()
that can be used to free the resources allocated by the
drivers and if enabled of the OS layer.
Deprecated name
FS_InitStorage
Example
#include "FS.h"
void SampleStorageInit(void) {
FS_STORAGE_Init();
//
// Access logical sectors...
//
}
Description
Checks if a storage device is low-level formatted.
Prototype
int FS_STORAGE_IsLLFormattedEx(FS_VOLUME * pVolume);
Parameters
Parameter | Description |
pVolume | Instance of the volume to be queried. |
Return value
= 1 Volume is low | level formatted. |
= 0 Volume is not low | level formatted. |
< 0 Low | level format not supported by volume or an error occurred. |
Additional information
This function performs the same operation as FS_IsLLFormatted()
with the difference that the volume to be queried is identified
by a volume instance instead a volume name. The application
can get a volume instance from a volume name by calling FS_STORAGE_FindVolume().
FS_STORAGE_Mount()
Description
Initializes a volume in a specified access mode.
Prototype
int FS_STORAGE_Mount(const char * sVolumeName,
U8 MountType);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be mounted. |
MountType | Specifies how the volume has to be mounted. FS_MOUNT_RO Read only access mode. FS_MOUNT_RW Read and write access mode. |
Return value
= 0 | Volume is not mounted. |
= FS_MOUNT_RO | Volume is mounted read only mode. |
= FS_MOUNT_RW | Volume is mounted read and write mode. |
< 0 | Error code indicating the failure reason. |
Additional information
The application is not required to call this function before
the first access to the storage device. The file system mounts
by default the storage device at the first access after the
file system initialization. This behavior can be configured
via FS_SetAutoMount().
A mounted volume can be unmounted via FS_STORAGE_Unmount()
or FS_STORAGE_UnmountForced().
FS_STORAGE_MountEx()
Description
Initializes a volume in a specified access mode.
Prototype
int FS_STORAGE_MountEx(FS_VOLUME * pVolume,
U8 MountType);
Parameters
Parameter | Description |
pVolume | Instance of the volume to be mounted. |
MountType | Specifies how the volume has to be mounted. FS_MOUNT_RO Read only access mode. FS_MOUNT_RW Read and write access mode. |
Return value
= 0 | Volume is not mounted. |
= FS_MOUNT_RO | Volume is mounted read only mode. |
= FS_MOUNT_RW | Volume is mounted read and write mode. |
< 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_Mount()
with the difference that the volume is specified via a volume
instance instead of a volume name.
FS_STORAGE_ReadSector()
Description
Reads the data of one logical sector.
Prototype
int FS_STORAGE_ReadSector(const char * sVolumeName,
void * pData,
U32 SectorIndex);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to read from. It cannot be NULL. |
pData | out Buffer that receives the read sector data. It cannot be NULL. |
SectorIndex | Index of the sector to read from. |
Return value
= 0 | OK, sector data read. |
≠ 0 | Error code indicating the failure reason. |
Additional information
pData has to point to a memory region sufficiently large
to store the contents of one logical sector.
The size of the logical sector depends on the type of storage device used.
The application can query the size of the logical sector as well as
the number of logical sectors of a storage device via FS_STORAGE_GetDeviceInfo().
Typically, the size of a logical sector is 512 bytes.
FS_STORAGE_ReadSector() reports an error and does not store any
data to pData if SectorIndex is out of bounds.
The application can call FS_STORAGE_ReadSectors() instead of
calling FS_STORAGE_ReadSector() multiple times if it has to
read consecutive logical sectors at once.
Deprecated name
FS_ReadSector
Example
#include "FS.h"
void SampleStorageReadSector(void) {
U32 aSectorData[512 / 4];
//
// Read the data of the logical sector with the index 10.
//
FS_STORAGE_ReadSector("", aSectorData, 10);
}
FS_STORAGE_ReadSectorEx()
Description
Reads the contents of one logical sector from the storage device.
Prototype
int FS_STORAGE_ReadSectorEx(FS_VOLUME * pVolume,
void * pData,
U32 SectorIndex);
Parameters
Parameter | Description |
pVolume | Instance of the volume to read from. |
pData | out Contents of the logical sector. |
SectorIndex | Index of the logical sector to be read. |
Return value
= 0 | OK, logical sector read successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_ReadSector()
with the difference that the volume is specified via a volume instance
instead a volume name. The application can get a volume instance from a
volume name by calling FS_STORAGE_FindVolume() or FS_STORAGE_FindVolumeByIndex().
FS_STORAGE_ReadSectors()
Description
Reads the data of one or more logical sectors.
Prototype
int FS_STORAGE_ReadSectors(const char * sVolumeName,
void * pData,
U32 SectorIndex,
U32 NumSectors);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to read from. It cannot be NULL. |
pData | out Buffer that receives the read sector data. It cannot be NULL. |
SectorIndex | Index of the first sector to read from. |
NumSectors | Number of sectors to be read. |
Return value
= 0 | OK, sector data read. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function can be used to read the contents of multiple
consecutive logical sectors. pData has to point to a memory
region sufficiently large to store the contents of all logical
sectors read.
The size of the logical sector depends on the type of storage device used.
The application can query the size of the logical sector as well as
the number of logical sectors of a storage device via FS_STORAGE_GetDeviceInfo().
Typically, the size of a logical sector is 512 bytes.
FS_STORAGE_ReadSectors() reports an error and does not perform
any operation if the specified range of logical sectors exceeds
the size of the storage device.
Example
#include "FS.h"
void SampleStorageReadSectors(void) {
U32 aSectorData[512 * 2 / 4];
//
// Read the data of the logical sectors with the indexes 10 and 11.
//
FS_STORAGE_ReadSectors("", aSectorData, 10, 2);
}
FS_STORAGE_ReadSectorsEx()
Description
Reads the contents of multiple logical sectors from a storage device.
Prototype
int FS_STORAGE_ReadSectorsEx(FS_VOLUME * pVolume,
void * pData,
U32 SectorIndex,
U32 NumSectors);
Parameters
Parameter | Description |
pVolume | Instance of the volume to read from. |
pData | out Contents of the logical sector. |
SectorIndex | Index of the logical sector to be read. |
NumSectors | Number of logical sectors to be read. |
Return value
= 0 | OK, logical sectors read successfully. |
≠ 0 | Error code indicating the failure reason |
Additional information
This function performs the same operation as FS_STORAGE_ReadSectors()
with the difference that the volume is specified via a volume instance
instead a volume name. The application can get a volume instance from a
volume name by calling FS_STORAGE_FindVolume() or FS_STORAGE_FindVolumeByIndex().
FS_STORAGE_RefreshSectors()
Description
Reads the contents of a logical sector and writes it back.
Prototype
int FS_STORAGE_RefreshSectors(const char * sVolumeName,
U32 SectorIndex,
U32 NumSectors,
void * pBuffer,
U32 NumBytes);
Parameters
Parameter | Description |
sVolumeName | Name of the volume on which to perform the operation. It cannot be NULL. |
SectorIndex | Index of the first sector to refresh (0-based). |
NumSectors | Number of sectors to refresh starting with SectorIndex. |
pBuffer | Temporary storage for the sector data. Must be at least one sector large. It cannot be NULL. |
NumBytes | Number of bytes in pBuffer. |
Return value
= 0 | OK, sectors refreshed. |
≠ 0 | Error code indicating the failure reason |
Additional information
This function reads the contents of each specified logical
sector to pBuffer and then it writes the same data to it.
FS_STORAGE_RefreshSectors() can read and write more than one
logical sector at once if the size of pBuffer allows it.
The larger pBuffer the faster runs the refresh operation.
FS_STORAGE_RefreshSectors() function can be used on volumes
mounted on a NAND flash device to prevent the accumulation
of bit errors due to excessive read operations (read disturb
effect). The function can also be used to prevent data loses
caused by the data reaching the retention limit.
Reading and then writing back the contents of a logical
sector causes the NAND driver to relocate the data on the NAND
flash device that in turn eliminates bit errors.
Typically, the refresh operation has to be performed periodically
at large time intervals (weeks). The NAND flash may wear out
too soon if the refresh operation is performed too often.
Example
#include "FS.h"
static U32 _aBuffer[2048 * 2 / 4];
void SampleStorageRefreshSectors(void) {
//
// Refresh the logical sectors with the indexes 10-99
// stored on the NAND flash.
//
FS_STORAGE_RefreshSectors("nand:0:", 10, 100, _aBuffer, sizeof(_aBuffer));
}
FS_STORAGE_RefreshSectorsEx()
Description
Reads the contents of a logical sector and writes it back.
Prototype
int FS_STORAGE_RefreshSectorsEx(FS_VOLUME * pVolume,
U32 SectorIndex,
U32 NumSectors,
void * pBuffer,
U32 NumBytes);
Parameters
Parameter | Description |
pVolume | Instance of the volume on which to perform the operation. It cannot be NULL. |
SectorIndex | Index of the first sector to refresh (0-based). |
NumSectors | Number of sectors to refresh starting with SectorIndex. |
pBuffer | Temporary storage for the sector data. Must be at least one sector large. It cannot be NULL. |
NumBytes | Number of bytes in pBuffer. |
Return value
= 0 | OK, sectors refreshed. |
≠ 0 | Error code indicating the failure reason |
Additional information
This function performs the same operation as FS_STORAGE_RefreshSectors()
with the difference that the volume is specified via a volume instance
instead of a volume name.
FS_STORAGE_ResetCounters()
Description
Sets all statistical counters to 0.
Prototype
void FS_STORAGE_ResetCounters(void);
Additional information
This function can be used to set to 0 all the statistical
counters maintained by the storage layer. This can be useful
for example in finding out how many sector operations are
performed during a specific file system operation.
The application calls FS_STORAGE_ResetCounters() before the
file system operation and then FS_STORAGE_GetCounters()
at the end.
The statistical counters are available only on debug builds
if the file system sources are compiled with FS_DEBUG_LEVEL
greater then or equal to FS_DEBUG_LEVEL_CHECK_PARA or
FS_STORAGE_ENABLE_STAT_COUNTERS set to 1.
Example
#include "FS.h"
void SampleStorageResetCounters(void) {
FS_STORAGE_COUNTERS StatCnt;
//
// Set all statistical counters to 0.
//
FS_STORAGE_ResetCounters();
//
// Perform the file system operation...
//
//
// Check the statistical counters.
//
FS_STORAGE_GetCounters(&StatCnt);
}
FS_STORAGE_SetAutoMountType()
Description
Sets the automatic mount behavior.
Prototype
int FS_STORAGE_SetAutoMountType(const char * sVolumeName,
U8 MountType);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be configured. |
MountType | Specifies 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 and write mode. 0 Disables the automatic mount operation for the volume. |
Return value
≥ 0 | OK, the previous mount type. |
< 0 | Error code indicating the failure reason. |
Additional information
This function is available only if the file system is built
with FS_STORAGE_SUPPORT_MOUNT set to 1.
FS_STORAGE_SetAutoMountTypeEx()
Description
Sets the automatic mount behavior.
Prototype
int FS_STORAGE_SetAutoMountTypeEx(FS_VOLUME * pVolume,
U8 MountType);
Parameters
Parameter | Description |
pVolume | Instance of the volume to be configured. |
MountType | Specifies 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 and write mode. 0 Disables the automatic mount operation for the volume. |
Return value
≥ 0 | OK, the previous mount type. |
< 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_SetAutoMount()
with the difference that the volume is specified via a volume
instance instead of a volume name.
This function is available only if the file system is built
with FS_STORAGE_SUPPORT_MOUNT set to 1.
FS_STORAGE_SetOnDeviceActivityCallback()
Description
Registers a function to be called on any logical sector read
or write operation.
Prototype
void FS_STORAGE_SetOnDeviceActivityCallback
(const char * sVolumeName,
FS_ON_DEVICE_ACTIVITY_CALLBACK * pfOnDeviceActivity);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which the callback function is registered. It cannot be NULL. |
pfOnDeviceActivity | Function to be invoked. |
Additional information
This function is optional. It is available only when the file
system is built with FS_DEBUG_LEVEL set to a value grater than
or equal to FS_DEBUG_LEVEL_CHECK_PARA or with
FS_STORAGE_SUPPORT_DEVICE_ACTIVITY set to 1.
Example
Refer to the sample application FS_DeviceActivity.c located
in the Sample/FS/Application folder of the emFile shipment.
FS_STORAGE_Sync()
Description
Writes cached information to storage device.
Prototype
void FS_STORAGE_Sync(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be synchronized. |
Additional information
This function updates all the information present only in sector
cache (if enabled) to storage device. It is also requests the
driver to perform a synchronization operation. The operations
performed during the synchronization are driver-dependent.
Typically, FS_STORAGE_Sync() has to be called if a write-back
sector cache is configured for the volume to reduce the chance
of a data loss in case of an unexpected reset.
Deprecated name
FS_CleanVolume
Example
#include <string.h>
#include "FS.h"
void SampleStorageSync(void) {
U32 aSectorData[512 / 4];
memset(aSectorData, 'a', sizeof(aSectorData));
//
// Write some data to sector with the index 0.
//
FS_STORAGE_WriteSector("", aSectorData, 0);
//
// Make sure that the data is written to storage device.
//
FS_STORAGE_Sync("");
}
FS_STORAGE_SyncEx()
Description
Writes cached information to storage device.
Prototype
int FS_STORAGE_SyncEx(FS_VOLUME * pVolume);
Parameters
Parameter | Description |
pVolume | Instance of the volume to be synchronized. |
Return value
= 0 | OK, volume synchronized successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_Sync()
with the difference that the volume to be synchronized
is identified by a volume instance instead of a volume name.
FS_STORAGE_SyncSectors()
Description
Synchronizes the contents of one or more logical sectors.
Prototype
int FS_STORAGE_SyncSectors(const char * sVolumeName,
U32 SectorIndex,
U32 NumSectors);
Parameters
Parameter | Description |
sVolumeName | Name of the volume that stores the logical sectors. |
SectorIndex | Index of the first sector to be synchronized (0-based). |
NumSectors | Number of sectors to be synchronized starting with SectorIndex. |
Return value
= 0 | OK, sectors synchronized. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This operation is driver-dependent and is currently supported
only by the RAID1 logical driver. The operation updates the
contents of the specified logical sectors that are located on
the secondary storage (mirrored) with the contents of the
corresponding logical sectors from the primary storage (master).
RAID1 logical driver updates the logical sectors only if
the contents is different.
Example
#include "FS.h"
void SampleStorageSyncSectors(void) {
//
// Synchronizes the logical sectors with the indexes 7, 8 and 9.
//
FS_STORAGE_SyncSectors("", 7, 3);
}
FS_STORAGE_SyncSectorsEx()
Description
Synchronizes the contents of one or more logical sectors.
Prototype
int FS_STORAGE_SyncSectorsEx(FS_VOLUME * pVolume,
U32 SectorIndex,
U32 NumSectors);
Parameters
Parameter | Description |
pVolume | Instance of the volume that stores the logical sectors. |
SectorIndex | Index of the first sector to be synchronized (0-based). |
NumSectors | Number of sectors to be synchronized starting with SectorIndex. |
Return value
= 0 | OK, sectors synchronized. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_SyncSectors()
with the difference that the volume is specified via a volume instance
instead of a volume name.
FS_STORAGE_Unmount()
Description
Synchronizes a volume and marks it as not initialized.
Prototype
void FS_STORAGE_Unmount(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be unmounted. It cannot be NULL. |
Additional information
The function sends an unmount command to the driver and marks
the volume as unmounted and uninitialized. If a write sector
cache is enabled, FS_STORAGE_Unmount() also stores any modified
data from sector cache to storage device.
This function has to be called before the device is shutdown
to prevent a data loss.
The file system mounts automatically the volume at the call to
an API function of the storage layer.
Deprecated name
FS_UnmountLL
Example
#include "FS.h"
void SampleStorageUnmount(void) {
//
// Synchronize the sector cache and mark the volume as not initialized.
//
FS_STORAGE_Unmount("");
//
// The device can be shutdown here without loosing any data.
//
}
FS_STORAGE_UnmountEx()
Description
Synchronizes the volume and marks it as not initialized.
Prototype
void FS_STORAGE_UnmountEx(FS_VOLUME * pVolume);
Parameters
Parameter | Description |
pVolume | Instance of the volume to be unmounted. |
Additional information
This function performs the same operation as FS_STORAGE_Unmount()
with the difference that the volume is specified via a volume instance
instead a volume name. The application can get a volume instance from a
volume name by calling FS_STORAGE_FindVolume() or FS_STORAGE_FindVolumeByIndex().
FS_STORAGE_UnmountForced()
Description
Marks a volume it as not initialized.
Prototype
void FS_STORAGE_UnmountForced(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be unmounted. It cannot be NULL. |
Additional information
This function performs the same operations as FS_STORAGE_Unmount().
FS_STORAGE_UnmountForced() has to be called if a storage device
has been removed before being regularly unmounted. When using
FS_STORAGE_UnmountForced() there is no guarantee that the
information cached by the file system is updated to storage.
The file system mounts automatically the volume at the call to
an API function of the storage layer.
Example
#include "FS.h"
void SampleStorageUnmountForced(void) {
if (FS_GetVolumeStatus("") == FS_MEDIA_IS_PRESENT) {
//
// Synchronize the sector cache and mark the volume as not initialized.
//
FS_STORAGE_Unmount("");
//
// The device can be shutdown here without loosing any data.
//
} else {
//
// Storage device has been removed. Mark the volume as not initialized.
// Data loss is possible.
//
FS_STORAGE_UnmountForced("");
}
}
FS_STORAGE_UnmountForcedEx()
Description
Marks the volume as not initialized without synchronizing it.
Prototype
void FS_STORAGE_UnmountForcedEx(FS_VOLUME * pVolume);
Parameters
Parameter | Description |
pVolume | Instance of the volume to be unmounted. |
Additional information
This function performs the same operation as FS_STORAGE_UnmountForced()
with the difference that the volume is specified via a volume instance
instead a volume name. The application can get a volume instance from a
volume name by calling FS_STORAGE_FindVolume().
FS_STORAGE_WriteSector()
Description
Modifies the data of a logical sector.
Prototype
int FS_STORAGE_WriteSector(const char * sVolumeName,
const void * pData,
U32 SectorIndex);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to write to. It cannot be NULL. |
pData | in Buffer that contains the sector data to be written. It cannot be NULL. |
SectorIndex | Index of the sector to write to. |
Return value
= 0 | OK, sector data modified. |
≠ 0 | Error code indicating the failure reason. |
Additional information
pData has to point to a memory region that stores the contents
of one logical sector.
The size of the logical sector depends on the type of storage device used.
The application can query the size of the logical sector as well as
the number of logical sectors of a storage device via FS_STORAGE_GetDeviceInfo().
Typically, the size of a logical sector is 512 bytes.
FS_STORAGE_WriteSector() reports an error and does modify the
contents of the logical sector if SectorIndex is out of bounds.
The application can call FS_STORAGE_WriteSectors() instead of
calling FS_STORAGE_WriteSector() multiple times if it has to
write consecutive logical sectors at once.
Deprecated name
FS_WriteSector
Example
#include <string.h>
#include "FS_Storage.h"
void SampleStorageWriteSector(void) {
U32 aSectorData[512 / 4];
memset(aSectorData, 'a', sizeof(aSectorData));
//
// Write the data of the logical sector with the index 7.
//
FS_STORAGE_WriteSector("", aSectorData, 7);
}
FS_STORAGE_WriteSectorEx()
Description
Writes a logical sector to the storage device.
Prototype
int FS_STORAGE_WriteSectorEx( FS_VOLUME * pVolume,
const void * pData,
U32 SectorIndex);
Parameters
Parameter | Description |
pVolume | Instance of the volume to write to. |
pData | in Contents of the logical sector. |
SectorIndex | Index of the logical sector to be written. |
Return value
= 0 | OK, logical sector written successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_WriteSector()
with the difference that the volume is specified via a volume instance
instead a volume name. The application can get a volume instance from a
volume name by calling FS_STORAGE_FindVolume().
FS_STORAGE_WriteSectors()
Description
Modifies the data of one or more logical sectors.
Prototype
int FS_STORAGE_WriteSectors(const char * sVolumeName,
const void * pData,
U32 SectorIndex,
U32 NumSectors);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to write to. It cannot be NULL. |
pData | in Buffer that contains the sector data to be written. It cannot be NULL. |
SectorIndex | Index of the first sector to be written. |
NumSectors | Number of sectors to be written. |
Return value
= 0 | OK, sector data modified. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function can be used to modify the contents of multiple
consecutive logical sectors. pData has to point to a memory
area that stores the contents of all the logical sectors to
be written.
The size of the logical sector depends on the type of storage device used.
The application can query the size of the logical sector as well as
the number of logical sectors of a storage device via FS_STORAGE_GetDeviceInfo().
Typically, the size of a logical sector is 512 bytes.
FS_STORAGE_WriteSectors() reports an error and does not perform
any operation if the specified range of logical sectors exceeds
the size of the storage device.
Example
#include "FS.h"
void SampleStorageWriteSectors(void) {
U32 aSectorData[512 / 4 * 2];
//
// Write the data of the logical sectors with the indexes 7 and 8.
//
FS_STORAGE_WriteSectors("", aSectorData, 7, 2);
}
FS_STORAGE_WriteSectorsEx()
Description
Writes multiple logical sectors to the storage device.
Prototype
int FS_STORAGE_WriteSectorsEx( FS_VOLUME * pVolume,
const void * pData,
U32 SectorIndex,
U32 NumSectors);
Parameters
Parameter | Description |
pVolume | Instance of the volume to write to. |
pData | in Contents of the logical sector. |
SectorIndex | Index of the logical sector to be written. |
NumSectors | Number of logical sectors to be written. |
Return value
= 0 | OK, logical sectors written successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function performs the same operation as FS_STORAGE_WriteSectors()
with the difference that the volume is specified via a volume instance
instead a volume name. The application can get a volume instance form
a volume name by calling FS_STORAGE_FindVolume().
FS_DEV_INFO
Description
Information about the storage device.
Type definition
typedef struct {
U16 NumHeads;
U16 SectorsPerTrack;
U32 NumSectors;
U16 BytesPerSector;
} FS_DEV_INFO;
Structure members
Member | Description |
NumHeads | Number of read / write heads. |
SectorsPerTrack | Number of sectors stored on a track. |
NumSectors | Total number of sectors on the storage device. |
BytesPerSector | Size of a logical sector in bytes. |
Additional information
NumHeads and SectorsPerTrack are relevant only for mechanical
drives. The application can access the information about
the storage device by calling FS_STORAGE_GetDeviceInfo().
FS_ON_DEVICE_ACTIVITY_CALLBACK
Description
The type of the callback function invoked by the file system
on a logical sector read or write operation.
Type definition
typedef void (FS_ON_DEVICE_ACTIVITY_CALLBACK)(FS_DEVICE * pDevice,
unsigned Operation,
U32 StartSector,
U32 NumSectors,
int SectorType);
Parameters
Parameter | Description |
pDevice | Storage device that performed the operation. |
Operation | Type of the operation performed. Can be one of the values listed in Transfer direction |
StartSector | Index of the first logical sector transfered (0-based) |
NumSectors | Number of logical sectors transfered in the current operation. |
SectorType | Type of the data stored in the logical sector. It can be one of the values listed in Sector data type |
Additional information
This is the type of function that can be registered
via FS_STORAGE_SetOnDeviceActivityCallback()
FS_STORAGE_COUNTERS
Description
Statistical counters.
Type definition
typedef struct {
U32 ReadOperationCnt;
U32 ReadSectorCnt;
U32 ReadSectorCachedCnt;
U32 WriteOperationCnt;
U32 WriteSectorCnt;
U32 WriteSectorCntCleaned;
U32 ReadSectorCntMan;
U32 ReadSectorCntDir;
U32 WriteSectorCntMan;
U32 WriteSectorCntDir;
} FS_STORAGE_COUNTERS;
Structure members
Member | Description |
ReadOperationCnt | Number of “Read sector operation” calls. |
ReadSectorCnt | Number of sectors read (before cache). |
ReadSectorCachedCnt | Number of sectors read from cache |
WriteOperationCnt | Number of “Write sector operation” calls |
WriteSectorCnt | Number of sectors written (before cache). |
WriteSectorCntCleaned | Number of sectors written by the cache to storage in order to make room for other data. |
ReadSectorCntMan | Number of management sectors read (before cache). |
ReadSectorCntDir | Number of directory sectors (which store directory entries) read (before cache). |
WriteSectorCntMan | Number of management sectors written (before cache). |
WriteSectorCntDir | Number of directory sectors (which store directory entries) written (before cache). |
Additional information
ReadSectorCnt can be (and typically is) higher than
ReadOperationCnt, since one read operation can request multiple
sectors (in a burst). The same applies to write operations:
WriteSectorCnt can be (and typically is) higher than
WriteOperationCnt, since one read operation can request multiple
sectors (in a burst).
The statistical counters can be read via FS_STORAGE_GetCounters().
They are set to 0 when the file system is initialized.
Additionally, the application can explicitly set them to 0
via FS_STORAGE_ResetCounters().
Sector data type
Description
Type of data stored in a logical sector
Definition
#define FS_SECTOR_TYPE_DATA 0u
#define FS_SECTOR_TYPE_DIR 1u
#define FS_SECTOR_TYPE_MAN 2u
Symbols
Definition | Description |
FS_SECTOR_TYPE_DATA | Sector that stores file data. |
FS_SECTOR_TYPE_DIR | Sector that stores directory entries. |
FS_SECTOR_TYPE_MAN | Sector that stores entries of the allocation table. |
Transfer direction
Description
Direction of the transfered data.
Definition
#define FS_OPERATION_READ 0
#define FS_OPERATION_WRITE 1
Symbols
Definition | Description |
FS_OPERATION_READ | Data is transferred from storage device to MCU. |
FS_OPERATION_WRITE | Data is transferred from MCU to storage device. |
Additional information
One of these values is passed by the file system via Operation
parameter to the callback function registered via
FS_STORAGE_SetOnDeviceActivityCallback()
The functions described in this section can be used only on volumes
formatted as FAT.
FS_FAT_ConfigDirtyFlagUpdate()
Description
Enables / disables the update of the flag that indicates if
the volume has been unmounted correctly.
Prototype
void FS_FAT_ConfigDirtyFlagUpdate(int OnOff);
Parameters
Parameter | Description |
OnOff | Activation status of the option. 0 Disable the option. 1 Enable the option. |
Additional information
If enabled, the file system updates an internal dirty flag that
is set to 1 each time data is written to storage device. The dirty
flag is set to 0 when the application unmounts the file system.
The value of the dirty flag is updated to storage device and
can be used to check if the storage device has been properly
unmounted before the system reset. FS_GetVolumeInfo() can
be used to get the value of this dirty flag (IsDirty member
of FS_DISK_INFO).
The update of the dirty flag is enabled by default if the
compile-time option FS_FAT_UPDATE_DIRTY_FLAG is set to 1.
FS_FAT_ConfigDirtyFlagUpdate() is available only if
the compile-time option FS_FAT_UPDATE_DIRTY_FLAG is set to 1.
Example
#include "FS.h"
void SampleFATConfigDirtyFlagUpdate(void) {
FS_FILE * pFile;
FS_DISK_INFO VolumeInfo;
FS_Init();
#if FS_FAT_UPDATE_DIRTY_FLAG
FS_FAT_ConfigDirtyFlagUpdate(1);
#endif
pFile = FS_FOpen("Test.txt", "w");
if (pFile) {
FS_FClose(pFile);
}
FS_GetVolumeInfo("", &VolumeInfo);
if (VolumeInfo.IsDirty) {
FS_X_Log("Volume has been modified.\n");
} else {
FS_X_Log("Volume has not been modified.\n");
}
}
FS_FAT_ConfigFATCopyMaintenance()
Description
Enables / disables the update of the second allocation table.
Prototype
void FS_FAT_ConfigFATCopyMaintenance(int OnOff);
Parameters
Parameter | Description |
OnOff | Activation status of the option. 0 Disable the option. 1 Enable the option. |
Additional information
The FAT file system has support for a second (redundant)
allocation table. FS_FAT_ConfigFATCopyMaintenance() can be used
to enable or disable the update of the second allocation table.
The data in the second allocation table is not used by the file
system but it may be required to be present by some PC file
system checking utilities. Enabling this option can possible
reduce the write performance of the file system.
The update of the second allocation table is enabled by default
if the compile-time option FS_MAINTAIN_FAT_COPY is set to 1.
FS_FAT_ConfigFATCopyMaintenance() is available only if the
compile-time option FS_MAINTAIN_FAT_COPY is set to 1.
Example
#include "FS.h"
void SampleFATConfigFATCopyMaintenance(void) {
FS_Init();
#if FS_MAINTAIN_FAT_COPY
FS_FAT_ConfigFATCopyMaintenance(1);
#endif
//
// At each write access to the allocation table
// the second allocation table is also updated.
//
}
FS_FAT_ConfigFSInfoSectorUse()
Description
Enables / disables the usage of information from the FSInfo sector.
Prototype
void FS_FAT_ConfigFSInfoSectorUse(int OnOff);
Parameters
Parameter | Description |
OnOff | Activation status of the option. 0 Disable the option. 1 Enable the option. |
Additional information
FSInfo sector is a management sector present on FAT32-formatted
volumes that stores information about the number of free clusters
and the id of the first free cluster. This information, when
available and valid, can be used to increase the performance of
the operation that calculates the available free space on a volume
such as FS_GetVolumeFreeSpace(), FS_GetVolumeFreeSpaceKB(),
FS_GetVolumeInfo(), or FS_GetVolumeInfoEx(). If the information
in the FSInfo sector is missing or invalid, the file system has
to scan the entire allocation to calculate the available free
space an operation that can take a long time to complete on
storage devices with a large capacity (few Gbytes.)
The file system invalidates the information in the FSInfo sector
on the first operation that allocates or frees a cluster. The
FSInfo sector is updated when the volume is unmounted via
FS_Unmount() or synchronized via FS_Sync().
FSInfo sector is evaluated and updated by default if the
compile-time option FS_FAT_USE_FSINFO_SECTOR is set to 1.
FS_FAT_ConfigFSInfoSectorUse() is available only if
the compile-time option FS_FAT_USE_FSINFO_SECTOR is set to 1.
Example
#include "FS.h"
void SampleFATConfigFSInfoSectorUse(void) {
U32 NumBytes;
FS_Init();
#if FS_FAT_USE_FSINFO_SECTOR
FS_FAT_ConfigFSInfoSectorUse(1);
#endif
NumBytes = FS_GetVolumeFreeSpace("");
}
FS_FAT_ConfigROFileMovePermission()
Description
Enables / disables the permission to move (and rename)
files and directories with the read-only file attribute set.
Prototype
void FS_FAT_ConfigROFileMovePermission(int OnOff);
Parameters
Parameter | Description |
OnOff | Activation status of the option. 0 Disable the option. 1 Enable the option. |
Additional information
The application is per default allowed to move or rename via
FS_Move() and FS_Rename() respectively files and directories
that have the read-only file attribute (FS_ATTR_READ_ONLY) set.
FS_FAT_ConfigROFileMovePermission() can be used to disable this
option and thus to prevent an application to perform move
or rename operations on files and directories marked as
read-only.
FS_FAT_ConfigROFileMovePermission() is available only if the
compile-time option FS_FAT_PERMIT_RO_FILE_MOVE is set to 1.
Example
#include "FS.h"
void SampleFATConfigROFileMovePermission(void) {
FS_FILE * pFile;
int r;
#if FS_FAT_PERMIT_RO_FILE_MOVE
FS_FAT_ConfigROFileMovePermission(0);
#endif
pFile = FS_FOpen("Test.txt", "w");
if (pFile != NULL) {
FS_FClose(pFile);
}
FS_SetFileAttributes("Test.txt", FS_ATTR_READ_ONLY);
r = FS_Move("Test.txt", "TestOld.txt");
if (r != 0) {
//
// A file marked as read-only cannot be moved to another location.
//
}
}
FS_FAT_DisableLFN()
Description
Disables the support for long file names.
Prototype
void FS_FAT_DisableLFN(void);
Additional information
After calling this function the file system accepts only file
and directory names in 8.3 format. Files and directories created
with support for long file names enabled are still accessible
since each long file name has an associated name in 8.3 format.
The short name is automatically generated by the file system
based on the first characters of the long name and a sequential
index. The support for long file names can be activated via
FS_FAT_SupportLFN().
This function applies only to volumes formatted as FAT.
EFS-formatted volumes have native support for long file names.
Example
#include "FS.h"
void SampleFATDisableLFN(void) {
FS_FILE * pFile;
FS_Init();
#if FS_SUPPORT_FAT
FS_FAT_DisableLFN();
#endif
pFile = FS_FOpen("FileName.txt", "w");
if (pFile) {
FS_FClose(pFile);
}
}
Description
Performs a high-level format as per SD Specification.
Prototype
int FS_FAT_FormatSD(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be formatted. |
Return value
= 0 | OK, format successful. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The SD Specification defines a layout for the information that
is stored to an SD, SDHC or SDXC card that ensures the best
read and write performance. The layout of the information
is set during the format operation and takes advantage
of the physical structure of the storage device being formatted
in order to optimize the access to it.
FS_FAT_FormatSD() formats the storage device using this layout.
SEGGER recommends formatting an SD card or an eMMC device using
this function for improved file system performance. FS_FAT_FormatSD()
can be used as well to format other types of storage devices.
Typically, FS_FAT_FormatSD() reserves more space for the file system
management information in comparison to FS_Format(). For this reason,
slightly less storage space will be available for the application
when formatting using FS_FAT_FormatSD().
FS_FAT_FormatSD() performs the following operations:
- Creates a Master Boot Record (MBR) if it does not exist.
- Stores information about the partition to the first entry of MBR.
- Formats the storage device as either FAT12, FAT16 or FAT32 depending on its capacity.
The type of FAT formatting used depends on the capacity of
the storage device. The following table shows this relationship.
FAT type | Storage capacity |
FAT12 | smaller than about 256 MB |
FAT16 | between about 256 MB and about 2 GB |
FAT32 | greater than about 2 GB |
The function is available only if the file system is built
with the FS_SUPPORT_FAT configuration define set to 1.
Deprecated name
FS_FormatSD
Example
#include "FS.h"
void SampleFATFormatSD(void) {
FS_Init();
#if FS_SUPPORT_FAT
FS_FAT_FormatSD("");
#endif
}
FS_FAT_GetConfig()
Description
Returns information about how the FAT component is configured to operate.
Prototype
int FS_FAT_GetConfig(FS_FAT_CONFIG * pConfig);
Parameters
Parameter | Description |
pConfig | out Configuration information. |
Return value
= 0 | OK, information returned. |
≠ 0 | Error code indicating the failure reason. |
FS_FAT_GetLFNConverter()
Description
Returns the type of configured file name converter.
Prototype
FS_UNICODE_CONV *FS_FAT_GetLFNConverter(void);
Return value
Configured file name converter.
Additional information
This function is available only if FS_SUPPORT_FILE_NAME_ENCODING
is set to 1 which is the default.
Refer to pUnicodeConv parameter of FS_FAT_SetLFNConverter() for
a list of possible return values.
FS_FAT_GrowRootDir()
Description
Increases the size of the root directory.
Prototype
U32 FS_FAT_GrowRootDir(const char * sVolumeName,
U32 NumAddEntries);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which to increase the root directory. |
NumAddEntries | Number of directory entries to be added. |
Return value
> 0 | Number of entries added. |
= 0 | Clusters after root directory are not free. The number of entries in the root directory has not been changed. |
= 0xFFFFFFFF | An error occurred. |
Additional information
The formatting function allocates per default one cluster
for the root directory of a FAT32 formatted volume. The file
system increases automatically the size of the root directory
as more files are added to it. This operation has a certain
overhead that depends on the size of the allocation table
and on the available free space. This overhead can be eliminated
by calling FS_FAT_GrowRootDir() to increase the size of the
root directory to the number of files and directories the
application is expected to store in it.
This function increases the size of the root directory on a
FAT32 formatted volume by the number of entries specified in
NumAddEntries. The file system allocates one directory entry
for each file or directory if the support for long file names
is not enabled. With the support for long file names enabled
the number of directory entries allocated to a file or directory
depends on the number of characters in the name of the created
file or directory.
This function fails if one of the following conditions is true:
- the function is not called immediately after the format operation.
- the specified volume is formatted as FAT12 or FAT16.
- the required number of clusters cannot be allocated following the cluster already allocated to the root directory.
FS_FAT_GrowRootDir() is available only if the compile-time option
FS_SUPPORT_FAT set to 1.
Example
#include "FS.h"
void SampleFATGrowRootDir(void) {
FS_Format("", NULL);
#if FS_SUPPORT_FAT
FS_FAT_GrowRootDir("", 64);
#endif
}
FS_FAT_SetLFNConverter()
Description
Configures how long file names are to be encoded and decoded.
Prototype
void FS_FAT_SetLFNConverter(const FS_UNICODE_CONV * pUnicodeConv);
Parameters
Parameter | Description |
pUnicodeConv | File name converter. |
Additional information
This function is available only if FS_SUPPORT_FILE_NAME_ENCODING
is set to 1 which is the default.
Permitted values for pUnicodeConv are:
Identifier | Description |
FS_UNICODE_CONV_CP437 | Unicode <-> CP437 (DOS Latin US) converter |
FS_UNICODE_CONV_CP932 | Unicode <-> CP932 (Shift JIS) converter |
FS_UNICODE_CONV_CP936 | Unicode <-> CP936 (GBK) converter |
FS_UNICODE_CONV_CP949 | Unicode <-> CP949 (Unified Hangul Code) converter |
FS_UNICODE_CONV_CP950 | Unicode <-> CP950 (Big5) converter |
FS_UNICODE_CONV_UTF8 | Unicode <-> UTF-8 converter |
FS_FAT_SupportLFN()
Description
Enables the support for long file names.
Prototype
void FS_FAT_SupportLFN(void);
Additional information
The file system accepts per default only file and directory
names in 8.3 format, that is maximum 8 characters in the base
name of a file, an optional period character, and an optional
extension of maximum 3 characters. The application can call
FS_FAT_SupportLFN() to enable the file system to work with
names for files and directories longer that in the 8.3 format.
This function applies only to volumes formatted as FAT.
EFS-formatted volumes have native support for long file names.
Example
#include "FS.h"
void SampleFATSupportLFN(void) {
FS_FILE * pFile;
FS_Init();
#if FS_SUPPORT_FAT
FS_FAT_SupportLFN();
#endif
pFile = FS_FOpen("This is an unusually long file name", "w");
if (pFile) {
FS_FClose(pFile);
}
}
FS_FAT_CONFIG
Description
Information about the FAT configuration.
Type definition
typedef struct {
U8 IsLFNSupported;
U8 IsFSInfoSectorUsed;
U8 IsATCopyMaintained;
U8 IsROFileMovePermitted;
U8 IsDirtyFlagUpdated;
U8 IsFAT32Supported;
U8 IsDeleteOptimized;
U8 LinearAccessOptimizationLevel;
U8 IsFreeClusterCacheSupported;
U8 IsLowerCaseSFNSupported;
} FS_FAT_CONFIG;
Structure members
Member | Description |
IsLFNSupported | Indicates if the support for long file names is enabled. |
IsFSInfoSectorUsed | Indicates if the information about the free clusters is read from the FSInfo sector. |
IsATCopyMaintained | Indicates if the copy of the allocation table is update. |
IsROFileMovePermitted | Indicates if the file system is allowed to move file that have the read-only attribute set. |
IsDirtyFlagUpdated | Indicates if the updates the dirty flag in the BPB sector. |
IsFAT32Supported | Indicates if the support for FAT32 formatted volumes is enabled. |
IsDeleteOptimized | Indicates if the optimization for the deletion of large files is enabled. |
LinearAccessOptimizationLevel | Optimization level for the access to linearly allocated files. |
IsFreeClusterCacheSupported | Indicates if the support for the cache of free clusters is enabled. |
IsLowerCaseSFNSupported | Indicates if the optimization for storing of short file names in lower case is enabled. |
The functions described in this section can be used only on volumes
formatted as EFS.
FS_EFS_ConfigCaseSensitivity()
Description
Configures how the file names are compared.
Prototype
void FS_EFS_ConfigCaseSensitivity(int OnOff);
Parameters
Parameter | Description |
OnOff | Specifies if the case of a character is important or not. 1 Character case is important. 0 Character case is ignored. |
Additional information
This function is optional and is active only when the file system
is compiled with FS_EFS_CASE_SENSITIVE set to 1. By default the
EFS file system layer ignores the case of a character in file
names when it compares two file names. That is, “testfile.txt”,
“TestFile.txt” and “TESTFILE.TXT” represent the same file name.
The case of a file name is preserved when the file is created
via FS_FOpen() or FS_FOpenEx() or in case of a directory when
FS_MkDir() and FS_CreateDir() is called to create one.
If the case sensitivity is enabled by calling FS_EFS_ConfigCaseSensitivity()
with the OnOff parameter set to 1 than “testfile.txt”,
“TestFile.txt” and “TESTFILE.TXT” are three different file names.
FS_EFS_ConfigStatusSectorSupport()
Description
Enables or disables the usage of information from the status sector.
Prototype
void FS_EFS_ConfigStatusSectorSupport(int OnOff);
Parameters
Parameter | Description |
OnOff | Specifies if the status sector information has to be used or not. 1 Status sector information is used. 0 Status sector information is not used. |
Additional information
This function is optional an is active only when the file system
is compiled with FS_EFS_SUPPORT_STATUS_SECTOR set to 1. The status
sector stores information about the free space available on the storage
which helps the file system improve the performance of the operations
that return the available free space such as FS_GetVolumeInfo().
FS_EFS_GetConfig()
Description
Returns information about how the EFS component is configured to operate.
Prototype
int FS_EFS_GetConfig(FS_EFS_CONFIG * pConfig);
Parameters
Parameter | Description |
pConfig | out Configuration information. |
Return value
= 0 | OK, information returned. |
≠ 0 | Error code indicating the failure reason. |
FS_EFS_SetFileNameConverter()
Description
Configures how file names are to be encoded.
Prototype
void FS_EFS_SetFileNameConverter(const FS_UNICODE_CONV * pUnicodeConv);
Parameters
Parameter | Description |
pUnicodeConv | File name converter. |
Additional information
This function is available only if FS_SUPPORT_FILE_NAME_ENCODING
is set to 1. By default, FS_SUPPORT_FILE_NAME_ENCODING is set
to 0 in order to reduce the RAM and ROM usage.
Permitted values for pUnicodeConv are:
Identifier | Description |
FS_UNICODE_CONV_CP437 | Unicode <-> CP437 (DOS Latin US) converter |
FS_UNICODE_CONV_CP932 | Unicode <-> CP932 (Shift JIS) converter |
FS_UNICODE_CONV_CP936 | Unicode <-> CP936 (GBK) converter |
FS_UNICODE_CONV_CP949 | Unicode <-> CP949 (Unified Hangul Code) converter |
FS_UNICODE_CONV_CP950 | Unicode <-> CP950 (Big5) converter |
FS_UNICODE_CONV_UTF8 | Unicode <-> UTF-8 converter |
FS_EFS_CONFIG
Description
Information about the EFS configuration.
Type definition
typedef struct {
U8 IsStatusSectorSupported;
U8 IsCaseSensitiveName;
U8 IsDirEntryBufferSupported;
U8 NumDirEntryBuffers;
U8 IsDeleteOptimized;
U8 LinearAccessOptimizationLevel;
U8 IsFreeClusterCacheSupported;
U8 MaxDirEntrySize;
} FS_EFS_CONFIG;
Structure members
Member | Description |
IsStatusSectorSupported | Indicates if the information of the status sector is updated. |
IsCaseSensitiveName | Indicates if the comparison of file names is case sensitive. |
IsDirEntryBufferSupported | Indicates if the support for directory entry buffers is enabled. |
NumDirEntryBuffers | Number of configured directory entry buffers. |
IsDeleteOptimized | Indicates if the optimization for the deletion of large files is enabled. |
LinearAccessOptimizationLevel | Optimization level for the access to linearly allocated files. |
IsFreeClusterCacheSupported | Indicates if the support for the cache of free clusters is enabled. |
MaxDirEntrySize | Maximum number of bytes in a directory entry. |
The functions described in this section can be used only on volumes
formatted as exFAT.
FS_EXFAT_ConfigDirtyFlagUpdate()
Description
Enables or disables the update of the flag that indicates if
the volume has been unmounted correctly.
Prototype
void FS_EXFAT_ConfigDirtyFlagUpdate(int OnOff);
Parameters
Parameter | Description |
OnOff | Activation status of the option. 0 Disable the option. 1 Enable the option. |
Additional information
If enabled, the file system updates an internal dirty flag that
is set to 1 each time data is written to storage device. The dirty
flag is set to 0 when the application unmounts the file system.
The value of the dirty flag is updated to storage device and
can be used to check if the storage device has been properly
unmounted before the system reset. FS_GetVolumeInfo() can
be used to get the value of this dirty flag (IsDirty member
of FS_DISK_INFO).
The update of the dirty flag is enabled by default if the
compile-time option FS_EXFAT_UPDATE_DIRTY_FLAG is set to 1.
FS_EXFAT_ConfigDirtyFlagUpdate() is available only if
the compile-time option FS_EXFAT_UPDATE_DIRTY_FLAG is set to 1.
FS_EXFAT_ConfigROFileMovePermission()
Description
Enables / disables the permission to move (and rename)
files and directories with the read-only file attribute set.
Prototype
void FS_EXFAT_ConfigROFileMovePermission(int OnOff);
Parameters
Parameter | Description |
OnOff | Activation status of the option. 0 Disable the option. 1 Enable the option. |
Additional information
The application is per default allowed to move or rename via
FS_Move() and FS_Rename() respectively files and directories
that have the read-only file attribute (FS_ATTR_READ_ONLY) set.
FS_EXFAT_ConfigROFileMovePermission() can be used to disable this
option and thus to prevent an application to perform move
or rename operations on files and directories marked as
read-only.
FS_EXFAT_ConfigROFileMovePermission() is available only if the
compile-time option FS_EXFAT_PERMIT_RO_FILE_MOVE is set to 1.
FS_EXFAT_ConfigSpaceUsageUpdate()
Description
Enables or disables the update of the storage usage.
Prototype
void FS_EXFAT_ConfigSpaceUsageUpdate(int OnOff);
Parameters
Parameter | Description |
OnOff | Activation status of the option. 0 Disable the option. 1 Enable the option. |
Additional information
If enabled, the file system updates the information about the
amount of storage used by the file system in the boot sector
of the volume.
The update of the usage information is enabled by default if the
compile-time option FS_EXFAT_UPDATE_SPACE_USAGE is set to 1.
FS_EXFAT_ConfigSpaceUsageUpdate() is available only if
the compile-time option FS_EXFAT_UPDATE_SPACE_USAGE is set to 1.
Description
Performs a high-level format as per SD Specification.
Prototype
int FS_EXFAT_FormatSD(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume to be formatted. |
Return value
= 0 | OK, format successful. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The SD Standard defines a layout for the information that
is stored to an SD, SDHC or SDXC card that ensures the best
read and write performance. The layout of the information
is set during the format operation and takes advantage
of the physical structure of the storage device being formatted
in order to optimize the access to it.
FS_EXFAT_FormatSD() formats the storage device using this layout.
SEGGER recommends formatting an SD card or an eMMC device using
this function for improved file system performance. FS_EXFAT_FormatSD()
can be used to format other types of storage devices as well.
Typically, FS_EXFAT_FormatSD() reserves more space for the file system
management information in comparison to FS_Format(). For this reason,
slightly less storage space will be available for the application
when formatting using FS_EXFAT_FormatSD().
FS_EXFAT_FormatSD() performs the following operations:
- Creates a Master Boot Record (MBR) if it does not exist.
- Stores information about the partition to the first entry of MBR.
- Formats the partition as exFAT.
The function is available only if the file system is built
with the FS_SUPPORT_EXFAT configuration define set to 1.
FS_EXFAT_GetConfig()
Description
Returns information about how the exFAT component is configured to operate.
Prototype
int FS_EXFAT_GetConfig(FS_EXFAT_CONFIG * pConfig);
Parameters
Parameter | Description |
pConfig | out Configuration information. |
Return value
= 0 | OK, information returned. |
≠ 0 | Error code indicating the failure reason. |
FS_EXFAT_GetFileNameConverter()
Description
Returns the type of configured file name converter.
Prototype
FS_UNICODE_CONV *FS_EXFAT_GetFileNameConverter(void);
Return value
Configured file name converter.
Additional information
This function is available only if FS_SUPPORT_FILE_NAME_ENCODING
is set to 1 which is the default.
Refer to pUnicodeConv parameter of FS_EXFAT_SetFileNameConverter() for
a list of possible return values.
FS_EXFAT_GrowRootDir()
Description
Increases the size of the root directory.
Prototype
U32 FS_EXFAT_GrowRootDir(const char * sVolumeName,
U32 NumAddEntries);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which to increase the root directory. |
NumAddEntries | Number of directory entries to be added. |
Return value
> 0 | Number of entries added. |
= 0 | Clusters after root directory are not free. The number of entries in the root directory has not been changed. |
= 0xFFFFFFFF | An error occurred. |
Additional information
The formatting function allocates by default one cluster
for the root directory of a formatted volume. The file
system increases automatically the size of the root directory
as more files are added to it. This operation has a certain
overhead that depends on the size of the allocation table
and on the available free space. This overhead can be eliminated
by calling FS_EXFAT_GrowRootDir() to increase the size of the
root directory to the number of files and directories the
application is expected to store in it.
This function increases the size of the root directory on a
formatted volume by the number of entries specified in
NumAddEntries. The file system allocates one directory entry
for each file or directory if the support for long file names
is not enabled. With the support for long file names enabled
the number of directory entries allocated to a file or directory
depends on the number of characters in the name of the created
file or directory.
This function fails if one of the following conditions is true:
- the function is not called immediately after the format operation.
- the required number of clusters cannot be allocated following the cluster already allocated to the root directory.
FS_EXFAT_GrowRootDir() is available only if the compile-time option
FS_SUPPORT_EXFAT set to 1.
FS_EXFAT_SetFileNameConverter()
Description
Configures how long file names are to be encoded and decoded.
Prototype
void FS_EXFAT_SetFileNameConverter(const FS_UNICODE_CONV * pUnicodeConv);
Parameters
Parameter | Description |
pUnicodeConv | File name converter. |
Additional information
This function is available only if FS_SUPPORT_FILE_NAME_ENCODING
is set to 1 which is the default.
Permitted values for pUnicodeConv are:
Identifier | Description |
FS_UNICODE_CONV_CP437 | Unicode <-> CP437 (DOS Latin US) converter |
FS_UNICODE_CONV_CP932 | Unicode <-> CP932 (Shift JIS) converter |
FS_UNICODE_CONV_CP936 | Unicode <-> CP936 (GBK) converter |
FS_UNICODE_CONV_CP949 | Unicode <-> CP949 (Unified Hangul Code) converter |
FS_UNICODE_CONV_CP950 | Unicode <-> CP950 (Big5) converter |
FS_UNICODE_CONV_UTF8 | Unicode <-> UTF-8 converter |
FS_EXFAT_CONFIG
Description
Information about the exFAT configuration.
Type definition
typedef struct {
U8 IsSpaceUsageUpdated;
U8 IsROFileMovePermitted;
U8 IsDirtyFlagUpdated;
U8 IsDeleteOptimized;
U8 LinearAccessOptimizationLevel;
U8 IsFreeClusterCacheSupported;
} FS_EXFAT_CONFIG;
Structure members
Member | Description |
IsSpaceUsageUpdated | Indicates if the information about storage usage is updated in the boot sector. |
IsROFileMovePermitted | Indicates if the file system is allowed to move file that have the read-only attribute set. |
IsDirtyFlagUpdated | Indicates if the updates the dirty flag in the BPB sector. |
IsDeleteOptimized | Indicates if the optimization for the deletion of large files is enabled. |
LinearAccessOptimizationLevel | Optimization level for the access to linearly allocated files. |
IsFreeClusterCacheSupported | Indicates if the support for the cache of free clusters is enabled. |
Error-handling functions
An application can use the following functions to check and clear the error
status of a file handle.
FS_ClearErr()
Description
Clears error status of a file handle.
Prototype
void FS_ClearErr(FS_FILE * pFile);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
Additional information
The function sets the error status of a file handle to
FS_ERRCODE_OK. FS_ClearErr() is the only function that clears
the error status of a file handle. The other API functions modify
the error status of a file handle only if it is cleared.
The application has to call this function after it detects that
an error occurred during a file system operation on an opened
file handle and before it starts a new file system operation
if it wants to get the correct error status in case of a failure.
Example
#include <stdio.h>
#include "FS.h"
void SampleClearErr(void) {
FS_FILE * pFile;
U32 aBuffer[32 / 4];
int ErrCode;
char ac[100];
U32 NumBytesRead;
pFile = FS_FOpen("Test.txt", "r");
if (pFile) {
NumBytesRead = FS_Read(pFile, aBuffer, sizeof(aBuffer));
ErrCode = FS_FError(pFile);
if (ErrCode == FS_ERRCODE_OK) {
SEGGER_snprintf(ac, sizeof(ac), "First read operation failed with: %d (%s)\n",
ErrCode, FS_ErrorNo2Text(ErrCode));
FS_X_Log(ac);
FS_ClearErr(pFile);
} else {
SEGGER_snprintf(ac, sizeof(ac), "The first operation read %lu bytes from file.\n",
NumBytesRead);
FS_X_Log(ac);
}
NumBytesRead = FS_Read(pFile, aBuffer, sizeof(aBuffer));
ErrCode = FS_FError(pFile);
if (ErrCode != FS_ERRCODE_OK) {
SEGGER_snprintf(ac, sizeof(ac), "Second read operation failed with: %d (%s)\n",
ErrCode, FS_ErrorNo2Text(ErrCode));
FS_X_Log(ac);
FS_ClearErr(pFile);
} else {
SEGGER_snprintf(ac, sizeof(ac), "The second operation read %lu bytes from file.\n",
NumBytesRead);
FS_X_Log(ac);
}
FS_FClose(pFile);
}
}
FS_ErrorNo2Text()
Description
Returns a human-readable text description of an API error code.
Prototype
char *FS_ErrorNo2Text(int ErrCode);
Parameters
Parameter | Description |
ErrCode | Error code for which the text description has to be returned. |
Return value
The text description as 0-terminated ASCII string.
Additional information
For a list of supported error codes refer to Error codes.
If the error code is not known FS_ErrorNo2Text() returns the
“Unknown error” string. The error status of an opened file
handle can be queried via FS_FError(). Most of the API functions
of the file system also return one of the defined codes in case
of an error. This error code can be passed to FS_ErrorNo2Text()
to get a human-readable text description.
Example
#include <stdio.h>
#include "FS.h"
void SampleErrorNo2Text(void) {
FS_FILE * pFile;
int r;
char ac[100];
r = FS_FOpenEx("Test.txt", "r", &pFile);
if (r) {
SEGGER_snprintf(ac, sizeof(ac),
"The file open operation failed with: %d (%s)\n", r, FS_ErrorNo2Text(r));
FS_X_Log(ac);
} else {
//
// Access the file contents...
//
FS_FClose(pFile);
}
}
FS_FEof()
Description
Returns if end of file has been reached.
Prototype
int FS_FEof(FS_FILE * pFile);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
Return value
= 1 | An attempt was made to read beyond the end of the file. |
= 0 | The end of file has not been reached. |
< 0 | An error occurred. |
Additional information
The end-of-file flag of the file handle is set by the file system
when the application tries to read more bytes than available in
the file. This is not an error condition but just an indication
that the file pointer is positioned beyond the last byte in the
file and that by trying to read from this position no bytes are
returned.
Example
#include "FS.h"
void SampleFEof(void) {
FS_FILE * pFile;
U32 aBuffer[32 / 4];
int r;
int ErrCode;
pFile = FS_FOpen("Test.txt", "r");
if (pFile) {
while (1) {
FS_Read(pFile, aBuffer, sizeof(aBuffer));
if (FS_FEof(pFile)) {
break; // End of file reached.
}
ErrCode = FS_FError(pFile);
if (ErrCode) {
break; // An error occurred while reading from file.
}
}
FS_FClose(pFile);
}
}
FS_FError()
Description
Returns error status of a file handle.
Prototype
I16 FS_FError(FS_FILE * pFile);
Parameters
Parameter | Description |
pFile | Handle to opened file. |
Return value
= FS_ERRCODE_OK | No error present. |
≠ FS_ERRCODE_OK | An error has occurred. |
Additional information
The application can use this function to check what kind
of error caused an API function that does not return an error code
such as FS_Read(), FS_FRead(), FS_Write() or FS_FWrite() to fail.
The error status remains set until the application calls
FS_ClearErr().
FS_ErrorNo2Text() can be used to return a human-readable
description of the error as a 0-terminated string.
Example
#include <stdio.h>
#include "FS.h"
void SampleFError(void) {
FS_FILE * pFile;
U32 aBuffer[32 / 4];
int ErrCode;
char ac[100];
U32 NumBytesRead;
pFile = FS_FOpen("Test.txt", "r");
if (pFile) {
NumBytesRead = FS_Read(pFile, aBuffer, sizeof(aBuffer));
ErrCode = FS_FError(pFile);
if (ErrCode != FS_ERRCODE_OK) {
SEGGER_snprintf(ac, sizeof(ac), "The read operation failed with: %d (%s)\n",
ErrCode, FS_ErrorNo2Text(ErrCode));
FS_X_Log(ac);
FS_ClearErr(pFile);
} else {
SEGGER_snprintf(ac, sizeof(ac), "The operation read %lu bytes from file.\n",
NumBytesRead);
FS_X_Log(ac);
}
FS_FClose(pFile);
}
}
Error codes
Description
Values returned by the API functions to indicate the reason of an error.
Definition
#define FS_ERRCODE_OK 0
#define FS_ERRCODE_EOF (-1)
#define FS_ERRCODE_PATH_TOO_LONG (-2)
#define FS_ERRCODE_INVALID_PARA (-3)
#define FS_ERRCODE_WRITE_ONLY_FILE (-5)
#define FS_ERRCODE_READ_ONLY_FILE (-6)
#define FS_ERRCODE_READ_FAILURE (-7)
#define FS_ERRCODE_WRITE_FAILURE (-8)
#define FS_ERRCODE_FILE_IS_OPEN (-9)
#define FS_ERRCODE_PATH_NOT_FOUND (-10)
#define FS_ERRCODE_FILE_DIR_EXISTS (-11)
#define FS_ERRCODE_NOT_A_FILE (-12)
#define FS_ERRCODE_TOO_MANY_FILES_OPEN (-13)
#define FS_ERRCODE_INVALID_FILE_HANDLE (-14)
#define FS_ERRCODE_VOLUME_NOT_FOUND (-15)
#define FS_ERRCODE_READ_ONLY_VOLUME (-16)
#define FS_ERRCODE_VOLUME_NOT_MOUNTED (-17)
#define FS_ERRCODE_NOT_A_DIR (-18)
#define FS_ERRCODE_FILE_DIR_NOT_FOUND (-19)
#define FS_ERRCODE_NOT_SUPPORTED (-20)
#define FS_ERRCODE_CLUSTER_NOT_FREE (-21)
#define FS_ERRCODE_INVALID_CLUSTER_CHAIN (-22)
#define FS_ERRCODE_STORAGE_NOT_PRESENT (-23)
#define FS_ERRCODE_BUFFER_NOT_AVAILABLE (-24)
#define FS_ERRCODE_STORAGE_TOO_SMALL (-25)
#define FS_ERRCODE_STORAGE_NOT_READY (-26)
#define FS_ERRCODE_BUFFER_TOO_SMALL (-27)
#define FS_ERRCODE_INVALID_FS_FORMAT (-28)
#define FS_ERRCODE_INVALID_FS_TYPE (-29)
#define FS_ERRCODE_FILENAME_TOO_LONG (-30)
#define FS_ERRCODE_VERIFY_FAILURE (-31)
#define FS_ERRCODE_VOLUME_FULL (-32)
#define FS_ERRCODE_DIR_NOT_EMPTY (-33)
#define FS_ERRCODE_IOCTL_FAILURE (-34)
#define FS_ERRCODE_INVALID_MBR (-35)
#define FS_ERRCODE_OUT_OF_MEMORY (-36)
#define FS_ERRCODE_UNKNOWN_DEVICE (-37)
#define FS_ERRCODE_ASSERT_FAILURE (-38)
#define FS_ERRCODE_TOO_MANY_TRANSACTIONS_OPEN (-39)
#define FS_ERRCODE_NO_OPEN_TRANSACTION (-40)
#define FS_ERRCODE_INIT_FAILURE (-41)
#define FS_ERRCODE_FILE_TOO_LARGE (-42)
#define FS_ERRCODE_INVALID_CONFIG (-43)
#define FS_ERRCODE_INVALID_USAGE (-44)
#define FS_ERRCODE_TOO_MANY_INSTANCES (-45)
#define FS_ERRCODE_TRANSACTION_ABORTED (-46)
#define FS_ERRCODE_INVALID_CHAR (-47)
#define FS_ERRCODE_INVALID_GPT (-48)
#define FS_ERRCODE_INVALID_CONTENT (-49)
#define FS_ERRCODE_COMPRESS_FAILURE (-50)
#define FS_ERRCODE_CRYPT_FAILURE (-51)
#define FS_ERRCODE_INVALID_DIR (-52)
#define FS_ERRCODE_DEFECTIVE_STORAGE (-53)
#define FS_ERRCODE_ERASE_FAILURE (-54)
#define FS_ERRCODE_PERMANENT_FAILURE (-55)
Symbols
Definition | Description |
FS_ERRCODE_OK | No error |
FS_ERRCODE_EOF | End of file reached |
FS_ERRCODE_PATH_TOO_LONG | Path to file or directory is too long |
FS_ERRCODE_INVALID_PARA | Invalid parameter passed |
FS_ERRCODE_WRITE_ONLY_FILE | File can only be written |
FS_ERRCODE_READ_ONLY_FILE | File can not be written |
FS_ERRCODE_READ_FAILURE | Error while reading from storage device |
FS_ERRCODE_WRITE_FAILURE | Error while writing to storage device |
FS_ERRCODE_FILE_IS_OPEN | Trying to delete a file which is open |
FS_ERRCODE_PATH_NOT_FOUND | Path to file or directory not found |
FS_ERRCODE_FILE_DIR_EXISTS | File or directory already exists |
FS_ERRCODE_NOT_A_FILE | Trying to open a directory instead of a file |
FS_ERRCODE_TOO_MANY_FILES_OPEN | Exceeded number of files opened at once |
FS_ERRCODE_INVALID_FILE_HANDLE | The file handle has been invalidated |
FS_ERRCODE_VOLUME_NOT_FOUND | The volume name specified in a path is does not exist |
FS_ERRCODE_READ_ONLY_VOLUME | Trying to write to a volume mounted in read-only mode |
FS_ERRCODE_VOLUME_NOT_MOUNTED | Trying access a volume which is not mounted |
FS_ERRCODE_NOT_A_DIR | Trying to open a file instead of a directory |
FS_ERRCODE_FILE_DIR_NOT_FOUND | File or directory not found |
FS_ERRCODE_NOT_SUPPORTED | Functionality not supported |
FS_ERRCODE_CLUSTER_NOT_FREE | Trying to allocate a cluster which is not free |
FS_ERRCODE_INVALID_CLUSTER_CHAIN | Detected a shorter than expected cluster chain |
FS_ERRCODE_STORAGE_NOT_PRESENT | Trying to access a removable storage which is not inserted |
FS_ERRCODE_BUFFER_NOT_AVAILABLE | No more sector buffers available |
FS_ERRCODE_STORAGE_TOO_SMALL | Not enough sectors on the storage device |
FS_ERRCODE_STORAGE_NOT_READY | Storage device can not be accessed |
FS_ERRCODE_BUFFER_TOO_SMALL | Sector buffer smaller than sector size of storage device |
FS_ERRCODE_INVALID_FS_FORMAT | Storage device is not formatted or the format is not valid |
FS_ERRCODE_INVALID_FS_TYPE | Type of file system is invalid or not configured |
FS_ERRCODE_FILENAME_TOO_LONG | The name of the file is too long |
FS_ERRCODE_VERIFY_FAILURE | Data verification failure |
FS_ERRCODE_VOLUME_FULL | No more space on storage device |
FS_ERRCODE_DIR_NOT_EMPTY | Trying to delete a directory which is not empty |
FS_ERRCODE_IOCTL_FAILURE | Error while executing a driver control command |
FS_ERRCODE_INVALID_MBR | Invalid information in the Master Boot Record |
FS_ERRCODE_OUT_OF_MEMORY | Could not allocate memory |
FS_ERRCODE_UNKNOWN_DEVICE | Storage device is not configured |
FS_ERRCODE_ASSERT_FAILURE | FS_DEBUG_ASSERT() macro failed |
FS_ERRCODE_TOO_MANY_TRANSACTIONS_OPEN | Maximum number of opened journal transactions exceeded |
FS_ERRCODE_NO_OPEN_TRANSACTION | Trying to close a journal transaction which is not opened |
FS_ERRCODE_INIT_FAILURE | Error while initializing the storage medium |
FS_ERRCODE_FILE_TOO_LARGE | Trying to write to a file which is larger than 4 Gbytes |
FS_ERRCODE_INVALID_CONFIG | The file system is not configured correctly |
FS_ERRCODE_INVALID_USAGE | Trying to call a function in an invalid state |
FS_ERRCODE_TOO_MANY_INSTANCES | Trying to create one instance more than maximum configured |
FS_ERRCODE_TRANSACTION_ABORTED | A journal transaction has been stopped by the application |
FS_ERRCODE_INVALID_CHAR | Invalid character in the name of a file |
FS_ERRCODE_INVALID_GPT | Invalid information in the GUID partition |
FS_ERRCODE_INVALID_CONTENT | The content of a file is invalid |
FS_ERRCODE_COMPRESS_FAILURE | Error while compressing or decompressing the data |
FS_ERRCODE_CRYPT_FAILURE | Error while encrypting or decrypting the data |
FS_ERRCODE_INVALID_DIR | Invalid directory contents |
FS_ERRCODE_DEFECTIVE_STORAGE | Storage device is not working properly |
FS_ERRCODE_ERASE_FAILURE | Error while erasing a storage device block |
FS_ERRCODE_PERMANENT_FAILURE | Processing disabled because of a critical error |
Additional information
The last error code of an file handle can be checked using FS_FError().
Configuration checking functions
The functions described in this section are useful to check at runtime how
the file system has been configured at compile time.
FS_CONF_GetDebugLevel()
Description
Returns the level of debug information configured for the file system.
Prototype
int FS_CONF_GetDebugLevel(void);
Return value
Value of FS_DEBUG_LEVEL configuration define.
FS_CONF_GetDirectoryDelimiter()
Description
Returns the character that is configured as delimiter between
the directory names in a file path.
Prototype
char FS_CONF_GetDirectoryDelimiter(void);
Return value
Value of FS_DIRECTORY_DELIMITER configuration define.
Example
#include <stdio.h>
#include "FS.h"
void SampleCONFGetDirectoryDelimiter(void) {
char ac[100];
char Delim;
Delim = FS_CONF_GetDirectoryDelimiter();
SEGGER_snprintf(ac, sizeof(ac),
"The '%c' character is used to delimit directory names in a path\n", Delim);
FS_X_Log(ac);
}
FS_CONF_GetMaxPath()
Description
Returns the configured maximum number of characters in a path to a file or directory.
Prototype
int FS_CONF_GetMaxPath(void);
Return value
Value of FS_MAX_PATH configuration define.
Example
#include <stdio.h>
#include "FS.h"
void SampleCONFGetMaxPath(void) {
char ac[100];
int NumChars;
NumChars = FS_CONF_GetMaxPath();
SEGGER_snprintf(ac, sizeof(ac),
"The maximum number of characters in the path is: %d\n", NumChars);
FS_X_Log(ac);
}
FS_CONF_GetNumVolumes()
Description
Returns the maximum number of volumes configured for the file system.
Prototype
int FS_CONF_GetNumVolumes(void);
Return value
Returns the value of FS_NUM_VOLUMES configuration define.
Example
#include <stdio.h>
#include "FS.h"
void SampleCONFGetNumVolumes(void) {
char ac[100];
int NumVolumes;
NumVolumes = FS_CONF_GetNumVolumes();
SEGGER_snprintf(ac, sizeof(ac),
"The maximum number of supported by Journal: %d\n", NumVolumes);
FS_X_Log(ac);
}
FS_CONF_GetOSLocking()
Description
Returns the type of task locking configured for the file system.
Prototype
int FS_CONF_GetOSLocking(void);
Return value
Value of FS_OS_LOCKING configuration define.
Example
#include "FS.h"
void SampleCONFGetOSLocking(void) {
int LockingType;
LockingType = FS_CONF_GetOSLocking();
switch (LockingType) {
case FS_OS_LOCKING_NONE:
FS_X_Log("The file system is not locked against concurrent access.\n");
break;
case FS_OS_LOCKING_API:
FS_X_Log("The file system is locked at API function level.\n");
break;
case FS_OS_LOCKING_DRIVER:
FS_X_Log("The file system is locked at device driver level.\n");
break;
default:
FS_X_Log("The type of locking is unknown.\n");
break;
}
}
FS_CONF_IsCacheSupported()
Description
Checks if the file system is configured to support the sector cache.
Prototype
int FS_CONF_IsCacheSupported(void);
Return value
Value of FS_SUPPORT_CACHE configuration define.
Additional information
This function does not check if the sector cache is actually active.
It only indicates if the file system has been compiled with support
for sector cache. The sector cache has to be activated via
FS_AssignCache().
Example
#include "FS.h"
void SampleCONFIsCacheSupported(void) {
int IsSupported;
IsSupported = FS_CONF_IsCacheSupported();
if (IsSupported) {
FS_X_Log("The sector cache is supported.\n");
} else {
FS_X_Log("The sector cache is not supported.\n");
}
}
FS_CONF_IsDeInitSupported()
Description
Checks if the file system is configured to support deinitialization.
Prototype
int FS_CONF_IsDeInitSupported(void);
Return value
Value of FS_SUPPORT_DEINIT configuration define.
Example
#include "FS.h"
void SampleCONFIsDeInitSupported(void) {
int IsSupported;
IsSupported = FS_CONF_IsDeInitSupported();
if (IsSupported) {
FS_X_Log("File system deinitialization is supported.\n");
} else {
FS_X_Log("File system deinitialization is not supported.\n");
}
}
FS_CONF_IsEFSSupported()
Description
Checks if the file system is configured to support the EFS file system.
Prototype
int FS_CONF_IsEFSSupported(void);
Return value
Value of FS_SUPPORT_EFS configuration define.
Example
#include "FS.h"
void SampleCONFIsEFSSupported(void) {
int IsSupported;
IsSupported = FS_CONF_IsEFSSupported();
if (IsSupported) {
FS_X_Log("The file system supports EFS.\n");
} else {
FS_X_Log("The file system does not support EFS.\n");
}
}
FS_CONF_IsEncryptionSupported()
Description
Checks if the file system is configured to support encryption.
Prototype
int FS_CONF_IsEncryptionSupported(void);
Return value
Value of FS_SUPPORT_ENCRYPTION configuration define.
Example
#include "FS.h"
void SampleCONFIsEncryptionSupported(void) {
int IsSupported;
IsSupported = FS_CONF_IsEncryptionSupported();
if (IsSupported) {
FS_X_Log("The file system supports encryption.\n");
} else {
FS_X_Log("The file system does not support encryption.\n");
}
}
FS_CONF_IsFATSupported()
Description
Checks if the file system is configured to support the FAT file system.
Prototype
int FS_CONF_IsFATSupported(void);
Return value
Value of FS_SUPPORT_FAT configuration define.
Example
#include "FS.h"
void SampleCONFIsFATSupported(void) {
int IsSupported;
IsSupported = FS_CONF_IsFATSupported();
if (IsSupported) {
FS_X_Log("The file system supports FAT.\n");
} else {
FS_X_Log("The file system does not support FAT.\n");
}
}
FS_CONF_IsFreeSectorSupported()
Description
Checks if the file system is configured to support the “free sector” command.
Prototype
int FS_CONF_IsFreeSectorSupported(void);
Return value
Value of FS_SUPPORT_FREE_SECTOR configuration define.
Example
#include "FS.h"
void SampleCONFIsFreeSectorSupported(void) {
int IsSupported;
IsSupported = FS_CONF_IsFreeSectorSupported();
if (IsSupported) {
FS_X_Log("The file system supports \"free sector\" operation.\n");
} else {
FS_X_Log("The file system does not support \"free sector\" operation.\n");
}
}
FS_CONF_IsJournalSupported()
Description
Checks if the file system is configured to support journaling.
Prototype
int FS_CONF_IsJournalSupported(void);
Return value
Value of FS_SUPPORT_JOURNAL configuration define.
Example
#include "FS.h"
void SampleCONFIsJournalSupported(void) {
int IsSupported;
IsSupported = FS_CONF_IsJournalSupported();
if (IsSupported) {
FS_X_Log("The file system supports journaling.\n");
} else {
FS_X_Log("The file system does not support journaling.\n");
}
}
FS_CONF_IsTrialVersion()
Description
Checks if the file system has been configured as a trial (limited) version.
Prototype
int FS_CONF_IsTrialVersion(void);
Return value
= 0 | Full version. |
≠ 0 | Trial version. |
Example
#include "FS.h"
void SampleCONFIsTrialVersion(void) {
int IsTrial;
IsTrial = FS_CONF_IsTrialVersion();
if (IsTrial) {
FS_X_Log("This is a trial version of emFile.\n");
} else {
FS_X_Log("This is a full-featured version of emFile.\n");
}
}
FS_GetVersion()
Description
Returns the version number of the file system.
Prototype
U32 FS_GetVersion(void);
Return value
Version number.
Additional information
The version is formatted as follows:
Mmmrr
where:
- M the major version number
- mm the minor version number
- rr the revision number
For example 40201 represents the version 4.02a (major version: 4,
minor version: 2, revision: a)
Example
#include <stdio.h>
#include "FS.h"
void SampleGetVersion(void) {
int Version;
int MajorVersion;
int MinorVersion;
char PatchVersion;
char ac[100];
Version = FS_GetVersion();
MajorVersion = Version / 10000;
MinorVersion = Version / 100 % 100;
PatchVersion = Version % 100;
SEGGER_snprintf(ac, sizeof(ac), "This is the version %d.%d.%d of emFile.\n",
MajorVersion, MinorVersion, PatchVersion);
FS_X_Log(ac);
}
Path processing functions
This section described functions that can be used to manipulate
a path to a file or directory.
FS_GetPathBaseName()
Description
Returns the name of the target file or directory with the extension removed.
Prototype
int FS_GetPathBaseName(const char * sPath,
char * pBaseName,
unsigned SizeOfBaseName);
Parameters
Parameter | Description |
sPath | in Path to the file or directory (0-terminated string). It cannot be set to NULL. |
pBaseName | out The basename of the file or directory as 0-terminated string. It can be set to NULL. |
SizeOfBaseName | Number of bytes in pBaseName. It can be set to 0. |
Return value
> 0 | Length of the basename in bytes. |
< 0 | An error occurred. |
Additional information
The function returns the length of the basename excluding the 0-terminator
irrespective of whether pBaseName is sufficiently large to store the basename or not.
If pBaseName is not sufficiently large to store the basename including the 0-terminator,
then the basename stored in pBaseName is truncated. The application can check for
this condition by comparing the returned value with the value of SizeOfBaseName.
If the returned value is greater than or equal to SizeOfBaseName,
then the basename stored to pBaseName is truncated. In any of the above cases,
the basename stored to pBaseName is 0-terminated.
The following tables show some usage examples.
Parameter | Value |
sPath | “nor:1:/SubDir” |
pBaseName | “SubDir” |
SizeOfBaseName | ≥ 7 |
Result | 6 |
Parameter | Value |
sPath | “SubDir/File.txt” |
pBaseName | “File” |
SizeOfBaseName | ≥ 5 |
Result | 4 |
Parameter | Value |
sPath | “nand:0:/SubDir/File.txt” |
pBaseName | “File” |
SizeOfBaseName | ≥ 5 |
Result | 4 |
Parameter | Value |
sPath | “File.txt” |
pBaseName | “File” |
SizeOfBaseName | ≥ 5 |
Result | 4 |
Parameter | Value |
sPath | “ram:1:/SubDir/” |
pBaseName | “” |
SizeOfBaseName | ≥ 1 |
Result | 0 |
Parameter | Value |
sPath | “File.old.txt” |
pBaseName | “File.old” |
SizeOfBaseName | ≥ 9 |
Result | 8 |
Parameter | Value |
sPath | “File.txt” |
pBaseName | “Fi” |
SizeOfBaseName | = 3 |
Result | 4 |
Example
#include "FS.h"
void SampleGetPathBaseName(void) {
char acBaseName[32];
FS_GetPathBaseName("nand:0:\\SubDir\\File.txt", acBaseName, sizeof(acBaseName));
}
FS_GetPathDirName()
Description
Returns the path to a target file or directory with the volume name,
base name, and extension removed.
Prototype
int FS_GetPathDirName(const char * sPath,
char * pDirName,
unsigned SizeOfDirName);
Parameters
Parameter | Description |
sPath | in Path to the file or directory (0-terminated string). It cannot be set to NULL. |
pDirName | out The path to the file or directory as 0-terminated string. It can be set to NULL. |
SizeOfDirName | Number of bytes in pDirName. It can be set to 0. |
Return value
> 0 | Length of the directory name in bytes. |
< 0 | An error occurred. |
Additional information
The function returns the length of the directory name excluding the 0-terminator
irrespective of whether pDirName is sufficiently large to store the directory name or not.
If pDirName is not sufficiently large to store the directory name including the 0-terminator,
then the directory name stored in pDirName is truncated. The application can check for
this condition by comparing the returned value with the value of SizeOfDirName.
If the returned value is greater than or equal to SizeOfDirName,
then the directory name stored to pDirName is truncated. In any of the above cases,
the directory name stored to pDirName is 0-terminated.
The following tables show some usage examples.
Parameter | Value |
sPath | “SubDir/File.txt” |
pDirName | “SubDir/” |
SizeOfDirName | ≥ 8 |
Result | 7 |
Parameter | Value |
sPath | “nand:0:/SubDir/File.txt” |
pDirName | “/SubDir/” |
SizeOfDirName | ≥ 9 |
Result | 8 |
Parameter | Value |
sPath | “File.txt” |
pDirName | “” |
SizeOfDirName | ≥ 1 |
Result | 0 |
Parameter | Value |
sPath | “ram:1:/SubDir/” |
pDirName | “/SubDir/” |
SizeOfDirName | ≥ 9 |
Result | 8 |
Parameter | Value |
sPath | “/SubDir1/SubDir2/SubDir3” |
pDirName | “/SubDir1/SubDir2/” |
SizeOfDirName | ≥ 18 |
Result | 17 |
Parameter | Value |
sPath | “nor:SubDir” |
pDirName | “/” |
SizeOfDirName | ≥ 2 |
Result | 1 |
Parameter | Value |
sPath | “ram:1:/SubDir/” |
pDirName | “/SubDi” |
SizeOfDirName | = 7 |
Result | 7 |
Example
#include "FS.h"
void SampleGetPathDirName(void) {
char acDirName[32];
FS_GetPathDirName("ram:1:\\SubDir\\Test.txt", acDirName, sizeof(acDirName));
}
FS_GetPathExtension()
Description
Returns the extension of a file or directory.
Prototype
int FS_GetPathExtension(const char * sPath,
char * pExtension,
unsigned SizeOfExtension);
Parameters
Parameter | Description |
sPath | in Path to the file or directory (0-terminated string). It cannot be set to NULL. |
pExtension | out The extension of the file or directory as 0-terminated string. It can be set to NULL. |
SizeOfExtension | Number of bytes in pExtension. It can be set to 0. |
Return value
> 0 | Length of the extension in bytes. |
< 0 | An error occurred. |
Additional information
The function returns the length of the extension excluding the 0-terminator
irrespective of whether pExtension is sufficiently large to store the extension or not.
If pExtension is not sufficiently large to store the extension including the 0-terminator,
then the extension stored in pExtension is truncated. The application can check for
this condition by comparing the returned value with the value of SizeOfExtension.
If the returned value is greater than or equal to SizeOfExtension,
then the extension stored to pExtension is truncated. In any of the above cases,
the extension stored to pExtension is 0-terminated and contains the leading point.
The following tables show some usage examples.
Parameter | Value |
sPath | “nor:1:/SubDir” |
pExtension | “” |
SizeOfExtension | ≥ 1 |
Result | 0 |
Parameter | Value |
sPath | “SubDir/File.txt” |
pExtension | “.txt” |
SizeOfExtension | ≥ 5 |
Result | 4 |
Parameter | Value |
sPath | “nand:0:/SubDir/File.txt” |
pExtension | “.txt” |
SizeOfExtension | ≥ 5 |
Result | 4 |
Parameter | Value |
sPath | “File.old.txt” |
pExtension | “.txt” |
SizeOfExtension | ≥ 4 |
Result | 0 |
Parameter | Value |
sPath | “ram:1:/SubDir/” |
pExtension | “” |
SizeOfExtension | ≥ 1 |
Result | 0 |
Parameter | Value |
sPath | “File” |
pExtension | “” |
SizeOfExtension | ≥ 1 |
Result | 0 |
Parameter | Value |
sPath | “.txt” |
pExtension | “.txt” |
SizeOfExtension | ≥ 5 |
Result | 4 |
Parameter | Value |
sPath | “File.txt” |
pExtension | “.tx” |
SizeOfExtension | = 3 |
Result | 3 |
Example
#include "FS.h"
void SampleGetPathExtension(void) {
char acExtension[32];
FS_GetPathExtension("SubDir\\File.txt", acExtension, sizeof(acExtension));
}
FS_GetPathVolumeName()
Description
Returns the name of the volume from a path.
Prototype
int FS_GetPathVolumeName(const char * sPath,
char * pVolumeName,
unsigned SizeOfVolumeName);
Parameters
Parameter | Description |
sPath | in Path to the file or directory (0-terminated string). It cannot be set to NULL. |
pVolumeName | out The name of the volume as 0-terminated string. It can be set to NULL. |
SizeOfVolumeName | Number of bytes in pVolumeName. It can be set to 0. |
Return value
> 0 | Length of the volume name in bytes. |
< 0 | An error occurred. |
Additional information
The function returns the length of the volume name excluding the 0-terminator
irrespective of whether pVolumeName is sufficiently large to store the volume name or not.
If pVolumeName is not sufficiently large to store the volume name including the 0-terminator,
then the volume name stored in pVolumeName is truncated. The application can check for
this condition by comparing the returned value with the value of SizeOfVolumeName.
If the returned value is greater than or equal to SizeOfVolumeName,
then the volume name stored to pVolumeName is truncated. In any of the above cases,
the volume name stored to pVolumeName is 0-terminated.
The following tables show some usage examples.
Parameter | Value |
sPath | “nor:1:/SubDir” |
pVolumeName | “nor:1:” |
SizeOfVolumeName | ≥ 7 |
Result | 6 |
Parameter | Value |
sPath | “nand:0:/File.txt” |
pVolumeName | “nand:” |
SizeOfVolumeName | ≥ 6 |
Result | 5 |
Parameter | Value |
sPath | “SubDir/File.txt” |
pVolumeName | “” |
SizeOfVolumeName | ≥ 1 |
Result | 0 |
Parameter | Value |
sPath | “SubDir” |
pVolumeName | “” |
SizeOfVolumeName | ≥ 1 |
Result | 0 |
Parameter | Value |
sPath | “” |
pVolumeName | “” |
SizeOfVolumeName | ≥ 1 |
Result | 0 |
Parameter | Value |
sPath | “ram:0:” |
pVolumeName | “ram:0:” |
SizeOfVolumeName | ≥ 7 |
Result | 6 |
Parameter | Value |
sPath | “mmc:0” |
pVolumeName | “mmc:” |
SizeOfVolumeName | ≥ 5 |
Result | 5 |
Parameter | Value |
sPath | “/SubDir1/SubDir2/SubDir3” |
pVolumeName | “/SubDir1/SubDir2/” |
SizeOfVolumeName | ≥ 18 |
Result | 17 |
Parameter | Value |
sPath | “nor:SubDir” |
pVolumeName | “no” |
SizeOfVolumeName | = 3 |
Result | 3 |
Example
#include "FS.h"
void SampleGetPathVolumeName(void) {
char acVolumeName[32];
FS_GetPathVolumeName("ram:1:\\Test.txt", acVolumeName, sizeof(acVolumeName));
}
FS_MakePath()
Description
Creates a path to a file or directory from individual components.
Prototype
int FS_MakePath( char * pPath,
unsigned SizeOfPath,
const char * sVolumeName,
const char * sDirName,
const char * sBaseName,
const char * sExtension);
Parameters
Parameter | Description |
pPath | out Created path (0-terminated string). It can be set to NULL. |
SizeOfPath | Number of bytes in pPath. It can be set to 0. |
sVolumeName | in Volume name (0-terminated string) It can be set to NULL. |
sDirName | in Directory name (0-terminated string) It can be set to NULL. |
sBaseName | in Basename of file or directory (0-terminated string) It can be set to NULL. |
sExtension | in Extension of file or directory (0-terminated string) It can be set to NULL. |
Return value
> 0 | Length of the path in bytes. |
< 0 | An error occurred. |
Additional information
This function returns the length of the path excluding the 0-terminator
irrespective of whether pPath is sufficiently large to store the path or not.
If pPath is not sufficiently large to store the path including the 0-terminator,
then the path stored in pPath is truncated. The application can check for
this condition by comparing the returned value with the value of SizeOfPath.
If the returned value is greater than or equal to SizeOfPath,
then the path stored to pPath is truncated. In any of the above cases,
the path stored to pPath is 0-terminated.
FS_MakePath() adds missing volume, directory and extension delimiters.
The following tables show some usage examples.
Parameter | Value |
sVolumeName | “nor:0:” |
sDirName | “/SubDir/” |
sBaseName | “File” |
sExtension | “.txt” |
pPath | “nor:0:/SubDir/File.txt” |
SizeOfPath | ≥ 23 |
Result | 22 |
Parameter | Value |
sVolumeName | “nand:0:” |
sDirName | “SubDir” |
sBaseName | NULL |
sExtension | NULL |
pPath | “nand:0:/SubDir/” |
SizeOfPath | ≥ 16 |
Result | 15 |
Parameter | Value |
sVolumeName | NULL |
sDirName | “SubDir” |
sBaseName | NULL |
sExtension | NULL |
pPath | “SubDir/” |
SizeOfPath | ≥ 8 |
Result | 7 |
Parameter | Value |
sVolumeName | NULL |
sDirName | “/SubDir” |
sBaseName | “File” |
sExtension | “.txt” |
pPath | “/SubDir/File.txt” |
SizeOfPath | ≥ 17 |
Result | 16 |
Parameter | Value |
sVolumeName | NULL |
sDirName | “/SubDir1/SubDir2” |
sBaseName | “SubDir3” |
sExtension | NULL |
pPath | “/SubDir1/SubDir2/SubDir3” |
SizeOfPath | ≥ 25 |
Result | 24 |
Parameter | Value |
sVolumeName | NULL |
sDirName | NULL |
sBaseName | “File.old” |
sExtension | “txt” |
pPath | “File.old.txt” |
SizeOfPath | ≥ 13 |
Result | 12 |
Parameter | Value |
sVolumeName | “ram” |
sDirName | NULL |
sBaseName | “File” |
sExtension | “.txt” |
pPath | “ram:/File.txt” |
SizeOfPath | ≥ 14 |
Result | 13 |
Parameter | Value |
sVolumeName | “ram” |
sDirName | NULL |
sBaseName | “File” |
sExtension | “.txt” |
pPath | “ram:/File.tx” |
SizeOfPath | = 13 |
Result | 13 |
Example
#include "FS.h"
void SampleMakePath(void) {
char acPath[FS_MAX_PATH];
FS_MakePath(acPath, sizeof(acPath), "nor:0:", "\\SubDir\\", "File", ".txt");
}
Obsolete functions
This section describes API functions that should no longer be used in new
applications. These functions will be removed in a future version of emFile.
FS_AddOnExitHandler()
Description
Registers a deinitialization callback.
Prototype
void FS_AddOnExitHandler(FS_ON_EXIT_CB * pCB,
void ( *pfOnExit)());
Parameters
Parameter | Description |
pCB | in Structure holding the callback information. |
pfOnExit | Pointer to the callback function to be invoked. |
Additional information
The pCB memory location is used internally by the file system
and it should remain valid from the time the handler is registered
until the FS_DeInit() function is called. The FS_DeInit() function
invokes all the registered callback functions in reversed order
that is the last registered function is called first.
In order to use this function the binary compile time
switch FS_SUPPORT_DEINIT has to be set to 1.
FS_CloseDir()
Description
Closes a directory.
Prototype
int FS_CloseDir(FS_DIR * pDir);
Parameters
Parameter | Description |
pDir | Handle to an opened directory. |
Return value
= 0 | Directory has been closed. |
≠ 0 | An error occurred. |
FS_ConfigOnWriteDirUpdate()
Description
Configures if the directory entry has be updated after writing
to file.
Prototype
void FS_ConfigOnWriteDirUpdate(char OnOff);
Parameters
Parameter | Description |
OnOff | Specifies if the feature has to be enabled or disabled. 1 Enable update directory after write. 0 Do not update directory. FS_FClose() updates the directory entry. |
FS_DirEnt2Attr()
Description
Loads attributes of a directory entry.
Prototype
void FS_DirEnt2Attr(FS_DIRENT * pDirEnt,
U8 * pAttr);
Parameters
Parameter | Description |
pDirEnt | in Data of directory entry. |
pAttr | out Pointer to a memory location that receives the attributes. |
FS_DirEnt2Name()
Description
Loads the name of a directory entry.
Prototype
void FS_DirEnt2Name(FS_DIRENT * pDirEnt,
char * pBuffer);
Parameters
Parameter | Description |
pDirEnt | in Data of directory entry. |
pBuffer | out Pointer to a memory location that receives the name. |
FS_DirEnt2Size()
Description
Loads the size of a directory entry.
Prototype
U32 FS_DirEnt2Size(FS_DIRENT * pDirEnt);
Parameters
Parameter | Description |
pDirEnt | in Data of directory entry. |
Return value
Size of the file or directory.
FS_DirEnt2Time()
Description
Loads the time stamp of a directory entry.
Prototype
U32 FS_DirEnt2Time(FS_DIRENT * pDirEnt);
Parameters
Parameter | Description |
pDirEnt | in Data of directory entry. |
Return value
Time stamp of the file or directory.
FS_GetNumFiles()
Description
API function. Returns the number of files in a directory.
Prototype
U32 FS_GetNumFiles(FS_DIR * pDir);
Parameters
Parameter | Description |
pDir | Pointer to an opened directory handle. |
Return value
0xFFFFFFFF Indicates failure.
0 - 0xFFFFFFFE File size of the given file.
FS_OpenDir()
Description
API function. Open an existing directory for reading.
Prototype
FS_DIR *FS_OpenDir(const char * sDirName);
Parameters
Parameter | Description |
sDirName | Fully qualified directory name. |
Return value
= 0 | Unable to open the directory. |
≠ 0 | Address of an FS_DIR data structure. |
FS_ReadDir()
Description
Reads next directory entry in directory.
Prototype
FS_DIRENT *FS_ReadDir(FS_DIR * pDir);
Parameters
Parameter | Description |
pDir | Handle to an opened directory. |
Return value
≠ 0 | Pointer to a directory entry. |
= 0 | No more directory entries or error. |
FS_RewindDir()
Description
Sets pointer for reading the next directory entry to
the first entry in the directory.
Prototype
void FS_RewindDir(FS_DIR * pDir);
Parameters
Parameter | Description |
pDir | Handle to an opened directory. |
Caching and buffering
This chapter gives an introduction into cache handling of emFile.
Furthermore, it contains the function description and an example.
Sector cache
The sector cache is a memory area where frequently used sector data can be
stored for fast access. In many cases, this can enhance the average access time
thus increasing the performance. With applications which do not use a cache,
data will always be read from the storage medium even if it has been used before.
The sector cache stores accessed and processed sector data. If the sector data
has to be processed again, it will be copied out of the cache instead of reading
it from the storage device. This condition is called “hit”. When the sector data
is not present in the sector cache and it has to be read from the storage device.
This condition is called “miss”. The sector cache works efficiently when the
number of hit conditions is greater than the number of miss conditions.
The number of hit and miss conditions can be queried using the
FS_STORAGE_GetCounters() function.
Write cache and journaling
The write back caching has to be disabled if the journaling is employed to make
the file system fail safe. The journaling will not work properly if the write
back cache (and generally any form of write cache) is enabled. More detailed
information can be found in the section Journaling and write caching.
Types of caches
emFile supports the usage of different cache modules as listed
in the following table:
FS_CACHE_ALL
This module is a pure read cache. All sectors that are read from a volume are
cached. The caching is enabled right after calling FS_AssignCache().
FS_CACHE_MAN
This module is also a pure read cache. In contrast to the FS_CACHE_ALL,
this module only caches the management sectors of the file system (for example,
the sectors of the allocation table). The caching is enabled right after calling
FS_AssignCache(). This type of cache is useful if the application is creating
and deleting a large number of files.
FS_CACHE_RW
This is a configurable cache module. It can be either used as read, write
or as read / write cache. Additionally, the type of sectors that has
to be cached are also configurable via FS_CACHE_SetMode().
FS_CACHE_RW_QUOTA
This is a configurable cache module. It can be either used as read, write
or as read / write cache. Additionally, the type of sectors and the maximum
number of sectors of a given type that can be cached at the same time are
configurable via FS_CACHE_SetMode() and FS_CACHE_SetQuota() respectively.
It is mandatory to call FS_CACHE_SetMode() and FS_CACHE_SetQuota(), otherwise
the functionality of the cache module is disabled.
FS_CACHE_MULTI_WAY
This is configurable cache module that can be used as read, write
or read / write cache. The type of sectors that should be cached and
the number of places in the cache where the data of a sector can be mapped
(associativity level) is configurable via FS_CACHE_SetMode()
and FS_CACHE_SetQuota() respectively. Per default, this cache works with
an associativity level of two.
Cache API functions
The following functions can be used to enable, configure and control
the emFile sector cache modules.
FS_AssignCache()
Description
Enables or disables a sector cache for a specific volume.
Prototype
U32 FS_AssignCache(const char * sVolumeName,
void * pData,
I32 NumBytes,
FS_CACHE_TYPE Type);
Parameters
Parameter | Description |
sVolumeName | Name of the volume on which the sector cache should be enabled / disabled. Cannot be NULL. |
pData | Pointer to a memory area that should be used as cache. |
NumBytes | Number of bytes in the memory area pointed by pData. |
Type | Specifies the type of the sector cache to be configured. It can take one of the following values: FS_CACHE_ALL FS_CACHE_MAN FS_CACHE_RW FS_CACHE_RW_QUOTA FS_CACHE_MULTI_WAY. |
Return value
> 0 | OK, Number of sectors which fit in cache. |
= 0 | An error occurred. The memory area cannot be used as sector cache. |
Additional information
The first configured volume is used if the empty string is specified
as sVolumeName.
To disable the cache for a specific device, call FS_AssignCache()
with NumBytes set to 0. In this case the function returns 0.
A range of the memory block assigned to the sector cache is used
to store the management data. The following defines can help an
application allocate a memory block sufficiently large to store
a specified number of logical sectors: FS_SIZEOF_CACHE_ALL(),
FS_SIZEOF_CACHE_MAN(), FS_SIZEOF_CACHE_RW(), FS_SIZEOF_CACHE_RW_QUOTA(),
or FS_SIZEOF_CACHE_MULTI_WAY().
Example
The following example demonstrates how to enable and then disable a sector
cache of type FS_CACHE_ALL.
#include "FS.h"
#define CACHE_SIZE FS_SIZEOF_CACHE_ALL(200, 512) // 200 sectors of 512 bytes.
static U32 _aCache[CACHE_SIZE / 4]; // Allocate RAM for the cache buffer.
void SampleCacheAssign(void) {
//
// Assign a read cache to the first configured storage device.
//
FS_AssignCache("", _aCache, sizeof(_aCache), FS_CACHE_ALL);
//
// Access the file system with sector cache.
//
//
// Disable the read cache.
//
FS_AssignCache("", 0, 0, 0);
}
FS_CACHE_Clean()
Description
Writes modified sector data to storage device.
Prototype
int FS_CACHE_Clean(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used. |
Return value
= 0 | OK, the sector cache was emptied successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function can be used to make sure that modifications made to
cached data are also committed to storage device.
Because only write or read / write caches need to be cleaned,
this function can only be called for volumes where FS_CACHE_RW,
FS_CACHE_RW_QUOTA, or FS_CACHE_MULTI_WAY module is assigned.
The other cache modules ignore the cache clean operation.
The cleaning of the cache is also performed when the volume
is unmounted via FS_Unmount() or when the cache is disabled
or reassigned via FS_AssignCache().
Example
#include "FS.h"
void SampleCacheClean(void) {
FS_CACHE_Clean("");
}
FS_CACHE_GetNumSectors()
Description
Obtains the size of the sector cache.
Prototype
int FS_CACHE_GetNumSectors(const char * sVolumeName,
U32 * pNumSectors);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used. |
pNumSectors | out Number of sectors that can be stored in the cache at the same time. It cannot be NULL. |
Return value
= 0 | OK, number of sectors in the sector cache. |
≠ 0 | An error occurred. |
Additional information
This function returns the number of sectors that can be stored
in the cache at the same time.
Example
#include "FS.h"
#include <stdio.h>
void SampleCacheGetNumSectors(void) {
U32 NumSectors;
char ac[100];
FS_CACHE_GetNumSectors("", &NumSectors);
SEGGER_snprintf(ac, sizeof(ac), "Number of sectors in cache: %lu\n", NumSectors);
FS_X_Log(ac);
}
FS_CACHE_GetType()
Description
Obtains the type of the configured sector cache.
Prototype
int FS_CACHE_GetType(const char * sVolumeName,
FS_CACHE_TYPE * pType);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used. |
pType | out Cache sector type. FS_CACHE_NONE No sector cache configured. FS_CACHE_ALL A pure read cache. FS_CACHE_MAN A pure read cache that caches only the management sectors. FS_CACHE_RW A read / write cache module. FS_CACHE_RW_QUOTA A read / write cache module with configurable capacity per sector type. FS_CACHE_MULTI_WAY A read / write cache module with configurable associativity level. |
Return value
= 0 | OK, type of sector cache returned. |
≠ 0 | Error code indicating the failure reason. |
FS_CACHE_Invalidate()
Description
Removes all sector data from cache.
Prototype
int FS_CACHE_Invalidate(const char * sVolumeName);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used. |
Return value
= 0 | OK, the sector cache was emptied successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function can be called to remove all the sectors from the
cache. FS_CACHE_Invalidate() does not write to storage modified
sector data. After calling FS_CACHE_Invalidate() the contents
of modified sector data is lost. FS_CACHE_Clean() has to be
called first to prevent a data loss.
Example
#include "FS.h"
void SampleCacheInvalidate(void) {
FS_CACHE_Invalidate("");
}
FS_CACHE_SetAssocLevel()
Description
Modifies the associativity level of multi-way cache.
Prototype
int FS_CACHE_SetAssocLevel(const char * sVolumeName,
int AssocLevel);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used. |
AssocLevel | Number of entries in the cache. It has to be a power of two value. |
Return value
= 0 | OK, associativity level set successfully. |
≠ 0 | Error code indicating the failure reason error occurred. |
Additional information
This function is supported only by the FS_CACHE_MULTI_WAY cache module.
An error is returned if the function is used with any other cache module.
The associativity level specifies on how many different places in the
cache the data of the same sector can be stored. The cache replacement
policy uses this information to decide where to store the contents of
a sector in the cache. Caches with higher associativity levels tend to
have higher hit rates. The default associativity level is two.
Example
The following example shows how to configure the FS_CACHE_MULTI_WAY cache module
to store the data of the same sector at 4 different places on the cache.
#include "FS.h"
void SampleCacheSetAssocLevel(void) {
FS_CACHE_SetAssocLevel("", 4);
}
FS_CACHE_SetMode()
Description
Sets the operating mode of sector cache.
Prototype
int FS_CACHE_SetMode(const char * sVolumeName,
int TypeMask,
int ModeMask);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used. |
TypeMask | Specifies the types of the sectors that have to be cached. This parameter can be an OR-combination of the Sector type masks (FS_SECTOR_TYPE_MASK_…) |
ModeMask | Specifies the operating mode of the cache module. This parameter can be one of the values defined as Sector cache modes (FS_CACHE_MODE_…) |
Return value
= 0 | OK, mode set successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function is supported by the following cache types: FS_CACHE_RW,
FS_CACHE_RW_QUOTA, and FS_CACHE_MULTI_WAY. These cache modules
have to be configured using this function otherwise, neither
read nor write operations are cached.
When configured in FS_CACHE_MODE_WB mode the cache module writes
the sector data automatically to storage device if free space
is required for new sector data. The application can call the
FS_CACHE_Clean() function at any time to write all the cache
sector data to storage device.
Example
The following example shows how to configure the FS_CACHE_MULTI_WAY cache module
to use a read cache for the data sectors, a write back cache for the management
and directory sectors.
#include "FS.h"
#define CACHE_SIZE FS_SIZEOF_CACHE_MULTI_WAY(200, 512)
static U32 _aCache[CACHE_SIZE / 4]; // Allocate RAM for the cache buffer.
void SampleCacheSetMode(void) {
//
// Assign a cache to the first available storage device.
//
FS_AssignCache("", _aCache, sizeof(_aCache), FS_CACHE_MULTI_WAY);
//
// Configure a read cache for the sectors that store file data.
//
FS_CACHE_SetMode("", FS_SECTOR_TYPE_MASK_DATA, FS_CACHE_MODE_R);
//
// Configure a write back cache for the sectors that store directory
// and allocation table entries.
//
FS_CACHE_SetMode("",
FS_SECTOR_TYPE_MASK_DIR | FS_SECTOR_TYPE_MASK_MAN,
FS_CACHE_MODE_WB);
//
// Access the file system with sector cache.
//
//
// Disable the cache.
//
FS_AssignCache("", 0, 0, FS_CACHE_NONE);
}
FS_CACHE_SetQuota()
Description
Sets the quotas of a specific sector cache.
Prototype
int FS_CACHE_SetQuota(const char * sVolumeName,
int TypeMask,
U32 NumSectors);
Parameters
Parameter | Description |
sVolumeName | Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used. |
TypeMask | Specifies the types of the sectors that have to be cached. This parameter can be an OR-combination of the Sector type masks (FS_SECTOR_TYPE_MASK_…) |
NumSectors | Specifies the maximum number of sectors to be stored for each sector type specified in TypeMask. |
Return value
= 0 | OK, maximum number of sectors set successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function is currently only usable with the FS_CACHE_RW_QUOTA
cache module. After the FS_CACHE_RW_QUOTA cache module has been
assigned to a volume and the cache mode has been set, the quotas
for the different sector types have to be configured using this
function. Otherwise, neither read nor write operations are cached.
Example
The following example shows how to configure the FS_CACHE_RW_QUOTA cache module
to limit the number of directory and data sector types to a maximum of 10 each.
#include "FS.h"
#define CACHE_SIZE FS_SIZEOF_CACHE_RW_QUOTA(200, 512)
static U32 _acCache[CACHE_SIZE / 4]; // Allocate RAM for the cache buffer.
void SampleCacheSetQuota(void) {
//
// Assign a cache to the first available storage device.
//
FS_AssignCache("", _acCache, sizeof(_acCache), FS_CACHE_RW_QUOTA);
//
// Configure the cache module to cache all sectors. The sector data is cached
// for read and write. Write operation to storage device are delayed.
//
FS_CACHE_SetMode("", FS_SECTOR_TYPE_MASK_ALL, FS_CACHE_MODE_WB);
//
// Set the maximum number of sectors to cache for directory
// and data sector types 10 sectors each.
//
FS_CACHE_SetQuota("", FS_SECTOR_TYPE_MASK_DATA | FS_SECTOR_TYPE_MASK_DIR, 10);
//
// Access the file system with sector cache.
//
//
// Make sure that the data is written to storage device.
//
FS_CACHE_Clean("");
//
// Perform other accesses to file system with sector cache.
//
//
// Disable the cache.
//
FS_AssignCache("", 0, 0, FS_CACHE_NONE);
}
Sector cache types
Description
Types of sector caches.
Definition
#define FS_CACHE_NONE NULL
#define FS_CACHE_ALL FS_CacheAll_Init
#define FS_CACHE_MAN FS_CacheMan_Init
#define FS_CACHE_RW FS_CacheRW_Init
#define FS_CACHE_RW_QUOTA FS_CacheRWQuota_Init
#define FS_CACHE_MULTI_WAY FS_CacheMultiWay_Init
Symbols
Definition | Description |
FS_CACHE_NONE | Pseudo-type that can be used to disable the sector cache. |
FS_CACHE_ALL | A pure read cache. |
FS_CACHE_MAN | A pure read cache that caches only the management sectors. |
FS_CACHE_RW | A read / write cache module. |
FS_CACHE_RW_QUOTA | A read / write cache module with configurable capacity per sector type. |
FS_CACHE_MULTI_WAY | A read / write cache module with configurable associativity level. |
Additional information
The type of a cache module can be configured via FS_AssignCache()
function when the sector cache is enabled for a specified volume.
Sector cache modes
Description
Operating modes of sector caches.
Definition
#define FS_CACHE_MODE_R 0x01u
#define FS_CACHE_MODE_WT (FS_CACHE_MODE_R | FS_CACHE_MODE_W)
#define FS_CACHE_MODE_WB (FS_CACHE_MODE_R | FS_CACHE_MODE_W | FS_CACHE_MODE_D)
Symbols
Definition | Description |
FS_CACHE_MODE_R | Pure read cache. |
FS_CACHE_MODE_WT | Write-through cache. |
FS_CACHE_MODE_WB | Write-back cache. |
Additional information
The operating mode of a cache module can be configured via
the FS_CACHE_SetMode() function separately for each sector type.
Sector cache size
Description
Calculates the cache size.
Definition
#define FS_SIZEOF_CACHE_ALL(NumSectors, SectorSize) (FS_SIZEOF_CACHE_ALL_DATA + \
(FS_SIZEOF_CACHE_ALL_BLOCK_INFO + \
(SectorSize)) * (NumSectors))
#define FS_SIZEOF_CACHE_MAN(NumSectors, SectorSize) (FS_SIZEOF_CACHE_MAN_DATA + \
(FS_SIZEOF_CACHE_MAN_BLOCK_INFO + \
(SectorSize)) * (NumSectors))
#define FS_SIZEOF_CACHE_RW(NumSectors, SectorSize) (FS_SIZEOF_CACHE_RW_DATA + \
(FS_SIZEOF_CACHE_RW_BLOCK_INFO + \
(SectorSize)) * (NumSectors))
#define FS_SIZEOF_CACHE_RW_QUOTA(NumSectors, SectorSize) (FS_SIZEOF_CACHE_RW_QUOTA_DATA + \
(FS_SIZEOF_CACHE_RW_QUOTA_BLOCK_INFO + \
(SectorSize)) * (NumSectors))
#define FS_SIZEOF_CACHE_MULTI_WAY(NumSectors, SectorSize) (FS_SIZEOF_CACHE_MULTI_WAY_DATA + \
(FS_SIZEOF_CACHE_MULTI_WAY_BLOCK_INFO + \
(SectorSize)) * (NumSectors))
#define FS_SIZEOF_CACHE_ANY(NumSectors, SectorSize) FS_SIZEOF_CACHE_RW_QUOTA(NumSectors, SectorSize)
Symbols
Definition | Description |
FS_SIZEOF_CACHE_ALL(NumSectors, | Calculates the cache size of a FS_CACHE_ALL cache module. |
FS_SIZEOF_CACHE_MAN(NumSectors, | Calculates the cache size of a FS_CACHE_MAN cache module. |
FS_SIZEOF_CACHE_RW(NumSectors, | Calculates the cache size of a FS_CACHE_RW cache module. |
FS_SIZEOF_CACHE_RW_QUOTA(NumSectors, | Calculates the cache size of a FS_CACHE_RW_QUOTA cache module. |
FS_SIZEOF_CACHE_MULTI_WAY(NumSectors, | Calculates the cache size of a FS_CACHE_MULTI_WAY cache module. |
FS_SIZEOF_CACHE_ANY(NumSectors, | Calculates the size of cache that works with any cache module. |
Additional information
These defines can be used to calculate the size of the memory
area to be assigned to a cache module based on the size of a
sector (SectorSize) and the number of sectors to be cached
(NumSectors). The sector size of a specific volume can be
queried via FS_GetVolumeInfo().
Sector data flags
Description
Type of data stored in a logical sector.
Definition
#define FS_SECTOR_TYPE_MASK_DATA (1u << FS_SECTOR_TYPE_DATA)
#define FS_SECTOR_TYPE_MASK_DIR (1u << FS_SECTOR_TYPE_DIR)
#define FS_SECTOR_TYPE_MASK_MAN (1u << FS_SECTOR_TYPE_MAN)
#define FS_SECTOR_TYPE_MASK_ALL (FS_SECTOR_TYPE_MASK_DATA | \
FS_SECTOR_TYPE_MASK_DIR | \
FS_SECTOR_TYPE_MASK_MAN)
#define FS_SECTOR_TYPE_COUNT 3u
Symbols
Definition | Description |
FS_SECTOR_TYPE_MASK_DATA | Sector that stores file data. |
FS_SECTOR_TYPE_MASK_DIR | Sector that stores directory entries. |
FS_SECTOR_TYPE_MASK_MAN | Sector that stores entries of the allocation table. |
FS_SECTOR_TYPE_MASK_ALL | All sector types. |
FS_SECTOR_TYPE_COUNT | Number of sector types (for internal use only) |
Additional information
These flags are typically used with the sector cache API functions
to specify the type of sector data for which a specified parameter
applies. The bit positions of the flags correspond to the values
defined via Sector data type
The listed performance values depend on the compiler options, the compiler
version, the used CPU, the storage medium and the defined cache size.
The performance values have been measured on a SEGGER emPower evaluation board
https://www.segger.com/evaluate-our-software/segger/empower/
using an SD card as storage device. The test application has been compiled
using SEGGER Embedded Studio IDE
https://www.segger.com/products/development-tools/embedded-studio/
but any other IDE can be used as well. The test application is provided in source
code and is located in the Application folder of the emFile shipment.
Description of the test
- Initialize the file system.
- Perform a high-level format if required.
- Create 50 files without a cache.
- Write the time which was required for creation in the terminal I/O window.
- Enable a read and write cache.
- Create 50 files with the enabled read and write cache.
- Write the time which was required for creation in the terminal I/O window.
- Flush the cache.
- Write the time which was required for flushing in the terminal I/O window.
- Disable the cache.
- Create again 50 files without a cache.
- Write the time which was required for creation in the terminal I/O window.
Terminal output
Start
High-level formatting
Cache disabled
Creation of 50 files took: 16 ms
Cache enabled
Creation of 50 files took: 2 ms
Cache flush took: 0 ms
Cache disabled
Creation of 50 files took: 57 ms
Finished
Source code
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : FS_SectorCache.c
Purpose : Demonstrates how to configure and use the sector cache.
Additional information:
Preparations:
Works out-of-the-box with any storage device.
Expected behavior:
Measures the time it takes to create a number of files with
and without the sector cache enabled. The results are output
on the debug console.
Sample output:
Start
Cache disabled
Creation of 50 files took: 60 ms
Cache enabled
Creation of 50 files took: 18 ms
Cache flush took: 0 ms
Cache disabled
Creation of 50 files took: 114 ms
Finished
*/
/*********************************************************************
*
* #include Section
*
**********************************************************************
*/
#include <string.h>
#include "FS.h"
#include "FS_OS.h"
#include "SEGGER.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#define VOLUME_NAME ""
#define NUM_FILES 32
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
static U32 _aCache[0x400];
static char _aacFileName[NUM_FILES][13];
static char _ac[128];
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _CreateFiles
*/
static void _CreateFiles(void) {
int i;
U32 Time;
FS_FILE * apFile[NUM_FILES];
Time = FS_X_OS_GetTime();
for (i = 0; i < NUM_FILES; i++) {
apFile[i] = FS_FOpen(&_aacFileName[i][0], "w");
#if ((FS_SUPPORT_FILE_BUFFER != 0) && (FS_SUPPORT_FILE_BUFFER_LIST != 0))
//
// A file buffer is not required for this test.
//
if (apFile[i] != NULL) {
if (FS_IsFileBufferSet(apFile[i]) != 0) {
(void)FS_UnsetFileBuffer(apFile[i]);
}
}
#endif // ((FS_SUPPORT_FILE_BUFFER != 0) && (FS_SUPPORT_FILE_BUFFER_LIST != 0))
}
Time = FS_X_OS_GetTime() - Time;
SEGGER_snprintf(_ac, (int)sizeof(_ac), "Creation of %d files took: %d ms\n", NUM_FILES, Time);
FS_X_Log(_ac);
for (i = 0; i < NUM_FILES; i++) {
(void)FS_FClose(apFile[i]);
}
}
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* MainTask
*/
#ifdef __cplusplus
extern "C" { /* Make sure we have C-declarations in C++ programs */
#endif
void MainTask(void);
#ifdef __cplusplus
}
#endif
void MainTask(void) {
int i;
U32 Time;
FS_X_Log("Start\n");
//
// Initialize file system
//
FS_Init();
//
// Check if low-level format is required
//
(void)FS_FormatLLIfRequired(VOLUME_NAME);
//
// Check if volume needs to be high level formatted.
//
if (FS_IsHLFormatted(VOLUME_NAME) == 0) {
FS_X_Log("High-level formatting\n");
(void)FS_Format(VOLUME_NAME, NULL);
}
//
// Prepare file names in advance.
//
for (i = 0; i < NUM_FILES; i++) {
SEGGER_snprintf(_aacFileName[i], (int)sizeof(_aacFileName[0]), "file%.2d.txt", i);
}
//
// Create and measure the time used to create the files with the cache enabled.
//
FS_X_Log("Cache disabled\n");
_CreateFiles();
//
// Create and measure the time used to create the files.
//
(void)FS_AssignCache(VOLUME_NAME, _aCache, (int)sizeof(_aCache), FS_CACHE_RW);
(void)FS_CACHE_SetMode(VOLUME_NAME, (int)FS_SECTOR_TYPE_MASK_ALL, (int)FS_CACHE_MODE_WB);
FS_X_Log("Cache enabled\n");
_CreateFiles();
Time = FS_X_OS_GetTime();
(void)FS_CACHE_Clean(VOLUME_NAME);
Time = FS_X_OS_GetTime() - Time;
SEGGER_snprintf(_ac, (int)sizeof(_ac), "Cache flush took: %d ms\n", Time);
FS_X_Log(_ac);
//
// Create and measure the time used to create the files with the cache disabled.
//
FS_X_Log("Cache disabled\n");
(void)FS_AssignCache(VOLUME_NAME, NULL, 0, FS_CACHE_NONE);
_CreateFiles();
FS_X_Log("Finished\n");
for(;;) {
;
}
}
/*************************** End of file ****************************/
File buffer
emFile comes with support for file buffer.
A file buffer is a small memory area assigned to an opened file where the
file system can store frequently accessed file data. Using a file buffer
can greatly increase the performance especially when the application has
to access small amounts of data.
The file buffer can be configured in different access modes. In read mode,
that is only the data that is read by the application from the file is stored
to file buffer or in read / write mode where the data read as well as the data
written by the application is stored to file buffer. The access modes can be
changed at runtime each time the file is opened via FS_SetFileBufferFlags()
or FS_SetFileBuffer().
The size of the file buffer is configurable either globally for all opened
files via FS_ConfigFileBufferDefault() or individually for each opened file
via FS_SetFileBuffer().
Device drivers
This chapter describes the file system components that provide access
to a storage device.
emFile has been designed to operate with any kind of storage device.
To use a specific type of storage device with emFile, a device
driver for that specific storage device is required. A device driver is a
file system component that provides block access to a storage device.
The device driver consists of basic I/O functions for accessing the storage
device and a global table that holds pointers to these functions.
The following table lists the device drivers available in emFile.
The two-letter combination “RO” in the driver identifier indicates
that the driver is not able to perform any write operations.
By default, the file system is not configured to access any particular storage
device. A device driver has to be added by the application by calling
FS_AddDevice() in FS_X_AddDevices(). The file system calls FS_X_AddDevices()
during the initialization to allow the application to configure the file system.
FS_AddDevice() takes as parameter a pointer to a the function table of the
particular device driver as specified in the “Identifier” column in the
table above. It is possible to add more than one device driver to the file
system if more than one storage device is present in the system or if the system
uses one storage device that is partitioned.
The file system assigns a volume to each device driver added by the application.
A volume is an internal structure that contains information about organization
of the storage device and how to access it. The application uses the volume name
as specified in the “Volume name” column in the table above to select a particular
storage device. The names of the volumes are fixed and cannot be changed by the
application.
If the same device driver is added to file system more than once, an unit number
is used to differentiate between them. The unit number is an optional part
of the volume name and it can be used by the application to access a specific
storage device. Most device driver functions as well as most of the underlying
hardware functions receive the unit number as the first parameter. If there are
for example tow NAND flash drivers which operate as two different NAND flash
devices, the first one is identified as unit 0, the second one as unit 1.
If there is just a single instance (as in most systems), the unit number
parameter can be ignored by the underlying hardware functions.
Hardware layer
Most of the device drivers require functions to access the hardware. This set of
functions is called hardware layer. The implementation of the hardware layer is
user responsibility. emFile comes with template and sample hardware layers
that can be used as a starting point in developing a new one.
The hardware layer can be implemented in two different ways:
- Polled mode
- Interrupt-driven mode
Polled mode
In the polled mode the software actively queries the completion of the I/O operation.
No operating system is required to implement the device driver in this way.
The following example to demonstrate the fundamentals of an polled-driven
hardware layer.
#include "FS.h"
/*********************************************************************
*
* _HW_Write
*
* Function description
* FS hardware layer function. Writes a specified number of bytes
* to storage device via DMA.
*/
static int _HW_Write(U8 Unit, const U8 * pData, int NumBytes) {
int r;
//
// Start transmission using DMA.
//
_StartDMAWrite(Unit, pData, NumBytes);
//
// Wait for the DMA operation to complete.
//
while (1) {
if (_IsDMAOperationCompleted()) {
r = 0; // OK, success.
break;
}
if (_IsDMAError()) {
r = 1; // Error, could not write data via DMA.
break;
}
}
return r;
}
Interrupt-driven mode
In the interrupt-driven mode the completion of an I/O operation is signaled through
an interrupt. This operating mode requires the support of an operating system.
The following example demonstrates the fundamentals of an interrupt-driven
hardware layer.
#include "FS.h"
#include "FS_OS.h"
/**********************************************************
*
* _IRQ_Handler
*
* Function description
* Handles the hardware interrupt. Has to be registered
* as interrupt service routine.
*/
static void _IRQ_Handler(void) {
//
// Disable further interrupts.
//
_DisableInterrupts();
//
// Signal (wake) the waiting task.
//
FS_X_OS_Signal();
}
/*********************************************************************
*
* _HW_Write
*
* Function description
* FS hardware layer function. Writes a specified number of bytes
* to storage device via DMA.
*/
static int _HW_Write(U8 Unit, const U8 * pData, int NumBytes) {
//
// Start transmission using DMA.
//
_StartDMAWrite(Unit, pData, NumBytes);
//
// Wait for the DMA operation to complete.
//
while (1) {
if (_IsDMAOperationCompleted()) {
r = 0; // OK, success.
break;
}
if (_IsDMAError()) {
r = 1; // Error, could not write data via DMA.
break;
}
//
// Wait for IRQ to signal the event and wake up the task.
//
r = FS_X_OS_Wait(TIMEOUT);
if (r) {
break; // Error, timeout expired.
}
}
}
RAM Disk driver
General information
The RAM disk driver supports the use of any type of volatile and non-volatile
RAM as storage. This includes the system memory as well as any RAM devices
connected serially via an SPI or I2C bus using FRAM, MRAM or any other
type of storage technology.
Two drivers for RAM storage are provided:
A file system configuration that uses the system memory as storage is
suitable for getting started using emFile because it does not require
any hardware access functions to be implemented. The RAM Disk driver is also
useful for testing the file system on a PC simulation.
Theory of operation
The RAM Disk driver stores the data of the logical sectors it receives from
file system without modification to the memory region configured by the application
via FS_RAMDISK_Configure(). The byte offset at which the data is stored is
calculated by multiplying the index of the logical sector by the size of a
logical sector. For example, the data of the logical sector with the index 7
is stored at the byte offset 7 * 512 = 3584 assuming that the size of the logical
sector is 512 bytes.
Fail-safe operation
Typically, all the file system data lost in case of an unexpected power loss
if a volatile RAM device or the system memory without battery backup is used
as storage. battery backup. For this reason, the fail-safety is relevant only
for file system configurations that use a non-volatile RAM as storage.
Unexpected reset
In case of an unexpected reset the data will be preserved. However, if the
unexpected reset interrupts a write operation, the data of the sector may
contain partially invalid data.
Power failure
A power failure causes an unexpected reset and has the same effects.
Wear leveling
Typically, a RAM storage does now wear out therefore the RAM Disk driver
does not perform any wear leveling.
The storage used by the RAM Disk driver has to be formatted after each
each startup of the system because its contents is typically lost.
Exceptions to this are file system configurations that use as storage
a system memory that is backed up via a battery or a non-volatile RAM
device connected serially to the MCU.
The application has to format the storage via FS_Format() before
it can store data on it. If the application adds only one RAM Disk driver to
file system, FS_Format() can be called with an empty string as volume name.
For example, FS_Format(“”, NULL). If more than one RAM Disk driver
is added to file system, a the volume name has to be specified. For example,
FS_Format(“ram:0:”, NULL) for the first storage device and
FS_Format(“ram:1:”, NULL) for the second.
System RAM Disk driver
This section describes the RAM Disk driver that can use the system memory as storage.
Supported hardware
The System RAM Disk driver can be used on any target hardware that has
sufficient system memory to be used as storage.
Configuring the driver
The application has to add the System RAM Disk driver to the file system before
using it. This is done by calling FS_AddDevice() in FS_X_AddDevices() with
the parameter set to the function table of the System RAM Disk driver FS_RAMDISK_Driver.
The maximum number of System RAM Disk driver instances that can be added to file
system can be configured a compile-time using the FS_RAMDISK_MAX_NUM_UNITS
configuration define. By default, a maximum number of four System RAM Disk driver
instances can be added to file system.
The application has to call FS_RAMDISK_Configure() for each driver instance
to configure the range of the system memory to be used as storage.
The specified memory range can be located on any system memory that is accessible
to the CPU.
Example
#include <FS.h>
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#define ALLOC_SIZE 0x1100 // Memory pool for the file system in bytes
#define NUM_SECTORS 16 // Number of sectors on the RAM storage
#define BYTES_PER_SECTOR 512 // Size of a sector in bytes
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
//
// Memory pool used for semi-dynamic allocation.
//
static U32 _aMemBlock[ALLOC_SIZE / 4];
//
// Memory to be used as storage.
//
static U32 _aRAMDisk[(NUM_SECTORS * BYTES_PER_SECTOR) / 4];
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* 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().
*
* Note
* (1) Other API functions may NOT be called, since this function is called
* during initialization. The devices are not yet ready at this point.
*/
void FS_X_AddDevices(void) {
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Add and configure the driver.
//
FS_AddDevice(&FS_RAMDISK_Driver);
FS_RAMDISK_Configure(0, _aRAMDisk, BYTES_PER_SECTOR, NUM_SECTORS);
#if FS_SUPPORT_FILE_BUFFER
//
// Enable the file buffer to increase the performance
// when reading/writing a small number of bytes.
//
FS_ConfigFileBufferDefault(BYTES_PER_SECTOR, FS_FILE_BUFFER_WRITE);
#endif // FS_SUPPORT_FILE_BUFFER
}
Compile-time configuration
The compile time configuration is realized via preprocessor defines that have
to be added to the FS_Conf.h file which is the main configuration file
of emFile. For detailed information about the configuration of emFile
and of the configuration define types, refer to Configuration of emFile
The System RAM disk driver does not require any hardware access functions.
The following table lists the configuration defines supported by the RAM Disk
driver.
FS_RAMDISK_NUM_UNITS
This define specifies the maximum number of driver instances that can be created
by the application. The memory for each driver instance is allocated dynamically.
Runtime configuration
This section describes the functions that can be used to configure an
instance of the System RAM Disk driver.
Description
Configures an instance of a System RAM disk driver.
Prototype
void FS_RAMDISK_Configure(U8 Unit,
void * pData,
U16 BytesPerSector,
U32 NumSectors);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
pData | Memory area to be used as storage. It cannot be NULL. |
BytesPerSector | Number of bytes in a logical sector. |
NumSectors | Number of logical sectors in the storage. |
Additional information
The application has to call this function for each instance
of the System RAM disk driver it adds to file system. Unit identifies
the instance of the System RAM disk driver. The instance of the RAM
disk driver added first to file system has the index 0,
the second instance has the index 1, and so on.
pData has to point to a memory region that is at least
BytesPerSector * NumSectors bytes large. The memory region can by
located on any system memory that is accessible by CPU.
BytesPerSector has to be a power of 2 value.
Example
#include <FS.h>
#define NUM_SECTORS 16 // Number of sectors on the RAM storage
#define BYTES_PER_SECTOR 512 // Size of a sector in bytes
static U32 _aRAMDisk[(NUM_SECTORS * BYTES_PER_SECTOR) / 4]; // Memory to be used as storage.
/*********************************************************************
*
* FS_X_AddDevices
*
* Function description
* This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
//
// Basic file system configuration...
//
//
// Add and configure the driver.
//
FS_AddDevice(&FS_RAMDISK_Driver);
FS_RAMDISK_Configure(0, _aRAMDisk, BYTES_PER_SECTOR, NUM_SECTORS);
//
// Additional file system configuration...
//
}
Performance and resource usage
ROM usage
The ROM usage depends on the compiler options, the compiler version and the used CPU.
The memory requirements of the System RAM Disk driver were measured as described in the section
Test procedure.
Usage: 500 bytes
Static RAM usage
Static RAM usage refers to the amount of RAM required by the System RAM Disk driver
internally for all the driver instances. The number of bytes can be seen in the
compiler list file of the FS_RAMDisk.c file.
Usage: 40 bytes
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the driver at runtime.
Each instance of the System RAM Disk driver requires the following number of bytes:
Usage: 10 bytes
Performance
These performance measurements are in no way complete, but they give an
approximation of the length of time required for common operations on various
targets. The tests have been performed as described in the section
Performance.
All values are given in Mbytes/sec.
CPU type | Write speed | Read speed |
Atmel AT91SAM9261 (200 MHz) | 128 | 128 |
LogicPD LH79520 (51 MHz) | 20 | 20 |
Universal RAM Disk driver
This section describes the RAM Disk driver that can use the system memory
as well as a serial RAM device a storage.
Supported hardware
The Universal RAM Disk driver can be used on any target hardware that has
sufficient system memory to be used as storage. In addition, the driver can
be used with volatile and non-volatile RAM devices that are connected to MCU
via a serial bus such as SPI or I2C.
The following table shows the serial RAM devices that were tested by SEGGER
or are known to be compatible with a tested device.
Device name | Storage capacity | Device type | Supported extra features |
MB85RC64TA | 64 Kibit | I2C | |
MB85RS128TY | 128 Kibit | SPI | |
MB85RS1MT | 1 Mibit | SPI | |
MB85RS256TY | 256 Kibit | SPI | |
MB85RS512T | 512 Kibit | SPI | |
CY15B104QSN | 4096 Mibit | SPI | extended SPI, DTR |
FM24CL64B | 64 Mibit | I2C | |
FM24V01A | 128 Mibit | I2C | |
FM24V02A | 256 Mibit | I2C | |
FM25V02A | 256 Mibit | SPI | |
FM25V05 | 512 Mibit | SPI | |
FM25V10 | 1 Mibit | SPI | |
Configuring the driver
The application has to add the Universal RAM Disk driver to the file system before
using it. This is done by calling FS_AddDevice() in FS_X_AddDevices() with
the parameter set to the function table of the Universal RAM Disk driver FS_RAMDISK_UNI_Driver.
The maximum number of Universal RAM Disk driver instances that can be added to file
system can be configured a compile-time using the FS_RAMDISK_MAX_NUM_UNITS
configuration define. By default, a maximum number of four Universal RAM Disk driver
instances can be added to file system.
In addition, the application has to configure the RAMDISK physical layer
to be used for accessing the storage and if required the RAMDISK hardware
layer to be used for the data transfer with the RAM device.
Example
The following configuration example uses the system memory as storage.
#include <FS.h>
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#define ALLOC_SIZE 0x1100 // Memory pool for the file system in bytes.
#define NUM_SECTORS 16 // Number of sectors on the RAM storage.
#define BYTES_PER_SECTOR 512 // Size of a sector in bytes.
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
//
// Memory pool used for semi-dynamic allocation.
//
static U32 _aMemBlock[ALLOC_SIZE / 4];
//
// Memory to be used as storage.
//
static U32 _aRAMDisk[(NUM_SECTORS * BYTES_PER_SECTOR) / 4];
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* 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().
*
* Note
* (1) Other API functions may NOT be called, since this function is called
* during initialization. The devices are not yet ready at this point.
*/
void FS_X_AddDevices(void) {
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Add and configure the driver.
//
FS_AddDevice(&FS_RAMDISK_UNI_Driver);
FS_RAMDISK_UNI_SetPhyType(0, &FS_RAMDISK_PHY_System);
FS_RAMDISK_UNI_SetSectorSize(0, BYTES_PER_SECTOR);
FS_RAMDISK_SYS_SetMemBlock(0, _aRAMDisk, sizeof(_aRAMDisk));
#if FS_SUPPORT_FILE_BUFFER
//
// Enable the file buffer to increase the performance
// when reading/writing a small number of bytes.
//
FS_ConfigFileBufferDefault(BYTES_PER_SECTOR, FS_FILE_BUFFER_WRITE);
#endif // FS_SUPPORT_FILE_BUFFER
}
The following configuration example uses as storage a RAM device connected via I2C.
#include <FS.h>
#include "FS_RAMDISK_HW_I2C_GPIO_Template.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#define ALLOC_SIZE 0x1100 // Memory pool for the file system in bytes.
#define NUM_SECTORS 16 // Number of sectors on the RAM storage.
#define BYTES_PER_SECTOR 512 // Size of a sector in bytes.
#define DEVICE_ADDRESS 0x50 // I2C address of the device.
#define DEVICE_SIZE 8192 // Capacity of the device in bytes.
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
//
// Memory pool used for semi-dynamic allocation.
//
static U32 _aMemBlock[ALLOC_SIZE / 4];
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* 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().
*
* Note
* (1) Other API functions may NOT be called, since this function is called
* during initialization. The devices are not yet ready at this point.
*/
void FS_X_AddDevices(void) {
//
// Give the file system memory to work with.
//
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Add and configure the driver.
//
FS_AddDevice(&FS_RAMDISK_UNI_Driver);
FS_RAMDISK_UNI_SetPhyType(0, &FS_RAMDISK_PHY_I2C);
FS_RAMDISK_UNI_SetSectorSize(0, BYTES_PER_SECTOR);
FS_RAMDISK_I2C_SetDeviceAddress(0, DEVICE_ADDRESS);
FS_RAMDISK_I2C_SetDeviceSize(0, DEVICE_SIZE);
FS_RAMDISK_I2C_SetHWType(0, &FS_RAMDISK_HW_I2C_GPIO_Template);
#if FS_SUPPORT_FILE_BUFFER
//
// Enable the file buffer to increase the performance
// when reading/writing a small number of bytes.
//
FS_ConfigFileBufferDefault(BYTES_PER_SECTOR, FS_FILE_BUFFER_WRITE);
#endif // FS_SUPPORT_FILE_BUFFER
}
The following configuration example uses as storage a RAM device connected via SPI.
#include <FS.h>
#include "FS_RAMDISK_HW_SPI_Template.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#define ALLOC_SIZE 0x1100 // Memory pool for the file system in bytes.
#define BYTES_PER_SECTOR 512 // Size of a sector in bytes.
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for semi-dynamic allocation.
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
/*********************************************************************
*
* 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().
*
* Note
* (1) Other API functions may NOT be called, since this function is called
* during initialization. The devices are not yet ready at this point.
*/
void FS_X_AddDevices(void) {
//
// Give the file system memory to work with.
//
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Add and configure the driver.
//
FS_AddDevice(&FS_RAMDISK_UNI_Driver);
FS_RAMDISK_UNI_SetPhyType(0, &FS_RAMDISK_PHY_SPI);
FS_RAMDISK_UNI_SetSectorSize(0, BYTES_PER_SECTOR);
FS_RAMDISK_SPI_SetHWType(0, &FS_RAMDISK_HW_SPI_Template);
FS_RAMDISK_SPI_SetDeviceList(0, &FS_RAMDISK_SPI_DeviceListAll);
FS_RAMDISK_SPI_Allow2bitMode(0, 1);
FS_RAMDISK_SPI_Allow4bitMode(0, 1);
#if FS_SUPPORT_FILE_BUFFER
//
// Enable the file buffer to increase the performance
// when reading/writing a small number of bytes.
//
FS_ConfigFileBufferDefault(BYTES_PER_SECTOR, FS_FILE_BUFFER_WRITE);
#endif // FS_SUPPORT_FILE_BUFFER
}
Compile-time configuration
The compile time configuration is realized via preprocessor defines that have
to be added to the FS_Conf.h file which is the main configuration file
of emFile. For detailed information about the configuration of emFile
and of the configuration define types, refer to Configuration of emFile
The RAM disk driver does not require any hardware access functions.
The following table lists the configuration defines supported by the RAM Disk
driver.
FS_RAMDISK_DATA_BUFFER_SIZE
This define can be used to specify the size of the buffers used by the
Universal RAM Disk driver for internal operations such as verifying
if the write operation was successful.
All these buffers are allocated on the stack therefore increasing the
value of FS_RAMDISK_DATA_BUFFER_SIZE increases the stack usage while providing
a better performance. FS_RAMDISK_DATA_BUFFER_SIZE has to be a non-zero value
that is a multiple of 4.
FS_RAMDISK_NUM_READ_RETRIES
FS_RAMDISK_NUM_READ_RETRIES can be used to specify the maximum number
of times the Universal RAM Disk driver repeats a read operation in case of an error.
A read retry is performed each time the read function of the RAMDISK physical layer
reports an error.
FS_RAMDISK_NUM_UNITS
This define specifies the maximum number of driver instances that can be created
by the application. The memory for each driver instance is allocated dynamically.
FS_RAMDISK_VERIFY_WRITE
This define can be used to activate the write verification of the Universal RAM Disk driver.
The write verification is performed after each write operation by reading back
the modified data from storage and by comparing it with the data requested
to be written. An error is reported if a difference is detected.
This feature has to be enabled at runtime by calling FS_RAMDISK_UNI_SetWriteVerification().
Note
Activating the write verification can negatively affect the write performance.
Runtime configuration
This section describes the functions that can be used to configure an
instance of the RAM Disk driver.
FS_RAMDISK_UNI_SetPhyType()
Description
Configures the physical layer type.
Prototype
int FS_RAMDISK_UNI_SetPhyType( U8 Unit,
const FS_RAMDISK_PHY_TYPE * pPhyType);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
pPhyType | Type of physical layer. It cannot be NULL. |
Return value
= 0 | OK, physical layer configured successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function is mandatory and it has to be called once in FS_X_AddDevices()
for each instance of the RAMDisk driver created by the application.
Different instances of the RAMDisk driver are identified by the Unit parameter.
Permitted values for the pPhyType parameter are:
Identifier | Description |
FS_RAMDISK_PHY_System | System memory. |
FS_RAMDISK_PHY_I2C | External RAM device connected via I2C. |
FS_RAMDISK_PHY_SPI | External RAM device connected via SPI. |
FS_RAMDISK_UNI_SetByteRange()
Description
Configures the range of memory to be used as storage.
Prototype
int FS_RAMDISK_UNI_SetByteRange(U8 Unit,
U32 StartOff,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
StartOff | Offset of the first byte to be used as storage (0-based). |
NumBytes | Number of bytes to be used as storage. |
Return value
= 0 | OK, memory range configured successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
StartOff is rounded up to a multiple while NumBytes is rounded
down to a multiple of logical sector size.
If NumBytes is set to 0 then the memory region used as storage
starts at byte offset StartOff and extends to the end of the
storage device.
FS_RAMDISK_UNI_SetSectorSize()
Description
Configures the size of the logical sector used by the driver.
Prototype
int FS_RAMDISK_UNI_SetSectorSize(U8 Unit,
unsigned BytesPerSector);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
BytesPerSector | Logical sector size in bytes. |
Return value
= 0 | OK, memory range configured successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function is optional. If the size of the logical sector
is not explicitly configured via FS_RAMDISK_UNI_SetSectorSize()
then the file system uses the maximum logical sector size
set via FS_SetMaxSectorSize(). FS_RAMDISK_UNI_SetSectorSize()
can be called only in FS_X_AddDevices().
BytesPerSector has to be a power of 2 value.
FS_RAMDISK_UNI_SetWriteVerification()
Description
Enables or disables the checking of the data write operation.
Prototype
int FS_RAMDISK_UNI_SetWriteVerification(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the Universal RAM Disk driver (0-based). |
OnOff | Specifies if the feature has to be enabled or disabled =0 The write operation is not checked. ≠0 The write operation is checked. |
Return value
= 0 | OK, write verification configured successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function is optional. It can be used to enable the checking
of the written data. This is done by reading back the contents
of the written data and by comparing it with the data requested
to be written. Enabling this feature can negatively impact the write
performance of Universal RAM Disk driver.
The write verification feature is active only when the Universal
RAM Disk driver is compiled with the FS_RAMDISK_VERIFY_WRITE configuration
define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL
configuration define is set to a value greater than or equal to
FS_DEBUG_LEVEL_CHECK_ALL.
Additional driver functions
The functions documented in this section are optional. They can be used
to get information about the status of the Universal RAM Disk driver or
to directly access the data stored on a RAM device.
FS_RAMDISK_UNI_GetDiskInfo()
Description
Gets information about the storage device.
Prototype
int FS_RAMDISK_UNI_GetDiskInfo(U8 Unit,
FS_RAMDISK_UNI_DISK_INFO * pDiskInfo);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
pDiskInfo | out Storage device information. It cannot be NULL. |
Return value
= 0 | OK, information returned successfully. |
≠ 0 | Error code indicating the failure reason. |
FS_RAMDISK_UNI_ReadOff()
Description
Reads a specified number of bytes from storage device.
Prototype
int FS_RAMDISK_UNI_ReadOff(U8 Unit,
U32 Off,
void * pData,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
Off | Byte offset to read from. |
pData | out Data read from storage device. It cannot be NULL. |
NumBytes | Number of bytes to be read. |
Return value
= 0 | OK, data read successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
Off has to be specified in bytes and is relative to the beginning
of the storage partition configured via FS_RAMDISK_UNI_SetByteRange().
FS_RAMDISK_UNI_WriteOff()
Description
Writes a specified number of bytes to storage device.
Prototype
int FS_RAMDISK_UNI_WriteOff( U8 Unit,
U32 Off,
const void * pData,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
Off | Byte offset to write to. |
pData | out Data to be written to the storage device. It cannot be NULL. |
NumBytes | Number of bytes to be written. |
Return value
= 0 | OK, data written successfully. |
≠ 0 | Error code indicating the failure reason. |
Additional information
Off has to be specified in bytes and is relative to the beginning
of the storage partition configured via FS_RAMDISK_UNI_SetByteRange().
FS_RAMDISK_UNI_DISK_INFO
Description
Management information maintained by the Universal RAM Disk driver.
Type definition
typedef struct {
U32 NumBytes;
U16 BytesPerSector;
} FS_RAMDISK_UNI_DISK_INFO;
Structure members
Member | Description |
NumBytes | Capacity of the storage device in bytes. |
BytesPerSector | Size of the logical sector used by the driver in bytes. |
Performance and resource usage
ROM usage
The ROM usage depends on the compiler options, the compiler version and the used CPU.
The memory requirements of the Universal RAM Disk driver were measured as described in the section
Test procedure.
Usage: 600 bytes
Static RAM usage
Static RAM usage refers to the amount of RAM required by the Universal RAM Disk driver
internally for all the driver instances. The number of bytes can be seen in the
compiler list file of the FS_RAMDISK_UNI_Drv.c file.
Usage: 16 bytes
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the driver at runtime.
Each instance of the Universal RAM Disk driver requires the following number of bytes:
Usage: 25 bytes
Performance
These performance measurements are in no way complete, but they give an
approximation of the length of time required for common operations on various
targets. The tests have been performed as described in the section
Performance.
All values are given in Mbytes/sec.
CPU type | RAM device | Write speed | Read speed |
ST STM32H743 (480 MHz) | Infineon CY15B104QSN (48 MHz, quad DTR)
| 48 | 64 |
RAMDISK physical layer
General information
The table below lists the RAMDISK physical layers that ship with emFile.
Refer to Configuring the driver
and Configuring the driver
for more information about how to add and configure a physical layer in an
application.
The following sections provide information about the usage and the implementation of
a RAMDISK physical layer.
I2C physical layer
This physical layer supports any RAM device connected to the MCU via I2C.
The physical layer has to be configured at runtime. The following
section describes how this can be done in the application.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the System physical layer. The application can call
these function only at the file system initialization in FS_X_AddDevices().
FS_RAMDISK_I2C_SetDeviceAddress()
Description
Configures the I2C address of the storage device.
Prototype
int FS_RAMDISK_I2C_SetDeviceAddress(U8 Unit,
unsigned Addr);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based). |
Addr | I2C address to be configured. |
Return value
= 0 | OK, device address configured. |
≠ 0 | Error code indicating the failure reason. |
Additional information
It is mandatory to call this function once for each configured
I2C RAMDisk physical layer. The application must call it in
FS_X_AddDevices().
FS_RAMDISK_I2C_SetDeviceSize()
Description
Configures the capacity of the storage device.
Prototype
int FS_RAMDISK_I2C_SetDeviceSize(U8 Unit,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based). |
NumBytes | Device capacity to be configured. |
Return value
= 0 | OK, device capacity configured. |
≠ 0 | Error code indicating the failure reason. |
Additional information
It is mandatory to call this function once for each configured
I2C RAMDisk physical layer. The application must call it in
FS_X_AddDevices().
FS_RAMDISK_I2C_SetHWType()
Description
Configures the HW layer for the device access.
Prototype
int FS_RAMDISK_I2C_SetHWType( U8 Unit,
const FS_RAMDISK_HW_TYPE_I2C * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based). |
pHWType | in HW layer to be used. It cannot be NULL. |
Return value
= 0 | OK, HW layer configured. |
≠ 0 | Error code indicating the failure reason. |
Additional information
It is mandatory to call this function once for each configured
I2C RAMDisk physical layer. The application must call it in
FS_X_AddDevices().
SPI physical layer
This physical layer supports any RAM device connected to the MCU via single
dual, quad and octal SPI.
The physical layer has to be configured at runtime. The following
section describes how this can be done in the application.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the System physical layer. The application can call
these function only at the file system initialization in FS_X_AddDevices().
FS_RAMDISK_SPI_Allow2bitMode()
Description
Specifies if the physical layer is permitted to exchange data
via two data lines.
Prototype
int FS_RAMDISK_SPI_Allow2bitMode(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based). |
OnOff | Activation status of the option. 0 Disable the option. 1 Enable the option. |
Return value
= 0 OK, 2 | bit mode configured. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function is optional. By default the data is exchanged via one
data line (standard SPI). The data transfer via two data lines is
used only if this type of data transfer is supported by the serial
RAM device. In dual mode two bits of data are transferred with
each clock period which helps improve the performance. If the serial
RAM device does not support the dual mode then the data is
transferred in standard mode (one data bit per clock period).
The application is permitted to call this function only at the file
system initialization in FS_X_AddDevices().
FS_RAMDISK_SPI_Allow4bitMode()
Description
Specifies if the physical layer is permitted to exchange data
via four data lines.
Prototype
int FS_RAMDISK_SPI_Allow4bitMode(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based). |
OnOff | Activation status of the option. 0 Disable the option. 1 Enable the option. |
Return value
= 0 OK, 4 | bit mode configured. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function is optional. By default the data is exchanged via one
data line (standard SPI). The data transfer via four data lines
is used only if this type of data transfer is supported by the serial
RAM device. In quad mode four bits of data are transferred on
each clock period which helps improve the performance. If the serial
RAM device does not support the quad mode then the data is
transferred in dual mode if enabled and supported or in standard
mode (one bit per clock period).
The application is permitted to call this function only at the file
system initialization in FS_X_AddDevices().
FS_RAMDISK_SPI_AllowDTRMode()
Description
Specifies if the physical layer is permitted to exchange data
on both clock edges.
Prototype
int FS_RAMDISK_SPI_AllowDTRMode(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based). |
OnOff | Activation status of the option. 0 Disable the option. 1 Enable the option. |
Return value
= 0 | OK, DTR mode configured. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function is optional. By default the data is exchanged only on one
of the clock edges (SDR mode). In DTR mode the data is transferred on
each edge of the clock which helps improve the performance. The SPI RAMDISK
physical layer transfers the data in DTR mode only if the used serial RAM
device supports it.
The application is permitted to call this function only at the file
system initialization in FS_X_AddDevices().
FS_RAMDISK_SPI_SetDeviceList()
Description
Configures the type of handled serial RAM devices.
Prototype
int FS_RAMDISK_SPI_SetDeviceList( U8 Unit,
const FS_RAMDISK_SPI_DEVICE_LIST * pDeviceList);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based). |
pDeviceList | List of serial RAM devices the physical layer can handle. |
Return value
= 0 | OK, device list successfully configured. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function is optional. By default the physical layer is configured
to handle Infineon (Ramtron) serial FRAM devices. Handling of serial RAM
devices from other manufacturers has to be explicitly enabled via
this function.
Permitted values for the pDeviceList parameter are:
Identifier | Description |
FS_NOR_SPI_DeviceListAll | Enables handling of serial RAM devices from all supported manufacturers. |
FS_NOR_SPI_DeviceListDefault | Enables handling of Infineon (Ramtron) serial RAM devices. |
FS_NOR_SPI_DeviceListFujitsu | Enables handling of Fujitsu serial RAM devices. |
FS_NOR_SPI_DeviceListInfineon | Enables handling of Infineon serial RAM devices. |
The application can save ROM space by setting FS_RAMDISK_DEVICE_LIST_DEFAULT
to NULL at compile time and by calling at runtime FS_RAMDISK_SPI_SetDeviceList()
with the actual list of serial RAM devices that have to be handled.
The application is permitted to call this function only at the file
system initialization in FS_X_AddDevices().
FS_RAMDISK_SPI_SetHWType()
Description
Configures the HW layer for the device access.
Prototype
int FS_RAMDISK_SPI_SetHWType( U8 Unit,
const FS_RAMDISK_HW_TYPE_SPI * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based). |
pHWType | in HW layer to be used. It cannot be NULL. |
Return value
= 0 | OK, HW layer configured. |
≠ 0 | Error code indicating the failure reason. |
Additional information
It is mandatory to call this function once for each configured
SPI RAMDisk physical layer. The application must call it in
FS_X_AddDevices().
FS_RAMDISK_SPI_SetMemAddr()
Description
Configures the address in the system memory where the device is mapped.
Prototype
int FS_RAMDISK_SPI_SetMemAddr(U8 Unit,
U32 Addr);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based). |
Addr | Address in the system memory. |
Return value
= 0 | OK, address successfully configured. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function has to be called only in FS_X_AddDevices().
RAMDISK HW layer flags
Description
Additional options for data exchanged by the SPI RAMDISK hardware layer.
Definition
#define FS_RAMDISK_HW_FLAG_DTR_DATA (1uL << 0)
#define FS_RAMDISK_HW_FLAG_DTR_ADDR (1uL << 1)
#define FS_RAMDISK_HW_FLAG_DTR_CMD (1uL << 2)
#define FS_RAMDISK_HW_FLAG_DQS_ACTIVE (1uL << 3)
#define FS_RAMDISK_HW_FLAG_MODE_8BIT (1uL << 4)
Symbols
Definition | Description |
FS_RAMDISK_HW_FLAG_DTR_DATA | Exchange the data on each clock transition. |
FS_RAMDISK_HW_FLAG_DTR_ADDR | Send the address on each clock transition. |
FS_RAMDISK_HW_FLAG_DTR_CMD | Send the command on each clock transition. |
FS_RAMDISK_HW_FLAG_DQS_ACTIVE | Enable the data strobe signal. |
FS_RAMDISK_HW_FLAG_MODE_8BIT | Send eight mode bits after the data address. |
System physical layer
This physical layer supports any system memory.
The physical layer has to be configured at runtime. The following
section describes how this can be done in the application.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the System physical layer. The application can call
these function only at the file system initialization in FS_X_AddDevices().
FS_RAMDISK_SYS_SetMemBlock()
Description
Configures the memory block to be used as storage.
Prototype
int FS_RAMDISK_SYS_SetMemBlock(U8 Unit,
void * pData,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based). |
pData | Memory area to be used as storage. It cannot be NULL. |
NumBytes | Number of bytes to be used as storage. |
Return value
= 0 | OK, memory block configured. |
≠ 0 | Error code indicating the failure reason. |
Additional information
The application has to call this function for each instance
of the RAM disk physical layer that is added to the file system.
Unit identifies the instance of the RAM disk physical layer.
pData has to point to a memory region that is at least
NumBytes bytes large. The memory region can by located on any
system memory that is accessible by CPU.
Physical layer API
The physical layers that come with emFile provide support most of the popular
RAM device and target MCU types. Therefore, there is typically no need to modify
any of the provided RAMDISK physical layers. In most of the cases, only the RAMDISK hardware
layer has to be adapted to a specific target hardware. However, when none of the provided
RAMDISK physical layers are compatible with the target hardware a new RAMDISK physical
layer implementation is required. This section provides information about the API
of the RAMDISK physical layer that helps to create a new physical layer from scratch
or to modify an existing one.
The API of the physical layer is implemented as a structure of type FS_RAMDISK_PHY_TYPE
that contains pointers to functions. The following sections describe these functions
in detail together with the data structure passed to these functions as parameters.
FS_RAMDISK_PHY_TYPE
Description
RAMDISK physical layer API.
Type definition
typedef struct {
FS_RAMDISK_PHY_TYPE_INIT_GET_DEVICE_INFO * pfInitGetDeviceInfo;
FS_RAMDISK_PHY_TYPE_READ_OFF * pfReadOff;
FS_RAMDISK_PHY_TYPE_WRITE_OFF * pfWriteOff;
FS_RAMDISK_PHY_TYPE_DEINIT * pfDeInit;
} FS_RAMDISK_PHY_TYPE;
Structure members
Member | Description |
pfInitGetDeviceInfo | Initializes the instance of the RAM physical layer and returns the information about the RAM device. |
pfReadOff | Reads data from the RAM device. |
pfWriteOff | Writes data to the RAM device. |
pfDeInit | Frees the resources allocated by the RAM physical layer instance. |
FS_RAMDISK_PHY_TYPE_INIT_GET_DEVICE_INFO
Description
Initializes the physical layer.
Type definition
typedef int FS_RAMDISK_PHY_TYPE_INIT_GET_DEVICE_INFO(U8 Unit,
FS_RAMDISK_DEVICE_INFO * pDeviceInfo);
Parameters
Parameter | Description |
Unit | Index of the RAMDISK physical layer instance (0-based) |
pDeviceInfo | out Information about the NAND flash device. |
Return value
= 0 | OK, physical layer successfully initialized. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the RAMDISK physical layer API.
It has to be implemented by all the RAMDISK physical layers.
This is the first function of the physical layer API that is called
by the Universal RAM Disk driver when the RAM device is mounted.
This function has to perform the initialization of the hardware layer,
and the identification of the RAM device. If the RAM device can be handled,
then the function has to fill pDevInfo with information about the organization
of the RAM device.
FS_RAMDISK_PHY_TYPE_READ_OFF
Description
Reads data from a RAM device.
Type definition
typedef int FS_RAMDISK_PHY_TYPE_READ_OFF(U8 Unit,
U32 Off,
void * pData,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the RAMDISK physical layer instance (0-based) |
Off | Byte offset to read from. |
pData | out Data read from RAM device. |
NumBytes | Number of bytes to be read. |
Return value
= 0 | OK, data read successfully. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the RAMDISK physical layer API.
It has to be implemented by all the RAMDISK physical layers.
FS_RAMDISK_PHY_TYPE_WRITE_OFF
Description
Writes data to a RAM device.
Type definition
typedef int FS_RAMDISK_PHY_TYPE_WRITE_OFF( U8 Unit,
U32 Off,
const void * pData,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the RAMDISK physical layer instance (0-based) |
Off | Byte offset to write to. |
pData | in Data to be written to the RAM device. |
NumBytes | Number of bytes to be written. |
Return value
= 0 | OK, data written. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the RAMDISK physical layer API.
It has to be implemented by all the RAMDISK physical layers.
FS_RAMDISK_PHY_TYPE_DEINIT
Description
Releases the allocated resources.
Type definition
typedef void FS_RAMDISK_PHY_TYPE_DEINIT(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the RAMDISK physical layer instance (0-based) |
Additional information
This function is a member of the RAMDISK physical layer API.
It has to be implemented by the all the RAMDISK physical layers that allocate
resources dynamically during the initialization such as memory
for the physical layer instance.
The RAMDISK driver calls this function when the file system is unmounted.
FS_RAMDISK_DEVICE_INFO
Description
Information about a RAM device.
Type definition
typedef struct {
U32 NumBytes;
} FS_RAMDISK_DEVICE_INFO;
Structure members
Member | Description |
NumBytes | Capacity of the storage device in bytes. |
Resource usage
This section describes the ROM and RAM usage of the RAMDISK physical layers.
ROM usage
The ROM usage depends on the compiler options, the compiler version, and the used
CPU. The memory requirements of the RAMDISK physical layers were measured as described
in the section
Test procedure.
The following table lists the ROM usage of all the available RAMDISK physical layers.
Static RAM usage
Static RAM usage is the amount of RAM required by the driver for static variables
inside the driver. The number of bytes can be seen in a compiler list file.
The next table lists the static RAM usage of all the available RAMDISK physical layers.
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the physical layer at runtime.
The amount of RAM required depends on the compile time and runtime configuration.
The following table lists the the dynamic RAM usage of the available RAMDISK physical layers.
RAMDISK hardware layer
General information
The RAMDISK hardware layer provides functionality for accessing a RAM device
via the target hardware such as GPIO, SPI, I2C, etc.
The functions of the RAMDISK hardware layer are called by the RAMDISK physical layer
to exchange commands and data with a RAM device. These functions are
hardware dependent and therefore they have to be implemented in the application.
emFile comes with template hardware layers and sample implementations
for popular evaluation boards that can be used as starting point for implementing
new hardware layers. The relevant files are located in the /Sample/FS/Driver/RAM
folder of the emFile shipment.
The functions of the RAMDISK hardware layer are organized in a function table implemented
as a C structure. Different hardware layer types are provided to support different
ways of interfacing a RAM device. The type of hardware layer an application
has to use depends on the type RAMDISK physical layer configured. The following table
shows what hardware layer is required by each physical layer.
Hardware layer API - FS_RAMDISK_HW_TYPE_I2C
This hardware layer supports serial RAM devices that are interfaced via I2C.
The functions of this hardware layer are grouped in a structure of type FS_RAMDISK_HW_TYPE_I2C.
The following sections describe these functions in detail.
FS_RAMDISK_HW_TYPE_I2C
Description
HW layer for RAM devices connected via I2C.
Type definition
typedef struct {
FS_RAMDISK_HW_TYPE_I2C_INIT * pfInit;
FS_RAMDISK_HW_TYPE_I2C_START * pfStart;
FS_RAMDISK_HW_TYPE_I2C_STOP * pfStop;
FS_RAMDISK_HW_TYPE_I2C_READ * pfRead;
FS_RAMDISK_HW_TYPE_I2C_WRITE * pfWrite;
} FS_RAMDISK_HW_TYPE_I2C;
Structure members
Member | Description |
pfInit | Initializes the I2C hardware. |
pfStart | Generates a START condition on the I2C bus. |
pfStop | Generates a STOP condition on the I2C bus. |
pfRead | Transfers data from I2C device to MCU. |
pfWrite | Transfers data from MCU to I2C device. |
FS_RAMDISK_HW_TYPE_I2C_INIT
Description
Initializes the HW layer.
Type definition
typedef int FS_RAMDISK_HW_TYPE_I2C_INIT(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
Return value
= 0 | OK, HW layer successfully initialized. |
≠ 0 | An error occurred. |
FS_RAMDISK_HW_TYPE_I2C_START
Description
Start an I2C transaction.
Type definition
typedef int FS_RAMDISK_HW_TYPE_I2C_START(U8 Unit,
unsigned Addr,
int IsRead);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
Addr | Address of the device to be accessed. |
IsRead | Type of operation to be executed. 0 - Write operation. 1 - Read operation. |
Return value
= 0 | OK, transaction successfully started. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the I2C RAMDISK hardware layer API.
It has to be implemented by all the hardware layers.
FS_RAMDISK_HW_TYPE_I2C_STOP
Description
Ends an I2C transaction.
Type definition
typedef int FS_RAMDISK_HW_TYPE_I2C_STOP(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
Return value
= 0 | OK, transaction successfully ended. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the I2C RAMDISK hardware layer API.
It has to be implemented by all the hardware layers.
FS_RAMDISK_HW_TYPE_I2C_READ
Description
Transfers data from I2C device to MCU.
Type definition
typedef int FS_RAMDISK_HW_TYPE_I2C_READ(U8 Unit,
U8 * pData,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
pData | out Data read from I2C device. |
NumBytes | Number of bytes to transfer. |
Return value
= 0 | OK, data successfully transferred. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the I2C RAMDISK hardware layer API.
It has to be implemented by all the hardware layers.
The function has to send a NAK after the last byte transferred.
FS_RAMDISK_HW_TYPE_I2C_WRITE
Description
Transfers data from MCU to I2C device.
Type definition
typedef int FS_RAMDISK_HW_TYPE_I2C_WRITE( U8 Unit,
const U8 * pData,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
pData | in Data written to I2C device. |
NumBytes | Number of bytes to transfer. |
Return value
= 0 | OK, data successfully transferred. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the I2C RAMDISK hardware layer API.
It has to be implemented by all the hardware layers.
Sample implementation
The following sample implementation uses the GPIOs of an ST STM32H743 MCU
to interface with a I2C RAM device. This RAMDISK hardware layer was tested on the
SGGER QSPI Flash Evaluator board (https://www.segger.com/evaluate-our-software/segger/qspi-flash-evaluator/)
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : FS_RAMDISK_HW_I2C_GPIO_STM32H743_SEGGER_QSPI_Flash_Evaluator.c
Purpose : Hardware layer for SEGGER QSPI Flash Evaluator
with RAM device connected via I2C.
Literature:
[1] RM0433 Reference manual STM32H7x3 advanced ARM-based 32-bit MCUs
[2] STM32H753xI Errata sheet STM32H753xI rev Y device limitations
Additional information:
The value of RAM_NUM_DELAY_LOOPS was determined by testing with
different I2C RAM devices. The resulting maximum SCL frequency
for a stable data transfer is about 100 kHz which is relatively
slow compared with the 1 MHz clock frequency supported by most
of the I2C RAM devices.
The reason for this limitation is that the HW layer is using
the internal pull-up resistors of the GPIO ports for the SCL
and SDA signals. According to the datasheet of STM32H7 device
the value of the internal pull-up resistors is about 40 kOhm.
The frequency of SCL signal can be greatly improved by using
external pull-up resistors of about 4.7 kOhm.
The device select address signals (A0-2) are set to logic low.
*/
/*********************************************************************
*
* #include section
*
**********************************************************************
*/
#include "FS.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#define RAM_NUM_DELAY_LOOPS 500 // Number of software cycles required
// to generate a delay of at least
// 4.7 us if the I2C device supports
// standard-mode (400kHz) or of at least
// 1.3 us if the I2C device support
// fast-mode (1MHz).
/*********************************************************************
*
* RAM_SET_SCL
*
* Description
* Sets the logic level of SCL signal to high.
*/
#define RAM_SET_SCL() GPIOF_BSRR = 1uL << RAM_SCL_BIT
/*********************************************************************
*
* RAM_CLR_SCL
*
* Description
* Sets the logic level of SCL signal to low.
*/
#define RAM_CLR_SCL() GPIOF_BSRR = 1uL << (RAM_SCL_BIT + 16)
/*********************************************************************
*
* RAM_SET_SDA
*
* Description
* Sets the logic level of SDA signal to high.
*/
#define RAM_SET_SDA() GPIOF_BSRR = 1uL << RAM_SDA_BIT
/*********************************************************************
*
* RAM_CLR_SDA
*
* Description
* Sets the logic level of SDA signal to high.
*/
#define RAM_CLR_SDA() GPIOF_BSRR = 1uL << (RAM_SDA_BIT + 16)
/*********************************************************************
*
* RAM_SET_SDA_TO_INPUT
*
* Description
* Configures the direction of the SDA signal to input.
*/
#define RAM_SET_SDA_TO_INPUT() GPIOF_MODER &= ~(MODER_MASK << (RAM_SDA_BIT << 1));
/*********************************************************************
*
* RAM_SET_SDA_TO_OUTPUT
*
* Description
* Configures the direction of the SDA signal to output.
*/
#define RAM_SET_SDA_TO_OUTPUT() GPIOF_MODER |= MODER_OUT << (RAM_SDA_BIT << 1)
/*********************************************************************
*
* RAM_GET_SDA
*
* Description
* Returns the logic level of the SDA signal.
*/
#define RAM_GET_SDA() (GPIOF_IDR & (1uL << RAM_SDA_BIT))
/*********************************************************************
*
* Defines, fixed
*
**********************************************************************
*/
/*********************************************************************
*
* RAM_DELAY
*
* Description
* Blocks the execution for a fixed period of time.
*/
#if RAM_NUM_DELAY_LOOPS
#define RAM_DELAY() _Delay()
#else
#define RAM_DELAY()
#endif
/*********************************************************************
*
* Port B registers
*/
#define GPIOB_BASE_ADDR 0x58020400uL
#define GPIOB_MODER (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x00))
#define GPIOB_OTYPE (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x04))
#define GPIOB_OSPEEDR (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x08))
#define GPIOB_PUPDR (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x0C))
#define GPIOB_IDR (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x10))
#define GPIOB_ODR (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x14))
#define GPIOB_BSRR (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x18))
#define GPIOB_AFRL (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x20))
/*********************************************************************
*
* Port F registers
*/
#define GPIOF_BASE_ADDR 0x58021400uL
#define GPIOF_MODER (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x00))
#define GPIOF_OTYPE (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x04))
#define GPIOF_OSPEEDR (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x08))
#define GPIOF_PUPDR (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x0C))
#define GPIOF_IDR (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x10))
#define GPIOF_ODR (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x14))
#define GPIOF_BSRR (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x18))
#define GPIOF_AFRL (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x20))
#define GPIOF_AFRH (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x24))
/*********************************************************************
*
* Reset and clock control
*/
#define RCC_BASE_ADDR 0x58024400uL
#define RCC_AHB3RSTR (*(volatile U32*)(RCC_BASE_ADDR + 0x7C))
#define RCC_AHB3ENR (*(volatile U32*)(RCC_BASE_ADDR + 0xD4))
#define RCC_AHB4ENR (*(volatile U32*)(RCC_BASE_ADDR + 0xE0))
/*********************************************************************
*
* GPIO bit positions of SPI signals
*/
#define RAM_SCL_BIT 10 // Port F
#define RAM_SDA_BIT 8 // Port F
#define RAM_A0_BIT 6 // Port B
#define RAM_A1_BIT 9 // Port F
#define RAM_A2_BIT 7 // Port F
#define RAM_WP_BIT 6 // Port F
/*********************************************************************
*
* GPIO bits and masks
*/
#define OSPEEDR_HIGH 2uL
#define OSPEEDR_MASK 0x3uL
#define MODER_MASK 0x3uL
#define MODER_OUT 1uL
#define MODER_ALT 2uL
#define AFR_MASK 0xFuL
#define PUPDR_MASK 0x3uL
#define PUPDR_PULLUP 0x1uL
/*********************************************************************
*
* Masks for the peripheral enable bits
*/
#define AHB1ENR_GPIOBEN_BIT 1
#define AHB1ENR_GPIOFEN_BIT 5
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _Delay
*
* Function description
* Blocks the execution for a specified time.
*
* Additional information
* The delay time is specified via RAM_NUM_DELAY_LOOPS.
*/
static void _Delay(void) {
volatile int i;
for (i = 0; i < RAM_NUM_DELAY_LOOPS; ++i) {
;
}
}
/*********************************************************************
*
* _WriteByte
*
* Function description
* Transfers 8 bits of data from MCU to I2C device.
*
* Parameters
* Data 8-bit value to be transferred.
*
* Return value
* ==0 Data accepted by the I2C device (ACK/NACK bit set to 0)
* !=0 Data rejected by the I2C device (ACK/NACK bit set to 1)
*/
static int _WriteByte(U8 Data) {
int r;
int i;
//
// Send data bits with MSB first.
//
for (i = 0; i < 8; ++i) {
if ((Data & (1 << 7)) != 0) {
RAM_SET_SDA();
} else {
RAM_CLR_SDA();
}
Data <<= 1;
RAM_DELAY(); // Wait tLOW
RAM_SET_SCL();
RAM_DELAY(); // Wait tHIGH
RAM_CLR_SCL();
}
//
// Receive ACK/NACK.
//
RAM_SET_SDA_TO_INPUT();
RAM_DELAY(); // Wait tLOW
RAM_SET_SCL();
RAM_DELAY(); // Wait tHIGH
r = RAM_GET_SDA();
RAM_CLR_SCL();
RAM_DELAY(); // Wait tLOW
RAM_SET_SDA_TO_OUTPUT();
return r;
}
/*********************************************************************
*
* _ReadByte
*
* Function description
* Transfers 8 bits of data from I2C device to MCU.
*
* Parameters
* AckNack Value of the ACK/NACK bit.
* * 0 - More data will be transferred (ACK/NACK is set to 0)
* * 1 - Last data to be transferred (ACK/NACK is set to 1)
*
* Return value
* Transferred 8-bit value.
*/
static U8 _ReadByte(int AckNack) {
U8 Value;
int i;
//
// Receive data bits with MSB first.
//
RAM_SET_SDA_TO_INPUT();
RAM_DELAY(); // Wait tLOW
Value = 0;
for (i = 0; i < 8; ++i) {
RAM_SET_SCL();
RAM_DELAY(); // Wait tHIGH
Value <<= 1;
if (RAM_GET_SDA() != 0) {
Value |= 1u;
}
RAM_CLR_SCL();
RAM_DELAY(); // Wait tLOW
}
//
// Send ACK/NACK.
//
if (AckNack != 0) {
RAM_CLR_SDA();
} else {
RAM_SET_SDA();
}
RAM_SET_SDA_TO_OUTPUT();
RAM_SET_SCL();
RAM_DELAY(); // Wait tHIGH
RAM_CLR_SCL();
return Value;
}
/*********************************************************************
*
* Static code (public via callback)
*
**********************************************************************
*/
/*********************************************************************
*
* _HW_Init
*
* Function description
* Initializes the HW layer.
*
* Parameters
* Unit Index of the hardware layer (0-based).
*
* Return value
* ==0 OK, HW layer successfully initialized.
* !=0 An error occurred.
*/
static int _HW_Init(U8 Unit) {
FS_USE_PARA(Unit);
//
// Enable the clocks of GPIO peripherals.
//
RCC_AHB4ENR |= 0
| (1uL << AHB1ENR_GPIOBEN_BIT)
| (1uL << AHB1ENR_GPIOFEN_BIT)
;
//
// Clock signal (SCL).
//
GPIOF_MODER &= ~(MODER_MASK << (RAM_SCL_BIT << 1));
GPIOF_AFRH &= ~(AFR_MASK << ((RAM_SCL_BIT - 8) << 2));
GPIOF_PUPDR &= ~(PUPDR_MASK << (RAM_SCL_BIT << 1));
GPIOF_PUPDR |= PUPDR_PULLUP << (RAM_SCL_BIT << 1);
GPIOF_BSRR = 1uL << RAM_SCL_BIT; // Set to high logic level.
GPIOF_OTYPE |= 1uL << RAM_SCL_BIT; // Set to open-drain.
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_SCL_BIT << 1));
GPIOF_MODER |= MODER_OUT << (RAM_SCL_BIT << 1);
//
// Data signal (SDA).
//
GPIOF_MODER &= ~(MODER_MASK << (RAM_SDA_BIT << 1));
GPIOF_AFRH &= ~(AFR_MASK << ((RAM_SDA_BIT - 8) << 2));
GPIOF_PUPDR &= ~(PUPDR_MASK << (RAM_SDA_BIT << 1));
GPIOF_PUPDR |= PUPDR_PULLUP << (RAM_SDA_BIT << 1);
GPIOF_BSRR = 1uL << RAM_SDA_BIT; // Set to high logic level.
GPIOF_OTYPE |= 1uL << RAM_SDA_BIT; // Set to open-drain.
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_SDA_BIT << 1));
GPIOF_MODER |= MODER_OUT << (RAM_SDA_BIT << 1);
//
// Address pin 0 (A0).
//
GPIOB_MODER &= ~(MODER_MASK << (RAM_A0_BIT << 1));
GPIOB_AFRL &= ~(AFR_MASK << (RAM_A0_BIT << 2));
GPIOB_BSRR = 1uL << (RAM_A0_BIT + 16); // Set to low logic level.
GPIOB_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_A0_BIT << 1));
GPIOB_MODER |= MODER_OUT << (RAM_A0_BIT << 1);
//
// Address pin 1 (A1).
//
GPIOF_MODER &= ~(MODER_MASK << (RAM_A1_BIT << 1));
GPIOF_AFRH &= ~(AFR_MASK << ((RAM_A1_BIT - 8) << 2));
GPIOF_BSRR = 1uL << (RAM_A1_BIT + 16); // Set to low logic level.
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_A1_BIT << 1));
GPIOF_MODER |= MODER_OUT << (RAM_A1_BIT << 1);
//
// Address pin 2 (A2).
//
GPIOF_MODER &= ~(MODER_MASK << (RAM_A2_BIT << 1));
GPIOF_AFRL &= ~(AFR_MASK << (RAM_A2_BIT << 2));
GPIOF_BSRR = 1uL << (RAM_A2_BIT + 16); // Set to low logic level.
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_A2_BIT << 1));
GPIOF_MODER |= MODER_OUT << (RAM_A2_BIT << 1);
//
// Write protect pin (WP).
//
GPIOF_MODER &= ~(MODER_MASK << (RAM_WP_BIT << 1));
GPIOF_AFRL &= ~(AFR_MASK << (RAM_WP_BIT << 2));
GPIOF_BSRR = 1uL << (RAM_WP_BIT + 16); // Set to low logic level to disable the write protection.
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_WP_BIT << 1));
GPIOF_MODER |= MODER_OUT << (RAM_WP_BIT << 1);
return 0;
}
/*********************************************************************
*
* _HW_Start
*
* Function description
* Start an I2C transaction.
*
* Parameters
* Unit Index of the hardware layer (0-based).
* Addr Address of the device to be accessed.
* IsRead Type of operation to be executed.
* * 0 - Write operation.
* * 1 - Read operation.
*
* Return value
* ==0 OK, transaction successfully started.
* !=0 An error occurred.
*/
static int _HW_Start(U8 Unit, unsigned Addr, int IsRead) {
int r;
U8 AddrByte;
FS_USE_PARA(Unit);
AddrByte = (U8)(Addr << 1);
if (IsRead != 0) {
AddrByte |= 1u;
}
RAM_SET_SDA();
RAM_SET_SCL();
RAM_DELAY(); // Wait tBUF
RAM_CLR_SDA();
RAM_DELAY(); // Wait tHD;STA
RAM_CLR_SCL();
r = _WriteByte(AddrByte);
if (r != 0) {
return 1;
}
return 0;
}
/*********************************************************************
*
* _HW_Stop
*
* Function description
* Ends an I2C transaction.
*
* Parameters
* Unit Index of the hardware layer (0-based).
*
* Return value
* ==0 OK, transaction successfully ended.
* !=0 An error occurred.
*/
static int _HW_Stop(U8 Unit) {
FS_USE_PARA(Unit);
RAM_CLR_SDA();
RAM_DELAY(); // Wait tLOW
RAM_SET_SCL();
RAM_DELAY(); // Wait tSU;STO
RAM_SET_SDA();
return 0;
}
/*********************************************************************
*
* _HW_Read
*
* Function description
* Transfers data from I2C device to MCU.
*
* Parameters
* Unit Index of the hardware layer (0-based).
* pData [OUT] Data read from I2C device.
* NumBytes Number of bytes to transfer.
*
* Return value
* ==0 OK, data successfully transferred.
* !=0 An error occurred.
*/
static int _HW_Read(U8 Unit, U8 * pData, U32 NumBytes) {
FS_USE_PARA(Unit);
if (NumBytes != 0u) {
--NumBytes;
if (NumBytes != 0) {
do {
*pData++ = _ReadByte(1);
} while (--NumBytes != 0u);
}
*pData = _ReadByte(0);
}
return 0;
}
/*********************************************************************
*
* _HW_Write
*
* Function description
* Transfers data from MCU to I2C device.
*
* Parameters
* Unit Index of the hardware layer (0-based).
* pData [IN] Data written to I2C device.
* NumBytes Number of bytes to transfer.
*
* Return value
* ==0 OK, data successfully transferred.
* !=0 An error occurred.
*/
static int _HW_Write(U8 Unit, const U8 * pData, U32 NumBytes) {
int r;
FS_USE_PARA(Unit);
r = 0; // Set to indicate success.
if (NumBytes != 0u) {
do {
r = _WriteByte(*pData++);
if (r != 0) {
break;
}
} while (--NumBytes != 0u);
}
return r;
}
/*********************************************************************
*
* Public data
*
**********************************************************************
*/
/*********************************************************************
*
* FS_RAMDISK_HW_I2C_GPIO_STM32H743_SEGGER_QSPI_Flash_Evaluator
*/
const FS_RAMDISK_HW_TYPE_I2C FS_RAMDISK_HW_I2C_GPIO_STM32H743_SEGGER_QSPI_Flash_Evaluator = {
_HW_Init,
_HW_Start,
_HW_Stop,
_HW_Read,
_HW_Write
};
/*************************** End of file ****************************/
Hardware layer API - FS_RAMDISK_HW_TYPE_SPI
This hardware layer supports serial RAM devices that are interfaced via SPI.
The functions of this hardware layer are grouped in a structure of type FS_RAMDISK_HW_TYPE_SPI.
The following sections describe these functions in detail.
FS_RAMDISK_HW_TYPE_SPI
Description
HW layer for RAM devices connected via SPI (single, dual, quad or octal).
Type definition
typedef struct {
FS_RAMDISK_HW_TYPE_SPI_INIT * pfInit;
FS_RAMDISK_HW_TYPE_SPI_UNMAP * pfUnmap;
FS_RAMDISK_HW_TYPE_SPI_MAP * pfMap;
FS_RAMDISK_HW_TYPE_SPI_CONTROL * pfControl;
FS_RAMDISK_HW_TYPE_SPI_READ * pfRead;
FS_RAMDISK_HW_TYPE_SPI_WRITE * pfWrite;
FS_RAMDISK_HW_TYPE_SPI_LOCK * pfLock;
FS_RAMDISK_HW_TYPE_SPI_UNLOCK * pfUnlock;
} FS_RAMDISK_HW_TYPE_SPI;
Structure members
Member | Description |
pfInit | Initializes the hardware. |
pfUnmap | Configures the hardware for direct access to serial RAM device. |
pfMap | Configures the hardware for access to serial RAM device via system memory. |
pfControl | Sends a command to serial RAM device that does not transfer any data. |
pfRead | Transfers data from serial RAM device to MCU. |
pfWrite | Transfers data from MCU to serial RAM device. |
pfLock | Requests exclusive access to SPI bus. |
pfUnlock | Releases the exclusive access to SPI bus. |
FS_RAMDISK_HW_TYPE_SPI_INIT
Description
Initializes the SPI hardware.
Type definition
typedef int FS_RAMDISK_HW_TYPE_SPI_INIT(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
Return value
> 0 | OK, frequency of the SPI clock in Hz. |
= 0 | An error occurred. |
Additional information
This function is a member of the SPI RAMDISK hardware layer API.
It has to be implemented by all the hardware layers.
This function is called by the SPI RAMDISK physical layer before
any other function of the hardware layer each time the file system
mounts the serial RAM deice. FS_RAMDISK_HW_TYPE_SPI_INIT
has to perform the initialization of clock signals, GPIO ports,
SPI controller, etc.
FS_RAMDISK_HW_TYPE_SPI_UNMAP
Description
Configures the hardware for direct access to serial RAM device.
Type definition
typedef int FS_RAMDISK_HW_TYPE_SPI_UNMAP(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
Return value
= 0 | OK, direct mode configured successfully. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the SPI RAMDISK hardware layer API.
It has to be implemented by all the hardware layers.
The physical layer calls this function before it starts sending commands
directly to the serial RAM device. Typically, the SPI hardware can operate
in two modes: command and memory. In command mode the physical layer can
access the serial RAM device directly by sending commands to it.
In the memory mode the SPI hardware translates read accesses to an assigned
memory region to serial RAM device read commands. In this way, the contents
of the contents of the serial RAM device is mapped into this memory region.
If the command and memory mode are mutually exclusive,
FS_NOR_HW_TYPE_SPIFI_UNMAP has to disable the memory mode.
FS_RAMDISK_HW_TYPE_SPI_MAP
Description
Configures the hardware for access to serial RAM device via system memory.
Type definition
typedef int FS_RAMDISK_HW_TYPE_SPI_MAP( U8 Unit,
const U8 * pCmd,
unsigned NumBytesCmd,
const U8 * pPara,
unsigned NumBytesPara,
unsigned NumBytesAddr,
U16 BusWidth,
unsigned Flags);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
pCmd | in Code of the command to be used for reading the data. Cannot be NULL. |
NumBytesCmd | Number of bytes in the command code. Cannot be 0. |
pPara | in Command parameters (address and dummy bytes). Can be NULL. |
NumBytesPara | Total number of address and dummy bytes to be sent. Can be 0. |
NumBytesAddr | Number of address bytes to be send. Can be 0. |
BusWidth | Number of data lines to be used for the data transfer. |
Flags | Options for the data exchange. |
Return value
= 0 | OK, memory mode configured successfully. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the SPI RAMDISK hardware layer API.
The implementation of this function is mandatory if the SPI
hardware supports the access to RAM device via system memory.
If FS_RAMDISK_HW_TYPE_SPI_MAP is not provided then the SPI
RAMDISK physical layer accesses the RAM device in command mode.
Flags is a bitwise-or combination of RAMDISK HW layer flags.
FS_RAMDISK_HW_TYPE_SPI_CONTROL
Description
Sends a command to serial RAM device that does not transfer any data.
Type definition
typedef int FS_RAMDISK_HW_TYPE_SPI_CONTROL( U8 Unit,
const U8 * pCmd,
unsigned NumBytesCmd,
U8 BusWidth,
unsigned Flags);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
pCmd | in Code of the command to be sent. Cannot be NULL. |
NumBytesCmd | Number of bytes in the command code. Cannot be 0. |
BusWidth | Number of data lines to be used for sending the command. |
Flags | Options for the data exchange. |
Return value
= 0 | OK, command transferred successfully. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the SPI RAMDISK hardware layer API. The implementation
of this function is mandatory.
Flags is a bitwise-or combination of RAMDISK HW layer flags.
The value of BusWidth is not encoded as is the case with the other functions of this
physical layer. The value specified via BusWith is the actual number of data lines
that have to be used for the data transfer of the command code.
Permitted values are 1, 2, 4 and 8.
FS_RAMDISK_HW_TYPE_SPI_READ
Description
Transfers data from serial RAM device to MCU.
Type definition
typedef int FS_RAMDISK_HW_TYPE_SPI_READ( U8 Unit,
const U8 * pCmd,
unsigned NumBytesCmd,
const U8 * pPara,
unsigned NumBytesPara,
unsigned NumBytesAddr,
U8 * pData,
unsigned NumBytesData,
U16 BusWidth,
unsigned Flags);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
pCmd | in Code of the command to be sent. Cannot be NULL. |
NumBytesCmd | Number of bytes in the command code. Cannot be 0. |
pPara | in Command parameters (address and dummy bytes). Can be NULL. |
NumBytesPara | Total number of address and dummy bytes to be sent. Can be 0. |
NumBytesAddr | Number of address bytes to be send. Can be 0. |
pData | out Data read from the serial RAM device. Can be NULL. |
NumBytesData | Number of bytes to read from the serial RAM device. Can be 0. |
BusWidth | Number of data lines to be used for the data transfer. |
Flags | Options for the data exchange. |
Return value
= 0 | OK, data transferred successfully. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the SPI RAMDISK hardware layer API. The implementation
of this function is mandatory.
The first address byte is stored at *pPara. NumBytesAddr is always smaller
than or equal to NumBytesPara. If NumBytesAddr is equal to NumBytesPara then
neither mode nor dummy bytes have to be sent.
The number of dummy bytes to be generated can be calculated as NumBytesPara - NumBytesAddr.
If the hardware generates dummy cycles instead of bytes then the number
of dummy bytes has to converted to clock cycles by taking into account the number
of data lines used for the data transfer of the address.
Flags is a bitwise-or combination of RAMDISK HW layer flags.
FS_RAMDISK_HW_TYPE_SPI_WRITE
Description
Transfers data from MCU to serial RAM device.
Type definition
typedef int FS_RAMDISK_HW_TYPE_SPI_WRITE( U8 Unit,
const U8 * pCmd,
unsigned NumBytesCmd,
const U8 * pPara,
unsigned NumBytesPara,
unsigned NumBytesAddr,
const U8 * pData,
unsigned NumBytesData,
U16 BusWidth,
unsigned Flags);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
pCmd | in Code of the command to be sent. Cannot be NULL. |
NumBytesCmd | Number of bytes in the command code. Cannot be 0. |
pPara | in Command parameters (address and dummy bytes). Can be NULL. |
NumBytesPara | Total number of address and dummy bytes to be sent. Can be 0. |
NumBytesAddr | Number of address bytes to be send. Can be 0. |
pData | in Data to be sent to the serial RAM device. Can be NULL. |
NumBytesData | Number of bytes to be written the serial RAM device. Can be 0. |
BusWidth | Number of data lines to be used for the data transfer. |
Flags | Options for the data exchange. |
Return value
= 0 | OK, data transferred successfully. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the SPI RAMDISK hardware layer API. The implementation
of this function is mandatory.
The first address byte is stored at *pPara. NumBytesAddr is always smaller
than or equal to NumBytesPara.
Flags is a bitwise-or combination of RAMDISK HW layer flags.
FS_RAMDISK_HW_TYPE_SPI_LOCK
Description
Requests exclusive access to SPI bus.
Type definition
typedef void FS_RAMDISK_HW_TYPE_SPI_LOCK(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
Additional information
This function is a member of the SPIFI NOR hardware layer API.
The implementation of this function is optional.
The NOR physical layer calls this function to indicate that it
needs exclusive to access the NOR flash device via the SPI bus.
It is guaranteed that the NOR physical layer does not attempt to
exchange any data with the serial NOR flash device via the SPI bus
before calling this function first. It is also guaranteed that
FS_RAMDISK_HW_TYPE_SPI_LOCK and FS_RAMDISK_HW_TYPE_SPI_UNLOCK are called in pairs.
Typically, this function is used for synchronizing the access to SPI bus
when the SPI bus is shared between the serial NOR flash and other SPI devices.
A possible implementation would make use of an OS semaphore that is
acquired in FS_RAMDISK_HW_TYPE_SPI_LOCK and released in FS_RAMDISK_HW_TYPE_SPI_UNLOCK.
FS_RAMDISK_HW_TYPE_SPI_UNLOCK
Description
Requests exclusive access to SPI bus.
Type definition
typedef void FS_RAMDISK_HW_TYPE_SPI_UNLOCK(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
Additional information
This function is a member of the SPIFI NOR hardware layer API.
The implementation of this function is optional.
The NOR physical layer calls this function when it no longer needs
to access the serial NOR flash device via the SPI bus. It is guaranteed
that the NOR physical layer does not attempt to exchange any data with
the serial NOR flash device via the SPI bus before calling FS_RAMDISK_HW_TYPE_SPI_LOCK.
It is also guaranteed that FS_RAMDISK_HW_TYPE_SPI_UNLOCK and
FS_RAMDISK_HW_TYPE_SPI_LOCK are called in pairs.
FS_RAMDISK_HW_TYPE_SPI_UNLOCK and FS_RAMDISK_HW_TYPE_SPI_LOCK can be used to
synchronize the access to the SPI bus when other devices than the
serial NOR flash are connected to it. A possible implementation would
make use of an OS semaphore that is acquired FS_RAMDISK_HW_TYPE_SPI_LOCK
and released in FS_RAMDISK_HW_TYPE_SPI_UNLOCK.
Sample implementation
The following sample implementation uses the QUADSPI controller of an ST STM32H743 MCU
to interface with a SPI RAM device. This RAMDISK hardware layer was tested on the
SGGER QSPI Flash Evaluator board (https://www.segger.com/evaluate-our-software/segger/qspi-flash-evaluator/)
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : FS_RAMDISK_HW_SPI_STM32H743_SEGGER_QSPI_Flash_Evaluator.c
Purpose : Hardware layer for SEGGER QSPI Flash Evaluator
with RAM device connected via SPI.
Literature:
[1] RM0433 Reference manual STM32H7x3 advanced ARM-based 32-bit MCUs
[2] STM32H753xI Errata sheet STM32H753xI rev Y device limitations
*/
/*********************************************************************
*
* #include section
*
**********************************************************************
*/
#include "FS.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#ifndef FS_RAMDISK_HW_PER_CLK_HZ
#define FS_RAMDISK_HW_PER_CLK_HZ 240000000 // Clock of Quad-SPI unit.
#endif
#ifndef FS_RAMDISK_HW_RAM_CLK_HZ
#define FS_RAMDISK_HW_RAM_CLK_HZ 48000000 // Frequency of the clock supplied to RAM device.
#endif
#ifndef FS_RAMDISK_HW_QUADSPI_MEM_ADDR
#define FS_RAMDISK_HW_QUADSPI_MEM_ADDR 0x90000000 // This is the start address of the memory region used by the file system
// to read the data from the serial RAM device. The hardware layer
// uses this address to invalidate the data cache.
#endif
#ifndef FS_RAMDISK_HW_USE_QUAD_MODE
#define FS_RAMDISK_HW_USE_QUAD_MODE 1 // Enables/disables the support for quad mode.
#endif
#ifndef FS_RAMDISK_HW_USE_MEM_MAP_MODE
#define FS_RAMDISK_HW_USE_MEM_MAP_MODE 1 // Enables or disables the access to the RAM device data via system memory.
#endif
#ifndef FS_RAMDISK_HW_RESET_TIME_MS
#define FS_RAMDISK_HW_RESET_TIME_MS 10 // Number milliseconds to keep the reset line low.
#endif
/*********************************************************************
*
* Defines, fixed
*
**********************************************************************
*/
/*********************************************************************
*
* QSPI registers
*/
#define QUADSPI_BASE_ADDR 0x52005000uL
#define QUADSPI_CR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x00))
#define QUADSPI_DCR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x04))
#define QUADSPI_SR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x08))
#define QUADSPI_FCR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x0C))
#define QUADSPI_DLR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x10))
#define QUADSPI_CCR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x14))
#define QUADSPI_AR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x18))
#define QUADSPI_ABR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x1C))
#define QUADSPI_DR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x20))
#define QUADSPI_DR_BYTE (*(volatile U8 *)(QUADSPI_BASE_ADDR + 0x20))
#define QUADSPI_PSMKR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x24))
#define QUADSPI_PSMAR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x28))
#define QUADSPI_PIR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x2C))
#define QUADSPI_LPTR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x30))
/*********************************************************************
*
* Port B registers
*/
#define GPIOB_BASE_ADDR 0x58020400uL
#define GPIOB_MODER (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x00))
#define GPIOB_OSPEEDR (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x08))
#define GPIOB_PUPDR (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x0C))
#define GPIOB_ODR (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x14))
#define GPIOB_AFRL (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x20))
/*********************************************************************
*
* Port F registers
*/
#define GPIOF_BASE_ADDR 0x58021400uL
#define GPIOF_MODER (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x00))
#define GPIOF_OSPEEDR (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x08))
#define GPIOF_PUPDR (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x0C))
#define GPIOF_ODR (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x14))
#define GPIOF_BSRR (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x18))
#define GPIOF_AFRL (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x20))
#define GPIOF_AFRH (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x24))
/*********************************************************************
*
* Reset and clock control
*/
#define RCC_BASE_ADDR 0x58024400uL
#define RCC_AHB3RSTR (*(volatile U32*)(RCC_BASE_ADDR + 0x7C))
#define RCC_AHB3ENR (*(volatile U32*)(RCC_BASE_ADDR + 0xD4))
#define RCC_AHB4ENR (*(volatile U32*)(RCC_BASE_ADDR + 0xE0))
/*********************************************************************
*
* System Control Block
*/
#define SCB_BASE_ADDR 0xE000E000uL
#define SCB_CCR (*(volatile U32 *)(SCB_BASE_ADDR + 0xD14)) // Configuration Control Register
/*********************************************************************
*
* Memory protection unit
*/
#define MPU_BASE_ADDR 0xE000ED90uL
#define MPU_TYPE (*(volatile U32 *)(MPU_BASE_ADDR + 0x00))
#define MPU_CTRL (*(volatile U32 *)(MPU_BASE_ADDR + 0x04))
#define MPU_RNR (*(volatile U32 *)(MPU_BASE_ADDR + 0x08))
#define MPU_RBAR (*(volatile U32 *)(MPU_BASE_ADDR + 0x0C))
#define MPU_RASR (*(volatile U32 *)(MPU_BASE_ADDR + 0x10))
/*********************************************************************
*
* Masks for the peripheral enable bits
*/
#define AHB1ENR_GPIOBEN 1
#define AHB1ENR_GPIOFEN 5
#define AHB3ENR_QSPIEN 14
/*********************************************************************
*
* GPIO bit positions of SPI signals
*/
#define RAM_BK1_NCS_BIT 6 // Port B
#define RAM_CLK_BIT 10 // Port F
#define RAM_BK1_D0_BIT 8 // Port F
#define RAM_BK1_D1_BIT 9 // Port F
#define RAM_BK1_D2_BIT 7 // Port F
#define RAM_BK1_D3_BIT 6 // Port F
#define RAM_MP6_BIT 3 // Port F
#define RAM_RST_BIT 11 // Port F
/*********************************************************************
*
* GPIO bits and masks
*/
#define OSPEEDR_HIGH 2uL
#define OSPEEDR_MASK 0x3uL
#define MODER_MASK 0x3uL
#define MODER_OUT 1uL
#define MODER_ALT 2uL
#define AFR_MASK 0xFuL
/*********************************************************************
*
* Quad-SPI control register
*/
#define CR_EN_BIT 0
#define CR_ABORT_BIT 1
#define CR_SSHIFT_BIT 4
#define CR_SMIE_BIT 19
#define CR_APMS_BIT 22
#define CR_PRESCALER_BIT 24
#define CR_PRESCALER_MAX 255
/*********************************************************************
*
* Quad-SPI device configuration register
*/
#define DCR_CKMODE_BIT 0
#define DCR_FSIZE_BIT 16
#define DCR_FSIZE_MAX 0x1FuL
/*********************************************************************
*
* Quad-SPI status register
*/
#define SR_TEF_BIT 0
#define SR_TCF_BIT 1
#define SR_SMF_BIT 3
#define SR_TOF_BIT 4
#define SR_BUSY_BIT 5
#define SR_FLEVEL_BIT 8
#define SR_FLEVEL_MASK 0x3FuL
/*********************************************************************
*
* Quad-SPI communication configuration register
*/
#define CCR_INTRUCTION_BIT 0
#define CCR_IMODE_BIT 8
#define CCR_MODE_NONE 0
#define CCR_MODE_SINGLE 1uL
#define CCR_MODE_DUAL 2uL
#define CCR_MODE_QUAD 3uL
#define CCR_ADMODE_BIT 10
#define CCR_ADSIZE_BIT 12
#define CCR_ADSIZE_MASK 0x03uL
#define CCR_ABMODE_BIT 14
#define CCR_ABSIZE_BIT 16
#define CCR_ABSIZE_MASK 0x03uL
#define CCR_DCYC_BIT 18
#define CCR_DMODE_BIT 24
#define CCR_FMODE_BIT 26
#define CCR_FMODE_WRITE 0x0uL
#define CCR_FMODE_READ 0x1uL
#define CCR_FMODE_POLL 0x2uL
#define CCR_FMODE_MMAP 0x3uL
#define CCR_FMODE_MASK 0x3uL
#define CCR_DDRM_BIT 31
/*********************************************************************
*
* MPU defines
*/
#define CTRL_ENABLE_BIT 0
#define CTRL_PRIVDEFENA_BIT 2
#define RNR_REGION_MASK 0xFF
#define RASR_ENABLE_BIT 0
#define RASR_SIZE_BIT 1
#define RASR_TEX_BIT 19
#define RASR_AP_BIT 24
#define RASR_XN_BIT 28
#define RASR_AP_FULL 0x3uL
#define TYPE_DREGION_BIT 8
#define TYPE_DREGION_MASK 0xFFuL
#define RBAR_REGION_BIT 0
#define RBAR_REGION_MASK 0x1FuL
#define RBAR_VALID_BIT 5
/*********************************************************************
*
* Misc. defines
*/
#define NUM_BYTES_FIFO 32
#define CCR_DC_BIT 16
#define QUADSPI_MEM_SIZE_SHIFT 28 // Size of the memory region reserved for QUADSPI (256 MB)
#define QUADSPI_PRIO 15
#define CYCLES_PER_MS 150000 // Depends on the CPU clock frequency.
#define WAIT_TIMEOUT_MS 500
#define WAIT_TIMEOUT_CYCLES (WAIT_TIMEOUT_MS * CYCLES_PER_MS)
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _CalcClockDivider
*
* Function description
* Calculates the divider for the clock supplied to RAM device.
*/
static U8 _CalcClockDivider(U32 * pFreq_Hz) {
U8 Div;
U32 Freq_Hz;
U32 MaxFreq_Hz;
Div = 0;
MaxFreq_Hz = *pFreq_Hz;
for (;;) {
Freq_Hz = FS_RAMDISK_HW_PER_CLK_HZ / (Div + 1);
if (Freq_Hz <= MaxFreq_Hz) {
break;
}
++Div;
if (Div == CR_PRESCALER_MAX) {
break;
}
}
*pFreq_Hz = Freq_Hz;
return Div;
}
/*********************************************************************
*
* _GetMode
*
* Function description
* Returns the transfer mode for the QUADSPI peripheral.
*/
static U32 _GetMode(unsigned BusWidth, U32 NumBytes) {
U32 Mode;
Mode = CCR_MODE_NONE;
if (NumBytes) {
switch (BusWidth) {
case 1:
Mode = CCR_MODE_SINGLE;
break;
case 2:
Mode = CCR_MODE_DUAL;
break;
case 4:
Mode = CCR_MODE_QUAD;
break;
default:
break;
}
}
return Mode;
}
/*********************************************************************
*
* _CalcNumCycles
*
* Function description
* Calculates the number of clock cycles required to transfer a specified number of bytes.
*/
static U32 _CalcNumCycles(unsigned BusWidth, U32 NumBytes, int IsDTRMode) {
U32 NumCycles;
NumCycles = 0;
if (NumBytes != 0) {
NumCycles = NumBytes << 3; // Assume 8-bits per byte.
switch (BusWidth) {
case 2:
NumCycles >>= 1;
break;
case 4:
NumCycles >>= 2;
break;
default:
break;
}
if (IsDTRMode != 0) {
NumCycles >>= 1; // The data is sent on both clock edges.
}
}
return NumCycles;
}
/*********************************************************************
*
* _ClearFlags
*
* Function description
* Clears the status flags of QUADSPI peripheral.
*/
static int _ClearFlags(void) {
U32 TimeOut;
int r;
QUADSPI_FCR = 0
| (1uL << SR_TEF_BIT)
| (1uL << SR_TCF_BIT)
| (1uL << SR_SMF_BIT)
| (1uL << SR_TOF_BIT)
;
//
// Wait for the flags to be cleared.
//
r = 0;
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if ((QUADSPI_SR & ((1uL << SR_TEF_BIT) |
(1uL << SR_TCF_BIT) |
(1uL << SR_SMF_BIT) |
(1uL << SR_TOF_BIT))) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, could not clear flags.
break;
}
}
return r;
}
/*********************************************************************
*
* _Cancel
*
* Function description
* Interrupts an ongoing data transfer.
*/
static int _Cancel(void) {
U32 TimeOut;
int r;
r = 0;
TimeOut = WAIT_TIMEOUT_CYCLES;
QUADSPI_CR |= 1uL << CR_ABORT_BIT;
for (;;) {
if ((QUADSPI_CR & (1uL << CR_ABORT_BIT)) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, could not cancel data transfer.
break;
}
}
return r;
}
/*********************************************************************
*
* _DisableDCache
*
* Function description
* Disables the data cache for the memory region where the RAM device is mapped.
*/
static void _DisableDCache(void) {
U32 NumRegions;
U32 iRegion;
U32 Mask;
if (SCB_CCR & (1uL << CCR_DC_BIT)) { // Is data cache enabled?
NumRegions = (MPU_TYPE >> TYPE_DREGION_BIT) & TYPE_DREGION_MASK;
//
// Find the next free region.
//
for (iRegion = 0; iRegion < NumRegions; ++iRegion) {
MPU_RNR = iRegion;
if ((MPU_RASR & (1uL << RASR_ENABLE_BIT)) == 0) {
break; // Found a free region.
}
//
// Check if we already configured the MPU.
//
Mask = 0uL
| (RBAR_REGION_MASK << RBAR_REGION_BIT)
| (1uL << RBAR_VALID_BIT)
;
if ((MPU_RBAR & ~Mask) == FS_RAMDISK_HW_QUADSPI_MEM_ADDR) {
iRegion = NumRegions;
break; // Already configured.
}
}
if (iRegion < NumRegions) {
//
// Use MPU to disable the data cache on the memory region assigned to QSPI.
//
MPU_CTRL &= ~(1uL << CTRL_ENABLE_BIT); // Disable MPU first.
MPU_RNR = iRegion & RNR_REGION_MASK;
MPU_RBAR = FS_RAMDISK_HW_QUADSPI_MEM_ADDR;
MPU_RASR = 0
| (1uL << RASR_XN_BIT)
| (RASR_AP_FULL << RASR_AP_BIT)
| (1uL << RASR_TEX_BIT)
| ((QUADSPI_MEM_SIZE_SHIFT - 1) << RASR_SIZE_BIT)
| (1uL << RASR_ENABLE_BIT)
;
//
// Enable MPU.
//
MPU_CTRL |= 0
| (1uL << CTRL_PRIVDEFENA_BIT)
| (1uL << CTRL_ENABLE_BIT)
;
}
}
}
/*********************************************************************
*
* Static code (public via callback)
*
**********************************************************************
*/
/*********************************************************************
*
* _HW_Init
*
* Function description
* Initializes the SPI hardware.
*
* Parameters
* Unit Index of the hardware layer (0-based).
*
* Return value
* > 0 OK, frequency of the SPI clock in Hz.
* ==0 An error occurred.
*/
static int _HW_Init(U8 Unit) {
U32 Div;
U32 Freq_Hz;
FS_USE_PARA(Unit);
//
// Enable the clocks of peripherals and reset them.
//
RCC_AHB4ENR |= 0
| (1uL << AHB1ENR_GPIOBEN)
| (1uL << AHB1ENR_GPIOFEN)
;
RCC_AHB3ENR |= 1uL << AHB3ENR_QSPIEN;
RCC_AHB3RSTR |= 1uL << AHB3ENR_QSPIEN;
RCC_AHB3RSTR &= ~(1uL << AHB3ENR_QSPIEN);
//
// Wait for the unit to exit reset.
//
for (;;) {
if ((RCC_AHB3RSTR & (1uL << AHB3ENR_QSPIEN)) == 0) {
break;
}
}
//
// Disable the cache on the memory region assigned to QSPI.
//
_DisableDCache();
//
// NCS of bank 1 is an output signal and is controlled by the QUADSPI unit.
//
GPIOB_MODER &= ~(MODER_MASK << (RAM_BK1_NCS_BIT << 1));
GPIOB_MODER |= MODER_ALT << (RAM_BK1_NCS_BIT << 1);
GPIOB_AFRL &= ~(AFR_MASK << (RAM_BK1_NCS_BIT << 2));
GPIOB_AFRL |= 0xAuL << (RAM_BK1_NCS_BIT << 2);
GPIOB_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_NCS_BIT << 1));
GPIOB_OSPEEDR |= OSPEEDR_HIGH << (RAM_BK1_NCS_BIT << 1);
//
// CLK is an output signal controlled by the QUADSPI unit.
//
GPIOF_MODER &= ~(MODER_MASK << (RAM_CLK_BIT << 1));
GPIOF_MODER |= MODER_ALT << (RAM_CLK_BIT << 1);
GPIOF_AFRH &= ~(AFR_MASK << ((RAM_CLK_BIT - 8) << 2));
GPIOF_AFRH |= 0x9uL << ((RAM_CLK_BIT - 8) << 2);
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_CLK_BIT << 1));
GPIOF_OSPEEDR |= OSPEEDR_HIGH << (RAM_CLK_BIT << 1);
//
// D0 of bank 1 is an input/output signal controlled by the QUADSPI unit.
//
GPIOF_MODER &= ~(MODER_MASK << (RAM_BK1_D0_BIT << 1));
GPIOF_MODER |= MODER_ALT << (RAM_BK1_D0_BIT << 1);
GPIOF_AFRH &= ~(AFR_MASK << ((RAM_BK1_D0_BIT - 8) << 2));
GPIOF_AFRH |= 0xAuL << ((RAM_BK1_D0_BIT - 8) << 2);
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_D0_BIT << 1));
GPIOF_OSPEEDR |= OSPEEDR_HIGH << (RAM_BK1_D0_BIT << 1);
//
// D1 of bank 1 is an input/output signal controlled by the QUADSPI unit.
//
GPIOF_MODER &= ~(MODER_MASK << (RAM_BK1_D1_BIT << 1));
GPIOF_MODER |= MODER_ALT << (RAM_BK1_D1_BIT << 1);
GPIOF_AFRH &= ~(AFR_MASK << ((RAM_BK1_D1_BIT - 8) << 2));
GPIOF_AFRH |= 0xAuL << ((RAM_BK1_D1_BIT - 8) << 2);
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_D1_BIT << 1));
GPIOF_OSPEEDR |= OSPEEDR_HIGH << (RAM_BK1_D1_BIT << 1);
#if FS_RAMDISK_HW_USE_QUAD_MODE
//
// D2 of bank 1 is an input/output signal and is controlled by the QUADSPI unit.
//
GPIOF_MODER &= ~(MODER_MASK << (RAM_BK1_D2_BIT << 1));
GPIOF_MODER |= MODER_ALT << (RAM_BK1_D2_BIT << 1);
GPIOF_AFRL &= ~(AFR_MASK << (RAM_BK1_D2_BIT << 2));
GPIOF_AFRL |= 0x9uL << (RAM_BK1_D2_BIT << 2);
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_D2_BIT << 1));
GPIOF_OSPEEDR |= OSPEEDR_HIGH << (RAM_BK1_D2_BIT << 1);
//
// D3 of bank 1 is an output signal and is controlled by the QUADSPI unit.
//
GPIOF_MODER &= ~(MODER_MASK << (RAM_BK1_D3_BIT << 1));
GPIOF_MODER |= MODER_ALT << (RAM_BK1_D3_BIT << 1);
GPIOF_AFRL &= ~(AFR_MASK << (RAM_BK1_D3_BIT << 2));
GPIOF_AFRL |= 0x9uL << (RAM_BK1_D3_BIT << 2);
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_D3_BIT << 1));
GPIOF_OSPEEDR |= OSPEEDR_HIGH << (RAM_BK1_D3_BIT << 1);
#else
//
// D2 and D3 are used as WP and HOLD signals when the quad mode
// is disabled in the RAM device. We set these signals to
// logic high here so that the data transfer works correctly
// in single and dual mode.
//
GPIOF_BSRR = 1uL << RAM_BK1_D2_BIT;
GPIOF_MODER &= ~(MODER_MASK << (RAM_BK1_D2_BIT << 1));
GPIOF_MODER |= MODER_OUT << (RAM_BK1_D2_BIT << 1);
GPIOF_AFRL &= ~(AFR_MASK << (RAM_BK1_D2_BIT << 2));
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_D2_BIT << 1));
GPIOF_BSRR = 1uL << RAM_BK1_D3_BIT;
GPIOF_MODER &= ~(MODER_MASK << (RAM_BK1_D3_BIT << 1));
GPIOF_MODER |= MODER_OUT << (RAM_BK1_D3_BIT << 1);
GPIOF_AFRL &= ~(AFR_MASK << (RAM_BK1_D3_BIT << 2));
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_BK1_D3_BIT << 1));
#endif // FS_RAMDISK_HW_USE_QUAD_MODE
//
// The MP6 is the signal connected to the pin 6 of the RAM device
// which is used by some dual stack devices as the chip select signal
// for the second stack. We have to disable the second stack
// by setting the MP6 signal to high in order to prevent that the
// second stack is accidentally activated.
//
GPIOF_BSRR = 1uL << RAM_MP6_BIT;
GPIOF_MODER &= ~(MODER_MASK << (RAM_MP6_BIT << 1));
GPIOF_MODER |= MODER_OUT << (RAM_MP6_BIT << 1);
GPIOF_AFRL &= ~(AFR_MASK << (RAM_MP6_BIT << 2));
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_MP6_BIT << 1));
//
// Set the RST signal to high to make sure that the RAM
// device is not accidentally reset during the data transfer.
//
GPIOF_BSRR = 1uL << RAM_RST_BIT;
GPIOF_MODER &= ~(MODER_MASK << (RAM_RST_BIT << 1));
GPIOF_MODER |= MODER_OUT << (RAM_RST_BIT << 1);
GPIOF_AFRH &= ~(AFR_MASK << ((RAM_RST_BIT - 8) << 2));
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (RAM_RST_BIT << 1));
//
// Initialize the Quad-SPI controller.
//
Freq_Hz = FS_RAMDISK_HW_RAM_CLK_HZ;
Div = (U32)_CalcClockDivider(&Freq_Hz);
QUADSPI_CR = 0
| (1uL << CR_EN_BIT) // Enable the Quad-SPI unit.
| (Div << CR_PRESCALER_BIT)
;
QUADSPI_DCR = 0
| (1uL << DCR_CKMODE_BIT) // CLK signal stays HIGH when the RAM device is not selected.
| (DCR_FSIZE_MAX << DCR_FSIZE_BIT) // We set the size of the RAM device to maximum because the actual capacity is not known at this stage.
;
#if FS_RAMDISK_HW_RESET_TIME_MS
{
volatile U32 NumCycles;
GPIOF_BSRR = 1uL << (RAM_RST_BIT + 16); // Put the RAM device into reset state by setting the signal to low.
NumCycles = FS_RAMDISK_HW_RESET_TIME_MS * CYCLES_PER_MS;
do {
;
} while (--NumCycles != 0u);
GPIOF_BSRR = 1uL << RAM_RST_BIT; // Release the RAM device from the reset state by setting reset signal to high.
NumCycles = FS_RAMDISK_HW_RESET_TIME_MS * CYCLES_PER_MS;
do {
;
} while (--NumCycles != 0u);
}
#endif // FS_RAMDISK_HW_RESET_TIME_MS
return (int)Freq_Hz;
}
/*********************************************************************
*
* _HW_Unmap
*
* Function description
* Enables the direct access to RAM device.
*
* Parameters
* Unit Index of the hardware layer (0-based).
*
* Return value
* ==0 OK, command mode configured successfully.
* !=0 An error occurred.
*
* Additional information
* This function disables the memory-mapped mode.
*/
static int _HW_Unmap(U8 Unit) {
int r;
FS_USE_PARA(Unit); // This device has only one HW unit.
r = 0;
//
// Restore the default sampling mode.
//
QUADSPI_CR &= ~(1uL << CR_SSHIFT_BIT);
//
// Cancel the memory mode so that the BUSY bit goes to 0
// and we can write to QUADSPI_CCR register.
//
if ((QUADSPI_CCR & (CCR_FMODE_MASK << CCR_FMODE_BIT)) == (CCR_FMODE_MMAP << CCR_FMODE_BIT)) {
r = _Cancel();
}
return r;
}
#if FS_RAMDISK_HW_USE_MEM_MAP_MODE
/*********************************************************************
*
* _HW_Map
*
* Function description
* Configures the hardware for access to serial RAM device via system memory.
*
* Parameters
* Unit Index of the hardware layer (0-based).
* pCmd [IN] Code of the command to be used for reading the data. Cannot be NULL.
* NumBytesCmd Number of bytes in the command code. Cannot be 0.
* pPara [IN] Command parameters (address and dummy bytes). Can be NULL.
* NumBytesPara Total number of address and dummy bytes to be sent. Can be 0.
* NumBytesAddr Number of address bytes to be send. Can be 0.
* BusWidth Number of data lines to be used for the data transfer.
* Flags Options for the data exchange.
*
* Return value
* ==0 OK, memory mode configured successfully.
* !=0 An error occurred.
*/
static int _HW_Map(U8 Unit, const U8 * pCmd, unsigned NumBytesCmd, const U8 * pPara,
unsigned NumBytesPara, unsigned NumBytesAddr, U16 BusWidth, unsigned Flags) {
U32 CfgReg;
U32 CmdMode;
U32 AddrMode;
U32 DataMode;
U32 NumDummyCycles;
U32 AddrSize;
U32 IsDTR;
U32 AltMode;
U32 AltSize;
U32 NumBytesAlt;
U32 NumBytes;
U32 AltReg;
int r;
U32 TimeOut;
FS_USE_PARA(Unit); // This MCU has only one QSPI controller.
FS_USE_PARA(pPara);
FS_DEBUG_ASSERT(FS_MTYPE_DRIVER, NumBytesCmd == 1u); // The QSPI controller is able to handle only 1-byte commands.
//
// Fill local variables.
//
r = 0;
AltReg = 0;
NumBytesAlt = NumBytesPara - NumBytesAddr;
//
// Calculate the transfer mode.
//
IsDTR = 0;
if ( ((Flags & FS_RAMDISK_HW_FLAG_DTR_ADDR) != 0u)
|| ((Flags & FS_RAMDISK_HW_FLAG_DTR_DATA) != 0u)) {
IsDTR = 1;
}
//
// Encode the mode and dummy bytes.
//
NumDummyCycles = 0;
if (NumBytesAlt != 0) {
NumBytes = NumBytesAlt;
//
// Check if a mode byte has to be sent and if yes encode its value.
//
if ((Flags & FS_RAMDISK_HW_FLAG_MODE_8BIT) != 0u) {
NumBytes = NumBytesAlt - 1u;
NumBytesAlt = 1; // We never send more than one mode byte.
if (pPara != NULL) {
AltReg = (U32)*pPara;
} else {
AltReg = 0xFFuL;
}
} else {
NumBytesAlt = 0;
}
if (NumBytes != 0u) {
//
// The remaining alternate bytes are not sent. Instead, we generate dummy cycles.
//
NumDummyCycles = _CalcNumCycles(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytes, IsDTR);
}
}
//
// It seems that QUADSPI is driving the data lines one half of the clock
// cycle longer than required. This can cause that a wrong value is
// sampled immediately after a data line is switched from output to input.
// For this reason we configure QUADSPI to sample the data later than default.
//
if ((IsDTR == 0) && (NumBytesAlt != 0) && (NumDummyCycles == 0) ) {
QUADSPI_CR |= 1uL << CR_SSHIFT_BIT;
}
//
// Calculate the number of data lines to be used for the transfer.
//
CmdMode = _GetMode(FS_BUSWIDTH_GET_CMD(BusWidth), NumBytesCmd);
AddrMode = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAddr);
AltMode = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAlt);
DataMode = _GetMode(FS_BUSWIDTH_GET_DATA(BusWidth), 1); // We always read at least one byte.
//
// Calculate the number of bytes in each command phase.
//
AddrSize = 0;
if (NumBytesAddr) {
AddrSize = (NumBytesAddr - 1) & CCR_ADSIZE_MASK;
}
AltSize = 0;
if (NumBytesAlt) {
AltSize = (NumBytesAlt - 1) & CCR_ABSIZE_MASK;
}
//
// Configure the operation.
//
CfgReg = 0
| (CCR_FMODE_MMAP << CCR_FMODE_BIT)
| (DataMode << CCR_DMODE_BIT)
| (AddrSize << CCR_ADSIZE_BIT)
| (AddrMode << CCR_ADMODE_BIT)
| (AltSize << CCR_ABSIZE_BIT)
| (AltMode << CCR_ABMODE_BIT)
| (NumDummyCycles << CCR_DCYC_BIT)
| (IsDTR << CCR_DDRM_BIT)
| (CmdMode << CCR_IMODE_BIT)
| (*pCmd << CCR_INTRUCTION_BIT)
;
//
// Wait until the unit is ready for the new command.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, QUADSPI is not ready.
goto Done;
}
}
r = _ClearFlags();
if (r != 0) {
goto Done; // Error, could not clear status flags.
}
QUADSPI_ABR = AltReg;
QUADSPI_CCR = CfgReg;
Done:
return r;
}
#endif // FS_RAMDISK_HW_USE_MEM_MAP_MODE
/*********************************************************************
*
* _HW_Control
*
* Function description
* Sends a command to serial RAM device that does not transfer any data.
*
* Parameters
* Unit Index of the hardware layer (0-based).
* pCmd [IN] Code of the command to be sent. Cannot be NULL.
* NumBytesCmd Number of bytes in the command code. Cannot be 0.
* BusWidth Number of data lines to be used for sending the command.
* Flags Options for the data exchange.
*
* Return value
* ==0 OK, command transferred successfully.
* !=0 An error occurred.
*/
static int _HW_Control(U8 Unit, const U8 * pCmd, unsigned NumBytesCmd, U8 BusWidth, unsigned Flags) {
U32 CfgReg;
U32 CmdMode;
U32 TimeOut;
int r;
FS_USE_PARA(Unit); // This MCU has only one QSPI controller.
FS_USE_PARA(Flags);
FS_DEBUG_ASSERT(FS_MTYPE_DRIVER, NumBytesCmd == 1u); // The QSPI controller is able to handle only 1-byte commands.
//
// Fill local variables.
//
r = 0;
CmdMode = _GetMode(BusWidth, NumBytesCmd);
CfgReg = 0
| (CCR_FMODE_WRITE << CCR_FMODE_BIT)
| (CmdMode << CCR_IMODE_BIT)
| (*pCmd << CCR_INTRUCTION_BIT)
;
//
// Wait until the unit is ready for the new command.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, QUADSPI is not ready.
goto Done;
}
}
//
// Execute the command.
//
r = _ClearFlags();
if (r != 0) {
goto Done; // Error, could not clear status flags.
}
QUADSPI_DLR = 0;
QUADSPI_ABR = 0;
QUADSPI_CCR = CfgReg;
//
// Wait until the command has been completed.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, QUADSPI is not ready.
break;
}
}
Done:
return r;
}
/*********************************************************************
*
* _HW_Read
*
* Function description
* Transfers data from serial RAM device to MCU.
*
* Parameters
* Unit Index of the hardware layer (0-based).
* pCmd [IN] Code of the command to be sent. Cannot be NULL.
* NumBytesCmd Number of bytes in the command code. Cannot be 0.
* pPara [IN] Command parameters (address and dummy bytes). Can be NULL.
* NumBytesPara Total number of address and dummy bytes to be sent. Can be 0.
* NumBytesAddr Number of address bytes to be send. Can be 0.
* pData [OUT] Data read from the serial RAM device. Can be NULL.
* NumBytesData Number of bytes to read from the serial RAM device. Can be 0.
* BusWidth Number of data lines to be used for the data transfer.
* Flags Options for the data exchange.
*
* Return value
* ==0 OK, data transferred successfully.
* !=0 An error occurred.
*/
static int _HW_Read(U8 Unit, const U8 * pCmd, unsigned NumBytesCmd, const U8 * pPara, unsigned NumBytesPara,
unsigned NumBytesAddr, U8 * pData, unsigned NumBytesData, U16 BusWidth, unsigned Flags) {
U32 AddrReg;
U32 AltReg;
U32 CfgReg;
U32 DataMode;
U32 AddrMode;
U32 AltMode;
U32 CmdMode;
U32 DataReg;
U32 AltSize;
U32 AddrSize;
U32 NumBytesAvail;
U32 NumBytes;
U32 NumBytesAlt;
U32 IsDTR;
U32 NumDummyCycles;
U32 TimeOut;
int r;
FS_USE_PARA(Unit); // This MCU has only one QSPI controller.
FS_DEBUG_ASSERT(FS_MTYPE_DRIVER, NumBytesCmd == 1u); // The QSPI controller is able to handle only 1-byte commands.
//
// Fill local variables.
//
r = 0;
AddrReg = 0;
AltReg = 0;
NumBytesAlt = NumBytesPara - NumBytesAddr;
//
// Calculate the transfer mode.
//
IsDTR = 0;
if ( ((Flags & FS_RAMDISK_HW_FLAG_DTR_ADDR) != 0u)
|| ((Flags & FS_RAMDISK_HW_FLAG_DTR_DATA) != 0u)) {
IsDTR = 1;
}
//
// Encode the address.
//
if (NumBytesAddr) {
NumBytes = NumBytesAddr;
do {
AddrReg <<= 8;
AddrReg |= (U32)(*pPara++);
} while (--NumBytes);
}
//
// Encode the mode and dummy bytes.
//
NumDummyCycles = 0;
if (NumBytesAlt != 0) {
NumBytes = NumBytesAlt;
//
// Check if a mode byte has to be sent and if yes encode its value.
//
if ((Flags & FS_RAMDISK_HW_FLAG_MODE_8BIT) != 0u) {
NumBytes = NumBytesAlt - 1u;
NumBytesAlt = 1; // We never send more than one mode byte.
if (pPara != NULL) {
AltReg = (U32)*pPara;
} else {
AltReg = 0xFFuL;
}
} else {
NumBytesAlt = 0;
}
if (NumBytes != 0u) {
//
// The remaining alternate bytes are not sent. Instead, we generate dummy cycles.
//
NumDummyCycles = _CalcNumCycles(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytes, IsDTR);
}
}
//
// Calculate the number of data lines to be used for the transfer.
//
CmdMode = _GetMode(FS_BUSWIDTH_GET_CMD(BusWidth), NumBytesCmd);
AddrMode = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAddr);
AltMode = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAlt);
DataMode = _GetMode(FS_BUSWIDTH_GET_DATA(BusWidth), NumBytesData);
//
// Calculate the number of bytes in each command phase.
//
AddrSize = 0;
if (NumBytesAddr) {
AddrSize = (NumBytesAddr - 1) & CCR_ADSIZE_MASK;
}
AltSize = 0;
if (NumBytesAlt) {
AltSize = (NumBytesAlt - 1) & CCR_ABSIZE_MASK;
}
//
// Configure the operation.
//
CfgReg = 0
| (CCR_FMODE_READ << CCR_FMODE_BIT)
| (DataMode << CCR_DMODE_BIT)
| (AltSize << CCR_ABSIZE_BIT)
| (AltMode << CCR_ABMODE_BIT)
| (AddrSize << CCR_ADSIZE_BIT)
| (AddrMode << CCR_ADMODE_BIT)
| (NumDummyCycles << CCR_DCYC_BIT)
| (IsDTR << CCR_DDRM_BIT)
| (CmdMode << CCR_IMODE_BIT)
| (*pCmd << CCR_INTRUCTION_BIT)
;
//
// Wait until the unit is ready for the new command.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, QUADSPI is not ready.
goto Done;
}
}
//
// It seems that QUADSPI is driving the data lines one half of the clock
// cycle longer than required. This can cause that a wrong value is
// sampled immediately after a data line is switched from output to input.
// For this reason we configure QUADSPI to sample the data later than default.
//
if ((IsDTR == 0) && (NumBytesAlt != 0) && (NumDummyCycles == 0) ) {
QUADSPI_CR |= 1uL << CR_SSHIFT_BIT;
}
//
// Execute the command.
//
r = _ClearFlags();
if (r != 0) {
goto Done; // Error, could not clear status flags.
}
if (NumBytesData != 0) {
QUADSPI_DLR = NumBytesData - 1; // 0 means "read 1 byte".
}
QUADSPI_ABR = AltReg;
QUADSPI_CCR = CfgReg;
if (NumBytesAddr != 0) {
QUADSPI_AR = AddrReg;
}
//
// Read data from RAM device.
//
if (NumBytesData != 0) {
do {
//
// Wait for the data to be received.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
NumBytesAvail = (QUADSPI_SR >> SR_FLEVEL_BIT) & SR_FLEVEL_MASK;
if ((NumBytesAvail >= 4) || (NumBytesAvail >= NumBytesData)) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, no data received.
goto Done;
}
}
//
// Read data and store it to destination buffer.
//
if (NumBytesData < 4) {
//
// Read single bytes.
//
do {
*pData++ = QUADSPI_DR_BYTE;
} while (--NumBytesData != 0);
} else {
//
// Read 4 bytes at a time.
//
DataReg = QUADSPI_DR;
*pData++ = (U8)DataReg;
*pData++ = (U8)(DataReg >> 8);
*pData++ = (U8)(DataReg >> 16);
*pData++ = (U8)(DataReg >> 24);
NumBytesData -= 4;
}
} while (NumBytesData != 0);
}
//
// Wait until the data transfer has been completed.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if (QUADSPI_SR & (1uL << SR_TCF_BIT)) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, transaction not completed.
break;
}
}
Done:
//
// Restore the default sampling mode.
//
QUADSPI_CR &= ~(1uL << CR_SSHIFT_BIT);
return r;
}
/*********************************************************************
*
* _HW_Write
*
* Function description
* Transfers data from MCU to serial RAM device.
*
* Parameters
* Unit Index of the hardware layer (0-based).
* pCmd [IN] Code of the command to be sent. Cannot be NULL.
* NumBytesCmd Number of bytes in the command code. Cannot be 0.
* pPara [IN] Command parameters (address and dummy bytes). Can be NULL.
* NumBytesPara Total number of address and dummy bytes to be sent. Can be 0.
* NumBytesAddr Number of address bytes to be send. Can be 0.
* pData [IN] Data to be sent to the serial RAM device. Can be NULL.
* NumBytesData Number of bytes to be written the serial RAM device. Can be 0.
* BusWidth Number of data lines to be used for the data transfer.
* Flags Options for the data exchange.
*
* Return value
* ==0 OK, data transferred successfully.
* !=0 An error occurred.
*/
static int _HW_Write(U8 Unit, const U8 * pCmd, unsigned NumBytesCmd, const U8 * pPara, unsigned NumBytesPara,
unsigned NumBytesAddr, const U8 * pData, unsigned NumBytesData, U16 BusWidth, unsigned Flags) {
U32 AddrReg;
U32 AltReg;
U32 CfgReg;
U32 DataMode;
U32 AddrMode;
U32 AltMode;
U32 CmdMode;
U32 DataReg;
U32 AddrSize;
U32 AltSize;
U32 NumBytes;
U32 NumBytesAlt;
U32 NumBytesFree;
U32 IsDTR;
U32 TimeOut;
int r;
FS_USE_PARA(Unit); // This MCU has only one QSPI controller.
FS_DEBUG_ASSERT(FS_MTYPE_DRIVER, NumBytesCmd == 1u); // The QSPI controller is able to handle only 1-byte commands.
//
// Fill local variables.
//
r = 0;
AddrReg = 0;
AltReg = 0;
NumBytesAlt = NumBytesPara - NumBytesAddr;
//
// Calculate the transfer mode.
//
IsDTR = 0;
if ( ((Flags & FS_RAMDISK_HW_FLAG_DTR_ADDR) != 0u)
|| ((Flags & FS_RAMDISK_HW_FLAG_DTR_DATA) != 0u)) {
IsDTR = 1;
}
//
// Encode the address.
//
if (NumBytesAddr) {
NumBytes = NumBytesAddr;
do {
AddrReg <<= 8;
AddrReg |= (U32)(*pPara++);
} while (--NumBytes);
}
//
// Encode additional information.
//
if (NumBytesPara > NumBytesAddr) {
NumBytes = NumBytesAlt;
do {
AltReg <<= 8;
AltReg |= (U32)(*pPara++);
} while (--NumBytes);
}
//
// Calculate the number of data lines to be used for the transfer.
//
CmdMode = _GetMode(FS_BUSWIDTH_GET_CMD(BusWidth), NumBytesCmd);
AddrMode = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAddr);
AltMode = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAlt);
DataMode = _GetMode(FS_BUSWIDTH_GET_DATA(BusWidth), NumBytesData);
//
// Calculate the number of bytes in each command phase.
//
AddrSize = 0;
if (NumBytesAddr) {
AddrSize = NumBytesAddr - 1;
}
AltSize = 0;
if (NumBytesAlt) {
AltSize = NumBytesAlt - 1;
}
//
// Configure the operation.
//
CfgReg = 0
| (CCR_FMODE_WRITE << CCR_FMODE_BIT)
| (DataMode << CCR_DMODE_BIT)
| (AltSize << CCR_ABSIZE_BIT)
| (AltMode << CCR_ABMODE_BIT)
| (AddrSize << CCR_ADSIZE_BIT)
| (AddrMode << CCR_ADMODE_BIT)
| (IsDTR << CCR_DDRM_BIT)
| (CmdMode << CCR_IMODE_BIT)
| (*pCmd << CCR_INTRUCTION_BIT)
;
//
// Wait until the unit is ready for the new command.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, QUADSPI is not ready.
goto Done;
}
}
//
// Execute the command.
//
r = _ClearFlags();
if (r != 0) {
goto Done; // Error, could not clear status flags.
}
if (NumBytesData != 0) {
QUADSPI_DLR = NumBytesData - 1; // 0 means "read 1 byte".
}
QUADSPI_ABR = AltReg;
QUADSPI_CCR = CfgReg;
if (NumBytesAddr != 0) {
QUADSPI_AR = AddrReg;
}
//
// Write data to RAM device.
//
if (NumBytesData != 0) {
do {
//
// Wait for free space in FIFO.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
NumBytesFree = (QUADSPI_SR >> SR_FLEVEL_BIT) & SR_FLEVEL_MASK;
NumBytesFree = NUM_BYTES_FIFO - NumBytesFree;
if ((NumBytesFree >= 4) || (NumBytesFree >= NumBytesData)) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, no free space in FIFO.
goto Done;
}
}
//
// Get the data from source buffer and write it.
//
if (NumBytesData < 4) {
//
// Write single bytes.
//
do {
QUADSPI_DR_BYTE = *pData++;
} while (--NumBytesData != 0);
} else {
//
// Write 4 bytes at a time if possible.
//
DataReg = (U32)*pData++;
DataReg |= (U32)*pData++ << 8;
DataReg |= (U32)*pData++ << 16;
DataReg |= (U32)*pData++ << 24;
NumBytesData -= 4;
QUADSPI_DR = DataReg;
}
} while (NumBytesData != 0);
}
//
// Wait until the data transfer has been completed.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if (QUADSPI_SR & (1uL << SR_TCF_BIT)) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, transfer not completed.
break;
}
}
Done:
return r;
}
/*********************************************************************
*
* Global data
*
**********************************************************************
*/
/*********************************************************************
*
* FS_RAMDISK_HW_SPI_STM32H743_SEGGER_QSPI_Flash_Evaluator
*/
const FS_RAMDISK_HW_TYPE_SPI FS_RAMDISK_HW_SPI_STM32H743_SEGGER_QSPI_Flash_Evaluator = {
_HW_Init,
_HW_Unmap,
#if FS_RAMDISK_HW_USE_MEM_MAP_MODE
_HW_Map,
#else
NULL,
#endif // FS_RAMDISK_HW_USE_MEM_MAP_MODE
_HW_Control,
_HW_Read,
_HW_Write,
NULL,
NULL
};
/*************************** End of file ****************************/
NAND flash driver
General information
emFile supports the use of unmanaged NAND flash devices as data storage.
Two drivers for NAND flash devices also known as flash translation layers are provided:
- SLC1 NAND driver - Supports SLC NAND flash devices that require 1-bit
error correction. In addition, it also supports the Microchip / Atmel and Adesto DataFlash devices.
- Universal NAND driver - Supports all modern SLC and MLC NAND flash devices.
It can make use of the hardware ECC engine integrated into NAND flash devices to correct
bit errors.
Selecting the correct NAND driver
The first factor to be considered is the type of storage device used.
Microchip / Atmel and Adesto DataFlash devices are currently supported only by the SLC1 NAND
driver while NAND flash devices are typically supported by both NAND drivers.
The bit error correction requirement of the NAND flash device is the next factor.
It indicates how many bit errors the error correcting code (ECC) have to be able
to detect and correct. If the NAND flash devices requires only 1-bit correction
capability then the SLC1 NAND driver can be used. The SLC1 NAND driver performs
the bit error detection and correction in the software. For an correction capability
larger than 1 bit the Universal NAND driver has to be used instead.
The Universal NAND driver is able to calculated the ECC either in the hardware using
the ECC integrated into the NAND flash device or MCU or in the software using an
ECC library such as SEGGER emLib-ECC (https://www.segger.com/products/security-iot/emlib/variations/ecc/)
You can always get in contact with us if you are not sure what type of NAND driver to choose.
Multiple driver configurations
Both NAND drivers store management information to spare area of a page. The layout and
the content of this information is different for each NAND driver which means that data
written using one NAND driver cannot be accessed with the other one and vice versa.
For example, if an application uses the SLC1 NAND driver to store data to a NAND flash device
than it cannot use the Universal NAND driver to access it. The Universal NAND driver
reports in this case that the NAND flash device is not properly formatted.
For applications that have to support different types of NAND flash devices that
require the usage of both NAND drivers it is possible to select the correct NAND driver
by checking the device id of the connected NAND flash device. The description of
the FS_NAND_PHY_ReadDeviceId() function provides an example showing how to
a NAND flash device can be identified at the configuration of the file system.
Software structure
The NAND driver is organized into different layers that contains from top to bottom:
It is possible to use the NAND driver with custom hardware. If port pins or a simple
memory controller are used for accessing the flash memory, only the hardware layer
needs to be ported, normally no changes to the physical layer are required. If the
NAND driver should be used with a special memory controller (for example special
FPGA implementations), the physical layer needs to be adapted. In this case, the
hardware layer is not required, because the memory controller manages the hard-
ware access.
Bad block management
Bad block management is supported in the driver. Blocks marked as defective are
skipped and are not used for data storage. The block is recognized as defective when
the first byte in the spare area of the first or second page is different than 0xFF. The
driver marks blocks as defective in the following cases:
- when the NAND flash reports an error after a write operation.
- when the NAND flash reports an error after an erase operation.
- when an uncorrectable ECC error is detected on the data read from NAND flash.
Garbage collection
The driver performs the garbage collection automatically during the write operations.
If no empty NAND blocks are available to store the data, new empty NAND blocks are
created by erasing the data of the NAND blocks marked as invalid. This involves a
NAND block erase operation which, depending on the characteristics of the NAND
flash, can potentially take a long time to complete, and therefor reduces the write
throughput. For applications which require maximum write throughput, the garbage
collection can be done in the application. Typically, this operation can be performed
when the file system is idle.
Two API functions are provided: FS_STORAGE_Clean() and FS_STORAGE_CleanOne().
They can be called directly from the task which is performing the write or from a
background task. The FS_STORAGE_Clean() function blocks until all the invalid NAND
blocks are converted to free NAND blocks. A write operation following the call to this
function runs at maximum speed. The other function, FS_STORAGE_CleanOne(),
converts a single invalid NAND block. Depending on the number of invalid NAND blocks,
several calls to this function are required to clean up the entire NAND flash.
Fail-safe operation
The NAND drivers are fail-safe which means that the drivers make only atomic operations
and guarantee that the file system data is always valid. If an unexpected power loss or
reset interrupts a a write operation, then the old data is kept while the new corrupted
data is discarded. The fail-safe operation can only be guaranteed if the NAND flash device
is able to fully complete the last command it received from the MCU.
The picture below is an oscilloscope capture which shows how a power down sequence
should look like in order to meet the requirements needed for a fail-safe operation
of a NAND driver.
The labels in the picture have the following meaning:
- VCC is the main power supply voltage.
- RESET is a signal driven high by a program running on the CPU. This signal goes
low when the CPU stops running indicating the point in time when the last command
could have been sent to NAND flash.
- VCCmin is the minimum supply voltage required for the NAND flash to properly
operate.
- Tmax is the time it takes for the longest NAND flash operation to complete which
is 2 ms for the NAND flash used in the test.
As it can be seen in the picture the supply voltage stays above VCCmin long enough
to allow for any NAND flash command to finish.

Wear leveling
Wear leveling is supported by the NAND drivers. The procedure makes sure that
the number of times a NAND block is erased remains approximately equal for all
the NAND blocks. This is realized by maintaining an erase count for each NAND block.
The maximum allowed erase count difference is configurable at compile time via
FS_NAND_MAX_ERASE_CNT_DIFF as well as at runtime via FS_NAND_SetMaxEraseCntDiff()
for the SLC1 NAND driver and FS_NAND_UNI_SetMaxEraseCntDiff() for the Universal
NAND driver.
Read disturb errors
Read disturb errors are bit errors that occur when a large number of read operations
(a few hundred thousand to one million) are preformed on a NAND flash block
without an erase operation taking place in between. These bit errors can be avoided by
simply rewriting the sector data. This can be realized by calling in the application the
FS_STORAGE_RefreshSectors() storage layer API function that is able to refresh
multiple sectors in a single call.
Before using a NAND flash device for the first time, the application has to initialize it
by performing a low-level format operation on it. Refer to FS_FormatLow() and FS_FormatLLIfRequired()
for detailed information about this.
NAND flash organization
A NAND flash device is a serial-type memory device that uses the I/O pins for both
address and data transfer as well as for command inputs. A NAND flash device consist
of a number of individual storage blocks. Every block contains a number of pages,
typically 64. The pages can be written to individually, one at a time. When writing
to a page, bits can only be changed from 1 to 0. Only entire blocks (all pages in the
block) can be erased. Erasing means bringing all memory bits in all pages of the
block to logical 1. The erase and program operations are executed automatically
by the NAND flash device.

Small NAND flashes (up to 256 Mbytes) have a page size of 528 bytes, that is 512
bytes for storing file system data and 16 bytes, called the spare area,
for storing management information (ECC, etc.).
Large NAND devices (256 Mbytes or more) have a page size of 2112 bytes with
2048 bytes used for storing file system data data and with 64 bytes of spare area.
Pin description - parallel NAND flash device
This type of devices uses 8 or 16 I/O signals to exchange the data with the MCU
an additional set of signals that are used to control the data transfer.
Signal name | Description |
CE | Chip Enable - The CE signal enables the device. This signal is
active low. If the signal is inactive, device is in standby mode. |
WE | Write Enable - The WE signal controls the transfer of data from
MCU to NAND flash device. This signal is active low. Commands,
address and data are latched on the rising edge of the WE pulse. |
RE | Read Enable - The RE signal controls the transfer of data from
NAND flash device to MCU. This signal is active low. When active
the NAND flash device outputs data. |
CLE | Command Latch Enable - The CLE signal controls the activating
path for commands sent to NAND flash device. This signal is active high.
When active, command data sent via the I/O signals is latched
by the NAND flash device into the internal command register
on the rising edge of the WE signal. |
ALE | Address Latch Enable - The ALE signal controls the activating
path for address to the internal address registers. This signal is active high.
Address data is latched on the rising edge of WE with ALE high. |
WP | Write Protect - The WP signal controls if data can be stored to
NAND flash device. This signal is active low and is typically
connected to VCC (recommended), but may also be connected to port pin. |
R/B | Ready/Busy - The R/B signal indicates the status of the NAND flash
device operation to MCU. When low, it indicates that a program,
erase or read operation is in process. The signal returns to high
when the operation is completed. It is an open drain output
that should be connected to a port pin with pull-up. If available,
a port pin which can trigger an interrupt can be connected to this signal. |
I/O0-I/O7 | Data Input/Output - The data I/O signals are used to input command,
address and data, and to output data during read operations. |
I/O8-I/O15 | Data Input/Output - Additional data I/O signals. |
Pin description - DataFlash device
DataFlash devices are commonly used when low pin count and easy data transfer are
required. DataFlash devices use the following pins:
Signal name | Description |
CS | Chip Select - This signal selects the DataFlash device. The device is
selected, when CS pin is driven low. |
SCLK | Serial Clock - The SCLK signal is used to control the flow of data
to and from the DataFlash. Data is always clocked into the device
on the rising edge of SCLK and clocked out of the device on the
falling edge of SCLK. |
SI | Serial Data In - The SI signal is used to transfer data to the
DataFlash device. It is used for all data input including opcodes
and address sequences. |
SO | Serial Data Out - The SO signal is used to transfer data serially
out of the DataFlash device. |
Additionally, the host system has to comply with the following requirements:
- The data transfer width is 8 bit.
- The Chip Select (CS) signal sets the device active at low-level and inactive at high level.
- The clock signal has to be generated by the target system. The serial flash devices are always in slave mode.
- The bit order requires most significant bit (MSB) to be sent out first.
SLC1 NAND driver
SLC1 NAND driver is an extremely efficient and low footprint driver that can be
used to access the data stored on a raw NAND flash device. The driver is designed
to support one or multiple Single Level Cell (SLC) NAND flash devices that
require 1-bit error correction capability. The SLC1 NAND flash driver can also
be used to access the data stored on Microchip / Atmel and Adesto DataFlash devices.
Different sector sizes are supported to help reduce the RAM usage of the file system.
Supported hardware
the SLC1 NAND driver supports almost all SLC NAND flash devices.
This includes NAND flash devices with page sizes of 512 + 16 and 2048 + 64 bytes.
Tested and compatible NAND flash devices
The table below lists the NAND flash devices that have been tested
or are compatible with a tested device. In addition the NAND flash driver
fully supports the Dialog Semiconductor / Adesto / Atmel DataFlash devices
with capacities up to 128 MBit.
Device name | Page size | Number of blocks | Storage capacity | Bus width |
AFND1G08U3 | 2048+64 byte | 1024 | 128 MiB | 16 bit |
AT25PE16 | 512+16 byte | 512 | 2 MiB | 1 bit |
AT45BR3214B | 512+16 byte | 1024 | 4 MiB | 1 bit |
AT45DB011B | 256+8 byte | 64 | 128 KiB | 1 bit |
AT45DB021B | 256+8 byte | 128 | 256 KiB | 1 bit |
AT45DB041B | 256+8 byte | 256 | 512 KiB | 1 bit |
AT45DB081B | 256+8 byte | 512 | 1 MiB | 1 bit |
AT45DB1282 | 1024+32 byte | 2048 | 16 MiB | 1 bit |
AT45DB161B | 512+16 byte | 512 | 2 MiB | 1 bit |
AT45DB161E | 512+16 byte | 512 | 2 MiB | 1 bit |
AT45DB321C | 512+16 byte | 1024 | 4 MiB | 1 bit |
AT45DB321E | 512+16 byte | 1024 | 4 MiB | 1 bit |
AT45DB641E | 256+8 byte | 4096 | 8 MiB | 1 bit |
AT45DB642D | 1024+32 byte | 1024 | 8 MiB | 1 bit |
AT45DCB002 | 512+16 byte | 512 | 2 MiB | 1 bit |
AT45DCB004 | 512+16 byte | 1024 | 4 MiB | 1 bit |
AT45DCB008 | 1024+32 byte | 1024 | 8 MiB | 1 bit |
HY27SA081G1M | 512+16 byte | 8192 | 512 MiB | 8 bit |
HY27SS08121M | 512+16 byte | 4096 | 512 MiB | 8 bit |
HY27SS08561M | 512+16 byte | 2048 | 256 MiB | 8 bit |
HY27UA081G1M | 512+16 byte | 8192 | 512 MiB | 8 bit |
HY27UF081G2A | 2048+64 byte | 1024 | 128 MiB | 8 bit |
HY27UF081G2M | 2048+64 byte | 1024 | 128 MiB | 8 bit |
HY27UF082G2M | 2048+64 byte | 2048 | 256 MiB | 8 bit |
HY27UF084G2M | 2048+64 byte | 4096 | 512 MiB | 8 bit |
HY27UG084G2M | 2048+64 byte | 4096 | 512 MiB | 8 bit |
HY27UG084GDM | 2048+64 byte | 4096 | 512 MiB | 8 bit |
HY27US08121M | 512+16 byte | 4096 | 512 MiB | 8 bit |
HY27US08281A | 512+16 byte | 1024 | 128 MiB | 8 bit |
HY27US08561M | 512+16 byte | 2048 | 256 MiB | 8 bit |
TC5816BFT | 256+8 byte | 512 | 2 MiB | 8 bit |
TC582562A | 512+8 byte | 2048 | 32 MiB | 8 bit |
TC58256AFT | 512+8 byte | 2048 | 32 MiB | 8 bit |
TC58512FT | 512+8 byte | 4096 | 64 MiB | 8 bit |
TC58V32AFT | 512+8 byte | 512 | 4 MiB | 8 bit |
TC58V64BFT | 512+8 byte | 1024 | 8 MiB | 8 bit |
TH58100FT | 512+8 byte | 8192 | 128 MiB | 8 bit |
MT29F2G08AAB | 2048+64 byte | 2048 | 256 MiB | 8 bit |
MT29F2G08ABD | 2048+64 byte | 2048 | 256 MiB | 8 bit |
MT29F2G16AAD | 2048+64 byte | 2048 | 256 MiB | 16 bit |
MT29F4G08AAA | 2048+64 byte | 4096 | 512 MiB | 8 bit |
MT29F4G08BAB | 2048+64 byte | 4096 | 512 MiB | 8 bit |
NAND01GR3A | 512+16 byte | 8192 | 1 GiB | 8 bit |
NAND01GR3B | 2048+64 byte | 1024 | 128 MiB | 8 bit |
NAND01GW3A | 512+16 byte | 8192 | 1 GiB | 8 bit |
NAND01GW3B | 2048+64 byte | 1024 | 128 MiB | 8 bit |
NAND02GR3B | 2048+64 byte | 2048 | 256 MiB | 8 bit |
NAND02GW3B | 2048+64 byte | 2048 | 256 MiB | 8 bit |
NAND04GW3B | 2048+64 byte | 4096 | 512 MiB | 8 bit |
NAND128R3A | 512+16 byte | 1024 | 128 MiB | 8 bit |
NAND128W3A | 512+16 byte | 1024 | 128 MiB | 8 bit |
NAND256R3A | 512+16 byte | 2048 | 256 MiB | 8 bit |
NAND256W3A | 512+16 byte | 2048 | 256 MiB | 8 bit |
NAND512R3A | 512+16 byte | 4096 | 512 MiB | 8 bit |
NAND512W3A | 512+16 byte | 4096 | 512 MiB | 8 bit |
K9F1208B0B | 512+16 byte | 4096 | 64 MiB | 8 bit |
K9F1208R0B | 512+16 byte | 4096 | 64 MiB | 8 bit |
K9F1208U0B | 512+16 byte | 4096 | 64 MiB | 8 bit |
K9F1G08R0A | 2048+64 byte | 1024 | 128 MiB | 8 bit |
K9F1G08U0A | 2048+64 byte | 1024 | 128 MiB | 8 bit |
K9F1G08U0C | 2048+64 byte | 1024 | 128 MiB | 8 bit |
K9F2808Q0B | 512+16 byte | 1024 | 16 MiB | 8 bit |
K9F2808U0B | 512+16 byte | 1024 | 16 MiB | 8 bit |
K9F2G08U0M | 2048+64 byte | 2048 | 256 MiB | 8 bit |
K9F4G08U0A | 2048+64 byte | 4096 | 512 MiB | 8 bit |
K9F4G08U0M | 2048+64 byte | 4096 | 512 MiB | 8 bit |
K9F5608B0D | 512+16 byte | 2048 | 32 MiB | 8 bit |
K9F5608R0D | 512+16 byte | 2048 | 32 MiB | 8 bit |
K9F5608U0D | 512+16 byte | 2048 | 32 MiB | 8 bit |
K9F6408Q0C | 512+16 byte | 1024 | 8 MiB | 8 bit |
K9F6408U0C | 512+16 byte | 1024 | 8 MiB | 8 bit |
K9F8G08U0M | 2048+128 byte | 4096 | 1 GiB | 8 bit |
K9K1G08B0B | 512+16 byte | 8192 | 128 MiB | 8 bit |
K9K1G08R0B | 512+16 byte | 8192 | 128 MiB | 8 bit |
K9K1G08U0B | 512+16 byte | 8192 | 128 MiB | 8 bit |
K9K1G08U0M | 512+16 byte | 8192 | 128 MiB | 8 bit |
K9K2G08R0A | 2048+64 byte | 2048 | 256 MiB | 8 bit |
K9K2G08U0M | 2048+64 byte | 2048 | 256 MiB | 8 bit |
S34ML01G100TFI000 | 2048+64 byte | 1024 | 128 MiB | 8 bit |
S34ML04G100TFI000 | 2048+64 byte | 4096 | 512 MiB | 8 bit |
S34MS02G100TFI000 | 2048+64 byte | 2048 | 256 MiB | 8 bit |
W29N08GVSIAA | 2048+64 byte | 8192 | 1 GiB | 8 bit |
Support for devices not in this list
Most other NAND flash devices are compatible with one of the supported devices.
Thus, the driver can be used with these devices or may only need a little modification,
which can be easily done. Get in touch with us, if you have questions about support
for devices not in this list.
Note
DataFlash devices with a page size that is a power of 2 are not supported
by the SLC1 NAND driver.
Theory of operation
NAND flash devices are divided into physical blocks and physical pages. One physical
block is the smallest erasable unit; one physical page is the smallest writable unit.
Small block NAND flashes contain multiple pages. One block contain typically 16 / 32
/ 64 pages per block. Every page has a size of 528 bytes (512 data bytes + 16 spare
bytes). Large block NAND Flash devices contain blocks made up of 64 pages, each
page containing 2112 bytes (2048 data bytes + 64 spare bytes).
The driver uses the spare bytes for the following purposes:
- To check if the data status byte and block status are valid.
If they are valid the driver uses this sector. When the driver detects a bad sector, the
whole block is marked as invalid and its content is copied to a non-defective block.
- To store/read an ECC (Error Correcting Code) for data reliability.
When reading a sector, the driver also reads the ECC stored in the spare area of
the sector, calculates the ECC based on the read data and compares the ECCs. If
the ECCs are not identical, the driver tries to recover the data, based on the read
ECC. When writing to a page the ECC is calculated based on the data the driver has to
write to the page. The calculated ECC is then stored in the spare area.
Error correction using ECC
The SLC1 NAND driver is highly speed optimized and offers a better error detection
and correction than a standard memory controller ECC. The ECC is capable of single
bit error correction and 2-bit random detection. When a block for which the ECC is
calculated has 2 or more bit errors, the data cannot be corrected.
Standard memory controllers calculate an ECC for the complete block size (512 / 2048
bytes). The ECC routines of the SLC1 NAND driver calculates the ECC for data chunks
of 256 bytes (e.g. a page with 2048 bytes is divided into 8 parts of 256 bytes),
therefore the probability to detect and also correct data errors is much higher.
This enhancement is realized with a very good performance. The ECC computation of
the SLC1 NAND driver is highly optimized, so that a performance of 18 Mbytes/second
can be achieved with an ARM7 based MCU running at 48 MHz.
We suggest the use of the SLC1 NAND driver without enabling the hardware ECC of
the memory controller, because the performance of the driver is very high and the
error correction is much better.
Partial write operations
Most NAND devices allow a write operation to change an arbitrary number of bytes
starting from any byte offset inside a page. A write operation that does not change
all the bytes in page is called partial write or partial programming. The driver makes
extensive use of this feature to increase the write speed and to reduce the RAM
usage. But there is a limitation of this method imposed by the NAND technology. The
manufacturer does not guarantee the integrity of the data if a page is partially
written more than a number of times without an intermediate erase operation.
The maximum number of partial writes is usually four. Exceeding the maximum number of
partial writes does not lead automatically to the corruption of data in that page but it
can increase the probability of bit errors. The driver is be able to correct single
bit errors using ECC. For some combinations of logical sector size and NAND page size
the driver might exceed the limit for the number of partial write operations.
The table below summarizes the maximum number of partial writes performed by the
SLC1 NAND driver for different logical sector sizes:
NAND page size (bytes) | Logical sector size (bytes) | Maximum number of partial write operations |
512 | 512 | 4 |
2048 | 2048 | 4 |
2048 | 1024 | 5 |
2048 | 512 | 8 |
Configuring the driver
This section describes how to configure the file system to make use of the SLC1 NAND driver.
Compile time configuration
The SLC1 NAND driver can optionally be configured at compile time. Typically,
this step can be omitted because the SLC1 NAND driver provides reasonable
default values that work for most of the target applications.
The compile time configuration is realized via preprocessor defines that have
to be added to the FS_Conf.h file which is the main configuration file
of emFile. For detailed information about the configuration of emFile
and of the configuration define types, refer to Configuration of emFile
The following table lists the configuration defines supported by the SLC1
NAND driver.
FS_NAND_ENABLE_STATS
This define can be used to enable the support for statistical counters.
The statistical counters provide information about the number of operations
performed internally by the SLC1 NAND driver that can be useful for debugging.
The statistical counters can be queried via FS_NAND_GetStatCounters().
By default FS_NAND_ENABLE_STATS is set to 1 if FS_DEBUG_LEVEL is set
to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.
FS_NAND_NUM_READ_RETRIES
Number of times the SLC1 NAND driver reties the operation in case of a
read error (device error or uncorrectable bit error). NumReadRetries
of FS_NAND_STAT_COUNTERS is incremented by 1 on each retry.
FS_NAND_NUM_WRITE_RETRIES
Number of times the SLC1 NAND driver reties the operation in case of a
write error. A write error occurs when the NAND flash device is not
able to write the data to memory array. This condition is typically
reported via a flag in the status register of the NAND flash device
that is queried by the NAND physical layer after each write operation.
NumWriteRetries of FS_NAND_STAT_COUNTERS is incremented by 1 on each retry.
FS_NAND_NUM_UNITS
This define specifies the maximum number of driver instances of the SLC1 NAND driver
the application is allowed create. Four bytes of static RAM are reserved for each instance.
If the maximum number of driver instances is smaller than the default then FS_NAND_NUM_UNITS
can be set to the to that value in order to reduce the RAM usage.
FS_NAND_VERIFY_ERASE
This define can be used to activate the erase verification of the SLC1 NOR driver.
The erase verification is performed after each erase operation by reading back
the entire data of the erase block and by comparing each byte in the block with 0xFF.
An error is reported if a difference is detected.
This feature has to be enabled at runtime by calling FS_NAND_SetEraseVerification().
Note
Activating the erase verification may negatively affect the write performance.
FS_NAND_VERIFY_WRITE
This define can be used to activate the write verification of the SLC1 NAND driver.
The write verification is performed after each write operation by reading back
the modified data and by comparing it with the data requested to be written.
An error is reported if a difference is detected.
This feature has to be enabled at runtime by calling FS_NAND_SetWriteVerification().
Note
Activating the write verification may negatively affect the write performance.
Runtime configuration
The driver must be added to the file system by calling FS_AddDevice() with the
driver identifier set to the address of FS_NAND_Driver. This function call together
with other function calls that configure the driver operation have to be added
to FS_X_AddDevices() as demonstrated in the following example.
Example
#include <FS.h>
#include "FS_NAND_HW_Template.h"
#define ALLOC_SIZE 0x9000 // Memory pool for the file system in bytes
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for semi-dynamic allocation.
void FS_X_AddDevices(void) {
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Add the driver to file system.
//
FS_AddDevice(&FS_NAND_Driver);
//
// Set the physical interface of the NAND flash.
//
FS_NAND_SetPhyType(0, &FS_NAND_PHY_x8);
//
// Skip 2 blocks (256 Kbytes in case of 2K device)
// The size of the configured area is 128 blocks.
// For 2K devices, this means 2 Kbytes * 64 * 128 = 16 Mbytes
//
FS_NAND_SetBlockRange(0, 2, 128);
//
// Configure the HW access routines.
//
FS_NAND_x8_SetHWType(0, &FS_NAND_HW_Template);
#if FS_SUPPORT_FILE_BUFFER
//
// Enable the file buffer to increase the performance
// when reading/writing a small number of bytes.
//
FS_ConfigFileBufferDefault(512, FS_FILE_BUFFER_WRITE);
#endif // FS_SUPPORT_FILE_BUFFER
}
The API functions listed in the next table can be used by the application to
configure the behavior of the SLC1 NAND driver. The application can call
them only at the file system initialization in FS_X_AddDevices().
FS_NAND_SetBlockRange()
Description
Specifies which NAND flash blocks can used as data storage.
Prototype
void FS_NAND_SetBlockRange(U8 Unit,
U16 FirstBlock,
U16 MaxNumBlocks);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
FirstBlock | Index of the first NAND flash block to be used as storage (0-based). |
MaxNumBlocks | Maximum number of NAND flash blocks to be used as storage. |
Additional information
This function is optional. By default, the SLC1 NAND driver uses
all blocks of the NAND flash as data storage. FS_NAND_SetBlockRange()
is useful when a part of the NAND flash has to be used for another
purpose, for example to store the application program used by a boot loader,
and therefore it cannot be managed by the SLC1 NAND driver. Limiting
the number of blocks used by the SLC1 NAND driver can also help reduce the RAM usage.
FirstBlock is the index of the first physical NAND block were
0 is the index of the first block of the NAND flash device.
MaxNumBlocks can be larger that the actual number of available
NAND blocks in which case the SCL1 NAND driver silently truncates
the value to reflect the actual number of NAND blocks available.
The SLC1 NAND driver uses the first NAND block in the range to store
management information at low-level format. If the first NAND block happens
to be marked as defective, then the next usable NAND block is used.
The read optimization of the FS_NAND_PHY_2048x8 physical layer has to be
disabled when this function is used to partition the NAND flash device
in order to ensure data consistency. The read cache can be disabled at
runtime using FS_NAND_2048x8_DisableReadCache().
If the FS_NAND_SetBlockRange() is used to subdivide the same
physical NAND flash device into two or more partitions than
the application has to make sure that they do not overlap.
Example
Sample configuration showing how to reserve the first 16 blocks of the NAND flash.
#include <FS.h>
void FS_X_AddDevices(void) {
//
// Basic file system configuration...
//
//
// Add and configure the SLC1 NAND driver.
// Only the NAND blocks with the physical
// indexes 16-143 are used for storage.
//
FS_AddDevice(&FS_NAND_Driver);
FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
FS_NAND_SetBlockRange(0, 16, 128);
//
// Additional file system configuration...
//
}
Sample configuration showing how to partition the same NAND flash device.
#include <FS.h>
void FS_X_AddDevices(void) {
//
// Basic file system configuration...
//
//
// Add and configure the first SLC1 NAND driver.
// The blocks 16 blocks are used for storage,
// that is the NAND blocks with the physical
// indexes 0-15.
//
FS_AddDevice(&FS_NAND_Driver);
FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
FS_NAND_SetBlockRange(0, 0, 16);
//
// Add and configure the second SLC1 NAND driver.
// The blocks 64 blocks are used for storage,
// that is the NAND blocks with the physical
// indexes 16-79.
//
FS_AddDevice(&FS_NAND_Driver);
FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
FS_NAND_SetBlockRange(0, 16, 64);
//
// Additional file system configuration...
//
}
FS_NAND_SetCleanThreshold()
Description
Specifies the minimum number sectors that the driver should keep
available for fast write operations.
Prototype
int FS_NAND_SetCleanThreshold(U8 Unit,
unsigned NumBlocksFree,
unsigned NumSectorsFree);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
NumBlocksFree | Number of blocks to be kept free. |
NumSectorsFree | Number of sectors to be kept free on each block. |
Return value
= 0 | OK, threshold set. |
≠ 0 | An error occurred. |
Additional information
Typically, used for allowing the NAND flash to write data fast to a file
on a sudden reset. At the startup, the application reserves free space,
by calling the function with NumBlocksFree and NumSectorsFree set to a
value different than 0. The number of free sectors depends on the number
of bytes written and on how the file system is configured.
When the unexpected reset occurs, the application tells the driver that
it can write to the free sectors, by calling the function with
NumBlocksFree and NumSectorsFree set to 0. Then, the application writes
the data to file and the NAND driver stores it to the free space.
Since no erase or copy operation is required, the data is written as
fastest as the NAND flash device permits it.
The NAND flash device will wear out faster than normal if sectors
are reserved in a work block (NumSectors > 0).
FS_NAND_SetEraseVerification()
Description
Enables or disables the checking of the block erase operation.
Prototype
void FS_NAND_SetEraseVerification(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
OnOff | Specifies if the feature has to be enabled or disabled =0 The erase operation is not checked. ≠0 The erase operation is checked. |
Additional information
This function is optional. The result of a block erase operation
is normally checked by evaluating the error bits maintained by the
NAND flash device in a internal status register. FS_NAND_SetEraseVerification()
can be used to enable additional verification of the block erase
operation that is realized by reading back the contents of the entire
erased physical block and by checking that all the bytes in it are
set to 0xFF. Enabling this feature can negatively impact the write
performance of SLC1 NAND driver.
The block erase verification feature is active only when the SLC1
NAND driver is compiled with the FS_NAND_VERIFY_ERASE configuration
define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL
configuration define is set to a value greater than or equal to
FS_DEBUG_LEVEL_CHECK_ALL.
FS_NAND_SetMaxEraseCntDiff()
Description
Configures the threshold of the wear leveling procedure.
Prototype
void FS_NAND_SetMaxEraseCntDiff(U8 Unit,
U32 EraseCntDiff);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
EraseCntDiff | Maximum allowed difference between the erase counts of any two NAND blocks. |
Additional information
This function is optional. It can be used to control how
the SLC1 NAND driver performs the wear leveling.
The wear leveling procedure makes sure that the NAND blocks
are equally erased to meet the life expectancy of the storage
device by keeping track of the number of times a NAND block
has been erased (erase count). The SLC1 NAND driver executes
this procedure when a new empty NAND block is required for
data storage. The wear leveling procedure works by first
choosing the next available NAND block. Then the difference
between the erase count of the chosen block and the NAND block
with lowest erase count is computed. If this value is greater
than EraseCntDiff the NAND block with the lowest erase count
is freed and made available for use.
The same threshold can also be configured at compile time
via the FS_NAND_MAX_ERASE_CNT_DIFF configuration define.
Example
#include <FS.h>
void FS_X_AddDevices(void) {
//
// Basic file system configuration...
//
//
// Add and configure the SLC1 NAND driver.
//
FS_AddDevice(&FS_NAND_Driver);
FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
FS_NAND_SetMaxEraseCntDiff(0, 5000);
//
// Additional file system configuration...
//
}
FS_NAND_SetNumWorkBlocks()
Description
Sets number of work blocks the SLC1 NAND driver uses for write operations.
Prototype
void FS_NAND_SetNumWorkBlocks(U8 Unit,
U32 NumWorkBlocks);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
NumWorkBlocks | Number of work blocks. |
Additional information
This function is optional. It can be used to change the default
number of work blocks according to the requirements of the application.
Work blocks are physical NAND blocks that the SLC1 NAND driver
uses to temporarily store the data written to NAND flash device.
The SLC1 NAND driver calculates at low-level format the number of
work blocks based on the total number of blocks available on the
NAND flash device.
By default, the NAND driver allocates 10% of the total number of
NAND blocks used as storage, but no more than 10 NAND blocks.
The minimum number of work blocks allocated by default depends
on whether journaling is used or not. If the journal is active
4 work blocks are allocated, else SLC1 NAND driver allocates 3
work blocks. The currently allocated number of work blocks can
be checked via FS_NAND_GetDiskInfo(). The value is returned in the
NumWorkBlocks member of the FS_NAND_DISK_INFO structure.
Increasing the number of work blocks can help increase the write
performance of the SLC1 NAND driver. At the same time the RAM
usage of the SLC1 NAND driver increases since each configured
work block requires a certain amount of RAM for the data management.
This is a trade-off between write performance and RAM usage.
The new value take effect after the NAND flash device is low-level
formatted via FS_FormatLow() or FS_NAND_FormatLow() API functions.
Example
#include <FS.h>
void FS_X_AddDevices(void) {
//
// Basic file system configuration...
//
//
// Add and configure the SLC1 NAND driver.
//
FS_AddDevice(&FS_NAND_Driver);
FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
FS_NAND_SetNumWorkBlocks(0, 5);
//
// Additional file system configuration...
//
}
FS_NAND_SetOnFatalErrorCallback()
Description
Registers a function to be called by the driver when a fatal error occurs.
Prototype
void FS_NAND_SetOnFatalErrorCallback
(FS_NAND_ON_FATAL_ERROR_CALLBACK * pfOnFatalError);
Parameters
Parameter | Description |
pfOnFatalError | Pointer to callback function. |
Additional information
This function is optional. If no callback function is registered
the SLC1 NAND driver behaves as if the callback function returned 1.
This means that the NAND flash remains writable after the occurrence
of the fatal error. emFile versions previous to 4.04b behave differently
and mark the NAND flash as read-only in this case. For additional
information refer to FS_NAND_ON_FATAL_ERROR_CALLBACK.
Typically, the SLC1 NAND driver reports a fatal error when an
uncorrectable bit error occurs, that is when the ECC is not able
to correct the bit errors. A fatal error can also be reported
on other events such the failure to erase a NAND block. The type of
error is indicated to the callback function via the ErrorType member
of the FS_NAND_FATAL_ERROR_INFO structure.
All instances of the SLC1 NAND driver share the same callback function.
The Unit member of the FS_NAND_FATAL_ERROR_INFO structure passed
as parameter to the pfOnFatalError callback function can be used to
determine which driver instance triggered the fatal error.
FS_NAND_SetPhyType()
Description
Configures NAND flash access functions.
Prototype
void FS_NAND_SetPhyType( U8 Unit,
const FS_NAND_PHY_TYPE * pPhyType);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based) |
pPhyType | in Physical layer to be used to access the NAND flash device. |
Additional information
This function is mandatory and it has to be called in FS_X_AddDevices()
once for each instance of the SLC1 NAND driver. The driver instance
is identified by the Unit parameter. First SLC1 NAND driver instance
added to the file system via a FS_AddDevice(&FS_NAND_Driver) call
has the unit number 0, the SLC1 NAND driver added by a second call
to FS_AddDevice() has the unit number 1 and so on.
FS_NAND_SetWriteVerification()
Description
Enables or disables the checking of each page write operation.
Prototype
void FS_NAND_SetWriteVerification(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
OnOff | Specifies if the feature has to be enabled or disabled =0 The write operation is not checked. ≠0 The write operation is checked. |
Additional information
This function is optional. The result of a page write operation
is normally checked by evaluating the error bits maintained by the
NAND flash device in a internal status register. FS_NAND_SetWriteVerification()
can be used to enable additional verification of the page write
operation that is realized by reading back the contents of the written
page and by checking that all the bytes are matching the data
requested to be written. Enabling this feature can negatively
impact the write performance of SLC1 NAND driver.
The page write verification feature is active only when the SLC1
NAND driver is compiled with the FS_NAND_VERIFY_WRITE configuration
define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL
configuration define is set to a value greater than or equal to
FS_DEBUG_LEVEL_CHECK_ALL.
FS_NAND_ON_FATAL_ERROR_CALLBACK
Description
The type of the callback function invoked by the NAND driver
when a fatal error occurs.
Type definition
typedef int FS_NAND_ON_FATAL_ERROR_CALLBACK(FS_NAND_FATAL_ERROR_INFO * pFatalErrorInfo);
Parameters
Parameter | Description |
pFatalErrorInfo | Information about the fatal error. |
Return value
= 0 | The NAND driver has to mark the NAND flash device as read only. |
≠ 0 | The NAND flash device has to remain writable. |
Additional information
If the callback function returns a 0 the NAND driver marks the NAND flash
device as read-only and it remains in this state until the NAND flash device
is low-level formatted. In this state all further write operations are rejected
with an error by the NAND driver.
The application is responsible for handling the fatal error for example by
checking the consistency of the file system via FS_CheckDisk(). The callback
function is not allowed to invoke any other FS API functions therefore the
handling of the error has to be done after the FS API function that triggered
the error returns.
Depending on the type of NAND driver used, the fatal error handler can be registered
either via FS_NAND_SetOnFatalErrorCallback() or FS_NAND_UNI_SetOnFatalErrorCallback().
FS_NAND_FATAL_ERROR_INFO
Description
Information passed to callback function when a fatal error occurs.
Type definition
typedef struct {
U8 Unit;
U8 ErrorType;
U32 ErrorSectorIndex;
} FS_NAND_FATAL_ERROR_INFO;
Structure members
Member | Description |
Unit | Instance of the NAND driver that generated the fatal error. |
ErrorType | Type of fatal error. |
ErrorSectorIndex | Index of the physical sector where the error occurred. Not applicable for all type of errors. |
Additional driver functions
The following functions are optional and can be used by the application to
perform operations directly on the NAND flash device.
FS_NAND_Clean()
Description
Makes sectors available for fast write operations.
Prototype
int FS_NAND_Clean(U8 Unit,
unsigned NumBlocksFree,
unsigned NumSectorsFree);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
NumBlocksFree | Number of blocks to be kept free. |
NumSectorsFree | Number of sectors to be kept free on each block. |
Return value
= 0 | OK |
≠ 0 | An error occurred |
Additional information
This function is optional. It can be used to free space on the
NAND flash device for data that the application has to write
as fast as possible. FS_NAND_UNI_Clean() performs two internal
operations:
(1) Converts all work blocks that have less free sectors than
NumSectorsFree into data blocks.
(2) If required, convert work blocks until at least NumBlocksFree
are available.
FS_NAND_EraseBlock()
Description
Sets all the bytes in a NAND block to 0xFF.
Prototype
int FS_NAND_EraseBlock(U8 Unit,
unsigned BlockIndex);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
BlockIndex | Index of the NAND flash block to be erased. |
Return value
= 0 | OK, block erased. |
≠ 0 | An error occurred. |
Additional information
This function is optional. FS_NAND_EraseBlock() function does
not check if the block is marked as defective before erasing it.
FS_NAND_EraseFlash()
Description
Erases the entire NAND partition.
Prototype
int FS_NAND_EraseFlash(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
Return value
≥ 0 | Number of blocks which failed to erase. |
< 0 | An error occurred. |
Additional information
This function is optional. After the call to FS_NAND_EraseFlash()
all the bytes in the NAND partition are set to 0xFF.
This function has to be used with care, since it also erases
blocks marked as defective and therefore the information about
the block status will be lost. FS_NAND_EraseFlash() can be used
without this side effect on storage devices that are guaranteed
to not have any bad blocks, such as DataFlash devices.
Description
Performs a low-level format of the NAND flash device.
Prototype
int FS_NAND_FormatLow(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
Return value
= 0 | OK, NAND flash device is low-level formatted. |
≠ 0 | An error occurred. |
Additional information
This function is optional. It is recommended that application
use FS_FormatLow() to initialize the NAND flash device instead
of FS_NAND_FormatLow().
After the low-level format operation all data that was stored on
the NAND flash device is lost. A low-level format has to be performed
only once before using the NAND flash device for the first time.
The application can check if the NAND flash device is low-level
formatted by calling FS_IsLLFormated() or alternatively
FS_NAND_IsLLFormated().
FS_NAND_GetBlockInfo()
Description
Returns information about a specified NAND block.
Prototype
int FS_NAND_GetBlockInfo(U8 Unit,
U32 PhyBlockIndex,
FS_NAND_BLOCK_INFO * pBlockInfo);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
PhyBlockIndex | Index of the physical block to get information about. |
pBlockInfo | out Information about the NAND block. |
Return value
= 0 | OK, information returned. |
≠ 0 | An error occurred. |
Additional information
This function is not required for the functionality of the SLC1 NAND driver
and is typically not linked in in production builds.
Example
#include <stdio.h>
#include "FS.h"
void SampleNANDGetBlockInfo(void) {
FS_NAND_BLOCK_INFO BlockInfo;
char ac[100];
FS_X_Log("Get information about block 1 of the first SLC1 NAND driver instance\n");
FS_NAND_GetBlockInfo(0, 1, &BlockInfo);
SEGGER_snprintf(ac, sizeof(ac), " sType: %s\n", BlockInfo.sType);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " EraseCnt: 0x%.8x\n", BlockInfo.EraseCnt);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " LBI: %lu\n", BlockInfo.lbi);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumSectorsBlank: %d\n", BlockInfo.NumSectorsBlank);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumSectorsECCCorrectable: %d\n", BlockInfo.NumSectorsECCCorrectable);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumSectorsErrorInECC: %d\n", BlockInfo.NumSectorsErrorInECC);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumSectorsECCError: %d\n", BlockInfo.NumSectorsECCError);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumSectorsInvalid: %d\n", BlockInfo.NumSectorsInvalid);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumSectorsValid: %d\n", BlockInfo.NumSectorsValid);
}
FS_NAND_GetDiskInfo()
Description
Returns information about the NAND partition.
Prototype
int FS_NAND_GetDiskInfo(U8 Unit,
FS_NAND_DISK_INFO * pDiskInfo);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
pDiskInfo | out Information about the NAND partition. |
Return value
= 0 | OK, information returned. |
≠ 0 | An error occurred. |
Additional information
This function is not required for the functionality of the
SLC1 NAND driver and is typically not linked in production
builds.
Example
#include <stdio.h>
#include "FS.h"
void SampleNANDGetDiskInfo(void) {
FS_NAND_DISK_INFO DiskInfo;
char ac[100];
memset(&DiskInfo, 0, sizeof(DiskInfo));
FS_X_Log("Get information about the first SLC1 NAND driver instance:\n");
FS_NAND_GetDiskInfo(0, &DiskInfo);
SEGGER_snprintf(ac, sizeof(ac), " NumPhyBlocks: %lu\n", DiskInfo.NumPhyBlocks);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumLogBlocks: %lu\n", DiskInfo.NumLogBlocks);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumPagesPerBlock: %lu\n", DiskInfo.NumPagesPerBlock);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumSectorsPerBlock: %lu\n", DiskInfo.NumSectorsPerBlock);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " BytesPerPage: %lu\n", DiskInfo.BytesPerPage);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " BytesPerSector: %lu\n", DiskInfo.BytesPerSector);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumUsedPhyBlocks: %lu\n", DiskInfo.NumUsedPhyBlocks);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " NumBadPhyBlocks: %lu\n", DiskInfo.NumBadPhyBlocks);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " EraseCntMin: %lu\n", DiskInfo.EraseCntMin);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " EraseCntMax: %lu\n", DiskInfo.EraseCntMax);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " EraseCntAvg: %lu\n", DiskInfo.EraseCntAvg);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " IsWriteProtected: %d\n", DiskInfo.IsWriteProtected);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " HasFatalError: %d\n", DiskInfo.HasFatalError);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " ErrorType: %d\n", DiskInfo.ErrorType);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " ErrorSectorIndex: %lu\n", DiskInfo.ErrorSectorIndex);
FS_X_Log(ac);
}
FS_NAND_GetStatCounters()
Description
Returns the actual values of statistical counters.
Prototype
void FS_NAND_GetStatCounters(U8 Unit,
FS_NAND_STAT_COUNTERS * pStat);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based) |
pStat | out Values of statistical counters. |
Additional information
This function is optional. It is active only when the file system
is compiled with FS_DEBUG_LEVEL set to a value greater than or
equal to FS_DEBUG_LEVEL_CHECK_ALL or FS_NAND_ENABLE_STATS set to 1.
The statistical counters can be cleared via FS_NAND_ResetStatCounters().
FS_NAND_IsBlockBad()
Description
Checks if a NAND block is marked as defective.
Prototype
int FS_NAND_IsBlockBad(U8 Unit,
unsigned BlockIndex);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
BlockIndex | Index of the NAND flash block to be checked. |
Return value
1 | Block is defective |
0 | Block is not defective |
Additional information
This function is optional.
Description
Checks if the NAND flash is low-level formatted.
Prototype
int FS_NAND_IsLLFormatted(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
Return value
= 1 | NAND flash device is low-level formatted. |
= 0 | NAND flash device is not low-level formatted. |
< 0 | An error occurred. |
Additional information
This function is optional.
FS_NAND_ReadPageRaw()
Description
Reads data from a page without ECC.
Prototype
int FS_NAND_ReadPageRaw(U8 Unit,
U32 PageIndex,
void * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
PageIndex | Index of the page to be read. |
pData | out Data to be written. |
NumBytes | Number of bytes to be read. |
Return value
= 0 | OK, data read. |
≠ 0 | An error occurred. |
Additional information
This function is optional.
The data is read beginning from byte offset 0 in the page.
If more data is requested than the page + spare area size,
typ. 2 Kbytes + 64 bytes, the function does not modify the
remaining bytes in pData.
FS_NAND_ReadPhySector()
Description
This function reads a physical sector from NAND flash.
Prototype
int FS_NAND_ReadPhySector(U8 Unit,
U32 PhySectorIndex,
void * pData,
unsigned * pNumBytesData,
void * pSpare,
unsigned * pNumBytesSpare);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
PhySectorIndex | Physical sector index. |
pData | Pointer to a buffer to store read data. |
pNumBytesData | in Pointer to variable storing the size of the data buffer. out The number of bytes that were stored in the data buffer. |
pSpare | Pointer to a buffer to store read spare data. |
pNumBytesSpare | in Pointer to variable storing the size of the spare data buffer. out The number of bytes that were stored in the spare data buffer. |
Return value
< 0 | OK, all bytes are set to 0xFF in the physical sector. |
= 0 | OK, no bit errors. |
= 1 | OK, one bit error found and corrected. |
= 2 | OK, one bit error found in the ECC. |
= 3 | Error, more than 1 bit errors occurred. |
= 4 | Error, could not read form NAND flash device. |
= 5 | Error, internal operation. |
Additional information
This function is optional.
FS_NAND_ResetStatCounters()
Description
Sets the values of statistical counters to 0.
Prototype
void FS_NAND_ResetStatCounters(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based) |
Additional information
This function is optional. It is active only when the file system
is compiled with FS_DEBUG_LEVEL set to a value greater than or
equal to FS_DEBUG_LEVEL_CHECK_ALL or FS_NAND_ENABLE_STATS set to 1.
The statistical counters can be queried via FS_NAND_GetStatCounters().
FS_NAND_TestBlock()
Description
Fills all the pages in a block (including the spare area) with the
specified pattern and verifies if the data was written correctly.
Prototype
int FS_NAND_TestBlock(U8 Unit,
unsigned BlockIndex,
U32 Pattern,
FS_NAND_TEST_INFO * pInfo);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
BlockIndex | Index of the NAND block to be tested. |
Pattern | Data pattern to be written during the test. |
pInfo | out Optional information about the test result. |
Return value
FS_NAND_TEST_RETVAL_OK | OK, no bit errors. |
FS_NAND_TEST_RETVAL_CORRECTABLE_ERROR | OK, correctable bit errors found. The number of bit errors is returned in NumErrorsCorrectable of pResult. |
FS_NAND_TEST_RETVAL_FATAL_ERROR | Fatal error, uncorrectable bit error found. The page index is returned in PageIndexFatalError of pResult. |
FS_NAND_TEST_RETVAL_BAD_BLOCK | Bad block, skipped. |
FS_NAND_TEST_RETVAL_ERASE_FAILURE | Erase operation failed. The block has been marked as defective. |
FS_NAND_TEST_RETVAL_WRITE_FAILURE | Write operation failed. The block has been marked as defective. |
FS_NAND_TEST_RETVAL_READ_FAILURE | Read operation failed. |
FS_NAND_TEST_RETVAL_INTERNAL_ERROR | NAND flash access error. |
Additional information
This function is optional. It can be used by the application to
test the data reliability of a NAND block. BlockIndex is relative
to the beginning of the NAND partition where the first block has
the index 0.
Example
#include <stdio.h>
#include "FS.h"
void _SampleNANDTestBlock(void) {
int r;
U32 NumPhyBlocks;
U32 iBlock;
FS_NAND_DISK_INFO DiskInfo;
FS_NAND_TEST_INFO TestInfo;
char ac[100];
memset(&DiskInfo, 0, sizeof(DiskInfo));
memset(&TestInfo, 0, sizeof(TestInfo));
FS_NAND_GetDiskInfo(0, &DiskInfo);
NumPhyBlocks = DiskInfo.NumPhyBlocks;
for (iBlock = 0; iBlock < NumPhyBlocks; ++iBlock) {
r = FS_NAND_TestBlock(0, iBlock, 0xAA5500FFuL, &TestInfo);
switch (r) {
case FS_NAND_TEST_RETVAL_OK:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: OK.\n", iBlock);
FS_X_Log(ac);
break;
case FS_NAND_TEST_RETVAL_CORRECTABLE_ERROR:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: %lu correctable error(s).\n",
iBlock, TestInfo.BitErrorCnt);
FS_X_Log(ac);
break;
case FS_NAND_TEST_RETVAL_FATAL_ERROR:
SEGGER_snprintf(ac, sizeof(ac),
"Block %lu: %lu correctable error(s), fatal error on page %lu.\n",
iBlock, TestInfo.BitErrorCnt, TestInfo.PageIndex);
FS_X_Log(ac);
break;
case FS_NAND_TEST_RETVAL_BAD_BLOCK:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Bad. Skipped.\n", iBlock);
FS_X_Log(ac);
break;
case FS_NAND_TEST_RETVAL_ERASE_FAILURE:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Erase failure. Marked as bad.\n", iBlock);
FS_X_Log(ac);
break;
case FS_NAND_TEST_RETVAL_WRITE_FAILURE:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Write failure on page %lu. Marked as bad.\n",
iBlock, TestInfo.PageIndex);
FS_X_Log(ac);
break;
case FS_NAND_TEST_RETVAL_READ_FAILURE:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Read failure on page %lu.\n",
iBlock, TestInfo.PageIndex);
FS_X_Log(ac);
break;
default:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Internal error.\n", iBlock);
FS_X_Log(ac);
break;
}
}
}
FS_NAND_WritePage()
Description
Stores data to a page of a NAND flash with ECC.
Prototype
int FS_NAND_WritePage( U8 Unit,
U32 PageIndex,
const void * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
PageIndex | Index of the page to be written. |
pData | in Data to be written. |
NumBytes | Number of bytes to be written. |
Return value
= 0 | OK, data written. |
≠ 0 | An error occurred. |
Additional information
This function is optional.
The data is written beginning with the byte offset 0 in the page.
If more data is written than the size of the page, typically 2 KB + 64 bytes,
the excess bytes are discarded. Data in the area reserved for ECC cannot
be written using this function and it will be overwritten.
FS_NAND_WritePageRaw()
Description
Stores data to a page of a NAND flash without ECC.
Prototype
int FS_NAND_WritePageRaw( U8 Unit,
U32 PageIndex,
const void * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
PageIndex | Index of the page to be written. |
pData | in Data to be written. |
NumBytes | Number of bytes to be written. |
Return value
= 0 | OK, data written. |
≠ 0 | An error occurred. |
Additional information
This function is optional.
The data is written beginning at the byte offset 0 in the page.
If more data is written than the size of the page + spare area,
typically 2 Kbytes + 64 bytes, the excess bytes are ignored.
FS_NAND_DISK_INFO
Description
Information about the NAND partition.
Type definition
typedef struct {
U32 NumPhyBlocks;
U32 NumLogBlocks;
U32 NumUsedPhyBlocks;
U32 NumBadPhyBlocks;
U32 NumPagesPerBlock;
U32 NumSectorsPerBlock;
U32 BytesPerPage;
U32 BytesPerSpareArea;
U32 BytesPerSector;
U32 EraseCntMin;
U32 EraseCntMax;
U32 EraseCntAvg;
U8 BadBlockMarkingType;
U8 IsWriteProtected;
U8 HasFatalError;
U8 ErrorType;
U32 ErrorSectorIndex;
U16 BlocksPerGroup;
U32 NumWorkBlocks;
U8 IsFormatted;
} FS_NAND_DISK_INFO;
Structure members
Member | Description |
NumPhyBlocks | Total number of blocks in the NAND partition. |
NumLogBlocks | Total number of NAND blocks that can be used to store data. |
NumUsedPhyBlocks | Number of NAND blocks that store valid data. |
NumBadPhyBlocks | Number of NAND blocks that are marked as defective. |
NumPagesPerBlock | Number of pages in a NAND block. |
NumSectorsPerBlock | Number of logical sectors stored in a NAND block. |
BytesPerPage | Number of bytes in the main area of a NAND page. |
BytesPerSpareArea | Number of bytes in the spare area of a NAND page. |
BytesPerSector | Number of bytes is a logical sector. |
EraseCntMin | Minimum value of the erase counts in the NAND partition. |
EraseCntMax | Maximum value of the erase counts in the NAND partition. |
EraseCntAvg | Average value of the erase counts of all the NAND blocks in the NAND partition. |
BadBlockMarkingType | Type of the bad block marking. |
IsWriteProtected | Set to 1 if the NAND flash device cannot be written. |
HasFatalError | Set to 1 if the SLC1 NAND driver reported a fatal error. |
ErrorType | Type of fatal error that has occurred. |
ErrorSectorIndex | Sector index on which a fatal error occurred. |
BlocksPerGroup | Number of NAND blocks in a group. |
NumWorkBlocks | Number of work blocks used by the SLC1 NAND driver. |
IsFormatted | Set to 1 if the NAND partition has been low-level formatted. |
Additional information
Refer to Bad block marking types for a list of permitted
values for BadBlockMarkingType.
FS_NAND_BLOCK_INFO
Description
Information about a NAND block.
Type definition
typedef struct {
U32 EraseCnt;
U32 lbi;
U16 NumSectorsBlank;
U16 NumSectorsValid;
U16 NumSectorsInvalid;
U16 NumSectorsECCError;
U16 NumSectorsECCCorrectable;
U16 NumSectorsErrorInECC;
U8 IsDriverBadBlock;
U8 BadBlockErrorType;
U16 BadBlockErrorBRSI;
U8 Type;
const char * sType;
} FS_NAND_BLOCK_INFO;
Structure members
Member | Description |
EraseCnt | Number of times the block has been erased |
lbi | Logical block index assigned to queried physical block. |
NumSectorsBlank | Sectors are not used yet. |
NumSectorsValid | Sectors contain correct data. |
NumSectorsInvalid | Sectors have been invalidated. |
NumSectorsECCError | Sectors have incorrect ECC. |
NumSectorsECCCorrectable | Sectors have correctable ECC error. |
NumSectorsErrorInECC | Sectors have error in ECC. |
IsDriverBadBlock | Set to 1 if the block has been marked as bad by the driver. |
BadBlockErrorType | Type of the error that caused the block to be marked as defective. |
BadBlockErrorBRSI | Block-relative sector index on which the fatal error occurred that caused the block to be marked as defective. |
Type | Type of data stored in the block. |
sType | Zero-terminated string holding the block type. |
Additional information
Refer to NAND block types for a list of permitted values for Type.
IsDriverBadBlock is valid only when Type is set to FS_NAND_BLOCK_TYPE_BAD.
Performance and resource usage
This section provides information about the ROM and RAM usage as well
as the performance of the SLC1 NAND driver. Each SLC1 NAND driver instance
requires one instance of one NAND physical layer in order to operate.
The resource usage of the used NAND physical layer has to be taken into
account when calculating the total resource usage of the SLC1 NAND driver.
ROM usage
The ROM usage depends on the compiler options, the compiler version and the used CPU.
The memory requirements of the SLC1 NAND driver were measured as described in the section
Test procedure.
Usage: 4.5 Kbytes
Static RAM usage
Static RAM usage refers to the amount of RAM required by the SLC1 NAND driver
internally for all the driver instances. The number of bytes can be seen in the
compiler list file of the {FS_NAND_Drv.c} file.
Usage: 32 bytes
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the driver at runtime. The
amount RAM required depends on the runtime configuration and on the characteristics
of the used NAND flash device. The approximate RAM usage of the SLC1 NAND driver can be
calculated as follows:
MemAllocated = 160 + 2 * NumberOfUsedBlocks + 4 * SectorsPerBlock
+ 1.04 * MaxSectorSize
Parameter | Description |
MemAllocated | Number of bytes allocated for one instance of the NAND driver |
NumberOfUsedBlocks | Number of NAND blocks used for data storage |
SectorsPerBlock | Number of logical sectors that can be stored in a NAND block |
MaxSectorSize | Size of a logical sector in bytes |
Example 1
2 GBit NAND flash with 2K pages, 2048 blocks used, 512-byte sectors, one NAND block
consists of 64 pages, each page holds 4 sectors of 512 bytes.
SectorsPerBlock = 256
NumberOfUsedBlocks = 2048
MaxSectorSize = 512
RAM usage = (160 + 2 * 2048 + 4 * 256 + 1.04 * 512) bytes
RAM usage = 5813 bytes
Example 2
2 GBit NAND flash with 2K pages, 2048 blocks used, 2048-byte sectors,
one block consists of 64 pages, each page holds 1 sector of 2048 bytes.
SectorsPerBlock = 64
NumberOfUsedBlocks = 2048
MaxSectorSize = 2048
RAM usage = (160 + 2 * 2048 + 4 * 64 + 1.04 * 2048) bytes
RAM usage = 6642 bytes
Example 3
512 MBit NAND flash with 512 pages, 4096 blocks used, 512-byte sectors,
one block consists of 64 pages, each page holds 1 sector of 512 bytes.
SectorsPerBlock = 32
NumberOfUsedBlocks = 8192
MaxSectorSize = 512
RAM usage = (160 + 2 * 4096 + 4 * 32 + 1.04 * 512) bytes
RAM usage = 9013 bytes
Performance
The following performance measurements are in no way complete, but they
give a good approximation of time required for common operations on various
target hardware. The tests were performed as described in the section
Performance.
All values are given in Mbytes/sec.
CPU type | NAND flash device | Write speed | Read speed |
Atmel AT91SAM7S (48 MHz) | NAND flash with 512 bytes per page using port mode. | 0.8 | 2.0 |
Atmel AT91SAM7S (48 MHz) | NAND flash with 2048 bytes per page and a sector
size of 512 bytes using Port mode. | 0.7 | 2.0 |
Atmel AT91SAM7S (48 MHz) | NAND flash with 2048 bytes per page and a sector
size of 2048 bytes using the built-in NAND
controller/external bus-interface. | 1.3 | 2.3 |
Atmel AT91SAM7SE (48 MHz) | NAND flash with 2048 bytes per page and a sector
size of 512 bytes using the built-in NAND
controller/external bus-interface. | 1.6 | 3.1 |
Atmel AT91SAM7SE (48 MHz) | NAND flash with 2048 bytes per page and a sector
size of 2048 bytes using the built-in NAND
controller/external bus-interface. | 3.8 | 5.9 |
Atmel AT91SAM9261 (200 MHz) | NAND flash with 2048 bytes per page and a sector
size of 512 bytes using the built-in NAND
controller/external bus-interface. | 2.3 | 6.5 |
Atmel AT91SAM9261 (200 MHz) | NAND flash with 2048 bytes per page and a sector
size of 2048 bytes using the built-in
NAND controller/external bus-interface. | 5.1 | 9.8 |
Atmel AT91SAM9G45 (384 MHz) | NAND flash with 2048 bytes per page and a sector
size of 2048 bytes using the built-in NAND
controller/external bus-interface. | 4.7 | 12.4 |
Atmel AT91SAM3U (96 MHz) | NAND flash with 2048 bytes per page and a sector
size of 2048 bytes using the built-in NAND
controller/external bus-interface. | 5.0 | 5.9 |
Atmel AT91SAM3U (96 MHz) | NAND flash with 2048 bytes per page and a sector
size of 512 bytes using the built-in NAND
controller/external bus-interface. | 2.3 | 4.7 |
Atmel AT91SAM9261 (200 MHz) | AT45DB64 DataFlash with a sector size of 1024
bytes using the SPI interface. | 0.16 | 0.67 |
Universal NAND driver
Universal NAND driver is a very efficient device driver that was designed to support
NAND flash devices that are using Single-Level Cell (SLC) as well Multi-Level Cell (MLC) technology.
It requires a relatively small amount of RAM to operate and it can correct multiple
bit errors by using the internal ECC of a NAND flash device or by calling ECC calculation
routines provided by the application. The ECC protects the sector data and the driver
management data stored in the spare area of a page which provides better data reliability.
The Universal NAND driver uses a logical sector size that is equal to page size of the
used NAND flash device. The NAND flash device must have a page of least 2048 bytes.
Smaller logical sector sizes can be used with the help of an additional file system
layer such as Sector Size Adapter driver.
Supported hardware
In general, the Universal NAND driver supports almost all popular Single-Level Cell NAND flashes
(SLC) with a page size larger than 2048+64 bytes. The table below shows the NAND flash devices
that have been tested or are compatible with a tested device:
Device name | Page size | Number of blocks | Storage capacity | Bus width | HW ECC | Supported extra features |
AFND1G08U3 | 2048+64 byte | 1024 | 128 MiB | 16 bit | No | |
AS5F32G04SND | 2048+128 byte | 2048 | 256 MiB | 1 bit | Yes | |
AS5F34G04SND | 2048+128 byte | 4096 | 512 MiB | 1 bit | Yes | |
AS5F38G04SND | 4096+256 byte | 4096 | 1 GiB | 1 bit | Yes | |
AS9F31G08SA | 2048+64 byte | 1024 | 1 GiB | 8 bit | No | |
AS9F32G08SA | 2048+128 byte | 2048 | 2 GiB | 8 bit | No | |
AS9F34G08SA | 2048+128 byte | 4096 | 4 GiB | 8 bit | No | |
AS9F38G08SA | 2048+128 byte | 8192 | 8 GiB | 8 bit | No | |
GD5F1GQ4UF | 2048+64 byte | 1024 | 128 MiB | 1 bit | Yes | |
GD5F2GQ5UE | 2048+128 byte | 2048 | 256 MiB | 1 bit | Yes | |
GD9FU1G8F2A | 2048+128 byte | 1024 | 128 MiB | 8 bit | No | |
GD9FU4G8F2A | 2048+128 byte | 4096 | 512 MiB | 8 bit | Yes | |
HY27UF081G2A | 2048+64 byte | 1024 | 128 MiB | 8 bit | No | |
HY27UF081G2M | 2048+64 byte | 1024 | 128 MiB | 8 bit | No | |
HY27UF082G2M | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
HY27UF084G2M | 2048+64 byte | 4096 | 512 MiB | 8 bit | No | |
HY27UG084G2M | 2048+64 byte | 4096 | 512 MiB | 8 bit | No | |
HY27UG084GDM | 2048+64 byte | 4096 | 512 MiB | 8 bit | No | |
IS34ML01G081 | 2048+64 byte | 1024 | 128 MiB | 8 bit | No | |
IS34ML01G084 | 2048+64 byte | 1024 | 128 MiB | 8 bit | No | |
IS34ML02G084 | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
IS34ML04G081 | 2048+64 byte | 4096 | 512 MiB | 8 bit | No | |
IS34ML04G084 | 2048+64 byte | 4096 | 512 MiB | 8 bit | No | |
IS34ML04G088 | 4096+256 byte | 2048 | 512 MiB | 8 bit | No | |
IS35ML02G081 | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
IS37SML01G1 | 2048+64 byte | 1024 | 128 MiB | 1 bit | Yes | |
IS38SML01G1 | 2048+64 byte | 1024 | 128 MiB | 1 bit | Yes | |
TC58BVG0S3HTAI0 | 2048+64 byte | 1024 | 128 MiB | 8 bit | Yes | |
TC58BVG1S3HTA00 | 2048+64 byte | 2048 | 256 MiB | 8 bit | Yes | |
TC58BYG0S3HBAI6 | 2048+64 byte | 1024 | 128 MiB | 8 bit | Yes | |
TC58CVG0S3HRAIJ | 2048+64 byte | 1024 | 128 MiB | 1 bit | Yes | |
TC58CVG1S3HRAIF | 2048+128 byte | 2048 | 256 MiB | 1 bit | Yes | |
TC58CVG1S3HRAIG | 2048+64 byte | 2048 | 256 MiB | 1 bit | Yes | |
TC58CVG1S3HRAIJ | 2048+64 byte | 2048 | 256 MiB | 1 bit | Yes | |
TC58CVG2S0HRAIJ | 4096+128 byte | 2048 | 512 MiB | 1 bit | Yes | |
TC58CYG0S3HRAIJ | 2048+64 byte | 1024 | 128 MiB | 1 bit | Yes | |
TC58CYG1S3HRAIJ | 2048+64 byte | 2048 | 256 MiB | 1 bit | Yes | |
TC58CYG2S0HRAIG | 4096+128 byte | 2048 | 512 MiB | 1 bit | Yes | |
TC58CYG2S0HRAIJ | 4096+128 byte | 2048 | 512 MiB | 1 bit | Yes | |
TH58BYG3S0HBAI6 | 4096+128 byte | 4096 | 1 GiB | 8 bit | Yes | |
TH58CVG3S0HRAIJ | 4096+128 byte | 4096 | 1 GiB | 1 bit | Yes | |
TH58CYG3S0HRAIJ | 4096+128 byte | 4096 | 1 GiB | 1 bit | Yes | |
MX30LF1G18AC | 2048+64 byte | 1024 | 128 MiB | 8 bit | No | |
MX30LF1G28AD | 2048+128 byte | 1024 | 128 MiB | 8 bit | No | |
MX30LF1GE8AB | 2048+64 byte | 1024 | 128 MiB | 8 bit | Yes | |
MX30LF2G28AD | 2048+128 byte | 2048 | 256 MiB | 8 bit | No | |
MX30LF2GE8AB | 2048+64 byte | 2048 | 256 MiB | 8 bit | Yes | |
MX30LF4G28AD | 4096+256 byte | 2048 | 512 MiB | 8 bit | No | |
MX30LF4GE8AB | 2048+64 byte | 4096 | 512 MiB | 8 bit | Yes | |
MX35LF1G24AD | 2048+128 byte | 1024 | 128 MiB | 1 bit | No | |
MX35LF1GE4AB | 2048+64 byte | 1024 | 128 MiB | 1 bit | Yes | |
MX35LF2G24AD | 2048+128 byte | 2048 | 256 MiB | 1 bit | No | |
MX35LF2GE4AD | 2048+64 byte | 2048 | 256 MiB | 1 bit | Yes | |
MX35LF4G24AD | 4096+256 byte | 2048 | 512 MiB | 1 bit | No | |
MX35LF4GE4AD | 4096+128 byte | 2048 | 512 MiB | 1 bit | Yes | |
MX60LF8G28AB | 2048+112 byte | 8192 | 1 GiB | 8 bit | No | |
MX60LF8G28AD | 4096+256 byte | 4096 | 1 GiB | 8 bit | No | |
MT29F1G01AAADD | 2048+64 byte | 1024 | 128 MiB | 1 bit | Yes | |
MT29F1G01ABAFD | 2048+128 byte | 1024 | 128 MiB | 1 bit | Yes | |
MT29F1G01ABBFD | 2048+128 byte | 1024 | 128 MiB | 1 bit | Yes | |
MT29F1G08ABADA | 2048+64 byte | 1024 | 128 MiB | 8 bit | Yes | |
MT29F1G08ABAEA | 2048+64 byte | 1024 | 128 MiB | 8 bit | No | |
MT29F1G08ABAFA | 2048+128 byte | 1024 | 128 MiB | 8 bit | Yes | |
MT29F2G01AAAED | 2048+64 byte | 2048 | 256 MiB | 1 bit | Yes | |
MT29F2G01ABAGD | 2048+128 byte | 2048 | 256 MiB | 1 bit | Yes | |
MT29F2G08AAB | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
MT29F2G08ABABA | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
MT29F2G08ABAEA | 2048+64 byte | 2048 | 256 MiB | 8 bit | Yes | |
MT29F2G08ABAGA | 2048+128 byte | 2048 | 256 MiB | 8 bit | Yes | |
MT29F2G08ABD | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
MT29F2G16AAD | 2048+64 byte | 2048 | 256 MiB | 16 bit | No | |
MT29F2G16ABAEA | 2048+64 byte | 2048 | 256 MiB | 16 bit | Yes | |
MT29F4G01AAADD | 2048+64 byte | 4096 | 512 MiB | 1 bit | Yes | |
MT29F4G01ABAFD | 4096+256 byte | 4096 | 512 MiB | 1 bit | Yes | |
MT29F4G01ABBFD | 4096+256 byte | 2048 | 512 MiB | 1 bit | Yes | |
MT29F4G08AAA | 2048+64 byte | 4096 | 512 MiB | 8 bit | No | |
MT29F4G08ABADA | 2048+64 byte | 4096 | 512 MiB | 8 bit | Yes | |
MT29F4G08BAB | 2048+64 byte | 4096 | 512 MiB | 8 bit | No | |
MT29F8G01ADAFD | 4096+256 byte | 4096 | 1 GiB | 1 bit | Yes | |
MT29F8G01ADBFD | 4096+256 byte | 4096 | 1 GiB | 1 bit | Yes | |
MT29F8G08ABABA | 4096+224 byte | 2048 | 1 GiB | 8 bit | No | |
MT29F8G08ABACA | 4096+224 byte | 4096 | 1 GiB | 8 bit | No | |
NAND01GR3B | 2048+64 byte | 1024 | 128 MiB | 8 bit | No | |
NAND01GW3B | 2048+64 byte | 1024 | 128 MiB | 8 bit | No | |
NAND02GR3B | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
NAND02GW3B | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
NAND04GW3B | 2048+64 byte | 4096 | 512 MiB | 8 bit | No | |
K9F1G08R0A | 2048+64 byte | 1024 | 128 MiB | 8 bit | No | |
K9F1G08U0A | 2048+64 byte | 1024 | 128 MiB | 8 bit | No | |
K9F1G08U0C | 2048+64 byte | 1024 | 128 MiB | 8 bit | No | |
K9F1G08U0F | 2048+64 byte | 1024 | 128 MiB | 8 bit | Yes | |
K9F2G08U0M | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
K9F4G08U0A | 2048+64 byte | 4096 | 512 MiB | 8 bit | No | |
K9F4G08U0M | 2048+64 byte | 4096 | 512 MiB | 8 bit | No | |
K9F8G08U0M | 2048+128 byte | 4096 | 1 GiB | 8 bit | No | |
K9K2G08R0A | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
K9K2G08U0M | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
S34ML01G100TFI000 | 2048+64 byte | 1024 | 128 MiB | 8 bit | No | |
S34ML01G300TFI013 | 2048+64 byte | 1024 | 128 MiB | 8 bit | Yes | |
S34ML04G100TFI000 | 2048+64 byte | 4096 | 512 MiB | 8 bit | No | |
S34ML04G200TFI000 | 2048+128 byte | 4096 | 512 MiB | 8 bit | No | |
S34ML04G300TFI000 | 2048+128 byte | 4096 | 512 MiB | 8 bit | Yes | |
S34ML04G300TFI100 | 4096+256 byte | 2048 | 512 MiB | 8 bit | Yes | |
S34ML08G201TFI000 | 2048+128 byte | 8192 | 1 GiB | 8 bit | No | |
S34ML08G301TFI000 | 2048+128 byte | 8192 | 1 GiB | 8 bit | Yes | |
S34ML16G202TFI200 | 2048+128 byte | 16384 | 2 GiB | 8 bit | No | |
S34ML16G303TFI000 | 2048+128 byte | 16384 | 2 GiB | 8 bit | Yes | |
S34MS02G100TFI000 | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
W25M02GVZEIT | 2048+64 byte | 2048 | 256 MiB | 1 bit | Yes | |
W25N01GVZEIG | 2048+64 byte | 1024 | 128 MiB | 1 bit | Yes | |
W25N01JWSFIT | 2048+64 byte | 1024 | 128 MiB | 1 bit | Yes | DTR |
W25N02JWZEIF | 2048+64 byte | 2048 | 256 MiB | 1 bit | Yes | DTR |
W25N02KVZEIU | 2048+128 byte | 2048 | 256 MiB | 1 bit | Yes | |
W25N04KVZEIR | 2048+128 byte | 4096 | 512 MiB | 1 bit | Yes | |
W25N512GVEIG | 2048+64 byte | 512 | 64 MiB | 1 bit | Yes | |
W29N02GZSIBF | 2048+64 byte | 2048 | 256 MiB | 8 bit | No | |
W29N08GVSIAA | 2048+64 byte | 8192 | 1 GiB | 8 bit | No | |
XT27G02BTSIG | 2048+64 byte | 2048 | 256 MiB | 8 bit | Yes | |
Support for devices not in the list
Most other NAND flash devices are compatible with one of the supported devices.
Thus, the driver can be used with these devices or may only need a little
modification, which can be easily done. Get in touch with us, if you have questions about
support for devices not in this list.
Theory of operation
NAND flash devices are divided into physical blocks and physical pages. One physical
block is the smallest erasable unit while one physical page is the smallest writable unit.
Large block NAND Flash devices contain blocks made up of 64 pages, each page containing
2112 bytes (2048 data bytes + 64 spare bytes). The Universal NAND driver reserves the first
page of a block for management data such as erase count.
The Universal NAND driver uses the spare bytes for the following purposes:
- To check if the block is valid.
If a block is valid then the driver uses it for data storage. When the driver detects
a uncorrectable bit error in a page, the entire block containing that page is marked
as invalid and its content is copied to a non-defective block.
- To store/load management information.
This includes the mapping of pages to logical sectors, the number of times a
block has been erased and whether a page contains valid data or not.
- To store and load an ECC (Error Correction Code) for data reliability.
When reading a page, the driver also reads the ECC stored in the spare area of
that page, calculates the ECC based on the read data and compares the ECCs. If
the ECCs are not identical, the driver tries to recover the data, based on the read
ECC. When writing to a page the ECC is calculated based on the data the driver has to
write to the page. The calculated ECC is then stored in the spare area of that page.
Support for custom hardware
It is possible to use the Universal NAND driver with a custom hardware. If port pins
or a simple memory controller are used for accessing the flash memory, only the hardware
layer needs to be ported and normally no changes to the physical layer are required. If the
NAND driver has to be used with a special memory controller (for example special
FPGA implementations), the physical layer needs to be adapted. In this case, the
hardware layer is not required, because the memory controller manages all the hardware accesses.
Partial write operations
The Universal NAND driver writes only once in any page of the NAND flash between
two erase operations of the NAND block that contain that page. Therefore, the number
of partial write operation is one which makes the driver compatible with any SLC and
MLC NAND flash device.
High-reliability operation
The Universal NAND driver supports a feature that can be used to increase the reliability
of the data stored to a NAND flash device. It works by checking the number of bit errors
corrected by the ECC during each page read operation. If the number of bit errors is equal
to or greater than a configured threshold the Universal NAND driver copies the contents of
the NAND block containing the read page to an other location. This prevents the accumulation
of bit errors that may cause ECC correction errors. An ECC correction error occurs when the
number of bit errors is larger than the number of bit errors the ECC is able to correct.
Typically, a correction error leads to a data loss.
This feature requires support for the FS_NAND_PHY_TYPE_GET_ECC_RESULT function in the
NAND physical layer. By default, the feature is disabled for performance reasons
and has to be explicitly enabled at compile time by setting FS_NAND_MAX_BIT_ERROR_CNT
to a value greater than 0. This value can be modified at runtime by calling
FS_NAND_UNI_SetMaxBitErrorCnt().
Note
Enabling the high-reliability operation may reduce the specified lifetime of the
NAND flash due to the increased number of erase cycles.
Configuring the driver
This section describes how to configure the file system to make use of the Universal NAND driver.
Compile time configuration
The Universal NAND driver can optionally be configured at compile time. Typically,
this step can be omitted because the Universal NAND driver provides reasonable
default values that work for most of the target applications.
The compile time configuration is realized via preprocessor defines that have
to be added to the FS_Conf.h file which is the main configuration file
of emFile. For detailed information about the configuration of emFile
and of the configuration define types, refer to Configuration of emFile
The following table lists the configuration defines supported by the Universal
NAND driver.
FS_NAND_ECC_HOOK_DEFAULT
The FS_NAND_ECC_HOOK_DEFAULT can be used to specify default ECC calculation routines.
For a file system configuration that has support for calculating the ECC in the hardware
FS_NAND_ECC_HOOK_DEFAULT can be set to NULL to reduce the ROM usage.
In this case it is mandatory that the application specifies at runtime a different
ECC algorithm via FS_NAND_UNI_SetECCHook().
FS_NAND_ENABLE_ERROR_RECOVERY
This define can be used to enable the support for error recovery in the Universal NAND driver.
The error recovery is performed by getting corrected data from a redundant partition via one of
the RAID components of the file system. Refer to RAID1 driver and RAID5 driver for
more information about this.
FS_NAND_ENABLE_STATS
This define can be used to enable the support for statistical counters.
The statistical counters provide information about the number of operations
performed internally by the Universal NAND driver. This information can be
useful for analyzing the performance.
The statistical counters can be queried via FS_NAND_UNI_GetStatCounters().
By default FS_NAND_ENABLE_STATS is set to 1 if FS_DEBUG_LEVEL is set
to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.
FS_NAND_ENABLE_STATS_SECTOR_STATUS
This define can be used to configure if the Universal NAND driver has to collect
information about the number of valid logical sectors. Enabling this operation may negatively
affect the performance of the low-level mount operation because the the Universal NAND
driver has to check the status of all logical sectors.
FS_NAND_ENABLE_STATS_SECTOR_STATUS takes effect only if FS_NAND_ENABLE_STATS is set to 1.
FS_NAND_FILL_READ_BUFFER
FS_NAND_FILL_READ_BUFFER can be used to configure if the read buffer that receives the
contents of an invalid logical sector has to be initialized with predefined data. The byte pattern
that has to be used for filling the buffer contents can be specified via FS_NAND_READ_BUFFER_FILL_PATTERN.
By default this feature is enabled only if no file system layer is used
(both FS_SUPPORT_FAT and FS_SUPPORT_EFS set to 0), because the file system layer does not rely on this feature.
FS_NAND_MAX_BIT_ERROR_CNT
This define can be used to configure the monitoring of bit errors in the
Universal NAND driver. The assigned value specifies the maximum number of correctable
bit errors that are allowed to occur in a page before the block that contains that
page is copied to another location. This is done in order to reduce the probability
of a data loss as a result of an ECC correction error by keeping the number of bit errors
below the bit error correction capability of the ECC algorithm.
The value of FS_NAND_MAX_BIT_ERROR_CNT has to be smaller than or equal to the bit
error correction capability that is required by the NAND flash device. The bit error
monitoring is disabled if FS_NAND_MAX_BIT_ERROR_CNT is set to 0. The maximum number
of bit errors can also be changed at runtime via FS_NAND_UNI_SetMaxBitErrorCnt().
Enabling this feature increases the data reliability but it may negatively affect the performance.
FS_NAND_MAX_PAGE_SIZE
FS_NAND_MAX_PAGE_SIZE can be used to configure the the size of the internal buffer
that the Universal NAND driver uses for reading and writing the data of the main area of a page.
If FS_NAND_MAX_PAGE_SIZE is set to 0 then the Universal NAND driver allocates a buffer
with a size equal to the logical sector of the file system. In addition, the size
of the buffer can be configured at runtime via FS_NAND_UNI_SetMaxPageSize().
FS_NAND_MAX_SPARE_AREA_SIZE
FS_NAND_MAX_SPARE_AREA_SIZE can be used to configure the size of the internal buffer
that the Universal NAND driver uses for reading and writing the data of the spare area of a page.
If FS_NAND_MAX_SPARE_AREA_SIZE is set to 0 then the Universal NAND driver allocates
a buffer that is 1/32 of the internal buffer allocated for the main area of a page.
For example, 64 bytes are allocated if the size of the buffer used for the main area
of a page is 2048 bytes. If the ratio between the size of the main and spare area of the page
is different than 1/32 then FS_NAND_MAX_SPARE_AREA_SIZE has to be set to the number of bytes
in the spare area of the NAND flash device. In addition, the size of the buffer can be configured
a runtime via FS_NAND_UNI_SetMaxSpareAreaSize().
FS_NAND_NUM_READ_RETRIES
FS_NAND_NUM_READ_RETRIES can be used to specify the number of times the Universal NAND driver
reties the operation in case of a read error (device error or uncorrectable bit error). NumReadRetries
of FS_NAND_STAT_COUNTERS is incremented by 1 on each retry.
FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS
FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS can be used to configure the behavior of the Universal NAND driver
during the low-level format operation with regards to the NAND blocks marked as defective.
If FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS is set to 1 then the NAND blocks marked as defective by
the Universal NAND driver are erased during the low-level format operation.
If FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS is set to 0 then the low-level format operation does not
erase the NAND blocks marked as defective by the Universal NAND driver. This is the default behavior.
Setting FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS to 1 is useful during the development of a NAND physical
or hardware layer when NAND blocks may be marked as defective by mistake. These blocks can then be easily
erased via a low-level format operation. The NAND blocks marked as defective by the manufacturer are never erased.
In addition, these NAND blocks are never used for data storage.
FS_NAND_NUM_WRITE_RETRIES
FS_NAND_NUM_WRITE_RETRIES can be used to specify the number of times
the Universal NAND driver reties the operation in case of a write error.
A write error occurs when the NAND flash device is not
able to write the data to memory array. This condition is typically
reported via a flag in the status register of the NAND flash device
that is queried by the NAND physical layer after each write operation.
NumWriteRetries of FS_NAND_STAT_COUNTERS is incremented by 1 on each retry.
FS_NAND_NUM_UNITS
This define specifies the maximum number of driver instances of the Universal NAND driver
the application is allowed create. Four bytes of static RAM are reserved for each instance.
If the maximum number of driver instances is smaller than the default then FS_NAND_NUM_UNITS
can be set to the to that value in order to reduce the RAM usage.
FS_NAND_OPTIMIZE_SPARE_AREA_READ
This configuration define can be used to enable an optimization that reduces the amount of data
transferred by the Universal NAND driver from the spare area from a page to the MCU.
With FS_NAND_OPTIMIZE_SPARE_AREA_READ set to 0 the entire spare are of a page is transferred
to MCU each time the Universal NAND driver has to evaluate the management data of that page.
If FS_NAND_OPTIMIZE_SPARE_AREA_READ set to 1 then only the regions of the spare area that
store the management data are transferred to the MCU. This may help improve the performance
when the NAND flash device is connected to the MCU via a relatively slow interface such as SPI.
FS_NAND_READ_BUFFER_FILL_PATTERN
The Universal NAND driver uses the byte value assigned to FS_NAND_READ_BUFFER_FILL_PATTERN
to fill the read buffer that receives the contents of a logical sector that does not contain any valid data.
The contents of a logical sector becomes valid when the file system layer writes any data to it.
After a low-level format operation the contents of all logical sectors is invalid.
The contents of a logical sector can be explicitly invalidated via a sector free operation.
FS_NAND_READ_BUFFER_FILL_PATTERN takes effect only if FS_NAND_FILL_READ_BUFFER is set to 1.
FS_NAND_STAT_MAX_BIT_ERRORS
FS_NAND_STAT_MAX_BIT_ERRORS defines how many bit error counters the Universal NAND driver
has to maintain. Each counter keeps track of the number of times a certain number of bit
errors occurred at the same time during one page read operation. The first counter keeps track of the number
of 1 bit errors, the second counter keeps track of the number of 2 bit errors and so on.
The bit error counters can be read via FS_NAND_UNI_GetStatCounters().
FS_NAND_ENABLE_STATS_SECTOR_STATUS takes effect only if FS_NAND_ENABLE_STATS is set to 1.
FS_NAND_SUPPORT_BLOCK_GROUPING
FS_NAND_SUPPORT_BLOCK_GROUPING can be used to specify if the Universal NAND driver
is able to handle of two or more adjacent NAND blocks as a single block.
The number of blocks in the group has to be configured at runtime via
FS_NAND_UNI_SetNumBlocksPerGroup(). The RAM usage of the Universal NAND driver depends
on the number of NAND blocks it has to manage. Therefore, enabling the block grouping
feature can help reduce the RAM usage because the the number of blocks decreases.
If the block grouping feature is not required by the application then FS_NAND_SUPPORT_BLOCK_GROUPING
can be set to 0 in order to reduce the RAM and ROM usage of the Universal NAND driver.
FS_NAND_SUPPORT_FAIL_SAFE_ERASE
FS_NAND_SUPPORT_FAIL_SAFE_ERASE can be used to enable or disable the detection of interrupted
block erase operations. This feature works by invalidating the management data of the block
before the erase operation and by storing a valid erase count to the block after a successful
erase operation. In this way, the driver is able to identify and erase again these blocks during
the low-level mount operation. With the support for the fail-safe erase operation enabled,
the target hardware is no longer required to meet the timing requirements described in
Fail-safe operation. Instead, the target hardware will
have to make sure that a write page operation completes successfully. Typically, such an operation
takes about 250 us to complete.
FS_NAND_VERIFY_ERASE
This define can be used to activate the erase verification of the Universal NOR driver.
The erase verification is performed after each erase operation by reading back
the entire data of the erased block and by comparing each byte in the block with 0xFF.
An error is reported if a difference is detected.
This feature has to be enabled at runtime by calling FS_NAND_UNI_SetEraseVerification().
Note
Activating the erase verification may negatively affect the write performance.
FS_NAND_VERIFY_WRITE
This define can be used to activate the write verification of the Universal NAND driver.
The write verification is performed after each write operation by reading back
the modified data and by comparing it with the data requested to be written.
An error is reported if a difference is detected.
This feature has to be enabled at runtime by calling FS_NAND_UNI_SetWriteVerification().
Note
Activating the write verification may negatively affect the write performance.
Runtime configuration
The driver must be added to the file system by calling FS_AddDevice() with the
driver identifier set to the address of FS_NAND_UNI_Driver. This function call
together with other function calls that configure the driver operation have to
be added to FS_X_AddDevices() as demonstrated in the following example.
Example
#include "FS.h"
#include "FS_NAND_HW_Template.h"
#define ALLOC_SIZE 0x9000 // Memory pool for the file system in bytes
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for semi-dynamic allocation.
void FS_X_AddDevices(void) {
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Add the NAND flash driver to file system. Volume name: "nand:0:".
//
FS_AddDevice(&FS_NAND_UNI_Driver);
//
// Set the physical interface of the NAND flash.
//
FS_NAND_UNI_SetPhyType(0, &FS_NAND_PHY_ONFI);
//
// Configure the driver to use the internal ECC of NAND flash for error correction.
//
FS_NAND_UNI_SetECCHook(0, &FS_NAND_ECC_HW_NULL);
//
// Configure the HW access routines.
//
FS_NAND_ONFI_SetHWType(0, &FS_NAND_HW_Template);
#if FS_SUPPORT_FILE_BUFFER
//
// Enable the file buffer to increase the performance
// when reading/writing a small number of bytes.
//
FS_ConfigFileBufferDefault(512, FS_FILE_BUFFER_WRITE);
#endif // FS_SUPPORT_FILE_BUFFER
}
The API functions listed in the next table can be used by the application to
configure the behavior of the Universal NAND driver. The application can call
them only at the file system initialization in FS_X_AddDevices().
FS_NAND_UNI_AllowBlankUnusedSectors()
Description
Configures if the data of unused sectors has to be initialized.
Prototype
void FS_NAND_UNI_AllowBlankUnusedSectors(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of driver instance (0-based). |
OnOff | Specifies if the feature has to be enabled or disabled =0 Sector data is filled with 0s. ≠0 Sector data is not initialized (all bytes remain set to 0xFF). |
Additional information
This function is optional.
The default behavior of the Universal NAND driver is to fill
the data of unused logical sectors with 0s. This done in order
to reduce the chance of a bit error caused by an unwanted transition
from 1 to 0 of the value stored to these memory cells.
Some NAND flash devices may wear out faster than expected if
excessive number of bytes are set to 0. This limitation is typically
documented in the data sheet of the corresponding NAND flash.
For such devices it is recommended configure the Universal NAND
driver to do not initialize the unused sectors with 0s. This can
be realized by calling FS_NAND_UNI_AllowBlankUnusedSectors() with
the OnOff parameter set to 1 in FS_X_AddDevices().
FS_NAND_UNI_AllowReadErrorBadBlocks()
Description
Configures if a block is marked as defective on read fatal error.
Prototype
void FS_NAND_UNI_AllowReadErrorBadBlocks(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of driver instance (0-based). |
OnOff | Specifies if the feature has to be enabled or disabled =0 The block is not marked as defective. ≠0 The block is marked as defective. |
Additional information
This function is optional.
The default behavior of the Universal NAND driver is to mark a
block as defective if a read error or and uncorrectable bit error
occurs while reading data from a page of that block.
FS_NAND_UNI_SetBlockRange()
Description
Specifies which NAND blocks the driver can use to store the data.
Prototype
void FS_NAND_UNI_SetBlockRange(U8 Unit,
U16 FirstBlock,
U16 MaxNumBlocks);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
FirstBlock | Index of the first NAND flash block to be used as storage (0-based). |
MaxNumBlocks | Maximum number of NAND flash blocks to be used as storage. |
Additional information
This function is optional. By default, the Universal NAND driver uses
all blocks of the NAND flash as data storage. FS_UNI_NAND_SetBlockRange()
is useful when a part of the NAND flash has to be used for another
purpose, for example to store the application program used by a boot loader,
and therefore it cannot be managed by the Universal NAND driver. Limiting
the number of blocks used by the Universal NAND driver can also help reduce the RAM usage.
FirstBlock is the index of the first physical NAND block were
0 is the index of the first block of the NAND flash device.
MaxNumBlocks can be larger that the actual number of available
NAND blocks in which case the Universal NAND driver silently truncates
the value to reflect the actual number of NAND blocks available.
The Universal NAND driver uses the first NAND block in the range to store
management information at low-level format. If the first NAND block happens
to be marked as defective, then the next usable NAND block is used.
If the FS_UNI_NAND_SetBlockRange() is used to subdivide the same
physical NAND flash device into two or more partitions than
the application has to make sure that the created partitions do not overlap.
The read optimization of the FS_NAND_PHY_2048x8 physical layer has to be
disabled when this function is used to partition the NAND flash device
in order to ensure data consistency. The read cache can be disabled at
runtime via FS_NAND_2048x8_DisableReadCache().
FS_NAND_UNI_SetBlockReserve()
Description
Configures the number of NAND flash blocks to be reserved
as replacement for the NAND flash blocks that become defective.
Prototype
void FS_NAND_UNI_SetBlockReserve(U8 Unit,
unsigned pctOfBlocks);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
pctOfBlocks | Number of NAND flash blocks to be reserved as percentage of the total number of NAND flash blocks. |
Additional information
This function is optional. The Universal NAND driver reserves
by default about 3% of the total number of NAND flash blocks
which is sufficient for most applications. Reserving more NAND flash
blocks can increase the lifetime of the NAND flash device.
The NAND flash device has to be low-level formatted after
changing the number of reserved blocks.
FS_NAND_UNI_SetCleanThreshold()
Description
Specifies the minimum number sectors that the driver should keep
available for fast write operations.
Prototype
int FS_NAND_UNI_SetCleanThreshold(U8 Unit,
unsigned NumBlocksFree,
unsigned NumSectorsFree);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
NumBlocksFree | Number of blocks to be kept free. |
NumSectorsFree | Number of sectors to be kept free on each block. |
Return value
= 0 | OK, threshold has been set. |
≠ 0 | An error occurred. |
Additional information
This function is optional.
It can be used by the application to prepare the NAND flash device to
write data as fast as possible once when an event occurs such an
unexpected reset. At the startup, the application reserves free space,
by calling the function with NumBlocksFree and NumSectorsFree set to a
value different than 0. The number of free sectors depends on the number
of bytes written and on how the file system is configured.
When the unexpected reset occurs, the application tells the driver that
it can write to the free sectors, by calling the function with
NumBlocksFree and NumSectorsFree set to 0. Then, the application writes
the data to file and the NAND driver stores it to the free space.
Since no erase or copy operation is required, the data is written as
fastest as the NAND flash device permits it.
The NAND flash device will wear out faster than normal if sectors
are reserved in a work block (NumSectors > 0).
Example
The following sample code demonstrates how to determine the threshold parameters.
#include <stdio.h>
#include "FS.h"
void SampleNAND_UNISetCleanThreshold(void) {
unsigned NumPhyBlocks;
unsigned NumWorkBlocks;
FS_FILE * pFile;
FS_NAND_DISK_INFO DiskInfo;
FS_NAND_BLOCK_INFO BlockInfo;
U32 BlockIndex;
unsigned MaxNumSectors;
unsigned NumSectorsValid;
char ac[100];
//
// Get information about the storage.
//
memset(&DiskInfo, 0, sizeof(DiskInfo));
FS_NAND_UNI_GetDiskInfo(0, &DiskInfo);
NumPhyBlocks = DiskInfo.NumPhyBlocks;
NumWorkBlocks = DiskInfo.NumWorkBlocks;
//
// Make sure that all work blocks are converted to data blocks.
//
FS_NAND_UNI_Clean(0, NumWorkBlocks, 0);
//
// Create a test file, write to file the data
// to be saved on sudden reset then close it.
//
pFile = FS_FOpen("Test.txt", "w");
FS_Write(pFile, "Reset", 5);
FS_FClose(pFile);
//
// Calculate how many work blocks were written
// and the maximum number of sectors written in a work block.
//
NumWorkBlocks = 0;
BlockIndex = 0;
MaxNumSectors = 0;
do {
memset(&BlockInfo, 0, sizeof(BlockInfo));
FS_NAND_UNI_GetBlockInfo(0, BlockIndex++, &BlockInfo);
if (BlockInfo.Type == FS_NAND_BLOCK_TYPE_WORK) {
++NumWorkBlocks;
NumSectorsValid = BlockInfo.NumSectorsValid;
if (MaxNumSectors < NumSectorsValid) {
MaxNumSectors = NumSectorsValid;
}
}
} while (--NumPhyBlocks);
//
// Clean up: remove the test file.
//
FS_Remove("Test.txt");
//
// Show the calculated values.
// NumWorkBlocks and MaxNumSectors can be passed as 2nd and 3rd
// argument in the call to FS_NAND_UNI_SetWorkBlockReserve().
//
SEGGER_snprintf(ac, sizeof(ac), "Number of work blocks used: %u\n", NumWorkBlocks);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), "Max. number of used sectors: %u\n", MaxNumSectors);
FS_X_Log(ac);
}
Sample output
Number of work blocks used: 1
Max. number of used sectors: 5
FS_NAND_UNI_SetDriverBadBlockReclamation()
Description
Configures if the bad blocks marked as defective by the driver
have to be erased at low-level format or not.
Prototype
void FS_NAND_UNI_SetDriverBadBlockReclamation(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
OnOff | Configures if the feature has to be enable or disabled. =1 Defective blocks marked as such by the driver are erased at low-level format. =0 Defective blocks marked as such by the driver are not erased at low-level format. |
Additional information
This function is active only when the option
FS_NAND_RECLAIM_DRIVER_BAD_BLOCKS is set to 1.
The default behavior is to erase the blocks marked as
defective by the driver.
FS_NAND_UNI_SetECCHook()
Description
Configures the ECC algorithm to be used for the correction of bit errors.
Prototype
void FS_NAND_UNI_SetECCHook( U8 Unit,
const FS_NAND_ECC_HOOK * pECCHook);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based) |
pECCHook | in ECC algorithm. |
Additional information
This function is optional. By default, the Universal NAND driver
uses an software algorithm that is capable of correcting 1 bit
errors and of detecting 2 bit errors. If the NAND flash device
requires a better error correction, the application has to specify
an different ECC algorithm via FS_NAND_UNI_SetECCHook().
The ECC algorithms can be either implemented in the software or
the calculation routines can take advantage of any dedicated ECC
HW available on the target system.
The following ECC algorithms are supported:
Type | Description |
FS_NAND_ECC_HW_NULL | This is a pseudo ECC algorithm that requests the Universal NAND driver to use the internal HW ECC of a NAND flash device. |
FS_NAND_ECC_HW_4BIT | This is a pseudo ECC algorithm that requests the Universal NAND driver to use HW 4 bit error correction. It can be used for example with dedicated a NAND flash controller that comes with a configurable HW ECC. |
FS_NAND_ECC_HW_8BIT | This is a pseudo ECC algorithm that requests the Universal NAND driver to use HW 8 bit error correction. It can be used for example with dedicated a NAND flash controller that comes with a configurable HW ECC. |
FS_NAND_ECC_SW_1BIT | This is an software algorithm that is able to correct 1 bit errors and detect 2 bit errors. More specifically it can correct a 1 bit error per 256 bytes of data and a 1 bit error per 4 bytes of spare area. |
Additional software algorithms with error correction capabilities
greater than 1 are supported via the SEGGER emLib ECC component
(www.segger.com/products/security-iot/emlib/variations/ecc/).
FS_NAND_UNI_SetEraseVerification()
Description
Enables or disables the checking of the block erase operation.
Prototype
void FS_NAND_UNI_SetEraseVerification(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
OnOff | Specifies if the feature has to be enabled or disabled =0 The erase operation is not checked. ≠0 The erase operation is checked. |
Additional information
This function is optional. The result of a block erase operation
is normally checked by evaluating the error bits maintained by the
NAND flash device in a internal status register. FS_NAND_UNI_SetEraseVerification()
can be used to enable additional verification of the block erase
operation that is realized by reading back the contents of the entire
erased physical block and by checking that all the bytes in it are
set to 0xFF. Enabling this feature can negatively impact the write
performance of Universal NAND driver.
The block erase verification feature is active only when the Universal
NAND driver is compiled with the FS_NAND_VERIFY_ERASE configuration
define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL
configuration define is set to a value greater than or equal to
FS_DEBUG_LEVEL_CHECK_ALL.
FS_NAND_UNI_SetMaxBitErrorCnt()
Description
Configures the number of bit errors that trigger the relocation
of the data stored in a NAND block.
Prototype
void FS_NAND_UNI_SetMaxBitErrorCnt(U8 Unit,
unsigned BitErrorCnt);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
BitErrorCnt | Number of physical bit errors. |
Additional information
This function is optional and is active only when the
file system is compiled with FS_NAND_MAX_BIT_ERROR_CNT set to
a value greater than 0.
FS_NAND_UNI_SetMaxBitErrorCnt() can be used to configure when
the Universal NAND Driver has to copy the contents of a NAND block
to another location in order to prevent the accumulation of bit errors.
BitErrorCnt has to be smaller than or equal to the bit error
correction requirement of the NAND flash device. The feature can
be disabled by calling FS_NAND_UNI_SetMaxBitErrorCnt() with
BitErrorCnt set to 0.
The lifetime of the NAND flash device can be negatively affected
if this feature is enabled due to the increased number of block
erase operations.
FS_NAND_UNI_SetMaxEraseCntDiff()
Description
Configures the threshold of the wear leveling procedure.
Prototype
void FS_NAND_UNI_SetMaxEraseCntDiff(U8 Unit,
U32 EraseCntDiff);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
EraseCntDiff | Maximum allowed difference between the erase counts of any two NAND blocks. |
Additional information
This function is optional. It can be used to control how
the Universal NAND driver performs the wear leveling.
The wear leveling procedure makes sure that the NAND blocks
are equally erased to meet the life expectancy of the storage
device by keeping track of the number of times a NAND block
has been erased (erase count). The Universal NAND driver executes
this procedure when a new empty NAND block is required for
data storage. The wear leveling procedure works by first
choosing the next available NAND block. Then the difference
between the erase count of the chosen block and the NAND block
with lowest erase count is computed. If this value is greater
than EraseCntDiff the NAND block with the lowest erase count
is freed and made available for use.
The same threshold can also be configured at compile time
via the FS_NAND_MAX_ERASE_CNT_DIFF configuration define.
FS_NAND_UNI_SetMaxPageSize()
Description
Configures the maximum handled page size.
Prototype
void FS_NAND_UNI_SetMaxPageSize(unsigned NumBytes);
Parameters
Parameter | Description |
NumBytes | NAND page size in bytes. |
Additional information
This function can be used at runtime to configure the size of
the internal buffer used by the Universal NAND driver to read
the data from a NAND page. This buffer is shared by all instances
of the Universal NAND driver. If the application does not call
FS_NAND_UNI_SetMaxPageSize() then the size of the internal page
buffer is set to FS_NAND_MAX_PAGE_SIZE if FS_NAND_MAX_PAGE_SIZE
is different than 0 or to the logical sector size of the file
system if FS_NAND_MAX_PAGE_SIZE is set to 0.
FS_NAND_UNI_SetMaxPageSize() is for example useful when
the application is using two NAND flash devices with different
page sizes. In this case, the application has to call
FS_NAND_UNI_SetMaxPageSize() with the NumBytes parameter set to
the largest of the two page sizes.
FS_NAND_UNI_SetMaxPageSize() is available only if the file system
is built with FS_NAND_MAX_PAGE_SIZE set to a value different
than 0. The function has to be called in FS_X_AddDevices()
before any instance of the Universal NAND driver is created.
NumBytes has to be a power of 2 value.
FS_NAND_UNI_SetMaxSpareAreaSize()
Description
Configures the maximum handled spare area size.
Prototype
void FS_NAND_UNI_SetMaxSpareAreaSize(unsigned NumBytes);
Parameters
Parameter | Description |
NumBytes | Spare area size of the NAND page in bytes. |
Additional information
This function can be used at runtime to configure the size of
the internal buffer used by the Universal NAND driver to read
the data from a spare area of a NAND page. This buffer is shared
by all instances of the Universal NAND driver. If the application
does not call FS_NAND_UNI_SetMaxSpareAreaSize() then the size of
the internal spare area buffer is set to FS_NAND_MAX_SPARE_AREA_SIZE
if FS_NAND_MAX_SPARE_AREA_SIZE is different than 0 or to 1/32 of
the logical sector size of the file system if FS_NAND_MAX_SPARE_AREA_SIZE
is set to 0.
FS_NAND_UNI_SetMaxSpareAreaSize() is for example useful when NAND
flash device has a spare area that is larger than 1/32 of the page size.
In this case, the application has to call FS_NAND_UNI_SetMaxSpareAreaSize()
with the NumBytes parameter set to the spare area size specified
in the data sheet of the NAND flash device.
FS_NAND_UNI_SetMaxSpareAreaSize() is available only if the file system
is built with FS_NAND_MAX_SPARE_AREA_SIZE set to a value different
than 0. The function has to be called in FS_X_AddDevices()
before any instance of the Universal NAND driver is created.
FS_NAND_UNI_SetNumBlocksPerGroup()
Description
Specifies the number of physical NAND blocks in a virtual block.
Prototype
int FS_NAND_UNI_SetNumBlocksPerGroup(U8 Unit,
unsigned BlocksPerGroup);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
BlocksPerGroup | Number of physical blocks in a virtual block. The value must be a power of 2. |
Return value
= 0 | OK, value configured. |
≠ 0 | Error code indicating the failure reason. |
Additional information
This function is optional.
It can be used to specify how many physical NAND blocks
are grouped together to form a virtual block. Grouping physical blocks
helps reduce the RAM usage of the driver when the NAND flash device
contains a large number of physical blocks. For example, the
dynamic RAM usage of the Universal NAND driver using a NAND flash
device with 8196 blocks and a page size of 2048 bytes is about 20 KB.
The dynamic RAM usage is reduced to about 7 KB if 4 physical blocks
are grouped together.
The FS_NAND_SUPPORT_BLOCK_GROUPING configuration define has to be set
to 1 in order to enable this function. The FS_NAND_SUPPORT_BLOCK_GROUPING
configuration define is set to 1 by default. When set to 0 the function
returns an error if called in the application.
FS_NAND_UNI_SetNumBlocksPerGroup() is optional and may be called
only from FS_X_AddDevices(). Changing the block grouping requires
a low-level format of the NAND flash device.
FS_NAND_UNI_SetNumWorkBlocks()
Description
Sets number of work blocks the Universal NAND driver uses for write operations.
Prototype
void FS_NAND_UNI_SetNumWorkBlocks(U8 Unit,
U32 NumWorkBlocks);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
NumWorkBlocks | Number of work blocks. |
Additional information
This function is optional. It can be used to change the default
number of work blocks according to the requirements of the application.
Work blocks are physical NAND blocks that the Universal NAND driver
uses to temporarily store the data written to NAND flash device.
The Universal NAND driver calculates at low-level format the number of
work blocks based on the total number of blocks available on the
NAND flash device.
By default, the NAND driver allocates 10% of the total number of
NAND blocks used as storage, but no more than 10 NAND blocks.
The minimum number of work blocks allocated by default depends
on whether journaling is used or not. If the journal is active
4 work blocks are allocated, else Universal NAND driver allocates 3
work blocks. The currently allocated number of work blocks can
be checked via FS_NAND_UNI_GetDiskInfo(). The value is returned in the
NumWorkBlocks member of the FS_NAND_DISK_INFO structure.
Increasing the number of work blocks can help increase the write
performance of the Universal NAND driver. At the same time the RAM
usage of the Universal NAND driver increases since each configured
work block requires a certain amount of RAM for the data management.
This is a trade-off between write performance and RAM usage.
The new value take effect after the NAND flash device is low-level
formatted via the FS_FormatLow() API function.
FS_NAND_UNI_SetOnFatalErrorCallback()
Description
Registers a function to be called by the driver when a fatal error occurs.
Prototype
void FS_NAND_UNI_SetOnFatalErrorCallback
(FS_NAND_ON_FATAL_ERROR_CALLBACK * pfOnFatalError);
Parameters
Parameter | Description |
pfOnFatalError | Function to be called when a fatal error occurs. |
Additional information
This function is optional. The application can use this function
to register a routine to be called by the file system when a fatal
error occurs. Typically, a fatal error occurs when the ECC is not able
to correct all the bit errors in a page and is an indication that some
data was lost. A data loss leads in most of the cases to a damage of
the file system structure.
FS_NAND_UNI_SetPhyType()
Description
Configures NAND flash access functions.
Prototype
void FS_NAND_UNI_SetPhyType( U8 Unit,
const FS_NAND_PHY_TYPE * pPhyType);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based) |
pPhyType | in Physical layer to be used to access the NAND flash device. |
Additional information
This function is mandatory and it has to be called in FS_X_AddDevices()
once for each instance of the Universal NAND driver. The driver instance
is identified by the Unit parameter. First Universal NAND driver instance
added to the file system via a FS_AddDevice(&FS_NAND_UNI_Driver) call
has the unit number 0, the Universal NAND driver added by a second call
to FS_AddDevice() has the unit number 1 and so on.
FS_NAND_UNI_SetWriteDisturbHandling()
Description
Configures if the bit errors caused by write operations are
handled or not.
Prototype
void FS_NAND_UNI_SetWriteDisturbHandling(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
OnOff | Activation status of the feature. =0 Write disturb errors are not handled (default). ≠0 Write disturb errors are handled. |
Additional information
This function is optional and is active only when the
file system is compiled with FS_NAND_MAX_BIT_ERROR_CNT
set to a value greater than 0.
A write operation can cause bit errors in the pages located on
the same NAND block with the page being currently written.
Normally, these bit errors are corrected later when the data of the
NAND block is copied internally by the Universal NAND driver to
another location on the NAND flash device during a wear leveling,
a garbage collection or a write operation. This is the default
behavior of the Universal NAND driver.
The Universal NAND driver is also able to check for and correct
any bit errors right a after the write operation in order to reduce
the accumulation of bit errors that can lead to a data loss.
This error handling mode can be enabled by calling
FS_NAND_UNI_SetWriteDisturbHandling() with the OnOff parameter
set to 1. In this error handling mode if the number of bit errors
in any page in the checked NAND block is greater than or equal
to the value configured via FS_NAND_UNI_SetMaxBitErrorCnt() then
the NAND block is copied to another location on the NAND flash
device in order to correct the bit errors.
The lifetime of the NAND flash device can be negatively affected
if this feature is enabled due to the increased number of block
erase operations. The write performance can be negatively affected
as well.
FS_NAND_UNI_SetWriteVerification()
Description
Enables or disables the checking of each page write operation.
Prototype
void FS_NAND_UNI_SetWriteVerification(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
OnOff | Specifies if the feature has to be enabled or disabled =0 The write operation is not checked. ≠0 The write operation is checked. |
Additional information
This function is optional. The result of a page write operation
is normally checked by evaluating the error bits maintained by the
NAND flash device in a internal status register. FS_NAND_UNI_SetWriteVerification()
can be used to enable additional verification of the page write
operation that is realized by reading back the contents of the written
page and by checking that all the bytes are matching the data
requested to be written. Enabling this feature can negatively
impact the write performance of Universal NAND driver.
The page write verification feature is active only when the Universal
NAND driver is compiled with the FS_NAND_VERIFY_WRITE configuration
define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL
configuration define is set to a value greater than or equal to
FS_DEBUG_LEVEL_CHECK_ALL.
FS_NAND_ECC_HOOK
Description
ECC calculation algorithm.
Type definition
typedef struct {
FS_NAND_ECC_HOOK_CALC * pfCalc;
FS_NAND_ECC_HOOK_APPLY * pfApply;
U8 NumBitsCorrectable;
U8 ldBytesPerBlock;
U8 NumBitsCorrectableSpare;
} FS_NAND_ECC_HOOK;
Structure members
Member | Description |
pfCalc | Calculates the ECC of specified data. |
pfApply | Verifies and corrects bit errors using ECC. |
NumBitsCorrectable | Number of bits the ECC algorithm is able to correct in the data block and 4 bytes of spare area. |
ldBytesPerBlock | Number of bytes in the data block given as power of 2 exponent. |
NumBitsCorrectableSpare | Number of bits the ECC algorithm is able to correct in the 4 bytes of the spare area. |
Additional information
This structure contains pointers to API functions and attributes
related to an ECC calculation algorithm.
ldBytesPerBlock is typically set to 9 which indicates a block
size of 512 bytes. The size of the ECC block is imposed by the
specifications of the NAND flash device. If the value is set to
0 the Universal NAND driver assumes that the ECC block is 512 bytes large.
NumBitsCorrectable is used by the Universal NAND driver to check
if the ECC algorithm is capable of correcting the number of bit
errors required by the used NAND flash device.
NumBitsCorrectableSpare is used by the Universal NAND driver
to activate an optimization related to reading the data from
the spare area. If NumBitsCorrectableSpare is set to a value
different than 0 than the Universal NAND driver assumes that
the 4 bytes of management data stored in the spare area
of the NAND page are protected by a dedicated ECC. This enables
the Universal NAND driver to read only the spare area
instead of the entire NAND page when only the management data
has to be evaluated which can help increase the performance
of specific operations such as the mounting of NAND flash device.
FS_NAND_ECC_HOOK_CALC
Description
Calculates the parity bits of the specified data using ECC.
Type definition
typedef void FS_NAND_ECC_HOOK_CALC(const U32 * pData,
U8 * pSpare);
Parameters
Parameter | Description |
pData | in Data to be written to the main area of the page. |
pSpare | in Data to be written to the spare area of the page. out The calculated parity bits. |
Additional information
FS_NAND_ECC_HOOK_CALC is called by the Universal NAND driver before it writes
the data to the NAND flash device to calculate the parity check bits. The parity
check bits are stored together with the data to NAND flash device. They are
used by FS_NAND_ECC_HOOK_CALC to correct eventual bit errors.
This function has to calculate the parity bits of pData and of
four bytes of pSpare. That is the calculated parity bits are used
to protect the data stored in pData as well as pSpare. The number
of bytes in pData to be protected by ECC is specified via ldBytesPerBlock
in FS_NAND_ECC_HOOK. The data in pSpare to be protected by ECC is located
at byte offset four. The calculated parity bits must be stored to pSpare
at byte offset eight. The byte order of the stored parity bits is
not relevant for the Universal NAND driver. pSpare is organized as follows:
Byte range | Description |
0-3 | Not protected by ECC |
4-7 | Data to be protected by ECC |
8-N | Parity check bits calculated via the ECC algorithm |
FS_NAND_ECC_HOOK_CALC is not allowed to store more than N - 8 + 1
parity check bytes at byte offset eight to pSpare. N depends on the
size of the main and spare are of the NAND flash and on ldBytesPerBlock
and can be calculate using this formula:
N = ((BytesPerSpareArea / (BytesPerPage >> ldBytesPerBlock)) - 8) - 1
Parameter | Description |
BytesPerSpareArea | Number of bytes in the spare area of the NAND flash device |
BytesPerPage | Number of bytes in the spare area of the NAND flash device |
ldBytesPerBlock | Value specified in FS_NAND_ECC_HOOK |
FS_NAND_ECC_HOOK_APPLY
Description
Checks and corrects bit errors in the specified data using ECC.
Type definition
typedef int FS_NAND_ECC_HOOK_APPLY(U32 * pData,
U8 * pSpare);
Parameters
Parameter | Description |
pData | in Data read from the main area of the page. out Corrected main area data. |
pSpare | in Data read from the spare area of the page. out Corrected spare area data. |
Return value
< 0 | Uncorrectable bit errors detected. |
≥ 0 | Number of bit errors detected and corrected. |
Additional information
FS_NAND_ECC_HOOK_APPLY is called by the Universal NAND driver after it reads
data with from the NAND flash device to verify that the data is not corrupted.
If the function detects bit errors then it uses the parity check bits to correct
them. The correction has to be performed in place that is directly in pData and pSpare.
The parity check bits are located at byte offset eight in pSpare.
They protect all the bytes in pData and four bytes of pSpare. Refer to
FS_NAND_ECC_HOOK_CALC for a description of pSpare data layout.
FS_NAND_ECC_HOOK_APPLY function has to also correct the bit errors that occurred
in the parity check.
For backwards compatibility the return value is interpreted
differently by the Universal NAND driver if ldBytesPerBlock
is set to 0 as follows:
Value | Description |
0 | No error detected. |
1 | Bit errors corrected. Data is OK. |
2 | Error in ECC detected. Data is OK. |
3 | Uncorrectable bit error. Data is corrupted. |
The Universal NAND driver can possibly call this function with
pData set to NULL when it needs to check only the data stored
in the spare area of a NAND page if NumBitsCorrectableSpare in
FS_NAND_ECC_HOOK is set to a value different than 0.
Additional driver functions
The following functions are optional and can be used by the application to
perform operations directly on the NAND flash device.
FS_NAND_UNI_Clean()
Description
Makes storage space available for fast write operations.
Prototype
int FS_NAND_UNI_Clean(U8 Unit,
unsigned NumBlocksFree,
unsigned NumSectorsFree);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
NumBlocksFree | Number of blocks to be kept free. |
NumSectorsFree | Number of sectors to be kept free on each block. |
Return value
= 0 | OK, space has been made available. |
≠ 0 | An error occurred. |
Additional information
This function is optional. It can be used to free space on the
NAND flash device for data that the application has to write
as fast as possible. FS_NAND_UNI_Clean() performs two internal
operations:
(1) Converts all work blocks that have less free sectors than
NumSectorsFree into data blocks.
(2) If required, convert work blocks until at least NumBlocksFree
are available.
FS_NAND_UNI_EraseBlock()
Description
Sets all the bytes in a NAND block to 0xFF.
Prototype
int FS_NAND_UNI_EraseBlock(U8 Unit,
unsigned BlockIndex);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
BlockIndex | Index of the NAND flash block to be erased. |
Return value
= 0 | OK, block erased |
≠ 0 | An error occurred |
Additional information
This function is optional. FS_NAND_UNI_EraseBlock() function does
not check if the block is marked as defective before erasing it.
FS_NAND_UNI_EraseFlash()
Description
Erases the entire NAND partition.
Prototype
int FS_NAND_UNI_EraseFlash(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
Return value
≥ 0 | . Number of blocks which failed to erase. |
< 0 | An error occurred. |
Additional information
This function is optional. After the call to this function all the
bytes in the NAND partition are set to 0xFF.
This function has to be used with care, since it also erases
blocks marked as defective and therefore the information about
the block status will be lost. FS_NAND_EraseFlash() can be used
without this side effect on storage devices that are guaranteed
to not have any bad blocks, such as DataFlash devices.
FS_NAND_UNI_GetBlockInfo()
Description
Returns information about the specified NAND block.
Prototype
int FS_NAND_UNI_GetBlockInfo(U8 Unit,
U32 BlockIndex,
FS_NAND_BLOCK_INFO * pBlockInfo);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
BlockIndex | Index of the physical block to get information about. |
pBlockInfo | out Information about the NAND block. |
Return value
= 0 | OK, information returned. |
≠ 0 | An error occurred. |
Additional information
This function is not required for the functionality of the driver
and will typically not be linked in production builds.
FS_NAND_UNI_GetBlockInfo() has to read the contents of the entire
NAND block in order to collect all the information which may take
a relatively long time to complete. If the application does not
require the information about the block status or about the
status of the logical sectors stored in the NAND block it can
call FS_NAND_UNI_GetBlockInfoEx() instead.
FS_NAND_UNI_GetBlockInfoEx()
Description
Returns information about the specified NAND block.
Prototype
int FS_NAND_UNI_GetBlockInfoEx(U8 Unit,
U32 BlockIndex,
FS_NAND_BLOCK_INFO * pBlockInfo,
unsigned Flags);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
BlockIndex | Index of the physical block to get information about. |
pBlockInfo | out Information about the NAND block. |
Flags | Specifies the information to be returned. |
Return value
= 0 | OK, information returned. |
≠ 0 | An error occurred. |
Additional information
This function is not required for the functionality of the driver
and will typically not be linked in production builds.
Flags is a bitwise-or combination of Block info flags.
The FS_NAND_BLOCK_INFO_FLAG_BAD_STATUS flag specifies if the
information about the block status has to be returned via
the members IsDriverBadBlock, BadBlockErrorType, BadBlockErrorBRSI
of FS_NAND_BLOCK_INFO. If FS_NAND_UNI_GetBlockInfoEx() is called
on a NAND block marked as defective with the FS_NAND_BLOCK_INFO_FLAG_BAD_STATUS
flag cleared than the member Type of FS_NAND_BLOCK_INFO is set
to NAND_BLOCK_TYPE_UNKNOWN.
The FS_NAND_BLOCK_INFO_FLAG_SECTOR_STATUS flag specifies if
FS_NAND_UNI_GetBlockInfoEx() has to return information about
the logical sectors stored in the NAND block. This information
is returned via the members NumSectorsBlank, NumSectorsValid,
NumSectorsInvalid, NumSectorsECCError, NumSectorsECCCorrectable,
NumSectorsErrorInECC of FS_NAND_BLOCK_INFO
FS_NAND_UNI_GetDiskInfo()
Description
Returns information about the NAND partition.
Prototype
int FS_NAND_UNI_GetDiskInfo(U8 Unit,
FS_NAND_DISK_INFO * pDiskInfo);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
pDiskInfo | out Information about the NAND partition. |
Return value
= 0 | OK, information returned. |
≠ 0 | An error occurred. |
Additional information
FS_NAND_UNI_GetDiskInfo() can be used to get information about
the NAND flash device and about the instance of the Universal
NAND driver that is used to access it. If the NAND flash device
is formatted then FS_NAND_UNI_GetDiskInfo() also returns statistical
information about the usage of NAND blocks. If this information
is not relevant to the application FS_NAND_UNI_Mount() can be
called instead which typically requires less time to complete.
FS_NAND_UNI_GetDiskInfo() mounts the NAND flash device if required
and leaves it in this state upon return.
This function is not required for the functionality of the
Universal NAND driver and is typically not linked in production
builds.
FS_NAND_UNI_GetStatCounters()
Description
Returns the actual values of statistical counters.
Prototype
void FS_NAND_UNI_GetStatCounters(U8 Unit,
FS_NAND_STAT_COUNTERS * pStat);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based) |
pStat | out Values of statistical counters. |
Additional information
This function is optional. It is active only when the file system
is compiled with FS_DEBUG_LEVEL set to a value greater than or
equal to FS_DEBUG_LEVEL_CHECK_ALL or FS_NAND_ENABLE_STATS set to 1.
The statistical counters can be cleared via FS_NAND_UNI_ResetStatCounters().
FS_NAND_UNI_IsBlockBad()
Description
Checks if a NAND block is marked as defective.
Prototype
int FS_NAND_UNI_IsBlockBad(U8 Unit,
unsigned BlockIndex);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
BlockIndex | Index of the NAND flash block to be checked. |
Return value
1 | Block is defective |
0 | Block is not defective |
Additional information
This function is optional.
FS_NAND_UNI_Mount()
Description
Mounts the NAND flash device.
Prototype
int FS_NAND_UNI_Mount(U8 Unit,
FS_NAND_MOUNT_INFO * pMountInfo);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
pMountInfo | out Information about the mounted NAND flash device. Can be set to NULL. |
Return value
= 0 | OK, NAND flash device successfully mounted. |
≠ 0 | Error, could not mount NAND flash device. |
Additional information
FS_NAND_UNI_Mount() can be used to explicitly mount the NAND flash
device and to get information about it. This function returns a subset
of the information returned by FS_NAND_UNI_GetDiskInfo() and therefore
can be used instead of it if the application does not require statistical
information about the usage of the NAND blocks. Typically, FS_NAND_UNI_Mount()
requires less time to complete than FS_NAND_UNI_GetDiskInfo().
This function is not required for the functionality of the
Universal NAND driver and is typically not linked in production
builds.
FS_NAND_UNI_ReadLogSectorPartial()
Description
Reads a specified number of bytes from a logical sector.
Prototype
int FS_NAND_UNI_ReadLogSectorPartial(U8 Unit,
U32 LogSectorIndex,
void * pData,
unsigned Off,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
LogSectorIndex | Index of the logical sector to read from. |
pData | out Data read from NAND flash. |
Off | Byte offset to read from (relative to beginning of the sector). |
NumBytes | Number of bytes to be read. |
Return value
≠ 0 | Number of bytes read. |
= 0 | An error occurred. |
Additional information
This function is optional.
For NAND flash devices with internal HW ECC only the specified
number of bytes is transferred and not the entire sector.
Typ. used by the applications that access the NAND flash
directly (that is without a file system) to increase
the read performance.
FS_NAND_UNI_ReadPageRaw()
Description
Reads data from a page without ECC.
Prototype
int FS_NAND_UNI_ReadPageRaw(U8 Unit,
U32 PageIndex,
void * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
PageIndex | Index of the page to be read. |
pData | out Data to be written. |
NumBytes | Number of bytes to be read. |
Return value
= 0 | OK, data read. |
≠ 0 | An error occurred. |
Additional information
This function is optional.
The data is read from byte offset 0 relative to the beginning
of the page. If more data is requested than the page size
(main + spare area, typically 2048 + 64 bytes)
the function does not modify excess bytes in pData.
FS_NAND_UNI_ReadPageRaw() does not work correctly on NAND flash
devices with HW ECC that cannot be disabled.
FS_NAND_UNI_ReadPhySector()
Description
This function reads a physical sector from NAND flash.
Prototype
int FS_NAND_UNI_ReadPhySector(U8 Unit,
U32 PhySectorIndex,
void * pData,
unsigned * pNumBytesData,
void * pSpare,
unsigned * pNumBytesSpare);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
PhySectorIndex | Physical sector index. |
pData | Pointer to a buffer to store read data. |
pNumBytesData | in Pointer to variable storing the size of the data buffer. out The number of bytes that were stored in the data buffer. |
pSpare | Pointer to a buffer to store read spare data. |
pNumBytesSpare | in Pointer to variable storing the size of the spare data buffer. out The number of bytes that were stored in the spare data buffer. |
Return value
≥ 0 | OK, sector data read. |
< 0 | An error occurred. |
Additional information
This function is optional.
FS_NAND_UNI_ResetStatCounters()
Description
Sets the values of statistical counters to 0.
Prototype
void FS_NAND_UNI_ResetStatCounters(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based) |
Additional information
This function is optional. It is active only when the file system
is compiled with FS_DEBUG_LEVEL set to a value greater than or
equal to FS_DEBUG_LEVEL_CHECK_ALL or FS_NAND_ENABLE_STATS set to 1.
The statistical counters can be queried via FS_NAND_UNI_GetStatCounters().
FS_NAND_UNI_TestBlock()
Description
Fills all the pages in a block (including the spare area) with the
specified pattern and verifies if the data was written correctly.
Prototype
int FS_NAND_UNI_TestBlock(U8 Unit,
unsigned BlockIndex,
U32 Pattern,
FS_NAND_TEST_INFO * pInfo);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
BlockIndex | Index of the NAND block to be tested. |
Pattern | Data pattern to be written during the test. |
pInfo | Additional parameters and information about the test. |
Return value
FS_NAND_TEST_RETVAL_OK | OK, no bit errors. |
FS_NAND_TEST_RETVAL_CORRECTABLE_ERROR | OK, correctable bit errors found. The number of bit errors is returned in NumErrorsCorrectable of pResult. |
FS_NAND_TEST_RETVAL_FATAL_ERROR | Fatal error, uncorrectable bit error found. The page index is returned in PageIndexFatalError of pResult. |
FS_NAND_TEST_RETVAL_BAD_BLOCK | Bad block, skipped. |
FS_NAND_TEST_RETVAL_ERASE_FAILURE | Erase operation failed. The block has been marked as defective. |
FS_NAND_TEST_RETVAL_WRITE_FAILURE | Write operation failed. The block has been marked as defective. |
FS_NAND_TEST_RETVAL_READ_FAILURE | Read operation failed. |
FS_NAND_TEST_RETVAL_INTERNAL_ERROR | NAND flash access error. |
Additional information
This function is optional. It can be used by the application to
test the data reliability of a NAND block. BlockIndex is relative
to the beginning of the NAND partition where the first block has
the index 0.
Example
The following sample code demonstrates how FS_NAND_UNI_TestBlock() can be used
to check all the blocks of a NAND flash device. The function does not work
correctly on NAND flash devices with HW ECC that cannot be disabled.
#include <stdio.h>
#include "FS.h"
void SampleNAND_UNITestBlocks(void) {
int r;
U32 NumPhyBlocks;
U32 iBlock;
FS_NAND_DISK_INFO DiskInfo;
FS_NAND_TEST_INFO TestInfo;
char ac[100];
memset(&DiskInfo, 0, sizeof(DiskInfo));
memset(&TestInfo, 0, sizeof(TestInfo));
FS_NAND_UNI_GetDiskInfo(0, &DiskInfo);
NumPhyBlocks = DiskInfo.NumPhyBlocks;
TestInfo.NumBitsCorrectable = 1;
TestInfo.BytesPerSpare = (U16)DiskInfo.BytesPerSpareArea;
for (iBlock = 0; iBlock < NumPhyBlocks; ++iBlock) {
r = FS_NAND_UNI_TestBlock(0, iBlock, 0xAA5500FFuL, &TestInfo);
switch (r) {
case FS_NAND_TEST_RETVAL_OK:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: OK.\n", iBlock);
FS_X_Log(ac);
break;
case FS_NAND_TEST_RETVAL_CORRECTABLE_ERROR:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: %lu correctable error(s).\n",
iBlock, TestInfo.BitErrorCnt);
FS_X_Log(ac);
break;
case FS_NAND_TEST_RETVAL_FATAL_ERROR:
SEGGER_snprintf(ac, sizeof(ac),
"Block %lu: %lu correctable error(s), fatal error on page %lu.\n",
iBlock, TestInfo.BitErrorCnt, TestInfo.PageIndex);
FS_X_Log(ac);
break;
case FS_NAND_TEST_RETVAL_BAD_BLOCK:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Bad. Skipped.\n", iBlock);
FS_X_Log(ac);
break;
case FS_NAND_TEST_RETVAL_ERASE_FAILURE:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Erase failure. Marked as bad.\n", iBlock);
FS_X_Log(ac);
break;
case FS_NAND_TEST_RETVAL_WRITE_FAILURE:
SEGGER_snprintf(ac, sizeof(ac),
"Block %lu: Write failure on page %lu. Marked as bad.\n",
iBlock, TestInfo.PageIndex);
FS_X_Log(ac);
break;
case FS_NAND_TEST_RETVAL_READ_FAILURE:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Read failure on page %lu.\n",
iBlock, TestInfo.PageIndex);
FS_X_Log(ac);
break;
default:
SEGGER_snprintf(ac, sizeof(ac), "Block %lu: Internal error.\n", iBlock);
FS_X_Log(ac);
break;
}
}
}
FS_NAND_UNI_WritePage()
Description
Stores data to a page of a NAND flash with ECC.
Prototype
int FS_NAND_UNI_WritePage( U8 Unit,
U32 PageIndex,
const void * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
PageIndex | Index of the page to be written. |
pData | in Data to be written. |
NumBytes | Number of bytes to be written. |
Return value
= 0 | OK, data written. |
≠ 0 | An error occurred. |
Additional information
This function is optional.
The data is written at byte offset 0 relative to the beginning of the page.
If more data is written than the size of the page (main + spare area,
typically 2048 + 64 bytes) then the excess bytes are discarded.
The data in the area reserved for ECC cannot be modified using this function.
FS_NAND_UNI_WritePageRaw()
Description
Stores data to a page of a NAND flash without ECC.
Prototype
int FS_NAND_UNI_WritePageRaw( U8 Unit,
U32 PageIndex,
const void * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the driver instance (0-based). |
PageIndex | Index of the page to be written. |
pData | in Data to be written. |
NumBytes | Number of bytes to be written. |
Return value
= 0 | OK, data written. |
≠ 0 | An error occurred. |
Additional information
This function is optional.
The data is written at the byte offset 0 relative to the beginning
of the page. If more data is written than the size of the page
(main + spare area, typically 2048 + 64 bytes) the excess
bytes are discarded.
FS_NAND_UNI_WritePageRaw() does not work correctly on NAND flash
devices with HW ECC that cannot be disabled.
Bad block marking types
Description
Methods to mark a block as defective.
Definition
#define FS_NAND_BAD_BLOCK_MARKING_TYPE_FSPS 0
#define FS_NAND_BAD_BLOCK_MARKING_TYPE_FPS 1
#define FS_NAND_BAD_BLOCK_MARKING_TYPE_FLPS 2
#define FS_NAND_BAD_BLOCK_MARKING_TYPE_FSLPS 3
#define FS_NAND_BAD_BLOCK_MARKING_TYPE_FLPMS 4
Symbols
Definition | Description |
FS_NAND_BAD_BLOCK_MARKING_TYPE_FSPS | The block is marked as defective in the spare area of the first and second page of the block. |
FS_NAND_BAD_BLOCK_MARKING_TYPE_FPS | The block is marked as defective in the spare area of the first page of the block. |
FS_NAND_BAD_BLOCK_MARKING_TYPE_FLPS | The block is marked as defective in the spare area of first and last page of the block. |
FS_NAND_BAD_BLOCK_MARKING_TYPE_FSLPS | The block is marked as defective in the spare area of first, second and last page of the block. |
FS_NAND_BAD_BLOCK_MARKING_TYPE_FLPMS | The block is marked as defective in the main and spare area of first and last page of the block. |
Block info flags
Description
Flags that control the information returned by FS_NAND_UNI_GetBlockInfoEx().
Definition
#define FS_NAND_BLOCK_INFO_FLAG_BAD_STATUS 0x01u
#define FS_NAND_BLOCK_INFO_FLAG_SECTOR_STATUS 0x02u
Symbols
Definition | Description |
FS_NAND_BLOCK_INFO_FLAG_BAD_STATUS | Return information about the status of the NAND block (defective or not) |
FS_NAND_BLOCK_INFO_FLAG_SECTOR_STATUS | Return information about the status of all logical sectors in the NAND block. |
Additional information
These flags can be passed as Flags parameter to FS_NAND_UNI_GetBlockInfoEx()
in order to specify the type of information that has to be returned.
ECC correction status
Description
Result of the bit error correction.
Definition
#define FS_NAND_CORR_NOT_APPLIED 0u
#define FS_NAND_CORR_APPLIED 1u
#define FS_NAND_CORR_FAILURE 2u
Symbols
Definition | Description |
FS_NAND_CORR_NOT_APPLIED | No bit errors detected. |
FS_NAND_CORR_APPLIED | Bit errors were detected and corrected. |
FS_NAND_CORR_FAILURE | Bit errors were detected but not corrected. |
FS_NAND_MOUNT_INFO
Description
Information about the mounted NAND flash device.
Type definition
typedef struct {
U32 NumPhyBlocks;
U32 NumLogBlocks;
U32 NumPagesPerBlock;
U32 NumSectorsPerBlock;
U32 BytesPerPage;
U32 BytesPerSpareArea;
U32 BytesPerSector;
U8 BadBlockMarkingType;
U8 IsWriteProtected;
U8 HasFatalError;
U8 ErrorType;
U32 ErrorSectorIndex;
U16 BlocksPerGroup;
U32 NumWorkBlocks;
} FS_NAND_MOUNT_INFO;
Structure members
Member | Description |
NumPhyBlocks | Total number of blocks in the NAND partition. |
NumLogBlocks | Total number of NAND blocks that can be used to store data. |
NumPagesPerBlock | Number of pages in a NAND block. |
NumSectorsPerBlock | Number of logical sectors stored in a NAND block. |
BytesPerPage | Number of bytes in the main area of a NAND page. |
BytesPerSpareArea | Number of bytes in the spare area of a NAND page. |
BytesPerSector | Number of bytes is a logical sector. |
BadBlockMarkingType | Type of the bad block marking. |
IsWriteProtected | Set to 1 if the NAND flash device cannot be written. |
HasFatalError | Set to 1 if the SLC1 NAND driver reported a fatal error. |
ErrorType | Type of fatal error that has occurred. |
ErrorSectorIndex | Sector index on which a fatal error occurred. |
BlocksPerGroup | Number of NAND blocks in a group. |
NumWorkBlocks | Number of work blocks used by the SLC1 NAND driver. |
FS_NAND_STAT_COUNTERS
Description
Statistical counters of NAND flash driver.
Type definition
typedef struct {
U32 NumFreeBlocks;
U32 NumBadBlocks;
U32 EraseCnt;
U32 ReadDataCnt;
U32 ReadSpareCnt;
U32 ReadSectorCnt;
U32 NumReadRetries;
U32 WriteDataCnt;
U32 WriteSpareCnt;
U32 WriteSectorCnt;
U32 NumWriteRetries;
U32 ConvertViaCopyCnt;
U32 ConvertInPlaceCnt;
U32 NumValidSectors;
U32 CopySectorCnt;
U32 BlockRelocationCnt;
U32 ReadByteCnt;
U32 WriteByteCnt;
U32 BitErrorCnt;
U32 aBitErrorCnt[];
} FS_NAND_STAT_COUNTERS;
Structure members
Member | Description |
NumFreeBlocks | Number of NAND blocks not used for data. |
NumBadBlocks | Number of NAND blocks marked as defective. |
EraseCnt | Number of block erase operation performed. |
ReadDataCnt | Number of times the NAND driver read from the main area of a page. |
ReadSpareCnt | Number of times the NAND driver read from the spare area of a page. |
ReadSectorCnt | Number of logical sectors read from the NAND flash. |
NumReadRetries | Number of times a read operation has been retried because of an error. |
WriteDataCnt | Number of times the NAND driver wrote to the main area of a page. |
WriteSpareCnt | Number of times the NAND driver wrote to the spare area of a page. |
WriteSectorCnt | Number of logical sectors wrote to the NAND flash. |
NumWriteRetries | Number of times a write operation has been retried because of an error. |
ConvertViaCopyCnt | Number of block conversions via copy. |
ConvertInPlaceCnt | Number of block conversions in place. |
NumValidSectors | Number of logical sectors that contain valid data. |
CopySectorCnt | Number of times the NAND driver copied a logical sector to another location. |
BlockRelocationCnt | Number of times the NAND driver relocated a NAND block due to errors. |
ReadByteCnt | Number of bytes read from NAND flash. |
WriteByteCnt | Number of bytes written to NAND flash. |
BitErrorCnt | Number of bit errors detected and corrected. |
aBitErrorCnt | Number of times a specific number of bit errors occurred. |
Additional information
This structure can be used to get statistical information about
the operation of the Universal as well as SLC1 NAND driver via
the function FS_NAND_UNI_GetStatCounters() and FS_NAND_GetStatCounters()
respectively.
aBitErrorCnt[0] stores the number of 1 bit error occurrences,
aBitErrorCnt[1] stores the number of 2 bit error occurrences, and so on.
Example
Refer to FS_NAND_UNI_GetStatCounters() and FS_NAND_GetStatCounters()
for a sample usage.
FS_NAND_TEST_INFO
Description
Additional information passed to test routine.
Type definition
typedef struct {
U8 NumBitsCorrectable;
U8 OffSpareECCProt;
U8 NumBytesSpareECCProt;
U16 BytesPerSpare;
U32 BitErrorCnt;
U32 PageIndex;
} FS_NAND_TEST_INFO;
Structure members
Member | Description |
NumBitsCorrectable | Number of bits the ECC can correct in the data and spare area (typically 4) |
OffSpareECCProt | Offset in the spare area of the first byte protected by ECC (typically 4). |
NumBytesSpareECCProt | Number of bytes in the spare area protected by ECC (typically 4 bytes) |
BytesPerSpare | Total number of bytes in the spare area. When set to 0 the default value of 1/32 of page size is used. |
BitErrorCnt | Number of bit errors detected and corrected. |
PageIndex | Index of the physical page where the error happened. |
Additional information
The test routine returns information about what went wrong during
a test via FS_NAND_UNI_TestBlock() and FS_NAND_TestBlock().
Example
Refer to FS_NAND_UNI_TestBlock() and FS_NAND_TestBlock() for a sample usage.
NAND block types
Description
Type of data stored to a NAND block.
Definition
#define FS_NAND_BLOCK_TYPE_UNKNOWN 0u
#define FS_NAND_BLOCK_TYPE_BAD 1u
#define FS_NAND_BLOCK_TYPE_EMPTY 2u
#define FS_NAND_BLOCK_TYPE_WORK 3u
#define FS_NAND_BLOCK_TYPE_DATA 4u
Symbols
Definition | Description |
FS_NAND_BLOCK_TYPE_UNKNOWN | The type of the block cannot be determined. |
FS_NAND_BLOCK_TYPE_BAD | The block marked as defective. |
FS_NAND_BLOCK_TYPE_EMPTY | The block does not store any data. |
FS_NAND_BLOCK_TYPE_WORK | The block that stores data temporarily. |
FS_NAND_BLOCK_TYPE_DATA | The block that stores data permanently. |
NAND test return values
Description
Return values of the NAND block test functions.
Definition
#define FS_NAND_TEST_RETVAL_OK 0
#define FS_NAND_TEST_RETVAL_CORRECTABLE_ERROR 1
#define FS_NAND_TEST_RETVAL_FATAL_ERROR 2
#define FS_NAND_TEST_RETVAL_BAD_BLOCK 3
#define FS_NAND_TEST_RETVAL_ERASE_FAILURE 4
#define FS_NAND_TEST_RETVAL_WRITE_FAILURE 5
#define FS_NAND_TEST_RETVAL_READ_FAILURE 6
#define FS_NAND_TEST_RETVAL_INTERNAL_ERROR (-1)
Symbols
Definition | Description |
FS_NAND_TEST_RETVAL_OK | The test was successful. |
FS_NAND_TEST_RETVAL_CORRECTABLE_ERROR | Bit errors occurred that were corrected via ECC. |
FS_NAND_TEST_RETVAL_FATAL_ERROR | Bit errors occurred that the ECC was not able to correct. |
FS_NAND_TEST_RETVAL_BAD_BLOCK | The tested block was marked as defective. |
FS_NAND_TEST_RETVAL_ERASE_FAILURE | An error occurred during the block erase operation. |
FS_NAND_TEST_RETVAL_WRITE_FAILURE | An error occurred while writing the data to the NAND block. |
FS_NAND_TEST_RETVAL_READ_FAILURE | An error occurred while reading the data from the NAND block. |
FS_NAND_TEST_RETVAL_INTERNAL_ERROR | An internal processing error occurred. |
Performance and resource usage
This section provides information about the ROM and RAM usage as well
as the performance of the Universal NAND driver. Please note that a
Universal NAND driver instance requires one instance of one NAND physical
layer in order to operate. The resource usage of the used NAND physical layer
has to be taken into account when calculating the total resource usage of the
Universal NAND driver.
ROM usage
The ROM usage depends on the compiler options, the compiler version and the used CPU.
The memory requirements of the Universal NAND driver were measured as described in the section
Test procedure.
Usage: 7.9 Kbytes
Static RAM usage
Static RAM usage refers to the amount of RAM required by the Universal NAND driver
internally for all the driver instances. The number of bytes can be seen in the
compiler list file of the {FS_NAND_UNI_Drv.c} file.
Usage: 32 bytes
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the driver at runtime.
The amount required depends on the runtime configuration and the characteristics
of the used NAND flash device. The approximate RAM usage of the Universal NAND driver
can be calculated as follows:
MemAllocated = 148 + 2 * NumBlocks
+ ((PagesPerBlock - 1) + 18) * NumWorkBlocks
+ 1.04 * PageSize
Parameter | Description |
MemAllocated | Number of bytes allocated for one instance of the NAND driver. |
NumBlocks | Number of blocks in the NAND flash device. |
NumWorkBlocks | Number of blocks the driver reserves as temporary storage for the written data.
By default, 3 blocks are reserved. The number of work blocks can be specified
at runtime via FS_NAND_UNI_SetNumWorkBlocks(). |
PageSize | Number of bytes in a page. |
Example
This example uses a 2 GBit NAND flash device with 2Kbyte pages and 2048 blocks.
One block consists of 64 pages and each page holds 1 sector of 2048 bytes.
PagesPerBlock = 64
NumBlocks = 2048
NumWorkBlocks = 4
PageSize = 2048
MemAllocated = 148 + 2 * 2048 + (64 - 1 + 18) * 4 + 1.04 * 2048
= 148 + 4096 + 324 + 2129
= 6397 bytes
Performance
The following performance measurements are in no way complete, but they
give a good approximation of time required for common operations on various
target hardware. The tests were performed as described in the section
Performance.
All values are given in Mbytes/sec.
CPU type | NAND flash device | Write speed | Read speed |
NXP LPC4322 (180 MHz) | Serial NAND flash with 2048 bytes per page connected
to a quad SPI controller via 4 data lines transferring
data at 60 MHz. | 4.1 | 12.2 |
NXP LPC4322 (180 MHz) | Serial NAND flash with 2048 bytes per page connected
to a standard SPI controller transferring data at
60 MHz. | 3.9 | 7.7 |
ST STM32MP157 (650 MHz) | Parallel NAND flash with 4096 bytes per page connected
to external memory controller via an 8-bit data bus.
The 8-bit ECC is calculated using SEGGER emFile-ECC. | 10.8 | 22.2 |
Atmel AT91SAM3U (96 MHz) | Parallel NAND flash with 2048 bytes per page and a sector
size of 2048 bytes with internal ECC enabled using
the built in NAND controller/external bus-interface. | 2.6 | 7.5 |
NAND physical layer
General information
The NAND physical layer provides the basic functionality for accessing a NAND flash device
such as device identification, block erase operation, page read and write operations, etc.
Every instance of the Universal or SLC1 NAND driver requires an instance of a NAND physical layer
in order to be able to operate. A NAND physical layer instance is automatically allocated either
statically or dynamically at the first call to one of its API functions. Each instance is
identified by a unit number that is identical with the unit number of the NAND driver that
uses that instance of the NAND physical layer. The type of the NAND physical layer assigned
to an instance of a Universal or SLC1 NAND driver is configured via FS_NAND_UNI_SetPhyType()
and FS_NAND_SetPhyType() respectively.
The table below lists the NAND physical layers that ship with emFile.
Refer to Configuring the driver
and Configuring the driver
for detailed information about how to add and configure a physical layer in an application.
The following sections provide information about the usage and the implementation of
a NAND physical layer.
512x8 physical layer
This NAND physical layer supports any NAND flash device with a page size of 512 bytes
and a spare area of 16 bytes that is connected to MCU via an 8-bit data bus.
It works only with the SLC1 NAND driver because the size of the spare area is not
sufficiently large for the amount of management data required by the Universal
NAND driver. The instances of this physical layer are allocated statically.
The maximum number of instances can be configured at compile time via FS_NAND_NUM_UNITS.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the 512x8 physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
Function | Description |
FS_NAND_512x8_SetHWType() | Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_512x8. |
FS_NAND_512x8_SetHWType()
Description
Configures the hardware access routines for a NAND physical layer
of type FS_NAND_PHY_512x8.
Prototype
void FS_NAND_512x8_SetHWType( U8 Unit,
const FS_NAND_HW_TYPE * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
pHWType | Type of the hardware layer to use. Cannot be NULL. |
Additional information
This function is mandatory and has to be called once in FS_X_AddDevices()
for every instance of a NAND physical layer of type FS_NAND_PHY_512x8.
2048x8 physical layer
This NAND physical layer supports any NAND flash device with a page size of 2048 bytes
and a spare area larger than or equal to 64 bytes that is connected to MCU via an 8-bit
data bus. The instances of this physical layer are allocated dynamically. The maximum
number of instances can be configured at compile time via FS_NAND_NUM_UNITS.
Compile time configuration
The 2048x8 physical layer can optionally be configured at compile time.
Typically, this step can be omitted because reasonable default values are provided
that work with most of the applications. The following table provides a summary of
the configuration defines supported by this physical layer.
Define | Default value | Type | Description |
FS_NAND_2048X8_DEVICE_LIST_DEFAULT | &FS_NAND_2048X8_DeviceListDefault | R | List of parallel NAND flash devices that can be handled by the physical layer. |
FS_NAND_SUPPORT_READ_CACHE | 0 | B | Specifies if the internal page register of the NAND flash device should be used as read cache. |
FS_NAND_2048X8_DEVICE_LIST_DEFAULT
FS_NAND_2048X8_DEVICE_LIST_DEFAULT specifies the list of parallel NAND flash devices that
can be handled by the physical layer. It can be set to NULL in order to reduce the ROM usage
if not all the devices included in FS_NAND_2048X8_DeviceListDefault have to be handled.
In this case it is mandatory that the application configures a list of devices via
FS_NAND_2048X8_SetDeviceList().
FS_NAND_SUPPORT_READ_CACHE
With FS_NAND_SUPPORT_READ_CACHE set to 1 the physical layer keeps track
of the index of the last page read from NAND flash device. If the same page is
read again then the physical layer omits the operation that transfers the page
data from the memory array to the internal page register of the NAND flash device.
In this case only a data transfer from the internal page register to host is executed
which helps improve the performance.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the 2048x8 physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
FS_NAND_2048x8_DisableReadCache()
Description
Deactivates the page read optimization.
Prototype
void FS_NAND_2048x8_DisableReadCache(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
Additional information
This function is optional and is available only when the file system
is build with FS_NAND_SUPPORT_READ_CACHE set to 1 which is the default.
The optimization can be enabled at runtime via FS_NAND_2048x8_EnableReadCache().
Refer to FS_NAND_2048x8_EnableReadCache() for more information about how
the page read optimization works
FS_NAND_2048x8_EnableReadCache()
Description
Activates the page read optimization.
Prototype
void FS_NAND_2048x8_EnableReadCache(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
Additional information
This function is optional and is available only when the file system
is build with FS_NAND_SUPPORT_READ_CACHE set to 1 which is the default.
Activating the read cache can increase the overall performance of the
NAND driver especially when using the SLC1 NAND driver with a logical
sector size smaller than the page of the used NAND flash device.
The optimization takes advantage of how the NAND flash device implements
the read page operation. A NAND page read operation consists of two steps.
In the first step, the page data is read from the memory array to internal
page register of the NAND flash device. In the second step, the data is
transferred from the internal page register of NAND flash device to MCU.
With the optimization enabled the first step is skipped whenever possible.
The optimization is enabled by default and has to be disabled if two
or more instances of the NAND driver are configured to access the same
physical NAND flash device. At runtime, the optimization can be disabled
via FS_NAND_2048x8_DisableReadCache().
FS_NAND_2048X8_SetDeviceList()
Description
Specifies the list of NAND flash devices that require special handling.
Prototype
void FS_NAND_2048X8_SetDeviceList( U8 Unit,
const FS_NAND_2048X8_DEVICE_LIST * pDeviceList);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based) |
pDeviceList | in List of NAND flash devices. |
Additional information
NAND flash devices that do not require special handling such
as devices without HW ECC are always enabled. The special handling
is required for example to determine if the HW ECC of the NAND flash
device can be enabled and disabled at runtime.
By default, only special handling for NAND flash devices from
Samsung and Toshiba is enabled (FS_NAND_ONFI_DeviceListDefault).
The correct operation of NAND flash device from a manufacturer
not included in the configured list of devices is not guaranteed
if the the NAND flash device requires special handling.
Permitted values for the pDeviceList parameter are:
Identifier | Description |
FS_NAND_2048X8_DeviceListAll | Enables the handling for all supported NAND flash devices. |
FS_NAND_2048X8_DeviceListDefault | Enables the handling of standard NAND flash devices and the special handling of Samsung and Toshiba NAND flashes. |
FS_NAND_2048X8_DeviceListStandard | Enables the handling of NAND flash devices that do not have any special features such as HW ECC. |
FS_NAND_2048X8_DeviceListSamsung | Enables the special handling of Samsung NAND flash devices. |
FS_NAND_2048X8_DeviceListToshiba | Enables the special handling of Toshiba NAND flash devices. |
FS_NAND_2048x8_SetHWType()
Description
Configures the hardware access routines for a NAND physical layer
of type FS_NAND_PHY_2048x8.
Prototype
void FS_NAND_2048x8_SetHWType( U8 Unit,
const FS_NAND_HW_TYPE * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
pHWType | Type of the hardware layer to use. Cannot be NULL. |
Additional information
This function is mandatory and has to be called once in FS_X_AddDevices()
for every instance of a NAND physical layer of type FS_NAND_PHY_2048x8.
Two plane 2048x8 physical layer
This NAND physical layer supports any NAND flash device with a page size of 2048 bytes
and a spare area larger than or equal to 64 bytes that is connected to MCU via an 8-bit
data bus. In addition, the NAND flash device has to be organized in two planes
and provide support for executing an operation on both planes simultaneously.
The instances of this physical layer are allocated dynamically. The maximum
number of instances can be configured at build time via FS_NAND_NUM_UNITS.
FS_NAND_PHY_2048x8_TwoPlane uses the same runtime functions and compile time
configuration defines as FS_NAND_PHY_2048x8.
Small 2048x8 physical layer
This physical layer is a variant of FS_NAND_PHY_2048x8
with reduced ROM usage. FS_NAND_PHY_2048x8_Small supports the same NAND flash
devices as FS_NAND_PHY_2048x8
but it does not provide support for the NAND internal page copy operation and for
the reading the ECC correction result.
FS_NAND_PHY_2048x8_Small provides read as well as write access to NAND flash device.
The instances of this physical layer are allocated statically.
FS_NAND_PHY_2048x8_Small uses the same runtime functions and compile time
configuration defines as FS_NAND_PHY_2048x8.
2048x16 physical layer
This physical layer supports NAND flash devices with page size of 2048 bytes and
a spare area larger than or equal to 64 bytes that is connected to MCU via an 16-bit
data bus. The instances of this physical layer are allocated statically. The maximum
number of instances can be configured at build time via FS_NAND_NUM_UNITS.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the 2048x16 physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
Function | Description |
FS_NAND_2048x16_SetHWType() | Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_2048x16. |
FS_NAND_2048x16_SetHWType()
Description
Configures the hardware access routines for a NAND physical layer
of type FS_NAND_PHY_2048x16.
Prototype
void FS_NAND_2048x16_SetHWType( U8 Unit,
const FS_NAND_HW_TYPE * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
pHWType | Type of the hardware layer to use. Cannot be NULL. |
Additional information
This function is mandatory and has to be called once in FS_X_AddDevices()
for every instance of a NAND physical layer of type FS_NAND_PHY_2048x16.
4096x8 physical layer
This NAND physical layer supports any NAND flash device with a page size of 4096 bytes
and a spare area larger than or equal to 128 bytes that is connected to MCU via an 8-bit
data bus. The instances of this physical layer are allocated statically. The maximum
number of instances can be configured at build time via FS_NAND_NUM_UNITS.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the 4096x8 physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
Function | Description |
FS_NAND_4096x8_SetHWType() | Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_4096x8. |
FS_NAND_4096x8_SetHWType()
Description
Configures the hardware access routines for a NAND physical layer
of type FS_NAND_PHY_4096x8.
Prototype
void FS_NAND_4096x8_SetHWType( U8 Unit,
const FS_NAND_HW_TYPE * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
pHWType | Type of the hardware layer to use. Cannot be NULL. |
Additional information
This function is mandatory and has to be called once in FS_X_AddDevices()
for every instance of a NAND physical layer of type FS_NAND_PHY_4096x8.
DataFlash physical layer
This physical layer supports Dialog Semiconductor / Adesto / Atmel DataFlash storage devices.
The devices are accessed via SPI using a hardware layer of type FS_NAND_HW_TYPE_DF.
FS_NAND_PHY_DataFlash works only with the SLC1 NAND driver because the size
of the spare area is not sufficiently large for the amount of management data
required by the Universal NAND driver. The instances of this physical layer are
allocated statically.
Compile time configuration
The DataFlash physical layer can optionally be configured at compile time.
Typically, this step can be omitted because reasonable default values are provided
that work with most of the applications. The following table provides a summary of
the configuration defines supported by this physical layer.
Define | Default value | Type | Description |
FS_NAND_BLOCK_TYPE | 2 | N | Specifies the size of the erase unit. |
FS_NAND_SUPPORT_READ_CACHE | 0 | B | Specifies if the internal page register of the DataFlash device should be used as read cache. |
FS_NAND_BLOCK_TYPE
FS_NAND_BLOCK_TYPE can be used to specify the size of the erase unit
used by the DataFlash physical layer. The following erase unit sizes
are supported: 1 block large (FS_NAND_BLOCK_TYPE = 0), 8 blocks large
(FS_NAND_BLOCK_TYPE = 1) and 1 sector large (FS_NAND_BLOCK_TYPE = 2).
By default FS_NAND_BLOCK_TYPE is set 2 because it ensures the maximum performance.
Note
The physical layer is not fail-safe when FS_NAND_BLOCK_TYPE is set to 1
because more than one erase operation has to be performed in order to
erase the entire block.
FS_NAND_SUPPORT_READ_CACHE
With FS_NAND_SUPPORT_READ_CACHE set to 1 the physical layer keeps track
of the index of the last page read from DataFlash flash device. If the same page is
read again then the physical layer omits the operation that transfers the page
data from the memory array to the internal page register of the DataFlash flash device.
In this case only a data transfer from the internal page register to host is executed
which helps improve the performance.
Note
This feature cannot be used if the DataFlash device is partitioned via
FS_NAND_SetBlockRange() and the created partitions are accessed via the file system.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the DataFlash physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
FS_NAND_DF_EraseChip()
Description
Erases the entire device.
Prototype
void FS_NAND_DF_EraseChip(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based) |
Additional information
This function is optional. It sets all the bits of the DataFlash
memory to 1. All the data stored on the DataFlash memory is lost.
FS_NAND_DF_SetMinPageSize()
Description
Configures the required minimum page size.
Prototype
void FS_NAND_DF_SetMinPageSize(U8 Unit,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based) |
NumBytes | Page size in bytes. |
Additional information
This function is optional. The application can use it to request
a minimum page size to work with. If the size of the physical page
is smaller than the specified value then then adjacent physical
pages are grouped together into one virtual page that is presented
as a single page to the SLC1 NAND driver. This is required when
the size of a physical page is smaller than 512 bytes which is
the minimum sector size the SLC1 NAND driver can work with.
NumBytes has to be a power of 2 value.
FS_NAND_DF_SetHWType()
Description
Configures the hardware access routines.
Prototype
void FS_NAND_DF_SetHWType( U8 Unit,
const FS_NAND_HW_TYPE_DF * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based) |
pHWType | Table of hardware routines. |
Additional information
This function is mandatory and it has to be called once for
each used instance of the physical layer.
ONFI physical layer
This physical layer supports NAND flash devices that are compliant to ONFI specification.
The organization of the NAND flash device such as page size and number of blocks is determined
automatically by evaluating the parameters stored in the NAND flash device according to
ONFI specification. The instances of this physical layer are allocated dynamically.
Compile time configuration
The ONFI physical layer can optionally be configured at compile time.
Typically, this step can be omitted because reasonable default values are provided
that work with most of the applications. The following table provides a summary of
the configuration defines supported by this physical layer.
FS_NAND_ONFI_DEVICE_LIST_DEFAULT
FS_NAND_ONFI_DEVICE_LIST_DEFAULT specifies the list of parallel NAND flash devices that
can be handled by the physical layer. It can be set to NULL in order to reduce the ROM usage
if not all the devices included in FS_NAND_ONFI_DeviceListDefault have to be handled.
In this case it is mandatory that the application configures a list of devices via
FS_NAND_ONFI_SetDeviceList().
FS_NAND_SUPPORT_EXT_ONFI_PARA
FS_NAND_SUPPORT_EXT_ONFI_PARA can be used to enable the evaluation of
extended ONFI parameters. By default the ONFI physical layer evaluates
only the standard ONFI parameters. The extended ONFI parameters provide
for example additional information about the bit error correction.
Setting FS_NAND_SUPPORT_EXT_ONFI_PARA to 0 reduces the ROM usage.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the ONFI physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
FS_NAND_ONFI_SetHWType()
Description
Configures the hardware access routines for a NAND physical layer
of type FS_NAND_PHY_ONFI.
Prototype
void FS_NAND_ONFI_SetHWType( U8 Unit,
const FS_NAND_HW_TYPE * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
pHWType | Type of the hardware layer to use. Cannot be NULL. |
Additional information
This function is mandatory and has to be called once in FS_X_AddDevices()
for every instance of a NAND physical layer of type FS_NAND_PHY_ONFI.
FS_NAND_ONFI_SetDeviceList()
Description
Specifies the list of ONFI NAND flash devices that require special handling.
Prototype
void FS_NAND_ONFI_SetDeviceList( U8 Unit,
const FS_NAND_ONFI_DEVICE_LIST * pDeviceList);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based) |
pDeviceList | in List of ONFI NAND flash devices. |
Additional information
NAND flash devices that do not require special handling such
as devices without HW ECC are always enabled. The special handling
is required for example to determine if the HW ECC of the NAND flash
device can be enabled and disabled at runtime.
By default, only special handling for NAND flash devices from
Micron and Macronix is enabled (FS_NAND_ONFI_DeviceListDefault).
The correct operation of NAND flash device from a manufacturer
not included in the configured list of devices is not guaranteed
if the the NAND flash device requires special handling.
Permitted values for the pDeviceList parameter are:
Identifier | Description |
FS_NAND_ONFI_DeviceListAll | Enables special handling for all supported NAND flash devices. |
FS_NAND_ONFI_DeviceListAllianceMemory | Enables special handling of Alliance Memory parallel NAND flash devices. |
FS_NAND_ONFI_DeviceListDefault | Enables special handling of NAND flash devices from Micron and Macronix. |
FS_NAND_ONFI_DeviceListGigaDevice | Enables special handling of GigaDevice parallel NAND flash devices. |
FS_NAND_ONFI_DeviceListISSI | Enables special handling of ISSI parallel NAND flash devices. |
FS_NAND_ONFI_DeviceListMacronix | Enables special handling of Macronix parallel NAND flash devices. |
FS_NAND_ONFI_DeviceListMicron | Enables special handling of Micron parallel NAND flash devices. |
FS_NAND_ONFI_DeviceListSkyHigh | Enables special handling of SkyHigh parallel NAND flash devices. |
FS_NAND_ONFI_DeviceListWinbond | Enables special handling of Winbond parallel NAND flash devices. |
Read-only ONFI physical layer
This physical layer is a variant of FS_NAND_PHY_ONFI
with read-only access. FS_NAND_PHY_ONFI_RO provides the same functionality as
FS_NAND_PHY_ONFI except that
it cannot modify any data stored on the NAND flash device only to read it.
The erase and write functions of FS_NAND_PHY_ONFI_RO do nothing and return
and error to NAND driver when called.
FS_NAND_PHY_ONFI_RO uses the same runtime configuration functions
and compile time configuration defines as FS_NAND_PHY_ONFI.
Small ONFI physical layer
This physical layer is a variant of FS_NAND_PHY_ONFI
with reduced ROM usage. FS_NAND_PHY_ONFI_Small supports the same NAND flash devices
as FS_NAND_PHY_ONFI but it does not
provide support for the internal page copy operation and for the reading the ECC correction result.
FS_NAND_PHY_ONFI_Small provides read as well as write access to NAND flash device.
FS_NAND_PHY_ONFI_Small uses the same runtime configuration functions
and compile time configuration defines as FS_NAND_PHY_ONFI.
Quad-SPI physical layer
This physical layer supports NAND flash devices interfaced via quad or dual SPI.
The organization of the NAND flash device such as page size and number of blocks is determined
automatically by evaluating the parameters stored in the NAND flash device.
The instances of this physical layer are allocated dynamically.
Compile time configuration
The QSPI physical layer can optionally be configured at compile time.
Typically, this step can be omitted because reasonable default values are provided
that work with most of the applications. The following table provides a summary of
the configuration defines supported by this physical layer.
FS_NAND_DEVICE_OPERATION_TIMEOUT
FS_NAND_DEVICE_OPERATION_TIMEOUT specifies the maximum time in milliseconds
the physical layer has to wait for a NAND flash operation to complete.
This timeout is used for the read, write and as well as erase operations.
This value has to be set according to the timings specified in the
data sheet of the NAND flash device.
FS_NAND_RESET_TIME
FS_NAND_RESET_TIME specifies the time in milliseconds the physical layer
waits for the NAND flash device to become ready after a reset command.
This value has to be set according to the timings specified in the
data sheet of the NAND flash device.
FS_NAND_SPI_DEVICE_LIST_DEFAULT
FS_NAND_SPI_DEVICE_LIST_DEFAULT specifies the list of serial NAND flash devices that
can be handled by the physical layer. It can be set to NULL in order to reduce the ROM
usage if not all the devices included in FS_NAND_SPI_DeviceListDefault have to be handled.
In this case it is mandatory that the application configures a list of devices via
FS_NAND_QSPI_SetDeviceList().
FS_NAND_SUPPORT_COMPATIBILITY_MODE
emFile versions older than 4.06b wrongly stored the management data to a region
of the spare area that was not protected by the HW ECC. This behavior affects only
configurations that use the Micron MT29F1G01ABAFD NAND flash device.
The correction of this behavior introduces a data compatibility that can be avoided by
setting this define either to 1 or to 2.
With FS_NAND_SUPPORT_COMPATIBILITY_MODE set to 1 the physical layer reads the management
data from old location if at the new location no management data is present.
With FS_NAND_SUPPORT_COMPATIBILITY_MODE set to 2 the physical layer updates the management data
to old and new location in addition to trying to read it from both of these locations.
FS_NAND_SUPPORT_READ_CACHE
With FS_NAND_SUPPORT_READ_CACHE set to 1 the physical layer keeps track
of the index of the last page read from the serial NAND flash device. If the same page
is read again then the physical layer omits the operation that transfers the page data
from the memory array to the internal page register of the serial NAND flash device.
In this case only a data transfer from the internal page register to host is executed
which helps improve the performance.
Note
This feature cannot be used if the NAND flash device is partitioned via
FS_NAND_UNI_SetBlockRange() and the created partitions are accessed via the file system.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the QSPI physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
FS_NAND_QSPI_Allow2bitMode()
Description
Specifies if the physical layer can exchange data via 2 data lines.
Prototype
void FS_NAND_QSPI_Allow2bitMode(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based) |
OnOff | Activation status of the option. 0 Data is exchanged via 1 data line. 1 Data is exchanged via 2 data lines. |
Additional information
This function is optional. By default the data is exchanged via 1
data line (standard SPI mode).
FS_NAND_QSPI_Allow4bitMode()
Description
Specifies if the physical layer can exchange data via 4 data lines.
Prototype
void FS_NAND_QSPI_Allow4bitMode(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based) |
OnOff | Activation status of the option. 0 Data is exchanged via 1 data line or 2 data lines. 1 Data is exchanged via 4 data lines. |
Additional information
This function is optional. By default the data is exchanged via 1
data line (standard SPI mode).
FS_NAND_QSPI_AllowDTRMode()
Description
Specifies if the physical layer is permitted to exchange data
on both clock edges.
Prototype
void FS_NAND_QSPI_AllowDTRMode(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based). |
OnOff | Activation status of the option. 0 Disable the option. 1 Enable the option. |
Additional information
This function is optional. By default the data is exchanged only on one
of the clock edges (SDR mode). In DTR mode the data is transferred on
each edge of the clock which helps improve the performance.
The application is permitted to call this function only at the file
system initialization in FS_X_AddDevices().
The DTR mode is enabled only if the configured hardware layer
implements the optional function FS_NAND_HW_TYPE_QSPI_READ_EX.
FS_NAND_QSPI_DisableReadCache()
Description
Deactivates the page read optimization
Prototype
void FS_NAND_QSPI_DisableReadCache(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
Additional information
This function is optional and is available only when the file system
is build with FS_NAND_SUPPORT_READ_CACHE set to 1 which is the default.
The optimization can be enabled at runtime via FS_NAND_QSPI_EnableReadCache().
Refer to FS_NAND_QSPI_EnableReadCache() for more information about how
the page read optimization works
FS_NAND_QSPI_EnableReadCache()
Description
Activates the page read optimization
Prototype
void FS_NAND_QSPI_EnableReadCache(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
Additional information
This function is optional and is available only when the file system
is build with FS_NAND_SUPPORT_READ_CACHE set to 1 which is the default.
Activating the read cache can increase the overall performance of the
NAND driver.
The optimization takes advantage of how the NAND flash device implements
the read page operation. A NAND page read operation consists of two steps.
In the first step, the page data is read from the memory array to internal
page register of the NAND flash device. In the second step, the data is
transferred from the internal page register of NAND flash device to MCU.
With the optimization enabled the first step is skipped whenever possible.
The optimization is enabled by default and has to be disabled if two
or more instances of the NAND driver are configured to access the same
physical NAND flash device. At runtime, the optimization can be disabled
via FS_NAND_QSPI_DisableReadCache().
FS_NAND_QSPI_SetDeviceList()
Description
Specifies the list of enabled serial NAND flash devices.
Prototype
void FS_NAND_QSPI_SetDeviceList( U8 Unit,
const FS_NAND_SPI_DEVICE_LIST * pDeviceList);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based) |
pDeviceList | in List of serial NAND flash devices. |
Additional information
All supported serial NAND flash devices are enabled by default.
Serial NAND flash devices that are not on the list are not
recognized by the file system.
Permitted values for the pDeviceList parameter are:
Identifier | Description |
FS_NAND_SPI_DeviceListAll | Enables handling of serial NAND flash devices from all manufacturers. |
FS_NAND_SPI_DeviceListAllianceMemory | Enables handling of Alliance Memory serial NAND flash devices. |
FS_NAND_SPI_DeviceListDefault | Enables handling of NAND flash devices from any other manufacturer. |
FS_NAND_SPI_DeviceListGigaDevice | Enables handling of GigaDevice serial NAND flash devices. |
FS_NAND_SPI_DeviceListISSI | Enables handling of ISSI serial NAND flash devices. |
FS_NAND_SPI_DeviceListMacronix | Enables handling of Macronix serial NAND flash devices. |
FS_NAND_SPI_DeviceListMicron | Enables handling of Micron serial NAND flash devices. |
FS_NAND_SPI_DeviceListToshiba | Enables handling of Kioxia/Toshiba serial NAND flash devices. |
FS_NAND_SPI_DeviceListWinbond | Enables handling of Winbond serial NAND flash devices. |
FS_NAND_QSPI_SetHWType()
Description
Configures the hardware access routines for a NAND physical layer
of type FS_NAND_PHY_QSPI.
Prototype
void FS_NAND_QSPI_SetHWType( U8 Unit,
const FS_NAND_HW_TYPE_QSPI * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
pHWType | Type of the hardware layer to use. Cannot be NULL. |
Additional information
This function is mandatory and has to be called once in FS_X_AddDevices()
for every instance of a NAND physical layer of type FS_NAND_PHY_QSPI.
SPI physical layer
This physical layer supports NAND flash devices interfaced via standard SPI.
The organization of the NAND flash device such as page size and number of blocks is determined
automatically by evaluating the parameters stored in the NAND flash device.
The instances of this physical layer are allocated dynamically.
Compile time configuration
The SPI physical layer can optionally be configured at compile time.
Typically, this step can be omitted because reasonable default values are provided
that work with most of the applications. The following table provides a summary of
the configuration defines supported by this physical layer.
FS_NAND_DEVICE_OPERATION_TIMEOUT
FS_NAND_DEVICE_OPERATION_TIMEOUT specifies the maximum time in milliseconds
the physical layer has to wait for a NAND flash operation to complete.
This value has to be set according to the timings specified in the
data sheet of the NAND flash device.
FS_NAND_RESET_TIME
FS_NAND_RESET_TIME specifies the time in milliseconds the physical layer
waits for the NAND flash device to become ready after a reset command.
This value has to be set according to the timings specified in the
data sheet of the NAND flash device.
FS_NAND_SPI_DEVICE_LIST_DEFAULT
FS_NAND_SPI_DEVICE_LIST_DEFAULT specifies the list of serial NAND flash devices that
can be handled by the physical layer. It can be set to NULL in order to reduce the ROM usage
if not all the devices included in FS_NAND_SPI_DeviceListDefault have to be handled.
In this case it is mandatory that the application configures a list of devices via
FS_NAND_SPI_SetDeviceList().
FS_NAND_SUPPORT_COMPATIBILITY_MODE
emFile versions older than 4.06b wrongly stored the management data to a region
of the spare area that was not protected by the HW ECC. This behavior affects only
configurations that use the Micron MT29F1G01ABAFD NAND flash device.
The correction of this behavior introduces a data compatibility that can be avoided by
setting this define either to 1 or to 2.
With FS_NAND_SUPPORT_COMPATIBILITY_MODE set to 1 the physical layer reads the management
data from old location if at the new location no management data is present.
With FS_NAND_SUPPORT_COMPATIBILITY_MODE set to 2 the physical layer updates the management data
to old and new location in addition to trying to read it from both of these locations.
FS_NAND_SUPPORT_READ_CACHE
With FS_NAND_SUPPORT_READ_CACHE set to 1 the physical layer keeps track
of the index of the last page read from the serial NAND flash device. If the same page
is read again then the physical layer omits the operation that transfers the page
data from the memory array to the internal page register of the serial NAND flash device.
In this case only a data transfer from the internal page register to host is executed
which helps improve the performance.
Note
This feature cannot be used if the NAND flash device is partitioned via
FS_NAND_UNI_SetBlockRange() and the created partitions are accessed via the file system.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the SPI physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
FS_NAND_SPI_DisableReadCache()
Description
Deactivates the page read optimization
Prototype
void FS_NAND_SPI_DisableReadCache(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
Additional information
This function is optional and is available only when the file system
is build with FS_NAND_SUPPORT_READ_CACHE set to 1 which is the default.
The optimization can be enabled at runtime via FS_NAND_SPI_EnableReadCache().
Refer to FS_NAND_SPI_EnableReadCache() for more information about how
the page read optimization works
FS_NAND_SPI_EnableReadCache()
Description
Activates the page read optimization
Prototype
void FS_NAND_SPI_EnableReadCache(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
Additional information
This function is optional and is available only when the file system
is build with FS_NAND_SUPPORT_READ_CACHE set to 1 which is the default.
Activating the read cache can increase the overall performance of the
NAND driver.
The optimization takes advantage of how the NAND flash device implements
the read page operation. A NAND page read operation consists of two steps.
In the first step, the page data is read from the memory array to internal
page register of the NAND flash device. In the second step, the data is
transferred from the internal page register of NAND flash device to MCU.
With the optimization enabled the first step is skipped whenever possible.
The optimization is enabled by default and has to be disabled if two
or more instances of the NAND driver are configured to access the same
physical NAND flash device. At runtime, the optimization can be disabled
via FS_NAND_SPI_DisableReadCache().
FS_NAND_SPI_SetDeviceList()
Description
Specifies the list of enabled serial NAND flash devices.
Prototype
void FS_NAND_SPI_SetDeviceList( U8 Unit,
const FS_NAND_SPI_DEVICE_LIST * pDeviceList);
Parameters
Parameter | Description |
Unit | Index of the physical layer (0-based) |
pDeviceList | in List of serial NAND flash devices. |
Additional information
All supported serial NAND flash devices are enabled by default.
Serial NAND flash devices that are not on the list are not
recognized by the file system.
Permitted values for the pDeviceList parameter are:
Identifier | Description |
FS_NAND_SPI_DeviceListAll | Enables handling of serial NAND flash devices from all manufacturers. |
FS_NAND_SPI_DeviceListDefault | Enables handling of NAND flash devices from any other manufacturer. |
FS_NAND_SPI_DeviceListISSI | Enables handling of ISSI serial NAND flash devices. |
FS_NAND_SPI_DeviceListMacronix | Enables handling of Macronix serial NAND flash devices. |
FS_NAND_SPI_DeviceListMicron | Enables handling of Micron serial NAND flash devices. |
FS_NAND_SPI_DeviceListToshiba | Enables handling of Kioxia/Toshiba serial NAND flash devices. |
FS_NAND_SPI_DeviceListWinbond | Enables handling of Winbond serial NAND flash devices. |
FS_NAND_SPI_SetHWType()
Description
Configures the hardware access routines for a NAND physical layer
of type FS_NAND_PHY_SPI.
Prototype
void FS_NAND_SPI_SetHWType( U8 Unit,
const FS_NAND_HW_TYPE_SPI * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
pHWType | Type of the hardware layer to use. Cannot be NULL. |
Additional information
This function is mandatory and has to be called once in FS_X_AddDevices()
for every instance of a NAND physical layer of type FS_NAND_PHY_SPI.
8/16-bit data bus physical layer
This physical layer supports all the NAND flash devices supported by the
following NAND physical layers:
Compile time configuration
The 16/8-bit data bus physical layer can optionally be configured at compile time.
Typically, this step can be omitted because reasonable default values are provided
that work with most of the applications. The following table provides a summary of
the configuration defines supported by this physical layer.
Define | Default value | Type | Description |
FS_NAND_SUPPORT_AUTO_DETECTION | 1 | B | Specifies if the parameters of the NAND flash device have to be automatically detected or not. |
FS_NAND_SUPPORT_AUTO_DETECTION
By default, the 8-bit data bus physical layer tries to automatically detect
the parameters of the NAND flash device such as the number of blocks and
the number of pages in the block by evaluating the value returned as response
to the READ ID (0x90) command. This behavior can be disabled by building
the physical layer with FS_NAND_SUPPORT_AUTO_DETECTION set to 0. In this case,
the application must call FS_NAND_x_Configure() in FS_X_AddDevices() to
specify the parameters of the NAND flash device.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the 16/8-bit data bus physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
Function | Description |
FS_NAND_x_Configure() | Configures the parameters of the NAND flash device for a NAND physical layer of type FS_NAND_PHY_x. |
FS_NAND_x_SetHWType() | Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_x. |
Description
Configures the parameters of the NAND flash device for a NAND
physical layer of type FS_NAND_PHY_x.
Prototype
void FS_NAND_x_Configure(U8 Unit,
unsigned NumBlocks,
unsigned PagesPerBlock,
unsigned BytesPerPage,
unsigned BytesPerSpareArea,
unsigned DataBusWidth);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
NumBlocks | Total number of blocks in the NAND flash device. |
PagesPerBlock | Total number of pages in a NAND block. |
BytesPerPage | Number of bytes in a page without the spare area. |
BytesPerSpareArea | Number of bytes in the spare area of a NAND page. |
DataBusWidth | Number of data lines used for data exchange. |
Additional information
This function is mandatory only when the file system is built with
FS_NAND_SUPPORT_AUTO_DETECTION set to 0 which is not the default.
FS_NAND_x_Configure() has to be called once in FS_X_AddDevices() for
each instance of the FS_NAND_PHY_x physical layer.
FS_NAND_x_Configure() is not available if FS_NAND_SUPPORT_AUTO_DETECTION is set to 0.
By default, the FS_NAND_PHY_x physical layer identifies the parameters
of the NAND flash device by evaluating the first and second byte of the reply
returned by the NAND flash device to the READ ID (0x90) command.
The identification operation is disabled if FS_NAND_SUPPORT_AUTO_DETECTION
set to 0 and the application must specify the NAND flash parameters via this
function.
FS_NAND_x_SetHWType()
Description
Configures the hardware access routines for a NAND physical layer
of type FS_NAND_PHY_x.
Prototype
void FS_NAND_x_SetHWType( U8 Unit,
const FS_NAND_HW_TYPE * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
pHWType | Type of the hardware layer to use. Cannot be NULL. |
Additional information
This function is mandatory and has to be called once in
FS_X_AddDevices() for every instance of a NAND physical
layer of type FS_NAND_PHY_x.
8-bit data bus physical layer
This physical layer supports all the NAND flash devices supported by the
following NAND physical layers:
Compile time configuration
The 8-bit data bus physical layer can optionally be configured at compile time.
Typically, this step can be omitted because reasonable default values are provided
that work with most of the applications. The following table provides a summary of
the configuration defines supported by this physical layer.
Define | Default value | Type | Description |
FS_NAND_SUPPORT_AUTO_DETECTION | 1 | B | Specifies if the parameters of the NAND flash device have to be automatically detected or not. |
FS_NAND_SUPPORT_AUTO_DETECTION
By default, the 8-bit data bus physical layer tries to automatically detect
the parameters of the NAND flash device such as the number of blocks and
the number of pages in the block by evaluating the value returned as response
to the READ ID (0x90) command. This behavior can be disabled by building
the physical layer with FS_NAND_SUPPORT_AUTO_DETECTION set to 0. In this case,
the application must call FS_NAND_x8_Configure() in FS_X_AddDevices() to
specify the parameters of the NAND flash device.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the 8-bit data bus physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
Function | Description |
FS_NAND_x8_Configure() | Configures the parameters of the NAND flash device for a NAND physical layer of type FS_NAND_PHY_x8. |
FS_NAND_x8_SetHWType() | Configures the hardware access routines for a NAND physical layer of type FS_NAND_PHY_x8. |
Description
Configures the parameters of the NAND flash device for a NAND
physical layer of type FS_NAND_PHY_x8.
Prototype
void FS_NAND_x8_Configure(U8 Unit,
unsigned NumBlocks,
unsigned PagesPerBlock,
unsigned BytesPerPage,
unsigned BytesPerSpareArea);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
NumBlocks | Total number of blocks in the NAND flash device. |
PagesPerBlock | Total number of pages in a NAND block. |
BytesPerPage | Number of bytes in a page without the spare area. |
BytesPerSpareArea | Number of bytes in the spare area of a NAND page. |
Additional information
This function is mandatory only when the file system is built with
FS_NAND_SUPPORT_AUTO_DETECTION set to 0 which is not the default.
FS_NAND_x_Configure() has to be called once in FS_X_AddDevices() for
each instance of the FS_NAND_PHY_x8 physical layer.
FS_NAND_x_Configure() is not available if FS_NAND_SUPPORT_AUTO_DETECTION is set to 0.
By default, the FS_NAND_PHY_x8 physical layer identifies the parameters
of the NAND flash device by evaluating the first and second byte of the reply
returned by the NAND flash device to the READ ID (0x90) command. The identification
operation is disabled if FS_NAND_SUPPORT_AUTO_DETECTION set to 0 and
the application must specify the NAND flash parameters via this function.
FS_NAND_x8_SetHWType()
Description
Configures the hardware access routines for a NAND physical layer
of type FS_NAND_PHY_x8.
Prototype
void FS_NAND_x8_SetHWType( U8 Unit,
const FS_NAND_HW_TYPE * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
pHWType | Type of the hardware layer to use. Cannot be NULL. |
Additional information
This function has to be called once in FS_X_AddDevices() for every
instance of a NAND physical layer of type FS_NAND_PHY_x8.
Physical layer API
The physical layers that come with emFile provide support most of the popular
NAND flash device and target MCU types. Therefore, there is no need to modify any
of the provided NAND physical layers. Typically, only the NAND hardware layer has
to be adapted to a specific target hardware. However, when none of the provided NAND
physical layers are compatible with the target hardware a new NAND physical layer
implementation is required. This section provides information about the API of the
NAND physical layer that helps to create a new physical layer from scratch
or to modify an existing one.
The API of the physical layer is implemented as a structure of type FS_NAND_PHY_TYPE
that contains pointers to functions. The following sections describe these functions
in detail together with the data structure passed to these functions as parameters.
FS_NAND_PHY_TYPE
Description
NAND physical layer API.
Type definition
typedef struct {
FS_NAND_PHY_TYPE_ERASE_BLOCK * pfEraseBlock;
FS_NAND_PHY_TYPE_INIT_GET_DEVICE_INFO * pfInitGetDeviceInfo;
FS_NAND_PHY_TYPE_IS_WP * pfIsWP;
FS_NAND_PHY_TYPE_READ * pfRead;
FS_NAND_PHY_TYPE_READ_EX * pfReadEx;
FS_NAND_PHY_TYPE_WRITE * pfWrite;
FS_NAND_PHY_TYPE_WRITE_EX * pfWriteEx;
FS_NAND_PHY_TYPE_ENABLE_ECC * pfEnableECC;
FS_NAND_PHY_TYPE_DISABLE_ECC * pfDisableECC;
FS_NAND_PHY_TYPE_CONFIGURE_ECC * pfConfigureECC;
FS_NAND_PHY_TYPE_COPY_PAGE * pfCopyPage;
FS_NAND_PHY_TYPE_GET_ECC_RESULT * pfGetECCResult;
FS_NAND_PHY_TYPE_DEINIT * pfDeInit;
FS_NAND_PHY_TYPE_SET_RAW_MODE * pfSetRawMode;
} FS_NAND_PHY_TYPE;
Structure members
FS_NAND_PHY_TYPE_ERASE_BLOCK
Description
Erases a NAND block.
Type definition
typedef int FS_NAND_PHY_TYPE_ERASE_BLOCK(U8 Unit,
U32 PageIndex);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
PageIndex | Index of the first page in the NAND block to be erased (0-based) |
Return value
= 0 | OK, the NAND block has been erased. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the NAND physical layer API.
It is mandatory to be implemented by all the NAND physical layers.
It is called by the NAND driver to set to 1 all the bits of a NAND block.
A NAND block is the smallest erasable unit of a NAND flash device.
The index of the actual NAND block to be erased depends on the
number of pages stored in a NAND block. For example if the NAND
block contains 64 pages, then the PageIndex parameter passed by
the NAND driver to the function has to be be interpreted as follows:
- 0 - NAND block 0
- 64 - NAND block 1
- 128 - NAND block 2
- etc.
FS_NAND_PHY_TYPE_INIT_GET_DEVICE_INFO
Description
Initializes the physical layer.
Type definition
typedef int FS_NAND_PHY_TYPE_INIT_GET_DEVICE_INFO(U8 Unit,
FS_NAND_DEVICE_INFO * pDevInfo);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
pDevInfo | out Information about the NAND flash device. |
Return value
= 0 | OK, physical layer has been initialized. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the NAND physical layer API.
It is mandatory to be implemented by all the NAND physical layers.
It is the first function of the physical layer API that is called
by the NAND driver when the NAND flash device is mounted.
This function initializes hardware layer, resets and tries to identify
the NAND flash device. If the NAND flash device can be handled, the
pDevInfo is filled with information about the organization and the ECC
requirements of the NAND flash device.
FS_NAND_PHY_TYPE_IS_WP
Description
Checks if the NAND flash device is write protected.
Type definition
typedef int FS_NAND_PHY_TYPE_IS_WP(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
Return value
= 0 | Data stored on the NAND flash device can be modified. |
≠ 0 | Data stored on the NAND flash device cannot be modified. |
Additional information
This function is a member of the NAND physical layer API.
It is mandatory to be implemented by all the NAND physical layers.
The write protection status is checked by evaluating the bit 7 of
the NAND status register. Typical reason for write protection is
that either the supply voltage is too low or the /WP-pin is connected
to ground.
FS_NAND_PHY_TYPE_READ
Description
Reads data from a NAND page.
Type definition
typedef int FS_NAND_PHY_TYPE_READ(U8 Unit,
U32 PageIndex,
void * pData,
unsigned Off,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
PageIndex | Index of the NAND page to read from (0-based). |
pData | out Data read from NAND page. |
Off | Byte offset to read from. |
NumBytes | Number of bytes to be read. |
Return value
= 0 | OK, data read. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the NAND physical layer API.
It has to be implemented by all the NAND physical layers.
The NAND driver uses FS_NAND_PHY_TYPE_READ to read data from
the main as well as from the spare area of a page.
FS_NAND_PHY_TYPE_READ_EX
Description
Reads data from two different locations of a NAND page.
Type definition
typedef int FS_NAND_PHY_TYPE_READ_EX(U8 Unit,
U32 PageIndex,
void * pData0,
unsigned Off0,
unsigned NumBytes0,
void * pData1,
unsigned Off1,
unsigned NumBytes1);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
PageIndex | Index of the NAND page to read from (0-based). |
pData0 | out Data read from Off0 of the NAND page. |
Off0 | Byte offset to read from for pData0. |
NumBytes0 | Number of bytes to be read. |
pData1 | out Data read from Off1 of a NAND page. |
Off1 | Byte offset to read from for pData1. |
NumBytes1 | Number of bytes to be read from Off1. |
Return value
= 0 | OK, data read. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the NAND physical layer API.
It has to be implemented by all the NAND physical layers.
FS_NAND_PHY_TYPE_READ_EX is typically used by the NAND driver
to read the data from main and spare area of a page at the same time.
It is guaranteed that Off0 is always smaller than Off1 and that
the region defined by Off0 and NumBytes0 does not overlap the
region defined by Off1 and NumBytes1
FS_NAND_PHY_TYPE_WRITE
Description
Writes data to a NAND page.
Type definition
typedef int FS_NAND_PHY_TYPE_WRITE( U8 Unit,
U32 PageIndex,
const void * pData,
unsigned Off,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
PageIndex | Index of the NAND page to write to (0-based). |
pData | in Data to be written to the NAND page. |
Off | Byte offset to write to. |
NumBytes | Number of bytes to be written. |
Return value
= 0 | OK, data written. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the NAND physical layer API.
It has to be implemented only by a NAND physical layer that
works with the SLC1 NAND driver. The Universal NAND driver
does not call this function. FS_NAND_PHY_TYPE_WRITE is used by
the SLC1 NAND driver to write data to the main as well as to the
spare area of a page.
FS_NAND_PHY_TYPE_WRITE_EX
Description
Writes data to two different locations of a NAND page.
Type definition
typedef int FS_NAND_PHY_TYPE_WRITE_EX( U8 Unit,
U32 PageIndex,
const void * pData0,
unsigned Off0,
unsigned NumBytes0,
const void * pData1,
unsigned Off1,
unsigned NumBytes1);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
PageIndex | Index of the NAND page to write to (0-based). |
pData0 | in Data to be written to the NAND page at Off0. |
Off0 | Byte offset to write to for pData0. |
NumBytes0 | Number of bytes to be written at Off0. |
pData1 | in Data to be written to the NAND page at Off1. |
Off1 | Byte offset to write to for pData1. |
NumBytes1 | Number of bytes to be written at Off1. |
Return value
= 0 | OK, data written. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the NAND physical layer API.
It has to be implemented by all the NAND physical layers.
The NAND driver uses FS_NAND_PHY_TYPE_WRITE_EX to write data to
the main and spare area of a page at the same time.
It is guaranteed that Off0 is always smaller than Off1 and that
the region defined by Off0 and NumBytes0 does not overlap the
region defined by Off1 and NumBytes1
FS_NAND_PHY_TYPE_ENABLE_ECC
Description
Enables the hardware ECC.
Type definition
typedef int FS_NAND_PHY_TYPE_ENABLE_ECC(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
Return value
= 0 | OK, hardware ECC activated. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the NAND physical layer API.
It has to be implemented by the NAND physical layers that provide
hardware support for bit error correction either on MCU via
a dedicated NAND flash controller or via on-die ECC of the NAND flash device.
FS_NAND_PHY_TYPE_ENABLE_ECC is called only by the Universal NAND driver.
After the call to this function the Universal NAND driver expects that
FS_NAND_PHY_TYPE_READ and FS_NAND_PHY_TYPE_READ_EX return corrected data
that is without bit errors. In addition, the Universal NAND driver expects
that FS_NAND_PHY_TYPE_WRITE and FS_NAND_PHY_TYPE_WRITE_EX calculate and store
the ECC to NAND flash device.
FS_NAND_PHY_TYPE_DISABLE_ECC
Description
Deactivates the hardware ECC.
Type definition
typedef int FS_NAND_PHY_TYPE_DISABLE_ECC(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
Return value
= 0 | OK, hardware ECC deactivated. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the NAND physical layer API. It has
to be implemented by the NAND physical layers that provide
hardware support for bit error correction. FS_NAND_PHY_TYPE_DISABLE_ECC
is called only by the Universal NAND driver.
After the call to this function the Universal NAND driver expects that
FS_NAND_PHY_TYPE_READ and FS_NAND_PHY_TYPE_READ_EX return data
that might contain bit errors. In addition, the Universal NADN driver expects
that FS_NAND_PHY_TYPE_WRITE and FS_NAND_PHY_TYPE_WRITE_EX store the data
without calculating the ECC.
Description
Configures the hardware ECC.
Type definition
typedef int FS_NAND_PHY_TYPE_CONFIGURE_ECC(U8 Unit,
U8 NumBitsCorrectable,
U16 BytesPerECCBlock);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
NumBitsCorrectable | Maximum number of bit errors the hardware ECC has to be able to correct. |
BytesPerECCBlock | Number of consecutive data bytes protected by a single ECC. |
Return value
= 0 | OK, hardware ECC configured. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the NAND physical layer API.
It has to be implemented by the NAND physical layers that provide
hardware support for bit error correction with configurable ECC
strength. FS_NAND_PHY_TYPE_CONFIGURE_ECC is called only by the
Universal NAND driver.
FS_NAND_PHY_TYPE_COPY_PAGE
Description
Copies the contents of an entire page to another page.
Type definition
typedef int FS_NAND_PHY_TYPE_COPY_PAGE(U8 Unit,
U32 PageIndexSrc,
U32 PageIndexDest);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
PageIndexSrc | Index of the page to copy from. |
PageIndexDest | Index of the page to copy to. |
Return value
= 0 | OK, page copied. |
≠ 0 | An error occurred or operation not supported. |
Additional information
This function is a member of the NAND physical layer API. It may be
be implemented by the NAND physical layers that can provide
a faster method of copying the contents of a page than by first reading
the source page contents to MCU and then by writing the contents to the
destination page. One such method is the internal page copy operation
supported by some NAND flash device. FS_NAND_PHY_TYPE_COPY_PAGE is called
only by the Universal NAND driver.
FS_NAND_PHY_TYPE_GET_ECC_RESULT
Description
Returns the error correction status of the last read page.
Type definition
typedef int FS_NAND_PHY_TYPE_GET_ECC_RESULT(U8 Unit,
FS_NAND_ECC_RESULT * pResult);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
pResult | out Information about the correction status. |
Return value
= 0 | OK, information returned. |
≠ 0 | An error occurred or operation not supported. |
Additional information
This function is a member of the NAND physical layer API. It may be
implemented by the NAND physical layers that can provide information
about the status of the bit correction operation and about the number
of bit errors corrected.
FS_NAND_PHY_TYPE_GET_ECC_RESULT is called only by the Universal NAND driver.
The information returned by FS_NAND_PHY_TYPE_GET_ECC_RESULT is used
by the Universal NAND driver to decide when a NAND block has to be relocated
in order to prevent bit correction errors. A bit correction error occurs when
the number of bit errors is greater than the number of bit errors the ECC is
able to correct. Typically, a bit correction error causes a data loss.
FS_NAND_PHY_TYPE_DEINIT
Description
Releases the allocated resources.
Type definition
typedef void FS_NAND_PHY_TYPE_DEINIT(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
Additional information
This function is a member of the NAND physical layer API. It has
to be implemented by the NAND physical layers that allocate
resources dynamically during the initialization such as memory
for the instance.
The NAND driver calls this function when the file system is unmounted.
FS_NAND_PHY_TYPE_SET_RAW_MODE
Description
Enables or disables the data translation.
Type definition
typedef int FS_NAND_PHY_TYPE_SET_RAW_MODE(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the NAND physical layer instance (0-based) |
OnOff | Activation status of the feature. |
Return value
= 0 | OK, status changed. |
≠ 0 | An error occurred or operation not supported. |
Additional information
This function is a member of the NAND physical layer API. It may
be implemented by the NAND physical layers that store the data to
NAND flash device using a different layout than the NAND driver.
FS_NAND_PHY_TYPE_SET_RAW_MODE is not called by the NAND driver
during the normal operation. It is called only by specific
functions of the Universal NAND driver such as FS_NAND_UNI_WritePageRaw()
and FS_NAND_UNI_ReadPageRaw().
FS_NAND_DEVICE_INFO
Description
Information about the NAND flash device.
Type definition
typedef struct {
U8 BPP_Shift;
U8 PPB_Shift;
U16 NumBlocks;
U16 BytesPerSpareArea;
FS_NAND_ECC_INFO ECC_Info;
U8 DataBusWidth;
U8 BadBlockMarkingType;
U8 PPO_Shift;
} FS_NAND_DEVICE_INFO;
Structure members
Member | Description |
BPP_Shift | Bytes per page as a power of two value. |
PPB_Shift | Pages per block as a power of two value. |
NumBlocks | Total number of blocks in the NAND flash device. |
BytesPerSpareArea | Number of bytes in the spare area. |
ECC_Info | Information about the ECC capability required by the NAND flash device. |
DataBusWidth | Number of lines used for exchanging the data with the NAND flash device. |
BadBlockMarkingType | Specifies how the blocks are marked as defective. |
PPO_Shift | Number of operations performed in parallel by the NAND physical layer. |
Additional information
The initialization function of the physical layer
FS_NAND_PHY_TYPE_INIT_GET_DEVICE_INFO uses this structure to return
information about the NAND flash device to the NAND driver.
Typical values for BPP_Shift are 9 and 11 for NAND flash devices
with a page size (without the spare area) of 512 and 2048 bytes
respectively.
BytesPerSpareArea is typically 1/32 of the page size (2^BPP_Shift)
but some NAND flash devices have a spare area larger than this.
For example Micron MT29F8G08ABABA has a spare area of 224 bytes
for a page size of 4096 bytes.
DataBusWith can take the following values:
- 0 - unknown
- 1 - SPI
- 8 - parallel 8-bit
- 16 - parallel 16-bit
Refer to Bad block marking types for a list of permitted values
for BadBlockMarkingType.
PPO_Shift (Planes Per Operation) has to be specified as a power of two value.
Most of the NAND physical layers set this value to 0 to indicate that
they do not support parallel operations. FS_NAND_PHY_2048x8_TwoPlane sets
this value to 1 because it can read and write two NAND pages at once and
it can erase two NAND blocks at once. This information is used by the
Universal NAND driver to correctly identify and mark defective blocks.
FS_NAND_ECC_INFO
Description
Information about the ECC used to protect data stored on the NAND flash.
Type definition
typedef struct {
U8 NumBitsCorrectable;
U8 ldBytesPerBlock;
U8 HasHW_ECC;
U8 IsHW_ECCEnabledPerm;
} FS_NAND_ECC_INFO;
Structure members
Member | Description |
NumBitsCorrectable | Maximum number of bit errors the ECC should be able to correct. |
ldBytesPerBlock | Number of bytes the ECC should protect as power of 2 exponent. |
HasHW_ECC | Set to 1 if the NAND flash device has internal HW ECC. |
IsHW_ECCEnabledPerm | Set to 1 if the internal HW ECC of the NAND flash device cannot be disabled. |
Additional information
The value of IsHW_ECCEnabledPerm is valid only if the value of
HasHW_ECC is different than 0.
ldBytesPerBlock is a power of 2 value. If HasHW_ECC is different than 0
ldBytesPerBlock represents the number of bytes in the main and spare area
of a NAND page the internal HW ECC is able to protect against bit errors.
More than one ECC is used to protect the data in a NAND page if the
size of the NAND page is larger than ldBytesPerBlock. ldBytesPerBlock
can never be larger than the size of a NAND page.
If HasHW_ECC is different than 0 than NumBitsCorrectable represents
the maximum number of bit errors the internal HW ECC is able to correct.
FS_NAND_ECC_RESULT
Description
Information about the ECC number of bits corrected in an ECC block.
Type definition
typedef struct {
U8 CorrectionStatus;
U8 MaxNumBitsCorrected;
} FS_NAND_ECC_RESULT;
Structure members
Member | Description |
CorrectionStatus | Indicates if the correction succeeded or failed. |
MaxNumBitsCorrected | Maximum number of bit errors detected and corrected in any ECC block of a page. |
Additional information
This structure is filled by the FS_NAND_PHY_TYPE_GET_ECC_RESULT
function of the NAND physical layer to return the result of the
bit error correction operation.
Refer to ECC correction status for a list of permitted values
for CorrectionStatus.
An ECC block is the number of bytes protected by a single ECC.
Typically, the ECC block is 512 bytes large, therefor the number
of ECC blocks in a 2 KByte page is 4. Most of the NAND flash devices
report the number of bits corrected in each of the ECC blocks.
The value stored to MaxNumBitsCorrected must be the maximum of these
values.
Additional physical layer functions
The following functions are optional. They can be called to get information about the
NAND flash device and to control additional functionality of physical layers.
FS_NAND_PHY_ReadDeviceId()
Description
Returns the id information stored in a NAND flash device.
Prototype
int FS_NAND_PHY_ReadDeviceId(U8 Unit,
U8 * pId,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of HW layer connected to NAND flash. |
pId | out Identification data read from NAND flash. |
NumBytes | Number of bytes to read. |
Return value
= 0 | OK, id information read. |
≠ 0 | An error occurred. |
Additional information
FS_NAND_PHY_ReadDeviceId() executes the READ ID command to read
the id information from the NAND flash device. NumBytes specifies
the number of bytes to be read. Refer to the data sheet of the
NAND flash device for additional information about the meaning of
the data returned by the NAND flash device. Typically, the first
byte stores the manufactured id while the second byte provides
information about the organization of the NAND flash device.
It is permitted to call FS_NAND_PHY_ReadONFIPara()from FS_X_AddDevices()
since it does not require for the file system to be fully initialized and
it invokes only functions of the NAND hardware layer. No instance of NAND
driver is required to invoke this function.
Typical usage is to determine at runtime the type of NAND driver to be
used for the connected NAND flash device.
Example
The following example shows how an application can select at runtime a different
NAND drivers based on the type of the used NAND flash.
#include "FS.h"
#define ALLOC_SIZE 0x4000 // Memory pool for the file system in bytes
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for semi-dynamic allocation.
/*********************************************************************
*
* FS_X_AddDevices
*/
void FS_X_AddDevices(void) {
U8 Id;
FS_AssignMemory(_aMemBlock, sizeof(_aMemBlock));
//
// Read the first byte of the identification array.
// This byte stores the manufacturer type.
//
FS_NAND_PHY_SetHWType(0, &FS_NAND_HW_Default);
FS_NAND_PHY_ReadDeviceId(0, &Id, sizeof(Id));
if (Id == 0xEC) {
//
// Found a Samsung NAND flash. Use the SLC1 NAND driver.
// ECC is performed by the NAND driver
//
FS_AddDevice(&FS_NAND_Driver);
FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
FS_NAND_2048x8_SetHWType(0, &FS_NAND_HW_Default);
} else if (Id == 0x2C) {
//
// Found a Micron NAND flash. Use the Universal NAND driver.
// The ECC is performed by the NAND flash.
//
FS_AddDevice(&FS_NAND_UNI_Driver);
FS_NAND_UNI_SetPhyType(0, &FS_NAND_PHY_ONFI);
FS_NAND_UNI_SetECCHook(0, &FS_NAND_ECC_HW_NULL);
FS_NAND_ONFI_SetHWType(0, &FS_NAND_HW_Default);
} else {
//
// NAND flash from another manufacturer, use auto-identification.
//
FS_AddDevice(&FS_NAND_Driver);
FS_NAND_SetPhyType(0, &FS_NAND_PHY_x8);
FS_NAND_x8_SetHWType(0, &FS_NAND_HW_Default);
}
}
FS_NAND_PHY_ReadONFIPara()
Description
Reads the ONFI parameters from a NAND flash.
Prototype
int FS_NAND_PHY_ReadONFIPara(U8 Unit,
void * pPara);
Parameters
Parameter | Description |
Unit | Index of HW layer connected to NAND flash. |
pPara | out Data of ONFI parameter page read from NAND flash. This parameter can be set to NULL. |
Return value
= 0 | ONFI parameters read. |
≠ 0 | ONFI is not supported by the NAND flash. |
Additional information
Refer to the data sheet of the NAND flash device for a description
of the data layout of the returned ONFI parameters.
This function can be used to read the ONFI parameter stored in a NAND flash.
It is permitted to call FS_NAND_PHY_ReadONFIPara()from FS_X_AddDevices()
since it does not require for the file system to be fully initialized and
it invokes only functions of the NAND hardware layer. No instance of NAND
driver is required to invoke this function.
FS_NAND_PHY_ReadONFIPara() can also be used to check if the NAND flash device
is ONFI compliant by setting pPara to NULL.
The size of the buffer passed via pParam must be at least 256 bytes large.
Example
This example demonstrates how an application can configure at runtime different
NAND driver based on the type of the NAND flash.
#include "FS.h"
#define ALLOC_SIZE 0x4000 // Memory pool for the file system in bytes
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for semi-dynamic allocation.
/*********************************************************************
*
* FS_X_AddDevices
*/
void FS_X_AddDevices(void) {
int r;
FS_AssignMemory(_aMemBlock, sizeof(_aMemBlock));
//
// Check whether the NAND flash supports ONFI.
//
FS_NAND_PHY_SetHWType(0, &FS_NAND_HW_Default);
r = FS_NAND_PHY_ReadONFIPara(0, NULL);
if (r != 0) {
//
// Found a NAND flash which does not support ONFI.
//
FS_AddDevice(&FS_NAND_Driver);
FS_NAND_SetPhyType(0, &FS_NAND_PHY_2048x8);
} else {
//
// Found a NAND flash which supports ONFI.
//
FS_AddDevice(&FS_NAND_UNI_Driver);
FS_NAND_UNI_SetPhyType(0, &FS_NAND_PHY_ONFI);
FS_NAND_UNI_SetECCHook(0, &FS_NAND_ECC_HW_NULL);
}
}
FS_NAND_PHY_SetHWType()
Description
Configures the hardware access routines for FS_NAND_PHY_ReadDeviceId()
and FS_NAND_PHY_ReadONFIPara().
Prototype
void FS_NAND_PHY_SetHWType( U8 Unit,
const FS_NAND_HW_TYPE * pHWType);
Parameters
Parameter | Description |
Unit | Index of the physical layer instance (0-based) |
pHWType | Type of the hardware layer to use. Cannot be NULL. |
Additional information
This function is mandatory if the application calls either FS_NAND_PHY_ReadDeviceId()
or FS_NAND_PHY_ReadONFIPara(). FS_NAND_PHY_SetHWType() has to be called once
in FS_X_AddDevices() for every different Unit number passed to FS_NAND_PHY_ReadDeviceId()
or FS_NAND_PHY_ReadONFIPara().
Resource usage
This section describes the ROM and RAM usage of the NAND physical layers.
ROM usage
The ROM usage depends on the compiler options, the compiler version, and the used
CPU. The memory requirements of the NAND physical layers were measured as described in the section
Test procedure.
The following table lists the ROM usage of all the available NOR physical layers.
Static RAM usage
Static RAM usage is the amount of RAM required by the driver for static variables
inside the driver. The number of bytes can be seen in a compiler list file.
The next table lists the static RAM usage of all the available NOR physical layers.
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the physical layer at runtime.
The amount of RAM required depends on the compile time and runtime configuration.
The following table lists the the dynamic RAM usage of the available NOR physical layers.
NAND hardware layer
General information
The NAND hardware layer provides functionality for accessing a NAND flash device
via the target hardware such as external memory controller, GPIO, SPI, etc.
The functions of the NAND hardware layer are called by the NAND physical layer
to exchange commands and data with a NAND flash device. Since these functions are
hardware dependent, they have to be implemented by the user. emFile comes
with template hardware layers and sample implementations for popular evaluation
boards that can be used as starting point for implementing new hardware layers.
The relevant files are located in the /Sample/FS/Driver/NAND folder of the
emFile shipment.
Hardware layer types
The functions of the NAND hardware layer are organized in a function table implemented
a C structure. Different hardware layer types are provided to support different
ways of interfacing a NAND flash device. The type of hardware layer an application
has to use depends on the type NAND physical layer configured. The following table
shows what hardware layer is required by each physical layer.
Hardware layer API - FS_NAND_HW_TYPE
This NAND hardware layer supports NAND flash devices that can be accessed
via an 8- or 16-bit data bus. The functions of this hardware layer are grouped
in a structure of type FS_NAND_HW_TYPE. The following sections describe these
functions in detail.
FS_NAND_HW_TYPE
Description
NAND hardware layer API for NAND flash devices connected via parallel I/O.
Type definition
typedef struct {
FS_NAND_HW_TYPE_INIT_X8 * pfInit_x8;
FS_NAND_HW_TYPE_INIT_X16 * pfInit_x16;
FS_NAND_HW_TYPE_DISABLE_CE * pfDisableCE;
FS_NAND_HW_TYPE_ENABLE_CE * pfEnableCE;
FS_NAND_HW_TYPE_SET_ADDR_MODE * pfSetAddrMode;
FS_NAND_HW_TYPE_SET_CMD_MODE * pfSetCmdMode;
FS_NAND_HW_TYPE_SET_DATA_MODE * pfSetDataMode;
FS_NAND_HW_TYPE_WAIT_WHILE_BUSY * pfWaitWhileBusy;
FS_NAND_HW_TYPE_READ_X8 * pfRead_x8;
FS_NAND_HW_TYPE_WRITE_X8 * pfWrite_x8;
FS_NAND_HW_TYPE_READ_X16 * pfRead_x16;
FS_NAND_HW_TYPE_WRITE_X16 * pfWrite_x16;
} FS_NAND_HW_TYPE;
Structure members
Member | Description |
pfInit_x8 | Initializes a NAND flash device with an 8-bit data interface. |
pfInit_x16 | Initializes a NAND flash device with a 16-bit data interface. |
pfDisableCE | Disables the NAND flash device. |
pfEnableCE | Enables the NAND flash device. |
pfSetAddrMode | Initiates the transfer of an address. |
pfSetCmdMode | Initiates the transfer of a command. |
pfSetDataMode | Initiates the transfer of data. |
pfWaitWhileBusy | Waits for the NAND flash device to become ready. |
pfRead_x8 | Reads a specified number of bytes from NAND flash device via the 8-bit data interface. |
pfWrite_x8 | Writes a specified number of bytes to NAND flash device via the 8-bit data interface. |
pfRead_x16 | Reads a specified number of bytes from NAND flash device via the 16-bit data interface. |
pfWrite_x16 | Writes a specified number of bytes to NAND flash device via the 16-bit data interface. |
FS_NAND_HW_TYPE_INIT_X8
Description
Initializes the hardware for 8-bit mode access.
Type definition
typedef void FS_NAND_HW_TYPE_INIT_X8(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_PHY_TYPE NAND hardware
layer API. It has to be implemented by a NAND hardware layer
that accesses a NAND flash device via an 8-bit data bus.
FS_NAND_HW_TYPE_INIT_X8 is the first function of the hardware
layer API that is called by a NAND physical layer during the
mounting of the file system.
This function has to perform any initialization of the MCU hardware
required to access the NAND flash device such as clocks, port pins,
memory controllers, etc.
FS_NAND_HW_TYPE_INIT_X16
Description
Initializes the hardware for 16-bit mode access.
Type definition
typedef void FS_NAND_HW_TYPE_INIT_X16(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_PHY_TYPE NAND hardware
layer API. The implementation of this function is optional for
systems that interface to the NAND flash device via an 8-bit data bus.
FS_NAND_HW_TYPE_INIT_X16 must be implemented for systems that
have the NAND flash device connected to MCU via an 16-bit data bus.
FS_NAND_HW_TYPE_INIT_X16 is the first function of the hardware
layer API that is called by the NAND physical layer when the NAND
flash device is mounted.
FS_NAND_HW_TYPE_DISABLE_CE
Description
Disables the NAND flash device.
Type definition
typedef void FS_NAND_HW_TYPE_DISABLE_CE(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_PHY_TYPE NAND hardware
layer API and it is mandatory to be implemented. The implementation
of this function can be left empty if the hardware is driving
the Chip Enable (CE) signal. Typically, the NAND flash device
is disabled by driving the CE signal to a logic low state level.
FS_NAND_HW_TYPE_ENABLE_CE
Description
Enables the NAND flash device.
Type definition
typedef void FS_NAND_HW_TYPE_ENABLE_CE(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_PHY_TYPE NAND hardware
layer API. It is mandatory to be implemented by all NAND hardware
layers. The implementation of this function can be left empty if the
hardware is driving the Chip Enable (CE) signal. Typically,
the NAND flash device is enabled by driving the CE signal to
a logic-high level.
FS_NAND_HW_TYPE_SET_ADDR_MODE
Description
Changes the data access to address mode.
Type definition
typedef void FS_NAND_HW_TYPE_SET_ADDR_MODE(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_PHY_TYPE NAND hardware
layer API. It is mandatory to be implemented by all NAND hardware layers.
After the call to this function the NAND hardware layer has to
make sure that any data sent to NAND flash device is interpreted
as address information. This can be achieved by setting the
Address Latch Enable signal (ALE) signal to logic-high
and the Command Latch Enable (CLE) signal to logic low state.
FS_NAND_HW_TYPE_SET_CMD_MODE
Description
Changes the data access to command mode.
Type definition
typedef void FS_NAND_HW_TYPE_SET_CMD_MODE(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_PHY_TYPE NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware layers.
After the call to this function the NAND hardware layer has to
make sure that any data sent to NAND flash device is interpreted
as command information. This can be achieved by setting the
Command Latch Enable (CLE) signal to logic-high and the Address
Latch Enable signal (ALE) signal to logic low state.
FS_NAND_HW_TYPE_SET_DATA_MODE
Description
Changes the data access to data mode.
Type definition
typedef void FS_NAND_HW_TYPE_SET_DATA_MODE(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_PHY_TYPE NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware layers.
After the call to this function the NAND hardware layer has to
make sure that any data sent to NAND flash device is interpreted
as data information. This can be achieved by setting the
Command Latch Enable (CLE) and Address Latch Enable signals to logic low state.
FS_NAND_HW_TYPE_WAIT_WHILE_BUSY
Description
Waits for the NAND flash device to become ready.
Type definition
typedef int FS_NAND_HW_TYPE_WAIT_WHILE_BUSY(U8 Unit,
unsigned us);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
us | Maximum time to wait in microseconds. |
Return value
= 0 | The NAND flash device is ready. |
≠ 0 | The NAND flash device is busy or the operation is not supported. |
Additional information
This function is a member of the FS_NAND_PHY_TYPE NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware layers.
A NAND hardware layer calls this function every time it checks
the status of the NAND flash device. A typical implementation uses
the status of the Ready/Busy (R/B) signal that is set to logic low state
by the NAND flash device as long as it is busy and it cannot accept
and other commands from MCU.
FS_NAND_HW_TYPE_WAIT_WHILE_BUSY must return 1 if the status of
the NAND flash device cannot be queried via R/B signal. In this case,
the NAND hardware layer checks the status via a read status command.
Typically, a NAND flash device does not set R/B signal to logic low state
immediately after it accepts a command from MCU but only after a time interval
labeled as tWB in the data sheet of the NAND flash device. This means that
FS_NAND_HW_TYPE_WAIT_WHILE_BUSY has to wait for tWB time interval
to elapse before it samples the R/B signal for the first time in
order to make sure that it returns correct status information to
the NAND physical layer.
FS_NAND_HW_TYPE_READ_X8
Description
Reads data from NAND flash device via 8-bit data bus.
Type definition
typedef void FS_NAND_HW_TYPE_READ_X8(U8 Unit,
void * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
pData | out Data read from NAND flash. It cannot be NULL. |
NumBytes | Number of bytes to be read. It cannot be 0. |
Additional information
This function is a member of the FS_NAND_PHY_TYPE NAND hardware
layer API. It has to be implemented by a NAND hardware layer
that exchanges the data with the NAND flash device via an 8-bit
data bus.
FS_NAND_HW_TYPE_READ_X8 is called by a NAND physical layer
in data mode to transfer data from NAND flash device to MCU.
It is not called in address and command data access modes.
The transfer of the data is controlled by the MCU using the
Read Enable (RE) signal. If the NAND hardware layer exchanges
the data via GPIO it has to make sure that the timing of the
RE signal meets the specifications of the NAND flash device.
FS_NAND_HW_TYPE_WRITE_X8
Description
Writes data to NAND flash device via 8-bit data bus.
Type definition
typedef void FS_NAND_HW_TYPE_WRITE_X8( U8 Unit,
const void * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
pData | in Data to be written to NAND flash. It cannot be NULL. |
NumBytes | Number of bytes to be read. It cannot be 0. |
Additional information
This function is a member of the FS_NAND_PHY_TYPE NAND hardware
layer API. It has to be implemented by a NAND hardware layer
that exchanges the data with the NAND flash device via an 8-bit
data bus.
FS_NAND_HW_TYPE_WRITE_X8 is called by a NAND physical layer
in all data access modes to transfer data from MCU to NAND flash device.
The transfer of the data is controlled by the MCU using the
Write Enable (WE) signal. If the NAND hardware layer exchanges
the data via GPIO it has to make sure that the timing of the
WE signal meets the specifications of the NAND flash device.
FS_NAND_HW_TYPE_READ_X16
Description
Reads data from NAND flash device via 16-bit data bus.
Type definition
typedef void FS_NAND_HW_TYPE_READ_X16(U8 Unit,
void * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
pData | out Data read from NAND flash. It cannot be NULL. |
NumBytes | Number of bytes to be read. It cannot be 0. |
Additional information
This function is a member of the FS_NAND_PHY_TYPE NAND hardware
layer API. It has to be implemented by a NAND hardware layer
that exchanges the data with the NAND flash device via an 16-bit
data bus.
FS_NAND_HW_TYPE_READ_X16 is called by a NAND physical layer
in data mode to transfer data from NAND flash device to MCU.
It is not called in address and command data access modes.
The transfer of the data is controlled by the MCU using the
Read Enable (RE) signal. If the NAND hardware layer exchanges
the data via GPIO it has to make sure that the timing of the
RE signal meets the specifications of the NAND flash device.
pData is aligned to a half-word (2-byte) boundary.
FS_NAND_HW_TYPE_WRITE_X16
Description
Writes data to NAND flash device via 16-bit data bus.
Type definition
typedef void FS_NAND_HW_TYPE_WRITE_X16( U8 Unit,
const void * pdata,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
pData | in Data to be written to NAND flash. It cannot be NULL. |
NumBytes | Number of bytes to be read. It cannot be 0. |
Additional information
This function is a member of the FS_NAND_PHY_TYPE NAND hardware
layer API. It has to be implemented by a NAND hardware layer
that exchanges the data with the NAND flash device via an 16-bit
data bus.
FS_NAND_HW_TYPE_WRITE_X16 is called by a NAND physical layer
in all data access modes to transfer data from MCU to NAND flash device.
The transfer of the data is controlled by the MCU using the
Write Enable (WE) signal. If the NAND hardware layer exchanges
the data via GPIO it has to make sure that the timing of the
WE signal meets the specifications of the NAND flash device.
pData is aligned to a half-word (2-byte) boundary.
Sample implementation
The following sample implementation uses the GPIO ports of an NXP K66 MCU to
interface with a NAND flash device. This NAND hardware layer was tested
on the SGGER emPower board (https://www.segger.com/evaluate-our-software/segger/empower/)
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : FS_NAND_HW_K66_SEGGER_emPower.c
Purpose : NAND flash hardware layer header file for the SEGGER emPower
V2 evaluation board.
Literature:
[1] K66 Sub-Family Reference Manual
[2] emPower Evaluation and prototyping platform for SEGGER software User Guide & Reference Manual
*/
/*********************************************************************
*
* #include Section
*
**********************************************************************
*/
#include "FS.h"
#include "FS_NAND_HW_K66_SEGGER_emPower.h"
#include "MK66F18.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#ifndef FS_NAND_HW_USE_OS
#define FS_NAND_HW_USE_OS 0 // Enables / disables the
// event-driven operation.
// 0 - OS support disabled.
// 1 - OS support enabled
// using the OS event of emFile.
// 2 - OS support enabled using
// OS events of this HW layer.
#endif
/*********************************************************************
*
* #include section, conditional
*
**********************************************************************
*/
#if FS_NAND_HW_USE_OS
#include "RTOS.h"
#include "FS_OS.h"
#endif // FS_NAND_HW_USE_OS
/*********************************************************************
*
* Defines, fixed
*
**********************************************************************
*/
/*********************************************************************
*
* Port pins
*/
#define NAND_CS_PIN 0
#define NAND_WAIT_PIN 1
#define NAND_ALE_PIN 4
#define NAND_CLE_PIN 5
#define NAND_nOE_PIN 6
#define NAND_nWE_PIN 7
#define NAND_DATA_MASK 0xff
#define NAND_D0_SHIFT 8
#define NAND_D0_PIN 8
#define NAND_D1_PIN 9
#define NAND_D2_PIN 10
#define NAND_D3_PIN 11
#define NAND_D4_PIN 12
#define NAND_D5_PIN 13
#define NAND_D6_PIN 14
#define NAND_D7_PIN 15
/*********************************************************************
*
* Macros for pin configuration
*/
#define SET_DATA2INPUT() GPIOD_PDDR &= ~(NAND_DATA_MASK << NAND_D0_SHIFT)
#define SET_DATA2OUTPUT() GPIOD_PDDR |= (NAND_DATA_MASK << NAND_D0_SHIFT)
/*********************************************************************
*
* Macros for pin control
*/
#define NAND_GET_DATA(Data) Data = *((volatile U8 *)&GPIOD_PDIR + 0x1);
#define NAND_SET_DATA(Data) *((volatile U8 *)&GPIOD_PDOR + 0x1) = Data;
#define NAND_SET_ALE() GPIOD_PSOR = (1 << NAND_ALE_PIN);
#define NAND_CLR_ALE() GPIOD_PCOR = (1 << NAND_ALE_PIN);
#define NAND_SET_CLE() GPIOD_PSOR = (1 << NAND_CLE_PIN);
#define NAND_CLR_CLE() GPIOD_PCOR = (1 << NAND_CLE_PIN);
#define NAND_SET_CE() GPIOD_PSOR = (1 << NAND_CS_PIN);
#define NAND_CLR_CE() GPIOD_PCOR = (1 << NAND_CS_PIN);
#define NAND_SET_RE() GPIOD_PSOR = (1 << NAND_nOE_PIN);
#define NAND_CLR_RE() GPIOD_PCOR = (1 << NAND_nOE_PIN);
#define NAND_SET_WE() GPIOD_PSOR = (1 << NAND_nWE_PIN);
#define NAND_CLR_WE() GPIOD_PCOR = (1 << NAND_nWE_PIN);
#define NAND_GET_BUSY() (GPIOD_PDIR & (1 << NAND_WAIT_PIN))
#define NAND_NOP() __asm("nop")
/*********************************************************************
*
* Misc. defines
*/
#define PORTD_IRQ_PRIO 15
#define WAIT_TIMEOUT_MS 1000 // Maximum time to wait for the NAND
// flash device to become ready.
#define NUM_LOOPS_TWB 17 // Delay for tWB time.
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
#if (FS_NAND_HW_USE_OS == 2)
static U8 _IsEventInited = 0;
static OS_EVENT _Event;
#endif // FS_NAND_HW_USE_OS == 2
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
#if FS_NAND_HW_USE_OS
/*********************************************************************
*
* _WaitForEvent
*
* Function description
* Waits for the interrupt to wake up the task.
*
* Parameters
* TimeOut Maximum time to wait for the event in milliseconds.
*
* Return values
* ==0 OK, event signaled.
* !=0 An error occurred.
*/
static int _WaitForEvent(U32 TimeOut) {
int r;
PORTD_PCR1 |= PORT_PCR_IRQC(0xC); // Generate an interrupt when the
// the busy signal goes HIGH.
#if (FS_NAND_HW_USE_OS == 2)
r = OS_EVENT_WaitTimed(&_Event, TimeOut);
#else
r = FS_OS_Wait(TimeOut);
#endif
if (r != 0) {
PORTD_PCR1 &= ~PORT_PCR_IRQC_MASK; // Disable the interrupt.
PORTD_PCR1 |= PORT_PCR_ISF_MASK;
}
return r;
}
#endif // FS_NAND_HW_USE_OS
/*********************************************************************
*
* Static code (public via callback)
*
**********************************************************************
*/
/*********************************************************************
*
* _HW_EnableCE
*
* Function description
* Enables the NAND flash device.
*
* Parameters
* Unit Index of the NAND hardware layer instance (0-based)
*/
static void _HW_EnableCE(U8 Unit) {
FS_USE_PARA(Unit);
NAND_CLR_CE();
}
/*********************************************************************
*
* _HW_DisableCE
*
* Function description
* Disables the NAND flash device.
*
* Parameters
* Unit Index of the NAND hardware layer instance (0-based)
*/
static void _HW_DisableCE(U8 Unit) {
FS_USE_PARA(Unit);
NAND_SET_CE();
}
/*********************************************************************
*
* _HW_SetDataMode
*
* Function description
* Changes the data access to data mode.
*
* Parameters
* Unit Index of the NAND hardware layer instance (0-based)
*/
static void _HW_SetDataMode(U8 Unit) {
FS_USE_PARA(Unit);
//
// nCE low, CLE low, ALE low
//
NAND_CLR_CLE();
NAND_CLR_ALE();
}
/*********************************************************************
*
* _HW_SetCmdMode
*
* Function description
* Changes the data access to command mode.
*
* Parameters
* Unit Index of the NAND hardware layer instance (0-based)
*/
static void _HW_SetCmdMode(U8 Unit) {
FS_USE_PARA(Unit);
//
// nCE low, CLE high, ALE low
//
NAND_SET_CLE();
NAND_CLR_ALE();
}
/*********************************************************************
*
* _HW_SetAddr
*
* Function description
* Changes the data access to address mode.
*
* Parameters
* Unit Index of the NAND hardware layer instance (0-based)
*/
static void _HW_SetAddrMode(U8 Unit) {
FS_USE_PARA(Unit);
//
// nCE low, CLE low, ALE high
//
NAND_CLR_CLE();
NAND_SET_ALE();
}
/*********************************************************************
*
* _HW_Read_x8
*
* Function description
* Reads data from NAND flash device via 8-bit data bus.
*
* Parameters
* Unit Index of the NAND hardware layer instance (0-based)
* pData [OUT] Data read from NAND flash. It cannot be NULL.
* NumBytes Number of bytes to be read. It cannot be 0.
*/
static void _HW_Read_x8(U8 Unit, void * p, unsigned NumBytes) {
U8 * pData;
FS_USE_PARA(Unit);
pData = (U8 *)p;
SET_DATA2INPUT();
do {
NAND_CLR_RE(); // Enable RE (active low)
//
// Wait for the data to be available (tREA time).
// Two NOPs should actually be sufficient but
// it seems that the MCU requires some time to
// synchronize the contents of the PDIR register
// of the GPIO port.
//
NAND_NOP();
NAND_NOP();
NAND_NOP();
NAND_NOP();
NAND_NOP();
NAND_NOP();
NAND_NOP();
NAND_NOP();
NAND_GET_DATA(*pData++);
NAND_SET_RE(); // Disable RE (active low)
} while (--NumBytes);
}
/*********************************************************************
*
* _HW_Write_x8
*
* Function description
* Writes data to NAND flash device via 8-bit data bus.
*
* Parameters
* Unit Index of the NAND hardware layer instance (0-based)
* pData [IN] Data to be written to NAND flash. It cannot be NULL.
* NumBytes Number of bytes to be read. It cannot be 0.
*/
static void _HW_Write_x8(U8 Unit, const void * p, unsigned NumBytes) {
const U8 * pData;
FS_USE_PARA(Unit);
pData = (const U8 *)p;
SET_DATA2OUTPUT();
do {
NAND_SET_DATA(*pData++);
NAND_CLR_WE(); // Enable WE (active low)
NAND_NOP();
NAND_SET_WE(); // Disable WE (active low)
} while (--NumBytes);
}
/*********************************************************************
*
* _HW_Init_x8
*
* Function description
* Initializes the hardware for 8-bit mode access.
*
* Parameters
* Unit Index of the NAND hardware layer instance (0-based)
*/
static void _HW_Init_x8(U8 Unit) {
FS_USE_PARA(Unit);
#if FS_NAND_HW_USE_OS
//
// Disable the interrupt.
//
NVIC_DisableIRQ(PORTD_IRQn);
NVIC_SetPriority(PORTD_IRQn, PORTD_IRQ_PRIO);
#endif // FS_NAND_HW_USE_OS
//
// Add here the initialization of your NAND hardware
//
SIM_SCGC5 |= SIM_SCGC5_PORTD_MASK; // Enable clock for Port D
PORTD_PCR0 = PORT_PCR_MUX(0x01); // Configure as GPIO
PORTD_PCR1 = PORT_PCR_MUX(0x01) // Configure as GPIO
| PORT_PCR_PS_MASK // Enable the pull-up.
| PORT_PCR_PE_MASK
;
PORTD_PCR4 = PORT_PCR_MUX(0x01); // Configure as GPIO
PORTD_PCR5 = PORT_PCR_MUX(0x01); // Configure as GPIO
PORTD_PCR6 = PORT_PCR_MUX(0x01); // Configure as GPIO
PORTD_PCR7 = PORT_PCR_MUX(0x01); // Configure as GPIO
PORTD_PCR8 = PORT_PCR_MUX(0x01); // Configure as GPIO
PORTD_PCR9 = PORT_PCR_MUX(0x01); // Configure as GPIO
PORTD_PCR10 = PORT_PCR_MUX(0x01); // Configure as GPIO
PORTD_PCR11 = PORT_PCR_MUX(0x01); // Configure as GPIO
PORTD_PCR12 = PORT_PCR_MUX(0x01); // Configure as GPIO
PORTD_PCR13 = PORT_PCR_MUX(0x01); // Configure as GPIO
PORTD_PCR14 = PORT_PCR_MUX(0x01); // Configure as GPIO
PORTD_PCR15 = PORT_PCR_MUX(0x01); // Configure as GPIO
GPIOD_PDDR |= (1u << NAND_CS_PIN)
| (1u << NAND_ALE_PIN)
| (1u << NAND_CLE_PIN)
| (1u << NAND_nOE_PIN)
| (1u << NAND_nWE_PIN)
;
GPIOD_PDDR &= ~(1 << NAND_WAIT_PIN);
NAND_SET_RE(); // Disable RE
NAND_SET_WE(); // Disable WE
NAND_SET_CLE(); // Disable CLE
NAND_SET_ALE(); // Disable ALE
NAND_SET_CE(); // Disable CE
#if FS_NAND_HW_USE_OS
//
// Create the OS event and enable the interrupt.
//
#if (FS_NAND_HW_USE_OS == 2)
if (_IsEventInited == 0) {
OS_EVENT_Create(&_Event);
_IsEventInited = 1;
}
#endif // FS_NAND_HW_USE_OS == 2
NVIC_EnableIRQ(PORTD_IRQn);
#endif
}
/*********************************************************************
*
* _HW_WaitWhileBusy
*
* Function description
* Waits for the NAND flash device to become ready.
*
* Parameters
* Unit Index of the NAND hardware layer instance (0-based)
* us Maximum time to wait in microseconds.
*
* Return value
* ==0 The NAND flash device is ready.
* !=0 The NAND flash device is busy or the operation is not supported.
*/
static int _HW_WaitWhileBusy(U8 Unit, unsigned us) {
volatile int NumLoops;
FS_USE_PARA(Unit);
FS_USE_PARA(us);
//
// Make sure that we do not sample the busy signal too early.
// In order to do so we have to wait here at least the time
// specified at tWB in the data sheet of the NAND flash device.
// Typically this time is about 100 ns. Assuming that the CPU
// is running at 168 MHz then we have to wait here 100 / 5.9 = 16.9
// that is about 17 cycles.
//
NumLoops = NUM_LOOPS_TWB;
do {
NAND_NOP();
} while (--NumLoops != 0);
for (;;) {
if (NAND_GET_BUSY() != 0) {
break;
}
#if FS_NAND_HW_USE_OS
(void)_WaitForEvent(WAIT_TIMEOUT_MS);
#else
NAND_NOP();
#endif // FS_NAND_HW_USE_OS
}
return 0;
}
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
#if FS_NAND_HW_USE_OS
/*********************************************************************
*
* PORTD_IRQHandler
*/
void PORTD_IRQHandler(void);
void PORTD_IRQHandler(void) {
OS_EnterNestableInterrupt();
PORTD_PCR1 &= ~PORT_PCR_IRQC_MASK; // Disable the interrupt.
PORTD_PCR1 |= PORT_PCR_ISF_MASK;
#if (FS_NAND_HW_USE_OS == 2)
OS_EVENT_Set(&_Event);
#else
FS_OS_Signal();
#endif
OS_LeaveNestableInterrupt();
}
#endif // FS_NAND_HW_USE_OS
/*********************************************************************
*
* Public data
*
**********************************************************************
*/
/*********************************************************************
*
* FS_NAND_HW_K66_SEGGER_emPower
*/
const FS_NAND_HW_TYPE FS_NAND_HW_K66_SEGGER_emPower = {
_HW_Init_x8,
NULL,
_HW_DisableCE,
_HW_EnableCE,
_HW_SetAddrMode,
_HW_SetCmdMode,
_HW_SetDataMode,
_HW_WaitWhileBusy,
_HW_Read_x8,
_HW_Write_x8,
NULL,
NULL
};
/*************************** End of file ****************************/
Hardware layer API - FS_NAND_HW_TYPE_DF
This hardware layer supports Microchip / Atmel / Adesto DataFlash devices
and is used by the FS_NAND_PHY_DataFlash physical layer to exchange data
with a DataFlash device via a standard SPI interface.
The functions of this hardware layer are grouped in the structure of type
FS_NAND_HW_TYPE_DF. The following sections describe these
functions in detail.
FS_NAND_HW_TYPE_DF
Description
NAND hardware layer API for DataFlash devices.
Type definition
typedef struct {
FS_NAND_HW_TYPE_DF_INIT * pfInit;
FS_NAND_HW_TYPE_DF_ENABLE_CS * pfEnableCS;
FS_NAND_HW_TYPE_DF_DISABLE_CS * pfDisableCS;
FS_NAND_HW_TYPE_DF_READ * pfRead;
FS_NAND_HW_TYPE_DF_WRITE * pfWrite;
} FS_NAND_HW_TYPE_DF;
Structure members
Member | Description |
pfInit | Initializes the hardware. |
pfEnableCS | Enables the DataFlash device. |
pfDisableCS | Disables the DataFlash device. |
pfRead | Transfers a specified number of bytes from DataFlash device to MCU. |
pfWrite | Transfers a specified number of bytes from MCU to DataFlash device. |
FS_NAND_HW_TYPE_DF_INIT
Description
Initializes the hardware.
Type definition
typedef int FS_NAND_HW_TYPE_DF_INIT(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Return value
= 0 | OK, initialization was successful. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the FS_NAND_HW_TYPE_DF NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type. FS_NAND_HW_TYPE_DF_INIT is the first function
of the hardware layer API that is called by a NAND physical layer
during the mounting of the file system.
This function has to perform any initialization of the MCU hardware
required to access the DataFlash device such as clocks, port pins,
memory controllers, etc.
A DataFlash requires that the SPI communication protocol meets the
following requirements:
- 8-bit data length.
- The most significant bit hast to be sent out first.
- Chip Select (CS) signal should be initially high to disable the DataFlash device.
- The SPI clock frequency does not have to exceed the maximum
clock frequency that is specified by the DataFlash device (Usually: 20MHz).
FS_NAND_HW_TYPE_DF_ENABLE_CS
Description
Enables the DataFlash device.
Type definition
typedef void FS_NAND_HW_TYPE_DF_ENABLE_CS(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_HW_TYPE_DF NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
The DataFlash device is enabled by driving the Chip Select (CS)
signal to logic low state.
FS_NAND_HW_TYPE_DF_DISABLE_CS
Description
Disables the DataFlash device.
Type definition
typedef void FS_NAND_HW_TYPE_DF_DISABLE_CS(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_HW_TYPE_DF NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
The DataFlash device is disabled by driving the Chip Select (CS)
signal to logic-high.
FS_NAND_HW_TYPE_DF_READ
Description
Transfers a specified number of bytes from DataFlash device to MCU.
Type definition
typedef void FS_NAND_HW_TYPE_DF_READ(U8 Unit,
U8 * pData,
int NumBytes);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
pData | out Data read from DataFlash device. |
NumBytes | Number of bytes to be read. |
Additional information
This function is a member of the FS_NAND_HW_TYPE_DF NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
FS_NAND_HW_TYPE_DF_WRITE
Description
Transfers a specified number of bytes from MCU to DataFlash device.
Type definition
typedef void FS_NAND_HW_TYPE_DF_WRITE( U8 Unit,
const U8 * pData,
int NumBytes);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
pData | in Data to be written to DataFlash device. |
NumBytes | Number of bytes to be written. |
Additional information
This function is a member of the FS_NAND_HW_TYPE_DF NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
Sample implementation
The following sample implementation uses the SPI controller of a NXP LPC4322 MCU
to interface with a DataFlash device. This NAND hardware layer was tested
on a SGGER internal test board.
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : FS_NAND_HW_DF_LPC4322_SEGGER_QSPIFI_Test_Board.c
Purpose : DataFlash hardware layer for NXP LPC4322.
Literature:
[1] UM10503 LPC43xx ARM Cortex-M4/M0 multi-core microcontroller
*/
/*********************************************************************
*
* #include section
*
**********************************************************************
*/
#include "FS.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#define PER_CLK_HZ 180000000uL // Frequency of the clock supplied to SPI unit
#ifndef SPI_CLK_HZ
#define SPI_CLK_HZ 25000000uL // Frequency of the clock supplied to DataFlash device
#endif
#define RESET_DELAY_LOOPS 100000 // Number of software loops to wait for DataFlash to reset
/*********************************************************************
*
* Defines, non-configurable
*
**********************************************************************
*/
/*********************************************************************
*
* SPI unit
*/
#define SPI_BASE_ADDR 0x40100000
#define SPI_CR (*(volatile U32*)(SPI_BASE_ADDR + 0x00)) // SPI Control Register
#define SPI_SR (*(volatile U32*)(SPI_BASE_ADDR + 0x04)) // SPI Status Register
#define SPI_DR (*(volatile U32*)(SPI_BASE_ADDR + 0x08)) // SPI Data Register
#define SPI_CCR (*(volatile U32*)(SPI_BASE_ADDR + 0x0C)) // SPI Clock Counter Register
#define SPI_TCR (*(volatile U32*)(SPI_BASE_ADDR + 0x10)) // SPI Test Control register
#define SPI_TSR (*(volatile U32*)(SPI_BASE_ADDR + 0x14)) // SPI Test Status register
#define SPI_INT (*(volatile U32*)(SPI_BASE_ADDR + 0x1C)) // SPI Interrupt Flag
/*********************************************************************
*
* Clock generation unit
*/
#define CGU_BASE_ADDR 0x40050000
#define BASE_SPI_CLK (*(volatile U32*)(CGU_BASE_ADDR + 0x0074))
/*********************************************************************
*
* Clock control unit 1
*/
#define CCU1_BASE_ADDR 0x40051000
#define CLK_SPI_CFG (*(volatile U32*)(CCU1_BASE_ADDR + 0x0A00))
#define CLK_SPI_STAT (*(volatile U32*)(CCU1_BASE_ADDR + 0x0A04))
/*********************************************************************
*
* System control unit
*/
#define SCU_BASE_ADDR 0x40086000
#define SFSP3_2 (*(volatile U32*)(SCU_BASE_ADDR + 0x188)) // Pin configuration register for pin P3_2
#define SFSP3_3 (*(volatile U32*)(SCU_BASE_ADDR + 0x18C)) // Pin configuration register for pin P3_3
#define SFSP3_6 (*(volatile U32*)(SCU_BASE_ADDR + 0x198)) // Pin configuration register for pin P3_6
#define SFSP3_7 (*(volatile U32*)(SCU_BASE_ADDR + 0x19C)) // Pin configuration register for pin P3_7
#define SFSP3_8 (*(volatile U32*)(SCU_BASE_ADDR + 0x1A0)) // Pin configuration register for pin P3_8
/*********************************************************************
*
* GPIO unit
*/
#define GPIO_BASE_ADDR 0x400F4000
#define GPIO_DIR5 (*(volatile U32*)(GPIO_BASE_ADDR + 0x2014)) // Direction registers port 5
#define GPIO_SET5 (*(volatile U32*)(GPIO_BASE_ADDR + 0x2214)) // Set register for port 5
#define GPIO_CLR5 (*(volatile U32*)(GPIO_BASE_ADDR + 0x2294)) // Clear register for port 5
/*********************************************************************
*
* Misc. defines
*/
#define CGU_IDIV_BIT 2
#define CGU_AUTOBLOCK_BIT 11
#define CGU_CLK_SEL_BIT 24
#define SFS_MODE_BIT 0
#define SFS_EPUN_BIT 4
#define SFS_EHS_BIT 5
#define SFS_EZI_BIT 6
#define SFS_ZIF_BIT 7
#define CLK_STAT_RUN_BIT 0
#define CLK_CFG_RUN_BIT 0
#define NOR_CS_BIT 11
#define CR_MSTR_BIT 5
#define SR_SPIF 7
#define CCR_COUNTER_MAX 0xFE // The actual maximum value is 0xFF but it has to be a multiple of 2
#define NOR_RESET_BIT 9
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _SetSpeed
*
* Function description
* Configures the speed of the clock supplied NOR flash device.
*
* Return value
* Frequency of the SPI clock in Hz.
*/
static U32 _SetSpeed(unsigned MaxFreq_Hz) {
U32 Div;
U32 Freq_Hz;
//
// According to [1] the clock divisor has to be >= 8 and a multiple of 2.
//
Div = 8;
while (1) {
Freq_Hz = PER_CLK_HZ / Div;
if (Freq_Hz <= MaxFreq_Hz) {
break;
}
Div += 2;
if (Div >= CCR_COUNTER_MAX) {
Div = CCR_COUNTER_MAX;
Freq_Hz = PER_CLK_HZ / Div;
break;
}
}
SPI_CCR = Div;
return Freq_Hz;
}
/*********************************************************************
*
* _TransferByte
*
* Function description
* Exchanges 8 bits of data with the NOR flash.
*
* Parameters
* Data Data to be sent to NOR flash.
*
* Return value
* The data received from NOR flash
*/
static U8 _Transfer8Bits(U8 Data) {
SPI_DR = Data;
while (1) {
if (SPI_SR & (1uL << SR_SPIF)) {
break;
}
}
Data = SPI_DR;
return Data;
}
/*********************************************************************
*
* Public code (via callback)
*
**********************************************************************
*/
/*********************************************************************
*
* _HW_Init
*
* Function description
* Initialize the hardware before accessing the device.
*
* Parameters
* Unit Device index
*
* Return Value
* ==0 Hardware successfully initialized
* !=0 An error occurred
*/
static int _HW_Init(U8 Unit) {
unsigned NumLoops;
FS_USE_PARA(Unit); // This device has only one HW unit.
BASE_SPI_CLK = 0
| 9uL << CGU_CLK_SEL_BIT // Use PLL1 as clock generator
| 1uL << CGU_AUTOBLOCK_BIT
;
//
// Enable the SPI clock if required.
//
if ((CLK_SPI_STAT & (1uL << CLK_STAT_RUN_BIT)) == 0) {
CLK_SPI_CFG |= (1uL << CLK_CFG_RUN_BIT);
while (1) {
if (CLK_SPI_STAT & (1uL << CLK_CFG_RUN_BIT)) {
;
}
}
}
//
// Clock pin (SPI_CLK).
//
SFSP3_3 = 0
| (1uL << SFS_MODE_BIT) // Controlled by SPI unit.
| (1uL << SFS_EPUN_BIT)
| (1uL << SFS_EHS_BIT)
| (1uL << SFS_EZI_BIT)
;
//
// Master In Slave Out (SPI_MISO).
//
SFSP3_6 = 0
| (1uL << SFS_MODE_BIT) // Controlled by SPI unit.
| (1uL << SFS_EPUN_BIT)
| (1uL << SFS_EZI_BIT)
;
//
// Master Out Slave In (SPI_MOSI).
//
SFSP3_7 = 0
| (1uL << SFS_MODE_BIT) // Controlled by SPI unit.
| (1uL << SFS_EPUN_BIT)
| (1uL << SFS_EZI_BIT)
;
//
// Chip select pin (SPI_CS).
//
SFSP3_8 = 0
| (4uL << SFS_MODE_BIT) // GPIO controlled by the this hardware layer.
| (1uL << SFS_EPUN_BIT)
;
GPIO_DIR5 |= 1uL << NOR_CS_BIT;
GPIO_SET5 = 1uL << NOR_CS_BIT; // Set to idle state.
//
// Reset pin. Present only on 16-pin devices.
//
SFSP3_2 = 0
| (4uL << SFS_MODE_BIT) // Controlled by this HW layer.
| (1uL << SFS_EPUN_BIT)
;
GPIO_DIR5 |= 1uL << NOR_RESET_BIT;
//
// Reset the NOR device.
//
GPIO_CLR5 = 1uL << NOR_RESET_BIT; // Assert reset signal (active low).
NumLoops = RESET_DELAY_LOOPS;
do {
;
} while (--NumLoops);
GPIO_SET5 = 1uL << NOR_RESET_BIT; // De-assert reset signal (active low).
//
// Configure the SPI unit.
//
SPI_CR = 0
| (1uL << CR_MSTR_BIT)
;
(void)_SetSpeed(SPI_CLK_HZ);
return 0;
}
/*********************************************************************
*
* _HW_EnableCS
*
* Function description
* Sets the device active using the chip select (CS) line.
*
* Parameters
* Unit Device index
*/
static void _HW_EnableCS(U8 Unit) {
FS_USE_PARA(Unit);
GPIO_CLR5 = 1uL << NOR_CS_BIT; // The CS signal is active low.
}
/*********************************************************************
*
* _HW_DisableCS
*
* Function description
* Sets the device inactive using the chip select (CS) line.
*
* Parameters
* Unit Device index
*/
static void _HW_DisableCS(U8 Unit) {
FS_USE_PARA(Unit);
GPIO_SET5 = 1uL << NOR_CS_BIT; // The CS signal is active low.
}
/*********************************************************************
*
* _HW_Read
*
* Function description
* Reads a specified number of bytes from device.
*
* Parameters
* Unit Device index
* pData Pointer to a data buffer
* NumBytes Number of bytes
*/
static void _HW_Read(U8 Unit, U8 * pData, int NumBytes) {
FS_USE_PARA(Unit);
do {
*pData++ = _Transfer8Bits(0xFF);
} while (--NumBytes);
}
/*********************************************************************
*
* _HW_Write
*
* Function description
* Writes a specified number of bytes from data buffer to device.
*
* Parameters
* Unit Device index
* pData Pointer to a data buffer
* NumBytes Number of bytes
*/
static void _HW_Write(U8 Unit, const U8 * pData, int NumBytes) {
FS_USE_PARA(Unit);
do {
(void)_Transfer8Bits(*pData++);
} while (--NumBytes);
}
/*********************************************************************
*
* Public data
*
**********************************************************************
*/
const FS_NAND_HW_TYPE_DF FS_NAND_HW_DF_LPC4322_SEGGER_QSPIFI_Test_Board = {
_HW_Init,
_HW_EnableCS,
_HW_DisableCS,
_HW_Read,
_HW_Write
};
/*************************** End of file ****************************/
Hardware layer API - FS_NAND_HW_TYPE_QSPI
This hardware layer supports any serial NAND flash device with a standard, dual or quad SPI interface.
It is used by the FS_NAND_PHY_QSPI physical layer to exchange data with a NAND flash device
that supports such an interface.
Typically, the implementation of FS_NAND_HW_TYPE_QSPI hardware layer makes use of a SPI
controller that is able to exchange the data via two or four data lines. This kind of
SPI controllers are found on most of the popular MCUs and they are typically used to
execute code in-place from an external NOR flash device but they can be equally well
used to exchange data with a serial NAND flash device.
The functions of this hardware layer are grouped in the structure of type
FS_NAND_HW_TYPE_QSPI. The following sections describe these functions in detail.
FS_NAND_HW_TYPE_QSPI
Description
NAND hardware layer API for NAND flash devices connected via quad and dual SPI.
Type definition
typedef struct {
FS_NAND_HW_TYPE_QSPI_INIT * pfInit;
FS_NAND_HW_TYPE_QSPI_CONTROL * pfExecCmd;
FS_NAND_HW_TYPE_QSPI_READ * pfReadData;
FS_NAND_HW_TYPE_QSPI_WRITE * pfWriteData;
FS_NAND_HW_TYPE_QSPI_POLL * pfPoll;
FS_NAND_HW_TYPE_QSPI_DELAY * pfDelay;
FS_NAND_HW_TYPE_QSPI_LOCK * pfLock;
FS_NAND_HW_TYPE_QSPI_UNLOCK * pfUnlock;
FS_NAND_HW_TYPE_QSPI_READ_EX * pfReadEx;
} FS_NAND_HW_TYPE_QSPI;
Structure members
Member | Description |
pfInit | Initializes the hardware. |
pfExecCmd | Executes a command without data transfer. |
pfReadData | Transfers data from NAND flash device to MCU. |
pfWriteData | Transfers data from MCU to NAND flash device. |
pfPoll | Sends a command repeatedly and checks the response data for a specified condition. |
pfDelay | Blocks the execution for the specified number of milliseconds. |
pfLock | Requests exclusive access to SPI bus. |
pfUnlock | Releases the exclusive access of SPI bus. |
pfReadEx | Transfers data from NAND flash device to MCU. |
FS_NAND_HW_TYPE_QSPI_INIT
Description
Initializes the hardware.
Type definition
typedef int FS_NAND_HW_TYPE_QSPI_INIT(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Return value
Frequency of the QSPI clock in kHz.
Additional information
This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
This function has to configure anything necessary for the data transfer
via QSPI such as clocks, port pins, QSPI peripheral, DMA, etc.
The frequency value returned by the function has to be greater
than or equal to the actual clock frequency used to transfer
the data via QSPI. The FS_NAND_PHY_QSPI physical layer uses this value
to calculate the number of software cycles it has to wait for NAND flash
device to finish an operation before a timeout error is reported.
FS_NAND_HW_TYPE_QSPI_INIT must return 0 if the clock frequency is unknown.
In this case, the FS_NAND_PHY_QSPI physical layer waits indefinitely for
the end of a NAND flash operation and it never reports a timeout error.
FS_NAND_HW_TYPE_QSPI_CONTROL
Description
Executes a command without data transfer.
Type definition
typedef int FS_NAND_HW_TYPE_QSPI_CONTROL(U8 Unit,
U8 Cmd,
U8 BusWidth);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Cmd | Code of the command to be sent. |
BusWidth | Number of data lines to be used for sending the command code. |
Return value
= 0 | OK, command sent. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
FS_NAND_HW_TYPE_QSPI_CONTROL must to send a 8 bits to NAND flash
device containing the value specified via Cmd.
BusWidth specifies the number of data lines to be used when sending
the command code. Permitted values are:
- 1 for standard SPI
- 2 for quad SPI (2 data lines)
- 4 for quad SPI (4 data lines)
Please note that this is not an encoded value such as the value
passed via BusWidth in a call to FS_NAND_HW_TYPE_QSPI_READ,
FS_NAND_HW_TYPE_QSPI_WRITE or FS_NAND_HW_TYPE_QSPI_POLL.
FS_NAND_HW_TYPE_QSPI_READ
Description
Transfers data from NAND flash device to MCU.
Type definition
typedef int FS_NAND_HW_TYPE_QSPI_READ( U8 Unit,
U8 Cmd,
const U8 * pPara,
unsigned NumBytesPara,
unsigned NumBytesAddr,
U8 * pData,
unsigned NumBytesData,
U16 BusWidth);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Cmd | Code of the command to be sent. |
pPara | Additional command parameters (can be NULL). |
NumBytesPara | Number of additional bytes to be sent after command. Can be 0 if pPara is NULL. |
NumBytesAddr | Number of address bytes to be sent. Can be 0 if pPara is NULL. |
pData | Data received from the NAND flash device. |
NumBytesData | Number of bytes to be received from the NAND flash device. |
BusWidth | Specifies the number of data lines to be used during the data transfer. |
Return value
= 0 | OK, data transferred. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
The data has to be sent in this order: Cmd (1 byte) and pPara (NumBytesPara bytes).
The first NumBytesAddr bytes in pPara represent the address bytes while the
rest until NumBytesPara bytes are dummy bytes. These values are useful for
QSPI hardware that can differentiate between address and dummy bytes.
If NumBytesPara and NumBytesAddr are equal, no dummy bytes have to be sent.
NumBytesPara is never be smaller than NumBytesAddr. The data received from
NAND flash has to be stored to pData (NumBytesData bytes).
The number of data lines to be used during the data transfer
is specified via BusWidth. The value is encoded with each nibble (4 bits)
specifying the number of data lines for one part of the data transfer.
The macros SPI bus width decoding can be used to decode the number
of data lines of each part of the request (command and address)
and of the response (data). The dummy bytes have to be sent using
the number of data lines returned by FS_BUSWIDTH_GET_ADDR().
FS_NAND_HW_TYPE_QSPI_WRITE
Description
Transfers data from MCU to NAND flash device.
Type definition
typedef int FS_NAND_HW_TYPE_QSPI_WRITE( U8 Unit,
U8 Cmd,
const U8 * pPara,
unsigned NumBytesPara,
unsigned NumBytesAddr,
const U8 * pData,
unsigned NumBytesData,
U16 BusWidth);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Cmd | Code of the command to be sent. |
pPara | Additional command parameters (can be NULL). |
NumBytesPara | Number of additional bytes to be sent after command. Can be 0 if pPara is NULL. |
NumBytesAddr | Number of address bytes to be sent. Can be 0 if pPara is NULL. |
pData | Data to be sent to NAND flash device. |
NumBytesData | Number of data bytes to be sent to NAND flash device. |
BusWidth | Specifies the number of data lines to be used during the data transfer. |
Additional information
This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
The data has to be sent in this order: Cmd (1 byte), pPara (NumBytesPara bytes),
pData (NumBytesData bytes). The first NumBytesAddr bytes in pPara represent
the address bytes while the rest until NumBytesPara bytes are dummy bytes.
These values are useful for QSPI hardware that can differentiate between
address and dummy bytes. If NumBytesPara and NumBytesAddr are equal,
no dummy bytes have to be sent. NumBytesPara will never be smaller than NumBytesAddr.
The number of data lines to be used during the data transfer
is specified via BusWidth. The value is encoded with each nibble
specifying the number of data lines for one part of the data transfer.
The macros SPI bus width decoding can be used to decode the number
of data lines of each part of the request (command, address and data).
The dummy bytes have to be sent using the number of data lines returned
by FS_BUSWIDTH_GET_ADDR().
FS_NAND_HW_TYPE_QSPI_POLL
Description
Sends a command repeatedly and checks the response data for a specified condition.
Type definition
typedef int FS_NAND_HW_TYPE_QSPI_POLL( U8 Unit,
U8 Cmd,
const U8 * pPara,
unsigned NumBytesPara,
U8 BitPos,
U8 BitValue,
U32 Delay,
U32 TimeOut_ms,
U16 BusWidth);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Cmd | Code of the command to be sent. |
pPara | Additional command parameters (can be NULL). |
NumBytesPara | Number of additional bytes to be sent after command. Can be 0 if pPara is NULL. |
BitPos | Position of the bit inside response data that has to be checked (0-based, with 0 being LSB) |
BitValue | Bit value to wait for. |
Delay_ms | Time between two command executions. |
TimeOut_ms | Maximum time to wait for the bit at BitPos to be set to BitValue. |
BusWidth | Specifies how many data lines have to be used for sending the command and parameters and for reading the data. |
Return value
> 0 | Error, timeout occurred. |
= 0 | OK, bit set to specified value. |
< 0 | Error, feature not supported. |
Additional information
This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware
layer API. The implementation of this function is optional.
FS_NAND_HW_TYPE_QSPI_POLL is called by the QSPI NAND physical layer
when it has to wait for the NAND flash device to reach a certain status.
FS_NAND_HW_TYPE_QSPI_POLL has to read periodically a byte of data from
the NAND flash device until the value of the bit at BitPos in the
in the returned data byte is set to a value specified by BitValue.
The data is read by sending a command with a code specified
by Cmd followed by an optional number of additional bytes
specified by pPara and NumBytesPara. Then 8 bits of data are
transferred from NAND flash device to MCU and this the value
stores the bit to be checked.
The number of data lines to be used during the data transfer
is specified via BusWidth. The value is encoded with each nibble
specifying the number of data lines for one part of the data transfer.
The macros SPI bus width decoding can be used to decode the number
of data lines of each part of the request (command, parameters and data).
The pPara data has to be sent using the number of data lines returned
by FS_BUSWIDTH_GET_ADDR().
The time FS_NAND_HW_TYPE_QSPI_POLL waits for the condition to be true
shall not exceed the number of milliseconds specified by TimeOut_ms.
Delay_ms specifies the number of milliseconds that can elapse
between the execution of two consecutive commands.
FS_NAND_HW_TYPE_QSPI_DELAY
Description
Blocks the execution for the specified number of milliseconds.
Type definition
typedef void FS_NAND_HW_TYPE_QSPI_DELAY(U8 Unit,
int ms);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
ms | Number of milliseconds to wait. |
Additional information
This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
The time FS_NAND_HW_TYPE_QSPI_DELAY blocks does not have to be
accurate. That is the function can block the execution longer
that the number of specified milliseconds but no less than that.
FS_NAND_HW_TYPE_QSPI_LOCK
Description
Requests exclusive access to SPI bus.
Type definition
typedef void FS_NAND_HW_TYPE_QSPI_LOCK(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware
layer API. The implementation of this function is optional.
The FS_NAND_PHY_QSPI physical layer calls this function to indicate
that it needs exclusive to access the NAND flash device via the SPI bus.
It is guaranteed that the FS_NAND_PHY_QSPI physical layer does not attempt
to communicate via the SPI bus before calling this function first. It is also
guaranteed that FS_NAND_HW_TYPE_QSPI_LOCK and FS_NAND_HW_TYPE_QSPI_UNLOCK
are called in pairs.
FS_NAND_HW_TYPE_QSPI_UNLOCK and FS_NAND_HW_TYPE_QSPI_LOCK can be used to
synchronize the access to the SPI bus when other devices than the NAND flash
are connected to it. A possible implementation would make use of an
OS semaphore that is acquired in this function and released in
FS_NAND_HW_TYPE_QSPI_UNLOCK.
FS_NAND_HW_TYPE_QSPI_UNLOCK
Description
Releases the exclusive access of SPI bus.
Type definition
typedef void FS_NAND_HW_TYPE_QSPI_UNLOCK(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_HW_TYPE_QSPI NAND hardware
layer API. The implementation of this function is optional.
The FS_NAND_PHY_QSPI physical layer calls this function when it no
longer needs to access the NAND flash device via the SPI bus.
It is guaranteed that the FS_NAND_PHY_QSPI physical layer does not
attempt to communicate via the SPI bus before calling FS_NAND_HW_TYPE_QSPI_LOCK.
It is also guaranteed that FS_NAND_HW_TYPE_QSPI_UNLOCK and
FS_NAND_HW_TYPE_QSPI_LOCK are called in pairs.
FS_NAND_HW_TYPE_QSPI_UNLOCK and FS_NAND_HW_TYPE_QSPI_LOCK can be used to
synchronize the access to the SPI bus when other devices than the NAND flash
are connected to it. A possible implementation would make use of an
OS semaphore that is acquired in this function and released in
FS_NAND_HW_TYPE_QSPI_UNLOCK.
FS_NAND_HW_TYPE_QSPI_READ_EX
Description
Transfers data from serial NAND flash device to MCU.
Type definition
typedef int FS_NAND_HW_TYPE_QSPI_READ_EX( U8 Unit,
const U8 * pCmd,
unsigned NumBytesCmd,
const U8 * pPara,
unsigned NumBytesPara,
unsigned NumBytesAddr,
U8 * pData,
unsigned NumBytesData,
U16 BusWidth,
unsigned Flags);
Parameters
Parameter | Description |
Unit | Index of the hardware layer (0-based). |
pCmd | in Code of the command to be sent. Cannot be NULL. |
NumBytesCmd | Number of bytes in the command code. Cannot be 0. |
pPara | in Command parameters (address and dummy bytes). Can be NULL. |
NumBytesPara | Total number of address and dummy bytes to be sent. Can be 0. |
NumBytesAddr | Number of address bytes to be send. Can be 0. |
pData | out Data read from the serial NOR flash device. Can be NULL. |
NumBytesData | Number of bytes to read from the serial NOR flash device. Can be 0. |
BusWidth | Number of data lines to be used for the data transfer. |
Flags | Options for the data exchange. |
Return value
= 0 | OK, data transferred successfully. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the QSPI NAND hardware layer API. The implementation
of this function is optional. The function has to be implemented only by hardware
layers that have to be able to transfer the data in DTR mode.
If the hardware layer does not implement this function then FS_NAND_HW_TYPE_QSPI_READ
is called instead.
The first address byte is stored at *pPara. NumBytesAddr is always smaller
than or equal to NumBytesPara. If NumBytesAddr is equal to NumBytesPara then
no dummy bytes have to be sent. The number of dummy bytes to be generated can be calculated
as NumBytesPara - NumBytesAddr.
If the hardware generates dummy cycles instead of bytes then the number
of dummy bytes has to converted to clock cycles by taking into account the number
of data lines used for the data transfer of the address.
This function performs the same operation as FS_NAND_HW_TYPE_QSPI_READ
with the difference that it can handle multi-byte commands and additional
data transfer options specified via Flags. Flags is a bitwise-or combination
of NAND HW layer flags. In addition, this function is able to report an error
via the return value.
NAND HW layer flags
Description
Additional options for data exchanged via the QSPI NAND HW layer.
Definition
#define FS_NAND_HW_FLAG_DTR_DATA (1uL << 0)
#define FS_NAND_HW_FLAG_DTR_ADDR (1uL << 1)
Symbols
Definition | Description |
FS_NAND_HW_FLAG_DTR_DATA | Exchange the data on each clock transition. |
FS_NAND_HW_FLAG_DTR_ADDR | Send the address on each clock transition. |
SPI bus width decoding
Description
Macros for the handling of SPI bus width.
Definition
#define FS_BUSWIDTH_GET_CMD(BusWidth) (((BusWidth) >> FS_BUSWIDTH_CMD_SHIFT) & FS_BUSWIDTH_MASK)
#define FS_BUSWIDTH_GET_ADDR(BusWidth) (((BusWidth) >> FS_BUSWIDTH_ADDR_SHIFT) & FS_BUSWIDTH_MASK)
#define FS_BUSWIDTH_GET_DATA(BusWidth) (((BusWidth) >> FS_BUSWIDTH_DATA_SHIFT) & FS_BUSWIDTH_MASK)
Symbols
Definition | Description |
FS_BUSWIDTH_GET_CMD(BusWidth) | Returns the number of data lines to be used for sending the command code. |
FS_BUSWIDTH_GET_ADDR(BusWidth) | Returns the number of data lines to be used for sending the data address. |
FS_BUSWIDTH_GET_DATA(BusWidth) | Returns the number of data lines to be used for sending and receiving of the user data. |
Additional information
The functions of the FS_NOR_HW_TYPE_SPIFI NOR hardware layer
and of the FS_NAND_HW_TYPE_QSPI NAND hardware layer that exchange
data with the storage device take a parameter that specifies
how many data lines have to be used to send different parts
of a request and to receive the answer. The value of this
parameter is encoded as a 16-bit value and the macros in
this section can help extract the bus width value for a
specific part of the request and response.
The value is encoded as follows:
Bit range | Description |
0-3 | Number of data lines to be used to transfer the data. |
4-7 | Number of data lines to be used to transfer the address. |
8-11 | Number of data lines to be used to transfer the command. |
Sample implementation
The sample implementation listed below uses the QUADSPI controller of an ST STM32H743
MCU to interface with a serial NAND flash device. This NAND hardware layer was tested
on a SGGER internal test board.
/*********************************************************************
* (c) SEGGER Microcontroller GmbH *
* The Embedded Experts *
* www.segger.com *
**********************************************************************
-------------------------- END-OF-HEADER -----------------------------
File : FS_NAND_HW_QSPI_STM32H743_SEGGER_QSPI_Flash_Evaluator.c
Purpose : HW layer for quad and dual serial NAND flash for ST STM32H743.
Literature:
[1] RM0433 Reference manual STM32H7x3 advanced ARM-based 32-bit MCUs
[2] STM32H753xI Errata sheet STM32H753xI rev Y device limitations
*/
/*********************************************************************
*
* #include section
*
**********************************************************************
*/
#include "FS.h"
/*********************************************************************
*
* Defines, configurable
*
**********************************************************************
*/
#ifndef FS_NAND_HW_PER_CLK_HZ
#define FS_NAND_HW_PER_CLK_HZ 240000000 // Clock of Quad-SPI unit
#endif
#ifndef FS_NAND_HW_NAND_CLK_HZ
#define FS_NAND_HW_NAND_CLK_HZ 48000000 // Frequency of the clock
// supplied to NAND flash device
#endif
#ifndef FS_NAND_HW_CYCLES_PER_MS
#define FS_NAND_HW_CYCLES_PER_MS 150000 // Number of software loops
// create a 1ms delay
#endif
#ifndef FS_NAND_HW_USE_OS
#define FS_NAND_HW_USE_OS 0 // Enables/disables the interrupt-driven operation.
// Permitted values:
// 0 - polling via CPU
// 1 - event-driven using embOS
// 2 - event-driven using other RTOS
#endif
/*********************************************************************
*
* #include section, conditional
*
**********************************************************************
*/
#if FS_NAND_HW_USE_OS
#include "stm32h7xx.h"
#include "FS_OS.h"
#if (FS_NAND_HW_USE_OS == 1)
#include "RTOS.h"
#endif // FS_NAND_HW_USE_OS == 1
#endif // FS_NAND_HW_USE_OS
/*********************************************************************
*
* Defines, fixed
*
**********************************************************************
*/
/*********************************************************************
*
* QSPI registers
*/
#define QUADSPI_BASE_ADDR 0x52005000uL
#define QUADSPI_CR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x00))
#define QUADSPI_DCR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x04))
#define QUADSPI_SR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x08))
#define QUADSPI_FCR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x0C))
#define QUADSPI_DLR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x10))
#define QUADSPI_CCR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x14))
#define QUADSPI_AR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x18))
#define QUADSPI_ABR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x1C))
#define QUADSPI_DR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x20))
#define QUADSPI_DR_BYTE (*(volatile U8 *)(QUADSPI_BASE_ADDR + 0x20))
#define QUADSPI_PSMKR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x24))
#define QUADSPI_PSMAR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x28))
#define QUADSPI_PIR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x2C))
#define QUADSPI_LPTR (*(volatile U32 *)(QUADSPI_BASE_ADDR + 0x30))
/*********************************************************************
*
* Port B registers
*/
#define GPIOB_BASE_ADDR 0x58020400uL
#define GPIOB_MODER (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x00))
#define GPIOB_OSPEEDR (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x08))
#define GPIOB_PUPDR (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x0C))
#define GPIOB_ODR (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x14))
#define GPIOB_AFRL (*(volatile U32 *)(GPIOB_BASE_ADDR + 0x20))
/*********************************************************************
*
* Port F registers
*/
#define GPIOF_BASE_ADDR 0x58021400uL
#define GPIOF_MODER (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x00))
#define GPIOF_OSPEEDR (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x08))
#define GPIOF_PUPDR (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x0C))
#define GPIOF_ODR (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x14))
#define GPIOF_AFRL (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x20))
#define GPIOF_AFRH (*(volatile U32 *)(GPIOF_BASE_ADDR + 0x24))
/*********************************************************************
*
* Reset and clock control
*/
#define RCC_BASE_ADDR 0x58024400uL
#define RCC_AHB3RSTR (*(volatile U32*)(RCC_BASE_ADDR + 0x7C))
#define RCC_AHB3ENR (*(volatile U32*)(RCC_BASE_ADDR + 0xD4))
#define RCC_AHB4ENR (*(volatile U32*)(RCC_BASE_ADDR + 0xE0))
/*********************************************************************
*
* Masks for the peripheral enable bits
*/
#define AHB4ENR_GPIOBEN 1
#define AHB4ENR_GPIOFEN 5
#define AHB3ENR_QSPIEN 14
/*********************************************************************
*
* GPIO bit positions of SPI signals
*/
#define NAND_BK1_NCS_BIT 6 // Port B
#define NAND_CLK_BIT 10 // Port F
#define NAND_BK1_D0_BIT 8 // Port F
#define NAND_BK1_D1_BIT 9 // Port F
#define NAND_BK1_D2_BIT 7 // Port F
#define NAND_BK1_D3_BIT 6 // Port F
/*********************************************************************
*
* GPIO bits and masks
*/
#define OSPEEDR_HIGH 2uL
#define OSPEEDR_MASK 0x3uL
#define MODER_MASK 0x3uL
#define MODER_ALT 2uL
#define AFR_MASK 0xFuL
/*********************************************************************
*
* Quad-SPI control register
*/
#define CR_EN_BIT 0
#define CR_ABORT_BIT 1
#define CR_SMIE_BIT 19
#define CR_APMS_BIT 22
#define CR_PRESCALER_BIT 24
#define CR_PRESCALER_MAX 255
/*********************************************************************
*
* Quad-SPI device configuration register
*/
#define DCR_CKMODE_BIT 0
#define DCR_FSIZE_BIT 16
#define DCR_FSIZE_MAX 0x1FuL
/*********************************************************************
*
* Quad-SPI status register
*/
#define SR_TEF_BIT 0
#define SR_TCF_BIT 1
#define SR_SMF_BIT 3
#define SR_TOF_BIT 4
#define SR_BUSY_BIT 5
#define SR_FLEVEL_BIT 8
#define SR_FLEVEL_MASK 0x3FuL
/*********************************************************************
*
* Quad-SPI communication configuration register
*/
#define CCR_INTRUCTION_BIT 0
#define CCR_IMODE_BIT 8
#define CCR_MODE_NONE 0
#define CCR_MODE_SINGLE 1uL
#define CCR_MODE_DUAL 2uL
#define CCR_MODE_QUAD 3uL
#define CCR_ADMODE_BIT 10
#define CCR_ADSIZE_BIT 12
#define CCR_ADSIZE_MASK 0x03uL
#define CCR_ABMODE_BIT 14
#define CCR_ABSIZE_BIT 16
#define CCR_ABSIZE_MASK 0x03uL
#define CCR_DCYC_BIT 18
#define CCR_DMODE_BIT 24
#define CCR_FMODE_BIT 26
#define CCR_FMODE_WRITE 0x0uL
#define CCR_FMODE_READ 0x1uL
#define CCR_FMODE_POLL 0x2uL
#define CCR_FMODE_MMAP 0x3uL
#define CCR_FMODE_MASK 0x3uL
#define CCR_DDRM_BIT 31
/*********************************************************************
*
* Misc. defines
*/
#define NUM_BYTES_FIFO 32
#define WAIT_TIMEOUT_MS 500
#define WAIT_TIMEOUT_CYCLES (WAIT_TIMEOUT_MS * FS_NAND_HW_CYCLES_PER_MS)
#define QUADSPI_PRIO 15
/*********************************************************************
*
* ASSERT_IS_LOCKED
*/
#if FS_SUPPORT_TEST
#define ASSERT_IS_LOCKED() \
if (_LockCnt != 1) { \
FS_X_PANIC(FS_ERRCODE_INVALID_USAGE); \
}
#else
#define ASSERT_IS_LOCKED()
#endif
/*********************************************************************
*
* IF_TEST
*/
#if FS_SUPPORT_TEST
#define IF_TEST(Expr) Expr
#else
#define IF_TEST(Expr)
#endif
/*********************************************************************
*
* Static data
*
**********************************************************************
*/
#if FS_SUPPORT_TEST
static U8 _LockCnt = 0; // Just to test if the Lock()/Unlock
// function are called correctly.
#endif
/*********************************************************************
*
* Static code
*
**********************************************************************
*/
/*********************************************************************
*
* _CalcClockDivider
*/
static U8 _CalcClockDivider(U32 * pFreq_Hz) {
U8 Div;
U32 Freq_Hz;
U32 MaxFreq_Hz;
Div = 0;
MaxFreq_Hz = *pFreq_Hz;
for (;;) {
Freq_Hz = FS_NAND_HW_PER_CLK_HZ / (Div + 1);
if (Freq_Hz <= MaxFreq_Hz) {
break;
}
++Div;
if (Div == CR_PRESCALER_MAX) {
break;
}
}
*pFreq_Hz = Freq_Hz;
return Div;
}
/*********************************************************************
*
* _GetMode
*/
static U32 _GetMode(unsigned BusWidth, U32 NumBytes) {
U32 Mode;
Mode = CCR_MODE_NONE;
if (NumBytes) {
switch (BusWidth) {
case 1:
Mode = CCR_MODE_SINGLE;
break;
case 2:
Mode = CCR_MODE_DUAL;
break;
case 4:
Mode = CCR_MODE_QUAD;
break;
default:
break;
}
}
return Mode;
}
/*********************************************************************
*
* _CalcNumCycles
*
* Function description
* Calculates the number of clock cycles required to transfer a specified number of bytes.
*/
static U32 _CalcNumCycles(unsigned BusWidth, U32 NumBytes, int IsDTRMode) {
U32 NumCycles;
NumCycles = 0;
if (NumBytes != 0) {
NumCycles = NumBytes << 3; // Assume 8-bits per byte.
switch (BusWidth) {
case 2:
NumCycles >>= 1;
break;
case 4:
NumCycles >>= 2;
break;
default:
break;
}
if (IsDTRMode != 0) {
NumCycles >>= 1; // The data is sent on both clock edges.
}
}
return NumCycles;
}
/*********************************************************************
*
* _ClearFlags
*
* Function description
* Clears the status flags of QUADSPI peripheral.
*/
static int _ClearFlags(void) {
U32 TimeOut;
int r;
QUADSPI_FCR = 0
| (1uL << SR_TEF_BIT)
| (1uL << SR_TCF_BIT)
| (1uL << SR_SMF_BIT)
| (1uL << SR_TOF_BIT)
;
//
// Wait for the flags to be cleared.
//
r = 0;
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if ((QUADSPI_SR & ((1uL << SR_TEF_BIT) |
(1uL << SR_TCF_BIT) |
(1uL << SR_SMF_BIT) |
(1uL << SR_TOF_BIT))) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, could not clear flags.
break;
}
}
return r;
}
#if FS_NAND_HW_USE_OS
/*********************************************************************
*
* _Cancel
*
* Function description
* Interrupts an ongoing data transfer.
*/
static int _Cancel(void) {
U32 TimeOut;
int r;
r = 0;
TimeOut = WAIT_TIMEOUT_CYCLES;
QUADSPI_CR |= 1uL << CR_ABORT_BIT;
for (;;) {
if ((QUADSPI_CR & (1uL << CR_ABORT_BIT)) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, could not cancel data transfer.
break;
}
}
return r;
}
#endif // FS_NAND_HW_USE_OS
/*********************************************************************
*
* _Init
*
* Function description
* Initializes the QSPI hardware.
*/
static int _Init(void) {
U32 Div;
U32 Freq_Hz;
//
// Enable the clocks of peripherals and reset them.
//
RCC_AHB4ENR |= 0
| (1uL << AHB4ENR_GPIOBEN)
| (1uL << AHB4ENR_GPIOFEN)
;
RCC_AHB3ENR |= 1uL << AHB3ENR_QSPIEN;
RCC_AHB3RSTR |= 1uL << AHB3ENR_QSPIEN;
RCC_AHB3RSTR &= ~(1uL << AHB3ENR_QSPIEN);
//
// Wait for the unit to exit reset.
//
for (;;) {
if ((RCC_AHB3RSTR & (1uL << AHB3ENR_QSPIEN)) == 0) {
break;
}
}
//
// NCS of bank 1 is an output signal and is controlled by the QUADSPI unit.
//
GPIOB_MODER &= ~(MODER_MASK << (NAND_BK1_NCS_BIT << 1));
GPIOB_MODER |= MODER_ALT << (NAND_BK1_NCS_BIT << 1);
GPIOB_AFRL &= ~(AFR_MASK << (NAND_BK1_NCS_BIT << 2));
GPIOB_AFRL |= 0xAuL << (NAND_BK1_NCS_BIT << 2);
GPIOB_OSPEEDR &= ~(OSPEEDR_MASK << (NAND_BK1_NCS_BIT << 1));
GPIOB_OSPEEDR |= OSPEEDR_HIGH << (NAND_BK1_NCS_BIT << 1);
//
// CLK is an output signal controlled by the QUADSPI unit.
//
GPIOF_MODER &= ~(MODER_MASK << (NAND_CLK_BIT << 1));
GPIOF_MODER |= MODER_ALT << (NAND_CLK_BIT << 1);
GPIOF_AFRH &= ~(AFR_MASK << ((NAND_CLK_BIT - 8) << 2));
GPIOF_AFRH |= 0x9uL << ((NAND_CLK_BIT - 8) << 2);
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (NAND_CLK_BIT << 1));
GPIOF_OSPEEDR |= OSPEEDR_HIGH << (NAND_CLK_BIT << 1);
//
// D0 of bank 1 is an input/output signal controlled by the QUADSPI unit.
//
GPIOF_MODER &= ~(MODER_MASK << (NAND_BK1_D0_BIT << 1));
GPIOF_MODER |= MODER_ALT << (NAND_BK1_D0_BIT << 1);
GPIOF_AFRH &= ~(AFR_MASK << ((NAND_BK1_D0_BIT - 8) << 2));
GPIOF_AFRH |= 0xAuL << ((NAND_BK1_D0_BIT - 8) << 2);
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (NAND_BK1_D0_BIT << 1));
GPIOF_OSPEEDR |= OSPEEDR_HIGH << (NAND_BK1_D0_BIT << 1);
//
// D1 of bank 1 is an input/output signal controlled by the QUADSPI unit.
//
GPIOF_MODER &= ~(MODER_MASK << (NAND_BK1_D1_BIT << 1));
GPIOF_MODER |= MODER_ALT << (NAND_BK1_D1_BIT << 1);
GPIOF_AFRH &= ~(AFR_MASK << ((NAND_BK1_D1_BIT - 8) << 2));
GPIOF_AFRH |= 0xAuL << ((NAND_BK1_D1_BIT - 8) << 2);
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (NAND_BK1_D1_BIT << 1));
GPIOF_OSPEEDR |= OSPEEDR_HIGH << (NAND_BK1_D1_BIT << 1);
//
// D2 of bank 1 is an input/output signal and is controlled by the QUADSPI unit.
//
GPIOF_MODER &= ~(MODER_MASK << (NAND_BK1_D2_BIT << 1));
GPIOF_MODER |= MODER_ALT << (NAND_BK1_D2_BIT << 1);
GPIOF_AFRL &= ~(AFR_MASK << (NAND_BK1_D2_BIT << 2));
GPIOF_AFRL |= 0x9uL << (NAND_BK1_D2_BIT << 2);
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (NAND_BK1_D2_BIT << 1));
GPIOF_OSPEEDR |= OSPEEDR_HIGH << (NAND_BK1_D2_BIT << 1);
//
// D3 of bank 1 is an output signal and is controlled by the QUADSPI unit.
//
GPIOF_MODER &= ~(MODER_MASK << (NAND_BK1_D3_BIT << 1));
GPIOF_MODER |= MODER_ALT << (NAND_BK1_D3_BIT << 1);
GPIOF_AFRL &= ~(AFR_MASK << (NAND_BK1_D3_BIT << 2));
GPIOF_AFRL |= 0x9uL << (NAND_BK1_D3_BIT << 2);
GPIOF_OSPEEDR &= ~(OSPEEDR_MASK << (NAND_BK1_D3_BIT << 1));
GPIOF_OSPEEDR |= OSPEEDR_HIGH << (NAND_BK1_D3_BIT << 1);
#if FS_NAND_HW_USE_OS
//
// Disable the interrupt and configure the priority.
//
NVIC_DisableIRQ(QUADSPI_IRQn);
NVIC_SetPriority(QUADSPI_IRQn, QUADSPI_PRIO);
#endif // FS_NAND_HW_USE_OS
//
// Initialize the Quad-SPI controller.
//
Freq_Hz = FS_NAND_HW_NAND_CLK_HZ;
Div = (U32)_CalcClockDivider(&Freq_Hz);
QUADSPI_CR = 0
| (1uL << CR_EN_BIT) // Enable the Quad-SPI unit.
| (Div << CR_PRESCALER_BIT)
;
QUADSPI_DCR = 0
| (1uL << DCR_CKMODE_BIT) // CLK signal stays HIGH
// when the NAND flash is not selected.
| (DCR_FSIZE_MAX << DCR_FSIZE_BIT) // We set the NAND flash size to maximum
// since the actual value is not known
// at this stage.
;
#if FS_NAND_HW_USE_OS
//
// Clear interrupt flags and enable the interrupt.
//
QUADSPI_CR |= 0
| (1uL << CR_SMIE_BIT)
| (1uL << CR_APMS_BIT)
;
QUADSPI_FCR = 1uL << SR_SMF_BIT;
NVIC_EnableIRQ(QUADSPI_IRQn);
#endif // FS_NAND_HW_USE_OS
return (int)Freq_Hz / 1000;
}
/*********************************************************************
*
* _Control
*
* Function description
* Executes a NAND flash command without data transfer.
*/
static int _Control(U8 Cmd, U8 BusWidth) {
U32 CfgReg;
U32 CmdMode;
U32 TimeOut;
int r;
//
// Initialize local variables.
//
r = 0;
CmdMode = _GetMode(BusWidth, sizeof(Cmd));
CfgReg = 0
| (CCR_FMODE_WRITE << CCR_FMODE_BIT)
| (CmdMode << CCR_IMODE_BIT)
| (Cmd << CCR_INTRUCTION_BIT)
;
//
// Wait until the unit is ready for the new command.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, QUADSPI is not ready.
goto Done;
}
}
//
// Execute the command.
//
QUADSPI_DLR = 0;
QUADSPI_ABR = 0;
QUADSPI_CCR = CfgReg;
//
// Wait until the command has been completed.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, QUADSPI is not ready.
break;
}
}
Done:
return r;
}
/*********************************************************************
*
* _Read
*
* Function description
* Transfers data from NAND flash device to MCU.
*/
static int _Read(const U8 * pCmd, unsigned NumBytesCmd, const U8 * pPara,
unsigned NumBytesPara, unsigned NumBytesAddr, U8 * pData,
unsigned NumBytesData, U16 BusWidth, unsigned Flags) {
U32 AddrReg;
U32 AltReg;
U32 CfgReg;
U32 DataMode;
U32 AddrMode;
U32 CmdMode;
U32 DataReg;
U32 NumCyclesDummy;
U32 AddrSize;
U32 NumBytesAvail;
U32 NumBytes;
U32 NumBytesDummy;
U32 TimeOut;
int r;
U32 IsDTR;
U32 Cmd;
FS_DEBUG_ASSERT(FS_MTYPE_DRIVER, NumBytesCmd == 1u); // This QSPI controller is able to handle only 1-byte commands.
//
// Initialize local variables.
//
r = 0;
AddrReg = 0;
AltReg = 0;
NumBytesDummy = NumBytesPara - NumBytesAddr;
Cmd = *pCmd;
//
// Calculate the transfer mode.
//
IsDTR = 0;
if ( ((Flags & FS_NAND_HW_FLAG_DTR_ADDR) != 0u)
|| ((Flags & FS_NAND_HW_FLAG_DTR_DATA) != 0u)) {
IsDTR = 1;
}
//
// Calculate the number of data lines to be used for the transfer.
//
CmdMode = _GetMode(FS_BUSWIDTH_GET_CMD(BusWidth), NumBytesCmd);
AddrMode = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAddr);
NumCyclesDummy = _CalcNumCycles(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesDummy, IsDTR); // The dummy bytes are sent using the address bus mode.
DataMode = _GetMode(FS_BUSWIDTH_GET_DATA(BusWidth), NumBytesData);
//
// Encode the address.
//
if (NumBytesAddr) {
NumBytes = NumBytesAddr;
do {
AddrReg <<= 8;
AddrReg |= (U32)(*pPara++);
} while (--NumBytes);
}
AddrSize = 0;
if (NumBytesAddr) {
AddrSize = (NumBytesAddr - 1) & CCR_ADSIZE_MASK;
}
CfgReg = 0
| (CCR_FMODE_READ << CCR_FMODE_BIT)
| (DataMode << CCR_DMODE_BIT)
| (NumCyclesDummy << CCR_DCYC_BIT)
| (IsDTR << CCR_DDRM_BIT)
| (AddrSize << CCR_ADSIZE_BIT)
| (AddrMode << CCR_ADMODE_BIT)
| (CmdMode << CCR_IMODE_BIT)
| (Cmd << CCR_INTRUCTION_BIT)
;
//
// Wait until the unit is ready for the new command.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, QUADSPI is not ready.
goto Done;
}
}
//
// Execute the command.
//
r = _ClearFlags();
if (r != 0) {
goto Done;
}
if (NumBytesData) {
QUADSPI_DLR = NumBytesData - 1; // 0 means "read 1 byte".
}
QUADSPI_ABR = AltReg;
QUADSPI_CCR = CfgReg;
if (NumBytesAddr) {
QUADSPI_AR = AddrReg;
}
//
// Read data from NOR flash.
//
if (NumBytesData) {
do {
//
// Wait for the data to be received.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
NumBytesAvail = (QUADSPI_SR >> SR_FLEVEL_BIT) & SR_FLEVEL_MASK;
if ((NumBytesAvail >= 4) || (NumBytesAvail >= NumBytesData)) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, no data received.
goto Done;
}
}
//
// Read data and store it to destination buffer.
//
if (NumBytesData < 4) {
//
// Read single bytes.
//
do {
*pData++ = QUADSPI_DR_BYTE;
} while (--NumBytesData);
} else {
//
// Read 4 bytes at a time.
//
DataReg = QUADSPI_DR;
*pData++ = (U8)DataReg;
*pData++ = (U8)(DataReg >> 8);
*pData++ = (U8)(DataReg >> 16);
*pData++ = (U8)(DataReg >> 24);
NumBytesData -= 4;
}
} while (NumBytesData);
}
//
// Wait until the data transfer has been completed.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if (QUADSPI_SR & (1uL << SR_TCF_BIT)) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, transaction not completed.
break;
}
}
Done:
return r;
}
/*********************************************************************
*
* _Write
*
* Function description
* Transfers data from MCU to NAND flash device.
*/
static int _Write(U8 Cmd, const U8 * pPara, unsigned NumBytesPara,
unsigned NumBytesAddr, const U8 * pData, unsigned NumBytesData,
U16 BusWidth) {
U32 AddrReg;
U32 AltReg;
U32 CfgReg;
U32 DataMode;
U32 AddrMode;
U32 CmdMode;
U32 DataReg;
U32 AddrSize;
U32 NumCyclesDummy;
U32 NumBytes;
U32 NumBytesDummy;
U32 NumBytesFree;
U32 TimeOut;
int r;
//
// Initialize local variables.
//
r = 0;
AddrReg = 0;
AltReg = 0;
NumBytesDummy = NumBytesPara - NumBytesAddr;
CmdMode = _GetMode(FS_BUSWIDTH_GET_CMD(BusWidth), sizeof(Cmd));
AddrMode = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAddr);
NumCyclesDummy = _CalcNumCycles(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesDummy, 0); // The dummy bytes are sent using the address bus mode.
DataMode = _GetMode(FS_BUSWIDTH_GET_DATA(BusWidth), NumBytesData);
//
// Encode the address.
//
if (NumBytesAddr) {
NumBytes = NumBytesAddr;
do {
AddrReg <<= 8;
AddrReg |= (U32)(*pPara++);
} while (--NumBytes);
}
AddrSize = 0;
if (NumBytesAddr) {
AddrSize = NumBytesAddr - 1;
}
CfgReg = 0
| (CCR_FMODE_WRITE << CCR_FMODE_BIT)
| (DataMode << CCR_DMODE_BIT)
| (NumCyclesDummy << CCR_DCYC_BIT)
| (AddrSize << CCR_ADSIZE_BIT)
| (AddrMode << CCR_ADMODE_BIT)
| (CmdMode << CCR_IMODE_BIT)
| (Cmd << CCR_INTRUCTION_BIT)
;
//
// Wait until the unit is ready for the new command.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, QUADSPI is not ready.
goto Done;
}
}
//
// Execute the command.
//
r = _ClearFlags();
if (r != 0) {
goto Done;
}
if (NumBytesData) {
QUADSPI_DLR = NumBytesData - 1; // 0 means "read 1 byte".
}
QUADSPI_ABR = AltReg;
QUADSPI_CCR = CfgReg;
if (NumBytesAddr) {
QUADSPI_AR = AddrReg;
}
//
// write data to NOR flash.
//
if (NumBytesData) {
do {
//
// Wait for free space in FIFO.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
NumBytesFree = (QUADSPI_SR >> SR_FLEVEL_BIT) & SR_FLEVEL_MASK;
NumBytesFree = NUM_BYTES_FIFO - NumBytesFree;
if ((NumBytesFree >= 4) || (NumBytesFree >= NumBytesData)) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, no free space in FIFO.
goto Done;
}
}
//
// Get the data from source buffer and write it.
//
if (NumBytesData < 4) {
//
// Write single bytes.
//
do {
QUADSPI_DR_BYTE = *pData++;
} while (--NumBytesData);
} else {
//
// Write 4 bytes at a time if possible.
//
DataReg = (U32)*pData++;
DataReg |= (U32)*pData++ << 8;
DataReg |= (U32)*pData++ << 16;
DataReg |= (U32)*pData++ << 24;
NumBytesData -= 4;
QUADSPI_DR = DataReg;
}
} while (NumBytesData);
}
//
// Wait until the data transfer has been completed.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if (QUADSPI_SR & (1uL << SR_TCF_BIT)) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, transfer not completed.
break;
}
}
Done:
return r;
}
/*********************************************************************
*
* _Delay
*
* Function description
* Blocks the execution for the specified number of milliseconds.
*/
static void _Delay(int ms) {
#if FS_NAND_HW_USE_OS
if (ms) {
FS_OS_Delay(ms);
}
#else
if (ms) {
volatile U32 NumCycles;
do {
NumCycles = FS_NAND_HW_CYCLES_PER_MS;
do {
;
} while (--NumCycles);
} while (--ms);
}
#endif // FS_NAND_HW_USE_OS
}
#if FS_NAND_HW_USE_OS
/*********************************************************************
*
* _Poll
*
* Function description
* Checks periodically the value of a status flag.
*
* Parameters
* Cmd Code of the command to be sent. Cannot be NULL.
* pPara [IN] Command parameters (address and dummy bytes). Can be NULL.
* NumBytesPara Total number of address and dummy bytes to be sent. Can be 0.
* NumBytesAddr Number of address bytes to be send. Can be 0.
* BitPos Position of the bit to be checked.
* BitValue Value of the bit to wait for.
* Delay Number of clock cycles to wait between two queries.
* TimeOut_ms Maximum number of milliseconds to wait for the bit to be set.
* BusWidth Number of data lines to be used for the data transfer.
*
* Return value
* > 0 Timeout occurred.
* ==0 OK, bit set to specified value.
* < 0 Feature not supported.
*/
static int _Poll(U8 Cmd, const U8 * pPara, unsigned NumBytesPara, unsigned NumBytesAddr, U8 BitPos, U8 BitValue, U32 Delay, U32 TimeOut_ms, U16 BusWidth) {
U32 CfgReg;
U32 DataMode;
U32 CmdMode;
U32 NumBytes;
U32 NumBytesData;
U32 DataMask;
U32 DataMatch;
U32 AddrReg;
U32 AltReg;
U32 NumBytesDummy;
U32 AddrMode;
U32 AddrSize;
U32 NumCyclesDummy;
U32 TimeOut;
int r;
//
// Initialize local variables.
//
r = 0;
AddrReg = 0;
AltReg = 0;
DataMask = 1uL << BitPos;
DataMatch = (U32)BitValue << BitPos;
Delay <<= 4; // 16 clock cycles are required to transfer 2 bytes.
NumBytesData = 1; // The response consists of only one byte.
NumBytesDummy = NumBytesPara - NumBytesAddr;
//
// Encode the address.
//
if (NumBytesAddr) {
NumBytes = NumBytesAddr;
do {
AddrReg <<= 8;
AddrReg |= (U32)(*pPara++);
} while (--NumBytes);
}
//
// Calculate the number of data lines to be used for the transfer.
//
CmdMode = _GetMode(FS_BUSWIDTH_GET_CMD(BusWidth), sizeof(Cmd));
AddrMode = _GetMode(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesAddr);
NumCyclesDummy = _CalcNumCycles(FS_BUSWIDTH_GET_ADDR(BusWidth), NumBytesDummy, 0); // The dummy bytes are sent using the address bus mode.
DataMode = _GetMode(FS_BUSWIDTH_GET_DATA(BusWidth), NumBytesData);
//
// Calculate the number of bytes in each command phase.
//
AddrSize = 0;
if (NumBytesAddr) {
AddrSize = (NumBytesAddr - 1) & CCR_ADSIZE_MASK;
}
//
// Configure the operation.
//
CfgReg = 0
| (CCR_FMODE_POLL << CCR_FMODE_BIT)
| (AddrMode << CCR_ADMODE_BIT)
| (AddrSize << CCR_ADSIZE_BIT)
| (DataMode << CCR_DMODE_BIT)
| (NumCyclesDummy << CCR_DCYC_BIT)
| (CmdMode << CCR_IMODE_BIT)
| (Cmd << CCR_INTRUCTION_BIT)
;
//
// Wait until the unit is ready for the new command.
//
TimeOut = WAIT_TIMEOUT_CYCLES;
for (;;) {
if ((QUADSPI_SR & (1uL << SR_BUSY_BIT)) == 0) {
break;
}
if (--TimeOut == 0u) {
r = 1; // Error, QUADSPI is not ready.
goto Done;
}
}
//
// Start the poll operation. The end of operation is signaled by interrupt.
//
r = _ClearFlags();
if (r != 0) {
goto Done; // Error, could not clear status flags.
}
if (NumBytesData != 0) {
QUADSPI_DLR = NumBytesData - 1; // 0 means "read 1 byte".
}
QUADSPI_ABR = AltReg;
QUADSPI_PSMKR = DataMask;
QUADSPI_PSMAR = DataMatch;
QUADSPI_PIR = Delay;
QUADSPI_FCR = 1uL << SR_SMF_BIT;
QUADSPI_CCR = CfgReg;
if (NumBytesAddr != 0u) {
QUADSPI_AR = AddrReg;
}
r = FS_OS_Wait(TimeOut_ms);
if (r != 0) {
//
// The timeout has expired. Cancel the poll operation.
//
(void)_Cancel();
r = 1; // A timeout occurred.
}
Done:
return r;
}
#endif // FS_NAND_HW_USE_OS
/*********************************************************************
*
* Static code (public via callback)
*
**********************************************************************
*/
/*********************************************************************
*
* _HW_Init
*
* Function description
* Initializes the QSPI hardware.
*
* Parameters
* Unit Device index (0-based)
*
* Return value
* Frequency of the QSPI clock in kHz.
*/
static int _HW_Init(U8 Unit) {
int r;
FS_USE_PARA(Unit);
r = _Init();
return r;
}
/*********************************************************************
*
* _HW_Control
*
* Function description
* Executes a NAND flash command without data transfer.
*
* Parameters
* Unit Device index (0-based)
* Cmd Code of the command to be sent.
* BusWidth Number of data lines to be used for sending
* the command code.
*
* Return value
* ==0 OK, command sent.
* !=0 An error occurred.
*/
static int _HW_Control(U8 Unit, U8 Cmd, U8 BusWidth) {
int r;
ASSERT_IS_LOCKED();
FS_USE_PARA(Unit); // This device has only one HW unit.
r = _Control(Cmd, BusWidth);
return r;
}
/*********************************************************************
*
* _HW_Read
*
* Function description
* Transfers data from NAND flash device to MCU.
*
* Parameters
* Unit Device index (0-based)
* Cmd Code of the command to be sent.
* pPara Additional command parameters (can be NULL).
* NumBytesPara Number of additional bytes to be sent after command.
* Can be 0 if pPara is NULL.
* NumBytesAddr Number of address bytes to be sent.
* Can be 0 if pPara is NULL.
* pData Data received from the NAND flash device.
* NumBytesData Number of bytes to be received from the NAND flash device.
* BusWidth Specifies the number of data lines to be used
* during the data transfer.
*
* Return value
* ==0 OK, data transferred.
* !=0 An error occurred.
*/
static int _HW_Read(U8 Unit, U8 Cmd, const U8 * pPara, unsigned NumBytesPara,
unsigned NumBytesAddr, U8 * pData, unsigned NumBytesData,
U16 BusWidth) {
int r;
ASSERT_IS_LOCKED();
FS_USE_PARA(Unit); // This device has only one HW unit.
r = _Read(&Cmd, sizeof(Cmd), pPara, NumBytesPara, NumBytesAddr, pData, NumBytesData, BusWidth, 0);
return r;
}
/*********************************************************************
*
* _HW_Write
*
* Function description
* Transfers data from MCU to NAND flash device.
*
* Parameters
* Unit Device index (0-based)
* Cmd Code of the command to be sent.
* pPara Additional command parameters (can be NULL).
* NumBytesPara Number of additional bytes to be sent after command.
* Can be 0 if pPara is NULL.
* NumBytesAddr Number of address bytes to be sent.
* Can be 0 if pPara is NULL.
* pData Data to be sent to NAND flash device.
* NumBytesData Number of data bytes to be sent to NAND flash device.
* BusWidth Specifies the number of data lines to be used
* during the data transfer.
*
* Return value
* ==0 OK, data transferred.
* !=0 An error occurred.
*/
static int _HW_Write(U8 Unit, U8 Cmd, const U8 * pPara, unsigned NumBytesPara,
unsigned NumBytesAddr, const U8 * pData, unsigned NumBytesData,
U16 BusWidth) {
int r;
ASSERT_IS_LOCKED();
FS_USE_PARA(Unit); // This device has only one HW unit.
r = _Write(Cmd, pPara, NumBytesPara, NumBytesAddr, pData, NumBytesData, BusWidth);
return r;
}
/*********************************************************************
*
* _HW_Delay
*
* Function description
* Blocks the execution for the specified number of milliseconds.
*
* Parameters
* Unit Device index (0-based)
* ms Number of milliseconds to wait.
*
* Additional information
* This function is mandatory and it has to be implemented by any
* hardware layer.
*/
static void _HW_Delay(U8 Unit, int ms) {
FS_USE_PARA(Unit);
_Delay(ms);
}
/*********************************************************************
*
* _HW_Poll
*
* Function description
* Sends a command repeatedly and checks the response data
* for a specified condition.
*
* Parameters
* Unit Device index (0-based)
* Cmd Code of the command to be sent.
* pPara Additional command parameters (can be NULL).
* NumBytesPara Number of additional bytes to be sent after command.
* Can be 0 if pPara is NULL.
* BitPos Position of the bit inside response data that has
* to be checked (0-based, with 0 being LSB)
* BitValue Bit value to wait for.
* Delay_ms Time between two command executions.
* TimeOut_ms Maximum time to wait for the bit at BitPos to be set to BitValue.
* BusWidth Specifies how many data lines have to be used for sending
* the command and parameters and for reading the data.
*
* Return value
* > 0 Error, timeout occurred.
* ==0 OK, bit set to specified value.
* < 0 Error, feature not supported.
*/
static int _HW_Poll(U8 Unit, U8 Cmd, const U8 * pPara, unsigned NumBytesPara,
U8 BitPos, U8 BitValue, U32 Delay_ms, U32 TimeOut_ms, U16 BusWidth) {
int r;
ASSERT_IS_LOCKED();
FS_USE_PARA(Unit); // This device has only one HW unit.
#if FS_NAND_HW_USE_OS
r = _Poll(Cmd, pPara, NumBytesPara, NumBytesPara, BitPos, BitValue, Delay_ms, TimeOut_ms, BusWidth);
#else
FS_USE_PARA(Cmd);
FS_USE_PARA(pPara);
FS_USE_PARA(NumBytesPara);
FS_USE_PARA(BitPos);
FS_USE_PARA(BitValue);
FS_USE_PARA(Delay_ms);
FS_USE_PARA(TimeOut_ms);
FS_USE_PARA(BusWidth);
r = -1; // Set to indicate that the feature is not supported.
#endif // FS_NAND_HW_USE_OS
return r;
}
/*********************************************************************
*
* _HW_ReadEx
*
* Function description
* Transfers data from serial NAND flash device to MCU.
*
* Parameters
* Unit Index of the hardware layer (0-based).
* pCmd [IN] Code of the command to be sent. Cannot be NULL.
* NumBytesCmd Number of bytes in the command code. Cannot be 0.
* pPara [IN] Command parameters (address and dummy bytes). Can be NULL.
* NumBytesPara Total number of address and dummy bytes to be sent. Can be 0.
* NumBytesAddr Number of address bytes to be send. Can be 0.
* pData [OUT] Data read from the serial NOR flash device. Can be NULL.
* NumBytesData Number of bytes to read from the serial NOR flash device. Can be 0.
* BusWidth Number of data lines to be used for the data transfer.
* Flags Options for the data exchange.
*
* Return value
* ==0 OK, data transferred successfully.
* !=0 An error occurred.
*/
static int _HW_ReadEx(U8 Unit, const U8 * pCmd, unsigned NumBytesCmd, const U8 * pPara,
unsigned NumBytesPara, unsigned NumBytesAddr, U8 * pData,
unsigned NumBytesData, U16 BusWidth, unsigned Flags) {
int r;
ASSERT_IS_LOCKED();
FS_USE_PARA(Unit); // This device has only one HW unit.
r = _Read(pCmd, NumBytesCmd, pPara, NumBytesPara, NumBytesAddr, pData, NumBytesData, BusWidth, Flags);
return r;
}
/*********************************************************************
*
* _HW_Lock
*
* Function description
* Requests exclusive access to SPI bus.
*
* Parameters
* Unit Device index (0-based)
*
* Additional information
* This function is optional and it can be left unimplemented
* or set to NULL in the structure of the hardware layer below.
*/
static void _HW_Lock(U8 Unit) {
FS_USE_PARA(Unit);
IF_TEST(_LockCnt++);
ASSERT_IS_LOCKED();
}
/*********************************************************************
*
* _HW_Unlock
*
* Function description
* Releases the exclusive access of SPI bus.
*
* Parameters
* Unit Device index (0-based)
*
* Additional information
* This function is optional and it can be left unimplemented
* or set to NULL in the structure of the hardware layer below.
*/
static void _HW_Unlock(U8 Unit) {
FS_USE_PARA(Unit);
ASSERT_IS_LOCKED();
IF_TEST(_LockCnt--);
}
/*********************************************************************
*
* Public code
*
**********************************************************************
*/
#if FS_NAND_HW_USE_OS
/*********************************************************************
*
* QUADSPI_IRQHandler
*/
void QUADSPI_IRQHandler(void);
void QUADSPI_IRQHandler(void) {
#if (FS_NAND_HW_USE_OS == 1)
OS_EnterNestableInterrupt();
#endif // FS_NOR_HW_USE_OS == 1
QUADSPI_FCR = 1uL << SR_SMF_BIT; // Prevent other interrupts from occurring.
FS_OS_Signal();
#if (FS_NAND_HW_USE_OS == 1)
OS_LeaveNestableInterrupt();
#endif // FS_NAND_HW_USE_OS == 1
}
#endif // FS_NOR_HW_USE_OS
/*********************************************************************
*
* Public const
*
**********************************************************************
*/
/*********************************************************************
*
* FS_NAND_HW_QSPI_STM32H743_SEGGER_QSPI_Flash_Evaluator
*/
const FS_NAND_HW_TYPE_QSPI FS_NAND_HW_QSPI_STM32H743_SEGGER_QSPI_Flash_Evaluator = {
_HW_Init,
_HW_Control,
_HW_Read,
_HW_Write,
_HW_Poll,
_HW_Delay,
_HW_Lock,
_HW_Unlock,
_HW_ReadEx
};
/*************************** End of file ****************************/
Hardware layer API - FS_NAND_HW_TYPE_SPI
This hardware layer supports any serial NAND flash device with a standard SPI.
It is used by the FS_NAND_PHY_SPI physical layer to exchange data with a NAND flash device
that supports such an interface.
Typically, the implementation of FS_NAND_HW_TYPE_SPI hardware layer makes use of a SPI
controller. It is also possible to implement the data exchange via GPIO pins.
The functions of this hardware layer are grouped in the structure of type
FS_NAND_HW_TYPE_SPI. The following sections describe these functions in detail.
FS_NAND_HW_TYPE_SPI
Description
NAND hardware layer API for NAND flash devices connected via SPI.
Type definition
typedef struct {
FS_NAND_HW_TYPE_SPI_INIT * pfInit;
FS_NAND_HW_TYPE_SPI_DISABLE_CS * pfDisableCS;
FS_NAND_HW_TYPE_SPI_ENABLE_CS * pfEnableCS;
FS_NAND_HW_TYPE_SPI_DELAY * pfDelay;
FS_NAND_HW_TYPE_SPI_READ * pfRead;
FS_NAND_HW_TYPE_SPI_WRITE * pfWrite;
FS_NAND_HW_TYPE_SPI_LOCK * pfLock;
FS_NAND_HW_TYPE_SPI_UNLOCK * pfUnlock;
} FS_NAND_HW_TYPE_SPI;
Structure members
Member | Description |
pfInit | Initializes the hardware. |
pfDisableCS | Disables the NAND flash device. |
pfEnableCS | Enables the NAND flash device. |
pfDelay | Block the execution for a specified number of milliseconds. |
pfRead | Transfers a specified number of bytes from NAND flash device to MCU. |
pfWrite | Transfers a specified number of bytes from MCU to NAND flash device. |
pfLock | Request exclusive access to SPI bus. |
pfUnlock | Releases the exclusive access to SPI bus. |
FS_NAND_HW_TYPE_SPI_INIT
Description
Initializes the hardware.
Type definition
typedef int FS_NAND_HW_TYPE_SPI_INIT(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Return value
≠ 0 | OK, frequency of the SPI clock in kHz. |
= 0 | An error occurred. |
Additional information
This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type. FS_NAND_HW_TYPE_SPI_INIT is the first function
of the hardware layer API that is called by a NAND physical layer
during the mounting of the file system.
This function has to perform any initialization of the MCU hardware
required to access the NAND flash device such as clocks, port pins,
SPI controllers, etc.
A serial NAND flash requires that the SPI communication protocol meets the
following requirements:
- 8-bit data length.
- The most significant bit hast to be sent out first.
- Chip Select (CS) signal should be initially high to disable the serial NAND flash device.
- The SPI clock frequency does not have to exceed the maximum
clock frequency that is specified by the serial NAND flash device.
Typically, two SPI modes are supported:
- Mode 0 - CPOL = 0, CPHA = 0, SPI clock remains low in idle state.
- Mode 3 - CPOL = 1, CPHA = 1, SPI clock remains high in idle state.
FS_NAND_HW_TYPE_SPI_DISABLE_CS
Description
Disables the NAND flash device.
Type definition
typedef void FS_NAND_HW_TYPE_SPI_DISABLE_CS(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
The NAND flash device is disabled by driving the Chip Select (CS)
signal to logic-high. The NAND flash device ignores any command
or data sent with the CS signal set to logic-high.
FS_NAND_HW_TYPE_SPI_ENABLE_CS
Description
Enables the NAND flash device.
Type definition
typedef void FS_NAND_HW_TYPE_SPI_ENABLE_CS(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
The NAND flash device is enabled by driving the Chip Select (CS)
signal to logic low state. Typically, the NAND flash device is enabled
at the beginning of command and data sequence and disabled at the
end of it.
FS_NAND_HW_TYPE_SPI_DELAY
Description
Blocks the execution for the specified number of milliseconds.
Type definition
typedef void FS_NAND_HW_TYPE_SPI_DELAY(U8 Unit,
int ms);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
ms | Number of milliseconds to wait. |
Additional information
This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
The time FS_NAND_HW_TYPE_SPI_DELAY blocks does not have to be
accurate. That is the function can block the execution longer
that the number of specified milliseconds but no less than that.
FS_NAND_HW_TYPE_SPI_READ
Description
Transfers a specified number of bytes from NAND flash device to MCU.
Type definition
typedef int FS_NAND_HW_TYPE_SPI_READ(U8 Unit,
void * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
pData | Data read from NAND flash device. |
NumBytes | Number of bytes to be read. |
Return value
= 0 | OK, data read successfully. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
The function has to sample the data on the falling edge of the SPI clock.
FS_NAND_HW_TYPE_SPI_WRITE
Description
Transfers a specified number of bytes from MCU to NAND flash device.
Type definition
typedef int FS_NAND_HW_TYPE_SPI_WRITE( U8 Unit,
const void * pData,
unsigned NumBytes);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
pData | in Data to be written to NAND flash device. |
NumBytes | Number of bytes to be written. |
Return value
= 0 | OK, data written successfully. |
≠ 0 | An error occurred. |
Additional information
This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware
layer API. It is mandatory to be implemented by all the NAND hardware
layers of this type.
The NAND flash device samples the data on the rising edge of the SPI clock.
FS_NAND_HW_TYPE_SPI_LOCK
Description
Requests exclusive access to SPI bus.
Type definition
typedef void FS_NAND_HW_TYPE_SPI_LOCK(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware
layer API. The implementation of this function is optional.
The FS_NAND_PHY_SPI physical layer calls this function to indicate
that it needs exclusive to access the serial NAND flash device via the SPI bus.
It is guaranteed that the FS_NAND_PHY_SPI physical layer does not attempt
to exchange any data with the serial NAND flash device via the SPI bus before
calling this function first. It is also guaranteed that FS_NAND_HW_TYPE_SPI_LOCK
and FS_NAND_HW_TYPE_SPI_UNLOCK are called in pairs. Typically, this function
is used for synchronizing the access to SPI bus when the SPI bus is shared
between the serial NAND flash and other SPI devices.
A possible implementation would make use of an OS semaphore that is
acquired in FS_NAND_HW_TYPE_SPI_LOCK and released in FS_NAND_HW_TYPE_SPI_UNLOCK.
FS_NAND_HW_TYPE_SPI_UNLOCK
Description
Releases the exclusive access of SPI bus.
Type definition
typedef void FS_NAND_HW_TYPE_SPI_UNLOCK(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the NAND hardware layer instance (0-based) |
Additional information
This function is a member of the FS_NAND_HW_TYPE_SPI NAND hardware
layer API. The implementation of this function is optional.
The FS_NAND_PHY_SPI physical layer calls this function after it no
longer needs to access the serial NAND flash device via the SPI bus.
It is guaranteed that the FS_NAND_PHY_SPI physical layer does not
attempt to exchange any data with the serial NAND flash device via
the SPI bus before calling FS_NAND_HW_TYPE_SPI_LOCK.
It is also guaranteed that FS_NAND_HW_TYPE_SPI_UNLOCK and
FS_NAND_HW_TYPE_SPI_LOCK are called in pairs.
FS_NAND_HW_TYPE_SPI_UNLOCK and FS_NAND_HW_TYPE_SPI_LOCK can be used to
synchronize the access to the SPI bus when other devices than the
serial NAND flash are connected to it. A possible implementation would
make use of an OS semaphore that is acquired FS_NAND_HW_TYPE_SPI_LOCK
and released in FS_NAND_HW_TYPE_SPI_UNLOCK.
Test hardware
The SEGGER NAND-Flash EVAL board is an easy to use and cost effective testing
tool designed to evaluate the features and the performance of the emFile
NAND driver.
The NAND driver can be used with emFile or emUSB-Device, in which case the board
behaves like a mass storage device (USB drive).
Common evaluation boards are usually used to perform these tests but this approach
brings several disadvantages. Software and hardware development tools are required
to build and load the application into the target system. Moreover, the tests are
restricted to the type of NAND flash which is soldered on the board.
The NAND-Flash EVAL board was designed to overcome these limitations and provides
the user with an affordable alternative. The main feature is that the NAND flash
is not directly soldered on the board. A 48-pin TSOP socket is used instead which allows
the user to experiment with different types of NAND flashes. This helps finding the
right NAND flash for an application and thus reducing costs.
A further important feature is that the NAND-Flash EVAL board comes preloaded
with a USB-MSD application. When connected to a PC over USB, the board shows up
as a removable storage on the host operating system. Performance and functionality
tests of NAND flash can thus be performed without the need of an expensive development
environment. All current operating systems will recognize the board out of the box.
The NAND-Flash EVAL board comes with a ready to use USB-MSD application in
binary form. emFile is provided in object code{c} form together with a
start project which can be easily modified to create custom applications.
For programming and debugging a JTAG debug probe like J-Link is required.
The package also contains the schematics of the board.

Feature list
- Atmel ATSAM3U4C ARM Cortex-M3 microcontroller
- NAND flash socket
- 2 color LED
- 20-pin JTAG header
- High speed USB interface
FAQs
- Are Multi-Level Cell NAND flashes (MLCs) supported?
- Yes, the Universal NAND driver supports MLCs.
- Are NAND flash devices with 4 Kbyte pages supported?
- Yes, they are supported via the FS_NAND_PHY_4096x8 and FS_NAND_PHY_ONFI physical layers.
NOR flash driver
General information
emFile supports the use of unmanaged NOR flash devices as data storage.
Two drivers for NOR flash devices also known as flash translation layers are provided:
- Sector Map NOR driver - Supports almost any parallel or serial NOR flash device.
This driver was optimized for increase write performance.
- Block Map NOR driver - Supports almost any parallel or serial NOR flash device.
This driver was optimized for reduced RAM usage.
The difference between the two NOR drivers consists in the way they are managing the mapping
of file system logical sectors to the NOR flash device. The Sector map driver was designed
with the goal to access the data fast at a time when NOR flash devices had a relatively
small capacity (a few Mbytes). To achieve this, the driver maintains a mapping table
at logical sector granularity. This approach has proven to be very efficient, but for
modern NOR flash devices with capacities larger than 8 Mbytes the RAM usage of the
Sector Map NOR driver becomes increasingly high. This is the reason why the Block Map NOR
driver was developed. The design goal of the Block Map NOR driver was to use as
few RAM as possible. This is realized, by mapping blocks of file system logical sectors
to NOR flash device.
Software structure
The NOR drivers are organized into different layers that contain from top to bottom:
A hardware layer is required only for serial NOR flash devices. Typically,
CFI compliant NOR flash device is mapped into the system memory of the MCU
and can be accessed directly without a hardware layer. Normally no changes
to the physical layer are required. If the physical layer needs to be adapted,
a template is provided.
Garbage collection
The driver performs the garbage collection automatically during the write operations.
If no empty logical sectors are available to store the data, new empty logical sectors
are created by erasing the data of the logical sectors marked as invalid. This involves
a NOR physical sector erase operation which, depending on the characteristics of the
NOR flash, can potentially take a long time to complete, and therefor reduces the
write performance. For applications which require maximum write throughput, the
garbage collection can be done in the application. Typically, this operation can be
performed when the file system is idle.
Two API functions are provided: FS_STORAGE_Clean() and FS_STORAGE_CleanOne().
They can be called directly from the task which is performing the write or from a
background task. The FS_STORAGE_Clean() function blocks until all the invalid logical
sectors are converted to free logical sectors. A write operation following the call to
this function runs at maximum speed. The other function, FS_STORAGE_CleanOne(),
converts the invalid sectors of a single physical sector. Depending on the number of
invalid logical sectors, several calls to this function are required to clean up the
entire storage device.
Fail-safe operation
The operation of emFile NOR driver is fail-safe. This means that the driver
performs only atomic operations in order to make sure that the stored data is always valid
after a unexpected power failure that interrupts a write operation. If the unexpected power
failure interrupts the write operation, then the old version of the modified data is preserved.
The fail-safe operation is only guaranteed if the NOR flash device is able to fully
complete the last write operation that it receives from the file system before the unexpected
power failure. This means that the supply voltage of the NOR flash device has to remain valid
for a sufficiently long time after the MCU enters reset (typically few hundreds of microseconds)
to allow the NOR flash device to complete that write operation.
The exact timing can be taken from the data sheet of the NOR flash device.
The number of bytes written by the NOR driver in one write operation varies between the value
configured via FS_NOR_LINE_SIZE and the page size of the NOR flash device.
Not all the data the NOR driver writes to the storage is critical. Non-critical write operations
can be interrupted by an unexpected power failure without negatively affecting the fail-safe operation.
The critical data is always stored as a write operation containing FS_NOR_LINE_SIZE bytes.
This type of write operations have to be completed by the NOR flash device and cannot be interrupted.
The erase operation of a NOR flash sector can be interrupted by an unexpected power failure
because the NOR driver is able determine at low-level mount which NOR flash sector
was not completely erased. The incompletely erased NOR flash sectors will be erased again
when required.
The above requirements for the write operation do not apply for configurations
that use the Block Map NOR driver with the CRC verification enabled because
in this configuration the file system is able to determine and discard incomplete
write operations at low-level mount. However, the retention time of the data written
during the interrupted operation can no longer be guaranteed.
Wear leveling
Wear leveling is supported by both NOR drivers. The wear leveling procedure makes
sure that the number of erase cycles remains approximately equal for each physical sector.
This works by keeping track of the index of the last erased physical sector.
When a new erased physical sector is required to store data then the first free
physical sector with an index greater than the last one is selected. The index
of the physical sector wraps around when the end of the NOR flash device is reached.
In addition, the wear leveling procedure keeps a count of the number of times each
physical sector has been erased called erase count that is stored on the NOR flash device.
The erase count is used to make sure that physical sectors that store data that
is rarely modified are also equally erased. For this purpose the wear leveling
procedure calculates the difference between the erase counts of the selected
physical sector and of the physical sector with the smallest erase count.
If the calculated difference is greater than the value specified via
FS_NOR_MAX_ERASE_CNT_DIFF or FS_NOR_BM_SetMaxEraseCntDiff() then the physical
sector with the smaller erase count is used instead.
Low-level format
Before using a NOR flash device for the first time, the application has to initialize it
by performing a low-level format operation on it. Refer to FS_FormatLow() and FS_FormatLLIfRequired()
for detailed information about this.
CRC verification
The integrity of the data stored to a NOR flash device using the Block Map NOR driver
can be increased by enabling the CRC verification feature. With the CRC verification
feature enabled the Block Map NOR driver calculates a checksum of payload and management
data that is written to NOR flash device using a CRC (Cyclic Redundancy Check) algorithm.
The calculated checksum is stored together with the payload and management data to
NOR flash device. Each time the Block Map NOR driver reads some data from the NOR flash
device it also calculates the checksum of it using the same algorithm. The calculated
checksum is then compared with the checksum read from NOR flash device and if a mismatch
occurs an error is reported to the application via the return value of the called
API function as well as via the callback registered using FS_NOR_BM_SetOnFatalErrorCallback().
Depending on what data was exactly damaged an error recovery may be possible or not.
The application may try to repair the damaged data by running a disk checking operation
via FS_CheckDisk().
The CRC verification is disabled by default and has to be enabled at compile time
as well as at runtime. FS_NOR_SUPPORT_CRC has to be set to 1 in order to enable
the support for CRC verification at compile time. At runtime FS_NOR_BM_EnableCRC()
has to be called in FS_X_AddDevices() to activate the CRC verification feature.
By default, the Block Map NOR driver uses the internal CRC calculation routines
of the file system but the application can register its own CRC calculation routines
via FS_NOR_BM_SetCRCHook().
Bit error correction
The integrity of the data stored to a NOR flash device using the Block Map NOR driver
can be increased by enabling the bit error correction. With the bit error correction
feature enabled the Block Map NOR driver calculates a parity check of payload and management
data that is written to NOR flash device using an error correction algorithm.
The calculated parity check is stored together with the payload and management data to
NOR flash device. Each time the Block Map NOR driver reads some data from the NOR flash
device it uses the same error correction algorithm and read parity check to verify if
any bit errors occurred and if so to correct them. If the algorithm is not able to
correct the bit errors than an error is reported to the application via the return value
of the called API function as well as via the callback registered using FS_NOR_BM_SetOnFatalErrorCallback().
Depending on what data was exactly damaged an error recovery may be possible or not.
The application may try to repair the damaged data by running a disk checking operation
via FS_CheckDisk().
The bit error correction is disabled by default and has to be enabled at compile time
as well as at runtime. FS_NOR_SUPPORT_ECC has to be set to 1 in order to enable
the support for bit error correction at compile time. At runtime FS_NOR_BM_EnableECC()
has to be called in FS_X_AddDevices() to activate the bit error correction feature.
By default, the Block Map NOR driver uses an error correction algorithm that is able
to correct 1 bit error and to detect 2 bit errors in the management and payload data
of the file system but the application can register its own bit error correction routines
via FS_NOR_BM_SetECCHook().
Supported hardware
The NOR flash drivers can be used with almost any NOR flash device. This includes
NOR flash device with 8-bit and 16-bit parallel interfaces, as well as two 16-bit
interfaces in parallel. Serial NOR flash devices are also supported.
A NOR flash device has to meet the following requirements:
- The NOR flash device has to contain a minimum of two physical sectors.
The physical sectors do not need to be of equal size but at least two physical
sectors of each size must exist. For example a NOR flash device 11 physical sectors
organized as 8 * 8 Kbytes + 3 * 64 Kbytes is supported.
- All the physical sectors need to be at least 2048 bytes large.
- The erase operation must set all bits in a physical sector to one.
In order to provide the best write performance, the NOR drivers make use of
a NOR flash device feature that permits the same location to be modified
multiple times without an erase operation in between, as long as only bits set
to 1 are changed to 0. For NOR flash devices that do not support this feature,
the NOR drivers have to be compiled with the configuration define
FS_NOR_CAN_REWRITE set to 0.
In general, the NOR drivers support almost all serial and parallel NOR flashes which
meet the listed requirements. In addition, the NOR drivers can use the internal
flash memory of a MCU as storage device.
The following table shows the serial NOR flash devices that were tested by SEGGER
or are known to be compatible with a tested device.
Device name | Storage capacity | Device type | Supported extra features |
S25FL032P | 32 Mibit | SPI | extended SPI |
S25FL064L | 64 Mibit | SPI | extended SPI |
S25FL064P | 64 Mibit | SPI | extended SPI |
S25FL127S | 128 Mibit | SPI | extended SPI |
S25FL128L | 128 Mibit | SPI | extended SPI |
S25FL128S | 128 Mibit | SPI | extended SPI |
S25FL129P | 128 Mibit | SPI | extended SPI |
S25FL132K | 32 Mibit | SPI | extended SPI |
S25FL164K | 64 Mibit | SPI | extended SPI |
S25FL256L | 256 Mibit | SPI | extended SPI |
S25FL256S | 256 Mibit | SPI | extended SPI |
S25FL512S | 512 Mibit | SPI | extended SPI |
S25FS128S | 128 Mibit | SPI | extended SPI |
S25FS256S | 256 Mibit | SPI | extended SPI |
S25FS512S | 512 Mibit | SPI | extended SPI |
S26KL512S | 512 Mibit | HyperBus | write buffer |
S29GL064N | 64 Mibit | CFI | write buffer |
S70FL01GS | 1 Gibit | SPI | extended SPI |
S70FL256P | 256 Mibit | CFI | extended SPI |
AT25SF128A | 128 Mibit | SPI | extended SPI |
AT25SL321 | 32 Mibit | SPI | extended SPI |
AT25XE041D | 4 Mibit | SPI | extended SPI |
AT25XE081D | 8 Mibit | SPI | extended SPI |
AT25XE321D | 32 Mibit | SPI | extended SPI |
EN25QH128A | 128 Mibit | SPI | extended SPI |
EN25QX64A | 64 Mibit | SPI | extended SPI |
GD25LQ128D | 128 Mibit | SPI | extended SPI |
GD25LQ128E | 128 Mibit | SPI | extended SPI |
GD25LQ16C | 16 Mibit | SPI | extended SPI |
GD25Q127C | 128 Mibit | SPI | extended SPI |
GD25Q16B | 16 Mibit | SPI | extended SPI |
GD25Q16C | 16 Mibit | SPI | extended SPI |
GD25Q256D | 256 Mibit | SPI | extended SPI |
GD25Q32C | 32 Mibit | SPI | extended SPI |
GD25Q32E | 32 Mibit | SPI | extended SPI |
GD25Q64C | 64 Mibit | SPI | extended SPI |
GD25Q64E | 64 Mibit | SPI | extended SPI |
IS25LP01G | 1 Gibit | SPI | extended SPI |
IS25LP032D | 32 Mibit | SPI | extended SPI |
IS25LP064A | 64 Mibit | SPI | extended SPI |
IS25LP128 | 128 Mibit | SPI | extended SPI |
IS25LP128F | 128 Mibit | SPI | extended SPI |
IS25LP256D | 256 Mibit | SPI | extended SPI |
IS25LP256E | 256 Mibit | SPI | extended SPI |
IS25LP512M | 512 Mibit | SPI | extended SPI |
IS25LQ016B | 16 Mibit | SPI | extended SPI |
IS25LQ032B | 32 Mibit | SPI | extended SPI |
IS25LQ080 | 8 Mibit | SPI | extended SPI |
IS25LQ080B | 8 Mibit | SPI | extended SPI |
IS25WP01G | 1 Gibit | SPI | extended SPI |
IS25WP064A | 64 Mibit | SPI | extended SPI |
IS25WP256D | 256 Mibit | SPI | extended SPI |
S25HL512T | 512 Mibit | SPI | extended SPI |
S25HS01GT | 1 Gibit | SPI | extended SPI |
MX25L12835F | 128 Mibit | SPI | extended SPI |
MX25L25635F | 256 Mibit | SPI | extended SPI |
MX25L25645G | 256 Mibit | SPI | extended SPI |
MX25L3233F | 32 Mibit | SPI | extended SPI |
MX25L3235E | 32 Mibit | SPI | extended SPI |
MX25L51245G | 512 Mibit | SPI | extended SPI |
MX25L6433F | 64 Mibit | SPI | extended SPI |
MX25L8035E | 8 Mibit | SPI | extended SPI |
MX25LM51245G | 512 Mibit | SPI | OPI STR, OPI DTR |
MX25R3235F | 32 Mibit | SPI | extended SPI |
MX25R6435F | 64 Mibit | SPI | extended SPI |
MX25U256 | 256 Mibit | SPI | extended SPI |
MX25UM51245G | 512 Mibit | SPI | OPI STR, OPI DTR |
MX25V1635F | 16 Mibit | SPI | extended SPI |
MX66L1G45G | 1 Gibit | SPI | extended SPI |
MX66L2G45G | 2 Gibit | SPI | extended SPI |
MX66L51235F | 512 Mibit | SPI | extended SPI |
MX66U2G45G | 2 Gibit | SPI | extended SPI |
SST25VF016B | 16 Mibit | SPI | |
SST26VF016B | 16 Mibit | SPI | extended SPI |
SST26VF032B | 32 Mibit | SPI | extended SPI |
SST26VF032BA | 32 Mibit | SPI | extended SPI |
SST26VF064B | 64 Mibit | SPI | extended SPI |
M25P128 | 128 Mibit | SPI | |
M25P16 | 16 Mibit | SPI | |
M25P32 | 32 Mibit | SPI | |
M25P40 | 4 Mibit | SPI | |
M25P64 | 64 Mibit | SPI | |
M25P80 | 8 Mibit | SPI | |
M25PX16 | 16 Mibit | SPI | |
M28F256 | 256 Kibit | CFI | |
M28W160 | 16 Mibit | CFI | |
M28W320 | 32 Mibit | CFI | |
M28W640 | 64 Mibit | CFI | |
M29F080 | 8 Mibit | CFI | |
M29W128GL | 128 Mibit | CFI | |
M29W160 | 16 Mibit | CFI | |
M29W320 | 32 Mibit | CFI | |
M29W640 | 64 Mibit | CFI | |
M58LW064 | 64 Mibit | CFI | |
MT25QL01GBB | 1 Gibit | SPI | extended SPI |
MT25QL02GC | 2 Gibit | SPI | extended SPI |
MT25QL128ABA | 128 Mibit | SPI | extended SPI |
MT25QL256ABA | 256 Mibit | SPI | extended SPI |
MT25QL512ABB | 512 Mibit | SPI | extended SPI |
MT25QU01GAB | 1 Gibit | SPI | extended SPI |
MT25QU02GAB | 2 Gibit | SPI | extended SPI |
MT25QU128ABA | 128 Mibit | SPI | extended SPI |
MT25TL01GHBB | 1 Gibit | SPI | extended SPI |
MT28F128 | 128 Mibit | CFI | |
MT28F320 | 32 Mibit | CFI | |
MT28F640 | 64 Mibit | CFI | |
N25Q00AA | 1 Gibit | SPI | extended SPI |
N25Q032A | 32 Mibit | SPI | extended SPI |
N25Q064 | 64 Mibit | SPI | extended SPI |
N25Q064A | 64 Mibit | SPI | extended SPI |
N25Q128A | 128 Mibit | SPI | extended SPI |
N25Q256 | 256 Mibit | SPI | extended SPI |
N25Q256A | 256 Mibit | SPI | extended SPI |
N25Q512A | 512 Mibit | SPI | extended SPI |
TE28F128P30B85 | 128 Mibit | CFI | |
TE28F128P33B85 | 128 Mibit | CFI | |
TE28F256P30B95 | 256 Mibit | CFI | |
TE28F256P33B95 | 256 Mibit | CFI | |
TE28F640P30B85 | 64 Mibit | CFI | |
TE28F640P33B85 | 64 Mibit | CFI | |
M95P08 | 8 Mibit | SPI | extended SPI |
M95P16 | 16 Mibit | SPI | extended SPI |
M95P32 | 32 Mibit | SPI | extended SPI |
W25Q01JV | 1 Gibit | SPI | extended SPI |
W25Q02JV | 2 Gibit | SPI | extended SPI, DTR |
W25Q128FW | 128 Mibit | SPI | extended SPI |
W25Q128JV | 128 Mibit | SPI | extended SPI |
W25Q16DV | 16 Mibit | SPI | extended SPI |
W25Q16JV | 16 Mibit | SPI | extended SPI |
W25Q256JV | 256 Mibit | SPI | extended SPI |
W25Q256JW | 256 Mibit | SPI | extended SPI |
W25Q32JV | 32 Mibit | SPI | extended SPI |
W25Q512JV | 512 Mibit | SPI | extended SPI, DTR |
W25Q64FV | 64 Mibit | SPI | extended SPI |
W25Q64FW | 64 Mibit | SPI | extended SPI |
W25Q64JV | 64 Mibit | SPI | extended SPI |
W25Q80DV | 8 Mibit | SPI | extended SPI |
W25Q80EW | 8 Mibit | SPI | extended SPI |
Support for devices not available in this list
Most other NOR flash devices are compatible with one of the supported devices. Thus
the driver can be used with these devices or may only need a little modification,
which can easily be done. Get in touch with us if you have questions about support
for devices not in this list.
Using the same NOR flash device for code and data
Most NOR flash device cannot be read out during a program or erase operation.
This means that the CPU cannot execute code from the NOR flash device while the
NOR flash device is busy performing a program or erase operation. A program crash
is almost certain if the CPU tries to execute code in this case.
There are multiple options to solve this problem:
- Multiple NOR flash devices can be used with code and data being stored
on different devices.
- A NOR flash device that supports multiple flash banks can be used.
Typically, this type of NOR flash device allows the code execution from one back
while performing an erase or program operation on a different one.
- The hardware routines that program, erase or identify the NOR flash
device are located in RAM and the interrupts are disabled.
Interfacing with a NOR flash device
The most common setup is a CFI compliant NOR flash device with a 16-bit interface.
The picture below shows how this can be realized.

In addition to this, emFile supports the use of two CFI compliant NOR flash
devices with a 16-bit interface which are connected to the same address bus as
illustrated in the picture below.

Common flash interface (CFI)
The NOR flash drivers can be used with any CFI-compliant 16-bit device. CFI is an
open specification which may be implemented freely by flash memory vendors in
their devices. It was developed jointly by Intel, AMD, Sharp, and Fujitsu.
The idea behind CFI was the interchangeability of current and future flash memory
devices offered by different vendors. If you use only CFI compliant flash memory
device, you are able to use one driver for different flash products by reading
identifying information out of the flash device itself. The identifying information
for the device, such as memory size, byte/word configuration, block configuration,
necessary voltages, and timing information, is stored directly on the device.
For more technical details about CFI (Common Flash Interface) and SFDP (Serial
Flash Discoverable Parameters), check the documents and specifications that are
available free of charge at https://www.jedec.org
Sector Map NOR driver
This section describes the NOR driver that was optimized for increased write performance.
The Sector Map NOR driver works by mapping single logical sectors to locations on the NOR flash device.
Theory of operation
Differentiating between logical sectors or blocks and physical sectors is essential
to understand this section. A logical sector/block s the smallest
readable and writable unit of any file system and its usual size is 512 bytes.
A physical sector is an array of bytes on the NOR flash device that are erased
together (typically between 2 Kbytes - 128 Kbytes). The Sector Map NOR driver
is an abstraction layer between these two types of sectors.
Every time a logical sector is being updated, it is marked as invalid and the new
content of this sector is written into another area of the flash. The physical address and
the order of physical sectors can change with every write access. Hence, a direct
relation between the sector number and its physical location cannot exist.
The flash driver manages the logical sector numbers by writing it into special
headers. To the upper layer, it does not matter were the logical sector is stored or how
much flash memory is used as a buffer. All logical sectors (starting with sector 0)
always exist and are always available for user access.
Configuring the driver
This section describes how to configure the file system to make use of the Sector Map NOR driver.
Compile time configuration
The Sector Map NOR driver can optionally be configured at compile time. Typically,
this step can be omitted because reasonable default values are provided that work
with most of the applications.
The compile time configuration is realized via preprocessor defines that have
to be added to the FS_Conf.h file which is the main configuration file
of emFile. For detailed information about the configuration of emFile
and of the configuration define types, refer to Configuration of emFile
The following table lists the configuration defines supported by the Sector Map
NOR driver.
FS_NOR_CAN_REWRITE
For the majority of NOR flash device the same byte can be modified more than
once without a erase operation in between while preserving the bits set to 0.
That is a byte can be written up to eight times with each write operation
setting a different bit in that byte to 0. The Sector Map NOR driver makes use
of this feature to make efficient use of the storage space and to improve the
performance. FS_NOR_CAN_REWRITE has to be set to 0 for NOR flash devices
that permit only one write operation to a byte or a range of bytes between
two erase operations of that storage block.
FS_NOR_ENABLE_STATS
This define can be used to enable the support for statistical counters.
The statistical counters provide information about the number of operations
performed internally by the Sector Map NOR driver that can be useful for debugging.
The statistical counters can be queried via FS_NOR_GetStatCounters().
By default FS_NOR_ENABLE_STATS is set to 1 if FS_DEBUG_LEVEL is set
to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.
FS_NOR_LINE_SIZE
FS_NOR_LINE_SIZE specifies the minimum number of bytes the Sector Map NOR driver
writes at once. The amount of data written is always a multiple of this value.
In addition, FS_NOR_LINE_SIZE specifies the alignment of the written data.
That is the offset at which the Sector Map NOR driver writes the data is always
a multiple of this value. FS_NOR_LINE_SIZE has to be a power of two value.
FS_NOR_MAX_ERASE_CNT
The Sector Map NOR driver uses the value of FS_NOR_MAX_ERASE_CNT to check the
validity of an erase count stored in the header of a physical sector.
If the value of the erase count is larger than FS_NOR_MAX_ERASE_CNT then the
erase count is considered invalid and is set to the maximum value of all valid
erase counts.
FS_NOR_MAX_ERASE_CNT_DIFF
The value of this define is used by the Sector Map NOR driver during the wear leveling
procedure to decide which physical sector has to be used for storage.
FS_NOR_SetMaxEraseCntDiff() can be used to modify this value at runtime.
Refer to Wear Leveling for more information about how this
value is used.
FS_NOR_MAX_NUM_SECTOR_SIZES
FS_NOR_MAX_NUM_SECTOR_SIZES can be used to specify how many different physical sector sizes
the Sector Map NOR driver is able to use as data storage. If FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST
is set to 1 then the supported sector sizes depend on the value of FS_NOR_MIN_SECTOR_SIZE_SHIFT.
More exactly the Sector Map NOR driver is able to use as storage any physical sector with a size
between 2FS_NOR_MIN_SECTOR_SIZE_SHIFT and 2(FS_NOR_MIN_SECTOR_SIZE_SHIFT + FS_NOR_MAX_NUM_SECTOR_SIZES - 1)
that is a power of two value.
With FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST set to 0 up to FS_NOR_MAX_NUM_SECTOR_SIZES
physical sectors of arbitrary sizes are supported.
FS_NOR_MIN_SECTOR_SIZE_SHIFT
FS_NOR_MIN_SECTOR_SIZE_SHIFT can be used to specify the minimum size of a physical sector
that is supported by the Sector Map NOR driver. The physical sector size is specified
as a power of two exponent. This configuration define takes effect only when FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST
is set to 1. For example, a value of 8 indicates that the minimum size of a physical sector
is 28 = 256 bytes.
FS_NOR_NUM_FREE_SECTORCACHE
FS_NOR_NUM_FREE_SECTORCACHE can be used to specify the maximum number of physical
sector indexes that an instance of the Sector Map NOR driver can remember as being
ready to store data. Each entry of this list occupies 4 bytes. Increasing the capacity
of the list can help increase the performance of the write operation at the cost of
increased RAM usage.
FS_NOR_NUM_UNITS
This define specifies the maximum number of driver instances of the Sector Map NOR driver
the application is allowed create. Four bytes of static RAM are reserved for each instance.
If the maximum number of driver instances is smaller than the default then FS_NOR_NUM_UNITS
can be set to the to that value in order to reduce the RAM usage.
FS_NOR_OPTIMIZE_DIRTY_CHECK
This define can be used to enable a speed optimization related to the check performed
by the the Sector Map NOR driver to determine if a logical sector is blank or not.
With FS_NOR_OPTIMIZE_DIRTY_CHECK set to 1 the Sector Map NOR driver remembers which
physical sectors were already checked so that the blank checking operation can be
skipped. Activating this feature can help improve the write performance at the cost
of increased RAM usage. The Sector Map NOR driver requires 1 bit of RAM for each
physical sector used as storage.
FS_NOR_OPTIMIZE_HEADER_WRITE can be used to specify how the management data is
written to storage. The management data is stored at the beginning of each physical
and logical sector in an area called header. By default, the size of the physical
sector header is 16 bytes and of the logical sector header is 8 bytes. The size
of these headers is larger for NOR flash devices that specify a minimum number
of bytes that have to be written at once and that are not able to perform incremental
write operations. The default behavior of the Sector Map NOR driver, that is when
FS_NOR_OPTIMIZE_HEADER_WRITE is set to 0, is to write the entire header every
time some of the information stored in it changes. With FS_NOR_OPTIMIZE_HEADER_WRITE
set to 1 the Sector Map NOR driver tracks the changes made to a header and
writes only the information that actually changed. Reducing the amount of data
written to storage can help increase the write performance.
The internal flash memory of some MCUs do not allow a second write operation
to the same byte with identical data without an erase operation in between.
If this type of flash memory is used as storage then it is mandatory to set
FS_NOR_OPTIMIZE_HEADER_WRITE to 1.
FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST
The Sector Map NOR driver keeps track of the size of physical sectors it uses as storage.
FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST can be used to configure how this list is managed.
With FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST set to 1 the Sector Map NOR driver takes
advantage of the fact that the size of a physical sector is typically a power
of two value to keep the RAM usage to a minimum. If any of the physical sectors used
as storage has a size that is not a power of two value then FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST
will have to be set to 0. With FS_NOR_OPTIMIZE_SECTOR_SIZE_LIST set to 0 the RAM usage
of the Sector Map NOR driver increases by FS_NOR_MAX_NUM_SECTOR_SIZES * 4 per driver instance.
FS_NOR_READ_BUFFER_FILL_PATTERN
The value of FS_NOR_READ_BUFFER_FILL_PATTERN is used by the Sector Map NOR driver
to fill the contents of invalid logical sectors that is logical sectors that were
not written yet. The contents of all logical sectors is invalid after a low-level
format operation. In addition, the contents of a logical sector can be invalidated
via FS_STORAGE_FreeSectors().
FS_NOR_SKIP_BLANK_SECTORS
FS_NOR_SKIP_BLANK_SECTORS can be used to enable the support for the optimization
that omits the erase of physical sectors that are already blank. This feature
has to be explicitly enabled a runtime by calling FS_NOR_BM_SetBlankSectorSkip().
FS_NOR_SUPPORT_CLEAN
This define specifies if the application is allowed to perform a garbage collection
operation. If FS_NOR_SUPPORT_CLEAN is set to 1 then the application can perform a
garbage collection operation via FS_STORAGE_Clean() and FS_STORAGE_CleanOne().
For more information about the garbage collection refer to
Garbage collection.
The automatic garbage collection operation performed by the Sector Map NOR driver
is not disabled when FS_NOR_SUPPORT_CLEAN is set to 0.
If the application does not call either FS_STORAGE_Clean() or FS_STORAGE_CleanOne()
then FS_NOR_SUPPORT_CLEAN can be safely set to 0 in order to save ROM space.
FS_NOR_SUPPORT_VARIABLE_LINE_SIZE
FS_NOR_SUPPORT_VARIABLE_LINE_SIZE can be used to enable the runtime configuration
of the minimum number of bytes to be written by the Sector Map NOR driver at once.
With FS_NOR_SUPPORT_VARIABLE_LINE_SIZE set to 1 the minimum number of bytes to
be written at once can be configured via FS_NOR_SetDeviceLineSize() between
1 and FS_NOR_LINE_SIZE. In addition, the ability of the NOR flash device to
perform incremental write operations can be configured via
FS_NOR_SetDeviceRewriteSupport().
FS_NOR_SUPPORT_VARIABLE_LINE_SIZE is set to 1 when building the NOR Image Creator
utility in order to give it the ability to create images for NOR flash devices
with different characteristics. Typically, there is no need to modify the default
value of FS_NOR_SUPPORT_VARIABLE_LINE_SIZE when building a target application.
FS_NOR_VERIFY_WRITE
This define can be used to activate the write verification of the Sector Map NOR driver.
The write verification is performed after each write operation by reading back
the modified data from storage and by comparing it with the data requested
to be written. An error is reported if a difference is detected.
This feature has to be enabled at runtime by calling FS_NOR_SetWriteVerification().
Note
Activating the write verification can negatively affect the write performance.
FS_NOR_VERIFY_ERASE
This define can be used to activate the erase verification of the Sector Map NOR driver.
The erase verification is performed after each erase operation by reading back
the entire data of the erase physical sector from storage and by comparing it
with 0xFF. An error is reported if a difference is detected.
This feature has to be enabled at runtime by calling FS_NOR_SetEraseVerification().
Note
Activating the erase verification can negatively affect the write performance.
Runtime configuration
The driver must be added to the file system by calling FS_AddDevice() with the
driver identifier set to the address of FS_NOR_Driver. This function call together
with other function calls that configure the driver operation have to be added
to FS_X_AddDevices() as demonstrated in the following example. This example
shows how to configure the file system to access a NOR flash device connected via SPI.
#include "FS.h"
#define ALLOC_SIZE 0x4000 // Size defined in bytes
#define BYTES_PER_SECTOR 2048
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for
// semi-dynamic allocation.
/*********************************************************************
*
* FS_X_AddDevices
*
* Function description
* This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
//
// Give the file system memory to work with.
//
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Add and configure the NOR flash driver. The first 65536 bytes of the
// serial NOR flash device are not used by the file system as data storage
// and can be used by the application for other purposes. The file system
// uses a total of 1 Mbyte from the serial NOR flash device as storage.
//
FS_AddDevice(&FS_NOR_Driver);
FS_NOR_SetPhyType(0, &FS_NOR_PHY_ST_M25);
FS_NOR_Configure(0, 0x00000000, 0x00010000, 0x00100000);
FS_NOR_SetSectorSize(0, BYTES_PER_SECTOR);
//
// Set a larger logical sector size as the default
// in order to reduce the RAM usage of the NOR driver.
//
FS_SetMaxSectorSize(BYTES_PER_SECTOR);
}
The API functions listed in the next table can be used by the application to
configure the behavior of the Sector Map NOR driver. The application can call
them only at the file system initialization in FS_X_AddDevices().
Description
Configures an instance of the sector map NOR driver
Prototype
void FS_NOR_Configure(U8 Unit,
U32 BaseAddr,
U32 StartAddr,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
BaseAddr | Address of the first byte in NOR flash. |
StartAddr | Address of the first byte the NOR driver is permitted to use as storage. |
NumBytes | Number of bytes starting from StartAddr available to be used by the NOR driver as storage. |
Additional information
This function is mandatory and it has to be called once in FS_X_AddDevices()
for each instance of the sector map NOR driver created by the application.
Different instances of the NOR driver are identified by the Unit parameter.
BaseAddr is used only for NOR flash devices that are memory mapped.
For serial NOR flash devices that are not memory mapped BaseAddr
has to be set to 0.
StartAddr has to be greater than or equal to BaseAddr and smaller
than the total number of bytes in the NOR flash device. The sector map
NOR driver rounds up StartAddr to the start address of the next physical
sector in the NOR flash device.
NumBytes is rounded up to a physical sector boundary if the memory
range defined by StartAddr and NumBytes is smaller than the capacity
of the NOR flash device. If the memory range defined by StartAddr
and NumBytes is larger than the capacity of the NOR flash device
than NumBytes is rounded down so that the memory range fits into
the NOR flash device.
The sector map NOR driver can work with physical sectors of different size.
It is required that at least two physical sectors of each sector size are
available.
Example
The following sample demonstrates how to configure the file system to work with
a single CFI compliant NOR flash device connected via a 16-bit data bus.
#include "FS.h"
#define ALLOC_SIZE 0x2000 // Size defined in bytes
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for
// semi-dynamic allocation.
/*********************************************************************
*
* FS_X_AddDevices
*
* Function description
* This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
//
// Give the file system memory to work with.
//
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Add the NOR driver.
//
FS_AddDevice(&FS_NOR_Driver);
//
// Set the physical layer type for single CFI compliant
// NOR flash device with 16-bit data bus interface.
//
FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
//
// Configure the range of NOR flash device to be used as storage (2 Mbytes)
//
FS_NOR_Configure(0, 0x1000000, 0x1000000, 0x00200000);
}
The next sample demonstrates how to configure the file system to work with two
CFI compliant NOR flash devices with each device being connected via a separate
16-bit data bus.
#include "FS.h"
#define ALLOC_SIZE 0x4000 // Size defined in bytes
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for
// semi-dynamic allocation.
/*********************************************************************
*
* FS_X_AddDevices
*
* Function description
* This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
//
// Give the file system memory to work with.
//
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Add the NOR driver.
//
FS_AddDevice(&FS_NOR_Driver);
//
// Set the physical layer type for two CFI compliant
// NOR flash devices with 16-bit data bus interface.
//
FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_2x16);
//
// Configure the range of NOR flash device to be used as storage (2 Mbytes each)
//
FS_NOR_Configure(0, 0x1000000, 0x1000000, 0x00400000);
}
The file system is able to handle two or more NOR flash devices that are not
connected in parallel. The next sample shows how this can be realized.
#include "FS.h"
#define ALLOC_SIZE 0x4000 // Size defined in bytes
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for
// semi-dynamic allocation.
/*********************************************************************
*
* FS_X_AddDevices
*
* Function description
* This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
//
// Give the file system memory to work with.
//
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Add and configure the first NOR driver. The storage can be accessed
// using the volume name "nor:0:". The physical layer is set to single
// CFI compliant NOR flash device with 16-bit interface. The NOR flash
// device is mapped at address 0x10000000 in the system memory and
// 2 Mbytes of it are used by the file system as storage.
//
FS_AddDevice(&FS_NOR_Driver);
FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
FS_NOR_Configure(0, 0x1000000, 0x1000000, 0x00200000);
//
// Add and configure the second NOR driver. The storage can be accessed
// using the volume name "nor:1:". The physical layer is set to single
// CFI compliant NOR flash device with 16-bit interface. The NOR flash
// device is mapped at address 0x40000000 in the system memory and
// 4 Mbytes of it are used by the file system as storage.
//
FS_AddDevice(&FS_NOR_Driver);
FS_NOR_SetPhyType(1, &FS_NOR_PHY_CFI_1x16);
FS_NOR_Configure(1, 0x4000000, 0x4000000, 0x00400000);
}
Description
Configures the number of logical sectors to be reserved.
Prototype
void FS_NOR_ConfigureReserve(U8 Unit,
U8 pctToReserve);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
pctToReserve | Percent of the total number of logical sectors to reserve. |
Additional information
This function is optional. By default, the sector map NOR driver
reserves about 10% of the total number of logical sector for
future improvements and extensions. FS_NOR_ConfigureReserve()
can be used in an application to modify this value. If set to 0
the sector map NOR driver uses all the available logical sectors
to store file system data.
The application has to reformat the NOR flash device in order
for the modified value to take effect.
FS_NOR_SetBlankSectorSkip()
Description
Configures if the physical sectors which are already blank
should be erased during the low-level format operation.
Prototype
void FS_NOR_SetBlankSectorSkip(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
OnOff | Specifies if the feature has to be enabled or disabled =0 All the physical sectors are erased. ≠0 Physical sectors are not erased if they are blank (default). |
Additional information
This function is optional. The blank checking feature is disabled
by default and has to be explicitly enabled at compile time by
setting FS_NOR_SKIP_BLANK_SECTORS to 1. The feature can then be
enabled or disabled at runtime using FS_NOR_SetBlankSectorSkip().
Activating this feature can improve the speed of the low-level
format operation when most of the physical sectors of the NOR flash
device are already blank which is typically the case with NOR flash
devices that ship from factory.
FS_NOR_SetDeviceLineSize()
Description
Configures the minimum number of bytes that can be written to NOR flash.
Prototype
void FS_NOR_SetDeviceLineSize(U8 Unit,
U8 ldBytesPerLine);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
ldBytesPerLine | Line size in bytes as power of 2 exponent. |
Additional information
This function is optional. Typically, the NOR flash have lines smaller
than 4 bytes which is the fixed default value configured at compile time.
The FS_NOR_SUPPORT_VARIABLE_LINE_SIZE configuration define has to be set to a value
different than 0 in order to enable this function.
FS_NOR_SetDeviceRewriteSupport()
Description
Specifies if the NOR flash device can rewrite the same data
if 0s are preserved.
Prototype
void FS_NOR_SetDeviceRewriteSupport(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
OnOff | Specifies if the feature has to be enabled or disabled =0 Rewrite operations are not performed. ≠0 Rewrite operation are performed (default). |
Additional information
This function is optional. Typically, the NOR flash devices are
able to rewrite the same data and by default this feature is
disabled at compile time. The FS_NOR_SUPPORT_VARIABLE_LINE_SIZE
configuration define has to be set to a value different than 0
in order to enable this function, otherwise the function does nothing.
FS_NOR_SetDirtyCheckOptimization()
Description
Enables or disables the blank checking of a logical sector before write.
Prototype
void FS_NOR_SetDirtyCheckOptimization(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
OnOff | Specifies if the feature has to be enabled or disabled =0 Dirty check is disabled (default). ≠0 Dirty check is enabled. |
Additional information
This function is optional. Per default, the NOR driver checks
if the data of the logical sector is blank (all bytes 0xFF)
before it writes the data. This is necessary in order to make
sure that the NOR driver does not write to partially written
logical sectors. Writing to a partially written logical sector
can cause a data loss since the write operation can change
the value of a bit only from 1 to 0. A partially written logical
sector occurs when the write operation is interrupted by an
unexpected reset. In this case the status of the logical sector
indicates that the logical sector is blank which is not correct.
Therefore the logical sector cannot be used for storage and
it is marked by the NOR driver as invalid.
Typically, the blank checking runs fast but on some targets
it may reduce the write performance. In this cases, this option
can be used to skip the blank checking which helps improve
the performance. When the optimization is enabled, the blank
checking is not longer performed on the logical sectors located
on physical sectors that have been erased at least once since
the last mount operation. The NOR driver can skip the blank
checking for these physical sectors since it knows that they
do not contain any partially written logical sectors. The application
can remove any partially written logical sectors by performing
a clean operation of the entire storage via the FS_STORAGE_Clean()
or FS_STORAGE_CleanOne() API functions. The NOR driver requires
one bit of RAM storage for each physical sector used as storage.
The FS_NOR_OPTIMIZE_DIRTY_CHECK configuration define has to be
set to a value different than 0 in order to enable this function,
otherwise the function does nothing.
FS_NOR_SetEraseVerification()
Description
Enables or disables the checking of the sector erase operation.
Prototype
void FS_NOR_SetEraseVerification(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
OnOff | Specifies if the feature has to be enabled or disabled =0 The erase operation is not checked. ≠0 The erase operation is checked. |
Additional information
This function is optional. The result of a sector erase operation
is normally checked by evaluating the error bits maintained by the
NOR flash device in a internal status register. FS_NOR_SetEraseVerification()
can be used to enable additional verification of the sector erase
operation that is realized by reading back the contents of the entire
erased physical sector and by checking that all the bytes in it are
set to 0xFF. Enabling this feature can negatively impact the write
performance of sector map NOR driver.
The sector erase verification feature is active only when the sector map
NOR driver is compiled with the FS_NOR_VERIFY_ERASE configuration
define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL
configuration define is set to a value greater than or equal to
FS_DEBUG_LEVEL_CHECK_ALL.
FS_NOR_SetPhyType()
Description
Configures the type of NOR physical layer.
Prototype
void FS_NOR_SetPhyType( U8 Unit,
const FS_NOR_PHY_TYPE * pPhyType);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
pPhyType | in NOR physical layer. |
Additional information
This function is mandatory and it has to be called once in FS_X_AddDevices()
for each instance of the sector map NOR driver created by the application.
Different instances of the sector map NOR driver are identified by the Unit parameter.
Permitted values for the pPhyType parameter are:
Identifier | Description |
FS_NOR_PHY_CFI_1x16 | One CFI compliant NOR flash device with 16-bit interface. |
FS_NOR_PHY_CFI_2x16 | Two CFI compliant NOR flash device with 16-bit interfaces. |
FS_NOR_PHY_DSPI | This a pseudo physical layer that uses the physical layers FS_NOR_PHY_ST_M25 and FS_NOR_PHY_SFDP |
FS_NOR_PHY_SFDP | Serial NOR flash devices that support Serial Flash Discoverable Parameters (SFDP) |
FS_NOR_PHY_SPIFI | Memory mapped serial quad NOR flash devices. |
FS_NOR_PHY_ST_M25 | Serial NOR flash devices compatible to ST ST25Pxx. |
FS_NOR_SetSectorSize()
Description
Configures the number of bytes in a logical sector.
Prototype
void FS_NOR_SetSectorSize(U8 Unit,
U16 SectorSize);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
SectorSize | Number of bytes in a logical sector. |
Additional information
This function is optional. It can be used to modify the size
of the logical sector used by the sector map NOR driver.
By default the sector map NOR driver uses the logical sector
size configured a file system level that is set to 512 bytes
at the file system initialization and can be later changed
via FS_SetMaxSectorSize(). The NOR flash device has to be
reformatted in order for the new logical sector size to take
effect.
SectorSize has to be a power of 2 value.
FS_NOR_SetWriteVerification()
Description
Enables or disables the checking of the page write operation.
Prototype
void FS_NOR_SetWriteVerification(U8 Unit,
U8 OnOff);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
OnOff | Specifies if the feature has to be enabled or disabled =0 The write operation is not checked. ≠0 The write operation is checked. |
Additional information
This function is optional. The result of a page write operation
is normally checked by evaluating the error bits maintained by the
NOR flash device in a internal status register. FS_NOR_SetWriteVerification()
can be used to enable additional verification of the page write
operation that is realized by reading back the contents of the written
page and by checking that all the bytes are matching the data
requested to be written. Enabling this feature can negatively
impact the write performance of sector map NOR driver.
The page write verification feature is active only when the sector map
NOR driver is compiled with the FS_NOR_VERIFY_WRITE configuration
define is set to 1 (default is 0) or when the FS_DEBUG_LEVEL
configuration define is set to a value greater than or equal to
FS_DEBUG_LEVEL_CHECK_ALL.
FS_NOR_STAT_COUNTERS
Description
Statistical counters maintained by the Sector Map NOR driver.
Type definition
typedef struct {
U32 EraseCnt;
U32 ReadSectorCnt;
U32 WriteSectorCnt;
U32 CopySectorCnt;
U32 ReadCnt;
U32 ReadByteCnt;
U32 WriteCnt;
U32 WriteByteCnt;
} FS_NOR_STAT_COUNTERS;
Structure members
Member | Description |
EraseCnt | Number of sector erase operations. |
ReadSectorCnt | Number of logical sectors read by the file system. |
WriteSectorCnt | Number of logical sectors written by the file system. |
CopySectorCnt | Number of logical sectors copied internally by the driver. |
ReadCnt | Number of times the driver read data from the NOR flash device. |
ReadByteCnt | Number of bytes read by the driver from the NOR flash device. |
WriteCnt | Number of times the driver wrote data to the NOR flash device. |
WriteByteCnt | Number of bytes written by the driver to the NOR flash device. |
Additional sample configurations
The sample configurations below show how to create multiple volumes,
logical volumes etc., on a NOR flash device. All configuration steps
have to be performed inside the FS_X_AddDevices() function that is called
during the initialization of the file system.
Multiple volumes on a single NOR flash device
The following example illustrates how to create multiple volumes on a single NOR
flash device. The sample creates two volumes on one NOR flash device.
#include "FS.h"
#define ALLOC_SIZE 0x2000 // Size defined in bytes
//
// Config: 1 NOR flash, where NOR flash size -> 2 MB
// 2 volumes, , where volume 0 size -> 1MB, volume 1 -> 0.5MB
//
#define FLASH_BASE_ADDR 0x80000000
#define FLASH_VOLUME_0_START_ADDR 0x80000000
#define FLASH_VOLUME_0_SIZE 0x00100000 // 1 MByte
#define FLASH_VOLUME_1_START_ADDR 0x80100000
#define FLASH_VOLUME_1_SIZE 0x00080000 // 0.5 MByte
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for
// semi-dynamic allocation.
/*********************************************************************
*
* FS_X_AddDevices
*
* Function description
* This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
//
// Give the file system memory to work with.
//
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Volume name: "nor:0:"
//
FS_AddDevice(&FS_NOR_Driver);
FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
FS_NOR_Configure(0, FLASH_BASE_ADDR, FLASH_VOLUME_0_START_ADDR, FLASH_VOLUME_0_SIZE);
//
// Volume name: "nor:1:"
//
FS_AddDevice(&FS_NOR_Driver);
FS_NOR_SetPhyType(1, &FS_NOR_PHY_CFI_1x16);
FS_NOR_Configure(1, FLASH_BASE_ADDR, FLASH_VOLUME_1_START_ADDR, FLASH_VOLUME_1_SIZE);
}
Multiple volumes on different NOR flash devices
The following example illustrates how to create multiple volumes on multiple NOR
flash devices. This sample creates two volume, each one located on different NOR
flash device.
#include "FS.h"
#define ALLOC_SIZE 0x2000 // Size defined in bytes
//
// Config: 2 NOR flash devices, where NOR flash 0 size -> 2 MB, NOR flash 1 -> 16MB
// 2 volumes, volume 0 size -> complete NOR 0, volume 1 -> complete NOR 1
//
#define FLASH0_BASE_ADDR 0x80000000
#define FLASH_VOLUME_0_START_ADDR FLASH0_BASE_ADDR
#define FLASH_VOLUME_0_SIZE 0xFFFFFFFF // Use the complete flash
#define FLASH1_BASE_ADDR 0x40000000
#define FLASH_VOLUME_1_START_ADDR FLASH1_BASE_ADDR
#define FLASH_VOLUME_1_SIZE 0xFFFFFFFF // Use the complete flash
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for
// semi-dynamic allocation.
/*********************************************************************
*
* FS_X_AddDevices
*
* Function description
* This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
//
// Give the file system memory to work with.
//
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Volume name: "nor:0:"
//
FS_AddDevice(&FS_NOR_Driver);
FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
FS_NOR_Configure(0, FLASH0_BASE_ADDR, FLASH_VOLUME_0_START_ADDR, FLASH_VOLUME_0_SIZE);
//
// Volume name: "nor:1:"
//
FS_AddDevice(&FS_NOR_Driver);
FS_NOR_SetPhyType(1, &FS_NOR_PHY_CFI_1x16);
FS_NOR_Configure(1, FLASH1_BASE_ADDR, FLASH_VOLUME_1_START_ADDR, FLASH_VOLUME_1_SIZE);
}
Volume that stretches over multiple NOR flash devices
The following example illustrates how to create a volume that stretches over
two NOR flash devices. This is realized by using the logical volume functionality.
#include "FS.h"
#define ALLOC_SIZE 0x2000 // Size defined in bytes
//
// Config: 2 NOR flash devices, where NOR flash 0 size -> 2 MB, NOR flash 1 -> 16MB
// 1 volume, where volume is NOR flash 0 + NOR flash 1
//
#define FLASH0_BASE_ADDR 0x80000000
#define FLASH_VOLUME_0_START_ADDR FLASH0_BASE_ADDR
#define FLASH_VOLUME_0_SIZE 0xFFFFFFFF // Use the complete flash
#define FLASH1_BASE_ADDR 0x40000000
#define FLASH_VOLUME_1_START_ADDR FLASH1_BASE_ADDR
#define FLASH_VOLUME_1_SIZE 0xFFFFFFFF // Use the complete flash
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for
// semi-dynamic allocation.
/*********************************************************************
*
* FS_X_AddDevices
*
* Function description
* This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
//
// Give the file system memory to work with.
//
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Create physical device 0, this device will not be visible as a volume.
//
FS_AddPhysDevice(&FS_NOR_Driver);
FS_NOR_SetPhyType(0, &FS_NOR_PHY_CFI_1x16);
FS_NOR_Configure(0, FLASH0_BASE_ADDR, FLASH_VOLUME_0_START_ADDR, FLASH_VOLUME_0_SIZE);
//
// Create physical device 1, this device will not be visible as a volume
//
FS_AddPhysDevice(&FS_NOR_Driver);
FS_NOR_SetPhyType(1, &FS_NOR_PHY_CFI_1x16);
FS_NOR_Configure(1, FLASH1_BASE_ADDR, FLASH_VOLUME_1_START_ADDR, FLASH_VOLUME_1_SIZE);
//
// Now create a logical volume, containing the physical devices. Volume name: "LogVol"
//
FS_LOGVOL_Create("LogVol");
FS_LOGVOL_AddDevice("LogVol", &FS_NOR_Driver, 0, 0, 0);
FS_LOGVOL_AddDevice("LogVol", &FS_NOR_Driver, 1, 0, 0);
}
Additional driver functions
The functions documented in this section are optional. They can be used
to get information about the status of the Sector Map NOR driver or to
directly access the data stored on the NOR flash device.
FS_NOR_EraseDevice()
Description
Erases all the physical sectors configured as storage.
Prototype
int FS_NOR_EraseDevice(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
Return value
= 0 | Physical sectors erased. |
≠ 0 | An error occurred. |
Additional information
This function is optional. After the call to this function
all the bytes in area of the NOR flash device configured
as storage are set to 0xFF.
FS_NOR_ErasePhySector()
Description
Sets all the bits in a physical sector to 1.
Prototype
int FS_NOR_ErasePhySector(U8 Unit,
U32 PhySectorIndex);
Parameters
Parameter | Description |
Unit | Index of the Block Map NOR driver (0-based). |
PhySectorIndex | Index of the physical sector to be erased. |
Return value
= 0 | OK, physical sector erased successfully. |
≠ 0 | An error occurred. |
Additional information
PhySectorIndex is 0-based and is relative to the beginning
of the NOR flash area configured via FS_NOR_Configure().
The number of bytes actually erased depends on the size of the
physical sector supported by the NOR flash device.
Information about a physical sector can be obtained via
FS_NOR_GetSectorInfo().
Description
Performs a low-level format of NOR flash device.
Prototype
int FS_NOR_FormatLow(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
Return value
= 0 | OK, NOR flash device has been successfully low-level formated. |
≠ 0 | An error occurred. |
Additional information
This function is optional. FS_NOR_FormatLow() erases the first
physical sector and stores the format information in it. The other
physical sectors are either erased or invalidated. Per default
the physical sectors are invalidated in order to reduce the time
it takes for the operation to complete.
FS_NOR_GetDiskInfo()
Description
Returns information about the organization and the management
of the NOR flash device.
Prototype
int FS_NOR_GetDiskInfo(U8 Unit,
FS_NOR_DISK_INFO * pDiskInfo);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
pDiskInfo | out Requested information. |
Return value
= 0 | OK, information returned. |
≠ 0 | An error occurred. |
Additional information
This function is not required for the functionality of the sector
map NOR driver and will typically not be linked in production builds.
Example
#include "FS.h"
void SampleNORGetDiskInfo(void) {
int r;
char ac[128];
FS_NOR_DISK_INFO DiskInfo;
FS_X_Log("Get information about the first Sector Map NOR driver instance\n");
r = FS_NOR_GetDiskInfo(0, &DiskInfo);
if (r == 0) {
SEGGER_snprintf(ac, sizeof(ac), " Physical sectors: %lu\n", DiskInfo.NumPhysSectors);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Logical sectors : %lu\n", DiskInfo.NumLogSectors);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Used sectors: %lu\n", DiskInfo.NumUsedSectors);
FS_X_Log(ac);
}
}
FS_NOR_GetSectorInfo()
Description
Returns information about a specified physical sector.
Prototype
int FS_NOR_GetSectorInfo(U8 Unit,
U32 PhySectorIndex,
FS_NOR_SECTOR_INFO * pSectorInfo);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
PhySectorIndex | Index of the physical sector to be queried (0-based). |
pSectorInfo | out Information related to the specified physical sector. |
Return value
= 0 | OK, information returned successfully. |
≠ 0 | An error occurred. |
Additional information
This function is optional. The application can use it to get
information about the usage of a particular physical sector.
PhySectorIndex is relative to the beginning of the region configured
as storage via FS_NOR_Configure().
Example
#include "FS.h"
void SampleNORGetDiskInfo(void) {
char ac[128];
FS_NOR_SECTOR_INFO SectorInfo;
FS_X_Log("Get information about the physical sector 0 of the first Sector Map NOR driver instance\n");
FS_NOR_GetSectorInfo(0, 0, &SectorInfo);
SEGGER_snprintf(ac, sizeof(ac), " Offset: %lu\n", SectorInfo.Off);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Size: %lu bytes\n", SectorInfo.Size);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Erase count: %lu\n", SectorInfo.EraseCnt);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Used logical sectors: %lu\n", SectorInfo.NumUsedSectors);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Free logical sectors: %lu\n", SectorInfo.NumFreeSectors);
FS_X_Log(ac);
SEGGER_snprintf(ac, sizeof(ac), " Erasable logical sectors: %lu\n", SectorInfo.NumEraseableSectors);
FS_X_Log(ac);
}
FS_NOR_GetStatCounters()
Description
Returns the values of the statistical counters.
Prototype
void FS_NOR_GetStatCounters(U8 Unit,
FS_NOR_STAT_COUNTERS * pStat);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
pStat | out Statistical counter values. |
Additional information
This function is optional. The application can use it to get
the actual values of the statistical counters maintained by
the sector map NOR driver. The statistical counters provide
information about the number of internal operations performed
by the sector map NOR driver such as sector read and write.
All statistical counters are set to 0 when the NOR flash device
is low-level mounted. The application can explicitly set them
to 0 by using FS_NOR_ResetStatCounters(). A separate set of
statistical counters is maintained for each instance of the
sector map NOR driver.
The statistical counters are available only when the sector
map NOR driver is compiled with the FS_DEBUG_LEVEL configuration
define set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL
or with the FS_NOR_ENABLE_STATS configuration define set to 1.
Description
Checks it the NOR flash is low-level formatted.
Prototype
int FS_NOR_IsLLFormatted(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
Return value
≠ 0 | The NOR flash device is low-level formatted. |
= 0 | The NOR flash device is not low-level formatted or an error has occurred. |
Additional information
This function is optional. An application should use FS_IsLLFormatted() instead.
FS_NOR_LogSector2PhySectorAddr()
Description
Returns the address in memory of a specified logical sector.
Prototype
void *FS_NOR_LogSector2PhySectorAddr(U8 Unit,
U32 LogSectorIndex);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
LogSectorIndex | Index of the logical sector for which the address has to be calculated. |
Return value
≠ NULL | OK, address of the first byte in the logical sector. |
= NULL | An error occurred. |
Additional information
This function is optional. It can be used only with NOR flash
devices that are memory mapped. FS_NOR_LogSector2PhySectorAddr()
returns the address in the system memory of the first byte in the
specified logical sector.
FS_NOR_ReadOff()
Description
Reads a range of bytes from the NOR flash device.
Prototype
int FS_NOR_ReadOff(U8 Unit,
U32 Off,
void * pData,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
Off | Offset of the first byte to be read. |
pData | out Read data. |
NumBytes | Number of bytes to be read. |
Return value
= 0 | OK, data read. |
≠ 0 | An error occurred. |
Additional information
This function is not required for the functionality of the driver
and will typically not be linked in production builds.
Off has to be specified in bytes and is relative to the beginning
of the NOR flash area configured via FS_NOR_Configure().
FS_NOR_ResetStatCounters()
Description
Sets the value of the statistical counters to 0.
Prototype
void FS_NOR_ResetStatCounters(U8 Unit);
Parameters
Parameter | Description |
Unit | Index of the sector map NOR driver (0-based). |
Additional information
This function is optional. The application can use it to set
the statistical counters maintained by the sector map NOR driver
to 0. The statistical counters can be read via FS_NOR_GetStatCounters()
FS_NOR_ResetStatCounters() is available only when the sector
map NOR driver is compiled with the FS_DEBUG_LEVEL configuration
define set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL
or with the FS_NOR_ENABLE_STATS configuration define set to 1.
FS_NOR_WriteOff()
Description
Writes data to NOR flash memory.
Prototype
int FS_NOR_WriteOff( U8 Unit,
U32 Off,
const void * pData,
U32 NumBytes);
Parameters
Parameter | Description |
Unit | Index of the Sector Map NOR driver (0-based). |
Off | Location where to write the data. |
pData | in Data to be written. |
NumBytes | Number of bytes to be written. |
Return value
= 0 | OK, data written successfully. |
≠ 0 | An error occurred. |
Additional information
Off has to be specified in bytes and is relative to the beginning
of the NOR flash area configured via FS_NOR_Configure().
FS_NOR_WriteOff() is able to write across page and physical
sector boundaries. This function can only change bit values from
1 to 0. The bits can be set to 1 block-wise via FS_NOR_ErasePhySector().
The function takes care of the alignment required when writing
to NOR flash devices with line size larger than 1.
FS_NOR_DISK_INFO
Description
Management information maintained by the Sector Map NOR driver.
Type definition
typedef struct {
U32 NumPhysSectors;
U32 NumLogSectors;
U32 NumUsedSectors;
U16 BytesPerSector;
} FS_NOR_DISK_INFO;
Structure members
Member | Description |
NumPhysSectors | Number of physical sectors available for data storage. |
NumLogSectors | Number of available logical sectors. |
NumUsedSectors | Number of logical sectors that store valid data. |
BytesPerSector | Size of the logical sector used by the driver in bytes. |
FS_NOR_SECTOR_INFO
Description
Information about a physical sector maintained by the Sector Map NOR driver.
Type definition
typedef struct {
U32 Off;
U32 Size;
U32 EraseCnt;
U16 NumUsedSectors;
U16 NumFreeSectors;
U16 NumEraseableSectors;
U8 Type;
} FS_NOR_SECTOR_INFO;
Structure members
Member | Description |
Off | Position of the physical sector relative to the first byte of NOR flash device |
Size | Size of physical sector in bytes |
EraseCnt | Number of times the physical sector has been erased |
NumUsedSectors | Number of logical sectors that contain valid data |
NumFreeSectors | Number of logical sectors that are empty (i.e. blank) |
NumEraseableSectors | Number of logical sectors that contain old (i.e. invalid) data. |
Type | Type of data stored in the physical sector (see FS_NOR_SECTOR_TYPE_…) |
Performance and resource usage
This section provides information about the ROM and RAM usage as well
as the performance of the Sector Map NOR driver. Each driver instance
requires one instance of one NOR physical layer in order to operate.
The resource usage of the used NOR physical layer has to be taken into
account when calculating the total resource usage of the Sector Map NOR driver.
Refer to the section Resource usage
for information about the resource usage of the available NOR physical layers.
ROM usage
The ROM usage depends on the compiler options, the compiler version and the used CPU.
The memory requirements of the Sector Map NOR driver were measured as described in the section
Test procedure.
Usage: 4.0 Kbytes
Static RAM usage
Static RAM usage refers to the amount of RAM required by the Sector Map NOR driver
internally for all the driver instances. The number of bytes can be seen in the
compiler list file of the FS_NOR_Drv.c file.
Usage: 20 bytes
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the driver at runtime.
The amount of RAM required depends on the runtime configuration and on the
used NOR flash device. The approximate RAM usage of the Sector Map NOR driver
can be calculated as follows:
MemAllocated = 500 + (BitsPerEntry * FlashSize / 8) / LogSectorSize
Parameter | Description |
MemAllocated | Number of bytes allocated. |
BitsPerEntry | Number of bits required to store the offset of the last byte on the storage. |
FlashSize | Size in bytes of a NOR flash. |
LogSectorSize | Size in bytes of a file system sector.
Typically, 512 bytes or the value set in the call to
FS_SetMaxSectorSize(). |
The following table lists the approximate amount of RAM required for different
combinations of NOR flash size and logical sector size:
Flash size (Mbytes) | 512 byte sectors | 1 Kbyte sectors | 2 Kbyte sectors |
1 | 4.6 KBytes | 2.5 KBytes | 1.5 KBytes |
2 | 8.7 KBytes | 4.6 KBytes | 2.5 KBytes |
4 | 16.8 KBytes | 8.7 KBytes | 4.6 KBytes |
8 | 33.2 KBytes | 16.8 KBytes | 8.7 KBytes |
Note
Please note that by increasing the logical sector size the RAM usage of
the file system increases too because more memory is required for the
sector buffers.
Performance
These performance measurements are in no way complete, but they give an
approximation of the length of time required for common operations on various
targets. The tests were performed as described in the section
Performance.
All values are given in Kbytes/second
CPU type | NOR flash device | Write speed | Read speed |
ST STR912 (96 MHz) | Winbond W25Q32BV (SPI) | 75 | 2625 |
NXP LPC2478 (57.6 MHz) | SST SST39VF201 CFI NOR flash device with 16-bit
interface and without support for write buffer | 53.5 | 2560 |
ST STM32F103 (72 MHz) | ST M29W128 CFI NOR flash device 16-bit interface
and with support for write buffer | 60.4 | 8000 |
ST STM32F103 (72 MHz) | ST M25P64 SPI NOR flash device | 62.8 | 1125 |
NXP LPC4357 (204 MHz) | Spansion S25FL032P serial NOR flash device
interfaced via SPIFI. | 185 | 26947 |
FAQs
- How many physical sectors are reserved by the driver?
- The driver reserves 2 physical sectors for its internal use.
Block Map NOR driver
This section describes the NOR driver which is optimized for reduced RAM usage.
It works by mapping blocks of logical sectors to physical sectors of the NOR flash device.
Theory of operation
Differentiating between logical sectors or blocks and physical sectors is
essential to understand this section. A logical sector or block is the smallest
readable and writable unit of any file system and its usual size is 512 bytes.
A physical sector is an array of bytes on the NOR flash device that are erased
together (typically between 2 Kbytes - 128 Kbytes). The NOR flash driver is an
abstraction layer between these two types of sectors.
The Block Map NOR driver maintains a table that maps ranges of logical sectors,
called logical blocks, to physical sectors on the NOR flash device. The number of logical
sectors in a logical block depends on how many logical sectors fit in a physical sector.
Every time a logical sector is updated, its content is written to a special physical sector
called work block. A work block is a kind of temporary storage for the modified data
of a logical sector that is later converted into a data block when a new empty work
block needs to be allocated.
Configuring the driver
The Block Map NOR driver has to be configured at runtime and optionally at
compile time. The following sections described how this can be realized
in the application.
Compile time configuration
The Block Map NOR driver can optionally be configured at compile time. Typically,
this step can be omitted because reasonable default values are provided that work
with most of the applications.
The compile time configuration is realized via preprocessor defines that have
to be added to the FS_Conf.h file which is the main configuration file
of emFile. For detailed information about the configuration of emFile
and of the configuration define types, refer to Configuration of emFile
The following table lists the configuration defines supported by the Block Map
NOR driver.
FS_NOR_CAN_REWRITE
For the majority of NOR flash device the same byte can be modified more than
once without a erase operation in between while preserving the bits set to 0.
That is a byte can be written up to eight times with each write operation
setting a different bit in that byte to 0. The Block Map NOR driver makes use
of this feature to make efficient use of the storage space and to improve the
performance. FS_NOR_CAN_REWRITE has to be set to 0 for NOR flash devices
that permit only one write operation to a byte or a range of bytes between
two erase operations of that storage block.
FS_NOR_CRC_HOOK_DEFAULT
This define specifies the default routines for the CRC calculation. It can
be set to NULL in order to save ROM space if the application registers its
own routines via FS_NOR_BM_SetCRCHook()
FS_NOR_DATA_BUFFER_SIZE
This define can be used to specify the size of the buffers used by the
Block Map NOR driver for internal operations such as copying the contents
of a logical sector or verifying if a physical sector is blank.
All these buffers are allocated on the stack therefore increasing the
value of FS_NOR_DATA_BUFFER_SIZE increases the stack usage while providing
a better performance. FS_NOR_DATA_BUFFER_SIZE has to be a non-zero value
multiple of 4.
If the file system is built with FS_SUPPORT_EXT_MEM_MANAGER
set to 0 then the Block Map NOR driver is using as buffer the available free
memory at the time the buffer is required if the number of free bytes
is larger than FS_NOR_DATA_BUFFER_SIZE. This means that it is possible
to reduce the stack usage by setting FS_NOR_DATA_BUFFER_SIZE to a smaller value
than the default and by increasing the size of the memory pool assigned to the
file system via FS_AssignMemory() by the amount of memory required for the buffer.
FS_NOR_ECC_HOOK_DATA_DEFAULT
This define specifies the default routines for the ECC calculation of sector data.
It can be set to NULL in order to save ROM space if the application registers its
own routines via FS_NOR_BM_SetECCHook()
FS_NOR_ECC_HOOK_MAN_DEFAULT
This define specifies the default routines for the ECC calculation of the management data.
It can be set to NULL in order to save ROM space if the application registers its
own routines via FS_NOR_BM_SetECCHook()
FS_NOR_ENABLE_STATS
This define can be used to enable the support for statistical counters.
The statistical counters provide information about the number of operations
performed internally by the Block Map NOR driver that can be useful for debugging.
The statistical counters can be queried via FS_NOR_BM_GetStatCounters().
By default FS_NOR_ENABLE_STATS is set to 1 if FS_DEBUG_LEVEL is set
to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.
FS_NOR_LINE_SIZE
FS_NOR_LINE_SIZE specifies the minimum number of bytes the Block Map NOR driver
writes at once. The amount of data written is always a multiple of this value.
In addition, FS_NOR_LINE_SIZE specifies the alignment of the written data.
That is the offset at which the Block Map NOR driver writes the data is always
a multiple of this value. FS_NOR_LINE_SIZE has to be a power of two value.
FS_NOR_LOG_SECTOR_RESERVE
This define can by used to specify the number of additional bytes to be allocated
for the management data of a logical sector. The NOR flash device has to be low-level
formatted after FS_NOR_LOG_SECTOR_RESERVE is modified. FS_NOR_LOG_SECTOR_RESERVE
exists for backward compatibility reasons with older emFile versions.
Typically, the default value of FS_NOR_LOG_SECTOR_RESERVE does not have to be
modified. FS_NOR_LOG_SECTOR_RESERVE must be a multiple of 4 bytes.
FS_NOR_MAX_ERASE_CNT
The Block Map NOR driver uses the value of FS_NOR_MAX_ERASE_CNT to check the
validity of an erase count stored in the header of a physical sector.
If the value of the erase count is larger than FS_NOR_MAX_ERASE_CNT then the
erase count is considered invalid and is set to the maximum value of all valid
erase counts.
FS_NOR_MAX_ERASE_CNT_DIFF
The value of this define is used by the Block Map NOR driver during the wear leveling
procedure to decide which physical sector has to be used for storage.
FS_NOR_BM_SetMaxEraseCntDiff() can be used to modify this value at runtime.
Refer to Wear Leveling for more information about how this
value is used.
FS_NOR_NUM_READ_RETRIES
FS_NOR_NUM_READ_RETRIES specifies the maximum number of times the Block Map NOR driver
repeats a read operation in case of an error. A read retry is performed each time
the read function of the NOR physical layer reports an error or if the CRC feature
is activated when the CRC verification fails. NumReadRetries
of FS_NOR_BM_STAT_COUNTERS is incremented by 1 on each retry.
FS_NOR_NUM_WRITE_RETRIES
FS_NOR_NUM_WRITE_RETRIES specifies the maximum number of times the Block Map NOR driver
repeats a write operation in case of an error. A write retry is performed each time
the write function of the NOR physical layer reports an error.
FS_NOR_NUM_UNITS
This define specifies the maximum number of driver instances of the Block Map NOR driver
the application is allowed create. Four bytes of static RAM are reserved for each instance.
If the maximum number of driver instances is smaller than the default then FS_NOR_NUM_UNITS
can be set to the to that value in order to reduce the RAM usage.
FS_NOR_OPTIMIZE_EMPTY_CHECK
This configuration define can be used to enable an optimization that reduces the number
of read operations performed by the Block Map NOR driver when it checks if a physical
sector can be used to write data to it without being erased first.
Setting FS_NOR_OPTIMIZE_EMPTY_CHECK to 1 has effect only if either FS_NOR_SUPPORT_CLEAN
or FS_NOR_SKIP_BLANK_SECTORS are set to 1 and the support for fail-safe erase operation
is disabled.
FS_NOR_OPTIMIZE_HEADER_WRITE
FS_NOR_OPTIMIZE_HEADER_WRITE can be used to specify how the management data is
written to storage. The management data is stored at the beginning of each physical
and logical sector in an area called header. By default, the size of the physical
sector header is 16 bytes and of the logical sector header is 8 bytes. The size
of these headers is larger for NOR flash devices that specify a minimum number
of bytes that have to be written at once and that are not able to perform incremental
write operations. The default behavior of the Block Map NOR driver, that is when
FS_NOR_OPTIMIZE_HEADER_WRITE is set to 0, is to write the entire header every
time some of the information stored in it changes. With FS_NOR_OPTIMIZE_HEADER_WRITE
set to 1 the Block Map NOR driver tracks the changes made to a header and
writes only the information that actually changed. Reducing the amount of data
written to storage can help increase the write performance.
The internal flash memory of some MCUs do not allow a second write operation
to the same byte with identical data without an erase operation in between.
If this type of flash memory is used as storage then it is mandatory to set
FS_NOR_OPTIMIZE_HEADER_WRITE to 1.
FS_NOR_OPTIMIZE_DATA_WRITE
This configuration define can be used to enable an optimization that can help increase
the performance of the write operation. With FS_NOR_OPTIMIZE_DATA_WRITE set to 1 the
Block Map NOR driver tries to write the sector data directly to a data block instead
of writing it first to a work block. In this way the total number of write operations
is reduced, which as a side effect helps extend the lifetime of NOR flash device.
Enabling this optimization increases the RAM and ROM usage of the Block Map NOR driver.
FS_NOR_PHY_SECTOR_RESERVE
This define can by used to specify the number of additional bytes to be allocated
for the management data of a physical sector. The NOR flash device has to be low-level
formatted after FS_NOR_PHY_SECTOR_RESERVE is modified. FS_NOR_PHY_SECTOR_RESERVE
exists for backward compatibility reasons with older emFile versions.
Typically, the default value of FS_NOR_PHY_SECTOR_RESERVE does not have to be
modified. FS_NOR_PHY_SECTOR_RESERVE must be a multiple of 4 bytes.
FS_NOR_READ_BUFFER_FILL_PATTERN
The value of FS_NOR_READ_BUFFER_FILL_PATTERN is used by the Block Map NOR driver
to fill the contents of invalid logical sectors that is logical sectors that were
not written yet. The contents of all logical sectors is invalid after a low-level
format operation. In addition, the contents of a logical sector can be invalidated
via FS_STORAGE_FreeSectors().
FS_NOR_SKIP_BLANK_SECTORS
FS_NOR_SKIP_BLANK_SECTORS can be used to enable the support for the optimization
that omits the erase of physical sectors that are already blank. This feature
has to be explicitly enabled a runtime by calling FS_NOR_BM_SetBlankSectorSkip().
FS_NOR_STRICT_FORMAT_CHECK can be used to enable additional checks related to
the low-level formatting of the NOR flash device. If FS_NOR_STRICT_FORMAT_CHECK
is set to 1 then the Block Map NOR driver checks at low-level mount if the number
of logical blocks stored during the last low-level format operation matches the
actual number of logical blocks available for storage. The low-level format
operation fails if the number of logical blocks is not equal that for example
triggers a low-level format operation if the application calls FS_FormatLLIfRequired()
This can be useful in a situation where an already low-level formatted NOR partition
is enlarged. With FS_NOR_STRICT_FORMAT_CHECK set to 0 the low-level mount operation
succeeds and the Block Map NOR driver will not use the additional space as storage.
A low-level mount operation fails when an already formatted NOR partition is shrunk
irrespective of the value of FS_NOR_STRICT_FORMAT_CHECK.
FS_NOR_SUPPORT_CLEAN
This define specifies if the application is allowed to perform a garbage collection
operation. If FS_NOR_SUPPORT_CLEAN is set to 1 then the application can perform a
garbage collection operation via FS_STORAGE_Clean() and FS_STORAGE_CleanOne().
For more information about the garbage collection refer to
Garbage collection.
The automatic garbage collection operation performed by the Block Map NOR driver
is not disabled when FS_NOR_SUPPORT_CLEAN is set to 0.
If the application does not call either FS_STORAGE_Clean() or FS_STORAGE_CleanOne()
then FS_NOR_SUPPORT_CLEAN can be safely set to 0 in order to save ROM space.
FS_NOR_SUPPORT_CRC
FS_NOR_SUPPORT_CRC can be used to enable the support for the CRC verification.
This feature has to be enabled at runtime via FS_NOR_BM_EnableCRC().
For more information about the CRC feature refer to
CRC verification
FS_NOR_SUPPORT_ECC
FS_NOR_SUPPORT_ECC can be used to enable the support for the ECC verification.
This feature has to be enabled at runtime via FS_NOR_BM_EnableECC().
For more information about the ECC feature refer to
Bit error correction
FS_NOR_SUPPORT_FORMAT can be used to disable the support for the low-level format operation.
The ability of the Block Map NOR driver to perform a low-level format operation is not
required if the NOR flash device is already formatted for example by storing a file
system image via an external utility to it. In such a case FS_NOR_SUPPORT_FORMAT
can be set to 0 to reduce the ROM usage.
FS_NOR_SUPPORT_TRIM
FS_NOR_SUPPORT_TRIM can be used to enable or disable the handling of file system operations
that inform the Block Map NOR driver about logical sectors that are no longer in use.
The Block Map NOR driver can use this information to optimize the internal operation
that copies the data from one physical sector to another by not copying the contents
of the logical sectors that are marked as being no longer in use.
Enabling this feature increases the ROM usage of the Block Map NOR driver.
FS_NOR_SUPPORT_VARIABLE_BYTE_ORDER
This define can be used to specify if the byte order of the management data
can be configured at runtime or not. By default, multi-byte management data
is stored in the native order of the MCU on which the target application is
running. With FS_NOR_SUPPORT_VARIABLE_BYTE_ORDER set to 1 the byte order
can be configured at runtime via FS_NOR_BM_SetByteOrderLE() and
FS_NOR_BM_SetByteOrderBE().
FS_NOR_SUPPORT_VARIABLE_BYTE_ORDER is set to 1 when building the NOR Image Creator
utility in order to give it the ability to create images for a MCU with a different
byte ordering than of the host PC. Typically, there is no need to modify the default
value of FS_NOR_SUPPORT_VARIABLE_BYTE_ORDER when building a target application.
FS_NOR_SUPPORT_VARIABLE_LINE_SIZE
FS_NOR_SUPPORT_VARIABLE_LINE_SIZE can be used to enable the runtime configuration
of the minimum number of bytes to be written by the Block Map NOR driver at once.
With FS_NOR_SUPPORT_VARIABLE_LINE_SIZE set to 1 the minimum number of bytes to
be written at once can be configured via FS_NOR_BM_SetDeviceLineSize() between
1 and FS_NOR_LINE_SIZE. In addition, the ability of the NOR flash device to
perform incremental write operations can be configured via
FS_NOR_BM_SetDeviceRewriteSupport().
FS_NOR_SUPPORT_VARIABLE_LINE_SIZE is set to 1 when building the NOR Image Creator
utility in order to give it the ability to create images for NOR flash devices
with different characteristics. Typically, there is no need to modify the default
value of FS_NOR_SUPPORT_VARIABLE_LINE_SIZE when building a target application.
FS_NOR_VERIFY_WRITE
This define can be used to activate the write verification of the Block Map NOR driver.
The write verification is performed after each write operation by reading back
the modified data from storage and by comparing it with the data requested
to be written. An error is reported if a difference is detected.
This feature has to be enabled at runtime by calling FS_NOR_BM_SetWriteVerification().
Note
Activating the write verification can negatively affect the write performance.
FS_NOR_VERIFY_ERASE
This define can be used to activate the erase verification of the Block Map NOR driver.
The erase verification is performed after each erase operation by reading back
the entire data of the erase physical sector from storage and by comparing it
with 0xFF. An error is reported if a difference is detected.
This feature has to be enabled at runtime by calling FS_NOR_BM_SetEraseVerification().
Note
Activating the erase verification can negatively affect the write performance.
Runtime configuration
The driver must be added to the file system by calling FS_AddDevice() with the
driver identifier set to the address of FS_NOR_BM_Driver. This function call together
with other function calls that configure the driver operation have to be added
to FS_X_AddDevices() as demonstrated in the following example. This example
shows how to configure the file system to access a NOR flash device connected via SPI.
#include "FS.h"
#define ALLOC_SIZE 0x4000 // Size defined in bytes
static U32 _aMemBlock[ALLOC_SIZE / 4]; // Memory pool used for
// semi-dynamic allocation.
/*********************************************************************
*
* FS_X_AddDevices
*
* Function description
* This function is called by the FS during FS_Init().
*/
void FS_X_AddDevices(void) {
//
// Give the file system memory to work with.
//
FS_AssignMemory(&_aMemBlock[0], sizeof(_aMemBlock));
//
// Add and configure the NOR flash driver. The first 65536 bytes of the
// serial NOR flash device are not used by the file system as data storage
// and can be used by the application for other purposes. The file system
// uses a total of 1 Mbyte from the serial NOR flash device as storage.
//
FS_AddDevice