Contiki 2.6

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 #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