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.
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:
voidmain(void);voidmain(void){MainTask();}
voidMainTask(void){U32 v;FS_FILE*pFile;charac[256];characFileName[32];constchar*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 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:
Config
FS
SEGGER
Select the start application
For quick and easy testing of your emFile integration, start with the code
found in the Application folder of the shipment. Exclude all files in the
Application folder of your project except the supplied main.c
and FS_Start.c files.
The application performs the following steps:
main.c calls MainTask().
MainTask() initializes and adds a device to file system.
Checks if volume is low-level formatted and formats if required.
Checks if volume is high-level formatted and formats if required.
Outputs the volume name.
Calls FS_GetVolumeFreeSpace() and outputs the return value -- the available
total space of the RAM disk -- to console window.
Creates and opens a file test with write access (File.txt)
on the storage device
Writes 4 bytes of data into the file and closes the file handle
or outputs an error message.
Calls FS_GetVolumeFreeSpace() and outputs the return value
-- the available free space of the RAM disk -- again to console window.
Outputs a quit message and runs into an endless loop.
Build the project and test it
Build the project. It should compile without errors and warnings. If you
encounter any problem during the build process, check your include path and
your project configuration settings. The start application should print out
the storage space of the device twice, once before a file has been written
to the device and once afterwards.
Step 3: Adding the device driver
To configure emFile with a device driver, two modifications have to be performed:
Adding device driver source to project.
Adding hardware routines to project.
Each step is explained in the following sections. For example,
the implementation of the MMC/SD driver is shown, but all steps can easily be
adapted to every other device driver implementation.
Adding the device driver source to project
Add the driver sources to the project and add the directory to the include path.
Most drivers require additional hardware routines to work with the specific hardware.
If your driver requires low-level I/O routines to access the hardware, you will have to
provide them.
Drivers which require hardware routines are:
NAND flash
NOR flash with serial devices
MMC/SD cards
Compact flash / IDE
Drivers which do not require hardware routines are:
NOR flash with CFI compliant devices
RAM disk
Nearly all drivers have to be configured before they can be used. The runtime
configuration functions which specify for example the memory addresses and
the size of memory are located in the configuration file of the respective
driver. All required configurations are explained in the configuration section
of the respective driver. If you use one of the drivers which do not require
hardware routines skip the next section and refer to
Step 4: Activating the driver.
Adding hardware routines to project
A template with empty function bodies and in most cases one ore more sample
implementations are supplied for every driver that requires hardware routines.
The easiest way to start is to use one of the ready-to-use samples.
The ready-to-use samples can be found in the subfolders
Sample/FS/Driver/<DRIVER_DIR> of the emFile shipment where
DRIVER_DIR is the type of the device driver. You should check the
Readme.txt file located in the driver directory to see which samples
are included. If there is one which is a good or close match for your hardware,
it should be used. Otherwise, use the template to implement the hardware routines.
The template is a skeleton driver which contains empty implementations of the
required functions and is the ideal base to start the implementation of hardware
specific I/O routines.
What to do
Copy the compatible hardware function sample or the template into a subdirectory of
your work directory and add it to your project. The template file is located in the
Sample/FS/Driver/<DRIVER_DIR> folder; the example implementations are
located in the respective directories. If you start the implementation
of hardware routines with the hardware routine template, refer to
Device drivers for detailed information about the implementation
of the driver specific hardware functions, else refer to section
Step 4: Activating the driver.
Note
You cannot run and test the project with the new driver on your hardware
as long as you have not added the proper configuration file for the driver
to your project. Refer to section Step 4: Activating the driver
for more information about the activation of the driver with
the configuration file.
Step 4: Activating the driver
After adding the driver source, and if required the hardware function
implementation, copy the FS_Config<DRIVER_NAME>.c file (for example,
FS_ConfigMMC_CardMode.c for the MMC/SD card driver using card mode)
into the Config folder of your emFile work directory
and add it to your project.
The configuration files contain, all the runtime configuration functions of
the file system. The configuration files include a start configuration which
allows a quick and easy start with every driver. The most important function
for the beginning is FS_X_AddDevices(). It activates and configures the driver,
if required. A driver which does not require hardware routines has to be
configured before it can be used.
Modifying the runtime configuration
The following example a single CFI compliant NOR flash chip with a 16-bit
interface and a size of 256 Mbytes to the file system. The base address,
the start address and the size of the NOR flash are defined using the macros
FLASH0_BASE_ADDR, FLASH0_START_ADDR and FLASH0_SIZE.
Normally, only the “Defines, configurable” section of the configuration files
requires changes for typical embedded systems. The “Public code” section which
includes the time and date functions and FS_X_AddDevices() does not require
modifications on most systems.
/*********************************************************************** Defines, configurable** This section is the only section which requires changes for* typical embedded systems using the NOR flash driver with a* single device.************************************************************************/#defineALLOC_SIZE 0x10000// Size of memory dedicated to the file// system. This value should be fine-tuned// according for your system.#defineFLASH0_BASE_ADDR 0x40000000// Base address of the NOR flash device// to be used as storage#defineFLASH0_START_ADDR 0x40000000// Start address of the first sector// to be used as storage. If the entire// device is used for file system,// it is identical to// the base address.#defineFLASH0_SIZE 0x200000// Number of bytes to be used for storage/*********************************************************************** Static data.** This section does not require modifications in most systems.************************************************************************/staticU32 _aMemBlock[ALLOC_SIZE /4];// Memory pool used for semi-dynamic// allocation in FS_AssignMemory()./*********************************************************************** Public code** This section does not require modifications in most systems.************************************************************************//*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().* It is supposed to add all devices, using primarily FS_AddDevice().*/voidFS_X_AddDevices(void){FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Add driver the NOR driver.//FS_AddDevice(&FS_NOR_Driver);//// Configure the NOR flash interface.//FS_NOR_SetPhyType(0,&FS_NOR_PHY_CFI_1x16);FS_NOR_Configure(0,FLASH0_BASE_ADDR,FLASH0_START_ADDR,FLASH0_SIZE);//// Configure a read buffer for the file data.//FS_ConfigFileBufferDefault(512,0);}
After the driver has been added, the configuration functions (in this example
FS_NOR_SetPhyType() and FS_NOR_Configure()) should be called.
Detailed information about the driver configuration can be found
in the configuration section of the respective driver.
Refer to section Runtime configuration for detailed
information about the other runtime configurations of the file system.
Before compiling and running the sample application with the added driver,
you have to exclude FS_ConfigRAMDisk.c from the project.
Note
For the drivers which required hardware access routines, if you have only
added the template with empty function bodies until now, the project should
compile without errors or warning messages. But you can only run the project
on your hardware if you have finished the implementation of the hardware
functions.
Step 5: Adjusting the RAM usage
The file system needs RAM for management purposes in various places. The amount
of RAM required depends primarily on the configuration, especially the drivers
used. The drivers which have their own level of management
(such as NOR / NAND drivers) require in general more RAM than the “simple”
drivers such as for hard drives, compact flash or MMC/SD cards.
Every driver needs to allocate RAM. The file system allocates RAM in the
initialization phase and holds it while the file system is running. The macro
ALLOC_SIZE which is located in the respective driver configuration file
specifies the size of RAM used by the file system. This value should be
fine-tuned according to the requirements of your target system.
Per default, ALLOC_SIZE is set to a value which should be appropriate
for most target systems. Nevertheless, you should adjust it in order to avoid
wasting too much RAM. Once your file system project is up and running, you can
check the real RAM requirement of the driver via the public variable
FS_Global.MemManager.NumBytesAllocated. Check the value of
FS_Global.MemManager.NumBytesAllocated after the initialization
of the file system and after a volume has been mounted. At this point
FS_Global.MemManager.NumBytesAllocated can be used as reference for
the dynamic memory usage of emFile. You should reserve a few more bytes
for emFile as the value of FS_Global.MemManager.NumBytesAllocated
is at this point, since every file which is opened needs dynamic memory
for maintenance information. For more information about resource usage
of the file handlers, please refer to Dynamic RAM usage.
Note
If you define ALLOC_SIZE with a value which is smaller than the appropriate
size, the file system will run into FS_X_Panic(). If you define ALLOC_SIZE
with a value which is above the limits of your target system, the linker will
give an error during the build process of the project.
API functions
This chapter provides a detailed description of emFile API layer.
General information
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.
“”
“nor”
“nor:0:”
API function overview
The table below lists the available API functions within their respective categories.
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.
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"voidSampleDeInit(void){FS_Init();//// Access the file system...//FS_DeInit();//// The file system cannot be accessed anymore.//}
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"voidSampleMount(void){FS_Init();//// Mount default volume in read / write mode.//FS_Mount("");//// Access the data stored on the file system.//}
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"voidSampleMountEx(void){FS_Init();//// Mount default volume in read-only mode.//FS_MountEx("",FS_MOUNT_RO);//// Access the data stored on the file system.//}
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"voidSampleSetAutoMount(void){FS_SetAutoMount("",FS_MOUNT_R);// Mount default volume in read-only mode.}
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"voidSampleSync(void){FS_Sync("");// Synchronize the default volume.}
FS_Unmount()
Description
Synchronizes the data and marks the volume as not initialized.
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"voidSampleUnmount(void){FS_Unmount("");// Unmount the default volume.}
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"voidSampleUnmountForced(void){intIsPresentNew;intIsPresent;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);}}
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().
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"voidFS_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.
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.
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"#defineALLOC_SIZE 0x1000staticU32 _aMemBlock[ALLOC_SIZE /4];voidFS_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.
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"#defineALLOC_SIZE 0x1000staticU32 _aMemBlock[ALLOC_SIZE /4];voidFS_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}
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().
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.
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.
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"voidFS_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...//}
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"voidFS_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...//}
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"voidFS_X_AddDevices(void){#ifFS_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...//}
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.
#include"FS.h"voidFS_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.
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.
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().
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.
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 (0x0D0x0A).
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().
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"voidSampleOpenFile(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");}
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.*/voidSampleFOpenEx(void){intr;charac[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);}}
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.
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.
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"characBuffer[100];voidSampleFRead(void){FS_FILE*pFile;U32 NumItems;intErrCode;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);}}
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"constcharacText[]="Some text will be overwritten";voidSampleFSeek(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);}}
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"constcharacText[]="Some text will be overwritten";voidSampleFSeek64(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);}}
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.
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.
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.
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.
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];voidSampleRead(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);}}
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"voidSampleSetEndOfFile(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.
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"voidSampleSetFileSize(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.
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"voidSampleSetFileSize64(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);}}
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"voidSampleFileSync(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);}}
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"voidSampleTruncate(void){FS_FILE*pFile;U32 FileSize;intr;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);}
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"voidSampleTruncate64(void){FS_FILE*pFile;U64 FileSize;intr;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);}
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"constU8 abVerifyData[4]={1,2,3,4};voidSampleVerify(void){FS_FILE*pFile;intr;//// 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);}}
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.
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.
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"staticU32 _aBuffer[1024/4];// Buffer to be used as temporary storage.voidSampleCopyFileEx(void){FS_CopyFileEx("Src.txt","Dest.txt",_aBuffer,sizeof(_aBuffer));}
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"voidSampleGetFileAttributes(void){U8 Attr;charac[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);}}
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.
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.
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.
Type of timestamp to return. It can take one of the following values: FS_FILETIME_CREATEFS_FILETIME_ACCESSFS_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.
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"voidSampleIsFileBufferSet(void){FS_FILE*pFile;intr;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.
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"voidSampleModifyFileAttributes(void){U8 Attr;charac[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);}
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"voidSampleMove(void){//// File tree before the operation.//// <root>// |// +->SubDir2// |// +->SubDir3//FS_Move("SubDir1","SubDir2\\SubDir3");//// File tree after the operation.//// <root>// |// +->SubDir1// |// +->SubDir2//}
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"voidSampleRename(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.
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.
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:
when the file buffer is full.
when place is required for new data read from file.
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"voidSampleSetFileBuffer(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);}}
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"voidSampleSetFileTime(void){U32 TimeStamp;FS_FILETIMEFileTime;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);}
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"voidSampleUnsetFileBuffer(void){FS_FILE*pFile;intr;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.
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"voidSampleWipeFile(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");}
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.
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.
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.
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.
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.
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.
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 allocated
on the stack for parsing the path to directory.
Example
#include"FS.h"voidSampleCreateDir(void){//// File tree before the operation.//// <root>// |// +->SubDir1//FS_CreateDir("SubDir1\\SubDir2\\SubDir3");//// File tree after the operation.//// <root>// |// +->SubDir1// |// +->SubDir2// |// +->SubDir3//}
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"voidSampleDeleteDir(void){//// File tree before the operation.//// <root>// |// +->SubDir1// |// +->SubDir2// |// +->File1.txt// |// +->File2.txt//FS_DeleteDir("SubDir2",1);//// File tree after the operation.//// <root>// |// +->SubDir1//}
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"voidSampleFindClose(void){FS_FIND_DATAfd;intr;characFileName[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);}
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"voidSampleFindClose64(void){FS_FIND_DATA64fd;intr;characFileName[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);}
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"voidSampleFindFirstFile(void){FS_FIND_DATAfd;intr;characFileName[32];charac[100];FS_FILETIMEFileTime;//// 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);}
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"voidSampleFindFirstFile64(void){FS_FIND_DATA64fd;intr;characFileName[32];charac[100];FS_FILETIMEFileTime;//// 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.
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.
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.
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.
If FileNameLen is greater than the length of the 0-terminated string
stored to sFileName then the file name was truncated.
Formatting functions
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.
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"voidSampleFormat(void){FS_FORMAT_INFOFormatInfo;//// 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);}
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"voidSampleFormatLLIfRequired(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:");}
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"voidSampleFormatLow(void){FS_Init();//// Performs a low-level format of the NOR flash.//FS_FormatLow("nor:0:");}
FS_IsHLFormatted()
Description
Checks if a volume is high-level formatted or not.
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"voidSampleIsHLFormatted(void){FS_Init();//// Perform a high-level format if required.//if(FS_IsHLFormatted("")==0){FS_Format("",NULL);}}
FS_IsLLFormatted()
Description
Returns whether a volume is low-level formatted or not.
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"voidSampleIsLLFormatted(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:");}}
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
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.
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"staticconstU8 _abDiskId[FS_NUM_BYTES_GUID]={// FB223EF0-C45C-D24A-4787-F2E856469D590xFB,0x22,0x3E,0xF0,0xC4,0x5C,0xD2,0x4A,0x47,0x87,0xF2,0xE8,0x56,0x46,0x9D,0x59};staticconstU8 _abTypeBasicData[FS_NUM_BYTES_GUID]={// A2A0D0EB-E5B9-3344-87C0-68B6B72699C70xA2u,0xA0u,0xD0u,0xEBu,0xE5u,0xB9u,0x33u,0x44u,0x87u,0xC0u,0x68u,0xB6u,0xB7u,0x26u,0x99u,0xC7};staticconstU8 _abPartId0[FS_NUM_BYTES_GUID]={// E633CD2E-2D08-7C46-5E97-7283101E324D0xE6,0x33,0xCD,0x2E,0x2D,0x08,0x7C,0x46,0x5E,0x97,0x72,0x83,0x10,0x1E,0x32,0x4D};staticconstU8 _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};staticconstU8 _abPartId2[FS_NUM_BYTES_GUID]={// 621D39CB-6DD4-6448-7539-487394C67FCF0x62,0x1D,0x39,0xCB,0x6D,0xD4,0x64,0x48,0x75,0x39,0x48,0x73,0x94,0xC6,0x7F,0xCF};voidSampleCreateGPT(void){FS_PARTITION_INFO_GPTaPartInfo[3];FS_GPT_INFOgptInfo;//// 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.
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"voidSampleCreateMBR(void){FS_PARTITION_INFO_MBRaPartInfo[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);}
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"voidSampleGetPartitionInfoMBR(void){intiPart;FS_PARTITION_INFO_MBRPartInfo;charac[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");}}}
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"voidSampleGetPartitionInfoGPT(void){intiPart;FS_PARTITION_INFO_GPTPartInfo;charac[100];intr;FS_GPT_INFOgptInfo;intIsEmpty;unsignedi;//// 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.
#include"FS.h"voidSampleGetPartitioningScheme(void){intScheme;Scheme =FS_GetPartitioningScheme("");if(Scheme >=0){switch(Scheme){caseFS_PARTITIONING_SCHEME_NONE:FS_X_Log("The storage device is not partitioned.\n");break;caseFS_PARTITIONING_SCHEME_MBR:FS_X_Log("The storage device is partitioned via MBR.\n");break;caseFS_PARTITIONING_SCHEME_GPT:FS_X_Log("The storage device is partitioned via GPT.\n");break;default:FS_X_Log("Unknown partitioning scheme.\n");break;}}}
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.
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().
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.
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.
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"staticU32 _aBuffer[1024/4];staticint_NumErrors;/*********************************************************************** _OnError*/staticint_OnError(intErrCode,...){va_list ParamList;constchar*sFormat;charc;charac[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')){returnFS_CHECKDISK_ACTION_SAVE_CLUSTERS;}elseif((c =='a')||(c =='A')){returnFS_CHECKDISK_ACTION_ABORT;}elseif((c =='d')||(c =='D')){returnFS_CHECKDISK_ACTION_DELETE_CLUSTERS;}returnFS_CHECKDISK_ACTION_DO_NOT_REPAIR;// Do not repair anything.}/*********************************************************************** SampleCheckDisk*/voidSampleCheckDisk(void){intr;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.
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.
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"voidSampleGetATInfo(void){intr;FS_AT_INFOATInfo;charac[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.
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"voidSampleGetClusterInfo(void){intr;FS_CLUSTER_INFOClusterInfo;charac[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.
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"voidSampleGetDiskLayout(void){intr;FS_DISK_LAYOUTDiskLayout;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.
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"voidSampleGetFirstCluster(void){charac[100];U32 ClusterId;intr;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.
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.
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.
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"#defineVOLUME_NAME ""#defineMAX_RECURSION 5staticU32 _aBuffer[1024/4];staticint_NumErrors;/*********************************************************************** _IsSystemDir*/staticint_IsSystemDir(constchar*sDirName){if(((*sDirName =='.')&&(*(sDirName +1)=='\0'))){return1;}if(((*sDirName =='.')&&(*(sDirName +1)=='.')&&(*(sDirName +2)=='\0'))){return1;}return0;}/*********************************************************************** _cbOnError*/staticint_cbOnError(intErrCode,...){va_list ParamList;constchar*sFormat;intc;charac[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')){returnFS_CHECKDISK_ACTION_SAVE_CLUSTERS;}elseif((c =='a')||(c =='A')){returnFS_CHECKDISK_ACTION_ABORT;}elseif((c =='d')||(c =='D')){returnFS_CHECKDISK_ACTION_DELETE_CLUSTERS;}returnFS_CHECKDISK_ACTION_DO_NOT_REPAIR;}/*********************************************************************** _CheckDir** Function description* Checks the consistency of a directory tree.** Notes* (1) This function calls itself recursively.*/staticint_CheckDir(FS_CHECK_DATA*pCheckData,char*sDirPath,unsignedSizeOfDirPath,intMaxRecursionLevel){intr;intResult;FS_FIND_DATAFindData;characDirName[32];unsignedLenPath;unsignedLenName;char*p;char*pEnd;unsignedNumBytes;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()}returnr;}/*********************************************************************** _CheckDisk** Function description* Checks the consistency of the file system.*/staticint_CheckDisk(void){intr;characDirName[FS_MAX_PATH];FS_CHECK_DATACheckData;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.}}returnr;}/*********************************************************************** SampleCheckDiskBG*/voidSampleCheckDiskBG(void){FS_CHECK_DATACheckData;FS_CHECK_DATACheckDataOld;intr;//// 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));}}
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 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().
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.
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.
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.
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.
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.
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().
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.
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.
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_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.
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.
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"voidSampleGetFSType(void){intFSType;#ifFS_SUPPORT_MULTIPLE_FSFSType =FS_GetFSType("");#elseFSType =FS_FAT;#endifFS_X_Log("File system type: ");switch(FSType){caseFS_FAT:FS_X_Log("FAT");break;caseFS_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.
Default value of the maximum logical sector size is 512 bytes.
Refer to FS_SetMaxSectorSize() for more information about
the maximum logical sector size.
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.
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.
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"voidSampleGetNumFilesOpen(void){FS_FILE*pFile1;FS_FILE*pFile2;intNumFileHandles;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.
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.
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.
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.
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.
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"voidSampleGetVolumeFreeSpace(void){charac[100];FS_FREE_SPACE_DATAfsd;intr;FS_DISK_INFOVolumeInfo;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);}
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"voidSampleGetVolumeInfo(void){FS_DISK_INFOVolumeInfo;intr;charac[100];constchar*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){caseFS_TYPE_FAT12:sFSType ="FAT12";break;caseFS_TYPE_FAT16:sFSType ="FAT16";break;caseFS_TYPE_FAT32:sFSType ="FAT32";break;caseFS_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);}}
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.
#include<stdio.h>#include<string.h>#include"FS.h"voidSampleGetVolumeInfoEx(void){FS_DISK_INFOVolumeInfo;intr;charac[100];constchar*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){caseFS_TYPE_FAT12:sFSType ="FAT12";break;caseFS_TYPE_FAT16:sFSType ="FAT16";break;caseFS_TYPE_FAT32:sFSType ="FAT32";break;caseFS_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);}}
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.
out Receives the name of the volume as 0-terminated string. It cannot be NULL.
SizeOfVolumeName
Number of bytes in sVolumeName.
Return value
> 0
Number of bytes in the volume name or number of bytes required to store the volume name.
< 0
An error occurred.
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 sVolumeName 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().
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.
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.
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"voidSampleUnmountForced(void){intIsPresentNew;intIsPresent;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);}}
The function returns 1 if the volume is mounted either in
read-only mode or in read / write mode.
Example
#include"FS.h"voidSampleIsVolumeMounted(void){intIsMounted;IsMounted =FS_IsVolumeMounted("");if(IsMounted){FS_X_Log("Volume is mounted.\n");}else{FS_X_Log("Volume is not mounted.\n");}}
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"voidSampleLock(void){FS_FILE*pFile;FS_NAND_DISK_INFODiskInfo;//// 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 == 1FS_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 == 1pFile =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}
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.
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"voidSampleLockVolume(void){FS_FILE*pFile;FS_NAND_DISK_INFODiskInfo;//// 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 == 2FS_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 == 2pFile =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.
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"staticvoid_cbBusyLED(U8 OnOff){if(OnOff){//// Set LED on.//}else{//// Set LED off.//}}voidSampleSetBusyLEDCallback(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.
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:
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"voidSampleSetFSType(void){//// Format the "nand:0:" volume as EFS.//#ifFS_SUPPORT_MULTIPLE_FSFS_SetFSType("nand:0:",FS_EFS);#endif// FS_SUPPORT_MULTIPLE_FSFS_Format("nand:0:",NULL);//// Format the "nor:0:" volume as FAT.//#ifFS_SUPPORT_MULTIPLE_FSFS_SetFSType("nor:0:",FS_FAT);#endif// FS_SUPPORT_MULTIPLE_FSFS_Format("nor:0:",NULL);}
FS_SetMemCheckCallback()
Description
Registers a callback for checking of 0-copy operations.
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.
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.
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.
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.
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.
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.
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 ErrCodeFS_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.
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.
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.
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.
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.
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.
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.
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().
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.
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"voidSampleStorageClean(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);}}
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.
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"voidSampleStorageCleanOne(void){FS_FILE*pFile;intMoreToClean;//// 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);}}
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.
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"voidSampleStorageDeInit(void){FS_STORAGE_Init();#ifFS_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.
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.
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().
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.
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().
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.
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().
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"voidSampleStorageFreeSectors(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);}
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.
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.
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.
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.
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.
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"voidSampleStorageGetDeviceInfo(void){FS_DEV_INFODeviceInfo;charac[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);}
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.
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.
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"voidSampleStorageGetSectorUsage(void){intSectorUsage;SectorUsage =FS_STORAGE_GetSectorUsage("",7);switch(SectorUsage){caseFS_SECTOR_IN_USE:FS_X_Log("The sector is used to store data.\n");break;caseFS_SECTOR_NOT_USED:FS_X_Log("The sector is not used to store data.\n");break;caseFS_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.
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.
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().
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.
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().
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().
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.
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.
#include"FS.h"voidSampleStorageReadSector(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.
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"voidSampleStorageReadSectors(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.
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"staticU32 _aBuffer[2048*2/4];voidSampleStorageRefreshSectors(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.
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.
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"voidSampleStorageResetCounters(void){FS_STORAGE_COUNTERSStatCnt;//// Set all statistical counters to 0.//FS_STORAGE_ResetCounters();//// Perform the file system operation...////// Check the statistical counters.//FS_STORAGE_GetCounters(&StatCnt);}
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.
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.
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.
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"voidSampleStorageSync(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("");}
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.
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"voidSampleStorageSyncSectors(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.
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.
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"voidSampleStorageUnmount(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.
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"voidSampleStorageUnmountForced(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.
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().
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.
#include<string.h>#include"FS_Storage.h"voidSampleStorageWriteSector(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);}
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().
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"voidSampleStorageWriteSectors(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.
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().
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.
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().
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.
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"voidSampleFATConfigFATCopyMaintenance(void){FS_Init();#ifFS_MAINTAIN_FAT_COPYFS_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.
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.
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.
#include"FS.h"voidSampleFATConfigROFileMovePermission(void){FS_FILE*pFile;intr;#ifFS_FAT_PERMIT_RO_FILE_MOVEFS_FAT_ConfigROFileMovePermission(0);#endifpFile =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.//}}
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.
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().
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.
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.
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"voidSampleFATSupportLFN(void){FS_FILE*pFile;FS_Init();#ifFS_SUPPORT_FATFS_FAT_SupportLFN();#endifpFile =FS_FOpen("This is an unusually long file name","w");if(pFile){FS_FClose(pFile);}}
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.
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.
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.
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.
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.
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.
FS_EXFAT_FormatSD()
Description
Performs a high-level format as per SD Specification.
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().
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.
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.
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"voidSampleClearErr(void){FS_FILE*pFile;U32 aBuffer[32/4];intErrCode;charac[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.
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"voidSampleErrorNo2Text(void){FS_FILE*pFile;intr;charac[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);}}
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"voidSampleFEof(void){FS_FILE*pFile;U32 aBuffer[32/4];intr;intErrCode;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);}}
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.
Value of FS_DIRECTORY_DELIMITER configuration define.
Example
#include<stdio.h>#include"FS.h"voidSampleCONFGetDirectoryDelimiter(void){charac[100];charDelim;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.
#include<stdio.h>#include"FS.h"voidSampleCONFGetMaxPath(void){charac[100];intNumChars;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.
Returns the value of FS_NUM_VOLUMES configuration define.
Example
#include<stdio.h>#include"FS.h"voidSampleCONFGetNumVolumes(void){charac[100];intNumVolumes;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.
#include"FS.h"voidSampleCONFGetOSLocking(void){intLockingType;LockingType =FS_CONF_GetOSLocking();switch(LockingType){caseFS_OS_LOCKING_NONE:FS_X_Log("The file system is not locked against concurrent access.\n");break;caseFS_OS_LOCKING_API:FS_X_Log("The file system is locked at API function level.\n");break;caseFS_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.
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"voidSampleCONFIsCacheSupported(void){intIsSupported;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.
#include"FS.h"voidSampleCONFIsDeInitSupported(void){intIsSupported;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.
#include"FS.h"voidSampleCONFIsEFSSupported(void){intIsSupported;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.
Value of FS_SUPPORT_ENCRYPTION configuration define.
Example
#include"FS.h"voidSampleCONFIsEncryptionSupported(void){intIsSupported;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.
#include"FS.h"voidSampleCONFIsFATSupported(void){intIsSupported;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.
Value of FS_SUPPORT_FREE_SECTOR configuration define.
Example
#include"FS.h"voidSampleCONFIsFreeSectorSupported(void){intIsSupported;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.
#include"FS.h"voidSampleCONFIsJournalSupported(void){intIsSupported;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.
#include"FS.h"voidSampleCONFIsTrialVersion(void){intIsTrial;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");}}
For example 40201 represents the version 4.02a (major version: 4,
minor version: 2, revision: a)
Example
#include<stdio.h>#include"FS.h"voidSampleGetVersion(void){intVersion;intMajorVersion;intMinorVersion;charPatchVersion;charac[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.
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.
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.
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.
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.
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 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.
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.
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:
A read / write cache module with configurable
associativity level.
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.
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
Type of the sector cache to be configured. It can take one of the following values: FS_CACHE_ALLFS_CACHE_MANFS_CACHE_RWFS_CACHE_RW_QUOTAFS_CACHE_MULTI_WAY.
Return value
> 0
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"#defineCACHE_SIZE FS_SIZEOF_CACHE_ALL(200,512)// 200 sectors of 512 bytes.staticU32 _aCache[CACHE_SIZE /4];// Allocate RAM for the cache buffer.voidSampleCacheAssign(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);}
Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used.
Return value
= 0
Success, the cache has been emptied.
≠ 0
An error occurred.
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().
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 returned.
≠ 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>voidSampleCacheGetNumSectors(void){U32 NumSectors;charac[100];FS_CACHE_GetNumSectors("",&NumSectors);SEGGER_snprintf(ac,sizeof(ac),"Number of sectors in cache: %lu\n",NumSectors);FS_X_Log(ac);}
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.
Name of the volume for which the cache should be cleaned. If not specified, the first volume will be used.
Return value
= 0
Success, the cache has been emptied.
≠ 0
An error occurred.
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.
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.
≠ 0
An 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.
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.
≠ 0
An error occurred.
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"#defineCACHE_SIZE FS_SIZEOF_CACHE_MULTI_WAY(200,512)staticU32 _aCache[CACHE_SIZE /4];// Allocate RAM for the cache buffer.voidSampleCacheSetMode(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);}
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.
≠ 0
An error occurred.
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"#defineCACHE_SIZE FS_SIZEOF_CACHE_RW_QUOTA(200,512)staticU32 _acCache[CACHE_SIZE /4];// Allocate RAM for the cache buffer.voidSampleCacheSetQuota(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);}
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 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
Performance and resource usage
Performance
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.cPurpose : 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************************************************************************/#defineVOLUME_NAME ""#defineNUM_FILES 32/*********************************************************************** Static data************************************************************************/staticU32 _aCache[0x400];staticchar_aacFileName[NUM_FILES][13];staticchar_ac[128];/*********************************************************************** Static code************************************************************************//*********************************************************************** _CreateFiles*/staticvoid_CreateFiles(void){inti;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__cplusplusextern"C"{/* Make sure we have C-declarations in C++ programs */#endifvoidMainTask(void);#ifdef__cplusplus}#endifvoidMainTask(void){inti;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().
This chapter describes the file system components that provide access
to a storage device.
General information
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.*/staticint_HW_Write(U8 Unit,constU8 *pData,intNumBytes){intr;//// 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;}}returnr;}
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.*/staticvoid_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.*/staticint_HW_Write(U8 Unit,constU8 *pData,intNumBytes){//// 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.
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.
Formatting
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************************************************************************/#defineALLOC_SIZE 0x1100// Memory pool for the file system in bytes#defineNUM_SECTORS 16// Number of sectors on the RAM storage#defineBYTES_PER_SECTOR 512// Size of a sector in bytes/*********************************************************************** Static data************************************************************************///// Memory pool used for semi-dynamic allocation.//staticU32 _aMemBlock[ALLOC_SIZE /4];//// Memory to be used as storage.//staticU32 _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.*/voidFS_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);#ifFS_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.
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.
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>#defineNUM_SECTORS 16// Number of sectors on the RAM storage#defineBYTES_PER_SECTOR 512// Size of a sector in bytesstaticU32 _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().*/voidFS_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
Fujitsu
MB85RC64TA
64 Kibit
I2C
MB85RS128TY
128 Kibit
SPI
MB85RS1MT
1 Mibit
SPI
MB85RS256TY
256 Kibit
SPI
MB85RS512T
512 Kibit
SPI
Infineon
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************************************************************************/#defineALLOC_SIZE 0x1100// Memory pool for the file system in bytes.#defineNUM_SECTORS 16// Number of sectors on the RAM storage.#defineBYTES_PER_SECTOR 512// Size of a sector in bytes./*********************************************************************** Static data************************************************************************///// Memory pool used for semi-dynamic allocation.//staticU32 _aMemBlock[ALLOC_SIZE /4];//// Memory to be used as storage.//staticU32 _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.*/voidFS_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));#ifFS_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************************************************************************/#defineALLOC_SIZE 0x1100// Memory pool for the file system in bytes.#defineNUM_SECTORS 16// Number of sectors on the RAM storage.#defineBYTES_PER_SECTOR 512// Size of a sector in bytes.#defineDEVICE_ADDRESS 0x50// I2C address of the device.#defineDEVICE_SIZE 8192// Capacity of the device in bytes./*********************************************************************** Static data************************************************************************///// Memory pool used for semi-dynamic allocation.//staticU32 _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.*/voidFS_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);#ifFS_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************************************************************************/#defineALLOC_SIZE 0x1100// Memory pool for the file system in bytes.#defineBYTES_PER_SECTOR 512// Size of a sector in bytes./*********************************************************************** Static data************************************************************************/staticU32 _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.*/voidFS_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);#ifFS_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.
Enables or disables the support for checking if the write operation was successful.
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.
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.
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.
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().
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().
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.
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.
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.
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().
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().
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.
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.
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.
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 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 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.
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.
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.
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.cPurpose : 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 limitationsAdditional 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************************************************************************/#defineRAM_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.*/#defineRAM_SET_SCL()GPIOF_BSRR =1uL<<RAM_SCL_BIT/*********************************************************************** RAM_CLR_SCL** Description* Sets the logic level of SCL signal to low.*/#defineRAM_CLR_SCL()GPIOF_BSRR =1uL<<(RAM_SCL_BIT +16)/*********************************************************************** RAM_SET_SDA** Description* Sets the logic level of SDA signal to high.*/#defineRAM_SET_SDA()GPIOF_BSRR =1uL<<RAM_SDA_BIT/*********************************************************************** RAM_CLR_SDA** Description* Sets the logic level of SDA signal to high.*/#defineRAM_CLR_SDA()GPIOF_BSRR =1uL<<(RAM_SDA_BIT +16)/*********************************************************************** RAM_SET_SDA_TO_INPUT** Description* Configures the direction of the SDA signal to input.*/#defineRAM_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.*/#defineRAM_SET_SDA_TO_OUTPUT()GPIOF_MODER |=MODER_OUT <<(RAM_SDA_BIT <<1)/*********************************************************************** RAM_GET_SDA** Description* Returns the logic level of the SDA signal.*/#defineRAM_GET_SDA()(GPIOF_IDR &(1uL<<RAM_SDA_BIT))/*********************************************************************** Defines, fixed************************************************************************//*********************************************************************** RAM_DELAY** Description* Blocks the execution for a fixed period of time.*/#ifRAM_NUM_DELAY_LOOPS#defineRAM_DELAY()_Delay()#else#defineRAM_DELAY()#endif/*********************************************************************** Port B registers*/#defineGPIOB_BASE_ADDR 0x58020400uL#defineGPIOB_MODER (*(volatileU32 *)(GPIOB_BASE_ADDR +0x00))#defineGPIOB_OTYPE (*(volatileU32 *)(GPIOB_BASE_ADDR +0x04))#defineGPIOB_OSPEEDR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x08))#defineGPIOB_PUPDR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x0C))#defineGPIOB_IDR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x10))#defineGPIOB_ODR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x14))#defineGPIOB_BSRR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x18))#defineGPIOB_AFRL (*(volatileU32 *)(GPIOB_BASE_ADDR +0x20))/*********************************************************************** Port F registers*/#defineGPIOF_BASE_ADDR 0x58021400uL#defineGPIOF_MODER (*(volatileU32 *)(GPIOF_BASE_ADDR +0x00))#defineGPIOF_OTYPE (*(volatileU32 *)(GPIOF_BASE_ADDR +0x04))#defineGPIOF_OSPEEDR (*(volatileU32 *)(GPIOF_BASE_ADDR +0x08))#defineGPIOF_PUPDR (*(volatileU32 *)(GPIOF_BASE_ADDR +0x0C))#defineGPIOF_IDR (*(volatileU32 *)(GPIOF_BASE_ADDR +0x10))#defineGPIOF_ODR (*(volatileU32 *)(GPIOF_BASE_ADDR +0x14))#defineGPIOF_BSRR (*(volatileU32 *)(GPIOF_BASE_ADDR +0x18))#defineGPIOF_AFRL (*(volatileU32 *)(GPIOF_BASE_ADDR +0x20))#defineGPIOF_AFRH (*(volatileU32 *)(GPIOF_BASE_ADDR +0x24))/*********************************************************************** Reset and clock control*/#defineRCC_BASE_ADDR 0x58024400uL#defineRCC_AHB3RSTR (*(volatileU32*)(RCC_BASE_ADDR +0x7C))#defineRCC_AHB3ENR (*(volatileU32*)(RCC_BASE_ADDR +0xD4))#defineRCC_AHB4ENR (*(volatileU32*)(RCC_BASE_ADDR +0xE0))/*********************************************************************** GPIO bit positions of SPI signals*/#defineRAM_SCL_BIT 10// Port F#defineRAM_SDA_BIT 8// Port F#defineRAM_A0_BIT 6// Port B#defineRAM_A1_BIT 9// Port F#defineRAM_A2_BIT 7// Port F#defineRAM_WP_BIT 6// Port F/*********************************************************************** GPIO bits and masks*/#defineOSPEEDR_HIGH 2uL#defineOSPEEDR_MASK 0x3uL#defineMODER_MASK 0x3uL#defineMODER_OUT 1uL#defineMODER_ALT 2uL#defineAFR_MASK 0xFuL#definePUPDR_MASK 0x3uL#definePUPDR_PULLUP 0x1uL/*********************************************************************** Masks for the peripheral enable bits*/#defineAHB1ENR_GPIOBEN_BIT 1#defineAHB1ENR_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.*/staticvoid_Delay(void){volatileinti;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)*/staticint_WriteByte(U8 Data){intr;inti;//// 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 tLOWRAM_SET_SCL();RAM_DELAY();// Wait tHIGHRAM_CLR_SCL();}//// Receive ACK/NACK.//RAM_SET_SDA_TO_INPUT();RAM_DELAY();// Wait tLOWRAM_SET_SCL();RAM_DELAY();// Wait tHIGHr =RAM_GET_SDA();RAM_CLR_SCL();RAM_DELAY();// Wait tLOWRAM_SET_SDA_TO_OUTPUT();returnr;}/*********************************************************************** _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.*/staticU8 _ReadByte(intAckNack){U8 Value;inti;//// Receive data bits with MSB first.//RAM_SET_SDA_TO_INPUT();RAM_DELAY();// Wait tLOWValue =0;for(i =0;i <8;++i){RAM_SET_SCL();RAM_DELAY();// Wait tHIGHValue <<=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 tHIGHRAM_CLR_SCL();returnValue;}/*********************************************************************** 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.*/staticint_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);return0;}/*********************************************************************** _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.*/staticint_HW_Start(U8 Unit,unsignedAddr,intIsRead){intr;U8 AddrByte;FS_USE_PARA(Unit);AddrByte =(U8)(Addr <<1);if(IsRead !=0){AddrByte |=1u;}RAM_SET_SDA();RAM_SET_SCL();RAM_DELAY();// Wait tBUFRAM_CLR_SDA();RAM_DELAY();// Wait tHD;STARAM_CLR_SCL();r =_WriteByte(AddrByte);if(r !=0){return1;}return0;}/*********************************************************************** _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.*/staticint_HW_Stop(U8 Unit){FS_USE_PARA(Unit);RAM_CLR_SDA();RAM_DELAY();// Wait tLOWRAM_SET_SCL();RAM_DELAY();// Wait tSU;STORAM_SET_SDA();return0;}/*********************************************************************** _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.*/staticint_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);}return0;}/*********************************************************************** _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.*/staticint_HW_Write(U8 Unit,constU8 *pData,U32 NumBytes){intr;FS_USE_PARA(Unit);r =0;// Set to indicate success.if(NumBytes !=0u){do{r =_WriteByte(*pData++);if(r !=0){break;}}while(--NumBytes !=0u);}returnr;}/*********************************************************************** Public data************************************************************************//*********************************************************************** FS_RAMDISK_HW_I2C_GPIO_STM32H743_SEGGER_QSPI_Flash_Evaluator*/constFS_RAMDISK_HW_TYPE_I2CFS_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).
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.
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.
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.
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.
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.
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.
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.cPurpose : 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************************************************************************/#ifndefFS_RAMDISK_HW_PER_CLK_HZ#defineFS_RAMDISK_HW_PER_CLK_HZ 240000000// Clock of Quad-SPI unit.#endif#ifndefFS_RAMDISK_HW_RAM_CLK_HZ#defineFS_RAMDISK_HW_RAM_CLK_HZ 48000000// Frequency of the clock supplied to RAM device.#endif#ifndefFS_RAMDISK_HW_QUADSPI_MEM_ADDR#defineFS_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#ifndefFS_RAMDISK_HW_USE_QUAD_MODE#defineFS_RAMDISK_HW_USE_QUAD_MODE 1// Enables/disables the support for quad mode.#endif#ifndefFS_RAMDISK_HW_USE_MEM_MAP_MODE#defineFS_RAMDISK_HW_USE_MEM_MAP_MODE 1// Enables or disables the access to the RAM device data via system memory.#endif#ifndefFS_RAMDISK_HW_RESET_TIME_MS#defineFS_RAMDISK_HW_RESET_TIME_MS 10// Number milliseconds to keep the reset line low.#endif/*********************************************************************** Defines, fixed************************************************************************//*********************************************************************** QSPI registers*/#defineQUADSPI_BASE_ADDR 0x52005000uL#defineQUADSPI_CR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x00))#defineQUADSPI_DCR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x04))#defineQUADSPI_SR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x08))#defineQUADSPI_FCR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x0C))#defineQUADSPI_DLR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x10))#defineQUADSPI_CCR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x14))#defineQUADSPI_AR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x18))#defineQUADSPI_ABR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x1C))#defineQUADSPI_DR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x20))#defineQUADSPI_DR_BYTE (*(volatileU8 *)(QUADSPI_BASE_ADDR +0x20))#defineQUADSPI_PSMKR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x24))#defineQUADSPI_PSMAR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x28))#defineQUADSPI_PIR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x2C))#defineQUADSPI_LPTR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x30))/*********************************************************************** Port B registers*/#defineGPIOB_BASE_ADDR 0x58020400uL#defineGPIOB_MODER (*(volatileU32 *)(GPIOB_BASE_ADDR +0x00))#defineGPIOB_OSPEEDR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x08))#defineGPIOB_PUPDR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x0C))#defineGPIOB_ODR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x14))#defineGPIOB_AFRL (*(volatileU32 *)(GPIOB_BASE_ADDR +0x20))/*********************************************************************** Port F registers*/#defineGPIOF_BASE_ADDR 0x58021400uL#defineGPIOF_MODER (*(volatileU32 *)(GPIOF_BASE_ADDR +0x00))#defineGPIOF_OSPEEDR (*(volatileU32 *)(GPIOF_BASE_ADDR +0x08))#defineGPIOF_PUPDR (*(volatileU32 *)(GPIOF_BASE_ADDR +0x0C))#defineGPIOF_ODR (*(volatileU32 *)(GPIOF_BASE_ADDR +0x14))#defineGPIOF_BSRR (*(volatileU32 *)(GPIOF_BASE_ADDR +0x18))#defineGPIOF_AFRL (*(volatileU32 *)(GPIOF_BASE_ADDR +0x20))#defineGPIOF_AFRH (*(volatileU32 *)(GPIOF_BASE_ADDR +0x24))/*********************************************************************** Reset and clock control*/#defineRCC_BASE_ADDR 0x58024400uL#defineRCC_AHB3RSTR (*(volatileU32*)(RCC_BASE_ADDR +0x7C))#defineRCC_AHB3ENR (*(volatileU32*)(RCC_BASE_ADDR +0xD4))#defineRCC_AHB4ENR (*(volatileU32*)(RCC_BASE_ADDR +0xE0))/*********************************************************************** System Control Block*/#defineSCB_BASE_ADDR 0xE000E000uL#defineSCB_CCR (*(volatileU32 *)(SCB_BASE_ADDR +0xD14))// Configuration Control Register/*********************************************************************** Memory protection unit*/#defineMPU_BASE_ADDR 0xE000ED90uL#defineMPU_TYPE (*(volatileU32 *)(MPU_BASE_ADDR +0x00))#defineMPU_CTRL (*(volatileU32 *)(MPU_BASE_ADDR +0x04))#defineMPU_RNR (*(volatileU32 *)(MPU_BASE_ADDR +0x08))#defineMPU_RBAR (*(volatileU32 *)(MPU_BASE_ADDR +0x0C))#defineMPU_RASR (*(volatileU32 *)(MPU_BASE_ADDR +0x10))/*********************************************************************** Masks for the peripheral enable bits*/#defineAHB1ENR_GPIOBEN 1#defineAHB1ENR_GPIOFEN 5#defineAHB3ENR_QSPIEN 14/*********************************************************************** GPIO bit positions of SPI signals*/#defineRAM_BK1_NCS_BIT 6// Port B#defineRAM_CLK_BIT 10// Port F#defineRAM_BK1_D0_BIT 8// Port F#defineRAM_BK1_D1_BIT 9// Port F#defineRAM_BK1_D2_BIT 7// Port F#defineRAM_BK1_D3_BIT 6// Port F#defineRAM_MP6_BIT 3// Port F#defineRAM_RST_BIT 11// Port F/*********************************************************************** GPIO bits and masks*/#defineOSPEEDR_HIGH 2uL#defineOSPEEDR_MASK 0x3uL#defineMODER_MASK 0x3uL#defineMODER_OUT 1uL#defineMODER_ALT 2uL#defineAFR_MASK 0xFuL/*********************************************************************** Quad-SPI control register*/#defineCR_EN_BIT 0#defineCR_ABORT_BIT 1#defineCR_SSHIFT_BIT 4#defineCR_SMIE_BIT 19#defineCR_APMS_BIT 22#defineCR_PRESCALER_BIT 24#defineCR_PRESCALER_MAX 255/*********************************************************************** Quad-SPI device configuration register*/#defineDCR_CKMODE_BIT 0#defineDCR_FSIZE_BIT 16#defineDCR_FSIZE_MAX 0x1FuL/*********************************************************************** Quad-SPI status register*/#defineSR_TEF_BIT 0#defineSR_TCF_BIT 1#defineSR_SMF_BIT 3#defineSR_TOF_BIT 4#defineSR_BUSY_BIT 5#defineSR_FLEVEL_BIT 8#defineSR_FLEVEL_MASK 0x3FuL/*********************************************************************** Quad-SPI communication configuration register*/#defineCCR_INTRUCTION_BIT 0#defineCCR_IMODE_BIT 8#defineCCR_MODE_NONE 0#defineCCR_MODE_SINGLE 1uL#defineCCR_MODE_DUAL 2uL#defineCCR_MODE_QUAD 3uL#defineCCR_ADMODE_BIT 10#defineCCR_ADSIZE_BIT 12#defineCCR_ADSIZE_MASK 0x03uL#defineCCR_ABMODE_BIT 14#defineCCR_ABSIZE_BIT 16#defineCCR_ABSIZE_MASK 0x03uL#defineCCR_DCYC_BIT 18#defineCCR_DMODE_BIT 24#defineCCR_FMODE_BIT 26#defineCCR_FMODE_WRITE 0x0uL#defineCCR_FMODE_READ 0x1uL#defineCCR_FMODE_POLL 0x2uL#defineCCR_FMODE_MMAP 0x3uL#defineCCR_FMODE_MASK 0x3uL#defineCCR_DDRM_BIT 31/*********************************************************************** MPU defines*/#defineCTRL_ENABLE_BIT 0#defineCTRL_PRIVDEFENA_BIT 2#defineRNR_REGION_MASK 0xFF#defineRASR_ENABLE_BIT 0#defineRASR_SIZE_BIT 1#defineRASR_TEX_BIT 19#defineRASR_AP_BIT 24#defineRASR_XN_BIT 28#defineRASR_AP_FULL 0x3uL#defineTYPE_DREGION_BIT 8#defineTYPE_DREGION_MASK 0xFFuL#defineRBAR_REGION_BIT 0#defineRBAR_REGION_MASK 0x1FuL#defineRBAR_VALID_BIT 5/*********************************************************************** Misc. defines*/#defineNUM_BYTES_FIFO 32#defineCCR_DC_BIT 16#defineQUADSPI_MEM_SIZE_SHIFT 28// Size of the memory region reserved for QUADSPI (256 MB)#defineQUADSPI_PRIO 15#defineCYCLES_PER_MS 150000// Depends on the CPU clock frequency.#defineWAIT_TIMEOUT_MS 500#defineWAIT_TIMEOUT_CYCLES (WAIT_TIMEOUT_MS *CYCLES_PER_MS)/*********************************************************************** Static code************************************************************************//*********************************************************************** _CalcClockDivider** Function description* Calculates the divider for the clock supplied to RAM device.*/staticU8 _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;returnDiv;}/*********************************************************************** _GetMode** Function description* Returns the transfer mode for the QUADSPI peripheral.*/staticU32 _GetMode(unsignedBusWidth,U32 NumBytes){U32 Mode;Mode =CCR_MODE_NONE;if(NumBytes){switch(BusWidth){case1:Mode =CCR_MODE_SINGLE;break;case2:Mode =CCR_MODE_DUAL;break;case4:Mode =CCR_MODE_QUAD;break;default:break;}}returnMode;}/*********************************************************************** _CalcNumCycles** Function description* Calculates the number of clock cycles required to transfer a specified number of bytes.*/staticU32 _CalcNumCycles(unsignedBusWidth,U32 NumBytes,intIsDTRMode){U32 NumCycles;NumCycles =0;if(NumBytes !=0){NumCycles =NumBytes <<3;// Assume 8-bits per byte.switch(BusWidth){case2:NumCycles >>=1;break;case4:NumCycles >>=2;break;default:break;}if(IsDTRMode !=0){NumCycles >>=1;// The data is sent on both clock edges.}}returnNumCycles;}/*********************************************************************** _ClearFlags** Function description* Clears the status flags of QUADSPI peripheral.*/staticint_ClearFlags(void){U32 TimeOut;intr;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;}}returnr;}/*********************************************************************** _Cancel** Function description* Interrupts an ongoing data transfer.*/staticint_Cancel(void){U32 TimeOut;intr;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;}}returnr;}/*********************************************************************** _DisableDCache** Function description* Disables the data cache for the memory region where the RAM device is mapped.*/staticvoid_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.*/staticint_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);#ifFS_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.;#ifFS_RAMDISK_HW_RESET_TIME_MS{volatileU32 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_MSreturn(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.*/staticint_HW_Unmap(U8 Unit){intr;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();}returnr;}#ifFS_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.*/staticint_HW_Map(U8 Unit,constU8 *pCmd,unsignedNumBytesCmd,constU8 *pPara,unsignedNumBytesPara,unsignedNumBytesAddr,U16 BusWidth,unsignedFlags){U32 CfgReg;U32 CmdMode;U32 AddrMode;U32 DataMode;U32 NumDummyCycles;U32 AddrSize;U32 IsDTR;U32 AltMode;U32 AltSize;U32 NumBytesAlt;U32 NumBytes;U32 AltReg;intr;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.gotoDone;}}r =_ClearFlags();if(r !=0){gotoDone;// Error, could not clear status flags.}QUADSPI_ABR =AltReg;QUADSPI_CCR =CfgReg;Done:returnr;}#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.*/staticint_HW_Control(U8 Unit,constU8 *pCmd,unsignedNumBytesCmd,U8 BusWidth,unsignedFlags){U32 CfgReg;U32 CmdMode;U32 TimeOut;intr;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.gotoDone;}}//// Execute the command.//r =_ClearFlags();if(r !=0){gotoDone;// 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:returnr;}/*********************************************************************** _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.*/staticint_HW_Read(U8 Unit,constU8 *pCmd,unsignedNumBytesCmd,constU8 *pPara,unsignedNumBytesPara,unsignedNumBytesAddr,U8 *pData,unsignedNumBytesData,U16 BusWidth,unsignedFlags){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;intr;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.gotoDone;}}//// 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){gotoDone;// 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.gotoDone;}}//// 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);returnr;}/*********************************************************************** _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.*/staticint_HW_Write(U8 Unit,constU8 *pCmd,unsignedNumBytesCmd,constU8 *pPara,unsignedNumBytesPara,unsignedNumBytesAddr,constU8 *pData,unsignedNumBytesData,U16 BusWidth,unsignedFlags){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;intr;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.gotoDone;}}//// Execute the command.//r =_ClearFlags();if(r !=0){gotoDone;// 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.gotoDone;}}//// 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:returnr;}/*********************************************************************** Global data************************************************************************//*********************************************************************** FS_RAMDISK_HW_SPI_STM32H743_SEGGER_QSPI_Flash_Evaluator*/constFS_RAMDISK_HW_TYPE_SPIFS_RAMDISK_HW_SPI_STM32H743_SEGGER_QSPI_Flash_Evaluator ={_HW_Init,_HW_Unmap,#ifFS_RAMDISK_HW_USE_MEM_MAP_MODE_HW_Map,#elseNULL,#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.
Low-level format
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
ATO
AFND1G08U3
2048+64 byte
1024
128 MiB
16 bit
Dialog Semiconductor/Adesto/Atmel
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
Hynix
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
Kioxia/Toshiba
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
Micron
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
STMicroelectronics
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
Samsung
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
SkyHigh/Cypress
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
Winbond
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.
Enables or disables the verification of the write operation.
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"#defineALLOC_SIZE 0x9000// Memory pool for the file system in bytesstaticU32 _aMemBlock[ALLOC_SIZE /4];// Memory pool used for semi-dynamic allocation.voidFS_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);#ifFS_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().
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>voidFS_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>voidFS_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.
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.
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.
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.
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>voidFS_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.
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.
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.
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.
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.
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.
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.
FS_NAND_FormatLow()
Description
Performs a low-level format of the NAND flash device.
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().
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 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.
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.
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){intr;U32 NumPhyBlocks;U32 iBlock;FS_NAND_DISK_INFODiskInfo;FS_NAND_TEST_INFOTestInfo;charac[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){caseFS_NAND_TEST_RETVAL_OK:SEGGER_snprintf(ac,sizeof(ac),"Block %lu: OK.\n",iBlock);FS_X_Log(ac);break;caseFS_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;caseFS_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;caseFS_NAND_TEST_RETVAL_BAD_BLOCK:SEGGER_snprintf(ac,sizeof(ac),"Block %lu: Bad. Skipped.\n",iBlock);FS_X_Log(ac);break;caseFS_NAND_TEST_RETVAL_ERASE_FAILURE:SEGGER_snprintf(ac,sizeof(ac),"Block %lu: Erase failure. Marked as bad.\n",iBlock);FS_X_Log(ac);break;caseFS_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;caseFS_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;}}}
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.
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.
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:
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
ATO
AFND1G08U3
2048+64 byte
1024
128 MiB
16 bit
No
Alliance Memory
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
GigaDevice
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
Hynix
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
ISSI
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
Kioxia/Toshiba
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
Macronix
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
Micron
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
STMicroelectronics
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
Samsung
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
SkyHigh/Cypress
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
Winbond
W25M02GVZEIT
2048+64 byte
2048
256 MiB
1 bit
Yes
W25N01GVZEIG
2048+64 byte
1024
128 MiB
1 bit
Yes
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
XTX
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.
Enables or disables the verification of the write operation.
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"#defineALLOC_SIZE 0x9000// Memory pool for the file system in bytesstaticU32 _aMemBlock[ALLOC_SIZE /4];// Memory pool used for semi-dynamic allocation.voidFS_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);#ifFS_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().
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.
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.
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.
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.
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"voidSampleNAND_UNISetCleanThreshold(void){unsignedNumPhyBlocks;unsignedNumWorkBlocks;FS_FILE*pFile;FS_NAND_DISK_INFODiskInfo;FS_NAND_BLOCK_INFOBlockInfo;U32 BlockIndex;unsignedMaxNumSectors;unsignedNumSectorsValid;charac[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:1Max.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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
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.
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.
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.
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.
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() 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.
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.
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.
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.
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.
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.
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.
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.
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.
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:
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.
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().
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.
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.
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().
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().
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.
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.
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().
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().
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.
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().
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.
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.
Specifies if the extended ONFI parameters have to be evaluated or not.
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().
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.
Specifies if the internal page register of the NAND flash should be used as read cache.
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().
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().
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.
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.
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.
Specifies if the internal page register of the NAND flash should be used as read cache.
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().
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().
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.
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.
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.
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().
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.
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.
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().
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.
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.
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:
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.
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.
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.
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
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.
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
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.
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.
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.
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.
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.
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.
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().
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.
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.
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.
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.
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() 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"#defineALLOC_SIZE 0x4000// Memory pool for the file system in bytesstaticU32 _aMemBlock[ALLOC_SIZE /4];// Memory pool used for semi-dynamic allocation./*********************************************************************** FS_X_AddDevices*/voidFS_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);}elseif(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);}}
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"#defineALLOC_SIZE 0x4000// Memory pool for the file system in bytesstaticU32 _aMemBlock[ALLOC_SIZE /4];// Memory pool used for semi-dynamic allocation./*********************************************************************** FS_X_AddDevices*/voidFS_X_AddDevices(void){intr;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);}}
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 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 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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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.cPurpose : 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************************************************************************/#ifndefFS_NAND_HW_USE_OS#defineFS_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************************************************************************/#ifFS_NAND_HW_USE_OS#include"RTOS.h"#include"FS_OS.h"#endif// FS_NAND_HW_USE_OS/*********************************************************************** Defines, fixed************************************************************************//*********************************************************************** Port pins*/#defineNAND_CS_PIN 0#defineNAND_WAIT_PIN 1#defineNAND_ALE_PIN 4#defineNAND_CLE_PIN 5#defineNAND_nOE_PIN 6#defineNAND_nWE_PIN 7#defineNAND_DATA_MASK 0xff#defineNAND_D0_SHIFT 8#defineNAND_D0_PIN 8#defineNAND_D1_PIN 9#defineNAND_D2_PIN 10#defineNAND_D3_PIN 11#defineNAND_D4_PIN 12#defineNAND_D5_PIN 13#defineNAND_D6_PIN 14#defineNAND_D7_PIN 15/*********************************************************************** Macros for pin configuration*/#defineSET_DATA2INPUT()GPIOD_PDDR &=~(NAND_DATA_MASK <<NAND_D0_SHIFT)#defineSET_DATA2OUTPUT()GPIOD_PDDR |=(NAND_DATA_MASK <<NAND_D0_SHIFT)/*********************************************************************** Macros for pin control*/#defineNAND_GET_DATA(Data)Data =*((volatileU8 *)&GPIOD_PDIR +0x1);#defineNAND_SET_DATA(Data)*((volatileU8 *)&GPIOD_PDOR +0x1)=Data;#defineNAND_SET_ALE()GPIOD_PSOR =(1<<NAND_ALE_PIN);#defineNAND_CLR_ALE()GPIOD_PCOR =(1<<NAND_ALE_PIN);#defineNAND_SET_CLE()GPIOD_PSOR =(1<<NAND_CLE_PIN);#defineNAND_CLR_CLE()GPIOD_PCOR =(1<<NAND_CLE_PIN);#defineNAND_SET_CE()GPIOD_PSOR =(1<<NAND_CS_PIN);#defineNAND_CLR_CE()GPIOD_PCOR =(1<<NAND_CS_PIN);#defineNAND_SET_RE()GPIOD_PSOR =(1<<NAND_nOE_PIN);#defineNAND_CLR_RE()GPIOD_PCOR =(1<<NAND_nOE_PIN);#defineNAND_SET_WE()GPIOD_PSOR =(1<<NAND_nWE_PIN);#defineNAND_CLR_WE()GPIOD_PCOR =(1<<NAND_nWE_PIN);#defineNAND_GET_BUSY()(GPIOD_PDIR &(1<<NAND_WAIT_PIN))#defineNAND_NOP()__asm("nop")/*********************************************************************** Misc. defines*/#definePORTD_IRQ_PRIO 15#defineWAIT_TIMEOUT_MS 1000// Maximum time to wait for the NAND// flash device to become ready.#defineNUM_LOOPS_TWB 17// Delay for tWB time./*********************************************************************** Static data************************************************************************/#if(FS_NAND_HW_USE_OS ==2)staticU8 _IsEventInited =0;staticOS_EVENT _Event;#endif// FS_NAND_HW_USE_OS == 2/*********************************************************************** Static code************************************************************************/#ifFS_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.*/staticint_WaitForEvent(U32 TimeOut){intr;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);#elser =FS_OS_Wait(TimeOut);#endifif(r !=0){PORTD_PCR1 &=~PORT_PCR_IRQC_MASK;// Disable the interrupt.PORTD_PCR1 |=PORT_PCR_ISF_MASK;}returnr;}#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)*/staticvoid_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)*/staticvoid_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)*/staticvoid_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)*/staticvoid_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)*/staticvoid_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.*/staticvoid_HW_Read_x8(U8 Unit,void*p,unsignedNumBytes){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.*/staticvoid_HW_Write_x8(U8 Unit,constvoid*p,unsignedNumBytes){constU8 *pData;FS_USE_PARA(Unit);pData =(constU8 *)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)*/staticvoid_HW_Init_x8(U8 Unit){FS_USE_PARA(Unit);#ifFS_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 DPORTD_PCR0 =PORT_PCR_MUX(0x01);// Configure as GPIOPORTD_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 GPIOPORTD_PCR5 =PORT_PCR_MUX(0x01);// Configure as GPIOPORTD_PCR6 =PORT_PCR_MUX(0x01);// Configure as GPIOPORTD_PCR7 =PORT_PCR_MUX(0x01);// Configure as GPIOPORTD_PCR8 =PORT_PCR_MUX(0x01);// Configure as GPIOPORTD_PCR9 =PORT_PCR_MUX(0x01);// Configure as GPIOPORTD_PCR10 =PORT_PCR_MUX(0x01);// Configure as GPIOPORTD_PCR11 =PORT_PCR_MUX(0x01);// Configure as GPIOPORTD_PCR12 =PORT_PCR_MUX(0x01);// Configure as GPIOPORTD_PCR13 =PORT_PCR_MUX(0x01);// Configure as GPIOPORTD_PCR14 =PORT_PCR_MUX(0x01);// Configure as GPIOPORTD_PCR15 =PORT_PCR_MUX(0x01);// Configure as GPIOGPIOD_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 RENAND_SET_WE();// Disable WENAND_SET_CLE();// Disable CLENAND_SET_ALE();// Disable ALENAND_SET_CE();// Disable CE#ifFS_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 == 2NVIC_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.*/staticint_HW_WaitWhileBusy(U8 Unit,unsignedus){volatileintNumLoops;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;}#ifFS_NAND_HW_USE_OS(void)_WaitForEvent(WAIT_TIMEOUT_MS);#elseNAND_NOP();#endif// FS_NAND_HW_USE_OS}return0;}/*********************************************************************** Public code************************************************************************/#ifFS_NAND_HW_USE_OS/*********************************************************************** PORTD_IRQHandler*/voidPORTD_IRQHandler(void);voidPORTD_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);#elseFS_OS_Signal();#endifOS_LeaveNestableInterrupt();}#endif// FS_NAND_HW_USE_OS/*********************************************************************** Public data************************************************************************//*********************************************************************** FS_NAND_HW_K66_SEGGER_emPower*/constFS_NAND_HW_TYPEFS_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.
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).
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.
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.
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.
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.cPurpose : DataFlash hardware layer for NXP LPC4322.Literature: [1] UM10503 LPC43xx ARM Cortex-M4/M0 multi-core microcontroller*//*********************************************************************** #include section************************************************************************/#include"FS.h"/*********************************************************************** Defines, configurable************************************************************************/#definePER_CLK_HZ 180000000uL// Frequency of the clock supplied to SPI unit#ifndefSPI_CLK_HZ#defineSPI_CLK_HZ 25000000uL// Frequency of the clock supplied to DataFlash device#endif#defineRESET_DELAY_LOOPS 100000// Number of software loops to wait for DataFlash to reset/*********************************************************************** Defines, non-configurable************************************************************************//*********************************************************************** SPI unit*/#defineSPI_BASE_ADDR 0x40100000#defineSPI_CR (*(volatileU32*)(SPI_BASE_ADDR +0x00))// SPI Control Register#defineSPI_SR (*(volatileU32*)(SPI_BASE_ADDR +0x04))// SPI Status Register#defineSPI_DR (*(volatileU32*)(SPI_BASE_ADDR +0x08))// SPI Data Register#defineSPI_CCR (*(volatileU32*)(SPI_BASE_ADDR +0x0C))// SPI Clock Counter Register#defineSPI_TCR (*(volatileU32*)(SPI_BASE_ADDR +0x10))// SPI Test Control register#defineSPI_TSR (*(volatileU32*)(SPI_BASE_ADDR +0x14))// SPI Test Status register#defineSPI_INT (*(volatileU32*)(SPI_BASE_ADDR +0x1C))// SPI Interrupt Flag/*********************************************************************** Clock generation unit*/#defineCGU_BASE_ADDR 0x40050000#defineBASE_SPI_CLK (*(volatileU32*)(CGU_BASE_ADDR +0x0074))/*********************************************************************** Clock control unit 1*/#defineCCU1_BASE_ADDR 0x40051000#defineCLK_SPI_CFG (*(volatileU32*)(CCU1_BASE_ADDR +0x0A00))#defineCLK_SPI_STAT (*(volatileU32*)(CCU1_BASE_ADDR +0x0A04))/*********************************************************************** System control unit*/#defineSCU_BASE_ADDR 0x40086000#defineSFSP3_2 (*(volatileU32*)(SCU_BASE_ADDR +0x188))// Pin configuration register for pin P3_2#defineSFSP3_3 (*(volatileU32*)(SCU_BASE_ADDR +0x18C))// Pin configuration register for pin P3_3#defineSFSP3_6 (*(volatileU32*)(SCU_BASE_ADDR +0x198))// Pin configuration register for pin P3_6#defineSFSP3_7 (*(volatileU32*)(SCU_BASE_ADDR +0x19C))// Pin configuration register for pin P3_7#defineSFSP3_8 (*(volatileU32*)(SCU_BASE_ADDR +0x1A0))// Pin configuration register for pin P3_8/*********************************************************************** GPIO unit*/#defineGPIO_BASE_ADDR 0x400F4000#defineGPIO_DIR5 (*(volatileU32*)(GPIO_BASE_ADDR +0x2014))// Direction registers port 5#defineGPIO_SET5 (*(volatileU32*)(GPIO_BASE_ADDR +0x2214))// Set register for port 5#defineGPIO_CLR5 (*(volatileU32*)(GPIO_BASE_ADDR +0x2294))// Clear register for port 5/*********************************************************************** Misc. defines*/#defineCGU_IDIV_BIT 2#defineCGU_AUTOBLOCK_BIT 11#defineCGU_CLK_SEL_BIT 24#defineSFS_MODE_BIT 0#defineSFS_EPUN_BIT 4#defineSFS_EHS_BIT 5#defineSFS_EZI_BIT 6#defineSFS_ZIF_BIT 7#defineCLK_STAT_RUN_BIT 0#defineCLK_CFG_RUN_BIT 0#defineNOR_CS_BIT 11#defineCR_MSTR_BIT 5#defineSR_SPIF 7#defineCCR_COUNTER_MAX 0xFE// The actual maximum value is 0xFF but it has to be a multiple of 2#defineNOR_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.*/staticU32 _SetSpeed(unsignedMaxFreq_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;returnFreq_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*/staticU8 _Transfer8Bits(U8 Data){SPI_DR =Data;while(1){if(SPI_SR &(1uL<<SR_SPIF)){break;}}Data =SPI_DR;returnData;}/*********************************************************************** 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*/staticint_HW_Init(U8 Unit){unsignedNumLoops;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);return0;}/*********************************************************************** _HW_EnableCS** Function description* Sets the device active using the chip select (CS) line.** Parameters* Unit Device index*/staticvoid_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*/staticvoid_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*/staticvoid_HW_Read(U8 Unit,U8 *pData,intNumBytes){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*/staticvoid_HW_Write(U8 Unit,constU8 *pData,intNumBytes){FS_USE_PARA(Unit);do{(void)_Transfer8Bits(*pData++);}while(--NumBytes);}/*********************************************************************** Public data************************************************************************/constFS_NAND_HW_TYPE_DFFS_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.
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.
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.
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().
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.
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.
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.
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.
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.
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.cPurpose : 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************************************************************************/#ifndefFS_NAND_HW_PER_CLK_HZ#defineFS_NAND_HW_PER_CLK_HZ 240000000// Clock of Quad-SPI unit#endif#ifndefFS_NAND_HW_NAND_CLK_HZ#defineFS_NAND_HW_NAND_CLK_HZ 48000000// Frequency of the clock// supplied to NAND flash device#endif#ifndefFS_NAND_HW_CYCLES_PER_MS#defineFS_NAND_HW_CYCLES_PER_MS 10000// Number of software loops// create a 1ms delay#endif/*********************************************************************** Defines, fixed************************************************************************//*********************************************************************** QSPI registers*/#defineQUADSPI_BASE_ADDR 0x52005000uL#defineQUADSPI_CR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x00))#defineQUADSPI_DCR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x04))#defineQUADSPI_SR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x08))#defineQUADSPI_FCR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x0C))#defineQUADSPI_DLR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x10))#defineQUADSPI_CCR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x14))#defineQUADSPI_AR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x18))#defineQUADSPI_ABR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x1C))#defineQUADSPI_DR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x20))#defineQUADSPI_DR_BYTE (*(volatileU8 *)(QUADSPI_BASE_ADDR +0x20))#defineQUADSPI_PSMKR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x24))#defineQUADSPI_PSMAR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x28))#defineQUADSPI_PIR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x2C))#defineQUADSPI_LPTR (*(volatileU32 *)(QUADSPI_BASE_ADDR +0x30))/*********************************************************************** Port B registers*/#defineGPIOB_BASE_ADDR 0x58020400uL#defineGPIOB_MODER (*(volatileU32 *)(GPIOB_BASE_ADDR +0x00))#defineGPIOB_OSPEEDR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x08))#defineGPIOB_PUPDR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x0C))#defineGPIOB_ODR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x14))#defineGPIOB_AFRL (*(volatileU32 *)(GPIOB_BASE_ADDR +0x20))/*********************************************************************** Port F registers*/#defineGPIOF_BASE_ADDR 0x58021400uL#defineGPIOF_MODER (*(volatileU32 *)(GPIOF_BASE_ADDR +0x00))#defineGPIOF_OSPEEDR (*(volatileU32 *)(GPIOF_BASE_ADDR +0x08))#defineGPIOF_PUPDR (*(volatileU32 *)(GPIOF_BASE_ADDR +0x0C))#defineGPIOF_ODR (*(volatileU32 *)(GPIOF_BASE_ADDR +0x14))#defineGPIOF_AFRL (*(volatileU32 *)(GPIOF_BASE_ADDR +0x20))#defineGPIOF_AFRH (*(volatileU32 *)(GPIOF_BASE_ADDR +0x24))/*********************************************************************** Reset and clock control*/#defineRCC_BASE_ADDR 0x58024400uL#defineRCC_AHB3RSTR (*(volatileU32*)(RCC_BASE_ADDR +0x7C))#defineRCC_AHB3ENR (*(volatileU32*)(RCC_BASE_ADDR +0xD4))#defineRCC_AHB4ENR (*(volatileU32*)(RCC_BASE_ADDR +0xE0))/*********************************************************************** Masks for the peripheral enable bits*/#defineAHB4ENR_GPIOBEN 1#defineAHB4ENR_GPIOFEN 5#defineAHB3ENR_QSPIEN 14/*********************************************************************** GPIO bit positions of SPI signals*/#defineNAND_BK1_NCS_BIT 6// Port B#defineNAND_CLK_BIT 10// Port F#defineNAND_BK1_D0_BIT 8// Port F#defineNAND_BK1_D1_BIT 9// Port F#defineNAND_BK1_D2_BIT 7// Port F#defineNAND_BK1_D3_BIT 6// Port F/*********************************************************************** GPIO bits and masks*/#defineOSPEEDR_HIGH 2uL#defineOSPEEDR_MASK 0x3uL#defineMODER_MASK 0x3uL#defineMODER_ALT 2uL#defineAFR_MASK 0xFuL/*********************************************************************** Quad-SPI control register*/#defineCR_EN_BIT 0#defineCR_ABORT_BIT 1#defineCR_PRESCALER_BIT 24#defineCR_PRESCALER_MAX 255/*********************************************************************** Quad-SPI device configuration register*/#defineDCR_CKMODE_BIT 0#defineDCR_FSIZE_BIT 16#defineDCR_FSIZE_MAX 0x1FuL/*********************************************************************** Quad-SPI status register*/#defineSR_TEF_BIT 0#defineSR_TCF_BIT 1#defineSR_SMF_BIT 3#defineSR_TOF_BIT 4#defineSR_BUSY_BIT 5#defineSR_FLEVEL_BIT 8#defineSR_FLEVEL_MASK 0x3FuL/*********************************************************************** Quad-SPI communication configuration register*/#defineCCR_INTRUCTION_BIT 0#defineCCR_IMODE_BIT 8#defineCCR_MODE_NONE 0#defineCCR_MODE_SINGLE 1uL#defineCCR_MODE_DUAL 2uL#defineCCR_MODE_QUAD 3uL#defineCCR_ADMODE_BIT 10#defineCCR_ADSIZE_BIT 12#defineCCR_ADSIZE_MASK 0x03uL#defineCCR_ABMODE_BIT 14#defineCCR_ABSIZE_BIT 16#defineCCR_ABSIZE_MASK 0x03uL#defineCCR_DCYC_BIT 18#defineCCR_DMODE_BIT 24#defineCCR_FMODE_BIT 26#defineCCR_FMODE_WRITE 0x0uL#defineCCR_FMODE_READ 0x1uL#defineCCR_FMODE_MMAP 0x3uL#defineCCR_FMODE_MASK 0x3uL/*********************************************************************** Misc. defines*/#defineNUM_BYTES_FIFO 32/*********************************************************************** ASSERT_IS_LOCKED*/#ifFS_SUPPORT_TEST#defineASSERT_IS_LOCKED() \if(_LockCnt !=1){ \FS_X_PANIC(FS_ERRCODE_INVALID_USAGE); \}#else#defineASSERT_IS_LOCKED()#endif/*********************************************************************** IF_TEST*/#ifFS_SUPPORT_TEST#defineIF_TEST(Expr)Expr#else#defineIF_TEST(Expr)#endif/*********************************************************************** Static data************************************************************************/#ifFS_SUPPORT_TESTstaticU8 _LockCnt =0;// Just to test if the Lock()/Unlock// function are called correctly.#endif/*********************************************************************** Static code************************************************************************//*********************************************************************** _CalcClockDivider*/staticU8 _CalcClockDivider(U32 *pFreq_Hz){U8 Div;U32 Freq_Hz;U32 MaxFreq_Hz;Div =0;MaxFreq_Hz =*pFreq_Hz;while(1){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;returnDiv;}/*********************************************************************** _GetMode*/staticU32 _GetMode(unsignedBusWidth,U32 NumBytes){U32 Mode;Mode =CCR_MODE_NONE;if(NumBytes){switch(BusWidth){case1:Mode =CCR_MODE_SINGLE;break;case2:Mode =CCR_MODE_DUAL;break;case4:Mode =CCR_MODE_QUAD;break;default:break;}}returnMode;}/*********************************************************************** _GetNumCycles*/staticU32 _GetNumCycles(unsignedBusWidth,U32 NumBytes){U32 NumCycles;NumCycles =0;if(NumBytes){NumCycles =NumBytes <<3;// Assume 8-bits per byte.switch(BusWidth){case2:NumCycles >>=1;break;case4:NumCycles >>=2;break;default:break;}}returnNumCycles;}/*********************************************************************** _ClearFlags*/staticvoid_ClearFlags(void){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.//while(1){if((QUADSPI_SR &((1uL<<SR_TEF_BIT)|(1uL<<SR_TCF_BIT)|(1uL<<SR_SMF_BIT)|(1uL<<SR_TOF_BIT)))==0){break;}}}/*********************************************************************** Public code (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.** Additional information* _HW_Init() is mandatory and it has to be implemented by any* hardware layer. The QSPI NAND physical layer calls this function* first before any other function of the hardware layer. This function* has to configure anything necessary for the data transfer via QSPI* such as clocks, port pins, QSPI peripheral, DMA, etc.*/staticint_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<<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.//while(1){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);//// 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.;return(int)Freq_Hz /1000;}/*********************************************************************** _HW_ExecCmd** 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.** Additional information* This function is mandatory and it has to be implemented by any* hardware layer.*/staticint_HW_ExecCmd(U8 Unit,U8 Cmd,U8 BusWidth){U32 CfgReg;U32 CmdMode;ASSERT_IS_LOCKED();FS_USE_PARA(Unit);// This device has only one HW unit.//// Fill local variables.//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.//while(1){if((QUADSPI_SR &(1uL<<SR_BUSY_BIT))==0){break;}}//// Execute the command.//QUADSPI_DLR =0;QUADSPI_ABR =0;QUADSPI_CCR =CfgReg;//// Wait until the command has been completed.//while(1){if((QUADSPI_SR &(1uL<<SR_BUSY_BIT))==0){break;}}return0;}/*********************************************************************** _HW_ReadData** 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.** Additional information* This function is mandatory and it has to be implemented by any* hardware layer.*/staticint_HW_ReadData(U8 Unit,U8 Cmd,constU8 *pPara,unsignedNumBytesPara,unsignedNumBytesAddr,U8 *pData,unsignedNumBytesData,U16 BusWidth){U32 AddrReg;U32 AltReg;U32 CfgReg;U32 DataMode;U32 AddrMode;U32 CmdMode;U32 DataReg;U32 NumCyclesDummy;U32 AddrSize;U32 NumBytesAvail;U32 NumBytes;U32 NumBytesDummy;ASSERT_IS_LOCKED();FS_USE_PARA(Unit);// This device has only one HW unit.//// Fill local variables.//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 =_GetNumCycles(FS_BUSWIDTH_GET_ADDR(BusWidth),NumBytesDummy);// 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)|(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.//while(1){if((QUADSPI_SR &(1uL<<SR_BUSY_BIT))==0){break;}}//// Execute the command.//_ClearFlags();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.//while(1){NumBytesAvail =(QUADSPI_SR >>SR_FLEVEL_BIT)&SR_FLEVEL_MASK;if((NumBytesAvail >=4)||(NumBytesAvail >=NumBytesData)){break;}}//// 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.//while(1){if(QUADSPI_SR &(1uL<<SR_TCF_BIT)){break;}}return0;}/*********************************************************************** _HW_WriteData** 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.** Additional information* This function is mandatory and it has to be implemented by any* hardware layer.*/staticint_HW_WriteData(U8 Unit,U8 Cmd,constU8 *pPara,unsignedNumBytesPara,unsignedNumBytesAddr,constU8 *pData,unsignedNumBytesData,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;ASSERT_IS_LOCKED();FS_USE_PARA(Unit);// This device has only one HW unit.//// Fill local variables.//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 =_GetNumCycles(FS_BUSWIDTH_GET_ADDR(BusWidth),NumBytesDummy);// 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.//while(1){if((QUADSPI_SR &(1uL<<SR_BUSY_BIT))==0){break;}}//// Execute the command.//_ClearFlags();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.//while(1){NumBytesFree =(QUADSPI_SR >>SR_FLEVEL_BIT)&SR_FLEVEL_MASK;NumBytesFree =NUM_BYTES_FIFO -NumBytesFree;if((NumBytesFree >=4)||(NumBytesFree >=NumBytesData)){break;}}//// 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.//while(1){if(QUADSPI_SR &(1uL<<SR_TCF_BIT)){break;}}return0;}/*********************************************************************** _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.*/staticvoid_HW_Delay(U8 Unit,intms){FS_USE_PARA(Unit);if(ms){volatileU32 NumCycles;do{NumCycles =FS_NAND_HW_CYCLES_PER_MS;do{;}while(--NumCycles);}while(--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.** Additional information* This function is optional and it can be left unimplemented* or set to NULL in the structure of the hardware layer below.*/staticint_HW_Poll(U8 Unit,U8 Cmd,constU8 *pPara,unsignedNumBytesPara,U8 BitPos,U8 BitValue,U32 Delay_ms,U32 TimeOut_ms,U16 BusWidth){FS_USE_PARA(Unit);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);return-1;}/*********************************************************************** _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.*/staticvoid_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.*/staticvoid_HW_Unlock(U8 Unit){FS_USE_PARA(Unit);ASSERT_IS_LOCKED();IF_TEST(_LockCnt--);}/*********************************************************************** Public const************************************************************************//*********************************************************************** FS_NAND_HW_QSPI_STM32H743_SEGGER_QSPI_Flash_Evaluator*/constFS_NAND_HW_TYPE_QSPIFS_NAND_HW_QSPI_STM32H743_SEGGER_QSPI_Flash_Evaluator ={_HW_Init,_HW_ExecCmd,_HW_ReadData,_HW_WriteData,_HW_Poll,_HW_Delay,_HW_Lock,_HW_Unlock};/*************************** 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.
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.
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.
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.
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.
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.
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.
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.
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
Cypress/Spansion
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
Dialog Semiconductor/Adesto/Atmel
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
Eon
EN25QH128A
128 Mibit
SPI
extended SPI
EN25QX64A
64 Mibit
SPI
extended SPI
GigaDevice
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
ISSI
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
Macronix
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
Microchip
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
Micron
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
STMicroelectronics
M95P16
16 Mibit
SPI
extended SPI
M95P32
32 Mibit
SPI
extended SPI
Winbond
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.
Reads back and compares the sector data to check it the erase operation was successful.
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
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"#defineALLOC_SIZE 0x4000// Size defined in bytes#defineBYTES_PER_SECTOR 2048staticU32 _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().*/voidFS_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().
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"#defineALLOC_SIZE 0x2000// Size defined in bytesstaticU32 _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().*/voidFS_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"#defineALLOC_SIZE 0x4000// Size defined in bytesstaticU32 _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().*/voidFS_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"#defineALLOC_SIZE 0x4000// Size defined in bytesstaticU32 _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().*/voidFS_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);}
FS_NOR_ConfigureReserve()
Description
Configures the number of logical sectors to be reserved.
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.
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.
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.
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.
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.
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.
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.
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.
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.
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"#defineALLOC_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//#defineFLASH_BASE_ADDR 0x80000000#defineFLASH_VOLUME_0_START_ADDR 0x80000000#defineFLASH_VOLUME_0_SIZE 0x00100000// 1 MByte#defineFLASH_VOLUME_1_START_ADDR 0x80100000#defineFLASH_VOLUME_1_SIZE 0x00080000// 0.5 MBytestaticU32 _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().*/voidFS_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"#defineALLOC_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//#defineFLASH0_BASE_ADDR 0x80000000#defineFLASH_VOLUME_0_START_ADDR FLASH0_BASE_ADDR#defineFLASH_VOLUME_0_SIZE 0xFFFFFFFF// Use the complete flash#defineFLASH1_BASE_ADDR 0x40000000#defineFLASH_VOLUME_1_START_ADDR FLASH1_BASE_ADDR#defineFLASH_VOLUME_1_SIZE 0xFFFFFFFF// Use the complete flashstaticU32 _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().*/voidFS_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"#defineALLOC_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//#defineFLASH0_BASE_ADDR 0x80000000#defineFLASH_VOLUME_0_START_ADDR FLASH0_BASE_ADDR#defineFLASH_VOLUME_0_SIZE 0xFFFFFFFF// Use the complete flash#defineFLASH1_BASE_ADDR 0x40000000#defineFLASH_VOLUME_1_START_ADDR FLASH1_BASE_ADDR#defineFLASH_VOLUME_1_SIZE 0xFFFFFFFF// Use the complete flashstaticU32 _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().*/voidFS_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.
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().
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.
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"voidSampleNORGetDiskInfo(void){intr;charac[128];FS_NOR_DISK_INFODiskInfo;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.
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"voidSampleNORGetDiskInfo(void){charac[128];FS_NOR_SECTOR_INFOSectorInfo;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);}
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.
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.
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.
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.
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:
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.
Enables or disables the support for checking if the erase operation was successful.
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
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
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"#defineALLOC_SIZE 0x4000// Size defined in bytesstaticU32 _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().*/voidFS_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_BM_Driver);FS_NOR_BM_SetPhyType(0,&FS_NOR_PHY_ST_M25);FS_NOR_BM_Configure(0,0x00000000,0x00010000,0x00100000);}
The API functions listed in the next table can be used by the application to
configure the behavior of the Block Map NOR driver. The application can call
them only at the file system initialization in FS_X_AddDevices().
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 Block 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 Block 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 Block Map NOR driver can work only with physical sectors
of the same size. The longest continuous range of physical sectors
with the same size is chosen that fits in the range defined by
StartAddr and NumBytes parameters.
Example
#include"FS.h"#include"FS_NOR_HW_SPIFI_Template.h"#defineALLOC_SIZE 0x4000// Size defined in bytesstaticU32 _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().*/voidFS_X_AddDevices(void){//// Give file system memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Configure the size of the logical sector and activate the file buffering.//FS_SetMaxSectorSize(512);FS_ConfigFileBufferDefault(512,FS_FILE_BUFFER_WRITE);//// Add and configure the NOR driver.//FS_AddDevice(&FS_NOR_BM_Driver);FS_NOR_BM_SetPhyType(0,&FS_NOR_PHY_SPIFI);FS_NOR_BM_Configure(0,0x80000000,0x80000000,0x01000000);FS_NOR_BM_SetSectorSize(0,512);//// Configure the NOR physical layer.//FS_NOR_SPIFI_Allow2bitMode(0,1);FS_NOR_SPIFI_Allow4bitMode(0,1);FS_NOR_SPIFI_SetHWType(0,&FS_NOR_HW_SPIFI_Template);}
The support for data integrity check is not available by default and
it has to be included at compile time via the FS_NOR_SUPPORT_CRC define.
This function disables the data integrity check for all instances
of the NOR driver.
The support for data integrity check is not available by default and
it has to be included at compile time via the FS_NOR_SUPPORT_CRC define.
This function enables the data integrity check for all instances
of the NOR driver.
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_BM_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.
It is not recommended to enable this feature when performing a low-level
format of a NOR flash device that was already used for data storage
because the blank check operation is not able to determine if a physical
sector was completely erased only by checking that all the bits are set to 1.
An erase operation that is interrupted by an unexpected reset may leave
the storage cells in an instable state even when the values of all storage
cells in a physical sector read back as 1.
FS_NOR_BM_SetByteOrderBE()
Description
Sets the byte order of multi byte management data to big-endian (default).
Multi-byte management data is stored in big-endian format.
≠ 0
An error occurred.
Additional information
This function is optional. Multi-byte management data is stored
in the byte order of the CPU. Typically, FS_NOR_BM_SetByteOrderBE()
is used by the NOR Image Creator utility to create NOR images
with a byte order of the target CPU when the byte order of the
host CPU is different. The byte order can be set to little-endian
using FS_NOR_BM_SetByteOrderLE(). By default the byte order is
set to little-endian.
The support for configurable byte order is disabled by default and
has to be enabled by compiling the Block Map NOR driver with the
FS_NOR_SUPPORT_VARIABLE_BYTE_ORDER configuration define set to 1
otherwise FS_NOR_BM_SetByteOrderBE() does nothing.
FS_NOR_BM_SetByteOrderLE()
Description
Sets the byte order of multi-byte management data to little-endian format.
Multi-byte management data is stored in little-endian format.
≠ 0
An error occurred.
Additional information
This function is optional. Multi-byte management data is stored
in the byte order of the CPU. Typically, FS_NOR_BM_SetByteOrderLE()
is used by the NOR Image Creator utility to create NOR images
with a byte order of the target CPU when the byte order of the
host CPU is different. The byte order can be set to big-endian
using FS_NOR_BM_SetByteOrderBE(). By default the byte order is
set to little-endian.
The support for configurable byte order is disabled by default and
has to be enabled by compiling the Block Map NOR driver with the
FS_NOR_SUPPORT_VARIABLE_BYTE_ORDER configuration define set to 1
otherwise FS_NOR_BM_SetByteOrderLE() does nothing.
FS_NOR_BM_SetCRCHook()
Description
Configures the calculation routines for CRC verification.
This function is optional. The driver uses by default the internal
software routines of the file system for the CRC calculation.
FS_NOR_BM_SetCRCHook() can be used by the application to specify
different CRC calculation functions. This function is available
only when the FS_NOR_SUPPORT_CRC configuration define is set to 1.
In order to save ROM space, the internal CRC software routines can
be disabled a runtime by setting the FS_NOR_CRC_HOOK_DEFAULT
configuration define to NULL.
Example
#include"FS.h"#include"FS_NOR_HW_SPI_Template.h"#defineALLOC_SIZE 0x4000// Size defined in bytesstaticU32 _aMemBlock[ALLOC_SIZE /4];// Memory pool used for// semi-dynamic allocation.#ifFS_NOR_SUPPORT_CRC/*********************************************************************** _CalcCRC8** Function description* Calculates an 8-bit CRC using a bit-by-bit algorithm.*/staticU8 _CalcCRC8(constU8 *pData,unsignedNumBytes,U8 crc){FS_USE_PARA(pData);FS_USE_PARA(NumBytes);FS_USE_PARA(crc);return0;// TBD: Calculate the CRC.}/*********************************************************************** _CalcCRC16** Function description* Calculates an 16-bit CRC using a bit-by-bit algorithm.*/staticU16 _CalcCRC16(constU8 *pData,unsignedNumBytes,U16 crc){FS_USE_PARA(pData);FS_USE_PARA(NumBytes);FS_USE_PARA(crc);return0;// TBD: Calculate the CRC.}/*********************************************************************** _CRCHook*/staticconstFS_NOR_CRC_HOOK_CRCHook ={_CalcCRC8,_CalcCRC16};#endif// FS_NOR_SUPPORT_CRC/*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){//// Give file system memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Configure the size of the logical sector and activate the file buffering.//FS_SetMaxSectorSize(512);#ifFS_SUPPORT_FILE_BUFFERFS_ConfigFileBufferDefault(512,FS_FILE_BUFFER_WRITE);#endif//// Add and configure the Block Map NOR driver.//FS_AddDevice(&FS_NOR_BM_Driver);FS_NOR_BM_SetPhyType(0,&FS_NOR_PHY_SFDP);FS_NOR_BM_Configure(0,0,0,0x01000000);FS_NOR_BM_SetSectorSize(0,512);#ifFS_NOR_SUPPORT_CRCFS_NOR_BM_EnableCRC();FS_NOR_BM_SetCRCHook(&_CRCHook);#endif//// Configure the NOR physical layer.//FS_NOR_SFDP_SetHWType(0,&FS_NOR_HW_SPI_Template);}
FS_NOR_BM_SetECCHook()
Description
Configures the functions to be used for performing
the bit error correction via ECC.
Functions for the bit error correction of the management data.
pECCHookData
Functions for the bit error correction of the sector data.
Return value
= 0
OK, ECC functions registered.
≠ 0
An error occurred.
Additional information
This function is optional. The driver uses by default the internal
software routines of the file system for the parity check calculation.
FS_NOR_BM_SetECCHook() can be used by the application to specify
different parity check calculation functions. This function is available
only when the FS_NOR_SUPPORT_ECC configuration define is set to 1.
In order to save ROM space, the internal CRC software routines can
be disabled a runtime by setting the FS_NOR_ECC_HOOK_MAN_DEFAULT
and FS_NOR_ECC_HOOK_DATA_DEFAULT configuration define to NULL.
FS_NOR_BM_SetDeviceLineSize()
Description
Configures the minimum number of bytes that can be written to NOR flash.
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_BM_SetDeviceRewriteSupport()
Description
Specifies if the NOR flash device can rewrite the same data
if 0s are preserved.
Enables / disables the support for rewrite. =0 Rewrite support is disabled. ≠0 Rewrite support is enabled.
Return value
= 0
OK, support for rewrite changed.
≠ 0
Error code indicating the failure reason.
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_BM_SetEraseVerification()
Description
Enables or disables the checking of the sector erase operation.
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_BM_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 Block Map NOR driver.
The sector erase verification feature is active only when the Block 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_BM_SetFailSafeErase()
Description
Configures the fail-safe mode of the sector erase operation.
Specifies if the feature has to be enabled or disabled =0 Sector erase operation is not fail-safe. ≠0 Sector erase operation is fail-safe.
Return value
= 0 OK, fail
safe mode configured.
≠ 0
Error code indicating the failure reason.
Additional information
This function is optional. It can be used by the application to
enable or disable the fail-safe sector erase feature of the Block Map
NOR driver. The fail-safe sector erase feature helps the driver
identify a sector erase operation that did not completed successfully
due to an unexpected power failure. The Block Map NOR driver enables
the fail-safe sector erase feature by default except when the NOR
flash device does not support modifying the same data more than once
(rewrite) or when the application activates the data integrity check
feature via CRC. This is done for backward compatibility reasons.
The application has to use FS_NOR_BM_SetFailSafeErase() to explicitly
enable the fail-safe sector erase feature for configurations that
require a fail-safe operation.
In addition, enabling the fail-safe sector erase feature has the potential
of improving the performance of the clean operation executed via
FS_STORAGE_Clean() and FS_STORAGE_CleanOne().
The value configured via FS_NOR_BM_SetFailSafeErase() is evaluated
only during the low-level format operation. That is, after changing
the activation status of the fail-safe sector erase feature a low-level
format operation has to be performed via FS_FormatLow() in order for
the new configuration to be applied.
FS_NOR_BM_SetInvalidSectorError()
Description
Configures if an error is reported when an invalid sector is read.
Specifies if the feature has to be enabled or disabled =0 No error is reported. ≠0 An error is reported.
Additional information
This function is optional. An invalid sector is a logical sector
that does not store any data. All logical sectors are invalid after
a low-level format operation. A logical sector becomes valid as
soon as the file system writes some data to it. The file system
does not read invalid sectors with the exception of a high-level
format operation.
By default the Block Map NOR driver does not report any error when
the file system reads an invalid sector. The contents of an invalid
sector is filled with the byte pattern specified via FS_NOR_READ_BUFFER_FILL_PATTERN.
FS_NOR_BM_SetMaxEraseCntDiff()
Description
Configure the threshold for the active wear leveling operation.
This function is optional. The application can use
FS_NOR_BM_SetMaxEraseCntDiff() to modify the value of
the threshold that is used to decide if a data block has to be
relocated to make sure that is equally erased. The Block Map
NOR driver compares the difference between the erase counts
of two blocks with the configured value. If the calculated
difference is larger than EraseCntDiff then the block with
the smaller erase count is copied to the block with the larger
erase count then the block with the smaller erase count is
used to store new data to it.
This function is optional. Work blocks are physical sectors that
are used by the Block Map NOR driver to temporarily store the data
written to NOR flash device by the file system layer. An application
can use this function to modify the number of work blocks used by the
Block Map NOR driver according to its requirements. By default,
the Block Map NOR driver allocates 1% from the total number of physical
sectors configured for storage but no more than 10 work blocks.
The minimum number of work blocks allocated by default depends on whether
journaling is activated or not in the application. If the journal is active
the 4 work blocks are allocated otherwise 3.
The write performance of the Block Map NOR driver can be improved by
increasing the number work blocks which at the same time increases the
RAM usage.
The NOR flash device has to be reformatted in order for the new number of
work blocks to take effect.
FS_NOR_BM_SetOnFatalErrorCallback()
Description
Registers a function to be called by the driver when a fatal error occurs.
Typically, the NOR driver reports a fatal error when data integrity
check (CRC) fails.
All instances of the NOR driver share the same callback function.
The Unit member of the FS_NOR_FATAL_ERROR_INFO structure passed
as parameter to the pfOnFatalError callback function indicates what
driver instance triggered the fatal error.
This function is mandatory and it has to be called once in FS_X_AddDevices()
for each instance of the Block Map NOR driver created by the application.
Different instances of the Block 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_BM_SetSectorSize()
Description
Configures the number of bytes in a logical sector.
This function is optional. It can be used to modify the size
of the logical sector used by the Block Map NOR driver.
By default the Block 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_BM_SetUsedSectorsErase()
Description
Configures if the physical sectors have to be erased at low-level format.
Specifies if the feature has to be enabled or disabled =0 Physical sectors are invalidated (default). ≠0 Physical sectors are erased.
Additional information
This function is optional. The default behavior of the Block Map
NOR driver is to invalidate the physical sectors at low-level format
which makes the format operation faster.
FS_NOR_BM_SetWriteVerification()
Description
Enables or disables the checking of the page write operation.
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_BM_SetWriteVerification()
can be used to enable additional verification of the page write
operation. This is done 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 Block Map NOR driver.
The page write verification feature is active only when the Block 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.
By default the Block Map NOR driver uses internal functions of
the file system for the CRC calculation. This structure can be
used to configure external CRC calculation callback functions
that for example use hardware CRC calculation units for increased
performance. The application can register the calculation callback
functions via FS_NOR_BM_SetCRCHook()
FS_NOR_CRC_HOOK_CALC_CRC8
Description
The type of the callback function invoked by the NOR driver
to calculate an 8-bit CRC.
This function calculates the CRC of the NumBytes of data
pointed to by pData. The type of polynomial is not relevant.
NumBytes is always an even number. pData is always aligned
to a 16-bit boundary.
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 value.
Additional information
By default the Block Map NOR driver uses internal functions of
the file system for the ECC calculation. This structure can be
used to configure external ECC calculation callback functions
that for example use hardware ECC calculation units for increased
performance. The application can register the calculation callback
functions via FS_NOR_BM_SetECCHook()
FS_NOR_ECC_HOOK_CALC
Description
Callback function that calculates the ECC of a data block.
The NOR driver has to mark the NOR flash device as read only.
≠ 0
The NOR flash device has to remain writable.
Additional information
If the callback function returns a 0 the NOR driver marks the NOR flash
device as read-only and it remains in this state until the NOR flash device
is low-level formatted. In this state, all further write operations
are rejected with an error by the NOR 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.
Additional driver functions
The functions documented in this section are optional. They can be used
to get information about the Block Map NOR driver or to directly access
the data stored on the NOR flash device.
PhySectorIndex is 0-based and is relative to the beginning
of the NOR flash area configured via FS_NOR_BM_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_BM_GetSectorInfo().
OK, NOR flash device has been successfully low-level formated.
≠ 0
An error occurred.
Additional information
This function is optional. FS_NOR_BM_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. The application can request
the Block Map NOR driver to erase the physical sectors instead
of invalidating them by calling FS_NOR_BM_SetUsedSectorsErase()
with the Off parameter set to 1.
FS_NOR_BM_GetDiskInfo()
Description
Returns information about the organization and the management
of the NOR flash device.
This function is optional. The application can use it to get
the actual values of the statistical counters maintained by
the Block Map NOR driver. The statistical counters provide
information about the number of internal operations performed
by the Block 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_BM_ResetStatCounters(). A separate set of
statistical counters is maintained for each instance of the
Block Map NOR driver.
The statistical counters are available only when the file system
is built 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.
out Information about the mounted NOR flash device. Can be set to NULL.
Return value
= 0
OK, NOR flash device successfully mounted.
≠ 0
Error, could not mount NOR flash device.
Additional information
FS_NOR_BM_Mount() can be used to explicitly mount the NOR flash
device and to get information about it. This function returns a subset
of the information returned by FS_NOR_BM_GetDiskInfo() and therefore
can be used instead of it if the application does not require statistical
information about the usage of the NOR sectors. Typically, FS_NOR_BM_Mount()
requires less time to complete than FS_NOR_BM_GetDiskInfo().
This function is not required for the functionality of the
Block Map driver and is typically not linked in production
builds.
This function is optional. The application can use it to set to 0
the statistical counters maintained by the Block Map NOR driver.
The statistical counters can be read via FS_NOR_BM_GetStatCounters()
FS_NOR_BM_ResetStatCounters() is available only when the file system
is built 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.
This function is optional. Disabling the wear leveling can help
reduce the write latencies that occur when the Block Map NOR driver
has to make space for the new data by erasing storage blocks that
contain invalid data. With the wear leveling disabled the Block Map
NOR driver searches for an already empty block (i.e. a storage block
that does not have to be erased before use) when it needs more space.
Empty blocks are created when the application performs a clean operation
via FS_STORAGE_Clean() or FS_STORAGE_CleanOne(). The wear leveling is
automatically re-enabled by the Block Map NOR driver when no more
empty storage blocks are available and an erase operation is required
to create one.
FS_NOR_BM_SuspendWearLeveling() disables only the wear leveling operation
performed when the file system writes data to NOR flash device. The wear
leveling is still performed during a clean operation.
The activation status of the wear leveling is returned via the IsWLSuspended
member of the FS_NOR_BM_DISK_INFO structure that can be queried via
FS_NOR_BM_GetDiskInfo()
Off has to be specified in bytes and is relative to the beginning
of the NOR flash area configured via FS_NOR_BM_Configure().
FS_NOR_BM_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_BM_ErasePhySector().
The function takes care of the alignment required when writing
to NOR flash devices with line size larger than 1.
FS_NOR_BM_DISK_INFO
Description
Management information maintained by the Block Map NOR driver.
Number of physical sectors available for data storage.
NumLogBlocks
Number blocks available for the storage of file system data.
NumUsedPhySectors
Number of physical sectors that store valid data.
LSectorsPerPSector
Number of logical sectors that are mapped in a physical sector.
BytesPerSector
Size of the logical sector used by the driver in bytes.
EraseCntMax
Maximum value of an erase count.
EraseCntMin
Minimum value of an erase count.
EraseCntAvg
Average value of an erase count.
HasFatalError
Indicates if a fatal error has occurred during the operation (0 - no fatal error, 1 - a fatal error occurred)
ErrorType
Code indicating the type of fatal error that occurred.
ErrorPSI
Index of the physical sector where the fatal error occurred.
IsWriteProtected
Indicates if the NOR flash device has been switched permanently to read-only mode as a result of a fatal error (0 - NOR flash device is writable, 1 - NOR flash device is write protected)
IsWLSuspended
Indicates if the wear leveling process is temporarily suspended (0 - active, 1 - suspended)
MaxEraseCntDiff
Difference between the erase counts of two physical sectors that trigger an active wear leveling operation.
NumEraseCnt
Number of erase counts used for the calculation of the erase count average (EraseCntAvg)
NumPhySectorsValid
Number of physical sectors that have a valid header.
NumWorkBlocks
Number of work blocks used by the Block Map NOR driver.
Number of physical sectors available for data storage.
NumLogBlocks
Number blocks available for the storage of file system data.
LSectorsPerPSector
Number of logical sectors that are mapped in a physical sector.
BytesPerSector
Size of the logical sector used by the driver in bytes.
HasFatalError
Indicates if a fatal error has occurred during the operation (0 - no fatal error, 1 - a fatal error occurred)
ErrorType
Code indicating the type of fatal error that occurred.
ErrorPSI
Index of the physical sector where the fatal error occurred.
IsWriteProtected
Indicates if the NOR flash device has been switched permanently to read-only mode as a result of a fatal error (0 - NOR flash device is writable, 1 - NOR flash device is write protected)
IsWLSuspended
Indicates if the wear leveling process is temporarily suspended (0 - active, 1 - suspended)
NumWorkBlocks
Number of work blocks used by the Block Map NOR driver.
FS_NOR_BM_SECTOR_INFO
Description
Information about a physical sector maintained by the Block Map NOR driver.
aBitErrorCnt[0] stores the number of 1 bit error occurrences,
aBitErrorCnt[1] stores the number of 2 bit error occurrences, and so on.
PreEraseCnt stores the number of times the Block Map NOR driver marked
a physical sector as ready to be erased. The physical sectors are then
erased before being used.
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 Sector Map NOR driver were measured as described in the section
Test procedure.
Usage: 5.5 Kbytes
Static RAM usage
Static RAM usage refers to the amount of RAM required by the Block 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_BM_Drv.c file.
Usage: 72 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 Block Map NOR driver
can be calculated as follows:
Size in bytes of a file system sector. Typically 512 bytes or the value set in the call to FS_SetMaxSectorSize() configuration function.
NumWorkBlocks
Number of physical sectors the driver reserves as temporary storage for the written data. Typically 3 physical sectors or the number specified in the call to the FS_NOR_BM_SetNumWorkBlocks() configuration function.
NumPhySectors
Number of physical sectors managed by the driver.
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
NXP LPC2478 (57.6 MHz)
SST SST39VF201 CFI NOR flash device with 16-bit
interface and without support for write buffer
45.5
2064
ST STM32F103 (72 MHz)
ST M25P64 serial NOR flash device
59.3
1110
NXP LPC4357 (204 MHz)
Two Spansion S29GL064N CFI NOR flash devices
with 16-bit interface and with support for
write buffer.
179
25924
NOR physical layer
General information
The NOR physical layer provides the basic functionality for accessing a NOR flash device
such as device identification, block erase operation, read and write operations, etc.
Every instance of the Sector map or Block Map NOR driver requires an instance of a NOR physical layer
in order to be able to operate. A NOR 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 NOR driver that
uses that instance of the NOR physical layer. The type of the NOR physical layer assigned
to an instance of a Sector map or Block Map NOR driver is configured via FS_NOR_SetPhyType()
and FS_NOR_BM_SetPhyType() respectively.
The table below lists the NOR 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 NOR physical layer.
CFI 1x16 physical layer
This physical layer supports any CFI compliant NOR flash device connected via
a 16-bit data bus.
The physical layer 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 CFI 1x16 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_NOR_AMD_WRITE_BUFFER_SIZE specifies the maximum number of bytes the NOR flash
device is able to buffer internally before the data is written to memory array.
This define is relevant only for NOR flash devices that comply with the AMD command set.
FS_NOR_AMD_STATUS_CHECK_TYPE
FS_NOR_AMD_STATUS_CHECK_TYPE specifies how the physical layer waits for a write
or erase operation to complete. The following values are permitted:
Value
Description
0
The status is checked by polling the toggle bit. No error checking
is possible because the devices to not provide this information.
Typically, this polling mode is supported by legacy NOR flash devices.
This is the default behavior for backward compatibility.
1
The status is checked by polling toggle bit. In addition, the status
of the erase and write operation is checked for errors.
This polling mode is supported by modern NOR flash devices such as from Micron.
2
The status is checked by polling the status register. This polling mode
supported by Cypress HyperFlash devices.
FS_NOR_DMB()
FS_NOR_DMB() specifies a function that the file system can call to make sure
that a code sequence is executed only after all the previous memory accesses
are finished. On a Cortex-M architecture this macro has to expand to a DMB
instruction.
FS_NOR_DELAY()
FS_NOR_DELAY() specifies a function that blocks the execution for a certain period
of time. The function does not take any parameters and returns void. It is called
each time the physical layer is checking for the completion status of a write or
erase operation. For performance reasons, the amount of time the function blocks
should be configured to be smaller than the time required by the NOR flash device
to complete a write or erase operation. Using this feature can help reduce the CPU
usage of the file system.
FS_NOR_DI()
FS_NOR_DI() specifies a function that disables the interrupts globally.
The function does not take any parameters and returns void.
The specified function is called after each access to the memory region
where the NOR flash device is mapped in the system memory.
FS_NOR_EI()
FS_NOR_EI() specifies a function that enables the interrupts globally.
The function does not take any parameters and returns void.
The specified function is called before each access to the memory region
where the NOR flash device is mapped in the system memory.
FS_NOR_FAR
FS_NOR_FAR is a memory type specifier that is used to cast the pointers used for
the access to the memory region where NOR flash device is mapped in the system
memory. This configuration define is C compiler specific and is typically
required only on 8- or 16-bit targets.
FS_NOR_INTEL_WRITE_BUFFER_SIZE
FS_NOR_INTEL_WRITE_BUFFER_SIZE specifies the maximum number of bytes the NOR flash
device is able to buffer internally before the data is written to memory array.
This define is relevant only for NOR flash devices that comply with the Intel command set.
FS_NOR_MAX_SECTOR_BLOCKS
FS_NOR_MAX_SECTOR_BLOCKS specifies the number of different physical sector sizes
that the physical layer can handle. This define can be set to 1 for NOR flash
devices with physical sectors of the same size.
FS_NOR_REVERSE_ENDIANESS
FS_NOR_REVERSE_ENDIANESS specifies if the byte ordering of the CFI information
has to be reversed because it is not presented in the byte ordering expected
by the CPU.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the CFI 1x16 physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
This function is optional. The application can use FS_NOR_CFI_SetAddrGap()
to specify a range in the memory region where the contents of the
NOR flash device is mapped that is not assigned to the NOR flash device.
Any access to an address equal to or greater than StartAddr is translated
by NumBytes. StartAddr and NumBytes have to be aligned to a physical sector
boundary of the used NOR flash device.
#include"FS.h"#defineALLOC_SIZE 0x4000#defineFLASH_BASE_ADDR 0x80000000#defineFLASH_START_ADDR 0x80000000#defineFLASH_SIZE 0x00400000#defineFLASH_GAP_START_ADDR 0x80200000#defineFLASH_GAP_SIZE 0x00200000staticU32 _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().*/voidFS_X_AddDevices(void){//// Give the file system memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Add and configure the driver for a 4MB NOR flash.//FS_AddDevice(&FS_NOR_Driver);FS_NOR_SetPhyType(0,&FS_NOR_PHY_CFI_1x16);FS_NOR_Configure(0,FLASH_BASE_ADDR,FLASH_START_ADDR,FLASH_SIZE);//// Configure a 2MB gap in the address space of NOR flash.//FS_NOR_CFI_SetAddrGap(0,FLASH_GAP_START_ADDR,FLASH_GAP_SIZE);}
This function is optional. It can be used to specify a different
function for the reading of CFI parameters than the default function
used by the physical layer. This is typically required when the CFI
parameters do not fully comply with the CFI specification.
#include"FS.h"#defineALLOC_SIZE 0x4000// Size defined in bytes#defineBYTES_PER_SECTOR 2048#defineCFI_READCONFIG(BaseAddr)// TBD#defineCFI_RESET(BaseAddr)// TBD#defineCFI_READCONFIG_NON_CONFORM(BaseAddr)// TBDstaticU32 _aMemBlock[ALLOC_SIZE /4];// Memory pool used for// semi-dynamic allocation.staticint_IsInited =0;staticint_IsCFICompliant =0;/*********************************************************************** _cbReadCFI*/staticvoid_cbReadCFI(U8 Unit,U32 BaseAddr,U32 Off,U8 *pData,unsignedNumItems){volatileU16 FS_NOR_FAR *pAddr;U8 aData[3];FS_USE_PARA(Unit);//// We initially need to check whether the flash is fully CFI compliant.//if(_IsInited ==0){FS_MEMSET(aData,0,sizeof(aData));pAddr =(volatileU16 FS_NOR_FAR *)(BaseAddr +(0x10<<1));CFI_READCONFIG(BaseAddr);aData[0]=(U8)*pAddr++;aData[1]=(U8)*pAddr++;aData[2]=(U8)*pAddr++;CFI_RESET(BaseAddr);if((aData[0]=='Q')&&(aData[1]=='R')&&(aData[2]=='Y')){_IsCFICompliant =1;}_IsInited =1;}pAddr =(volatileU16 FS_NOR_FAR *)(BaseAddr +(Off <<1));//// Write the correct CFI-query sequence//if(_IsCFICompliant){CFI_READCONFIG(BaseAddr);}else{CFI_READCONFIG_NON_CONFORM(BaseAddr);}//// Read the data//do{*pData++=(U8)*pAddr++;// Only the low byte of the CFI data is relevant}while(--NumItems);//// Perform a reset, which means, return from CFI mode to normal mode//CFI_RESET(BaseAddr);}/*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){//// Give the file system memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Add and configure the NOR flash driver.//FS_AddDevice(&FS_NOR_Driver);FS_NOR_SetPhyType(0,&FS_NOR_PHY_CFI_1x16);//// Configure a different function for reading CFI information.//FS_NOR_CFI_SetReadCFICallback(0,_cbReadCFI);FS_NOR_Configure(0,0x10000000,0x10000000,0xFFFFFFFF);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);}
Address in system memory where the NOR flash device is mapped.
Off
Byte offset to read from.
pData
out CFI information read
NumItems
Number of 16-bit values to be read.
Additional information
This is the type of the callback function invoked by CFI NOR physical
layers to read CFI information from NOR flash device. The CFI NOR physical
layers already have an internal function for reading the CFI information.
FS_NOR_CFI_SetReadCFICallback() can be used to register a callback function
that replaces the functionality of this internal function.
This physical layer supports any setup with two CFI compliant NOR flash devices
each one being connected via a 16-bit data bus. It can be configured at compile
time as well as at runtime in the same way as the CFI 1x16 physical layer.
DSPI physical layer
This a pseudo physical layer that uses the ST M25 and SFDP physical layers
to access a serial NOR flash device. The data is exchanged via 1 SPI data line.
The DSPI physical layer has to be configured at runtime and optionally at
compile time. The following sections described how this can be realized
in the application.
The API functions listed in the following table can be used by the application to
configure the behavior of the DSPI physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
This function is mandatory and it has to be called once for each
instance of the physical layer.
SFDP physical layer
This physical layer supports any serial NOR flash device that complies with the
JEDEC JESD216 specification. This specification standardizes the method of
describing the capabilities of a serial NOR flash device. This information is
stored internally by any compatible serial NOR flash device and is used
by the SFDP physical layer to determine the capacity of the serial NOR
flash device, the codes of single, dual, and quad read commands and so on.
Compile time configuration
The SFDP 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.
Timeout in milliseconds for the sector erase operation.
FS_NOR_BYTES_PER_PAGE
FS_NOR_BYTES_PER_PAGE specifies the maximum number of bytes that can be written
at once by the serial NOR flash device. This value can be taken from the data sheet
of the device. A write operation with a number of bytes larger than FS_NOR_BYTES_PER_PAGE
is split by the physical layer into multiple write operations with a number of
bytes smaller than or equal to FS_NOR_BYTES_PER_PAGE.
FS_NOR_DELAY_SECTOR_ERASE
FS_NOR_DELAY_SECTOR_ERASE specifies the number of milliseconds the physical layer
has to wait between two device status request. A device status request is performed
by the physical layer when it waits for an erase operation to complete.
Using this feature can help reduce the CPU usage of the file system.
FS_NOR_DEVICE_LIST_DEFAULT
FS_NOR_DEVICE_LIST_DEFAULT specifies the list of serial NOR flash devices that
can be handled by the physical layer. FS_NOR_DEVICE_LIST_DEFAULT can be set to
NULL in order to reduce the ROM usage if not all the devices included in
FS_NOR_SPI_DeviceListDefault have to be handled. In this case it is mandatory
that the application configures a list of devices via FS_NOR_SFDP_SetDeviceList().
FS_NOR_TIMEOUT_PAGE_WRITE
FS_NOR_TIMEOUT_PAGE_WRITE specifies the maximum number of milliseconds the physical layer
has to wait for a write operation to complete. The completion of the write operation
is determined by evaluating the value returned by the serial NOR flash device
to a status request.
FS_NOR_TIMEOUT_SECTOR_ERASE
FS_NOR_TIMEOUT_SECTOR_ERASE specifies the maximum number of milliseconds the physical layer
has to wait for a physical sector erase operation to complete. The completion of the erase
operation is determined by evaluating the value returned by the serial NOR flash device
to a status request.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the SFDP physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
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 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
NOR flash device. In dual mode two bits of data are transferred with
each clock period which helps improve the performance. If the serial
NOR flash 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_NOR_SFDP_Allow4bitMode()
Description
Specifies if the physical layer is permitted to exchange data
via four data lines.
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 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
NOR flash device. In quad mode four bits of data are transferred on
each clock period which helps improve the performance. If the serial
NOR flash 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().
Address of the first byte the SFDP physical layer is permitted to use as storage.
NumBytes
Number of bytes starting from StartAddr available to be used by the SFDP physical layer as storage.
Additional information
This function is optional. It can be called instead of the FS_NOR_BM_Configure()
or FS_NOR_Configure(). Different instances of the SFDP physical layer
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 SFDP physical
layer 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.
FS_NOR_SFDP_SetDeviceList()
Description
Configures the type of handled serial NOR flash devices.
List of NOR flash devices the physical layer can handle.
Additional information
This function is optional. This function can be used to enable handling
for vendor specific features of serial NOR flash device such as error
handling and data protection. By default the physical layer is configured
to handle only Micron serial NOR flash devices. Handling for serial NOR
flash devices from other manufacturers has to be explicitly enabled via
this function.
Permitted values for the pDeviceList parameter are:
Identifier
Description
FS_NOR_SPI_DeviceListAdesto
Enables handling of Adesto serial NOR flash devices.
FS_NOR_SPI_DeviceListAll
Enables handling of serial NOR flash devices from all manufacturers.
FS_NOR_SPI_DeviceListCypress
Enables handling of Cypress serial NOR flash devices.
FS_NOR_SPI_DeviceListDefault
Enables handling of Micron and of SFDP compatible serial NOR flash devices.
FS_NOR_SPI_DeviceListEon
Enables handling of Eon serial NOR flash devices.
FS_NOR_SPI_DeviceListGigaDevice
Enables handling of GigaDevice serial NOR flash devices.
FS_NOR_SPI_DeviceListISSI
Enables handling of ISSI serial NOR flash devices.
FS_NOR_SPI_DeviceListMacronix
Enables handling of Macronix serial NOR flash devices.
FS_NOR_SPI_DeviceListMicron
Enables handling of Micron serial NOR flash devices.
FS_NOR_SPI_DeviceListMicron_x
Enables handling of Micron serial NOR flash devices in single and dual chip setups.
FS_NOR_SPI_DeviceListMicron_x2
Enables handling of Micron serial NOR flash devices in dual chip setups.
FS_NOR_SPI_DeviceListMicrochip
Enables handling of Microchip serial NOR flash devices.
FS_NOR_SPI_DeviceListSpansion
Enables handling of Spansion serial NOR flash devices.
FS_NOR_SPI_DeviceListSTM
Enables handling of STMicroelectronics serial NOR flash devices.
FS_NOR_SPI_DeviceListWinbond
Enables handling of Winbond serial NOR flash devices.
The application can save ROM space by setting FS_NOR_DEVICE_LIST_DEFAULT
to NULL at compile time and by calling at runtime FS_NOR_SFDP_SetDeviceList()
with the actual list of serial NOR flash 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_NOR_SFDP_SetDeviceParaList()
Description
Configures parameters of serial NOR flash devices.
This function is optional. By default, the parameters of the used
serial NOR flash device are determined by evaluating the SFDP
tables stored in it. However, the information about the commands
that can be used to write the data via two and four data lines
is not stored to this parameters. FS_NOR_SFDP_SetDeviceParaList()
can be used to specify this information. The parameters are matched
by comparing the first byte (manufacturer id) and the third byte
(device id) of the information returned by the READ ID (0x9F) function
with the MfgId and Id members of the FS_NOR_SPI_DEVICE_PARA structure.
The application is permitted to call this function only at the file
system initialization in FS_X_AddDevices().
Typically, a serial NOR flash device supports erase commands
that can be used to erase sectors of different sizes (4 KB, 32 KB, etc.)
For performance reasons the physical layer chooses always the
erase command corresponding to the largest physical sector.
This function can be used to request the physical layer to use
a different (smaller) physical sector size. The mount operation fails
if the serial NOR flash device does not support the specified
physical sector size.
The application is permitted to call this function only at the file
system initialization in FS_X_AddDevices().
FS_NOR_SPI_DEVICE_PARA_LIST
Description
Defines a list of serial NOR flash device parameters.
This physical layer supports serial NOR flash devices that are mapped to the
system memory of the target system. The SPIFI physical layer is able to make use
of the SFDP information stored to the interfaced NOR flash device in order to
determine the storage geometry and the supported command set of that device.
Compile configuration
The SPIFI 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.
Timeout in milliseconds for the sector erase operation.
FS_NOR_BYTES_PER_PAGE
FS_NOR_BYTES_PER_PAGE specifies the maximum number of bytes that can be written
at once by the serial NOR flash device. This value can be taken from the data sheet
of the device. A write operation with a number of bytes larger than FS_NOR_BYTES_PER_PAGE
is split by the physical layer into multiple write operations with a number of
bytes smaller than or equal to FS_NOR_BYTES_PER_PAGE.
FS_NOR_DELAY_SECTOR_ERASE
FS_NOR_DELAY_SECTOR_ERASE specifies the number of milliseconds the physical layer
has to wait between two device status request. A device status request is performed
by the physical layer when it waits for an erase operation to complete.
Using this feature can help reduce the CPU usage of the file system.
FS_NOR_DEVICE_LIST_DEFAULT
FS_NOR_DEVICE_LIST_DEFAULT specifies the list of serial NOR flash devices that
can be handled by the physical layer. FS_NOR_DEVICE_LIST_DEFAULT can be set to
NULL in order to reduce the ROM usage if not all the devices included in
FS_NOR_SPI_DeviceListDefault have to be handled. In this case it is mandatory
that the application configures a list of devices via FS_NOR_SFDP_SetDeviceList().
FS_NOR_MAX_NUM_BYTES_DUMMY
FS_NOR_MAX_NUM_BYTES_DUMMY specifies the maximum number of dummy bytes the
physical layer can send when executing a read operation. The dummy bytes are
necessary in order to give the serial NOR flash device to prepare the data.
The information about the actual number of dummy bytes required is read by
the physical layer from the serial NOR flash device via SFDP.
FS_NOR_TIMEOUT_PAGE_WRITE
FS_NOR_TIMEOUT_PAGE_WRITE specifies the maximum number of milliseconds the physical layer
has to wait for a write operation to complete. The completion of the write operation
is determined by evaluating the value returned by the serial NOR flash device
to a status request.
FS_NOR_TIMEOUT_SECTOR_ERASE
FS_NOR_TIMEOUT_SECTOR_ERASE specifies the maximum number of milliseconds the physical layer
has to wait for a physical sector erase operation to complete. The completion of the erase
operation is determined by evaluating the value returned by the serial NOR flash device
to a status request.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the SPIFI physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
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 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
NOR flash device. In dual mode two bits of data are transferred with
each clock period which helps improve the performance. If the serial
NOR flash 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_NOR_SPIFI_Allow4bitMode()
Description
Specifies if the physical layer is permitted to exchange data
via four data lines.
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 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
NOR flash device. In quad mode four bits of data are transferred on
each clock period which helps improve the performance. If the serial
NOR flash 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_NOR_SPIFI_AllowDTRMode()
Description
Specifies if the physical layer is permitted to exchange data
on both clock edges.
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 SPIFI NOR
physical layer transfers the data in DTR mode only if the used serial NOR
flash device supports it.
The application is permitted to call this function only at the file
system initialization in FS_X_AddDevices().
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 via one
data line (standard SPI). The data transfer via eight data lines is
used only if this type of data transfer is supported by the serial
NOR flash device. In octal mode eight bits of data are transferred with
each clock period which helps improve the performance. If the serial
NOR flash device does not support the octal mode then the data is
transferred 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().
List of NOR flash devices the physical layer can handle.
Additional information
This function is optional. By default the physical layer is configured
to handle Micron serial NOR flash devices. Handling of serial NOR
flash devices from other manufacturers has to be explicitly enabled via
this function.
Permitted values for the pDeviceList parameter are:
Identifier
Description
FS_NOR_SPI_DeviceListAdesto
Enables handling of Adesto serial NOR flash devices.
FS_NOR_SPI_DeviceListAll
Enables handling of serial NOR flash devices from all manufacturers.
FS_NOR_SPI_DeviceListCypress
Enables handling of Cypress serial NOR flash devices.
FS_NOR_SPI_DeviceListDefault
Enables handling of Micron and of SFDP compatible serial NOR flash devices.
FS_NOR_SPI_DeviceListEon
Enables handling of Eon serial NOR flash devices.
FS_NOR_SPI_DeviceListGigaDevice
Enables handling of GigaDevice serial NOR flash devices.
FS_NOR_SPI_DeviceListISSI
Enables handling of ISSI serial NOR flash devices.
FS_NOR_SPI_DeviceListMacronix
Enables handling of Macronix serial NOR flash devices.
FS_NOR_SPI_DeviceListMacronixOctal
Enables handling of Macronix serial NOR flash devices working in octal mode.
FS_NOR_SPI_DeviceList_Micron
Enables handling of Micron serial NOR flash devices.
FS_NOR_SPI_DeviceList_Micron_x
Enables handling of Micron serial NOR flash devices in single and dual chip setups.
FS_NOR_SPI_DeviceList_Micron_x2
Enables handling of Micron serial NOR flash devices in dual chip setups.
FS_NOR_SPI_DeviceListMicrochip
Enables handling of Microchip serial NOR flash devices.
FS_NOR_SPI_DeviceListSpansion
Enables handling of Spansion serial NOR flash devices.
FS_NOR_SPI_DeviceListSTM
Enables handling of STMicroelectronics serial NOR flash devices.
FS_NOR_SPI_DeviceListWinbond
Enables handling of Winbond serial NOR flash devices.
The application can save ROM space by setting FS_NOR_DEVICE_LIST_DEFAULT
to NULL at compile time and by calling at runtime FS_NOR_SPIFI_SetDeviceList()
with the actual list of serial NOR flash 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_NOR_SPIFI_SetDeviceParaList()
Description
Configures parameters of serial NOR flash devices.
This function is optional. This function can be used to enable handling
for vendor specific features of serial NOR flash device such as error
handling and data protection. By default, the parameters of the used
serial NOR flash device are determined by evaluating the SFDP
tables stored in it. However, the information about the commands
that can be used to write the data via two and four data lines
is not stored to this parameters. FS_NOR_SFDP_SetDeviceParaList()
can be used to specify this information. The parameters are matched
by comparing the first byte (manufacturer id) and the third byte
(device id) of the information returned by the READ ID (0x9F) function
with the MfgId and Id members of the FS_NOR_SPI_DEVICE_PARA structure.
The application is permitted to call this function only at the file
system initialization in FS_X_AddDevices().
Typically, a serial NOR flash device supports erase commands
that can be used to erase sectors of different sizes (4 KB, 32 KB, etc.)
For performance reasons the physical layer chooses always the
erase command corresponding to the largest physical sector.
This function can be used to request the physical layer to use
a different (smaller) physical sector size. The mount operation fails
if the serial NOR flash device does not support the specified
physical sector size.
The application is permitted to call this function only at the file
system initialization in FS_X_AddDevices().
Additional functions
The API functions listed in the following table can be used by the application to
operate directly with the SPIFI physical layer. These functions can be called
only after the file system configuration is completed.
List of command codes. Must be different than NULL.
NumBytes
Number of command codes. Must be different than 0.
Return value
= 0
OK, command sequence sent successfully.
≠ 0
Error code that indicates the failure reason.
Additional information
This function is optional. It can be used to send one or more
single byte commands to a NOR flash device. Each command code has to be
specified as a single byte in pCmd. The specified commands
are executed sequentially in separate SPI transactions beginning
with pCmd[0]. All the commands are sent in single SPI mode.
Example
#include"FS.h"voidSampleNOR_SPIFIExeCmd(void){U8 abCmd[2];//// Execute a software reset of the NOR flash device.//abCmd[0]=0x66;abCmd[1]=0x99;FS_NOR_SPIFI_ExecCmd(0,abCmd,sizeof(abCmd));}
ST M25 physical layer
This physical layer supports legacy serial NOR flash devices.
Compile time configuration
The ST M25 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.
Timeout in milliseconds for the sector erase operation.
FS_NOR_MAX_NUM_DEVICES
FS_NOR_MAX_NUM_DEVICES specifies the maximum number of user-defined device
parameters. This configuration define is used together with FS_NOR_SPI_AddDevice()
FS_NOR_TIMEOUT_PAGE_WRITE
FS_NOR_TIMEOUT_PAGE_WRITE specifies the maximum number of milliseconds the physical layer
has to wait for a write operation to complete. The completion of the write operation
is determined by evaluating the value returned by the serial NOR flash device
to a status request.
FS_NOR_TIMEOUT_SECTOR_ERASE
FS_NOR_TIMEOUT_SECTOR_ERASE specifies the maximum number of milliseconds the physical layer
has to wait for a physical sector erase operation to complete. The completion of the erase
operation is determined by evaluating the value returned by the serial NOR flash device
to a status request.
Runtime configuration
The API functions listed in the following table can be used by the application to
configure the behavior of the ST M25 physical layer. The application can call
them only at the file system initialization in FS_X_AddDevices().
This function is optional. It allows an application to define the parameters
of a NOR flash device that is not yet supported by the physical layer.
The maximum number of NOR flash devices that can be added to the list
can be specified via FS_NOR_MAX_NUM_DEVICES define. By default this
feature is disabled, that is FS_NOR_MAX_NUM_DEVICES is set to 0.
The data pointed to by pDevicePara should remain valid until FS_DeInit()
is called, because the function saves internally only the pointer value.
This function is available only when the file system is compiled with
FS_NOR_MAX_NUM_DEVICES set to a value larger than 0.
FS_NOR_SPI_Configure()
Description
Configures the parameters of the NOR flash device.
This function is optional. By default the physical layer identifies
the parameters of the NOR flash device automatically using the
information returned by the READ ID (0x9F) command. This method
does not work for some older ST M25 NOR flash devices. In this
case the application can use FS_NOR_SPI_Configure() to specify
the parameters of the NOR flash device. SPI NOR (M25 series) flash
devices have uniform sectors, which means only one sector size
is used for the entire device.
The capacity of the serial NOR flash device is determined as follows:
Value of 3rd byte
Capacity in Mbits
0x11
1
0x12
2
0x13
4
0x14
8
0x15
16
0x16
32
0x17
64
0x18
128
The application required to call FS_NOR_SPI_Configure(), only if the serial
NOR flash device does not identify itself with one of the values specified
in the table above.
SectorSize must be set to the size of the size of the storage area
erased via the Block Erase (0xD8) command. NumSectors is the device
capacity in bytes divided by SectorSize.
The application is permitted to call this function only at the file system
initialization in FS_X_AddDevices().
Example
#include"FS.h"#defineALLOC_SIZE 0x4000// Size defined in bytesstaticU32 _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().*/voidFS_X_AddDevices(void){//// Give the file system memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Add the NOR driver driver.//FS_AddDevice(&FS_NOR_Driver);//// Configure manually a 16 Mbit SPI NOR flash.//FS_NOR_SetPhyType(0,&FS_NOR_PHY_ST_M25);FS_NOR_SPI_Configure(0,0x10000,32);FS_NOR_Configure(0,0,0,0x10000*32);}
This function is optional. A page is the largest amount of bytes
that can be written at once to a serial NOR flash device. By default
the physical layer uses a page size of 256 bytes a value that is supported
by the majority of serial NOR flash devices.
The size of a page cannot be automatically detected by the physical layer
at runtime. Therefore, if the used serial NOR flash device has a page size
different than 256 bytes, FS_NOR_SPI_SetPageSize() has to be used to configure
the page size to the actual value. The write operation fails if the page
size used by the physical layer is larger than the page size used by the
serial NOR flash device. The write operation works if the application
specifies a smaller page size than the actual page size of the serial NOR
flash device but the write performance will be worst.
BytesPerPage has to be a power of 2 value.
FS_NOR_SPI_DEVICE_PARA
Description
Defines the parameters of a serial NOR flash device.
Value to identify the serial NOR flash device. This is the 3rd byte in the response to READ ID (0x9F) command.
ldBytesPerSector
Number of bytes in a physical sector as power of 2 exponent.
ldBytesPerPage
Number of bytes in a page as a power of 2 exponent.
NumBytesAddr
Number of address bytes. 4 for NOR flash devices with a capacity larger than 128 Mbit (16 Mbyte).
NumSectors
Total number of physical sectors in the device.
Flags
Additional functionality supported by device that requires special processing.
MfgId
Id of device manufacturer. This is the 1st byte in the response to READ ID (0x9F) command.
CmdWrite112
Code of the command used to write the data to NOR flash via 2 data lines. The command itself and the address are transferred via data 1 line.
CmdWrite122
Code of the command used to write the data to NOR flash via 2 data lines. The command itself is transferred via data 1 line while the address via 2 data lines.
CmdWrite114
Code of the command used to write the data to NOR flash via 4 data lines. The command itself and the address are transferred via data 1 line.
CmdWrite144
Code of the command used to write the data to NOR flash via 4 data lines. The command itself is transferred via data 1 line while the address via 4 data lines.
The data returned by this function is the response to
the READ ID (0x9F) command.
Physical layer API
The physical layers that come with emFile provide support most of the popular
NOR flash device and target MCU types. Therefore, there is typically no need to modify
any of the provided NOR physical layers. Typically, only the NOR hardware layer
has to be adapted to a specific target hardware. However, when none of the provided
NOR physical layers are compatible with the target hardware a new NOR physical
layer implementation is required. This section provides information about the API
of the NOR 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_NOR_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.
This function is a member of the NOR physical layer API.
It is mandatory to be implemented by all the NOR physical layers.
The NOR driver calls this function when it writes data to the
NOR flash device. It is guaranteed that the NOR driver tries to
modify memory regions of the NOR flash device that are erased.
This means that the function does not have to check if the memory
region it has to modify are already erased. FS_NOR_PHY_TYPE_WRITE_OFF
has to be able to handle write requests that stretch over multiple
physical sectors.
Off specifies a number of bytes relative to the StartAddr value specified
in the call to FS_NOR_PHY_TYPE_CONFIGURE.
This function is a member of the NOR physical layer API.
It is mandatory to be implemented by all the NOR physical layers.
The NOR driver calls this function when it reads data from the
NOR flash device. FS_NOR_PHY_TYPE_READ_OFF has to be able to handle
read request that stretch over multiple physical sectors.
Off specifies a number of bytes relative to the StartAddr value specified
in the call to FS_NOR_PHY_TYPE_CONFIGURE.
This function is a member of the NOR physical layer API.
It is mandatory to be implemented by all the NOR physical layers.
The NOR driver calls this function when it erases a physical sector
NOR flash device. The erase operation must set to 1 all the bits
in the specified physical sector.
SectorIndex is relative to StartAddr value specified in the call to
FS_NOR_PHY_TYPE_CONFIGURE. The physical sector located at StartAddr
has the index 0.
out Byte offset of the NOR physical sector. Can be NULL.
pNumBytes
out Number of bytes in the NOR physical sector. Can be NULL.
Additional information
This function is a member of the NOR physical layer API.
It is mandatory to be implemented by all the NOR physical layers.
The NOR driver calls this function when it tries to determine
the position and the size of a physical sector.
The value returned via pOff and SectorIndex are relative to StartAddr
value specified in the call to FS_NOR_PHY_TYPE_CONFIGURE.
An error can be reported by setting *pNumBytes to 0 or by setting
This function is a member of the NOR physical layer API.
It is mandatory to be implemented by all the NOR physical layers.
The value returned by this function is the number of physical
sectors located in the memory region specified by StartAddr
and NumBytes values specified in the call to FS_NOR_PHY_TYPE_CONFIGURE.
Address in system memory where the first byte of the NOR flash device is mapped.
StartAddr
Address of the first byte of the NOR flash device to be used for data storage.
NumBytes
Number of bytes to be used for data storage.
Additional information
This function is a member of the NOR physical layer API.
It is mandatory to be implemented by all the NOR physical layers.
FS_NOR_PHY_TYPE_CONFIGURE is called by the NOR driver during the
initialization of the file system.
This function is a member of the NOR physical layer API.
It is mandatory to be implemented by all the NOR physical layer.
The NOR driver calls this function during the file system
initialization when a NOR physical layer is assigned to
a driver instance. Typically, FS_NOR_PHY_TYPE_ON_SELECT_PHY
allocates the memory requires for the instance of the
NOR physical layer and set up everything requires for
the access to NOR flash device.
FS_NOR_PHY_TYPE_DE_INIT
Description
Frees the resources allocated by the NOR physical layer instance.
This function is a member of the NOR physical layer API.
It is mandatory to be implemented only by the NOR physical layers
that allocate dynamic memory. FS_NOR_PHY_TYPE_DE_INIT is called
by the NOR driver at the file system deinitialization when the application
calls FS_DeInit(). It has to free any dynamic memory allocated
for the instance of specified the NOR physical layer.
This function is a member of the NOR physical layer API.
The implementation of this function is optional. By default
the NOR driver checks if a physical sector is blank by reading
the entire contents of the physical sector and by checking that
all bits are set to 1. If the hardware provides a faster method
to check if a physical sector is blank then this function can
implemented to use this method for increasing the write performance.
If the operation of the NOR driver has to be fail-safe then
FS_NOR_PHY_TYPE_IS_SECTOR_BLANK must be able to detect an
interrupted erase operation and in that case return that the
physical sector is not blank even when all the bits in the
physical sector read as 1.
FS_NOR_PHY_TYPE_INIT
Description
Initializes the instance of the NOR physical layer.
This function is a member of the NOR physical layer API.
The implementation of this function is optional.
If implemented, FS_NOR_PHY_TYPE_INIT is called by the NOR driver
before the first access to the NOR flash device to identify the device,
read the device parameters, etc.
Resource usage
This section describes the ROM and RAM usage of the 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 NOR 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 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 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.
The NOR hardware layer provides functionality for accessing a NOR flash device
via the target hardware such as external memory controller, GPIO, SPI, etc.
The functions of the NOR hardware layer are called by the NOR physical layer
to exchange commands and data with a NOR flash 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/NOR
folder of the emFile shipment.
The functions of the NOR 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 NOR flash device. The type of hardware layer an application
has to use depends on the type NOR physical layer configured. The following table
shows what hardware layer is required by each physical layer.
This hardware layer supports serial NOR flash devices that are interfaced via single or extended SPI.
It is able to transfer the data via one, two or four data lines.
The functions of this hardware layer are grouped in a structure of type FS_NOR_HW_TYPE_SPI.
The following sections describe these functions in detail.
This function is a member of the SPI NOR hardware layer API.
It it has to be implemented by all the hardware layers.
This function is called by the NOR physical layer once and
before any other function of the hardware layer each time
the file system mounts the serial NOR flash.
This function is a member of the SPI NOR hardware layer API.
It it has to be implemented by all the hardware layers.
The Chip Select (CS) signal is used to address a specific serial NOR
flash device connected via SPI. Enabling is equal to setting the CS
signal to a logic low level.
This function is a member of the SPI NOR hardware layer API.
It has to be implemented by all the hardware layers.
The Chip Select (CS) signal is used to address a specific serial NOR
flash device connected via SPI. Disabling is equal to setting the CS
signal to a logic high level.
FS_NOR_HW_TYPE_SPI_READ
Description
Transfers data from serial NOR flash device to MCU via 1 data line.
out Data transferred from the serial NOR flash device.
NumBytes
Number of bytes to be transferred.
Additional information
This function is a member of the SPI NOR hardware layer API.
FS_NOR_HW_TYPE_SPI_READ does not have to be implemented if
the hardware layer provides an implementation for FS_NOR_HW_TYPE_SPI_READ_EX.
FS_NOR_HW_TYPE_SPI_WRITE
Description
Transfers data from MCU to serial NOR flash device via 1 data line.
in Data transferred to the serial NOR flash device.
NumBytes
Number of bytes to be transferred.
Additional information
This function is a member of the SPI NOR hardware layer API.
FS_NOR_HW_TYPE_SPI_WRITE does not have to be implemented if
the hardware layer provides an implementation for FS_NOR_HW_TYPE_SPI_WRITE_EX.
FS_NOR_HW_TYPE_SPI_READ_X2
Description
Transfers data from serial NOR flash device to MCU via 2 data lines.
out Data transferred from the serial NOR flash device.
NumBytes
Number of bytes to be transferred.
Additional information
This function is a member of the SPI NOR hardware layer API.
The implementation of this function is optional.
FS_NOR_HW_TYPE_SPI_READ_X2 transfers 2 bits of data on each clock period.
Typically, the data is transferred via the DataOut (DO) and DataIn (DI)
signals of the serial NOR flash where the even numbered bits of a byte
are sent via the DI signal while the odd-numbered bits via the DO signal.
in Data transferred to the serial NOR flash device.
NumBytes
Number of bytes to be transferred.
Additional information
This function is a member of the SPI NOR hardware layer API.
The implementation of this function is optional.
FS_NOR_HW_TYPE_SPI_WRITE_X2 transfers 2 bits of data on each clock period.
Typically, the data is transferred via the DataOut (DO) and DataIn (DI)
signals of the serial NOR flash where the even numbered bits of a byte
are sent via the DI signal while the odd-numbered bits via the DO signal.
out Data transferred from the serial NOR flash device.
NumBytes
Number of bytes to be transferred.
Additional information
This function is a member of the SPI NOR hardware layer API.
The implementation of this function is optional.
FS_NOR_HW_TYPE_SPI_READ_X4 exchanges 4 bits of data on each clock period.
Typically, the data is transferred via the DataOut (DO), DataIn (DO),
Write Protect (WP), and Hold (H) signals of the serial NOR flash device.
A byte is transferred as follows:
in Data transferred to the serial NOR flash device.
NumBytes
Number of bytes to be transferred.
Additional information
This function is a member of the SPI NOR hardware layer API.
The implementation of this function is optional.
FS_NOR_HW_TYPE_SPI_WRITE_X4 exchanges 4 bits of data on each clock period.
Typically, the data is transferred via the DataOut (DO), DataIn (DO),
Write Protect (WP), and Hold (H) signals of the serial NOR flash device.
A byte is transferred as follows:
This function is a member of the SPI NOR hardware layer API.
The implementation of this function is optional. FS_NOR_HW_TYPE_SPI_DELAY
can block the execution for longer than the number of milliseconds
specified but not less than that. Typically, the function is implemented
using a delay function of the used RTOS if any. If the hardware layer
chooses not to implement FS_NOR_HW_TYPE_SPI_DELAY then the pfDelay
member of FS_NOR_HW_TYPE_SPI can be set to NULL or to the address of
a function that returns a negative value. If the function is not
implemented by the hardware layer then the NOR physical layer blocks
the execution by using a software loop. The number of software loops
is calculated based in the SPI clock frequency returned by FS_NOR_HW_TYPE_SPI_INIT.
This function is a member of the SPI 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_NOR_HW_TYPE_SPI_LOCK and FS_NOR_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_NOR_HW_TYPE_SPI_LOCK and released in FS_NOR_HW_TYPE_SPI_UNLOCK.
This function is a member of the SPI NOR hardware layer API.
The implementation of this function is optional.
The NOR physical layer calls this function after 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_NOR_HW_TYPE_SPI_LOCK.
It is also guaranteed that FS_NOR_HW_TYPE_SPI_UNLOCK and
FS_NOR_HW_TYPE_SPI_LOCK are called in pairs.
FS_NOR_HW_TYPE_SPI_UNLOCK and FS_NOR_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_NOR_HW_TYPE_SPI_LOCK
and released in FS_NOR_HW_TYPE_SPI_UNLOCK.
FS_NOR_HW_TYPE_SPI_READ_EX
Description
Transfers data from serial NOR flash device to MCU.
out Data transferred from the serial NOR flash device.
NumBytes
Number of bytes to be transferred.
BusWidth
Number of data lines to be used for the data transfer.
Return value
= 0
OK, data transferred successfully.
≠ 0
An error occurred.
Additional information
This function is a member of the SPI NOR hardware layer API.
FS_NOR_HW_TYPE_SPI_READ_EX does not have to be implemented if
the hardware layer provides an implementation for FS_NOR_HW_TYPE_SPI_READ.
in Data transferred to the serial NOR flash device.
NumBytes
Number of bytes to be transferred.
BusWidth
Number of data lines to be used for the data transfer.
Return value
= 0
OK, data transferred successfully.
≠ 0
An error occurred.
Additional information
This function is a member of the SPI NOR hardware layer API.
FS_NOR_HW_TYPE_SPI_WRITE_EX does not have to be implemented if
the hardware layer provides an implementation for FS_NOR_HW_TYPE_SPI_WRITE.
The following sample implementation uses the SPI controller of an NXP K66 MCU
to interface with a serial NOR flash device. This NOR 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_NOR_HW_SPI_K66_SEGGER_emPower.cPurpose : NOR SPI hardware layer for the SEGGER emPower boardLiterature: [1] K66 Sub-Family Reference Manual [2] emPower Evaluation and prototyping platform for SEGGER software User Guide & Reference Manual*//*********************************************************************** #include section************************************************************************/#include"FS.h"/*********************************************************************** Defines, configurable************************************************************************/#ifndefFS_NOR_HW_SPI_BUS_CLK_HZ#defineFS_NOR_HW_SPI_BUS_CLK_HZ (168000000uL/3)// SPI module clock#endif#ifndefFS_NOR_HW_SPI_NOR_CLK_HZ#defineFS_NOR_HW_SPI_NOR_CLK_HZ 28000000uL// Clock of NOR flash device#endif#ifndefFS_NOR_HW_SPI_INIT_WAIT_LOOPS#defineFS_NOR_HW_SPI_INIT_WAIT_LOOPS 20000// Waits about 1ms for the SPI module to start/stop#endif#ifndefFS_NOR_HW_SPI_UNIT_NO#defineFS_NOR_HW_SPI_UNIT_NO 0// Selects the number of SPI unit to be used for data transfer (Permitted values: 0 and 2)#endif#ifndefFS_NOR_HW_SPI_USE_OS#defineFS_NOR_HW_SPI_USE_OS 0// Enables / disables the event-driven operation.// 0 - OS support disabled.// 1 - OS support enabled using OS event of emFile.// 2 - OS support enabled using OS events of this HW layer.#endif/*********************************************************************** #include section, conditional************************************************************************/#ifFS_NOR_HW_SPI_USE_OS#include"FS_OS.h"#include"RTOS.h"#include"MK66F18.h"#endif// FS_NOR_HW_SPI_USE_OS/*********************************************************************** Defines, fixed************************************************************************//*********************************************************************** SPI module*/#if(FS_NOR_HW_SPI_UNIT_NO ==2)#defineSPI_BASE_ADDR 0x400AC000uL#else#defineSPI_BASE_ADDR 0x4002C000uL#endif#defineSPI_MCR (*(volatileU32 *)(SPI_BASE_ADDR +0x00))// Module Configuration Register#defineSPI_TCR (*(volatileU32 *)(SPI_BASE_ADDR +0x08))// Transfer Count Register#defineSPI_CTAR0 (*(volatileU32 *)(SPI_BASE_ADDR +0x0C))// Clock and Transfer Attributes Register (In Master Mode)#defineSPI_CTAR1 (*(volatileU32 *)(SPI_BASE_ADDR +0x10))// Clock and Transfer Attributes Register (In Master Mode)#defineSPI_SR (*(volatileU32 *)(SPI_BASE_ADDR +0x2C))// Status Register#defineSPI_RSER (*(volatileU32 *)(SPI_BASE_ADDR +0x30))// DMA/Interrupt Request Select and Enable Register#defineSPI_PUSHR (*(volatileU32 *)(SPI_BASE_ADDR +0x34))// PUSH TX FIFO Register In Master Mode#defineSPI_POPR (*(volatileU32 *)(SPI_BASE_ADDR +0x38))// POP RX FIFO Register#defineSPI_TXFR0 (*(volatileU32 *)(SPI_BASE_ADDR +0x3C))// Transmit FIFO Registers#defineSPI_TXFR1 (*(volatileU32 *)(SPI_BASE_ADDR +0x40))// Transmit FIFO Registers#defineSPI_TXFR2 (*(volatileU32 *)(SPI_BASE_ADDR +0x44))// Transmit FIFO Registers#defineSPI_TXFR3 (*(volatileU32 *)(SPI_BASE_ADDR +0x48))// Transmit FIFO Registers#defineSPI_RXFR0 (*(volatileU32 *)(SPI_BASE_ADDR +0x7C))// Receive FIFO Registers#defineSPI_RXFR1 (*(volatileU32 *)(SPI_BASE_ADDR +0x80))// Receive FIFO Registers#defineSPI_RXFR2 (*(volatileU32 *)(SPI_BASE_ADDR +0x84))// Receive FIFO Registers#defineSPI_RXFR3 (*(volatileU32 *)(SPI_BASE_ADDR +0x88))// Receive FIFO Registers#if(FS_NOR_HW_SPI_USE_OS ==0)/*********************************************************************** System integration module*/#defineSIM_BASE_ADDR 0x40047000uL#defineSIM_SCGC3 (*(volatileU32 *)(SIM_BASE_ADDR +0x1030))// System Clock Gating Control Register 3#defineSIM_SCGC5 (*(volatileU32 *)(SIM_BASE_ADDR +0x1038))// System Clock Gating Control Register 5#defineSIM_SCGC6 (*(volatileU32 *)(SIM_BASE_ADDR +0x103C))// System Clock Gating Control Register 6/*********************************************************************** Port B*/#definePORTB_BASE_ADDR 0x4004A000uL#definePORTB_PCR20 (*(volatileU32 *)(PORTB_BASE_ADDR +0x50))// Port Control Register#definePORTB_PCR21 (*(volatileU32 *)(PORTB_BASE_ADDR +0x54))// Port Control Register#definePORTB_PCR22 (*(volatileU32 *)(PORTB_BASE_ADDR +0x58))// Port Control Register#definePORTB_PCR23 (*(volatileU32 *)(PORTB_BASE_ADDR +0x5C))// Port Control Register#definePORTB_DFER (*(volatileU32 *)(PORTB_BASE_ADDR +0xC0))// Digital filter enable register/*********************************************************************** Port C*/#definePORTC_BASE_ADDR 0x4004B000uL#definePORTC_PCR4 (*(volatileU32 *)(PORTC_BASE_ADDR +0x10))// Port Control Register#definePORTC_PCR5 (*(volatileU32 *)(PORTC_BASE_ADDR +0x14))// Port Control Register#definePORTC_PCR6 (*(volatileU32 *)(PORTC_BASE_ADDR +0x18))// Port Control Register#definePORTC_PCR7 (*(volatileU32 *)(PORTC_BASE_ADDR +0x1C))// Port Control Register#definePORTC_DFER (*(volatileU32*)(PORTC_BASE_ADDR +0xC0))// Digital filter enable register/*********************************************************************** GPIO B*/#defineGPIOB_BASE_ADDR 0x400FF040uL#defineGPIOB_PDOR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x00))// Port Data Output Register#defineGPIOB_PSOR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x04))// Port Set Output Register#defineGPIOB_PCOR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x08))// Port Clear Output Register#defineGPIOB_PTOR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x0C))// Port Toggle Output Register#defineGPIOB_PDIR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x10))// Port Data Input Register#defineGPIOB_PDDR (*(volatileU32 *)(GPIOB_BASE_ADDR +0x14))// Port Data Direction Register/*********************************************************************** GPIO C*/#defineGPIOC_BASE_ADDR 0x400FF080uL#defineGPIOC_PDOR (*(volatileU32 *)(GPIOC_BASE_ADDR +0x00))// Port Data Output Register#defineGPIOC_PSOR (*(volatileU32 *)(GPIOC_BASE_ADDR +0x04))// Port Set Output Register#defineGPIOC_PCOR (*(volatileU32 *)(GPIOC_BASE_ADDR +0x08))// Port Clear Output Register#defineGPIOC_PTOR (*(volatileU32 *)(GPIOC_BASE_ADDR +0x0C))// Port Toggle Output Register#defineGPIOC_PDIR (*(volatileU32 *)(GPIOC_BASE_ADDR +0x10))// Port Data Input Register#defineGPIOC_PDDR (*(volatileU32 *)(GPIOC_BASE_ADDR +0x14))// Port Data Direction Register#else/*********************************************************************** Port C*/#definePORTC_BASE_ADDR 0x4004B000uL#definePORTC_DFER (*(volatileU32*)(PORTC_BASE_ADDR +0xC0))// Digital filter enable register#endif// FS_NOR_HW_SPI_USE_OS/*********************************************************************** Port Control Register*/#definePCR_MUX_BIT 8// Alternate port setting#definePCR_MUX_GPIO 1uL// Controlled directly by the HW layer#definePCR_MUX_SPI0 2uL// Controlled by SPI module#definePCR_MUX_SPI2 2uL// Controlled by SPI module#definePCR_MUX_MASK 0x7uL#definePCR_DSE_BIT 6// Driver strength enable#definePCR_PE_BIT 1// Pull enable#definePCR_PS_BIT 0// Pull-up enable/*********************************************************************** Clock enable bits*/#defineSCGC3_SPI2_BIT 12// SPI2#defineSCGC5_PORTB_BIT 10// GPIO B#defineSCGC5_PORTC_BIT 11// GPIO C#defineSCGC6_SPI0_BIT 12// SPI0/*********************************************************************** SPI Module Configuration Register*/#defineMCR_MSTR_BIT 31#defineMCR_FRZ_BIT 27#defineMCR_CLR_TXF_BIT 11#defineMCR_CLR_RXF_BIT 10#defineMCR_HALT_BIT 0/*********************************************************************** SPI Status Register*/#defineSR_TCF_BIT 31#defineSR_TXRXS_BIT 30#defineSR_EOQF_BIT 28#defineSR_TFUF_BIT 27#defineSR_TFFF_BIT 25#defineSR_RFOF_BIT 19#defineSR_RFDF_BIT 17#defineSR_RXCTR_BIT 4#defineSR_RXCTR_MASK 0xFuL/*********************************************************************** SPI Clock and Transfer Attributes Register*/#defineCTAR_DBR_BIT 31#defineCTAR_FMSZ_BIT 27#defineCTAR_CPOL_BIT 26#defineCTAR_CPHA_BIT 25#defineCTAR_BR_BIT 0#defineCTAR_BR_MAX 0xFuL/*********************************************************************** SPI misc. defines*/#definePUSHR_CTAS_BIT 28#defineRSER_RFDF_RE_BIT 17#defineSPI_IRQ_PRIO 15#defineWAIT_TIMEOUT_MS 1000/*********************************************************************** NOR flash pin assignments*/#if(FS_NOR_HW_SPI_UNIT_NO ==2)#defineNOR_CS_PIN 20// Port B#defineNOR_CLK_PIN 21// Port B#defineNOR_MOSI_PIN 22// Port B#defineNOR_MISO_PIN 23// Port B#else#defineNOR_CS_PIN 4// Port C#defineNOR_CLK_PIN 5// Port C#defineNOR_MOSI_PIN 6// Port C#defineNOR_MISO_PIN 7// Port C#endif/*********************************************************************** Static data************************************************************************/#if(FS_NOR_HW_SPI_USE_OS ==2)staticU8 _IsEventInited =0;staticOS_EVENT _Event;#endif// FS_NOR_HW_SPI_USE_OS == 2/*********************************************************************** Static code************************************************************************/#ifFS_NOR_HW_SPI_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.*/staticint_WaitForEvent(U32 TimeOut){intr;SPI_RSER |=1uL<<RSER_RFDF_RE_BIT;// Enable the interrupt.#if(FS_NOR_HW_SPI_USE_OS ==2)r =OS_EVENT_WaitTimed(&_Event,TimeOut);#elser =FS_OS_Wait(TimeOut);#endifif(r !=0){SPI_RSER &=~(1uL<<RSER_RFDF_RE_BIT);// Disable the interrupt.}returnr;}#endif// FS_NOR_HW_SPI_USE_OS/*********************************************************************** _StoreU16BE** Function description* Stores a 16 bit value in big endian format into a byte array.*/staticvoid_StoreU16BE(U8 *pBuffer,unsignedData){*pBuffer++=(U8)(Data >>8);*pBuffer =(U8)Data;}/*********************************************************************** _LoadU16BE** Function description* Reads a 16 bit value stored in big endian format from a byte array.*/staticU16 _LoadU16BE(constU8 *pBuffer){U16 r;r =*pBuffer++;r =(U16)((r <<8)|*pBuffer);returnr;}/*********************************************************************** _Transfer8Bit*/staticU8 _Transfer8Bit(U8 Data){U32 NumBytes;SPI_PUSHR =Data;//// Wait to receive 1 byte.//while(1){NumBytes =(SPI_SR >>SR_RXCTR_BIT)&SR_RXCTR_MASK;if(NumBytes ==1){break;}#ifFS_NOR_HW_SPI_USE_OS{intr;r =_WaitForEvent(WAIT_TIMEOUT_MS);if(r !=0){break;}}#endif// FS_NOR_HW_SPI_USE_OS}Data =(U8)SPI_POPR;returnData;}#if(FS_NOR_HW_SPI_UNIT_NO ==0)/*********************************************************************** _Read64Bits** Function description* Transfers 64 bits of data from NOR device to MCU.*/staticvoid_Read64Bits(U8 *pData){U16 Data16;U32 NumItems;U32 Dummy;//// Send dummy data.//Dummy =0|0xFFFFuL|(1uL<<PUSHR_CTAS_BIT)// Use the second set of parameters which is configured for 16-bit transfers.;SPI_PUSHR =Dummy;SPI_PUSHR =Dummy;SPI_PUSHR =Dummy;SPI_PUSHR =Dummy;//// Wait to receive 4 half-words (4 is the FIFO size)//while(1){NumItems =(SPI_SR >>SR_RXCTR_BIT)&SR_RXCTR_MASK;if(NumItems ==4){break;}#ifFS_NOR_HW_SPI_USE_OS{intr;r =_WaitForEvent(WAIT_TIMEOUT_MS);if(r !=0){break;}}#endif// FS_NOR_HW_SPI_USE_OS}//// Read data from FIFO.//Data16 =(U16)SPI_POPR;_StoreU16BE(pData,Data16);Data16 =(U16)SPI_POPR;_StoreU16BE(pData +2,Data16);Data16 =(U16)SPI_POPR;_StoreU16BE(pData +4,Data16);Data16 =(U16)SPI_POPR;_StoreU16BE(pData +6,Data16);}/*********************************************************************** _Write64Bits** Function description* Transfers 64 bits of data from MCU to NOR device.*/staticvoid_Write64Bits(constU8 *pData){U16 Data16;U32 NumItems;//// Write data to NOR device. Use the second set of parameters which is configured for 16-bit transfers.//Data16 =_LoadU16BE(pData);SPI_PUSHR =(U32)Data16 |(1uL<<PUSHR_CTAS_BIT);Data16 =_LoadU16BE(pData +2);SPI_PUSHR =(U32)Data16 |(1uL<<PUSHR_CTAS_BIT);Data16 =_LoadU16BE(pData +4);SPI_PUSHR =(U32)Data16 |(1uL<<PUSHR_CTAS_BIT);Data16 =_LoadU16BE(pData +6);SPI_PUSHR =(U32)Data16 |(1uL<<PUSHR_CTAS_BIT);//// Wait to receive 4 half-words (4 is the FIFO size)//while(1){NumItems =(SPI_SR >>SR_RXCTR_BIT)&SR_RXCTR_MASK;if(NumItems ==4){break;}#ifFS_NOR_HW_SPI_USE_OS{intr;r =_WaitForEvent(WAIT_TIMEOUT_MS);if(r !=0){break;}}#endif// FS_NOR_HW_SPI_USE_OS}//// Discard the received data.//SPI_MCR |=1uL<<MCR_CLR_RXF_BIT;}#endif// FS_NOR_HW_SPI_UNIT_NO == 0/*********************************************************************** Static code (public via callback)************************************************************************//*********************************************************************** _HW_Init** Function description* Initialize the SPI for use with the NOR flash.** Parameters* Unit Device index** Return value* SPI frequency that is set - given in kHz, 0 in case of an error.*/staticint_HW_Init(U8 Unit){intFreq_Hz;unsignedNumLoops;unsignedScaler;unsignedDiv;FS_USE_PARA(Unit);#if(FS_NOR_HW_SPI_UNIT_NO ==2)//// Enable the clock of GPIOs and SPI0.//SIM_SCGC3 |=1uL<<SCGC3_SPI2_BIT;SIM_SCGC5 |=1uL<<SCGC5_PORTB_BIT;//// Clock line (controlled by the SPI module)//PORTB_PCR21 =0|(PCR_MUX_SPI2 <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT)|(1uL<<PCR_DSE_BIT);//// MOSI line (controlled by the SPI module)//PORTB_PCR22 =0|(PCR_MUX_SPI2 <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT)|(1uL<<PCR_DSE_BIT);//// MISO line (controlled by the SPI module)//PORTB_PCR23 =0|(PCR_MUX_SPI2 <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT)|(1uL<<PCR_DSE_BIT);//// Chip select (controlled by the HW layer)//PORTB_PCR20 =0|(PCR_MUX_GPIO <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT);GPIOB_PSOR =1uL<<NOR_CS_PIN;// Active lowGPIOB_PDDR |=1uL<<NOR_CS_PIN;//// Disable the digital filtering on all port pins controlled by the SPI module.//PORTB_DFER &=~((1uL<<NOR_CLK_PIN)|(1uL<<NOR_MISO_PIN)|(1uL<<NOR_MOSI_PIN));#else//// Enable the clock of GPIOs and SPI0.//SIM_SCGC5 |=1uL<<SCGC5_PORTC_BIT;SIM_SCGC6 |=1uL<<SCGC6_SPI0_BIT;//// Clock line (controlled by the SPI module)//PORTC_PCR5 =0|(PCR_MUX_SPI0 <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT)|(1uL<<PCR_DSE_BIT);//// MOSI line (controlled by the SPI module)//PORTC_PCR6 =0|(PCR_MUX_SPI0 <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT)|(1uL<<PCR_DSE_BIT);//// MISO line (controlled by the SPI module)//PORTC_PCR7 =0|(PCR_MUX_SPI0 <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT)|(1uL<<PCR_DSE_BIT);//// Chip select (controlled by the HW layer)//PORTC_PCR4 =0|(PCR_MUX_GPIO <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT);GPIOC_PSOR =1uL<<NOR_CS_PIN;// Active lowGPIOC_PDDR |=1uL<<NOR_CS_PIN;//// Disable the digital filtering on all port pins controlled by the SPI module.//PORTC_DFER &=~((1uL<<NOR_CLK_PIN)|(1uL<<NOR_MISO_PIN)|(1uL<<NOR_MOSI_PIN));#endif// FS_NOR_HW_SPI_UNIT_NO == 2#ifFS_NOR_HW_SPI_USE_OS//// Disable the interrupt and configure the priority.//NVIC_DisableIRQ(SPI0_IRQn);NVIC_SetPriority(SPI0_IRQn,SPI_IRQ_PRIO);#endif// FS_NOR_HW_SPI_USE_OS//// Calculate the clock scaler based on the configured clock frequency.//Scaler =0;Div =2;Freq_Hz =FS_NOR_HW_SPI_BUS_CLK_HZ;for(;;){if(((unsigned)Freq_Hz /Div)<=FS_NOR_HW_SPI_NOR_CLK_HZ){break;}//// We do this here since the 3rd divisor is not power of 2.//if(Div ==2){Div =4;}elseif(Div ==4){Div =6;}elseif(Div ==6){Div =8;}else{Div <<=1;}++Scaler;if(Scaler ==CTAR_BR_MAX){break;}}//// Stop the SPI module.//SPI_MCR |=1uL<<MCR_HALT_BIT;NumLoops =FS_NOR_HW_SPI_INIT_WAIT_LOOPS;do{if((SPI_SR &(1uL<<SR_TXRXS_BIT))==0){break;}}while(--NumLoops);//// Configure the SPI module.//SPI_MCR =0|(1uL<<MCR_MSTR_BIT)|(1uL<<MCR_CLR_TXF_BIT)|(1uL<<MCR_CLR_RXF_BIT)|(1uL<<MCR_HALT_BIT);SPI_TCR =0;SPI_CTAR0 =0|(1uL<<CTAR_DBR_BIT)|(7uL<<CTAR_FMSZ_BIT)// 8 bits|(1uL<<CTAR_CPOL_BIT)|(1uL<<CTAR_CPHA_BIT)|(Scaler <<CTAR_BR_BIT);SPI_CTAR1 =0|(1uL<<CTAR_DBR_BIT)|(15uL<<CTAR_FMSZ_BIT)// 16 bits|(1uL<<CTAR_CPOL_BIT)|(1uL<<CTAR_CPHA_BIT)|(Scaler <<CTAR_BR_BIT);SPI_SR =0|(1uL<<SR_TCF_BIT)|(1uL<<SR_EOQF_BIT)|(1uL<<SR_TFUF_BIT)|(1uL<<SR_TFFF_BIT)|(1uL<<SR_RFOF_BIT)|(1uL<<SR_RFDF_BIT);//// Start the SPI module.//SPI_MCR &=~(1uL<<MCR_HALT_BIT);NumLoops =FS_NOR_HW_SPI_INIT_WAIT_LOOPS;do{if(SPI_SR &(1uL<<SR_TXRXS_BIT)){break;}}while(--NumLoops);#ifFS_NOR_HW_SPI_USE_OS//// Create the OS event and enable the interrupt.//#if(FS_NOR_HW_SPI_USE_OS ==2)if(_IsEventInited ==0){OS_EVENT_Create(&_Event);_IsEventInited =1;}#endif// FS_NOR_HW_SPI_USE_OS == 2NVIC_EnableIRQ(SPI0_IRQn);#endif// FS_NOR_HW_SPI_USE_OS//// Make a dummy transfer so that the polarity of the clock signal is set correctly.// Without this, the first byte transfer will send/receive the wrong value.//_Transfer8Bit(0xFF);#if(FS_NOR_HW_SPI_USE_OS ==0)SPI_RSER =0;#endifreturnFreq_Hz;}/*********************************************************************** _HW_EnableCS** Function description* Activates chip select signal (CS) of the NOR flash chip.** Parameters* Unit Device index*/staticvoid_HW_EnableCS(U8 Unit){FS_USE_PARA(Unit);#if(FS_NOR_HW_SPI_UNIT_NO ==2)GPIOB_PCOR =1uL<<NOR_CS_PIN;// Active low#elseGPIOC_PCOR =1uL<<NOR_CS_PIN;// Active low#endif}/*********************************************************************** _HW_DisableCS** Function description* Deactivates chip select signal (CS) of the NOR flash chip.** Parameters* Unit Device index*/staticvoid_HW_DisableCS(U8 Unit){FS_USE_PARA(Unit);#if(FS_NOR_HW_SPI_UNIT_NO ==2)GPIOB_PSOR =1uL<<NOR_CS_PIN;// Active low#elseGPIOC_PSOR =1uL<<NOR_CS_PIN;// Active low#endif}/*********************************************************************** _HW_Read** Function description* Reads a specified number of bytes from NOR flash to buffer.** Parameters* Unit Device index* pData Pointer to a data buffer* NumBytes Number of bytes to be read*/staticvoid_HW_Read(U8 Unit,U8 *pData,intNumBytes){FS_USE_PARA(Unit);if(NumBytes){#if(FS_NOR_HW_SPI_UNIT_NO ==2)do{*pData++=_Transfer8Bit(0xFF);}while(--NumBytes);#else//// Read 64 bits at a time if possible.//if(((unsigned)NumBytes &7)==0){// Multiple of 8 bytes?unsignedNumLoops;NumLoops =(unsigned)NumBytes >>3;do{_Read64Bits(pData);pData +=8;}while(--NumLoops);}else{do{*pData++=_Transfer8Bit(0xFF);}while(--NumBytes);}#endif}}/*********************************************************************** _HW_Write** Function description* Writes a specified number of bytes from data buffer to NOR flash.** Parameters* Unit Device index* pData Pointer to a data buffer* NumBytes Number of bytes to be written*/staticvoid_HW_Write(U8 Unit,constU8 *pData,intNumBytes){FS_USE_PARA(Unit);if(NumBytes){#if(FS_NOR_HW_SPI_UNIT_NO ==2)do{(void)_Transfer8Bit(*pData++);}while(--NumBytes);#else//// Write 64 bits at a time if possible.//if(((unsigned)NumBytes &7)==0){// Multiple of 8 bytes?unsignedNumLoops;NumLoops =(unsigned)NumBytes >>3;do{_Write64Bits(pData);pData +=8;}while(--NumLoops);}else{do{(void)_Transfer8Bit(*pData++);}while(--NumBytes);}#endif}}/*********************************************************************** Public code************************************************************************/#ifFS_NOR_HW_SPI_USE_OS/*********************************************************************** SPI0_IRQHandler*/voidSPI0_IRQHandler(void);voidSPI0_IRQHandler(void){OS_EnterInterrupt();SPI_RSER &=~(1uL<<RSER_RFDF_RE_BIT);// Disable the interrupt.#if(FS_NOR_HW_SPI_USE_OS ==2)OS_EVENT_Set(&_Event);#elseFS_OS_Signal();#endif// FS_NOR_HW_SPI_USE_OS == 2OS_LeaveInterrupt();}#endif// FS_NOR_HW_SPI_USE_OS/*********************************************************************** Public data************************************************************************/constFS_NOR_HW_TYPE_SPIFS_NOR_HW_SPI_K66_SEGGER_emPower ={_HW_Init,_HW_EnableCS,_HW_DisableCS,_HW_Read,_HW_Write,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};/*************************** End of file ****************************/
Hardware layer API - FS_NOR_HW_TYPE_SPIFI
This hardware layer supports serial NOR flash devices that are interfaced via SPI
with their data content being mapped to the system memory of the MCU. This type of
interface translates read accesses to the system memory region where the serial NOR
flash device is mapped to read operations via SPI bus. Therefore, the hardware layer
can read the data from the serial NOR flash device by simply reading data from
the system memory. Any other operations with the serial NOR flash device are
performed by sending the commands directly via the SPI bus.
That is this hardware layer is able to transfer the data via one, two or four data lines.
The functions of this hardware layer are grouped in a structure of type FS_NOR_HW_TYPE_SPIFI.
The following sections describe these functions in detail.
FS_NOR_HW_TYPE_SPIFI
Description
Hardware layer for serial NOR flash devices that are memory-mapped.
This function is a member of the SPIFI NOR hardware layer API.
It has to be implemented by all the hardware layers.
This function is called by the NOR physical layer before any other
function of the hardware layer each time the file system mounts the
serial NOR flash. FS_NOR_HW_TYPE_SPIFI_INIT has to perform the initialization
of clock signals, GPIO ports, SPI controller, etc.
FS_NOR_HW_TYPE_SPIFI_UNMAP
Description
Configures the hardware for direct access to serial NOR flash.
This function is a member of the SPIFI NOR 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 NOR flash. Typically, the SPI hardware can operate
in two modes: command and memory. In command mode the physical layer can
access the serial NOR flash directly by sending commands to it.
In the memory mode the SPI hardware translates read accesses to an assigned
memory region to serial NOR flash read commands. In this way, the contents
of the contents of the serial NOR flash 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_NOR_HW_TYPE_SPIFI_MAP
Description
Configures the hardware for access to serial NOR flash via system memory.
Code of the command to be used for reading the data.
NumBytesAddr
Number of address bytes to be used for the read command.
NumBytesDummy
Number of dummy bytes to be sent after the read command.
BusWidth
Number of data lines to be used for the data transfer.
Additional information
This function is a member of the SPIFI NOR hardware layer API.
The implementation of this function is not required if the
hardware layer implements FS_NOR_HW_TYPE_SPIFI_MAP_EX.
This function is called by the physical layer when it no longer wants to send
commands directly to the serial NOR flash device. After the call to this
function the physical layer expects that the contents of the serial NOR flash
device is available in the system memory region assigned to SPI hardware
and that the data can be accessed by simple memory read operations.
If the command and memory mode are mutually exclusive,
then FS_NOR_HW_TYPE_SPIFI_MAP has to disable the command mode.
If the specified read command requires the generation of a number of dummy
cycles that is not a multiple of eight then the hardware layer will have to
implement the FS_NOR_HW_TYPE_SPIFI_MAP_EX function.
BusWidth encodes the number of data lines to be used when transferring the
command, address and data. The value can be decoded using FS_BUSWIDTH_GET_CMD(),
FS_BUSWIDTH_GET_ADDR() and FS_BUSWIDTH_GET_DATA(). The dummy bytes are sent
using the same number of data lines as the address. For additional information
refer to SPI bus width decoding
FS_NOR_HW_TYPE_SPIFI_CONTROL
Description
Sends a command to serial NOR flash that does not transfer any data.
Number of data lines to be used for sending the command.
Additional information
This function is a member of the SPIFI NOR hardware layer API.
The implementation of this function is not required if the
hardware layer implements FS_NOR_HW_TYPE_SPIFI_CONTROL_EX.
Typically, the physical layer calls FS_NOR_HW_TYPE_SPIFI_CONTROL
to enable or disable the write mode in the serial NOR flash, to set the
number of address bytes, etc. FS_NOR_HW_TYPE_SPIFI_CONTROL is called by
the physical layer only with the SPI hardware configured in command mode.
FS_NOR_HW_TYPE_SPIFI_CONTROL has to wait for the command to complete
before it returns.
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, and 4.
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.
Additional information
This function is a member of the SPIFI NOR hardware layer API.
The implementation of this function is not required if the
hardware layer implements FS_NOR_HW_TYPE_SPIFI_READ_EX.
This function is called with the SPI hardware in command mode. Typically,
the physical layer calls this function when it wants to read parameters
or status information from the serial NOR flash device.
FS_NOR_HW_TYPE_SPIFI_READ has to wait for the data transfer to complete
before it returns.
If FS_NOR_HW_TYPE_SPIFI_MAP is provided then the physical layer
reads the contents of the serial NOR flash device via reads accesses to the
system memory. FS_NOR_HW_TYPE_SPIFI_READ is used by the physical
layer to read the contents of the serial NOR flash device if
FS_NOR_HW_TYPE_SPIFI_MAP is not provided.
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 generated. The number of dummy bytes to be generated can
be calculated as NumBytesPara - NumBytesAddr. If the hardware is generating
dummy cycles instead of bytes then the number of dummy bytes have to converted
to clock cycles by taking into account the number of data lines used for the
data transfer of the address.
If the specified read command requires the generation of a number of dummy
cycles that is not a multiple of eight then the hardware layer will have to
implement the FS_NOR_HW_TYPE_SPIFI_READ_EX function.
BusWidth encodes the number of data lines to be used when transferring the
command, address and data. The value can be decoded using FS_BUSWIDTH_GET_CMD(),
FS_BUSWIDTH_GET_ADDR() and FS_BUSWIDTH_GET_DATA(). The dummy bytes are sent
using the same number of data lines as the address. For additional information
refer to SPI bus width decoding
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 NOR flash device. Can be NULL.
NumBytesData
Number of bytes to be written the serial NOR flash device. Can be 0.
BusWidth
Number of data lines to be used for the data transfer.
Additional information
This function is a member of the SPIFI NOR hardware layer API.
The implementation of this function is not required if the
hardware layer implements FS_NOR_HW_TYPE_SPIFI_WRITE_EX.
This function is called with the SPI hardware in command mode. Typically, the
physical layer calls this function when it wants to modify the data in a page
of the serial NOR flash device or to erase a NOR physical sector.
FS_NOR_HW_TYPE_SPIFI_WRITE has to wait for the data transfer to complete
before it returns.
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 additional data have to be sent. The number of additional bytes to be sent
can be calculated as NumBytesPara - NumBytesAddr. This data has to be sent
via the same number of data lines as the address.
BusWidth encodes the number of data lines to be used when transferring the
command, address and data. The value can be decoded using FS_BUSWIDTH_GET_CMD(),
FS_BUSWIDTH_GET_ADDR() and FS_BUSWIDTH_GET_DATA(). The dummy bytes are sent
using the same number of data lines as the address. For additional information
refer to SPI bus width decoding
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.
Additional information
This function is a member of the SPIFI NOR hardware layer API.
The implementation of this function is optional.
This function is called with the SPI hardware in command mode.
FS_NOR_HW_TYPE_SPIFI_POLL has to wait for the NOR flash device to set a flag
to a specified value. This has to be realized by periodically reading one
byte from the serial NOR flash device via the specified command and by checking
that the bit at BitPos in the read byte is set to the value specified by BitValue.
A BitPos of 0 specifies the position of the least significant bit in the response.
BusWidth encodes the number of data lines to be used when transferring the
command and data. The value can be decoded using FS_BUSWIDTH_GET_CMD(),
and FS_BUSWIDTH_GET_DATA(). For additional information refer to
SPI bus width decoding
This function is a member of the SPIFI NOR hardware layer API.
The implementation of this function is optional. FS_NOR_HW_TYPE_SPIFI_DELAY
can block the execution for longer than the number of milliseconds
specified but not less than that. Typically, the function is implemented
using a delay function of the used RTOS if any. If the hardware layer
chooses not to implement FS_NOR_HW_TYPE_SPIFI_DELAY then the pfDelay
member of FS_NOR_HW_TYPE_SPIFI can be set to NULL or to the address of
a function that returns a negative value. If the function is not
implemented by the hardware layer then the NOR physical layer blocks
the execution by using a software loop. The number of software loops
is calculated based in the SPI clock frequency returned by FS_NOR_HW_TYPE_SPIFI_INIT.
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_NOR_HW_TYPE_SPIFI_LOCK and FS_NOR_HW_TYPE_SPIFI_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_NOR_HW_TYPE_SPIFI_LOCK and released in FS_NOR_HW_TYPE_SPIFI_UNLOCK.
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_NOR_HW_TYPE_SPIFI_LOCK.
It is also guaranteed that FS_NOR_HW_TYPE_SPIFI_UNLOCK and
FS_NOR_HW_TYPE_SPIFI_LOCK are called in pairs.
FS_NOR_HW_TYPE_SPIFI_UNLOCK and FS_NOR_HW_TYPE_SPIFI_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_NOR_HW_TYPE_SPIFI_LOCK
and released in FS_NOR_HW_TYPE_SPIFI_UNLOCK.
FS_NOR_HW_TYPE_SPIFI_MAP_EX
Description
Configures the hardware for access to serial NOR flash via system memory.
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 SPIFI NOR 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 via eight data lines or in DTR mode.
If the hardware layer does not implement this function then FS_NOR_HW_TYPE_SPIFI_MAP
is called instead.
This function performs the same operation as FS_NOR_HW_TYPE_SPIFI_MAP
with the difference that it can handle multi-byte commands and additional
data transfer options received via Flags. Flags is a bitwise-or combination
of NOR HW layer flags. In addition, this function is able to report an error
via the return value.
FS_NOR_HW_TYPE_SPIFI_CONTROL_EX
Description
Sends a command to serial NOR flash that does not transfer any data.
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 SPIFI NOR 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 via eight data lines or in DTR mode.
If the hardware layer does not implement this function then FS_NOR_HW_TYPE_SPIFI_CONTROL
is called instead.
This function performs the same operation as FS_NOR_HW_TYPE_SPIFI_CONTROL
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 NOR HW layer flags. In addition, this function is able to report an error
via the return value.
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.
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 SPIFI NOR 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 via eight data lines or in DTR mode.
If the hardware layer does not implement this function then FS_NOR_HW_TYPE_SPIFI_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
neither mode nor dummy bytes have to be sent. The number of mode bytes is always one
and is indicated by FS_NOR_HW_FLAG_MODE_BYTE being set in Flags. The value of the
mode byte is located at *(pPara + NumBytesAddr).
The number of dummy bytes to be generated can be calculated as NumBytesPara - NumBytesAddr.
If FS_NOR_HW_FLAG_MODE_BYTE is set in Flags then one has to be subtracted from the calculate value.
One additional dummy nibble (half-byte) has to be generated if FS_NOR_HW_FLAG_DUMMY_NIBBLE
is set in Flags.
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_NOR_HW_TYPE_SPIFI_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 NOR HW layer flags. In addition, this function is able to report an error
via the return value.
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 NOR flash device. Can be NULL.
NumBytesData
Number of bytes to be written 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 SPIFI NOR 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 via eight data lines or in DTR mode.
If the hardware layer does not implement this function then FS_NOR_HW_TYPE_SPIFI_WRITE
is called instead.
This function performs the same operation as FS_NOR_HW_TYPE_SPIFI_WRITE
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 NOR HW layer flags. In addition, this function is able to report an error
via the return value.
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.
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.
Flags
Options for the data exchange.
Return value
> 0
Timeout occurred.
= 0
OK, bit set to specified value.
< 0
Feature not supported.
Additional information
This function is a member of the SPIFI NOR 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 of the polling
command via eight data lines or in DTR mode. If the hardware layer does not implement
this function then FS_NOR_HW_TYPE_SPIFI_POLL is called instead.
This function performs the same operation as FS_NOR_HW_TYPE_SPIFI_POLL
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 NOR HW layer flags. In addition, this function is able to report an error
via the return value.
This function is a member of the SPIFI NOR hardware layer API.
The implementation of this function is optional.
The SPIFI NOR physical layer calls this function at the end
of a write or erase operation to inform the SPIFI HW layer
about the range of bytes modified by the operation.
This information can be used for example to invalidate
a data cache.
This function is a member of the SPIFI NOR hardware layer API.
The implementation of this function is optional.
The SPIFI NOR physical layer calls this function when it has
to read data from the NOR flash device via the system memory.
If this function is not implemented, then the SPIFI NOR physical
layer reads the data directly from the system memory.
Addr is the address in the system memory.
NOR HW layer flags
Description
Additional options for data exchanged by the SPI NOR HW layers.
Data strobe signal is inverted in reference to clock signal.
FS_NOR_HW_FLAG_DTR_D1_D0
Send odd-numbered bytes on the rising edge of the clock signal.
FS_NOR_HW_FLAG_ADDR_3BYTE
Send a 3-byte address to NOR flash device.
FS_NOR_HW_FLAG_DUMMY_4BIT
Generate additional dummy cycles equivalent to four bits of data.
FS_NOR_HW_FLAG_DUMMY_2BIT
Generate additional dummy cycles equivalent to two bits of data.
FS_NOR_HW_FLAG_DUMMY_1BIT
Generate additional dummy cycles equivalent to one bit of data.
FS_NOR_HW_FLAG_MODE_8BIT
Send eight mode bits after the data address.
FS_NOR_HW_FLAG_MODE_4BIT
Send four mode bits after the data address.
FS_NOR_HW_FLAG_MODE_2BIT
Send two mode bits after the data address.
FS_NOR_HW_FLAG_MODE_1BIT
Send one mode bit after the data address.
Sample implementation
The following sample implementation uses the SPIFI controller of an NXP LPC4322
MCU to interface with a serial NOR flash device. This NOR hardware layer has been
tested on a SGGER internal test board.
/********************************************************************** (c) SEGGER Microcontroller GmbH ** The Embedded Experts ** www.segger.com ***********************************************************************-------------------------- END-OF-HEADER -----------------------------File : NOR_PHY_SPIFI_NXP_LPC4322_SEGGER_QSPIFI_Test_Board.cPurpose : Low-level flash driver for NXP SPIFI interface.Literature: [1] UM10503 LPC43xx ARM Cortex-M4/M0 multi-core microcontroller*//*********************************************************************** #include section************************************************************************/#include"FS.h"/*********************************************************************** Defines, configurable************************************************************************/#defineSPIFI_CLK_HZ 60000000uL// Frequency of the clock supplied to SPIFI unit.#defineSPIFI_DATA_ADDR 0x80000000// This is the start address of the memory region used by the file system// to read the data from the serial NOR flash device. The hardware layer// performs a dummy read from this address when switching to memory mode// in order to clean the caches. It should be set to the value passed// as second parameter to FS_NOR_Configure()/FS_NOR_BM_Configure() in FS_X_AddDevices().#defineRESET_DELAY_LOOPS 100000// Number of software loops to wait for NOR device to reset#defineUSE_OS 0// Enables / disables the interrupt driver operation/*********************************************************************** #include section, conditional************************************************************************/#ifUSE_OS#include"RTOS.h"#include"lpc43xx.h"#endif/*********************************************************************** Defines, fixed************************************************************************//*********************************************************************** SPIFI unit*/#defineSPIFI_BASE_ADDR 0x40003000#defineSPIFI_CTRL (*(volatileU32*)(SPIFI_BASE_ADDR +0x00))// SPIFI control register#defineSPIFI_CMD (*(volatileU32*)(SPIFI_BASE_ADDR +0x04))// SPIFI command register#defineSPIFI_ADDR (*(volatileU32*)(SPIFI_BASE_ADDR +0x08))// SPIFI address register#defineSPIFI_IDATA (*(volatileU32*)(SPIFI_BASE_ADDR +0x0C))// SPIFI intermediate data register#defineSPIFI_CLIMIT (*(volatileU32*)(SPIFI_BASE_ADDR +0x10))// SPIFI cache limit register#defineSPIFI_DATA32 (*(volatileU32*)(SPIFI_BASE_ADDR +0x14))// SPIFI data register (32-bit access, 4 bytes at once)#defineSPIFI_DATA16 (*(volatileU16*)(SPIFI_BASE_ADDR +0x14))// SPIFI data register (16-bit access, 2 bytes at once)#defineSPIFI_DATA8 (*(volatileU8*)(SPIFI_BASE_ADDR +0x14))// SPIFI data register (8-bit access, 1 byte at once)#defineSPIFI_MCMD (*(volatileU32*)(SPIFI_BASE_ADDR +0x18))// SPIFI memory command register#defineSPIFI_STAT (*(volatileU32*)(SPIFI_BASE_ADDR +0x1C))// SPIFI status register/*********************************************************************** Clock generation unit*/#defineCGU_BASE_ADDR 0x40050000#defineIDIVA_CTRL (*(volatileU32*)(CGU_BASE_ADDR +0x0048))#defineIDIVB_CTRL (*(volatileU32*)(CGU_BASE_ADDR +0x004C))#defineBASE_SPIFI_CLK (*(volatileU32*)(CGU_BASE_ADDR +0x0070))/*********************************************************************** Clock control unit 1*/#defineCCU1_BASE_ADDR 0x40051000#defineCLK_SPIFI_CFG (*(volatileU32*)(CCU1_BASE_ADDR +0x0300))#defineCLK_SPIFI_STAT (*(volatileU32*)(CCU1_BASE_ADDR +0x0304))/*********************************************************************** System control unit*/#defineSCU_BASE_ADDR 0x40086000#defineSFSP3_2 (*(volatileU32*)(SCU_BASE_ADDR +0x188))// Pin configuration register for pin P3_2#defineSFSP3_3 (*(volatileU32*)(SCU_BASE_ADDR +0x18C))// Pin configuration register for pin P3_3#defineSFSP3_4 (*(volatileU32*)(SCU_BASE_ADDR +0x190))// Pin configuration register for pin P3_4#defineSFSP3_5 (*(volatileU32*)(SCU_BASE_ADDR +0x194))// Pin configuration register for pin P3_5#defineSFSP3_6 (*(volatileU32*)(SCU_BASE_ADDR +0x198))// Pin configuration register for pin P3_6#defineSFSP3_7 (*(volatileU32*)(SCU_BASE_ADDR +0x19C))// Pin configuration register for pin P3_7#defineSFSP3_8 (*(volatileU32*)(SCU_BASE_ADDR +0x1A0))// Pin configuration register for pin P3_8/*********************************************************************** GPIO unit*/#defineGPIO_BASE_ADDR 0x400F4000#defineGPIO_DIR5 (*(volatileU32*)(GPIO_BASE_ADDR +0x2014))// Direction registers port 5#defineGPIO_SET5 (*(volatileU32*)(GPIO_BASE_ADDR +0x2214))// Set register for port 5#defineGPIO_CLR5 (*(volatileU32*)(GPIO_BASE_ADDR +0x2294))// Clear register for port 5/*********************************************************************** SPIFI command register*/#defineCMD_BITPOS_BIT 0#defineCMD_BITPOS_MASK 0x7uL#defineCMD_BITVAL_BIT 3#defineCMD_BITVAL_MASK 0x1uL#defineCMD_DATALEN_BIT 0#defineCMD_DATALEN_MASK 0x3FFFuL#defineCMD_POLL_BIT 14#defineCMD_DOUT_BIT 15#defineCMD_INTLEN_BIT 16#defineCMD_INTLEN_MASK 0x7uL#defineCMD_FIELDFORM_BIT 19#defineCMD_FIELDFORM_ALL_SERIAL 0x0uL#defineCMD_FIELDFORM_QUAD_DUAL_DATA 0x1uL#defineCMD_FIELDFORM_SERIAL_OPCODE 0x2uL#defineCMD_FIELDFORM_ALL_QUAD_DUAL 0x3uL#defineCMD_FRAMEFORM_BIT 21#defineCMD_FRAMEFORM_OPCODE 0x1uL#defineCMD_FRAMEFORM_OPCODE_1BYTE 0x2uL#defineCMD_FRAMEFORM_OPCODE_2BYTES 0x3uL#defineCMD_FRAMEFORM_OPCODE_3BYTES 0x4uL#defineCMD_FRAMEFORM_OPCODE_4BYTES 0x5uL#defineCMD_OPCODE_BIT 24#defineCMD_OPCODE_MASK 0xFFuL/*********************************************************************** SPIFI control register*/#defineCTRL_TIMEOUT_BIT 0#defineCTRL_CSHIGH_BIT 16#defineCTRL_D_PRFTCH_DIS_BIT 21#defineCTRL_MODE3_BIT 23#defineCTRL_INTEN_BIT 22#defineCTRL_PRFTCH_DIS_BIT 27#defineCTRL_DUAL_BIT 28#defineCTRL_FBCLK_BIT 30/*********************************************************************** SPIFI status register*/#defineSTAT_MCINIT_BIT 0#defineSTAT_CMD_BIT 1#defineSTAT_RESET_BIT 4#defineSTAT_INTRQ_BIT 5/*********************************************************************** Misc. defines*/#defineCGU_IDIV_BIT 2#defineCGU_AUTOBLOCK_BIT 11#defineCGU_CLK_SEL_BIT 24#defineSFS_MODE_BIT 0#defineSFS_EPUN_BIT 4#defineSFS_EHS_BIT 5#defineSFS_EZI_BIT 6#defineSFS_ZIF_BIT 7#defineCLK_STAT_RUN_BIT 0#defineCLK_CFG_RUN_BIT 0#defineNOR_RESET_BIT 9#defineSPIFI_PRIO 15/*********************************************************************** ASSERT_IS_LOCKED*/#ifFS_SUPPORT_TEST#defineASSERT_IS_LOCKED() \if(_LockCnt !=1){ \FS_X_PANIC(FS_ERRCODE_INVALID_USAGE); \}#else#defineASSERT_IS_LOCKED()#endif/*********************************************************************** IF_TEST*/#ifFS_SUPPORT_TEST#defineIF_TEST(Expr)Expr#else#defineIF_TEST(Expr)#endif/*********************************************************************** Static data************************************************************************/#ifFS_SUPPORT_TESTstaticU8 _LockCnt =0;// Just to test if the Lock()/Unlock function are called correctly.#endif/*********************************************************************** Static code************************************************************************//*********************************************************************** _GetFieldForm** Function description* Determines the value to be stored in the FIELDFORM field* of the SPIFI_CMD and SPIFI_MCMD registers. It also returns* the value of the SPIFI_CTRL.DUAL field.*/staticU32 _GetFieldForm(U16 BusWidth,int*pIsDual){U32 FieldForm;intIsDual;IsDual =0;if(BusWidth ==0x112u){FieldForm =CMD_FIELDFORM_QUAD_DUAL_DATA;// Data field is dual other fields are serial.IsDual =1;}elseif(BusWidth ==0x114u){FieldForm =CMD_FIELDFORM_QUAD_DUAL_DATA;// Data field is quad other fields are serial.}elseif(BusWidth ==0x122u){FieldForm =CMD_FIELDFORM_SERIAL_OPCODE;// Opcode field is serial. Other fields are dual.IsDual =1;}elseif(BusWidth ==0x144u){FieldForm =CMD_FIELDFORM_SERIAL_OPCODE;// Opcode field is serial. Other fields are quad.}elseif(BusWidth ==0x444u){FieldForm =CMD_FIELDFORM_ALL_QUAD_DUAL;// Opcode field is serial. Other fields are quad.}else{FieldForm =CMD_FIELDFORM_ALL_SERIAL;// All fields of the command are serial.}if(pIsDual){*pIsDual =IsDual;}returnFieldForm;}/*********************************************************************** _GetFieldFormEx** Function description* Same functionality as _GetFieldForm() with BusWidth not encoded.*/staticU32 _GetFieldFormEx(U8 BusWidth,int*pIsDual){U32 FieldForm;intIsDual;IsDual =0;if(BusWidth ==1){FieldForm =CMD_FIELDFORM_ALL_SERIAL;// All fields of the command are serial.}elseif(BusWidth ==2){FieldForm =CMD_FIELDFORM_ALL_QUAD_DUAL;// All fields are dual.IsDual =1;}elseif(BusWidth ==4){FieldForm =CMD_FIELDFORM_ALL_QUAD_DUAL;// All fields are quad.}else{FieldForm =CMD_FIELDFORM_ALL_SERIAL;// All fields of the command are serial.}if(pIsDual){*pIsDual =IsDual;}returnFieldForm;}/*********************************************************************** _GetFrameForm** Function description* Determines the value to be stored in the FAMEFORM field* of the SPIFI_CMD and SPIFI_MCMD registers.*/staticU32 _GetFrameForm(unsignedNumBytesAddr){U32 FrameForm;if(NumBytesAddr ==1){FrameForm =CMD_FRAMEFORM_OPCODE_1BYTE;// Opcode + 1 address byte.}elseif(NumBytesAddr ==2){FrameForm =CMD_FRAMEFORM_OPCODE_2BYTES;// Opcode + 2 address bytes.}elseif(NumBytesAddr ==3){FrameForm =CMD_FRAMEFORM_OPCODE_3BYTES;// Opcode + 3 address bytes.}elseif(NumBytesAddr ==4){FrameForm =CMD_FRAMEFORM_OPCODE_4BYTES;// Opcode + 4 address bytes.}else{FrameForm =CMD_FRAMEFORM_OPCODE;// Opcode, no address bytes.}returnFrameForm;}/*********************************************************************** _Reset*/staticvoid_Reset(void){SPIFI_STAT =(1uL<<STAT_RESET_BIT);// Reset the SPIFI controller. The controller is put into SPI mode.while(1){if((SPIFI_STAT &((1uL<<STAT_CMD_BIT)|(1uL<<STAT_RESET_BIT)|(1uL<<STAT_MCINIT_BIT)))==0){break;// Wait until the SPIFI controller is ready again.}}}/*********************************************************************** Public code************************************************************************/#ifUSE_OS/*********************************************************************** SPIFI_IRQHandler*/voidSPIFI_IRQHandler(void);voidSPIFI_IRQHandler(void){OS_EnterInterrupt();SPIFI_STAT |=1uL<<STAT_INTRQ_BIT;// Prevent other interrupts from occurring.FS_X_OS_Signal();OS_LeaveInterrupt();}#endif/*********************************************************************** Public code (via callback)************************************************************************//*********************************************************************** _HW_Init** Function description* HW layer function. It is called before any other function of the physical layer.* It should configure the HW so that the other functions can access the NOR flash.** Return value* Frequency of the SPI clock in Hz.*/staticint_HW_Init(U8 Unit){unsignedNumLoops;FS_USE_PARA(Unit);// This device has only one HW unit.//// Use IDIVA as clock for SPIFI. The input of IDIVA is PLL1.//IDIVA_CTRL =0|(9uL<<CGU_CLK_SEL_BIT)// Use PLL1 as input|(2uL<<CGU_IDIV_BIT)// Divide PLL1 by 3|(1uL<<CGU_AUTOBLOCK_BIT);BASE_SPIFI_CLK =0|12uL<<CGU_CLK_SEL_BIT // Use IDIVA as clock generator|1uL<<CGU_AUTOBLOCK_BIT;//// Enable the SPIFI clock if required.//if((CLK_SPIFI_STAT &(1uL<<CLK_STAT_RUN_BIT))==0){CLK_SPIFI_CFG |=(1uL<<CLK_CFG_RUN_BIT);while(1){if(CLK_SPIFI_STAT &(1uL<<CLK_CFG_RUN_BIT)){;}}}//// Clock pin.//SFSP3_3 =0|(3uL<<SFS_MODE_BIT)|(1uL<<SFS_EPUN_BIT)|(1uL<<SFS_EHS_BIT)|(1uL<<SFS_EZI_BIT);//// Data pins.//SFSP3_4 =0|(3uL<<SFS_MODE_BIT)|(1uL<<SFS_EPUN_BIT)|(1uL<<SFS_EZI_BIT);SFSP3_5 =0|(3uL<<SFS_MODE_BIT)|(1uL<<SFS_EPUN_BIT)|(1uL<<SFS_EZI_BIT);SFSP3_6 =0|(3uL<<SFS_MODE_BIT)|(1uL<<SFS_EPUN_BIT)|(1uL<<SFS_EZI_BIT);SFSP3_7 =0|(3uL<<SFS_MODE_BIT)|(1uL<<SFS_EPUN_BIT)|(1uL<<SFS_EZI_BIT);//// Chip select pin.//SFSP3_8 =0|(3uL<<SFS_MODE_BIT)// Controlled by this HW layer.|(1uL<<SFS_EPUN_BIT);//// 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).#ifUSE_OS//// Disable the interrupt and configure the priority.//NVIC_DisableIRQ(SPIFI_IRQn);NVIC_SetPriority(SPIFI_IRQn,SPIFI_PRIO);#endif//// Configure the SPIFI unit.//SPIFI_CTRL =0|(0xFFFFuL<<CTRL_TIMEOUT_BIT)// Use the maximum timeout.|(0xFuL<<CTRL_CSHIGH_BIT)// Set minimum CS high time to maximum value.|(0x1uL<<CTRL_D_PRFTCH_DIS_BIT)// Disable memory prefetches.|(0x1uL<<CTRL_MODE3_BIT)// CLK idle mode is high.|(0x1uL<<CTRL_PRFTCH_DIS_BIT)// Disables prefetching of cache lines.|(0x1uL<<CTRL_FBCLK_BIT)// Read data is sampled using a feedback clock from the SCK pin.;#ifUSE_OS//// Clear interrupt flag.//SPIFI_STAT =1uL<<STAT_INTRQ_BIT;NVIC_EnableIRQ(SPIFI_IRQn);#endifreturnSPIFI_CLK_HZ;}/*********************************************************************** _HW_SetCmdMode** Function description* HW layer function. It enables the direct access to NOR flash via SPI.* This function disables the memory-mapped mode.*/staticvoid_HW_SetCmdMode(U8 Unit){ASSERT_IS_LOCKED();FS_USE_PARA(Unit);// This device has only one HW unit._Reset();}/*********************************************************************** _HW_SetMemMode** Function description* HW layer function. It enables the memory-mapped mode. In this mode* the data can be accessed by doing read operations from memory.* The HW is responsible to transfer the data via SPI.* This function disables the direct access to NOR flash via SPI.*/staticvoid_HW_SetMemMode(U8 Unit,U8 ReadCmd,unsignedNumBytesAddr,unsignedNumBytesDummy,U16 BusWidth){U32 FieldForm;U32 FrameForm;U32 OpCode;U32 IntLen;intIsDual;U32 MCmdReg;U32 v;ASSERT_IS_LOCKED();FS_USE_PARA(Unit);// This device has only one HW unit.//// Determine how the data transferred is sent (serial, dual or quad)// and how many address bytes to send.//IsDual =0;FieldForm =_GetFieldForm(BusWidth,&IsDual);FrameForm =_GetFrameForm(NumBytesAddr);IntLen =NumBytesDummy &CMD_INTLEN_MASK;OpCode =ReadCmd &CMD_OPCODE_MASK;MCmdReg =0|(IntLen <<CMD_INTLEN_BIT)|(FieldForm <<CMD_FIELDFORM_BIT)|(FrameForm <<CMD_FRAMEFORM_BIT)|(OpCode <<CMD_OPCODE_BIT);//// Configure the SPIFI controller to work in memory-mapped mode.//v =SPIFI_CTRL;if(IsDual){v |=1uL<<CTRL_DUAL_BIT;}else{v &=~(1uL<<CTRL_DUAL_BIT);}SPIFI_CTRL =v;SPIFI_MCMD =MCmdReg;//// Wait until MCMD is written//while(1){if(SPIFI_STAT &(1uL<<STAT_MCINIT_BIT)){break;}}//// Perform dummy read to bring controller into sync and invalidate all caches etc.// It seems to be necessary but not documented in the datasheet.//*(volatileU32*)SPIFI_DATA_ADDR;}/*********************************************************************** _HW_ExecCmd** Function description* HW layer function. It requests the NOR flash to execute a simple command.* The HW has to be in SPI mode.*/staticvoid_HW_ExecCmd(U8 Unit,U8 Cmd,U8 BusWidth){U32 FieldForm;intIsDual;U32 FrameForm;U32 CmdReg;U32 v;ASSERT_IS_LOCKED();FS_USE_PARA(Unit);// This device has only one HW unit.IsDual =0;FieldForm =_GetFieldFormEx(BusWidth,&IsDual);FrameForm =_GetFrameForm(0);// 0 - No address bytes are sent.CmdReg =0|(FieldForm <<CMD_FIELDFORM_BIT)// Configure the transfer mode.|(FrameForm <<CMD_FRAMEFORM_BIT)// Send only the command byte.|((U32)Cmd <<CMD_OPCODE_BIT)// Command code.;v =SPIFI_CTRL;if(IsDual){v |=1uL<<CTRL_DUAL_BIT;}else{v &=~(1uL<<CTRL_DUAL_BIT);}SPIFI_CTRL =v;SPIFI_CMD =CmdReg;//// Wait until nCS is set high, indicating that the command has been completed.//while(1){if((SPIFI_STAT &(1uL<<STAT_CMD_BIT))==0){break;}}}/*********************************************************************** _HW_ReadData** Function description* HW layer function. It transfers data from NOR flash to MCU.* The HW has to be in SPI mode.*/staticvoid_HW_ReadData(U8 Unit,U8 Cmd,constU8 *pPara,unsignedNumBytesPara,unsignedNumBytesAddr,U8 *pData,unsignedNumBytesData,U16 BusWidth){U32 DataLen;U32 AddrReg;U32 IDataReg;U32 CmdReg;U32 FieldForm;intIsDual;U32 FrameForm;U32 IntLen;unsignedNumBytes;U32 v;ASSERT_IS_LOCKED();FS_USE_PARA(Unit);// This device has only one HW unit.//// Fill local variables.//IsDual =0;FieldForm =_GetFieldForm(BusWidth,&IsDual);FrameForm =_GetFrameForm(NumBytesAddr);IntLen =0;DataLen =NumBytesData &CMD_DATALEN_MASK;AddrReg =0;IDataReg =0;//// Encode the address.//if(NumBytesAddr){NumBytes =NumBytesAddr;do{AddrReg <<=8;AddrReg |=(U32)(*pPara++);}while(--NumBytes);}//// Encode the dummy and mode bytes.//if(NumBytesPara >NumBytesAddr){NumBytes =NumBytesPara -NumBytesAddr;IntLen =NumBytes;do{IDataReg <<=8;IDataReg |=(U32)(*pPara++);}while(--NumBytes);}CmdReg =0|(DataLen <<CMD_DATALEN_BIT)|(IntLen <<CMD_INTLEN_BIT)|(FieldForm <<CMD_FIELDFORM_BIT)|(FrameForm <<CMD_FRAMEFORM_BIT)|((U32)Cmd <<CMD_OPCODE_BIT);//// Set dual/quad mode.//v =SPIFI_CTRL;if(IsDual){v |=1uL<<CTRL_DUAL_BIT;}else{v &=~(1uL<<CTRL_DUAL_BIT);}SPIFI_CTRL =v;//// Execute the command.//SPIFI_ADDR =AddrReg;SPIFI_IDATA =IDataReg;SPIFI_CMD =CmdReg;//// Read data from NOR flash.//if(NumBytesData){do{*pData++=SPIFI_DATA8;}while(--NumBytesData);}//// Wait until nCS is set high, indicating that the command has been completed.//while(1){if((SPIFI_STAT &(1uL<<STAT_CMD_BIT))==0){break;}}}/*********************************************************************** _HW_WriteData** Function description* HW layer function. It transfers data from MCU to NOR flash.* The HW has to be in SPI mode.*/staticvoid_HW_WriteData(U8 Unit,U8 Cmd,constU8 *pPara,unsignedNumBytesPara,unsignedNumBytesAddr,constU8 *pData,unsignedNumBytesData,U16 BusWidth){U32 DataLen;U32 AddrReg;U32 IDataReg;U32 FieldForm;intIsDual;U32 FrameForm;U32 IntLen;unsignedNumBytesAtOnce;unsignedNumBytes;U32 v;U32 CmdReg;ASSERT_IS_LOCKED();FS_USE_PARA(Unit);// This device has only one HW unit.//// Fill local variables.//IsDual =0;FieldForm =_GetFieldForm(BusWidth,&IsDual);FrameForm =_GetFrameForm(NumBytesAddr);IntLen =0;DataLen =NumBytesData &CMD_DATALEN_MASK;AddrReg =0;IDataReg =0;//// Encode the address.//if(NumBytesAddr){NumBytes =NumBytesAddr;do{AddrReg <<=8;AddrReg |=(U32)(*pPara++);}while(--NumBytes);}//// Encode the dummy and mode bytes.//if(NumBytesPara >NumBytesAddr){NumBytes =NumBytesPara -NumBytesAddr;IntLen =NumBytes;do{IDataReg <<=8;IDataReg |=(U32)(*pPara++);}while(--NumBytes);}CmdReg =0|(DataLen <<CMD_DATALEN_BIT)|(1uL<<CMD_DOUT_BIT)// Transfer data to NOR flash|(IntLen <<CMD_INTLEN_BIT)|(FieldForm <<CMD_FIELDFORM_BIT)|(FrameForm <<CMD_FRAMEFORM_BIT)|((U32)Cmd <<CMD_OPCODE_BIT);//// Set dual/quad mode.//v =SPIFI_CTRL;if(IsDual){v |=1uL<<CTRL_DUAL_BIT;}else{v &=~(1uL<<CTRL_DUAL_BIT);}SPIFI_CTRL =v;//// Execute the command.//SPIFI_ADDR =AddrReg;SPIFI_IDATA =IDataReg;SPIFI_CMD =CmdReg;//// Wait for the command to start execution.//if(NumBytesData){while(1){if(SPIFI_STAT &(1uL<<STAT_CMD_BIT)){break;}}}//// Write data to NOR flash.//if(NumBytesData){do{NumBytesAtOnce =NumBytesData >=4?4:1;if(NumBytesAtOnce ==4){v =0|(U32)*pData|((U32)(*(pData +1))<<8)|((U32)(*(pData +2))<<16)|((U32)(*(pData +3))<<24);SPIFI_DATA32 =v;}else{SPIFI_DATA8 =*pData;}NumBytesData -=NumBytesAtOnce;pData +=NumBytesAtOnce;}while(NumBytesData);}//// Wait until nCS is set high, indicating that the command has been completed.//while(1){if((SPIFI_STAT &(1uL<<STAT_CMD_BIT))==0){break;}}}/*********************************************************************** _HW_Poll** Function description* HW layer function. Sends a command repeatedly and checks the* response for a specified condition.** Return value* > 0 Timeout occurred.* ==0 OK, bit set to specified value.* < 0 Feature not supported.** Additional information* The function executes periodically a command and waits* until specified bit in the response returned by the NOR flash* is set to a value specified by BitValue. The position of the bit* that has to be checked is specified by BitPos where 0 is the* position of the least significant bit in the byte.*/staticint_HW_Poll(U8 Unit,U8 Cmd,U8 BitPos,U8 BitValue,U32 Delay,U32 TimeOut_ms,U16 BusWidth){intr;ASSERT_IS_LOCKED();FS_USE_PARA(Unit);FS_USE_PARA(Delay);r =-1;// Set to indicate that the feature is not supported.#ifUSE_OS{U32 AddrReg;U32 IDataReg;U32 CmdReg;U32 FieldForm;intIsDual;U32 FrameForm;U32 v;//// Fill local variables.//IsDual =0;FieldForm =_GetFieldForm(BusWidth,&IsDual);FrameForm =_GetFrameForm(0);// The command does not require any address bytes.AddrReg =0;IDataReg =0;CmdReg =0|((BitValue &CMD_BITVAL_MASK)<<CMD_BITVAL_BIT)|((BitPos &CMD_BITPOS_MASK)<<CMD_BITPOS_BIT)|(1uL<<CMD_POLL_BIT)|(FieldForm <<CMD_FIELDFORM_BIT)|(FrameForm <<CMD_FRAMEFORM_BIT)|(Cmd <<CMD_OPCODE_BIT);//// Set dual/quad mode.//v =SPIFI_CTRL;if(IsDual){v |=1uL<<CTRL_DUAL_BIT;}else{v &=~(1uL<<CTRL_DUAL_BIT);}SPIFI_CTRL =v;//// Execute the command.//SPIFI_STAT =1uL<<STAT_INTRQ_BIT;// Clear the interrupt flag.SPIFI_CTRL |=1uL<<CTRL_INTEN_BIT;// Enable interrupt.SPIFI_ADDR =AddrReg;SPIFI_IDATA =IDataReg;SPIFI_CMD =CmdReg;r =FS_X_OS_Wait(TimeOut_ms);SPIFI_CTRL &=~(1uL<<CTRL_INTEN_BIT);// Disable interrupt.if(r){r =1;// A timeout occurred.}else{r =0;// Bit set to the requested value.}_Reset();// Cancel the polling operation.//// Wait until nCS is set high, indicating that the command has been completed.//while(1){if((SPIFI_STAT &(1uL<<STAT_CMD_BIT))==0){break;}}}#elseFS_USE_PARA(Cmd);FS_USE_PARA(BitPos);FS_USE_PARA(BitValue);FS_USE_PARA(Delay);FS_USE_PARA(TimeOut_ms);FS_USE_PARA(BusWidth);#endifreturnr;}/*********************************************************************** _HW_Delay** Function description* HW layer function. Blocks the execution for the specified number* of milliseconds.*/staticint_HW_Delay(U8 Unit,U32 ms){intr;FS_USE_PARA(Unit);r =-1;// Set to indicate that the feature is not supported.#ifUSE_OSif(ms){FS_X_OS_Delay(ms);r =0;}#elseFS_USE_PARA(ms);#endifreturnr;}/*********************************************************************** _HW_Lock** Function description* HW layer function. Requests exclusive access to SPI bus.*/staticvoid_HW_Lock(U8 Unit){FS_USE_PARA(Unit);IF_TEST(_LockCnt++);ASSERT_IS_LOCKED();}/*********************************************************************** _HW_Unlock** Function description* HW layer function. Releases the exclusive access of SPI bus.*/staticvoid_HW_Unlock(U8 Unit){FS_USE_PARA(Unit);ASSERT_IS_LOCKED();IF_TEST(_LockCnt--);}/*********************************************************************** Global data************************************************************************/constFS_NOR_HW_TYPE_SPIFIFS_NOR_HW_SPIFI_LPC4322_SEGGER_QSPIFI_Test_Board ={_HW_Init,_HW_SetCmdMode,_HW_SetMemMode,_HW_ExecCmd,_HW_ReadData,_HW_WriteData,_HW_Poll,_HW_Delay,_HW_Lock,_HW_Unlock,NULL,NULL,NULL,NULL,NULL,NULL,NULL};/*************************** End of file ****************************/
MMC/SD card driver
General information
emFile supports the use of MultiMediaCard (MMC) and Secure Digital (SD)
cards as well as of eMMC (Embedded MMC) as storage device.
MMC/SD cards are mechanically small, removable mass storage devices. The main design
goal of these devices is to provide a very low cost mass storage product, implemented
as a card with a simple controlling unit, and a compact, easy-to-implement interface.
These requirements lead to a reduction of the functionality of each card to an absolute
minimum. eMMC devices are operate in the same way as an MMC card with the difference
that they are not removable devices. Instead, they can be soldered on a circuit board.
In order to meet the requirements of any system, the MMC/SD cards are designed
to operate in two different I/O modes:
SPI mode
Card mode
Two device drivers are provided that support these different operating modes:
SPI MMC/SD driver - Supports legacy MMC and SD cards and it transfers
the data via standard SPI.
Card Mode MMC/SD driver - Supports legacy eMMC and SD cards and it
can transfer the data via one, four or eight data lines.
The drivers require very little RAM and provide and extremely efficient data transfer.
The selection of the driver depends on the access mode supported by the target hardware.
For more technical details about MMC and SD cards, check the documents
and specifications available on https://www.jedec.org and https://www.sdcard.org
Fail-safe operation
The data will be preserved in case of unexpected reset. However, a power failure can be critical
because data may be lost if the SD card does not have sufficient time to complete the in-progress write operation.
As a countermeasure, the hardware has to make sure that the power supply to the SD card drops slowly enough
to allow the SD card to complete the write operation. The SD specification requires that a write operation
has to finish within 250 ms time. However, an SD card is allowed to buffer the data written by host
and that can potentially increase the time it takes the SD card to complete the write operation.
This type of write buffering can be disabled via FS_MMC_CM_AllowBufferedWrite().
Typically, industrial-grade SD cards are able to handle power failures internally so that no special
hardware and software considerations are required.
eMMC devices have the same requirements in regards to the fail-safe operation as SD cards.
In addition, eMMC devices have the ability to write the data in a fail-safe way that reduces
the chance of a data loss in case of a power failure. This type of write operation is called
Reliable Write and can be enabled via FS_MMC_CM_AllowReliableWrite(). Enabling this write mode
is recommended for a correct fail-safe operation of the file system.
Wear leveling
MMC/SD cards are controlled by an internal controller, this controller also handles
wear leveling. Therefore, the driver does not need to handle wear-leveling.
CRC verification
CRC (Cyclic Redundancy Check) is a method to produce a checksum.
The checksum is a small, fixed number of bits calculated based on the contents of
a block of data. The checksum is used to detect errors in a data block after transmission
or storage. A CRC is computed and appended before transmission or storage,
and verified afterwards by the recipient to confirm that no changes occurred.
CRC is a good solution for error detection, but reduces the transmission speed,
because a CRC checksum has to be computed for every data block is transmitted or stored.
FS_MMC_ActivateCRC()and FS_MMC_DeactivateCRC() can be used to control the CRC calculation
of the SPI MMC/SD driver. The Card Mode MMC/SD driver calculates the CRC in the hardware
with the help of the SD host controller. In this case, the CRC calculation and verification
is always enabled and it can not be deactivated.
Power control
Power control should be considered when creating designs using the MMC and/or SD
cards. The ability to have software power control of the cards makes the design more
flexible and robust. The host will be able to turn power to the card on or off
independent of whether the card is inserted or removed. This can improve card initialization
when there is a contact bounce during card insertion. The host waits a specified time
after the card is inserted before powering up the card and starting the initialization
process. Also, if the card goes into an unknown state, the host can cycle the power
and start the initialization process again. When card access is unnecessary, allowing
the host to power-down the bus can reduce the overall power consumption.
Supported hardware
Generally emFile supports any SD card that comply with any the version of
the SD Specification up to and including 3.0. In addition, MMC devices are supported
that comply with the any version of the MMC Specification up to and including 5.0.
The following memory card and device types are supported:
SD - SDSC (SD Standard Capacity), SDHC (SD High Capacity), SDXC (SD eXtended Capacity) in any form factor.
Note
The MMC cards conforming with the version 4.x or newer of the MMC specification
(MMCplus, MMCmobile, MMCmicro, eMMC, etc.) work only with the Card Mode MMC/SD
driver because these devices do not support the SPI mode.
The difference between MMC and SD cards is that SD cards can operate with a higher
clock frequency. In normal mode the range range of the clock frequency supplied
to an SD card can be between 0 and 25 MHz, whereas MMC cards can only operate up
to 20 MHz. The newer MMC cards that comply to the version 4.x or higher of the
MMC specification can also operate at higher frequencies up to 26 MHz.
An SD card can also operate in high speed mode with a clock frequency up to 50 MHz.
The MMC cards conforming to the version 3.x or lower of the MMC specification do
not support the high speed mode. The version 4.x of the MMC specification improves
this and allows the MMC cards to operate with a clock frequency of up to 52 MHz
in high speed mode.
The version 3.0 of the SD Specification and the version 4.5 of the MMC Specification
introduce new access modes that allow the devices to exchanged the data with a host
at a clock frequency of up to around 200 MHz in single and dual data rate modes.
These ultra high speed access modes use a voltage level of 1.8 V for SD cards and
either 1.8 or 1.2 V for MMC devices for the I/O signals.
The following table lists the access modes currently supported by emFile:
Device Type
Access Mode
Data Rate
I/O Voltage [V]
Bus Width [Data Lines]
Max. Clock Frequency [MHz]
SD
Default Speed
Single
3.3
1, 4
25
SD
High Speed
Single
3.3
1, 4
50
SD
SDR12
Single
1.8
1, 4
25
SD
SDR25
Single
1.8
1, 4
50
SD
DDR50
Dual
1.8
4
50
SD
SDR50
Single
1.8
4
100
SD
SDR104
Single
1.8
4
208
MMC
Default Speed
Single
3.3, 1.8
1, 4, 8
26
MMC
High Speed
Single
3.3, 1.8
1, 4, 8
52
MMC
High Speed
Dual
3.3, 1.8
4, 8
52
MMC
HS200
Single
1.8
4, 8
200
MMC
HS400
Dual
1.8
8
200
The HS400 Enhanced Strobe mode and 1.2 V I/O voltage are currently not supported for eMMC.
The ultra high speed access modes are supported only by the Card Mode MMC/SD driver.
MMC and SD cards also differ in the number of interface signals with MMC cards
typically requiring more signals than the SD cards. The number of signals used
depends on the operating mode.
Card mode
In this mode the MMC cards compliant to version 3.x or smaller of the MMC specification
require 6 signals: 1 command, 1 clock, 1 data and 3 power lines. The MMC cards compliant
with the version 4.x or higher of the MMC specification require up to 13 signals:
1 command, 1 clock, up to 8 data and 3 power lines. In contrast to the MMC cards,
SD cards require up to 9 signals: 1 command, 1 clock, up to 4 data and 3 power lines.
SPI mode
Both card systems use the same interface signals: 1 chip select, 1 data input, 1 data output,
1 clock and 3 power lines.
Pin description - MMC/SD card in card mode
The table below describes the pin assignment of the electrical interface of SD
and MMC cards working in card mode
Pin No.
Name
Type
Description
1
CD/DAT3
Input/Output using push pull drivers
Card Detect / Data line [Bit 3]. After power up this line is input with 50-kOhm pull-up resistor. This can be used for card detection; relevant only for SD cards. The pull-up resistor is disabled after the initialization procedure for using this line as DAT3, Data line [Bit 3], for data transfer.
2
CMD
Push Pull
Command/Response. CMD is a bidirectional command channel used for card initialization and data transfer commands. The CMD signal has two operation modes: open-drain for initialization mode and push-pull for fast command transfer. Commands are sent from the MMC bus master (card host controller) to the card and responses are sent from the cards to the host.
3
VSS
Power supply
Supply voltage ground.
4
VDD
Power supply
Supply voltage.
5
CLK
Input
Clock signal. With each cycle of this signal a one bit transfer on the command and data lines is done. The frequency may vary between zero and the maximum clock frequency.
6
VSS2
Power supply
Supply voltage ground.
7
DAT0
Input/Output using push pull drivers
Data line [Bit 0]. DAT is a bidirectional data channel. The DAT signal operates in push-pull mode. Only one card or the host is driving this signal at a time. Relevant only for SD cards: For data transfers, this line is the Data line [Bit 0].
8
DAT1
Input/Output using push pull drivers
Data line [Bit 1]. For data transfer, this line is the Data line [Bit 1]. Connect an external pull-up resistor to this data line even if only DAT0 is to be used. Otherwise, non-expected high current consumption may occur due to the floating inputs of DAT1.
9
DAT2
Input/Output using push pull drivers
Data line [Bit 2]. For data transfer, this line is the Data line [Bit 2]. Connect an external pull-up resistor to this data line even if only DAT0 is to be used. Otherwise, non-expected high current consumption may occur due to the floating inputs of DAT2.
10
DAT4
Input/Output using push pull drivers
Data line [Bit 4]. Relevant only for MMC storage devices. On SD cards this line does not exist. Not used for data transfers via four data lines. For data transfer via eight data lines, this line is carries the bit 4.
11
DAT5
Input/Output using push pull drivers
Data line [Bit 5]. Relevant only for MMC storage devices. On SD cards this line does not exist. Not used for data transfers via four data lines. For data transfer via eight data lines, this line is carries the bit 5.
12
DAT6
Input/Output using push pull drivers
Data line [Bit 6]. Relevant only for MMC storage devices. On SD cards this line does not exist. Not used for data transfers via four data lines. For data transfer via eight data lines, this line is carries the bit 6.
13
DAT7
Input/Output using push pull drivers
Data line [Bit 7]. Relevant only for MMC storage devices. On SD cards this line does not exist. Not used for data transfers via four data lines. For data transfer via eight data lines, this line is carries the bit 7.
The table below describes the pin assignment of the electrical interface of a
micro SD card working in card mode
Pin no.
Name
Type
Description
1
DAT2
Input/Output using push pull drivers
Data line [Bit 2]. On MMC card this line does not exist. Relevant only for SD cards: For data transfer, this line is the Data line [Bit 2]. Connect an external pull-up resistor to this data line even if only DAT0 is to be used. Otherwise, non-expected high current consumption may occur due to the floating inputs of DAT2.
2
CD/DAT3
Input/Output using push pull drivers
Card Detect / Data line [Bit 3]. After power up this line is input with 50-kOhm pull-up resistor. This can be used for card detection; relevant only for SD cards. The pull-up resistor is disabled after the initialization procedure for using this line as DAT3, Data line [Bit 3], for data transfer.
3
CMD
Push Pull
Command/Response. CMD is a bidirectional command channel used for card initialization and data transfer commands. The CMD signal has two operation modes: open-drain for initialization mode and push-pull for fast command transfer. Commands are sent from the MMC bus master (card host controller) to the card and responses are sent from the cards to the host.
4
VDD
Power supply
Supply voltage.
5
CLK
Input
Clock signal. With each cycle of this signal an one bit transfer on the command and data lines is done. The frequency may vary between zero and the maximum clock frequency.
6
VSS
Power supply
Supply ground.
7
DAT0
Input/Output using push pull drivers
Data line [Bit 0]. DAT is a bidirectional data channel. The DAT signal operates in push-pull mode. Only one card or the host is driving this signal at a time. Relevant only for SD cards: For data transfers, this line is the Data line [Bit 0].
8
DAT1
Input/Output using push pull drivers
Data line [Bit 1]. On MMC card this line does not exist. Relevant only for SD cards: For data transfer, this line is the Data line [Bit 1]. Connect an external pull-up resistor to this data line even if only DAT0 is to be used. Otherwise, non-expected high current consumption may occur due to the floating inputs of DAT1.
Additional information
External pull-up resistors must be connected to all data lines even it they are not
used. Otherwise, unexpected high current consumption may occur due to the floating
of these signals.
Pin description - MMC/SD card in SPI mode
The table below describes the pin assignment of the electrical interface
of SD and MMC cards working in SPI mode
Pin no.
Name
Type
Description
1
CS
Input
Chip Select. It sets the card active at low-level and inactive at high level.
2
DataIn (MOSI)
Input
Data Input (Master Out Slave In.) Transmits data to the card.
3
VSS
Supply ground
Power supply ground. Supply voltage ground.
4
VDD
Supply voltage
Supply voltage.
5
SCLK
Input
Clock signal. It must be generated by the target system. The card is always in slave mode.
6
VSS2
Supply ground
Supply ground.
7
DataOut (MISO)
Output
Data Output (Master In Slave Out.) Line to transfer data to the host.
8
Reserved
Not used
The reserved pin is a floating input. Therefore, connect an external pull-up resistor to it. Otherwise, non-expected high current consumption may occur due to the floating input.
9
Reserved
Not used
The reserved pin is a floating input. Therefore, connect an external pull-up resistor to it. Otherwise, non-expected high current consumption may occur due to the floating input.
The table below describes the pin assignment of the electrical interface of a micro SD
card working in SPI mode:
Pin no.
Name
Type
Description
1
Reserved
Not used
The reserved pin is a floating input. There- fore, connect an external pull-up resistor to it. Otherwise, non-expected high current consumption may occur due to the floating input.
2
CS
Input
Chip Select. It sets the card active at low-level and inactive at high level.
3
DataIn (MOSI)
Input
Data Input (Master Out Slave In.) Transmits data to the card.
4
VDD
Supply voltage
Supply voltage.
5
SCLK
Input
Clock signal. It must be generated by the target system. The card is always in slave mode.
6
VSS
Supply ground
Supply ground.
7
DataOut (MISO)
Output
Data Output (Master In Slave Out.) Line to transfer data to the host.
8
Reserved
Not used
The reserved pin is a floating input. Therefore, connect an external pull-up resistor to it. Otherwise, non-expected high current consumption may occur due to the floating input.
Additional information
The data transfer width is 8 bits.
Data should be output on the falling edge and must remain valid until the next
period. Rising edge means data is sampled (i.e. read).
The bit order requires most significant bit (MSB) to be sent out first.
Data polarity is normal, which means a logical “1” is represented with a high
level on the data line and a logical “0” is represented with low-level.
MMC/SD cards support different voltage ranges. Initial voltage should be 3.3V.
Interfacing with an MMC/SD card
The following picture shows how an MMC/SD card working in card mode can be
interfaced to a system.
The following picture shows how an MMC/SD card working in SPI mode can be
interfaced to a system.
SPI MMC/SD driver
Theory of operation
The Serial Peripheral Interface (SPI) bus is a very loose de facto standard for
controlling almost any digital electronics that accepts a clocked serial stream
of bits. SPI operates in full duplex (sending and receiving at the same time).
Configuring the driver
This section describes how to configure the file system to make use of the SPI MMC/SD driver.
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_MMC_SPI_Driver structure. 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 an MMC/SD card
connected via SPI.
#include"FS.h"#include"FS_MMC_HW_SPI_Template.h"#defineALLOC_SIZE 0x1300// Size defined in bytesstaticU32 _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().*/voidFS_X_AddDevices(void){//// Give the file system memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Add and configure the SPI MMC/SD driver.//FS_AddDevice(&FS_MMC_SPI_Driver);FS_MMC_SetHWType(0,&FS_MMC_HW_SPI_Template);// FS_MMC_ActivateCRC(); // Uncommenting this line activates// the CRC calculation of the SPI MMC/SD driver.//// Configure the file system for fast write operations.//#ifFS_SUPPORT_FILE_BUFFERFS_ConfigFileBufferDefault(512,FS_FILE_BUFFER_WRITE);#endifFS_SetFileWriteMode(FS_WRITEMODE_FAST);}
The API functions listed in the next table can be used by the application to
configure the behavior of the SPI MMC/SD driver. The application can call
them only at the file system initialization in FS_X_AddDevices().
This function is optional. The data verification uses a 16-bit CRC
to detect any corruption of the data being exchanged with the storage
device. By default, the data verification is disabled to improve performance.
FS_MMC_ActivateCRC() can be used at runtime to enable the data
verification for all driver instances. The data verification can
be disabled via FS_MMC_DeactivateCRC().
This function is mandatory and it has to be called once for each
instance of the driver.
Additional driver functions
These functions are optional. They can be used to get information about the
operation of the Card Mode MMC/SD driver and to perform additional operations
on the used SD card or MMC device.
This function is optional. The application can call this
function to get the information stored in the CID register
of an MMC or SD card. The CID register stores information which
can be used to uniquely identify the card such as serial number,
product name, manufacturer id, etc. For more information about
the information stored in this register refer to SD or MMC specification.
Example
The following example shows how to read and decode the contents of the CID register.
This function is optional. The SPI SD/MMC driver collects
statistics about the number of internal operations such as the
number of logical sectors read or written by the file system layer.
The application can use FS_MMC_GetStatCounters() to get the
current value of these counters. The statistical counters are
automatically set to 0 when the storage device is mounted or when
the application calls FS_MMC_ResetStatCounters().
The statistical counters are available only when the file system
is compiled with FS_DEBUG_LEVEL greater than or equal to
FS_DEBUG_LEVEL_CHECK_ALL or with FS_MMC_ENABLE_STATS set to 1.
This function is optional. The statistical counters are
automatically set to 0 when the storage device is mounted.
The application can use FS_MMC_ResetStatCounters() at any
time during the file system operation. The statistical counters
can be queried via FS_MMC_GetStatCounters().
The statistical counters are available only when the file system
is compiled with FS_DEBUG_LEVEL greater than or equal to
FS_DEBUG_LEVEL_CHECK_ALL or with FS_MMC_ENABLE_STATS set to 1.
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 Card Mode MMC/SD driver were measured as described in the section
Test procedure.
Usage: 2.8 Kbytes
Static RAM usage
Static RAM usage refers to the amount of RAM required by the Card Mode MMC/SD driver
internally for all the driver instances. The number of bytes can be seen in the
compiler list file of the FS_MMC_CM_Drv.c file.
Usage: 12 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 compile time and runtime configuration.
Usage: 22 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 were performed as described in the section
Performance.
All values are given in Mbytes/second.
CPU type
MMC/SD device
Write speed
Read speed
Atmel AT91SAM7S (48 MHz)
Ultron 256MB SD card
2.3
2.3
Atmel AT91SAM9261 (178 MHz)
Ultron 256MB SD card
2.3
2.5
TI TM4C129
SanDisk 16GB Ultra PLUS SD card
2.0
2.2
NXP LPC1768
SanDisk Extreme PRO 32GB
1.6
1.6
ST STM32H753
SanDisk Extreme PRO 32GB
1.4
1.5
Card Mode MMC/SD driver
Configuring the driver
This section describes how to configure the file system to make use of the Card Mode MMC/SD driver.
Compile time configuration
The Card Mode MMC/SD driver can optionally be configured at compile time.
Typically, this step can be omitted because the Card Mode MMC/SD 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 Card Mode MMC/SD driver.
Maximum number of times to check for the ready status of the storage device.
FS_MMC_DISABLE_DAT3_PULLUP
An SD card has an internal pull-up mounted on the DAT3 signal that
can be used for card detection. Typically, this way detecting the
presence of an SD card is not used. Instead, the SD card slot has
a mechanical switch that is used for this purpose. The internal
pull-up is no longer necessary after the initialization of the
SD card. Therefore, the SD Specification recommends to disable
the pull-up during data transfers that use the DAT3 signal that
is when the data is transferred via four data lines.
If FS_MMC_DISABLE_DAT3_PULLUP is set to 1 then the Card Mode MMC/SD
driver will disable the pull up before the SD card is configured to
transfer the data via the four data lines.
FS_MMC_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 Card Mode MMC/SD driver that can be useful for debugging.
The statistical counters can be queried via FS_MMC_CM_GetStatCounters() and
set to 0 via FS_MMC_CM_ResetStatCounters().
By default FS_MMC_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_MMC_NOTIFY_EVENT
FS_MMC_NOTIFY_EVENT can be used to configure the Card Mode MMC/SD driver
to report internal events such a device initialization via a registered
callback function.
FS_MMC_NUM_RETRIES
This device can be used to specify the number of times the Card Mode MMC/SD driver
reties the operation in case of a read or write error.
FS_MMC_NUM_UNITS
This define specifies the maximum number of driver instances of the Card Mode MMC/SD 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 value then
FS_MMC_NUM_UNITS can be set to the to that value in order to reduce the RAM usage.
FS_MMC_READ_DATA_TIMEOUT
FS_MMC_READ_DATA_TIMEOUT specifies the maximum number of milliseconds the Card Mode MMC/SD driver
has to wait for the data to be received from the storage device. A value of 0 is interpreted as
0xFFFFFFFF milliseconds for backward compatibility. Typically, a storage device requires a maximum
of 200 milliseconds to complete a read operation.
FS_MMC_READ_SINGLE_LAST_SECTOR
FS_MMC_READ_SINGLE_LAST_SECTOR can be used to specify how the last logical sector located on the
storage device has to be read. If FS_MMC_READ_SINGLE_LAST_SECTOR is set to 0 then the last logical
sector can be read either via a command that reads one logical sector (CMD_READ_SINGLE_BLOCK)
or via a command that reads multiple logical sectors (CMD_READ_MULTIPLE_BLOCKS).
If FS_MMC_READ_SINGLE_LAST_SECTOR is set to 1 then the last logical sector is always read via
a CMD_READ_SINGLE_BLOCK command. This feature has to be activated for a storage device that
is not able to handle correctly CMD_READ_MULTIPLE_BLOCKS commands that read the last sector.
FS_MMC_SELECT_CARD_TIMEOUT
FS_MMC_SELECT_CARD_TIMEOUT specifies the maximum number of times the Card Mode MMC/SD driver
has to repeat a failed card select operation before it reports an error to the Storage layer.
The Card Mode MMC/SD driver selects a storage device before each data exchange operation.
At the end of the operation the storage device is deselected.
FS_MMC_SUPPORT_ERROR_RECOVERY
FS_MMC_SUPPORT_ERROR_RECOVERY can be used to enable advanced error recovery procedures
of the Card Mode MMC/SD driver such as storage device reinitialization.
FS_MMC_SUPPORT_MMC
FS_MMC_SUPPORT_MMC can be used to disable the handling of MMC devices in the Card Mode MMC/SD driver.
If the target application is expected to work only with SD cards then this configuration define
can be safely set to 0 in order to save ROM space. The handling of MMC device does not have to
be explicitly enabled at runtime if FS_MMC_SUPPORT_MMC is set to 1.
FS_MMC_SUPPORT_POWER_SAVE
FS_MMC_SUPPORT_POWER_SAVE can be used to enable the support for putting MMC device into sleep mode.
This feature has to be enabled at runtime by calling FS_MMC_CM_AllowPowerSaveMode() with the
second argument set to 1. With this feature enabled the Card Mode MMC/SD driver puts the MMC device
into sleep mode after each operation to preserve power. In addition, the application
can explicitly put the MMC device into sleep mode by calling FS_MMC_CM_EnterPowerSaveMode().
FS_MMC_SUPPORT_SD
FS_MMC_SUPPORT_SD can be used to disable the handling of SD cards in the Card Mode MMC/SD driver.
If the target application is expected to work only with MMC devices such as eMMC then this
configuration define can be safely set to 0 in order to save ROM space. The handling of SD cards
does not have to be explicitly enabled at runtime if FS_MMC_SUPPORT_SD is set to 1.
FS_MMC_SUPPORT_TRIM
FS_MMC_SUPPORT_TRIM can be used to specify if the information about unused logical sectors is
forward to the storage device. If FS_MMC_SUPPORT_TRIM is set to 1 then the storage device is
informed about logical sectors that do not contain valid data anymore such as when a file is
deleted. Currently, only MMC devices support this operation.
FS_MMC_SUPPORT_UHS
FS_MMC_SUPPORT_UHS can be used to enable the support for access modes with a clock
frequency of up to about 200 MHz. Refer to Supported hardware
for a list of supported access modes. All ultra high speed access modes are disabled by default
and have to be explicitly enabled at runtime by the application in FS_X_AddDevices()
by calling one of the functions listed in the following table with the OnOff parameter
set to 1.
In addition, the voltage level of the I/O lines has to be set to 1.8 V by
calling the FS_MMC_CM_AllowVoltageLevel1V8() with the OnOff parameter set to 1.
FS_MMC_TEST_BUS_WIDTH
This configuration define can be used to enable the runtime detection
of the number of data signals connected to an eMMC device.
If FS_MMC_TEST_BUS_WIDTH is set to 1 then the Card Mode MMC/SD driver
requests the eMMC device to send a predefined data pattern that can
be used to determine how many data signals are physically connected.
This information is used by the Card Mode MMC/SD driver to configure
the eMMC device for a data transfer via the maximum number of data
signals available.
FS_MMC_WAIT_READY_TIMEOUT
FS_MMC_WAIT_READY_TIMEOUT specifies the maximum number of times the
Card Mode MMC/SD driver has to check for the ready status of the storage
device before it reports an error to the Storage layer.
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_MMC_CM_Driver structure. 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 an MMC/SD card
in card mode.
#include"FS.h"#include"FS_MMC_HW_CM_Template.h"#defineALLOC_SIZE 0x1300// Size defined in bytesstaticU32 _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().*/voidFS_X_AddDevices(void){//// Give the file system memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Add and configure the Card mode MMC/SD driver.//FS_AddDevice(&FS_MMC_CM_Driver);FS_MMC_CM_Allow4bitMode(0,1);FS_MMC_CM_SetHWType(0,&FS_MMC_HW_CM_Template);//// Configure the file system for fast write operations.//#ifFS_SUPPORT_FILE_BUFFERFS_ConfigFileBufferDefault(512,FS_FILE_BUFFER_WRITE);#endifFS_SetFileWriteMode(FS_WRITEMODE_FAST);}
The API functions listed in the next table can be used by the application to
configure the behavior of the Card Mode MMC/SD driver. The application can call
them only at the file system initialization in FS_X_AddDevices().
Specifies the permission status. 0 Data is exchanged via 1 line. 1 Data is exchanged via 4 lines.
Additional information
This function is optional. By default, the 4-bit mode is disabled
which means that the Card Mode MMC/SD driver exchanges data via only
one data line. Using 4-bit mode can help increase the performance
of the data transfer. The 4-bit mode is used for the data transfer
only if the connected MMC/SD card supports it which is typically the
case with all modern cards. If not then the Card Mode MMC/SD driver
falls back to 1-bit mode.
The application can query the actual number of data lines used by
the Card Mode MMC/SD driver for the data transfer by evaluating the
value of BusWith member of the FS_MMC_CARD_INFO structure returned
by FS_MMC_CM_GetCardInfo().
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_Allow8bitMode()
Description
Allows the driver to exchange the data via 8 data lines.
Specifies the permission status. 0 Data is exchanged via 1 or 4 lines. 1 Data is exchanged via 8 lines.
Additional information
This function is optional. By default, the 8-bit mode is disabled
which means that the Card Mode MMC/SD driver exchanges data via only
one data line. Using 8-bit mode can help increase the performance
of the data transfer. The 8-bit mode is used for the data transfer
only if the connected MMC/SD card supports it. If not then the Card
mode MMC/SD driver falls back to either 4- or 1-bit mode. Only MMC
devices support the 8-bit mode. The SD cards are not able to transfer
the data via 8-bit lines.
The application can query the actual number of data lines used by
the Card Mode MMC/SD driver for the data transfer by evaluating the
value of BusWith member of the FS_MMC_CARD_INFO structure returned
by FS_MMC_CM_GetCardInfo().
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_AllowCacheActivation()
Description
Allows the driver to activate the data cache of an eMMC device.
Specifies the permission status. 0 Cache activation is not allowed. 1 Cache activation is allowed.
Additional information
This function is optional. It can be used to configure if
the Card Mode MMC/SD driver is allowed to enable the data cache
of an eMMC device. The data cache is activated only if supported
by the eMMC device. By default, the Card Mode MMC/SD driver
activates the data cache for improved read and write performance.
With the data cache enabled, the fail-safety of the file system
can no longer be guaranteed.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
Specifies the permission status. 0 Use another access mode. 1 Use DDR50 access mode.
Additional information
This function is optional. The application can use it to request the Card Mode
MMC/SD driver to exchange data with an SD card on both clock edges and at a
clock frequency of maximum 50 MHz. The voltage level of the I/O lines used
by this access mode is 1.8 V. The support for the 1.8 V voltage level can be enabled
vis FS_MMC_CM_AllowVoltageLevel1V8(). The DDR50 access mode is used only if the
connected SD card supports it.
The application can check if the Card Mode MMC/SD driver is actually
using the DDR50 access mode for the data transfer by evaluating the
AccessMode member of the FS_MMC_CARD_INFO structure returned
by FS_MMC_CM_GetCardInfo().
The DDR50 access mode can be used only if the SD/MMC host controller
supports it. The availability of this functionality is not checked
by the Card Mode MMC/SD driver.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_AllowAccessModeDDR50() is available only when the file system
is built with FS_MMC_SUPPORT_UHS and FS_MMC_SUPPORT_SD set to 1.
FS_MMC_CM_AllowAccessModeHS200()
Description
Allows the driver to exchange the data with an MMC device using the HS200 access mode.
Specifies the permission status. 0 Use another access mode. 1 Use HS200 access mode.
Additional information
This function is optional. The application can use it to request the Card Mode
MMC/SD driver to exchange data with an MMC device on a single clock edge and at a
clock frequency of maximum 200 MHz. The voltage level of the I/O lines used
by this access mode can be either 1.8 V. The support for the 1.8 V voltage
level can be enabled via FS_MMC_CM_AllowVoltageLevel1V8(). The HS200 access
mode is used only if the connected MMC device supports it. In this access mode
the data is transferred either via 4 or 8 lines. The data transfer via 4 and 8
data lines can be enabled via FS_MMC_CM_Allow4bitMode() and FS_MMC_CM_Allow8bitMode()
respectively.
The application can check if the Card Mode MMC/SD driver is actually
using the HS200 access mode for the data transfer by evaluating the
AccessMode member of the FS_MMC_CARD_INFO structure returned
by FS_MMC_CM_GetCardInfo().
The HS200 access mode can be used only if the SD/MMC host controller
supports it. The availability of this functionality is not checked
by the Card Mode MMC/SD driver.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_AllowAccessModeHS200() is available only when the file system
is built with FS_MMC_SUPPORT_UHS and FS_MMC_SUPPORT_MMC set to 1.
FS_MMC_CM_AllowAccessModeHS400()
Description
Allows the driver to exchange the data with an eMMC device using the HS400 access mode.
Specifies the permission status. 0 Use another access mode. 1 Use HS400 access mode.
Additional information
This function is optional. The application can use it to request the Card Mode
MMC/SD driver to exchange data with an MMC device on both clock edges and at a
clock frequency of maximum 200 MHz. The voltage level of the I/O lines used
by this access mode can be either 1.8 V. The support for the 1.8 V voltage
level can be enabled via FS_MMC_CM_AllowVoltageLevel1V8(). The HS400 access
mode is used only if the connected MMC device supports it. In this access mode
the data is always transferred via 8 lines. The data transfer via 8 data lines
can be enabled via FS_MMC_CM_Allow8bitMode().
The application can check if the Card Mode MMC/SD driver is actually
using the HS400 access mode for the data transfer by evaluating the
AccessMode member of the FS_MMC_CARD_INFO structure returned
by FS_MMC_CM_GetCardInfo().
The HS400 access mode can be used only if the SD/MMC host controller
supports it. The availability of this functionality is not checked
by the Card Mode MMC/SD driver.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_AllowAccessModeHS400() is available only when the file system
is built with FS_MMC_SUPPORT_UHS and FS_MMC_SUPPORT_MMC set to 1.
FS_MMC_CM_AllowAccessModeHS_DDR()
Description
Allows the driver to exchange the data with an MMC device using
the High Speed DDR access mode.
Specifies the permission status. 0 Use another access mode. 1 Use High Speed DRR access mode.
Additional information
This function is optional. The application can use it to request the Card Mode
MMC/SD driver to exchange data with an MMC device on both clock edges and at a
clock frequency of maximum 52 MHz. The voltage level of the I/O lines used
by this access mode can be either 3.3 V or 1.8 V. The support for the 1.8 V voltage
level can be enabled vis FS_MMC_CM_AllowVoltageLevel1V8(). The 3.3 V voltage
level is enabled by default. The High Speed DDR access mode is used only if
the connected MMC device supports it.
The application can check if the Card Mode MMC/SD driver is actually
using the high speed DDR access mode for the data transfer by evaluating the
AccessMode member of the FS_MMC_CARD_INFO structure returned
by FS_MMC_CM_GetCardInfo().
The High Speed DDR access mode can be used only if the SD/MMC host controller
supports it. The availability of this functionality is not checked
by the Card Mode MMC/SD driver.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_AllowAccessModeHS_DDR() is available only when the file system
is built with FS_MMC_SUPPORT_UHS and FS_MMC_SUPPORT_MMC set to 1.
FS_MMC_CM_AllowAccessModeSDR104()
Description
Allows the driver to exchange the data with an SD card using SDR104 access mode.
Specifies the permission status. 0 Use another access mode. 1 Use SDR104 access mode.
Additional information
This function is optional. The application can use it to request the Card Mode
MMC/SD driver to exchange data with an SD card on a single clock edge and at a
clock frequency of maximum 208 MHz. The voltage level of the I/O lines used
by this access mode is 1.8 V. The support for the 1.8 V voltage level can be enabled
vis FS_MMC_CM_AllowVoltageLevel1V8(). The SDR104 access mode is used only if the
connected SD card supports it.
The application can check if the Card Mode MMC/SD driver is actually
using the SDR104 access mode for the data transfer by evaluating the
AccessMode member of the FS_MMC_CARD_INFO structure returned
by FS_MMC_CM_GetCardInfo().
The SDR104 access mode can be used only if the SD/MMC host controller
supports it. The availability of this functionality is not checked
by the Card Mode MMC/SD driver.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_AllowAccessModeSDR104() is available only when the file system
is built with FS_MMC_SUPPORT_UHS and FS_MMC_SUPPORT_SD set to 1.
FS_MMC_CM_AllowAccessModeSDR50()
Description
Allows the driver to exchange the data with an SD card using SDR50 access mode.
Specifies the permission status. 0 Use another access mode. 1 Use SDR50 access mode.
Additional information
This function is optional. The application can use it to request the Card Mode
MMC/SD driver to exchange data with an SD card on a single clock edge and at a
clock frequency of maximum 100 MHz. The voltage level of the I/O lines used
by this access mode is 1.8 V. The support for the 1.8 V voltage level can be enabled
vis FS_MMC_CM_AllowVoltageLevel1V8(). The SDR50 access mode is used only if the
connected SD card supports it.
The application can check if the Card Mode MMC/SD driver is actually
using the SDR50 access mode for the data transfer by evaluating the
AccessMode member of the FS_MMC_CARD_INFO structure returned
by FS_MMC_CM_GetCardInfo().
The SDR50 access mode can be used only if the SD/MMC host controller
supports it. The availability of this functionality is not checked
by the Card Mode MMC/SD driver.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_AllowAccessModeSDR50() is available only when the file system
is built with FS_MMC_SUPPORT_UHS and FS_MMC_SUPPORT_SD set to 1.
Specifies if the buffered write operation should be enabled or not. 0 Buffered write operation is disabled. 1 Buffered write operation is enabled.
Additional information
SD and MMC storage devices can perform write operations in parallel
to receiving data from the host by queuing write requests. This feature is
used by the driver in order to achieve the highest write performance possible.
In case of a power fail the hardware has to prevent that the write operation
is interrupted by powering the storage device until the write queue is emptied.
The time it takes the storage device to empty the queue is not predictable
and it can take from a few hundreds o milliseconds to a few seconds to complete.
This function allows the application to disable the buffered write and thus
reduce the time required to supply the storage device at power fail.
With the write buffering disabled the driver writes only one sector at time
and it waits for the previous write sector operation to complete.
Disabling the write buffering can considerably reduce the write performance.
Most of the industrial grade SD and MMC storage devices are fail safe
so that disabling the write buffering is not required. For more information
consult the data sheet of your storage device.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_AllowHighSpeedMode()
Description
Allows the driver to exchange the data in high speed mode.
Specifies the permission status. 0 Use standard speed mode. 1 Use high speed mode.
Additional information
This function is optional. The application can use this function
to request the Card Mode MMC/SD driver to use the highest clock
frequency supported by the used MMC/SD card. The standard clock
frequency supported by an SD card is 25 MHz and 26 MHz by an MMC device.
This is the clock frequency used by the Card Mode MMC/SD driver
after the initialization of the MMC/SD card. However, most of the
modern SD cards and MMC devices are able to exchange the data at
higher clock frequencies up to 50 MHz for SD cards and 52 MHz for MMC
devices. This high speed mode has to be explicitly enabled in the
SD card or MMC device after initialization. The Card mode SD/MMC driver
automatically enables the high speed mode in the SD card or MMC device
if FS_MMC_CM_AllowHighSpeedMode() is called with OnOff set to 1 and
the used SD card or MMC device actually supported.
The application can check if the Card Mode MMC/SD driver is actually
using the high speed mode for the data transfer by evaluating the
IsHighSpeedMode member of the FS_MMC_CARD_INFO structure returned
by FS_MMC_CM_GetCardInfo().
The high speed mode can be used only if the SD/MMC host controller
supports it. The availability of this functionality is not checked
by the Card Mode MMC/SD driver.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_AllowPowerSaveMode()
Description
Configures if the driver has to request the eMMC to save power.
Specifies the permission status. 0 Reliable write operation is disabled (default). 1 Reliable write operation is enabled.
Additional information
This function is optional. A reliable write operation makes sure
that the sector data is not corrupted in case of a unexpected reset.
MMC devices compliant with the version 4.3 or newer of the MMC specification
support a fail-safe write feature which makes sure that the old data
remains unchanged until the new data is successfully programmed.
Using this type of write operation the data remains valid in case of an
unexpected reset which improves the data reliability. The support for this
feature is optional and the Card Mode MMC/SD driver activates it only if
the used MMC device actually supports it and it FS_MMC_CM_AllowReliableWrite()
has been called with OnOff set to 1.
Enabling the reliable write feature can possibly reduce the write performance.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_AllowVoltageLevel1V8()
Description
Allows the driver to user 1.8 V signaling on the I/O lines.
Specifies the permission status. 0 1.8 V signaling is not allowed. 1 1.8 V signaling is allowed.
Additional information
This function is optional. It gives the application the ability
to configure if the Card Mode MMC/SD driver can exchange the data
with an SD card or MMC device using 1.8 V voltage level on the
I/O lines. This voltage level is required for the ultra high speed
access modes.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
This function is optional. It gives the application the ability
to configure if the output driving strength of the MMC/SD device.
Refer to Driver strength types for permitted values for DriverStrength.
The specified driver strength is used only if the MMC/SD device
actually supports it. If the MMC/SD device does not support the
specified driver strength then the default driver strength is used.
The actual driver strength can be queried via FS_MMC_CM_GetCardInfo().
The value is stored in the FS_MMC_CARD_INFO::DriverStrength member
of the returned data structure.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
This function is optional. It allows an application to use only
a specific area of an SD/MMC storage device as storage. By default
the Card Mode MMC/SD driver uses the entire available space as storage.
StartSector is relative to the beginning of the SD/MMC storage device.
For example, if StartSector is set to 3 than the sectors with
the indexes 0, 1, and 2 are not used for storage.
The initialization of SD/MMC storage device fails if StartSector
is out of range.
If MaxNumSectors is set to 0 the Card mode SD/MMC driver uses for storage
the remaining sectors starting from StartSector. If MaxNumSectors
is larger than the available number or sectors the actual number
of sectors used for storage is limited to the number of sectors
available.
FS_MMC_CM_SetHS200Tuning()
Description
Enables or disables the tuning for the HS200 access mode.
Specifies the tuning activation status. 0 Tuning is not performed. 1 Tuning is performed.
Additional information
This function is optional. It gives the application the ability to
select if a tuning procedure is performed at the initialization of
an MMC device that is exchanging the data in HS200 access mode.
The tuning procedure is required in order to determine the correct
sampling point of the data that is received from the SD card.
By default, the tuning procedure is enabled for the HS200 access mode.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_SetHS200Tuning() is available only when the file system
is built with FS_MMC_SUPPORT_UHS and FS_MMC_SUPPORT_MMC set to 1.
in Specifies the type of the hardware layer to be used to communicate with the storage device.
Additional information
This function is mandatory. It has to be called in FS_X_AddDevices()
once for each instance of the card mode SD/MMC driver. The driver
instance is identified by the Unit parameter.
FS_MMC_CM_SetOnDeviceInitCallback()
Description
Registers a callback function for the device initialization event.
Specifies the tuning activation status. 0 Tuning is not performed. 1 Tuning is performed.
Additional information
This function is optional. It gives the application the ability to
select if a tuning procedure is performed at the initialization of
the SD card that is exchanging the data in SDR104 access mode.
The tuning procedure is required in order to determine the correct
sampling point of the data that is received from the SD card.
By default, the tuning procedure is enabled for the SDR104 access mode
as required by the SD Specification.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_SetSDR104Tuning() is available only when the file system
is built with FS_MMC_SUPPORT_UHS and FS_MMC_SUPPORT_SD set to 1.
FS_MMC_CM_SetSDR50Tuning()
Description
Enables or disables the tuning for the SDR50 access mode.
Specifies the tuning activation status. 0 Tuning is not performed. 1 Tuning is performed.
Additional information
This function is optional. It gives the application the ability to
select if a tuning procedure is performed at the initialization of
the SD card that is exchanging the data in SDR50 access mode.
The tuning procedure is required in order to determine the correct
sampling point of the data that is received from the SD card.
By default, the tuning procedure is disabled for the SDR50 access mode.
An application is permitted to call this function only
at the file system initialization in FS_X_AddDevices().
FS_MMC_CM_SetSDR50Tuning() is available only when the file system
is built with FS_MMC_SUPPORT_UHS and FS_MMC_SUPPORT_SD set to 1.
Driver strength types
Description
Types of output driver strengths of an MMC/SD storage device.
FS_MMC_CM_SetOnDeviceInitCallback() can be used to register
a function of this type as a callback for the device initialization
event. The Card Mode MMC/SD driver will report an initialization
failure to the application if the registered callback function
returns a value different than 0.
Additional driver functions
These functions are optional. They can be used to get information about the
operation of the Card Mode MMC/SD driver and to perform additional operations
on the used SD card or MMC device.
This function is optional. The application can use it to set the
contents of the specified logical sectors to a predefined value.
The erase operation sets all the bits in the specified logical
sectors either to 1 or to 0. The actual value is implementation
defined in the EXT_CSD register.
The erase operation is supported only for MMC devices.
FS_MMC_CM_GetCardId()
Description
Returns the identification data of the SD/MMC device.
This function is optional. The application can call this
function to get the information stored in the CID register
of an MMC or SD card. The CID register stores information which
can be used to uniquely identify the card such as serial number,
product name, manufacturer id, etc. For more information about
the information stored in this register refer to SD or MMC specification.
The data of the CID register starts at byte offset 1
in pCardId->aData.
Example
The following example shows how to read and decode the contents of the CID register.
This function is optional. It can be used to get information about the
type of the storage card used, about how many data lines are used for
the data transfer, etc.
Example
The following example shows how to get information about the storage device.
#include<stdio.h>#include"FS.h"voidSampleMMC_CMGetCardInfo(void){FS_MMC_CARD_INFOCardInfo;constchar*sCardType;charac[100];constchar*sAccessMode;FS_MEMSET(&CardInfo,0,sizeof(CardInfo));FS_MMC_CM_GetCardInfo(0,&CardInfo);switch(CardInfo.CardType){caseFS_MMC_CARD_TYPE_MMC:sCardType ="MMC";break;caseFS_MMC_CARD_TYPE_SD:sCardType ="SD";break;caseFS_MMC_CARD_TYPE_UNKNOWN:// throughdefault:sCardType ="UNKNOWN";break;}switch(CardInfo.AccessMode){caseFS_MMC_ACCESS_MODE_DS:sAccessMode ="DS";break;caseFS_MMC_ACCESS_MODE_HS:sAccessMode ="HS";break;caseFS_MMC_ACCESS_MODE_SDR50:sAccessMode ="SDR50";break;caseFS_MMC_ACCESS_MODE_DDR50:sAccessMode ="DDR50";break;caseFS_MMC_ACCESS_MODE_SDR104:sAccessMode ="SDR104";break;caseFS_MMC_ACCESS_MODE_HS_DDR:sAccessMode ="HS DDR";break;caseFS_MMC_ACCESS_MODE_HS200:sAccessMode ="HS200";break;caseFS_MMC_ACCESS_MODE_HS400:sAccessMode ="HS400";break;caseFS_MMC_ACCESS_MODE_UNKNOWN:// throughdefault:sAccessMode ="UNKNOWN";break;}FS_X_Log("Card information:\n");SEGGER_snprintf(ac,sizeof(ac)," Card type: %s\n",sCardType);FS_X_Log(ac);SEGGER_snprintf(ac,sizeof(ac)," Bus width: %d line(s)\n",CardInfo.BusWidth);FS_X_Log(ac);SEGGER_snprintf(ac,sizeof(ac)," Write protected: %s\n",CardInfo.IsWriteProtected ?"yes":"no");FS_X_Log(ac);SEGGER_snprintf(ac,sizeof(ac)," High speed mode: %s\n",CardInfo.IsHighSpeedMode ?"yes":"no");FS_X_Log(ac);SEGGER_snprintf(ac,sizeof(ac)," Bytes per sector: %d\n",(int)CardInfo.BytesPerSector);FS_X_Log(ac);SEGGER_snprintf(ac,sizeof(ac)," Number of sectors: %lu\n",CardInfo.NumSectors);FS_X_Log(ac);SEGGER_snprintf(ac,sizeof(ac)," Clock frequency: %lu Hz\n",CardInfo.ClockFreq);FS_X_Log(ac);SEGGER_snprintf(ac,sizeof(ac)," Voltage level: %d.%d V\n",(int)CardInfo.VoltageLevel /1000,(int)CardInfo.VoltageLevel %1000/100);FS_X_Log(ac);SEGGER_snprintf(ac,sizeof(ac)," Access mode: %s\n",sAccessMode);FS_X_Log(ac);SEGGER_snprintf(ac,sizeof(ac)," Driver strength: %d\n",(int)CardInfo.DriverStrength);FS_X_Log(ac);}
This function is optional. The Card mode SD/MMC driver collects
statistics about the number of internal operations such as the
number of logical sectors read or written by the file system layer.
The application can use FS_MMC_CM_GetStatCounters() to get the
current value of these counters. The statistical counters are
automatically set to 0 when the storage device is mounted or when
the application calls FS_MMC_CM_ResetStatCounters().
The statistical counters are available only when the file system
is compiled with FS_DEBUG_LEVEL greater than or equal to
FS_DEBUG_LEVEL_CHECK_ALL or with FS_MMC_ENABLE_STATS set to 1.
FS_MMC_CM_ReadCSD()
Description
Reads the contents of the CSD register of a storage device.
This function is optional. It can be used to read the information
stored in the Card-Specific Register that is found in any SD card
or MMC device. For more information about the contents of the CSD
register refer to the SD specification.
pData has to be at least 16 bytes large.
Bit 127 of CSD is returned in bit 7 of pData[0] byte.
Bit 0 of CSD is returned in bit 0 of pData[15] byte.
Typically, an SD host controller sets to 0 the CRC bits
(CSD bits 1-7) and the CSD bit 0.
FS_MMC_CM_ReadExtCSD()
Description
Reads the contents of the Extended CSD register of an MMC device.
This function is optional. For more information about the contents
of the Extended CSD register refer to the MMC specification.
The contents of the Extended CSD register can be modified via
FS_MMC_CM_WriteExtCSD().
pData has to be at least 512 bytes large.
Example
The following example shows how to read data from the Extended CSD register
of an MMC device.
This function is optional. It can be used to read vendor-specific
data from the storage device such as a health report.
Additional information about the usage of CMD56 can be found in the
data sheet of the storage device.
Not all the storage devices support CMD56. FS_MMC_CM_ReadGeneral()
does not check if the command is actually supported by the storage
device. Typically, the storage device reports an error if it does
not support CMD56.
The value passed via Arg is vendor-specific and is sent as is to the storage
device. The only exception is the bit 0 of Arg that indicates the direction
of the data transfer and that is automatically set to 1 by this function.
pData has to be at least 512 bytes large.
FS_MMC_CM_ReadSectors()
Description
Reads blocks of data from the active partition of the storage card.
In addition to reading data from the default partition of an eMMC device
(User Data Area), this function can be used to read data from the Boot Area
1 and 2 partitions. The application is responsible for selecting
the corresponding partition via the Extended CSD register as described
in the eMMC specification. The Extended CSD register can be modified
via FS_MMC_CM_WriteExtCSD().
An SD card has only one data partition.
Example
The following example reads the contents of the data blocks with the
indexes 7 and 8 from the selected partition of the storage device.
This function is optional. The statistical counters are
automatically set to 0 when the storage device is mounted.
The application can use FS_MMC_CM_ResetStatCounters() at any
time during the file system operation. The statistical counters
can be queried via FS_MMC_CM_GetStatCounters().
The statistical counters are available only when the file system
is compiled with FS_DEBUG_LEVEL greater than or equal to
FS_DEBUG_LEVEL_CHECK_ALL or with FS_MMC_ENABLE_STATS set to 1.
This function is optional. SD cards can be locked with a password
in order to prevent inadvertent access to sensitive data. It is
not possible to access the data on a locked SD card without knowing
the locking password. The application can use FS_MMC_CM_UnlockCardForced()
to make locked SD card accessible again. The unlocking operation erases
all the data stored on the SD card including the lock password.
FS_MMC_CM_WriteExtCSD()
Description
Writes to the Extended CSD register of a MMC device.
This function is optional. Only the byte range 0-191 of the Extended CSD register
is modifiable. For more information about the contents of the Extended CSD
register refer to the MMC specification. The contents of the Extended CSD
register can be read via FS_MMC_CM_ReadExtCSD().
Example
The following example shows how to select the Boot Area 1 of the connected
eMMC device as the active partition.
This function is optional. It can be used to write vendor-specific
data to a storage device such as the programming of a product string.
Additional information about the usage of CMD56 can be found in the
data sheet of the storage device.
Not all the storage devices support CMD56. FS_MMC_CM_WriteGeneral()
does not check if the command is actually supported by the storage
device. Typically, the storage device reports an error if it does
not support CMD56.
The value passed via Arg is vendor-specific and is sent as is to the storage
device. The only exception is the bit 0 of Arg that indicates the direction
of the data transfer and that is automatically set to 0 by this function.
pData has to be at least 512 bytes large.
FS_MMC_CM_WriteSectors()
Description
Writes blocks of data to the selected partition of the storage card.
In addition to writing data to the default partition of an eMMC device
(User Data Area), this function can be used to write data to the Boot Area
1 and 2 partitions. The application is responsible for selecting
the corresponding partition via the Extended CSD register as described
in the eMMC specification. The Extended CSD register can be modified
via FS_MMC_CM_WriteExtCSD().
An SD card has only one data partition.
Example
The following example writes the contents of the data blocks with the
indexes 5 and 6 to the selected partition of the storage device.
Set to 1 if the card operates in the high-speed mode.
BytesPerSector
Number of bytes in a sector.
NumSectors
Total number of sectors on the card.
ClockFreq
Frequency of the clock supplied to storage device in Hz.
VoltageLevel
Voltage level of I/O lines.
AccessMode
Type of data transfer.
DriverStrength
Actual output driving strength of the MMC/SD device.
Additional information
For a list of permitted values for CardType refer to Storage card types.
BusWidth can take one of these values: 1, 4 or 8. BytesPerSector is typically 512 bytes.
For a list of permitted values for AccessMode refer to Data transfer types.
IsHighSpeedMode is deprecated and AccessMode can be used instead.
IsHighSpeedMode set to 1 is equivalent to AccessMode set to FS_MMC_ACCESS_MODE_HS.
FS_MMC_STAT_COUNTERS
Description
Statistical counters maintained by the MMC/SD driver
The ROM usage depends on the compiler options, the compiler version and the used CPU.
The memory requirements of the Card Mode MMC/SD driver were measured as described in the section
Test procedure.
Usage: 3.9 Kbytes
Static RAM usage
Static RAM usage refers to the amount of RAM required by the Card Mode MMC/SD driver
internally for all the driver instances. The number of bytes can be seen in the
compiler list file of the FS_MMC_CM_Drv.c file.
Usage: 12 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 compile time and runtime configuration.
Usage: 42 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 were performed as described in the section
Performance.
All values are given in Mbytes/second.
CPU type
MMC/SD device
Write speed
Read speed
Atmel AT91SAM9263 (200 MHz)
Ultron 256MB SD card
10.0
9.3
NXP LPC2478 (57 MHz)
Ultron 256MB SD card
2.4
3.1
NXP LPC3250 (208 MHz)
Ultron 256MB SD card
3.9
8.4
NXP K66 (168 MHz)
SanDisk 16GB Ultra PLUS SD card
3.6
11.1
Microchip SAME70 (300 MHz)
SanDisk 16GB Ultra PLUS SD card
11.1
20.4
NXP iMX6U5
SanDisk 16GB Ultra PLUS SD card
15.1
18.4
NXP iMXRT1052
SanDisk 16GB Ultra PLUS SD card
16.9
19.5
NPX LPC54608
SanDisk 16GB Ultra PLUS SD card
11.6
18.4
Renesas RZGE1
Silicon Motion SM661G8 eMMC
5.5
16.5
ST STM32H743
SanDisk 16GB Ultra PLUS SD card
10.0
14.4
ST STM32F746
Transcend 16GB Class 10 SD card
12.2
18.9
ST STM32F469
SanDisk 16GB Ultra PLUS SD card
16.1
17.8
ST STM32H753 (400 MHz)
SanDisk 32GB Ultra SD card
13.7
49.8
NXP iMXRT595
SanDisk SDINBDA6-16 eMMC device
102.4
136.5
MMC/SD hardware layer
The hardware layer provides the functions required to the MMC/SD driver to access
the target hardware via SPI controller, SD host controller, GPIO, etc.
The functions of the MMC/SD hardware layer are called by the MMC/SD driver
to exchange commands and data with an MMC or SD card. 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 the implementation of new hardware
layers. The relevant files are located in the /Sample/FS/Driver/MMC_SPI
and /Sample/FS/Driver/MMC_CM folders of the emFile shipment.
Hardware layer types
The functions of the MMC/SD hardware layer are organized in a function table implemented
a C structure. Different hardware layer types are provided to support different
ways of interfacing an MMC or SD card. The type of hardware layer an application
has to use depends on the MMC/SD driver used. The following table lists
what hardware layer is required by each MMC/SD driver.
This hardware layer supports MMC cards that comply with the version 3.x or older
of the MMC specification and SD cards of all types that are interfaced to the target
MCU via SPI. The functions of this hardware layer are grouped in a structure of type
FS_MMC_HW_TYPE_SPI. The following sections describe these functions in detail.
This function is a member of the SPI MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
The Chip Select (CS) signal is used to address a specific MMC or SD
card connected via SPI. Enabling the card is equal to setting the CS
signal to a logic low level.
This function is a member of the SPI MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
The Chip Select (CS) signal is used to address a specific MMC or SD
card connected via SPI. Disabling the card is equal to setting the CS
signal to a logic high level.
This function is a member of the SPI MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
Typically, the card presence detection is implemented via a dedicated
Card Detect (CD) signal. This signal is connected to a switch inside
the card slot that changes its state each time the card is removed
or inserted. If the hardware does not provide such signal the function
has to return FS_MEDIA_STATE_UNKNOWN.
This function is a member of the SPI MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
Typically, the card protection status is implemented via a dedicated
Write Protected (WP) signal. This signal is connected to a switch inside
the card slot that reflects the status of the write protect switch
found on SD cards. If the hardware does not provide such signal the
function has to return 0.
MMC and micro SD cards do not have a write protection switch.
Please note that the write protect switch does not really protect the
data on an SD card form being modified. It is merely an indication
that the data has to be protected. It is the responsibility of the host
MCU to respect the status of this switch.
FS_MMC_HW_TYPE_SPI_SET_MAX_SPEED
Description
Configures the clock frequency supplied to the storage card.
Maximum allowed frequency of the SPI clock in kHz.
Return value
≠ 0
The actual clock frequency in kHz.
= 0
An error occurred.
Additional information
This function is a member of the SPI MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
The hardware layer is allowed to set a clock frequency smaller
than the value specified via MaxFreq but never greater than that.
The SPI MMC/SD driver calls this function at least two times during
the initialization of the MMC or SD card:
Before the initialization starts to set the clock frequency to 400 kHz.
After the card identification to set the standard clock frequency
which is 25 MHz for SD cards or 20 MHz for MMC cards.
The function has to return the actual configured clock frequency.
If the precise frequency is unknown such as for implementation using
I/O port “bit-banging”, the return value has to be less than the specified
frequency. This may lead to longer timeout values but is in general
does not cause any problems. The SPI MMC/SD driver uses the returned
value to calculate timeout values.
FS_MMC_HW_TYPE_SPI_SET_VOLTAGE
Description
Configures the voltage level of the storage card power supply.
This function is a member of the SPI MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
By default, all cards work with the initial voltage of 3.3V.
If hardware layer has to save power, then the supply voltage can
be adjusted within the specified range.
This function is a member of the SPI MMC/SD hardware layer.
FS_MMC_HW_TYPE_SPI_READ does not have to be implemented if
the hardware layer provides an implementation for FS_MMC_HW_TYPE_SPI_READ_EX.
The data is received via the DIN (MISO) signal of the SPI interface with
the data being sampled on the rising edge of the clock signal. According
to the SD specification the DOUT (MOSI) signal must be driven to logic high
during the data transfer, otherwise the SD card will not work properly.
The SPI MMC/SD driver calls this function only when the card is
enabled that is with the CS signal at logic low level.
The following picture shows the waveforms of the SPI signals during
the transfer of 8 bits from card to MCU.
This function is a member of the SPI MMC/SD hardware layer.
FS_MMC_HW_TYPE_SPI_WRITE does not have to be implemented if
the hardware layer provides an implementation for FS_MMC_HW_TYPE_SPI_WRITE_EX.
The data is sent via the DOUT (MOSI) signal of the SPI interface with
the data being changed on the falling edge of the clock signal.
The SPI MMC/SD driver also calls this function when the card is not
enabled that is with the CS signal at logic low in order to generate
empty cycles.
The following picture shows the waveforms of the SPI signals during
the transfer of 8 bits from MCU to card.
This function is a member of the SPI MMC/SD hardware layer.
FS_MMC_HW_TYPE_SPI_READ_EX does not have to be implemented if
the hardware layer provides an implementation for FS_MMC_HW_TYPE_SPI_READ.
It provides the same functionality as FS_MMC_HW_TYPE_SPI_READ
with the difference that it can report the result of the operation
to the SPI MMC/SD driver.
The SPI MMC/SD driver calls this function only when the card is
enabled that is with the CS signal at logic low level.
This function is a member of the SPI MMC/SD hardware layer.
FS_MMC_HW_TYPE_SPI_WRITE_EX does not have to be implemented if
the hardware layer provides an implementation for FS_MMC_HW_TYPE_SPI_WRITE.
It provides the same functionality as FS_MMC_HW_TYPE_SPI_WRITE
with the difference that it can report the result of the operation
to the SPI MMC/SD driver.
The SPI MMC/SD driver also calls this function when the card is not
enabled that is with the CS signal at logic low in order to generate
empty cycles.
This function is a member of the SPI MMC/SD hardware layer.
The implementation of this function is optional.
The SPI MMC/SD driver calls this function to indicate that it
needs exclusive to access the card via the SPI bus.
It is guaranteed that the SPI MMC/SD driver does not attempt to
exchange any data with the card via the SPI bus before calling
this function first. It is also guaranteed that FS_MMC_HW_TYPE_SPI_LOCK
and FS_MMC_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 card and other SPI devices.
A possible implementation would make use of an OS semaphore that is
acquired in FS_MMC_HW_TYPE_SPI_LOCK and released in FS_MMC_HW_TYPE_SPI_UNLOCK.
FS_MMC_HW_TYPE_SPI_LOCK is called only when the SPI MMC/SD driver
is compiled with FS_MMC_SUPPORT_LOCKINGset to 1.
This function is a member of the SPI MMC/SD hardware layer.
The implementation of this function is optional.
The SPI MMC/SD driver calls this function when it no longer needs
to access the card via the SPI bus. It is guaranteed that the SPI MMC/SD
driver does not attempt to exchange any data with the card via the SPI bus
before calling FS_MMC_HW_TYPE_SPI_LOCK.
It is also guaranteed that FS_MMC_HW_TYPE_SPI_UNLOCK and
FS_MMC_HW_TYPE_SPI_LOCK are called in pairs.
FS_MMC_HW_TYPE_SPI_UNLOCK and FS_MMC_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_MMC_HW_TYPE_SPI_LOCK
and released in FS_MMC_HW_TYPE_SPI_UNLOCK.
FS_MMC_HW_TYPE_SPI_LOCK is called only when the SPI MMC/SD driver
is compiled with FS_MMC_SUPPORT_LOCKING set to 1.
Sample implementation
The following sample implementation uses the SPI controller of an TI TM4C129 MCU
to interface with an SD card. This hardware layer was tested on the TI TIVAC129
evaluation board.
/********************************************************************** (c) SEGGER Microcontroller GmbH ** The Embedded Experts ** www.segger.com ***********************************************************************-------------------------- END-OF-HEADER -----------------------------File : FS_MMC_HW_SPI_TM4C129_TI_TIVAC129.cPurpose : Generic HW layer for the MMC / SD driver working in SPI mode.Literature : [1] Tiva TM4C129XNCZAD Microcontroller DATA SHEET [2] Tiva TM4C129X Development Board User's GuideAdditional information The SD card and NOR flash device share the same CS signal. In order to be able to work with the SD card, the jumper J7 has to be configured according to "2.1.10 EEPROM and SD Card" in [2].*//*********************************************************************** #include Section************************************************************************/#include"FS.h"/*********************************************************************** Defines, configurable************************************************************************/#ifndefFS_MMC_HW_SPI_PERIPH_CLOCK_KHZ#defineFS_MMC_HW_SPI_PERIPH_CLOCK_KHZ 120000uL// Clock of SSI peripheral in kHz#endif#ifndefFS_MMC_HW_SPI_MAX_SPI_CLOCK_KHZ#defineFS_MMC_HW_SPI_MAX_SPI_CLOCK_KHZ 24000uL// Maximum clock frequency supplied to SD card#endif#ifndefFS_MMC_HW_SPI_WAIT_TIMEOUT_CYCLES#defineFS_MMC_HW_SPI_WAIT_TIMEOUT_CYCLES 100000uL// Time to wait for an operation to finish (software loops)#endif#ifndefFS_MMC_HW_SPI_USE_DMA#defineFS_MMC_HW_SPI_USE_DMA 1// Enables/disables the data transfer via DMA#endif#ifndefFS_MMC_HW_SPI_DEFAULT_SUPPLY_VOLTAGE#defineFS_MMC_HW_SPI_DEFAULT_SUPPLY_VOLTAGE 3300// in mV, example means 3.3V#endif/*********************************************************************** Defines, fixed************************************************************************//*********************************************************************** SSI registers*/#defineSSI_BASE_ADDR 0x4000B000uL#defineSSICR0 (*(volatileU32 *)(SSI_BASE_ADDR +0x000))// SSI Control 0#defineSSICR1 (*(volatileU32 *)(SSI_BASE_ADDR +0x004))// SSI Control 1#defineSSIDR (*(volatileU32 *)(SSI_BASE_ADDR +0x008))// SSI Data#defineSSISR (*(volatileU32 *)(SSI_BASE_ADDR +0x00C))// SSI Status#defineSSICPSR (*(volatileU32 *)(SSI_BASE_ADDR +0x010))// SSI Clock Prescale#defineSSIIM (*(volatileU32 *)(SSI_BASE_ADDR +0x014))// SSI Interrupt Mask#defineSSIRIS (*(volatileU32 *)(SSI_BASE_ADDR +0x018))// SSI Raw Interrupt Status#defineSSIMIS (*(volatileU32 *)(SSI_BASE_ADDR +0x01C))// SSI Masked Interrupt Status#defineSSIICR (*(volatileU32 *)(SSI_BASE_ADDR +0x020))// SSI Interrupt Clear#defineSSIDMACTL (*(volatileU32 *)(SSI_BASE_ADDR +0x024))// SSI DMA Control#defineSSICC (*(volatileU32 *)(SSI_BASE_ADDR +0xFC8))// SSI Clock Configuration/*********************************************************************** System control registers*/#defineSYS_BASE_ADDR 0x400FE000uL#defineRCGCGPIO (*(volatileU32 *)(SYS_BASE_ADDR +0x608))// GPIO Run Mode Clock Gating Control#defineRCGCDMA (*(volatileU32 *)(SYS_BASE_ADDR +0x60C))// DMA Run Mode Clock Gating Control#defineRCGCSSI (*(volatileU32 *)(SYS_BASE_ADDR +0x61C))// SSI Run Mode Clock Gating Control#definePRGPIO (*(volatileU32 *)(SYS_BASE_ADDR +0xA08))// GPIO Run Mode Peripheral Ready#definePRDMA (*(volatileU32 *)(SYS_BASE_ADDR +0xA0C))// DMA Run Mode Peripheral Ready#definePRSSI (*(volatileU32 *)(SYS_BASE_ADDR +0xA1C))// SSI Run Mode Peripheral Ready/*********************************************************************** GPIO Port F*/#definePF_BASE_ADDR 0x4005D000uL#definePF_GPIOAFSEL (*(volatileU32 *)(PF_BASE_ADDR +0x420))// GPIO Alternate Function Select#definePF_GPIODR2R (*(volatileU32 *)(PF_BASE_ADDR +0x500))// GPIO 2-mA Drive Select#definePF_GPIODR4R (*(volatileU32 *)(PF_BASE_ADDR +0x504))// GPIO 4-mA Drive Select#definePF_GPIODR8R (*(volatileU32 *)(PF_BASE_ADDR +0x508))// GPIO 8-mA Drive Select#definePF_GPIOODR (*(volatileU32 *)(PF_BASE_ADDR +0x50C))// GPIO Open Drain Select#definePF_GPIOPUR (*(volatileU32 *)(PF_BASE_ADDR +0x510))// GPIO Pull-Up Select#definePF_GPIOPDR (*(volatileU32 *)(PF_BASE_ADDR +0x514))// GPIO Pull-Down Select#definePF_GPIODEN (*(volatileU32 *)(PF_BASE_ADDR +0x51C))// GPIO Digital Enable#definePF_GPIOPCTL (*(volatileU32 *)(PF_BASE_ADDR +0x52C))// GPIO Port Control#definePF_GPIOPC (*(volatileU32 *)(PF_BASE_ADDR +0xFC4))// GPIO Peripheral Configuration/*********************************************************************** GPIO Port H*/#definePH_BASE_ADDR 0x4005F000uL#definePH_GPIODATA (*(volatileU32 *)(PH_BASE_ADDR +0x000))// GPIO Data#definePH_GPIODIR (*(volatileU32 *)(PH_BASE_ADDR +0x400))// GPIO Direction#definePH_GPIOAFSEL (*(volatileU32 *)(PH_BASE_ADDR +0x420))// GPIO Alternate Function Select#definePH_GPIODR2R (*(volatileU32 *)(PH_BASE_ADDR +0x500))// GPIO 2-mA Drive Select#definePH_GPIODR4R (*(volatileU32 *)(PH_BASE_ADDR +0x504))// GPIO 4-mA Drive Select#definePH_GPIODR8R (*(volatileU32 *)(PH_BASE_ADDR +0x508))// GPIO 8-mA Drive Select#definePH_GPIOODR (*(volatileU32 *)(PH_BASE_ADDR +0x50C))// GPIO Open Drain Select#definePH_GPIOPUR (*(volatileU32 *)(PH_BASE_ADDR +0x510))// GPIO Pull-Up Select#definePH_GPIOPDR (*(volatileU32 *)(PH_BASE_ADDR +0x514))// GPIO Pull-Down Select#definePH_GPIODEN (*(volatileU32 *)(PH_BASE_ADDR +0x51C))// GPIO Digital Enable#definePH_GPIOPCTL (*(volatileU32 *)(PH_BASE_ADDR +0x52C))// GPIO Port Control#definePH_GPIOPC (*(volatileU32 *)(PH_BASE_ADDR +0xFC4))// GPIO Peripheral Configuration/*********************************************************************** GPIO Port Q*/#definePQ_BASE_ADDR 0x40066000uL#definePQ_GPIODATA (*(volatileU32 *)(PQ_BASE_ADDR +0x000))// GPIO Data#definePQ_GPIODIR (*(volatileU32 *)(PQ_BASE_ADDR +0x400))// GPIO Direction#definePQ_GPIOAFSEL (*(volatileU32 *)(PQ_BASE_ADDR +0x420))// GPIO Alternate Function Select#definePQ_GPIODR2R (*(volatileU32 *)(PQ_BASE_ADDR +0x500))// GPIO 2-mA Drive Select#definePQ_GPIODR4R (*(volatileU32 *)(PQ_BASE_ADDR +0x504))// GPIO 4-mA Drive Select#definePQ_GPIODR8R (*(volatileU32 *)(PQ_BASE_ADDR +0x508))// GPIO 8-mA Drive Select#definePQ_GPIOODR (*(volatileU32 *)(PQ_BASE_ADDR +0x50C))// GPIO Open Drain Select#definePQ_GPIOPUR (*(volatileU32 *)(PQ_BASE_ADDR +0x510))// GPIO Pull-Up Select#definePQ_GPIOPDR (*(volatileU32 *)(PQ_BASE_ADDR +0x514))// GPIO Pull-Down Select#definePQ_GPIODEN (*(volatileU32 *)(PQ_BASE_ADDR +0x51C))// GPIO Digital Enable#definePQ_GPIOPCTL (*(volatileU32 *)(PQ_BASE_ADDR +0x52C))// GPIO Port Control#definePQ_GPIOPC (*(volatileU32 *)(PQ_BASE_ADDR +0xFC4))// GPIO Peripheral Configuration/*********************************************************************** DMA controller*/#defineDMA_BASE_ADDR 0x400FF000uL#defineDMACFG (*(volatileU32 *)(DMA_BASE_ADDR +0x004))// DMA configuration#defineDMACTLBASE (*(volatileU32 *)(DMA_BASE_ADDR +0x008))// DMA Channel Control Base Pointer#defineDMAUSEBURSTCLR (*(volatileU32 *)(DMA_BASE_ADDR +0x01C))// DMA Channel Useburst Clear#defineDMAREQMASKCLR (*(volatileU32 *)(DMA_BASE_ADDR +0x024))// DMA Channel Request Mask Clear#defineDMAENASET (*(volatileU32 *)(DMA_BASE_ADDR +0x028))// DMA Channel Enable Set#defineDMAENACLR (*(volatileU32 *)(DMA_BASE_ADDR +0x02C))// DMA Channel Enable Clear#defineDMAALTCLR (*(volatileU32 *)(DMA_BASE_ADDR +0x034))// DMA Channel Primary Alternate Clear#defineDMAPRIOCLR (*(volatileU32 *)(DMA_BASE_ADDR +0x03C))// DMA Channel Priority Clear#defineDMACHMAP0 (*(volatileU32 *)(DMA_BASE_ADDR +0x510))// DMA Channel Map Select 0#defineDMACHMAP1 (*(volatileU32 *)(DMA_BASE_ADDR +0x514))// DMA Channel Map Select 1#defineDMACHMAP2 (*(volatileU32 *)(DMA_BASE_ADDR +0x518))// DMA Channel Map Select 2#defineDMACHMAP3 (*(volatileU32 *)(DMA_BASE_ADDR +0x51C))// DMA Channel Map Select 3/*********************************************************************** Flash controller*/#defineFLASH_BASE_ADDR 0x400FD000uL#defineFLASHPP (*(volatileU32 *)(FLASH_BASE_ADDR +0xFC0))// Flash Peripheral Properties#defineFLASHDMASZ (*(volatileU32 *)(FLASH_BASE_ADDR +0xFD0))// Flash DMA Address Size#defineFLASHDMAST (*(volatileU32 *)(FLASH_BASE_ADDR +0xFD4))// Flash DMA Starting Address/*********************************************************************** Pin assignment*/#defineCS_PIN 4// Port H#defineCLK_PIN 0// Port Q#defineDAT0_PIN 2// Port Q#defineDAT1_PIN 0// Port F/*********************************************************************** Flags in system registers*/#defineRCGCSSI_SSI3 3#defineRCGCGPIO_GPIOF 5#defineRCGCGPIO_GPIOH 7#defineRCGCGPIO_GPIOQ 14/*********************************************************************** SSI related defines*/#defineCR0_DSS 0#defineCR0_DSS_8BIT 7uL#defineCR0_SPO 6#defineCR0_SCR 8#defineCR0_SPH 7#defineCR0_SCR_MASK 0xFFuL#defineCR1_SSE 1#defineCR1_MODE 6#defineCR1_MODE_BI 1uL#defineCR1_MODE_QUAD 2uL#defineCR1_MODE_ADV 3uL#defineCR1_MODE_MASK 3uL#defineCR1_DIR 8#defineSR_TNF 1#defineSR_RNE 2#defineSR_BSY 4/*********************************************************************** DMA related defines*/#defineDMA_MAX_TRANSFER_SIZE 1024// in items#defineDMA_CHANNEL_READ 14#defineDMA_CHANNEL_WRITE 15#defineCHMAP1_SSI3_RX 2uL#defineCHMAP1_SSI3_TX 2uL#defineCHMAP_CHSEL_MASK 0xFuL#defineCHCTL_XFERMODE 0#defineCHCTL_XFERMODE_BASIC 1uL#defineCHCTL_XFERSIZE 4#defineCHCTL_XFERSIZE_MASK 0x3FFuL#defineCHCTL_ARBSIZE 14#defineCHCTL_ARBSIZE_4 2uL#defineCHCTL_SRCINC 26#defineCHCTL_SRCINC_NOINC 3uL#defineCHCTL_DSTINC 30#defineCHCTL_DSTINC_NOINC 3uL#defineDMACTL_RXDMAE 0#defineDMACTL_TXDMAE 1#defineCFG_MASTEREN 0#definePP_DFA 28/*********************************************************************** Misc. defines*/#defineDEFAULT_SPI_CLOCK_KHZ 400uL#if(DMA_CHANNEL_READ <DMA_CHANNEL_WRITE)#defineNUM_DMA_DESC (DMA_CHANNEL_WRITE +1)#else#defineNUM_DMA_DESC (DMA_CHANNEL_READ +1)#endif/*********************************************************************** Local data types************************************************************************//*********************************************************************** DMA_DESC*/typedefstructDMA_DESC {volatileU32 SRCENDP;volatileU32 DESTENDP;volatileU32 CHCTL;volatileU32 Reserved;}DMA_DESC;/*********************************************************************** Static data************************************************************************/staticU8 _IsInited;#ifFS_MMC_HW_SPI_USE_DMA//// The DMA descriptors have to aligned on a 1KB boundary.//#ifdef__ICCARM__#pragmadata_alignment=1024staticDMA_DESC _aDMADesc[NUM_DMA_DESC];#endif#ifdef__SES_ARMstaticDMA_DESC _aDMADesc[NUM_DMA_DESC]__attribute__((aligned (1024)));#endifstaticvolatileU8 _Dummy;#endif/*********************************************************************** Static code************************************************************************//*********************************************************************** _EnableClocks*/staticvoid_EnableClocks(void){U32 TimeOut;//// Provide a clock to SSI module and wait for it to become ready.//RCGCSSI |=1uL<<RCGCSSI_SSI3;TimeOut =FS_MMC_HW_SPI_WAIT_TIMEOUT_CYCLES;while(1){if(PRSSI &(1uL<<RCGCSSI_SSI3)){break;}if(--TimeOut ==0){break;}}//// Provide a clock to GPIO ports and wait for them to become ready.//RCGCGPIO |=0|(1uL<<RCGCGPIO_GPIOF)|(1uL<<RCGCGPIO_GPIOH)|(1uL<<RCGCGPIO_GPIOQ);TimeOut =FS_MMC_HW_SPI_WAIT_TIMEOUT_CYCLES;while(1){if(PRGPIO &((1uL<<RCGCGPIO_GPIOF)|(1uL<<RCGCGPIO_GPIOQ)|(1uL<<RCGCGPIO_GPIOH))){break;}if(--TimeOut ==0){break;}}#ifFS_MMC_HW_SPI_USE_DMA//// Provide a clock to DMA controller and wait for it to become ready.//RCGCDMA |=1uL<<0;TimeOut =FS_MMC_HW_SPI_WAIT_TIMEOUT_CYCLES;while(1){if(PRDMA &((1uL<<0))){break;}if(--TimeOut ==0){break;}}#endif}/*********************************************************************** _InitPins*/staticvoid_InitPins(void){//// Give the control of CLK, DAT0-3 signals to SSI module.//PQ_GPIOAFSEL |=0|(1uL<<CLK_PIN)|(1uL<<DAT0_PIN);PF_GPIOAFSEL |=0|(1uL<<DAT1_PIN);PQ_GPIOPCTL &=~((0xFuL<<(CLK_PIN <<2))|(0xFuL<<(DAT0_PIN <<2)));PQ_GPIOPCTL |=0|(0xEuL<<(CLK_PIN <<2))|(0xEuL<<(DAT0_PIN <<2));PF_GPIOPCTL &=~((0xFuL<<(DAT1_PIN <<2)));PF_GPIOPCTL |=0|(0xEuL<<(DAT1_PIN <<2));//// Set the output drive strength to 2mA as done in the TI sample code.//PQ_GPIOPC &=~((0x3uL<<(CLK_PIN <<1))|(0x3uL<<(DAT0_PIN <<1)));PF_GPIOPC &=~((0x3uL<<(DAT1_PIN <<1)));PQ_GPIODR2R |=0|(1uL<<CLK_PIN)|(1uL<<DAT0_PIN);PQ_GPIODR4R &=~((0x1uL<<CLK_PIN)|(0x1uL<<DAT0_PIN));PQ_GPIODR8R &=~((0x1uL<<CLK_PIN)|(0x1uL<<DAT0_PIN));PF_GPIODR2R |=0|(1uL<<DAT1_PIN);PF_GPIODR4R &=~((0x1uL<<DAT1_PIN));PF_GPIODR8R &=~((0x1uL<<DAT1_PIN));//// Enable pull-ups on all signal lines.//PQ_GPIOPUR |=0|(1uL<<CLK_PIN)|(1uL<<DAT0_PIN);PF_GPIOPUR |=0|(1uL<<DAT1_PIN);PQ_GPIOODR &=~((0x1uL<<CLK_PIN)|(0x1uL<<DAT0_PIN));PF_GPIOODR &=~((0x1uL<<DAT1_PIN));PQ_GPIOPDR &=~((0x1uL<<CLK_PIN)|(0x1uL<<DAT0_PIN));PF_GPIOPDR &=~((0x1uL<<DAT1_PIN));//// Enable the pins.//PQ_GPIODEN |=0|(1uL<<CLK_PIN)|(1uL<<DAT0_PIN);PF_GPIODEN |=0|(1uL<<DAT1_PIN);//// The CS signal is controlled by the driver.//PH_GPIODIR |=1uL<<CS_PIN;PH_GPIOAFSEL &=~(1uL<<CS_PIN);PH_GPIOPUR &=~(1uL<<CS_PIN);PH_GPIOPDR &=~(1uL<<CS_PIN);PH_GPIOODR &=~(1uL<<CS_PIN);PH_GPIODEN |=1uL<<CS_PIN;}#ifFS_MMC_HW_SPI_USE_DMA/*********************************************************************** _InitDMA*/staticvoid_InitDMA(void){DMACFG |=1uL<<CFG_MASTEREN;// Enable the DMA controller.DMACTLBASE =(U32)_aDMADesc;// The descriptor table must be 1024 aligned.DMAPRIOCLR =0// Set the priority to default.|(1uL<<DMA_CHANNEL_READ)|(1uL<<DMA_CHANNEL_WRITE);DMAALTCLR =0// Use the primary control structure in the DMA descriptor table.|(1uL<<DMA_CHANNEL_READ)|(1uL<<DMA_CHANNEL_WRITE);DMAUSEBURSTCLR =0// Respond to single and burst requests.|(1uL<<DMA_CHANNEL_READ)|(1uL<<DMA_CHANNEL_WRITE);DMAREQMASKCLR =0// Allow the recongition of requests.|(1uL<<DMA_CHANNEL_READ)|(1uL<<DMA_CHANNEL_WRITE);//// Receive requests from SSI.//DMACHMAP1 &=~((CHMAP_CHSEL_MASK <<((DMA_CHANNEL_READ -8)<<2))|(CHMAP_CHSEL_MASK <<((DMA_CHANNEL_WRITE -8)<<2)));DMACHMAP1 |=(CHMAP1_SSI3_RX <<((DMA_CHANNEL_READ -8)<<2))|(CHMAP1_SSI3_TX <<((DMA_CHANNEL_WRITE -8)<<2));//// Give DMA access to internal flash memory.//FLASHPP |=1uL<<PP_DFA;FLASHDMASZ =0x3FFFFuL;FLASHDMAST =0;// Internal flash memory starts at address 0.}/*********************************************************************** _StartDMAWrite*/staticvoid_StartDMAWrite(constU8 *pData,U32 NumBytes){U32 TimeOut;U32 CHCTLReg;DMA_DESC *pDMADesc;//// Stop the DMA channels if required.//if(DMAENASET &((1uL<<DMA_CHANNEL_WRITE)|(1uL<<DMA_CHANNEL_READ))){DMAENACLR =0|(1uL<<DMA_CHANNEL_WRITE)|(1uL<<DMA_CHANNEL_READ);TimeOut =FS_MMC_HW_SPI_WAIT_TIMEOUT_CYCLES;while(1){if((DMAENASET &((1uL<<DMA_CHANNEL_WRITE)|(1uL<<DMA_CHANNEL_READ)))==0){break;}if(--TimeOut ==0){break;}}}//// Configure the write data transfer.//NumBytes =(NumBytes -1)&CHCTL_XFERSIZE_MASK;CHCTLReg =0|(CHCTL_DSTINC_NOINC <<CHCTL_DSTINC)|(CHCTL_ARBSIZE_4 <<CHCTL_ARBSIZE)|(NumBytes <<CHCTL_XFERSIZE)|(CHCTL_XFERMODE_BASIC <<CHCTL_XFERMODE);//// Fill in the DMA descriptor.//pDMADesc =&_aDMADesc[DMA_CHANNEL_WRITE];pDMADesc->SRCENDP =(U32)(pData +NumBytes);pDMADesc->DESTENDP =(U32)&SSIDR;pDMADesc->CHCTL =CHCTLReg;//// Configure the read data transfer.//CHCTLReg =0|(CHCTL_DSTINC_NOINC <<CHCTL_DSTINC)|(CHCTL_SRCINC_NOINC <<CHCTL_SRCINC)|(CHCTL_ARBSIZE_4 <<CHCTL_ARBSIZE)|(NumBytes <<CHCTL_XFERSIZE)|(CHCTL_XFERMODE_BASIC <<CHCTL_XFERMODE);//// Fill in the DMA descriptor.//pDMADesc =&_aDMADesc[DMA_CHANNEL_READ];pDMADesc->SRCENDP =(U32)&SSIDR;pDMADesc->DESTENDP =(U32)&_Dummy;pDMADesc->CHCTL =CHCTLReg;//// Start the DMA transfer.//SSIDMACTL =0|(1uL<<DMACTL_RXDMAE)|(1uL<<DMACTL_TXDMAE);DMAENASET |=0|(1uL<<DMA_CHANNEL_READ)|(1uL<<DMA_CHANNEL_WRITE);}/*********************************************************************** _StartDMARead*/staticvoid_StartDMARead(U8 *pData,U32 NumBytes){U32 TimeOut;U32 CHCTLReg;DMA_DESC *pDMADesc;_Dummy =0xFF;FS_USE_PARA(_Dummy);//// Stop the DMA channels if required.//if(DMAENASET &((1uL<<DMA_CHANNEL_WRITE)|(1uL<<DMA_CHANNEL_READ))){DMAENACLR =0|(1uL<<DMA_CHANNEL_WRITE)|(1uL<<DMA_CHANNEL_READ);TimeOut =FS_MMC_HW_SPI_WAIT_TIMEOUT_CYCLES;while(1){if((DMAENASET &((1uL<<DMA_CHANNEL_WRITE)|(1uL<<DMA_CHANNEL_READ)))==0){break;}if(--TimeOut ==0){break;}}}//// Configure the write data transfer.//NumBytes =(NumBytes -1)&CHCTL_XFERSIZE_MASK;CHCTLReg =0|(CHCTL_DSTINC_NOINC <<CHCTL_DSTINC)|(CHCTL_SRCINC_NOINC <<CHCTL_SRCINC)|(CHCTL_ARBSIZE_4 <<CHCTL_ARBSIZE)|(NumBytes <<CHCTL_XFERSIZE)|(CHCTL_XFERMODE_BASIC <<CHCTL_XFERMODE);//// Fill in the DMA descriptor.//pDMADesc =&_aDMADesc[DMA_CHANNEL_WRITE];pDMADesc->SRCENDP =(U32)&_Dummy;pDMADesc->DESTENDP =(U32)&SSIDR;pDMADesc->CHCTL =CHCTLReg;//// Configure the read data transfer.//CHCTLReg =0|(CHCTL_SRCINC_NOINC <<CHCTL_SRCINC)|(CHCTL_ARBSIZE_4 <<CHCTL_ARBSIZE)|(NumBytes <<CHCTL_XFERSIZE)|(CHCTL_XFERMODE_BASIC <<CHCTL_XFERMODE);//// Fill in the DMA descriptor.//pDMADesc =&_aDMADesc[DMA_CHANNEL_READ];pDMADesc->SRCENDP =(U32)&SSIDR;pDMADesc->DESTENDP =(U32)(pData +NumBytes);pDMADesc->CHCTL =CHCTLReg;//// Start the DMA transfer.//SSIDMACTL =0|(1uL<<DMACTL_RXDMAE)|(1uL<<DMACTL_TXDMAE);DMAENASET |=0|(1uL<<DMA_CHANNEL_READ)|(1uL<<DMA_CHANNEL_WRITE);}/*********************************************************************** _WaitForEndOfDMAOperation*/staticvoid_WaitForEndOfDMAOperation(void){U32 TimeOut;TimeOut =FS_MMC_HW_SPI_WAIT_TIMEOUT_CYCLES;while(1){if((DMAENASET &(1uL<<DMA_CHANNEL_READ))==0){break;}if(--TimeOut ==0){break;}}}#endif/*********************************************************************** _SetMaxSpeed*/staticU16 _SetMaxSpeed(U16 MaxFreq_kHz){U32 SCRValue;U32 CPSValue;U32 Factor;if(MaxFreq_kHz >FS_MMC_HW_SPI_MAX_SPI_CLOCK_KHZ){MaxFreq_kHz =FS_MMC_HW_SPI_MAX_SPI_CLOCK_KHZ;}CPSValue =0;Factor =(FS_MMC_HW_SPI_PERIPH_CLOCK_KHZ +(MaxFreq_kHz -1))/MaxFreq_kHz;do{CPSValue +=2;SCRValue =((Factor +(CPSValue -1))/CPSValue)-1;}while(SCRValue >255);SSICPSR =CPSValue;SSICR0 &=~(CR0_SCR_MASK <<CR0_SCR);SSICR0 |=SCRValue <<CR0_SCR;MaxFreq_kHz =(U16)(FS_MMC_HW_SPI_PERIPH_CLOCK_KHZ /(CPSValue *(1+SCRValue)));returnMaxFreq_kHz;}/*********************************************************************** _Write*/staticvoid_Write(constU8 *pData,intNumBytes){#ifFS_MMC_HW_SPI_USE_DMAintNumBytesAtOnce;do{NumBytesAtOnce =SEGGER_MIN(NumBytes,DMA_MAX_TRANSFER_SIZE);_StartDMAWrite(pData,(U32)NumBytesAtOnce);_WaitForEndOfDMAOperation();NumBytes -=(int)NumBytesAtOnce;pData +=NumBytesAtOnce;}while(NumBytes);#elsedo{volatileU8 Dummy;//// Wait for room in FIFO.//while((SSISR &(1uL<<SR_TNF))==0){;}SSIDR =*pData++;//// Discard received data.//while((SSISR &(1ul<<SR_RNE))==0){;}Dummy =SSIDR;FS_USE_PARA(Dummy);}while(--NumBytes);#endif//// Wait for the data transfer to finish.//while(SSISR &(1uL<<SR_BSY)){;}}/*********************************************************************** _Read*/staticvoid_Read(U8 *pData,intNumBytes){#ifFS_MMC_HW_SPI_USE_DMAintNumBytesAtOnce;do{NumBytesAtOnce =SEGGER_MIN(NumBytes,DMA_MAX_TRANSFER_SIZE);_StartDMARead(pData,(U32)NumBytesAtOnce);_WaitForEndOfDMAOperation();NumBytes -=NumBytesAtOnce;pData +=NumBytesAtOnce;}while(NumBytes);#elsedo{//// Wait for room in FIFO.//while((SSISR &(1uL<<SR_TNF))==0){;}SSIDR =0xFF;//// Wait for some data to be received.//while((SSISR &(1ul<<SR_RNE))==0){;}*pData++=(U8)SSIDR;}while(--NumBytes);#endif}/*********************************************************************** _Init*/staticvoid_Init(void){_EnableClocks();_InitPins();SSICR1 =0;SSICR0 =0|(CR0_DSS_8BIT <<CR0_DSS)|(1uL<<CR0_SPO)|(1uL<<CR0_SPH);SSICC =0;SSIICR =~0uL;SSIIM =0;SSIDMACTL =0;(void)_SetMaxSpeed(DEFAULT_SPI_CLOCK_KHZ);SSICR1 |=1uL<<CR1_SSE;//// Empty the receive queue.//while(1){if((SSISR &(1uL<<SR_RNE))==0){break;}(void)SSIDR;}#ifFS_MMC_HW_SPI_USE_DMA_InitDMA();#endif_IsInited =1;}/*********************************************************************** Public code (through callback)************************************************************************//*********************************************************************** _HW_EnableCS** Function description* FS low level function. Sets the card slot active using the* chip select (CS) line.** Parameters* Unit Device index*/staticvoid_HW_EnableCS(U8 Unit){volatileU32 *pReg;FS_USE_PARA(Unit);pReg =(volatileU32 *)((U8 *)&PH_GPIODATA +((1uL<<CS_PIN)<<2));*pReg =~(1uL<<CS_PIN);// Active low}/*********************************************************************** _HW_DisableCS** Function description* FS low level function. Clears the card slot inactive using the* chip select (CS) line.** Parameters* Unit Device index*/staticvoid_HW_DisableCS(U8 Unit){volatileU32 *pReg;FS_USE_PARA(Unit);pReg =(volatileU32 *)((U8 *)&PH_GPIODATA +((1uL<<CS_PIN)<<2));*pReg =1uL<<CS_PIN;// Active low}/*********************************************************************** _HW_IsWriteProtected** Function description* FS low level function. Returns the state of the physical write* protection of the SD cards.** Parameters* Unit Device index** Return value* ==1 The card is write protected* ==0 The card is not write protected*/staticint_HW_IsWriteProtected(U8 Unit){FS_USE_PARA(Unit);return0;}/*********************************************************************** _HW_SetMaxSpeed** Function description* FS low level function. Sets the SPI interface to a maximum frequency.* Make sure that you set the frequency lower or equal but never higher* than the given value. Recommended startup frequency is 100kHz - 400kHz.** Parameters* Unit Device index* MaxFreq SPI clock frequency in kHz** Return value* max. frequency The maximum frequency set in kHz* ==0 The frequency could not be set*/staticU16 _HW_SetMaxSpeed(U8 Unit,U16 MaxFreq){FS_USE_PARA(Unit);MaxFreq =_SetMaxSpeed(MaxFreq);returnMaxFreq;// We are not faster than this.}/*********************************************************************** _HW_SetVoltage** Function description* FS low level function. Be sure that your card slot si within the given* voltage range. Return 1 if your slot can support the required voltage,* and if not, return 0;** Parameters* Unit Device index* Vmin Minimum supply voltage supported by host* Vmax Maximum supply voltage supported by host** Return value* ==1 The card slot supports the voltage range* ==0 The card slot does not support the voltage range*/staticint_HW_SetVoltage(U8 Unit,U16 Vmin,U16 Vmax){FS_USE_PARA(Unit);if((FS_MMC_HW_SPI_DEFAULT_SUPPLY_VOLTAGE >=Vmin)&&(FS_MMC_HW_SPI_DEFAULT_SUPPLY_VOLTAGE <=Vmax)){return1;// Supply voltage supported.}return0;// Supply voltage not supported.}/*********************************************************************** _HW_IsPresent** Function description* Returns the state of the media. If you do not know the state, return* FS_MEDIA_STATE_UNKNOWN and the higher layer will try to figure out if* a media is present.** Parameters* Unit Device index** Return value* FS_MEDIA_STATE_UNKNOWN Media state is unknown* FS_MEDIA_NOT_PRESENT Media is not present* FS_MEDIA_IS_PRESENT Media is present*/staticint_HW_IsPresent(U8 Unit){FS_USE_PARA(Unit);if(_IsInited ==0){_Init();}returnFS_MEDIA_IS_PRESENT;}/*********************************************************************** _HW_Read** Function description* FS low level function. Reads a specified number of bytes from MMC* card to buffer.** Parameters* Unit Device index* pData Pointer to a data buffer* NumBytes Number of bytes*/staticvoid_HW_Read(U8 Unit,U8 *pData,intNumBytes){FS_USE_PARA(Unit);_Read(pData,NumBytes);}/*********************************************************************** _HW_Write** Function description* FS low level function. Writes a specified number of bytes from* data buffer to the MMC/SD card.** Parameters* Unit Device index* pData Pointer to a data buffer* NumBytes Number of bytes*/staticvoid_HW_Write(U8 Unit,constU8 *pData,intNumBytes){FS_USE_PARA(Unit);_Write(pData,NumBytes);}/*********************************************************************** Public data************************************************************************/constFS_MMC_HW_TYPE_SPIFS_MMC_HW_SPI_TM4C129_TI_TIVAC129 ={_HW_EnableCS,_HW_DisableCS,_HW_IsPresent,_HW_IsWriteProtected,_HW_SetMaxSpeed,_HW_SetVoltage,_HW_Read,_HW_Write,NULL,NULL,NULL,NULL};/*************************** End of file ****************************/
Hardware layer API - FS_MMC_HW_TYPE_CM
This hardware layer supports MMC cards and eMMC devices that comply with the
version 4.x or newer of the MMC specification and SD cards of all types that
are interfaced to the target MCU via a host controller that works in card mode.
The functions of this hardware layer are grouped in a structure of type
FS_MMC_HW_TYPE_CM. The following sections describe these functions in detail.
This function is a member of the Card Mode MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
The Card Mode MMC/SD driver calls FS_MMC_HW_TYPE_CM_INIT before
any other function of the hardware layer. FS_MMC_HW_TYPE_CM_INIT
must perform any steps required to initialize the target hardware
such as enabling the clocks, setting up special function registers,
etc.
This function is a member of the Card Mode MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
The specified time is a minimum delay. The actual delay is permitted
to be longer. This can be helpful when using an RTOS. Every RTOS has
a delay API function, but the accuracy is typically 1 tick, which is
1 ms in most cases. Therefore, a delay of 1 tick is typically between
0 and 1 ms. To compensate for this, the equivalent of 1 tick should
be added to the delay parameter before passing it to an RTOS delay function.
This function is a member of the Card Mode MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
Typically, the card presence detection is implemented via a dedicated
Card Detect (CD) signal. This signal is connected to a switch inside
the card slot that changes its state each time the card is removed
or inserted. If the hardware does not provide such signal the function
has to return FS_MEDIA_STATE_UNKNOWN.
This function is a member of the Card Mode MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
Typically, the card protection status is implemented via a dedicated
Write Protected (WP) signal. This signal is connected to a switch inside
the card slot that reflects the status of the write protect switch
found on SD cards. If the hardware does not provide such signal the
function has to return 0.
eMMC devices and micro SD cards do not have a write protection switch.
Please note that the write protect switch does not really protect the
data on an SD card form being modified. It is merely an indication
that the data has to be protected. It is the responsibility of the host
MCU to respect the status of this switch.
FS_MMC_HW_TYPE_CM_SET_MAX_SPEED
Description
Configures the clock frequency supplied to the card.
Maximum allowed frequency of the bus clock in kHz.
Return value
≠ 0
The actual clock frequency in kHz.
= 0
An error occurred.
Additional information
This function is a member of the Card Mode MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
The hardware layer is allowed to set a clock frequency smaller
than the value specified via MaxFreq but never greater than that.
The Card Mode MMC/SD driver calls this function at least two times during
the initialization of the MMC or SD card:
Before the initialization starts to set the clock frequency to 400 kHz.
After the card identification to set the standard clock frequency
which is 25 MHz for SD cards or 26 MHz for MMC cards and eMMC devices.
FS_MMC_HW_TYPE_CM_SPI_SET_MAX_SPEED is called a third time by the
Card Mode MMC/SD driver during the initialization if the high speed mode
is enabled in the driver via FS_MMC_CM_AllowHighSpeedMode() and the card
supports this mode. In this case the clock frequency is set to 50 MHz for
SD cards and to 52 MHz for MMC cards and eMMC devices.
The function has to return the actual configured clock frequency.
If the precise frequency is unknown such as for implementation using
I/O port “bit-banging”, the return value has to be less than the specified
frequency. This may lead to longer timeout values but is in general
does not cause any problems. The Card Mode MMC/SD driver uses the returned
value to calculate timeout values.
FS_MMC_HW_TYPE_CM_SET_RESPONSE_TIMEOUT
Description
Configures the maximum time to wait for a response from card.
This function is a member of the Card Mode MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
The specified value is the maximum number of clock cycles the
hardware layer has to wait for a response from the card.
If the card does not respond within the specified timeout then
FS_MMC_HW_TYPE_CM_GET_RESPONSE has to return an error to the
Card Mode MMC/SD driver.
FS_MMC_HW_TYPE_CM_SET_READ_DATA_TIMEOUT
Description
Configures the maximum time to wait for data from card.
This function is a member of the Card Mode MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
The specified value is the maximum number of clock cycles the
hardware layer has to wait for data to be received from the card.
If the card does not starts sending the data within the specified
timeout then FS_MMC_HW_TYPE_CM_READ_DATA has to return an error
to the Card Mode MMC/SD driver. The timeout value specified via
FS_MMC_HW_TYPE_CM_SET_READ_DATA_TIMEOUT has to be used as timeout
for a write data operation if the MMC/SD host controller supports
this feature.
This function is a member of the Card Mode MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
Cmd is a command code defined in the SD or MMC specification.
CmdFlags specifies additional information about the command execution
such as the direction of the data transfer if any, the number of data
lines to be used for the data exchange, etc. CmdFlags is a bitwise-or
combination of Card mode command flags
ResponseType specifies the format of the response expected for the sent command.
It can be one of Card mode response formats. If the command requests
a response from the card then the Card Mode MMC/SD driver calls
FS_MMC_HW_TYPE_CM_GET_RESPONSE to get it.
Arg is the value that is stored at the bit positions 8:39 in a command codeword.
A command codeword is always sent via the CMD signal. The same signal is used
by a card to send a response back to MCU.
The MMC and SD specifications describe the structure of a response
in terms of bit units with bit 0 being the first transmitted via
the CMD signal. The following table shows at which byte offsets
the response has to be stored to pData.
48-bit response:
Byte offset pData
Bit range response
0
47-40
1
39-32
2
31-24
3
23-16
4
15-8
5
7-0
136-bit response:
Byte offset pData
Bit range response
0
135-128
1
127-120
2
119-112
3
111-104
4
103-96
5
95-88
6
87-80
7
79-72
8
71-64
9
63-56
10
55-48
11
47-40
12
39-32
13
31-24
14
23-16
15
15-8
16
7-0
The first and last byte of a response codeword store control and check
information that is not used by the Card Mode MMC/SD driver.
If this information is not provided by the SD and MMC host controller
then the hardware layer does not have to store any data to these locations
of pData. That is the response data must be stored at byte offset 1 in pData.
Typically, an MMC or SD host controller transfers the data one block
at a time. BlockSize specifies the size of one block in bytes with the
number of blocks being specified via NumBlocks. BlockSize and NumBlocks
can never be 0. Typically the size of block is 512 bytes but during the
initialization of the card the Card Mode MMC/SD driver can request blocks
of different (smaller) sizes. The total number of bytes to be transferred by
FS_MMC_HW_TYPE_CM_READ_DATA is BlockSize * NumBlocks.
The number of data signals to be used for the data transfer is specified
by the Card Mode MMC/SD driver via the command flags when the command that
initiates the read operation is sent. FS_MMC_CMD_FLAG_USE_SD4MODE is
set in the command flags when the data has to be exchanged via 4 data
signals. This flag can be set for SD cards as well as MMC devices.
FS_MMC_CMD_FLAG_USE_MMC8MODE is set only for MMC devices to transfer
the data via 8 data signals.
Typically, an MMC or SD host controller transfers the data one block
at a time. BlockSize specifies the size of one block in bytes with the
number of blocks being specified via NumBlocks. BlockSize and NumBlocks
can never be 0. Typically the size of block is 512 bytes but during the
initialization of the card the Card Mode MMC/SD driver can request blocks
of different (smaller) sizes. The total number of bytes to be transferred by
FS_MMC_HW_TYPE_CM_WRITE_DATA is BlockSize * NumBlocks.
The number of data signals to be used for the data transfer is specified
by the Card Mode MMC/SD driver via the command flags when the command that
initiates the write operation is sent. FS_MMC_CMD_FLAG_USE_SD4MODE is
set in the command flags when the data has to be exchanged via 4 data
signals. This flag can be set for SD cards as well as MMC devices.
FS_MMC_CMD_FLAG_USE_MMC8MODE is set only for MMC devices to transfer
the data via 8 data signals.
This function is a member of the Card Mode MMC/SD hardware layer
It has to be implemented only by a hardware layer that has to
prepare the data transfer such as via DMA before the read or write
command that initiates that data transfer is sent to card.
FS_MMC_HW_TYPE_CM_SET_DATA_POINTER is called by the Card Mode MMC/SD driver
before each command that exchanges the data with the card. pData points
to the same memory region as pData passed to FS_MMC_HW_TYPE_CM_READ_DATA
and FS_MMC_HW_TYPE_CM_WRITE_DATA.
FS_MMC_HW_TYPE_CM_SET_BLOCK_LEN
Description
Configures the size of the data block to be exchanged.
This function is a member of the Card Mode MMC/SD hardware layer
It has to be implemented only by a hardware layer that has to
prepare the data transfer such as via DMA before the read or write
command that initiates that data transfer is sent to card.
FS_MMC_HW_TYPE_CM_SET_BLOCK_LEN is called by the Card Mode MMC/SD driver
before each command that exchanges the data with the card. The same value
is passed via BlockSize as the value passed via BlockSize to
FS_MMC_HW_TYPE_CM_READ_DATA and FS_MMC_HW_TYPE_CM_WRITE_DATA.
FS_MMC_HW_TYPE_CM_SET_NUM_BLOCKS
Description
Configures the number of data blocks to be exchanged.
This function is a member of the Card Mode MMC/SD hardware layer
It has to be implemented only by a hardware layer that has to
prepare the data transfer such as via DMA before the read or write
command that initiates that data transfer is sent to card.
FS_MMC_HW_TYPE_CM_SET_NUM_BLOCKS is called by the Card Mode MMC/SD driver
before each command that exchanges the data with the card. The same value
is passed via NumBlocks as the value passed via NumBlocks to
FS_MMC_HW_TYPE_CM_READ_DATA and FS_MMC_HW_TYPE_CM_WRITE_DATA.
FS_MMC_HW_TYPE_CM_GET_MAX_READ_BURST
Description
Returns the maximum number of data blocks that can be transferred
at once from card to MCU.
Number of blocks that can be transferred at once. It cannot be 0.
Additional information
This function is a member of the Card Mode MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
FS_MMC_HW_TYPE_CM_GET_MAX_READ_BURST is called by the Card Mode MMC/SD driver
during initialization. It has to return the maximum number of 512 byte blocks
the hardware layer is able to transfer from the card via a single read command.
The larger the number of blocks the hardware layer can exchange at once the
better is the read performance.
FS_MMC_HW_TYPE_CM_GET_MAX_WRITE_BURST
Description
Returns the maximum number of data blocks that can be transferred
at once from MCU to card.
Number of blocks that can be transferred at once. It cannot be 0.
Additional information
This function is a member of the Card Mode MMC/SD hardware layer.
It has to be implemented by all the hardware layers.
FS_MMC_HW_TYPE_CM_GET_MAX_WRITE_BURST is called by the Card Mode MMC/SD driver
during initialization. It has to return the maximum number of 512 byte blocks
the hardware layer is able to transfer to the card via a single write command.
The larger the number of blocks the hardware layer can exchange at once the
better is the write performance.
FS_MMC_HW_TYPE_CM_GET_MAX_REPEAT_WRITE_BURST
Description
Returns the maximum number of blocks of identical data that can be
transferred from MCU to card.
This function is a member of the Card Mode MMC/SD hardware layer.
A hardware layer is not required to implement this function.
FS_MMC_HW_TYPE_CM_GET_MAX_REPEAT_WRITE_BURST is called by the Card Mode
MMC/SD driver during initialization. It has to return the maximum number
of 512 byte blocks the hardware layer is able to repeatedly transfer
to the card via a single write command. The command that starts a repeated
write operation has FS_MMC_CMD_FLAG_WRITE_BURST_REPEAT set in the command
flags passed to FS_MMC_HW_TYPE_CM_SEND_CMD. The Card Mode MMC/SD driver
transfers the data by calling FS_MMC_HW_TYPE_CM_WRITE_DATA with pData
always pointing to a single block of BlockSize regardless of the NumBlock
value. That FS_MMC_HW_TYPE_CM_WRITE_DATA does not have to increment pData
by BlockSize after each block transfer. The larger the number of blocks
the hardware layer can exchange at once the better is the write performance.
A return value of 0 indicates that the feature is not supported.
FS_MMC_HW_TYPE_CM_GET_MAX_FILL_WRITE_BURST
Description
Returns the maximum number of blocks of identical data that can be
transferred from MCU to card.
This function is a member of the Card Mode MMC/SD hardware layer.
A hardware layer is not required to implement this function.
FS_MMC_HW_TYPE_CM_GET_MAX_FILL_WRITE_BURST is called by the Card Mode
MMC/SD driver during initialization. It has to return the maximum number
of 512 byte blocks the hardware layer is able to repeatedly transfer
to the card via a single write command. The command that starts a repeated
write operation has FS_MMC_CMD_FLAG_WRITE_BURST_FILL set in the command
flags passed to FS_MMC_HW_TYPE_CM_SEND_CMD. The Card Mode MMC/SD driver
transfers the data by calling FS_MMC_HW_TYPE_CM_WRITE_DATA with pData
always pointing to a single block of BlockSize regardless of the NumBlocks
value. FS_MMC_HW_TYPE_CM_GET_MAX_FILL_WRITE_BURST has to take the first
four bytes from pData and send them repeatedly to card until
BlockSize * NumBlocks are sent. Typically this operation is realized by
using DMA configured to transfer four bytes at once and without incrementing
the destination address. The larger the number of blocks the hardware layer
can exchange at once the better is the write performance.
A return value of 0 indicates that the feature is not supported.
Specifies if a voltage switch sequence has to be performed according to SD specification. 1 Voltage switch sequence has to be performed. 0 No voltage switch sequence is required.
Return value
= 0
OK, voltage switched successfully.
≠ 0
Error code indicating the failure reason.
Additional information
This function is a member of the Card Mode MMC/SD hardware layer.
A hardware layer has to implement this function if the hardware
supports 1.8 V signaling and the application enables any ultra high
speed mode in the Card Mode MMC/SD driver.
The values of VMin and VMax are specified in mV with VMin always
smaller than or equal to VMax.
IsSwitchSequence is set to 1 only if an SD card is connected.
For MMC cards or eMMC devices IsSwitchSequence is always set to 0.
If IsSwitchSequence is set to 1 then the function has to wait
for the SD card to change the voltage level of the I/O lines as follows:
Wait for the SD card to drive either the CMD or one of the DAT lines to low.
Stop providing clock to SD card.
Wait for the SD card to start the switch sequence by checking if
either the CMD or one of the DAT lines to low.
Wait at least 5 ms.
Start providing the clock to SD card using a 1.8 V voltage level.
Wait at least 1 ms.
Check if the SD card drives one of the DAT lines to high.
This function has to wait for the power to stabilize before it returns.
This function is a member of the Card Mode MMC/SD hardware layer.
A hardware layer has to implement this function if the hardware
supports 1.8 V signaling and the application enables any ultra high
speed mode in the Card Mode MMC/SD driver.
FS_MMC_HW_TYPE_CM_SET_MAX_CLOCK
Description
Configures the clock frequency supplied to the card.
Maximum allowed frequency of the bus clock in kHz.
ClkFlags
Additional clock generation options.
Return value
≠ 0
The actual clock frequency in kHz.
= 0
An error occurred.
Additional information
This function is a member of the Card Mode MMC/SD hardware layer.
A hardware layer has to implement this function if the hardware
supports 1.8 V signaling and the application enables any ultra high
speed mode in the Card Mode MMC/SD driver.
The hardware layer is allowed to set a clock frequency smaller
than the value specified via MaxFreq but never greater than that.
FS_MMC_HW_TYPE_CM_SPI_SET_MAX_SPEED_EX is similar to
FS_MMC_HW_TYPE_CM_SPI_SET_MAX_SPEED with the exception that it
allows the configuration of a clock frequency greater than 65535 kHz
which is required by some of the ultra high speed modes.
In addition, FS_MMC_HW_TYPE_CM_SPI_SET_MAX_SPEED_EX has the ability
to configure if the data received from the card has to be sampled
on one clock edge or on both clock edges.
ClkFlags is a bitwise-or combination of Card mode clock flags
that specifies for example how the data has to be sampled.
FS_MMC_HW_TYPE_CM_ENABLE_TUNING
Description
Stops the normal operation and enters the tuning procedure.
This function is a member of the Card Mode MMC/SD hardware layer.
A hardware layer has to implement this function if the hardware
supports 1.8 V signaling and the application enables an ultra high
speed mode that requires the tuning of the data sampling point.
Specifies if the tuning procedure was successful or not. 0 - The tuning procedure was successful. 1 - The tuning procedure failed.
Return value
= 0
OK, tuning procedure deactivated.
≠ 0
An error occurred.
Additional information
This function is a member of the Card Mode MMC/SD hardware layer.
A hardware layer has to implement this function if the hardware
supports 1.8 V signaling and the application enables an ultra high
speed mode that requires the tuning of the data sampling point.
This function is a member of the Card Mode MMC/SD hardware layer.
A hardware layer has to implement this function if the hardware
supports 1.8 V signaling and the application enables an ultra high
speed mode that requires the tuning of the data sampling point.
FS_MMC_HW_TYPE_CM_START_TUNING is called by the Card Mode MMC/SD driver
one time at the beginning of each tuning sequence. On the first call
TuningIndex is set to 0, on the second to 1 and so on. The maximum
value of TuningIndex is the value returned by FS_MMC_HW_TYPE_CM_GET_MAX_TUNINGS
minus 1. TuningIndex can be used for example to select a different
delay line unit.
This function is a member of the Card Mode MMC/SD hardware layer.
A hardware layer has to implement this function if the hardware
supports 1.8 V signaling and the application enables an ultra high
speed mode that requires the tuning of the data sampling point.
FS_MMC_HW_TYPE_CM_GET_MAX_TUNINGS is called by the Card Mode MMC/SD driver
one time at the beginning of the tuning procedure after the call to
FS_MMC_HW_TYPE_CM_ENABLE_TUNING.
The return value can be for example the number of delay line units
available.
Command that sends data to card. Implies FS_MMC_CMD_FLAG_DATATRANSFER.
FS_MMC_CMD_FLAG_SETBUSY
Command that expects an R1b command.
FS_MMC_CMD_FLAG_INITIALIZE
Specifies that the initialization delay has to be performed. According to SD specification this is the maximum of 1 millisecond, 74 clock cycles and supply ramp up time.
FS_MMC_CMD_FLAG_USE_SD4MODE
Command that transfers the data via 4 data lines.
FS_MMC_CMD_FLAG_STOP_TRANS
Command that stops a data transfer (typically CMD12)
FS_MMC_CMD_FLAG_WRITE_BURST_REPEAT
Specifies that the same sector data is written to consecutive sector indexes.
FS_MMC_CMD_FLAG_USE_MMC8MODE
Command that transfers the data via 8 data lines (MMC only).
FS_MMC_CMD_FLAG_NO_CRC_CHECK
CRC verification has to be disabled for the command. Typically used with the MMC bus test commands.
FS_MMC_CMD_FLAG_WRITE_BURST_FILL
Specifies that the 32-bit value is used to fill the contents of consecutive sector indexes.
FS_MMC_CMD_FLAG_SWITCH_VOLTAGE
Specifies that the the signaling of the I/O lines has to be changed to 1.8 V
Specifies that the data is exchanged on both clock edges.
FS_MMC_CLK_FLAG_STROBE_MODE
Specifies that the received data is sampled using a strobe signal generated by the storage device.
FS_MMC_CLK_FLAG_ENHANCED_STROBE
Specifies that the received response and data are sampled using a strobe signal generated by the storage device.
Additional information
The FS_MMC_CLK_FLAG_STROBE_MODE and FS_MMC_CLK_FLAG_ENHANCED_STROBE
flags are used to specify how to sample the data coming from an eMMC
device in HS400 access mode. If FS_MMC_CLK_FLAG_STROBE_MODE is set
and FS_MMC_CLK_FLAG_ENHANCED_STROBE and cleared then the received
data is sampled using the strobe signal while the command response
using the clock supplied to eMMC device. If FS_MMC_CLK_FLAG_STROBE_MODE
and FS_MMC_CLK_FLAG_ENHANCED_STROBE are both set then the received
data as well as the command response are sampled using the strobe signal.
The following sample implementation uses the SD host controller of an NXP K66 MCU
to interface with an SD card. This NOR 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_MMC_HW_CM_K66_SEGGER_emPower.cPurpose : SD/MMC (card mode) hardware layer for Freescale Kinetis K66Literature: [1] UM06001 emPower Evaluation and prototyping platform for SEGGER software User Guide & Reference Manual [2] K66P144M180SF5RMV2 K66 Sub-Family Reference Manual [3] SD Specifications Part 1 Physical Layer Simplified Specification Version 2.00*//*********************************************************************** #include section************************************************************************/#include"FS.h"/*********************************************************************** Defines, configurable************************************************************************/#ifndefFS_MMC_HW_CM_USE_DMA#defineFS_MMC_HW_CM_USE_DMA 1// Turns the DMA support on and off#endif#ifndefFS_MMC_HW_CM_PERIPH_CLOCK#defineFS_MMC_HW_CM_PERIPH_CLOCK 168000000uL// Peripheral clock speed in Hz#endif#ifndefFS_MMC_HW_CM_MAX_SPEED#defineFS_MMC_HW_CM_MAX_SPEED 50000// Limits the maximum communication speed to this value (kHz)#endif#ifndefFS_MMC_HW_CM_NUM_DMA_DESC#defineFS_MMC_HW_CM_NUM_DMA_DESC 32// Number of DMA descriptors to allocate#endif#ifndefFS_MMC_HW_CM_POWER_GOOD_DELAY#defineFS_MMC_HW_CM_POWER_GOOD_DELAY 1000// Number of milliseconds to wait for the power to stabilize.#endif#ifndefFS_MMC_HW_CM_USE_OS#defineFS_MMC_HW_CM_USE_OS 0// Enables / disables the event-driven operation.// 0 - OS support disabled.// 1 - OS support enabled using OS event of emFile.// 2 - OS support enabled using OS events of this HW layer.#endif/*********************************************************************** #include section, conditional************************************************************************/#ifFS_MMC_HW_CM_USE_OS#include"FS_OS.h"#include"RTOS.h"#include"MK66F18.h"#endif// FS_MMC_HW_CM_USE_OS/*********************************************************************** Defines, fixed************************************************************************/#if(FS_MMC_HW_CM_USE_OS ==0)/*********************************************************************** System integration module*/#defineSIM_BASE_ADDR 0x40047000#defineSIM_SCGC3 (*(volatileU32*)(SIM_BASE_ADDR +0x1030))// System Clock Gating Control Register 3#defineSIM_SCGC5 (*(volatileU32*)(SIM_BASE_ADDR +0x1038))// System Clock Gating Control Register 5/*********************************************************************** PORT E*/#definePORTE_BASE_ADDR 0x4004D000#definePORTE_PCR0 (*(volatileU32*)(PORTE_BASE_ADDR +0x00))// Pin control register 0#definePORTE_PCR1 (*(volatileU32*)(PORTE_BASE_ADDR +0x04))// Pin control register 1#definePORTE_PCR2 (*(volatileU32*)(PORTE_BASE_ADDR +0x08))// Pin control register 2#definePORTE_PCR3 (*(volatileU32*)(PORTE_BASE_ADDR +0x0C))// Pin control register 3#definePORTE_PCR4 (*(volatileU32*)(PORTE_BASE_ADDR +0x10))// Pin control register 4#definePORTE_PCR5 (*(volatileU32*)(PORTE_BASE_ADDR +0x14))// Pin control register 5#definePORTE_PCR6 (*(volatileU32*)(PORTE_BASE_ADDR +0x18))// Pin control register 5#definePORTE_PCR27 (*(volatileU32*)(PORTE_BASE_ADDR +0x6C))// Pin control register 27#definePORTE_DFER (*(volatileU32*)(PORTE_BASE_ADDR +0xC0))// Digital filter enable register/*********************************************************************** GPIO E*/#defineGPIOE_BASE 0x400FF000#defineGPIOE_PDOR (*(volatileU32*)(GPIOE_BASE +0x100))// Port Data Output Register#defineGPIOE_PDIR (*(volatileU32*)(GPIOE_BASE +0x110))// Port Data Input Register#defineGPIOE_PDDR (*(volatileU32*)(GPIOE_BASE +0x114))// Port Data Direction Register/*********************************************************************** SDHC*/#defineSDHC_BASE 0x400B1000#defineSDHC_BLKATTR (*(volatileU32*)(SDHC_BASE +0x04))// Block Attributes Register#defineSDHC_CMDARG (*(volatileU32*)(SDHC_BASE +0x08))// Command Argument Register#defineSDHC_XFERTYP (*(volatileU32*)(SDHC_BASE +0x0C))// Transfer Type Register#defineSDHC_CMDRSP0 (*(volatileU32*)(SDHC_BASE +0x10))// Command Response 0#defineSDHC_DATPORT (*(volatileU32*)(SDHC_BASE +0x20))// Buffer Data Port Register#defineSDHC_PRSSTAT (*(volatileU32*)(SDHC_BASE +0x24))// Present State Register#defineSDHC_PROCTL (*(volatileU32*)(SDHC_BASE +0x28))// Protocol Control Register#defineSDHC_SYSCTL (*(volatileU32*)(SDHC_BASE +0x2C))// System Control Register#defineSDHC_IRQSTAT (*(volatileU32*)(SDHC_BASE +0x30))// Interrupt Status Register#defineSDHC_IRQSTATEN (*(volatileU32*)(SDHC_BASE +0x34))// Interrupt Status Enable Register#defineSDHC_IRQSIGEN (*(volatileU32*)(SDHC_BASE +0x38))// Interrupt Signal Enable Register#defineSDHC_WML (*(volatileU32*)(SDHC_BASE +0x44))// Watermark Level Register#defineSDHC_ADSADDR (*(volatileU32*)(SDHC_BASE +0x58))// ADMA System Address Register#defineSDHC_VENDOR (*(volatileU32*)(SDHC_BASE +0xC0))// Vendor Specific Register/*********************************************************************** MPU*/#defineMPU_BASE 0x4000D000#defineMPU_RGDAAC0 (*(volatileU32*)(MPU_BASE +0x800))// Region Descriptor Alternate Access Control 0#else/*********************************************************************** Port E*/#definePORTE_BASE_ADDR 0x4004D000uL#definePORTE_DFER (*(volatileU32 *)(PORTE_BASE_ADDR +0xC0))// Digital filter enable register#endif// (FS_MMC_HW_CM_USE_OS == 0)/*********************************************************************** Pin assignments of signals*/#defineSD_CMD_BIT 3// Command (GPIO E)#defineSD_CLK_BIT 2// Clock (GPIO E)#defineSD_D0_BIT 1// Data 0 (GPIO E)#defineSD_D1_BIT 0// Data 1 (GPIO E)#defineSD_D2_BIT 5// Data 2 (GPIO E)#defineSD_D3_BIT 4// Data 3 (GPIO E)#defineSD_CD_BIT 6// Card detect (GPIO E)/*********************************************************************** Port control register bits*/#definePCR_MUX_BIT 8// Alternate port setting#definePCR_MUX_GPIO 1// Controlled directly by the HW layer#definePCR_MUX_SDHC 4// Controlled by SDHC#definePCR_DSE_BIT 6// Driver strength enable#definePCR_PE_BIT 1// Pull enable#definePCR_PS_BIT 0// Pull-up enable/*********************************************************************** Clock enable bits*/#defineSCGC3_SDHC_BIT 17// SDHC#defineSCGC5_PORTE_BIT 13// GPIO E/*********************************************************************** SDHC interrupt request bits*/#defineIRQSTAT_CC_BIT 0// Command complete#defineIRQSTAT_TC_BIT 1// Transfer complete#defineIRQSTAT_DINT_BIT 3// DMA interrupt#defineIRQSTAT_BWR_BIT 4// Buffer write ready#defineIRQSTAT_BRR_BIT 5// Buffer read ready#defineIRQSTAT_CTOE_BIT 16// Command timeout error#defineIRQSTAT_CCE_BIT 17// Command CRC error#defineIRQSTAT_CEBE_BIT 18// Command end bit error#defineIRQSTAT_CIE_BIT 19// Command index error#defineIRQSTAT_DTOE_BIT 20// Data timeout error#defineIRQSTAT_DCE_BIT 21// Data CRC error#defineIRQSTAT_DEBE_BIT 22// Data end bit error#defineIRQSTAT_DMAE_BIT 28// DMA error/*********************************************************************** SDHC present status bits*/#definePRSSTAT_CIHB_BIT 0// Command inhibit (CMD)#definePRSSTAT_CDIHB_BIT 1// Command inhibit (DAT)#definePRSSTAT_SDSTB_BIT 3// Set to 1 if the clock is stable#definePRSSTAT_SDOFF_BIT 7#definePRSSTAT_BWEN_BIT 10#definePRSSTAT_DLSL_DAT0_BIT 24/*********************************************************************** SDHC system control bits*/#defineSYSCTL_IPGEN_BIT 0#defineSYSCTL_HCKEN_BIT 1#defineSYSCTL_PEREN_BIT 2#defineSYSCTL_SDCLKEN_BIT 3#defineSYSCTL_DVS_BIT 4#defineSYSCTL_DVS_MASK 0xFuL#defineSYSCTL_DVS_MAX (SYSCTL_DVS_MASK +1)#defineSYSCTL_SDCLKFS_BIT 8#defineSYSCTL_SDCLKFS_MASK 0xFFuL#defineSYSCTL_DTOCV_BIT 16#defineSYSCTL_DTOCV_MASK 0xFuL#defineSYSCTL_DTOCV_MAX (SYSCTL_DTOCV_MASK -1)#defineSYSCTL_RSTA_BIT 24#defineSYSCTL_RSTC_BIT 25#defineSYSCTL_RSTD_BIT 26#defineSYSCTL_INITA_BIT 27/*********************************************************************** SDHC transfer type bits*/#defineXFERTYP_DMAEN_BIT 0// DMA enable#defineXFERTYP_BCEN_BIT 1#defineXFERTYP_DTDSEL_BIT 4#defineXFERTYP_MSBSEL_BIT 5#defineXFERTYP_RSPTYP_BIT 16#defineXFERTYP_RSPTYP_NONE 0uL#defineXFERTYP_RSPTYP_136BIT 1uL#defineXFERTYP_RSPTYP_48BIT 2uL#defineXFERTYP_RSPTYP_48BIT_BUSY 3uL#defineXFERTYP_CCCEN_BIT 19#defineXFERTYP_CICEN_BIT 20#defineXFERTYP_DPSEL_BIT 21#defineXFERTYP_CMDIDX_BIT 24#defineXFERTYP_CMDIDX_MASK 0x3FuL/*********************************************************************** SDHC protocol control bits*/#definePROCTL_DTW_BIT 1#definePROCTL_DTW_MASK 0x3uL#definePROCTL_DTW_4BIT 0x1uL#definePROCTL_EMODE_BIT 4#definePROCTL_EMODE_LE 2uL#definePROCTL_DMAS_BIT 8#definePROCTL_DMAS_MASK 0x3uL#definePROCTL_DMAS_DMA2 2uL/*********************************************************************** SDHC block attributes bits*/#defineBLKATTR_BLKCNT_BIT 16/*********************************************************************** SDHC Watermark level*/#defineWML_RDWML_BIT 0#defineWML_RDWML_MASK 0xFFuL#defineWML_WRWML_BIT 16#defineWML_WRWML_MASK 0xFFuL/*********************************************************************** DMA attributes*/#defineDMA_ATTR_VALID_BIT 0#defineDMA_ATTR_END_BIT 1#defineDMA_ATTR_INT_BIT 2#defineDMA_ATTR_ACT_BIT 4#defineDMA_ATTR_ACT_TRAN 2uL/*********************************************************************** MPU region descriptor bits*/#defineRGD_M5RE_BIT 27#defineRGD_M5WE_BIT 26/*********************************************************************** Number of sectors to transfer at once*/#defineMAX_BLOCK_SIZE 512#defineMAX_DMA_LEN 65532#ifFS_MMC_HW_CM_USE_DMA#defineNUM_BLOCKS_AT_ONCE ((FS_MMC_HW_CM_NUM_DMA_DESC *MAX_DMA_LEN)/MAX_BLOCK_SIZE)#else#defineNUM_BLOCKS_AT_ONCE 65535#endif// FS_MMC_HW_CM_USE_DMA#ifFS_MMC_HW_CM_USE_DMA#defineNUM_BLOCKS_AT_ONCE_REPEAT_SAME FS_MMC_HW_CM_NUM_DMA_DESC#else#defineNUM_BLOCKS_AT_ONCE_REPEAT_SAME 65535#endif/*********************************************************************** Timeouts and delays*/#defineCYCLES_PER_MS 2100#defineWAIT_TIMEOUT_MS 1000#defineWAIT_TIMEOUT_CYCLES (WAIT_TIMEOUT_MS *CYCLES_PER_MS)#defineSDHC_IRQ_PRIO 15#ifFS_MMC_HW_CM_USE_DMA#defineSTAT_MASK ((1uL<<IRQSTAT_CC_BIT)| \(1uL<<IRQSTAT_TC_BIT)| \(1uL<<IRQSTAT_CTOE_BIT)| \(1uL<<IRQSTAT_CCE_BIT)| \(1uL<<IRQSTAT_CEBE_BIT)| \(1uL<<IRQSTAT_CIE_BIT)| \(1uL<<IRQSTAT_DTOE_BIT)| \(1uL<<IRQSTAT_DCE_BIT)| \(1uL<<IRQSTAT_DEBE_BIT)| \(1uL<<IRQSTAT_DINT_BIT))#else#defineSTAT_MASK ((1uL<<IRQSTAT_CC_BIT)| \(1uL<<IRQSTAT_TC_BIT)| \(1uL<<IRQSTAT_BWR_BIT)| \(1uL<<IRQSTAT_BRR_BIT)| \(1uL<<IRQSTAT_CTOE_BIT)| \(1uL<<IRQSTAT_CCE_BIT)| \(1uL<<IRQSTAT_CEBE_BIT)| \(1uL<<IRQSTAT_CIE_BIT)| \(1uL<<IRQSTAT_DTOE_BIT)| \(1uL<<IRQSTAT_DCE_BIT)| \(1uL<<IRQSTAT_DEBE_BIT))#endif/*********************************************************************** Local data types************************************************************************/#ifFS_MMC_HW_CM_USE_DMA/*********************************************************************** DMA_DESC** Description* Memory layout of a ADMA2 descriptor*/typedefstruct{U16 Attr;// Descriptor attributesU16 NumBytes;// Number of bytes to transferU32 Addr;// Destination/source memory address (32-bit aligned)}DMA_DESC;#endif/*********************************************************************** Static data************************************************************************/staticU16 _BlockSize;// Size of the block to transfer as set by the upper layerstaticU16 _NumBlocks;// Number of blocks to transfer as set by the upper layerstaticU8 _RepeatSame;// Set to 1 if the same data has to be written to consecutive block indexes.#ifFS_MMC_HW_CM_USE_DMAstaticDMA_DESC _aDMADesc[FS_MMC_HW_CM_NUM_DMA_DESC];// List of DMA descriptorsstaticvoid*_pData;// Destination/source buffer for the DMA transfers#endif// FS_MMC_HW_CM_USE_DMA#if(FS_MMC_HW_CM_USE_OS ==2)staticU8 _IsEventInited =0;staticOS_EVENT _Event;#endif// FS_MMC_HW_CM_USE_OS == 2/*********************************************************************** Static code************************************************************************/#ifFS_MMC_HW_CM_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.*/staticint_WaitForEvent(U32 TimeOut){intr;SDHC_IRQSIGEN |=STAT_MASK;// Enable interrupts.#if(FS_MMC_HW_CM_USE_OS ==2)r =OS_EVENT_WaitTimed(&_Event,TimeOut);#elser =FS_OS_Wait(TimeOut);#endifif(r !=0){SDHC_IRQSIGEN &=~STAT_MASK;// Disable interrupts.}returnr;}#endif// FS_MMC_HW_CM_USE_OS/*********************************************************************** _WaitForResponse** Function description* Waits for a command response to arrive.** Return values* FS_MMC_CARD_NO_ERROR Success* FS_MMC_CARD_RESPONSE_CRC_ERROR CRC error in response* FS_MMC_CARD_RESPONSE_TIMEOUT No response received* FS_MMC_CARD_RESPONSE_GENERIC_ERROR Any other error*/staticint_WaitForResponse(void){U32 Status;U32 TimeOut;intr;//// Wait for command to finish//TimeOut =WAIT_TIMEOUT_CYCLES;for(;;){Status =SDHC_IRQSTAT;if((Status &(1uL<<IRQSTAT_CTOE_BIT))!=0u){r =FS_MMC_CARD_RESPONSE_TIMEOUT;// Error, no response received.break;}if((Status &(1uL<<IRQSTAT_CCE_BIT))!=0u){r =FS_MMC_CARD_RESPONSE_CRC_ERROR;// Error, CRC error detected in response.break;}if((Status &(1uL<<IRQSTAT_CEBE_BIT))!=0u){r =FS_MMC_CARD_RESPONSE_GENERIC_ERROR;// Error, end bit of response is 0.break;}if((Status &(1uL<<IRQSTAT_CIE_BIT))!=0u){r =FS_MMC_CARD_RESPONSE_GENERIC_ERROR;// Error, command index do not match.break;}#ifFS_MMC_HW_CM_USE_DMAif((Status &(1uL<<IRQSTAT_DMAE_BIT))!=0u){r =FS_MMC_CARD_RESPONSE_GENERIC_ERROR;// Error, DMA failure.break;}#endif// FS_MMC_HW_CM_USE_DMAif((Status &(1uL<<IRQSTAT_CC_BIT))!=0u){r =FS_MMC_CARD_NO_ERROR;// OK, valid response received.break;}#ifFS_MMC_HW_CM_USE_OSr =_WaitForEvent(WAIT_TIMEOUT_MS);if(r !=0){r =FS_MMC_CARD_RESPONSE_TIMEOUT;// Error, no response received.break;}#endif// FS_MMC_HW_CM_USE_OSif(TimeOut--==0u){r =FS_MMC_CARD_RESPONSE_TIMEOUT;// Error, no response received.break;}}returnr;}#if(FS_MMC_HW_CM_USE_DMA ==0)/*********************************************************************** _WaitForRxReady** Function description* Waits until new data is received. The function returns in case of a receiving error.** Return values* FS_MMC_CARD_NO_ERROR Success* FS_MMC_CARD_READ_CRC_ERROR CRC error in received data* FS_MMC_CARD_READ_TIMEOUT No data received* FS_MMC_CARD_READ_GENERIC_ERROR Any other error** Additional information*/staticint_WaitForRxReady(void){U32 Status;U32 TimeOut;intr;TimeOut =WAIT_TIMEOUT_CYCLES;for(;;){Status =SDHC_IRQSTAT;if((Status &(1uL<<IRQSTAT_DEBE_BIT))!=0u){r =FS_MMC_CARD_READ_GENERIC_ERROR;// Error, 0 detected on the end bit.break;}if((Status &(1uL<<IRQSTAT_DCE_BIT))!=0u){r =FS_MMC_CARD_READ_CRC_ERROR;// Error, CRC check failed.break;}if((Status &(1uL<<IRQSTAT_DTOE_BIT))!=0u){r =FS_MMC_CARD_READ_TIMEOUT;// Error, data timeout.break;}if((Status &(1uL<<IRQSTAT_BRR_BIT))!=0u){r =FS_MMC_CARD_NO_ERROR;// OK, data can be read from queue.break;}#ifFS_MMC_HW_CM_USE_OSr =_WaitForEvent(WAIT_TIMEOUT_MS);if(r !=0){r =FS_MMC_CARD_RESPONSE_TIMEOUT;// Error, no response received.break;}#endif// FS_MMC_HW_CM_USE_OSif(TimeOut--==0u){r =FS_MMC_CARD_READ_TIMEOUT;// Error, data timeout.break;}}returnr;}/*********************************************************************** _WaitForTxReady** Function description* Waits until the transmitter is ready to send new data.* The function returns in case of an underrun condition.* This can happen when we are not able to deliver the data fast enough.** Return values* FS_MMC_CARD_NO_ERROR Success* FS_MMC_CARD_WRITE_GENERIC_ERROR Any other error*/staticint_WaitForTxReady(void){U32 Status;U32 TimeOut;intr;TimeOut =WAIT_TIMEOUT_CYCLES;for(;;){Status =SDHC_IRQSTAT;if((Status &(1uL<<IRQSTAT_DTOE_BIT))!=0u){r =FS_MMC_CARD_WRITE_GENERIC_ERROR;// Error, data timeout.break;}if((Status &(1uL<<IRQSTAT_DCE_BIT))!=0u){r =FS_MMC_CARD_WRITE_CRC_ERROR;// Error, CRC check failed.break;}if((Status &(1uL<<IRQSTAT_BWR_BIT))!=0u){r =FS_MMC_CARD_NO_ERROR;// OK, data can be written to queue.break;}#ifFS_MMC_HW_CM_USE_OSr =_WaitForEvent(WAIT_TIMEOUT_MS);if(r !=0){r =FS_MMC_CARD_RESPONSE_TIMEOUT;// Error, no response received.break;}#endif// FS_MMC_HW_CM_USE_OSif(TimeOut--==0u){r =FS_MMC_CARD_WRITE_GENERIC_ERROR;// Error, data timeout.break;}}returnr;}#endif// FS_MMC_HW_CM_USE_DMA == 0/*********************************************************************** _WaitForCmdReady** Function description* Waits for the last command to finish.*/staticvoid_WaitForCmdReady(void){U32 Status;U32 TimeOut;TimeOut =WAIT_TIMEOUT_CYCLES;for(;;){Status =SDHC_PRSSTAT;if((Status &(1uL<<PRSSTAT_CIHB_BIT))==0u){if((Status &(1uL<<PRSSTAT_CDIHB_BIT))==0u){if((Status &(1uL<<PRSSTAT_DLSL_DAT0_BIT))!=0u){break;}}}if(TimeOut--==0u){break;}}}/*********************************************************************** _Delay1ms** Function description* Busy loops for about 1 millisecond.*/staticvoid_Delay1ms(void){volatileinti;for(i =0;i <CYCLES_PER_MS;++i){;}}/*********************************************************************** _Reset** Function description* Resets the command and data state machines. Typ. called in case of an error.*/staticvoid_Reset(void){//// Reset command path.//SDHC_SYSCTL |=1uL<<SYSCTL_RSTC_BIT;SDHC_SYSCTL &=~(1uL<<SYSCTL_RSTC_BIT);//// Reset data path.//SDHC_SYSCTL |=1uL<<SYSCTL_RSTD_BIT;SDHC_SYSCTL &=~(1uL<<SYSCTL_RSTD_BIT);}/*********************************************************************** _SetWMLRead** Function description* Sets the watermark level for read operations.*/staticvoid_SetWMLRead(U32 NumBytes){U32 NumWords;NumWords =NumBytes >>2;NumWords /=3;if(NumWords ==0){NumWords =1;}if(NumWords >WML_RDWML_MASK){NumWords =WML_RDWML_MASK;}SDHC_WML &=~(WML_RDWML_MASK <<WML_RDWML_BIT);SDHC_WML |=NumWords <<WML_RDWML_BIT;}/*********************************************************************** _SetWMLlWrite** Function description* Sets the watermark level for write operations.*/staticvoid_SetWMLWrite(U32 NumBytes){U32 NumWords;NumWords =NumBytes >>2;NumWords =(NumWords <<1)/3;if(NumWords ==0){NumWords =1;}if(NumWords >WML_WRWML_MASK){NumWords =WML_WRWML_MASK;}SDHC_WML &=~(WML_WRWML_MASK <<WML_WRWML_BIT);SDHC_WML |=NumWords <<WML_WRWML_BIT;}#if(FS_MMC_HW_CM_USE_DMA ==0)/*********************************************************************** _GetWMLRead*/staticU32 _GetWMLRead(void){U32 NumWords;NumWords =(SDHC_WML >>WML_RDWML_BIT)&WML_RDWML_MASK;returnNumWords;}/*********************************************************************** _GetWMLWrite*/staticU32 _GetWMLWrite(void){U32 NumWords;NumWords =(SDHC_WML >>WML_WRWML_BIT)&WML_WRWML_MASK;returnNumWords;}#endif// FS_MMC_HW_CM_USE_DMA == 0#ifFS_MMC_HW_CM_USE_DMA/*********************************************************************** _StartDMATransfer** Function description* Starts a DMA data transfer.*/staticvoid_StartDMATransfer(void){U32 NumBytes;DMA_DESC *pDesc;inti;U8 *pAddr;U32 NumBytesAtOnce;pDesc =_aDMADesc;pAddr =(U8 *)_pData;NumBytes =_NumBlocks *_BlockSize;for(i =0;i <FS_MMC_HW_CM_NUM_DMA_DESC;++i){if(_RepeatSame ==0){NumBytesAtOnce =SEGGER_MIN(NumBytes,MAX_DMA_LEN);}else{NumBytesAtOnce =SEGGER_MIN(NumBytes,MAX_BLOCK_SIZE);}pDesc->Addr =(U32)pAddr;pDesc->NumBytes =NumBytesAtOnce;pDesc->Attr =(DMA_ATTR_ACT_TRAN <<DMA_ATTR_ACT_BIT)|(1uL<<DMA_ATTR_VALID_BIT);if(_RepeatSame ==0){pAddr +=NumBytesAtOnce;}NumBytes -=NumBytesAtOnce;if(NumBytes ==0){pDesc->Attr |=(1uL<<DMA_ATTR_INT_BIT)// Set the DMA interrupt flag at the end of transfer.|(1uL<<DMA_ATTR_END_BIT);break;}++pDesc;}SDHC_ADSADDR =(U32)_aDMADesc;SDHC_PROCTL &=~(PROCTL_DMAS_MASK <<PROCTL_DMAS_BIT);SDHC_PROCTL |=(PROCTL_DMAS_DMA2 <<PROCTL_DMAS_BIT);}/*********************************************************************** _WaitForEndOfDMARead** Function description* Waits for the end of a DMA read transfer.** Return value* ==0 OK, data transferred successfully.* !=0 An error occurred.*/staticint_WaitForEndOfDMARead(void){U32 Status;U32 TimeOut;intr;TimeOut =WAIT_TIMEOUT_CYCLES;for(;;){Status =SDHC_IRQSTAT;if((Status &(1uL<<IRQSTAT_DTOE_BIT))!=0u){r =FS_MMC_CARD_READ_TIMEOUT;// Error, data timeout.break;}if((Status &(1uL<<IRQSTAT_DCE_BIT))!=0u){r =FS_MMC_CARD_READ_CRC_ERROR;// Error, CRC check failed.break;}if((Status &(1uL<<IRQSTAT_DMAE_BIT))!=0u){r =FS_MMC_CARD_READ_GENERIC_ERROR;// Error, DMA transfer failed.break;}if((Status &(1uL<<IRQSTAT_DINT_BIT))!=0u){r =FS_MMC_CARD_NO_ERROR;// OK, DMA transfer complete.break;}#ifFS_MMC_HW_CM_USE_OSr =_WaitForEvent(WAIT_TIMEOUT_MS);if(r !=0){r =FS_MMC_CARD_READ_TIMEOUT;// Error, no response received.break;}#endif// FS_MMC_HW_CM_USE_OSif(TimeOut--==0u){r =FS_MMC_CARD_READ_TIMEOUT;// Error, data timeout.break;}}returnr;}/*********************************************************************** _WaitForEndOfDMAWrite** Function description* Waits for the end of a DMA write transfer.** Return value* ==0 OK, data transferred successfully.* !=0 An error occurred.*/staticint_WaitForEndOfDMAWrite(void){U32 Status;U32 TimeOut;intr;TimeOut =WAIT_TIMEOUT_CYCLES;for(;;){Status =SDHC_IRQSTAT;if((Status &(1uL<<IRQSTAT_DTOE_BIT))!=0u){r =FS_MMC_CARD_WRITE_GENERIC_ERROR;// Error, data timeout.break;}if((Status &(1uL<<IRQSTAT_DCE_BIT))!=0u){r =FS_MMC_CARD_WRITE_CRC_ERROR;// Error, CRC check failed.break;}if((Status &(1uL<<IRQSTAT_DMAE_BIT))!=0u){r =FS_MMC_CARD_WRITE_GENERIC_ERROR;// Error, DMA transfer failed.break;}if((Status &(1uL<<IRQSTAT_DINT_BIT))!=0u){r =FS_MMC_CARD_NO_ERROR;// OK, DMA transfer complete.break;}#ifFS_MMC_HW_CM_USE_OSr =_WaitForEvent(WAIT_TIMEOUT_MS);if(r !=0){r =FS_MMC_CARD_WRITE_GENERIC_ERROR;// Error, no response received.break;}#endif// FS_MMC_HW_CM_USE_OSif(TimeOut--==0u){r =FS_MMC_CARD_WRITE_GENERIC_ERROR;// Error, data timeout.break;}}returnr;}#endif// FS_MMC_HW_CM_USE_DMA/*********************************************************************** Public code (via callback)************************************************************************//*********************************************************************** _HW_Init** Function description* Initialize the SD / MMC host controller.** Parameters* Unit Index of the SD / MMC host controller (0-based).*/staticvoid_HW_Init(U8 Unit){inti;FS_USE_PARA(Unit);//// Enable the clock of GPIOs and of SDHC//SIM_SCGC3 |=1uL<<SCGC3_SDHC_BIT;SIM_SCGC5 |=1uL<<SCGC5_PORTE_BIT;//// Clock line//PORTE_PCR2 =(PCR_MUX_SDHC <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT)|(1uL<<PCR_DSE_BIT);//// Command line//PORTE_PCR3 =(PCR_MUX_SDHC <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT)|(1uL<<PCR_DSE_BIT);//// Data 0 line//PORTE_PCR1 =(PCR_MUX_SDHC <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT)|(1uL<<PCR_DSE_BIT);//// Data 1 line//PORTE_PCR0 =(PCR_MUX_SDHC <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT)|(1uL<<PCR_DSE_BIT);//// Data 2 line//PORTE_PCR5 =(PCR_MUX_SDHC <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT)|(1uL<<PCR_DSE_BIT);//// Data 3 line//PORTE_PCR4 =(PCR_MUX_SDHC <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT)|(1uL<<PCR_DSE_BIT);//// Write protect is controlled by the HW layer.//PORTE_PCR27 =(PCR_MUX_GPIO <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT);//// Card detect is controlled by the HW layer//PORTE_PCR6 =(PCR_MUX_GPIO <<PCR_MUX_BIT)|(1uL<<PCR_PE_BIT)|(1uL<<PCR_PS_BIT);//// Disable the digital filtering on all port pins assigned to SDHC.//PORTE_DFER &=~((1uL<<SD_CD_BIT)|(1uL<<SD_CLK_BIT)|(1uL<<SD_CMD_BIT)|(1uL<<SD_D0_BIT)|(1uL<<SD_D1_BIT)|(1uL<<SD_D2_BIT)|(1uL<<SD_D3_BIT));#ifFS_MMC_HW_CM_USE_DMA//// Give DMA access to system memory.//MPU_RGDAAC0 |=(1uL<<RGD_M5RE_BIT)|(1uL<<RGD_M5WE_BIT);#endif#ifFS_MMC_HW_CM_USE_OS//// Disable the interrupt and configure the priority.//NVIC_DisableIRQ(SDHC_IRQn);NVIC_SetPriority(SDHC_IRQn,SDHC_IRQ_PRIO);#endif// FS_MMC_HW_CM_USE_OS//// Configure SDHC.//SDHC_SYSCTL =1uL<<SYSCTL_RSTA_BIT;// Reset peripheral.SDHC_SYSCTL =0;// Start peripheral.SDHC_PROCTL =PROCTL_EMODE_LE <<PROCTL_EMODE_BIT;// Muti-byte data is little endian.SDHC_VENDOR =0;// No external DMA requests.SDHC_IRQSIGEN =0;// Disable all the interrupts.//// Wait for the power to stabilize before the first access to SD card//for(i =0;i <FS_MMC_HW_CM_POWER_GOOD_DELAY;++i){_Delay1ms();}#ifFS_MMC_HW_CM_USE_OS//// Create the OS event and enable the interrupt.//#if(FS_MMC_HW_CM_USE_OS ==2)if(_IsEventInited ==0){OS_EVENT_Create(&_Event);_IsEventInited =1;}#endif// FS_MMC_HW_CM_USE_OS == 2NVIC_EnableIRQ(SDHC_IRQn);#endif// FS_MMC_HW_CM_USE_OS}/*********************************************************************** _HW_Delay** Function description* Blocks the execution for the specified time.** Parameters* ms Number of milliseconds to delay.*/staticvoid_HW_Delay(intms){inti;for(i =0;i <ms;++i){_Delay1ms();}}/*********************************************************************** _HW_IsPresent** Function description* Returns the state of the media. If you do not know the state, return* FS_MEDIA_STATE_UNKNOWN and the higher layer will try to figure out if* a media is present.** Parameters* Unit Index of the SD / MMC host controller (0-based).** Return value* FS_MEDIA_STATE_UNKNOWN The state of the media is unknown* FS_MEDIA_NOT_PRESENT No card is present* FS_MEDIA_IS_PRESENT A card is present*/staticint_HW_IsPresent(U8 Unit){intr;FS_USE_PARA(Unit);r =(GPIOE_PDIR &(1uL<<SD_CD_BIT))?FS_MEDIA_IS_PRESENT :FS_MEDIA_NOT_PRESENT;returnr;}/*********************************************************************** _HW_IsWriteProtected** Function description* Returns whether card is write protected or not.** Parameters* Unit Index of the SD / MMC host controller (0-based).** Notes* (1) The emPower V2 board does not have an WP detect pin.*/staticint_HW_IsWriteProtected(U8 Unit){FS_USE_PARA(Unit);return0;// Note 1}/*********************************************************************** _HW_SetMaxSpeed** Function description* Sets the frequency of the MMC/SD card controller.* The frequency is given in kHz.** Parameters* Unit Index of the SD / MMC host controller (0-based).** Additional information* This function is called two times:* 1. During card initialization* Initialize the frequency to not more than 400kHz.** 2. After card initialization* The CSD register of card is read and the max frequency* the card can operate is determined.* [In most cases: MMC cards 20MHz, SD cards 25MHz]*/staticU16 _HW_SetMaxSpeed(U8 Unit,U16 Freq){U32 Prescaler;U32 Divisor;U32 Factor;U32 SDClock;FS_USE_PARA(Unit);//// Limit the communication speed.//if(Freq >FS_MMC_HW_CM_MAX_SPEED){Freq =FS_MMC_HW_CM_MAX_SPEED;}SDClock =Freq *1000;// Convert to HzFactor =(FS_MMC_HW_CM_PERIPH_CLOCK +SDClock -1)/SDClock;//// Determine the prescaler and the divisor values.//if(Factor ==0){Factor =1;}if(Factor <=SYSCTL_DVS_MAX){Prescaler =0;Divisor =Factor -1;}else{Prescaler =1;while(1){//// Compensate for integer division errors. We must generate a clock frequency <= Freq.//if(Factor &1){++Factor;}Factor >>=1;if(Factor <=SYSCTL_DVS_MAX){Divisor =Factor -1;break;}Prescaler <<=1;}}//// Stop the clock to be able to change its frequency.//SDHC_SYSCTL &=~(1uL<<SYSCTL_SDCLKEN_BIT);//// Set the prescaler and the divisor.//SDHC_SYSCTL &=~((SYSCTL_SDCLKFS_MASK <<SYSCTL_SDCLKFS_BIT)|(SYSCTL_DVS_MASK <<SYSCTL_DVS_BIT));SDHC_SYSCTL |=((Prescaler &SYSCTL_SDCLKFS_MASK)<<SYSCTL_SDCLKFS_BIT)|((Divisor &SYSCTL_DVS_MASK)<<SYSCTL_DVS_BIT);//// Enable the clock to SD card.//SDHC_SYSCTL |=(1uL<<SYSCTL_SDCLKEN_BIT)|(1uL<<SYSCTL_PEREN_BIT)|(1uL<<SYSCTL_HCKEN_BIT)|(1uL<<SYSCTL_IPGEN_BIT);//// Wait for the clock to stabilize.//while((SDHC_PRSSTAT &(1uL<<PRSSTAT_SDSTB_BIT))==0){;}//// Return the actual clock frequency.//Factor =1;if(Prescaler){Factor *=Prescaler <<1;}Factor *=Divisor +1;Freq =FS_MMC_HW_CM_PERIPH_CLOCK /1000/Factor;returnFreq;}/*********************************************************************** _HW_SetResponseTimeOut** Function description* Sets the response time out value given in MMC/SD card cycles.** Parameters* Unit Index of the SD / MMC host controller (0-based).** Notes* (1) The SD host controller has only a short and a long timeout.* We always set the long timeout before we send a command.*/staticvoid_HW_SetResponseTimeOut(U8 Unit,U32 Value){FS_USE_PARA(Unit);FS_USE_PARA(Value);//// Note 1//}/*********************************************************************** _HW_SetReadDataTimeOut** Function description* Sets the read data time out value given in MMC/SD card cycles.** Parameters* Unit Index of the SD / MMC host controller (0-based).*/staticvoid_HW_SetReadDataTimeOut(U8 Unit,U32 Value){FS_USE_PARA(Unit);if(Value >SYSCTL_DTOCV_MAX){Value =SYSCTL_DTOCV_MAX;}SDHC_SYSCTL &=~(SYSCTL_DTOCV_MASK <<SYSCTL_DTOCV_BIT);SDHC_SYSCTL |=Value <<SYSCTL_DTOCV_BIT;}/*********************************************************************** _HW_SendCmd** Function description* Sends a command to the card.** Parameters* Unit Index of the SD / MMC host controller (0-based).* Cmd Command number according to [4]* CmdFlags Additional information about the command to execute* ResponseType Type of response as defined in [4]* Arg Command parameter*/staticvoid_HW_SendCmd(U8 Unit,unsignedCmd,unsignedCmdFlags,unsignedResponseType,U32 Arg){U32 RegValue;FS_USE_PARA(Unit);_WaitForCmdReady();_Reset();_RepeatSame =0;if(CmdFlags &FS_MMC_CMD_FLAG_WRITE_BURST_REPEAT){_RepeatSame =1;}RegValue =(Cmd &XFERTYP_CMDIDX_MASK)<<XFERTYP_CMDIDX_BIT;// Set the command index.switch(ResponseType){//// No response is expected//caseFS_MMC_RESPONSE_FORMAT_NONE:default:RegValue |=XFERTYP_RSPTYP_NONE <<XFERTYP_RSPTYP_BIT;break;//// Short response is expected (48bit)//caseFS_MMC_RESPONSE_FORMAT_R3:RegValue |=XFERTYP_RSPTYP_48BIT <<XFERTYP_RSPTYP_BIT;break;caseFS_MMC_RESPONSE_FORMAT_R1:if(CmdFlags &FS_MMC_CMD_FLAG_SETBUSY){RegValue |=XFERTYP_RSPTYP_48BIT_BUSY <<XFERTYP_RSPTYP_BIT;}else{RegValue |=XFERTYP_RSPTYP_48BIT <<XFERTYP_RSPTYP_BIT;}RegValue |=0|(1uL<<XFERTYP_CICEN_BIT)// Check the received command index.|(1uL<<XFERTYP_CCCEN_BIT)// Check the CRC of response.;break;//// Long response is expected (136bit)//caseFS_MMC_RESPONSE_FORMAT_R2:RegValue |=(XFERTYP_RSPTYP_136BIT <<XFERTYP_RSPTYP_BIT)|(1uL<<XFERTYP_CCCEN_BIT)// Check the CRC of response.;break;}//// If required, Setup the transfer over data lines.//if(CmdFlags &FS_MMC_CMD_FLAG_DATATRANSFER){RegValue |=(1uL<<XFERTYP_DPSEL_BIT);if(_NumBlocks >1){RegValue |=(1uL<<XFERTYP_MSBSEL_BIT)|(1uL<<XFERTYP_BCEN_BIT);}if(CmdFlags &FS_MMC_CMD_FLAG_WRITETRANSFER){_SetWMLWrite(_BlockSize);}else{_SetWMLRead(_BlockSize);RegValue |=(1uL<<XFERTYP_DTDSEL_BIT);// Read data from SD card.}//// Configure the size and the number of blocks to transfer//SDHC_BLKATTR =(_NumBlocks <<BLKATTR_BLKCNT_BIT)|_BlockSize;//// Configure the number of data lines to use for the transfer.//SDHC_PROCTL &=~(PROCTL_DTW_MASK <<PROCTL_DTW_BIT);if(CmdFlags &FS_MMC_CMD_FLAG_USE_SD4MODE){SDHC_PROCTL |=(PROCTL_DTW_4BIT <<PROCTL_DTW_BIT);}#ifFS_MMC_HW_CM_USE_DMARegValue |=(1uL<<XFERTYP_DMAEN_BIT);_StartDMATransfer();#endif// FS_MMC_HW_CM_USE_DMA}//// Enable all the status flags we handle.//SDHC_IRQSTATEN =STAT_MASK;//// This is the initialization delay defined by the SD card specification as:// maximum of 1 msec, 74 clock cycles and supply ramp up time.// The sequence below sends 80 clock cycles which is enough for// the power supply of SD card to raise to Vdd min.//if(CmdFlags &FS_MMC_CMD_FLAG_INITIALIZE){SDHC_SYSCTL |=1uL<<SYSCTL_INITA_BIT;while(SDHC_SYSCTL &(1uL<<SYSCTL_INITA_BIT)){;}}SDHC_IRQSTAT =~0uL;// Reset all status flags.SDHC_CMDARG =Arg;SDHC_XFERTYP =RegValue;// Send the command.}/*********************************************************************** _HW_GetResponse** Function description* Receives the responses that was sent by the card after* a command was sent to the card.** Parameters* Unit Index of the SD / MMC host controller (0-based).* pBuffer User allocated buffer where the response is stored.* Size Size of the buffer in bytes** Return values* FS_MMC_CARD_NO_ERROR Success* FS_MMC_CARD_RESPONSE_CRC_ERROR CRC error in response* FS_MMC_CARD_RESPONSE_TIMEOUT No response received* FS_MMC_CARD_RESPONSE_GENERIC_ERROR Any other error** Notes* (1) The response data has to be stored at byte offset 1 since* the controller does not provide the first byte of response.*/staticint_HW_GetResponse(U8 Unit,void*pBuffer,U32 Size){U8 *pData;volatileU32 *pReg;U32 NumWords;U32 Value;U32 i;intr;FS_USE_PARA(Unit);r =_WaitForResponse();if(r !=FS_MMC_CARD_NO_ERROR){_Reset();returnr;// Error}//// The size we get from the upper driver is total response size in bytes.// We compute here the number of read accesses to the 32-bit register which// holds the response. Take into account that the first byte of the response// is not delivered by the hardware//NumWords =(Size -1)/4;pData =(U8 *)pBuffer;pReg =(volatileU32 *)&SDHC_CMDRSP0 +(NumWords -1);//// In case of a 136 bit response SDHC does not deliver the checksum byte.// By not incrementing the data pointer the bytes are saved at expected positions.//if(NumWords !=4){++pData;// See note (1)}for(i =0;i <NumWords;++i){Value =*pReg;*pData++=(U8)(Value >>24);*pData++=(U8)(Value >>16);*pData++=(U8)(Value >>8);*pData++=(U8)Value;--pReg;}returnFS_MMC_CARD_NO_ERROR;// OK, valid command received.}/*********************************************************************** _HW_ReadData** Function description* Reads data from the card using the SD / MMC host controller.** Return values* FS_MMC_CARD_NO_ERROR Success* FS_MMC_CARD_READ_CRC_ERROR CRC error in received data* FS_MMC_CARD_READ_TIMEOUT No data received* FS_MMC_CARD_READ_GENERIC_ERROR Any other error*/staticint_HW_ReadData(U8 Unit,void*pBuffer,unsignedNumBytes,unsignedNumBlocks){#ifFS_MMC_HW_CM_USE_DMAintr;FS_USE_PARA(Unit);FS_USE_PARA(pBuffer);FS_USE_PARA(NumBytes);FS_USE_PARA(NumBlocks);r =_WaitForEndOfDMARead();returnr;#elseU32 NumWords;U32 *pData32;U32 NumWordsAtOnce;U32 WordsPerBlock;U32 WMLRead;intr;FS_USE_PARA(Unit);pData32 =(U32 *)pBuffer;WordsPerBlock =NumBytes /4;WMLRead =_GetWMLRead();do{NumWords =WordsPerBlock;do{r =_WaitForRxReady();if(r !=FS_MMC_CARD_NO_ERROR){_Reset();returnr;// Error}NumWordsAtOnce =SEGGER_MIN(NumWords,WMLRead);NumWords -=NumWordsAtOnce;do{*pData32++=SDHC_DATPORT;}while(--NumWordsAtOnce);SDHC_IRQSTAT =1uL<<IRQSTAT_BRR_BIT;// This flag is only set by SDHC. We have to clear it here to get the next notification.}while(NumWords);}while(--NumBlocks);returnFS_MMC_CARD_NO_ERROR;// OK, data received.#endif}/*********************************************************************** _HW_WriteData** Function description* Writes the data to SD / MMC card using the SD / MMC host controller.** Return values* FS_MMC_CARD_NO_ERROR Success* FS_MMC_CARD_READ_TIMEOUT No data received*/staticint_HW_WriteData(U8 Unit,constvoid*pBuffer,unsignedNumBytes,unsignedNumBlocks){#ifFS_MMC_HW_CM_USE_DMAintr;FS_USE_PARA(Unit);FS_USE_PARA(pBuffer);FS_USE_PARA(NumBytes);FS_USE_PARA(NumBlocks);r =_WaitForEndOfDMAWrite();returnr;#elseU32 NumWords;constU32 *pData32;intr;U32 NumWordsAtOnce;U32 WordsPerBlock;U32 WMLWrite;FS_USE_PARA(Unit);pData32 =(U32 *)pBuffer;WordsPerBlock =NumBytes /4;WMLWrite =_GetWMLWrite();do{NumWords =WordsPerBlock;if(_RepeatSame){pData32 =(U32 *)pBuffer;}do{r =_WaitForTxReady();if(r !=FS_MMC_CARD_NO_ERROR){_Reset();returnr;// Error}NumWordsAtOnce =SEGGER_MIN(NumWords,WMLWrite);NumWords -=NumWordsAtOnce;do{SDHC_DATPORT =*pData32++;}while(--NumWordsAtOnce);SDHC_IRQSTAT =1uL<<IRQSTAT_BWR_BIT;// This flag is only set by SDHC. We have to clear it here to get the next notification.}while(NumWords);}while(--NumBlocks);returnFS_MMC_CARD_NO_ERROR;// OK, data sent.#endif}/*********************************************************************** _HW_SetDataPointer** Function description* Tells the hardware layer where to read data from or write data to.* Some SD host controllers require the address of the data buffer* before sending the command to the card, eg. programming the DMA.* In most cases this function can be left empty.** Parameters* Unit Index of the SD / MMC host controller (0-based).* p Data buffer.*/staticvoid_HW_SetDataPointer(U8 Unit,constvoid*p){FS_USE_PARA(Unit);#ifFS_MMC_HW_CM_USE_DMA_pData =(void*)p;// Cast const away. The same buffer is used also for read operations.#elseFS_USE_PARA(p);#endif}/*********************************************************************** _HW_SetBlockLen** Function description* Sets the block size (sector size) that has to be transferred.** Parameters* Unit Index of the SD / MMC host controller (0-based).*/staticvoid_HW_SetBlockLen(U8 Unit,U16 BlockSize){FS_USE_PARA(Unit);_BlockSize =BlockSize;}/*********************************************************************** _HW_SetNumBlocks** Function description* Sets the number of blocks (sectors) to be transferred.** Parameters* Unit Index of the SD / MMC host controller (0-based).*/staticvoid_HW_SetNumBlocks(U8 Unit,U16 NumBlocks){FS_USE_PARA(Unit);_NumBlocks =NumBlocks;}/*********************************************************************** _HW_GetMaxReadBurst** Function description* Returns the number of block (sectors) that can be read at once* with a single READ_MULTIPLE_SECTOR command.** Parameters* Unit Index of the SD / MMC host controller (0-based).** Return value* Number of sectors that can be read at once.*/staticU16 _HW_GetMaxReadBurst(U8 Unit){FS_USE_PARA(Unit);returnNUM_BLOCKS_AT_ONCE;}/*********************************************************************** _HW_GetMaxWriteBurst** Function description* Returns the number of block (sectors) that can be written at once* with a single WRITE_MULTIPLE_SECTOR command.** Parameters* Unit Index of the SD / MMC host controller (0-based).** Return value* Number of sectors that can be written at once.*/staticU16 _HW_GetMaxWriteBurst(U8 Unit){FS_USE_PARA(Unit);returnNUM_BLOCKS_AT_ONCE;}/*********************************************************************** _HW_GetMaxWriteBurstRepeat** Function description* Returns the number of block (sectors) that can be written at once* with a single WRITE_MULTIPLE_SECTOR command and that contain the* same data.** Parameters* Unit Index of the SD / MMC host controller (0-based).** Return value* Number of sectors that can be written at once. The function has* to return 0 if the feature is not supported.*/staticU16 _HW_GetMaxWriteBurstRepeat(U8 Unit){FS_USE_PARA(Unit);returnNUM_BLOCKS_AT_ONCE_REPEAT_SAME;}/*********************************************************************** Public code************************************************************************/#ifFS_MMC_HW_CM_USE_OS/*********************************************************************** SDHC_IRQHandler*/voidSDHC_IRQHandler(void);voidSDHC_IRQHandler(void){OS_EnterInterrupt();SDHC_IRQSIGEN &=~STAT_MASK;// Disable interrupts.#if(FS_MMC_HW_CM_USE_OS ==2)OS_EVENT_Set(&_Event);#elseFS_OS_Signal();#endif// FS_MMC_HW_CM_USE_OS == 2OS_LeaveInterrupt();}#endif// FS_MMC_HW_CM_USE_OS/*********************************************************************** FS_MMC_HW_CM_K66_SEGGER_emPower*/constFS_MMC_HW_TYPE_CMFS_MMC_HW_CM_K66_SEGGER_emPower ={_HW_Init,_HW_Delay,_HW_IsPresent,_HW_IsWriteProtected,_HW_SetMaxSpeed,_HW_SetResponseTimeOut,_HW_SetReadDataTimeOut,_HW_SendCmd,_HW_GetResponse,_HW_ReadData,_HW_WriteData,_HW_SetDataPointer,_HW_SetBlockLen,_HW_SetNumBlocks,_HW_GetMaxReadBurst,_HW_GetMaxWriteBurst,_HW_GetMaxWriteBurstRepeat,NULL,NULL,NULL,NULL,NULL,NULL,NULL,NULL};/*************************** End of file ****************************/
Troubleshooting
If the driver test fails or if the card cannot be accessed at all, please follow
the trouble shooting guidelines below.
SPI mode troubleshooting guide
First, verify the SPI configuration. The SPI data transfer has to be configured as follows:
8 bits per transfer.
Most significant bit first.
Data changes on falling edge.
Data is sampled on rising edge.
Then verify the waveform of the SPI signals using an oscilloscope. The following
reference images were taken with an oscilloscope that was set up to trigger
a single time on falling edge of Chip Select (CS) signal. The color coding of the
signals in these pictures is as follows:
Color
Description
RED
MOSI - Master Out Slave In (Pin 2)
PURPLE
MISO - Master In Slave Out (Pin 7)
GREEN
CLK - Clock (Pin 5)
YELLOW
CS - Chip Select (Pin 1)
To check if your implementation of the hardware layer works correct, compare your
output of the relevant lines (SCLK, CS, MISO, MOSI) with the correct output which is
shown in the following pictures. The output of your card should be similar.
In the example, MISO has a pull-up and a pull-down of equal value. This means that
the MISO signal level is at 50% (1.65V) when the output of the card is inactive. On
other target hardware, the inactive level can be low (in case a pull-down is used) or
high (if a pull-up is used).
The initial communication sequence consists of the following three parts:
Outputs 10 dummy bytes with CS disabled, MOSI = 1.
Sets CS low and send a 6-byte command ( GO_IDLE_STATE command).
Receives two bytes, sets CS high and outputs 1 dummy byte with CS disabled,MOSI = 1.
The following picture shows the data flow of a correct initialization of an SD card.
After sending 8 dummy bytes to the card, CS is activated and the GO_IDLE_STATE
command is sent to the card. The first byte is 0x40 or b01000000. You can see (and
should verify) that MOSI changes on the falling edge of CLK. The GO_IDLE_STATE
command is the reset command. It sets the card into idle state regardless of the
current card state.
The card responses to a command with two bytes. The SD Card Association defines
that the first byte of the response should always be ignored. The second byte is the
answer from the card. The answer to GO_IDLE_STATE command should be 0x01. This
means that the card is in idle state.
If the card does not return 0x01 then check initialization sequence of your
hardware. At the end of the command sequence the CS signal has to be deselected
that is the signal has to be set to logic high.
Test hardware
The SEGGER SD Card Adapter is an easy to use measurement board that can be used
to troubleshoot problems related to interfacing emFile with MMC and SD cards
in SPI as well as card mode.
The adapter board is shaped in the form of an SD card on one side so that it
can be directly inserted into any SD card slot. The pads on the same side of
the board provide mechanical contact with the signals of SD card slot of the
target hardware. The signals are routed on the adapter board to an SD card
socket mounted on it where the SD card can be inserted. All the signals are
connected to a header where they can be easily captured using an oscilloscope
probe. Another header is provided for GND signals.
The picture below shows the schematic of the adapter board.
CompactFlash card and IDE driver
General information
emFile supports the use of CompactFlash (CF) cards and IDE devices as storage device.
Both types of storage devices share a common interface and are supported by the CF/IDE driver
that is able to operate in different modes specified by this interface. The access to the
hardware is realized via a set of I/O routines called CF/IDE hardware layer.
For details on CompactFlash cards check the specification which is available
at: http://www.compactflash.org/
Information about the AT Attachment interface can be found at the Technical
Committee T13 that is responsible for the ATA standard: http://www.t13.org/
Fail-safe operation
The data will be preserved in case of an unexpected reset but a power failure
can be critical. If the card does not have sufficient time to complete a write
operation, data may be lost. As a countermeasure the hardware has to make sure
that the power supply to the device drops slowly.
Wear-leveling
CF cards and IDE devices have an internal controller, that is responsible for
performing the wear-leveling. Therefore, the CF/IDE driver does not need to
handle wear-leveling.
Supported hardware
The CF/IDE driver can be used to access most ATA HD drives and CF cards
using the True IDE or Memory card mode.
Pin description - True IDE mode
The following table describes the signals used in True IDE mode.
Signal name
Dir
Pin
Description
A2-A0
I
18, 19, 20
Only A[2:0] are used to select one of eight registers in the Task File, the remaining address lines should be grounded by the host.
PDIAG
I/O
46
This input / output is the Pass Diagnostic signal in the Master / Slave handshake protocol.
DASP
I/O
45
This input/output is the Disk Active/Slave Present signal in the Master/Slave handshake protocol.
CD1, CD2
O
26, 25
These Card Detect pins are connected to ground on the CompactFlash Storage Card or CF+ Card. They are used by the host to determine that the CompactFlash Storage Card or CF+ Card is fully inserted into its socket.
CS0, CS1
I
7, 32
CS0 is the chip select for the task file registers while CS1 is used to select the Alternate Status Register and the Device Control Register.
CSEL
I
39
This internally pulled up signal is used to configure this device as a Master or a Slave when configured in True IDE Mode. When this pin is grounded, the device is configured as a Master. When the pin is open, the device is configured as a Slave.
D15 - D00
I/O
27 - 31
47 - 49
2 - 6
21 - 23
All Task File operations occur in byte mode on the low order bus D00-D07 while all data transfers are 16 bit using D00-D15.
GND
--
1, 5
Ground.
IORD
I
34
This is an I/O Read strobe generated by the host. This signal gates I/O data onto the bus from the CompactFlash Storage Card or CF+ Card when the card is configured to use the I/O interface.
IOWR
I
35
I/O Write strobe pulse is used to clock I/O data on the Card Data bus into the CompactFlash Storage Card or CF+ Card controller registers when the CompactFlash Storage Card or CF+ Card is configured to use the I/O interface. The clocking will occur on negative to positive edge of the signal (trailing edge).
OE (ATA SEL)
I
9
To enable True IDE Mode this input should be grounded by the host.
INTRQ
O
37
Signal is the active high interrupt request to the host.
REG
I
44
This input signal is not used and should be connected to VCC by the host.
RESET
I
41
This input pin is the active low hardware reset from the host.
VCC
--
13, 38
+5V, +3.3V power.
VS1, VS2
O
33, 4
Voltage Sense Signals. -VS1 is grounded so that the CompactFlash Storage Card or CF+ Card CIS can be read at 3.3 volts and -VS2 is reserved by PCMCIA for a secondary voltage.
IORDY
O
42
This output signal may be used as IORDY
WE
I
36
This input signal is not used and should be connected to VCC by the host.
IOIS16
O
24
This output signal is asserted low when the device is expecting a word data transfer cycle.
Pin description - Memory card mode
The following table describes the signals used in Memory card mode.
Signal name
Dir
Pin
Description
A10 - A0
I
8, 10, 11,
12, 14, 15,
16, 17, 18,
19, 20
These address lines along with the -REG signal are used to select the following: the I/O port address registers within the CompactFlash Storage Card or CF+ Card, the memory mapped port address registers within the CompactFlash Storage Card or CF+ Card, a byte in the card’s information structure and its configuration control and status registers.
BVD1
I/O
46
This signal is asserted high, as BVD1 is not supported.
BVD2
I/O
45
This signal is asserted high, as BVD2 is not supported.
CD1, CD2
O
26, 25
These Card Detect pins are connected to ground on the CompactFlash Storage Card or CF+ Card. They are used by the host to determine that the CompactFlash Storage Card or CF+ Card is fully inserted into its socket.
CE1, CE2
I
7, 32
These input signals are used both to select the card and to indicate to the card whether a byte or a word operation is being performed. -CE2 always accesses the odd byte of the word. We recommend connecting these pins together.
CSEL
I
39
This signal is not used for this mode, but should be grounded by the host.
D15 - D00
I/O
27 - 31
47 - 49
2 - 6
21 - 23
These lines carry the Data, Commands and Status information between the host and the controller. D00 is the LSB of the Even Byte of the Word. D08 is the LSB of the Odd Byte of the Word.
GND
--
1, 5
Ground.
INPACK
O
43
This signal is not used in this mode.
IORD
I
34
This signal is not used in this mode.
IOWR
I
35
This signal is not used in this mode.
OE (ATA SEL)
I
9
This is an Output Enable strobe generated by the host interface. It is used to read data from the CompactFlash Storage Card or CF+ Card in Memory Mode and to read the CIS and configuration registers.
READY
O
37
In Memory Mode, this signal is set high when the CompactFlash Storage Card or CF+ Card is ready to accept a new data transfer operation and is held low when the card is busy. At power up and at Reset, the READY signal is held low (busy) until the CompactFlash Storage Card or CF+ Card has completed its power up or reset function. No access of any type should be made to the CompactFlash Storage Card or CF+ Card during this time.Note, however, that when a card is powered up and used with +RESET continuously disconnected or asserted, the reset function of this pin is disabled and consequently the continuous assertion of +RESET will not cause the READY signal to remain continuously in the busy state.
REG
I
44
This signal is used during Memory Cycles to distinguish between Common Memory and Register (Attribute) Memory accesses. High for Common Memory, Low for Attribute Memory. To use it with emFile, this signal should be high.
RESET
I
41
When the pin is high, this signal Resets the CompactFlash Storage Card or CF+ Card. The CompactFlash Storage Card or CF+ Card is reset only at power up if this pin is left high or open from power up.
VCC
--
13, 38
+5 V, +3.3 V power.
VS1, VS2
O
33, 4
Voltage Sense Signals. -VS1 is grounded so that the CompactFlash Storage Card or CF+ Card CIS can be read at 3.3 volts and -VS2 is reserved by PCMCIA for a secondary voltage.
WAIT
O
42
The -WAIT signal is driven low by the CompactFlash Storage Card or CF+ Card to signal the host to delay completion of a memory or I/O cycle that is in progress.
WE
I
36
This is a signal driven by the host and used for strobing memory write data to the registers of the CompactFlash Storage Card or CF+ Card when the card is configured in the memory interface mode.
WP
O
24
The CompactFlash Storage Card or CF+ Card does not have a write protect switch. This signal is held low after the completion of the reset initialization sequence.
Theory of operation
CompactFlash card
A CF card is a mechanically small, removable mass storage device. It contains
a single chip controller and one or more flash memory modules in a matchbox-sized
package with a 50-pin connector consisting of two rows of 25 female contacts each
on 50 mil (1.27 mm) centers. The controller interfaces with a host system allowing
data to be written to and read from the flash memory modules.
There are two different Compact Flash Types, namely CF Type I and CF Type II.
The only difference between CF Type I and CF Type II cards is the card thickness.
CF Type I is 3.3 mm thick and CF Type II cards are 5mm thick. A CF Type I card will
operate in a CF Type I or CF Type II slot. A CF Type II card will only fit in a CF Type II
slot. The electrical interfaces are identical. CompactFlash is available in both CF Type
I and CF Type II cards, though predominantly in CF Type I cards. The Microdrive is a
CF Type II card. Most CF I/O cards are CF Type I, but there are some CF Type II I/O
cards.
CF cards are designed with flash technology, a nonvolatile storage solution that
does not require a battery to retain data indefinitely. The CF card specification
version 2.0 supports data rates up to 16MB/sec and capacities up to 137GB.
CF cards consume only five percent of the power required by small disk drives.
CompactFlash cards support both 3.3V and 5V operation and can be interchanged
between 3.3V and 5V systems. This means that any CF card can operate at either
voltage. Other small form factor flash cards may be available to operate at 3.3V
or 5V, but any single card can operate at only one of the voltages.
CF+ data storage cards are also available using magnetic disk (IBM Microdrive).
CF cards can operate in three modes:
Memory card mode
I/O Card mode
True IDE mode
Currently, only the True IDE and Memory card mode are supported by the CD/IDE driver.
IDE (ATA) Drives
Just like Compact Flash cards, ATA drives have a built-in controller to drive
and control the mechanical hardware. There are two types of connecting ATA drives.
5.25 and 3.5 inch drives are using a 40 pin male interface to connect to an IDE
controller. 2.5 and 1.8 inch drives, mostly used in Notebooks and embedded
systems, have a 50 pin male interface.
IDE ATA drives can operate in three different modes:
PIO (Programmed I/O)
Multiword DMA
Ultra DMA
Currently, the CF/IDE driver supports only PIO mode via True IDE.
Configuring the driver
This section describes how to configure the file system to make use of the CF/IDE driver.
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_IDE_Driver structure. 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.
#include"FS.h"#include"FS_IDE_HW_TrueIDE_Template.h"#defineALLOC_SIZE 0x800// Size defined in bytesstaticU32 _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().*/voidFS_X_AddDevices(void){//// Give the file system memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Add and configure the CF/IDE driver in master mode.//FS_AddDevice(&FS_IDE_Driver);FS_IDE_Configure(0,0);FS_IDE_SetHWType(0,&FS_IDE_HW_TrueIDE_Template);}
The API functions listed in the next table can be used by the application to
configure the behavior of the CF/IDE driver. The application can call
them only at the file system initialization in FS_X_AddDevices().
This function is optional. The application has to call this function only
when the device does not use the default IDE master/slave configuration.
By default, all even-numbered units (0, 2, 4…) work in master mode,
while all odd-numbered units work in slave mode.
FS_IDE_Configure function has to be called from FS_X_AddDevices() and
it can be called before or after adding the device driver to the file
system.
Example
The following example demonstrates how to configure two different CF cards
or IDE devices:
#include"FS.h"#include"FS_IDE_HW_TrueIDE_Template.h"#defineALLOC_SIZE 0x800// Size defined in bytesstaticU32 _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().*/voidFS_X_AddDevices(void){FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Add and configure the first driver.// The device works as master on the IDE bus. Volume name: "ide:0:"//FS_AddDevice(&FS_IDE_Driver);FS_IDE_Configure(0,0);FS_IDE_SetHWType(0,&FS_IDE_HW_TrueIDE_Template);//// Add and configure the second driver.// The device works also as master on the IDE bus. Volume name: "ide:1:"//FS_AddDevice(&FS_IDE_Driver);FS_IDE_Configure(1,0);FS_IDE_SetHWType(1,&FS_IDE_HW_TrueIDE_Template);}
This function is mandatory. The FS_IDE_HW_Default hardware layer
is provided to help the porting to the new hardware layer API.
This hardware layer contains pointers to the public functions used
by the device driver to access the hardware in the version 3.x of emFile.
Configure FS_IDE_HW_Default as hardware layer if you do not want
to port your existing hardware layer to the new hardware layer API.
The CF/IDE hardware layer provides the functions to access the target hardware
(IDE controller, GPIO, etc.). They have to be implemented by the user since they
are hardware dependent. emFile comes with template hardware layers and some
sample implementations for popular evaluation boards. These files can be found in
the Sample/FS/Driver/IDE folder of the emFile shipment. The functions
are organized in a function table which is a structure of type FS_IDE_HW_TYPE.
Hardware layer API - FS_IDE_HW_TYPE
This hardware layer supports all CF cards and IDE devices. The following sections
describe the functions of this hardware layer in detail.
This function is a member of the CF/IDE hardware layer.
All hardware layers are required to implement this function.
This function is called when the driver detects a new storage device.
For ATA HD drives, there is no action required and this function
can be left empty.
This function is a member of the CF/IDE hardware layer.
All hardware layers are required to implement this function.
The function is always called when a command is sent or parameters
are set in the CF card or IDE device to give the integrated logic
time to finish a command. When using slow CF cards or IDE devices
with fast processors this function should guarantee that a delay of 400ns
is respected. However, this function may be left empty if you fast devices
are used (modern CF-Cards and IDE drives are faster than 400ns when
executing commands.)
This function is a member of the CF/IDE hardware layer.
All hardware layers are required to implement this function.
RegOff is always a multiple of two value because the IDE
driver always reads two 8-bit registers at a time.
The value of the register at the offset RegOff must be stored
in the low-order byte of the return value while the value
of the register at RegOff + 1 in the high-order byte.
This function is a member of the CF/IDE hardware layer.
All hardware layers are required to implement this function.
RegOff is always a multiple of two value because the IDE
driver always writes two 8-bit registers at a time.
The value of the register at the offset RegOff is stored
in the low-order byte of Data while the value of the register
at the offset RegOff + 1 in the high-order byte of Data.
This function is a member of the CF/IDE hardware layer.
All hardware layers are required to implement this function.
pData is always 16-bit aligned in order to enable the writing of
two bytes at a time. For the same reason, NumBytes is always
a multiple of two value.
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 IDE/CF driver were measured as described in the section
Test procedure.
Usage: 1.6 Kbytes
Static RAM usage
Static RAM usage is the amount of RAM required by the driver for variables inside
the driver. The number of bytes can be seen in a compiler list file.
Usage: 24 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.
Usage: 18 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 were performed as described in the section
Performance.
All values are given in Mbytes/sec.
CPU type
Storage device
Write speed
Read speed
LogicPD H79520 (51 MHz)
IDE memory-mapped
1.4
1.7
Cogent EP7312 (74 MHz)
CompacFlash card, True IDE mode
1.9
2.5
Cogent EP7312 (74 MHz)
HDD, True IDE mode
1.7
2.4
Windows Drive driver
This driver can be used to access to access the data stored on any drive
of a Windows operating system via the emFile API functions.
Typical usage includes testing and evaluation emFile before deployment
on a target hardware. The Windows Drive driver is also able to use a regular
file stored on the file system of the Windows PC as storage.
Supported hardware
The Windows Drive driver is compatible with any Windows operating system version newer
as Windows 98. Older Windows version not supported, because they do not provide
access to a Windows drive via the API functions. Windows drives formatted as NTFS
are not supported.
Theory of operation
The driver works by reading and writing entire logical sectors. The size of
a logical sector can be specified at compile time via FS_WINDRIVE_SECTOR_SIZE
or at runtime via FS_WINDRIVE_SetGeometry(). The size of the logical sector
has to match the size of the logical sector used by the Windows drive. Any
logical sector size can be used if the Windows Drive driver is configured to use
a regular file as storage. On some Windows systems, administrator privileges
are required to access a Windows drive. The Windows Drive driver reports an error
if the user does not have the required privileges.
Note
Do not use this driver on partitions containing important data.
Windows Drive driver is primarily meant to be used for evaluation purposes.
Problems may occur if the program using emFile is debugged or terminated
unexpectedly using the Windows Task Manager.
Fail-safe operation
The driver is not designed to be used on a target hardware therefore the fail-safe
operation is not relevant. However, the fail-safe operation is generally guaranteed
because it is handled by the underlying operating system and hardware.
Wear-leveling
The driver does not perform any wear leveling. The wear leveling is handled
by the storage device.
Configuring the Windows Drive driver
Compile time configuration
The configuration at compile time 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 Windows Drive driver does not require any hardware access functions.
The following table lists the configuration defines supported by the Windows
Drive driver.
This define specifies the default size of the logical sector when the driver
is configured to use a regular file as storage. This value can be modified
at runtime via FS_WINDRIVE_SetGeometry()
FS_WINDRIVE_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
from the memory pool assigned to file system.
Runtime configuration
The driver can be added to the file system by calling FS_AddDevice() with the
driver label FS_WINDRIVE_Driver. This function call together with other function
calls that configure the driver operation has to be added to FS_X_AddDevices()
as demonstrated in the following example.
Example
#include"FS.h"#defineFS_ALLOC_SIZE 0x1000// Memory pool for the file system in bytesstaticU32 _aMemBlock[FS_ALLOC_SIZE /4];// Memory pool used for semi-dynamic allocation.voidFS_X_AddDevices(void){FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));#ifdef_WIN32//// Add and configure the driver to access the Windows drive with the letter 'E'.//FS_AddDevice(&FS_WINDRIVE_Driver);FS_WINDRIVE_Configure(0,"\\\\.\\E:");#endif// _WIN32#ifFS_SUPPORT_FILE_BUFFER//// Enable the file buffer to increase the performance // when reading and 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 Windows Drive driver. The application can call
them only at the file system initialization in FS_X_AddDevices().
Specifies the permission status. 1 Using a regular file is permitted. 0 Using a regular file is not permitted.
Return value
= 0
OK, file storage configured successfully.
≠ 0
Error code indicating the failure reason.
Additional information
This is an optional function can be used to specify if the
driver instance is allowed to use a regular file as data storage.
By default, a driver instance is allowed to use a Windows drive
as well as a regular file as storage.
If the function is called with OnOff set to 0 then the driver
instance is permitted to access the data stored to regular files.
in Name of the Windows drive or of the image file to be used as storage. Can be NULL.
Additional information
Either FS_WINDRIVE_Configure() or FS_WINDRIVE_ConfigureEx()
has to be called once for each instance of the WINDRIVE driver.
sName is a 0-terminated wide char string that stores the path
to the Windows drive or to the image file to be used as storage.
If sName is set to NULL the driver shows a dialog box that
allows the user to select a specific drive from a list a list
of available Windows drives. If sName is a path to a regular
file that file has to exists before FS_WINDRIVE_ConfigureEx()
is called. Selecting a Windows drive as storage requires
administrator privileges. The file system reports an error
to the application if this is not the case and the application
will not be able to access the to use the Windows drive as storage.
The size of the logical sector used by the WinDrive driver
can be configured at compile time via FS_WINDRIVE_SECTOR_SIZE
or at runtime via FS_WINDRIVE_SetGeometry().
in Name of the Windows drive or of the image file to be used as storage. Can be NULL.
Additional information
This function performs the same operation as FS_WINDRIVE_Configure()
with the difference that sName is a pointer to a 0-terminated
string containing wide characters. FS_WINDRIVE_ConfigureEx() has
to be used when the path to the Windows drive or image file
can contain non-ASCII characters.
sName has to point to 0-terminated string containing wide characters.
A string literal can be declared in C by prefixing it with
the ’L’ character. For example the path to the drive with the
letter ’E’ can be specified as L“\\\\.\\E:”
If sName is set to NULL the driver shows a dialog box that
allows the user to select a specific drive from a list a list
of available Windows drives. If sName is a path to a regular
file that file has to exists before FS_WINDRIVE_ConfigureEx()
is called. Selecting a Windows drive as storage requires
administrator privileges. The file system reports an error
to the application if this is not the case and the application
will not be able to access the to use the Windows drive as storage.
The size of the logical sector used by the WINDRIVE driver
can be configured at compile time via FS_WINDRIVE_SECTOR_SIZE
or at runtime via FS_WINDRIVE_SetGeometry().
Example
#include"FS.h"#defineFS_ALLOC_SIZE 0x1000// Memory pool for the file system in bytesstaticU32 _aMemBlock[FS_ALLOC_SIZE /4];// Memory pool used for semi-dynamic allocation.voidFS_X_AddDevices(void){FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));#ifdef_WIN32//// Add and configure the driver to access the Windows drive with// the letter 'E' assigned to it.//FS_AddDevice(&FS_WINDRIVE_Driver);FS_WINDRIVE_ConfigureEx(0,L"\\\\.\\E:");#endif// _WIN32#ifFS_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}
Number of bytes in a logical sector. Has to be a power of 2 value.
NumSectors
Number of logical sectors that can be stored to the image file.
Return value
= 0
OK, parameters set.
≠ 0
Error code indicating the failure reason.
Additional information
This function is optional. When not called the driver uses the
sector size configured via FS_WINDRIVE_SECTOR_SIZE. The number of
sectors is calculated by dividing the size of the image file to
FS_WINDRIVE_SECTOR_SIZE. This implies that by default the driver
fails to initialize if the image file is missing.
Calling FS_WINDRIVE_SetGeometry() changes the behavior of the
driver during initialization in that the driver will try to
create the image file if missing. In addition, if an image file
is present the driver checks verifies if the size of the image
file matches the size configured via FS_WINDRIVE_SetGeometry()
and if not it recreates the image file.
The size of the image file in bytes is NumSectors * BytesPerSector.
Image files larger than or equal to 4 Gbytes are not supported.
Example
#include"FS.h"#defineFS_ALLOC_SIZE 0x1000// Memory pool for the file system in bytes#defineBYTES_PER_SECTOR 512// Logical sector size in bytes#defineNUM_SECTORS 1024// Number of logical sectorsstaticU32 _aMemBlock[FS_ALLOC_SIZE /4];// Memory pool used for semi-dynamic allocation.voidFS_X_AddDevices(void){FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));#ifdef_WIN32//// Add and configure the driver to use a regular file as storage.//FS_AddDevice(&FS_WINDRIVE_Driver);FS_WINDRIVE_Configure(0,"C:\\Temp\\WinDrive.bin");FS_WINDRIVE_SetGeometry(0,BYTES_PER_SECTOR,NUM_SECTORS);#endif// _WIN32#ifFS_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}
File Disk driver
This driver uses as storage a regular file located on the host file system.
Typical usage includes testing and evaluation emFile before deployment
on a target hardware.
Supported hardware
The File Disk driver is compatible with any Windows or Linux operating system.
Theory of operation
The driver works by reading and writing entire logical sectors. The size of
a logical sector as well as the number of logical sectors can be specified
at runtime time via FS_FILEDISK_Configure(). Any logical sector size is supported.
The file used as storage is automatically created if it does not exist.
If the file already exists then the size of the file is truncated to the
size configured via FS_FILEDISK_Configure().
Fail-safe operation
The File Disk driver is not designed to be used on a target hardware therefore the fail-safe
operation is not relevant. However, the fail-safe operation is generally guaranteed
because it is handled by the underlying operating system and hardware.
Wear-leveling
The File Disk driver does not perform any wear leveling. The wear leveling is handled
by the underlying operating system and hardware.
Configuring the File Disk driver
Compile time configuration
The configuration at compile time is done via preprocessor defines that have
to be added to the FS_Conf.h file the 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 File Disk driver does not require any hardware access functions.
The following table lists the configuration defines supported by the File Disk driver.
Size of the working buffer used for the access to storage device.
FS_FILEDISK_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
from the memory pool assigned to file system.
FS_FILEDISK_SUPPORT_TRIM
FS_FILEDISK_SUPPORT_TRIM can be used to enable or disable the handling of file
system operations that inform the File Disk driver about logical sectors that
are no longer in use. This functionality is optional and not required for the
correct operation of the File Disk driver. The Storage Image Creator utility
uses this functionality for implementation of the exportimage command.
The information about the usage of the logical sectors is stored to a separate
status file located in the same directory as the data file used for the storage of the file
system data. The name of the status file is created by appending the “.sta” file extension
to the name of the data file.
FS_FILEDISK_WORK_BUFFER_SIZE
FS_FILEDISK_WORK_BUFFER_SIZE is the size of all the working buffers that the
File Disk driver for operations that access the storage device such as changing
the usage status if logical sectors. These buffers are allocated on the stack.
Increasing the buffer size can help improve the performance of the driver.
Runtime configuration
The driver can be added to the file system by calling FS_AddDevice() with the
driver label FS_FILEDISK_Driver. This function call together with other function
calls that configure the driver operation has to be added to FS_X_AddDevices()
as demonstrated in the following example.
Example
#include"FS.h"#defineFS_ALLOC_SIZE 0x1000// Memory pool for the file system in bytes.staticU32 _aMemBlock[FS_ALLOC_SIZE /4];// Memory pool used for semi-dynamic allocation.voidFS_X_AddDevices(void){FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));#ifdef_WIN32//// Add and configure the driver to use the "FileDisk.bin" as storage.// The total capacity of the storage device is 512 * 1024 = 512 KB//FS_AddDevice(&FS_FILEDISK_Driver);FS_FILEDISK_Configure(0,"FileDisk.bin",512,1024);#endif// _WIN32#ifFS_SUPPORT_FILE_BUFFER//// Enable the file buffer to increase the performance // when reading and 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 File Disk driver. The application can call
these functions only at the file system initialization in FS_X_AddDevices().
FS_FILEDISK_Configure() has to be called once for each instance
of the File Disk driver. The application is allowed to call this
function only at file system initialization in FS_X_AddDevices().
sFileName is a 0-terminated character string that stores the path
to the file to be used as storage. A copy of this path is stored
to the driver instance.
If BytesPerSector is set to 0 then the File Disk driver uses the
the maximum logical sector size configured for the file system.
By default, the maximum logical sector size is set to 512 bytes.
This value can be modified via FS_SetMaxSectorSize().
If the file used as storage does not exist then the file is created
when the driver is initialized. The size of the created file is calculated
as BytesPerSector * NumSectors.
If the file used as storage exists and NumSectors is different than
0 then the size of the file is set to BytesPerSector * NumSectors.
If the file used as storage exists and NumSectors is set to 0 then
the actual number of sectors is calculated based on the size of the
file used as storage.
Size of the logical sector used by the driver in bytes.
sFileName
Name of the file that is used as storage.
Logical drivers
This chapter describes the file system components that provide block processing.
General information
A logical driver is a file system component that provides block processing of
the data exchanged between the Storage layer and the storage device such as
partitioning and encryption. It implements the same interface as a device driver
but in contrast to a device driver it does not access any storage device.
Instead, the requests received from the Storage layer are processed internally
and then forwarded to either another logical driver or to a device driver to
perform the data access.
The following table lists the available logical drivers.
A logical driver has to be added to the file system in the same way as a device driver.
To add a logical driver to emFile, FS_AddDevice() has to be called with the address
of the corresponding driver identifier as parameter. For more information about the
usage of the names listed in the “Volume name” column refer to
General information
Disk Partition driver
This logical driver can be used to access storage device partitions as defined by
Master Boot Record (MBR) or GUID Partition Table (GPT). Typically, the partitioning
information is stored in the first logical sectors of a storage device.
Master Boot Record
A MBR contains information about how the storage device is divided and an optional machine
code for bootstrapping PC-compatible computers. This information is always stored on the
first logical sector of the storage device. The partitioning information is organized
in a table that contains four entries of 16 bytes. Each entry stores the following
information about the partition:
Offset (bytes)
Size (byte)
Description
0
1
Partition status:
0x80 - bootable
0x00 - non-bootable
Any other value is invalid.
1
3
First sector in the partition as cylinder/head/sector address.
4
1
Partition type.
5
3
Last sector in the partition as cylinder/head/sector address.
8
4
First sector in the partition as logical block address.
12
4
Number of sectors in the partition.
The driver uses only the information stored in a valid partition table entry. Invalid
partition table entries are ignored. The position and the size of the partition are
taken from the last two fields in the entry. The cylinder, head and sector information
as well as the partition type are also ignored.
A separate volume is assigned to each driver instance. The volumes can be accessed
using the following names: “diskpart:0:”, “diskpart:1:”, “diskpart:2:” and “diskpart:3:”.
Note
This logical driver is not required if an application has to access only the
first storage device partition, as emFile uses this partition by default.
Configuring the driver
Runtime configuration
To add the driver, use FS_AddDevice() with the driver identifier set to
FS_DISKPART_Driver. This function has to be called from within FS_X_AddDevices().
Refer to FS_X_AddDevices() for more information. The following table lists the
API functions that can be called by the application to configure the driver.
Type of device driver that is used to access the storage device.
DeviceUnit
Index of the device driver instance that is used to access the storage device (0-based).
PartIndex
Index of the partition in the partition table stored in MBR.
Additional information
This function has to be called once for each instance of the driver.
The application can use FS_DISKPART_Configure() to set the parameters
that allows the driver to access the partition table stored in
Master Boot Record (MBR). The size and the position of the partition
are read from MBR on the first access to storage device.
Example
This example demonstrates how to configure the file system to access the first
two MBR partitions of an SD card.
#include"FS.h"#defineALLOC_SIZE 2048// Size of emFile memory poolstaticU32 _aMemBlock[ALLOC_SIZE /4];/*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){U8 DeviceUnit;U8 PartIndex;U8 Unit;FS_AssignMemory(_aMemBlock,sizeof(_aMemBlock));//// Add SD/MMC card device driver.//DeviceUnit =0;FS_AddPhysDevice(&FS_MMC_CM_Driver);//// Configure logical driver to access the first MBR partition.// Partition will be mounted as volume "diskpart:0:".//PartIndex =0;Unit =0;FS_AddDevice(&FS_DISKPART_Driver);FS_DISKPART_Configure(Unit,&FS_MMC_CM_Driver,DeviceUnit,PartIndex);//// Configure logical driver to access the second MBR partition.// Partition will be mounted as volume "diskpart:1:".//PartIndex =1;Unit =1;FS_AddDevice(&FS_DISKPART_Driver);FS_DISKPART_Configure(Unit,&FS_MMC_CM_Driver,DeviceUnit,PartIndex);}
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 driver presented in the tables below were
measured as described in the section
Test procedure.
Usage: 1.5 Kbytes
Static RAM usage
Static RAM usage is the amount of RAM required by the driver for variables inside of
the driver. The number of bytes can be seen in the compiler list file.
Usage: 20 bytes
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the driver at runtime.
Usage: 18 bytes
Encryption driver
The Encryption driver is a logical driver that can be used to protect the file system data
against an unauthorized accesses. This is done by encrypting the data before writing it to the
storage device using an encryption algorithm and a key specified by the application.
emFile comes with a very efficient implementation of the Data Encryption Standard (DES)
and of the Advanced Encryption Standard (AES) algorithms. The AES algorithm supports 128-bit
and 256-bit key lengths.
The logical driver can be used with both the FAT and EFS file systems and with any storage device.
A separate volume is assigned to each driver instance. The volumes can be accessed
using the following names: “crypt:0:”, “crypt:1:”, etc.
Theory of operation
The sector data is transformed to make it unreadable for anyone who tries to read it
directly. The operation which makes the data unreadable is called encryption and is
performed when the file system writes the sector data. When the contents of a sector
is read, the reversed operation is applied that makes the data readable again.
This is operation called decryption. Both operations use a cryptographic algorithm
and a key for data transformation. The same key is used for encryption and decryption.
Without the knowledge of the key it is not possible to decrypt the data.
Configuring the driver
Compile time configuration
The next table lists the available configuration defines followed
by a detailed description of them. The configuration defines have to
be added to the FS_Conf.h file that 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
This define specifies the maximum number of driver instances
an application is allowed create. Four bytes of static RAM are
reserved for each driver instance. If the maximum number of driver
instances is smaller than the default then FS_CRYPT_NUM_UNITS
can be set to the to that value in order to reduce the RAM usage.
Runtime configuration
To add the driver, call FS_AddDevice() with the driver identifier set to
FS_CRYPT_Driver. This function has to be called from within FS_X_AddDevices().
Refer to FS_X_AddDevices() for more information. The following table lists the
API functions that can be called by the application to configure the driver.
Number of device to access the storage medium (0-based).
pAlgoType
in The type of encryption algorithm.
pContext
in Data specific to cryptographic algorithm.
pKey
in Password for data encryption/decryption.
Additional information
This function has to be called once for each driver instance.
pAlgoType is a pointer to one of the following structures:
Algorithm type
Description
FS_CRYPT_ALGO_DES
Data Encryption Standard with 56-bit key length
FS_CRYPT_ALGO_AES128
Advanced Encryption Standard with 128-bit key length
FS_CRYPT_ALGO_AES256
Advanced Encryption Standard with 256-bit key length
pContext is passed to as parameter to the encryption and decryption routines via
pContext. The memory region pContext points to has to remain valid from the
moment the driver is configured until the FS_DeInit() function is called.
The number of bytes in pKey array has to match the size of the key required
by the used cryptographic algorithm as follows:
Algorithm type
Size in bytes
FS_CRYPT_ALGO_DES
8
FS_CRYPT_ALGO_AES128
16
FS_CRYPT_ALGO_AES256
32
Example
#include"FS.h"#defineALLOC_SIZE 2048// Size of emFile memory poolstaticU32 _aMemBlock[ALLOC_SIZE /4];staticFS_AES_CONTEXT _Context;/*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){U8 DeviceUnit;U8 Unit;U8 aPass[16]={'s','e','c','r','e','t'};FS_AssignMemory(_aMemBlock,sizeof(_aMemBlock));//// Add SD/MMC card device driver.//DeviceUnit =0;FS_AddPhysDevice(&FS_MMC_CM_Driver);FS_MMC_CM_Allow4bitMode(DeviceUnit,1);//// Add the encryption driver. The storage can be accessed as volume "crypt:0:".//Unit =0;FS_AddDevice(&FS_CRYPT_Driver);FS_CRYPT_Configure(Unit,&FS_MMC_CM_Driver,DeviceUnit,&FS_CRYPT_ALGO_AES128,&_Context,aPass);}
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 driver presented in the tables below were measured
as described in the section
Test procedure.
Usage: 1.3 Kbytes
In addition, one of the following cryptographic algorithms is required:
Physical layer
Description
ROM [Kbytes]
FS_CRYPT_ALGO_DES
DES encryption algorithm.
3.2
FS_CRYPT_ALGO_AES128
AES encryption algorithm using an 128-bit key.
12.0
FS_CRYPT_ALGO_AES256
AES encryption algorithm using a 256-bit key.
12.0
Static RAM usage
Static RAM usage is the amount of RAM required by the driver for variables inside of
the driver. The number of bytes can be seen in a compiler list file.
Usage: 24 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 on the selected encryption algorithm.
Every driver instance requires 16 bytes of RAM. In addition, the context
of the AES encryption algorithm requires 480 bytes and that of the DES
encryption algorithm 128 bytes of RAM.
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 KB/second.
CPU type
Storage device
Encryption algorithm
Write speed
Read speed
ST STM32F207 (96 MHz)
SD card in 4 bit mode
AES with an 128-bit key (SW)
639
661
NXP Kinetis K60 (120 MHz)
NAND flash device
interfaced via 8-bit bus
AES with an 128-bit key (SW)
508
550
Authenticated Encryption driver
General information
The Authentication Encryption driver is a logical driver that can be used to protect the file
system data against an unauthorized access. This is done by encrypting the data before writing
it to the storage device using an encryption algorithm and a key specified by the application.
In addition to this, this logical driver is able to check if the encrypted data was maliciously
manipulated by using a message authentication code.
emFile comes with sample encryption algorithms that use the encryption routines included
in SEGGER emCrypt product (https://www.segger.com/products/security-iot/emcrypt/)
In addition, sample encryption algorithms are provided that use the cryptographic hardware acceleration
units of individual MCUs. The Authentication Encryption driver is also able to use encryption algorithms
that are provided by the application. More information about the encryption algorithm can be found
in the section Encryption algorithm
The logical driver can be used with both the FAT and EFS file systems and with any storage device.
A separate volume is assigned to each driver instance. The volumes can be accessed
using the following names: “crypt:0:”, “crypt:1:”, etc.
Theory of operation
The sector data is transformed to make it unreadable for anyone who tries to read it
directly. The operation which makes the data unreadable is called encryption and is
performed when the file system writes the sector data. When the contents of a sector
is read, the reversed operation is applied that makes the data readable again.
This is operation called decryption. Both operations use a cryptographic algorithm
and a key for data transformation. The same key is used for encryption and decryption.
Without the knowledge of the key it is not possible to decrypt the data.
Low-level format
The driver uses some of the available storage space to store management information.
This management information has to be initialized once before any data access
to the storage via a low-level format operation. The application is responsible
for performing this operation either via FS_FormatLow() or FS_FormatLLIfRequired().
Fail-safe operation
The operation of the driver is fail-safe. This means that the driver makes sure that
after an unexpected power failure that interrupts a sector write operation either
the old or the new sector data is present but not some combination of both.
An unexpected power failure may affect the consistency of the stored data.
More exactly the message authentication code of the sectors being written during
the power failure may be left invalid. These data inconsistencies are automatically
corrected by the driver during the low-level mount operation before any access to the sector data.
Configuring the driver
Compile time configuration
The next table lists the available configuration defines followed
by a detailed description of them. The configuration defines have to
be added to the FS_Conf.h file that 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
Enables or disables the support for marking logical sectors are not being in use.
FS_CRYPT_ENABLE_STATS
This configuration 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 Authenticated Encryption driver that can be used
for example for analyzing the driver performance.
The statistical counters can be queried via FS_CRYPT_AE_GetStatCounters().
By default FS_CRYPT_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_CRYPT_NUM_UNITS
This define specifies the maximum number of driver instances
an application is allowed create. Four bytes of static RAM are
reserved for each driver instance. If the maximum number of driver
instances is smaller than the default then FS_CRYPT_NUM_UNITS
can be set to the to that value in order to reduce the RAM usage.
FS_CRYPT_MAX_AUTH_TAG_SIZE
This define specifies the maximum number of bytes in an authentication tag
that is supported by any instance of the CRYPT logical driver. If set to 0,
then the support for authenticated encryption is disabled.
FS_CRYPT_READ_BUFFER_FILL_PATTERN
This define can be used to specify the value that has to be stored in the
data of a invalid logical sector that is read by the file system.
FS_CRYPT_SUPPORT_TRIM
FS_CRYPT_SUPPORT_TRIM can be used to enable or disable the handling
of file system operations that inform a driver about logical sectors
that are no longer in use. The Authenticated Encryption driver can use
this information to optimize some of the internal operations such as
the data consistency check. Enabling this feature increases the ROM usage
of the Authenticated Encryption driver.
Runtime configuration
To add the driver, call FS_AddDevice() with the driver identifier set to
FS_CRYPT_AE_Driver. This function has to be called from within FS_X_AddDevices().
Refer to FS_X_AddDevices() for more information. The following table lists the
API functions that can be called by the application to configure the driver.
Number of device to access the storage medium (0-based).
pAlgoType
in The type of encryption algorithm.
pContext
in Data specific to cryptographic algorithm.
pKey
in Password for data encryption/decryption.
Return value
= 0
OK, driver instance configured successfully.
≠ 0
An error occurred.
Additional information
This function has to be called once for each driver instance.
pContext is passed to as parameter to the encryption and decryption routines via
pContext. The memory region pContext points to has to remain valid from the
moment the driver is configured until the FS_DeInit() function is called.
The number of bytes in pKey array has to match the size of the key required
by the used cryptographic algorithm.
Example
#include"FS.h"#include"FS_CRYPT_ALGO_AES_CCM_emCrypt.h"#defineALLOC_SIZE 2048// Size of emFile memory poolstaticU32 _aMemBlock[ALLOC_SIZE /4];staticFS_AES_CONTEXT _Context;/*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){U8 DeviceUnit;U8 Unit;U8 aPass[16]={'s','e','c','r','e','t'};FS_AssignMemory(_aMemBlock,sizeof(_aMemBlock));//// Add SD/MMC card device driver.//DeviceUnit =0;FS_AddPhysDevice(&FS_MMC_CM_Driver);FS_MMC_CM_Allow4bitMode(DeviceUnit,1);//// Add the Authenticated Encryption driver. // The storage can be accessed as volume "crypt:0:".//Unit =0;FS_AddDevice(&FS_CRYPT_AE_Driver);FS_CRYPT_AE_Configure(Unit,&FS_MMC_CM_Driver,DeviceUnit,&FS_CRYPT_ALGO_AES128_CCM_emCrypt,&_Context,aPass);}
FS_CRYPT_AE_SetAuthTagBufferSize()
Description
Sets the size of the internal buffer used for storing authentication tags.
The CRYPT logical driver uses an internal buffer for authentication tags
that is shared by all the driver instances. By default, the size
of this buffer is equal to FS_CRYPT_MAX_AUTH_TAG_SIZE.
FS_CRYPT_AE_SetMaxAuthTagSize()
Description
Sets maximum number of bytes in an authentication tag.
Typically, the Authentication Encryption driver reports a fatal error
when the data authentication fails.
All instances of the Authentication Encryption driver share the same
callback function. The Unit member of the FS_CRYPT_AE_FATAL_ERROR_INFO
structure passed as parameter to the pfOnFatalError callback function
indicates what driver instance triggered the fatal error.
FS_CRYPT_AE_SetSectorBufferSize()
Description
Sets the size of the internal buffer used for storing sector data.
The CRYPT logical driver uses an internal sector buffer that
is shared by all the driver instances. By default, the size
of this buffer is equal to the maximum sector size set for
the file system via FS_SetMaxSectorSize(). This function can
be used to modify the size of the internal sector buffer for
example for reducing the RAM usage if the storage device uses
a sector size that is smaller than the maximum sector size of
the file system.
FS_CRYPT_ON_FATAL_ERROR_CALLBACK
Description
The type of the callback function invoked by the Authenticated Encryption
driver when a fatal error occurs.
The application is responsible for handling the fatal error by for example
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.
Index of the Authenticated Encryption 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 Authenticated Encryption driver. The statistical counters provide
information about the number of internal operations performed
by the Authenticated Encryption driver such as sector read and write
from the information and data area.
All statistical counters are set to 0 when the storage device
is low-level mounted. The application can explicitly set the statistical
counters to 0 by using FS_CRYPT_AE_ResetStatCounters().
A separate set of statistical counters is maintained for each instance
of the Authentication Encryption driver.
The statistical counters are available only when the file system is built
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_CRYPT_AE_IsLLFormatted()
Description
Checks it the storage device is low-level formatted.
Index of the Authenticated Encryption driver (0-based).
Additional information
This function is optional. The application can use it to set to 0
the statistical counters maintained by the Authenticated Encryption driver.
The statistical counters can be read via FS_CRYPT_AE_GetStatCounters()
FS_CRYPT_AE_ResetStatCounters() is available only when the file system
is built 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_CRYPT_ENABLE_STATS
configuration define set to 1.
FS_CRYPT_AE_DISK_INFO
Description
Management information maintained by the Authenticated Encryption driver.
RepairSectorCnt indicates for how many logical sectors the check operation
of the Authenticated Encryption driver had to recalculate the authentication tag.
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 driver presented in the tables below were measured
as described in the section
Test procedure.
Usage: 4 KB
Static RAM usage
Static RAM usage is the amount of RAM required by the driver for variables inside of
the driver. The number of bytes can be seen in a compiler list file.
Usage: 42 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
selected encryption algorithm.
Every driver instance requires 61 bytes of RAM.
In addition, two work buffers are allocated that are shared for all the
driver instances. The first buffer is used for storing sector data. By default,
the size of this buffer is equal to the maximum logical sector size that
is supported by the file system. The second buffer is used for storing
authentication tags. The size of this buffer is by default FS_CRYPT_MAX_AUTH_TAG_SIZE 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 were performed as described in the section Performance.
All values are given in KB/second.
CPU type
Storage device
Encryption algorithm
Write speed
Read speed
ST STM32H573 (240 MHz)
SD card in 4 bit mode
AES with an 128-bit key (HW)
1302
3324
ST STM32H573 (240 MHz)
NOR flash device
interfaced via 8-bit bus
AES with an 128-bit key (HW)
62
5725
Sector Read-Ahead driver
The driver reads in advance more sectors than requested and caches them to provided
buffer. The maximum number of sectors which fit in the buffer are read at
once. If the requested sectors are present in the buffer the driver returns the cached
sector contents and the storage medium is not accessed. The driver should be used
on SD/MMC/eMMC storage devices where reading single sectors is less efficient
than reading all the sectors at once. By default the driver is not active. The file system
activates the driver when the allocation table is searched for free clusters. This
will improve performance in the case where the whole allocation table needs to be
scanned. To activate the support for read-ahead in the file system the
FS_SUPPORT_READ_AHEAD define must be set to 1 in FS_Conf.h.
The logical driver works with the FAT as well as with the EFS file system.
Configuring the driver
Runtime configuration
To add the driver, call FS_AddDevice() with the driver identifier set to
FS_READAHEAD_Driver. This function has to be called from within
FS_X_AddDevices(). Refer to FS_X_AddDevices() for more information.
The following table lists the API functions that can be called by the
application to configure the driver.
in Device driver used to access the storage device.
DeviceUnit
Index of the storage device (0-based)
pData
in Buffer to store the sector data read from storage device.
NumBytes
Number of bytes in the read buffer.
Additional information
This function is mandatory and it has to be called once for each
instance of the driver. The read buffer has to be sufficiently large
to store at least one logical sector.
Example
This example demonstrates how to configure the driver in order to access the data
stored on an SD card.
#include"FS.h"#defineALLOC_SIZE 2048// Size of emFile memory pool#defineBUFFER_SIZE 4096staticU32 _aMemBlock[ALLOC_SIZE /4];staticU32 _aReadBuffer[BUFFER_SIZE /4];/*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){FS_AssignMemory(_aMemBlock,sizeof(_aMemBlock));//// Add SD/MMC card device driver.//FS_AddPhysDevice(&FS_MMC_CM_Driver);//// Add and configure the read-ahead driver. Volume name: "rah:0:"//FS_AddDevice(&FS_READAHEAD_Driver);FS_READAHEAD_Configure(0,&FS_MMC_CM_Driver,0,_aReadBuffer,sizeof(_aReadBuffer));}
Additional driver functions
The following table lists the API functions that can be called by the
application at runtime to perform operations on the driver.
This function is optional. The statistical counters are updated
only when the file system is compiled with FS_READAHEAD_ENABLE_STATS
set to 1 or with FS_DEBUG_LEVEL set to a value greater than or equal
to FS_DEBUG_LEVEL_CHECK_ALL.
This function is optional. It is available only when the file system
is compiled with FS_READAHEAD_ENABLE_STATS set to 1 or with FS_DEBUG_LEVEL
set to a value greater than or equal to FS_DEBUG_LEVEL_CHECK_ALL.
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the driver presented in the tables below were measured
as described in the section
Test procedure.
Usage: 1.4 Kbytes
Static RAM usage
Static RAM usage is the amount of RAM required by the driver for variables inside of
the driver. The number of bytes can be seen in the compiler list file.
Usage: 20 bytes
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the driver at runtime.
Usage: 30 bytes
Performance
The detection of free space is 2 times faster when a 4KB read ahead buffer is used
(measured on 4GB SD card formatted with 4KB clusters).
Sector Size Adapter driver
The logical driver supports access to a storage device using a sector size different
than that of the underlying layer (typically a storage driver). The sector size of the
logical driver is configurable and can be larger or smaller than the sector size of the
below layer.
Typically, the logical driver is placed between the file system and a storage driver and
it is configured with a sector size smaller than that of the storage layer to help
reduce the RAM usage of the internal sector buffers of the file system.
Configuring the driver
To add the driver, call FS_AddDevice() with the driver identifier set to
FS_SECSIZE_Driver. This function has to be called from within FS_X_AddDevices().
Refer to FS_X_AddDevices() for more information. The following table lists the
API functions that can be called by the application to configure the driver.
This function is mandatory and it has to be called once for each
instance of the driver. BytesPerSector has to be a power of 2 value.
Example
This example demonstrates how to configure the logical driver to access a NAND
flash via the Universal NAND driver.
#include"FS.h"#defineALLOC_SIZE 0x8000// Size of emFile memory poolstaticU32 _aMemBlock[ALLOC_SIZE /4];/*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){FS_AssignMemory(_aMemBlock,sizeof(_aMemBlock));//// Add NAND flash device driver.//FS_AddPhysDevice(&FS_NAND_UNI_Driver);FS_NAND_UNI_SetPhyType(0,&FS_NAND_PHY_ONFI);FS_NAND_UNI_SetECCHook(0,&FS_NAND_ECC_HW_NULL);//// Add sector conversion logical driver.//FS_AddDevice(&FS_SECSIZE_Driver);FS_SECSIZE_Configure(0,&FS_NAND_UNI_Driver,0,512);}
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 driver presented in the tables below were measured
as described in the section
Test procedure.
Usage: 1.1 Kbytes
Static RAM usage
Static RAM usage is the amount of RAM required by the driver for variables inside of
the driver. The number of bytes can be seen in the compiler list file.
Usage: 20 bytes
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the driver at runtime.
Each driver instance requires 30 bytes of RAM. In addition, a driver instance
requires a working buffer of the size of one storage driver logical sector
if the sector size of the storage driver is larger than the sector size configured
for the logical driver configured via FS_SECSIZE_Configure().
Sector Write Buffer driver
This driver was designed to help improve the write performance of the file system.
It operates by temporarily storing the sector data to RAM which takes significantly
less time than writing directly to a storage. The sector data is written later to
storage at the request of the application or when the internal buffer is full. The sectors
are written to storage in the same order in which they were written by the file
system.
The advantages of using this driver are:
a file system write operation blocks for a very short period of time.
the number of write operations is reduced when the same sector is written in
succession.
the driver can be used with activated Journal since the write order is preserved.
The internal buffer can be cleaned from application by calling the
FS_STORAGE_Sync() API function. The function blocks until all sectors stored in the
internal buffer are written to storage. Typically, this function should be called from a
low priority task when the application does not access the file system.
Configuring the driver
Runtime configuration
To add the driver, call FS_AddDevice() with the driver identifier set to
FS_WRBUF_Driver. This function has to be called from within FS_X_AddDevices().
Refer to FS_X_AddDevices() for more information. The following table lists the
API functions that can be called by the application to configure the driver.
This function is mandatory and it has to be called once for each
instance of the driver. FS_SIZEOF_WRBUF() can be used to calculate
the number of bytes required to be allocated in order to store a
specified number of logical sectors.
Example
This example demonstrates how to configure the logical driver to access an SD
card via the SD/MMC card mode driver.
#include"FS.h"#defineALLOC_SIZE 0x1000// Size of emFile memory poolstaticU32 _aMemBlock[ALLOC_SIZE /4];staticU32 _aWriteBuffer[FS_SIZEOF_WRBUF(8,512)/4];/*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){FS_AssignMemory(_aMemBlock,sizeof(_aMemBlock));//// Add and configure the NOR flash driver.//FS_AddPhysDevice(&FS_MMC_CM_Driver);FS_MMC_CM_Allow4bitMode(0,1);FS_MMC_CM_SetHWType(0,&FS_MMC_HW_CM_Default);//// Add and configure the write buffer driver.//FS_AddDevice(&FS_WRBUF_Driver);FS_WRBUF_Configure(0,&FS_MMC_CM_Driver,0,_aWriteBuffer,sizeof(_aWriteBuffer));}
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 logical sectors. NumSectors specifies the number
of logical sectors while BytesPerSector the size of a logical
sector 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 driver presented in the tables below were measured
as described in the section
Test procedure.
Usage: 1.2 Kbytes
Static RAM usage
Static RAM usage is the amount of RAM required by the driver for variables inside of
the driver. The number of bytes can be seen in a compiler list file.
Usage: 20 bytes
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the driver at runtime.
Usage: 32 bytes
RAID1 driver
RAID1 is a logical file system driver that can be used to increase the integrity and
reliability of the data saved on a storage device. This is realized by keeping a copy
of all sector data on a separate partition also known as mirroring. When a read error
occurs the data is recovered by reading it from the mirror partition.
Theory of operation
The logical driver uses a master and a mirror partition. On a file system write
request, the sector data is written to both master and mirror partitions. On a file system
read request, the logical driver tries to read the sector data from the master partition
first. If a read error occurs, then the sector data is read from the mirror
partition. This way the data is recovered and no error is reported to the file system.
The logical driver can be configured to store the sector data either on the same or on
two separate storage devices, according to user requirements. If a single storage
device is used, the first half is used as master partition. When using two different
storage devices the size of the volumes does not have to be equal. The number of
sectors available to the file system will be that of the smallest storage device. However,
it is required that the sector size of both storage devices are equal. If necessary,
the sector size can be adapted using the SECSIZE logical driver. For more
information refer to Sector Size Adapter driver.
NAND flash error recovery
The Universal NAND driver can make use of the RAID driver to avoid a data loss when
an uncorrectable ECC error happens during a read operation. This feature is by
default disabled and it can be enabled at compile time by setting the
FS_NAND_ENABLE_ERROR_RECOVERY switch to 1 in FS_Conf.h.
Sector data synchronization
An unexpected reset that interrupts a write operation may lead to a data inconsistency. It
is possible that the data of the last written sector is stored only to the master, but
not to the mirror partition. After restart, the file system will continue to operate correctly
but in case of a read error affecting this sector, old data is read from the mirror
partition which may cause a data corruption. This situation can be prevented by synchronizing
all the sectors on the RAID volume. The application can perform the synchronization by calling
the FS_STORAGE_SyncSectors() API function. For example, a low priority task can call the function
in parallel to other file system activities. For an example refer to FS_RAID1_SetSyncBuffer().
Configuring the driver
Runtime configuration
The API functions listed in the next table can be used by the application to
configure the behavior of the RAID1 driver. The application can call
them only at the file system initialization in FS_X_AddDevices().
Index of the primary (master) storage device (0-based).
pDeviceType1
in Type of the secondary (mirror) storage device.
DeviceUnit1
Index of the secondary (mirror) storage device.
Additional information
This function has to be called once for each driver instance.
The same storage device can used both as primary and as secondary
device in which case the first half is used as primary device the
other half is used as secondary device.
Example
The following example shows how to configure RAID1 on a single volume.
#include"FS.h"#defineALLOC_SIZE 0x8000// Size of the memory pool in bytesstaticU32 _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().*/voidFS_X_AddDevices(void){//// Give the file system some memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Set the file system sector size.//FS_SetMaxSectorSize(2048);//// Add and configure the first NAND driver.//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);//// Add and configure the RAID driver.//FS_AddDevice(&FS_RAID1_Driver);FS_RAID1_Configure(0,&FS_NAND_UNI_Driver,0,&FS_NAND_UNI_Driver,0);}
The next example demonstrates how to configure a RAID1 on 2 separate volumes.
#include"FS.h"#defineALLOC_SIZE 0x8000// Size of the memory pool in bytesstaticU32 _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().*/voidFS_X_AddDevices(void){//// Give the file system some memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Set the file system sector size.//FS_SetMaxSectorSize(2048);//// Add and configure the NAND driver for the primary storage.//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);//// Add and configure the NAND driver for the secondary storage.//FS_AddDevice(&FS_NAND_UNI_Driver);FS_NAND_UNI_SetPhyType(1,&FS_NAND_PHY_ONFI);FS_NAND_UNI_SetECCHook(1,&FS_NAND_ECC_HW_NULL);//// Add and configure the RAID driver.//FS_AddDevice(&FS_RAID1_Driver);FS_RAID1_Configure(0,&FS_NAND_UNI_Driver,0,&FS_NAND_UNI_Driver,1);}
FS_RAID1_SetSectorRanges()
Description
Configures the position and the size of the RAID partitions.
This function is optional. Per default, the RAID1 driver uses
the entire available space of a storage device. The application
can use FS_RAID1_SetSectorRanges() to specify areas of the
primary and secondary storage devices the RAID1 driver has to
use as storage.
Example
This example configures a RAID volume of 10000 sectors. The primary storage starts
at sector index 0 and the secondary storage at sector index 10000.
#include"FS.h"#defineALLOC_SIZE 0x8000// Size of the memory pool in bytesstaticU32 _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().*/voidFS_X_AddDevices(void){//// Give the file system some memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Set the file system sector size.//FS_SetMaxSectorSize(2048);//// Add and configure the first NAND driver.//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);//// Add and configure the RAID driver.//FS_AddDevice(&FS_RAID1_Driver);FS_RAID1_Configure(0,&FS_NAND_UNI_Driver,0,&FS_NAND_UNI_Driver,0);FS_RAID1_SetSectorRanges(0,10000,0,10000);}
Pointer to a memory location to be used as buffer.
NumBytes
Number of bytes in the buffer.
Additional information
This function is optional. The configured buffer is used for
when the sector data is synchronized between the primary and
the secondary storage device via FS_STORAGE_SyncSectors().
The size of the buffer has to be sufficiently large to store
at least two logical sectors otherwise the synchronization
operation will fail. A larger buffer allows the driver to read
and write multiple logical sectors at once which help increase
the performance of the synchronization operation.
Example
The following example shows how to configure a synchronization buffer of 16KB
and how to synchronize the RAID volume after an unexpected reset.
#include"FS.h"#defineALLOC_SIZE 0x8000// Size of the memory pool in bytes#defineBUFFER_SIZE 0x8000// Size of the sync buffer in bytesstaticU32 _aMemBlock[ALLOC_SIZE /4];// Memory pool used for// semi-dynamic allocation.staticU32 _aSyncBuffer[BUFFER_SIZE /4];// Buffer for the RAID synchronization./*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){//// Give the file system some memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Set the file system sector size.//FS_SetMaxSectorSize(2048);//// Add and configure the first NAND driver.//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);//// Add and configure the RAID driver.//FS_AddDevice(&FS_RAID1_Driver);FS_RAID1_Configure(0,&FS_NAND_UNI_Driver,0,&FS_NAND_UNI_Driver,0);FS_RAID1_SetSyncBuffer(0,_aSyncBuffer,sizeof(_aSyncBuffer));}/*********************************************************************** _SampleSyncRAID1** Function description* Performs synchronization of the RAID1 partitions. This function may* be called from a low-priority task in order to minimize the effect* on the normal file system activity.*/staticvoid_SampleSyncRAID1(void){U32 iSector;FS_DEV_INFODevInfo;//// Get the number of sectors on the storage.//FS_STORAGE_GetDeviceInfo("",&DevInfo);//// Synchronize one sector at a time to avoid// blocking the application for too long time.//for(iSector =0;iSector <DevInfo.NumSectors;++iSector){FS_STORAGE_SyncSectors("",iSector,1);}}
FS_RAID1_SetSyncSource()
Description
Specifies the source storage device for the synchronization operation.
Index of the storage device to be used as source. 0 - primary storage device. 1 - secondary storage device.
Additional information
This function is optional. It can be used by an application to specify
the storage device that has to be used as source when synchronizing
the RAID1 partitions via FS_STORAGE_SyncSectors(). Per default the
primary storage device is used as source.
Example
The following example shows how to use the secondary device as source for the
synchronization operation.
#include"FS.h"#defineALLOC_SIZE 0x8000// Size of the memory pool in bytes#defineBUFFER_SIZE 0x8000// Size of the sync buffer in bytes#defineNUM_SECTORS 2048// Number of sectors on the RAM disk#defineBYTES_PER_SECTOR 512// Size of a RAM disk sector#defineBASE_ADDR 0x80000000// Address in memory of the first byte// in the NOR flashstaticU32 _aMemBlock[ALLOC_SIZE /4];// Memory pool used for// semi-dynamic allocation.staticU32 _aRAMDisk[(NUM_SECTORS *BYTES_PER_SECTOR)/4];// Storage for RAM disk.staticU32 _aSyncBuffer[BUFFER_SIZE /4];// Buffer for the synchronization./*********************************************************************** 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* Other API functions may NOT be called, since this function is called* during initialization. The devices are not yet ready at this point.*/voidFS_X_AddDevices(void){//// Give the file system some memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Add and configure the RAM disk first for maximum read performance.//FS_AddDevice(&FS_RAMDISK_Driver);FS_RAMDISK_Configure(0,_aRAMDisk,BYTES_PER_SECTOR,NUM_SECTORS);//// Add and configure the driver for NOR flash.//FS_AddDevice(&FS_NOR_BM_Driver);FS_NOR_BM_SetPhyType(0,&FS_NOR_PHY_CFI_1x16);FS_NOR_BM_Configure(0,BASE_ADDR,BASE_ADDR,BYTES_PER_SECTOR *NUM_SECTORS);//// Add and configure the RAID driver.//FS_AddDevice(&FS_RAID1_Driver);FS_RAID1_Configure(0,&FS_RAMDISK_Driver,0,&FS_NOR_BM_Driver,0);FS_RAID1_SetSyncBuffer(0,_aSyncBuffer,sizeof(_aSyncBuffer));//// Copy data from NOR flash to RAM disk when synchronizing at restart.//FS_RAID1_SetSyncSource(0,1);}
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 driver presented in the tables below were measured
as described in the section
Test procedure.
Usage: 1.5 Kbytes
Static RAM usage
Static RAM usage is the amount of RAM required by the driver for variables inside of
the driver. The number of bytes can be seen in a compiler list file.
Usage: 20 bytes
Runtime RAM usage
Runtime RAM usage is the amount of RAM allocated by the driver at runtime.
Usage: 48 bytes
RAID5 driver
RAID5 is a logical file system driver that can be used to increase the integrity and
reliability of the data saved on a storage device. This is realized by keeping a parity
check of the sector data of two or more consecutive sectors. In case of a read error
the sector data is recovered the parity check information.
Theory of operation
RAID5 requires at least three storage partitions. Storage space equivalent to the
size of one partition is used for parity check information, making it unavailable
for data storage. Parity checking means adding an extra piece of information
(a formula result) that can be used to replicate data in the case of a hardware
defect or failure. The storage capacity required for the parity checking information
can be reduced by increasing the number of partitions, thus increasing overall available
capacity. The RAID5 add-on calculates the parity checking information using the “eXclusive Or”
function (XOR). The result of an XOR function performed on any number of inputs
is such that if one input is lost (i.e. one partition fails) the missing piece
of information can be calculated (i.e. recovered or replicated) using the XOR result
and the other known inputs.
NAND flash error recovery
The Universal NAND driver can make use of the RAID5 driver to avoid a data loss when
an uncorrectable ECC error happens during a read operation. This feature is by
default disabled and it can be enabled at compile time by setting the
FS_NAND_ENABLE_ERROR_RECOVERY configuration define to 1 in FS_Conf.h.
Configuring the driver
Runtime configuration
The API functions listed in the next table can be used by the application to
configure the behavior of the RAID5 driver. The application can call
them only at the file system initialization in FS_X_AddDevices().
Index of the first sector to be used for data storage (0-based).
Additional information
This function has to be called at least three times in FS_X_AddDevices()
because the RAID5 logical driver requires at least three partitions
for correct operation. One partition stores the parity check data while the
the other partitions the payload. The partitions do not have to be
located on different physical storage devices.
The number of logical sectors covered by a single parity check
sector is one less than the total number of partitions added
to the RAID5 logical driver. A configuration with one or two partitions
is invalid and is reported as an error during the initialization
of the RAID5 logical driver instance.
It is mandatory that all the configured partitions have
the same logical sector size. If the configured partitions
have different logical sector sizes, than the SECSIZE logical
driver can be used to adapt them.
The RAID5 logical driver uses as storage the same number of logical
sectors from each partition because the data is distributed equally
between these partitions. Typically, the RAID5 logical driver uses
the entire partition for data storage. This is the case
when all configured partitions contain the same number of sectors.
When the configured partitions have different number of sectors,
then the RAID5 logical driver uses the number of logical
sectors of the partition with smallest capacity.
The number of logical sectors used by the RAID logical driver
from each partition can be also explicitly configured
via FS_RAID5_SetNumSectors().
StartSector can be used to locate the RAID partition at other
logical sector offset on the storage device than 0, when the first
number of logical sectors on the partition are reserved for other purposes.
Example
The following code snippet shows how to configure a the RAID 5 add-on
that uses three partitions located on the same NAND flash device.
#include"FS.h"#include"FS_NAND_HW_Template.h"#defineALLOC_SIZE 0x8000// Size of the memory pool in bytesstaticU32 _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().*/voidFS_X_AddDevices(void){//// Give the file system some memory to work with.//FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Add and configure the RAID5 volume. Volume name: "raid5:0:"//FS_AddDevice(&FS_RAID5_Driver);FS_RAID5_AddDevice(0,&FS_NAND_UNI_Driver,0,0);FS_RAID5_AddDevice(0,&FS_NAND_UNI_Driver,0,1000);FS_RAID5_AddDevice(0,&FS_NAND_UNI_Driver,0,2000);FS_RAID5_SetNumSectors(0,1000);//// Add and configure the driver NAND driver. Volume name: "nand:0:"//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_Template);}
FS_RAID5_SetNumSectors()
Description
Specifies the number of logical sectors in a single RAID partition.
This function is optional and can be called only from FS_X_AddDevices().
By default, the RAID5 logical driver uses all the logical sectors
of a partition to store the data. FS_RAID5_SetNumSectors()
can be used to configure a different value for the number of logical
sectors when for example the end of a partition is reserved and cannot
be used for data storage.
FS_RAID5_GetOperatingMode()
Description
Returns the operating mode of the specified RAID5 partition.
This function is optional and can be called from an application
to get the operating mode of the RAID5 logical driver.
The RAID5 logical driver can operate in one of the flowing modes:
FS_RAID_OPERATING_MODE_NORMAL All storage devices are present and are operating normally.
FS_RAID_OPERATING_MODE_DEGRADED One storage device is not operating properly.
FS_RAID_OPERATING_MODE_FAILURE Two or more storage devices are not operating properly.
The ROM usage depends on the compiler options, the compiler version and the used
CPU. The memory requirements of the driver presented in the tables below were measured
as described in the section
Test procedure.
Usage: 2.2 Kbytes
Static RAM usage
Static RAM usage is the amount of RAM required by the driver for variables inside of
the driver. The number of bytes can be taken from the compiler list file.
Usage: 30 bytes
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the driver at runtime.
Each driver instance requires 23 bytes of RAM. In addition, 11 bytes
of RAM are required for each different storage device used by the RAID5 driver
instance and 12 bytes for each configured partition.
Logical Volume driver
This driver can be used by an application to create a volume that extents
over two or more existing volumes. In addition, the Logical Volume driver
can also be configured to create a volume using as storage only a specified
sector range of an already existing volume. The volumes created via
the Logical Volume driver can be accessed by the application in the same way
as any other volume attached to a device or logical driver. The type of
the storage device attached to the volumes combined via the Logical Volume
driver is not relevant as long as they have the same logical sector size.
The combined volumes can be attached to device as well as logical drivers.
The Logical Volume driver is included in the LOGVOL component that
also provides the implementation of the FS_LOGVOL_Create() and
FS_LOGVOL_AddDevice() API functions. These functions were the only
way for creating logical volumes in emFile versions older than 5.x
The functionality provided by the Logical Volume driver is similar to
the functionality of the API functions FS_LOGVOL_Create() and
FS_LOGVOL_AddDevice(). The difference is that the volume created using
the later method is not attached to a driver and as a consequence
the volume cannot be used with any of the logical drivers for example
to encrypt its contents via the Encryption driver.
Therefore SEGGER recommends the Logical Volume driver as the preferred
method of creating logical volumes.
The volume attached to a Logical Volume driver has a fixed name
as described in the section General information.
If the application wishes to access the volume under a different
name then it can do so by configuring an alias for the volume name
via FS_SetVolumeAlias().
Configuring the driver
The Logical Volume driver has to be configured at compile time
and at runtime. This section describes how this can be realized.
Compile time configuration
The next table lists the available configuration defines followed
by a detailed description of them. The configuration defines must
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
Enables or disables the support for marking logical sectors are not being in use.
FS_LOGVOL_NUM_UNITS
This define specifies the maximum number of driver instances
an application is allowed create. Four bytes of static RAM are
reserved for each driver instance. If the maximum number of driver
instances is smaller than the default then FS_LOGVOL_NUM_UNITS
can be set to the to that value in order to reduce the RAM usage.
FS_LOGVOL_SUPPORT_CLEAN
This define specifies if the application is allowed to perform a garbage collection
operation via the LOGVOL driver. If FS_LOGVOL_SUPPORT_CLEAN is set to 1 then
the application can perform a garbage collection operation via FS_STORAGE_Clean()
and FS_STORAGE_CleanOne() on the device configured as data storage.
If the used storage device does not support garbage collection
then FS_NOR_SUPPORT_CLEAN can be safely set to 0 in order to reduce
the ROM usage.
FS_LOGVOL_SUPPORT_DRIVER_MODE
FS_LOGVOL_SUPPORT_DRIVER_MODE can be used to configure if the LOGVOL
component works in legacy or driver mode. By default the component
works in legacy mode which means that the application has to use
the functions FS_LOGVOL_Create() and FS_LOGVOL_AddDevice() to
configure a volume. If FS_LOGVOL_SUPPORT_DRIVER_MODE is set to 1
then the LOGVOL component works in driver mode. In this mode
the LOGVOL component behaves like any other logical driver in that
an instance of the driver can be added to the file system via
FS_AddDevice(). Each instance of the Logical Volume driver must
be configured at runtime by calling FS_LOGVOL_AddDeviceEx()
in FS_X_AddDevice().
FS_LOGVOL_SUPPORT_TRIM
FS_LOGVOL_SUPPORT_TRIM can be used to enable or disable the handling of file system operations
that inform a device driver about logical sectors that are no longer in use.
A device driver can use this information to optimize the internal operation
that copies the data from one physical location 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 LOGVOL driver.
Runtime configuration
The Logical Volume driver has to be added to the file system by calling
FS_AddDevice() in FS_X_AddDevices() with the driver identifier set to
FS_LOGVOL_Driver. Refer to FS_X_AddDevices() for more information.
The following table lists the API functions that can be called by
the application to configure the driver.
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
This function has to be called at least once for each instance
of a LOGVOL driver. Each call to FS_LOGVOL_AddDeviceEx() defines a
range of sectors to be used a storage from a volume attached to
a device or logical driver. The volume to be used as storage is
identified by pDeviceType and DeviceUnit. If the defined logical
volume extends over two or more existing sectors then all of
these volumes need to have the same logical sector size.
If NumSectors is set to 0 then all the sectors of the specified volume
are used as storage.
FS_LOGVOL_AddDeviceEx does nothing if FS_LOGVOL_SUPPORT_DRIVER_MODE is set to 0.
Example
This following example demonstrates how to configure the logical driver
to use as storage only a sector range of an SD card via the SD/MMC card mode
driver. The application can access the volume under the name “sdcard”.
#include"FS.h"#include"FS_MMC_HW_CM_Template.h"#defineALLOC_SIZE 0x2000// Size of emFile memory pool#defineSTART_SECTOR 0// Index of the first sector to be used.#defineNUM_SECTORS 10000// Number of sectors in the LOGVOL volume.staticU32 _aMemBlock[ALLOC_SIZE /4];// emFile memory pool./*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){//// Give file system memory to work with.//FS_AssignMemory(_aMemBlock,sizeof(_aMemBlock));//// Add SD/MMC card device driver but do not attach any volume to it.//FS_AddPhysDevice(&FS_MMC_CM_Driver);FS_MMC_CM_Allow4bitMode(0,1);FS_MMC_CM_AllowHighSpeedMode(0,1);FS_MMC_CM_SetHWType(0,&FS_MMC_HW_CM_Template);//// Add and configure the logical volume. Volume name: "sdcard".//#ifFS_LOGVOL_SUPPORT_DRIVER_MODEFS_AddDevice(&FS_LOGVOL_Driver);FS_LOGVOL_AddDeviceEx(0,&FS_MMC_CM_Driver,0,START_SECTOR,NUM_SECTORS);#endif// FS_LOGVOL_SUPPORT_DRIVER_MODE#if(FS_MAX_LEN_VOLUME_ALIAS >0)FS_SetVolumeAlias("lvol:0:","sdcard");#endif// FS_MAX_LEN_VOLUME_ALIAS > 0}
This next example demonstrates how to configure the logical driver to use
as storage volumes attached to a NAND and NOR flash device.
#include"FS.h"#include"FS_NAND_HW_Template.h"#include"FS_NOR_HW_SPIFI_Template.h"#defineALLOC_SIZE 0x4000// Size of emFile memory pool#defineBYTES_PER_SECTOR 2048// Number of bytes in a logical sector.staticU32 _aMemBlock[ALLOC_SIZE /4];// emFile memory pool./*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){//// Give file system memory to work with.//FS_AssignMemory(_aMemBlock,sizeof(_aMemBlock));//// Configure the size of the logical sector and activate the file buffering.//FS_SetMaxSectorSize(BYTES_PER_SECTOR);//// Add and configure the Universal NAND driver.//FS_AddPhysDevice(&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_Template);//// Add and configure the NOR driver.//FS_AddPhysDevice(&FS_NOR_BM_Driver);FS_NOR_BM_SetPhyType(0,&FS_NOR_PHY_SPIFI);FS_NOR_BM_Configure(0,0x80000000,0x80000000,0x01000000);FS_NOR_BM_SetSectorSize(0,BYTES_PER_SECTOR);FS_NOR_SPIFI_Allow2bitMode(0,1);FS_NOR_SPIFI_Allow4bitMode(0,1);FS_NOR_SPIFI_SetHWType(0,&FS_NOR_HW_SPIFI_Template);#ifFS_LOGVOL_SUPPORT_DRIVER_MODE//// Add and configure the logical volume.// The entire storage space of the NAND and NOR device is used.// Volume name: "lvol:0:".//FS_AddDevice(&FS_LOGVOL_Driver);FS_LOGVOL_AddDeviceEx(0,&FS_NAND_UNI_Driver,0,0,0);FS_LOGVOL_AddDeviceEx(0,&FS_NOR_BM_Driver,0,0,0);#endif// FS_LOGVOL_SUPPORT_DRIVER_MODE}
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 driver presented in the tables below were measured
as described in the section
Test procedure.
Usage: 1.0 Kbytes
Static RAM usage
Static RAM usage is the amount of RAM required by the driver for variables inside of
the driver. The number of bytes can be seen in a compiler list file.
Usage: 24 bytes
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the driver at runtime.
Usage: 6 bytes for each driver instance + 21 bytes for each sector range
defined via FS_LOGVOL_AddDeviceEx().
Custom drivers
This chapter describes how to implement a custom device or logical driver.
General information
emFile comes with device drivers that support all of the popular storage
devices such as NAND flash, NOR flash and SD card. However, using a storage
device that is not supported by emFile may require the implementation of
a custom device driver. In addition, the functionality of the file system may
be extended by implementing a custom logical driver. The following sections
describe which functions are required to be implemented and how the custom
device or logical driver can be used with emFile.
Driver layer API
This section describes the functions of a device or logical driver.
The API of the driver layer is implemented as a structure of type
FS_DEVICE_TYPE that contains pointers to functions.
Note
The actual names of these functions are not relevant because the file system accesses them via the function table.
The returned name is used by the file system to create the volume name.
The name must be unique between all device and logical drivers configured
by the application.
This is the first function called by the file system. Typically,
it is called from FS_AddDevice() or FS_AddPhysDevice()
at the file system initialization.
FS_DEVICE_TYPE_READ
Description
Reads one or more logical sectors from storage device.
Pointer to buffer containing the sector data to be written.
NumSectors
Number of logical sectors to write.
RepeatSame
Specifies how the sector data has to be written 0 - Different data is stored to each sector. 1 - Same data is stored to all sectors.
Return value
= 0
OK, data successfully written.
≠ 0
An error occurred.
Additional information
The sector data is stored at the following bytes offsets in pData
if RepeatSame is set to 0:
Byte offset
Logical sector index
0
SectorIndex
BytesPerSector
SectorIndex + 1
BytesPerSector * 2
SectorIndex + 2
BytesPerSector * 3
SectorIndex + 3
…
…
BytesPerSector * (NumSectors - 1)
SectorIndex + (NumSectors - 1)
If RepeatSame is set to 1 then pData points to a memory region that
is BytePerSector bytes large. This block of data has to be stored
repeatedly to the logical sector indexes SectorIndex to
SectorIndex + (NumSectors - 1)
Cmd can be one of the codes listed in I/O command codes.
Aux and pBuffer are optional parameters to the command.
pBuffer is used by some of the commands to return a value
to the caller.
This function is relevant only for drivers that access a removable
storage device such as an SD card. For other storage devices or
for a logical driver this function can simply return FS_MEDIA_IS_PRESENT.
Checks if the storage device is low-level formatted.
FS_CMD_GET_DEVINFO
Returns information about the storage device.
FS_CMD_FORMAT_LOW_LEVEL
Performs a low-level format operation.
FS_CMD_FREE_SECTORS
Informs the driver about unused logical sectors.
FS_CMD_SET_DELAY
Configures an access delay.
FS_CMD_UNMOUNT
Invalidates all information about the storage device.
FS_CMD_UNMOUNT_FORCED
Invalidates all information about the storage device.
FS_CMD_SYNC
Request the driver to write any cached information to the storage device.
FS_CMD_DEINIT
Frees all resources allocated by all the driver instances.
FS_CMD_CLEAN_ONE
Requests the driver to perform one clean operation.
FS_CMD_CLEAN
Requests the driver to completely clean the storage device.
FS_CMD_GET_SECTOR_USAGE
Queries the driver about the usage of a logical sector.
FS_CMD_ENABLE_READ_AHEAD
Requests the driver to start reading sectors in advance.
FS_CMD_DISABLE_READ_AHEAD
Requests the driver to stop reading sectors in advance.
FS_CMD_GET_CLEAN_CNT
Returns the number of operations required to completely clean the storage device.
FS_CMD_SET_READ_ERROR_CALLBACK
Registers a handler for sector read errors.
FS_CMD_SYNC_SECTORS
Informs the driver about the sectors that must be synchronized.
Additional information
FS_CMD_GET_DEVINFO is mandatory to be implemented. In addition,
the driver implementation has to return 0 in response to
FS_CMD_FREE_SECTORS if it does not implement this command.
The other commands are optional and the driver
is permitted to return -1 if it does not implement them.
FS_CMD_REQUIRES_FORMAT and FS_CMD_FORMAT_LOW_LEVEL must be implemented
by any device driver that uses a storage device which has to be
initialize once before use. FS_CMD_FORMAT_LOW_LEVEL is used
by FS_FormatLow().
FS_CMD_SET_DELAY is used only by the FS simulation to test the
RAM Disk driver.
The handling of FS_CMD_UNMOUNT and FS_CMD_UNMOUNT_FORCED has to
invalidate any cached information related to the storage device.
The handling of FS_CMD_SYNC must write any dirty cached sector data
to the storage device.
FS_CMD_DEINIT has to be handled only if the driver allocates dynamic
memory and only when the file system is built with FS_SUPPORT_DEINIT
set to 1.
The following tables details the usage of the Aux and pBuffer
parameters specified in the call to FS_DEVICE_TYPE_IOCTL for
each command code as well as the meaning of the return value.
The commands that are not specified in a table do not make
use of that parameter.
Cmd
Aux
FS_CMD_FREE_SECTORS
Index of the first unused logical sector.
FS_CMD_SET_DELAY
Read delay in milliseconds.
FS_CMD_GET_SECTOR_USAGE
Index of the logical sector to be queried.
FS_CMD_SYNC_SECTORS
Index of the first logical sector to be synchronized.
Cmd
pBuffer (input)
FS_CMD_FREE_SECTORS
Number of logical sectors as pointer to U32 value.
The following template implementation can be used as a starting point for the
implementation of a new device or logical driver. The implementation is included
in the emFile shipment in the Sample/FS/Driver/Template folder.
/********************************************************************** (c) SEGGER Microcontroller GmbH ** The Embedded Experts ** www.segger.com ***********************************************************************-------------------------- END-OF-HEADER -----------------------------File : TEMPLATE_Driver.cPurpose : Template for a FS driver.*//*********************************************************************** #include Section************************************************************************/#include"FS_Int.h"/*********************************************************************** Defines, configurable************************************************************************/#ifndefFS_TEMPLATE_NUM_UNITS#defineFS_TEMPLATE_NUM_UNITS 4// Maximum number of driver instances.#endif/*********************************************************************** Type definitions************************************************************************/typedefstruct{U8 IsInited;U8 Unit;U16 NumHeads;U16 SectorsPerTrack;U32 NumSectors;U16 BytesPerSector;}DRIVER_INST;/*********************************************************************** Static data************************************************************************/staticDRIVER_INST *_apInst[FS_TEMPLATE_NUM_UNITS];staticint_NumUnits =0;/*********************************************************************** Static code************************************************************************//*********************************************************************** _Init** Function description* Resets/Initializes the device.** Parameters* pInst Driver instance** Return value* ==0 Device has been reset and initialized.* !=0 An error has occurred.*/staticint_Init(DRIVER_INST *pInst){FS_USE_PARA(pInst);return0;}/*********************************************************************** _Unmount** Function description* Unmounts the volume.** Parameters* pInst Driver instance*/staticvoid_Unmount(DRIVER_INST *pInst){if(pInst->IsInited){FS_MEMSET(pInst,0,sizeof(DRIVER_INST));}}/*********************************************************************** Public code (indirectly via callback)************************************************************************//*********************************************************************** _GetDriverName** Function description* Returns the driver name.** Parameters* Unit Index of the driver instance (0-based).** Return value* Name of the driver as 0-terminated string.** Additional information* The returned name is used by the file system to create the volume name.*/staticconstchar*_GetDriverName(U8 Unit){FS_USE_PARA(Unit);return"template";}/*********************************************************************** _AddDevice** Function description* Initializes a new driver instance.** Return value* >=0 OK, index of the created driver instance.* < 0 An error occurred.*/staticint_AddDevice(void){U8 Unit;DRIVER_INST *pInst;if(_NumUnits >=FS_TEMPLATE_NUM_UNITS){return-1;// Error, too many driver instances.}Unit =(U8)_NumUnits++;pInst =(DRIVER_INST *)FS_AllocZeroed(sizeof(DRIVER_INST));if(pInst ==NULL){return-1;// Error, out of memory.}_apInst[Unit]=pInst;returnUnit;}/*********************************************************************** _Read** Function description* Reads one or more logical sectors from storage device.** Parameters* Unit Index of the driver instance (0-based).* SectorIndex First sector to be read from the device.* pData Pointer to buffer for storing the data.* NumSectors Number of sectors to read.** Return value* ==0 OK, data successfully written.* !=0 An error occurred.** Additional information* The sector data has to be stored at the following offsets in pData:* Byte offset Sector index* -----------------------------------------------* 0 SectorIndex* BytesPerSector SectorIndex + 1* BytesPerSector * 2 SectorIndex + 2* BytesPerSector * 3 SectorIndex + 3* ...* BytesPerSector * (NumSectors - 1) SectorIndex + (NumSectors - 1)*/staticint_Read(U8 Unit,U32 SectorIndex,void*pData,U32 NumSectors){DRIVER_INST *pInst;FS_USE_PARA(SectorIndex);FS_USE_PARA(pData);FS_USE_PARA(NumSectors);pInst =_apInst[Unit];returnpInst->IsInited ?0:1;}/*********************************************************************** _Write** Function description* Writes one or more logical sectors to storage device.** Parameters* Unit Index of the driver instance (0-based).* SectorNo First sector to be written to the device.* pData Pointer to buffer containing the data to write.* NumSectors Number of sectors to store.* RepeatSame Repeat the same data to all sectors.** Return value* ==0 OK, data successfully written.* !=0 An error has occurred.** Additional information* The sector data is stored at the following offsets in pData* if RepeatSame is set to 0:* Byte offset Sector index* -----------------------------------------------* 0 SectorIndex* BytesPerSector SectorIndex + 1* BytesPerSector * 2 SectorIndex + 2* BytesPerSector * 3 SectorIndex + 3* ...* BytesPerSector * (NumSectors - 1) SectorIndex + (NumSectors - 1)** If RepeatSame is set to 1 then pData points to a memory region that* is BytePerSector bytes large. This block of data has to be stored* repeatedly to the sector indexes SectorIndex to SectorIndex + (NumSectors - 1)*/staticint_Write(U8 Unit,U32 SectorIndex,constvoid*pData,U32 NumSectors,U8 RepeatSame){DRIVER_INST *pInst;FS_USE_PARA(SectorIndex);FS_USE_PARA(pData);FS_USE_PARA(NumSectors);FS_USE_PARA(RepeatSame);pInst =_apInst[Unit];returnpInst->IsInited ?0:1;}/*********************************************************************** _IoCtl** Function description* FS driver function. Execute device command.** Parameters* Unit Index of the driver instance (0-based).* Cmd Command to be executed.* Aux Parameter depending on command.* pBuffer Pointer to a buffer used for the command.** Return value* Command specific. In general a negative value means an error.** Additional information* A short description of the command parameters can be found in* the FS.h header file.*/staticint_IoCtl(U8 Unit,I32 Cmd,I32 Aux,void*pBuffer){DRIVER_INST *pInst;FS_DEV_INFO*pInfo;intr;pInst =_apInst[Unit];r =-1;FS_USE_PARA(Aux);switch(Cmd){caseFS_CMD_GET_DEVINFO:pInfo =(FS_DEV_INFO*)pBuffer;pInfo->NumHeads =pInst->NumHeads;pInfo->SectorsPerTrack =pInst->SectorsPerTrack;pInfo->NumSectors =pInst->NumSectors;pInfo->BytesPerSector =pInst->BytesPerSector;r =0;break;caseFS_CMD_UNMOUNT://// (Optional)// Device shall be unmounted - sync all operations and mark it as unmounted//_Unmount(pInst);r =0;break;caseFS_CMD_UNMOUNT_FORCED://// (Optional)// Device shall be unmounted - mark it as unmounted without syncing any pending operations//break;caseFS_CMD_SYNC://// (Optional)// Sync/flush any pending operations//break;caseFS_CMD_FREE_SECTORS://// (Optional)// The range of logical sectors passed via Aux and pBuffer store invalid data.//r =0;break;default:break;}returnr;}/*********************************************************************** _InitMedium** Function description* Initialize the specified medium.** Parameters* Unit Index of the driver instance (0-based).** Return value* ==0 OK, storage medium initialized.* !=0 An error occurred.*/staticint_InitMedium(U8 Unit){intr;DRIVER_INST *pInst;pInst =_apInst[Unit];if(pInst->IsInited ==0){r =_Init(pInst);if(r){FS_DEBUG_ERROROUT((FS_MTYPE_DRIVER,"DRV: Could not initialize the driver.\n"));return1;}pInst->IsInited =1;}return0;}/*********************************************************************** _GetStatus** Function description* Returns status the presence status of the storage device.** Parameters* Unit Index of the driver instance (0-based).** Return value* FS_MEDIA_STATE_UNKNOWN The state of the media is unknown.* FS_MEDIA_NOT_PRESENT No card is present.* FS_MEDIA_IS_PRESENT If a card is present.** Additional information* This function is relevant only for removable storage devices* such as SD cards. For other storage devices this function* can simply return FS_MEDIA_IS_PRESENT.*/staticint_GetStatus(U8 Unit){FS_USE_PARA(Unit);returnFS_MEDIA_IS_PRESENT;}/*********************************************************************** _GetNumUnits** Function description* Returns the number of driver instances.** Return value* >=0 OK, number of driver instances.* < 0 An error occurred.*/staticint_GetNumUnits(void){return_NumUnits;}/*********************************************************************** Public data************************************************************************/constFS_DEVICE_TYPEFS_TEMPLATE_Driver ={_GetDriverName,_AddDevice,_Read,_Write,_IoCtl,_InitMedium,_GetStatus,_GetNumUnits};/*************************** End of file ****************************/
Configuration of emFile
This chapter describes how to configure emFile at compile time
as well as at runtime.
General information
emFile was designed to be highly configurable in order to meet the different
requirements of target applications. Typically, the configuration is performed by
the application runtime and optionally by the user at compile time.
emFile can be used without the need for changing any of the configuration
defines at compile time. All configuration defines are preconfigured with valid
values, that meet the requirements of most the applications. Device and logical
drivers do not have to be configured at compile time. The application can added
them at runtime as required.
The default configuration of emFile can be changed at compile time by
specifying different values for the configuration defines in FS_Conf.h
that is dedicated for this purpose. This is the main configuration file for
the file system. It is not recommended to modify any file system files in order
to change the default values of the configuration defines.
Compile time configuration
This section describes the configuration defines of the File system and Storage
layer that can be used to customize the behavior of emFile. The configuration
defines of other file system components are described in their respective sections
of the emFile manual.
The following types of configuration defines exist:
Binary switches (B) - Switches can have a value of either 0 or 1,
for deactivated and activated respectively. Actually, anything other than 0 works,
but 1 makes it easier to read a configuration file. These switches can enable
or disable a certain functionality or behavior. Switches are the simplest form
of configuration defines.
Numerical values (N) - Numerical values are used somewhere in the code
in place of a numerical constant. A typical example is the configuration of
the sector size of a storage device.
Character values (C) - This is a configuration define that takes a single
character as value. A typical example is the character used to separate directory
name in a path to file or directory.
Character strings (S) - A configuration define of this type can take as
value a 0-terminated array of characters. A typical usage is a configuration
define that specify file name.
Text replacement (R) - This type of configuration define contains text to
be replaced by the preprocessor. It is typically used for functions and variable
specifiers the enable compiler specific optimizations.
Function replacement (F) - Configuration defines of this type are function
replacement macros that can also take parameters. They are typical used to
substitute at compile time the default implementation of functions used by
the file system.
General file system configuration
The following table lists the configuration defines that apply to the entire
file system.
FS_CopyFile() uses a work buffer located on the stack for reading the data
from the file to be copied. FS_BUFFER_SIZE_FILE_COPY can be used to specify
the size of this work buffer. A larger buffer provides a better performance
at the expense of increased stack usage.
FS_BUFFER_SIZE_FILE_PRINT
FS_FPrintf() uses a work buffer located on the stack for formatting the data
before is written to the file. FS_BUFFER_SIZE_FILE_PRINT can be used to specify the size
of this work buffer. A larger buffer provides a better performance at the expense
of increased stack usage.
FS_BUFFER_SIZE_FILE_WIPE
FS_WipeFile() uses a work buffer located on the stack for the random data that
is written to the file. FS_BUFFER_SIZE_FILE_WIPE can be used to specify the size
of this work buffer. A larger buffer provides a better performance at the expense
of increased stack usage.
FS_BUFFER_SIZE_TRUNCATE
FS_Truncate() uses a work buffer located on the stack for the initialization
of the extended file contents when the support for POSIX operation is enabled.
FS_BUFFER_SIZE_TRUNCATE can be used to specify the size of this work buffer.
A larger buffer provides a better performance at the expense of increased stack usage.
FS_BUFFER_SIZE_VERIFY
FS_Verify() uses a work buffer located on the stack for reading the data
from the file to be verified. FS_BUFFER_SIZE_VERIFY can be used to specify
the size of this work buffer. A larger buffer provides a better performance
at the expense of increased stack usage.
FS_DIRECTORY_DELIMITER
FS_DIRECTORY_DELIMITER defines the character that is used to separate the
names of the directories in a path to a file or directory. Typically the
value of this define is set either to ’\’ or to ’/’.
FS_DRIVER_ALIGNMENT
The value of this define is used by the file system to check if a 0-copy
operation can be executed. A 0-copy operation is performed only when the
address of the data is aligned to FS_DRIVER_ALIGNMENT and the number of
data bytes in the block is a multiple of the logical sector size.
If the data to be read or written is not aligned to FS_DRIVER_ALIGNMENT
then the file system uses the internal sector buffers for the data transfers
which is typically slower in comparison with a 0-copy operation.
FS_FILL_PATTERN_UNUSED_DATA
The value of this define is used by the file system to initialize all the
unused bytes of the logical sector that stores the data located at the end
of a file that has a size which is not multiple of a logical sector size.
FS_MAX_LEN_FULL_FILE_NAME
This configuration define is used when FS_MULTI_HANDLE_SAFE is set to 1
to reserve space for the fully qualified file name in the file object
assigned to an opened file. The value specified via this configuration define
is also used by the BigFAT component to reserves space in the file handle
for the name of the opened file.
FS_MAX_LEN_VOLUME_ALIAS
This configuration define specifies the maximum number of characters
allowed in a volume alias including the 0-terminator. If set to 0 then
only a reference to the volume alias is stored. A volume alias can be
set via FS_SetVolumeAlias(). The RAM usage of the file system increases if
this configuration define is set to a value different than 0.
The volume alias feature can be enabled via FS_SUPPORT_VOLUME_ALIAS.
FS_MAX_PATH
FS_MAX_PATH specifies the maximum number of characters in a path to a file
or directory including the 0-terminator. It is used for example by FS_CreateDir()
for allocating a work buffer for path processing.
FS_MULTI_HANDLE_SAFE
This configuration define has to be set to 1 if the application is expected
to write and read from a file at the same time. Activating this feature
increases the RAM usage of the file system. For more information refer to
Resource usage.
FS_NUM_DIR_HANDLES
The value of this configuration define specifies the maximum of directory
handles that can be opened at the same time via FS_OpenDir(). Please note
that FS_OpenDir() is deprecated. It is recommended that the applications
use FS_FindFirstFile() and FS_FindNextFile() instead for listing the contents
of a directory.
FS_NUM_VOLUMES
FS_NUM_VOLUMES specifies the maximum number of volumes the file system can handle.
This value is currently used only by the Journaling component and it represents
the maximum number of volumes on which the journal can be enabled.
FS_OPTIMIZATION_TYPE
This configuration define can be used to modify multiple configuration defines at
once in order to configure the file system operation for a specified goal such
as reduced memory usage or increased speed. If FS_OPTIMIZATION_TYPE is set to
FS_OPTIMIZATION_TYPE_BALANCED then the configuration defines are set as
documented in the “Default value” column of the summary table that documents
that define.
With FS_OPTIMIZATION_TYPE set to FS_OPTIMIZATION_TYPE_MIN_SIZE the configuration
defines are set as in the following table.
Define
Value
FS_SUPPORT_FREE_SECTOR
0
FS_SUPPORT_CACHE
0
FS_MAX_LEN_FULL_FILE_NAME
64
FS_SUPPORT_BUSY_LED
0
FS_SUPPORT_FILE_BUFFER
0
FS_SUPPORT_VOLUME_ALIAS
0
FS_NUM_VOLUMES
1
FS_BUFFER_SIZE_VERIFY
32
FS_BUFFER_SIZE_FILE_COPY
32
FS_BUFFER_SIZE_FILE_WIPE
32
FS_BUFFER_SIZE_TRUNCATE
32
FS_BUFFER_SIZE_PRINT
32
FS_DEBUG_LEVEL
0
FS_JOURNAL_SUPPORT_FREE_SECTOR
0
FS_JOURNAL_SUPPORT_FAST_SECTOR_SEARCH
0
FS_FAT_SUPPORT_FAT32
0
FS_FAT_USE_FSINFO_SECTOR
0
FS_FAT_OPTIMIZE_DELETE
0
FS_FAT_OPTIMIZE_LINEAR_ACCESS
0
FS_FAT_SUPPORT_FREE_CLUSTER_CACHE
0
FS_FAT_LFN_BIT_ARRAY_SIZE
32
FS_FAT_LFN_LOWER_CASE_SHORT_NAMES
0
FS_EFS_OPTIMIZE_DELETE
0
FS_EFS_SUPPORT_STATUS_SECTOR
0
FS_EFS_SUPPORT_DIRENTRY_BUFFERS
1
FS_EFS_OPTIMIZE_LINEAR_ACCESS
0
FS_NO_CLIB
1
FS_NAND_NUM_UNITS
1
FS_NAND_SUPPORT_CLEAN
0
FS_NAND_ECC_HOOK_DEFAULT
NULL
FS_NAND_SUPPORT_BLOCK_GROUPING
0
FS_NAND_SUPPORT_FAST_WRITE
0
FS_NAND_SPI_DEVICE_LIST_DEFAULT
NULL
FS_NAND_SUPPORT_EXT_ONFI_PARA
0
FS_NAND_ONFI_DEVICE_LIST_DEFAULT
NULL
FS_NAND_2048X8_DEVICE_LIST_DEFAULT
NULL
FS_NOR_NUM_UNITS
1
FS_NOR_SUPPORT_CLEAN
0
FS_NOR_SKIP_BLANK_SECTORS
0
FS_NOR_NUM_FREE_SECTORCACHE
32
FS_NOR_SUPPORT_FORMAT
0
FS_NOR_MAX_SECTOR_BLOCKS
1
FS_NOR_DEVICE_LIST_DEFAULT
NULL
FS_NOR_OPTIMIZE_DATA_WRITE
0
FS_MMC_NUM_UNITS
1
FS_IDE_NUM_UNITS
1
FS_RAMDISK_NUM_UNITS
1
FS_WINDRIVE_NUM_UNITS
1
FS_CRYPT_NUM_UNITS
1
FS_CRYPT_AES_OPTIMIZE_MIX_SUBST
0
FS_LOGVOL_NUM_UNITS
1
FS_READAHEAD_NUM_UNITS
1
FS_DISKPART_NUM_UNITS
1
FS_RAID_NUM_UNITS
1
FS_SECSIZE_NUM_UNITS
1
FS_WRBUF_NUM_UNITS
1
With FS_OPTIMIZATION_TYPE set to FS_OPTIMIZATION_TYPE_MAX_SPEED the configuration
defines are set as in the following table.
Define
Value
FS_SUPPORT_SECTOR_BUFFER_BURST
1
FS_SUPPORT_SECTOR_BUFFER_CACHE
1
FS_EFS_SUPPORT_FREE_CLUSTER_CACHE
1
FS_CRYPT_AES_OPTIMIZE_MIX_COLUMNS
2
FS_NOR_OPTIMIZE_EMPTY_CHECK
1
The configuration defines that are not listed in the above tables are left to their default values.
These values can be assigned at compile-time to the FS_OPTIMIZATION_TYPE
configuration define.
FS_OPTIMIZE
The declaration of some of the computing intensive file system functions is
prefixed with this configuration define. The application can set it to a compiler
specific specifier that makes the function runs faster such as executing the
function from RAM.
FS_SUPPORT_BUSY_LED
FS_SUPPORT_BUSY_LED can be used to enable or disable the support for a callback
function that is invoked by the file system at the beginning and at the end of
a sector read or write operation. As the name of this configuration define
suggests the registered callback function can be used to indicate that the
file system is busy accessing the storage device by turning an LED on and off.
The callback function must be registered at runtime via FS_SetBusyLEDCallback()
FS_SUPPORT_CACHE
This configuration define can be used to enable or disable the support for
sector cache. The sector cache must be enabled at runtime by the application.
Refer to Sector cache for more information about this.
FS_SUPPORT_CHECK_MEMORY
FS_SUPPORT_CHECK_MEMORY can be used to enable or disable additional checks
on the data subject to 0-copy operations. The check is performed by a callback
function registered by the application via FS_SetMemAccessCallback().
If FS_SUPPORT_CHECK_MEMORY is set to 1 then the callback is invoked on each
read and write operation to check if a 0-copy operation can be performed.
FS_SUPPORT_DEINIT
By default the file system does not free any resources it allocates at runtime
such as dynamic memory. By setting FS_SUPPORT_DEINIT to 1 support is enabled
in the file system for freeing the allocated resources. This can be useful when
the application does not longer use the file system and the resources are required
for other purposes. The application can free the resources at runtime by calling
FS_DeInit(). If the application wishes to use the file system again it has to call
FS_Init() before doing this in order to reallocate the resources.
FS_SUPPORT_EFS
This configuration define can be used to enable or disable the support for
the EFS file system. The support for EFS file system is disabled by default.
FS_SUPPORT_EXFAT
This configuration define can be used to enable or disable the support for
the exFAT file system. The support for exFAT file system is disabled by default.
FS_SUPPORT_EXT_ASCII
FS_SUPPORT_EXT_ASCII can be used to enable or disable the support for extended
ASCII characters in the file names. Extended ASCII characters are characters
with a value between 128 and 255. Typically, this is the range where the
language-specific characters are stored. The file system requires this
information for the case insensitive comparison of the file names.
If the application uses file names that contain only ASCII characters that is
with a value between 0 and 127 then FS_SUPPORT_EXT_ASCII can be set to 0 which
is the default. Setting FS_SUPPORT_EXT_ASCII to 1 increases the ROM usage
of the file system.
The support for extended ASCII characters is automatically enabled
if the support for the exFAT file system is enabled via FS_SUPPORT_EXFAT.
FS_SUPPORT_EXT_MEM_MANAGER
This configuration define can be used to enable or disable the support for
external memory allocation. By default the file system uses a very simple
internal memory allocator that is suitable for any embedded application.
If FS_SUPPORT_EXT_MEM_MANAGER is set to 1 then the application can configure
at runtime a pair of callback functions for the management of the memory
allocation. This can be realized vis FS_SetMemHandler().
FS_SUPPORT_FAT
This configuration define can be used to enable or disable the support for
the FAT file system. The support for FAT file system is enabled by default.
FS_SUPPORT_FILE_BUFFER
This configuration define controls the activation of the file buffer functionality.
File buffers make the access to a file faster when the application is reading
or writing small amounts of data. Enabling this functionality increases the ROM
and RAM usage of the file system. The file buffer functionality has to be
explicitly enabled at runtime. For more information refer to File buffer.
FS_SUPPORT_FILE_BUFFER_LIST
This configuration define controls how the file system manages the file buffers
it allocates for each opened file handle.
By default a file buffer is allocated when a file handle is created for the first
time and remains attached to this file handle until the file system is deinitialized.
This is the case when FS_SUPPORT_FILE_BUFFER_LIST set to 0 which is the default.
By building the file system with FS_SUPPORT_FILE_BUFFER_LIST set to 1 the file buffers
are managed via a dedicated list. This allows an application to detach a file buffer
from a opened file handle via FS_UnsetFileBuffer() if a file buffer is not required for
the access to the file data. In this way the file buffer is made available to another
file handle that may make use of it.
The RAM usage of the file system increases by six bytes per file buffer with
FS_SUPPORT_FILE_BUFFER_LIST set to 1
FS_SUPPORT_FILE_NAME_ENCODING
FS_SUPPORT_FILE_NAME_ENCODING can be used to enable the support for encoded
file names such as UTF-8 and Shift JIS. The encoding type of the file and
directory names has to be configured at runtime via FS_FAT_SetLFNConverter()
or FS_EFS_SetFileNameConverter()
FS_SUPPORT_FREE_SECTOR
If FS_SUPPORT_FREE_SECTOR is set to 1 then the file system informs the
device and logical drivers about the unused sectors. For example when
a file is deleted the file system sends a notification to the driver
indicating that the range or ranges of sectors that were used to
store the file contents are no longer in use. The driver can use
this information to optimize the management of data. Not all the
drivers make use of this information. This functionality is similar
to the TRIM command of the ATA command set.
FS_SUPPORT_GPT
This configuration define can be used to enable the support for GUID
partition tables. With FS_SUPPORT_GPT set to 0 the file system is
able to handle only MBR partition tables.
FS_SUPPORT_LARGE_FILES
This configuration define can be used to enable the support for files
with a size larger than or equal to 4GB. By default, the support for large
files is disabled because the maximum file size supported by the FAT
and the EFS file systems is smaller than 4GB.
The support for large files is automatically enabled if the support
for the exFAT file system is enabled via FS_SUPPORT_EXFAT.
It is not required to enable the support for large files when using
the BigFAT component.
FS_SUPPORT_MBCS
This configuration define can be used to enable the support for file and
directory names that use multi-byte character sets. Enabling this feature
increases the ROM usage of the file system. The type of character set
used by the file system can be configured at runtime via FS_SetCharSetType().
FS_SUPPORT_POSIX
This configuration define can be used to change the behavior of the API functions
so that they work in the same way as their equivalent POSIX function. The POSIX
behavior is enabled by setting FS_SUPPORT_POSIX to 1. The behavior can also be
changed at runtime using FS_ConfigPOSIXSupport().
FS_SUPPORT_SECTOR_BUFFER_BURST
This configuration define can be used to enable the internal sector buffers
to access more than one logical sector at once. Currently, this feature is
used only for accelerating the calculation of the free space via FS_GetVolumeInfoEx()
when the application specifies a work buffer.
FS_SUPPORT_SECTOR_BUFFER_CACHE
The FS_SUPPORT_SECTOR_BUFFER_CACHE configuration define can be used to activate
a cache that stores information about the data present in the internal sector
buffers of the file system. Enabling this feature can help accelerate file system
operations that access the same logical sector such as the creation or removal
of files located in the same directory.
FS_SUPPORT_VOLUME_ALIAS
This configuration define can be used to enable the setting of an alternative
name for a volume name. The configured volume alias can then be used as a
replacement for the volume name in a path to a file or directory or to identify
a volume in a call to an API function that requires a volume name. A volume alias
can be set via FS_SetVolumeAlias(). The configured volume alias can be obtained
either via FS_GetVolumeInfo() or FS_GetVolumeAlias().
FS_SUPPRESS_EOF_ERROR
FS_SUPPRESS_EOF_ERROR can be used to configure the file system to not generate
an error in case of an end-of-file condition. An end-of-file condition occurs
when the application is trying to read past the end of file. If FS_SUPPRESS_EOF_ERROR
is set to 1 then no FS_ERRCODE_EOF error is reported via FS_FError().
The handling of an end-of-file condition can be changed at runtime via
FS_ConfigEOFErrorSuppression().
FS_VERIFY_WRITE
FS_VERIFY_WRITE can be used for testing purposes to verify if the sector data
was correctly written to storage. If the configuration define is set to 1
the file system reads back and compares the contents of each written logical
sector to the sector data actually written. Enabling this functionality can
potentially have a negative impact on the write performance of the file system.
Therefore SEGGER recommends to enable it only when investigating a problem
related to the file system. In addition, the write verification can be enabled
and disabled at runtime via FS_ConfigWriteVerification(). The write verification
requires a work buffer of the logical sector size that is allocated dynamically
at runtime from the memory pool assigned to the file system.
FAT configuration
This section describes the configuration defines specific to the FAT file system.
Additional entries in the Unicode letter case conversion table.
FS_FAT_CHECK_UNUSED_DIR_ENTRIES
This configuration define can be used to enable additional verification
steps of a directory contents. By default the disk checking operation stops
the processing of a directory as soon as it reaches the first unused directory
entry. If FS_FAT_CHECK_UNUSED_DIR_ENTRIES is set to 1 then the disk checking
operation verifies that all the directory entries located after the first unused
directory entry are also marked as not in used. Enabling this feature can
potentially increase the time required for the disk checking operation to complete.
FS_FAT_LFN_LOWER_CASE_SHORT_NAMES
This configuration define specifies how the file system handles the creation
of files or directories with names consisting only of small letters and punctuation
that fit in 8.3 format. If FS_FAT_LFN_LOWER_CASE_SHORT_NAMES
is set to 1 then the file system creates only a short directory entry for
the file or directory name if it consists only of small letters and punctuation
characters. This is done in order to save storage space. The information about
the case of the letters in the name is preserved.
If FS_FAT_LFN_LOWER_CASE_SHORT_NAMES is set to 0 then in addition to the short
entry a long file name entry is generated.
The described handling is available only when the support for long file
name is enabled via FS_FAT_SupportLFN().
FS_FAT_LFN_BIT_ARRAY_SIZE
FS_FAT_LFN_BIT_ARRAY_SIZE can be used to specify the size of the work buffer of the functionality
that generates short file names from long file names. The value represents size in bits of the array
used to remember the index of the short file names found. The work buffer is allocated on the stack.
FS_FAT_LFN_MAX_SHORT_NAME
The short names generated automatically by the file system for each long file name
have a prefix that consists of the first characters of the long file name followed
by an generated index. FS_FAT_LFN_MAX_SHORT_NAME can be used to specify the maximum
value of that index. The maximum index value of a short file name is
FS_FAT_LFN_MAX_SHORT_NAME + FS_FAT_LFN_BIT_ARRAY_SIZE - 1.
FS_FAT_LFN_UNICODE_CONV_DEFAULT
FS_FAT_LFN_UNICODE_CONV_DEFAULT specifies the set of routines to be used for
the conversion of file name characters to Unicode. It can be set to NULL
in order to save ROM space if the file names are encoded using another code page.
In this case, the application must specify a Unicode converter at runtime via
FS_FAT_SetLFNConverter().
FS_FAT_OPTIMIZE_LINEAR_ACCESS
FS_FAT_OPTIMIZE_LINEAR_ACCESS can be used to enable or disable an optimization that
caches the ids of clusters allocated linearly for a file. Enabling this optimization
can improve read and write performance of the file system by reducing the number
of accesses to the allocation table.
FS_FAT_OPTIMIZE_LINEAR_ACCESS can take the values 0 and 1. The optimization
is disabled if FS_FAT_OPTIMIZE_LINEAR_ACCESS is set to 0. With FS_FAT_OPTIMIZE_LINEAR_ACCESS
set to 1, which is the default value, the file system caches only the the ids of the
linearly allocated clusters that are located after the current file position.
FS_FAT_OPTIMIZE_DELETE
FS_FAT_OPTIMIZE_DELETE can be used to enable or disable an optimization related
to the deletion of large files. If FS_FAT_OPTIMIZE_DELETE is set to 1 the delete
operation is accelerated by updating the allocation table at once if possible.
FS_FAT_OPTIMIZE_DELETE can be set to 0 for applications that do not deal with
large files in order to reduce the ROM usage.
FS_FAT_PERMIT_RO_FILE_MOVE
By default the files and directories with the read-only file attribute set can not
be moved or renamed via the API functions FS_Move() and FS_Rename() respectively.
If FS_FAT_PERMIT_RO_FILE_MOVE is set to 1 then the read-only file attribute is ignored
and the files and directories with this attribute set can be moved and renamed.
This behavior can also be modified at runtime via FS_FAT_ConfigROFileMovePermission()
FS_FAT_SUPPORT_FAT32
FS_FAT_SUPPORT_FAT32 can be used to enable or disable the handling of FAT32 formatted
volumes. If FS_FAT_SUPPORT_FAT32 is set to 0 then the file system will not be able
to recognize volumes formatted as FAT32. In this case the file system will also not
be able to format a volume as FAT32.
FS_FAT_SUPPORT_FREE_CLUSTER_CACHE
This configuration define can be used to enable or disable an optimization related
to the handling of the allocation table. If FS_FAT_SUPPORT_FREE_CLUSTER_CACHE is set to 1
then the file system caches the information about which clusters are free in order
to reduce the number of accesses to the allocation table. This functionality is used
only in the FAST write mode. In the SAFE or MEDIUM write modes the functionality is not
used even when enabled at compile time. FS_FAT_SUPPORT_FREE_CLUSTER_CACHE can be set to 0
in order to reduce the ROM usage.
FS_FAT_UPDATE_DIRTY_FLAG
If FS_FAT_UPDATE_DIRTY_FLAG is set 1 then the file system sets a dirty flag in the Boot
Parameter Block (BPB) of the FAT volume on the first write operation to indicate that
the volume has been modified and that the file system may not have updated all the information
to the storage device. The dirty flag is cleared later when FS_Unmount(), FS_UnmountForced(),
FS_Sync(), or FS_DeInit() is called. The application can query the volume dirty flag using
FS_GetVolumeInfo(). A dirty flag set to 1 at file system mount indicates that the file system
was not properly unmounted before reset. In this case, it is recommended to call FS_CheckDisk()
to check the integrity of the file system structure.
The feature can also be enabled or disabled at runtime via FS_FAT_ConfigDirtyFlagUpdate().
FS_FAT_UPDATE_DIRTY_FLAG can be set to 0 to reduce the ROM usage.
FS_FAT_USE_FSINFO_SECTOR
FS_FAT_USE_FSINFO_SECTOR can be used to enable or disable the handling of the information
stored to FSInfo sector of a volume formatted as FAT32. The FSInfo sector stores information
about the number of free clusters and the index of the first free cluster. This information
can be used to accelerate the calculation of available free space. If the information stored
in the FSInfo sector is not valid then the file system falls back to calculating the free
space by evaluating the entire contents of the allocation table that may take a relatively
long time to complete on large capacity volumes.
FS_FAT_USE_FSINFO_SECTOR can be safely set to 0 to reduce ROM usage without affecting the
correct operation of the file system.
FS_MAINTAIN_FAT_COPY
This configuration define can be used to enable or disable the update of the backup allocation
table of a FAT file system. It FS_MAINTAIN_FAT_COPY is set to 1 then the file system updates
the main as well as the backup allocation table. The backup allocation table is not evaluated
by the emFile but some other file systems my fail to mount a volume it the backup allocation
is not present and up to date. This feature can also be enabled or disabled at runtime via
FS_FAT_ConfigFATCopyMaintenance().
Setting FS_MAINTAIN_FAT_COPY to 0 increases the write performance and reduces the ROM usage.
FS_UNICODE_UPPERCASE_EXT
The long file name component of the file system uses a table allocated in ROM for the case
conversion of Unicode letters. In order to save ROM space this table does not contain entries
for every possible letter supported by Unicode. FS_UNICODE_UPPERCASE_EXT can be used to extend
this table with new entries. Each entry is an initializer for a C structure containing two
16-bit values. The first value is the code point of the small letter and the second value is
the code point of corresponding capital letter. The entries are separated by comma characters.
The last entry must always be {0x0000, 0x0000} which is the end of table indicator.
EFS configuration
This section describes the configuration defines specific to the EFS file system.
FS_EFS_CASE_SENSITIVE specifies if the comparison of file or directory names should consider
the case of the letters or not. It FS_EFS_CASE_SENSITIVE is set to 0 then the case of the letters
in a file or directory name is not relevant. That is TEST.TXT and test.txt represent
the same file. It FS_EFS_CASE_SENSITIVE is set to 1 the TEST.TXT, test.txt and TEST.txt
represent different file names. This feature can also be enabled or disabled at runtime via
FS_EFS_ConfigCaseSensitivity().
FS_EFS_MAX_DIR_ENTRY_SIZE
FS_EFS_MAX_DIR_ENTRY_SIZE can be used to specify the maximum directory entry size.
The minimum size of a directory entry is 21 bytes while the maximum is 255 bytes.
The first 20 bytes in the directory store the size of the file, attributes, time
stamps, etc. The remaining bytes are used to store the file name.
FS_EFS_NUM_DIRENTRY_BUFFERS
FS_EFS_NUM_DIRENTRY_BUFFERS specifies the number of work buffers the file system
has to allocate for the handling of directory entries. The value of this configuration
define is evaluated only when FS_EFS_SUPPORT_DIRENTRY_BUFFERS is set to 1.
FS_EFS_OPTIMIZE_DELETE
FS_EFS_OPTIMIZE_DELETE can be used to enable or disable an optimization related
to the deletion of large files. If FS_EFS_OPTIMIZE_DELETE is set to 1 the delete
operation is accelerated by updating the allocation table at once if possible.
FS_EFS_OPTIMIZE_DELETE can be set to 0 for applications that do not deal with
large files in order to reduce the ROM usage.
FS_EFS_OPTIMIZE_LINEAR_ACCESS
FS_EFS_OPTIMIZE_LINEAR_ACCESS can be used to enable or disable an optimization that
caches the ids of clusters allocated linearly for a file. Enabling this optimization
can improve read and write performance of the file system by reducing the number
of accesses to the allocation table.
FS_EFS_OPTIMIZE_LINEAR_ACCESS can take the values 0 and 1. The optimization
is disabled if FS_EFS_OPTIMIZE_LINEAR_ACCESS is set to 0. With FS_EFS_OPTIMIZE_LINEAR_ACCESS
set to 1, which is the default value, the file system caches only the the ids of the
linearly allocated clusters that are located after the current file position.
FS_EFS_SUPPORT_STATUS_SECTOR
This configuration define can be used to enable or disable the handling of
the Status sector of an EFS formatted volume. The status sector is the
equivalent of FSInfo sector for FAT32 formatted volumes. It stores information
about the the number of free clusters. This information is used by the file
system to accelerate the operation that calculates the available free space.
The handling of the Status sector can also be enabled or disabled at runtime
via FS_EFS_ConfigStatusSectorSupport().
FS_EFS_SUPPORT_DIRENTRY_BUFFERS
FS_EFS_SUPPORT_DIRENTRY_BUFFERS can be used to specify where the work buffers
for the handling of directory entries are allocated. If FS_EFS_SUPPORT_DIRENTRY_BUFFERS
is set to 1 the the work buffers are allocated from the memory pool of file
system. Each work buffer is FS_EFS_MAX_DIR_ENTRY_SIZE + 1 bytes large.
If FS_EFS_SUPPORT_DIRENTRY_BUFFERS is set to 0 then the work buffers are
allocated on the stack which is the default.
FS_EFS_SUPPORT_FREE_CLUSTER_CACHE
This configuration define can be used to enable or disable an optimization related
to the handling of the allocation table. If FS_EFS_SUPPORT_FREE_CLUSTER_CACHE is set to 1
then the file system caches the information about which clusters are free in order
to reduce the number of accesses to the allocation table. This functionality is used
only in the FAST write mode. In the SAFE or MEDIUM write modes the functionality is not
used even when enabled at compile time. FS_EFS_SUPPORT_FREE_CLUSTER_CACHE can be set to
0 in order to reduce the ROM usage.
exFAT configuration
This section describes the configuration defines specific to the exFAT file system.
Enables/disables support for space usage maintenance.
FS_EXFAT_FILE_NAME_CONV_DEFAULT
FS_EXFAT_FILE_NAME_CONV_DEFAULT specifies the set of routines to be used for
the conversion of file name characters to Unicode. It can be set to NULL
in order to save ROM space if the file names are encoded using another code page.
In this case, the application must specify a Unicode converter at runtime via
FS_EXFAT_SetFileNameConverter().
FS_EXFAT_OPTIMIZE_LINEAR_ACCESS
FS_EXFAT_OPTIMIZE_LINEAR_ACCESS can be used to enable or disable an optimization that
caches the ids of clusters allocated linearly for a file. Enabling this optimization
can improve read and write performance of the file system by reducing the number
of accesses to the allocation table.
FS_EXFAT_OPTIMIZE_LINEAR_ACCESS can take the values 0 and 1. The optimization
is disabled if FS_EXFAT_OPTIMIZE_LINEAR_ACCESS is set to 0. With FS_EXFAT_OPTIMIZE_LINEAR_ACCESS
set to 1, which is the default value, the file system caches only the the ids of the
linearly allocated clusters that are located after the current file position.
FS_EXFAT_PERMIT_RO_FILE_MOVE
By default the files and directories with the read-only file attribute set can not
be moved or renamed via the API functions FS_Move() and FS_Rename() respectively.
If FS_EXFAT_PERMIT_RO_FILE_MOVE is set to 1 then the read-only file attribute is ignored
and the files and directories with this attribute set can be moved and renamed.
This behavior can also be modified at runtime via FS_EXFAT_ConfigROFileMovePermission()
FS_EXFAT_SUPPORT_FREE_CLUSTER_CACHE
This configuration define can be used to enable or disable an optimization related
to the handling of the allocation table. If FS_EXFAT_SUPPORT_FREE_CLUSTER_CACHE is set to 1
then the file system caches the information about which clusters are free in order
to reduce the number of accesses to the allocation table. This functionality is used
only in the FAST write mode. In the SAFE or MEDIUM write modes the functionality is not
used even when enabled at compile time. FS_EXFAT_SUPPORT_FREE_CLUSTER_CACHE can be set to 0
in order to reduce the ROM usage.
FS_EXFAT_UPDATE_DIRTY_FLAG
If FS_EXFAT_UPDATE_DIRTY_FLAG is set 1 then the file system sets a dirty flag in the boot
sector of the exFAT volume on the first write operation to indicate that
the volume has been modified and that the file system may not have updated all the information
to the storage device. The dirty flag is cleared later when FS_Unmount(), FS_UnmountForced(),
FS_Sync(), or FS_DeInit() is called. The application can query the volume dirty flag using
FS_GetVolumeInfo(). A dirty flag set to 1 at file system mount indicates that the file system
was not properly unmounted before reset. In this case, it is recommended to call FS_CheckDisk()
to check the integrity of the file system structure.
The feature can also be enabled or disabled at runtime via FS_EXFAT_ConfigDirtyFlagUpdate().
FS_EXFAT_UPDATE_DIRTY_FLAG can be set to 0 to reduce the ROM usage.
FS_EXFAT_UPDATE_SPACE_USAGE
FS_EXFAT_UPDATE_SPACE_USAGE can be used to enable or disable the maintenance of the information
about the used storage space. This information is stored in the boot sector of the volume
and it can be used by the file system to accelerate the calculation of available free space.
If the information stored in the boot sector is not valid, then the file system falls back
to calculating the free space by evaluating the entire contents of the Allocation Bitmap.
The Allocation Bitmap stores information about the allocation status of the file system clusters.
Scanning the Allocation Bitmap may take a relatively long time to complete on large capacity volumes.
Enables/disables the support for mounting the storage device.
FS_STORAGE_ENABLE_STAT_COUNTERS
This configuration define can be used to enable the statistical counters of
the Storage layer. The statistical counters are enabled by default when the
file system is configured at compile time with FS_DEBUG_LEVEL set to a value
greater than or equal to FS_DEBUG_LEVEL_CHECK_PARA. The statistical counters
can be queried using FS_STORAGE_GetCounters() and cleared using FS_STORAGE_ResetCounters()
FS_STORAGE_SUPPORT_DEVICE_ACTIVITY
FS_STORAGE_SUPPORT_DEVICE_ACTIVITY enables or disables the support for a callback
that is invoked by the file system at each sector read or write operation.
The callback function can be registered by the application at runtime via
FS_STORAGE_SetOnDeviceActivityCallback(). The support for the device
activity callback is enabled by default at compile time when the file system
is configured with FS_DEBUG_LEVEL set to a value greater than or equal to
FS_DEBUG_LEVEL_CHECK_PARA.
Enables/disables standard C function replacements.
FS_STRCHR(s, c)
F
strchr(s, c)
Replaces strchr() standard C function.
FS_STRCMP(s1, s2)
F
strcmp(s1, s2)
Replaces strcmp() standard C function.
FS_STRCPY(s1, s2)
F
strcpy(s1, s2)
Replaces strcpy() standard C function.
FS_STRLEN(s)
F
strlen(s)
Replaces strlen() standard C function.
FS_STRNCAT(s1, s2, n)
F
strncat(s1, s2, n)
Replaces strncat() standard C function.
FS_STRNCMP(s1, s2, n)
F
strncmp(s1, s2, n)
Replaces strncmp() standard C function.
FS_STRNCPY(s1, s2, n)
F
strncpy(s1, s2, n)
Replaces strncpy() standard C function.
FS_TOLOWER(c)
F
tolower(c)
Replaces tolower() standard C function.
FS_TOUPPER(c)
F
toupper(c)
Replaces toupper() standard C function.
FS_ISLOWER(c)
F
islower(c)
Replaces islower() standard C function.
FS_ISUPPER(c)
F
isupper(c)
Replaces isupper() standard C function.
FS_VSNPRINTF(s, n, f, a)
F
SEGGER_vsnprintf(s, n, f, a)
Replaces vsnprintf() standard C function.
FS_NO_CLIB
emFile uses functions of the standard C library to preform specific
operations. If FS_NO_CLIB is set to 1 then the file system calls internal
functions instead to perform these operations instead of the equivalent
standard C library functions.
CRC function replacement
This section describes the configuration defines that can be used to replace
the internal CRC calculations functions used by emFile.
Define
Type
Default value
Description
FS_CRC32_CALC(pData, NumBytes, crc)
F
FS_CRC32_Calc(pData, NumBytes, crc)
32-bit CRC that uses the polynomial 0x04C11DB7 (CRC-32)
FS_CRC16_CCITT_CALC(pData, NumBytes, crc)
F
FS_CRC16_CCITT_Calc(pData, NumBytes, crc)
16-bit CRC that uses the polynomial 0x1021 (CRC-16-CCITT)
FS_CRC16_ANSI_CALC(pData, NumBytes, crc)
F
FS_CRC16_ANSI_Calc(pData, NumBytes, crc)
16-bit CRC that uses the polynomial 0x8005 (CRC-16-ANSI)
FS_CRC8_CCITT_CALC(pData, NumBytes, crc)
F
FS_CRC8_CCITT_Calc(pData, NumBytes, crc)
8-bit CRC that uses the polynomial 0x07 (CRC-8-CCITT)
Sample configuration
A sample configuration file FS_Conf.h can be found in the Config
folder of the emFile shipment. If you want to change the default
configuration, insert the corresponding configuration defines in this file.
/********************************************************************** (c) SEGGER Microcontroller GmbH ** The Embedded Experts ** www.segger.com ***********************************************************************-------------------------- END-OF-HEADER -----------------------------File : FS_Conf.hPurpose : emFile compile time configuration.*/#ifndefFS_CONF_H#defineFS_CONF_H // Avoid multiple inclusion//// Enable the EFS file system.//#defineFS_SUPPORT_FAT 0#defineFS_SUPPORT_EFS 1#endif// Avoid multiple inclusion/*************************** End of file ****************************/
Runtime configuration
The runtime configuration of the file system is realized via a set of functions
that have to be implemented by the application according to its requirements.
This section describes these functions in detail.
emFile comes with sample implementations that can be used as a starting
point for creating a custom file system configuration. Every folder of the
emFile shipment that contain sample hardware layer implementations
also contain a suitable configuration file (e.g. Sample/FS/RAM/FS_ConfigRamDisk.c)
with implementations of runtime configuration functions explained in this chapter.
The configuration files can be used without modification, to run emFile “out of the box”.
The following table lists the names of the functions that have to be provided by
the application followed by a detailed description of these functions.
Additional functions are required to be implemented by the application
if the emFile is configured to generate debug messages. For additional
information refer to Debug messages
API functions that access a storage device may not be called in
FS_X_AddDevices() because the device drivers may not be ready
at this point to perform any data transfers.
Current time and date in a format suitable for the file system.
Additional information
This function is called by the file system in order to generate
the time stamps for the accessed files and directories.
FS_X_GetTimeDate() is not required when the application accesses
the storage device only via the Storage layer and not via the
File system layer.
Alternatively, the application can register a runtime a callback
function via FS_SetTimeDateCallback() that returns the date and time.
The return value is formatted as follows:
Bit range
Description
0-4
2-second count (0-29)
5-10
Minutes (0-59)
11-15
Hours (0-23)
16-20
Day of month (1-31)
21-24
Month of year (1-12)
25-31
Count of years from 1980 (0-127)
OS integration
This chapter provides information about how to configure emFile
to work in a multitasking application.
General information
emFile does not require an operating system to work. However, when
an application uses two or more tasks to concurrently access the file system
then these accesses have to be synchronized in order to prevent a corruption
of the file system structure. The access to the file system is synchronized via
a set of API functions called OS layer. The implementation of the OS layer is
specific to the OS used by the application. emFile comes with ready to
use OS layers for SEGGER embOS and Micrium uC/OS. The implementation of these
OS layers can be found in the Sample/FS/OS folder of the emFile
shipment. Support for other operating systems is available on request.
Compile time configuration
By default, the support for OS is disabled in emFile because the majority
of the applications either use only one task or if they use multiple tasks only
one task accesses the file system at a time. Therefore, the OS support has to be
explicitly enabled at compile time. The following table lists the configuration
defines that can be used for this.
Setting FS_OS_LOCKING to FS_OS_LOCKING_NONE disables the OS support.
This is the default value. The OS layer is not required in this case.
If FS_OS_LOCKING is set to FS_OS_LOCKING_API or FS_OS_LOCKING_DRIVER then
the support for OS is enabled and an OS layer is required.
With FS_OS_LOCKING set to FS_OS_LOCKING_API (coarse lock granularity) the file
system requires only one OS synchronization object. The task synchronization
takes place in API layer. The file system is locked at the beginning of an API
function an unlocked upon return. This means that only one task can execute a
file system operation at a time. The API functions of the device and logical
driver do not lock the file system. These are the functions that are described
in the Device drivers and Logical drivers sections. It is the
responsibility of the application to lock the file system by using either
FS_Lock()/FS_Unlock() or FS_LockVolume()/FS_UnlockVolume() when calling one
of the driver API functions.
With FS_OS_LOCKING set to FS_OS_LOCKING_DRIVER (fine lock granularity) an OS
synchronization object is required for each device or logical driver type
configured by the application. In addition an OS synchronization object is
required for the protection of the internal file system resources that are
shared between the tasks. In this locking mode the task synchronization
takes place at driver level and every time a task accesses an internal shared
resource such as sector buffer or file handle.
It is recommended to use this type of locking only when the file system is
configured to use different storage device types such as NOR and NAND flash,
SD card and NAND flash etc. This type of locking cannot be used when the same
storage device is accessed via two different logical drivers. For example
when a NAND flash device is partitioned in two and the first partition is
accessed via the Encryption driver and the second via the RAID1 driver
Locking is performed at API function level (coarse locking).
FS_OS_LOCKING_DRIVER
Locking is performed at device driver level (fine locking).
Additional information
These values can be assigned at compile-time to the FS_OS_LOCKING
configuration define.
Runtime configuration
emFile requires an OS layer specific to the OS used by the application
if FS_OS_LOCKING is set to a value different than 0 at compile time. The OS layer
is responsible for providing the OS specific synchronization routines the file
system can use to make sure that only one task executes a critical section
of the file system.
The following table lists the functions of the OS layer followed by a detailed
description of each function.
This function has to be implemented by any OS layer.
FS_X_OS_Init() is called during the file system initialization.
It has to create the number of specified OS synchronization objects.
The type of the OS synchronization object is not relevant as long
as it can be used to protect a critical section. The file system
calls FS_X_OS_Lock() before it enters a critical section and
FS_X_OS_Unlock() when the critical sector is leaved.
This function has to be implemented only for file system configurations
that set FS_SUPPORT_DEINIT to 1. FS_X_OS_DeInit() has to release all
the OS synchronization objects that were allocated in FS_X_OS_Init().
The implementation of this function is optional. FS_X_OS_Delay()
is called by implementations of the hardware layers to block
efficiently the execution of a task.
This function has to be implemented by any OS layer.
The file system calls FS_X_OS_Lock() when it tries to enter a critical
section that is protected by the OS synchronization object specified via
LockIndex. FS_X_OS_Lock() has to block the execution of the calling task
until the OS synchronization object can be acquired. The OS synchronization
object is later released via a call to FS_X_OS_Unlock(). All OS synchronization
objects are created in FS_X_OS_Init().
It is guaranteed that the file system does not perform a recursive locking
of the OS synchronization object. That is FS_X_OS_Lock() is not called
two times in a row from the same task on the same OS synchronization object
without a call to FS_X_OS_Unlock() in between.
This function has to be implemented by any OS layer.
The OS synchronization object to be released was acquired via
a call to FS_X_OS_Lock(). All OS synchronization objects are
created in FS_X_OS_Init().
FS_X_OS_Wait()
Description
Waits for an OS synchronization object to be signaled.
Maximum time in milliseconds to wait for the OS synchronization object to be signaled.
Return value
= 0
OK, the OS synchronization object was signaled within the timeout.
≠ 0
An error or a timeout occurred.
Additional information
The implementation of this function is optional. FS_X_OS_Wait()
is called by some hardware layer implementations that work
in event-driven mode. That is a condition is not check periodically
by the CPU until is met but the hardware layer calls FS_X_OS_Wait()
to block the execution while waiting for the condition to be met.
The blocking is realized via an OS synchronization object that is
signaled via FS_X_OS_Signal() in an interrupt that is triggered
when the condition is met.
The implementation of this function is optional. FS_X_OS_Signal()
is called by some hardware layer implementations that work in
event-driven mode. Refer to FS_X_OS_Wait() for more details about
how this works.
FS_X_OS_GetTime()
Description
Number of milliseconds elapsed since the start of the application.
The implementation of this function is optional. FS_X_OS_GetTime()
is not called by the file system. It is typically used by some
test applications as time base for performance measurements.
Sample implementation
The following example shows the implementation of an OS layer for SEGGER embOS.
The implementation file is located in the Sample/FS/OS folder of the
emFile shipment.
/********************************************************************** (c) SEGGER Microcontroller GmbH ** The Embedded Experts ** www.segger.com ***********************************************************************-------------------------- END-OF-HEADER -----------------------------File : FS_OS_embOS.cPurpose : embOS OS Layer for the file system.*//*********************************************************************** #include Section************************************************************************/#include"FS.h"#include"FS_OS.h"#include"RTOS.h"/*********************************************************************** Static data************************************************************************/staticOS_RSEMA *_paSema;staticOS_EVENT _Event;#ifFS_SUPPORT_DEINITstaticunsigned_NumLocks;#endif/*********************************************************************** Public code************************************************************************//*********************************************************************** FS_X_OS_Lock** Function description* Acquires the specified OS resource.** Parameters* LockIndex Identifies the OS resource (0-based).** Additional information* This function has to block until it can acquire the OS resource.* The OS resource is later released via a call to FS_X_OS_Unlock().*/voidFS_X_OS_Lock(unsignedLockIndex){OS_RSEMA *pSema;pSema =_paSema +LockIndex;(void)OS_Use(pSema);FS_DEBUG_LOG((FS_MTYPE_OS,"OS: LOCK Index: %d\n",LockIndex));}/*********************************************************************** FS_X_OS_Unlock** Function description* Releases the specified OS resource.** Parameters* LockIndex Identifies the OS resource (0-based).** Additional information* The OS resource to be released was acquired via a call to FS_X_OS_Lock()*/voidFS_X_OS_Unlock(unsignedLockIndex){OS_RSEMA *pSema;pSema =_paSema +LockIndex;FS_DEBUG_LOG((FS_MTYPE_OS,"OS: UNLOCK Index: %d\n",LockIndex));OS_Unuse(pSema);}/*********************************************************************** FS_X_OS_Init** Function description* Initializes the OS resources.** Parameters* NumLocks Number of locks that should be created.** Additional information* This function is called by FS_Init(). It has to create all resources* required by the OS to support multi tasking of the file system.*/voidFS_X_OS_Init(unsignedNumLocks){unsignedi;OS_RSEMA *pSema;unsignedNumBytes;NumBytes =NumLocks *sizeof(OS_RSEMA);_paSema =SEGGER_PTR2PTR(OS_RSEMA,FS_ALLOC_ZEROED((I32)NumBytes,"OS_RSEMA"));pSema =_paSema;for(i =0;i <NumLocks;i++){OS_CREATERSEMA(pSema++);}OS_EVENT_Create(&_Event);#ifFS_SUPPORT_DEINIT_NumLocks =NumLocks;#endif}#ifFS_SUPPORT_DEINIT/*********************************************************************** FS_X_OS_DeInit** Function description* This function has to release all the resources that have been* allocated by FS_X_OS_Init().*/voidFS_X_OS_DeInit(void){unsignedi;OS_RSEMA *pSema;unsignedNumLocks;NumLocks =_NumLocks;pSema =&_paSema[0];for(i =0;i <NumLocks;i++){OS_DeleteRSema(pSema);pSema++;}OS_EVENT_Delete(&_Event);FS_Free(_paSema);_paSema =NULL;_NumLocks =0;}#endif// FS_SUPPORT_DEINIT/*********************************************************************** FS_X_OS_GetTime*/U32 FS_X_OS_GetTime(void){return(U32)OS_GetTime32();}/*********************************************************************** FS_X_OS_Wait** Function description* Waits for an event to be signaled.** Parameters* Timeout Time to be wait for the event object.** Return value* ==0 Event object was signaled within the timeout value* !=0 An error or a timeout occurred.*/intFS_X_OS_Wait(intTimeOut){intr;r =-1;if((U8)OS_EVENT_WaitTimed(&_Event,TimeOut)==0u){r =0;}returnr;}/*********************************************************************** FS_X_OS_Signal** Function description* Signals an event.*/voidFS_X_OS_Signal(void){OS_EVENT_Set(&_Event);}/*********************************************************************** FS_X_OS_Delay** Function description* Blocks the execution for the specified number of milliseconds.*/voidFS_X_OS_Delay(intms){OS_Delay(ms +1);}/*************************** End of file ****************************/
Debugging
This chapter provides information about how to troubleshoot
emFile in case that is not working as expected.
General information
emFile comes with an optional debug functionality that helps investigating
potential issues related to the file system operation. The debug functionality
can be used by an application to enable additional parameter and consistency checks
and to enable the reporting of debug messages. The type of checks to be performed
as well as the type of debug messages to be generated can be configured at compile
time by assigning a different value (debug level) to FS_DEBUG_LEVEL configuration
define.
Note
Enabling the debug functionality can have a negative effect on the read and write
performance and it can also increase the ROM and RAM usage of the file system.
Debug messages
Debug messages are human-readable text messages generated by the file system
on error or warning conditions or when specific internal operations are performed.
The file system provides the debug messages as 0-terminated strings to the application
via calls to dedicated API functions. These functions have to be implemented in
the application and the application is free to choose how to handle the debug messages.
For example the debug messages can be forwarded to a host system via the SEGGER Real Time Transfer
(https://www.segger.com/products/debug-probes/j-link/technology/about-real-time-transfer/)
The debug messages are organized in three classes: error, warning and trace.
Each debug message class is passed to the application via a separate API function.
In addition, the reporting of a specific class of debug messages can be enabled or
disabled via different debug levels. The table below lists the supported debug message
classes together with the API function that is used to pass them to the application.
The debug messages also have a type assigned to them that is used to identify
the component of the file system that reported that message. Refer to section
Debug message types for a description of the supported message types.
It is possible to configure at compile time as well as at runtime what type
of debug messages are reported by the file system. The sections
FS_LOG_MASK_DEFAULT and Runtime configuration provide more
information about how this is realized.
Debug output and error functions
This section describes the API functions an application has to provide in order
to be able to handle the debug messages and assertion errors generated by the file system.
emFile comes with a sample implementation for these functions that demonstrate
how to send the debug messages to a host system The implementation of the sample
functions can be found in the Config/FS_ConfigIO.c file of the emFile
shipment. These functions can be adapted according to the requirements of the
target application. The typical release build does not use debugging and therefore
these functions may be removed from the source code to save some ROM space if the
linker is not able to eliminate unreferenced functions automatically.
The table below and the next sections provide more detailed information about
these API functions.
Reported text debug message (0-terminated). It can never be NULL.
Additional information
This function is optional. It is required to be present only when
the file system is built with FS_DEBUG_LEVEL set to a value greater
than or equal to FS_DEBUG_LEVEL_LOG_ERRORS. The generated text message
is not terminated by a newline character.
Generated text debug message (0-terminated). It can never be NULL.
Additional information
This function is optional. It is required to be present only when
the file system is built with FS_DEBUG_LEVEL set to a value greater
than or equal to FS_DEBUG_LEVEL_LOG_ALL. The generated text message
terminated by a newline character as required.
This function is called by the file system only when the sources
are built with FS_DEBUG_LEVEL set to a value greater than or equal
to FS_DEBUG_LEVEL_CHECK_PARA. FS_X_Panic() is called only on a
critical error condition such as insufficient memory or invalid
parameter.
Refer to Error codes for permitted values for ErrorCode.
Reported text debug message (0-terminated). It can never be NULL.
Additional information
This function is optional. It is required to be present only when
the file system is built with FS_DEBUG_LEVEL set to a value greater
than or equal to FS_DEBUG_LEVEL_LOG_WARNINGS. The generated text message
is not terminated by a newline character.
The debug functionality has to be configured at compiled time and can be
optionally configured at runtime.
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 following table lists the configuration defines supported by the debug
functionality.
This define can be used to configure the behavior of the debug functionality.
The application can choose between six debug levels that enable different
features of the debug functionality. The debug levels are structured hierarchically
so that higher debug levels also enable the features assigned to lower debug levels.
Parameter checks and consistency checks are performed.
FS_DEBUG_LEVEL_LOG_ERRORS
Error conditions are reported.
FS_DEBUG_LEVEL_LOG_WARNINGS
Error and warning conditions are reported.
FS_DEBUG_LEVEL_LOG_ALL
Error and warning conditions as well as trace messages are reported.
Additional information
These values can be assigned at compile-time to the FS_DEBUG_LEVEL
configuration define.
The debug levels are hierarchical so that higher debug levels
also enable the features assigned to lower debug levels.
FS_DEBUG_MAX_LEN_MESSAGE
This define specifies the size of the buffer to be used for the formatting of
debug messages. This buffer is allocated on the stack. It can be set to a
smaller value than the default to save stack space. The debug messages will be
truncated if they do not fit in the formatting buffer.
FS_DEBUG_STATIC_MESSAGE_BUFFER
FS_DEBUG_STATIC_MESSAGE_BUFFER can be used to specify where the buffer used for
the formatting of debug messages is allocated (statically or on the stack).
By default the buffer for the formatting of debug messages are allocate on the stack.
The size of the buffer is specified by FS_DEBUG_MAX_LEN_MESSAGE. The stack load
can be reduced by setting FS_DEBUG_STATIC_MESSAGE_BUFFER to 1 in which case
the buffer is allocated statically. It is not recommended to set
FS_DEBUG_STATIC_MESSAGE_BUFFER to 1 with FS_OS_LOCKING set to FS_OS_LOCKING_DRIVER
because the debug messages may get corrupted when two or more tasks access different
storage devices of different types at the same time.
FS_LOG_MASK_DEFAULT
This configuration define specifies the type of debug messages to be generated
from the class of log messages. The value is a bitwise-OR combination of the
message types described in the section Debug message types.
The type of log debug messages to be generated can be modified at runtime via
FS_SetLogFilter() and FS_AddLogFilter().
FS_X_PANIC()
This configuration define can be used to replace the default handler
for assertion errors. It takes the error code as parameter. Refer to
FS_X_Panic() for more information.
Runtime configuration
The type of debug messages that are generated by the file system during the
operation can be managed using the API functions listed in the following table.
FS_AddErrorFilter() can be used to enable a specified set of
debug message types of the error class.
This function is optional and is available only when the file
system is built with FS_DEBUG_LEVEL set to a value equal or
greater than FS_DEBUG_LEVEL_LOG_ERRORS.
FileMask is specified by or-ing one or more message types described
at Debug message types.
FS_AddLogFilter() can be used to enable a specified set of
debug message types of the trace class.
This function is optional and is available only when the file
system is built with FS_DEBUG_LEVEL set to a value equal or
greater than FS_DEBUG_LEVEL_LOG_ALL.
FileMask is specified by or-ing one or more message types
described at Debug message types.
FS_AddWarnFilter() can be used to enable a specified set of
debug message types of the warning class.
This function is optional and is available only when the file
system is built with FS_DEBUG_LEVEL set to a value equal or
greater than FS_DEBUG_LEVEL_LOG_WARNINGS.
FileMask is specified by or-ing one or more message types described
at Debug message types.
FS_GetErrorFilter()
Description
Queries activation status of error debug messages.
Value indicating the activation status for all debug message
types of the error class.
Additional information
This function is optional and is available only when the file
system is built with FS_DEBUG_LEVEL set to a value equal or
greater than FS_DEBUG_LEVEL_LOG_ERRORS.
The return value is specified by or-ing one or more message types
described at Debug message types.
FS_GetLogFilter()
Description
Queries activation status of trace debug messages.
Value indicating the activation status for all debug message
types of the trace class.
Additional information
This function is optional and is available only when the file
system is built with FS_DEBUG_LEVEL set to a value equal or
greater than FS_DEBUG_LEVEL_LOG_ALL.
The return value is specified by or-ing one or more message types
described at Debug message types.
FS_GetWarnFilter()
Description
Queries activation status of warning debug messages.
Value indicating the activation status for all debug message
types of the warning class.
Additional information
This function is optional and is available only when the file
system is built with FS_DEBUG_LEVEL set to a value equal or
greater than FS_DEBUG_LEVEL_LOG_WARNINGS.
The return value is specified by or-ing one or more message types
described at Debug message types.
FS_AddErrorFilter() can be used to enable and disable a specified
set of debug message types of the error class. The debug message
types that have the bit set to 1 in FilterMask are enabled while
the other debug message types are disabled.
This function is optional and is available only when the file
system is built with FS_DEBUG_LEVEL set to a value equal or
greater than FS_DEBUG_LEVEL_LOG_ERRORS.
FileMask is specified by or-ing one or more message types described
at Debug message types.
FS_SetLogFilter() can be used to enable and disable a specified
set of debug message types of the trace class. The debug message
types that have the bit set to 1 in FilterMask are enabled while
the other debug message types are disabled.
This function is optional and is available only when the file
system is built with FS_DEBUG_LEVEL set to a value equal or
greater than FS_DEBUG_LEVEL_LOG_ALL.
FileMask is specified by or-ing one or more message types described
at Debug message types.
FS_SetWarnFilter() can be used to enable and disable a specified
set of debug message types of the warning class. The debug message
types that have the bit set to 1 in FilterMask are enabled while
the other debug message types are disabled.
This function is optional and is available only when the file
system is built with FS_DEBUG_LEVEL set to a value equal or
greater than FS_DEBUG_LEVEL_LOG_WARNINGS.
FileMask is specified by or-ing one or more message types described
at Debug message types.
Debug messages from the device and logical drivers.
FS_MTYPE_OS
Debug messages from the OS layer.
FS_MTYPE_MEM
Debug messages from the internal memory allocator.
FS_MTYPE_BIGFAT
Debug messages from the BigFAT component.
FS_MTYPE_ADAPT
Debug messages from emFile adaptation layers.
Troubleshooting
This section provides some ideas about how to analyze why the file system is not
working as expected.
emFile comes with an API function called FS_FOpen() that is the equivalent
of the fopen() function that is part of any standard C library. This function
takes as parameters a file name and an access mode. If the specified file access
type is allowed and no error occurs, the function returns a pointer to a file
handle that can be used to perform operations on that file.
#include"FS.h"intSampleFileOpen(constchar*s){FS_FILE*pFile;pFile =FS_FOpen("test.txt","r");if(pFile ==NULL){return-1;// report error}else{return0;// file system is up and running!}}
If this pointer is zero after calling FS_FOpen(), there was a problem opening the file.
There are basically three main reasons why this could happen:
The file or path does not exist.
The drive could not be read or written.
The drive contains an invalid BIOS parameter block or partition table.
These faults can be caused by corrupted media. To verify the validity of your
medium, either check if the medium is physically okay or check the medium with
another operation system (for example Windows).
There are also faults that are relatively seldom but also possible:
A compiler/linker error has occurred.
Stack overflow.
Memory failure.
Electro-magnetic influence (EMC, EMV, ESD.)
To find out what the real reason for the error is, you may just try reading and writing
a raw sector. Here is an example function that tries writing a single sector to your
device. After reading back and verifying the sector data, you know if sectored access
to the device is possible and if your device is working.
#include"FS.h"#defineBYTES_PER_SECTOR 512intSampleWriteSector(void){U8 acBufferOut[BYTES_PER_SECTOR];U8 acBufferIn[BYTES_PER_SECTOR];U32 SectorIndex;intr;inti;//// Do not write on the first sectors. They contain// information about partitioning and media geometry.//SectorIndex =80;//// Fill the buffer with data.//for(i =0;i <BYTES_PER_SECTOR;i++){acBufferOut[i]=i %256;}//// Write one sector.//r =FS_STORAGE_WriteSector("",acBufferOut,SectorIndex);if(r){FS_X_Log("Cannot write to sector.\n");return-1;}//// Read back the sector contents.//r =FS_STORAGE_ReadSector("",acBufferIn,SectorIndex);if(r){FS_X_Log("Cannot read from sector.\n");return-1;}//// Compare the sector contents.//for(i =0;i <BYTES_PER_SECTOR;i++){if(acBufferIn[i]!=acBufferOut[i]){FS_X_Log("Sector not correctly written.\n");return-1;}}return0;}
If you still receive no valid pointer to a file handle although the sectors of the device
are accessible and other operating systems report the device to be valid, you may
have to take a look into the running system by stepping through the function
FS_FOpen().
Profiling with SystemView
This chapter describes the profiling instrumentation of emFile.
General information
emFile is instrumented to generate profiling information of API functions and driver-level
functions. This profiling information expose the run-time behavior of emFile in an application,
recording which API functions have been called, how long the execution took, and revealing
which driver-level functions have been called by API functions or evens like interrupts.
The profiling information is recorded using SystemView. SystemView is a real-time
recording and visualization tool for profiling data. It exposes the true run-time
behavior of a system, going far deeper than the insight provided by debuggers. This
is particularly effective when developing and working with complex systems comprising
an OS with multiple threads and interrupts, and one or more middle ware components.
SystemView can ensure a system performs as designed, can track down inefficiencies,
and show unintended interactions and resource conflicts. The recording of profiling
information with SystemView is minimally intrusive to the system and can be
done on virtually any system. With SEGGERs Real Time Technology (RTT) and a J-Link SystemView
can record data in real-time and analyze the data live, while the system is running.
The emFile profiling instrumentation can be easily configured and set up.
Configuring profiling
Profiling can be included or excluded at compile-time and enabled at run-time.
When profiling is excluded, no additional overhead in performance or memory
usage is generated. Even when profiling is enabled the overhead is minimal,
due to the efficient implementation of SystemView.
The SystemView module needs to be added to the application to enable profiling.
If not already part of the project, download the sources from
https://www.segger.com/systemview.html and add them to the project.
Also make sure that the FS_SYSVIEW.c file from the FS directory
of the emFile shipment is included in the project.
Compile time configuration
The configuration of emFile can be changed via compile time flags which
can be added to FS_Conf.h. FS_Conf.h is the main configuration file
of the file system.
To include profiling, the configuration define FS_SUPPORT_PROFILE must be set
to 1 in the emFile configuration (FS_Conf.h) or via the project
preprocessor defines.
The following table lists the configuration defines related to profiling.
This configuration define can be used to enable the support for profiling
instrumentation in emFile. By default the support is disabled to
save ROM space.
FS_SUPPORT_PROFILE_END_CALL
This configuration define specifies if the return values of the profiled
functions have to be recoded. This feature is disabled by default to save
ROM space. FS_SUPPORT_PROFILE_END_CALL has effect only when FS_SUPPORT_PROFILE
is set to 1.
For detailed information about the configuration of emFile and the types
of the configuration defines, refer to Configuration of emFile.
Runtime configuration
To enable profiling at run-time, FS_SYSVIEW_Init() needs to be called. Profiling can
be enabled at any time but it is recommended to do this in FS_X_AddDevices() as
demonstrated in the sample below:
#include"FS.h"/*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){#ifFS_SUPPORT_PROFILEFS_SYSVIEW_Init();#endif//// Add device driver initialization here.//}
Recording and analyzing profiling information
When profiling is included and enabled emFile generates profiling events. On a system
which supports RTT (i.e. ARM Cortex-M and Renesas RX) the data can be read and analyzed
with SystemView and a J-Link. Connect the J-Link to the target system using the default
debug interface and start the SystemView host application. If the system does not support
RTT, SystemView can be configured for single-shot or postmortem mode. Please refer to
the SystemView User Manual for more information.
Performance and resource usage
This chapter contains information about the RAM and ROM requirements and how to
measure and improve performance of emFile.
Resource usage
emFile has been designed to meet the requirements of any embedded system.
This means the the file system can be configured to include only the features
required by a specific system in order to keep the RAM and ROM usage at a minimum
while providing efficient access to the storage device.
The actual RAM and ROM memory requirements of emFile depend on the used features.
The following section provides information about how to calculate the memory requirements
and some values for typical applications. Note that the values are valid for the given
configuration. Features can affect the size of others. For example, if FAT32 is deactivated,
the format function gets smaller because the 32 bit specific part of format is not added
into the final executable.
ROM usage
Test procedure
The ROM usage was measured by compiling the file system sources with
SEGGER Embedded Studio for ARM V7.10 for a Cortex-M CPU with the
size optimization enabled.
The file system was configured to use the lowest debug level and the
OS support was disabled:
#defineFS_OS_LOCKING 0// Disable OS support#defineFS_DEBUG_LEVEL 0// Set debug level
No driver has been added to the file system. For information about the memory usage
of a specific emFile driver refer to the “Performance and resource usage”
section of the respective driver in the Device drivers section.
The sample application listed below has been used to calculate the memory resources
of commonly used functions. You can easily reproduce the measurement results by
compile this sample application. Build the application listed below and generate
a linker listing to get the memory requirements of an application which only includes
startup code and the empty main() function. Afterwards, set the value of the macro STEP
to 1 to get the memory requirement of the minimum file system. Subtract the ROM requirements
from STEP=0 from the ROM requirements of STEP=1 to get the exact ROM requirements
of a minimal file system. Increment the value of the macro STEP to include
more file system functions and repeat your calculation.
FS_TEST_ROMUsage.c
/********************************************************************** (c) SEGGER Microcontroller GmbH ** The Embedded Experts ** www.segger.com ***********************************************************************-------------------------- END-OF-HEADER -----------------------------File : FS_TEST_ROMUsage.cPurpose : Application to calculate the ROM usage of the file system.*//*********************************************************************** #include section************************************************************************/#include"FS.h"#include"FS_Int.h"#ifFS_DEBUG_LEVEL >0#errorFS_DEBUG_LEVEL has to be to 0.#endif/*********************************************************************** Defines, configurable************************************************************************/#ifndefSTEP#defineSTEP 0// Change this line to adjust which portions of code are linked#endif#ifndefSUBSTEP#defineSUBSTEP 0#endif/*********************************************************************** Static data************************************************************************/#ifSTEP >=9staticU32 _aCache[FS_SIZEOF_CACHE_ANY(2,512)/4];#endif// STEP >= 9#if(STEP >=10)staticU32 _aBuffer[16];staticU8 _NumErrors;#endif// STEP >= 10/*********************************************************************** Static code************************************************************************/#if(STEP >=10)/*********************************************************************** _OnError*/staticint_cbOnError(intErrCode,...){(void)ErrCode;_NumErrors++;returnFS_CHECKDISK_ACTION_DO_NOT_REPAIR;}#endif// STEP >= 10/*********************************************************************** Public code************************************************************************//*********************************************************************** MainTask*/voidMainTask(void);voidMainTask(void){#ifSTEP >=1// Step 1: Minimum file systemFS_FILE*pFile;FS_Init();#ifFS_SUPPORT_JOURNALFS_JOURNAL_Create("",100uL*1024uL);#endifpFile =FS_FOpen("File.txt","w");#endif#ifSTEP >=2// Step 2: Write a fileFS_Write(pFile,"Test",4);#endif#ifSTEP >=3// Step 3: Remove a fileFS_Remove("File.txt");#endif#ifSTEP >=4// Step 4: Open a directory{FS_FIND_DATAfd;characFileName[16];FS_FindFirstFile(&fd,"",acFileName,sizeof(acFileName));FS_FindClose(&fd);}#endif#ifSTEP >=5// Step 5: Create a directoryFS_MkDir("TestDir");#endif#ifSTEP >=6// Step 6: Add long file name support#if(FS_SUPPORT_FAT !=0)FS_FAT_SupportLFN();#endif#endif#ifSTEP >=7// Step 7: Low-level format a storage deviceFS_FormatLow("");#endif#ifSTEP >=8// Step 8: High-level format a storage deviceFS_Format("",NULL);#endif#ifSTEP >=9// Step 9: Assign cache#if(SUBSTEP ==0)FS_AssignCache("",_aCache,sizeof(_aCache),FS_CACHE_ALL);#endif#if(SUBSTEP ==1)FS_AssignCache("",_aCache,sizeof(_aCache),FS_CACHE_MAN);#endif#if(SUBSTEP ==2)FS_AssignCache("",_aCache,sizeof(_aCache),FS_CACHE_RW);#endif#if(SUBSTEP ==3)FS_AssignCache("",_aCache,sizeof(_aCache),FS_CACHE_RW_QUOTA);#endif#if(SUBSTEP ==4)FS_AssignCache("",_aCache,sizeof(_aCache),FS_CACHE_MULTI_WAY);#endif#endif#ifSTEP >=10// Step 10: Disk checking_NumErrors =0;FS_CheckDisk("",_aBuffer,sizeof(_aBuffer),1,_cbOnError);#endif#ifSTEP >=11// Step 11: Get information about storage device{FS_DISK_INFODiskInfo;FS_GetVolumeInfo("",&DiskInfo);}#endif#ifSTEP >=12// Step 12: Get the size of a fileFS_GetFileSize(pFile);#endif#ifSTEP >=1// Step 1: Minimum file systemFS_FClose(pFile);#endif}/*********************************************************************** FS_X_AddDevices*/voidFS_X_AddDevices(void){;}/*********************************************************************** FS_X_GetTimeDate** Description:* Current time and date in a format suitable for the file system.** 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)**/U32 FS_X_GetTimeDate(void){U32 r;U16 Sec,Min,Hour;U16 Day,Month,Year;Sec =0;// 0 based. Valid range: 0..59Min =0;// 0 based. Valid range: 0..59Hour =0;// 0 based. Valid range: 0..23Day =1;// 1 based. Means that 1 is 1. Valid range is 1..31 (depending on month)Month =1;// 1 based. Means that January is 1. Valid range is 1..12.Year =0;// 1980 based. Means that 2007 would be 27.r =Sec /2+(Min <<5)+(Hour <<11);r |=(U32)(Day +(Month <<5)+(Year <<9))<<16;returnr;}/*************************** End of file ****************************/
Test results
The following table shows the ROM usage of different API functions
for the FAT file system.
Step
Substep
Description
ROM [Kbytes]
1
File system core (without driver)
9.5
2
Write file
1.1
3
Remove file
0.03
4
Open directory
0.5
5
Create directory
0.5
6
Long file name support
3.5
7
Low-level format storage device
0.3
8
High-level format storage device
1.7
9
0
Assign a cache (FS_CACHE_ALL)
0.4
9
1
Assign a cache (FS_CACHE_MAN)
0.4
9
2
Assign a cache (FS_CACHE_RW)
0.7
9
3
Assign a cache (FS_CACHE_RW_QUOTA)
1.0
9
4
Assign a cache (FS_CACHE_MULTI_WAY)
1.1
10
Disk checking
3.5
11
Get information about storage device
0.4
12
Get the size of a file.
0.05
Additional information
Typically, a simple file system uses about 10 Kbytes of ROM. To calculate the
overall ROM usage, the ROM usage of the used driver(s) needs to be added.
Static RAM usage
Static RAM usage refers to the amount of RAM required by the file system
internally for all the storage devices.
Usage: 150 bytes
Dynamic RAM usage
Dynamic RAM is the amount of memory allocated by the file system at runtime.
Most of the dynamic RAM is allocated during the initialization of the file system.
The amount of memory allocated depends on the number of added devices, the number
of simultaneously opened files and of the type of OS locking as follows:
Data structure
Size (Bytes)
Count
File handle
24
+ 4 (if FS_SUPPORT_FILE_BUFFER = 1)
Maximum number of simultaneously open files.
Depends on application, minimum is 1.
The RAM usage of a volume instance does not include the RAM required by the device or logical
driver attached to that volume. The amount of RAM required by a driver instance is documented
in the “Performance and resource usage” of that driver.
Note
File handles and file objects can also be allocated after the file system initialization
depending on how many files the application opens at the same time.
RAM usage example
A small file system application with the following configuration
only one file is opened at a time
no operating system support
using the SD card driver
requires approximately 1300 bytes.
Performance
A benchmark is used to measure the speed of the software on available targets. This
benchmark is in no way complete, but it gives an approximation of the length of time
required for common operations on various targets. You can find the measurement
results in the chapter describing the individual drivers.
Test procedure
The performance tests are executed using the FS_PerformanceSimple.c application
that can be found in the {Sample/FS/Application} folder of the emFile shipment.
The test application performs the following steps:
Format the drive.
Create and open a file for writing.
Start measuring of write performance.
Write a multiple of 8 Kbytes.
Stop measuring of write performance.
Close the file.
Reopen the file for reading.
Start measuring of read performance.
Read a multiple of 8 Kbytes.
Stop measuring of read performance.
Close the file.
Show the performance results.
FS_PerformanceSimple.c
/********************************************************************** (c) SEGGER Microcontroller GmbH ** The Embedded Experts ** www.segger.com ***********************************************************************-------------------------- END-OF-HEADER -----------------------------File : FS_PerformanceSimple.cPurpose : Sample program that can be used to measure the performance of the file system.Additional information: Preparations: Works out-of-the-box with any storage device. Expected behavior: Measures the speed at witch the file system can write and read blocks of data to and from a file. The size of the file as well as the number of bytes that have to be written at once are configurable. The application always formats the storage device to make sure that the measurements are not influenced by the data already stored on the file system. Sample output: Start High-level format Writing 4 chunks of 2048 KiB.......OK Reading 4 chunks of 2048 KiB.......OK W Speed: 9183 KiB/s R Speed: 18123 KiB/s Finished Notes: The sample application may report a write or read speed of 0 if a very fast storage device is used for the test such as a RAM disk. This is normal behavior and the reason for this is that the accuracy of the time base used for the measurements is limited to 1 ms. This limitation can be removed by increasing the size of the work buffer via the BLOCK_SIZE configuration define.*//*********************************************************************** #include Section************************************************************************/#include<string.h>#include"FS.h"#include"FS_OS.h"#include"SEGGER.h"/*********************************************************************** Defines, configurable************************************************************************/#ifndefFILE_SIZE#defineFILE_SIZE (8192L*1024L)// Size of the file in bytes to be used for testing.#endif#ifndefBLOCK_SIZE#defineBLOCK_SIZE (8*1024L)// Block size for individual read / write operation in bytes.#endif#ifndefNUM_BLOCKS_MEASURE#defineNUM_BLOCKS_MEASURE (64)// Number of blocks for individual measurement#endif#ifndefVOLUME_NAME#defineVOLUME_NAME ""// Name of the volume to be used for testing.#endif#ifndefFILE_NAME#defineFILE_NAME "SEGGER.txt"// Name of the file to be used for testing.#endif#ifndefUSE_PREALLOCATION#defineUSE_PREALLOCATION 1// Configures if the file preallocation has to be used.#endif#ifFS_SUPPORT_JOURNAL#ifndefJOURNAL_SIZE#defineJOURNAL_SIZE 0// Size of the Journaling file in bytes.#endif#endif/*********************************************************************** Types************************************************************************/typedefstruct{constchar*sName;I32 Min;I32 Max;I32 Av;I32 Sum;I32 NumSamples;U32 NumBytes;}RESULT;/*********************************************************************** Static data************************************************************************/staticU32 _aBuffer[BLOCK_SIZE /4];staticRESULT _aResult[2];staticint_TestNo;staticchar_ac[512];/*********************************************************************** Static code************************************************************************//*********************************************************************** _WriteFile** Function description* Measures the write time.*/staticI32 _WriteFile(FS_FILE*pFile,constvoid*pData,U32 NumBytes,U32 NumBlocksMeasure){I32 t;U32 i;t =(I32)FS_X_OS_GetTime();for(i =0;i <NumBlocksMeasure;i++){(void)FS_Write(pFile,pData,NumBytes);}return(I32)FS_X_OS_GetTime()-t;}/*********************************************************************** _ReadFile** Function description* Measures the read performance.*/staticI32 _ReadFile(FS_FILE*pFile,void*pData,U32 NumBytes,U32 NumBlocksMeasure){I32 t;U32 i;t =(I32)FS_X_OS_GetTime();for(i =0;i <NumBlocksMeasure;i++){(void)FS_Read(pFile,pData,NumBytes);}return(I32)FS_X_OS_GetTime()-t;}/*********************************************************************** _StartTest*/staticvoid_StartTest(constchar*sName,U32 NumBytes){RESULT *pResult;if((_TestNo +1)<(int)SEGGER_COUNTOF(_aResult)){pResult =&_aResult[++_TestNo];pResult->sName =sName;pResult->Min =0x7fffffff;pResult->Max =-0x7fffffff;pResult->NumSamples =0;pResult->Sum =0;pResult->NumBytes =NumBytes;}}/*********************************************************************** _StoreResult*/staticvoid_StoreResult(I32 t){RESULT *pResult;pResult =&_aResult[_TestNo];if(t >pResult->Max){pResult->Max =t;}if(t <pResult->Min){pResult->Min =t;}pResult->NumSamples++;pResult->Sum +=(I32)t;pResult->Av =pResult->Sum /pResult->NumSamples;}/*********************************************************************** _GetAverage*/staticdouble_GetAverage(intIndex){RESULT *pResult;doublev;unsignedNumKBytes;pResult =&_aResult[Index];v =(double)pResult->Av;if((U32)v ==0u){v =1.0;// Make sure that we display the maximum speed if the timer resolution is too low.}v =(double)1000.0/v;NumKBytes =pResult->NumBytes >>10;v =v *(double)NumKBytes;returnv;}/*********************************************************************** Public code************************************************************************//*********************************************************************** MainTask*/#ifdef__cplusplusextern"C"{/* Make sure we have C-declarations in C++ programs */#endifvoidMainTask(void);#ifdef__cplusplus}#endifvoidMainTask(void){inti;U32 Space;unsignedNumLoops;U32 NumBytes;U32 NumBytesAtOnce;FS_FILE*pFile;I32 t;intr;U32 NumBlocksMeasure;characFileName[128];FS_X_Log("Start\n");FS_Init();_TestNo =-1;//// Check if we need to low-level format the volume//if(FS_IsLLFormatted(VOLUME_NAME)==0){FS_X_Log("Low-level format\n");(void)FS_FormatLow(VOLUME_NAME);}//// Volume is always high level formatted// before doing any performance tests.//FS_X_Log("High-level format\n");#ifFS_SUPPORT_FATr =FS_FAT_FormatSD(VOLUME_NAME);#elifFS_SUPPORT_EXFAT#ifFS_EXFAT_UPDATE_SPACE_USAGEFS_EXFAT_ConfigSpaceUsageUpdate(0);// Make sure that we get exact information about the free space.#endif// FS_EXFAT_UPDATE_SPACE_USAGEr =FS_EXFAT_FormatSD(VOLUME_NAME);#elser =FS_Format(VOLUME_NAME,NULL);#endif// FS_SUPPORT_FATif(r ==0){#ifFS_SUPPORT_JOURNALFS_SetFileWriteMode(FS_WRITEMODE_SAFE);#ifJOURNAL_SIZE//// Enable Journaling.//FS_JOURNAL_CreateEx(VOLUME_NAME,JOURNAL_SIZE,1);#endif// JOURNAL_SIZE#else//// Configure the file system so that the// directory entry and the allocation table// are updated when the file is closed.//FS_SetFileWriteMode(FS_WRITEMODE_FAST);#endif// FS_SUPPORT_JOURNAL//// Fill the buffer with data.//memset(_aBuffer,(int)'a',sizeof(_aBuffer));//// Get some general info.//Space =FS_GetVolumeFreeSpace(VOLUME_NAME);Space =SEGGER_MIN(Space,(U32)FILE_SIZE);NumBytesAtOnce =BLOCK_SIZE;NumBlocksMeasure =NUM_BLOCKS_MEASURE;for(;;){NumBytes =NumBytesAtOnce *NumBlocksMeasure;if(NumBytes <=Space){break;}NumBytesAtOnce >>=1;NumBlocksMeasure >>=1;}NumLoops =Space /NumBytes;if(NumLoops !=0u){//// Create file of full size.//_StartTest("W",NumBytes);SEGGER_snprintf(acFileName,(int)sizeof(acFileName),"%s%c%s",VOLUME_NAME,FS_DIRECTORY_DELIMITER,FILE_NAME);pFile =FS_FOpen(acFileName,"w");#ifUSE_PREALLOCATION//// Preallocate the file, setting the file pointer to the highest position// and declare it as the end of the file.//(void)FS_FSeek(pFile,(I32)Space,FS_SEEK_SET);(void)FS_SetEndOfFile(pFile);//// Set file position to the beginning.//(void)FS_FSeek(pFile,0,FS_SEEK_SET);#endif// USE_PREALLOCATION//// Check write performance with clusters/file size preallocated.//SEGGER_snprintf(_ac,(int)sizeof(_ac),"Writing %d chunks of %lu KiB...",NumLoops,NumBytes >>10);FS_X_Log(_ac);for(i =0;i <(int)NumLoops ;i++){t =_WriteFile(pFile,_aBuffer,NumBytesAtOnce,NumBlocksMeasure);_StoreResult(t);FS_X_Log(".");}FS_X_Log("OK\n");(void)FS_FClose(pFile);//// Check read performance.//_StartTest("R",NumBytes);SEGGER_snprintf(_ac,(int)sizeof(_ac),"Reading %d chunks of %lu KiB...",NumLoops,NumBytes >>10);FS_X_Log(_ac);pFile =FS_FOpen(acFileName,"r");for(i =0;i <(int)NumLoops;i++){t =_ReadFile(pFile,_aBuffer,NumBytesAtOnce,NumBlocksMeasure);_StoreResult(t);FS_X_Log(".");}FS_X_Log("OK\n\n");(void)FS_FClose(pFile);(void)FS_Remove(acFileName);//// Show results for performance list.//for(i =0;i <=_TestNo;i++){SEGGER_snprintf(_ac,(int)sizeof(_ac),"%s Speed: %d KiB/s\n",_aResult[i].sName,(int)_GetAverage(i));FS_X_Log(_ac);}}else{FS_X_Log("ERROR: Not enough free space available on the storage.\n");}FS_Unmount(VOLUME_NAME);}else{FS_X_Log("ERROR: Volume could not be formatted!\n");}FS_X_Log("Finished\n");for(;;){;}}/*************************** End of file ****************************/
How to improve performance
If you find that the performance of emFile on your hardware is not what you expect
there are several ways you can improve it.
Use a different write mode
The default behavior of the file system is to update the allocation table and the directory
entry after each write operation. If several write operations are performed
between the opening and the closing of the file it is recommended to set the write
mode to FS_WRITEMODE_MEDIUM or FS_WRITEMODE_FAST to increase the performance.
In these modes the allocation table and the directory entry are updated only when
the file is closed. Refer to FS_SetFileWriteMode() to learn how the write
mode can be configured. Please note that these write modes can not be used when
journaling is enabled.
Pre-allocate the files
The pre-allocation of a file helps reduce the number of accesses to the storage
device and therefore improves the read and write performance. When a file is
pre-allocated the file system reserves storage space for that file in the
allocation table before the file is actually filled with data. As such, a write
access to the allocation table is no longer necessary when the data is actually
stored to the file. A file can be pre-allocated by calling either FS_SetEndOfFile()
or FS_SetFileSize() in the application after the file is opened.
Write multiples of a logical sector size
The file system implements a 0-copy mechanism in which data written to a file using
the FS_FWrite() and FS_Write() functions is passed directly to the device driver if the
data is written at a sector boundary and the number of bytes written is a multiple of
sector size. In any other case the file system uses a read-modify-write operation
which increases the number of I/O operations and reduces the performance. The file
system makes sure that the content of a file always begins at a sector boundary.
Use a file buffer
It is recommended to activate the file buffering when the application reads and
writes amounts of data smaller than the sector size. Refer to
FS_ConfigFileBufferDefault() to see how this can be done. The file buffer
is a small cache which helps reducing the number of times storage medium is
accessed and thus increasing the performance.
Use a sector cache
The sector cache can be enabled to increase the overall performance of the file system.
For more information refer to Caching and buffering.
Configure a read-ahead driver
The read-ahead driver is useful when a storage medium is used which is more efficient
when several sectors are read or written at once. This includes storage media
such as CompactFlash cards, SD and MMC cards and USB sticks. Normally, the file
system reads the allocation table one sector at a time. If configured, the file system
activates the read-ahead driver at runtime when the allocation table is accessed. This
reduces, for example, the time it takes to determine the amount of free space. For
more information refer to Sector Read-Ahead driver.
Optimize the hardware layer
Ensure that the routines of the hardware layer are fast. It depends on your compiler
how to do that. Some compilers have the option to define a function as running from
RAM which is faster compared to running it from flash.
Use the FS_OPTIMIZE macro
The definitions of time critical functions in emFile are prefixed with the macro
FS_OPTIMIZE. By default it expands to nothing. You can use this macro to enable the
compiler optimization only for these functions. It depends on your compiler how to
define this macro.
Journaling
This chapter documents and explains emFile’s Journaling component.
The Journaling component is an extension to file system that makes
the file operations fail-safe.
General information
emFile Journaling is an additional component that can be used to
protect the integrity of the file system structure against an unexpected reset.
The FAT and EFS file systems are by design not fail-safe therefore the
usage of the Journaling component is recommended for any system that
may suddenly lose power while writing data to a storage device.
The Journaling component is located between the file system and the storage layer
and works by temporarily storing all the data changes performed by the file system
layer to a journal file. The changes are then copied at once from the journal file
to the actual destination on the storage device.
Driver fail-safety
Data can be lost in case of unexpected reset in either the file system layer (FAT or
EFS) or in the driver layer. The entire system is fail-safe only if both layers are fail
safe. The Journaling component makes only sure that the file system layer fail-safe.
For fail-safety of the driver layer, refer to Device drivers.
Features
Non fail-safe file systems will be fail-safe.
Fully compatible to standard file system implementations (e.g. FAT).
Every type of storage device is supported. No reformat required.
Multiple write accesses to the storage medium can be combined in user application.
Theory of operation
emFile is typically used with non fail-safe file systems like FAT.
Loss of data can occur in either the driver layer or the file system layer.
The driver layer is typically fail-safe therefore the only place where a typical
data loss can occur is the file system layer. The file system can be corrupted
when a write operation is interrupted for example in the event of power failure
or system crash. This derives from the design of FAT file system and is true for all
implementations from any vendor. The emFile Journaling component adds
fail-safety to the file system layer.
The goal of this additional component is to guarantee a file system that is always
in a consistent state. Operations on file system layer are mostly not atomic.
For example, a single call to FS_FWrite() that writes data into a new file
causes the execution of the following three storage layer operations:
Allocate cluster and update FAT.
Write user data.
Update directory entry.
An unexpected interrupt (such as a power failure) in this process can corrupt the file
system. To prevent such corruptions the Journaling component stores every write access to
achieve an always consistent state of the file system. All changes to the file system
are stored in a journal file. The data stored in the journal file is copied to the actual
destination on the storage device only if the file system layer operation has been finished
without interruption. This procedure guarantees an always consistent state of the file system,
because an interruption of the copy process does not lead to data loss. The interrupted
copy process is restarted after a restart of the target hardware.
The following table lists the possible error scenarios:
Moment of error
State
Data
1.
Journal empty
Consistent
—
2.
While writing into journal
Consistent
Lost
3.
While finalizing the journal
Consistent
Lost
4.
After finalization
Consistent
Preserved
5.
While copying from journal into file system
Consistent
Preserved
6.
After copy process, before invalidating of the journal
Consistent
Preserved
7.
While invalidating of the journal
Consistent
Preserved
Write optimization
The Journaling component has been optimized for write performance. When data is written
at the end of a file, which is the case in the most applications, only the management
information (allocation table and directory entry) is actually stored to journal file.
The file contents is written directly to the actual destination on the storage device
that helps improving the write performance. The fail-safety of the file system layer
is not affected as the file contents overwrite storage blocks that are not allocated
to any file or directory. The optimization is disabled as soon as a file or directory
is deleted during a journal transaction. This is done in order to make sure that the
data of the deleted file or directory is preserved in case of an unexpected reset.
How to use the Journaling component
Using Journaling component is very simple from the application’s perspective.
Only two changes have to be made to an existing application in order to enable
the Journaling component:
The Journaling component has to be enabled in the file system configuration
via the FS_SUPPORT_JOURNAL configuration define. Optionally, the name of the journal
file can be configured via the FS_JOURNAL_FILE_NAME configuration define.
For more information about additional compile time options refer to the section Configuration.
Everything else is done by the Journaling component.
Combining multiple write operations
The Journaling component can be used in the application to create a journal
transaction that consists of multiple write operations. This can be useful when
for example the changes made to two different files have to be performed in an
atomic way. That is after an unexpected reset that interrupts the write operation
the files have to contain either the old or the new data but never a combination
of both. A journal transaction can be opened via FS_JOURNAL_Begin() and has to be
closed using FS_JOURNAL_End() as shown in the sample below.
#include"FS.h"voidSampleJournalMultipleWrite(void){FS_FILE*pFile;//// Begin an operations which have to be be fail-safe.// All following steps will be stored into journal.//#ifFS_SUPPORT_JOURNALFS_JOURNAL_Begin("");#endif// FS_SUPPORT_JOURNALpFile =FS_FOpen("File1.txt","w");if(pFile){FS_Write(pFile,"Test 1",6);FS_FClose(pFile);}pFile =FS_FOpen("File2.txt","w");if(pFile){FS_Write(pFile,"Test 2",6);FS_FClose(pFile);}//// End an operation which has to be be fail-safe.// Data is copied from journal into file system.//#ifFS_SUPPORT_JOURNALFS_JOURNAL_End("");#endif// FS_SUPPORT_JOURNAL}
Preserving the consistency of a file
The Journaling component can be used in the application to protect the contents
of the file against unexpected resets. This means that after an unexpected
reset that interrupted the file write operation, the file will contain either
the old data or the new data but not a combination of both. The same applies to
the particular case were the application writes to an empty file.
The first method uses FS_JOURNAL_Begin() and FS_JOURNAL_End() to create a journal
transaction as shown in the next example code. The advantage of this method is
that a relatively small writing buffer can be used.
#include"FS.h"voidSampleJournalFileConsistency1(void){U8 aBuffer[128];FS_FILE*pFile;pFile =FS_FOpen("File.txt","w");if(pFile){#ifFS_SUPPORT_JOURNALFS_JOURNAL_Begin("");#endif// FS_SUPPORT_JOURNALmemset(aBuffer,'a',sizeof(aBuffer));FS_Write(pFile,aBuffer,sizeof(aBuffer));memset(aBuffer,'b',sizeof(aBuffer));FS_Write(pFile,aBuffer,sizeof(aBuffer));//// Changes are committed in a single journaling transaction// assuming the journal file is sufficiently large to store// all the changes performed by the file system.//#ifFS_SUPPORT_JOURNALFS_JOURNAL_End("");#endif// FS_SUPPORT_JOURNALFS_FClose(pFile);}}
The second method uses a buffer sufficiently large to store the contents
of the entire file that is then passed to FS_FWrite() or FS_Write() in single
function call. This method is demonstrated in the following example code.
#include"FS.h"voidSampleJournalFileConsistency2(void){U8 aBuffer[256];FS_FILE*pFile;pFile =FS_FOpen("File.txt","w");if(pFile){memset(aBuffer,'a',128);memset(&aBuffer[128],'b',128);//// The changes are committed in a single journal transaction// assuming that the journal file is sufficiently large to// store all the changes.//FS_Write(pFile,aBuffer,sizeof(aBuffer));FS_FClose(pFile);}}
Both methods require that the journal file is sufficiently large to store all
the changes made to the storage device by the file system during the write operation.
When writing to a file that is not empty the management data and the file contents
are stored the journal file. If the file the application is writing to is initially
empty then only the management data has to be stored to journal file. In this case
the contents of the file is written directly to the actual destination on the storage
device which means that a smaller journal file can be used.
Journaling and write caching
In order to guarantee the correct operation of the Journaling component
most of the write caching performed by the file system has to be disabled.
That is the file system has to be configured to write the data immediately
to storage device instead of keeping the data in its internally RAM buffers.
If not configured in this way, the journaling is no longer able to ensure
the fail safety of the file system on an unexpected reset because the data
stored in the internal RAM buffers will be lost.
The correct operation of the Journaling component is guaranteed when:
The sector cache in write back mode is disabled.
emFile comes with support for caching at logical sector level. The sector cache
is disabled by default and it has to be explicitly enabled in the application
via FS_AssignCache(). Five types of sector caches are provided with three of
them also supporting a write mode. The FS_CACHE_ALL and FS_CACHE_MAN cache types
are pure read caches and can always be used together with the Journaling component.
The other three types of caches FS_CACHE_RW, FS_CACHE_RW_QUOTA, and FS_CACHE_MULTI_WAY
can work in read as well as in write-back and write-through mode. The application
has to make sure that the write-back mode is disabled for this type of sector caches.
The write-through mode can be used together with the Journaling component without
negatively affecting the fail-safety of the file system. For detailed information
about the configuration of sector caches, refer to Caching and buffering.
The delayed update of directory entries is disabled.
The file system can be configured to update the directory entries only when
the file is closed. This is done in order to increase the write performance.
This feature is enabled via FS_ConfigOnWriteDirUpdate() with the OnOff parameter
set to 0. The application has to make sure that this API function is not called
at all or that it is called with the the OnOff parameter set to 1.
The file system write mode is set to FS_WRITEMODE_SAFE.
emFile can be configured to use different methods when it writes data to a file.
The application has to make sure that the write mode is set to FS_WRITEMODE_SAFE.
This write mode guarantees that the data is written immediately to storage device.
By default the file system uses the FS_WRITEMODE_SAFE write mode. The write mode
can be changed at runtime via FS_SetFileWriteMode(). If this function is called
in the application than the WriteMode parameter has to be set to FS_WRITEMODE_SAFE.
Alternatively, the call to FS_SetFileWriteMode() can be removed.
Note
Beginning with the version 4.04g of emFile an application is allowed
to use a file buffer in write mode with the Journaling component enabled
without the risk of damaging the structure of a file system in case of an unexpected reset.
This was not possible with versions older that 4.04g because of the way the file buffer
was implemented.
Configuration
The Journaling component has to be configured at compile as well as runtime to
enable its operation.
Compile time configuration
The configuration at compile time 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 Journaling
component.
Enables or disables the efficient handling of consecutive logical sector operations.
FS_SUPPORT_JOURNAL
This define has to be set to 1 in order to enable the support for Journaling component in the file system.
The journal must be initialized in the application at runtime by calling either FS_JOURNAL_Create()
or FS_JOURNAL_CreateEx().
FS_JOURNAL_FILE_NAME
This define specifies the default name of the journal file. The name of the journal file can be changed
at runtime by calling FS_JOURNAL_SetFileName().
FS_MAX_LEN_JOURNAL_FILE_NAME
FS_MAX_LEN_JOURNAL_FILE_NAME is the maximum number of characters (including the 0-terminator)
in the name of the journal file. A value of 0 disables the feature which is the default.
The RAM usage of a volume instance increases the number of bytes specified via this configuration define.
The actual file name can be set at runtime using FS_JOURNAL_SetFileName()
FS_JOURNAL_ENABLE_STATS
The support for statistical counters can be enabled or disabled by using this define.
The statistical counters provide information about the operation of the Journaling component.
The values of the statistical counters can be queried via FS_JOURNAL_GetStatCounters()
and cleared via FS_JOURNAL_ResetStatCounters()
FS_JOURNAL_SUPPORT_FREE_SECTOR
With this feature enabled, the Journaling component forwards information about unused logical
sectors to the device driver. A device driver such as NAND or NOR driver can use this information
to optimize the handling of the data. The operation has to be enabled at runtime via the
IsFreeSectorSupported parameter of FS_JOURNAL_CreateEx()
FS_JOURNAL_SUPPORT_FAST_SECTOR_SEARCH
If this define set to 1 then each entry in the logical to physical mapping table
of the Journaling component is 32-bit large which improves the read and write performance.
At the same time setting FS_JOURNAL_SUPPORT_FAST_SECTOR_SEARCH to 1 it increases
the RAM usage of the Journaling component.
FS_JOURNAL_OPTIMIZE_SPACE_USAGE
Setting this configuration define to 1 enables the Journaling component to group consecutive
sector operations so that the space available in the journal file is used more efficiently.
Especially this option helps prevent the occurrence of journal overflow events
when the application deletes large files with the support for the free sector operation
enabled. Enabling this option increases the RAM usage of the Journaling component.
Runtime configuration
The Journaling component requires a file to temporarily store the changes performed
by the file system. This file has to be created at runtime after the storage device
is formatted by calling either FS_JOURNAL_Create() or FS_JOURNAL_CreateEx().
API functions
The table below lists the available API functions.
Journal instance identified by volume name (0-terminated string).
Return value
= 0
OK, journal transaction opened.
≠ 0
Error code indicating the failure reason.
Additional information
This function is optional. The file system opens and closes
journal transactions automatically as required. The application
can use this function together with FS_JOURNAL_End() to create
journal transactions that extend over multiple file system operations.
A journal transaction can be opened more than once using
FS_JOURNAL_Begin() and it has to be closed by calling FS_JOURNAL_End()
by the same number of times.
#include"FS.h"voidSampleJournalBegin(void){FS_FILE*pFile;#ifFS_SUPPORT_JOURNALFS_JOURNAL_Begin("");// Open the journal transaction.#endif// FS_SUPPORT_JOURNALpFile =FS_FOpen("File1.txt","w");if(pFile){FS_Write(pFile,"Test 1",6);FS_FClose(pFile);}pFile =FS_FOpen("File2.txt","w");if(pFile){FS_Write(pFile,"Test 2...",6);FS_FClose(pFile);}pFile =FS_FOpen("File3.txt","w");if(pFile){FS_Write(pFile,"Test 3...",6);FS_FClose(pFile);}#ifFS_SUPPORT_JOURNALFS_JOURNAL_End("");// Close the journal transaction.#endif// FS_SUPPORT_JOURNAL}
Journal instance identified by volume name (0-terminated string).
NumBytes
Size of journal file in bytes.
Return value
= 1
OK, journal already exists.
= 0
OK, journal successfully created.
< 0
Error code indicating the failure reason.
Additional information
This function is mandatory. It has to be called after the file
system initialization to create the journal file. FS_JOURNAL_Create()
does nothing if the journal file already exists. The name of the
journal file can be configured at compile time via FS_JOURNAL_FILE_NAME
or at runtime via FS_JOURNAL_SetFileName().
The size of the journal file can be calculated by using the following formula:
Number of logical sectors the journal has to be able to store.
The number of sectors the journal file is able to store on a transaction depends
on the file system operations performed by the application. The table below can
be used to calculate the approximate number of sectors that are stored during
a specific file system operation.
The number of sectors modified by FS_RmDir() times the number of directories that have to be deleted plus the number of sectors modified by FS_Remove() times the number of files that have to be deleted.
One sector when creating the file else no sectors. If the file exists and is truncated to 0 then total number of sectors in the allocation table that have to be modified.
Uses the remaining free space in the journal file at the start of the transaction. Two sectors and about 9 percent of the free space available in the journal file (rounded up to a multiple of sector size) are reserved for allocation table and directory entry updates. The remaining sectors are used to store the actual data. If more data is written than free space is available in the journal file, the operation is split into multiple journal transactions.
The values in the table above are for orientation only. The recommended
procedure for determining the size of the journal file is as follows:
Step
Action
1
Set the journal file to an arbitrary value (for example 200 Kbytes)
2
Let the application perform typical file system operations.
3
Verify if any journal overflow events occurred. If yes, then increase the journal file by a multiple of the logical sector size of the volume on which the journal file is stored and go to step 2.
If a journal is created using FS_JOURNAL_Create() the information
about unused logical sectors is not forwarded to the device driver.
FS_JOURNAL_CreateEx() can be used instead to specify how this
information has to be handled.
The journal operation remains disabled after the journal creation
if the application previously disable it via FS_JOURNAL_Disable().
In this case the journal operation has to be explicitly enabled
by the application after the journal creation via FS_JOURNAL_Enable().
Example
#include"FS.h"voidSampleJournalCreate(void){#ifFS_SUPPORT_JOURNAL//// Create journal of 200 Kbytes on the first volume of the file system.//FS_JOURNAL_Create("",200*1024);#endif// FS_SUPPORT_JOURNAL}
Journal instance identified by volume name (0-terminated string).
NumBytes
Size of journal file in bytes.
IsFreeSectorSupported
Handling of the information about unused sectors. 1 Forwarded to the device driver 0 Not forwarded to device driver.
Return value
= 1
OK, journal already exists.
= 0
OK, journal successfully created.
< 0
Error code indicating the failure reason.
Additional information
This function is mandatory. It performs the same operations as FS_JOURNAL_Create().
In addition, IsFreeSectorSupported can be used to specify if the information
about the logical sectors that are no longer in use has to be passed
to the device driver. The NOR and NAND drivers as well as the SD/MMC
driver with eMMC as storage device can use this information to improve
the write performance.
Example
#include"FS.h"voidSampleJournalCreateEx(void){#ifFS_SUPPORT_JOURNAL//// Create a journal file of 100 Kbytes on the first volume of the file system.// The journal component is configured to inform the device driver about// logical sectors that are no longer used by the file system.//FS_JOURNAL_CreateEx("",100*1024,1);#endif// FS_SUPPORT_JOURNAL}
Journal instance identified by volume name (0-terminated string).
Return value
= 0
OK, the journal operation is disabled.
≠ 0
Error code indicating the failure reason.
Additional information
This function is optional. FS_JOURNAL_Disable() can be used
to disable the journal if the next file system operations do
not have to be protected against unexpected resets.
After the call to this function the integrity of the file system
is no more guaranteed. The journal operation can be re-enabled
by calling FS_JOURNAL_Enable().
#include"FS.h"voidSampleJournalDisableEnable(void){FS_FILE*pFile;#ifFS_SUPPORT_JOURNALFS_JOURNAL_Disable("");#endif// FS_SUPPORT_JOURNAL//// The following file system operations are not fail safe.//pFile =FS_FOpen("File1.txt","w");if(pFile){FS_Write(pFile,"Test 1",6);FS_FClose(pFile);}#ifFS_SUPPORT_JOURNALFS_JOURNAL_Enable("");#endif// FS_SUPPORT_JOURNAL//// The following file system operations are fail safe.//pFile =FS_FOpen("File2.txt","w");if(pFile){FS_Write(pFile,"Test 2...",6);FS_FClose(pFile);}}
Journal instance identified by volume name (0-terminated string).
Return value
= 0
OK, the journal operation is enabled.
≠ 0
Error code indicating the failure reason.
Additional information
This function is optional. The journal is enabled automatically
when the file system is mounted if a valid journal file is found.
FS_JOURNAL_Enable() can be used to re-enable the journal after
the application disabled it via FS_JOURNAL_Disable().
After the call to FS_JOURNAL_Enable() all file system operations
are protected against unexpected resets.
#include"FS.h"voidSampleJournalDisableEnable(void){FS_FILE*pFile;#ifFS_SUPPORT_JOURNALFS_JOURNAL_Disable("");#endif// FS_SUPPORT_JOURNAL//// The following file system operations are not fail safe.//pFile =FS_FOpen("File1.txt","w");if(pFile){FS_Write(pFile,"Test 1",6);FS_FClose(pFile);}#ifFS_SUPPORT_JOURNALFS_JOURNAL_Enable("");#endif// FS_SUPPORT_JOURNAL//// The following file system operations are fail safe.//pFile =FS_FOpen("File2.txt","w");if(pFile){FS_Write(pFile,"Test 2...",6);FS_FClose(pFile);}}
Journal instance identified by volume name (0-terminated string).
Return value
= 0
OK, journal transaction closed.
≠ 0
Error code indicating the failure reason.
Additional information
This function is optional. The file system opens and closes
journal transactions automatically as required. The application
can use this function together with FS_JOURNAL_Begin() to create
journal transactions that extend over multiple file system operations.
Following the outermost call to FS_JOURNAL_End() the sector data
stored to journal file is copied to actual destination on the storage
device. The other nested calls to FS_JOURNAL_End() simply close
the transaction at that nesting level but do not copy any data.
#include"FS.h"voidSampleJournalBegin(void){FS_FILE*pFile;#ifFS_SUPPORT_JOURNALFS_JOURNAL_Begin("");// Open the journal transaction.#endif// FS_SUPPORT_JOURNALpFile =FS_FOpen("File1.txt","w");if(pFile){FS_Write(pFile,"Test 1",6);FS_FClose(pFile);}pFile =FS_FOpen("File2.txt","w");if(pFile){FS_Write(pFile,"Test 2...",6);FS_FClose(pFile);}pFile =FS_FOpen("File3.txt","w");if(pFile){FS_Write(pFile,"Test 3...",6);FS_FClose(pFile);}#ifFS_SUPPORT_JOURNALFS_JOURNAL_End("");// Close the journal transaction.#endif// FS_SUPPORT_JOURNAL}
Journal instance identified by volume name (0-terminated string).
pInfo
out Journal information.
Return value
= 0
OK, information returned.
< 0
Error code indicating the failure reason.
Additional information
This function is optional. The application can call it to get
information about the journal such as if the journal is enabled,
the number of free sectors in the journal and so on.
FS_JOURNAL_GetInfo() mounts the specified volume if the auto mount
feature is enabled for that volume and the volume is not mounted a
the time of the call.
FS_JOURNAL_GetOpenCnt()
Description
Returns the number times the current journal transaction has been opened.
Journal instance identified by volume name (0-terminated string).
pStat
out Statistical information.
Return value
= 0
OK, information returned.
≠ 0
Error code indicating the failure reason.
Additional information
This function is optional. It can be used to get information
about the number of operations performed by the journal since
the last file system mount operation or since the last call
to FS_JOURNAL_ResetStatCounters().
FS_JOURNAL_GetStatCounters() is available only when the file
system is compiled with either FS_JOURNAL_ENABLE_STATS set to 1
or with FS_DEBUG_LEVEL set to a value equal to or larger than
FS_DEBUG_LEVEL_CHECK_ALL.
Journal instance identified by volume name (0-terminated string).
Return value
≥ 0
OK, journal data has been discarded.
≠ 0
Error code indicating the failure reason.
Additional information
This function is optional. It can be used to discard all the
modifications stored in the journal during a journal transaction
opened via FS_JOURNAL_Begin(). After the call to FS_JOURNAL_Invalidate()
the current journal transaction is closed. In case of a journal
transaction opened multiple times it is not necessary to call
FS_JOURNAL_Invalidate() for the number of times the journal transaction
has been opened.
A read sector cache has to be invalidated after canceling a
journal transaction via FS_JOURNAL_Invalidate(). The application
can configure a read sector cache via FS_AssignCache().
Example
#include"FS.h"staticint_GetData(U8 *pData){intNumBytes;NumBytes =-1;//// ...//returnNumBytes;}voidSampleJournalInvalidate(void){intIsError;FS_FILE*pFile;U8 abBuffer[16];intNumBytes;IsError =0;//// Begin the journal transaction.//#ifFS_SUPPORT_JOURNALFS_JOURNAL_Begin("");#endif// FS_SUPPORT_JOURNAL//// Create the file and write to it.//pFile =FS_FOpen("Test.txt","w");if(pFile){while(1){//// Get the data from an external source.//NumBytes =_GetData(abBuffer);if(NumBytes ==0){FS_FClose(pFile);break;// No more data available.}if(NumBytes <0){IsError =1;break;// Error, could not get data.}//// Write the data to file.//FS_Write(pFile,abBuffer,(U32)NumBytes);}}//// Close the transaction.//#ifFS_SUPPORT_JOURNALif(IsError){FS_JOURNAL_Invalidate("");}else{FS_JOURNAL_End("");}#endif// FS_SUPPORT_JOURNAL}
Journal instance identified by volume name (0-terminated string).
Return value
= 1
The journal is active. All the file system operations are fail safe.
= 0
The journal is not active. The file system operations are not fail safe.
< 0
Error code indicating the failure reason.
Additional information
This function is optional. The journal is automatically activated
at file system mount if a valid journal file is present. The journal
file can be created using FS_JOURNAL_Create() or FS_JOURNAL_CreateEx().
The journal can be enabled and disabled at runtime using FS_JOURNAL_Enable()
and FS_JOURNAL_Disable() respectively.
Journal instance identified by volume name (0-terminated string).
Return value
= 1
OK, journal file is present and valid.
= 0
OK, journal file is not present.
< 0
Error code indicating the failure reason.
Additional information
This function is optional. The application can call it to check
if a journal file is present on the specified volume and that
the file is also valid.
FS_JOURNAL_IsPresent() mounts the specified volume if the auto mount
feature is enabled for that volume and the volume is not mounted a
the time of the call.
Journal instance identified by volume name (0-terminated string).
Return value
= 0
OK, statistical counters cleared.
≠ 0
Error code indicating the failure reason.
Additional information
This function is optional. The statistical counters are cleared
each time the volume is mounted. An application can use
FS_JOURNAL_ResetStatCounters() to explicitly clear the statistical
counters at runtime for example for testing purposes.
The statistical counters can be queried via FS_JOURNAL_GetStatCounters()
FS_JOURNAL_ResetStatCounters() is available only when the file
system is compiled with either FS_JOURNAL_ENABLE_STATS set to 1
or with FS_DEBUG_LEVEL set to a value equal to or larger than
FS_DEBUG_LEVEL_CHECK_ALL.
FS_JOURNAL_SetFileName() is available only when the file system
is compiled with the FS_MAX_LEN_JOURNAL_FILE_NAME configuration
define set to a value greater than 0.
FS_JOURNAL_SetOnOverflowExCallback()
Description
Registers a callback function for the journal full event.
Function to be invoked when the journal full event occurs.
Additional information
This function is optional. A journal full event occurs when there
is no more free space in the journal file to store the modifications
requested by the file system layer. When this event occurs, the data currently
stored in the journal is copied to the actual destination on the storage
device to make free space for the new data. This behavior can be changed
via the return value of the callback function. Refer to
FS_JOURNAL_ON_OVERFLOW_EX_CALLBACK for more information.
The file system is no longer fail safe in the time interval from
the occurrence of the journal full event to the end of current
journal transaction.
FS_JOURNAL_SetOnOverflowCallback()
Description
Registers a callback function for the journal full event.
Function to be invoked when the journal full event occurs.
Additional information
This function is optional. A journal full event occurs when there
is no more free space in the journal file to store the modifications
requested by the file system layer. When this event occurs, the data currently
stored in the journal is copied to the actual destination on the storage
device to make free space for the new data.
The file system is no longer fail safe in the time interval from
the occurrence of the journal full event to the end of current
journal transaction.
NumSectorsFree is always smaller than or equal to NumSectors.
The difference between NumSectors and NumSectorsFree represents
the number of logical sectors that can still be stored to journal
without causing a journal overflow.
MaxWriteSectorCnt can be used to fine tune the size of the journal file
by comparing its value with the number of sectors that can be stored
in the journal file. The number of sectors that can be stored in the
journal file can be read via FS_JOURNAL_GetInfo().
Performance and resource usage
This section describes the memory requirements (RAM and ROM) of the
Journaling component as well as the read and write performance.
ROM usage
The ROM usage depends on the compiler options, the compiler version and the used CPU.
The following values were measured as described in the section
Test procedure.
Usage: 3.3 Kbytes
Static RAM usage
The static RAM usage represents the amount of RAM required by the Journaling
component to store static variables. The number of bytes can be seen in the
list file of the compiled Journaling component.
Usage: 16 bytes
Dynamic RAM usage
The dynamic RAM usage is the amount of RAM allocated by the Journaling
component at runtime. The number of bytes allocated depends on the journal size
and on the number of volumes on which the Journaling component is enabled.
The approximate runtime RAM usage of the Journaling component can be calculated
as follows:
Number of volumes on which the journaling is active
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 and resource usage
section.
All speed values are in Kbytes/second.
CPU type
Storage device
Write speed
Reed speed
NXP LPC2478 (57.6 MHz)
SST SST39VF201 (1x16 bit, no “write burst”)
5.6
2534
ST STM32F103 (72 MHz)
ST M29W128 (1x16, with “write burst”, 64 bytes)
18.5
7877
FAQs
Can a journal be created when other files are already present on the disk?
Yes. The Journaling component saves the data in a regular file called per
default “Journal.dat”. If there is sufficient space left on the storage device
there is no problem to create the journal even if other files are present.
Can the journal file be recreated?
Yes. Follow this procedure to recreate the journal:
Re-initialize the file system via FS_DeInit() and FS_Init() if the size of the journal file is increased.
Can a journal be deleted?
Yes, by deleting the journal file.
What if the journal isn’t sufficiently large?
If the journal is not sufficiently large the data already present in the
journal file is copied to the actual destination on the storage device in order
to make room for the new data.
Can multiple tasks use a journal at the same time?
Yes. The Journaling component maintains an open counter that is incremented
each time FS_JOURNAL_Begin() is called and is decremented with each call
to FS_JOURNAL_End(). When the open counter reaches zero the data is copied from
journal file to the actual destination on the storage device and the journal
transaction is terminated.
Encryption
This chapter documents the emFile Encryption component.
The component can be used to stored the data in a secure way.
General information
emFile Encryption is an additional component which can be used to secure the data
of the entire volume or of individual files. Without encryption support all data is
stored in a readable form. Using the Encryption component the data can be made unreadable
before using a secret key being stored to the storage device. Without the knowledge of the
secret key it is not possible to make the data readable again.
The main features of the Encryption component are:
Can be used with both FAT and EFS file systems.
All storage types such as NAND, NOR, SD/MMC/CompactFlash cards are supported.
Only minor changes of application are required.
DES and AES with 128-bit and 256-bit key lengths are supported.
Encryption of entire storage device or of individual files.
Support for authenticated encryption.
An utility is provided for file decryption and encryption on a PC.
Two packages are available: Encryption (DES) and Extra Strong Encryption (DES and AES
AES encryption algorithm is subject to export regulations
)
How to use encryption
Using file encryption is very simple from the application’s perspective.
The following changes have to be made to an existing application in order
to enable the encryption of individual files:
Enable file encryption in the emFile configuration.
Refer to Compile time configuration for detailed information.
Call FS_CRYPT_Prepare() to initialize an encryption object.
This operation has to be performed only once. Refer to FS_CRYPT_Prepare()
for detailed information.
The actual encryption and decryption is performed by the Encryption component
when the application accesses the file contents via the file read and write API functions.
The application has to make sure that the size of an encrypted file
is always a multiple of the cryptographic algorithm block size (16 bytes
for DES and AES) so that the last bytes in the file are encrypted with that
cryptographic algorithm. Otherwise the data of the last incomplete block
is only scrambled by using a different algorithm. This limitation does not
apply to authenticated encryption.
Example usage
This sample function opens a file and writes a text message to it. The file contents
are encrypted using the DES encryption algorithm. The changes required to an
application to support encryption are marked with the comment: // Required for encryption.
#include"FS.h"voidSampleEncryptionFile(void){FS_FILE*pFile;#ifFS_SUPPORT_ENCRYPTIONconstU8 aKey[8]={1,2,3,4};// Required for encryptionFS_CRYPT_OBJCryptObj;// Required for encryptionstaticFS_DES_CONTEXT _Context;// Required for encryptionstaticint_IsInited;// Required for encryption#endif// FS_SUPPORT_ENCRYPTION#ifFS_SUPPORT_ENCRYPTION//// Create the encryption object. It contains all the necessary information// for the encryption/decryption of data. This step must be performed only once.//if(_IsInited ==0){// Required for encryptionFS_CRYPT_Prepare(&CryptObj,&FS_CRYPT_ALGO_DES,// Required for encryption&_Context,512,aKey);// Required for encryption_IsInited =1;// Required for encryption}#endif// FS_SUPPORT_ENCRYPTIONpFile =FS_FOpen("cipher.bin","w");if(pFile){#ifFS_SUPPORT_ENCRYPTION//// Assign the created encryption object to file handle.//FS_SetEncryptionObject(pFile,&CryptObj);// Required for encryption#endif// FS_SUPPORT_ENCRYPTION//// Write data to file using encryption. The message// is padded with '\n' characters to a multiple of// DES block size (16 bytes).//FS_Write(pFile,"This message has been encrypted using ""SEGGER emFile.\n\n\n\n\n\n\n\n\n\n\n\n",64);FS_FClose(pFile);}}
Additional information
The encryption component also supports the encryption of entire volumes.
For more information refer to Encryption driver.
Compile time configuration
The configuration of emFile can be changed via compile time flags that
can be added to FS_Conf.h which is the main configuration file of the file system.
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 Encryption
component.
Enables or disables the support for the file encryption.
FS_CRYPT_AES_OPTIMIZE_MIX_SUBST
This configuration define can be used to enable a speed optimization
of the AES software algorithm that makes use of precalculated values
stored in ROM. Setting this define to 1 increases the ROM usage of
the file system.
FS_CRYPT_AES_OPTIMIZE_MIX_COLUMNS
This define can be used to control the level of optimization enabled
via FS_CRYPT_AES_OPTIMIZE_MIX_SUBST. Permitted values are 0, 1, and 2
with 2 being the highest optimization level.
FS_CRYPT_AES_SUPPORT_INPLACE_CALC
Enables or disables the use of the same data buffer as input and output
for the AES encryption algorithm.
FS_CRYPT_AUTH_TAG_BUFFER_SIZE
This define can be used to specify the size of the work buffer used by the
file system to temporary store the values of processed authentication
tags during the access to a file. The set value has to be greater than
or equal to the size of the greatest authentication tag used by the
encryption algorithm. The work buffer is allocated on the stack.
FS_CRYPT_DES_SUPPORT_INPLACE_CALC
Enables or disables the use of the same data buffer as input and output
for the DES encryption algorithm.
FS_CRYPT_SUPPORT_ENHANCED_MODE
Enables or disables the support for authenticated file encryption.
The authenticated file encryption has to be enabled at runtime by
calling FS_SetEncryptionObjectEx() for the accessed file.
The IsEnhanced parameter has to set to 1.
FS_CRYPT_SUPPORT_STANDARD_MODE
Enables or disables the support for file encryption without authentication.
The file encryption has to be enabled at runtime by calling either
FS_SetEncryptionObject() or FS_SetEncryptionObjectEx() for the accessed file.
FS_SetEncryptionObjectEx() has to be called with the IsEnhanced parameter set to 0.
This configuration define can be set to 0 to save ROM space if the application
accesses the encrypted file is using only authenticated file encryption.
FS_SUPPORT_ENCRYPTION
Enables or disables the support for file encryption in the file system.
The encrypted access to a file has to be enabled at runtime by calling
either FS_SetEncryptionObject() or FS_SetEncryptionObjectEx().
API functions
The following table lists the available API functions.
in Index of the decrypted data block. out Index of the next block to be decrypted.
Return value
= 0
OK, object initialized successfully.
≠ 0
Error code indicating the failure reason.
Additional information
This function can be used on a host computer to decrypt a file
encrypted on a target system by using the Encryption component.
On a target system the data is decrypted automatically by the
file system. pBlockIndex can be used to start the decryption
at an arbitrary block index inside the file. The size of the block
is the value passed to BytesPerBlock in the call to FS_CRYPT_Prepare()
that was used to initialize the encryption object.
Example
For an example usage refer to the source code of the FSFileEncrypter.exe utility
located in the Windows\FS\FSFileEncrypter\Application\FSFileEncrypter.c file of the emFile shipment.
FS_CRYPT_DecryptEx()
Description
Decrypts the specified number of bytes and verifies the authentication tags.
in Index of the decrypted data block. out Index of the next block to be decrypted.
pAuthTagList
in List of authentication tags to be checked. It can be set to NULL.
SizeOfAuthTagList
Number of bytes in pAuthTagList. It can be set to 0.
Return value
= 0
OK, object initialized successfully.
≠ 0
Error code indicating the failure reason.
Additional information
This function can be used on a host computer to decrypt a file
encrypted on a target system by using the Encryption component.
On a target system the data is decrypted automatically by the
file system. pBlockIndex can be used to start the decryption
at an arbitrary block index inside the file. The size of the block
is the value passed to BytesPerBlock in the call to FS_CRYPT_Prepare()
that was used to initialize the encryption object.
The authentication tags have to be aligned to a four byte boundary
in pAuthTagList. If pAuthTagList is set to NULL and SizeOfAuthTagList
is set to 0 then the authentication tags are not verified.
in Index of the encrypted data block. out Index of the next block to be encrypted.
Return value
= 0
OK, object initialized successfully.
≠ 0
Error code indicating the failure reason.
Additional information
This function can be used on a host computer to encrypt a file
that can be later decrypted on a target system by using the Encryption
component. On a target system the data is decrypted automatically
by the file system when the application reads the data from file.
pBlockIndex can be used to start the encryption at an arbitrary
block index inside the file. The size of the block is the
value passed to BytesPerBlock in a call to FS_CRYPT_Prepare()
that was used to initialize the encryption object.
Example
For an example usage refer to the source code of the FSFileEncrypter.exe utility
located in the Windows\FS\FS_FileEncrypter\Src folder of the emFile shipment.
FS_CRYPT_EncryptEx()
Description
Encrypts the specified number of bytes and calculates the authentication tags.
in Index of the encrypted data block. out Index of the next block to be encrypted.
pAuthTagList
out List of calculated authentication tags. It can be set to NULL.
SizeOfAuthTagList
Number of bytes in pAuthTag. It can be set to 0.
Return value
= 0
OK, object initialized successfully.
≠ 0
Error code indicating the failure reason.
Additional information
This function can be used on a host computer to encrypt a file
that can be later decrypted on a target system by using the Encryption
component. On a target system the data is decrypted automatically
by the file system when the application reads the data from file.
pBlockIndex can be used to start the encryption at an arbitrary
block index inside the file. The size of the block is the
value passed to BytesPerBlock in a call to FS_CRYPT_Prepare()
that was used to initialize the encryption object.
The authentication tags are stored aligned to a four byte boundary
in pAuthTagList. If pAuthTagList is set to NULL and SizeOfAuthTagList
is set to 0 then the function does not calculates and stores
any authentication tags.
FS_CRYPT_Prepare()
Description
Initializes the object required for the encryption/decryption of file contents.
This function has to be called once for each encryption object.
pAlgoType is a pointer to one of the following structures:
Algorithm type
Description
FS_CRYPT_ALGO_DES
Data Encryption Standard with 56-bit key length
FS_CRYPT_ALGO_AES128
Advanced Encryption Standard with 128-bit key length
FS_CRYPT_ALGO_AES256
Advanced Encryption Standard with 256-bit key length
The pContext parameter points to a structure of type FS_DES_CONTEXT when the
FS_CRYPT_ALGO_DES algorithm is specified or to FS_AES_CONTEXT structure when
the FS_CRYPT_ALGO_AES128 or the FS_CRYPT_ALGO_AES256 are specified. The context
pointer is saved to object structure and must point to a valid memory location
as long as the encryption object is in use.
BytesPerBlock is a power of two value that has to be smaller than or equal to the
logical sector size of the volume that stores the file to be encrypted or decrypted.
The number of bytes in pKey depends on the algorithm type as follows:
Algorithm type
Size in bytes
FS_CRYPT_ALGO_DES
8
FS_CRYPT_ALGO_AES128
16
FS_CRYPT_ALGO_AES256
32
The encryption object can be shared between different files.
OK, configured the object to be used for file encryption.
≠ 0
Error code indicating the failure reason.
Additional information
This function has to be called once immediately after the file
has been opened and before any other operation on that file.
The pointer to encryption object is saved internally by the file
system to the file handle. This means that the memory it points
to has to remain valid until the file is closed or
until the FS_SetEncryptionObject() is called for the same file
handle with pCryptObj set to NULL.
Specifies the file encryption mode. 0 Standard encryption. 1 Enhanced encryption.
Return value
= 0
OK, configured the object to be used for file encryption.
≠ 0
Error code indicating the failure reason.
Additional information
This function has to be called once immediately after the file
has been opened and before any other operation on that file.
The pointer to encryption object is saved internally by the file
system to the file handle. This means that the memory it points
to has to remain valid until the file is closed or
until the FS_SetEncryptionObjectEx() is called for the same file
handle with pCryptObj set to NULL.
This function is available only when the file system is built with
FS_SUPPORT_ENCRYPTION set to 1.
FS_SetEncryptionObjectEx() performs the same operation as
FS_SetEncryptionObject() with the difference that is permits
the application to select the encryption mode via the IsEnhanced
parameter. FS_SetEncryptionObjectEx() reports an error if
IsEnhanced is set to 1 and the file system built with
FS_CRYPT_SUPPORT_ENHANCED_MODE set to 0 or if IsEnhanced is set to
0 and the file system built with FS_CRYPT_SUPPORT_STANDARD_MODE set to 0.
Encryption algorithm
The encryption algorithm is a set of functions that the file system
calls to perform the actual data encryption and decryption.
The following sections describe these functions in detail.
This function is a member of the FS_CRYPT_ALGO_TYPE cryptographic
algorithm. It encrypts the specified data block using the key
specified in the call to FS_CRYPT_Prepare().
NumBytes is always a multiple of the encryption block size specified
via BitsPerBlock of FS_CRYPT_ALGO_TYPE.
BlockIndex is set to the index of the logical sector
that stores the data being encrypted. It can be used
for example as initialization vector for AES and DES
cryptographic algorithms.
This function is a member of the FS_CRYPT_ALGO_TYPE cryptographic
algorithm. It decrypts the specified data block using the key
specified in the call to FS_CRYPT_Prepare().
NumBytes is always a multiple of the encryption block size specified
via BitsPerBlock of FS_CRYPT_ALGO_TYPE.
BlockIndex is set to the index of the logical sector
that stores the data being encrypted. It can be used
for example as initialization vector for AES and DES
cryptographic algorithms. BlockIndex is set to the
same value passed to FS_CRYPT_ALGO_TYPE_ENCRYPT when
encrypting the same data block.
FS_CRYPT_ALGO_TYPE_ENCRYPT_EX
Description
Encrypts a data block and calculates the authentication tag.
out Encrypted data (ciphertext). It can be set to NULL.
pDataIn
in Data to be encrypted (plaintext).
NumBytes
Number of bytes to be encrypted.
BlockIndex
Index of the data block to be encrypted.
pAuthTag
out Calculated authentication tag.
Return value
= 0
OK, data encrypted correctly.
≠ 0
An error occurred.
Additional information
This function is a member of the FS_CRYPT_ALGO_TYPE cryptographic
algorithm. It encrypts the specified data block using the key
specified in the call to FS_CRYPT_Prepare().
NumBytes is always a multiple of the encryption block size specified
via BitsPerBlock of FS_CRYPT_ALGO_TYPE.
BlockIndex is set to the index of the logical sector
that stores the data being encrypted. It can be used
for example as initialization vector for AES and DES
cryptographic algorithms.
pAuthTag is a buffer sufficiently large to store the authentication tag.
The size of the authentication tag is specified via BitsPerAuthTag of FS_CRYPT_ALGO_TYPE.
pDataOut and pDataIn can point to the same memory area.
If pDataOut is set to NULL, then the function has to calculate the
authentication tag of the data pointed to by pDataIn without encrypting it.
FS_CRYPT_ALGO_TYPE_DECRYPT_EX
Description
Decrypts a data block and verifies the authentication tag.
out Decrypted data (plaintext). It can be set to NULL.
pDataIn
in Data to be decrypted (ciphertext).
NumBytes
Number of bytes to be decrypted.
BlockIndex
Index of the data block to be decrypted.
pAuthTag
in Authentication tag to be verified.
Return value
= 0
OK, data decrypted correctly.
≠ 0
An error occurred such as authentication tag mismatch.
Additional information
This function is a member of the FS_CRYPT_ALGO_TYPE cryptographic
algorithm. It decrypts the specified data block using the key
specified in the call to FS_CRYPT_Prepare().
NumBytes is always a multiple of the encryption block size specified
via BitsPerBlock of FS_CRYPT_ALGO_TYPE.
BlockIndex is set to the index of the logical sector
that stores the data being encrypted. It can be used
for example as initialization vector for AES and DES
cryptographic algorithms. BlockIndex is set to the
same value passed to FS_CRYPT_ALGO_TYPE_ENCRYPT when
encrypting the same data block.
pAuthTag is the authentication tag calculated at encryption.
The size of the authentication tag is specified via BitsPerAuthTag
of FS_CRYPT_ALGO_TYPE.
pDataOut and pDataIn can point to the same memory area.
If pDataOut is set to NULL, then the function has to verify the
authentication tag of the data pointed to by pDataIn without decrypting it.
Encryption utility
emFile comes with command line utilities that allow the encryption and decryption
of files on a host PC. Due to export regulations of encryption software
two separate executables are provided that support cryptographic algorithms with
different strengths.
FSFileEncrypter.exe supports only the encryption algorithms with a key length
smaller than or equal to 56-bit that are not subject to any export regulations.
This utility supports only the DES cryptographic algorithm.
Encryption and decryption of files with any key length can be done using the
FSFileEncrypterES.exe utility that supports the DES as well as the AES cryptographic
algorithms.
Using the file encryption utility
The utilities can be invoked directly from the command line or via a batch file.
In order to use the utility directly, a terminal window must be opened first.
First, the name of the executable either FSFileEncrypter.exe or
FSFileEncrypterES.exe, has to be input on the command line followed by
optional and required arguments. By pressing the Enter key the utility starts
the encryption or decryption operation as specified.
Below is a screen shot of the FSFileEncrypter.exe utility that is invoked to
decrypt the contents of the file des.bin. The decrypted plain text is placed
into the file des.txt. The used cryptographic algorithm is DES as specified via
the -a option. Information about the decrypting process is displayed on the terminal
window. In case of an error, a message is displayed indicating the failure reason and
the utility returns with a status of 1. No destination file is created in this case.
Command line options
The following table lists the parameters which can be omitted when invoking
the utilities.
Selects the encryption algorithm. Default encryption algorithm is DES.
Syntax
-a <AlgoType>
Additional information
The following table lists all valid values for AlgoType:
Type
Description
DES
Data Encryption Standard, 56-bit key length.
AES128
Advanced Encryption Standard, 128-bit key length (supported only by FSFileEncrypterES.exe)
AES256
Advanced Encryption Standard, 256-bit key length (supported only by FSFileEncrypterES.exe)
Example
Shows how to encrypt the contents of the file plain.txt file to cipher.bin file
using the DES cryptographic algorithm. The encryption key is the string secret.
C:>FSFileEncrypter -a DES secret plain.txt cipher.bin
-b
Description
Sets the size of the encryption block. Default block size is 512 bytes.
Syntax
-b <BlockSize>
Additional information
The parameter has to be be a power of twp value and represents the number of bytes in
the block. The block size has to be equal to the value passed to BytesPerBlock
in the call to FS_CRYPT_Prepare() function that was used to initializes the encryption
object on the target application.
Example
Shows how to encrypt the contents of the file plain.txt file to cipher.bin
file using the DES cryptographic algorithm. The encryption key is the string
secret and the size of the encryption block is 2048 bytes.
Shows how to decrypt the contents of the file cipher.bin to the plain.txt
file using the DES cryptographic algorithm. The encryption key is the string secret.
FSFileEncrypter -d secret cipher.bin plain.txt
-h
Description
Shows the usage message and exits.
Syntax
-h
Example
C:>FSFileEncrypterES -h
DESCRIPTION
File encryption and decryption utility for SEGGER emFile.
USAGE
FSFileEncrypterES [-a <AlgoType>] [-b <BlockSize>]
[-d] [-h] [-q] [-v] <Key> <SrcFile> <DestFile>
OPTIONS
-a <AlgoType> Type of the encryption algorithm. AlgoType can be one of:
DES Data Encryption Standard, 56-bit key length
AES128 Advanced Encryption Standard, 128-bit key length
AES256 Advanced Encryption Standard, 256-bit key length
Default is DES.
-b <BlockSize> Number of bytes to be encrypted/decrypted at once.
BlockSize must be a power of 2 value. When encrypting a file
BlockSize must be smaller than or equal to the sector size
of the file system volume. When decrypting a file, BlockSize
must be equal to the value used to encrypt the file.
Default is 512 bytes.
-d Perform decryption. Default is encryption.
-h Show this help information.
-q Do not show log messages.
-v Show version information.
ARGUMENTS
<Key> Encryption or decryption key as ASCII string. Non-printable
characters can be specified as 2 hexadecimal characters
prefixed by the sequence '\x'.
Ex: the key value 1234 can be specified as \x04\xD2.
<SrcFile> Path to file to be encrypted or decrypted.
<DestFile> Path to encrypted or decrypted file.
-q
Description
Suppresses log information. Default is to log messages to console.
Syntax
-q
-v
Description
Shows version information and exits.
Syntax
-v
Example
C:>FSFileEncrypterES -v
SEGGER FS File Encrypter (Extra Strong) V1.01a ('?' or '-h' for help)
Compiled on Sep 4 2012 16:18:23
Command line arguments
The following table lists the mandatory parameters. They must be specified
on the command line in the order they are described in this table.
A string which specifies the encryption key. Non-printable characters can be input in
hexadecimal form by prefixing them with the string \x. The key is case sensitive.
Example
The file plain.txt is encrypted using DES cryptographic algorithm and the result
is stored to the cipher.bin file. The password looks like this in binary form:
0x700x610x730x730x010x020x030x04.
It specifies the plain text file in case encryption is performed. When decrypting
this parameter specifies the encrypted file. The parameters SrcFile and DestFile
must specify two different files.
Example
Shows how to encrypt the contents of the file plain.txt to the file cipher.bin
using the AES cryptographic algorithm. plain.txt is the source file.
C:>FSFileEncrypterES -a AES128 pass plain.txt cipher.bin
<DestFile>
Description
Path to the file to write to.
Additional information
It specifies the cipher text file in case encryption is performed. When decrypting
this parameter specifies the plain text file. The parameters SrcFile and DestFile
must specify two different files.
Example
Shows how to decrypt the contents of the file cipher.bin to the file plain.txt
using the AES cryptographic algorithm. plain.txt is the destination file.
C:>FSFileEncrypterES -d -a AES256 pass cipher.bin plain.txt
Performance and resource usage
This section describes the memory requirements (RAM and ROM) of the
encryption component as well as the read and write performance.
This section lists only the values for the encryption at the file level.
Refer to Performance and resource usage
for the performance and resource usage of volume encryption.
ROM usage
The ROM usage depends on the compiler options, the compiler version and the used CPU.
The following values were measured as described in the section
Test procedure.
Usage: 0.4 Kbytes
In addition, one of the following cryptographic algorithms is required:
Algorithm type
ROM usage
FS_CRYPT_ALGO_DES
3.2 Kbytes
FS_CRYPT_ALGO_AES128
12 Kbytes
FS_CRYPT_ALGO_AES256
12 Kbytes
Static RAM usage
Static RAM usage is the amount of RAM required by the encryption component
for static variables. The encryption component does not allocate any static
variables.
Dynamic RAM usage
Dynamic RAM usage is the amount of RAM allocated by the encryption
component at runtime. The encryption component requires one sector buffer for
the encryption and decryption of data. The size of a sector buffer is by default
512 bytes. This value can be changed in the application via FS_SetMaxSectorSize().
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 in Kbytes/second.
CPU type
Storage device
Write speed
Reed speed
NXP Kinetis K60 (120 MHz)
NAND flash interfaced via 8-bit bus using AES with an 128-bit key.
522
553
ST STM32F4 (96 MHz)
SD card as storage medium using AES with an 128-bit key
500
530
BigFAT
This chapter describes the component for files larger than 4GB.
General information
The FAT and EFS file systems are not able to handle files larger than
4 Gbytes because the size of the file is stored as a 32-bit value.
The BigFAT component can be used in a target application to remove
this limitation. Using the BigFAT component a target application can
create, read, write and otherwise perform typical operations
on files larger than 4GB. This is done by distributing the data
across fragment files smaller than 4GB. The created fragment files
are compatible with the file system on which they are stored.
The main features of the BigFAT component are:
Can be used with both FAT and EFS file systems.
Supports all storage types such as NAND, NOR, SD cards, and USB drives.
Utility available to merge or split files on a PC.
Theory of operation
BigFAT is built on top of the FAT and EFS file systems. It splits the data of a
file that grows larger than 4GB into smaller files. Consequently, they can be
stored to the file system as regular files. The file system operations are redirected
to the appropriate file, depending on the file position that is accessed by the embedded
application.
Files with a size smaller than 4GB - 128KB are treated like regular files.
In this case, the file access works as in a standard file system implementation.
As soon as the file grows above the limit, the file gets extended. An extended
file consists of one base file and one or more continuation files. The continuation
files are stored in the same directory as the base file, with the name derived
from the name of the base file plus an additional file extension. The name of
the base file remains unchanged. The file extension of a continuation file has
the format .<Index>.BigFAT, where the Index is a three digit decimal number.
The index of the first continuation file is set to one and it increases by one with
each additional continuation file. BigFAT requires support for long file names
on the underlying file system layer in order to be able to apply the additional
file extension of continuation files.
When the base file grows larger than 4GB - 128KB, the first continuation
file is created. This procedure is required in order to guarantee that the first
byte in the continuation file is aligned to a logical sector boundary. This helps
increase the performance of the file system accessing the file data. The same
procedure is applied when the first continuation file exceeds the
4GB - 128KB limit, with the second continuation file being created
and so on.
Configuration
The BigFAT component can optionally be configured at compile time
and does not have to be configured at runtime.
However, the application has to make sure that the support for long
file names is enabled via FS_FAT_SupportLFN() if the BigFAT files
are located on a FAT-formatted volume. This is not necessary for
EFS-formatted volumes because EFS comes with native support for long
file names.
Compile time configuration
The handle to an opened BigFAT file stores the fully qualified name
of the file. The maximum number of characters in the file name including
the 0-terminator is configured via the FS_MAX_LEN_FULL_FILE_NAME
configuration define. By default, FS_MAX_LEN_FULL_FILE_NAME is set
to a value that works with most of the applications.
FS_MAX_LEN_FULL_FILE_NAME can be set to a smaller value to save
RAM space if the paths to the BigFAT files accessed by the application
are not longer than that value.
API functions
The table below lists the available API functions.
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 checks.
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 performs the same operation as FS_CheckDisk() with the
difference that it checks big files for defects.
In addition to FS_CheckDisk(), FS_BIGFAT_CheckDisk() is able to detect the following errors:
missing fragment file.
fragment file without a corresponding base file.
fragment file with invalid size.
These checks are performed after the call to FS_CheckDisk().
Refer to FS_CheckDisk() for more information about the usage of this function.
Example
#include<stdio.h>#include<stdarg.h>#include<string.h>#include"FS.h"staticU32 _aBuffer[1024/4];staticint_NumErrors;/*********************************************************************** _OnError*/int_OnError(intErrCode,...){va_list ParamList;constchar*sFormat;charc;charac[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"" * Delete cluster chain (d)\n"" * Do not repair (n)\n"" * Abort (a) ");FS_X_Log("\n");}_NumErrors++;c =getchar();FS_X_Log("\n");if((c =='y')||(c =='Y')){returnFS_CHECKDISK_ACTION_SAVE_CLUSTERS;}elseif((c =='a')||(c =='A')){returnFS_CHECKDISK_ACTION_ABORT;}elseif((c =='d')||(c =='D')){returnFS_CHECKDISK_ACTION_DELETE_CLUSTERS;}returnFS_CHECKDISK_ACTION_DO_NOT_REPAIR;// Do not repair anything.}/*********************************************************************** SampleBigFATCheckDisk*/voidSampleBigFATCheckDisk(void){intr;while(1){r =FS_BIGFAT_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");}}
The application has to call FS_BIGFAT_Close() after it no longer
needs to access the big file. FS_BIGFAT_Close() frees all the
file system resources allocated to the opened file.
pBigFile has to point to a structure that was successfully
initialized via a call to FS_BIFILE_Open(). After the call to
FS_BIGFAT_Close() the file handle pBigFile is no longer valid
and the memory allocated for it can be released by the application.
The application can also use pBigFile as parameter
to FS_BIFILE_Open() to open a file again.
Example
#include"FS.h"voidSampleBigFATClose(void){FS_BIGFAT_FILEBigFile;intr;//// Opens a file for reading and then closes it.//r =FS_BIGFAT_Open(&BigFile,"Test.txt",FS_BIGFAT_OPEN_FLAG_READ);if(r ==0){//// Perform read accesses to file//FS_BIGFAT_Close(&BigFile);}}
in Buffer for the copy operation (optional). Can be set to NULL.
NumBytes
Size of the copy buffer.
Return value
= 0
OK, file duplicated.
≠ 0
Error code indicating the failure reason.
Additional information
The source and destination files can be located on different volumes.
If no working buffer is specified the function uses a buffer
of 512 bytes that is allocated on the stack.
Example
#include"FS.h"voidSampleBigFATCopy(void){//// Copies the contents of "Test.txt" to file "TestCopy.txt" in the folder "SubDir".//FS_BIGFAT_Copy("Test.txt","SubDir\\TestCopy.txt",NULL,0);}
OK, no files or directories available in directory.
= 0
OK, information about the file or directory returned.
< 0
Error code indicating the failure reason.
Additional information
The name of a visited file is truncated if it does not fit into
sFileName buffer.
The file system is able to handle a sFileName buffer with
a maximum size of 32767 bytes.
Example
#include<stdio.h>#include<string.h>#include"FS.h"voidSampleBigFATFind(void){FS_BIGFAT_FIND_DATAFindData;intr;characFileName[32];charac[100];//// Lists the names of all files and directories located in the root directory// of the default volume.//memset(acFileName,0,sizeof(acFileName));r =FS_BIGFAT_FindFirst(&FindData,"",acFileName,sizeof(acFileName));if(r <0){SEGGER_snprintf(ac,sizeof(ac),"Cannot list directory (%s)\n",FS_ErrorNo2Text(r));FS_X_Log(ac);}else{if(r ==1){FS_X_Log("Empty directory\n");}else{for(;;){SEGGER_snprintf(ac,sizeof(ac),"%s\n",acFileName);FS_X_Log(ac);r =FS_BIGFAT_FindNext(&FindData);if(r <0){SEGGER_snprintf(ac,sizeof(ac),"Cannot list directory (%s)\n",FS_ErrorNo2Text(r));FS_X_Log(ac);break;}else{if(r ==1){break;// No more files or directories available.}}}}}FS_BIGFAT_FindClose(&FindData);}
FS_BIGFAT_FindNext()
Description
Returns information about the next file or directory
in a directory scanning operation.
out Position in the file as byte offset (0-based).
Return value
= 0
OK, file position returned.
≠ 0
Error code indicating the failure reason.
Additional information
The current file position can be modified by using FS_BIGFAT_SetPos()
and is increased after each read or write operation by the number
of bytes accessed.
pBigFile has to point to a structure that was successfully
initialized via a call to FS_BIFILE_Open().
Example
#include<stdio.h>#include"FS.h"voidSampleBigFATGetPos(void){FS_BIGFAT_FILEBigFile;U64 FilePos;intr;charac[100];//// Opens a file for writing, writes some data to it and queries the file position.//r =FS_BIGFAT_Open(&BigFile,"Test.txt",FS_BIGFAT_OPEN_FLAG_WRITE |FS_BIGFAT_OPEN_FLAG_CREATE);if(r ==0){FS_BIGFAT_GetPos(&BigFile,&FilePos);SEGGER_snprintf(ac,sizeof(ac),"File position before write: %llu\n",FilePos);FS_X_Log(ac);FS_BIGFAT_Write(&BigFile,"Test",4,NULL);FS_BIGFAT_GetPos(&BigFile,&FilePos);SEGGER_snprintf(ac,sizeof(ac),"File position after write: %llu\n",FilePos);FS_X_Log(ac);FS_BIGFAT_Close(&BigFile);}}
pBigFile has to point to a structure that was successfully
initialized via a call to FS_BIFILE_Open().
Example
#include<stdio.h>#include"FS.h"voidSampleBigFATGetSize(void){FS_BIGFAT_FILEBigFile;U64 FileSize;intr;charac[100];//// Opens a file for writing, writes some data to it and queries the file size.//r =FS_BIGFAT_Open(&BigFile,"Test.txt",FS_BIGFAT_OPEN_FLAG_WRITE |FS_BIGFAT_OPEN_FLAG_CREATE);if(r ==0){FS_BIGFAT_Write(&BigFile,"Test",4,NULL);FS_BIGFAT_GetSize(&BigFile,&FileSize);SEGGER_snprintf(ac,sizeof(ac),"File size: %llu\n",FileSize);FS_X_Log(ac);FS_BIGFAT_Close(&BigFile);}}
in Partially-qualified path to the file to be queried (0-terminated)
pTimeStamp
out Read timestamp value.
TimeType
Type of timestamp to return. It can take one of the following values: FS_FILETIME_CREATEFS_FILETIME_ACCESSFS_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.
Example
#include"FS.h"voidSampleBigFATGetTime(void){U32 TimeStamp;FS_FILETIMEFileTime;charac[100];intr;//// Gets the last modification time of a big file.//r =FS_BIGFAT_GetTime("Test.txt",&TimeStamp,FS_FILETIME_MODIFY);if(r ==0){FS_TimeStampToFileTime(TimeStamp,&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);}}
The value passed to SetMask and ClrMask is an bitwise-or
combination of File attributes. The FS_ATTR_DIRECTORY
attribute cannot be set or cleared. The function does not
report any error if the application attempts to do this.
Example
#include"FS.h"voidSampleBigFATModifyAttr(void){//// Clears the ARCHIVE attribute and sets the SYSTEM and HIDDEN attributes// of the file "Test.txt".//FS_BIGFAT_ModifyAttr("Test.txt",FS_ATTR_SYSTEM |FS_ATTR_HIDDEN,FS_ATTR_ARCHIVE);}
The source and destination paths can be located on different volumes.
A file can be renamed by calling FS_BIGFAT_Move() with sFileNameDest
set to the same parent directory in sFileNameDest with the new
file name added to it.
Example
#include"FS.h"voidSampleBigFATMove(void){//// Moves the contents of "Test.txt" to file "TestCopy.txt" in the folder "SubDir".//FS_BIGFAT_Move("Test.txt","SubDir\\TestCopy.txt");}
in Path to the file to be opened (0-terminated character string).
Flags
Specifies how the file has to be accessed.
Return value
= 0
OK, file opened.
≠ 0
Error code indicating the failure reason.
Additional information
The application has to call this function once for each file it
wants to access. FS_BIGFAT_Open() creates or opens the base
file according to Flags and initializes pBigFile. The application
has to allocate pBigFile and to make sure that it stays valid
until FS_BIGFAT_Close() is called. pBigFile identifies the
opened file within the application and is passed as parameter
to all the other API functions that access the file.
FS_BIGFAT_Open() makes a copy of sFileName that is then stored
in pBigFile. Therefore, the application can release the memory
allocated to sFileName after FS_BIGFAT_Open() returns.
Flags is a bitwise-or combination of File open flags.
Permitted combinations are:
Create a new file or append to an existing one for reading and writing
Example
The next example demonstrates how to open a file for reading.
#include"FS.h"voidSampleBigFATOpenRead(void){FS_BIGFAT_FILEBigFile;intr;//// Opens a file for reading on the root directory of the default volume.// The file has to exist before opening it.//r =FS_BIGFAT_Open(&BigFile,"Test.txt",FS_BIGFAT_OPEN_FLAG_READ);if(r ==0){//// Perform read accesses to file//FS_BIGFAT_Close(&BigFile);}}
This example demonstrates how to open a file for writing.
#include"FS.h"voidSampleBigFATOpenWrite(void){FS_BIGFAT_FILEBigFile;intr;//// Opens a file for writing on the root directory of the default volume.// The file has to exist before opening it.//r =FS_BIGFAT_Open(&BigFile,"Test.txt",FS_BIGFAT_OPEN_FLAG_WRITE);if(r ==0){//// Perform write accesses to file.//FS_BIGFAT_Close(&BigFile);}}
This example demonstrates how to open a file for reading and writing.
#include"FS.h"voidSampleBigFATOpenReadWrite(void){FS_BIGFAT_FILEBigFile;intr;//// Opens a file for reading and writing on the root directory of the "nand:0:" volume.// The file has to exist before opening it.//r =FS_BIGFAT_Open(&BigFile,"nand:0:\\Test.txt",FS_BIGFAT_OPEN_FLAG_READ |FS_BIGFAT_OPEN_FLAG_WRITE);if(r ==0){//// Perform read and write accesses to file//FS_BIGFAT_Close(&BigFile);}}
This example demonstrates how to create a file.
#include<stdio.h>#include"FS.h"voidSampleBigFATOpenWriteCreate(void){FS_BIGFAT_FILEBigFile;intr;//// Opens a file for writing on the folder "SubDir" of the default volume.// The directory delimiter is the '\' character. If the file does// not exist it is created. If the file exists it is truncated to 0.//r =FS_BIGFAT_Open(&BigFile,"\\SubDir\\Test.txt",FS_BIGFAT_OPEN_FLAG_WRITE |FS_BIGFAT_OPEN_FLAG_CREATE);if(r ==0){//// Perform write accesses to file.//FS_BIGFAT_Close(&BigFile);}}
The next example demonstrates how open a file for writing at the end of it.
#include"FS.h"voidSampleBigFATOpenAppend(void){FS_BIGFAT_FILEBigFile;intr;//// Opens a file for writing at the end on the root directory of the default volume.// The file has to exist before opening it.//r =FS_BIGFAT_Open(&BigFile,"Test.txt",FS_BIGFAT_OPEN_FLAG_WRITE |FS_BIGFAT_OPEN_FLAG_APPEND);if(r ==0){//// Perform write accesses to file.//FS_BIGFAT_Close(&BigFile);}}
File handle that identifies the opened big file. It cannot be set to NULL.
pData
out Data read from big file.
NumBytesToRead
Number of bytes requested to be read from the big file.
pNumBytesRead
out Number of bytes actually read from the big file. It can be set to NULL.
Return value
= 0
OK, data read from file.
≠ 0
Error code indicating the failure reason.
Additional information
The data is read from the current position in the file that is
stored in the file handle. The current file position is set to
first byte in the file (that is 0) when the file is opened.
The file position is advanced by the number of bytes actually
read from file.
If either pData is set to NULL or NumBytesToRead is set to 0
success is returned but no data is read. *pNumBytesRead is set
to 0 in this case.
pBigFile has to point to a structure that was successfully
initialized via a call to FS_BIFILE_Open().
Example
#include"FS.h"voidSampleBigFATRead(void){FS_BIGFAT_FILEBigFile;intr;U8 abData[4];//// Opens a file for reading on the root directory of the default volume.//r =FS_BIGFAT_Open(&BigFile,"Test.txt",FS_BIGFAT_OPEN_FLAG_READ);if(r ==0){//// Read some data from the beginning of the opened file//FS_BIGFAT_Read(&BigFile,abData,sizeof(abData),NULL);//// Close the file.//FS_BIGFAT_Close(&BigFile);}}
pBigFile has to point to a structure that was successfully
initialized via a call to FS_BIFILE_Open().
Example
#include"FS.h"voidSampleBigFATSetPos(void){FS_BIGFAT_FILEBigFile;U64 FilePos;intr;//// Opens a file for writing, writes some data to it and then overwrites it.//r =FS_BIGFAT_Open(&BigFile,"Test.txt",FS_BIGFAT_OPEN_FLAG_WRITE |FS_BIGFAT_OPEN_FLAG_CREATE);if(r ==0){FS_BIGFAT_Write(&BigFile,"Test",4,NULL);FS_BIGFAT_SetPos(&BigFile,0);FS_BIGFAT_Write(&BigFile,"Done",4,NULL);FS_BIGFAT_Close(&BigFile);}}
If the file is extended then the additional bytes contain uninitialized data.
In addition, the position in the file is not modified.
pBigFile has to point to a structure that was successfully
initialized via a call to FS_BIFILE_Open().
Example
#include"FS.h"voidSampleBigFATSetSize(void){FS_BIGFAT_FILEBigFile;intr;//// Opens a file for writing and sets it size to 100 Kbytes.//r =FS_BIGFAT_Open(&BigFile,"Test.txt",FS_BIGFAT_OPEN_FLAG_WRITE |FS_BIGFAT_OPEN_FLAG_CREATE);if(r ==0){FS_BIGFAT_SetSize(&BigFile,100*1024);FS_BIGFAT_Close(&BigFile);}}
This function is optional because the file system automatically
updates the timestamps of a big file as required.
Example
#include"FS.h"voidSampleBigFATSetTime(void){U32 TimeStamp;FS_FILETIMEFileTime;//// Modifies the creation time of a big file.//FileTime.Year =2022;FileTime.Month =12;FileTime.Day =22;FileTime.Hour =8;FileTime.Minute =2;FileTime.Second =48;FS_FileTimeToTimeStamp(&FileTime,&TimeStamp);FS_BIGFAT_SetTime("Test.txt",TimeStamp,FS_FILETIME_CREATE);}
pBigFile has to point to a structure that was successfully
initialized via a call to FS_BIFILE_Open().
Example
#include<stdio.h>#include"FS.h"voidSampleBigFATSync(void){FS_BIGFAT_FILEBigFile;intr;//// Opens a file for writing, writes some data to it while making sure that// the data is written to storage.//r =FS_BIGFAT_Open(&BigFile,"Test.txt",FS_BIGFAT_OPEN_FLAG_WRITE |FS_BIGFAT_OPEN_FLAG_CREATE);if(r ==0){FS_BIGFAT_Write(&BigFile,"Test1",5,NULL);FS_BIGFAT_Sync(&BigFile);FS_BIGFAT_Write(&BigFile,"Test2",5,NULL);FS_BIGFAT_Close(&BigFile);}}
Number of bytes requested to be written to the big file.
pNumBytesWritten
out Number of bytes actually written to the big file. Can be NULL.
Return value
= 0
OK, data written to file.
≠ 0
Error code indicating the failure reason.
Additional information
The data is written at the current position in the file that is
stored in the file handle. The current file position is set to
first byte in the file (that is 0) when the file is opened.
The file position is advanced by the number of bytes actually
written to file.
pBigFile has to point to a structure that was successfully
initialized via a call to FS_BIFILE_Open().
Example
#include"FS.h"voidSampleBigFATWrite(void){FS_BIGFAT_FILEBigFile;intr;//// Opens a file for writing on the root directory of the default volume.// The file has to exist before opening it.//r =FS_BIGFAT_Open(&BigFile,"Test.txt",FS_BIGFAT_OPEN_FLAG_WRITE);if(r ==0){//// Write some data to file.//FS_BIGFAT_Write(&BigFile,"Test",4,NULL);FS_BIGFAT_Close(&BigFile);}}
The Attributes member is a bitwise-or combination of the following
flags: FS_ATTR_READ_ONLY, FS_ATTR_HIDDEN, FS_ATTR_SYSTEM,
FS_ATTR_ARCHIVE, or FS_ATTR_DIRECTORY.
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_BIGFAT_FIND_DATA is used as context
by the FS_BIGFAT_FindFirst() and FS_BIGFAT_FindNext() pair of functions.
The file is created if it does not exists or it is truncated to 0 if it exists.
FS_BIGFAT_OPEN_FLAG_APPEND
The application can write only at the end of the file.
Additional information
These flags can be used as values for the Flags parameter
of FS_BIGFAT_Open(). The flags are bitmasks
that can be combined by a bitwise-or operator.
BigFAT converter utility
emFile comes with a convenient command line utility for PC that
helps to convert between a regular host file and one or more fragment files
that can be managed by a target application using the BigFAT component.
The command line utility is able to merge the fragment files generated
on a target device into a single file larger than 4 Gbytes. In addition,
the command line utility is also able to split a file larger than 4 Gbytes
into fragment files that can later be copied to a target device in order
to be accessed by a target application.
Using the utility
The utility can be invoked directly from the command line or via a batch file.
A terminal window must be opened first in order to use the utility interactively.
First, the name of the executable (BigFAT.exe) has to be input on the
command line followed by optional and required arguments. By pressing the Enter
key the utility starts the merge or split operation as specified.
Below is a screen shot of the BigFAT.exe utility that is invoked to
merge the contents of the file TestFile1.bin created on the target device.
The merged data replaces the contents of the original file. In case of an error a
message is displayed indicating the failure reason and the utility returns with a
status of 1. The original target file is left unmodified in this case.
Assuming the original TestFile1.bin file is 6 Gbytes large then at the end of
execution it is truncated to 4 Gbytes - 128 Kbytes. The remaining number of bytes
is stored to a file named TestFile1.bin.001.BigFAT
Command line options
The following table lists the parameters which can be omitted when invoking
the utilities.
C:>BigFAT.exe -h
BigFAT V5.18.0 compiled Jul 22 2022 15:32:43
(c) 2010-2020 SEGGER Microcontroller GmbH www.segger.com
Press '?' for help
DESCRIPTION
BigFAT merge/split utility for SEGGER emFile.
USAGE
BigFAT [-d <DestFile>] [-h] [-q] [-s] [-v] <SrcFile>
OPTIONS
-d <DestFile> Path to merged/split file to be created.
Default is the name of the source file.
-h Show this help information.
-q Do not show log messages.
-s Split a big file. Default is merging.
-v Show version information.
ARGUMENTS
<SrcFile> Path to file to be merged/split.
-q
Description
Suppresses log information. By default all the log messages are shown in the terminal window.
Syntax
-q
-s
Description
Performs a split operation. By default a merge operation is performed.
Syntax
-s
Example
The following example demonstrates how to split the contents of the file
TestFile1.bin. The original file is overwritten. The created
fragment files can be copied to the target device.
C:>BigFAT.exe -s TestFile1.bin
-v
Description
Shows version information and exits.
Syntax
-v
Example
C:>BigFAT.exe -v
BigFAT V5.18.0 compiled Jul 22 2022 15:32:43
(c) 2010-2020 SEGGER Microcontroller GmbH www.segger.com
Press '?' for help
Command line arguments
The following table lists the mandatory parameters.
In case of a merge operation SrcFile specifies the name of the first fragment file
of a file created via the BigFAT component on a target storage device. If a split operation is
executed then SrcFile specifies the name of the host file to be converted.
Example
The following example demonstrates how to merge the contents of the file
TestFile1.bin generated on a target device via the BigFAT component.
C:>BigFAT.exe TestFile3.bin
NAND Image Creator
This chapter provides information about the emFile utility that
can be used to create file system images for NAND flash devices.
General information
The NAND Image Creator is a command line utility that can be used to create
a file containing a one-to-one representation of the contents of a NAND flash device
(image file) with preselected files and directories found on the host PC.
The NAND Image Creator provides commands for performing standard file system
operations such as formatting the storage device low as well as high level,
copying files and directories from the host PC to the image file or checking
the consistency of the file system structure.
The generated image file is a regular binary file that can be programmed directly
into the NAND flash device of the target system via a SEGGER production programmer
(https://www.segger.com/products/flash-in-circuit-programmers/)
or via any other third-party utility.
The NAND Image Creator ships with executables for Windows, Linux and macOS systems
that can be used to create images for the FAT and EFS file systems.
Using the NAND Image Creator
The NAND Image Creator utility can be used like any other command line based
program. For the ease of usage many commands are kept similar to their DOS
counterparts. By entering “?” or just pressing the Enter key an overview of the commands
is printed on the screen and it should look like the picture below.
The NAND Image Creator utility can work in two modes: interactive and script.
The interactive mode is entered when the utility is started with no command line
arguments. In this mode the user is prompted to type in the commands to be executed.
The script mode is entered when the utility is started with a command line argument
that specifies the name of a file containing the commands to be executed, one command per line.
Sample script file
The following sample shows a simple script file which does the following:
Creates a 128 Mbyte NAND flash image file C:\flash.bin
Sets the type of NAND driver which will be used on the target to access the NAND
flash device to Universal NAND driver. This command is optional since the default
driver type.
Creates the image file.
Low-level formats the volume on the image file.
High-level formats the volume on the image file.
Copies the Test.txt file from drive C: of the host Windows PC
to root directory of the volume stored on the image file.
Copies recursively the contents of Data directory from host PC to
Data directory of the volume stored on the image file.
createimage C:\flash.bin 1024 64 2048
setdrivertype uni
init
formatlow
format
addfile C:\Test.txt
addfolder C:\Data\
q
Supported commands
The image file can be processed by using build it commands of the NAND Image Creator
utility. The table below lists all the available commands followed by a detailed
description. The optional command parameters are enclosed in square brackets
in the syntax description of a command.
Number of bytes in a NAND page excluding the spare area.
SpareAreaSize
Number of bytes in the sparea are of a NAND page.
Additional information
This command is mandatory and it must be the first command to be executed.
The size of the image file is NumBlocks * PagesPerBlock *
(PageSize + SpareAreaSize) bytes large. The image file is silently
overwritten if the image file already exists but the calculated size of the file
does not match. If SpareAreaSize is not specified then the utility calculates
it as 1/32 of PageSize.
PageSize has to be a power of 2 value. The values for PagesPerBlock,
PageSize and SpareAreaSize have to match the values of the NAND flash
device the file image will be stored to otherwise the the application will not
be able to access the data via emFile. NumBlocks has to match either
the maximum number of blocks in the NAND flash device or the number of blocks
specified as the second parameter in the call to FS_NAND_SetBlockRange()
or FS_NAND_UNI_SetBlockRange().
Example
The example shows how to create 128 Mbytes image file.
This command is optional. If not executed an image file is created that can be
accessed on the target using the Universal NAND driver.
Example
The examples shows how to specify that the SLC1 NAND driver is used on the target
to access the NAND flash.
setdrivertype slc1
setsectorsize
Description
Configures the logical sector size.
Syntax
setsectorsize <SectorSize>
Parameters
Parameter
Description
SectorSize
The size of the logical sector in bytes.
Additional information
This command is optional. It can be used to set the size of the logical sector
when the SLC1 NAND driver type is selected. Any power of 2 value between 512
bytes and the number of bytes in a NAND page can be used. When this command
is not executed the size of the logical sector is set automatically to the
configured page size of NAND flash device. The size of the logical sector
as to be smaller than or equal to the size of the logical sector configured
on the target application via FS_SetMaxSectorSize().
Example
This example shows how to set the logical sector size to 512 bytes.
setsectorsize 512
addpartition
Description
Configures a logical partition.
Syntax
addpartition <StartSector> <NumSectors> [<PartType>]
ap <StartSector> <NumSectors> [<PartType>]
Parameters
Parameter
Description
StartSector
Index of the first sector in the partition.
NumSectors
Number of sectors in the partition.
PartType
Type of the partition to create. Permitted values are:
normal - The entire partition space is used by the file system as storage (default).
raid1 - The file system can use only half of the partition space as storage. The other half is used as mirror partition.
Additional information
This command is optional. It allows the creation of logical partitions on the image file.
The command fails if the defined sector range overlaps the range of an already
defined logical partition. A maximum of four logical partitions can be created.
The partition list has to be stored to image after initialization of the image using
the creatembr command. The data on the
created logical partitions can be accessed using the Disk Partition driver.
The logical partitions can be formatted using the format
command. The value of StartSector is relative to the beginning of the storage device.
Example
This example shows how to configure 2 logical partitions. The sector 0 is reserved
for Master Boot Record where the partition list is stored.
addpartition 1 10000
addpartition 10001 20000
A possible emFile configuration that allows the application to access
the logical partitions looks like this:
#include<FS.h>#include"FS_NAND_HW_Template.h"#defineALLOC_SIZE 0x9000// Memory pool for the file system in bytesstaticU32 _aMemBlock[ALLOC_SIZE /4];// Memory pool used for semi-dynamic allocation.voidFS_X_AddDevices(void){FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));FS_SetMaxSectorSize(2048);//// Add and configure the NAND partition. Volume name: "nand:0:"//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_Template);//// Add and configure the first logical volume. Volume name: "diskpart:0"//FS_AddDevice(&FS_DISKPART_Driver);FS_DISKPART_Configure(0,&FS_NAND_UNI_Driver,0,0);//// Add and configure the second logical volume. Volume name: "diskpart:1"//FS_AddDevice(&FS_DISKPART_Driver);FS_DISKPART_Configure(1,&FS_NAND_UNI_Driver,0,1);}
setecclevel
Description
Configures the error correction type.
Syntax
setecclevel <NumBitErrors>
sel <NumBitErrors>
Parameters
Parameter
Description
NumBitErrors
Number of bit errors the ECC stored to spare area must
be able to correct. Permitted values are:
0 - hardware ECC.
1 - 1-bit software ECC.
Additional information
This command is optional. If not executed a 1-bit software calculated ECC is
stored to spare area. If NumBitErrors is set to 0 then the bytes in
the spare area reserved for the ECC are set to 0xFF.
Example
This example shows how to set the correction level to hardware ECC.
setecclevel 0
setnumworkblocks
Description
Configures the number of work blocks.
Syntax
setnumworkblocks <NumBlocks>
snwb <NumBlocks>
Parameters
Parameter
Description
NumBlocks
Number of NAND blocks reserved for work blocks.
Additional information
This command is optional. If this command is not executed the number of work
blocks is set to 3. The number of work blocks specified via this command has
to match the number of work blocks configured by the target application via
FS_NAND_SetNumWorkBlocks() or FS_NAND_UNI_SetNumWorkBlocks().
Example
This example shows how to set the number of work blocks to 8.
setnumworkblocks 8
showimageinfo
Description
Shows information about the image file.
Syntax
showimageinfo
si
Example
showimageinfo
Name: nand.bin
Driver type: Universal
Num blocks: 1024
Pages per block: 64
Page size: 2048 bytes
Spare area size: 64 bytes
Bytes per sector: 2048 bytes
init
Description
Initializes the image file.
Syntax
init
Additional information
This command must be executed before any other command which operates on files
and directories.
Example
init
exportimage
Description
Saves to a file the NAND blocks that contain valid data.
Syntax
exportimage <FilePathOnHost>
ei <FilePathOnHost>
Parameters
Parameter
Description
FilePathOnHost
Path to destination file on host PC.
Additional information
This command is optional. It can be used to create an image file that
contains only NAND blocks with valid data. The NAND blocks that contain invalid
data or are empty are discarded. The created file can be used to program the NAND
flash device. The programming utility has to make sure that the NAND blocks
that are not programmed are blank that is all the bytes in these blocks are set
to 0xFF. Typically, the created file is smaller than the original image file
which helps reduce the programming time.
Example
exportimage C:\NAND.bin
File and directory related commands
The following sections describe the commands that can be used to operate on
the files and directories stored on the image file. The commands described
in this section can be executed only after the execution of the
init command.
cd
Description
Changes the current working directory.
Syntax
chdir <DirPathOnImage>
cd <DirPathOnImage>
Parameters
Parameter
Description
DirPathOnImage
Path to new directory to change to.
Additional information
If DirPathOnImage is set to .. the command changes to the parent directory.
After initialization the current directory is set to the root directory.
Example
In the following sample the working directory is changed to Test and then
back to the original directory.
cd Test
cd ..
md
Description
Creates a directory.
Syntax
mkdir <DirPathOnImage>
md <DirPathOnImage>
Parameters
Parameter
Description
DirPathOnImage
Path to directory to be created.
Additional information
This command is able to create any missing directories in the path.
The following example copies the contents of the Test.txt
to the Test2.txt file.
copy Test.txt Test2.txt
exportfile
Description
Copies a file from image file to host PC.
Syntax
exportfile <FilePathOnImage> <FilePathOnHost>
ef <FilePathOnImage> <FilePathOnHost>
Parameters
Parameter
Description
FilePathOnImage
Path to the source file on image.
FilePathOnHost
Path to the destination file on PC.
Example
The following command copies the contents of the Test.txt file from image
to Dest.txt file on host PC.
exportfile Test.txt C:\Dest.txt
exportfolder
Description
Copies a directory recursively from image to host PC.
Syntax
exportfolder <DirPathOnImage> <DirPathOnHost>
Parameters
Parameter
Description
DirPathOnImage
Path to the source directory on image.
DirPathOnHost
Path to the destination directory on PC.
Example
The following command copies the contents of the entire current volume from image
to Exported\RootDir directory on host PC.
exportfolder \ Exported\RootDir
Logical sector related commands
The following sections describe commands that can be used to operate on logical sectors.
storesectors
Description
Copies logical sector data from a file on the PC host to image file.
Syntax
storesectors <FilePathOnImage> [<StartSector>]
Parameters
Parameter
Description
FilePathOnImage
Path to the file on host that contains sector data.
StartSector
Index of the first logical sector to be written.
Additional information
This command is optional. The sector data must be stored sequentially in the file.
For example if the sector size is 2048 bytes and the data is stored starting from
sector index 100 then the byte at offset 0 in the file stores the first byte of
sector 100, the byte at offset 2048 in the file stores the first byte of sector
101 and so on. The size of the file has to be a multiple of sector size.
The size of the sector is the size specified as the argument to
setsectorsize command.
Example
This example reads sector data from the file SectorData.bin and writes
it starting from sector index 100.
storesectors SectorData.bin 100
dumpsector
Description
Shows the contents of a logical sector.
Syntax
dumpsector <SectorIndex>
ds <SectorIndex>
Parameters
Parameter
Description
SectorIndex
Index of the logical sector to be displayed.
Example
The following command shows the contents of the logical sector 0.
This command operates only on the nand:0: volume. The command reports
and error if the source and destination sector ranges overlap.
Example
This example copies 10000 logical sectors from sector index 0 to sector index 20000.
copysectors 0 20000 10000
Volume specific commands
The following sections describe commands that operate on the file system volumes
located on the image file.
formatlow
Description
Low-level formats a volume.
Syntax
formatlow [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume that has to be formatted.
Additional information
If VolumeName is not specified then the command formats
the current volume. The current volume can be selected via the
cd command.
Every NAND volume has to be low-level formatted once when the image file
is newly created.
Example
This example demonstrates how to format the volume nand:1:
formatlow nand:1:
Low-level format...OK
format
Description
High-level formats a volume.
Syntax
format [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume that has to be formatted.
Additional information
If VolumeName is not specified then the command formats
the current first volume. The current volume can be selected via the
cd command.
Every NAND volume has to be high-level formatted once when the image file
is newly created.
Example
This example demonstrates how to format the volume nand:0:
format
High-level format...OK
df
Description
Shows the available free space on a volume.
Syntax
diskfree [<VolumeName>]
df [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be queried.
Additional information
If VolumeName is not specified than the command calculates the free
space of the current volume. The current volume can be selected via the
cd command.
Example
This example demonstrates how to get the frees space on the first volume.
df
Available free space is 127647744 bytes
diskinfo
Description
Shows information about a storage device.
Syntax
diskinfo [<VolumeName>]
di [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be queried.
Additional information
If VolumeName is not specified then the command returns information
about the current volume. The current volume can be selected via the
cd command.
Example
This example demonstrates how to get information about the volume nand:1:.
diskinfo nand:1:
127647744 bytes total disk space
17719296 bytes available free space
8192 bytes per cluster
15582 cluster available on volume
2163 free cluster available on volume
getdevinfo
Description
Shows information about a volume.
Syntax
getdevinfo [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be queried.
Additional information
If VolumeName is not specified then the command returns information
about the first volume. The current volume can be selected via the
cd command.
Example
This example demonstrates how to get information about the storage device
used by the first volume.
getdevinfo
62370 available sectors
2048 bytes per sector
checkdisk
Description
Checks a volume for errors.
Syntax
checkdisk [<VolumeName>]
chkdsk [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be checked.
Additional information
If VolumeName is not specified then the command checks the current volume
for errors. The current volume can be selected via the
cd command.
Example
This example demonstrates how to check the file system structure of the first volume.
checkdisk
creatembr
Description
Writes partition table to master boot record (MBR).
Syntax
creatembr [<VolumeName>]
cm [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be written.
Additional information
If VolumeName is not specified then the command writes the MBR
to the current volume. The current volume can be selected via the
cd command.
This command stores the partition table configured via
addpartition
command to the MBR of the specified volume. The command has to be executed after
the low-level format and before any high-level format operation. Typically,
the partition table is located on nand:0: volume.
Example
This example stores the MBR to the sector 0 of the nand:0: volume.
creatembr nand:0:
listvolumes
Description
Shows the names of all available volumes.
Syntax
listvolumes
lv
Example
Shows the names of the volumes of in a configuration using five volumes.
listvolumes
Available volumes:
nand:0:
diskpart:0:
diskpart:1:
diskpart:2:
diskpart:3:
NOR Image Creator
This chapter provides information about the emFile utility that
can be used to create file system images for NOR flash devices.
General information
The NOR Image Creator is a command line utility that can be used to create
a file containing a one-to-one representation of the contents of a NOR flash device
(image file) with preselected files and directories found on the host PC.
The NOR Image Creator provides commands for performing standard file system
operations such as formatting the storage device low as well as high level,
copying files and directories from the host PC to the image file or checking
the consistency of the file system structure.
The generated image file is a regular binary file that can be programmed directly
into the NOR flash device of the target system via a SEGGER production programmer
(https://www.segger.com/products/flash-in-circuit-programmers/)
or any other third-party utility.
The NOR Image Creator ships with executables for Windows, Linux and macOS systems
that can be used to create images for the FAT and EFS file systems.
Using the NOR Image Creator
The NOR Image Creator utility can be used like any other command line based
program. For the ease of usage many commands are kept similar to their DOS
counterparts. By entering “?” or just pressing the Enter key an overview of
the commands is printed on the screen and it should look like the picture below.
The NOR Image Creator utility can work in two modes: interactive and script.
The interactive mode is entered when the utility is started with no command line
arguments. In this mode the user is prompted to type in the commands to be executed.
The script mode is entered when the utility is started with a command line argument
that specifies the name of a file containing the commands to be executed, one command per line.
Sample script file
he following sample shows a simple script file which does the following thing:
Creates a NOR flash image file C:\flash.bin
Adds a sector block of 4 Mbytes (64 x 64 kByte) to the image file.
Creates the image file.
Low-level formats the volume on the image file.
High-level formats the volume on the image file.
Copies the Test.txt file from drive C: of the host Windows PC
to root directory of the volume stored on the image file.
Copies recursively the contents of Data directory from host PC to
Data directory of the volume stored on the image file.
The image file can be processed by using build it commands of the NOR Image Creator
utility. The table below lists all the available commands followed by a detailed
description. The optional command parameters are enclosed in square brackets
in the syntax description of a command. If not otherwise stated all the
numeric parameters have to be specified as decimal format.
This command is mandatory and has to be executed at least once.
addsectorblock can be used
to describe the geometry of the physical NOR flash device used on the target.
It specifies the characteristics of a continuous block of NOR physical sectors.
The command can be executed more that once with different parameters.
SectorSize has to be specified in bytes as a hexadecimal number
without any prefix or suffix. For example a NOR physical sector of 64 Kbytes
can be specified as 10000.
ImageNo specifies the index of the image file. The first image file
created via createimage has the
index 0, the second image the index 1 and so on.
Example
The following example shows how to configure the image for a NOR flash device
that has 32 physical sectors of 64 Kbytes and 8 physical sectors of 4 Kbytes.
addsectorblock 0,32,10000
addsectorblock 0,8,1000
setsectorsize
Description
Configures the logical sector size.
Syntax
setsectorsize <SectorSize>
Parameters
Parameter
Description
SectorSize
The size of the logical sector in bytes.
Additional information
This command is optional. It can be used to set the size of the logical sector
used by the file system. By default the file system uses a logical sector size
of 512 bytes. The size of the logical sector as to be smaller than or equal to
the size of the logical sector configured on the target application via
FS_SetMaxSectorSize().
SectorSize has to be a power of 2 value.
Example
This example shows how to set the logical sector size to 512 bytes.
setsectorsize 2038
setlinesize
Description
Specifies the minimum number of bytes that can be programmed at once.
Syntax
setlinesize <LineSize>
Parameters
Parameter
Description
LineSize
Minimum number of bytes that can be programmed at once.
Additional information
This command is optional. By default, the minimum number of bytes that the
NOR driver programs is 4. LineSize has to be a power of 2 value.
Example
This example shows how to set the line size to 16 bytes.
setlinesize 16
setrewritesupport
Description
Configures if the NOR driver is allowed to perform rewrite operations.
Syntax
setrewritesupport <OnOff>
Parameters
Parameter
Description
OnOff
Indicates if the feature is activated or not.
1 - NOR driver is permitted to rewrite data (default).
0 - NOR driver is not permitted to rewrite data.
Additional information
This command is optional. By default, the NOR driver is permitted to modify
the same byte of the NOR flash device memory as long as bits are changed
from 0 to 1 without an erase operation in between. The majority of NOR flash
devices support this feature but some are not. For this type of NOR flash
devices this command has to be called with OnOff set to 0.
Example
This example shows how to specify that the NOR flash can rewrite data.
setrewritesupport 1
setbyteorder
Description
Specifies the byte order of the management data.
Syntax
setbyteorder <FormatType>
Parameters
Parameter
Description
FormatType
Specifies the byte ordering.
le - little endian format.
be - big endian format.
Additional information
This command is optional. By default, the NOR driver stores multi-byte management
data in the byte order of the host CPU which is typically little-endian.
The byte order of the management data has to match the byte order of the target CPU.
setbyteorder can be used to explicitly
configure the byte order.
Example
This example shows how to configure the byte order to big-endian.
setbyteorder be
settimesource
Description
Specifies how the timestamps of added files are generated.
Syntax
settimesource <TimeSource>
Parameters
Parameter
Description
TimeSource
Specifies the time source to be used.
sys - time of host PC (default).
none - constant value.
Additional information
This command is optional. By default, the NOR Image Creator uses the current
time and date of the host PC to generate the timestamps of the files and
directories. In some cases it is desirable to have the same constant time
stamp for all the files and directories stored on the image file so that
for example the generated image file can be compared correctness against
a reference image file.
Example
This example shows how to configure the NOR Image Creator to use a constant
time stamp for all the files and directories it creates on the image file.
settimesource none
setcrcsupport
Description
Specifies if the data has to be protected by CRC.
Syntax
setcrcsupport <OnOff>
Parameters
Parameter
Description
OnOff
Indicates if the feature is activated or not.
1 - Data is protected by CRC.
0 - Data is not protected by CRC (default).
Additional information
This command is optional. By default, the management and user data stored by
the NOR driver is not protected by CRC.
Example
This example shows how to configure the NOR Image Creator to protect the data via CRC.
setcrcsupport 1
setnumworkblocks
Description
Configures the number of work blocks.
Syntax
setnumworkblocks <NumWorkBlocks>
Parameters
Parameter
Description
NumWorkBlocks
Number of work blocks.
Additional information
This command is optional and applies only to Block Map NOR driver.
By default, the Block Map NOR driver calculates the number of work
blocks automatically based on the number of physical sectors available
as storage. The setnumworkblocks command can be used to overwrite
the calculated value. NumWorkBlocks has to be set to a value greater than 0.
Example
This example shows how to set the number of work blocks to 8.
setnumworkblocks 8
showimageinfo
Description
Shows information about the image file.
Syntax
showimageinfo <ImageNo>
Parameters
Parameter
Description
ImageNo
Index of the image file.
Example
showimageinfo
Information about image 0:
Name: NORImageCreator_NOR.img
ImageSize: 8388608 bytes
NumSectorBlocks: 1
Block 0: 128 sectors of 0x00010000 bytes
init
Description
Initializes the image file.
Syntax
init
Additional information
This command must be executed before any other command which operates on files
and directories.
Example
init
exportimage
Description
Saves to a file the NOR physical sectors that contain valid data.
Syntax
exportimage <FilePathOnHost>
ei <FilePathOnHost>
Parameters
Parameter
Description
FilePathOnHost
Path to destination file on host PC.
Additional information
This command is optional. It can be used to create an image file that
contains only NOR physical sectors with valid data. The NOR physical sectors
that contain invalid data or are empty are discarded. The created file can be used
to program the NOR flash device. The programming utility has to make sure that the
NOR physical sectors that are not programmed are blank that is all the bytes in these
physical sectors are set to 0xFF. Typically, the created file is smaller than the original
image file which helps reduce the programming time.
Example
exportimage C:\NOR.bin
File and directory related commands
The following sections describe the commands that can be used to operate on
the files and directories stored on the image file. The commands described
in this section can be executed only after the execution of the
init command.
cd
Description
Changes the current working directory.
Syntax
cd <DirPathOnImage>
Parameters
Parameter
Description
DirPathOnImage
Path to new directory to change to.
Additional information
If DirPathOnImage is set to .. the command changes to the parent directory.
After initialization the current directory is set to the root directory.
Example
In the following sample the working directory is changed to Test and then
back to the original directory.
cd Test
cd ..
md
Description
Creates a directory.
Syntax
md <DirPathOnImage>
Parameters
Parameter
Description
DirPathOnImage
Path to directory to be created.
Additional information
This command is able to create any missing directories in the path.
Example
md Test\Dir\
rd
Description
Removes a directory.
Syntax
rd <DirPathOnImage>
Parameters
Parameter
Description
DirPathOnImage
Path to directory to be deleted.
Additional information
The directory to be deleted must be empty.
Example
rd Test
addfile
Description
Copies a file from the host PC to the image file.
Syntax
addfile <FilePathOnHost> [<FilePathOnImage>]
Parameters
Parameter
Description
FilePathOnHost
Path to the source file on host PC.
FilePathOnImage
Path to destination file on the image.
Additional information
If FilePathOnImage is not specified then the name of the source file is used.
Example
The following command copies the contents of the Test.txt file from host
PC to Dest.txt file on image.
addfile C:\Test.txt Dest.txt
The following command copies the contents of Test.txt file to the file
with the same name of the image.
addfile C:\Test.txt
addfolder
Description
Copies a folder including its subfolders and files from the host PC to the image file.
Syntax
addfolder <DirPathOnHost> [<DirPathOnImage>]
Parameters
Parameter
Description
DirPathOnHost
Path to source directory on the host PC.
DirPathOnImage
Path to destination directory on the image.
Additional information
If DirPathOnImage is not specified then the name of the source directory is used.
Example
The following command copies the contents of the Data directory on PC to
Dest directory on the image.
addfolder C:\Data Dest
The following command copies the contents of the Data directory on PC to
a directory with the same name on the image.
addfolder C:\Data
type
Description
Shows the contents of a file.
Syntax
type <FilePathOnImage>
Parameters
Parameter
Description
FilePathOnImage
Path to the file on image to be shown.
Example
The following command line shows the contents of the file Test.txt
located on the root directory of the image.
type Test.txt
del
Description
Deletes a file.
Syntax
del <FilePathOnImage>
Parameters
Parameter
Description
FilePathOnImage
Path to the file on image to be deleted.
Example
The following command line deletes the file Test.txt located on the root
directory of the image.
del Test.txt
dir
Description
Lists the contents of the directory.
Syntax
dir [<DirPathOnImage>]
Parameters
Parameter
Description
DirPathOnImage
Path to directory on image to be listed.
Additional information
If DirPathOnImage is not specified then the command lists the contents
of the current working directory.
Example
The following command line shows the contents of the current directory.
If DirPathOnImage is not specified then the command lists the contents
of the current working directory.
Example
The following command line changes the name of Test.txt file located in
the Test directory to Test2.txt.
ren Test\Test.txt Test2.txt
move
Description
Moves a file or directory to another location.
Syntax
move <SrcFilePathOnImage> <DestFilePathOnImage>
Parameters
Parameter
Description
SrcFilePathOnImage
Path to file or directory to be moved.
DestFilePathOnImage
Path to destination file or directory on the image.
Example
The following command line moves the Test.txt file located in
the Test directory to the root directory. The file is renamed to New.txt.
move Test\Test.txt New.txt
attrib
Description
Shows/changes the file/directory attributes.
Syntax
attrib <PathOnImage> [<Operation> <Attributes>]
Parameters
Parameter
Description
PathOnImage
Path to file or directory.
Operation
Operation to be executed on attributes. Permitted values are:
+ sets the attributes.
- clears the attributes.
Attributes
The list of attributes to be changed The following attributes are supported:
a archive.
h hidden.
r read-only.
s system.
Example
The following example the clears the archive and read-only attributes
of the Test.txt file.
attr Test.txt -ar
copy
Description
Copies a file to another location.
Syntax
copy <SrcFilePathOnImage> <DestFilePathOnImage>
Parameters
Parameter
Description
SrcFilePathOnImage
Path to the file to be copied.
DestFilePathOnImage
Path to destination the file.
Example
The following example copies the contents of the Test.txt
to the Test2.txt file.
copy Test.txt Test2.txt
exportfile
Description
Copies a file from image file to host PC.
Syntax
exportfile <FilePathOnImage> <FilePathOnHost>
Parameters
Parameter
Description
FilePathOnImage
Path to the source file on image.
FilePathOnHost
Path to the destination file on PC.
Example
The following command copies the contents of the Test.txt file from image
to Dest.txt file on host PC.
exportfile Test.txt C:\Dest.txt
exportfolder
Description
Copies a folder including its subfolders and files from image file to host PC.
Syntax
exportfolder <DirPathOnImage> <DirPathOnHost>
Parameters
Parameter
Description
DirPathOnImage
Path to the source directory on image.
DirPathOnHost
Path to the destination directory on PC.
Additional information
The command copies the contents of a folder including all the folders and the
files that are stored in it. An identical copy of the specified directory
on the image file is created on the specified folder of the host PC.
Example
The following command copies the contents of the Data directory on the
image file to C:\Dest directory on the host PC.
addfolder Data C:\Dest
Volume specific commands
The following sections describe commands that operate on the file system volumes
located on the image file.
formatlow
Description
Low-level formats a volume.
Syntax
formatlow [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume that has to be formatted.
Additional information
If VolumeName is not specified then the command formats
the current volume. The current volume can be selected via the
cd command.
Every NOR volume has to be low-level formatted once when the image file
is newly created.
Example
This example demonstrates how to format the volume nor:1:
formatlow nor:1:
Low-level format...OK
format
Description
High-level formats a volume.
Syntax
format [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume that has to be formatted.
Additional information
If VolumeName is not specified then the command formats
the current first volume. The current volume can be selected via the
cd command.
Every NOR volume has to be high-level formatted once when the image file
is newly created.
Example
This example demonstrates how to format the volume nor:0:
format
High-level format...OK
df
Description
Shows the available free space on a volume.
Syntax
df [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be queried.
Additional information
If VolumeName is not specified than the command calculates the free
space of the current volume. The current volume can be selected via the
cd command.
Example
This example demonstrates how to get the frees space on the first volume.
df
Available free space is 127647744 bytes
diskinfo
Description
Shows information about a storage device.
Syntax
diskinfo [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be queried.
Additional information
If VolumeName is not specified then the command returns information
about the current volume. The current volume can be selected via the
cd command.
Example
This example demonstrates how to get information about the volume nor:1:.
diskinfo nor:1:
7333888 bytes total disk space
7333888 bytes available free space
1024 bytes per cluster
7162 cluster available on volume
7162 free cluster available on volume
getdevinfo
Description
Shows information about a volume.
Syntax
getdevinfo [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be queried.
Additional information
If VolumeName is not specified then the command returns information
about the first volume. The current volume can be selected via the
cd command.
Example
This example demonstrates how to get information about the storage device
used by the first volume.
getdevinfo
14399 Available sectors
512 bytes per sector
0 sectors per track
0 number of heads
checkdisk
Description
Checks a volume for errors.
Syntax
checkdisk [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be checked.
Additional information
If VolumeName is not specified then the command checks the current volume
for errors. The current volume can be selected via the
cd command.
Example
This example demonstrates how to check the file system structure of the first volume.
checkdisk
listvol
Description
Shows the names of all available volumes.
Syntax
listvol
Example
Shows the names of the volumes of in a configuration using five volumes.
listvol
Available volumes:
nor:0:
clean
Description
Runs a clean operation on a volume.
Syntax
clean [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be cleaned.
Additional information
If VolumeName is not specified then the command cleans the current volume
The current volume can be selected via the cd command.
Example
This example demonstrates how to clean the volume nor:1:.
If VolumeName is not specified then the command crates the journal on
the current volume. The current volume can be selected via the
cd command. If PathToFile is not
specified then the journal file is created on the root directory of the
specified volume. JournalSize has to be specified in bytes.
The value of SupportFreeSector is passed as third argument
to FS_JOURNAL_CreateEx(). If not specified SupportFreeSector is set to 0.
The parameters passed to the createjournal
command have to match the parameters passed to FS_JOURNAL_CreateEx() on the target application.
Example
This example demonstrates how to create a journal file of 128 Kbytes on the
current volume.
This chapter provides information about the emFile utilities that can
be used to a create file system image for an SD card, an eMMC device or a USB drive.
These utilities are also referred to as FAT Image Creator and EFS Image Creator.
General information
The Storage Image Creator is a command line utility that can be used to create
a file containing a one-to-one representation of the contents of a managed storage
device such as SD card, eMMC device or USB drive, with preselected files
and directories found on the host PC.
The Storage Image Creator provides commands for performing standard file system
operations such as formatting the storage device, copying files and directories
from the host PC to the image file or checking the consistency of the file system
structure.
The generated image file is a regular binary file that stores the contents of
all the logical sectors of the storage device. This file has to be stored via
an image writer utility to the target storage device.
The Storage Image Creator ships with executables for Windows, Linux and macOS systems
that can be used to create images for the FAT and EFS file systems. The utilities use
the same syntax regardless of the file and operating system. A separate set of excutables
is provided for each file system.
The Storage Image Creator utility for FAT (FAT Image Creator) ships with the following
executables:
OS
Executable
Location in shipment
Windows
StorageImageCreator.exe
Windows/FS
Linux
StorageImageCreator
Linux/FS
macOS
StorageImageCreator
macOS/FS
The Storage Image Creator utility for EFS (EFS Image Creator) ships with the following
executables:
OS
Executable
Location in shipment
Windows
StorageImageCreatorEFS.exe
Windows/FS
Linux
StorageImageCreatorEFS
Linux/FS
macOS
StorageImageCreatorEFS
macOS/FS
Using the Storage Image Creator
The Storage Image Creator utility can be used like any other command line based
program. For the ease of usage many commands are kept similar to their MS DOS
counterparts. By entering “?” or just pressing the Enter key an overview of the commands
is printed on the screen and it should look like the picture below.
The Storage Image Creator utility can work in two modes: interactive and script.
The interactive mode is entered when the utility is started with no command line
arguments. In this mode the user is prompted to type in the commands to be executed.
The script mode is entered when the utility is started with a command line argument
that specifies the name of a file containing the commands to be executed, one command per line.
Example script file
This is an example script file that performs the following operations:
Creates a 2 GB image file located at C:\Temp\SDCard.bin
Initializes the image file.
High-level formats the volume on the image file.
Copies the Test.txt file from C:\Temp folder of the host
Windows PC to root directory of the volume stored contained in the image file.
Copies recursively the contents of C:\Temp\Data directory from
host PC to Data directory located in the root directory of the volume
contained in the image file.
createimage C:\Temp\SDCard.bin 4194304
init
format
addfile C:\Temp\Test.txt
addfolder C:\Temp\Data
q
The image file can be processed by using the commands of the Storage Image Creator
utility. The table below lists all the available commands followed by a detailed
description. The optional command parameters are enclosed in square brackets
in the syntax description of a command.
The following sections describe the commands required to create an image file.
createimage
Description
Creates/opens a new/existing image file.
Syntax
createimage <ImageFileName> <NumSectors> [<SectorSize>]
ci <ImageFileName> <NumSectors> [<SectorSize>]
Parameters
Parameter
Description
ImageFileName
Name of the image file to be created/opened.
NumSectors
Number of logical sectors in the image.
SectorSize
Number of bytes in a logical sector.
Additional information
This command is mandatory and it must be the first command to be executed.
The size of the created image file is NumSectors * SectorSize bytes large.
The image file is silently overwritten if the image file already exists but the calculated
size of the file does not match. If SectorSize is not specified then the utility uses logical
sectors of 512 bytes.
SectorSize has to be a power of 2 value.
Example
The example shows how to create 1 GB image file.
createimage C:\Temp\SDcard.bin 2097152
addpartition
Description
Configures a logical partition.
Syntax
addpartition <StartSector> <NumSectors>
ap <StartSector> <NumSectors>
Parameters
Parameter
Description
StartSector
Index of the first sector in the partition.
NumSectors
Number of sectors in the partition.
Additional information
This command is optional. It allows the creation of logical partitions on the image file.
The command fails if the defined sector range overlaps the range of an already
defined logical partition. A maximum of four logical partitions can be created.
The partition list has to be stored to image after initialization of the image using
the creatembr command. The data on the
created logical partitions can be accessed using the Disk Partition driver.
The logical partitions can be formatted using the format
command. The value of StartSector is relative to the beginning of the storage device.
Example
This example shows how to configure 2 logical partitions. The sector 0 is reserved
for Master Boot Record where the partition list is stored.
addpartition 1 10000
addpartition 10001 20000
A possible emFile configuration that allows the application to access
the logical partitions looks like this:
#include<FS.h>#include"FS_MMC_HW_CM_Template.h"#defineALLOC_SIZE 0x9000// Memory pool for the file system in bytesstaticU32 _aMemBlock[ALLOC_SIZE /4];// Memory pool used for semi-dynamic allocation.voidFS_X_AddDevices(void){FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));FS_SetMaxSectorSize(2048);//// Add and configure the SD card partition. Volume name: "mmc:0:"//FS_AddDevice(&FS_MMC_CM_Driver);FS_MMC_CM_SetHWType(0,&FS_MMC_HW_CM_Template);//// Add and configure the first logical volume. Volume name: "diskpart:0"//FS_AddDevice(&FS_DISKPART_Driver);FS_DISKPART_Configure(0,&FS_MMC_CM_Driver,0,0);//// Add and configure the second logical volume. Volume name: "diskpart:1"//FS_AddDevice(&FS_DISKPART_Driver);FS_DISKPART_Configure(1,&FS_MMC_CM_Driver,0,1);}
showimageinfo
Description
Shows information about the image file.
Syntax
showimageinfo
si
Example
showimageinfo
File name: SDCard.bin
File size: 1073741824 bytes
Number of sectors: 2097152
Sector size: 512 bytes
init
Description
Initializes the image file.
Syntax
init
Additional information
This command must be executed before any other command which operates on files
and directories.
Example
init
exportimage
Description
Saves to a file the logical sectors that contain valid data.
Syntax
exportimage <FilePathOnHost> [FileType]
ei <FilePathOnHost> [FileType]
Parameters
Parameter
Description
FilePathOnHost
Path to destination file on host PC.
FileType
Format of the created file. Permitted values are:
trim - Binary file that stores the data of all the logical up to and including the last that contains valid data (default).
srec - Motorola S-record file that stores only the logical sectors that contain valid data.
sblk - Binary file that stores the data of all valid logical sectors.
Additional information
This command can be used to extract the contents of all the logical
sectors that contain valid data from the image file to an export file.
The information stored in the export file can be used to program
a storage device in a more efficient way than programming the actual
image file because the export file contains only the information that
has to actually be programmed which can help reduce the programming time.
The exportimage command is able to export the data in three file formats.
The format of the export file is specified via the second command parameter.
A trim file stores the contents of all the logical sectors up to and including
the last one that contains valid data. The index of the first logical sector
stored in the file is always 0 because the file system stores here either
format or partitioning information. The logical sectors are stored in consecutive
order and without gaps. Typically, exported file is smaller that the image file
because the the file system starts allocating storage space from the beginning
of the storage device. The exported file may contain invalid logical sectors.
The data of these logical sectors is filled with 0s.
A srec file stores the contents of all logical sectors that contain
valid data in Motorola S-record format. The address stored in the S-record
is the byte offset of the data relative to the beginning of the storage device.
A sblk file is organized in sector blocks that contain the data
of one or more consecutive sectors. Each sector block starts with a
16-byte header and is followed by the sector data. The sector block
header stores information about the sector data such as the index
of the first sector stored in the sector block and the size of the
sector block in bytes. Inside a sector block, the logical sectors
are stored in consecutive order and without gaps.
The following table describes the structure of the sector block header.
All values are stored in big endian format.
Byte range
Byte count
Description
0-3
4
Index of the first logical sector in the sector block.
4-7
4
Number of bytes in the sector data that follows the sector block header.
8-16
8
Reserved.
Example
exportimage C:\Temp\SDCard.bin
File and directory related commands
The following sections describe the commands that can be used to operate on
the files and directories stored on the image file. The commands described
in this section can be executed only after the execution of the
init command.
cd
Description
Changes the current working directory.
Syntax
chdir <DirPathOnImage>
cd <DirPathOnImage>
Parameters
Parameter
Description
DirPathOnImage
Path to new directory to change to.
Additional information
If DirPathOnImage is set to .. the command changes to the parent directory.
After initialization the current directory is set to the root directory.
Example
In the following sample the working directory is changed to Test and then
back to the original directory.
cd Test
cd ..
md
Description
Creates a directory.
Syntax
mkdir <DirPathOnImage>
md <DirPathOnImage>
Parameters
Parameter
Description
DirPathOnImage
Path to directory to be created.
Additional information
This command is able to create any missing directories in the path.
The following example copies the contents of the Test.txt
to the Test2.txt file.
copy Test.txt Test2.txt
exportfile
Description
Copies a file from image file to host PC.
Syntax
exportfile <FilePathOnImage> <FilePathOnHost>
ef <FilePathOnImage> <FilePathOnHost>
Parameters
Parameter
Description
FilePathOnImage
Path to the source file on image.
FilePathOnHost
Path to the destination file on PC.
Example
The following command copies the contents of the Test.txt file from image
to Dest.txt file on host PC.
exportfile Test.txt C:\Dest.txt
exportfolder
Description
Copies a directory recursively from image to host PC.
Syntax
exportfolder <DirPathOnImage> <DirPathOnHost>
Parameters
Parameter
Description
DirPathOnImage
Path to the source directory on image.
DirPathOnHost
Path to the destination directory on PC.
Example
The following command copies the contents of the entire current volume from image
to Exported\RootDir directory on host PC.
exportfolder \ Exported\RootDir
Logical sector related commands
The following sections describe commands that can be used to operate on logical sectors.
storesectors
Description
Copies logical sector data from a file on the PC host to image file.
Syntax
storesectors <FilePathOnImage> [<StartSector>]
Parameters
Parameter
Description
FilePathOnImage
Path to the file on host that contains sector data.
StartSector
Index of the first logical sector to be written.
Additional information
This command is optional. The sector data must be stored sequentially in the file.
For example if the sector size is 2048 bytes and the data is stored starting from
sector index 100 then the byte at offset 0 in the file stores the first byte of
sector 100, the byte at offset 2048 in the file stores the first byte of sector
101 and so on. The size of the file has to be a multiple of sector size.
The size of the sector is the size specified as second the argument to
createimage command.
Example
This example reads sector data from the file SectorData.bin and writes
it starting from sector index 100.
storesectors SectorData.bin 100
dumpsector
Description
Shows the contents of a logical sector.
Syntax
dumpsector <SectorIndex>
ds <SectorIndex>
Parameters
Parameter
Description
SectorIndex
Index of the logical sector to be displayed.
Example
The following command shows the contents of the logical sector 0.
This command operates only on the file:0: volume. The command reports
and error if the source and destination sector ranges overlap.
Example
This example copies 10000 logical sectors from sector index 0 to sector index 20000.
copysectors 0 20000 10000
Volume related commands
The following sections describe commands that operate on the file system volumes
located on the image file.
format
Description
High-level formats a volume.
Syntax
format [<VolumeName>] [<SectorsPerCluster>]
Parameters
Parameter
Description
VolumeName
Name of the volume that has to be formatted.
SectorsPerCluster
Number of logical sectors in a cluster.
Additional information
If VolumeName is not specified then the command formats
the current first volume. The current volume can be selected via the
cd command.
Every volume has to be high-level formatted once when the image file
is newly created.
If SectorsPerCluster is not specified then the file system
chooses an appropriate value that is based on the capacity of the
storage device. SectorsPerCluster has to be a power of two
value within the following limits: 1--128 for FAT and 1--32768 for EFS.
Example
This example demonstrates how to format the volume file:0:
format
High-level format...OK
df
Description
Shows the available free space on a volume.
Syntax
diskfree [<VolumeName>]
df [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be queried.
Additional information
If VolumeName is not specified than the command calculates the free
space of the current volume. The current volume can be selected via the
cd command.
Example
This example demonstrates how to get the frees space on the first volume.
df
Available free space is 127647744 bytes
diskinfo
Description
Shows information about a storage device.
Syntax
diskinfo [<VolumeName>]
di [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be queried.
Additional information
If VolumeName is not specified then the command returns information
about the current volume. The current volume can be selected via the
cd command.
Example
This example demonstrates how to get information about the volume file:1:.
diskinfo file:1:
127647744 bytes total disk space
17719296 bytes available free space
8192 bytes per cluster
15582 cluster available on volume
2163 free cluster available on volume
getdevinfo
Description
Shows information about a volume.
Syntax
getdevinfo [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be queried.
Additional information
If VolumeName is not specified then the command returns information
about the first volume. The current volume can be selected via the
cd command.
Example
This example demonstrates how to get information about the storage device
used by the first volume.
getdevinfo
62370 available sectors
2048 bytes per sector
checkdisk
Description
Checks a volume for errors.
Syntax
checkdisk [<VolumeName>]
chkdsk [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be checked.
Additional information
If VolumeName is not specified then the command checks the current volume
for errors. The current volume can be selected via the
cd command.
Example
This example demonstrates how to check the file system structure of the first volume.
checkdisk
creatembr
Description
Writes partition table to master boot record (MBR).
Syntax
creatembr [<VolumeName>]
cm [<VolumeName>]
Parameters
Parameter
Description
VolumeName
Name of the volume to be written.
Additional information
If VolumeName is not specified then the command writes the MBR
to the current volume. The current volume can be selected via the
cd command.
This command stores the partition table configured via
addpartition
command to the MBR of the specified volume. The command has to be executed after
the low-level format and before any high-level format operation. Typically,
the partition table is located on file:0: volume.
Example
This example stores the MBR to the sector 0 of the file:0: volume.
creatembr file:0:
listvolumes
Description
Shows the names of all available volumes.
Syntax
listvolumes
lv
Example
Shows the names of the volumes of in a configuration using five volumes.
listvolumes
Available volumes:
file:0:
diskpart:0:
diskpart:1:
diskpart:2:
diskpart:3:
If VolumeName is not specified then the command crates the journal on
the current volume. The current volume can be selected via the
cd command. If PathToFile is not
specified then the journal file is created on the root directory of the
specified volume. JournalSize has to be specified in bytes.
The value of SupportFreeSector is passed as third argument
to FS_JOURNAL_CreateEx(). If not specified SupportFreeSector is set to 0.
The parameters passed to the createjournal
command have to match the parameters passed to FS_JOURNAL_CreateEx() on the target application.
Example
This example demonstrates how to create a journal file of 128 Kbytes on the
current volume.
This is an optional command that can be used for updating the information about the
usage of all logical sectors of a volume. This is done by analyzing
the file system structure and by informing the device driver about
the logical sectors that do not store any valid data. The sector usage information
helps the Storage Image Creator utility to reduce the size of an exported
image to a minimum.
Typically, the freesectors command
has to be performed on a file system image that was not created using
the Storage Image Creator utility, for example by copying the data directly from
a physical storage device.
If the file system image contains more than one partition then
the freesectors command
has to be executed on each partition.
If VolumeName is not specified then the command processes
the current volume. The current volume can be selected via the
cd command.
Example
This example demonstrates to update the sector usage information
of the current volume.
freesectors
Freeing sectors of 'file:0:'...OK
Porting emFile 2.x to 3.x
This chapter describes the differences between the versions 2.x and 3.x
of emFile and the changes required to port an existing application.
Differences between version 2.x and 3.x
Most of the differences between emFile version 2.x to version 3.x are internal.
The API of emFile version 2.x is a subset of the API of version 3.x.
Only few functions were completely removed. Refer to section API differences
for a complete overview of the removed and obsolete functions.
emFile version 3.x has a new driver handling. You can include device
drivers and allocate the required memory for it without the need to recompile
the entire file system. Refer to Configuration of emFile for detailed
information about the integration of a driver into emFile.
For detailed information about the emFile device drivers, refer to the
chapter Device drivers.
Because of these differences, we recommend to start with a new file system
project and include your application code, if the start project runs without
any problem. Refer to the chapter Running emFile on target hardware
for detailed information about the best way to start to work with emFile
version 3.x. The following sections give an overview about the changes
introduced in the version 3.x of emFile.
API differences
Function
Description
Changed functions
FS_GetFreeSpace()
Number of parameters reduced. Parameter DevIndex removed.
FS_GetTotalSpace()
Number of parameters reduced. Parameter DevIndex removed.
This function should not be used in emFile version 3.x.
Alternatively, FS_IsLLFormatted() has to be used instead
to check if a low-level format is required and FS_GetDeviceInfo()
to get information about the storage device.
Note
The handling of the directories was changed in version 3.x of emFile.
Refer to FS_FindClose() for an example of the new way of directory handling.
In emFile version 3.x, the header file FS_Api.h is renamed to FS.h , therefore change
the name of the file system header file in your application.
Configuration differences
The configuration of emFile version 3.x has been simplified compared to emFile version 2.x. emFile version 3.x can be used “out of the box”. You can use it without the need for changing any of the compile time flags. All compile time configuration flags are preconfigured with valid values, which matches the requirements of most applications.
A lot of the compile time flags of emFile version 2.x were removed and replaced with runtime configuration function.
This chapter describes the differences between the versions 3.x and 4.x of
emFile and the changes required to port an application to the new version.
Differences between version 3.x and 4.x
Most of the differences between emFile version 3.x and version 4.x are
internal. The API of emFile version 3.x is a subset of the version 4.x.
There are two differences that require the porting of an application using
emFile:
The API of the hardware layer has been improved.
The SD/MMC device driver for Atmel MCUs has been removed.
emFile version 4.x has a new hardware layer API. The name of the functions
are no longer hard-coded in the source. Instead, the drivers call the functions
indirectly via a function table. The hardware layer is specified as an instance
of a structure that contains pointers to functions. This gives greater
flexibility to the application allowing it to configure different hardware
layers at runtime depending on the target hardware it runs on.
The emFile configurations that do not require a hardware layer are not
affected by this change.
The SD/MMC device driver for Atmel MCUs (FS_MMC_CM_Driver4Atmel) has been removed
from the version 4.x of emFile. The reason for this change is to eliminate
duplicated functionality. The SD/MMC card mode device driver
(FS_MMC_CM_Driver) supports all the functionality of the SD/MMC device
driver for Atmel MCUs and can be used as replacement.
The following sections give detailed information about the changes introduced
in the version 4.x of emFile that require changes in the application.
Hardware layer API differences
The function prototypes of the new hardware layer API of version 4.x are
identical to the hardware layer functions used in the version 3.x of emFile.
No functions have been added to or removed from the new hardware layer API and
no changes are required to the implementation of the existing hardware layer
functions. Typically, the following changes are required for porting an
application to version 4.x:
A function table containing pointers to the hardware layer functions has
to be declared as a global variable in the file that implements the old hardware
layer. The type of the function table depends on the hardware layer used.
A header file has to be created that declares the function table as external.
The header file has to be included in the file that defines the
FS_X_AddDevices() function.
A call to one of the functions that configure the type of the hardware
layer has to be added to FS_X_AddDevices(). These functions take as second
argument a pointer to the function table.
Alternatively, the steps 1 to 3 can be skipped and a default hardware layer
can be used instead. The function table of these hardware layers contain
pointers to functions used in the version 3.x of emFile. More information
can be found in the following sections that describe the differences for each
hardware layer type.
NAND device driver differences
Sample hardware layers using the new API and the corresponding file system
configuration files can be found in the Sample/FS/Driver/NAND folder of
the emFile shipment and are located in the following files:
Hardware layer for parallel NAND flash via memory controller
FS_NAND_HW_Template.h
FS_NAND_HW_Template.c
FS_ConfigNAND_Template.c
Hardware layer for parallel NAND flash via I/O port
FS_NAND_HW_TemplatePort.h
FS_NAND_HW_TemplatePort.c
FS_ConfigNAND_TemplatePort.c
Hardware layer for DataFlash via SPI
FS_NAND_HW_DF_Template.h
FS_NAND_HW_DF_Template.c
FS_ConfigNAND_DF_Template.c
Hardware layer for serial NAND flash via SPI
FS_NAND_HW_SPI_Template.h
FS_NAND_HW_SPI_Template.c
FS_ConfigNAND_UNI_SPI_Template.c
Porting without hardware layer modification
The porting of the application to the new hardware layer API can be done without
modifying the existing hardware layer. emFile comes with default hardware
layers that contain pointers to the hardware layer functions used in the
version 3.x of emFile. A call to the function that configures the hardware
layer type has to be added to file system configuration and the file that
defines the default hardware layer has to be added to the project.
The following table shows in which file each default hardware layer is defined.
All the files are located in the Sample/FS/Driver/NAND folder of the
emFile shipment.
Default hardware layer
File name
FS_NAND_HW_Default
FS_NAND_HW_Default.c
FS_NAND_HW_DF_Default
FS_NAND_HW_DF_Default.c
FS_NAND_HW_SPI_Default
FS_NAND_HW_SPI_Default.c
The table below lists the default hardware layer required by each physical layer:
Physical layer
Default hardware layer
FS_NAND_PHY_x
FS_NAND_HW_Default
FS_NAND_PHY_x8
FS_NAND_HW_Default
FS_NAND_PHY_512x8
FS_NAND_HW_Default
FS_NAND_PHY_2048x8
FS_NAND_HW_Default
FS_NAND_PHY_2048x16
FS_NAND_HW_Default
FS_NAND_PHY_4096x8
FS_NAND_HW_Default
FS_NAND_PHY_ONFI
FS_NAND_HW_Default
FS_NAND_PHY_DataFlash
FS_NAND_HW_DF_Default
FS_NAND_PHY_SPI
FS_NAND_HW_SPI_Default
For more information about the functions of the physical layers refer to
NAND physical layer.
Example
The following example shows how to port an existing configuration using
the SLC1 NAND device driver. Two changes are required:
The function call marked with the comment “Add this line” in the
code snippet below has to be added to the existing emFile configuration.
The file Sample/FS/Driver/NAND/FS_NAND_HW_Default.c that defines
the FS_NAND_HW_Default hardware layer has to be added to the project.
voidFS_X_AddDevices(void){FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// The next line is optional.//// FS_SetMaxSectorSize(2048);//// Add and configure the driver.//FS_AddDevice(&FS_NAND_Driver);FS_NAND_SetPhyType(0,&FS_NAND_PHY_2048x8);FS_NAND_2048x8_SetHWType(0,&FS_NAND_HW_Default);// Add this line.//// Enable the file buffer to increase the performance// when reading/writing a small number of bytes.//FS_ConfigFileBufferDefault(512,FS_FILE_BUFFER_WRITE);}
Replacement functions
The following table lists the replacement functions of the hardware layer
for parallel NAND flash.
Sample hardware layers using the new API and the corresponding file system
configurations can be found in the Sample/FS/Driver/NOR folder of the
emFile shipment and are located in the following files:
Hardware layer for serial NOR flash
FS_NOR_HW_SPI_Template.h
FS_NOR_HW_SPI_Template.c
FS_ConfigNOR_SPI_Template.c
Hardware layer for QSPI NOR flash
FS_NOR_HW_SPIFI_Template.h
FS_NOR_HW_SPIFI_Template.c
FS_ConfigNOR_BM_SPIFI_Template.c
Porting without hardware layer modification
The porting of the application to the new hardware layer API can be done without
modifying the existing hardware layer. emFile comes with default hardware
layers that contain pointers to the hardware layer functions used in the version
3.x of emFile. A call to the function that sets the hardware layer type
has to be added to file system configuration and the file that defines the
default hardware layer has to be added to the project. The table below shows
in which file each default hardware layer is defined. The files are located in
the Sample/FS/Driver/NOR folder of the emFile shipment:
Default hardware layer
File name
FS_NOR_HW_ST_M25_Default
FS_NOR_HW_ST_M25_Default.c
FS_NOR_HW_SFDP_Default
FS_NOR_HW_SFDP_Default.c
The table below lists the default hardware layer required by each physical layer:
Physical layer
Default hardware layer
FS_NOR_PHY_ST_M25
FS_NOR_HW_ST_M25_Default
FS_NOR_PHY_SFDP
FS_NOR_HW_SFDP_Default
For more information about the functions of the physical layers refer to
NOR physical layer.
Example
This example show how to port an existing configuration for a serial NOR flash.
The function call marked with the comment “Add this line” to be added
to existing configuration. No other changes of file system configuration are
required. Additionally, the file Sample/FS/Driver/NOR/FS_NOR_HW_ST_M25_Default.c
that defines the FS_NOR_HW_ST_M25_Default hardware layer has to be added to the
project.
The …_x2 and …_x4 functions have to be defined only
when the FS_NOR_PHY_SFDP physical layer configured and the hardware supports
dual and quad SPI data transfer modes.
MMC/SD SPI device driver differences
Sample hardware layers using the new API and the corresponding file system
configurations can be found in the Sample/FS/Driver/MMC_SPI folder
of the emFile shipment and are located in the following files:
Hardware layer for SD card via SPI
FS_MMC_HW_SPI_Template.h
FS_MMC_HW_SPI_Template.c
FS_ConfigMMC_SPI_Template.c
Hardware layer for SD card via I/O port
FS_MMC_HW_SPI_TemplatePort.h
FS_MMC_HW_SPI_TemplatePort.c
FS_ConfigMMC_SPI_TemplatePort.c
Porting without hardware layer modification
It is possible to port an existing application to the new hardware layer API
without modifying the existing hardware layer. emFile comes with a default
hardware layer that contains pointers to the hardware layer functions used
in the version 3.x of emFile. A call to the function FS_MMC_SetHWType()
has to be added to file system configuration and the file that defines the
default hardware layer (FS_MMC_HW_SPI_Default.c) has to be added to
the project. The file is located in the Sample/FS/Driver/MMC_SPI folder
of the emFile shipment.
Example
This example shows how to modify an existing emFile configuration to work
with the new hardware layer API. The function call marked marked with the
comment “Add this line.” has to be added to existing configuration. No other
changes to file system configuration are required. In addition, the file
Sample/FS/Driver/MMC_SPI/FS_MMC_HW_SPI_Default.c that defines the
FS_MMC_HW_SPI_Default hardware layer has to be added to the project.
voidFS_X_AddDevices(void){FS_AssignMemory(&_aMemBlock[0],sizeof(_aMemBlock));//// Add and configure the driver.//FS_AddDevice(&FS_MMC_SPI_Driver);FS_MMC_SetHWType(0,&FS_MMC_HW_SPI_Default);// Add this line.// FS_MMC_ActivateCRC(); // Uncommenting this line will activate// the CRC calculation of the MMC/SD SPI driver.//// Enable the file buffer to increase the performance// when reading/writing a small number of bytes.//FS_ConfigFileBufferDefault(512,FS_FILE_BUFFER_WRITE);}
Replacement functions
The following table lists the replacement functions of the SPI hardware layer.
The locking functions have to be implemented only when the MMC / SD
SPI device driver is compiled with the FS_MMC_SUPPORT_LOCKING define set to 1.
MMC/SD card mode device driver differences
Sample hardware layers using the new API and the corresponding file system
configurations are available in the Sample/FS/Driver/MMC_CM folder
of the emFile shipment and are located in the following files:
FS_MMC_HW_CM_Template.h
FS_MMC_HW_CM_Template.c
FS_ConfigMMC_CardModeTemplate.c
Porting without hardware layer modification
It is possible to port the application to the new hardware layer API without
modifying the existing hardware layer. emFile comes with a default
hardware layer that contains pointers to the hardware layer functions used
in the version 3.x of emFile. A call to the function FS_MMC_CM_SetHWType()
has to be added to file system configuration and the file that defines
the default hardware layer (FS_MMC_HW_CM_Default.c) has to be added
to the project. The file is located in the Sample/FS/Driver/MMC_CM
folder of the emFile shipment.
Example
This example shows the modifications that have to be done to an existing
application. The function call marked with the comment “Add this line.”
has to be added to existing configuration. No other changes of file system
configuration are required. Additionally, the file Sample/FS/Driver/MMC_CM/FS_MMC_HW_CM_Default.c
that defines the FS_MMC_HW_CM_Default hardware layer has to be added to the
project.
Sample hardware layers using the new API and the corresponding file system
configurations can be found in the Sample/FS/Driver/IDE folder
of the emFile shipment in the following files:
Hardware layer for memory map mode
FS_IDE_HW_TemplateMemMapped16bit.h
FS_IDE_HW_TemplateMemMapped16Bit.c
FS_ConfigIDE_TemplateMemMapped16Bit.c
Hardware layer for true IDE mode
FS_IDE_HW_TemplateTrueIDE.h
FS_IDE_HW_TemplateTrueIDE.c
FS_ConfigIDE_TemplateTrueIDE.c
Porting without hardware layer modification
It is possible to port the application to the new hardware layer API without
modifying the existing hardware layer. emFile comes with a default
hardware layer that contains pointers to the hardware layer functions used
in the version 3.x of emFile. A call to the function FS_IDE_SetHWType()
has to be added to file system configuration and the file that defines the
default hardware layer (FS_IDE_HW_Default.c) has to be added to the
project. The file is located in the Sample/FS/Driver/IDE folder
of the emFile shipment.
Example
This example shows the modifications that have to be done to an existing
application. The function call marked mark with the comment “Add this line.”
has to be added to existing configuration. No other changes of file system
configuration are required. In addition, the file
Sample/FS/Driver/IDE/FS_IDE_HW_Default.c which defines
the FS_IDE_HW_Default hardware layer has to be added to the project.
The MMC / SD device driver for ATMEL microcontrollers (FS_MMC_CM_Driver4Atmel)
is no longer available in the version 4.x of emFile. The MMC/SD card
mode device driver (FS_MMC_CM_Driver) provides the same functionality
and can be used as replacement. Changes are required both to emFile
configuration and to hardware layer in oder to port an existing application
to the version 4.x of emFile.
Configuration changes
The MMC / SD device driver for ATMEL MCUs has to be replaced in the
FS_X_AddDevices() function by the MMC/SD card mode device driver.
In addition, the hardware layer has to be explicitly configured.
Example
This example shows what changes have to be done to emFile configuration.
The function calls that marked with the comment “Remove this line.” have to be
removed from the file system configuration. The function calls that have to be
added are marked with the commend “Add this line.”
The hardware layer APIs of the MMC / SD device driver for ATMEL MCUS and that
of the MMC / SD card mode device driver are different. A new hardware layer
has to be implemented for the MMC/SD card mode device driver to port an existing
application. For more information about the functions of the hardware layer
for MMC / SD card mode device driver refer to Hardware layer.
Sample implementations for ATMEL AT91SAM9x MCU can be found in the
Sample/FS/Driver/MMC_CM folder of the emFile shipment.
The table below lists the functions of the hardware layer for the MMC / SD
device driver for ATMEL MCUS together with their possible replacement functions.
Old function
Possible replacement
FS_MCI_HW_EnableClock()
The clock to MCI host should be enabled in
the (*pfInitHW)() function.
FS_MCI_HW_EnableISR()
The interrupt of MCI host should be enabled
in the (*pfInitHW)() function.
FS_MCI_HW_GetMClk()
The information returned by this function is
not required anymore.
FS_MCI_HW_GetMCIInfo()
The information returned by this function is
not required anymore.
FS_MCI_HW_Init()
(*pfInitHW)()
FS_MCI_HW_IsCardPresent()
(*pfIsPresent)()
FS_MCI_HW_IsCardWriteProtected()
(*pfIsWriteProtected)()
FS_MCI_HW_GetTransferMem()
Non-cached memory should be allocated via
a dedicated BSP function.
Porting emFile 4.x to 5.x
This chapter describes the differences between the versions 4.x and 5.x
of emFile and the changes required to port an existing application.
Differences between version 4.x and 5.x
Most of the differences between emFile version 4.x to version 5.x are internal.
The API of emFile version 4.x is a subset of the version 5.x. There are two
differences that require the porting of an application using emFile:
The prototypes of the optional API functions are conditionally compiled.
Some header and source files were removed or renamed.
Function prototype differences
emFile uses configuration defines to enable or disable different optional
features of the file system at compile time. Typically, the optional features
come with API functions that can be called by an application to make use of that
optional feature. In older emFile versions these API functions performed
no operation or unnecessarily allocated resources when the feature was disabled.
The version 5.x changes this in that it defines the body and the prototype of
these API functions only when the feature is enabled.
As a result of these changes it is possible that errors are reported when building
an application that calls an API function of an optional feature that is not enabled
at compile time. The solution to this problem is to enclose the calls to these API
functions with #if/#endif processor commands that make sure the function is called
only when the optional feature is enabled.
For example if the same application is expected to be compiled to make use
of the memory allocator provided by emFile as well as of the memory
allocation functions of the C library then the emFile configuration
functions have to be called such in the following example:
#include<FS.h>#include<stdlib.h>#defineALLOC_SIZE 0x4000// Size defined in bytes#if(FS_SUPPORT_EXT_MEM_MANAGER ==0)staticU32 _aMemBlock[ALLOC_SIZE /4];// Memory pool used for// semi-dynamic allocation.#endif/*********************************************************************** FS_X_AddDevices** Function description* This function is called by the FS during FS_Init().*/voidFS_X_AddDevices(void){//// Give the file system memory to work with.//#if(FS_SUPPORT_EXT_MEM_MANAGER ==0)FS_AssignMemory(_aMemBlock,sizeof(_aMemBlock));#elseFS_SetMemHandler((FS_MEM_ALLOC_CALLBACK*)malloc,free);#endif// FS_SUPPORT_EXT_MEM_MANAGER == 0//// Additional file system configuration...//}
The following table lists all the prototypes of all optional API functions
together with the name and the value of the configuration define that enables
the optional feature. Note that the table contains all the function prototypes
that are conditionally compiled including the function prototypes that were
conditionally compiled in older emFile versions.
The names of some of the emFile header and source files were renamed in order to improve consistency.
This change makes sure that the names of all the header and source files that ship with emFile begin
with the prefix “FS_”. In addition, the contents of some of the header and source files was moved to other
files in order to keep the number of files to a minimum. The removal of some of the header files can possibly
cause compiler errors. The errors can be corrected by including the name of the header file specified in the
following table instead of the missing file header.
The next table lists the names of the header ans source files that were renamed, moved or deleted in the
version 5.x of emFile. The first column stores the original file name while the second column holds
either the new file name or the file name that stores its contents. If the file has been deleted the name
of the file is set to “-” in the second column. The third column stores a code indicating the operation
that was performed on that file:
M - contents of the file has been moved
R - file has been renamed
D - file has been deleted
Old file name
New file name
Operation
CRYPT_ALGO_AES.c
FS_CRYPT_ALGO_AES.c
R
CRYPT_ALGO_DES.c
FS_CRYPT_ALGO_DES.c
R
CRYPT_Drv.c
FS_CRYPT_Drv.c
R
CRYPT_File.c
FS_CRYPT_File.c
R
EFS.h
FS_EFS.h
R
EFS_API.c
FS_EFS_API.c
R
EFS_CheckDisk.c
FS_EFS_CheckDisk.c
R
EFS_Dir.c
FS_EFS_Dir.c
R
EFS_DirEntry.c
FS_EFS_DirEntry.c
R
EFS_Format.c
FS_EFS_Format.c
R
EFS_Intern.h
FS_EFS_Int.h
R
EFS_Misc.c
FS_EFS_Misc.c
R
EFS_Move.c
FS_EFS_Move.c
R
EFS_Open.c
FS_EFS_Open.c
R
EFS_Read.c
FS_EFS_Read.c
R
EFS_Rename.c
FS_EFS_Rename.c
R
EFS_SetEndOfFile.c
FS_EFS_SetEndOfFile.c
R
EFS_Write.c
FS_EFS_Write.c
R
FAT.h
FS_FAT.h
R
FAT_API.c
FS_FAT_API.c
R
FAT_CheckDisk.c
FS_FAT_CheckDisk.c
R
FAT_Dir.c
FS_FAT_Dir.c
R
FAT_DirEntry.c
FS_FAT_DirEntry.c
R
FAT_DiskInfo.c
FS_FAT_DiskInfo.c
R
FAT_Format.c
FS_FAT_Format.c
R
FAT_FormatSD.c
FS_FAT_FormatSD.c
R
FAT_Intern.h
FS_FAT_Int.h
R
FAT_Ioct.c
-
D
FAT_LFN.c
FS_FAT_LFN.c
R
FAT_Misc.c
FS_FAT_Misc.c
R
FAT_Move.c
FS_FAT_Move.c
R
FAT_Open.c
FS_FAT_Open.c
R
FAT_Read.c
FS_FAT_Read.c
R
FAT_Rename.c
FS_FAT_Rename.c
R
FAT_SetEndOfFile.c
FS_FAT_SetEndOfFile.c
R
FAT_VolumeLabel.c
FS_FAT_VolumeLabel.c
R
FAT_Write.c
FS_FAT_Write.c
R
FS_AddSpaceHex.c
FS_Debug.c
M
FS_API.h
-
D
FS_AssignCache.c
FS_CACHE_Core.c
R
FS_CacheAll.c
FS_CACHE_All.c
R
FS_CacheMan.c
FS_CACHE_Man.c
R
FS_CacheMultiWay.c
FS_CACHE_MultiWay.c
R
FS_CacheRW.c
FS_CACHE_RW.c
R
FS_CacheRWQuota.c
FS_CACHE_RWQuota.c
R
FS_CLib.h
-
D
FS_Dev.h
-
D
FS_DF_X_HW.h
FS.h
M
FS_ErrorOut.c
FS_Debug.c
M
FS_FRead.c
FS_Read.c
M
FS_FWrite.c
FS_Write.c
M
FS_GetFilePos.c
-
D
FS_GetNumOpenFiles.c
FS_Misc.c
M
FS_Lbl.h
-
D
FS_Log.c
FS_Debug.c
M
FS_SetFilePos.c
-
D
FS_Warn.c
FS_Debug.c
M
FS__ECC256.c
FS_ECC256.c
R
IDE_Drv.c
FS_IDE_Drv.c
R
IDE_X_HW.h
FS.h
M
MMC_Drv.c
FS_MMC_Drv.c
R
MMC_SD_CardMode_Drv.c
FS_MMC_CM_Drv.c
R
MMC_SD_CardMode_X_HW.h
FS.h
M
MMC_X_HW.h
FS.h
M
NAND_Drv.c
FS_NAND_Drv.c
R
NAND_ECC_HW.c
FS_NAND_ECC_HW.c
R
NAND_ECC_SW_1Bit.c
FS_NAND_ECC_SW_1Bit.c
R
NAND_HW_SPI_X.h
FS.h
M
NAND_Misc.c
FS_NAND_Misc.c
R
NAND_PHY_2048x16.c
FS_NAND_PHY_2048x16.c
R
NAND_PHY_2048x8.c
FS_NAND_PHY_2048x8.c
R
NAND_PHY_4096x8.c
FS_NAND_PHY_4096x8.c
R
NAND_PHY_512x8.c
FS_NAND_PHY_512x8.c
R
NAND_PHY_DataFlash.c
FS_NAND_PHY_DataFlash.c
R
NAND_PHY_ONFI.c
FS_NAND_PHY_ONFI.c
R
NAND_PHY_SPI.c
FS_NAND_PHY_SPI.c
R
NAND_PHY_x8.c
FS_NAND_PHY_x8.c
R
NAND_Private.h
FS_NAND_Int.h
R
NAND_UNI_Drv.c
FS_NAND_UNI_Drv.c
R
NAND_X_HW.h
FS.h
M
NOR_BM_Drv.c
FS_NOR_BM_Drv.c
R
NOR_Drv.c
FS_NOR_Drv.c
R
NOR_HW_CFI_1x16.c
FS_NOR_HW_CFI_1x16.c
R
NOR_HW_CFI_2x16.c
FS_NOR_HW_CFI_2x16.c
R
NOR_HW_SPI_X.h
FS.h
M
NOR_PHY_CFI.c
FS_NOR_PHY_CFI.c
R
NOR_PHY_DSPI.c
FS_NOR_PHY_DSPI.c
R
NOR_PHY_SFDP.c
FS_NOR_PHY_SFDP.c
R
NOR_PHY_SPIFI.c
FS_NOR_PHY_SPIFI.c
R
NOR_PHY_ST_M25.c
FS_NOR_PHY_ST_M25.c
R
NOR_Private.h
FS_NOR_Int.h
R
NOR_SPI_Dev.c
FS_NOR_SPI_Dev.c
R
NOR_SPI_Dev.h
FS.h
M
RAMDISK.c
FS_RAMDisk.c
R
WinDrive.c
FS_WinDrive.c
R
FS_X_embOS.c
FS_OS_embOS.c
R
FS_X_FreeRTOS.c
FS_OS_FreeRTOS.c
R
FS_X_None.c
FS_OS_None.c
R
FS_X_ucOS_II.c
FS_OS_ucOS_II.c
R
FS_X_Win32.c
FS_OS_Win32.c
R
Support
This chapter describes how to contact the SEGGER support.
Contacting support
There are different ways to contact the emFile support if you are a registered user:
Please include the following information in the email or ticket:
Used emFile version.
Used emFile license number.
If you are unsure about the above information you can also send the name of the emFile shipment file.
A detailed description of the problem.
Optionally, a test project that can be used to reproduce the problem.
Where can I find the license number?
The license number is part of the shipped .zip file name. For example the number of license shipped
in the file emFile_PRO_Src_V5.26.0_FS-01234_t17ynMvA_240129.zip file is FS-01234.
The license number is also stored in the header of all the *.c and *.h files that are included
in the emFile shipment. For example, if you open FS.h you should find the license number
as in the example below:
----------------------------------------------------------------------Licensing informationLicensor:SEGGER Microcontroller GmbHLicensed to:MyCompanyLicensed SEGGER software:emFileLicense number:FS-01234License model:SSLLicensed product:AnyLicensed platform:ARM Cortex MLicensed number of seats:-----------------------------------------------------------------------Support andUpdate Agreement (SUA)SUA period:2024-02-12-2024-08-12Contact to extend SUA:sales@segger.com----------------------------------------------------------------------File :FS.hPurpose :Define global functions andtypes to be used by anapplication usingthe file system.This file needs to be included by any module usingthefile system.--------------------------END-OF-HEADER -----------------------------
FAQs
This chapter contains a collection of frequently asked questions (FAQs)
together with their respective answers.
Questions and answers
Is my data safe when an unexpected reset occurs?
In general, the data which is already on the storage device is safe.
If a read operation is interrupted, this is completely harmless. If a write
operation is interrupted, then the data written during this operation may
or may not be stored on the storage device. This depends on when when the
unexpected reset occurred. In any case, the data which was on the storage
device prior to the write operation is not affected. This is true if the storage
device is not affected by the reset, meaning that the storage device is able to
complete a pending write operation. All this is true for the device drivers
that come with emFile. However, the structure of the FAT or EFS file systems
can be corrupted by an unexpected reset. This can be prevented by using the
Journaling component.
I use FAT and I can only create a limited number of root directory entries. Why?
With FAT12 and FAT16 the root directory is special because it has a fixed size.
The size of the root directory can be specified at format, but once formatted
this value is constant and determines the number of entries the root directory
can hold. FAT32 does not have this limitation and the size of the root directory
can be variable. Microsoft’s “FAT32 File System Specification” says
on page 22: “For FAT12 and FAT16 media, the root directory is located in a
fixed location on the disk immediately following the last FAT and is of a fixed
size in sectors computed from the BPB_RootEntCnt value […] For FAT32, the root
directory can be of variable size and is a cluster chain, just like any other
directory is.” Here BPB_RootEntCnt specifies the count of 32-byte directory
entries in the root directory and as the citation says, the number of sectors
is computed from this value. In addition, which file system is used depends
on the size of the storage medium, that is the number of clusters and the
cluster size, where each cluster contains one or more sectors. Using small
cluster sizes (for example cluster size equal to 512 bytes) one can use FAT32
on a storage medium with more than 32 MB. (FAT16 can address at least 216
clusters with a 512 byte cluster size. That is 65536 * 512 = 33554432 bytes
= 32768 KB = 32 MB). If the storage medium is smaller than or equal to 32 MB
or the cluster size is greater than 512 bytes, FAT32 cannot be used.
The second parameter of the FS_Format() API function can be used to set a custom
root directory size for FAT12 / FAT16 volume. This parameter is a pointer to
a FS_FORMAT_INFO structure that contains a member named NumRootDirEntries
which can be used to specify the number of entries in the root directory.
Glossary
List of some of the terms used in this manual together with a short explanation.
List of terms
Allocation table
A reserved storage area where the file system stores information about
what clusters are allocated.
BPB
BIOS Parameter Block. Logical sector (typically the first in a partition)
that stores information about how the storage device is formatted. This information
is updated during the high-level format operation.
BSP
Board Support Package.
CHS address
Address on a mechanical storage device specified as Cylinder, Head and Sector.
Cluster
Smallest storage allocation unit of the file system. It consist of one or more logical sectors.
Cluster chain
File system data structure that stores information about what clusters
are allocated to the same file or directory.
Directory entry
File system data structure that stores information about a file
or directory such as name, size, time stamps, etc.
EFS
Embedded File System. SEGGER’s proprietary file system
specifically designed for embedded systems.
eMMC
embedded Multi-Media Card. A MMC compatible storage device that is packaged
in an integrated circuit
FAT
File Allocation Table. Widely used file system designed by Microsoft.
LFN
Long File Name. Extension for FAT file system that provides support for
file and directory names longer that 8 characters in the base name and 3 characters
in the extension
Logical sector
Smallest storage allocation unit that a device or logical driver can handle.
MBR
Master Boot Record. File system data structure that stores information
about how the storage device is partitioned.
MCU
MicroController Unit. A small computer that embeds a CPU, memory and peripherals
on the same integrated circuit.
MMC
Multi-Media Card. Type of removable non-volatile storage device that conforms with MMC specification.
Flash memory
A type of non-volatile storage device that can be electrically erased and programmed.
OS layer
emFile interface to task synchronization services provided by an operating system.
SD card
Secure Digital card. Type of removable non-volatile storage device that conforms with SD specification.
Storage device
A device that can store and preserve data between power cycles such
as NAND flash, NOR flash, SD card, eMMC, or USB drive.