]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained/libboard_samv7-ek/source/at25_spi.c
Update version number ready for V8.2.1 release.
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained / libboard_samv7-ek / source / at25_spi.c
1 /* ----------------------------------------------------------------------------\r
2  *         ATMEL Microcontroller Software Support\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2010, Atmel Corporation\r
5  *\r
6  * All rights reserved.\r
7  *\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
10  *\r
11  * - Redistributions of source code must retain the above copyright notice,\r
12  * this list of conditions and the disclaimer below.\r
13  *\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
16  *\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
28  */\r
29 \r
30 /** \r
31  * \addtogroup at25_spi_module AT25 SPI driver\r
32  * \ingroup at25d_module\r
33  *\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
38  *\r
39  * \section Usage\r
40  * <ul>\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
50  *    \code\r
51  *        // Program page\r
52  *        error = AT25_SendCommand(pAt25, AT25_BYTE_PAGE_PROGRAM, 4,\r
53  *                pData, writeSize, address, 0, 0);\r
54  *    \endcode\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
57  *       provided.</li>\r
58  *    \code\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
62  *    \endcode\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
66  * </ul>\r
67  *\r
68  * Related files :\n\r
69  * \ref at25_spi.c\n\r
70  * \ref at25_spi.h.\n\r
71  */\r
72 \r
73 /**\r
74  * \file\r
75  *\r
76  * Implementation for the AT25 SPI driver.\r
77  *\r
78  */\r
79 \r
80 /*----------------------------------------------------------------------------\r
81  *        Headers\r
82  *----------------------------------------------------------------------------*/\r
83 #include <board.h>\r
84 #include <assert.h>\r
85 \r
86 /*----------------------------------------------------------------------------\r
87  *        Local definitions\r
88  *----------------------------------------------------------------------------*/\r
89 \r
90 /** SPI clock frequency used in Hz. */\r
91 #define SPCK            1000000\r
92 \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
98 \r
99 /** Number of recognized dataflash. */\r
100 #define NUMDATAFLASH    (sizeof(at25Devices) / sizeof(At25Desc))\r
101 \r
102 /*----------------------------------------------------------------------------\r
103  *        Local variables\r
104  *----------------------------------------------------------------------------*/\r
105 \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
139     /* Other */\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
144 };\r
145 \r
146 /*----------------------------------------------------------------------------\r
147  *        Exported functions\r
148  *----------------------------------------------------------------------------*/\r
149 \r
150 /**\r
151  * \brief Initializes an AT25 driver instance with the given SPI driver and chip\r
152  * select value.\r
153  *\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
157  */\r
158 void AT25_Configure(At25 *pAt25, Spid *pSpid, unsigned char cs)\r
159 {\r
160     SpidCmd *pCommand;\r
161 \r
162     assert(pAt25);\r
163     assert(pSpid);\r
164     assert(cs < 4);\r
165 \r
166     /* Configure the SPI chip select for the serial flash */\r
167     SPID_ConfigureCS(pSpid, cs, CSR);\r
168 \r
169     /* Initialize the AT25 fields */\r
170     pAt25->pSpid = pSpid;\r
171     pAt25->pDesc = 0;\r
172 \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
179 }\r
180 \r
181 /**\r
182  * \brief Is serial flash driver busy.\r
183  *\r
184  * \param pAt25  Pointer to an At25 driver instance.\r
185  *\r
186  * \return 1 if the serial flash driver is currently busy executing a command;\r
187  * otherwise returns 0.\r
188  */\r
189 unsigned char AT25_IsBusy(At25 *pAt25)\r
190 {\r
191     return SPID_IsBusy(pAt25->pSpid);\r
192 }\r
193 \r
194 /**\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
200  *\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
209  *\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
213  */\r
214 unsigned char AT25_SendCommand(\r
215     At25 *pAt25,\r
216     unsigned char cmd,\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
222     void *pArgument)\r
223 \r
224 {\r
225     SpidCmd *pCommand;\r
226 \r
227     assert(pAt25);\r
228 \r
229     /* Check if the SPI driver is available */\r
230     if (AT25_IsBusy(pAt25)) {\r
231 \r
232         return AT25_ERROR_BUSY;\r
233     }\r
234 \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
240 \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
248 \r
249     /* Start the SPI transfer */\r
250     if (SPID_SendCommand(pAt25->pSpid, pCommand)) {\r
251 \r
252         return AT25_ERROR_SPI;\r
253     }\r
254     return 0;\r
255 }\r
256 \r
257 /**\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
260  *\r
261  * \param pAt25  Pointer to an AT25 driver instance.\r
262  * \param jedecId  JEDEC identifier of device.\r
263  *\r
264  * \return the corresponding AT25 descriptor if found; otherwise returns 0.\r
265  */\r
266 const At25Desc * AT25_FindDevice(At25 *pAt25, unsigned int jedecId)\r
267 {\r
268     unsigned int i = 0;\r
269 \r
270     assert(pAt25);\r
271 \r
272     /* Search if device is recognized */\r
273     pAt25->pDesc = 0;\r
274     while ((i < NUMDATAFLASH) && !(pAt25->pDesc)) {\r
275 \r
276         if ((jedecId & 0xFF00FFFF) == (at25Devices[i].jedecId & 0xFF00FFFF)) {\r
277 \r
278             pAt25->pDesc = &(at25Devices[i]);\r
279         }\r
280 \r
281         i++;\r
282     }\r
283 \r
284     return pAt25->pDesc;\r
285 }\r