00001 /* ---------------------------------------------------------------------------- */ 00002 /* Atmel Microcontroller Software Support */ 00003 /* SAM Software Package License */ 00004 /* ---------------------------------------------------------------------------- */ 00005 /* Copyright (c) 2015, Atmel Corporation */ 00006 /* */ 00007 /* All rights reserved. */ 00008 /* */ 00009 /* Redistribution and use in source and binary forms, with or without */ 00010 /* modification, are permitted provided that the following condition is met: */ 00011 /* */ 00012 /* - Redistributions of source code must retain the above copyright notice, */ 00013 /* this list of conditions and the disclaimer below. */ 00014 /* */ 00015 /* Atmel's name may not be used to endorse or promote products derived from */ 00016 /* this software without specific prior written permission. */ 00017 /* */ 00018 /* DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR */ 00019 /* IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF */ 00020 /* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE */ 00021 /* DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT, */ 00022 /* INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT */ 00023 /* LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, */ 00024 /* OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF */ 00025 /* LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING */ 00026 /* NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, */ 00027 /* EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. */ 00028 /* ---------------------------------------------------------------------------- */ 00029 00030 //------------------------------------------------------------------------------ 00031 // Headers 00032 //------------------------------------------------------------------------------ 00033 00034 #include "at45.h" 00035 #include "board.h" 00036 #include <assert.h> 00037 00038 #include <string.h> 00039 00040 //------------------------------------------------------------------------------ 00041 // Internal definitions 00042 //------------------------------------------------------------------------------ 00043 00044 /// Number of dataflash which can be recognized. 00045 #define NUMDATAFLASH (sizeof(at45Devices) / sizeof(At45Desc)) 00046 00047 //------------------------------------------------------------------------------ 00048 // Local variables 00049 //------------------------------------------------------------------------------ 00050 00051 /// indicate if the device is configured as binary page or not. 00052 static unsigned char configuredBinaryPage; 00053 00054 //------------------------------------------------------------------------------ 00055 // Internal variables 00056 //------------------------------------------------------------------------------ 00057 00058 static const At45Desc at45Devices[] = { 00059 { 512, 1, 264, 9, 0x0C, "AT45DB011D"}, 00060 { 1024, 1, 264, 9, 0x14, "AT45DB021D"}, 00061 { 2048, 1, 264, 9, 0x1C, "AT45DB041D"}, 00062 { 4096, 1, 264, 9, 0x24, "AT45DB081D"}, 00063 { 4096, 1, 528, 10, 0x2C, "AT45DB161D"}, 00064 { 8192, 1, 528, 10, 0x34, "AT45DB321D"}, 00065 { 8192, 1, 1056, 11, 0x3C, "AT45DB642D"}, 00066 {16384, 1, 1056, 11, 0x10, "AT45DB1282"}, 00067 {16384, 1, 2112, 12, 0x18, "AT45DB2562"}, 00068 {32768, 1, 2112, 12, 0x20, "AT45DB5122"} 00069 }; 00070 00071 //------------------------------------------------------------------------------ 00072 // Exported functions 00073 //------------------------------------------------------------------------------ 00074 00075 //------------------------------------------------------------------------------ 00076 /// Initializes an AT45 instance and configures SPI chip select register. 00077 /// Always returns 0. 00078 /// \param pAt45 Pointer to the At45 instance to initialize. 00079 /// \param pSpid Pointer to the underlying SPI driver. 00080 /// \param spiCs Chip select value to connect to the At45. 00081 //------------------------------------------------------------------------------ 00082 unsigned char AT45_Configure(At45 *pAt45, Spid *pSpid, unsigned char spiCs) 00083 { 00084 SpidCmd *pCommand; 00085 00086 // Sanity checks 00087 ASSERT(pSpid, "AT45_Configure: pSpid is 0.\n\r"); 00088 ASSERT(pAt45, "AT45_Configure: pAt45 is 0.\n\r"); 00089 00090 // Initialize the At45 instance 00091 pAt45->pSpid = pSpid; 00092 pAt45->pDesc = 0; 00093 memset(pAt45->pCmdBuffer, 0, 8); 00094 00095 // Initialize the spidCmd structure 00096 pCommand = &(pAt45->command); 00097 pCommand->pCmd = pAt45->pCmdBuffer; 00098 pCommand->callback = 0; 00099 pCommand->pArgument = 0; 00100 pCommand->spiCs = spiCs; 00101 00102 return 0; 00103 } 00104 00105 //------------------------------------------------------------------------------ 00106 /// This function returns 1 if the At45 driver is not executing any command; 00107 /// otherwise it returns 0. 00108 /// \param pAt45 Pointer to an At45 instance. 00109 //------------------------------------------------------------------------------ 00110 unsigned char AT45_IsBusy(At45 *pAt45) 00111 { 00112 return SPID_IsBusy(pAt45->pSpid); 00113 } 00114 00115 //------------------------------------------------------------------------------ 00116 /// Sends a command to the dataflash through the SPI. The command is identified 00117 /// by its command code and the number of bytes to transfer (1 + number of 00118 /// address bytes + number of dummy bytes). If data needs to be received, then 00119 /// a data buffer must be provided. 00120 /// This function does not block; its optional callback will be invoked when 00121 /// the transfer completes. 00122 /// \param pAt45 Pointer to an At45 driver instance. 00123 /// \param cmd Command code. 00124 /// \param cmdSize Size of command code + address bytes + dummy bytes. 00125 /// \param pData Data buffer. 00126 /// \param dataSize Number of data bytes to send/receive. 00127 /// \param address Address at which the command is performed if meaningful. 00128 /// \param callback Optional callback to invoke at end of transfer. 00129 /// \param pArgument Optional parameter to the callback function. 00130 //------------------------------------------------------------------------------ 00131 unsigned char AT45_SendCommand( 00132 At45 *pAt45, 00133 unsigned char cmd, 00134 unsigned char cmdSize, 00135 unsigned char *pData, 00136 unsigned int dataSize, 00137 unsigned int address, 00138 SpidCallback callback, 00139 void *pArgument) 00140 { 00141 SpidCmd *pCommand; 00142 const At45Desc *pDesc = pAt45->pDesc; 00143 unsigned int dfAddress = 0; 00144 00145 // Sanity checks 00146 ASSERT(pAt45, "AT45_Command: pAt45 is 0.\n\r"); 00147 ASSERT(pDesc || (cmd == AT45_STATUS_READ), 00148 "AT45_Command: Device has no descriptor, only STATUS_READ command allowed\n\r"); 00149 00150 // Check if the SPI driver is available 00151 if (AT45_IsBusy(pAt45)) 00152 00153 return AT45_ERROR_LOCK; 00154 00155 // Compute command pattern 00156 pAt45->pCmdBuffer[0] = cmd; 00157 00158 // Add address bytes if necessary 00159 if (cmdSize > 1) { 00160 00161 ASSERT(pDesc, "AT45_Command: No descriptor for dataflash.\n\r"); 00162 00163 if (!configuredBinaryPage) { 00164 dfAddress = 00165 ((address / (pDesc->pageSize)) << pDesc->pageOffset) 00166 + (address % (pDesc->pageSize)); 00167 } else 00168 dfAddress = address; 00169 00170 // Write address bytes 00171 if (pDesc->pageNumber >= 16384) { 00172 00173 pAt45->pCmdBuffer[1] = ((dfAddress & 0x0F000000) >> 24); 00174 pAt45->pCmdBuffer[2] = ((dfAddress & 0x00FF0000) >> 16); 00175 pAt45->pCmdBuffer[3] = ((dfAddress & 0x0000FF00) >> 8); 00176 pAt45->pCmdBuffer[4] = ((dfAddress & 0x000000FF) >> 0); 00177 00178 if ((cmd != AT45_CONTINUOUS_READ) && (cmd != AT45_PAGE_READ)) 00179 00180 cmdSize++; 00181 } else { 00182 00183 pAt45->pCmdBuffer[1] = ((dfAddress & 0x00FF0000) >> 16); 00184 pAt45->pCmdBuffer[2] = ((dfAddress & 0x0000FF00) >> 8); 00185 pAt45->pCmdBuffer[3] = ((dfAddress & 0x000000FF) >> 0); 00186 } 00187 } 00188 00189 // Update the SPI Transfer descriptors 00190 pCommand = &(pAt45->command); 00191 pCommand->cmdSize = cmdSize; 00192 pCommand->pData = pData; 00193 pCommand->dataSize = dataSize; 00194 pCommand->callback = callback; 00195 pCommand->pArgument = pArgument; 00196 00197 // Send Command and data through the SPI 00198 if (SPID_SendCommand(pAt45->pSpid, pCommand)) 00199 00200 return AT45_ERROR_SPI; 00201 00202 return 0; 00203 } 00204 00205 //------------------------------------------------------------------------------ 00206 /// This function returns the At45Desc structure corresponding to the device 00207 /// connected 00208 /// It automatically initializes pAt45->pDesc field structure. 00209 /// This function shall be called by the application before AT45_SendCommand. 00210 /// Returns 0 if successful; Otherwise, returns AT45_ERROR_LOCK if the At45 00211 /// driver is in use or AT45_ERROR_SPI if there was an error with the SPI driver. 00212 /// \param pAt45 Pointer to an AT45 driver instance. 00213 /// \param status Device status register value. 00214 //------------------------------------------------------------------------------ 00215 const At45Desc *AT45_FindDevice(At45 *pAt45, unsigned char status) 00216 { 00217 unsigned int i; 00218 unsigned char id = AT45_STATUS_ID(status); 00219 00220 // Check if status is all one; in which case, it is assumed that no device 00221 // is connected 00222 if (status == 0xFF) 00223 00224 return 0; 00225 00226 // Look in device array 00227 i = 0; 00228 pAt45->pDesc = 0; 00229 00230 while ((i < NUMDATAFLASH) && !(pAt45->pDesc)) { 00231 00232 if (at45Devices[i].id == id) 00233 00234 pAt45->pDesc = &(at45Devices[i]); 00235 00236 i++; 00237 } 00238 00239 configuredBinaryPage = AT45_STATUS_BINARY(status); 00240 return pAt45->pDesc; 00241 } 00242 00243 //------------------------------------------------------------------------------ 00244 /// This function returns the pagesize corresponding to the device connected 00245 /// \param pAt45 Pointer to an AT45 driver instance. 00246 //------------------------------------------------------------------------------ 00247 unsigned int AT45_PageSize(At45 *pAt45) 00248 { 00249 unsigned int pagesize = pAt45->pDesc->pageSize; 00250 00251 if (((pAt45->pDesc->hasBinaryPage) == 0) || !configuredBinaryPage) 00252 return pagesize; 00253 00254 return ((pagesize >> 8) << 8); 00255 }