Contiki 2.6

nvm.c

Go to the documentation of this file.
00001 /** @file hal/micro/cortexm3/nvm.c
00002  * @brief Cortex-M3 Non-Volatile Memory data storage system.
00003  *
00004  * This file implements the NVM data storage system.  Refer to nvm.h for
00005  * full documentation of how the NVM data storage system works, is configured,
00006  * and is accessed.
00007  *
00008  * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved.        -->
00009  */
00010 
00011 #include PLATFORM_HEADER
00012 #include "error.h"
00013 
00014 #ifdef NVM_RAM_EMULATION
00015 
00016 static int16u calibrationData[32+2]={
00017    0xFFFF, 0xFFFF,
00018    0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
00019    0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
00020    0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
00021    0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF, 0xFFFF,
00022 };
00023 
00024 int8u halCommonReadFromNvm(void *data, int32u offset, int16u length)
00025 {
00026  halCommonMemCopy(data, ((int8u *) calibrationData) + offset, length); 
00027   return ST_SUCCESS;
00028 }
00029 int8u halCommonWriteToNvm(const void *data, int32u offset, int16u length)
00030 {
00031   halCommonMemCopy(((int8u *) calibrationData) + offset, data, length);
00032   return ST_SUCCESS;
00033 }
00034 
00035 #else
00036 
00037 //flash.h gives access to halInternalFlashErase and halInternalFlashWrite.
00038 #include "hal/micro/cortexm3/flash.h"
00039 //nvm.h includes memmap.h.  These two headers define the key parameters:
00040 //  MFB_PAGE_SIZE_B
00041 //  MFB_TOP
00042 //  NVM_LEFT_PAGE
00043 //  NVM_RIGHT_PAGE
00044 //  NVM_DATA_SIZE_B
00045 //  NVM_FLASH_PAGE_COUNT
00046 //  NVM_MGMT_SIZE_B
00047 #include "hal/micro/cortexm3/nvm.h"
00048 
00049 //Define two variables that hold the actual NVM data storage.  LEFT and RIGHT
00050 //are not required to be continuous memory blocks so they can be define
00051 //separately.  The linker is responsible for placing these storage containers
00052 //on flash page boundaries.
00053 NO_STRIPPING __no_init VAR_AT_SEGMENT (const int8u nvmStorageLeft[NVM_DATA_SIZE_B], __NVM__);
00054 NO_STRIPPING __no_init VAR_AT_SEGMENT (const int8u nvmStorageRight[NVM_DATA_SIZE_B], __NVM__);
00055 
00056 static int8u determineState(void)
00057 {
00058   int32u leftMgmt = *(int32u *)NVM_LEFT_PAGE;
00059   int32u rightMgmt = *(int32u *)NVM_RIGHT_PAGE;
00060   int8u state=0;
00061   
00062   if((leftMgmt==0xFFFF0000) && (rightMgmt==0xFFFFFFFF)) {
00063     //State 1 and state 4 use identical mgmt words.  The function
00064     //determineState() is only called at the start of a NVM read
00065     //or write.  During a read, state 1 and 4 both read from the
00066     //LEFT so there is no reason to make a distinction.  During
00067     //a write, the system will see the current page as LEFT and
00068     //therefore be transitioning from LEFT to RIGHT so state 4 is
00069     //correct.  State 1 is only required to transition from 0 to 2.
00070     state = 4;
00071   } else if((leftMgmt==0xFFFF0000) && (rightMgmt==0xFF00FFFF)) {
00072     state = 2;
00073   } else if((leftMgmt==0xFFFF0000) && (rightMgmt==0xFF000000)) {
00074     state = 3;
00075   } else if((leftMgmt==0xFFFF0000) && (rightMgmt==0xFFFFFFFF)) {
00076     state = 4;
00077   } else if((leftMgmt==0xFFFF0000) && (rightMgmt==0xFFFFFF00)) {
00078     state = 5;
00079   } else if((leftMgmt==0xFF000000) && (rightMgmt==0xFFFFFF00)) {
00080     state = 6;
00081   } else if((leftMgmt==0xFF000000) && (rightMgmt==0xFFFF0000)) {
00082     state = 7;
00083   } else if((leftMgmt==0xFFFFFFFF) && (rightMgmt==0xFFFF0000)) {
00084     state = 8;
00085   } else if((leftMgmt==0xFFFFFF00) && (rightMgmt==0xFFFF0000)) {
00086     state = 9;
00087   } else if((leftMgmt==0xFFFFFF00) && (rightMgmt==0xFF000000)) {
00088     state = 10;
00089   } else {
00090     //State 0 is used to indicate erased or invalid.
00091     state = 0;
00092   }
00093   
00094   return state;
00095 }
00096 
00097 
00098 int8u halCommonReadFromNvm(void *data, int32u offset, int16u length)
00099 {
00100   int16u i;
00101   int16u *flash;
00102   //Remember: all flash writes are 16bits.
00103   int16u *ram = (int16u*)data;
00104   
00105   //The NVM data storage system cannot function if the LEFT and RIGHT
00106   //storage are not aligned to physical flash pages.
00107   assert((NVM_LEFT_PAGE%MFB_PAGE_SIZE_B)==0);
00108   assert((NVM_RIGHT_PAGE%MFB_PAGE_SIZE_B)==0);
00109   //The offset of the NVM data must be 16bit aligned.
00110   assert((offset&0x1)==0);
00111   //The length of the NVM data must be 16bit aligned.
00112   assert((length&0x1)==0);
00113   
00114   assert(offset+length<NVM_DATA_SIZE_B);
00115   
00116   //Obtain the data from NVM storage.
00117   switch(determineState()) {
00118     case 1:
00119     case 2:
00120     case 3:
00121     case 4:
00122     case 9:
00123     case 10:
00124       flash = (int16u *)(NVM_LEFT_PAGE+offset);
00125       for(i=0;i<(length/2);i++) {
00126         ram[i] = flash[i];
00127       }
00128     break;
00129     case 5:
00130     case 6:
00131     case 7:
00132     case 8:
00133       flash = (int16u *)(NVM_RIGHT_PAGE+offset);
00134       for(i=0;i<(length/2);i++) {
00135         ram[i] = flash[i];
00136       }
00137     break;
00138     case 0:
00139     default:
00140       //Reading from NVM while the mgmt bytes are in an invalid state
00141       //should not return any bytes actually found in flash.  Instead,
00142       //return nothing but 0xFF.  This is legitimate because the next
00143       //call to the write function will also find invalid mgmt bytes
00144       //and trigger an erasure of NVM, after which the NVM really will
00145       //contain just 0xFF for data (plus the new data supplied during
00146       //the write call).
00147       for(i=0;i<(length/2);i++) {
00148         ram[i] = 0xFFFF;
00149       }
00150     //Inform the calling code. using ST_ERR_FATAL, that there were
00151     //invalid mgmt bytes and 0xFF was forcefully returned.
00152     return ST_ERR_FATAL;
00153   }
00154   
00155   return ST_SUCCESS;
00156 }
00157 
00158 int16u *halCommonGetAddressFromNvm(int32u offset)
00159 {
00160   int16u *flash;
00161   
00162   //The NVM data storage system cannot function if the LEFT and RIGHT
00163   //storage are not aligned to physical flash pages.
00164   assert((NVM_LEFT_PAGE%MFB_PAGE_SIZE_B)==0);
00165   assert((NVM_RIGHT_PAGE%MFB_PAGE_SIZE_B)==0);
00166   //The offset of the NVM data must be 16bit aligned.
00167   assert((offset&0x1)==0);
00168   
00169   //Obtain the data from NVM storage.
00170   switch(determineState()) {
00171     case 1:
00172     case 2:
00173     case 3:
00174     case 4:
00175     case 9:
00176     case 10:
00177       flash = (int16u *)(NVM_LEFT_PAGE+offset);
00178     break;
00179     case 5:
00180     case 6:
00181     case 7:
00182     case 8:
00183       flash = (int16u *)(NVM_RIGHT_PAGE+offset);
00184     break;
00185     case 0:
00186     default:
00187       // Flash is in an invalid state 
00188       // Fix it with a dummy write and then return the flash page left
00189       {
00190         int16u dummy = 0xFFFF;
00191         halCommonWriteToNvm(&dummy, 0, 2);
00192         flash = (int16u *)(NVM_LEFT_PAGE+offset);
00193       }
00194   }
00195   
00196   return flash;
00197 }
00198 
00199 
00200 static int8u erasePage(int32u page)
00201 {
00202   StStatus status;
00203   int32u i, k;
00204   int32u address;
00205   int8u *flash;
00206   
00207   //Erasing a LEFT or RIGHT page requires erasing all of the flash pages.
00208   //Since the mgmt bytes are stored at the bottom of a page, the flash pages
00209   //are erased from the top down ensuring that that mgmt words are the last
00210   //data to be erased.  This way, if a reset occurs while erasing, the mgmt
00211   //words are still valid the next time determineState() is called.
00212   for(i=NVM_FLASH_PAGE_COUNT;i>0;i--) {
00213     address = (page+((i-1)*MFB_PAGE_SIZE_B));
00214     flash = (int8u *)address;
00215     //Scan the page to determine if it is fully erased already.
00216     //If the flash is not erased, erase it.  The purpose of scanning
00217     //first is to save a little time if erasing is not required.
00218     for(k=0;k<MFB_PAGE_SIZE_B;k++,flash++) {
00219       if(*flash != 0xFF) {
00220         status = halInternalFlashErase(MFB_PAGE_ERASE, address);
00221         if(status != ST_SUCCESS) {
00222           return status;
00223         }
00224         //Don't bother looking at the rest of this flash page and just
00225         //move to the next.
00226         k=MFB_PAGE_SIZE_B;
00227       }
00228     }
00229   }
00230   return ST_SUCCESS;
00231 }
00232 
00233 
00234 //This macro is responsible for erasing an NVM page (LEFT or RIGHT).
00235 #define ERASE_PAGE(page)          \
00236   do {                            \
00237     status = erasePage(page);     \
00238     if(status != ST_SUCCESS) { \
00239       return status;              \
00240     }                             \
00241   } while(0)
00242 
00243 
00244 //This macro is responsible for writing the new data into the destination
00245 //page and copying existing data from the source page to the
00246 //destination page.
00247 #define WRITE_DATA(destPage, srcPage, offset, length)                     \
00248   do {                                                                    \
00249     /*Copy all data below the new data from the srcPage to the destPage*/ \
00250     status = halInternalFlashWrite(destPage+NVM_MGMT_SIZE_B,              \
00251                                    (int16u *)(srcPage+NVM_MGMT_SIZE_B),   \
00252                                    (offset-NVM_MGMT_SIZE_B)/2);           \
00253     if(status != ST_SUCCESS) { return status; }                        \
00254     /*Write the new data*/                                                \
00255     status = halInternalFlashWrite(destPage+offset,                       \
00256                                    ram,                                   \
00257                                    (length)/2);                           \
00258     if(status != ST_SUCCESS) { return status; }                        \
00259     /*Copy all data above the new data from the srcPage to the destPage*/ \
00260     status = halInternalFlashWrite(destPage+offset+length,                \
00261                                    (int16u *)(srcPage+offset+length),     \
00262                                    (NVM_DATA_SIZE_B-                      \
00263                                     length-offset-                        \
00264                                     NVM_MGMT_SIZE_B)/2);                  \
00265     if(status != ST_SUCCESS) { return status; }                        \
00266   } while(0)
00267 
00268 //This macro is responsible for writing 16bits of management data to
00269 //the proper management address.
00270 #define WRITE_MGMT_16BITS(address, data)                  \
00271   do{                                                     \
00272     int16u value = data;                                  \
00273     status = halInternalFlashWrite((address), &value, 1); \
00274     if(status != ST_SUCCESS) {                         \
00275       return status;                                      \
00276     }                                                     \
00277   } while(0)
00278 
00279 
00280 int8u halCommonWriteToNvm(const void *data, int32u offset, int16u length)
00281 {
00282   StStatus status;
00283   int8u state, exitState;
00284   int32u srcPage;
00285   int32u destPage;
00286   //Remember: NVM data storage works on 16bit quantities.
00287   int16u *ram = (int16u*)data;
00288   
00289   //The NVM data storage system cannot function if the LEFT and RIGHT
00290   //storage are not aligned to physical flash pages.
00291   assert((NVM_LEFT_PAGE%MFB_PAGE_SIZE_B)==0);
00292   assert((NVM_RIGHT_PAGE%MFB_PAGE_SIZE_B)==0);
00293   //The offset of the NVM data must be 16bit aligned.
00294   assert((offset&0x1)==0);
00295   //The length of the NVM data must be 16bit aligned.
00296   assert((length&0x1)==0);
00297   //It is illegal to write to an offset outside of NVM storage.
00298   assert(offset+length<NVM_DATA_SIZE_B);
00299   
00300   
00301   state = determineState();
00302   
00303   switch(state) {
00304     case 1:
00305     case 2:
00306     case 3:
00307     case 4:
00308     case 9:
00309     case 10:
00310       srcPage = NVM_LEFT_PAGE;
00311       destPage = NVM_RIGHT_PAGE;
00312       exitState = 7;
00313     break;
00314     case 5:
00315     case 6:
00316     case 7:
00317     case 8:
00318       srcPage = NVM_RIGHT_PAGE;
00319       destPage = NVM_LEFT_PAGE;
00320       exitState = 3;
00321     break;
00322     case 0:
00323     default:
00324       //Invalid state.  Default to writing to the LEFT page.  Defaulting to
00325       //using RIGHT as the source page is valid since the RIGHT page
00326       //will also be erased and therefore produce 0xFF for data values.
00327       state = 0;
00328       srcPage = NVM_RIGHT_PAGE;
00329       destPage = NVM_LEFT_PAGE;
00330       exitState = 3;
00331     break;
00332   }
00333   
00334   //Advance the state machine.  Starting on state 3 requires state 7 to
00335   //exit and starting on state 7 requires state 3 to exit.  Starting on
00336   //any other state requires either 3 or 7 to exit.
00337   //NOTE:  Refer to nvm.h for a description of the states and how the
00338   //       state transitions correspond to erasing, writing data, and
00339   //       writing mgmt values.
00340   while(TRUE) {
00341     switch(state) {
00342       case 0:
00343         //State 0 is the only state where the source page needs to be erased.
00344         ERASE_PAGE(srcPage);
00345         ERASE_PAGE(destPage);
00346         WRITE_DATA(destPage, srcPage, offset, length);
00347         WRITE_MGMT_16BITS(NVM_LEFT_PAGE+0, 0x0000);
00348         state=1;
00349       break;
00350       case 1:
00351         WRITE_MGMT_16BITS(NVM_RIGHT_PAGE+2, 0xFF00);
00352         state=2;
00353       break;
00354       case 2:
00355         WRITE_MGMT_16BITS(NVM_RIGHT_PAGE+0, 0x0000);
00356         state=3;
00357       break;
00358       case 3:
00359         if(exitState==3) {
00360           return ST_SUCCESS;
00361         }
00362         ERASE_PAGE(destPage);
00363         state=4;
00364       break;
00365       case 4:
00366         WRITE_DATA(destPage, srcPage, offset, length);
00367         WRITE_MGMT_16BITS(NVM_RIGHT_PAGE+0, 0xFF00);
00368         state=5;
00369       break;
00370       case 5:
00371         WRITE_MGMT_16BITS(NVM_LEFT_PAGE+2, 0xFF00);
00372         state=6;
00373       break;
00374       case 6:
00375         WRITE_MGMT_16BITS(NVM_RIGHT_PAGE+0, 0x0000);
00376         state=7;
00377       break;
00378       case 7:
00379         if(exitState==7) {
00380           return ST_SUCCESS;
00381         }
00382         ERASE_PAGE(destPage);
00383         state=8;
00384       break;
00385       case 8:
00386         WRITE_DATA(destPage, srcPage, offset, length);
00387         WRITE_MGMT_16BITS(NVM_LEFT_PAGE+0, 0xFF00);
00388         state=9;
00389       break;
00390       case 9:
00391         WRITE_MGMT_16BITS(NVM_RIGHT_PAGE+2, 0xFF00);
00392         state=10;
00393       break;
00394       case 10:
00395         WRITE_MGMT_16BITS(NVM_LEFT_PAGE+0, 0x0000);
00396         state=3;
00397       break;
00398     }
00399   }
00400 }
00401 
00402 #endif // NVM_RAM_EMULATION