]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained_IAR_Keil/libboard_samv7-ek/source/at25d.c
Final V8.2.1 release ready for tagging:
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained_IAR_Keil / libboard_samv7-ek / source / at25d.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 external_component External Component\r
32  *\r
33  * \addtogroup at25d_module AT25 driver\r
34  * \ingroup external_component\r
35  * The AT25 serial dataflash driver is based on the corresponding AT25 SPI driver.\r
36  * A AT25 instance has to be initialized using the Dataflash levle function\r
37  * AT25_Configure(). AT25 Dataflash can be automatically detected using\r
38  * the AT25_FindDevice() function. Then AT25 dataflash operations such as\r
39  * read, write and erase DF can be launched using AT25_SendCommand function\r
40  * with corresponding AT25 command set.\r
41  *\r
42  * \section Usage\r
43  * <ul>\r
44  * <li> Reads a serial flash device ID using AT25D_ReadJedecId().</li>\r
45  * <li> Reads data from the At25 at the specified address using AT25D_Read().</li>\r
46  * <li> Writes data on the At25 at the specified address using AT25D_Write().</li>\r
47  * <li> Erases all chip using AT25D_EraseBlock().</li>\r
48  * <li> Erases a specified block using AT25D_EraseBlock().</li>\r
49  * <li> Poll until the At25 has completed of corresponding operations using\r
50  * AT25D_WaitReady().</li>\r
51  * <li> Retrieves and returns the At25 current using AT25D_ReadStatus().</li>\r
52  * </ul>\r
53  *\r
54  * Related files :\n\r
55  * \ref at25d.c\n\r
56  * \ref at25d.h.\n\r
57  */\r
58 /*@{*/\r
59 /*@}*/\r
60 \r
61 /**\r
62  * \file\r
63  *\r
64  * Implementation for the AT25 Serialflash driver.\r
65  *\r
66  */\r
67 \r
68 /*----------------------------------------------------------------------------\r
69  *        Headers\r
70  *----------------------------------------------------------------------------*/\r
71 \r
72 #include <board.h>\r
73 \r
74 #include <assert.h>\r
75 \r
76 /*----------------------------------------------------------------------------\r
77  *        Local functions\r
78  *----------------------------------------------------------------------------*/\r
79 \r
80 /**\r
81  * \brief Wait for transfer to finish calling the SPI driver ISR. (interrupts are disabled)\r
82  *\r
83  * \param pAt25  Pointer to an AT25 driver instance.\r
84  */\r
85 static void AT25D_Wait(At25 *pAt25)\r
86 {\r
87     /* Wait for transfer to finish */\r
88     while (AT25_IsBusy(pAt25))\r
89         SPID_Handler(pAt25->pSpid);\r
90 }\r
91 \r
92 /**\r
93  * \brief Reads and returns the status register of the serial flash.\r
94  *\r
95  * \param pAt25  Pointer to an AT25 driver instance.\r
96  */\r
97 static unsigned char AT25D_ReadStatus(At25 *pAt25)\r
98 {\r
99     unsigned char error, status;\r
100 \r
101     assert(pAt25);\r
102 \r
103     /* Issue a status read command */\r
104     error = AT25_SendCommand(pAt25, AT25_READ_STATUS, 1, &status, 1, 0, 0, 0);\r
105     assert(!error);\r
106 \r
107     /* Wait for transfer to finish */\r
108     AT25D_Wait(pAt25);\r
109 \r
110     return status;\r
111 }\r
112 \r
113 /**\r
114  * \brief Writes the given value in the status register of the serial flash device.\r
115  *\r
116  * \param pAt25  Pointer to an AT25 driver instance.\r
117  * \param status  Status to write.\r
118  */\r
119 static void AT25D_WriteStatus(At25 *pAt25, unsigned char status)\r
120 {\r
121     unsigned char error;\r
122 \r
123     assert(pAt25);\r
124 \r
125     /* Issue a write status command */\r
126     error = AT25_SendCommand(pAt25, AT25_WRITE_STATUS, 1, &status, 1, 0, 0, 0);\r
127     assert(!error);\r
128 \r
129     /* Wait for transfer to finish */\r
130     AT25D_Wait(pAt25);\r
131 }\r
132 \r
133 /*----------------------------------------------------------------------------\r
134  *         Global functions\r
135  *----------------------------------------------------------------------------*/\r
136 \r
137 /**\r
138  * \brief  Waits for the serial flash device to become ready to accept new commands.\r
139  *\r
140  * \param pAt25  Pointer to an AT25 driver instance.\r
141  */\r
142 void AT25D_WaitReady(At25 *pAt25)\r
143 {\r
144     unsigned char ready = 0;\r
145 \r
146     assert(pAt25);\r
147 \r
148     /* Read status register and check busy bit */\r
149     while (!ready) {\r
150 \r
151         ready = ((AT25D_ReadStatus(pAt25) & AT25_STATUS_RDYBSY) == AT25_STATUS_RDYBSY_READY);\r
152     }\r
153 }\r
154 \r
155 /**\r
156  * \brief Reads and returns the serial flash device ID.\r
157  *\r
158  * \param pAt25  Pointer to an AT25 driver instance.\r
159  */\r
160 unsigned int AT25D_ReadJedecId(At25 *pAt25)\r
161 {\r
162     unsigned char error;\r
163     unsigned int id = 0;\r
164 \r
165     assert(pAt25);\r
166 \r
167     /* Issue a read ID command */\r
168     error = AT25_SendCommand(pAt25, AT25_READ_JEDEC_ID, 1,\r
169                              (unsigned char *) &id, 3, 0, 0, 0);\r
170     assert(!error);\r
171 \r
172     /* Wait for transfer to finish */\r
173     AT25D_Wait(pAt25);\r
174 \r
175     return id;\r
176 }\r
177 \r
178 /**\r
179  * \brief Enables critical writes operation on a serial flash device, such as sector\r
180  * protection, status register, etc.\r
181  *\r
182  * \para pAt25  Pointer to an AT25 driver instance.\r
183  */\r
184 void AT25D_EnableWrite(At25 *pAt25)\r
185 {\r
186     unsigned char error;\r
187 \r
188     assert(pAt25);\r
189 \r
190     /* Issue a write enable command */\r
191     error = AT25_SendCommand(pAt25, AT25_WRITE_ENABLE, 1, 0, 0, 0, 0, 0);\r
192     assert(!error);\r
193 \r
194     /* Wait for transfer to finish */\r
195     AT25D_Wait(pAt25);\r
196 }\r
197 \r
198 /**\r
199  * \brief Disables write operation on a serial flash device.\r
200  *\r
201  * \para pAt25  Pointer to an AT25 driver instance.\r
202  */\r
203 void AT25D_DisableWrite(At25 *pAt25)\r
204 {\r
205     unsigned char error;\r
206 \r
207     assert(pAt25);\r
208 \r
209     /* Issue a write enable command */\r
210     error = AT25_SendCommand(pAt25, AT25_WRITE_DISABLE, 1, 0, 0, 0, 0, 0);\r
211     assert(!error);\r
212 \r
213     /* Wait for transfer to finish */\r
214     AT25D_Wait(pAt25);\r
215 }\r
216 \r
217 /**\r
218  * \brief Unprotects the contents of the serial flash device.\r
219  *\r
220  * \param pAt25  Pointer to an AT25 driver instance.\r
221  *\r
222  * \return 0 if the device has been unprotected; otherwise returns\r
223  * AT25_ERROR_PROTECTED.\r
224  */\r
225 unsigned char AT25D_Unprotect(At25 *pAt25)\r
226 {\r
227     unsigned char status;\r
228 \r
229     assert(pAt25);\r
230 \r
231     /* Get the status register value to check the current protection */\r
232     status = AT25D_ReadStatus(pAt25);\r
233     if ((status & AT25_STATUS_SWP) == AT25_STATUS_SWP_PROTNONE) {\r
234 \r
235         /* Protection already disabled */\r
236         return 0;\r
237     }\r
238 \r
239     /* Check if sector protection registers are locked */\r
240     if ((status & AT25_STATUS_SPRL) == AT25_STATUS_SPRL_LOCKED) {\r
241 \r
242         /* Unprotect sector protection registers by writing the status reg. */\r
243         AT25D_EnableWrite(pAt25);\r
244         AT25D_WriteStatus(pAt25, 0);\r
245     }\r
246 \r
247     /* Perform a global unprotect command */\r
248     AT25D_EnableWrite(pAt25);\r
249 \r
250     AT25D_WriteStatus(pAt25, 0);\r
251 \r
252     /* Check the new status */\r
253     status = AT25D_ReadStatus(pAt25);\r
254     if ((status & (AT25_STATUS_SPRL | AT25_STATUS_SWP)) != 0) {\r
255 \r
256         return AT25_ERROR_PROTECTED;\r
257     }\r
258     else {\r
259 \r
260         return 0;\r
261     }\r
262 }\r
263 \r
264 /**\r
265  * \brief Erases all the content of the memory chip.\r
266  *\r
267  * \param pAt25  Pointer to an AT25 driver instance.\r
268  *\r
269  * \return 0 if the device has been unprotected; otherwise returns\r
270  * AT25_ERROR_PROTECTED.\r
271  */\r
272 unsigned char AT25D_EraseChip(At25 *pAt25)\r
273 {\r
274     unsigned char status;\r
275     unsigned char error;\r
276 \r
277     assert(pAt25);\r
278 \r
279     /* Check that the flash is unprotected */\r
280     status = AT25D_ReadStatus(pAt25);\r
281     if ((status & AT25_STATUS_SWP) != AT25_STATUS_SWP_PROTNONE) {\r
282         return AT25_ERROR_PROTECTED;\r
283     }\r
284 \r
285     /* Enable critical write operation */\r
286       AT25D_EnableWrite(pAt25);\r
287 \r
288     /* Erase the chip */\r
289     error = AT25_SendCommand(pAt25, AT25_CHIP_ERASE_2, 1, 0, 0, 0, 0, 0);\r
290     assert(!error);\r
291 \r
292     /* Wait for transfer to finish */\r
293     AT25D_Wait(pAt25);\r
294     /* Poll the Serial flash status register until the operation is achieved */\r
295     AT25D_WaitReady(pAt25);\r
296 \r
297     return 0;\r
298 }\r
299 \r
300 /**\r
301  *\brief  Erases the specified block of the serial firmware dataflash.\r
302  *\r
303  * \param pAt25  Pointer to an AT25 driver instance.\r
304  * \param address  Address of the block to erase.\r
305  *\r
306  * \return 0 if successful; otherwise returns AT25_ERROR_PROTECTED if the\r
307  * device is protected or AT25_ERROR_BUSY if it is busy executing a command.\r
308  */\r
309 unsigned char AT25D_EraseBlock(At25 *pAt25, unsigned int address)\r
310 {\r
311     unsigned char status;\r
312     unsigned char error;\r
313 \r
314     assert(pAt25);\r
315 \r
316     /* Check that the flash is ready and unprotected */\r
317     status = AT25D_ReadStatus(pAt25);\r
318     if ((status & AT25_STATUS_RDYBSY) != AT25_STATUS_RDYBSY_READY) {\r
319         TRACE_ERROR("AT25D_EraseBlock : Flash busy\n\r");\r
320         return AT25_ERROR_BUSY;\r
321     }\r
322     else if ((status & AT25_STATUS_SWP) != AT25_STATUS_SWP_PROTNONE) {\r
323         TRACE_ERROR("AT25D_EraseBlock : Flash protected\n\r");\r
324         return AT25_ERROR_PROTECTED;\r
325     }\r
326 \r
327     /* Enable critical write operation */\r
328       AT25D_EnableWrite(pAt25);\r
329 \r
330     /* Start the block erase command */\r
331     error = AT25_SendCommand(pAt25, AT25_BlockEraseCmd(pAt25), 4, 0, 0, address, 0, 0);\r
332     assert(!error);\r
333 \r
334     /* Wait for transfer to finish */\r
335     AT25D_Wait(pAt25);\r
336     /* Poll the Serial flash status register until the operation is achieved */\r
337     AT25D_WaitReady(pAt25);\r
338 \r
339     return 0;\r
340 }\r
341 \r
342 \r
343 /**\r
344  *\brief  Erases the specified 64KB block of the serial firmware dataflash.\r
345  *\r
346  * \param pAt25  Pointer to an AT25 driver instance.\r
347  * \param address  Address of the block to erase.\r
348  *\r
349  * \return 0 if successful; otherwise returns AT25_ERROR_PROTECTED if the\r
350  * device is protected or AT25_ERROR_BUSY if it is busy executing a command.\r
351  */\r
352 unsigned char AT25D_Erase64KBlock(At25 *pAt25, unsigned int address)\r
353 {\r
354     unsigned char status;\r
355     unsigned char error;\r
356 \r
357     assert(pAt25);\r
358 \r
359     /* Check that the flash is ready and unprotected */\r
360     status = AT25D_ReadStatus(pAt25);\r
361     if ((status & AT25_STATUS_RDYBSY) != AT25_STATUS_RDYBSY_READY) {\r
362         TRACE_ERROR("AT25D_EraseBlock : Flash busy\n\r");\r
363         return AT25_ERROR_BUSY;\r
364     }\r
365     else if ((status & AT25_STATUS_SWP) != AT25_STATUS_SWP_PROTNONE) {\r
366         TRACE_ERROR("AT25D_EraseBlock : Flash protected\n\r");\r
367         return AT25_ERROR_PROTECTED;\r
368     }\r
369 \r
370     /* Enable critical write operation */\r
371       AT25D_EnableWrite(pAt25);\r
372 \r
373     /* Start the block erase command */\r
374     error = AT25_SendCommand(pAt25, AT25_BLOCK_ERASE_64K, 4, 0, 0, address, 0, 0);\r
375     assert(!error);\r
376 \r
377     /* Wait for transfer to finish */\r
378     AT25D_Wait(pAt25);\r
379     /* Poll the Serial flash status register until the operation is achieved */\r
380     AT25D_WaitReady(pAt25);\r
381 \r
382     return 0;\r
383 }\r
384 \r
385 \r
386 /**\r
387  * \brief Writes data at the specified address on the serial firmware dataflash. The\r
388  * page(s) to program must have been erased prior to writing. This function\r
389  * handles page boundary crossing automatically.\r
390  *\r
391  * \param pAt25  Pointer to an AT25 driver instance.\r
392  * \param pData  Data buffer.\r
393  * \param size  Number of bytes in buffer.\r
394  * \param address  Write address.\r
395  *\r
396  * \return 0 if successful; otherwise, returns AT25_ERROR_PROGRAM is there has\r
397  * been an error during the data programming.\r
398  */\r
399 unsigned char AT25D_Write(\r
400     At25 *pAt25,\r
401     unsigned char *pData,\r
402     unsigned int size,\r
403     unsigned int address)\r
404 {\r
405     unsigned int pageSize;\r
406     unsigned int writeSize;\r
407     unsigned char error;\r
408     unsigned char status;\r
409     unsigned int i = 0;\r
410 \r
411     assert(pAt25);\r
412     assert(pData);\r
413 \r
414     /* Retrieve device page size */\r
415     pageSize = AT25_PageSize(pAt25);\r
416 \r
417     /* Program one page after the other */\r
418     while (size > 0) {\r
419         /* Compute number of bytes to program in page */\r
420         writeSize = min(size, pageSize - (address % pageSize));\r
421 \r
422         /* Enable critical write operation */\r
423         AT25D_EnableWrite(pAt25);\r
424 \r
425         /* Program page */\r
426         if (AT25_ManId(pAt25) == SST_SPI_FLASH) {\r
427 \r
428             error = AT25_SendCommand(pAt25, AT25_SEQUENTIAL_PROGRAM_1, 4,\r
429                                pData, 2, address, 0, 0);\r
430             \r
431             assert(!error);\r
432     \r
433             /* Wait for transfer to finish */\r
434             AT25D_Wait(pAt25);\r
435             /* Poll the Serial flash status register until the operation is achieved */\r
436             AT25D_WaitReady(pAt25);\r
437 \r
438             for (i = 2; i < pageSize; i += 2) {\r
439                 error = AT25_SendCommand(pAt25, AT25_SEQUENTIAL_PROGRAM_1, 1,\r
440                                    pData + i, 2, 0, 0, 0);\r
441 \r
442                 assert(!error);\r
443         \r
444                 /* Wait for transfer to finish */\r
445                 AT25D_Wait(pAt25);\r
446                 /* Poll the Serial flash status register until the operation is achieved */\r
447                 AT25D_WaitReady(pAt25);\r
448             }\r
449         \r
450         }\r
451         else {\r
452         error = AT25_SendCommand(pAt25, AT25_BYTE_PAGE_PROGRAM, 4,\r
453                            pData, writeSize, address, 0, 0);\r
454 \r
455         assert(!error);\r
456 \r
457         /* Wait for transfer to finish */\r
458         AT25D_Wait(pAt25);\r
459         /* Poll the Serial flash status register until the operation is achieved */\r
460         AT25D_WaitReady(pAt25);\r
461 \r
462         }\r
463         \r
464         /* Make sure that write was without error */\r
465         status = AT25D_ReadStatus(pAt25);\r
466         if ((status & AT25_STATUS_EPE) == AT25_STATUS_EPE_ERROR) {\r
467 \r
468             return AT25_ERROR_PROGRAM;\r
469         }\r
470 \r
471         pData += writeSize;\r
472         size -= writeSize;\r
473         address += writeSize;\r
474     }\r
475 \r
476     /* Enable critical write operation */\r
477     AT25D_DisableWrite(pAt25);\r
478 \r
479     return 0;\r
480 }\r
481 \r
482 /**\r
483  * \brief Reads data from the specified address on the serial flash.\r
484  *\r
485  * \param pAt25  Pointer to an AT25 driver instance.\r
486  * \param pData  Data buffer.\r
487  * \param size  Number of bytes to read.\r
488  * \param address  Read address.\r
489  *\r
490  * \return 0 if successful; otherwise, fail.\r
491  */\r
492 unsigned char AT25D_Read(\r
493     At25 *pAt25,\r
494     unsigned char *pData,\r
495     unsigned int size,\r
496     unsigned int address)\r
497 {\r
498     unsigned char error;\r
499 \r
500     /* Start a read operation */\r
501     error = AT25_SendCommand(pAt25, AT25_READ_ARRAY_LF, 4, pData, size, address, 0, 0);\r
502     assert(!error);\r
503 \r
504     /* Wait for transfer to finish */\r
505     AT25D_Wait(pAt25);\r
506 \r
507     return error;\r
508 }\r
509 \r