1 /*!
2 \file gd32f3x0_fmc.c
3 \brief FMC driver
4
5 \version 2017-06-06, V1.0.0, firmware for GD32F3x0
6 \version 2019-06-01, V2.0.0, firmware for GD32F3x0
7 \version 2020-09-30, V2.1.0, firmware for GD32F3x0
8 */
9
10 /*
11 Copyright (c) 2020, GigaDevice Semiconductor Inc.
12
13 Redistribution and use in source and binary forms, with or without modification,
14 are permitted provided that the following conditions are met:
15
16 1. Redistributions of source code must retain the above copyright notice, this
17 list of conditions and the following disclaimer.
18 2. Redistributions in binary form must reproduce the above copyright notice,
19 this list of conditions and the following disclaimer in the documentation
20 and/or other materials provided with the distribution.
21 3. Neither the name of the copyright holder nor the names of its contributors
22 may be used to endorse or promote products derived from this software without
23 specific prior written permission.
24
25 THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
26 AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED
27 WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
28 IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
29 INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
30 NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR
31 PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
32 WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
33 ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
34 OF SUCH DAMAGE.
35 */
36
37 #include "gd32f3x0_fmc.h"
38
39 /* FMC main memory programming functions */
40
41 /*!
42 \brief unlock the main FMC operation
43 it is better to used in pairs with fmc_lock
44 \param[in] none
45 \param[out] none
46 \retval none
47 */
fmc_unlock(void)48 void fmc_unlock(void)
49 {
50 if((RESET != (FMC_CTL & FMC_CTL_LK))){
51 /* write the FMC key */
52 FMC_KEY = UNLOCK_KEY0;
53 FMC_KEY = UNLOCK_KEY1;
54 }
55 }
56
57 /*!
58 \brief lock the main FMC operation
59 it is better to used in pairs with fmc_unlock after an operation
60 \param[in] none
61 \param[out] none
62 \retval none
63 */
fmc_lock(void)64 void fmc_lock(void)
65 {
66 /* set the LK bit*/
67 FMC_CTL |= FMC_CTL_LK;
68 }
69
70 /*!
71 \brief set the wait state counter value
72 \param[in] wscnt: wait state counter value
73 only one parameter can be selected which is shown as below:
74 \arg WS_WSCNT_0: 0 wait state added
75 \arg WS_WSCNT_1: 1 wait state added
76 \arg WS_WSCNT_2: 2 wait state added
77 \param[out] none
78 \retval none
79 */
fmc_wscnt_set(uint8_t wscnt)80 void fmc_wscnt_set(uint8_t wscnt)
81 {
82 uint32_t reg;
83
84 reg = FMC_WS;
85 /* set the wait state counter value */
86 reg &= ~FMC_WS_WSCNT;
87 FMC_WS = (reg | wscnt);
88 }
89
90 /*!
91 \brief fmc wait state enable
92 \param[in] none
93 \param[out] none
94 \retval none
95 */
fmc_wait_state_enable(void)96 void fmc_wait_state_enable(void)
97 {
98 /* unlock the main flash */
99 fmc_unlock();
100
101 /* set the WSEN bit in register FMC_WSEN */
102 FMC_WSEN |= FMC_WSEN_WSEN;
103
104 /* lock the main flash after operation */
105 fmc_lock();
106 }
107
108 /*!
109 \brief fmc wait state disable
110 \param[in] none
111 \param[out] none
112 \retval none
113 */
fmc_wait_state_disable(void)114 void fmc_wait_state_disable(void)
115 {
116 /* unlock the main flash */
117 fmc_unlock();
118
119 /* reset the WSEN bit in register FMC_WSEN */
120 FMC_WSEN &= ~FMC_WSEN_WSEN;
121
122 /* lock the main flash after operation */
123 fmc_lock();
124 }
125
126 /*!
127 \brief erase page
128 \param[in] page_address: target page start address
129 \param[out] none
130 \retval fmc_state
131 */
fmc_page_erase(uint32_t page_address)132 fmc_state_enum fmc_page_erase(uint32_t page_address)
133 {
134 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
135
136 if(FMC_READY == fmc_state){
137 /* start page erase */
138 FMC_CTL |= FMC_CTL_PER;
139 FMC_ADDR = page_address;
140 FMC_CTL |= FMC_CTL_START;
141
142 /* wait for the FMC ready */
143 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
144
145 /* reset the PER bit */
146 FMC_CTL &= ~FMC_CTL_PER;
147 }
148
149 /* return the FMC state */
150 return fmc_state;
151 }
152
153 /*!
154 \brief erase whole chip
155 \param[in] none
156 \param[out] none
157 \retval fmc_state
158 */
fmc_mass_erase(void)159 fmc_state_enum fmc_mass_erase(void)
160 {
161 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
162
163 if(FMC_READY == fmc_state){
164 /* start chip erase */
165 FMC_CTL |= FMC_CTL_MER;
166 FMC_CTL |= FMC_CTL_START;
167
168 /* wait for the FMC ready */
169 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
170
171 /* reset the MER bit */
172 FMC_CTL &= ~FMC_CTL_MER;
173 }
174
175 /* return the fmc state */
176 return fmc_state;
177 }
178
179 /*!
180 \brief program a word at the corresponding address
181 \param[in] address: address to program
182 \param[in] data: word to program
183 \param[out] none
184 \retval fmc_state
185 */
fmc_word_program(uint32_t address,uint32_t data)186 fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
187 {
188 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
189
190 if(FMC_READY == fmc_state){
191 /* set the PG bit to start program */
192 FMC_CTL |= FMC_CTL_PG;
193
194 REG32(address) = data;
195
196 /* wait for the FMC ready */
197 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
198
199 /* reset the PG bit */
200 FMC_CTL &= ~FMC_CTL_PG;
201 }
202
203 /* return the FMC state */
204 return fmc_state;
205 }
206
207 /*!
208 \brief program a half word at the corresponding address
209 \param[in] address: address to program
210 \param[in] data: word to program
211 \param[out] none
212 \retval fmc_state
213 */
fmc_halfword_program(uint32_t address,uint16_t data)214 fmc_state_enum fmc_halfword_program(uint32_t address, uint16_t data)
215 {
216 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
217
218 if(FMC_READY == fmc_state){
219 /* set the PG bit to start program */
220 FMC_CTL |= FMC_CTL_PG;
221
222 REG16(address) = data;
223
224 /* wait for the FMC ready */
225 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
226
227 /* reset the PG bit */
228 FMC_CTL &= ~FMC_CTL_PG;
229 }
230
231 /* return the FMC state */
232 return fmc_state;
233 }
234
235 /*!
236 \brief program a word at the corresponding address without erasing
237 \param[in] address: address to program
238 \param[in] data: word to program
239 \param[out] none
240 \retval fmc_state
241 */
fmc_word_reprogram(uint32_t address,uint32_t data)242 fmc_state_enum fmc_word_reprogram(uint32_t address, uint32_t data)
243 {
244 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
245 FMC_WSEN |= FMC_WSEN_BPEN;
246
247 if(FMC_READY == fmc_state){
248 /* set the PG bit to start program */
249 FMC_CTL |= FMC_CTL_PG;
250
251 REG32(address) = data;
252
253 /* wait for the FMC ready */
254 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
255
256 /* reset the PG bit */
257 FMC_CTL &= ~FMC_CTL_PG;
258 }
259
260 /* return the FMC state */
261 return fmc_state;
262 }
263
264 /* FMC option bytes programming functions */
265
266 /*!
267 \brief unlock the option byte operation
268 it is better to used in pairs with ob_lock
269 \param[in] none
270 \param[out] none
271 \retval none
272 */
ob_unlock(void)273 void ob_unlock(void)
274 {
275 if(RESET == (FMC_CTL & FMC_CTL_OBWEN)){
276 /* write the FMC key */
277 FMC_OBKEY = UNLOCK_KEY0;
278 FMC_OBKEY = UNLOCK_KEY1;
279 }
280 }
281
282 /*!
283 \brief lock the option byte operation
284 it is better to used in pairs with ob_unlock after an operation
285 \param[in] none
286 \param[out] none
287 \retval none
288 */
ob_lock(void)289 void ob_lock(void)
290 {
291 /* reset the OBWE bit */
292 FMC_CTL &= ~FMC_CTL_OBWEN;
293 }
294
295 /*!
296 \brief reload the option byte and generate a system reset
297 \param[in] none
298 \param[out] none
299 \retval none
300 */
ob_reset(void)301 void ob_reset(void)
302 {
303 /* set the OBRLD bit */
304 FMC_CTL |= FMC_CTL_OBRLD;
305 }
306
307 /*!
308 \brief erase the option byte
309 programmer must ensure FMC & option byte are both unlocked before calling this function
310 \param[in] none
311 \param[out] none
312 \retval fmc_state
313 */
ob_erase(void)314 fmc_state_enum ob_erase(void)
315 {
316 uint16_t fmc_spc;
317
318 uint32_t fmc_plevel = ob_obstat_plevel_get();
319 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
320
321 /* get the original option byte security protection code */
322 if(OB_OBSTAT_PLEVEL_NO == fmc_plevel){
323 fmc_spc = FMC_NSPC;
324 }else if(OB_OBSTAT_PLEVEL_LOW == fmc_plevel){
325 fmc_spc = FMC_LSPC;
326 }else{
327 fmc_spc = FMC_HSPC;
328 fmc_state = FMC_OB_HSPC;
329 }
330
331 if(FMC_READY == fmc_state){
332 /* start erase the option byte */
333 FMC_CTL |= FMC_CTL_OBER;
334 FMC_CTL |= FMC_CTL_START;
335
336 /* wait for the FMC ready */
337 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
338
339 if(FMC_READY == fmc_state){
340 /* reset the OBER bit */
341 FMC_CTL &= ~FMC_CTL_OBER;
342
343 /* set the OBPG bit */
344 FMC_CTL |= FMC_CTL_OBPG;
345
346 /* restore the last get option byte security protection code */
347 OB_SPC = fmc_spc;
348 OB_USER = OB_USER_DEFAULT;
349
350 /* wait for the FMC ready */
351 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
352
353 if(FMC_TOERR != fmc_state){
354 /* reset the OBPG bit */
355 FMC_CTL &= ~FMC_CTL_OBPG;
356 }
357 }else{
358 if(FMC_TOERR != fmc_state){
359 /* reset the OBPG bit */
360 FMC_CTL &= ~FMC_CTL_OBPG;
361 }
362 }
363 }
364 /* return the FMC state */
365 return fmc_state;
366 }
367
368 /*!
369 \brief enable option byte write protection(OB_WP) depending on current option byte
370 \param[in] ob_wp: write protection configuration data
371 setting the bit of ob_wp means enabling the corresponding sector write protection
372 \param[out] none
373 \retval fmc_state
374 */
ob_write_protection_enable(uint16_t ob_wp)375 fmc_state_enum ob_write_protection_enable(uint16_t ob_wp)
376 {
377 uint8_t ob_wrp0, ob_wrp1;
378 ob_parm_struct ob_parm;
379 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
380 ob_parm_get(&ob_parm);
381 ob_wp = (uint16_t)(~ob_wp);
382 ob_wrp0 = (uint8_t)(ob_wp & OB_LWP);
383 ob_wrp1 = (uint8_t)((ob_wp & OB_HWP) >> 8U);
384
385 if(0xFFU == (uint8_t)OB_WP0){
386 if (0xFFU == (uint8_t)OB_WP1){
387 if(FMC_READY == fmc_state){
388 /* set the OBPG bit*/
389 FMC_CTL |= FMC_CTL_OBPG;
390
391 if(0xFFU != ob_wrp0){
392 OB_WP0 = ob_wrp0 ;
393 /* wait for the FMC ready */
394 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
395 }
396
397 if((FMC_READY == fmc_state) && (0xFFU != ob_wrp1)){
398 OB_WP1 = ob_wrp1 ;
399 /* wait for the FMC ready */
400 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
401 }
402
403 if(FMC_TOERR != fmc_state){
404 /* reset the OBPG bit */
405 FMC_CTL &= ~FMC_CTL_OBPG;
406 }
407 }
408 }
409 }else{
410 if(FMC_READY == fmc_state){
411 /* start erase the option byte */
412 FMC_CTL |= FMC_CTL_OBER;
413 FMC_CTL |= FMC_CTL_START;
414
415 /* wait for the FMC ready */
416 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
417
418 if(FMC_READY == fmc_state){
419
420 /* reset the OBER bit */
421 FMC_CTL &= ~FMC_CTL_OBER;
422
423 /* enable the option bytes programming */
424 FMC_CTL |= FMC_CTL_OBPG;
425
426 ob_value_modify(OB_WP_ADDR0, ob_wp ,&ob_parm);
427 /* wait for the FMC ready */
428 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
429
430 if(FMC_TOERR != fmc_state){
431 /* reset the OBPG bit */
432 FMC_CTL &= ~FMC_CTL_OBPG;
433 }
434 }else{
435 if(FMC_TOERR != fmc_state){
436 /* reset the OBER bit */
437 FMC_CTL &= ~FMC_CTL_OBER;
438 }
439 }
440 }
441 }
442 /* return the FMC state */
443 return fmc_state;
444 }
445
446 /*!
447 \brief configure security protection
448 \param[in] ob_spc: specify security protection code
449 only one parameter can be selected which is shown as below:
450 \arg FMC_NSPC: no security protection
451 \arg FMC_LSPC: low security protection
452 \arg FMC_HSPC: high security protection
453 \param[out] none
454 \retval fmc_state
455 */
ob_security_protection_config(uint8_t ob_spc)456 fmc_state_enum ob_security_protection_config(uint8_t ob_spc)
457 {
458 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
459
460 ob_parm_struct ob_parm;
461 ob_parm_get(&ob_parm);
462
463 /* the OB_SPC byte cannot be reprogrammed if protection level is high */
464 if(OB_OBSTAT_PLEVEL_HIGH == ob_obstat_plevel_get()){
465 fmc_state = FMC_OB_HSPC;
466 }
467
468 if(FMC_READY == fmc_state){
469 /* start erase the option byte */
470 FMC_CTL |= FMC_CTL_OBER;
471 FMC_CTL |= FMC_CTL_START;
472
473 /* wait for the FMC ready */
474 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
475
476 if(FMC_READY == fmc_state){
477
478 /* reset the OBER bit */
479 FMC_CTL &= ~FMC_CTL_OBER;
480
481 /* enable the option bytes programming */
482 FMC_CTL |= FMC_CTL_OBPG;
483
484 ob_value_modify(OB_SPC_ADDR, (uint16_t)ob_spc ,&ob_parm);
485 /* wait for the FMC ready */
486 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
487
488 if(FMC_TOERR != fmc_state){
489 /* reset the OBPG bit */
490 FMC_CTL &= ~FMC_CTL_OBPG;
491 }
492 }else{
493 if(FMC_TOERR != fmc_state){
494 /* reset the OBER bit */
495 FMC_CTL &= ~FMC_CTL_OBER;
496 }
497 }
498 }
499 /* return the FMC state */
500 return fmc_state;
501 }
502
503 /*!
504 \brief program the FMC user option byte depending on current option byte
505 \param[in] ob_user: user option byte
506 one or more parameters (bitwise AND) can be selected which are shown as below:
507 \arg OB_FWDGT_HW: hardware free watchdog timer
508 \arg OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
509 \arg OB_STDBY_RST: generate a reset instead of entering standby mode
510 \arg OB_BOOT1_SET_1: BOOT1 bit is 1
511 \arg OB_VDDA_DISABLE: disable VDDA monitor
512 \arg OB_SRAM_PARITY_ENABLE: enable sram parity check
513 \param[out] none
514 \retval fmc_state
515 */
ob_user_write(uint8_t ob_user)516 fmc_state_enum ob_user_write(uint8_t ob_user)
517 {
518 /* check whether FMC is ready or not */
519 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
520 ob_parm_struct ob_parm;
521 ob_parm_get(&ob_parm);
522
523 if(FMC_READY == fmc_state){
524 /* start erase the option byte */
525 FMC_CTL |= FMC_CTL_OBER;
526 FMC_CTL |= FMC_CTL_START;
527
528 /* wait for the FMC ready */
529 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
530
531 if(FMC_READY == fmc_state){
532 /* reset the OBER bit */
533 FMC_CTL &= ~FMC_CTL_OBER;
534
535 /* set the OBPG bit */
536 FMC_CTL |= FMC_CTL_OBPG;
537
538 /* restore the last get option byte security protection code */
539 ob_value_modify(OB_USER_ADDR, (uint16_t)ob_user, &ob_parm);
540
541 /* wait for the FMC ready */
542 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
543
544 if(FMC_TOERR != fmc_state){
545 /* reset the OBPG bit */
546 FMC_CTL &= ~FMC_CTL_OBPG;
547 }
548 }else{
549 if(FMC_TOERR != fmc_state){
550 /* reset the OBPG bit */
551 FMC_CTL &= ~FMC_CTL_OBPG;
552 }
553 }
554 }
555 /* return the FMC state */
556 return fmc_state;
557 }
558
559 /*!
560 \brief program the FMC data option byte
561 \param[in] address: OB_DATA_ADDR0 or OB_DATA_ADDR1
562 only one parameter can be selected which is shown as below:
563 \arg OB_DATA_ADDR0: option byte data address 0
564 \arg OB_DATA_ADDR1: option byte data address 1
565 \param[in] data: the byte to be programmed
566 \param[out] none
567 \retval fmc_state
568 */
ob_data_program(uint32_t address,uint8_t data)569 fmc_state_enum ob_data_program(uint32_t address, uint8_t data)
570 {
571 fmc_state_enum fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
572 ob_parm_struct ob_parm;
573 ob_parm_get(&ob_parm);
574 if(0xFFU == REG8(address))
575 {
576 if(FMC_READY == fmc_state){
577 /* set the OBPG bit */
578 FMC_CTL |= FMC_CTL_OBPG;
579
580 REG16(address) = data ;
581
582 /* wait for the FMC ready */
583 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
584
585 if(FMC_TOERR != fmc_state){
586 /* reset the OBPG bit */
587 FMC_CTL &= ~FMC_CTL_OBPG;
588 }
589 }
590 }else{
591 if(FMC_READY == fmc_state){
592 /* start erase the option byte */
593 FMC_CTL |= FMC_CTL_OBER;
594 FMC_CTL |= FMC_CTL_START;
595
596 /* wait for the FMC ready */
597 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
598
599 if(FMC_READY == fmc_state){
600
601 /* reset the OBER bit */
602 FMC_CTL &= ~FMC_CTL_OBER;
603
604 /* enable the option bytes programming */
605 FMC_CTL |= FMC_CTL_OBPG;
606
607 ob_value_modify(address, (uint16_t)data ,&ob_parm);
608 /* wait for the FMC ready */
609 fmc_state = fmc_ready_wait(FMC_TIMEOUT_COUNT);
610
611 if(FMC_TOERR != fmc_state){
612 /* reset the OBPG bit */
613 FMC_CTL &= ~FMC_CTL_OBPG;
614 }
615 }else{
616 if(FMC_TOERR != fmc_state){
617 /* reset the OBER bit */
618 FMC_CTL &= ~FMC_CTL_OBER;
619 }
620 }
621 }
622 }
623
624 /* return the FMC state */
625 return fmc_state;
626 }
627
628 /*!
629 \brief get OB_USER in register FMC_OBSTAT
630 \param[in] none
631 \param[out] none
632 \retval ob_user
633 */
ob_user_get(void)634 uint8_t ob_user_get(void)
635 {
636 return (uint8_t)(FMC_OBSTAT >> 8U);
637 }
638
639 /*!
640 \brief get OB_DATA in register FMC_OBSTAT
641 \param[in] none
642 \param[out] none
643 \retval ob_data
644 */
ob_data_get(void)645 uint16_t ob_data_get(void)
646 {
647 return (uint16_t)(FMC_OBSTAT >> 16U);
648 }
649
650 /*!
651 \brief get the FMC option byte write protection (OB_WP) in register FMC_WP
652 \param[in] none
653 \param[out] none
654 \retval OB_WP
655 */
ob_write_protection_get(void)656 uint16_t ob_write_protection_get(void)
657 {
658 return (uint16_t)(FMC_WP);
659 }
660
661 /*!
662 \brief get the value of FMC option byte security protection level (PLEVEL) in FMC_OBSTAT register
663 \param[in] none
664 \param[out] none
665 \retval the value of PLEVEL
666 */
ob_obstat_plevel_get(void)667 uint32_t ob_obstat_plevel_get(void)
668 {
669 return (FMC_OBSTAT & (FMC_OBSTAT_PLEVEL_BIT0 | FMC_OBSTAT_PLEVEL_BIT1));
670 }
671
672 /* FMC interrupts and flags management functions */
673 /*!
674 \brief enable FMC interrupt
675 \param[in] interrupt: the FMC interrupt source
676 one or more parameters can be selected which are shown as below:
677 \arg FMC_INTEN_END: FMC end of operation interrupt
678 \arg FMC_INTEN_ERR: FMC error interrupt
679 \param[out] none
680 \retval none
681 */
fmc_interrupt_enable(uint32_t interrupt)682 void fmc_interrupt_enable(uint32_t interrupt)
683 {
684 FMC_CTL |= interrupt;
685 }
686
687 /*!
688 \brief disable FMC interrupt
689 \param[in] interrupt: the FMC interrupt source
690 one or more parameters can be selected which are shown as below:
691 \arg FMC_INTEN_END: FMC end of operation interrupt
692 \arg FMC_INTEN_ERR: FMC error interrupt
693 \param[out] none
694 \retval none
695 */
fmc_interrupt_disable(uint32_t interrupt)696 void fmc_interrupt_disable(uint32_t interrupt)
697 {
698 FMC_CTL &= ~(uint32_t)interrupt;
699 }
700
701 /*!
702 \brief get flag set or reset
703 \param[in] flag: check FMC flag
704 only one parameter can be selected which is shown as below:
705 \arg FMC_FLAG_BUSY: FMC busy flag
706 \arg FMC_FLAG_PGERR: FMC programming error flag
707 \arg FMC_FLAG_WPERR: FMC write protection error flag
708 \arg FMC_FLAG_END: FMC end of programming flag
709 \param[out] none
710 \retval FlagStatus: SET or RESET
711 */
fmc_flag_get(uint32_t flag)712 FlagStatus fmc_flag_get(uint32_t flag)
713 {
714 FlagStatus status = RESET;
715
716 if(FMC_STAT & flag){
717 status = SET;
718 }
719 /* return the state of corresponding FMC flag */
720 return status;
721 }
722
723 /*!
724 \brief clear the FMC pending flag by writing 1
725 \param[in] flag: clear FMC flag
726 only one parameter can be selected which is shown as below:
727 \arg FMC_FLAG_PGERR: FMC programming error flag
728 \arg FMC_FLAG_WPERR: FMC write protection error flag
729 \arg FMC_FLAG_END: fmc end of programming flag
730 \param[out] none
731 \retval none
732 */
fmc_flag_clear(uint32_t flag)733 void fmc_flag_clear(uint32_t flag)
734 {
735 /* clear the flags */
736 FMC_STAT = flag;
737 }
738
739 /*!
740 \brief get flag set or reset
741 \param[in] flag: check FMC flag
742 only one parameter can be selected which is shown as below:
743 \arg FMC_FLAG_PGERR: FMC programming error flag
744 \arg FMC_FLAG_WPERR: FMC write protection error flag
745 \arg FMC_FLAG_END: FMC end of programming flag
746 \param[out] none
747 \retval FlagStatus: SET or RESET
748 */
fmc_interrupt_flag_get(uint32_t flag)749 FlagStatus fmc_interrupt_flag_get(uint32_t flag)
750 {
751 FlagStatus status = RESET;
752
753 if(FMC_STAT & flag){
754 status = SET;
755 }
756 /* return the state of corresponding FMC flag */
757 return status;
758 }
759
760 /*!
761 \brief clear the FMC pending flag by writing 1
762 \param[in] flag: clear FMC flag
763 only one parameter can be selected which is shown as below:
764 \arg FMC_FLAG_PGERR: FMC programming error flag
765 \arg FMC_FLAG_WPERR: FMC write protection error flag
766 \arg FMC_FLAG_END: fmc end of programming flag
767 \param[out] none
768 \retval none
769 */
fmc_interrupt_flag_clear(uint32_t flag)770 void fmc_interrupt_flag_clear(uint32_t flag)
771 {
772 /* clear the flags */
773 FMC_STAT = flag;
774 }
775
776 /*!
777 \brief get the FMC state
778 \param[in] none
779 \param[out] none
780 \retval fmc_state
781 */
fmc_state_get(void)782 fmc_state_enum fmc_state_get(void)
783 {
784 fmc_state_enum fmc_state = FMC_READY;
785
786 if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_BUSY)){
787 fmc_state = FMC_BUSY;
788 }else{
789 if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_WPERR)){
790 fmc_state = FMC_WPERR;
791 }else{
792 if((uint32_t)0x00U != (FMC_STAT & FMC_STAT_PGERR)){
793 fmc_state = FMC_PGERR;
794 }
795 }
796 }
797 /* return the FMC state */
798 return fmc_state;
799 }
800
801 /*!
802 \brief check whether FMC is ready or not
803 \param[in] timeout: timeout count
804 \param[out] none
805 \retval fmc_state
806 */
fmc_ready_wait(uint32_t timeout)807 fmc_state_enum fmc_ready_wait(uint32_t timeout)
808 {
809 fmc_state_enum fmc_state = FMC_BUSY;
810
811 /* wait for FMC ready */
812 do{
813 /* get FMC state */
814 fmc_state = fmc_state_get();
815 timeout--;
816 }while((FMC_BUSY == fmc_state) && (0U != timeout));
817
818 if(FMC_BUSY == fmc_state){
819 fmc_state = FMC_TOERR;
820 }
821 /* return the FMC state */
822 return fmc_state;
823 }
824
825 /*!
826 \brief get current option byte value
827 \param[in] ob_parm: pointer to option byte parameter struct
828 \param[out] ob_parm: pointer to option byte parameter struct
829 \retval none
830 */
ob_parm_get(ob_parm_struct * ob_parm)831 void ob_parm_get(ob_parm_struct *ob_parm)
832 {
833 /* get current option byte value */
834 ob_parm->spc = (uint8_t)OB_SPC;
835 ob_parm->user = (uint8_t)OB_USER;
836 ob_parm->data0 = (uint8_t)OB_DATA0;
837 ob_parm->data1 = (uint8_t)OB_DATA1;
838 ob_parm->wp0 = (uint8_t)OB_WP0;
839 ob_parm->wp1 = (uint8_t)OB_WP1;
840 }
841
842 /*!
843 \brief modify the target option byte depending on the original value
844 \param[in] address: target option byte address
845 \param[in] value: target option byte value
846 \param[in] ob_parm: pointer to option byte parameter struct
847 \param[out] none
848 \retval none
849 */
ob_value_modify(uint32_t address,uint16_t value,ob_parm_struct * ob_parm)850 void ob_value_modify(uint32_t address, uint16_t value,ob_parm_struct *ob_parm)
851 {
852 uint8_t spc, user, data0, data1, wp0, wp1;
853 /* store the original option bytes */
854 spc = ob_parm->spc;
855 user = ob_parm->user;
856 data0 = ob_parm->data0;
857 data1 = ob_parm->data1;
858 wp0 = ob_parm->wp0;
859 wp1 = ob_parm->wp1;
860
861 /* bring in the target option byte */
862 if(OB_SPC_ADDR == address){
863 spc = (uint8_t)value;
864 }else if(OB_DATA_ADDR0 == address){
865 data0 = (uint8_t)value;
866 }else if(OB_DATA_ADDR1 == address){
867 data1 = (uint8_t)value;
868 }else if(OB_USER_ADDR == address){
869 user = user & (uint8_t)value;
870 }else{
871 wp0 = wp0 & ((uint8_t) (value));
872 wp1 = wp1 & ((uint8_t) (value >> 8U));
873 }
874 /* basing on original value, modify the target option byte */
875 OB_SPC = spc;
876 OB_USER = user;
877 if(0xFFU != data0){
878 OB_DATA0 = data0;
879 }
880 if(0xFFU != data1){
881 OB_DATA1 = data1;
882 }
883 if(0xFFU != wp0){
884 OB_WP0 = wp0;
885 }
886 if(0xFFU != wp1){
887 OB_WP1 = wp1;
888 }
889 }
890