Contiki 2.6
|
00001 /** @file hal/micro/cortexm3/flash.c 00002 * @brief Implements the generic flash manipulation routines. 00003 * 00004 * The file 'flash-sw-spec.txt' should provide *all* the information needed 00005 * to understand and work with the FLITF and flash. 00006 * 00007 * 00008 * <!--(C) COPYRIGHT 2010 STMicroelectronics. All rights reserved. --> 00009 */ 00010 00011 #include PLATFORM_HEADER 00012 #include "error.h" 00013 #include "hal/micro/cortexm3/bootloader/fib-bootloader.h" 00014 #include "hal/micro/cortexm3/mpu.h" 00015 #include "memmap.h" 00016 #include "flash.h" 00017 00018 #ifdef FLASH_PROGRAMMING_WITH_EMPTY_FIB 00019 #define ST_EMU_TEST 00020 #endif 00021 // A translation table used to convert FibStatus codes to corresponding 00022 // StStatus values 00023 static const StStatus fibToStStatus[] = { 00024 ST_SUCCESS, // FIB_SUCCESS 0 00025 ST_BAD_ARGUMENT, // FIB_ERR_UNALIGNED 1 00026 ST_BAD_ARGUMENT, // FIB_ERR_INVALID_ADDRESS 2 00027 ST_BAD_ARGUMENT, // FIB_ERR_INVALID_TYPE 3 00028 ST_ERR_FLASH_PROG_FAIL, // FIB_ERR_WRITE_PROTECTED 4 00029 ST_ERR_FLASH_PROG_FAIL, // FIB_ERR_WRITE_FAILED 5 00030 ST_ERR_FLASH_WRITE_INHIBITED, // FIB_ERR_ERASE_REQUIRED 6 00031 ST_ERR_FLASH_VERIFY_FAILED // FIB_ERR_VERIFY_FAILED 7 00032 }; 00033 00034 //The purpose of flashEraseIsActive and halFlashEraseIsActive() is so that 00035 //interrupts can query the flash library to find out of Flash Erase is 00036 //active when their ISR gets invoked. This is useful because Flash Erase 00037 //causes the chip to go ATOMIC for 21ms and this delay will disrupt interrupt 00038 //latency. By having a sinple API that an ISR can query for this state, 00039 //the ISR can appriopriately adjust for a 21ms latency time. 00040 boolean flashEraseIsActive = FALSE; 00041 boolean halFlashEraseIsActive(void) 00042 { 00043 return flashEraseIsActive; 00044 } 00045 00046 00047 // Emulators do not have FIB bootloaders, so need to include a copy of 00048 // these core flash routines. 00049 00050 #if defined(ST_EMU_TEST) 00051 00052 static void enableFlitf(void) 00053 { 00054 //First, unlock the FLITF by writing the two key values to the Flash 00055 //Protection Unlock register 00056 FPEC_KEY = FPEC_KEY1; 00057 FPEC_KEY = FPEC_KEY2; 00058 00059 //Second, unlock the CIB by writing the two key values to the CIB 00060 //Protection Unlock register 00061 OPT_KEY = FPEC_KEY1; 00062 OPT_KEY = FPEC_KEY2; 00063 00064 //Turn on the FPEC clock for flash manipulation operations 00065 FPEC_CLKREQ = FPEC_CLKREQ_FIELD; 00066 00067 //make sure the FPEC clock is running before we proceed 00068 while( (FPEC_CLKSTAT&FPEC_CLKACK) != FPEC_CLKACK) {} 00069 00070 //just in case, wait until the flash is no longer busy 00071 while( (FLASH_STATUS&FLASH_STATUS_FLA_BSY) == FLASH_STATUS_FLA_BSY ) {} 00072 } 00073 00074 static void disableFlitf(void) 00075 { 00076 //make sure the FPEC is completely idle before turning off the clock 00077 while( (FPEC_CLKSTAT&FPEC_CLKBSY) == FPEC_CLKBSY) {} 00078 00079 //Turn off the FPEC clock now that we're done 00080 FPEC_CLKREQ = FPEC_CLKREQ_RESET; 00081 00082 //Set LOCK and clear OPTWREN to lock both the FLITF and the CIB. 00083 //NOTE: The PROG bit must also be cleared otherwise Flash can still 00084 // be programmed even with the LOCK bit set. BugzID: 6267 00085 FLASH_CTRL = FLASH_CTRL_LOCK; //lock the flash from further accesses 00086 } 00087 00088 static FibStatus fibFlashWrite(int32u address, int8u *data, int32u length, int32u dummy) 00089 { 00090 int32u i; 00091 int16u *ptr; 00092 FibStatus status = FIB_SUCCESS; 00093 // Address and length must be half-word aligned. 00094 if ((address & 1) || (length & 1)) { 00095 return FIB_ERR_UNALIGNED; 00096 } 00097 // Start and end address must be in MFB or CIB. 00098 if (!((address >= MFB_BOTTOM && address + length <= MFB_TOP + 1) 00099 || (address >= CIB_BOTTOM && address + length <= CIB_TOP + 1))) { 00100 return FIB_ERR_INVALID_ADDRESS; 00101 } 00102 enableFlitf(); 00103 ptr = (int16u *)address; 00104 for (i = 0; i < length; i += 2) { 00105 int16u currentData = *ptr; 00106 int16u newData = HIGH_LOW_TO_INT(data[i + 1], data[i]); 00107 // Only program the data if it makes sense to do so. 00108 if (currentData == newData) { 00109 // If the new data matches the flash, don't bother doing anything. 00110 } else if (currentData == 0xFFFF || newData == 0x0000) { 00111 // If the flash is 0xFFFF we're allowed to write anything. 00112 // If the new data is 0x0000 it doesn't matter what the flash is. 00113 // OPTWREN must stay set to keep CIB unlocked. 00114 if ((CIB_OB_BOTTOM <= (int32u)ptr) && ((int32u)ptr <= CIB_OB_TOP)) { 00115 FLASH_CTRL = (FLASH_CTRL_OPTWREN | FLASH_CTRL_OPTPROG); 00116 } else { 00117 FLASH_CTRL = (FLASH_CTRL_OPTWREN | FLASH_CTRL_PROG); 00118 } 00119 // Assigning data to the address performs the actual write. 00120 (*ptr) = newData; 00121 // Wait for the busy bit to clear, indicating operation is done. 00122 while ((FLASH_STATUS & FLASH_STATUS_FLA_BSY) != 0) {} 00123 // Reset the operation complete flag. 00124 FLASH_STATUS = FLASH_STATUS_EOP; 00125 // Check if any error bits have been tripped, and if so, exit. 00126 // The bit PAGE_PROG_ERR is not relevant in this programming mode. 00127 if (FLASH_STATUS & (FLASH_STATUS_WRP_ERR | FLASH_STATUS_PROG_ERR)) { 00128 if (FLASH_STATUS & FLASH_STATUS_WRP_ERR) { 00129 status = FIB_ERR_WRITE_PROTECTED; 00130 } else { 00131 status = FIB_ERR_WRITE_FAILED; 00132 } 00133 FLASH_STATUS = FLASH_STATUS_WRP_ERR; 00134 FLASH_STATUS = FLASH_STATUS_PROG_ERR; 00135 break; 00136 } 00137 } else { 00138 status = FIB_ERR_ERASE_REQUIRED; 00139 break; 00140 } 00141 ptr++; 00142 } 00143 disableFlitf(); 00144 return status; 00145 } 00146 00147 static FibStatus fibFlashWriteVerify(int32u address, int8u *data, int32u length) 00148 { 00149 int32u i; 00150 int8u *ptr = (int8u *)address; 00151 for (i = 0; i < length; i++) { 00152 if (*ptr != data[i]) { 00153 return FIB_ERR_VERIFY_FAILED; 00154 } 00155 ptr++; 00156 } 00157 return FIB_SUCCESS; 00158 } 00159 00160 static FibStatus fibFlashErase(FibEraseType eraseType, int32u address) 00161 { 00162 int32u eraseOp; 00163 int32u *ptr; 00164 int32u length; 00165 FibStatus status = FIB_SUCCESS; 00166 if (BYTE_0(eraseType) == MFB_MASS_ERASE) { 00167 eraseOp = FLASH_CTRL_MASSERASE; 00168 ptr = (int32u *)MFB_BOTTOM; 00169 length = MFB_SIZE_W; 00170 } else if (BYTE_0(eraseType) == MFB_PAGE_ERASE) { 00171 if (address < MFB_BOTTOM || address > MFB_TOP) { 00172 return FIB_ERR_INVALID_ADDRESS; 00173 } 00174 eraseOp = FLASH_CTRL_PAGEERASE; 00175 ptr = (int32u *)(address & MFB_PAGE_MASK_B); 00176 length = MFB_PAGE_SIZE_W; 00177 } else if (BYTE_0(eraseType) == CIB_ERASE) { 00178 eraseOp = FLASH_CTRL_OPTWREN | FLASH_CTRL_OPTERASE; 00179 ptr = (int32u *)CIB_BOTTOM; 00180 length = CIB_SIZE_W; 00181 } else { 00182 return FIB_ERR_INVALID_TYPE; 00183 } 00184 if ((eraseType & DO_ERASE) != 0) { 00185 enableFlitf(); 00186 FLASH_CTRL = eraseOp; 00187 if (BYTE_0(eraseType) == MFB_PAGE_ERASE) { 00188 FLASH_ADDR = (address & MFB_PAGE_MASK_B); 00189 } 00190 eraseOp |= FLASH_CTRL_FLA_START; 00191 // Perform the actual erase. 00192 FLASH_CTRL = eraseOp; 00193 // Wait for the busy bit to clear, indicating operation is done. 00194 while ((FLASH_STATUS & FLASH_STATUS_FLA_BSY) != 0) {} 00195 // Reset the operation complete flag. 00196 FLASH_STATUS = FLASH_STATUS_EOP; 00197 // Check for errors; the only relevant one for erasing is write protection. 00198 if (FLASH_STATUS & FLASH_STATUS_WRP_ERR) { 00199 FLASH_STATUS = FLASH_STATUS_WRP_ERR; 00200 status = FIB_ERR_WRITE_PROTECTED; 00201 } 00202 disableFlitf(); 00203 } 00204 if (status == FIB_SUCCESS 00205 && (eraseType & DO_VERIFY) != 0) { 00206 int32u i; 00207 for (i = 0; i < length; i++) { 00208 if (*ptr != 0xFFFFFFFF) { 00209 return FIB_ERR_VERIFY_FAILED; 00210 } 00211 ptr++; 00212 } 00213 } 00214 return status; 00215 } 00216 #endif // ST_EMU_TEST 00217 00218 static boolean verifyFib(void) 00219 { 00220 // Ensure that a programmed FIB of a proper version is present 00221 return ( (halFixedAddressTable.baseTable.type == FIXED_ADDRESS_TABLE_TYPE) && 00222 ( ( (halFixedAddressTable.baseTable.version & FAT_MAJOR_VERSION_MASK) 00223 == 0x0000 ) && 00224 (halFixedAddressTable.baseTable.version >= 0x0002) 00225 ) 00226 ); 00227 } 00228 00229 //The parameter 'eraseType' chooses which erasure will be performed while 00230 //the 'address' parameter chooses the page to be erased during MFB page erase. 00231 StStatus halInternalFlashErase(int8u eraseType, int32u address) 00232 { 00233 FibStatus status; 00234 00235 ATOMIC( 00236 BYPASS_MPU( 00237 flashEraseIsActive = TRUE; 00238 #if defined(ST_EMU_TEST) 00239 // Always try to use the FIB bootloader if its present 00240 if(verifyFib()) { 00241 status = halFixedAddressTable.fibFlashErase( 00242 (((int32u)eraseType) | DO_ERASE), 00243 address); 00244 } else { 00245 status = fibFlashErase((((int32u)eraseType) | DO_ERASE), address); 00246 } 00247 #else 00248 00249 00250 00251 assert(verifyFib()); 00252 status = halFixedAddressTable.fibFlashErase( 00253 (((int32u)eraseType) | DO_ERASE), 00254 address); 00255 #endif 00256 ) 00257 ) 00258 //If there are any interrupts pending that could have been delayed for 21ms, 00259 //they will be serviced here since we exit the ATOMIC block. These ISRs 00260 //can query the flash library and find out that erasing is active. After 00261 //this point, we're no longer ATOMIC/disrupting latency so our erase 00262 //active flag should be cleared. 00263 flashEraseIsActive = FALSE; 00264 00265 if(status!=FIB_SUCCESS) { 00266 return fibToStStatus[status]; 00267 } 00268 00269 #if defined(ST_EMU_TEST) 00270 // Always try to use the FIB bootloader if its present 00271 if(verifyFib()) { 00272 status = halFixedAddressTable.fibFlashErase( 00273 (((int32u)eraseType) | DO_VERIFY), 00274 address); 00275 } else { 00276 status = fibFlashErase((((int32u)eraseType) | DO_VERIFY), address); 00277 } 00278 #else 00279 status = halFixedAddressTable.fibFlashErase( 00280 (((int32u)eraseType) | DO_VERIFY), 00281 address); 00282 #endif 00283 return fibToStStatus[status]; 00284 } 00285 00286 00287 //The parameter 'address' defines the starting address of where the 00288 //programming will occur - this parameter MUST be half-word aligned since all 00289 //programming operations are HW. The parameter 'data' is a pointer to a buffer 00290 //containin the 16bit half-words to be written. Length is the number of 16bit 00291 //half-words contained in 'data' to be written to flash. 00292 //NOTE: This function can NOT write the option bytes and will throw an error 00293 //if that is attempted. 00294 StStatus halInternalFlashWrite(int32u address, int16u * data, int32u length) 00295 { 00296 FibStatus status; 00297 00298 length = length * 2; // fib routines specify length in bytes 00299 00300 ATOMIC( 00301 BYPASS_MPU( 00302 #if defined(ST_EMU_TEST) 00303 // Always try to use the FIB bootloader if its present 00304 if(verifyFib()) { 00305 status = halFixedAddressTable.fibFlashWrite(address, 00306 (int8u *)data, 00307 length, 00308 0); 00309 } else { 00310 status = fibFlashWrite(address, (int8u *)data, length, 0); 00311 } 00312 #else 00313 00314 00315 00316 // Ensure that a programmed FIB of a proper version is present 00317 assert(verifyFib()); 00318 status = halFixedAddressTable.fibFlashWrite(address, 00319 (int8u *)data, 00320 length, 00321 0); 00322 #endif 00323 ) 00324 ) 00325 00326 if(status!=FIB_SUCCESS) { 00327 return fibToStStatus[status]; 00328 } 00329 00330 #if defined(ST_EMU_TEST) 00331 // Always try to use the FIB bootloader if its present 00332 if(verifyFib()) { 00333 status = halFixedAddressTable.fibFlashWrite(address, 00334 (int8u *)data, 00335 0, 00336 length); 00337 } else { 00338 status = fibFlashWriteVerify(address, (int8u *)data, length); 00339 } 00340 #else 00341 status = halFixedAddressTable.fibFlashWrite(address, 00342 (int8u *)data, 00343 0, 00344 length); 00345 #endif 00346 00347 return fibToStStatus[status]; 00348 } 00349 00350 00351 //The parameter 'byte' is the option byte number to be programmed. This 00352 //parameter can have a value of 0 through 7. 'data' is the 8bit value to be 00353 //programmed into the option byte since the hardware will calculate the 00354 //compliment and program the full 16bit option byte. 00355 StStatus halInternalCibOptionByteWrite(int8u byte, int8u data) 00356 { 00357 int16u dataAndInverse = HIGH_LOW_TO_INT(~data, data); 00358 // There are only 8 option bytes, don't try to program more than that. 00359 if (byte > 7) { 00360 return ST_ERR_FLASH_PROG_FAIL; 00361 } 00362 return halInternalFlashWrite(CIB_OB_BOTTOM + (byte << 1), &dataAndInverse, 1); 00363 } 00364 00365