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