1 /* ----------------------------------------------------------------------------
\r
2 * ATMEL Microcontroller Software Support
\r
3 * ----------------------------------------------------------------------------
\r
4 * Copyright (c) 2010, Atmel Corporation
\r
6 * All rights reserved.
\r
8 * Redistribution and use in source and binary forms, with or without
\r
9 * modification, are permitted provided that the following conditions are met:
\r
11 * - Redistributions of source code must retain the above copyright notice,
\r
12 * this list of conditions and the disclaimer below.
\r
14 * Atmel's name may not be used to endorse or promote products derived from
\r
15 * this software without specific prior written permission.
\r
17 * DISCLAIMER: THIS SOFTWARE IS PROVIDED BY ATMEL "AS IS" AND ANY EXPRESS OR
\r
18 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF
\r
19 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NON-INFRINGEMENT ARE
\r
20 * DISCLAIMED. IN NO EVENT SHALL ATMEL BE LIABLE FOR ANY DIRECT, INDIRECT,
\r
21 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
\r
22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA,
\r
23 * OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
\r
24 * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING
\r
25 * NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE,
\r
26 * EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
\r
27 * ----------------------------------------------------------------------------
\r
31 * \addtogroup at25_spi_module AT25 SPI driver
\r
32 * \ingroup at25d_module
\r
34 * The AT25 serial firmware dataflash driver is based on top of the
\r
35 * corresponding Spi driver. A Dataflash structure instance has to be
\r
36 * initialized using the AT25_Configure() function. Then a command can be send
\r
37 * to the serial flash using the SPI_SendCommand() function.
\r
41 * <li>Initializes an AT25 instance and configures SPI chip select pin
\r
42 * using AT25_Configure(). </li>
\r
43 * <li>Detect DF and returns DF description corresponding to the device
\r
44 * connected using AT25D_ReadJedecId() and AT25_FindDevice().
\r
45 * This function shall be called by the application before AT25_SendCommand().</li>
\r
46 * <li> Sends a command to the DF through the SPI using AT25_SendCommand().
\r
47 * The command is identified by its command code and the number of
\r
48 * bytes to transfer.</li>
\r
49 * <li> Example code for sending command to write a page to DF.</li>
\r
52 * error = AT25_SendCommand(pAt25, AT25_BYTE_PAGE_PROGRAM, 4,
\r
53 * pData, writeSize, address, 0, 0);
\r
55 * <li> Example code for sending command to read a page from DF.
\r
56 * If data needs to be received, then a data buffer must be
\r
59 * // Start a read operation
\r
60 * error = AT25_SendCommand(pAt25, AT25_READ_ARRAY_LF,
\r
61 * 4, pData, size, address, 0, 0);
\r
63 * <li> This function does not block; its optional callback will
\r
64 * be invoked when the transfer completes.</li>
\r
65 * <li> Check the AT25 driver is ready or not by polling AT25_IsBusy().</li>
\r
70 * \ref at25_spi.h.\n
\r
76 * Implementation for the AT25 SPI driver.
\r
80 /*----------------------------------------------------------------------------
\r
82 *----------------------------------------------------------------------------*/
\r
86 /*----------------------------------------------------------------------------
\r
88 *----------------------------------------------------------------------------*/
\r
90 /** SPI clock frequency used in Hz. */
\r
91 #define SPCK 1000000
\r
93 /** SPI chip select configuration value. */
\r
94 #define CSR (SPI_CSR_NCPHA | \
\r
95 SPID_CSR_DLYBCT(BOARD_MCK, 100) | \
\r
96 SPID_CSR_DLYBS(BOARD_MCK, 10) | \
\r
97 SPID_CSR_SCBR(BOARD_MCK, SPCK))
\r
99 /** Number of recognized dataflash. */
\r
100 #define NUMDATAFLASH (sizeof(at25Devices) / sizeof(At25Desc))
\r
102 /*----------------------------------------------------------------------------
\r
104 *----------------------------------------------------------------------------*/
\r
106 /** Array of recognized serial firmware dataflash chips. */
\r
107 static const At25Desc at25Devices[] = {
\r
108 /* name, Jedec ID, size, page size, block size, block erase command */
\r
109 {"AT25DF041A" , 0x0001441F, 512 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
110 {"AT25DF161" , 0x0002461F, 2 * 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
111 {"AT26DF081A" , 0x0001451F, 1 * 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
112 {"AT26DF0161" , 0x0000461F, 2 * 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
113 {"AT26DF161A" , 0x0001461F, 2 * 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
114 {"AT25DF321" , 0x0000471F, 4 * 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
115 {"AT25DF321A" , 0x0001471F, 4 * 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
116 {"AT25DF512B" , 0x0001651F, 64 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
117 {"AT25DF512B" , 0x0000651F, 64 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
118 {"AT25DF021" , 0x0000431F, 256 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
119 {"AT26DF641" , 0x0000481F, 8 * 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
120 /* Manufacturer: ST */
\r
121 {"M25P05" , 0x00102020, 64 * 1024, 256, 32 * 1024, AT25_BLOCK_ERASE_64K},
\r
122 {"M25P10" , 0x00112020, 128 * 1024, 256, 32 * 1024, AT25_BLOCK_ERASE_64K},
\r
123 {"M25P20" , 0x00122020, 256 * 1024, 256, 64 * 1024, AT25_BLOCK_ERASE_64K},
\r
124 {"M25P40" , 0x00132020, 512 * 1024, 256, 64 * 1024, AT25_BLOCK_ERASE_64K},
\r
125 {"M25P80" , 0x00142020, 1 * 1024 * 1024, 256, 64 * 1024, AT25_BLOCK_ERASE_64K},
\r
126 {"M25P16" , 0x00152020, 2 * 1024 * 1024, 256, 64 * 1024, AT25_BLOCK_ERASE_64K},
\r
127 {"M25P32" , 0x00162020, 4 * 1024 * 1024, 256, 64 * 1024, AT25_BLOCK_ERASE_64K},
\r
128 {"M25P64" , 0x00172020, 8 * 1024 * 1024, 256, 64 * 1024, AT25_BLOCK_ERASE_64K},
\r
129 /* Manufacturer: Windbond */
\r
130 {"W25X10" , 0x001130EF, 128 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
131 {"W25X20" , 0x001230EF, 256 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
132 {"W25X40" , 0x001330EF, 512 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
133 {"W25X80" , 0x001430EF, 1 * 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
134 /* Manufacturer: Macronix */
\r
135 {"MX25L512" , 0x001020C2, 64 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
136 {"MX25L3205" , 0x001620C2, 4 * 1024 * 1024, 256, 64 * 1024, AT25_BLOCK_ERASE_64K},
\r
137 {"MX25L6405" , 0x001720C2, 8 * 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
138 {"MX25L8005" , 0x001420C2, 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
140 {"SST25VF040" , 0x008D25BF, 512 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
141 {"SST25VF080" , 0x008E25BF, 1 * 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
142 {"SST25VF032" , 0x004A25BF, 4 * 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K},
\r
143 {"SST25VF064" , 0x004B25BF, 8 * 1024 * 1024, 256, 4 * 1024, AT25_BLOCK_ERASE_4K}
\r
146 /*----------------------------------------------------------------------------
\r
147 * Exported functions
\r
148 *----------------------------------------------------------------------------*/
\r
151 * \brief Initializes an AT25 driver instance with the given SPI driver and chip
\r
154 * \param pAt25 Pointer to an AT25 driver instance.
\r
155 * \param pSpid Pointer to an SPI driver instance.
\r
156 * \param cs Chip select value to communicate with the serial flash.
\r
158 void AT25_Configure(At25 *pAt25, Spid *pSpid, unsigned char cs)
\r
166 /* Configure the SPI chip select for the serial flash */
\r
167 SPID_ConfigureCS(pSpid, cs, CSR);
\r
169 /* Initialize the AT25 fields */
\r
170 pAt25->pSpid = pSpid;
\r
173 /* Initialize the command structure */
\r
174 pCommand = &(pAt25->command);
\r
175 pCommand->pCmd = (unsigned char *) pAt25->pCmdBuffer;
\r
176 pCommand->callback = 0;
\r
177 pCommand->pArgument = 0;
\r
178 pCommand->spiCs = cs;
\r
182 * \brief Is serial flash driver busy.
\r
184 * \param pAt25 Pointer to an At25 driver instance.
\r
186 * \return 1 if the serial flash driver is currently busy executing a command;
\r
187 * otherwise returns 0.
\r
189 unsigned char AT25_IsBusy(At25 *pAt25)
\r
191 return SPID_IsBusy(pAt25->pSpid);
\r
195 * \brief Sends a command to the serial flash through the SPI. The command is made up
\r
196 * of two parts: the first is used to transmit the command byte and optionally,
\r
197 * address and dummy bytes. The second part is the data to send or receive.
\r
198 * This function does not block: it returns as soon as the transfer has been
\r
199 * started. An optional callback can be invoked to notify the end of transfer.
\r
201 * \param pAt25 Pointer to an At25 driver instance.
\r
202 * \param cmd Command byte.
\r
203 * \param cmdSize Size of command (command byte + address bytes + dummy bytes).
\r
204 * \param pData Data buffer.
\r
205 * \param dataSize Number of bytes to send/receive.
\r
206 * \param address Address to transmit.
\r
207 * \param callback Optional user-provided callback to invoke at end of transfer.
\r
208 * \param pArgument Optional argument to the callback function.
\r
210 * \return 0 if successful; otherwise, returns AT25_ERROR_BUSY if the AT25
\r
211 * driver is currently executing a command, or AT25_ERROR_SPI if the command
\r
212 * cannot be sent because of a SPI error.
\r
214 unsigned char AT25_SendCommand(
\r
217 unsigned char cmdSize,
\r
218 unsigned char *pData,
\r
219 unsigned int dataSize,
\r
220 unsigned int address,
\r
221 SpidCallback callback,
\r
229 /* Check if the SPI driver is available */
\r
230 if (AT25_IsBusy(pAt25)) {
\r
232 return AT25_ERROR_BUSY;
\r
235 /* Store command and address in command buffer */
\r
236 pAt25->pCmdBuffer[0] = (cmd & 0x000000FF)
\r
237 | ((address & 0x0000FF) << 24)
\r
238 | ((address & 0x00FF00) << 8)
\r
239 | ((address & 0xFF0000) >> 8);
\r
241 /* Update the SPI transfer descriptor */
\r
242 pCommand = &(pAt25->command);
\r
243 pCommand->cmdSize = cmdSize;
\r
244 pCommand->pData = pData;
\r
245 pCommand->dataSize = dataSize;
\r
246 pCommand->callback = callback;
\r
247 pCommand->pArgument = pArgument;
\r
249 /* Start the SPI transfer */
\r
250 if (SPID_SendCommand(pAt25->pSpid, pCommand)) {
\r
252 return AT25_ERROR_SPI;
\r
258 * \brief Tries to detect a serial firmware flash device given its JEDEC identifier.
\r
259 * The JEDEC id can be retrieved by sending the correct command to the device.
\r
261 * \param pAt25 Pointer to an AT25 driver instance.
\r
262 * \param jedecId JEDEC identifier of device.
\r
264 * \return the corresponding AT25 descriptor if found; otherwise returns 0.
\r
266 const At25Desc * AT25_FindDevice(At25 *pAt25, unsigned int jedecId)
\r
268 unsigned int i = 0;
\r
272 /* Search if device is recognized */
\r
274 while ((i < NUMDATAFLASH) && !(pAt25->pDesc)) {
\r
276 if ((jedecId & 0xFF00FFFF) == (at25Devices[i].jedecId & 0xFF00FFFF)) {
\r
278 pAt25->pDesc = &(at25Devices[i]);
\r
284 return pAt25->pDesc;
\r