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 efc_module Working with EEFC 00031 * 00032 * The EEFC driver provides the interface to configure and use the EEFC 00033 * peripheral. 00034 * 00035 * The user needs to set the number of wait states depending on the frequency 00036 * used.\n 00037 * Configure number of cycles for flash read/write operations in the FWS field 00038 * of EEFC_FMR. 00039 * 00040 * It offers a function to send flash command to EEFC and waits for the 00041 * flash to be ready. 00042 * 00043 * To send flash command, the user could do in either of following way: 00044 * <ul> 00045 * <li>Write a correct key, command and argument in EEFC_FCR. </li> 00046 * <li>Or, Use IAP (In Application Programming) function which is executed from 00047 * ROM directly, this allows flash programming to be done by code running in 00048 * flash.</li> 00049 * <li>Once the command is achieved, it can be detected even by polling 00050 * EEFC_FSR or interrupt. 00051 * </ul> 00052 * 00053 * The command argument could be a page number,GPNVM number or nothing, it 00054 * depends on the command itself. Some useful functions in this driver could 00055 * help user translate physical flash address into a page number and vice verse. 00056 * 00057 * For more accurate information, please look at the EEFC section of the 00058 * Datasheet. 00059 * 00060 * Related files :\n 00061 * \ref efc.c\n 00062 * \ref efc.h.\n 00063 */ 00064 /*@{*/ 00065 /*@}*/ 00066 00067 00068 /** 00069 * \file 00070 * 00071 * Implementation of Enhanced Embedded Flash Controller (EEFC). 00072 * 00073 */ 00074 00075 00076 /*---------------------------------------------------------------------------- 00077 * Headers 00078 *----------------------------------------------------------------------------*/ 00079 #include "chip.h" 00080 00081 #include <assert.h> 00082 00083 00084 /*---------------------------------------------------------------------------- 00085 * Macro 00086 *----------------------------------------------------------------------------*/ 00087 #define EEFC_FCR_FCMD(value) ((EEFC_FCR_FCMD_Msk & ((value) << EEFC_FCR_FCMD_Pos))) 00088 00089 /*---------------------------------------------------------------------------- 00090 * Exported functions 00091 *----------------------------------------------------------------------------*/ 00092 00093 extern void EFC_WriteFMR( Efc* efc, uint32_t dwFmr ); 00094 00095 #ifdef __ICCARM__ 00096 extern __ramfunc void EFC_WriteFMR( Efc* efc, uint32_t dwFmr ) 00097 #else 00098 __attribute__ ((section (".ramfunc"))) 00099 extern void EFC_WriteFMR( Efc* efc, uint32_t dwFmr ) 00100 #endif 00101 { 00102 efc->EEFC_FMR = dwFmr; 00103 } 00104 00105 /** 00106 * \brief Enables the flash ready interrupt source on the EEFC peripheral. 00107 * 00108 * \param efc Pointer to a Efc instance 00109 */ 00110 extern void EFC_EnableFrdyIt( Efc* efc ) 00111 { 00112 uint32_t dwFmr; 00113 00114 dwFmr = efc->EEFC_FMR |= EEFC_FMR_FRDY; 00115 EFC_WriteFMR(efc, dwFmr); 00116 } 00117 00118 /** 00119 * \brief Disables the flash ready interrupt source on the EEFC peripheral. 00120 * 00121 * \param efc Pointer to a Efc instance 00122 */ 00123 extern void EFC_DisableFrdyIt( Efc* efc ) 00124 { 00125 uint32_t dwFmr; 00126 00127 dwFmr = efc->EEFC_FMR & (~EEFC_FMR_FRDY); 00128 EFC_WriteFMR(efc, dwFmr); 00129 } 00130 00131 00132 /** 00133 * \brief Set read/write wait state on the EEFC peripheral. 00134 * 00135 * \param efc Pointer to a Efc instance 00136 * \param cycles the number of wait states in cycle. 00137 */ 00138 extern void EFC_SetWaitState( Efc* efc, uint8_t ucCycles ) 00139 { 00140 uint32_t dwFmr ; 00141 00142 dwFmr = efc->EEFC_FMR ; 00143 dwFmr &= ~((uint32_t)EEFC_FMR_FWS_Msk) ; 00144 dwFmr |= EEFC_FMR_FWS(ucCycles); 00145 EFC_WriteFMR(efc, dwFmr); 00146 } 00147 00148 /** 00149 * \brief Returns the current status of the EEFC. 00150 * 00151 * \note Keep in mind that this function clears the value of some status bits 00152 * (LOCKE, PROGE). 00153 * 00154 * \param efc Pointer to a Efc instance 00155 */ 00156 extern uint32_t EFC_GetStatus( Efc* efc ) 00157 { 00158 return efc->EEFC_FSR ; 00159 } 00160 00161 /** 00162 * \brief Returns the result of the last executed command. 00163 * 00164 * \param efc Pointer to a Efc instance 00165 */ 00166 extern uint32_t EFC_GetResult( Efc* efc ) 00167 { 00168 return efc->EEFC_FRR ; 00169 } 00170 00171 /** 00172 * \brief Translates the given address page and offset values. 00173 * \note The resulting values are stored in the provided variables if they are 00174 * not null. 00175 * 00176 * \param efc Pointer to a Efc instance 00177 * \param address Address to translate. 00178 * \param pPage First page accessed. 00179 * \param pOffset Byte offset in first page. 00180 */ 00181 extern void EFC_TranslateAddress( Efc** ppEfc, uint32_t dwAddress, uint16_t* pwPage, 00182 uint16_t* pwOffset ) 00183 { 00184 assert( dwAddress >= IFLASH_ADDR ) ; 00185 assert( dwAddress <= (IFLASH_ADDR + IFLASH_SIZE) ) ; 00186 00187 /* Store values */ 00188 if ( ppEfc ) { 00189 *ppEfc = EFC ; 00190 } 00191 00192 if ( pwPage ) { 00193 *pwPage = (dwAddress - IFLASH_ADDR) / IFLASH_PAGE_SIZE ; 00194 } 00195 00196 if ( pwOffset ) { 00197 *pwOffset = (dwAddress - IFLASH_ADDR) % IFLASH_PAGE_SIZE; ; 00198 } 00199 } 00200 00201 00202 /** 00203 * \brief Computes the address of a flash access given the page and offset. 00204 * 00205 * \param efc Pointer to a Efc instance 00206 * \param page Page number. 00207 * \param offset Byte offset inside page. 00208 * \param pAddress Computed address (optional). 00209 */ 00210 extern void EFC_ComputeAddress( Efc *efc, uint16_t wPage, uint16_t wOffset, 00211 uint32_t *pdwAddress ) 00212 { 00213 uint32_t dwAddress ; 00214 00215 /* Stop warning */ 00216 efc = efc; 00217 00218 assert( efc ) ; 00219 assert( wPage <= IFLASH_NB_OF_PAGES ) ; 00220 assert( wOffset < IFLASH_PAGE_SIZE ) ; 00221 dwAddress = IFLASH_ADDR + wPage * IFLASH_PAGE_SIZE + wOffset ; 00222 00223 /* Store result */ 00224 if ( pdwAddress != NULL ) { 00225 *pdwAddress = dwAddress ; 00226 } 00227 } 00228 00229 /** 00230 * \brief Performs the given command and wait until its completion (or an error). 00231 * 00232 * \param efc Pointer to a Efc instance 00233 * \param command Command to perform. 00234 * \param argument Optional command argument. 00235 * 00236 * \return 0 if successful, otherwise returns an error code. 00237 */ 00238 00239 extern uint32_t EFC_PerformCommand( Efc* efc, uint32_t dwCommand, 00240 uint32_t dwArgument, uint32_t dwUseIAP ) 00241 { 00242 if ( dwUseIAP != 0 ) { 00243 /* Pointer on IAP function in ROM */ 00244 static uint32_t (*IAP_PerformCommand)( uint32_t, uint32_t ) ; 00245 00246 IAP_PerformCommand = (uint32_t (*)( uint32_t, uint32_t )) 00247 *((uint32_t*)CHIP_FLASH_IAP_ADDRESS ) ; 00248 if (efc == EFC) { 00249 IAP_PerformCommand( 0, EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(dwArgument) 00250 | EEFC_FCR_FCMD(dwCommand) ) ; 00251 } 00252 return (efc->EEFC_FSR & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE | EEFC_FSR_FLERR)) ; 00253 } else { 00254 uint32_t dwStatus ; 00255 00256 efc->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EEFC_FCR_FARG(dwArgument) 00257 | EEFC_FCR_FCMD(dwCommand) ; 00258 do { 00259 dwStatus = efc->EEFC_FSR ; 00260 } 00261 while ( (dwStatus & EEFC_FSR_FRDY) != EEFC_FSR_FRDY ) ; 00262 00263 return ( dwStatus & (EEFC_FSR_FLOCKE | EEFC_FSR_FCMDE | EEFC_FSR_FLERR) ) ; 00264 } 00265 } 00266 00267 /** 00268 * \brief Set flash access mode. 00269 * 00270 * \param dwMode - 0:128-bit, (1<<24):64-bit 00271 */ 00272 extern void EFC_SetFlashAccessMode(Efc* efc, uint32_t dwMode) 00273 { 00274 uint32_t dwFmr; 00275 00276 dwFmr = dwMode; 00277 EFC_WriteFMR(efc, dwFmr); 00278 } 00279