1 /**************************************************************************//**
2 * @file fmc.c
3 * @version V1.00
4 * @brief M460 series FMC driver source file
5 *
6 * @copyright SPDX-License-Identifier: Apache-2.0
7 * @copyright Copyright (C) 2021 Nuvoton Technology Corp. All rights reserved.
8 *****************************************************************************/
9
10 #include <stdio.h>
11
12 #include "NuMicro.h"
13
14
15 /** @addtogroup Standard_Driver Standard Driver
16 @{
17 */
18
19 /** @addtogroup FMC_Driver FMC Driver
20 @{
21 */
22
23
24 /** @addtogroup FMC_EXPORTED_FUNCTIONS FMC Exported Functions
25 @{
26 */
27
28 int32_t g_FMC_i32ErrCode = 0; /*!< FMC global error code */
29
30 /**
31 * @brief Disable FMC ISP function.
32 * @return None
33 */
FMC_Close(void)34 void FMC_Close(void)
35 {
36 FMC->ISPCTL &= ~FMC_ISPCTL_ISPEN_Msk;
37 }
38
39 /**
40 * @brief Config XOM Region
41 * @param[in] u32XomNum The XOM number(0~3)
42 * @param[in] u32XomBase The XOM region base address.
43 * @param[in] u8XomPage The XOM page number of region size.
44 *
45 * @retval 0 Success
46 * @retval 1 XOM is has already actived.
47 * @retval -1 Program failed.
48 * @retval -2 Invalid XOM number.
49 *
50 * @details Program XOM base address and XOM size(page)
51 * @note Global error code g_FMC_i32ErrCode
52 * -1 Program failed or program time-out
53 * -2 Invalid XOM number.
54 */
FMC_ConfigXOM(uint32_t u32XomNum,uint32_t u32XomBase,uint8_t u8XomPage)55 int32_t FMC_ConfigXOM(uint32_t u32XomNum, uint32_t u32XomBase, uint8_t u8XomPage)
56 {
57 int32_t ret = 0;
58 int32_t i32TimeOutCnt;
59
60 g_FMC_i32ErrCode = 0;
61
62 if(u32XomNum >= 4UL)
63 {
64 g_FMC_i32ErrCode = -2;
65 ret = -2;
66 }
67
68 if(ret == 0)
69 {
70 ret = FMC_GetXOMState(u32XomNum);
71 }
72
73 if(ret == 0)
74 {
75 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
76 FMC->ISPADDR = FMC_XOM_BASE + (u32XomNum * 0x10u);
77 FMC->ISPDAT = u32XomBase;
78 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
79 i32TimeOutCnt = FMC_TIMEOUT_WRITE;
80 while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk)
81 {
82 if( i32TimeOutCnt-- <= 0)
83 {
84 g_FMC_i32ErrCode = -1;
85 ret = -1;
86 break;
87 }
88 }
89
90 if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
91 {
92 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
93 g_FMC_i32ErrCode = -1;
94 ret = -1;
95 }
96 }
97
98 if(ret == 0)
99 {
100 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
101 FMC->ISPADDR = FMC_XOM_BASE + (u32XomNum * 0x10u + 0x04u);
102 FMC->ISPDAT = u8XomPage;
103 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
104 i32TimeOutCnt = FMC_TIMEOUT_WRITE;
105 while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk)
106 {
107 if( i32TimeOutCnt-- <= 0)
108 {
109 g_FMC_i32ErrCode = -1;
110 ret = -1;
111 break;
112 }
113 }
114
115 if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
116 {
117 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
118 g_FMC_i32ErrCode = -1;
119 ret = -1;
120 }
121 }
122
123 if(ret == 0)
124 {
125 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
126 FMC->ISPADDR = FMC_XOM_BASE + (u32XomNum * 0x10u + 0x08u);
127 FMC->ISPDAT = 0u;
128 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
129 i32TimeOutCnt = FMC_TIMEOUT_WRITE;
130 while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk)
131 {
132 if( i32TimeOutCnt-- <= 0)
133 {
134 g_FMC_i32ErrCode = -1;
135 ret = -1;
136 break;
137 }
138 }
139
140 if(FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
141 {
142 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
143 g_FMC_i32ErrCode = -1;
144 ret = -1;
145 }
146 }
147
148 return ret;
149 }
150
151 /**
152 * @brief Execute FMC_ISPCMD_PAGE_ERASE command to erase a flash page. The page size is 4096 bytes.
153 * @param[in] u32PageAddr Address of the flash page to be erased.
154 * It must be a 4096 bytes aligned address.
155 * @return ISP page erase success or not.
156 * @retval 0 Success
157 * @retval -1 Erase failed
158 *
159 * @note Global error code g_FMC_i32ErrCode
160 * -1 Erase failed or erase time-out
161 */
FMC_Erase(uint32_t u32PageAddr)162 int32_t FMC_Erase(uint32_t u32PageAddr)
163 {
164 int32_t ret = 0;
165 int32_t i32TimeOutCnt;
166
167 g_FMC_i32ErrCode = 0;
168
169 FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
170 FMC->ISPADDR = u32PageAddr;
171 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
172
173 i32TimeOutCnt = FMC_TIMEOUT_ERASE;
174 while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk)
175 {
176 if( i32TimeOutCnt-- <= 0)
177 {
178 g_FMC_i32ErrCode = -1;
179 ret = -1;
180 break;
181 }
182 }
183
184 if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
185 {
186 FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
187 g_FMC_i32ErrCode = -1;
188 ret = -1;
189 }
190
191 return ret;
192 }
193
194
195 /**
196 * @brief Execute FMC_ISPCMD_BANK_ERASE command to erase a flash block.
197 * @param[in] u32BankAddr Base address of the flash bank to be erased.
198 * @return ISP page erase success or not.
199 * @retval 0 Success
200 * @retval -1 Erase failed
201 *
202 * @note Global error code g_FMC_i32ErrCode
203 * -1 Erase failed or erase time-out
204 */
FMC_Erase_Bank(uint32_t u32BankAddr)205 int32_t FMC_Erase_Bank(uint32_t u32BankAddr)
206 {
207 int32_t ret = 0;
208 int32_t i32TimeOutCnt;
209
210 g_FMC_i32ErrCode = 0;
211
212 FMC->ISPCMD = FMC_ISPCMD_BANK_ERASE;
213 FMC->ISPADDR = u32BankAddr;
214 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
215
216 i32TimeOutCnt = FMC_TIMEOUT_ERASE;
217 while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk)
218 {
219 if( i32TimeOutCnt-- <= 0)
220 {
221 g_FMC_i32ErrCode = -1;
222 ret = -1;
223 break;
224 }
225 }
226
227 if (FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
228 {
229 FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
230 g_FMC_i32ErrCode = -1;
231 ret = -1;
232 }
233 return ret;
234 }
235
236 /**
237 * @brief Execute Erase XOM Region
238 *
239 * @param[in] u32XomNum The XOMRn(n=0~3)
240 *
241 * @return XOM erase success or not.
242 * @retval 0 Success
243 * @retval -1 Erase failed
244 * @retval -2 Invalid XOM number.
245 *
246 * @details Execute FMC_ISPCMD_PAGE_ERASE command to erase XOM.
247 *
248 * @note Global error code g_FMC_i32ErrCode
249 * -1 Program failed or program time-out
250 * -2 Invalid XOM number.
251 */
FMC_EraseXOM(uint32_t u32XomNum)252 int32_t FMC_EraseXOM(uint32_t u32XomNum)
253 {
254 uint32_t u32Addr;
255 int32_t i32Active, err = 0;
256 int32_t i32TimeOutCnt;
257
258 g_FMC_i32ErrCode = 0;
259
260 if(u32XomNum >= 4UL)
261 {
262 err = -2;
263 }
264
265 if(err == 0)
266 {
267 i32Active = FMC_GetXOMState(u32XomNum);
268
269 if(i32Active)
270 {
271 switch(u32XomNum)
272 {
273 case 0u:
274 u32Addr = (FMC->XOMR0STS & 0xFFFFFF00u) >> 8u;
275 break;
276 case 1u:
277 u32Addr = (FMC->XOMR1STS & 0xFFFFFF00u) >> 8u;
278 break;
279 case 2u:
280 u32Addr = (FMC->XOMR2STS & 0xFFFFFF00u) >> 8u;
281 break;
282 case 3u:
283 u32Addr = (FMC->XOMR3STS & 0xFFFFFF00u) >> 8u;
284 break;
285 default:
286 /* Should not be here */
287 err = -2;
288 goto lexit;
289 }
290 FMC->ISPCMD = FMC_ISPCMD_PAGE_ERASE;
291 FMC->ISPADDR = u32Addr;
292 FMC->ISPDAT = 0x55aa03u;
293 FMC->ISPTRG = 0x1u;
294 #if ISBEN
295 __ISB();
296 #endif
297 i32TimeOutCnt = FMC_TIMEOUT_ERASE;
298 while(FMC->ISPTRG)
299 {
300 if( i32TimeOutCnt-- <= 0)
301 {
302 err = -1;
303 break;
304 }
305 }
306
307 /* Check ISPFF flag to know whether erase OK or fail. */
308 if(FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
309 {
310 FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
311 err = -1;
312 }
313 }
314 else
315 {
316 err = -1;
317 }
318 }
319
320 lexit:
321 g_FMC_i32ErrCode = err;
322 return err;
323 }
324
325 /**
326 * @brief Check the XOM is actived or not.
327 *
328 * @param[in] u32XomNum The xom number(0~3).
329 *
330 * @retval 1 XOM is actived.
331 * @retval 0 XOM is not actived.
332 * @retval -2 Invalid XOM number.
333 *
334 * @details To get specify XOMRn(n=0~3) active status
335 */
FMC_GetXOMState(uint32_t u32XomNum)336 int32_t FMC_GetXOMState(uint32_t u32XomNum)
337 {
338 uint32_t u32act;
339 int32_t ret = 0;
340
341 if(u32XomNum >= 4UL)
342 {
343 ret = -2;
344 }
345
346 if(ret >= 0)
347 {
348 u32act = (((FMC->XOMSTS) & 0xful) & (1ul << u32XomNum)) >> u32XomNum;
349 ret = (int32_t)u32act;
350 }
351 return ret;
352 }
353
354 /**
355 * @brief Get the current boot source.
356 * @return The current boot source.
357 * @retval 0 Is boot from APROM.
358 * @retval 1 Is boot from LDROM.
359 * @retval 2 Is boot from Boot Loader.
360 */
FMC_GetBootSource(void)361 int32_t FMC_GetBootSource (void)
362 {
363 if (FMC->ISPCTL & FMC_ISPCTL_BL_Msk)
364 {
365 return 2;
366 }
367 if (FMC->ISPCTL & FMC_ISPCTL_BS_Msk)
368 {
369 return 1;
370 }
371 return 0;
372 }
373
374
375 /**
376 * @brief Enable FMC ISP function
377 * @return None
378 */
FMC_Open(void)379 void FMC_Open(void)
380 {
381 FMC->ISPCTL |= FMC_ISPCTL_ISPEN_Msk;
382 }
383
384
385 /**
386 * @brief Execute FMC_ISPCMD_READ command to read a word from flash.
387 * @param[in] u32Addr Address of the flash location to be read.
388 * It must be a word aligned address.
389 * @return The word data read from specified flash address.
390 * Return 0xFFFFFFFF if read failed.
391 * @note Global error code g_FMC_i32ErrCode
392 * -1 Read time-out
393 */
FMC_Read(uint32_t u32Addr)394 uint32_t FMC_Read(uint32_t u32Addr)
395 {
396 int32_t i32TimeOutCnt;
397
398 g_FMC_i32ErrCode = 0;
399 FMC->ISPCMD = FMC_ISPCMD_READ;
400 FMC->ISPADDR = u32Addr;
401 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
402
403 i32TimeOutCnt = FMC_TIMEOUT_READ;
404 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk)
405 {
406 if( i32TimeOutCnt-- <= 0)
407 {
408 g_FMC_i32ErrCode = -1;
409 return 0xFFFFFFFF;
410 }
411 }
412
413 return FMC->ISPDAT;
414 }
415
416
417 /**
418 * @brief Execute FMC_ISPCMD_READ_64 command to read a double-word from flash.
419 * @param[in] u32addr Address of the flash location to be read.
420 * It must be a double-word aligned address.
421 * @param[out] u32data0 Place holder of word 0 read from flash address u32addr.
422 * @param[out] u32data1 Place holder of word 0 read from flash address u32addr+4.
423 * @return 0 Success
424 * @return -1 Failed
425 *
426 * @note Global error code g_FMC_i32ErrCode
427 * -1 Read time-out
428 */
FMC_Read_64(uint32_t u32addr,uint32_t * u32data0,uint32_t * u32data1)429 int32_t FMC_Read_64(uint32_t u32addr, uint32_t * u32data0, uint32_t * u32data1)
430 {
431 int32_t ret = 0;
432 int32_t i32TimeOutCnt;
433
434 g_FMC_i32ErrCode = 0;
435 FMC->ISPCMD = FMC_ISPCMD_READ_64;
436 FMC->ISPADDR = u32addr;
437 FMC->ISPDAT = 0x0UL;
438 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
439
440 i32TimeOutCnt = FMC_TIMEOUT_READ;
441 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk)
442 {
443 if( i32TimeOutCnt-- <= 0)
444 {
445 g_FMC_i32ErrCode = -1;
446 ret = -1;
447 break;
448 }
449 }
450
451 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
452 {
453 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
454 g_FMC_i32ErrCode = -1;
455 ret = -1;
456 }
457 else
458 {
459 *u32data0 = FMC->MPDAT0;
460 *u32data1 = FMC->MPDAT1;
461 }
462 return ret;
463 }
464
465
466 /**
467 * @brief Get the base address of Data Flash if enabled.
468 * @retval The base address of Data Flash
469 */
FMC_ReadDataFlashBaseAddr(void)470 uint32_t FMC_ReadDataFlashBaseAddr(void)
471 {
472 return FMC->DFBA;
473 }
474
475 /**
476 * @brief Set boot source from LDROM or APROM after next software reset
477 * @param[in] i32BootSrc
478 * 1: Boot from LDROM
479 * 0: Boot from APROM
480 * @return None
481 * @details This function is used to switch APROM boot or LDROM boot. User need to call
482 * FMC_SetBootSource to select boot source first, then use CPU reset or
483 * System Reset Request to reset system.
484 */
FMC_SetBootSource(int32_t i32BootSrc)485 void FMC_SetBootSource(int32_t i32BootSrc)
486 {
487 if(i32BootSrc)
488 {
489 FMC->ISPCTL |= FMC_ISPCTL_BS_Msk; /* Boot from LDROM */
490 }
491 else
492 {
493 FMC->ISPCTL &= ~FMC_ISPCTL_BS_Msk;/* Boot from APROM */
494 }
495 }
496
497 /**
498 * @brief Execute ISP FMC_ISPCMD_PROGRAM to program a word to flash.
499 * @param[in] u32Addr Address of the flash location to be programmed.
500 * It must be a word aligned address.
501 * @param[in] u32Data The word data to be programmed.
502 * @return 0 Success
503 * @return -1 Failed
504 *
505 * @note Global error code g_FMC_i32ErrCode
506 * -1 Program failed or time-out
507 */
FMC_Write(uint32_t u32Addr,uint32_t u32Data)508 int32_t FMC_Write(uint32_t u32Addr, uint32_t u32Data)
509 {
510 int32_t i32TimeOutCnt;
511
512 g_FMC_i32ErrCode = 0;
513 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
514 FMC->ISPADDR = u32Addr;
515 FMC->ISPDAT = u32Data;
516 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
517
518 i32TimeOutCnt = FMC_TIMEOUT_WRITE;
519 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk)
520 {
521 if( i32TimeOutCnt-- <= 0)
522 {
523 g_FMC_i32ErrCode = -1;
524 return -1;
525 }
526 }
527
528 return 0;
529 }
530
531 /**
532 * @brief Execute ISP FMC_ISPCMD_PROGRAM_64 to program a double-word to flash.
533 * @param[in] u32addr Address of the flash location to be programmed.
534 * It must be a double-word aligned address.
535 * @param[in] u32data0 The word data to be programmed to flash address u32addr.
536 * @param[in] u32data1 The word data to be programmed to flash address u32addr+4.
537 * @return 0 Success
538 * @return -1 Failed
539 *
540 * @note Global error code g_FMC_i32ErrCode
541 * -1 Program failed or time-out
542 */
FMC_Write8Bytes(uint32_t u32addr,uint32_t u32data0,uint32_t u32data1)543 int32_t FMC_Write8Bytes(uint32_t u32addr, uint32_t u32data0, uint32_t u32data1)
544 {
545 int32_t ret = 0;
546 int32_t i32TimeOutCnt;
547
548 g_FMC_i32ErrCode = 0;
549 FMC->ISPCMD = FMC_ISPCMD_PROGRAM_64;
550 FMC->ISPADDR = u32addr;
551 FMC->MPDAT0 = u32data0;
552 FMC->MPDAT1 = u32data1;
553 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
554
555 i32TimeOutCnt = FMC_TIMEOUT_WRITE;
556 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk)
557 {
558 if( i32TimeOutCnt-- <= 0)
559 {
560 g_FMC_i32ErrCode = -1;
561 ret = -1;
562 }
563 }
564
565 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
566 {
567 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
568 g_FMC_i32ErrCode = -1;
569 ret = -1;
570 }
571 return ret;
572 }
573
574
575 /**
576 * @brief Program Multi-Word data into specified address of flash.
577 * @param[in] u32Addr Start flash address in APROM where the data chunk to be programmed into.
578 * This address must be 8-bytes aligned to flash address.
579 * @param[in] pu32Buf Buffer that carry the data chunk.
580 * @param[in] u32Len Length of the data chunk in bytes.
581 * @retval >=0 Number of data bytes were programmed.
582 * @retval -1 Program failed.
583 * @retval -2 Invalid address.
584 *
585 * @note Global error code g_FMC_i32ErrCode
586 * -1 Program failed or time-out
587 * -2 Invalid address
588 */
FMC_WriteMultiple(uint32_t u32Addr,uint32_t pu32Buf[],uint32_t u32Len)589 int32_t FMC_WriteMultiple(uint32_t u32Addr, uint32_t pu32Buf[], uint32_t u32Len)
590 {
591 int i, idx, retval = 0;
592 int32_t i32TimeOutCnt;
593
594 g_FMC_i32ErrCode = 0;
595
596 if ((u32Addr >= FMC_APROM_END) || ((u32Addr % 8) != 0))
597 {
598 g_FMC_i32ErrCode = -2;
599 return -2;
600 }
601
602 u32Len = u32Len - (u32Len % 8); /* u32Len must be multiple of 8. */
603
604 idx = 0;
605
606 while (u32Len >= 8)
607 {
608 FMC->ISPADDR = u32Addr;
609 FMC->MPDAT0 = pu32Buf[idx++];
610 FMC->MPDAT1 = pu32Buf[idx++];
611 FMC->MPDAT2 = pu32Buf[idx++];
612 FMC->MPDAT3 = pu32Buf[idx++];
613 FMC->ISPCMD = FMC_ISPCMD_PROGRAM_MUL;
614 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
615
616 for (i = 16; i < FMC_MULTI_WORD_PROG_LEN; )
617 {
618 i32TimeOutCnt = FMC_TIMEOUT_WRITE;
619 while (FMC->MPSTS & (FMC_MPSTS_D0_Msk | FMC_MPSTS_D1_Msk))
620 {
621 if( i32TimeOutCnt-- <= 0)
622 {
623 g_FMC_i32ErrCode = -1;
624 return -1;
625 }
626 }
627
628 retval += 8;
629 u32Len -= 8;
630 if (u32Len < 8)
631 {
632 return retval;
633 }
634
635 if (!(FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk))
636 {
637 /* printf(" [WARNING] busy cleared after D0D1 cleared!\n"); */
638 i += 8;
639 break;
640 }
641
642 FMC->MPDAT0 = pu32Buf[idx++];
643 FMC->MPDAT1 = pu32Buf[idx++];
644
645 if (i == FMC_MULTI_WORD_PROG_LEN/4)
646 break; // done
647
648 i32TimeOutCnt = FMC_TIMEOUT_WRITE;
649 while (FMC->MPSTS & (FMC_MPSTS_D2_Msk | FMC_MPSTS_D3_Msk))
650 {
651 if( i32TimeOutCnt-- <= 0)
652 {
653 g_FMC_i32ErrCode = -1;
654 return -1;
655 }
656 }
657
658 retval += 8;
659 u32Len -= 8;
660 if (u32Len < 8)
661 {
662 return retval;
663 }
664
665 if (!(FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk))
666 {
667 /* printf(" [WARNING] busy cleared after D2D3 cleared!\n"); */
668 i += 8;
669 break;
670 }
671
672 FMC->MPDAT2 = pu32Buf[idx++];
673 FMC->MPDAT3 = pu32Buf[idx++];
674 }
675
676 if (i != FMC_MULTI_WORD_PROG_LEN)
677 {
678 /* printf(" [WARNING] Multi-word program interrupted at 0x%x !!\n", i); */
679 return retval;
680 }
681
682 i32TimeOutCnt = FMC_TIMEOUT_WRITE;
683 while (FMC->MPSTS & FMC_MPSTS_MPBUSY_Msk)
684 {
685 if( i32TimeOutCnt-- <= 0)
686 {
687 g_FMC_i32ErrCode = -1;
688 return -1;
689 }
690 }
691
692 u32Addr += FMC_MULTI_WORD_PROG_LEN;
693 }
694 return retval;
695 }
696
697
698 /**
699 * @brief Program a 64-bits data to the specified OTP.
700 * @param[in] otp_num The OTP number.
701 * @param[in] low_word Low word of the 64-bits data.
702 * @param[in] high_word High word of the 64-bits data.
703 * @retval 0 Success
704 * @retval -1 Program failed.
705 * @retval -2 Invalid OTP number.
706 *
707 * @note Global error code g_FMC_i32ErrCode
708 * -1 Program failed or time-out
709 * -2 Invalid OTP number
710 */
FMC_WriteOTP(uint32_t otp_num,uint32_t low_word,uint32_t high_word)711 int32_t FMC_WriteOTP(uint32_t otp_num, uint32_t low_word, uint32_t high_word)
712 {
713 int32_t ret = 0;
714 int32_t i32TimeOutCnt;
715
716 g_FMC_i32ErrCode = 0;
717
718 if (otp_num > 255UL)
719 {
720 g_FMC_i32ErrCode = -2;
721 ret = -2;
722 }
723
724 if (ret == 0)
725 {
726 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
727 FMC->ISPADDR = FMC_OTP_BASE + otp_num * 8UL;
728 FMC->ISPDAT = low_word;
729 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
730
731 i32TimeOutCnt = FMC_TIMEOUT_WRITE;
732 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk)
733 {
734 if( i32TimeOutCnt-- <= 0)
735 {
736 g_FMC_i32ErrCode = -1;
737 ret = -1;
738 break;
739 }
740 }
741
742 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
743 {
744 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
745 g_FMC_i32ErrCode = -1;
746 ret = -1;
747 }
748 }
749
750 if (ret == 0)
751 {
752 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
753 FMC->ISPADDR = FMC_OTP_BASE + otp_num * 8UL + 4UL;
754 FMC->ISPDAT = high_word;
755 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
756
757 i32TimeOutCnt = FMC_TIMEOUT_WRITE;
758 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk)
759 {
760 if( i32TimeOutCnt-- <= 0)
761 {
762 g_FMC_i32ErrCode = -1;
763 ret = -1;
764 break;
765 }
766 }
767
768 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
769 {
770 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
771 g_FMC_i32ErrCode = -1;
772 ret = -1;
773 }
774 }
775
776 return ret;
777 }
778
779 /**
780 * @brief Read the 64-bits data from the specified OTP.
781 * @param[in] otp_num The OTP number.
782 * @param[in] low_word Low word of the 64-bits data.
783 * @param[in] high_word High word of the 64-bits data.
784 * @retval 0 Success
785 * @retval -1 Read failed.
786 * @retval -2 Invalid OTP number.
787 *
788 * @note Global error code g_FMC_i32ErrCode
789 * -1 Read failed or time-out
790 * -2 Invalid OTP number
791 */
FMC_ReadOTP(uint32_t otp_num,uint32_t * low_word,uint32_t * high_word)792 int32_t FMC_ReadOTP(uint32_t otp_num, uint32_t *low_word, uint32_t *high_word)
793 {
794 int32_t ret = 0;
795 int32_t i32TimeOutCnt;
796
797 g_FMC_i32ErrCode = 0;
798
799 if (otp_num > 255UL)
800 {
801 g_FMC_i32ErrCode = -2;
802 ret = -2;
803 }
804
805 if (ret == 0)
806 {
807 FMC->ISPCMD = FMC_ISPCMD_READ_64;
808 FMC->ISPADDR = FMC_OTP_BASE + otp_num * 8UL ;
809 FMC->ISPDAT = 0x0UL;
810 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
811
812 i32TimeOutCnt = FMC_TIMEOUT_READ;
813 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk)
814 {
815 if( i32TimeOutCnt-- <= 0)
816 {
817 g_FMC_i32ErrCode = -1;
818 ret = -1;
819 break;
820 }
821 }
822
823 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
824 {
825 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
826 g_FMC_i32ErrCode = -1;
827 ret = -1;
828 }
829 else
830 {
831 *low_word = FMC->MPDAT0;
832 *high_word = FMC->MPDAT1;
833 }
834 }
835 return ret;
836 }
837
838 /**
839 * @brief Lock the specified OTP.
840 * @param[in] otp_num The OTP number.
841 * @retval 0 Success
842 * @retval -1 Failed to write OTP lock bits.
843 * @retval -2 Invalid OTP number.
844 *
845 * @note Global error code g_FMC_i32ErrCode
846 * -1 Failed to write OTP lock bits or write time-out
847 * -2 Invalid OTP number
848 */
FMC_LockOTP(uint32_t otp_num)849 int32_t FMC_LockOTP(uint32_t otp_num)
850 {
851 int32_t ret = 0;
852 int32_t i32TimeOutCnt;
853
854 g_FMC_i32ErrCode = 0;
855
856 if (otp_num > 255UL)
857 {
858 g_FMC_i32ErrCode = -2;
859 ret = -2;
860 }
861
862 if (ret == 0)
863 {
864 FMC->ISPCMD = FMC_ISPCMD_PROGRAM;
865 FMC->ISPADDR = FMC_OTP_BASE + 0x800UL + otp_num * 4UL;
866 FMC->ISPDAT = 0UL;
867 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
868
869 i32TimeOutCnt = FMC_TIMEOUT_WRITE;
870 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk)
871 {
872 if( i32TimeOutCnt-- <= 0)
873 {
874 g_FMC_i32ErrCode = -1;
875 ret = -1;
876 break;
877 }
878 }
879
880 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
881 {
882 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
883 g_FMC_i32ErrCode = -1;
884 ret = -1;
885 }
886 }
887 return ret;
888 }
889
890 /**
891 * @brief Check the OTP is locked or not.
892 * @param[in] otp_num The OTP number.
893 * @retval 1 OTP is locked.
894 * @retval 0 OTP is not locked.
895 * @retval -1 Failed to read OTP lock bits.
896 * @retval -2 Invalid OTP number.
897 *
898 * @note Global error code g_FMC_i32ErrCode
899 * -1 Failed to read OTP lock bits or read time-out
900 * -2 Invalid OTP number
901 */
FMC_IsOTPLocked(uint32_t otp_num)902 int32_t FMC_IsOTPLocked(uint32_t otp_num)
903 {
904 int32_t ret = 0;
905 int32_t i32TimeOutCnt;
906
907 g_FMC_i32ErrCode = 0;
908
909 if (otp_num > 255UL)
910 {
911 g_FMC_i32ErrCode = -2;
912 ret = -2;
913 }
914
915 if (ret == 0)
916 {
917 FMC->ISPCMD = FMC_ISPCMD_READ;
918 FMC->ISPADDR = FMC_OTP_BASE + 0x800UL + otp_num * 4UL;
919 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
920
921 i32TimeOutCnt = FMC_TIMEOUT_READ;
922 while (FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk)
923 {
924 if( i32TimeOutCnt-- <= 0)
925 {
926 g_FMC_i32ErrCode = -1;
927 ret = -1;
928 break;
929 }
930 }
931
932 if (FMC->ISPSTS & FMC_ISPSTS_ISPFF_Msk)
933 {
934 FMC->ISPSTS |= FMC_ISPSTS_ISPFF_Msk;
935 g_FMC_i32ErrCode = -1;
936 ret = -1;
937 }
938 else
939 {
940 if (FMC->ISPDAT != 0xFFFFFFFFUL)
941 {
942 g_FMC_i32ErrCode = -1;
943 ret = 1; /* Lock work was progrmmed. OTP was locked. */
944 }
945 }
946 }
947 return ret;
948 }
949
950 /**
951 * @brief Execute FMC_ISPCMD_READ command to read User Configuration.
952 * @param[out] u32Config A two-word array.
953 * u32Config[0] holds CONFIG0, while u32Config[1] holds CONFIG1.
954 * @param[in] u32Count Available word count in u32Config.
955 * @return Success or not.
956 * @retval 0 Success.
957 * @retval -1 Read failed
958 * @retval -2 Invalid parameter.
959 *
960 * @note Global error code g_FMC_i32ErrCode
961 * -1 Read failed
962 * -2 Invalid parameter
963 */
FMC_ReadConfig(uint32_t u32Config[],uint32_t u32Count)964 int32_t FMC_ReadConfig(uint32_t u32Config[], uint32_t u32Count)
965 {
966 int32_t ret = 0;
967
968 u32Config[0] = FMC_Read(FMC_CONFIG_BASE);
969
970 if (g_FMC_i32ErrCode != 0)
971 return g_FMC_i32ErrCode;
972
973 if (u32Count < 2UL)
974 {
975 ret = -2;
976 }
977 else
978 {
979 u32Config[1] = FMC_Read(FMC_CONFIG_BASE+4UL);
980 }
981 return ret;
982 }
983
984
985 /**
986 * @brief Execute ISP commands to erase then write User Configuration.
987 * @param[in] u32Config A two-word array.
988 * u32Config[0] holds CONFIG0, while u32Config[1] holds CONFIG1.
989 * @param[in] u32Count The number of User Configuration words to be written.
990 * @return Success or not.
991 * @retval 0 Success
992 * @retval -1 Erase/program/read/verify failed
993 *
994 * @note Global error code g_FMC_i32ErrCode
995 * < 0 Errors caused by erase/program/read failed or time-out
996 */
FMC_WriteConfig(uint32_t u32Config[],uint32_t u32Count)997 int32_t FMC_WriteConfig(uint32_t u32Config[], uint32_t u32Count)
998 {
999 int i;
1000
1001 FMC_ENABLE_CFG_UPDATE();
1002
1003 if (FMC_Erase(FMC_CONFIG_BASE) != 0)
1004 return -1;
1005
1006 if ((FMC_Read(FMC_CONFIG_BASE) != 0xFFFFFFFF) || (FMC_Read(FMC_CONFIG_BASE+4) != 0xFFFFFFFF) ||
1007 (FMC_Read(FMC_CONFIG_BASE+8) != 0xFFFF5A5A))
1008 {
1009 FMC_DISABLE_CFG_UPDATE();
1010 return -1;
1011 }
1012
1013 if (g_FMC_i32ErrCode != 0)
1014 {
1015 FMC_DISABLE_CFG_UPDATE();
1016 return -1;
1017 }
1018
1019 for (i = 0; i < u32Count; i++)
1020 {
1021 if (FMC_Write(FMC_CONFIG_BASE+i*4UL, u32Config[i]) != 0)
1022 {
1023 FMC_DISABLE_CFG_UPDATE();
1024 return -1;
1025 }
1026
1027 if (FMC_Read(FMC_CONFIG_BASE+i*4UL) != u32Config[i])
1028 {
1029 FMC_DISABLE_CFG_UPDATE();
1030 return -1;
1031 }
1032
1033 if (g_FMC_i32ErrCode != 0)
1034 {
1035 FMC_DISABLE_CFG_UPDATE();
1036 return -1;
1037 }
1038 }
1039
1040 FMC_DISABLE_CFG_UPDATE();
1041 return 0;
1042 }
1043
1044
1045 /**
1046 * @brief Run CRC32 checksum calculation and get result.
1047 * @param[in] u32addr Starting flash address. It must be a page aligned address.
1048 * @param[in] u32count Byte count of flash to be calculated. It must be multiple of 512 bytes.
1049 * @return Success or not.
1050 * @retval 0 Success.
1051 * @retval 0xFFFFFFFF Invalid parameter or command failed.
1052 *
1053 * @note Global error code g_FMC_i32ErrCode
1054 * -1 Run/Read check sum time-out failed
1055 * -2 u32addr or u32count must be aligned with 512
1056 */
FMC_GetChkSum(uint32_t u32addr,uint32_t u32count)1057 uint32_t FMC_GetChkSum(uint32_t u32addr, uint32_t u32count)
1058 {
1059 uint32_t ret;
1060 int32_t i32TimeOutCnt;
1061
1062 g_FMC_i32ErrCode = 0;
1063
1064 if ((u32addr % 512UL) || (u32count % 512UL))
1065 {
1066 g_FMC_i32ErrCode = -2;
1067 ret = 0xFFFFFFFF;
1068 }
1069 else
1070 {
1071 FMC->ISPCMD = FMC_ISPCMD_RUN_CKS;
1072 FMC->ISPADDR = u32addr;
1073 FMC->ISPDAT = u32count;
1074 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
1075
1076 i32TimeOutCnt = FMC_TIMEOUT_CHKSUM;
1077 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk)
1078 {
1079 if( i32TimeOutCnt-- <= 0)
1080 {
1081 g_FMC_i32ErrCode = -1;
1082 return 0xFFFFFFFF;
1083 }
1084 }
1085
1086 FMC->ISPCMD = FMC_ISPCMD_READ_CKS;
1087 FMC->ISPADDR = u32addr;
1088 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
1089
1090 i32TimeOutCnt = FMC_TIMEOUT_CHKSUM;
1091 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk)
1092 {
1093 if( i32TimeOutCnt-- <= 0)
1094 {
1095 g_FMC_i32ErrCode = -1;
1096 return 0xFFFFFFFF;
1097 }
1098 }
1099
1100 ret = FMC->ISPDAT;
1101 }
1102
1103 return ret;
1104 }
1105
1106
1107 /**
1108 * @brief Run flash all one verification and get result.
1109 * @param[in] u32addr Starting flash address. It must be a page aligned address.
1110 * @param[in] u32count Byte count of flash to be calculated. It must be multiple of 512 bytes.
1111 * @retval READ_ALLONE_YES The contents of verified flash area are 0xFFFFFFFF.
1112 * @retval READ_ALLONE_NOT Some contents of verified flash area are not 0xFFFFFFFF.
1113 * @retval READ_ALLONE_CMD_FAIL Unexpected error occurred.
1114 *
1115 * @note Global error code g_FMC_i32ErrCode
1116 * -1 RUN_ALL_ONE or CHECK_ALL_ONE commands time-out
1117 */
FMC_CheckAllOne(uint32_t u32addr,uint32_t u32count)1118 uint32_t FMC_CheckAllOne(uint32_t u32addr, uint32_t u32count)
1119 {
1120 uint32_t ret = READ_ALLONE_CMD_FAIL;
1121 int32_t i32TimeOutCnt0, i32TimeOutCnt1;
1122
1123 g_FMC_i32ErrCode = 0;
1124
1125 FMC->ISPSTS = 0x80UL; /* clear check all one bit */
1126
1127 FMC->ISPCMD = FMC_ISPCMD_RUN_ALL1;
1128 FMC->ISPADDR = u32addr;
1129 FMC->ISPDAT = u32count;
1130 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
1131
1132 i32TimeOutCnt0 = FMC_TIMEOUT_CHKALLONE;
1133 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk)
1134 {
1135 if( i32TimeOutCnt0-- <= 0)
1136 {
1137 g_FMC_i32ErrCode = -1;
1138 break;
1139 }
1140 }
1141
1142 if(g_FMC_i32ErrCode == 0)
1143 {
1144 i32TimeOutCnt1 = FMC_TIMEOUT_CHKALLONE;
1145 do
1146 {
1147 FMC->ISPCMD = FMC_ISPCMD_READ_ALL1;
1148 FMC->ISPADDR = u32addr;
1149 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
1150
1151 i32TimeOutCnt0 = FMC_TIMEOUT_CHKALLONE;
1152 while (FMC->ISPSTS & FMC_ISPSTS_ISPBUSY_Msk)
1153 {
1154 if( i32TimeOutCnt0-- <= 0)
1155 {
1156 g_FMC_i32ErrCode = -1;
1157 break;
1158 }
1159 }
1160
1161 if( i32TimeOutCnt1-- <= 0)
1162 {
1163 g_FMC_i32ErrCode = -1;
1164 }
1165 }
1166 while ( (FMC->ISPDAT == 0UL) && (g_FMC_i32ErrCode == 0));
1167 }
1168
1169 if(g_FMC_i32ErrCode == 0)
1170 {
1171 if(FMC->ISPDAT == READ_ALLONE_YES)
1172 ret = READ_ALLONE_YES;
1173 else if(FMC->ISPDAT == READ_ALLONE_NOT)
1174 ret = READ_ALLONE_NOT;
1175 else
1176 g_FMC_i32ErrCode = -1;
1177 }
1178
1179 return ret;
1180 }
1181
1182 /**
1183 * @brief Remap Bank0/Bank1
1184 *
1185 * @param[in] u32Bank Bank Num which will remap to.
1186 *
1187 * @retval 0 Success
1188 * @retval -1 Program failed.
1189 *
1190 * @details Remap Bank0/Bank1
1191 *
1192 * @note Global error code g_FMC_i32ErrCode
1193 * -1 Program failed or time-out
1194 */
FMC_RemapBank(uint32_t u32Bank)1195 int32_t FMC_RemapBank(uint32_t u32Bank)
1196 {
1197 int32_t ret = 0;
1198 int32_t i32TimeOutCnt;
1199
1200 g_FMC_i32ErrCode = 0;
1201
1202 FMC->ISPCMD = FMC_ISPCMD_BANK_REMAP;
1203 FMC->ISPADDR = u32Bank;
1204 FMC->ISPDAT = 0x5AA55AA5UL;
1205 FMC->ISPTRG = FMC_ISPTRG_ISPGO_Msk;
1206
1207 i32TimeOutCnt = FMC_TIMEOUT_WRITE;
1208 while(FMC->ISPTRG & FMC_ISPTRG_ISPGO_Msk)
1209 {
1210 if( i32TimeOutCnt-- <= 0)
1211 {
1212 g_FMC_i32ErrCode = -1;
1213 ret = -1;
1214 break;
1215 }
1216 }
1217
1218 if(FMC->ISPCTL & FMC_ISPCTL_ISPFF_Msk)
1219 {
1220 FMC->ISPCTL |= FMC_ISPCTL_ISPFF_Msk;
1221 g_FMC_i32ErrCode = -1;
1222 ret = -1;
1223 }
1224 return ret;
1225 }
1226
1227
1228 /*@}*/ /* end of group FMC_EXPORTED_FUNCTIONS */
1229
1230 /*@}*/ /* end of group FMC_Driver */
1231
1232 /*@}*/ /* end of group Standard_Driver */
1233