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