]> git.sur5r.net Git - freertos/blob - FreeRTOS/Demo/CORTEX_M7_SAMV71_Xplained/libchip_samv7/source/flashd.c
Update version number ready for V8.2.1 release.
[freertos] / FreeRTOS / Demo / CORTEX_M7_SAMV71_Xplained / libchip_samv7 / source / flashd.c
1 /* ----------------------------------------------------------------------------\r
2  *         SAM Software Package License\r
3  * ----------------------------------------------------------------------------\r
4  * Copyright (c) 2012, 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 /** \addtogroup flashd_module Flash Memory Interface\r
31  * The flash driver manages the programming, erasing, locking and unlocking sequences\r
32  * with dedicated commands.\r
33  *\r
34  * To implement flash programing operation, the user has to follow these few steps :\r
35  * <ul>\r
36  * <li>Configue flash wait states to initializes the flash. </li>\r
37  * <li>Checks whether a region to be programmed is locked. </li>\r
38  * <li>Unlocks the user region to be programmed if the region have locked before.</li>\r
39  * <li>Erases the user page before program (optional).</li>\r
40  * <li>Writes the user page from the page buffer.</li>\r
41  * <li>Locks the region of programmed area if any.</li>\r
42  * </ul>\r
43  *\r
44  * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption.\r
45  * A check of this validity and padding for 32-bit alignment should be done in write algorithm.\r
46 \r
47  * Lock/unlock range associated with the user address range is automatically translated.\r
48  *\r
49  * This security bit can be enabled through the command "Set General Purpose NVM Bit 0".\r
50  *\r
51  * A 128-bit factory programmed unique ID could be read to serve several purposes.\r
52  *\r
53  * The driver accesses the flash memory by calling the lowlevel module provided in \ref efc_module.\r
54  * For more accurate information, please look at the EEFC section of the Datasheet.\r
55  *\r
56  * Related files :\n\r
57  * \ref flashd.c\n\r
58  * \ref flashd.h.\n\r
59  * \ref efc.c\n\r
60  * \ref efc.h.\n\r
61  */\r
62 /*@{*/\r
63 /*@}*/\r
64 \r
65 \r
66 /**\r
67  * \file\r
68  *\r
69  * The flash driver provides the unified interface for flash program operations.\r
70  *\r
71  */\r
72 \r
73 /*----------------------------------------------------------------------------\r
74  *        Headers\r
75  *----------------------------------------------------------------------------*/\r
76 #include "chip.h"\r
77 \r
78 #include <string.h>\r
79 #include <assert.h>\r
80 \r
81 /*----------------------------------------------------------------------------\r
82  *        Definitions\r
83  *----------------------------------------------------------------------------*/\r
84 \r
85 #define GPNVM_NUM_MAX    8\r
86 \r
87 /*----------------------------------------------------------------------------\r
88  *        Local variables\r
89  *----------------------------------------------------------------------------*/\r
90 \r
91 static uint32_t _pdwPageBuffer[IFLASH_PAGE_SIZE/sizeof(uint32_t)] ;\r
92 static uint32_t _dwUseIAP = 1; /* Use IAP interface by default. */\r
93 \r
94 /*----------------------------------------------------------------------------\r
95  *        Local macros\r
96  *----------------------------------------------------------------------------*/\r
97 \r
98 #define min( a, b ) (((a) < (b)) ? (a) : (b))\r
99 \r
100 /*----------------------------------------------------------------------------\r
101  *        Local functions\r
102  *----------------------------------------------------------------------------*/\r
103 \r
104 \r
105 /**\r
106  * \brief Computes the lock range associated with the given address range.\r
107  *\r
108  * \param dwStart  Start address of lock range.\r
109  * \param dwEnd  End address of lock range.\r
110  * \param pdwActualStart  Actual start address of lock range.\r
111  * \param pdwActualEnd  Actual end address of lock range.\r
112  */\r
113 static void ComputeLockRange( uint32_t dwStart, uint32_t dwEnd, uint32_t *pdwActualStart, uint32_t *pdwActualEnd )\r
114 {\r
115     Efc* pStartEfc ;\r
116     Efc* pEndEfc ;\r
117     uint16_t wStartPage ;\r
118     uint16_t wEndPage ;\r
119     uint16_t wNumPagesInRegion ;\r
120     uint16_t wActualStartPage ;\r
121     uint16_t wActualEndPage ;\r
122 \r
123     /* Convert start and end address in page numbers */\r
124     EFC_TranslateAddress( &pStartEfc, dwStart, &wStartPage, 0 ) ;\r
125     EFC_TranslateAddress( &pEndEfc, dwEnd, &wEndPage, 0 ) ;\r
126 \r
127     /* Find out the first page of the first region to lock */\r
128     wNumPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ;\r
129     wActualStartPage = wStartPage - (wStartPage % wNumPagesInRegion) ;\r
130     wActualEndPage = wEndPage ;\r
131 \r
132     if ( (wEndPage % wNumPagesInRegion) != 0 )\r
133     {\r
134         wActualEndPage += wNumPagesInRegion - (wEndPage % wNumPagesInRegion) ;\r
135     }\r
136     /* Store actual page numbers */\r
137     EFC_ComputeAddress( pStartEfc, wActualStartPage, 0, pdwActualStart ) ;\r
138     EFC_ComputeAddress( pEndEfc, wActualEndPage, 0, pdwActualEnd ) ;\r
139     TRACE_DEBUG( "Actual lock range is 0x%06X - 0x%06X\n\r",\r
140             (unsigned int)*pdwActualStart, (unsigned int)*pdwActualEnd ) ;\r
141 }\r
142 \r
143 \r
144 /*----------------------------------------------------------------------------\r
145  *        Exported functions\r
146  *----------------------------------------------------------------------------*/\r
147 \r
148 /**\r
149  * \brief Initializes the flash driver.\r
150  *\r
151  * \param dwMCk     Master clock frequency in Hz.\r
152  * \param dwUseIAP  0: use EEFC controller interface, 1: use IAP interface.\r
153  *                  dwUseIAP should be set to 1 when running out of flash.\r
154  */\r
155 \r
156 extern void FLASHD_Initialize( uint32_t dwMCk, uint32_t dwUseIAP )\r
157 {\r
158     dwMCk = dwMCk; /* avoid warnings */\r
159 \r
160     EFC_DisableFrdyIt( EFC ) ;\r
161     _dwUseIAP = dwUseIAP ;\r
162 }\r
163 \r
164 /**\r
165  * \brief Erases the entire flash.\r
166  *\r
167  * \param dwAddress  Flash start address.\r
168  * \return 0 if successful; otherwise returns an error code.\r
169  */\r
170 extern uint32_t FLASHD_Erase( uint32_t dwAddress )\r
171 {\r
172     Efc* pEfc ;\r
173     uint16_t wPage ;\r
174     uint16_t wOffset ;\r
175     uint32_t dwError ;\r
176 \r
177     assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ;\r
178 \r
179     /* Translate write address */\r
180     EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ;\r
181     dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EA, 0, _dwUseIAP ) ;\r
182 \r
183     return dwError ;\r
184 }\r
185 \r
186 /**\r
187  * \brief Erases flash by sector.\r
188  *\r
189  * \param dwAddress  Start address of be erased sector.\r
190  *\r
191  * \return 0 if successful; otherwise returns an error code.\r
192  */\r
193 extern uint32_t FLASHD_EraseSector( uint32_t dwAddress )\r
194 {\r
195     Efc* pEfc ;\r
196     uint16_t wPage ;\r
197     uint16_t wOffset ;\r
198     uint32_t dwError ;\r
199 \r
200     assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ;\r
201 \r
202     /* Translate write address */\r
203     EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ;\r
204     dwError = EFC_PerformCommand( pEfc, EFC_FCMD_ES, wPage, _dwUseIAP ) ;\r
205 \r
206     return dwError ;\r
207 }\r
208 \r
209 /**\r
210  * \brief Erases flash by pages.\r
211  *\r
212  * \param dwAddress  Start address of be erased pages.\r
213  * \param dwPageNum  Number of pages to be erased with EPA command (4, 8, 16, 32)\r
214  *\r
215  * \return 0 if successful; otherwise returns an error code.\r
216  */\r
217 extern uint32_t FLASHD_ErasePages( uint32_t dwAddress, uint32_t dwPageNum )\r
218 {\r
219     Efc* pEfc ;\r
220     uint16_t wPage ;\r
221     uint16_t wOffset ;\r
222     uint32_t dwError ;\r
223     static uint32_t dwFarg ;\r
224 \r
225     assert( (dwAddress >=IFLASH_ADDR) || (dwAddress <= (IFLASH_ADDR + IFLASH_SIZE)) ) ;\r
226 \r
227     /* Translate write address */\r
228     EFC_TranslateAddress( &pEfc, dwAddress, &wPage, &wOffset ) ;\r
229 \r
230     /* Get FARG field for EPA command:\r
231      * The first page to be erased is specified in the FARG[15:2] field of\r
232      * the MC_FCR register. The first page number must be modulo 4, 8,16 or 32\r
233      * according to the number of pages to erase at the same time.\r
234      *\r
235      * The 2 lowest bits of the FARG field define the number of pages to\r
236      * be erased (FARG[1:0]).\r
237      */\r
238     if (dwPageNum == 32)\r
239     {\r
240         wPage &= ~(32u - 1u);\r
241         dwFarg = (wPage << 2) | 3; /* 32 pages */\r
242     }\r
243     else if (dwPageNum == 16)\r
244     {\r
245         wPage &= ~(16u - 1u);\r
246         dwFarg = (wPage << 2) | 2; /* 16 pages */\r
247     }\r
248     else if (dwPageNum == 8)\r
249     {\r
250         wPage &= ~(8u - 1u);\r
251         dwFarg = (wPage << 2) | 1; /* 8 pages */\r
252     }\r
253     else\r
254     {\r
255         wPage &= ~(4u - 1u);\r
256         dwFarg = (wPage << 2) | 0; /* 4 pages */\r
257     }\r
258 \r
259     dwError = EFC_PerformCommand( pEfc, EFC_FCMD_EPA, dwFarg, _dwUseIAP ) ;\r
260 \r
261     return dwError ;\r
262 }\r
263 \r
264 \r
265 /**\r
266  * \brief Writes a data buffer in the internal flash\r
267  *\r
268  * \note This function works in polling mode, and thus only returns when the\r
269  * data has been effectively written.\r
270  * \param address  Write address.\r
271  * \param pBuffer  Data buffer.\r
272  * \param size  Size of data buffer in bytes.\r
273  * \return 0 if successful, otherwise returns an error code.\r
274  */\r
275 extern uint32_t FLASHD_Write( uint32_t dwAddress, const void *pvBuffer, uint32_t dwSize )\r
276 {\r
277     Efc* pEfc ;\r
278     uint16_t page ;\r
279     uint16_t offset ;\r
280     uint32_t writeSize ;\r
281     uint32_t pageAddress ;\r
282     uint16_t padding ;\r
283     uint32_t dwError ;\r
284     uint32_t dwIdx ;\r
285     uint32_t *pAlignedDestination ;\r
286     uint8_t  *pucPageBuffer = (uint8_t *)_pdwPageBuffer;\r
287 \r
288     assert( pvBuffer ) ;\r
289     assert( dwAddress >=IFLASH_ADDR ) ;\r
290     assert( (dwAddress + dwSize) <= (IFLASH_ADDR + IFLASH_SIZE) ) ;\r
291 \r
292     /* Translate write address */\r
293     EFC_TranslateAddress( &pEfc, dwAddress, &page, &offset ) ;\r
294 \r
295     /* Write all pages */\r
296     while ( dwSize > 0 )\r
297     {\r
298         /* Copy data in temporary buffer to avoid alignment problems */\r
299         writeSize = min((uint32_t)IFLASH_PAGE_SIZE - offset, dwSize ) ;\r
300         EFC_ComputeAddress(pEfc, page, 0, &pageAddress ) ;\r
301         padding = IFLASH_PAGE_SIZE - offset - writeSize ;\r
302 \r
303         /* Pre-buffer data */\r
304         memcpy( pucPageBuffer, (void *) pageAddress, offset);\r
305 \r
306         /* Buffer data */\r
307         memcpy( pucPageBuffer + offset, pvBuffer, writeSize);\r
308 \r
309         /* Post-buffer data */\r
310         memcpy( pucPageBuffer + offset + writeSize, (void *) (pageAddress + offset + writeSize), padding);\r
311 \r
312         /* Write page\r
313          * Writing 8-bit and 16-bit data is not allowed and may lead to unpredictable data corruption\r
314          */\r
315         pAlignedDestination = (uint32_t*)pageAddress ;\r
316         for (dwIdx = 0; dwIdx < (IFLASH_PAGE_SIZE / sizeof(uint32_t)); ++ dwIdx) {\r
317             *pAlignedDestination++ = _pdwPageBuffer[dwIdx];\r
318         }\r
319 \r
320         /* Note for sam3s16 and sam4s:\r
321          * It is not possible to use Erase and write Command (EWP) on all Flash (this\r
322          * command is available on the First 2 Small Sector, 16K Bytes). For the next\r
323          * block, Erase them first then use Write page command.\r
324          */\r
325         /* Send writing command */\r
326         dwError = EFC_PerformCommand( pEfc, EFC_FCMD_WP, page, _dwUseIAP ) ;\r
327         if ( dwError )\r
328         {\r
329             return dwError ;\r
330         }\r
331 \r
332         /* Progression */\r
333         pvBuffer = (void *)((uint32_t) pvBuffer + writeSize) ;\r
334         dwSize -= writeSize ;\r
335         page++;\r
336         offset = 0;\r
337     }\r
338 \r
339     return 0 ;\r
340 }\r
341 /**\r
342  * \brief Locks all the regions in the given address range. The actual lock range is\r
343  * reported through two output parameters.\r
344  *\r
345  * \param start  Start address of lock range.\r
346  * \param end    End address of lock range.\r
347  * \param pActualStart  Start address of the actual lock range (optional).\r
348  * \param pActualEnd  End address of the actual lock range (optional).\r
349  * \return 0 if successful, otherwise returns an error code.\r
350  */\r
351 extern uint32_t FLASHD_Lock( uint32_t start, uint32_t end, uint32_t *pActualStart, uint32_t *pActualEnd )\r
352 {\r
353     Efc *pEfc ;\r
354     uint32_t actualStart, actualEnd ;\r
355     uint16_t startPage, endPage ;\r
356     uint32_t dwError ;\r
357     uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;\r
358 \r
359     /* Compute actual lock range and store it */\r
360     ComputeLockRange( start, end, &actualStart, &actualEnd ) ;\r
361     if ( pActualStart != NULL )\r
362     {\r
363         *pActualStart = actualStart ;\r
364     }\r
365     if ( pActualEnd != NULL )\r
366     {\r
367         *pActualEnd = actualEnd;\r
368     }\r
369 \r
370     /* Compute page numbers */\r
371     EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ;\r
372     EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ;\r
373 \r
374     /* Lock all pages */\r
375     while ( startPage < endPage )\r
376     {\r
377         dwError = EFC_PerformCommand( pEfc, EFC_FCMD_SLB, startPage, _dwUseIAP ) ;\r
378         if ( dwError )\r
379         {\r
380             return dwError ;\r
381         }\r
382         startPage += numPagesInRegion;\r
383     }\r
384 \r
385     return 0 ;\r
386 }\r
387 \r
388 /**\r
389  * \brief Unlocks all the regions in the given address range. The actual unlock range is\r
390  * reported through two output parameters.\r
391  * \param start  Start address of unlock range.\r
392  * \param end  End address of unlock range.\r
393  * \param pActualStart  Start address of the actual unlock range (optional).\r
394  * \param pActualEnd  End address of the actual unlock range (optional).\r
395  * \return 0 if successful, otherwise returns an error code.\r
396  */\r
397 extern uint32_t FLASHD_Unlock( uint32_t start, uint32_t end, uint32_t *pActualStart, uint32_t *pActualEnd )\r
398 {\r
399     Efc* pEfc ;\r
400     uint32_t actualStart, actualEnd ;\r
401     uint16_t startPage, endPage ;\r
402     uint32_t dwError ;\r
403     uint16_t numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE;\r
404 \r
405     /* Compute actual unlock range and store it */\r
406     ComputeLockRange(start, end, &actualStart, &actualEnd);\r
407     if ( pActualStart != NULL )\r
408     {\r
409         *pActualStart = actualStart ;\r
410     }\r
411     if ( pActualEnd != NULL )\r
412     {\r
413         *pActualEnd = actualEnd ;\r
414     }\r
415 \r
416     /* Compute page numbers */\r
417     EFC_TranslateAddress( &pEfc, actualStart, &startPage, 0 ) ;\r
418     EFC_TranslateAddress( 0, actualEnd, &endPage, 0 ) ;\r
419 \r
420     /* Unlock all pages */\r
421     while ( startPage < endPage )\r
422     {\r
423         dwError = EFC_PerformCommand( pEfc, EFC_FCMD_CLB, startPage, _dwUseIAP ) ;\r
424         if ( dwError )\r
425         {\r
426             return dwError ;\r
427         }\r
428         startPage += numPagesInRegion ;\r
429     }\r
430     return 0 ;\r
431 }\r
432 \r
433 /**\r
434  * \brief Returns the number of locked regions inside the given address range.\r
435  *\r
436  * \param start  Start address of range\r
437  * \param end    End address of range.\r
438  */\r
439 extern uint32_t FLASHD_IsLocked( uint32_t start, uint32_t end )\r
440 {\r
441     uint32_t i, j;\r
442     Efc *pEfc ;\r
443     uint16_t startPage, endPage ;\r
444     uint8_t startRegion, endRegion ;\r
445     uint32_t numPagesInRegion ;\r
446     uint32_t status[IFLASH_NB_OF_LOCK_BITS / 32u] ;\r
447     uint32_t numLockedRegions = 0 ;\r
448 \r
449     assert( end >= start ) ;\r
450     assert( (start >=IFLASH_ADDR) && (end <= IFLASH_ADDR + IFLASH_SIZE) ) ;\r
451 \r
452     /* Compute page numbers */\r
453     EFC_TranslateAddress( &pEfc, start, &startPage, 0 ) ;\r
454     EFC_TranslateAddress( 0, end, &endPage, 0 ) ;\r
455 \r
456     /* Compute region numbers */\r
457     numPagesInRegion = IFLASH_LOCK_REGION_SIZE / IFLASH_PAGE_SIZE ;\r
458     startRegion = startPage / numPagesInRegion ;\r
459     endRegion = endPage / numPagesInRegion ;\r
460     if ((endPage % numPagesInRegion) != 0)\r
461     {\r
462         endRegion++ ;\r
463     }\r
464 \r
465     /* Retrieve lock status */\r
466     EFC_PerformCommand( pEfc, EFC_FCMD_GLB, 0, _dwUseIAP ) ;\r
467     for (i = 0; i < (IFLASH_NB_OF_LOCK_BITS / 32u); i++)\r
468     {\r
469         status[i] = EFC_GetResult( pEfc ) ;\r
470     }\r
471 \r
472     /* Check status of each involved region */\r
473     while ( startRegion < endRegion )\r
474     {\r
475         i = startRegion / 32u;\r
476         j = startRegion % 32u;\r
477         if ( (status[i] & (1 << j)) != 0 )\r
478         {\r
479             numLockedRegions++ ;\r
480         }\r
481         startRegion++ ;\r
482     }\r
483 \r
484     return numLockedRegions ;\r
485 }\r
486 \r
487 /**\r
488  * \brief Check if the given GPNVM bit is set or not.\r
489  *\r
490  * \param gpnvm  GPNVM bit index.\r
491  * \returns 1 if the given GPNVM bit is currently set; otherwise returns 0.\r
492  */\r
493 extern uint32_t FLASHD_IsGPNVMSet( uint8_t ucGPNVM )\r
494 {\r
495     uint32_t dwStatus ;\r
496 \r
497     assert( ucGPNVM < GPNVM_NUM_MAX ) ;\r
498 \r
499     /* Get GPNVMs status */\r
500     EFC_PerformCommand( EFC, EFC_FCMD_GFB, 0, _dwUseIAP ) ;\r
501     dwStatus = EFC_GetResult( EFC ) ;\r
502 \r
503     /* Check if GPNVM is set */\r
504     if ( (dwStatus & (1 << ucGPNVM)) != 0 )\r
505     {\r
506         return 1 ;\r
507     }\r
508     else\r
509     {\r
510         return 0 ;\r
511     }\r
512 }\r
513 \r
514 /**\r
515  * \brief Sets the selected GPNVM bit.\r
516  *\r
517  * \param gpnvm  GPNVM bit index.\r
518  * \returns 0 if successful; otherwise returns an error code.\r
519  */\r
520 extern uint32_t FLASHD_SetGPNVM( uint8_t ucGPNVM )\r
521 {\r
522     assert( ucGPNVM < GPNVM_NUM_MAX ) ;\r
523 \r
524     if ( !FLASHD_IsGPNVMSet( ucGPNVM ) )\r
525     {\r
526         return EFC_PerformCommand( EFC, EFC_FCMD_SFB, ucGPNVM, _dwUseIAP ) ;\r
527     }\r
528     else\r
529     {\r
530         return 0 ;\r
531     }\r
532 }\r
533 \r
534 /**\r
535  * \brief Clears the selected GPNVM bit.\r
536  *\r
537  * \param gpnvm  GPNVM bit index.\r
538  * \returns 0 if successful; otherwise returns an error code.\r
539  */\r
540 extern uint32_t FLASHD_ClearGPNVM( uint8_t ucGPNVM )\r
541 {\r
542     assert( ucGPNVM < GPNVM_NUM_MAX ) ;\r
543 \r
544     if ( FLASHD_IsGPNVMSet( ucGPNVM ) )\r
545     {\r
546         return EFC_PerformCommand( EFC, EFC_FCMD_CFB, ucGPNVM, _dwUseIAP ) ;\r
547     }\r
548     else\r
549     {\r
550         return 0 ;\r
551     }\r
552 }\r
553 \r
554 /**\r
555  * \brief Read the unique ID.\r
556  *\r
557  * \param pdwUniqueID pointer on a 4bytes char containing the unique ID value.\r
558  * \returns 0 if successful; otherwise returns an error code.\r
559  */\r
560 #ifdef __ICCARM__\r
561 extern __ramfunc uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID )\r
562 #else\r
563     __attribute__ ((section (".ramfunc")))\r
564 uint32_t FLASHD_ReadUniqueID( uint32_t* pdwUniqueID )\r
565 #endif\r
566 {\r
567     uint32_t status ;\r
568     if (pdwUniqueID == NULL) {\r
569         return 1;\r
570     }\r
571 \r
572     pdwUniqueID[0] = 0 ;\r
573     pdwUniqueID[1] = 0 ;\r
574     pdwUniqueID[2] = 0 ;\r
575     pdwUniqueID[3] = 0 ;\r
576 \r
577     /* Send the Start Read unique Identifier command (STUI) by writing the Flash\r
578        Command Register with the STUI command.*/\r
579     EFC->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EFC_FCMD_STUI;\r
580 \r
581     /* When the Unique Identifier is ready to be read, the FRDY bit in the Flash\r
582        Programming Status Register (EEFC_FSR) falls. */\r
583     do\r
584     {\r
585         status = EFC->EEFC_FSR ;\r
586     } while ( (status & EEFC_FSR_FRDY) == EEFC_FSR_FRDY ) ;\r
587 \r
588     /* The Unique Identifier is located in the first 128 bits of the Flash\r
589        memory mapping. So, at the address 0x400000-0x40000F. */\r
590     pdwUniqueID[0] = *(uint32_t *)IFLASH_ADDR;\r
591     pdwUniqueID[1] = *(uint32_t *)(IFLASH_ADDR + 4);\r
592     pdwUniqueID[2] = *(uint32_t *)(IFLASH_ADDR + 8);\r
593     pdwUniqueID[3] = *(uint32_t *)(IFLASH_ADDR + 12);\r
594 \r
595     /* To stop the Unique Identifier mode, the user needs to send the Stop Read\r
596        unique Identifier command (SPUI) by writing the Flash Command Register\r
597        with the SPUI command. */\r
598     EFC->EEFC_FCR = EEFC_FCR_FKEY_PASSWD | EFC_FCMD_SPUI ;\r
599 \r
600     /* When the Stop read Unique Unique Identifier command (SPUI) has been\r
601        performed, the FRDY bit in the Flash Programming Status Register (EEFC_FSR)\r
602        rises. */\r
603     do\r
604     {\r
605         status = EFC->EEFC_FSR ;\r
606     } while ( (status & EEFC_FSR_FRDY) != EEFC_FSR_FRDY ) ;\r
607 \r
608     return 0;\r
609 }\r
610 \r