The wait in mci_WaitForEvent will delay all card transactions.

Dependencies:   FATFileSystem

Fork of EALib by EmbeddedArtists AB

Embed: (wiki syntax)

« Back to documentation index

Show/hide line numbers SPIFI.cpp Source File

SPIFI.cpp

00001 #include "SPIFI.h"
00002 #include "mbed_debug.h"
00003 
00004 
00005 /******************************************************************************
00006  * Defines and typedefs
00007  *****************************************************************************/
00008 
00009 #define SPIFI_DBG             0
00010 
00011 /* 
00012  * The SPIFI_ROM_PTR (0x1FFF1FF8) points to an area where the pointers to
00013  * different drivers in ROM are stored.
00014  */
00015 typedef struct {
00016    /*const*/ unsigned p_usbd;     // USBROMD 
00017    /*const*/ unsigned p_clib;
00018    /*const*/ unsigned p_cand;
00019    /*const*/ unsigned p_pwrd;     // PWRROMD
00020    /*const*/ unsigned p_promd;    // DIVROMD
00021    /*const*/ SPIFI_RTNS *pSPIFID; // SPIFIROMD
00022    /*const*/ unsigned p_dev3;
00023    /*const*/ unsigned p_dev4; 
00024 } ROM;
00025 
00026 #define ROM_DRIVERS_PTR ((ROM *)(*((unsigned int *)SPIFI_ROM_PTR)))
00027 #define IS_ADDR_IN_SPIFI(__addr)  ( (((uint32_t)(__addr)) & 0xff000000) == SPIFI_MEM_BASE )
00028 
00029 #define SPIFI_MIN(__a, __b) (((__a) < (__b)) ? (__a) : (__b))
00030 
00031 /******************************************************************************
00032  * Local variables
00033  *****************************************************************************/
00034 
00035 /******************************************************************************
00036  * Private Functions
00037  *****************************************************************************/
00038 
00039 SPIFI::SpifiError SPIFI::translateError(int err, bool verify)
00040 {  
00041   SpifiError res;
00042   
00043   _verError = 0;
00044   
00045   if (err == 0)
00046   {
00047     res = Ok;
00048   }
00049   else if ((err >= Uninitialized) && (err <= UnknownError))
00050   {
00051     // This is a known error code
00052     res = (SpifiError)err;
00053   }
00054   else if ((err >= InternalError) && (err <= EraseConflict))
00055   {
00056     // This is a known error code
00057     res = (SpifiError)err;
00058   }
00059   else if (verify)
00060   {
00061     // As verification was selected and err is not in the list of known
00062     // codes this falls into this category in the User's Manual:
00063     //
00064     // "Other non-zero values can occur if options selects verification.
00065     //  They will be the address in the SPIFI memory area at which the
00066     //  first discrepancy was found."
00067     _verError = err;
00068     res = Verification;
00069   }
00070   else
00071   {
00072     // Should never happen :-) as all listed error codes are covered but
00073     // to be on the safe side and not interpret this as a success, a generic
00074     // error is set.
00075     res = UnknownError;
00076   }
00077   return res;
00078 }
00079 
00080 /******************************************************************************
00081  * Public Functions
00082  *****************************************************************************/
00083 
00084 SPIFI::SPIFI()
00085 {
00086   _verError       = 0;
00087   _initialized    = false;
00088   _device         = UnknownDevice;
00089   _memorySize     = 0;
00090   _eraseBlockSize = 0;
00091   
00092   _romData = (SPIFIobj*)malloc(sizeof(SPIFIobj));
00093   if (_romData == NULL) {
00094     debug("SPIFI: Failed to allocate memory for ROM data\n");
00095   }
00096 }
00097 
00098 SPIFI::~SPIFI()
00099 {
00100   if (_romData != NULL) {
00101     free(_romData);
00102   }
00103 }
00104 
00105 SPIFI::SpifiError SPIFI::init()
00106 {
00107   if (!_initialized) {
00108     
00109     // Turn on SPIFI block as it is disabled on reset
00110     LPC_SC->PCONP |= 0x00010000;
00111 
00112     // pinsel for SPIFI
00113     LPC_IOCON->P2_7 = 5; /* SPIFI_CSN @ P2.7 */
00114     LPC_IOCON->P0_22 = 5; /* SPIFI_CLK @ P0.22 */
00115     LPC_IOCON->P0_15 = 5; /* SPIFI_IO2 @ P0.15 */
00116     LPC_IOCON->P0_16 = 5; /* SPIFI_IO3 @ P0.16 */
00117     LPC_IOCON->P0_17 = 5; /* SPIFI_IO1 @ P0.17 */
00118     LPC_IOCON->P0_18 = 5; /* SPIFI_IO0 @ P0.18 */
00119     
00120     uint32_t spifi_clk_div = (*((volatile uint32_t*)0x400FC1B4)) & 0x1f;
00121     uint32_t spifi_clk_mhz = (SystemCoreClock / spifi_clk_div) / 1000000;
00122 
00123     _spifi = ROM_DRIVERS_PTR->pSPIFID;
00124 
00125     /* Typical time tCS is 20 ns min, we give 200 ns to be on safer side */
00126     int rc = _spifi->spifi_init (_romData, spifi_clk_mhz/5, S_FULLCLK+S_RCVCLK, spifi_clk_mhz);
00127     if (rc) {
00128       _spifi = NULL;
00129       return translateError(rc);
00130     }
00131 
00132     /* Make sure it is a tested flash module */
00133     if ((_romData->mfger == 1) && (_romData->devType == 0x2) && (_romData->devID == 0x15) && (_romData->memSize > 0x100000)) 
00134     {
00135       _device = Spansion_S25FL032;
00136       _memorySize = _romData->memSize;
00137       _eraseBlockSize = 64*1024;
00138     } 
00139     else if ((_romData->mfger == 0xef) && (_romData->devType == 0x40) && (_romData->devID == 0x17) && (_romData->memSize > 0x100000))
00140     {
00141       _device = Winbond_W25Q64FV;
00142       _memorySize = _romData->memSize;
00143       _eraseBlockSize = 4*1024;
00144     } 
00145     else 
00146     {
00147       debug("SPIFI::init(): Memory is unknown and may not work as expected\n");
00148       
00149       // Asuming it has 64Kb erase blocks (i.e. same setup as the Spansion S25FL032
00150       _device = UnknownDevice;
00151       _memorySize = _romData->memSize;
00152       _eraseBlockSize = 64*1024;
00153 
00154       /*
00155        * If this happens, check the manufacturer and device information
00156        * and compare with the data sheet for your chip. Also make sure
00157        * that the sector sizes are the same (i.e. 64KB) for your chip.
00158        * If everything is the same then add an exception for your chip.
00159        */
00160     }
00161     
00162     _initialized = true;
00163   }
00164   return Ok;
00165 }
00166 
00167 SPIFI::SpifiError SPIFI::program(uint32_t dest, unsigned len, char* src, Options options, bool verify, char* scratch)
00168 {
00169   unsigned written = 0;
00170   SPIFIopers opers;
00171   opers.dest = (char *)dest;
00172   opers.length = SPIFI_MIN(len, PROG_SIZE);
00173   opers.scratch = scratch;
00174   opers.protect = 0;
00175   opers.options = options;
00176   if (verify) {
00177     opers.options |= S_VERIFY_PROG;
00178   }
00179   
00180   if (IS_ADDR_IN_SPIFI(src))
00181   {
00182     // The SPIFI ROM driver cannot write data from SPIFI into
00183     // SPIFI (i.e. cannot read and write at the same time).
00184     // The workaround is to copy the source data into a buffer
00185     // in local memory and use that as source for the write
00186     // instead.
00187     while (written < len) {
00188       memcpy(_addrConflictBuff, src + written, opers.length);
00189       int rc = _spifi->spifi_program(_romData, _addrConflictBuff, &opers);
00190       if (rc) 
00191       {
00192         // got an error
00193         return translateError(rc, verify);
00194       }
00195       written += opers.length;
00196       opers.dest += opers.length;
00197       opers.length = SPIFI_MIN(len - written, PROG_SIZE);
00198     }
00199   }
00200   else 
00201   {
00202     while (written < len) {
00203       int rc = _spifi->spifi_program(_romData, src + written, &opers);
00204       if (rc) 
00205       {
00206         // got an error
00207         return translateError(rc, verify);
00208       }
00209       written += opers.length;
00210       opers.dest += opers.length;
00211       opers.length = SPIFI_MIN(len - written, PROG_SIZE);
00212     }
00213   }
00214   
00215   return Ok;
00216 }
00217 
00218 SPIFI::SpifiError SPIFI::erase(uint32_t dest, unsigned len, char* src, bool verify, char* scratch)
00219 {
00220   SPIFIopers opers;
00221   opers.dest = (char *)dest;
00222   opers.length = len;
00223   opers.scratch = scratch;
00224   opers.protect = 0;
00225   if (verify) {
00226     opers.options = S_VERIFY_ERASE;
00227   } else {
00228     opers.options = S_NO_VERIFY;
00229   }
00230   int rc = _spifi->spifi_erase(_romData, &opers);
00231   return translateError(rc);
00232 }
00233 
00234