1 /*!
2     \file    gd32vf103_fmc.c
3     \brief   FMC driver
4 
5     \version 2019-06-05, V1.0.0, firmware for GD32VF103
6     \version 2019-09-18, V1.0.1, firmware for GD32VF103
7     \version 2020-02-20, V1.0.2, firmware for GD32VF103
8     \version 2020-08-04, V1.1.0, firmware for GD32VF103
9 */
10 
11 /*
12     Copyright (c) 2020, GigaDevice Semiconductor Inc.
13 
14     Redistribution and use in source and binary forms, with or without modification,
15 are permitted provided that the following conditions are met:
16 
17     1. Redistributions of source code must retain the above copyright notice, this
18        list of conditions and the following disclaimer.
19     2. Redistributions in binary form must reproduce the above copyright notice,
20        this list of conditions and the following disclaimer in the documentation
21        and/or other materials provided with the distribution.
22     3. Neither the name of the copyright holder nor the names of its contributors
23        may be used to endorse or promote products derived from this software without
24        specific prior written permission.
25 
26     THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
27 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
28 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
29 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
30 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
31 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
32 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
33 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
34 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
35 OF SUCH DAMAGE.
36 */
37 
38 #include "gd32vf103_fmc.h"
39 
40 /*!
41     \brief      set the FMC wait state counter
42     \param[in]  wscnt��wait state counter value
43       \arg        WS_WSCNT_0: FMC 0 wait state
44       \arg        WS_WSCNT_1: FMC 1 wait state
45       \arg        WS_WSCNT_2: FMC 2 wait state
46     \param[out] none
47     \retval     none
48  */
fmc_wscnt_set(uint32_t wscnt)49 void fmc_wscnt_set(uint32_t wscnt)
50 {
51     uint32_t reg;
52 
53     reg = FMC_WS;
54     /* set the wait state counter value */
55     reg &= ~FMC_WS_WSCNT;
56     FMC_WS = (reg | wscnt);
57 }
58 
59 /*!
60     \brief      unlock the main FMC operation
61     \param[in]  none
62     \param[out] none
63     \retval     none
64  */
fmc_unlock(void)65 void fmc_unlock(void)
66 {
67     if((RESET != (FMC_CTL & FMC_CTL_LK))){
68         /* write the FMC unlock key */
69         FMC_KEY = UNLOCK_KEY0;
70         FMC_KEY = UNLOCK_KEY1;
71     }
72 }
73 
74 /*!
75     \brief      lock the main FMC operation
76     \param[in]  none
77     \param[out] none
78     \retval     none
79  */
fmc_lock(void)80 void fmc_lock(void)
81 {
82     /* set the LK bit */
83     FMC_CTL |= FMC_CTL_LK;
84 }
85 
86 
87 /*!
88     \brief      FMC erase page
89     \param[in]  page_address: the page address to be erased.
90     \param[out] none
91     \retval     state of FMC, refer to fmc_state_enum
92  */
fmc_page_erase(uint32_t page_address)93 fmc_state_enum fmc_page_erase(uint32_t page_address)
94 {
95     fmc_state_enum fmc_state;
96     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
97     /* if the last operation is completed, start page erase */
98     if (FMC_READY == fmc_state) {
99         FMC_CTL |= FMC_CTL_PER;
100         FMC_ADDR = page_address;
101         FMC_CTL |= FMC_CTL_START;
102         /* wait for the FMC ready */
103         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
104         /* reset the PER bit */
105         FMC_CTL &= ~FMC_CTL_PER;
106     }
107     /* return the FMC state */
108     return fmc_state;
109 }
110 
111 /*!
112     \brief      FMC erase whole chip
113     \param[in]  none
114     \param[out] none
115     \retval     state of FMC, refer to fmc_state_enum
116  */
fmc_mass_erase(void)117 fmc_state_enum fmc_mass_erase(void)
118 {
119     fmc_state_enum fmc_state;
120         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
121 
122         if(FMC_READY == fmc_state){
123             /* start whole chip erase */
124             FMC_CTL |= FMC_CTL_MER;
125             FMC_CTL |= FMC_CTL_START;
126             /* wait for the FMC ready */
127             fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
128             /* reset the MER bit */
129             FMC_CTL &= ~FMC_CTL_MER;
130         }
131     /* return the FMC state  */
132     return fmc_state;
133 }
134 
135 /*!
136     \brief      FMC program a word at the corresponding address
137     \param[in]  address: address to program
138     \param[in]  data: word to program
139     \param[out] none
140     \retval     state of FMC, refer to fmc_state_enum
141  */
fmc_word_program(uint32_t address,uint32_t data)142 fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
143 {
144     fmc_state_enum fmc_state = FMC_READY;
145     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
146 
147     if(FMC_READY == fmc_state){
148         /* set the PG bit to start program */
149         FMC_CTL |= FMC_CTL_PG;
150         REG32(address) = data;
151         /* wait for the FMC ready */
152         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
153         /* reset the PG bit */
154         FMC_CTL &= ~FMC_CTL_PG;
155     }
156     /* return the FMC state */
157     return fmc_state;
158 }
159 /*
160     \brief      FMC program a half word at the corresponding address
161     \param[in]  address: address to program
162     \param[in]  data: halfword to program
163     \param[out] none
164     \retval     state of FMC, refer to fmc_state_enum
165 */
fmc_halfword_program(uint32_t address,uint16_t data)166 fmc_state_enum fmc_halfword_program(uint32_t address, uint16_t data)
167 {
168     fmc_state_enum fmc_state = FMC_READY;
169     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
170 
171     if(FMC_READY == fmc_state){
172         /* set the PG bit to start program */
173         FMC_CTL |= FMC_CTL_PG;
174         REG16(address) = data;
175         /* wait for the FMC ready */
176         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
177         /* reset the PG bit */
178         FMC_CTL &= ~FMC_CTL_PG;
179     }
180     /* return the FMC state */
181     return fmc_state;
182 }
183 
184 /*!
185     \brief      unlock the option byte operation
186     \param[in]  none
187     \param[out] none
188     \retval     none
189  */
ob_unlock(void)190 void ob_unlock(void)
191 {
192     if(RESET == (FMC_CTL & FMC_CTL_OBWEN)){
193         /* write the FMC key */
194         FMC_OBKEY = UNLOCK_KEY0;
195         FMC_OBKEY = UNLOCK_KEY1;
196     }
197 
198     /* wait until OBWEN bit is set by hardware */
199     while (RESET == (FMC_CTL & FMC_CTL_OBWEN)){
200     }
201 }
202 
203 /*!
204     \brief      lock the option byte operation
205     \param[in]  none
206     \param[out] none
207     \retval     none
208  */
ob_lock(void)209 void ob_lock(void)
210 {
211     /* reset the OBWEN bit */
212     FMC_CTL &= ~FMC_CTL_OBWEN;
213 }
214 
215 /*!
216     \brief      erase the FMC option byte
217     unlock the FMC_CTL and option byte before calling this function
218     \param[in]  none
219     \param[out] none
220     \retval     state of FMC, refer to fmc_state_enum
221  */
ob_erase(void)222 fmc_state_enum ob_erase(void)
223 {
224     uint16_t temp_spc = FMC_NSPC;
225 
226     fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
227 
228     /* check the option byte security protection value */
229     if(RESET != ob_spc_get()){
230         temp_spc = FMC_USPC;
231     }
232 
233     if(FMC_READY == fmc_state){
234 
235         /* start erase the option byte */
236         FMC_CTL |= FMC_CTL_OBER;
237         FMC_CTL |= FMC_CTL_START;
238 
239         /* wait for the FMC ready */
240         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
241 
242         if(FMC_READY == fmc_state){
243             /* reset the OBER bit */
244             FMC_CTL &= ~FMC_CTL_OBER;
245             /* set the OBPG bit */
246             FMC_CTL |= FMC_CTL_OBPG;
247             /* no security protection */
248             OB_SPC = (uint16_t) temp_spc;
249             /* wait for the FMC ready */
250             fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
251             if (FMC_TOERR != fmc_state) {
252                 /* reset the OBPG bit */
253                 FMC_CTL &= ~FMC_CTL_OBPG;
254             }
255         }else{
256             if(FMC_TOERR != fmc_state){
257                 /* reset the OBPG bit */
258                 FMC_CTL &= ~FMC_CTL_OBPG;
259             }
260         }
261     }
262     /* return the FMC state */
263     return fmc_state;
264 }
265 
266 /*!
267     \brief      enable write protection
268     \param[in]  ob_wp: specify sector to be write protected, set the bit to 1 if
269     you want to protect the corresponding pages. meanwhile, sector
270     macro could used to set specific sector write protected.
271     one or more parameters can be selected which are shown as below:
272       \arg        OB_WP_x(x = 0..31): write protect specify sector
273       \arg        OB_WP_ALL: write protect all sector
274     \param[out] none
275     \retval     state of FMC, refer to fmc_state_enum
276  */
ob_write_protection_enable(uint32_t ob_wp)277 fmc_state_enum ob_write_protection_enable(uint32_t ob_wp)
278 {
279     uint16_t temp_wp0, temp_wp1, temp_wp2, temp_wp3;
280 
281     fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
282 
283     ob_wp = (uint32_t) (~ob_wp);
284     temp_wp0 = (uint16_t) (ob_wp & OB_WP0_WP0);
285     temp_wp1 = (uint16_t) ((ob_wp & OB_WP1_WP1) >> 8U);
286     temp_wp2 = (uint16_t) ((ob_wp & OB_WP2_WP2) >> 16U);
287     temp_wp3 = (uint16_t) ((ob_wp & OB_WP3_WP3) >> 24U);
288 
289     if(FMC_READY == fmc_state){
290 
291         /* set the OBPG bit*/
292         FMC_CTL |= FMC_CTL_OBPG;
293 
294         if(0xFFU != temp_wp0){
295             OB_WP0 = temp_wp0;
296 
297             /* wait for the FMC ready */
298             fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
299         }
300         if((FMC_READY == fmc_state) && (0xFFU != temp_wp1)){
301             OB_WP1 = temp_wp1;
302 
303             /* wait for the FMC ready */
304             fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
305         }
306         if((FMC_READY == fmc_state) && (0xFFU != temp_wp2)){
307             OB_WP2 = temp_wp2;
308 
309             /* wait for the FMC ready */
310             fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
311         }
312         if((FMC_READY == fmc_state) && (0xFFU != temp_wp3)){
313             OB_WP3 = temp_wp3;
314 
315             /* wait for the FMC ready */
316             fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
317         }
318         if(FMC_TOERR != fmc_state){
319             /* reset the OBPG bit */
320             FMC_CTL &= ~FMC_CTL_OBPG;
321         }
322     }
323     /* return the FMC state */
324     return fmc_state;
325 }
326 
327 /*!
328     \brief      configure security protection
329     \param[in]  ob_spc: specify security protection
330     only one parameter can be selected which is shown as below:
331       \arg        FMC_NSPC: no security protection
332       \arg        FMC_USPC: under security protection
333     \param[out] none
334     \retval     state of FMC, refer to fmc_state_enum
335  */
ob_security_protection_config(uint8_t ob_spc)336 fmc_state_enum ob_security_protection_config(uint8_t ob_spc)
337 {
338     fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
339 
340     if(FMC_READY == fmc_state){
341         FMC_CTL |= FMC_CTL_OBER;
342         FMC_CTL |= FMC_CTL_START;
343 
344         /* wait for the FMC ready */
345         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
346 
347         if(FMC_READY == fmc_state){
348             /* reset the OBER bit */
349             FMC_CTL &= ~FMC_CTL_OBER;
350 
351             /* start the option byte program */
352             FMC_CTL |= FMC_CTL_OBPG;
353 
354             OB_SPC = (uint16_t) ob_spc;
355 
356             /* wait for the FMC ready */
357             fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
358 
359             if (FMC_TOERR != fmc_state) {
360                 /* reset the OBPG bit */
361                 FMC_CTL &= ~FMC_CTL_OBPG;
362             }
363         }else{
364             if (FMC_TOERR != fmc_state) {
365                 /* reset the OBER bit */
366                 FMC_CTL &= ~FMC_CTL_OBER;
367             }
368         }
369     }
370     /* return the FMC state */
371     return fmc_state;
372 }
373 
374 /*!
375     \brief      program the FMC user option byte
376     \param[in]  ob_fwdgt: option byte watchdog value
377       \arg        OB_FWDGT_SW: software free watchdog
378       \arg        OB_FWDGT_HW: hardware free watchdog
379     \param[in]  ob_deepsleep: option byte deepsleep reset value
380       \arg        OB_DEEPSLEEP_NRST: no reset when entering deepsleep mode
381       \arg        OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
382     \param[in]  ob_stdby:option byte standby reset value
383       \arg        OB_STDBY_NRST: no reset when entering standby mode
384       \arg        OB_STDBY_RST: generate a reset instead of entering standby mode
385     \param[in]  ob_boot: specifies the option byte boot bank value
386       \arg        OB_BOOT_B0: boot from bank0
387     \param[out] none
388     \retval     state of FMC, refer to fmc_state_enum
389  */
ob_user_write(uint8_t ob_fwdgt,uint8_t ob_deepsleep,uint8_t ob_stdby,uint8_t ob_boot)390 fmc_state_enum ob_user_write(uint8_t ob_fwdgt, uint8_t ob_deepsleep, uint8_t ob_stdby, uint8_t ob_boot)
391 {
392     fmc_state_enum fmc_state = FMC_READY;
393     uint8_t temp;
394 
395     /* wait for the FMC ready */
396     fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
397 
398     if(FMC_READY == fmc_state){
399         /* set the OBPG bit*/
400         FMC_CTL |= FMC_CTL_OBPG;
401 
402         temp = ((uint8_t)((uint8_t)((uint8_t)(ob_boot | ob_fwdgt) | ob_deepsleep) | ob_stdby) | OB_USER_MASK);
403         OB_USER = (uint16_t) temp;
404 
405         /* wait for the FMC ready */
406         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
407 
408         if(FMC_TOERR != fmc_state){
409             /* reset the OBPG bit */
410             FMC_CTL &= ~FMC_CTL_OBPG;
411         }
412     }
413     /* return the FMC state */
414     return fmc_state;
415 }
416 
417 /*!
418     \brief      program the FMC data option byte
419     \param[in]  address: the option bytes address to be programmed
420     \param[in]  data: the byte to be programmed
421     \param[out] none
422     \retval     state of FMC, refer to fmc_state_enum
423  */
ob_data_program(uint32_t address,uint8_t data)424 fmc_state_enum ob_data_program(uint32_t address, uint8_t data)
425 {
426     fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
427 
428     if(FMC_READY == fmc_state){
429         /* set the OBPG bit */
430         FMC_CTL |= FMC_CTL_OBPG;
431         REG16(address) = data;
432 
433         /* wait for the FMC ready */
434         fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
435 
436         if(FMC_TOERR != fmc_state){
437             /* reset the OBPG bit */
438             FMC_CTL &= ~FMC_CTL_OBPG;
439         }
440     }
441     /* return the FMC state */
442     return fmc_state;
443 }
444 
445 /*!
446     \brief      get OB_USER in register FMC_OBSTAT
447     \param[in]  none
448     \param[out] none
449     \retval     the FMC user option byte values
450  */
ob_user_get(void)451 uint8_t ob_user_get(void)
452 {
453     /* return the FMC user option byte value */
454     return (uint8_t) (FMC_OBSTAT >> 2U);
455 }
456 
457 /*!
458     \brief      get OB_DATA in register FMC_OBSTAT
459     \param[in]  none
460     \param[out] none
461     \retval     ob_data
462  */
ob_data_get(void)463 uint16_t ob_data_get(void)
464 {
465     return (uint16_t) (FMC_OBSTAT >> 10U);
466 }
467 
468 /*!
469     \brief      get the FMC option byte write protection
470     \param[in]  none
471     \param[out] none
472     \retval     the FMC write protection option byte value
473  */
ob_write_protection_get(void)474 uint32_t ob_write_protection_get(void)
475 {
476     /* return the FMC write protection option byte value */
477     return FMC_WP;
478 }
479 
480 /*!
481     \brief      get FMC option byte security protection state
482     \param[in]  none
483     \param[out] none
484     \retval     FlagStatus: SET or RESET
485  */
ob_spc_get(void)486 FlagStatus ob_spc_get(void)
487 {
488     FlagStatus spc_state = RESET;
489 
490     if(RESET != (FMC_OBSTAT & FMC_OBSTAT_SPC)){
491         spc_state = SET;
492     }else{
493         spc_state = RESET;
494     }
495     return spc_state;
496 }
497 
498 /*!
499     \brief      enable FMC interrupt
500     \param[in]  interrupt: the FMC interrupt source
501     only one parameter can be selected which is shown as below:
502       \arg        FMC_INT_END: enable FMC end of program interrupt
503       \arg        FMC_INT_ERR: enable FMC error interrupt
504     \param[out] none
505     \retval     none
506  */
fmc_interrupt_enable(fmc_int_enum interrupt)507 void fmc_interrupt_enable(fmc_int_enum interrupt)
508 {
509     FMC_CTL |= (uint32_t)interrupt;
510 }
511 
512 /*!
513     \brief      disable FMC interrupt
514     \param[in]  interrupt: the FMC interrupt source
515     only one parameter can be selected which is shown as below:
516       \arg        FMC_INT_END: enable FMC end of program interrupt
517       \arg        FMC_INT_ERR: enable FMC error interrupt
518     \param[out] none
519     \retval     none
520  */
fmc_interrupt_disable(fmc_int_enum interrupt)521 void fmc_interrupt_disable(fmc_int_enum interrupt)
522 {
523     FMC_CTL &= ~(uint32_t)interrupt;
524 }
525 
526 /*!
527     \brief      check flag is set or not
528     \param[in]  flag: check FMC flag
529     only one parameter can be selected which is shown as below:
530       \arg        FMC_FLAG_BUSY: FMC busy flag
531       \arg        FMC_FLAG_PGERR: FMC operation error flag
532       \arg        FMC_FLAG_WPERR: FMC erase/program protection error flag
533       \arg        FMC_FLAG_END: FMC end of operation flag
534     \param[out] none
535     \retval     FlagStatus: SET or RESET
536  */
fmc_flag_get(fmc_flag_enum flag)537 FlagStatus fmc_flag_get(fmc_flag_enum flag)
538 {
539     FlagStatus status = RESET;
540 
541     if(FMC_STAT & flag){
542         status = SET;
543     }
544     /* return the state of corresponding FMC flag */
545     return status;
546 }
547 
548 /*!
549  \brief      clear the FMC flag
550  \param[in]  flag: clear FMC flag
551  only one parameter can be selected which is shown as below:
552  \arg        FMC_FLAG_PGERR: FMC operation error flag
553  \arg        FMC_FLAG_WPERR: FMC erase/program protection error flag
554  \arg        FMC_FLAG_END: FMC end of operation flag
555  \param[out] none
556  \retval     none
557  */
fmc_flag_clear(fmc_flag_enum flag)558 void fmc_flag_clear(fmc_flag_enum flag)
559 {
560     /* clear the flags */
561     FMC_STAT = flag;
562 }
563 
564 /*!
565     \brief      get FMC interrupt flag state
566     \param[in]  flag: FMC interrupt flags, refer to fmc_interrupt_flag_enum
567     only one parameter can be selected which is shown as below:
568       \arg        FMC_INT_FLAG_PGERR: FMC operation error interrupt flag
569       \arg        FMC_INT_FLAG_WPERR: FMC erase/program protection error interrupt flag
570       \arg        FMC_INT_FLAG_END: FMC end of operation interrupt flag
571     \param[out] none
572     \retval     FlagStatus: SET or RESET
573  */
fmc_interrupt_flag_get(fmc_interrupt_flag_enum flag)574 FlagStatus fmc_interrupt_flag_get(fmc_interrupt_flag_enum flag)
575 {
576     FlagStatus status = RESET;
577 
578     if(FMC_STAT & flag){
579         status = SET;
580     }
581     /* return the state of corresponding FMC flag */
582     return status;
583 }
584 
585 /*!
586     \brief      clear FMC interrupt flag state
587     \param[in]  flag: FMC interrupt flags, refer to can_interrupt_flag_enum
588     only one parameter can be selected which is shown as below:
589       \arg        FMC_INT_FLAG_PGERR: FMC operation error interrupt flag
590       \arg        FMC_INT_FLAG_WPERR: FMC erase/program protection error interrupt flag
591       \arg        FMC_INT_FLAG_END: FMC end of operation interrupt flag
592      \param[out] none
593      \retval     none
594  */
fmc_interrupt_flag_clear(fmc_interrupt_flag_enum flag)595 void fmc_interrupt_flag_clear(fmc_interrupt_flag_enum flag)
596 {
597     /* clear the flags */
598     FMC_STAT = flag;
599 }
600 
601 /*!
602     \brief      get the FMC state
603     \param[in]  none
604     \param[out] none
605     \retval     state of FMC, refer to fmc_state_enum
606  */
fmc_state_get(void)607 fmc_state_enum fmc_state_get(void)
608 {
609     fmc_state_enum fmc_state = FMC_READY;
610 
611     if((uint32_t) 0x00U != (FMC_STAT & FMC_STAT_BUSY)){
612         fmc_state = FMC_BUSY;
613     }else{
614         if((uint32_t) 0x00U != (FMC_STAT & FMC_STAT_WPERR)){
615             fmc_state = FMC_WPERR;
616         }else{
617             if((uint32_t) 0x00U != (FMC_STAT & (FMC_STAT_PGERR))){
618                 fmc_state = FMC_PGERR;
619             }
620         }
621     }
622     /* return the FMC state */
623     return fmc_state;
624 }
625 
626 /*!
627     \brief      check whether FMC is ready or not
628     \param[in]  timeout: count of loop
629     \param[out] none
630     \retval     state of FMC, refer to fmc_state_enum
631  */
fmc_ready_wait(uint32_t timeout)632 fmc_state_enum fmc_ready_wait(uint32_t timeout)
633 {
634     fmc_state_enum fmc_state = FMC_BUSY;
635 
636     /* wait for FMC ready */
637     do{
638         /* get FMC state */
639         fmc_state = fmc_state_get();
640         timeout--;
641     }while((FMC_BUSY == fmc_state) && (0x00U != timeout));
642 
643     if(FMC_BUSY == fmc_state){
644         fmc_state = FMC_TOERR;
645     }
646     /* return the FMC state */
647     return fmc_state;
648 }
649