Back to ESAcademy Home Page


www.philipsmcu.comUsing Flash Memory in Embedded Applications

By Olaf Pfeiffer and Andy Ayre

[ Introduction | ISP vs IAP | Self-Recovery | Storing Variables | Flash Life-Time | Summary ]

 

Home

News

Training Classes

Products

Consulting

Technical Library

Contact Us

Recommended Books

Storing Variables in Flash

Many applications require variables whose content does not change after a power-down. One common implementation is the configuration of consumer electronics: for example a radio remembering the last used station, volume and other tone settings. In many applications, this kind of information is stored in EEPROMs.

However, assuming we have Flash memory in our application anyway, isn't there a way of easily storing this information in Flash?

Well, define "easy"… - just be aware of some of the limitations!

Flash erase cycles are long - really long - it can take several seconds to erase a Flash sector. Also as the number of guaranteed erase / re-write cycles is usually limited (typically around 10,000 or up to 100,000), we cannot afford to erase an entire sector just because one variable changed.

The approach is to "sacrifice" an entire sector for variable storage. In this sector, variables are stored in a table. If a variable changes, it does not get overwritten, instead the old value is discarded and a new entry into the table gets generated.

To speed up variable access, the application code will typically work with pointers. If you have a pointer to the variable, read access is very simple (just read from the location the pointer points to). A write access takes a little more: it would involve things like

  1. Generating a new entry at the end of the table
  2. Marking it as "current"
  3. Marking the old table entry as "expired"
  4. Returning a pointer to the new location of the variable

After a power-down / power-up cycle, the entries in the table need to provide enough information for an initializing routine to locate all current variables in that table.

One of the additional challenges of such a table-based implementation is the so-called "garbage collection". This is the process of cleaning up and re-initializing the table. Once the table is full, all current variables would need to be saved, the table / sector erased and the variables written back to the table.

As this process involves erasing an entire sector and parsing through a full-table, it can take several seconds to complete. In order to avoid any delays during regular operation, a system using Flash variables needs to plan ahead and execute the garbage collection before the end of the table is reached (for example as part of the boot-up or shut-down procedures).

Another challenge is a fail-safe implementation. For a fail-safe system, recovery needs to be possible, even if a system crashes or loses power while performing a garbage collection. This can only be implemented, if two Flash sectors are used. The garbage collection would proceed as follows:

  1. Erase the currently unused sector
  2. Move all current variables to the new sector
  3. Mark the new sector as "current" and the old one as "expired"
    (for example by making the first byte a special status byte)

After a power-down and power-up cycle, the table initialization routine would check the status byte of each Flash sector to determine which of the two sectors is the current one and then start to extract the current variables from that table.

If, however, a power failure or reset occurs between marking the new sector as current and the old sector as expired, then after a power-up there would appear to be two current Flash sectors. The solution is to identify which sector contains the smaller table and is therefore the "real" current sector. The other sector can then be marked as expired.

To recognize variables themselves and whether they are "current" or "expired", each table entry requires several status bits or bytes. Assuming the variables can be of different length, the following information needs to be stored with each table entry:

  • An identifier for the variable (for example this is variable "volume", "balance" or "tone")
  • Is this table entry "current" or "expired"
  • Variable length in number of bytes (assuming the length of the variables can vary)
  • The variable contents itself

At first glance, a "current" or "expired" entry seems to be unnecessary - the initialization-variable-recovery routine could simply assume the last entry in the table as the "current" one. However, if the system failed while writing the last entry, then that should not be used at all. That's why it is important to not mark a new entry as current, unless all data bytes of that variable have been successfully programmed into the Flash memory.

To show in more detail how such a table works, the Embedded Systems Academy provides a C library with such an implementation. It allows reading and writing variables that are stored in Flash. For details, check ESAcademy's technical library at www.esacademy.com/faq/progs.

The library provides functions to store values, obtain a pointer to a value (necessary for fast and frequent accesses), determine when the table is full and a function to perform garbage collection, using fail-safe methods. The following is a short example of the start of an application using the library.


#include "rx2fvlib.h"                        // include library 
                                             // header file
void main(void)
{
  unsigned char code *flashbyte_ptr;         // pointer to flash 
                                             // variable w. status info

  fv_init(16, BLOCK_0x2000_0x3FFF,           // initialize the Flash 
              BLOCK_0x4000_0x7FFF);          // Variables library

  garbage_collector();                       // clean up the table

  flashbyte_ptr = fv_read_byte(flashbyte);   // obtain pointer to the 
                                             // flash variable 
                                             // flashbyte
  if (flashbyte_ptr == NULL)                 // if the pointer is null 
  {                                          // then the variable does
                                             // not exist

    fv_write_byte(0xAA, flashbyte);          // store default initial 
                                             // value

    flashbyte_ptr = fv_read_byte(flashbyte); // obtain pointer to
                                             // flash variable
  }

  switch(*flashbyte_ptr)                     // read status variable
  {                                          // to recover system   

[ Introduction | ISP vs IAP | Self-Recovery | Storing Variables | Flash Life-Time | Summary ]
Copyright (c) 2000 by Olaf Pfeiffer and Andy Ayre

ESAcademy, 2000

All materials
provided 'as is'
see Disclaimer

www.esacademy.com
info@esacademy.com