Contiki 2.6
|
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