SAMV71 Xplained Ultra Software Package 1.3

flashd.c

Go to the documentation of this file.
00001 /* ----------------------------------------------------------------------------
00002  *         SAM Software Package License
00003  * ----------------------------------------------------------------------------
00004  * Copyright (c) 2012, Atmel Corporation
00005  *
00006  * All rights reserved.
00007  *
00008  * Redistribution and use in source and binary forms, with or without
00009  * modification, are permitted provided that the following conditions are met:
00010  *
00011  * - Redistributions of source code must retain the above copyright notice,
00012  * this list of conditions and the disclaimer below.
00013  *
00014  * Atmel's name may not be used to endorse or promote products derived from
00015  * this software without specific prior written permission.
00016  *
00017  * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
00018  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
00019  * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
00020  * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
00021  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
00022  * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
00023  * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
00024  * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
00025  * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
00026  * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
00027  * ----------------------------------------------------------------------------
00028  */
00029 
00030 /** \addtogroup flashd_module Flash Memory Interface
00031  * The flash driver manages the programming, erasing, locking and unlocking 
00032  * sequences with dedicated commands.
00033  *
00034  * To implement flash programming operation, the user has to follow these few 
00035  * steps :
00036  * <ul>
00037  * <li>Configure flash wait states to initializes the flash. </li>
00038  * <li>Checks whether a region to be programmed is locked. </li>
00039  * <li>Unlocks the user region to be programmed if the region have locked 
00040  * before.</li>
00041  * <li>Erases the user page before program (optional).</li>
00042  * <li>Writes the user page from the page buffer.</li>
00043  * <li>Locks the region of programmed area if any.</li>
00044  * </ul>
00045  *
00046  * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable 
00047  * data corruption.
00048  * A check of this validity and padding for 32-bit alignment should be done in 
00049  * write algorithm.
00050  * Lock/unlock range associated with the user address range is automatically
00051  * translated.
00052  *
00053  * This security bit can be enabled through the command "Set General Purpose 
00054  * NVM Bit 0".
00055  *
00056  * A 128-bit factory programmed unique ID could be read to serve several 
00057  * purposes.
00058  *
00059  * The driver accesses the flash memory by calling the lowlevel module provided
00060  * in \ref efc_module.
00061  * For more accurate information, please look at the EEFC section of the 
00062  * Datasheet.
00063  *
00064  * Related files :\n
00065  * \ref flashd.c\n
00066  * \ref flashd.h.\n
00067  * \ref efc.c\n
00068  * \ref efc.h.\n
00069  */
00070 /*@{*/
00071 /*@}*/
00072 
00073 
00074 /**
00075  * \file
00076  *
00077  * The flash driver provides the unified interface for flash program operations.
00078  *
00079  */
00080 
00081 /*----------------------------------------------------------------------------
00082  *        Headers
00083  *----------------------------------------------------------------------------*/
00084 #include "chip.h"
00085 
00086 #include <string.h>
00087 #include <assert.h>
00088 
00089 /*----------------------------------------------------------------------------
00090  *        Definitions
00091  *----------------------------------------------------------------------------*/
00092 
00093 #define GPNVM_NUM_MAX    9
00094 
00095 /*----------------------------------------------------------------------------
00096  *        Local variables
00097  *----------------------------------------------------------------------------*/
00098 
00099 static uint32_t _pdwPageBuffer[IFLASH_PAGE_SIZE/sizeof(uint32_t)] ;
00100 static uint32_t _dwUseIAP = 1; /* Use IAP interface by default. */
00101 
00102 
00103 /*----------------------------------------------------------------------------
00104  *        Local functions
00105  *----------------------------------------------------------------------------*/
00106 
00107 
00108 /**
00109  * \brief Computes the lock range associated with the given address range.
00110  *
00111  * \param dwStart  Start address of lock range.
00112  * \param dwEnd  End address of lock range.
00113  * \param pdwActualStart  Actual start address of lock range.
00114  * \param pdwActualEnd  Actual end address of lock range.
00115  */
00116 static void ComputeLockRange( uint32_t dwStart, uint32_t dwEnd, 
00117                             uint32_t *pdwActualStart, uint32_t *pdwActualEnd )
00118 {
00119     Efc* pStartEfc ;
00120     Efc* pEndEfc ;
00121     uint16_t wStartPage ;
00122     uint16_t wEndPage ;
00123     uint16_t wNumPagesInRegion ;
00124     uint16_t wActualStartPage ;
00125     uint16_t wActualEndPage ;
00126 
00127     /* Convert start and end address in page numbers */
00128     EFC_TranslateAddress( &pStartEfc, dwStart, &wStartPage, 0 ) ;
00129     EFC_TranslateAddress( &pEndEfc, dwEnd, &wEndPage, 0 ) ;
00130 
00131     /* Find out the first page of the first region to lock */
00132     wNumPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ;
00133     wActualStartPage = wStartPage - (wStartPage % wNumPagesInRegion) ;
00134     wActualEndPage = wEndPage ;
00135 
00136     if ( (wEndPage % wNumPagesInRegion) != 0 ) {
00137         wActualEndPage += wNumPagesInRegion - (wEndPage % wNumPagesInRegion) ;
00138     }
00139     /* Store actual page numbers */
00140     EFC_ComputeAddress( pStartEfc, wActualStartPage, 0, pdwActualStart ) ;
00141     EFC_ComputeAddress( pEndEfc, wActualEndPage, 0, pdwActualEnd ) ;
00142     TRACE_DEBUG( "Actual lock range is 0x%06X - 0x%06X\n\r",
00143             (unsigned int)*pdwActualStart, (unsigned int)*pdwActualEnd ) ;
00144 }
00145 
00146 
00147 /*----------------------------------------------------------------------------
00148  *        Exported functions
00149  *----------------------------------------------------------------------------*/
00150 
00151 /**
00152  * \brief Initializes the flash driver.
00153  *
00154  * \param dwMCk     Master clock frequency in Hz.
00155  * \param dwUseIAP  0: use EEFC controller interface, 1: use IAP interface.
00156  *                  dwUseIAP should be set to 1 when running out of flash.
00157  */
00158 
00159 extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP )
00160 {
00161     dwMCk = dwMCk; /* avoid warnings */
00162 
00163     EFC_DisableFrdyIt( EFC ) ;
00164     _dwUseIAP = dwUseIAP ;
00165 }
00166 
00167 /**
00168  * \brief Erases the entire flash.
00169  *
00170  * \param dwAddress  Flash start address.
00171  * \return 0 if successful; otherwise returns an error code.
00172  */
00173 extern uint32_t FLASHD_Erase( uint32_t dwAddress )
00174 {
00175     Efc* pEfc ;
00176     uint16_t wPage ;
00177     uint16_t wOffset ;
00178     uint32_t dwError ;
00179 
00180     assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ;
00181 
00182     /* Translate write address */
00183     EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ;
00184     dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EA, 0, _dwUseIAP ) ;
00185 
00186     return dwError ;
00187 }
00188 
00189 /**
00190  * \brief Erases flash by sector.
00191  *
00192  * \param dwAddress  Start address of be erased sector.
00193  *
00194  * \return 0 if successful; otherwise returns an error code.
00195  */
00196 extern uint32_t FLASHD_EraseSector( uint32_t dwAddress )
00197 {
00198     Efc* pEfc ;
00199     uint16_t wPage ;
00200     uint16_t wOffset ;
00201     uint32_t dwError ;
00202 
00203     assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ;
00204 
00205     /* Translate write address */
00206     EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ;
00207     dwError = EFC_PerformCommand( pEfc, EFC_FCMD_ES, wPage, _dwUseIAP ) ;
00208 
00209     return dwError ;
00210 }
00211 
00212 /**
00213  * \brief Erases flash by pages.
00214  *
00215  * \param dwAddress  Start address of be erased pages.
00216  * \param dwPageNum  Number of pages to be erased with EPA command (4, 8, 16, 32)
00217  *
00218  * \return 0 if successful; otherwise returns an error code.
00219  */
00220 extern uint32_t FLASHD_ErasePages( uint32_t dwAddress, uint32_t dwPageNum )
00221 {
00222     Efc* pEfc ;
00223     uint16_t wPage ;
00224     uint16_t wOffset ;
00225     uint32_t dwError ;
00226     static uint32_t dwFarg ;
00227 
00228     assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ;
00229 
00230     /* Translate write address */
00231     EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ;
00232 
00233     /* Get FARG field for EPA command:
00234      * The first page to be erased is specified in the FARG[15:2] field of
00235      * the MC_FCR register. The first page number must be modulo 4, 8,16 or 32
00236      * according to the number of pages to erase at the same time.
00237      *
00238      * The 2 lowest bits of the FARG field define the number of pages to
00239      * be erased (FARG[1:0]).
00240      */
00241     if (dwPageNum == 32) {
00242         wPage &= ~(32u - 1u);
00243         dwFarg = (wPage << 2) | 3; /* 32 pages */
00244     } else if (dwPageNum == 16) {
00245         wPage &= ~(16u - 1u);
00246         dwFarg = (wPage << 2) | 2; /* 16 pages */
00247     } else if (dwPageNum == 8) {
00248         wPage &= ~(8u - 1u);
00249         dwFarg = (wPage << 2) | 1; /* 8 pages */
00250     } else {
00251         wPage &= ~(4u - 1u);
00252         dwFarg = (wPage << 2) | 0; /* 4 pages */
00253     }
00254     dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EPA, dwFarg, _dwUseIAP ) ;
00255 
00256     return dwError ;
00257 }
00258 
00259 
00260 /**
00261  * \brief Writes a data buffer in the internal flash
00262  *
00263  * \note This function works in polling mode, and thus only returns when the
00264  * data has been effectively written.
00265  * \param address  Write address.
00266  * \param pBuffer  Data buffer.
00267  * \param size  Size of data buffer in bytes.
00268  * \return 0 if successful, otherwise returns an error code.
00269  */
00270 extern uint32_t FLASHD_Write( uint32_t dwAddress, 
00271                             const void *pvBuffer, uint32_t dwSize )
00272 {
00273     Efc* pEfc ;
00274     uint16_t page ;
00275     uint16_t offset ;
00276     uint32_t writeSize ;
00277     uint32_t pageAddress ;
00278     uint16_t padding ;
00279     uint32_t dwError ;
00280     uint32_t dwIdx ;
00281     uint32_t *pAlignedDestination ;
00282     uint8_t  *pucPageBuffer = (uint8_t *)_pdwPageBuffer;
00283 
00284     assert( pvBuffer ) ;
00285     assert( dwAddress >=IFLASH_ADDR ) ;
00286     assert( (dwAddress + dwSize) <= (IFLASH_ADDR + IFLASH_SIZE) ) ;
00287 
00288     /* Translate write address */
00289     EFC_TranslateAddress( &pEfc, dwAddress, &page, &offset ) ;
00290 
00291     /* Write all pages */
00292     while ( dwSize > 0 ) {
00293         /* Copy data in temporary buffer to avoid alignment problems */
00294         writeSize = min((uint32_t)IFLASH_PAGE_SIZE - offset, dwSize ) ;
00295         EFC_ComputeAddress(pEfc, page, 0, &pageAddress ) ;
00296         padding = IFLASH_PAGE_SIZE - offset - writeSize ;
00297 
00298         /* Pre-buffer data */
00299         memcpy( pucPageBuffer, (void *) pageAddress, offset);
00300 
00301         /* Buffer data */
00302         memcpy( pucPageBuffer + offset, pvBuffer, writeSize);
00303 
00304         /* Post-buffer data */
00305         memcpy( pucPageBuffer + offset + writeSize, 
00306             (void *) (pageAddress + offset + writeSize), padding);
00307 
00308         /* Write page
00309          * Writing 8-bit and 16-bit data is not allowed and may 
00310             lead to unpredictable data corruption
00311          */
00312         pAlignedDestination = (uint32_t*)pageAddress ;
00313         for (dwIdx = 0; dwIdx < (IFLASH_PAGE_SIZE / sizeof(uint32_t)); ++ dwIdx) {
00314             *pAlignedDestination++ = _pdwPageBuffer[dwIdx];
00315             memory_barrier()
00316         }
00317 
00318         /* Note: It is not possible to use Erase and write Command (EWP) on all Flash
00319         (this command is available on the First 2 Small Sector, 16K Bytes). 
00320         For the next block, Erase them first then use Write page command. */
00321 
00322         /* Send writing command */
00323         dwError = EFC_PerformCommand( pEfc, EFC_FCMD_WP, page, _dwUseIAP ) ;
00324         if ( dwError ) {
00325             return dwError ;
00326         }
00327 
00328         /* Progression */
00329         pvBuffer = (void *)((uint32_t) pvBuffer + writeSize) ;
00330         dwSize -= writeSize ;
00331         page++;
00332         offset = 0;
00333     }
00334 
00335     return 0 ;
00336 }
00337 
00338 /**
00339  * \brief Locks all the regions in the given address range. The actual lock 
00340  * range is reported through two output parameters.
00341  *
00342  * \param start  Start address of lock range.
00343  * \param end    End address of lock range.
00344  * \param pActualStart  Start address of the actual lock range (optional).
00345  * \param pActualEnd  End address of the actual lock range (optional).
00346  * \return 0 if successful, otherwise returns an error code.
00347  */
00348 extern uint32_t FLASHD_Lock( uint32_t start, uint32_t end, 
00349                             uint32_t *pActualStart, uint32_t *pActualEnd )
00350 {
00351     Efc *pEfc ;
00352     uint32_t actualStart, actualEnd ;
00353     uint16_t startPage, endPage ;
00354     uint32_t dwError ;
00355     uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;
00356 
00357     /* Compute actual lock range and store it */
00358     ComputeLockRange( start, end, &actualStart, &actualEnd ) ;
00359     if ( pActualStart != NULL ) {
00360         *pActualStart = actualStart ;
00361     }
00362     if ( pActualEnd != NULL ) {
00363         *pActualEnd = actualEnd;
00364     }
00365 
00366     /* Compute page numbers */
00367     EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ;
00368     EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ;
00369 
00370     /* Lock all pages */
00371     while ( startPage < endPage ) {
00372         dwError = EFC_PerformCommand( pEfc, EFC_FCMD_SLB, startPage, _dwUseIAP ) ;
00373         if ( dwError ) {
00374             return dwError ;
00375         }
00376         startPage += numPagesInRegion;
00377     }
00378 
00379     return 0 ;
00380 }
00381 
00382 /**
00383  * \brief Unlocks all the regions in the given address range. The actual unlock 
00384  * range is reported through two output parameters.
00385  * \param start  Start address of unlock range.
00386  * \param end  End address of unlock range.
00387  * \param pActualStart  Start address of the actual unlock range (optional).
00388  * \param pActualEnd  End address of the actual unlock range (optional).
00389  * \return 0 if successful, otherwise returns an error code.
00390  */
00391 extern uint32_t FLASHD_Unlock( uint32_t start, uint32_t end, 
00392                             uint32_t *pActualStart, uint32_t *pActualEnd )
00393 {
00394     Efc* pEfc ;
00395     uint32_t actualStart, actualEnd ;
00396     uint16_t startPage, endPage ;
00397     uint32_t dwError ;
00398     uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;
00399 
00400     /* Compute actual unlock range and store it */
00401     ComputeLockRange(start, end, &actualStart, &actualEnd);
00402     if ( pActualStart != NULL ) {
00403         *pActualStart = actualStart ;
00404     }
00405     if ( pActualEnd != NULL ) {
00406         *pActualEnd = actualEnd ;
00407     }
00408 
00409     /* Compute page numbers */
00410     EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ;
00411     EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ;
00412 
00413     /* Unlock all pages */
00414     while ( startPage < endPage ) {
00415         dwError = EFC_PerformCommand( pEfc, EFC_FCMD_CLB, startPage, _dwUseIAP ) ;
00416         if ( dwError ) {
00417             return dwError ;
00418         }
00419         startPage += numPagesInRegion ;
00420     }
00421     return 0 ;
00422 }
00423 
00424 /**
00425  * \brief Returns the number of locked regions inside the given address range.
00426  *
00427  * \param start  Start address of range
00428  * \param end    End address of range.
00429  */
00430 extern uint32_t FLASHD_IsLocked( uint32_t start, uint32_t end )
00431 {
00432     uint32_t i, j;
00433     Efc *pEfc ;
00434     uint16_t startPage, endPage ;
00435     uint8_t startRegion, endRegion ;
00436     uint32_t numPagesInRegion ;
00437     uint32_t status[IFLASH_NB_OF_LOCK_BITS / 32u] ;
00438     uint32_t numLockedRegions = 0 ;
00439 
00440     assert( end >= start ) ;
00441     assert( (start >=IFLASH_ADDR) && (end <= IFLASH_ADDR + IFLASH_SIZE) ) ;
00442 
00443     /* Compute page numbers */
00444     EFC_TranslateAddress( &pEfc, start, &startPage, 0 ) ;
00445     EFC_TranslateAddress( 0, end, &endPage, 0 ) ;
00446 
00447     /* Compute region numbers */
00448     numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ;
00449     startRegion = startPage / numPagesInRegion ;
00450     endRegion = endPage / numPagesInRegion ;
00451     if ((endPage % numPagesInRegion) != 0) {
00452         endRegion++ ;
00453     }
00454 
00455     /* Retrieve lock status */
00456     EFC_PerformCommand( pEfc, EFC_FCMD_GLB, 0, _dwUseIAP ) ;
00457     for (i = 0; i < (IFLASH_NB_OF_LOCK_BITS / 32u); i++) {
00458         status[i] = EFC_GetResult( pEfc ) ;
00459     }
00460 
00461     /* Check status of each involved region */
00462     while ( startRegion < endRegion ) {
00463         i = startRegion / 32u;
00464         j = startRegion % 32u;
00465         if ( (status[i] & (1 << j)) != 0 ) {
00466             numLockedRegions++ ;
00467         }
00468         startRegion++ ;
00469     }
00470     return numLockedRegions ;
00471 }
00472 
00473 /**
00474  * \brief Check if the given GPNVM bit is set or not.
00475  *
00476  * \param gpnvm  GPNVM bit index.
00477  * \returns 1 if the given GPNVM bit is currently set; otherwise returns 0.
00478  */
00479 extern uint32_t FLASHD_IsGPNVMSet( uint8_t ucGPNVM )
00480 {
00481     uint32_t dwStatus ;
00482 
00483     assert( ucGPNVM < GPNVM_NUM_MAX ) ;
00484 
00485     /* Get GPNVMs status */
00486     EFC_PerformCommand( EFC, EFC_FCMD_GFB, 0, _dwUseIAP ) ;
00487     dwStatus = EFC_GetResult( EFC ) ;
00488 
00489     /* Check if GPNVM is set */
00490     if ( (dwStatus & (1 << ucGPNVM)) != 0 ) {
00491         return 1 ;
00492     } else {
00493         return 0 ;
00494     }
00495 }
00496 
00497 /**
00498  * \brief Sets the selected GPNVM bit.
00499  *
00500  * \param gpnvm  GPNVM bit index.
00501  * \returns 0 if successful; otherwise returns an error code.
00502  */
00503 extern uint32_t FLASHD_SetGPNVM( uint8_t ucGPNVM )
00504 {
00505     assert( ucGPNVM < GPNVM_NUM_MAX ) ;
00506 
00507     if ( !FLASHD_IsGPNVMSet( ucGPNVM ) ) {
00508         return EFC_PerformCommand( EFC, EFC_FCMD_SFB, ucGPNVM, _dwUseIAP ) ;
00509     } else {
00510         return 0 ;
00511     }
00512 }
00513 
00514 /**
00515  * \brief Clears the selected GPNVM bit.
00516  *
00517  * \param gpnvm  GPNVM bit index.
00518  * \returns 0 if successful; otherwise returns an error code.
00519  */
00520 extern uint32_t FLASHD_ClearGPNVM( uint8_t ucGPNVM )
00521 {
00522     assert( ucGPNVM < GPNVM_NUM_MAX ) ;
00523 
00524     if ( FLASHD_IsGPNVMSet( ucGPNVM ) ) {
00525         return EFC_PerformCommand( EFC, EFC_FCMD_CFB, ucGPNVM, _dwUseIAP ) ;
00526     } else {
00527         return 0 ;
00528     }
00529 }
00530 
00531 /**
00532  * \brief Read the unique ID.
00533  *
00534  * \param pdwUniqueID pointer on a 4bytes char containing the unique ID value.
00535  * \returns 0 if successful; otherwise returns an error code.
00536  */
00537 #ifdef __ICCARM__
00538 extern __ramfunc uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID )
00539 #else
00540     __attribute__ ((section (".ramfunc")))
00541 uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID )
00542 #endif
00543 {
00544     uint32_t status ;
00545     if (pdwUniqueID == NULL) {
00546         return 1;
00547     }
00548 
00549     pdwUniqueID[0] = 0 ;
00550     pdwUniqueID[1] = 0 ;
00551     pdwUniqueID[2] = 0 ;
00552     pdwUniqueID[3] = 0 ;
00553 
00554     /* Send the Start Read unique Identifier command (STUI) by writing the Flash
00555        Command Register with the STUI command.*/
00556     EFC->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EFC_FCMD_STUI;
00557 
00558     /* When the Unique Identifier is ready to be read, the FRDY bit in the Flash
00559        Programming Status Register (EEFC_FSR) falls. */
00560     do {
00561         status = EFC->EEFC_FSR ;
00562     } while ( (status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY ) ;
00563 
00564     /* The Unique Identifier is located in the first 128 bits of the Flash
00565        memory mapping. So, at the address 0x400000-0x40000F. */
00566     pdwUniqueID[0] = *(uint32_t *)IFLASH_ADDR;
00567     pdwUniqueID[1] = *(uint32_t *)(IFLASH_ADDR + 4);
00568     pdwUniqueID[2] = *(uint32_t *)(IFLASH_ADDR + 8);
00569     pdwUniqueID[3] = *(uint32_t *)(IFLASH_ADDR + 12);
00570 
00571     /* To stop the Unique Identifier mode, the user needs to send the Stop Read
00572        unique Identifier command (SPUI) by writing the Flash Command Register
00573        with the SPUI command. */
00574     EFC->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EFC_FCMD_SPUI ;
00575 
00576     /* When the Stop read Unique Unique Identifier command (SPUI) has been
00577     performed, the FRDY bit in the Flash Programming Status Register (EEFC_FSR)
00578     rises. */
00579     do {
00580         status = EFC->EEFC_FSR ;
00581     } while ( (status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY ) ;
00582 
00583     return 0;
00584 }
00585 
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines