SAM3S8/SD8 Software Package: libraries/libboard_sam3s-ek2/source/at45_spi.c Source File

SAM3S8/SD8 Software Package 1.2

# at45_spi.c

Go to the documentation of this file.

    00001 /* ----------------------------------------------------------------------------
    00002  *         ATMEL Microcontroller Software Support
    00003  * ----------------------------------------------------------------------------
    00004  * Copyright (c) 2009, 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 spi_at45_module SPI AT45 driver
    00031  * \ingroup at45d_module
    00032  * The Dataflash driver is based on top of the corresponding Spi driver.
    00033  * A Dataflash structure instance has to be initialized using the DF_Init
    00034  * function. Then basic dataflash operations can be launched using macros such
    00035  * as DF_continuous_read. These macros invoke the DF_Command() function which
    00036  * invokes the DPI low driver using the SPI_SendCommand() function.
    00037  * Beware to compute the dataflash internal address, the dataflash sector
    00038  * description must be known (DataflashDesc). Dataflash can be automatically
    00039  * detected using the DF_Scan() function.
    00040  *
    00041  * \section Usage
    00042  * <ul>
    00043  * <li> Initializes an AT45 instance and configures SPI chip select pin
    00044  *    using AT45_Configure(). </li>
    00045  * <li> Detect DF and returns DF description corresponding to the device
    00046  *    connected using AT45_FindDevice().This function shall be called by
    00047  *    the application before AT45_SendCommand.</li>
    00048  * <li>Sends a command to the DF through the SPI using AT45_SendCommand().
    00049  *    The command is identified by its command code and the number of
    00050  *    bytes to transfer.</li>
    00051  *    <li>Example code for sending command to write a page to DF. </li>
    00052  * \code
    00053  *    // Issue a page write through buffer 1 command
    00054  *     error = AT45_SendCommand(pAt45, AT45_PAGE_WRITE_BUF1, 4,
    00055  *             pBuffer, size, address, 0, 0);
    00056  * \endcode
    00057  *    <li>Example code for sending command to read a page from DF.
    00058  *       If data needs to be received, then a data buffer must be
    00059  *       provided.</li>
    00060  * \code
    00061  *    // Issue a continuous read array command
    00062  *    error = AT45_SendCommand(pAt45, AT45_CONTINUOUS_READ_LEG, 8,
    00063  *            pBuffer, size, address, 0, 0);
    00064  * \endcode
    00065  *    <li> This function does not block; its optional callback will
    00066  *       be invoked when the transfer completes.</li>
    00067  * <li> Check the AT45 driver is ready or not by polling AT45_IsBusy().
    00068  * </ul>
    00069  * Related files :\n
    00070  * \ref spi_at45.c\n
    00071  * \ref spi_at45.h.\n
    00072 */
    00073 /*@{*/
    00074 /*@}*/
    00075
    00076
    00077 /**
    00078  * \file
    00079  *
    00080  * Implementation of SPI At45 driver.
    00081  *
    00082  */
    00083
    00084
    00085
    00086 /*----------------------------------------------------------------------------
    00087  *        Headers
    00088  *----------------------------------------------------------------------------*/
    00089
    00090 #include "board.h"
    00091
    00092 #include <assert.h>
    00093 #include <string.h>
    00094
    00095 /*----------------------------------------------------------------------------
    00096  *        Internal definitions
    00097  *----------------------------------------------------------------------------*/
    00098
    00099 /** Number of dataflash which can be recognized.*/
    00100 #define NUMDATAFLASH    (sizeof(at45Devices) / sizeof(At45Desc))
    00101
    00102 /*----------------------------------------------------------------------------
    00103  *        Local variables
    00104  *----------------------------------------------------------------------------*/
    00105
    00106 /** indicate if the device is configured as binary page or not.*/
    00107 static uint8_t configuredBinaryPage;
    00108
    00109 /** At45 device descriptor structure. */
    00110 static const At45Desc at45Devices[] = {
    00111     {  512,  1, 264,   9, 0x0C, "AT45DB011D"},
    00112     { 1024,  1, 264,   9, 0x14, "AT45DB021D"},
    00113     { 2048,  1, 264,   9, 0x1C, "AT45DB041D"},
    00114     { 4096,  1, 264,   9, 0x24, "AT45DB081D"},
    00115     { 4096,  1, 528,  10, 0x2C, "AT45DB161D"},
    00116     { 8192,  1, 528,  10, 0x34, "AT45DB321D"},
    00117     { 8192,  1, 1056, 11, 0x3C, "AT45DB642D"},
    00118     {16384,  1, 1056, 11, 0x10, "AT45DB1282"},
    00119     {16384,  1, 2112, 12, 0x18, "AT45DB2562"},
    00120     {32768,  1, 2112, 12, 0x20, "AT45DB5122"}
    00121 };
    00122
    00123 /*----------------------------------------------------------------------------
    00124  *        Exported functions
    00125  *----------------------------------------------------------------------------*/
    00126
    00127 /**
    00128  * \brief Initializes an AT45 instance and configures SPI chip select register.
    00129  *
    00130  * \param pAt45  Pointer to the At45 instance to initialize.
    00131  * \param pSpid  Pointer to the underlying SPI driver.
    00132  * \param spiCs  Chip select value to connect to the At45.
    00133  * \return 0.
    00134  */
    00135 extern uint32_t AT45_Configure( At45* pAt45, Spid* pSpid, uint8_t ucSpiCs )
    00136 {
    00137     SpidCmd* pCommand ;
    00138
    00139     /* Sanity checks */
    00140     assert( pSpid != NULL ) ;
    00141     assert( pAt45 != NULL ) ;
    00142
    00143     /* Initialize the At45 instance */
    00144     pAt45->pSpid = pSpid ;
    00145     pAt45->pDesc = 0 ;
    00146     memset( pAt45->pCmdBuffer, 0, 8 ) ;
    00147
    00148     /* Initialize the spidCmd structure */
    00149     pCommand = &(pAt45->command) ;
    00150     pCommand->pCmd = pAt45->pCmdBuffer ;
    00151     pCommand->callback = 0 ;
    00152     pCommand->pArgument = 0 ;
    00153     pCommand->spiCs = ucSpiCs ;
    00154
    00155     return 0 ;
    00156 }
    00157
    00158 /**
    00159  * \brief Check if the At45 driver is in busy.
    00160  *
    00161  * \param pAt45  Pointer to the At45 instance to initialize.
    00162  * \return 1 if the At45 driver is not executing any command,otherwise it returns 0.
    00163  */
    00164 extern uint32_t AT45_IsBusy( At45* pAt45 )
    00165 {
    00166     return SPID_IsBusy( pAt45->pSpid ) ;
    00167 }
    00168
    00169 /**
    00170  * \brief Sends a command to the dataflash through the SPI.
    00171  * The command is identified by its command code and the number of bytes to transfer
    00172  * (1 + number of address bytes + number of dummy bytes).If data needs to be received,
    00173  * then a data buffer must be provided.
    00174  * \note This function does not block; its optional callback will be invoked when
    00175  * the transfer completes.
    00176  * \param pAt45  Pointer to the At45 instance to initialize.
    00177  * \param cmd  Command code.
    00178  * \param cmdSize  Size of command code + address bytes + dummy bytes.
    00179  * \param pData  Data buffer.
    00180  * \param dataSize  Number of data bytes to send/receive.
    00181  * \param address  Address at which the command is performed if meaningful.
    00182  * \param callback  Optional callback to invoke at end of transfer.
    00183  * \param pArgument  Optional parameter to the callback function.
    00184  * \return  0.
    00185  */
    00186 extern uint32_t AT45_SendCommand( At45* pAt45, uint8_t ucCmd, uint8_t ucCmdSize, uint8_t *pucData, uint32_t dwDataSize,
    00187                                   uint32_t dwAddress, SpidCallback pCallback, void *pArgument )
    00188 {
    00189     SpidCmd *pCommand ;
    00190     const At45Desc *pDesc;
    00191     uint32_t dfAddress = 0 ;
    00192
    00193     /* Sanity checks */
    00194     assert( pAt45 != NULL ) ;
    00195
    00196     pDesc = pAt45->pDesc ;
    00197
    00198     assert( pDesc || (ucCmd == AT45_STATUS_READ) ) ;
    00199
    00200     /* Check if the SPI driver is available*/
    00201     if ( AT45_IsBusy( pAt45 ) )
    00202     {
    00203         return AT45_ERROR_LOCK ;
    00204     }
    00205
    00206     /* Compute command pattern*/
    00207     pAt45->pCmdBuffer[0] = ucCmd ;
    00208
    00209     /* Add address bytes if necessary*/
    00210     if ( ucCmdSize > 1 )
    00211     {
    00212         assert( pDesc != NULL ) ;
    00213         if ( !configuredBinaryPage )
    00214         {
    00215             dfAddress = ((dwAddress / (pDesc->pageSize)) << pDesc->pageOffset)
    00216                         + (dwAddress % (pDesc->pageSize));
    00217         }
    00218         else
    00219         {
    00220             dfAddress = dwAddress ;
    00221         }
    00222
    00223         /* Write address bytes */
    00224         if ( pDesc->pageNumber >= 16384 )
    00225         {
    00226             pAt45->pCmdBuffer[1] = ((dfAddress & 0x0F000000) >> 24);
    00227             pAt45->pCmdBuffer[2] = ((dfAddress & 0x00FF0000) >> 16);
    00228             pAt45->pCmdBuffer[3] = ((dfAddress & 0x0000FF00) >> 8);
    00229             pAt45->pCmdBuffer[4] = ((dfAddress & 0x000000FF) >> 0);
    00230
    00231             if ( (ucCmd != AT45_CONTINUOUS_READ) && (ucCmd != AT45_PAGE_READ) )
    00232             {
    00233                 ucCmdSize++ ;
    00234             }
    00235         }
    00236         else
    00237         {
    00238             pAt45->pCmdBuffer[1] = ((dfAddress & 0x00FF0000) >> 16);
    00239             pAt45->pCmdBuffer[2] = ((dfAddress & 0x0000FF00) >> 8);
    00240             pAt45->pCmdBuffer[3] = ((dfAddress & 0x000000FF) >> 0);
    00241         }
    00242     }
    00243
    00244     /* Update the SPI Transfer descriptors */
    00245     pCommand = &(pAt45->command) ;
    00246     pCommand->cmdSize = ucCmdSize ;
    00247     pCommand->pData = pucData ;
    00248     pCommand->dataSize = dwDataSize ;
    00249     pCommand->callback = pCallback ;
    00250     pCommand->pArgument = pArgument ;
    00251
    00252     /* Send Command and data through the SPI */
    00253     if ( SPID_SendCommand( pAt45->pSpid, pCommand ) )
    00254     {
    00255         return AT45_ERROR_SPI ;
    00256     }
    00257
    00258     return 0 ;
    00259 }
    00260
    00261 /**
    00262  * \brief returns the At45Desc structure corresponding to the device connected.
    00263  * It automatically initializes pAt45->pDesc field structure.
    00264  *
    00265  * \note This function shall be called by the application before AT45_SendCommand.
    00266  *
    00267  * \param pAt45  Pointer to the At45 instance to initialize.
    00268  * \param status  Device status register value.
    00269  *
    00270  * \return 0 if successful; Otherwise, returns AT45_ERROR_LOCK if the At45
    00271  * driver is in use or AT45_ERROR_SPI if there was an error with the SPI driver.
    00272  */
    00273 extern const At45Desc * AT45_FindDevice( At45 *pAt45, uint8_t status )
    00274 {
    00275     uint32_t i;
    00276     uint8_t id = AT45_STATUS_ID(status);
    00277
    00278     /* Check if status is all one; in which case, it is assumed that no device is connected*/
    00279     if ( status == 0xFF )
    00280     {
    00281         return 0 ;
    00282     }
    00283
    00284     /* Look in device array */
    00285     i = 0 ;
    00286     pAt45->pDesc = 0 ;
    00287     while ( (i < NUMDATAFLASH) && !(pAt45->pDesc) )
    00288     {
    00289         if ( at45Devices[i].id == id )
    00290         {
    00291             pAt45->pDesc = &(at45Devices[i]) ;
    00292         }
    00293         i++ ;
    00294     }
    00295
    00296     configuredBinaryPage = AT45_STATUS_BINARY(status);
    00297
    00298     return pAt45->pDesc ;
    00299 }
    00300
    00301 /**
    00302  * \brief returns the pagesize corresponding to the device connected.
    00303  * \param pAt45  Pointer to the At45 instance to initialize.
    00304  * \return page size.
    00305  */
    00306 extern uint32_t AT45_PageSize( At45 *pAt45 )
    00307 {
    00308     uint32_t dwPageSize = pAt45->pDesc->pageSize ;
    00309
    00310     if ( ((pAt45->pDesc->hasBinaryPage) == 0) || !configuredBinaryPage )
    00311     {
    00312         return dwPageSize ;
    00313     }
    00314
    00315     return ((dwPageSize >> 8) << 8) ;
    00316 }

All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Defines