Intro

EEPFS is a very simple filesytem EEPROMs, non volatile RAM and so on. It is not suitable for flash, either NOR or NAND because it relies on being able to do writes with arbitrary data at a byte granularity.

Volume structure

The volume has a header and a series of pools holding data. Each pool holds items at fixed size offsets. The Header is a list off pools. As an example, consider a 8192 byte EEPROM. The header is 20 bytes, and there are three pools, for items of upto 2, 4 and 8 bytes long.

BytesContent
0-19Header
20-2747Pool to store 341 items upto 2 bytes
2748-5471Pool to store 227 items upto 4 bytes
5472-8191Pool to store 136 items upto 8 bytes

Each pool entry has a header 4 byte header and then two copies of each the data.

Each file in EEPFS is identified by a 32 bit ID. This is generated by a macro like this

#define	FILEID_LONG    EEP_MAKE_FILEID(long,  2)

This puts the size of a long into the high word of the ID, and an ordinal into the low word. EEPFS finds the best fit in the available pools, and uses the ordinal to work out an offset. Each pool item has space for two copies of the data to be stored, this is what makes EEPFS crash safe. There is an active version and an inactive one, identified by the header, which has the following structure. Note that because of the way the system works, you should make the ordinals unique per pool.

typedef struct { WORD filename; BYTE version[2]; } EEP_HEADER;

The version array has two bytes, the one with the highest value is the active, the other is inactive. On a read, the active version is read. On a write, the inactive version is first written, then it's version number is set to one more than the active version. If the power fails in the middle of this sequence, the old version will stay active.

The filename item is used for checking - it is set to the ordinal when the file is created. On open, if filename is different from ordinal, the file doesn't exist. A create function is provided which will either open an existing file, or create it with default data.

Function walkthrough

int eepfs_format( int size )

Format a volume with the specified size. This just writes the pool header.

int eepfs_mount( void )

Mount a volume - read the pool info from the device. Read the pool headers into a malloc'd buffer.

int eepfs_unmount( void )

Unmount a volume - the pool info is freed.

EEP_HANDLE* eepfs_create ( FILEID fileid, int create, void *default_data )

This attempts to open a file. The algorithm is simple -

  1. Calculate the size of the file needed to hold an item - the FILEID holds the item size in the high bits.
  2. Search the pool list in memory to find the first one that fits
  3. Use the nth item in the pool, where n is the ordinal in the low bits of the FILEID.
Next, look at the filename field in the header. If this matches the ordinal from the FILEID, the file handle is returned. If not, if create is true, the file is created with the default data, otherwise return NULL.

EEP_HANDLE* eepfs_open ( FILEID fileid )

A wrapper around eepfs_create. Either open a file, or return NULL if it does not exist

void eepfs_close ( EEP_HANDLE* pHndl )

Close a file handle from eepfs_create or eepfs_open

void eepfs_read( EEP_HANDLE* pHndl, void *buffer, int size )

The active version is found from the pHndl structure. The data is read from the device using eep_read into the buffer.

void eepfs_write ( EEP_HANDLE *pHndl, void *buffer, int size )

Find the inactive version of the file, write the buffer to it. Set the bump the version number so the inactive version is now the active one.

Porting

In order to make the code simple and efficient, the code uses C structures to access the EEPROM. These should be packed. The Microsoft compiler, GCC, and IAR all support #pragma packed() to remove alignment bytes, and this is used.

All low level IO to the device goes through two functions. These need to be written for the hardware. Sample implementations are provided for a emulated EEPROM that reads and writes data to a ram buffer.

int eep_read ( int offset, void *buffer, int len )

Read from the EEPROM to a buffer

int eep_write ( int offset, void *buffer, int len )

Write to the EEPROM from the buffer

Legal Stuff

This code is (c) Ridgecrop Consultants Ltd 2005. This is proof of concept code, and we do not warranty that it is suitable for anything. By using this code, you agree not to patent any of the algorithms, which are in any case published. Ridgecrop have not done a patent search, and it is possible that this code may infringe on other algorithms. You also agree not to sue us for anything at all. In return for that, you can use our copyrighted code, change it and keep the changes to yourself.

Download

Download the source code for EEPFS here. This is a MSDEV file with EEPFS and a test harness.

W3Counter