Contiki 2.6

nvm.h

Go to the documentation of this file.
00001 /** @file hal/micro/cortexm3/nvm.h
00002  * @brief Cortex-M3 Non-Volatile Memory data storage system.
00003  * See @ref nvm for documentation.
00004  *
00005  * The functions in this file return an ::StStatus value. 
00006  * See error-def.h for definitions of all ::StStatus return values.
00007  *
00008  * See hal/micro/cortexm3/nvm.h for source code.
00009  *
00010  * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved.        -->
00011  */
00012  
00013 /** @addtogroup nvm
00014  * @brief Cortex-M3 Non-Volatile Memory data storage system.
00015  *
00016  * This header defines the API for NVM data storage.  This header also
00017  * describes the algorithm behind the NVM data storage system with notes
00018  * on algorithm behavior.
00019  *
00020  * See hal/micro/cortexm3/nvm.h for source code.
00021  *
00022  * @note The algorithm description uses "page" to indicate an area of memory
00023  *       that is a multiple of physical flash pages.  There are two pages: LEFT
00024  *       and RIGHT.  The term "flash page" is used to refer to a page of
00025  *       physical flash.
00026  * 
00027  * NVM data storage works by alternating between two pages: LEFT and RIGHT.
00028  * The basic algorithm is driven by a call to halCommonSaveToNvm().  It will:
00029  * - erase the inactive page
00030  * - write the new data to the inactive page
00031  * - copy existing data from the active page to the inactive page
00032  * - mark the inactive page as the new active page
00033  * - mark the old active page as the new inactive page
00034  * To accomplish alternating between two pages and knowing which page has the
00035  * valid set of data, the algorithm uses 4 bytes of mgmt data that exists
00036  * at the top of both LEFT and RIGHT (the term "mgmt" is shorthand referring to
00037  * the management data).  The management data is comprised of a Valid marker,
00038  * an Active marker, a Dead marker, and a Spare byte.  Viewing the
00039  * management data as a single 32 bit quantity yields:
00040  * - Valid is mgmt[0]
00041  * - Active is mgmt[1]
00042  * - Dead is mgmt[2]
00043  * - Spare is mgmt[3]
00044  * The algorithm is based on a simple, circular state machine.  The following
00045  * discussion details all of the possible mgmt bytes and the states they
00046  * correspond to.  The "Reads from" line indicates which page a call to
00047  * halCommonReadFromNvm() will read from (an 'x' page will stuff the read
00048  * data with 0xFF).  The vertical "erase" and "write" words indicate the
00049  * flash altering actions taken between those states.  Invalid mgmt bytes
00050  * is equivalent to erased mgmt bytes (state 0) and will trigger an
00051  * erase of both LEFT and RIGHT.  State 3 and state 7 are the only exit
00052  * states.  When the algorithm is run, regardless of starting state, it
00053  * will advance to the next exit state.  This means if the "Read from"
00054  * is LEFT then the state machine will advance until state 7 and then exit.
00055  * If "Read from" is RIGHT, then the state machine will advance until
00056  * state 3 and then exit.
00057  * 
00058  * @code
00059  * Starting from erased or invalid mgmt, write to LEFT
00060  * State #       0     0         1      2      3  
00061  * Reads from:   x     x   e w   L      L      L  
00062  * Valid       xx|xx FF|FF r r 00|FF  00|FF  00|00
00063  * Active      xx|xx FF|FF a i 00|FF  00|FF  00|00
00064  * Dead        xx|xx FF|FF s t FF|FF  FF|00  FF|00
00065  * Spare       xx|xx FF|FF e e FF|FF  FF|FF  FF|FF
00066  * 
00067  * 
00068  * Starting from LEFT page, transition to RIGHT page:
00069  * State #      3       4       5      6      7  
00070  * Reads from:  L   e   L   w   R      R      R  
00071  * Valid      00|00 r 00|FF r 00|00  00|00  00|00
00072  * Active     00|00 a 00|FF i 00|FF  00|FF  00|00
00073  * Dead       FF|00 s FF|FF t FF|FF  00|FF  00|FF
00074  * Spare      FF|FF e FF|FF e FF|FF  FF|FF  FF|FF
00075  * 
00076  * 
00077  * Starting from RIGHT page, transition to LEFT page:
00078  * State #      7       8       9     10      3  
00079  * Reads from:  R   e   R   w   L      L      L  
00080  * Valid      00|00 r FF|00 r 00|00  00|00  00|00
00081  * Active     00|00 a FF|00 i FF|00  FF|00  00|00
00082  * Dead       00|FF s FF|FF t FF|FF  FF|00  FF|00
00083  * Spare      FF|FF e FF|FF e FF|FF  FF|FF  FF|FF
00084  * @endcode
00085  * 
00086  * Based on the 10 possible states, there are 5 valid 32bit mgmt words:
00087  * - 0xFFFFFFFF
00088  * - 0xFFFFFF00
00089  * - 0xFFFF0000
00090  * - 0xFF000000
00091  * - 0xFF00FFFF
00092  * The algorithm determines the current state by using these 5 mgmt words
00093  * with the 10 possible combinations of LEFT mgmt and RIGHT mgmt.
00094  * 
00095  * Detailed State Description:
00096  * - State 0:
00097  *   In this state the mgmt bytes do not conform to any of the other states
00098  *   and therefore the entire NVM system, both the LEFT and RIGHT, is
00099  *   invalid.  Invalid could be as simple as both LEFT and RIGHT are erased
00100  *   or as complex as serious memory corruption or a bug caused bad data to
00101  *   be written to the NVM.  By using a small set of very strict, precise,
00102  *   valid states (versus other management systems such as a simple counter),
00103  *   the algorithm/data gains some protection against not only corruption, but
00104  *   also executing the NVM algorithm on a chip that previously did not
00105  *   have the NVM system running on it.
00106  * - State 1, 4, 8
00107  *   In these states, mgmt is saying that one page is valid and active, while
00108  *   the other page is erased.  This tells the algorithm which page to read
00109  *   from and indicates that the other page has already been erased.
00110  * - State 2
00111  *   This state is only necessary for transitioning from state 0.  From state
00112  *   0, the goal is to arrive at state 3.  Ideally, the RIGHT mgmt would
00113  *   be written with 0xFF000000, but the flash library only permits 16 bit
00114  *   writes.  If a reset were to occur in the middle of this section of the
00115  *   algorithm, we want to ensure that the mgmt is left in a known state,
00116  *   state 2, so that the algorithm could continue from where it got
00117  *   interrupted.
00118  * - State 5, 9
00119  *   These states indicate that the other page has just become valid because
00120  *   the new data has just been written.  Once at these states, reading
00121  *   from the NVM will now pull data from the other page.
00122  * - State 6, 10
00123  *   These states indicate that the old page is now dead and not in use.
00124  *   While the algorithm already knows to read from the new page, the Dead
00125  *   mgmt byte is primarily used to indicate that the other page needs to
00126  *   be erased.  Conceptually, the Dead byte can also be considered a type
00127  *   of "garbage collection" flag indicating the old page needs to be
00128  *   destroyed and has not yet been erased.
00129  * - State 3, 7
00130  *   These states are the final exit points of the circular state machine.
00131  *   Once at these states, the current page is marked Valid and Active and
00132  *   the old page is marked as Dead.  The algorithm knows which page to
00133  *   read from and which page needs to be erased on the next write to the NVM.
00134  *   
00135  * 
00136  * Notes on algorithm behavior:
00137  * - Refer to nvm-def.h for a list of offset/length that define the data
00138  *   stored in NVM storage space.
00139  * - All writes to flash are 16bit granularity and therefore the internal
00140  *   flash writes cast the data to int16u.  Length is also required to be
00141  *   a multiple of 16bits.
00142  * - Flash page erase uses a granularity of a single flash page.  The size
00143  *   of a flash page depends on the chip and is defined in memmap.h with
00144  *   the define MFB_PAGE_SIZE_B.
00145  * - Erasing will only occur when halCommonSaveToNvm() is called.
00146  * - Erasing will always occur when halCommonSaveToNvm() is called unless the
00147  *   page intended to be erased is already entirely 0xFFFF.
00148  * - When reading and management is invalid, the read will return 0xFF for data.
00149  * - Calling halCommonSaveToNvm() while in any state is always valid and the
00150  *   new data will be written to flash.
00151  * - halCommonSaveToNvm() will always advance the state machine to 3 or 7.
00152  * - When writing and management is invalid, both LEFT and RIGHT will be erased
00153  *   and the new data will be written to LEFT.
00154  * - Writing causes the new data being passed into halCommonSaveToNvm() to be
00155  *   written to flash.  The data already existing in the currently valid page
00156  *   will be copied over to the new page.
00157  * - Reading or writing to an offset equal to or greater than NVM_DATA_SIZE_B is
00158  *   illegal and will cause an assert.
00159  * - Offset and length must always be multiples of 16bits.  If not, both a read
00160  *   and a write will trigger an assert.
00161  * - Offset and length must be supplied in bytes.
00162  * - All data in NVM storage must exist above the mgmt bytes, denoted by
00163  *   NVM_MGMT_SIZE_B.
00164  * - The bottom 64 bytes of NVM storage are allocated to radio calibration
00165  *   values.  These 64 bytes *must* exist for the radio to function.
00166  * - There is no error checking beyond checking for 16bit alignment.  This
00167  *   means it is possible to use data offset and size combinations that
00168  *   exceed NVM storage space or overlap with other data.  Be careful!
00169  *@{
00170  */
00171 
00172 
00173 #ifndef __NVM_H__
00174 #define __NVM_H__
00175 
00176 //Pull in the MFB_ definitions.
00177 #include "hal/micro/cortexm3/memmap.h"
00178 //Pull in nvm-def.h so any code including nvm.h has access to the
00179 //offsets and sizes defining the NVM data.
00180 #include "hal/micro/cortexm3/nvm-def.h"
00181 //Necessary to define StStatus and codes.
00182 #include "error.h"
00183 
00184 
00185 /**
00186  * @brief Copy the NVM data from flash into the provided RAM location.
00187  * It is illegal for the offset to be greater than NVM_DATA_SIZE_B.
00188  * 
00189  * @param data    A (RAM) pointer to where the data should be copied.
00190  *  
00191  * @param offset  The location from which the data should be copied.  Must be
00192  *                16bit aligned.
00193  * 
00194  * @param length  The length of the data in bytes.  Must be 16bit aligned.
00195  * 
00196  * @return An StStatus value indicating the success of the function.
00197  *  - ST_SUCCESS if the read completed cleanly.
00198  *  - ST_ERR_FATAL if the NVM storage management indicated an invalid
00199  *    state.  The function will return entirely 0xFF in the data parameter.
00200  */
00201 StStatus halCommonReadFromNvm(void *data, int32u offset, int16u length);
00202 
00203 /**
00204  * @brief Return the address of the token in NVM
00205  * 
00206  * @param offset  The location offset from which the address should be returned
00207  * 
00208  * 
00209  * @return The address requested
00210  */
00211 int16u *halCommonGetAddressFromNvm(int32u offset);
00212 
00213 /**
00214  * @brief Write the NVM data from the provided location RAM into flash.
00215  * It is illegal for the offset to be greater than NVM_DATA_SIZE_B.
00216  * 
00217  * @param data    A (RAM) pointer from where the data should be taken.
00218  *  
00219  * @param offset  The location to which the data should be written.  Must be
00220  *                16bit aligned.
00221  * 
00222  * @param length  The length of the data in bytes.  Must be 16bit aligned.
00223  * 
00224  * @return An StStatus value indicating the success of the function.
00225  *  - ST_SUCCESS if the write completed cleanly.
00226  *  - Any other status value is an error code generated by the low level
00227  *    flash erase and write API.  Refer to flash.h for details.
00228  */
00229 StStatus halCommonWriteToNvm(const void *data, int32u offset, int16u length);
00230 
00231 /**
00232  * @brief Define the number of physical flash pages that comprise a NVM page.
00233  * Since NVM_DATA_SIZE_B must be a multiple of MFB_PAGE_SIZE_B, increasing the
00234  * size of NVM storage should be done by modifying this define.
00235  *
00236  * @note The total flash area consumed by NVM storage is double this value.
00237  * This is due to the fact that there are two NVM pages, LEFT and RIGHT,
00238  * which the algorithm alternates between.
00239  */
00240 #define NVM_FLASH_PAGE_COUNT  (1)
00241 
00242 /**
00243  * @brief Define the total size of a NVM page, in bytes.  This must be a
00244  * multiple of the memory map define MFB_PAGE_SIZE_B.  Note that 4 bytes of
00245  * the total size of an NVM page are dedicated to page management.
00246  *
00247  * @note <b>DO NOT EDIT THIS DEFINE.  Instead, edit NVM_FLASH_PAGE_COUNT.</b>
00248  */
00249 #define NVM_DATA_SIZE_B  (MFB_PAGE_SIZE_B*NVM_FLASH_PAGE_COUNT)
00250 #if ((NVM_DATA_SIZE_B%MFB_PAGE_SIZE_B) != 0)
00251   #error Illegal NVM data storage size.  NVM_DATA_SIZE_B must be a multiple of MFB_PAGE_SIZE_B.
00252 #endif
00253 
00254 /**
00255  * @brief Define the absolute address of the LEFT page.  LEFT page storage
00256  * is defined by nvmStorageLeft[NVM_DATA_SIZE_B] and placed by the linker
00257  * using the segment "NVM".
00258  */
00259 #define NVM_LEFT_PAGE   ((int32u)nvmStorageLeft)
00260 
00261 /**
00262  * @brief Define the absolute address of the RIGHT page.  RIGHT page storage
00263  * is defined by nvmStorageRight[NVM_DATA_SIZE_B] and placed by the linker
00264  * using the segment "NVM".
00265  */
00266 #define NVM_RIGHT_PAGE  ((int32u)nvmStorageRight)
00267 
00268 /**
00269  * @brief Define the number of bytes that comprise the NVM management bytes.
00270  * All data must begin at an offset above the management bytes.
00271  *
00272  * @note This value <b>must not change</b>.
00273  */
00274 #define NVM_MGMT_SIZE_B  (4)
00275 
00276 /** @} END addtogroup */
00277 
00278 #endif // __NVM_H__
00279