00001 /* ---------------------------------------------------------------------------- 00002 * SAM Software Package License 00003 * ---------------------------------------------------------------------------- 00004 * Copyright (c) 2013, 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 00031 /** 00032 * \addtogroup at25_spi_module S25FL1 SPI driver 00033 * \ingroup lib_spiflash 00034 * 00035 * The S25FL1 serial firmware dataflash driver is based on top of the 00036 * corresponding SPI driver. A Dataflash structure instance has to be 00037 * initialized using the S25FL1_Configure() function. Then a command can be send 00038 * to the serial flash using the SPI_SendCommand() function. 00039 * 00040 * \section Usage 00041 * <ul> 00042 * <li>Initializes an S25FL1 instance and configures SPI chip select pin 00043 * using S25FL1_Configure(). </li> 00044 * <li>Detect DF and returns DF description corresponding to the device 00045 * connected using S25FL1D_ReadJedecId() and S25FL1_FindDevice(). 00046 * This function shall be called by the application before S25FL1_SendCommand().</li> 00047 * <li> Sends a command to the DF through the SPI using S25FL1_SendCommand(). 00048 * The command is identified by its command code and the number of 00049 * bytes to transfer.</li> 00050 * <li> Example code for sending command to write a page to DF.</li> 00051 * \code 00052 * // Program page 00053 * error = S25FL1_SendCommand(pS25fl1, S25FL1_BYTE_PAGE_PROGRAM, 4, 00054 * pData, writeSize, address, 0, 0); 00055 * \endcode 00056 * <li> Example code for sending command to read a page from DF. 00057 * If data needs to be received, then a data buffer must be 00058 * provided.</li> 00059 * \code 00060 * // Start a read operation 00061 * error = S25FL1_SendCommand(pS25fl1, S25FL1_READ_ARRAY_LF, 00062 * 4, pData, size, address, 0, 0); 00063 * \endcode 00064 * <li> This function does not block; its optional callback will 00065 * be invoked when the transfer completes.</li> 00066 * <li> Check the S25FL1 driver is ready or not by polling S25FL1_IsBusy().</li> 00067 * </ul> 00068 * 00069 * Related files :\n 00070 * \ref at25_spi.c\n 00071 * \ref at25_spi.h.\n 00072 */ 00073 00074 /** 00075 * \file 00076 * 00077 * Implementation for the S25FL1 SPI driver. 00078 * 00079 */ 00080 00081 /*---------------------------------------------------------------------------- 00082 * Headers 00083 *----------------------------------------------------------------------------*/ 00084 #include <board.h> 00085 #include <assert.h> 00086 00087 /*---------------------------------------------------------------------------- 00088 * Exported functions 00089 *----------------------------------------------------------------------------*/ 00090 00091 /** 00092 * \brief Initializes an S25FL1 driver instance with the given SPI driver and chip 00093 * select value. 00094 * 00095 * \param pS25fl1 Pointer to an S25FL1 driver instance. 00096 * \param pSpid Pointer to an SPI driver instance. 00097 * \param cs Chip select value to communicate with the serial flash. 00098 * \param polling Uses polling mode instead of IRQ trigger. 00099 */ 00100 void S25FL1_Configure(S25fl1 *pS25fl1, Qspid *pQspid, uint8_t polling) 00101 { 00102 SpidCmd *pCommand; 00103 00104 assert(pS25fl1); 00105 assert(pQSpid); 00106 00107 00108 /* Initialize the S25FL1 fields */ 00109 pS25fl1->pQspid = pSpid; 00110 pS25fl1->pDesc = 0; 00111 pS25fl1->pollingMode = polling; 00112 00113 /* Initialize the command structure */ 00114 pCommand = &(pS25fl1->command); 00115 pCommand->pCmd = (uint8_t *) pS25fl1->CmdBuffer; 00116 pCommand->callback = 0; 00117 pCommand->pArgument = 0; 00118 } 00119 00120 /** 00121 * \brief Is serial flash driver busy. 00122 * 00123 * \param pS25fl1 Pointer to an S25fl1 driver instance. 00124 * 00125 * \return 1 if the serial flash driver is currently busy executing a command; 00126 * otherwise returns 0. 00127 */ 00128 uint8_t S25FL1_IsBusy(S25fl1 *pS25fl1) 00129 { 00130 if (pS25fl1->pollingMode) 00131 { 00132 SPID_Handler(pS25fl1->pSpid); 00133 SPID_DmaHandler(pS25fl1->pSpid); 00134 } 00135 return SPID_IsBusy(pS25fl1->pSpid); 00136 } 00137 00138 /** 00139 * \brief Sends a command to the serial flash through the SPI. The command is made up 00140 * of two parts: the first is used to transmit the command byte and optionally, 00141 * address and dummy bytes. The second part is the data to send or receive. 00142 * This function does not block: it returns as soon as the transfer has been 00143 * started. An optional callback can be invoked to notify the end of transfer. 00144 * 00145 * \param pS25fl1 Pointer to an S25fl1 driver instance. 00146 * \param cmd Command byte. 00147 * \param cmdSize Size of command (command byte + address bytes + dummy bytes). 00148 * \param pData Data buffer. 00149 * \param dataSize Number of bytes to send/receive. 00150 * \param address Address to transmit. 00151 * \param callback Optional user-provided callback to invoke at end of transfer. 00152 * \param pArgument Optional argument to the callback function. 00153 * 00154 * \return 0 if successful; otherwise, returns S25FL1_ERROR_BUSY if the S25FL1 00155 * driver is currently executing a command, or S25FL1_ERROR_SPI if the command 00156 * cannot be sent because of a SPI error. 00157 */ 00158 uint8_t S25FL1_SendCommand(uint8_t Instr, uint8_t ReadWrite) 00159 00160 { 00161 pDev->Instruction = Instr; 00162 QSPI_SendFrame(QSPI, pDev, ReadWrite); 00163 } 00164 00165 /** 00166 * \brief Tries to detect a serial firmware flash device given its JEDEC identifier. 00167 * The JEDEC id can be retrieved by sending the correct command to the device. 00168 * 00169 * \param pS25fl1 Pointer to an S25FL1 driver instance. 00170 * \param jedecId JEDEC identifier of device. 00171 * 00172 * \return the corresponding S25FL1 descriptor if found; otherwise returns 0. 00173 */ 00174 const S25fl1Desc * S25FL1_FindDevice(S25fl1 *pS25fl1, uint32_t jedecId) 00175 { 00176 uint32_t i = 0; 00177 00178 assert(pS25fl1); 00179 /* Search if device is recognized */ 00180 pS25fl1->pDesc = 0; 00181 while ((i < NUMDATAFLASH) && !(pS25fl1->pDesc)) { 00182 if ((jedecId & 0xFF00FFFF) == (at25Devices[i].jedecId & 0xFF00FFFF)) { 00183 pS25fl1->pDesc = &(at25Devices[i]); 00184 } 00185 i++; 00186 } 00187 return pS25fl1->pDesc; 00188 }