flash.c

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

Generated on Mon Apr 11 14:23:36 2011 for Contiki 2.5 by  doxygen 1.6.1