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