1 /*!
2     \file    gd32f403_fmc.c
3     \brief   FMC driver
4 
5     \version 2017-02-10, V1.0.0, firmware for GD32F403
6     \version 2018-12-25, V2.0.0, firmware for GD32F403
7     \version 2020-09-30, V2.1.0, firmware for GD32F403
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 "gd32f403_fmc.h"
38 
39 /*!
40     \brief      set the wait state counter value
41     \param[in]  wscnt:wait state counter value
42       \arg        WS_WSCNT_0: FMC 0 wait
43       \arg        WS_WSCNT_1: FMC 1 wait
44       \arg        WS_WSCNT_2: FMC 2 wait
45     \param[out] none
46     \retval     none
47 */
fmc_wscnt_set(uint32_t wscnt)48 void fmc_wscnt_set(uint32_t wscnt)
49 {
50     uint32_t reg;
51 
52     reg = FMC_WS;
53     /* set the wait state counter value */
54     reg &= ~FMC_WS_WSCNT;
55     FMC_WS = (reg | wscnt);
56 }
57 
58 /*!
59     \brief      unlock the main FMC operation
60     \param[in]  none
61     \param[out] none
62     \retval     none
63 */
fmc_unlock(void)64 void fmc_unlock(void)
65 {
66     if((RESET != (FMC_CTL0 & FMC_CTL0_LK))){
67         /* write the FMC unlock key */
68         FMC_KEY0 = UNLOCK_KEY0;
69         FMC_KEY0 = UNLOCK_KEY1;
70     }
71     if(FMC_BANK0_SIZE < FMC_SIZE){
72         /* write the FMC unlock key */
73         if(RESET != (FMC_CTL1 & FMC_CTL1_LK)){
74             FMC_KEY1 = UNLOCK_KEY0;
75             FMC_KEY1 = UNLOCK_KEY1;
76         }
77     }
78 }
79 
80 /*!
81     \brief      unlock the FMC bank0 operation
82                 this function can be used for all GD32F403 devices.
83                 for GD32F403 with flash more than 512KB, this function unlocks bank0.
84                 for GD32F403 with flash no more than 512KB and it is equivalent to fmc_unlock function.
85     \param[in]  none
86     \param[out] none
87     \retval     none
88 */
fmc_bank0_unlock(void)89 void fmc_bank0_unlock(void)
90 {
91     if((RESET != (FMC_CTL0 & FMC_CTL0_LK))){
92         /* write the FMC unlock key */
93         FMC_KEY0 = UNLOCK_KEY0;
94         FMC_KEY0 = UNLOCK_KEY1;
95     }
96 }
97 
98 /*!
99     \brief      unlock the FMC bank1 operation
100                 this function can be used for GD32F403 with flash more than 512KB.
101     \param[in]  none
102     \param[out] none
103     \retval     none
104 */
fmc_bank1_unlock(void)105 void fmc_bank1_unlock(void)
106 {
107     if((RESET != (FMC_CTL1 & FMC_CTL1_LK))){
108         /* write the FMC unlock key */
109         FMC_KEY1 = UNLOCK_KEY0;
110         FMC_KEY1 = UNLOCK_KEY1;
111     }
112 }
113 
114 /*!
115     \brief      lock the main FMC operation
116     \param[in]  none
117     \param[out] none
118     \retval     none
119 */
fmc_lock(void)120 void fmc_lock(void)
121 {
122     /* set the LK bit */
123     FMC_CTL0 |= FMC_CTL0_LK;
124 
125     if(FMC_BANK0_SIZE < FMC_SIZE){
126         /* set the LK bit */
127         FMC_CTL1 |= FMC_CTL1_LK;
128     }
129 }
130 
131 /*!
132     \brief      lock the FMC bank0 operation
133                 this function can be used for all GD32F403 devices.
134                 for GD32F403 with flash more than 512KB, this function locks bank0.
135                 for GD32F403 with flash no more than 512KB and it is equivalent to fmc_lock function.
136     \param[in]  none
137     \param[out] none
138     \retval     none
139 */
fmc_bank0_lock(void)140 void fmc_bank0_lock(void)
141 {
142     /* set the LK bit*/
143     FMC_CTL0 |= FMC_CTL0_LK;
144 }
145 
146 /*!
147     \brief      lock the FMC bank1 operation
148                 this function can be used for GD32F403 with flash more than 512KB.
149     \param[in]  none
150     \param[out] none
151     \retval     none
152 */
fmc_bank1_lock(void)153 void fmc_bank1_lock(void)
154 {
155     /* set the LK bit*/
156     FMC_CTL1 |= FMC_CTL1_LK;
157 }
158 
159 /*!
160     \brief      erase page
161     \param[in]  page_address: the page address to be erased.
162     \param[out] none
163     \retval     state of FMC, refer to fmc_state_enum
164 */
fmc_page_erase(uint32_t page_address)165 fmc_state_enum fmc_page_erase(uint32_t page_address)
166 {
167     fmc_state_enum fmc_state;
168 
169     if(FMC_BANK0_SIZE < FMC_SIZE){
170         if(FMC_BANK0_END_ADDRESS > page_address){
171             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
172             /* if the last operation is completed, start page erase */
173             if(FMC_READY == fmc_state){
174                 FMC_CTL0 |= FMC_CTL0_PER;
175                 FMC_ADDR0 = page_address;
176                 FMC_CTL0 |= FMC_CTL0_START;
177                 /* wait for the FMC ready */
178                 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
179                 /* reset the PER bit */
180                 FMC_CTL0 &= ~FMC_CTL0_PER;
181             }
182         }else{
183             /* wait for the FMC ready */
184             fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
185             /* if the last operation is completed, start page erase */
186             if(FMC_READY == fmc_state){
187                 FMC_CTL1 |= FMC_CTL1_PER;
188                 FMC_ADDR1 = page_address;
189                 if(FMC_OBSTAT & FMC_OBSTAT_SPC){
190                     FMC_ADDR0 = page_address;
191                 }
192                 FMC_CTL1 |= FMC_CTL1_START;
193                 /* wait for the FMC ready */
194                 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
195                 /* reset the PER bit */
196                 FMC_CTL1 &= ~FMC_CTL1_PER;
197             }
198         }
199     }else{
200         fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
201         /* if the last operation is completed, start page erase */
202         if(FMC_READY == fmc_state){
203             FMC_CTL0 |= FMC_CTL0_PER;
204             FMC_ADDR0 = page_address;
205             FMC_CTL0 |= FMC_CTL0_START;
206             /* wait for the FMC ready */
207             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
208             /* reset the PER bit */
209             FMC_CTL0 &= ~FMC_CTL0_PER;
210         }
211     }
212     /* return the FMC state */
213     return fmc_state;
214 }
215 
216 /*!
217     \brief      erase whole chip
218     \param[in]  none
219     \param[out] none
220     \retval     state of FMC, refer to fmc_state_enum
221 */
fmc_mass_erase(void)222 fmc_state_enum fmc_mass_erase(void)
223 {
224     fmc_state_enum fmc_state;
225     if(FMC_BANK0_SIZE < FMC_SIZE){
226         /* wait for the FMC ready */
227         fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
228         if(FMC_READY == fmc_state){
229             /* start whole chip erase */
230             FMC_CTL0 |= FMC_CTL0_MER;
231             FMC_CTL0 |= FMC_CTL0_START;
232             /* wait for the FMC ready */
233             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
234             /* reset the MER bit */
235             FMC_CTL0 &= ~FMC_CTL0_MER;
236         }
237         fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
238         if(FMC_READY == fmc_state){
239             /* start whole chip erase */
240             FMC_CTL1 |= FMC_CTL1_MER;
241             FMC_CTL1 |= FMC_CTL1_START;
242             /* wait for the FMC ready */
243             fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
244             /* reset the MER bit */
245             FMC_CTL1 &= ~FMC_CTL1_MER;
246         }
247     }else{
248         fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
249 
250         if(FMC_READY == fmc_state){
251             /* start whole chip erase */
252             FMC_CTL0 |= FMC_CTL0_MER;
253             FMC_CTL0 |= FMC_CTL0_START;
254             /* wait for the FMC ready */
255             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
256             /* reset the MER bit */
257             FMC_CTL0 &= ~FMC_CTL0_MER;
258         }
259     }
260     /* return the FMC state  */
261     return fmc_state;
262 }
263 
264 /*!
265     \brief      erase bank0
266     \param[in]  none
267     \param[out] none
268     \retval     state of FMC, refer to fmc_state_enum
269 */
fmc_bank0_erase(void)270 fmc_state_enum fmc_bank0_erase(void)
271 {
272     fmc_state_enum fmc_state = FMC_READY;
273     /* wait for the FMC ready */
274     fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
275 
276     if(FMC_READY == fmc_state){
277         /* start FMC bank0 erase */
278         FMC_CTL0 |= FMC_CTL0_MER;
279         FMC_CTL0 |= FMC_CTL0_START;
280         /* wait for the FMC ready */
281         fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
282         /* reset the MER bit */
283         FMC_CTL0 &= ~FMC_CTL0_MER;
284     }
285     /* return the fmc state */
286     return fmc_state;
287 }
288 
289 /*!
290     \brief      erase bank1
291     \param[in]  none
292     \param[out] none
293     \retval     state of FMC, refer to fmc_state_enum
294 */
fmc_bank1_erase(void)295 fmc_state_enum fmc_bank1_erase(void)
296 {
297     fmc_state_enum fmc_state = FMC_READY;
298     /* wait for the FMC ready */
299     fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
300 
301    if(FMC_READY == fmc_state){
302         /* start FMC bank1 erase */
303         FMC_CTL1 |= FMC_CTL1_MER;
304         FMC_CTL1 |= FMC_CTL1_START;
305         /* wait for the FMC ready */
306         fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
307         /* reset the MER bit */
308         FMC_CTL1 &= ~FMC_CTL1_MER;
309     }
310     /* return the fmc state */
311     return fmc_state;
312 }
313 
314 /*!
315     \brief      program a word at the corresponding address
316     \param[in]  address: address to program
317     \param[in]  data: word to program
318     \param[out] none
319     \retval     state of FMC, refer to fmc_state_enum
320 */
fmc_word_program(uint32_t address,uint32_t data)321 fmc_state_enum fmc_word_program(uint32_t address, uint32_t data)
322 {
323     fmc_state_enum fmc_state = FMC_READY;
324     if(FMC_BANK0_SIZE < FMC_SIZE){
325         if(FMC_BANK0_END_ADDRESS > address){
326             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
327 
328             if(FMC_READY == fmc_state){
329                 /* set the PG bit to start program */
330                 FMC_CTL0 |= FMC_CTL0_PG;
331                 REG32(address) = data;
332                 /* wait for the FMC ready */
333                 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
334                 /* reset the PG bit */
335                 FMC_CTL0 &= ~FMC_CTL0_PG;
336             }
337         }else{
338             fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
339 
340             if(FMC_READY == fmc_state){
341                 /* set the PG bit to start program */
342                 FMC_CTL1 |= FMC_CTL1_PG;
343                 REG32(address) = data;
344                 /* wait for the FMC ready */
345                 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
346                 /* reset the PG bit */
347                 FMC_CTL1 &= ~FMC_CTL1_PG;
348             }
349         }
350     }else{
351         fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
352 
353         if(FMC_READY == fmc_state){
354             /* set the PG bit to start program */
355             FMC_CTL0 |= FMC_CTL0_PG;
356             REG32(address) = data;
357             /* wait for the FMC ready */
358             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
359             /* reset the PG bit */
360             FMC_CTL0 &= ~FMC_CTL0_PG;
361         }
362     }
363     /* return the FMC state */
364     return fmc_state;
365 }
366 
367 /*!
368     \brief      program a half word at the corresponding address
369     \param[in]  address: address to program
370     \param[in]  data: halfword to program
371     \param[out] none
372     \retval     state of FMC, refer to fmc_state_enum
373 */
fmc_halfword_program(uint32_t address,uint16_t data)374 fmc_state_enum fmc_halfword_program(uint32_t address, uint16_t data)
375 {
376     fmc_state_enum fmc_state = FMC_READY;
377     if(FMC_BANK0_SIZE < FMC_SIZE){
378         if(FMC_BANK0_END_ADDRESS > address){
379             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
380 
381             if(FMC_READY == fmc_state){
382                 /* set the PG bit to start program */
383                 FMC_CTL0 |= FMC_CTL0_PG;
384                 REG16(address) = data;
385                 /* wait for the FMC ready */
386                 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
387                 /* reset the PG bit */
388                 FMC_CTL0 &= ~FMC_CTL0_PG;
389             }
390         }else{
391             fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
392 
393             if(FMC_READY == fmc_state){
394                 /* set the PG bit to start program */
395                 FMC_CTL1 |= FMC_CTL1_PG;
396                 REG16(address) = data;
397                 /* wait for the FMC ready */
398                 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
399                 /* reset the PG bit */
400                 FMC_CTL1 &= ~FMC_CTL1_PG;
401             }
402         }
403     }else{
404         fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
405 
406         if(FMC_READY == fmc_state){
407             /* set the PG bit to start program */
408             FMC_CTL0 |= FMC_CTL0_PG;
409             REG16(address) = data;
410             /* wait for the FMC ready */
411             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
412             /* reset the PG bit */
413             FMC_CTL0 &= ~FMC_CTL0_PG;
414         }
415     }
416     /* return the FMC state */
417     return fmc_state;
418 }
419 
420 /*!
421     \brief      program a word at the corresponding address without erasing
422     \param[in]  address: address to program
423     \param[in]  data: word to program
424     \param[out] none
425     \retval     fmc_state
426 */
fmc_word_reprogram(uint32_t address,uint32_t data)427 fmc_state_enum fmc_word_reprogram(uint32_t address, uint32_t data)
428 {
429     fmc_state_enum fmc_state = FMC_READY;
430     if(FMC_BANK0_SIZE < FMC_SIZE){
431         if(FMC_BANK0_END_ADDRESS > address){
432             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
433             FMC_WSEN |= FMC_WSEN_BPEN;
434             if(FMC_READY == fmc_state){
435                 /* set the PG bit to start program */
436                 FMC_CTL0 |= FMC_CTL0_PG;
437                 REG32(address) = data;
438                 /* wait for the FMC ready */
439                 fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
440                 /* reset the PG bit */
441                 FMC_CTL0 &= ~FMC_CTL0_PG;
442             }
443         }else{
444             fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
445             FMC_WSEN |= FMC_WSEN_BPEN;
446             if(FMC_READY == fmc_state){
447                 /* set the PG bit to start program */
448                 FMC_CTL1 |= FMC_CTL1_PG;
449                 REG32(address) = data;
450                 /* wait for the FMC ready */
451                 fmc_state = fmc_bank1_ready_wait(FMC_TIMEOUT_COUNT);
452                 /* reset the PG bit */
453                 FMC_CTL1 &= ~FMC_CTL1_PG;
454             }
455         }
456     }else{
457         fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
458         FMC_WSEN |= FMC_WSEN_BPEN;
459         if(FMC_READY == fmc_state){
460             /* set the PG bit to start program */
461             FMC_CTL0 |= FMC_CTL0_PG;
462             REG32(address) = data;
463             /* wait for the FMC ready */
464             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
465             /* reset the PG bit */
466             FMC_CTL0 &= ~FMC_CTL0_PG;
467         }
468     }
469     /* return the FMC state */
470     return fmc_state;
471 }
472 
473 /*!
474     \brief      unlock the option byte operation
475     \param[in]  none
476     \param[out] none
477     \retval     none
478 */
ob_unlock(void)479 void ob_unlock(void)
480 {
481     if(RESET == (FMC_CTL0 & FMC_CTL0_OBWEN)){
482         /* write the FMC key */
483         FMC_OBKEY = UNLOCK_KEY0;
484         FMC_OBKEY = UNLOCK_KEY1;
485     }
486 }
487 
488 /*!
489     \brief      lock the option byte operation
490     \param[in]  none
491     \param[out] none
492     \retval     none
493 */
ob_lock(void)494 void ob_lock(void)
495 {
496     /* reset the OBWEN bit */
497     FMC_CTL0 &= ~FMC_CTL0_OBWEN;
498 }
499 
500 /*!
501     \brief      erase the FMC option byte
502                 unlock the FMC_CTL0 and option byte before calling this function
503     \param[in]  none
504     \param[out] none
505     \retval     state of FMC, refer to fmc_state_enum
506 */
ob_erase(void)507 fmc_state_enum ob_erase(void)
508 {
509     uint16_t temp_spc = FMC_NSPC;
510 
511     fmc_state_enum fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
512 
513     /* check the option byte security protection value */
514     if(RESET != ob_spc_get()){
515         temp_spc = FMC_USPC;
516     }
517 
518     if(FMC_READY == fmc_state){
519 
520         /* start erase the option byte */
521         FMC_CTL0 |= FMC_CTL0_OBER;
522         FMC_CTL0 |= FMC_CTL0_START;
523 
524         /* wait for the FMC ready */
525         fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
526 
527         if(FMC_READY == fmc_state){
528             /* reset the OBER bit */
529             FMC_CTL0 &= ~FMC_CTL0_OBER;
530             /* set the OBPG bit */
531             FMC_CTL0 |= FMC_CTL0_OBPG;
532             /* no security protection */
533             OB_SPC = (uint16_t)temp_spc;
534             /* wait for the FMC ready */
535             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
536             if(FMC_TOERR != fmc_state){
537                 /* reset the OBPG bit */
538                 FMC_CTL0 &= ~FMC_CTL0_OBPG;
539             }
540         }else{
541             if(FMC_TOERR != fmc_state){
542                 /* reset the OBPG bit */
543                 FMC_CTL0 &= ~FMC_CTL0_OBPG;
544             }
545         }
546     }
547     /* return the FMC state */
548     return fmc_state;
549 }
550 
551 /*!
552     \brief      enable write protection
553     \param[in]  ob_wp: specify sector to be write protected
554       \arg        OB_WPx(x=0..31): write protect specify sector
555       \arg        OB_WP_ALL: write protect all sector
556     \param[out] none
557     \retval     state of FMC, refer to fmc_state_enum
558 */
ob_write_protection_enable(uint32_t ob_wp)559 fmc_state_enum ob_write_protection_enable(uint32_t ob_wp)
560 {
561     uint16_t temp_wp0, temp_wp1, temp_wp2, temp_wp3;
562 
563     fmc_state_enum fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
564 
565     ob_wp = (uint32_t)(~ob_wp);
566     temp_wp0 = (uint16_t)(ob_wp & OB_WP0_WP0);
567     temp_wp1 = (uint16_t)((ob_wp & OB_WP1_WP1) >> 8U);
568     temp_wp2 = (uint16_t)((ob_wp & OB_WP2_WP2) >> 16U);
569     temp_wp3 = (uint16_t)((ob_wp & OB_WP3_WP3) >> 24U);
570 
571     if(FMC_READY == fmc_state){
572 
573         /* set the OBPG bit*/
574         FMC_CTL0 |= FMC_CTL0_OBPG;
575 
576         if(0xFFU != temp_wp0){
577             OB_WP0 = temp_wp0;
578 
579             /* wait for the FMC ready */
580             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
581         }
582         if((FMC_READY == fmc_state) && (0xFFU != temp_wp1)){
583             OB_WP1 = temp_wp1;
584 
585             /* wait for the FMC ready */
586             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
587         }
588         if((FMC_READY == fmc_state) && (0xFFU != temp_wp2)){
589             OB_WP2 = temp_wp2;
590 
591             /* wait for the FMC ready */
592             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
593         }
594         if((FMC_READY == fmc_state) && (0xFFU != temp_wp3)){
595             OB_WP3 = temp_wp3;
596 
597             /* wait for the FMC ready */
598             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
599         }
600         if(FMC_TOERR != fmc_state){
601             /* reset the OBPG bit */
602             FMC_CTL0 &= ~FMC_CTL0_OBPG;
603         }
604     }
605     /* return the FMC state */
606     return fmc_state;
607 }
608 
609 /*!
610     \brief      configure security protection
611     \param[in]  ob_spc: specify security protection
612       \arg        FMC_NSPC: no security protection
613       \arg        FMC_USPC: under security protection
614     \param[out] none
615     \retval     state of FMC, refer to fmc_state_enum
616 */
ob_security_protection_config(uint8_t ob_spc)617 fmc_state_enum ob_security_protection_config(uint8_t ob_spc)
618 {
619     fmc_state_enum fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
620 
621     if(FMC_READY == fmc_state){
622         FMC_CTL0 |= FMC_CTL0_OBER;
623         FMC_CTL0 |= FMC_CTL0_START;
624 
625         /* wait for the FMC ready */
626         fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
627 
628         if(FMC_READY == fmc_state){
629             /* reset the OBER bit */
630             FMC_CTL0 &= ~FMC_CTL0_OBER;
631 
632             /* start the option byte program */
633             FMC_CTL0 |= FMC_CTL0_OBPG;
634 
635             OB_SPC = (uint16_t)ob_spc;
636 
637             /* wait for the FMC ready */
638             fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
639 
640             if(FMC_TOERR != fmc_state){
641                 /* reset the OBPG bit */
642                 FMC_CTL0 &= ~FMC_CTL0_OBPG;
643             }
644         }else{
645             if(FMC_TOERR != fmc_state){
646                 /* reset the OBER bit */
647                 FMC_CTL0 &= ~FMC_CTL0_OBER;
648             }
649         }
650     }
651     /* return the FMC state */
652     return fmc_state;
653 }
654 
655 /*!
656     \brief      program the FMC user option byte
657     \param[in]  ob_fwdgt: option byte watchdog value
658       \arg        OB_FWDGT_SW: software free watchdog
659       \arg        OB_FWDGT_HW: hardware free watchdog
660     \param[in]  ob_deepsleep: option byte deepsleep reset value
661       \arg        OB_DEEPSLEEP_NRST: no reset when entering deepsleep mode
662       \arg        OB_DEEPSLEEP_RST: generate a reset instead of entering deepsleep mode
663     \param[in]  ob_stdby:option byte standby reset value
664       \arg        OB_STDBY_NRST: no reset when entering standby mode
665       \arg        OB_STDBY_RST: generate a reset instead of entering standby mode
666     \param[in]  ob_boot: specifies the option byte boot bank value
667       \arg        OB_BOOT_B0: boot from bank0
668       \arg        OB_BOOT_B1: boot from bank1 or bank0 if bank1 is void
669     \param[out] none
670     \retval     state of FMC, refer to fmc_state_enum
671 */
ob_user_write(uint8_t ob_fwdgt,uint8_t ob_deepsleep,uint8_t ob_stdby,uint8_t ob_boot)672 fmc_state_enum ob_user_write(uint8_t ob_fwdgt, uint8_t ob_deepsleep, uint8_t ob_stdby, uint8_t ob_boot)
673 {
674     fmc_state_enum fmc_state = FMC_READY;
675     uint8_t temp;
676 
677     /* wait for the FMC ready */
678     fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
679 
680     if(FMC_READY == fmc_state){
681         /* set the OBPG bit*/
682         FMC_CTL0 |= FMC_CTL0_OBPG;
683 
684         temp = ((uint8_t)((uint8_t)((uint8_t)(ob_boot | ob_fwdgt) | ob_deepsleep) | ob_stdby) | OB_USER_MASK);
685         OB_USER = (uint16_t)temp;
686 
687         /* wait for the FMC ready */
688         fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
689 
690         if(FMC_TOERR != fmc_state){
691             /* reset the OBPG bit */
692             FMC_CTL0 &= ~FMC_CTL0_OBPG;
693         }
694     }
695     /* return the FMC state */
696     return fmc_state;
697 }
698 
699 /*!
700     \brief      program option bytes data
701     \param[in]  address: the option bytes address to be programmed
702     \param[in]  data: the byte to be programmed
703     \param[out] none
704     \retval     state of FMC, refer to fmc_state_enum
705 */
ob_data_program(uint32_t address,uint8_t data)706 fmc_state_enum ob_data_program(uint32_t address, uint8_t data)
707 {
708     fmc_state_enum fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
709 
710     if(FMC_READY == fmc_state){
711         /* set the OBPG bit */
712         FMC_CTL0 |= FMC_CTL0_OBPG;
713         REG16(address) = data;
714 
715         /* wait for the FMC ready */
716         fmc_state = fmc_bank0_ready_wait(FMC_TIMEOUT_COUNT);
717 
718         if(FMC_TOERR != fmc_state){
719             /* reset the OBPG bit */
720             FMC_CTL0 &= ~FMC_CTL0_OBPG;
721         }
722     }
723     /* return the FMC state */
724     return fmc_state;
725 }
726 
727 /*!
728     \brief      get the FMC user option byte
729     \param[in]  none
730     \param[out] none
731     \retval     the FMC user option byte values
732 */
ob_user_get(void)733 uint8_t ob_user_get(void)
734 {
735     /* return the FMC user option byte value */
736     return (uint8_t)(FMC_OBSTAT >> 2U);
737 }
738 
739 /*!
740     \brief      get OB_DATA in register FMC_OBSTAT
741     \param[in]  none
742     \param[out] none
743     \retval     ob_data
744 */
ob_data_get(void)745 uint16_t ob_data_get(void)
746 {
747     return (uint16_t)(FMC_OBSTAT >> 10U);
748 }
749 
750 /*!
751     \brief      get the FMC option byte write protection
752     \param[in]  none
753     \param[out] none
754     \retval     the FMC write protection option byte value
755 */
ob_write_protection_get(void)756 uint32_t ob_write_protection_get(void)
757 {
758     /* return the FMC write protection option byte value */
759     return FMC_WP;
760 }
761 
762 /*!
763     \brief      get the FMC option byte security protection
764     \param[in]  none
765     \param[out] none
766     \retval     FlagStatus: SET or RESET
767 */
ob_spc_get(void)768 FlagStatus ob_spc_get(void)
769 {
770     FlagStatus spc_state = RESET;
771 
772     if(RESET != (FMC_OBSTAT & FMC_OBSTAT_SPC)){
773         spc_state = SET;
774     }else{
775         spc_state = RESET;
776     }
777     return spc_state;
778 }
779 
780 /*!
781     \brief      enable FMC interrupt
782     \param[in]  interrupt: the FMC interrupt source
783       \arg        FMC_INT_BANK0_END: FMC bank0 end of program interrupt
784       \arg        FMC_INT_BANK0_ERR: FMC bank0 error interrupt
785       \arg        FMC_INT_BANK1_END: FMC bank1 end of program interrupt
786       \arg        FMC_INT_BANK1_ERR: FMC bank1 error interrupt
787     \param[out] none
788     \retval     none
789 */
fmc_interrupt_enable(uint32_t interrupt)790 void fmc_interrupt_enable(uint32_t interrupt)
791 {
792     FMC_REG_VAL(interrupt) |= BIT(FMC_BIT_POS(interrupt));
793 }
794 
795 /*!
796     \brief      disable FMC interrupt
797     \param[in]  interrupt: the FMC interrupt source
798       \arg        FMC_INT_BANK0_END: FMC bank0 end of program interrupt
799       \arg        FMC_INT_BANK0_ERR: FMC bank0 error interrupt
800       \arg        FMC_INT_BANK1_END: FMC bank1 end of program interrupt
801       \arg        FMC_INT_BANK1_ERR: FMC bank1 error interrupt
802     \param[out] none
803     \retval     none
804 */
fmc_interrupt_disable(uint32_t interrupt)805 void fmc_interrupt_disable(uint32_t interrupt)
806 {
807     FMC_REG_VAL(interrupt) &= ~BIT(FMC_BIT_POS(interrupt));
808 }
809 
810 /*!
811     \brief      check flag is set or not
812     \param[in]  flag: check FMC flag
813                 only one parameter can be selected which is shown as below:
814       \arg        FMC_FLAG_BANK0_BUSY: FMC bank0 busy flag bit
815       \arg        FMC_FLAG_BANK0_PGERR: FMC bank0 operation error flag bit
816       \arg        FMC_FLAG_BANK0_WPERR: FMC bank0 erase/program protection error flag bit
817       \arg        FMC_FLAG_BANK0_END: FMC bank0 end of operation flag bit
818       \arg        FMC_FLAG_OBERR: FMC option bytes read error flag bit
819       \arg        FMC_FLAG_BANK1_BUSY: FMC bank1 busy flag bit
820       \arg        FMC_FLAG_BANK1_PGERR: FMC bank1 operation error flag bit
821       \arg        FMC_FLAG_BANK1_WPERR: FMC bank1 erase/program protection error flag bit
822       \arg        FMC_FLAG_BANK1_END: FMC bank1 end of operation flag bit
823     \param[out] none
824     \retval     FlagStatus: SET or RESET
825 */
fmc_flag_get(uint32_t flag)826 FlagStatus fmc_flag_get(uint32_t flag)
827 {
828     if(RESET != (FMC_REG_VAL(flag) & BIT(FMC_BIT_POS(flag)))){
829         return SET;
830     }else{
831         return RESET;
832     }
833 }
834 
835 /*!
836     \brief      clear the FMC flag
837     \param[in]  flag: clear FMC flag
838                 only one parameter can be selected which is shown as below:
839       \arg        FMC_FLAG_BANK0_PGERR: FMC bank0 operation error flag bit
840       \arg        FMC_FLAG_BANK0_WPERR: FMC bank0 erase/program protection error flag bit
841       \arg        FMC_FLAG_BANK0_END: FMC bank0 end of operation flag bit
842       \arg        FMC_FLAG_BANK1_PGERR: FMC bank1 operation error flag bit
843       \arg        FMC_FLAG_BANK1_WPERR: FMC bank1 erase/program protection error flag bit
844       \arg        FMC_FLAG_BANK1_END: FMC bank1 end of operation flag bit
845     \param[out] none
846     \retval     none
847 */
fmc_flag_clear(uint32_t flag)848 void fmc_flag_clear(uint32_t flag)
849 {
850     FMC_REG_VAL(flag) |= BIT(FMC_BIT_POS(flag));
851 }
852 
853 /*!
854     \brief      get FMC interrupt flag state
855     \param[in]  flag: FMC interrupt flags, refer to fmc_interrupt_flag_enum
856                 only one parameter can be selected which is shown as below:
857       \arg        FMC_INT_FLAG_BANK0_PGERR: FMC bank0 operation error interrupt flag bit
858       \arg        FMC_INT_FLAG_BANK0_WPERR: FMC bank0 erase/program protection error interrupt flag bit
859       \arg        FMC_INT_FLAG_BANK0_END: FMC bank0 end of operation interrupt flag bit
860       \arg        FMC_INT_FLAG_BANK1_PGERR: FMC bank1 operation error interrupt flag bit
861       \arg        FMC_INT_FLAG_BANK1_WPERR: FMC bank1 erase/program protection error interrupt flag bit
862       \arg        FMC_INT_FLAG_BANK1_END: FMC bank1 end of operation interrupt flag bit
863     \param[out] none
864     \retval     FlagStatus: SET or RESET
865 */
fmc_interrupt_flag_get(fmc_interrupt_flag_enum flag)866 FlagStatus fmc_interrupt_flag_get(fmc_interrupt_flag_enum flag)
867 {
868     FlagStatus ret1 = RESET;
869     FlagStatus ret2 = RESET;
870 
871     if(FMC_STAT0_REG_OFFSET == FMC_REG_OFFSET_GET(flag)){
872         /* get the staus of interrupt flag */
873         ret1 = (FlagStatus)(FMC_REG_VALS(flag) & BIT(FMC_BIT_POS0(flag)));
874         /* get the staus of interrupt enale bit */
875         ret2 = (FlagStatus)(FMC_CTL0 & BIT(FMC_BIT_POS1(flag)));
876     }else{
877         /* get the staus of interrupt flag */
878         ret1 = (FlagStatus)(FMC_REG_VALS(flag) & BIT(FMC_BIT_POS0(flag)));
879         /* get the staus of interrupt enale bit */
880         ret2 = (FlagStatus)(FMC_CTL1 & BIT(FMC_BIT_POS1(flag)));
881     }
882 
883     if(ret1 && ret2){
884         return SET;
885     }else{
886         return RESET;
887     }
888 }
889 
890 /*!
891     \brief      clear FMC interrupt flag state
892     \param[in]  flag: FMC interrupt flags, refer to can_interrupt_flag_enum
893                 only one parameter can be selected which is shown as below:
894       \arg        FMC_INT_FLAG_BANK0_PGERR: FMC bank0 operation error interrupt flag bit
895       \arg        FMC_INT_FLAG_BANK0_WPERR: FMC bank0 erase/program protection error interrupt flag bit
896       \arg        FMC_INT_FLAG_BANK0_END: FMC bank0 end of operation interrupt flag bit
897       \arg        FMC_INT_FLAG_BANK1_PGERR: FMC bank1 operation error interrupt flag bit
898       \arg        FMC_INT_FLAG_BANK1_WPERR: FMC bank1 erase/program protection error interrupt flag bit
899       \arg        FMC_INT_FLAG_BANK1_END: FMC bank1 end of operation interrupt flag bit
900     \param[out] none
901     \retval     none
902 */
fmc_interrupt_flag_clear(fmc_interrupt_flag_enum flag)903 void fmc_interrupt_flag_clear(fmc_interrupt_flag_enum flag)
904 {
905     FMC_REG_VALS(flag) |= BIT(FMC_BIT_POS0(flag));
906 }
907 
908 /*!
909     \brief      get the FMC bank0 state
910     \param[in]  none
911     \param[out] none
912     \retval     state of FMC, refer to fmc_state_enum
913 */
fmc_bank0_state_get(void)914 fmc_state_enum fmc_bank0_state_get(void)
915 {
916     fmc_state_enum fmc_state = FMC_READY;
917 
918     if((uint32_t)0x00U != (FMC_STAT0 & FMC_STAT0_BUSY)){
919         fmc_state = FMC_BUSY;
920     }else{
921         if((uint32_t)0x00U != (FMC_STAT0 & FMC_STAT0_WPERR)){
922             fmc_state = FMC_WPERR;
923         }else{
924             if((uint32_t)0x00U != (FMC_STAT0 & (FMC_STAT0_PGERR))){
925                 fmc_state = FMC_PGERR;
926             }
927         }
928     }
929     /* return the FMC state */
930     return fmc_state;
931 }
932 
933 /*!
934     \brief      get the FMC bank1 state
935     \param[in]  none
936     \param[out] none
937     \retval     state of FMC, refer to fmc_state_enum
938 */
fmc_bank1_state_get(void)939 fmc_state_enum fmc_bank1_state_get(void)
940 {
941     fmc_state_enum fmc_state = FMC_READY;
942 
943     if((uint32_t)0x00U != (FMC_STAT1 & FMC_STAT1_BUSY)){
944         fmc_state = FMC_BUSY;
945     }else{
946         if((uint32_t)0x00U != (FMC_STAT1 & FMC_STAT1_WPERR)){
947             fmc_state = FMC_WPERR;
948         }else{
949             if((uint32_t)0x00U != (FMC_STAT1 & FMC_STAT1_PGERR)){
950                 fmc_state = FMC_PGERR;
951             }
952         }
953     }
954 
955     /* return the FMC state */
956     return fmc_state;
957 }
958 
959 /*!
960     \brief      check whether FMC bank0 is ready or not
961     \param[in]  timeout: count of loop
962     \param[out] none
963     \retval     state of FMC, refer to fmc_state_enum
964 */
fmc_bank0_ready_wait(uint32_t timeout)965 fmc_state_enum fmc_bank0_ready_wait(uint32_t timeout)
966 {
967     fmc_state_enum fmc_state = FMC_BUSY;
968 
969     /* wait for FMC ready */
970     do{
971         /* get FMC state */
972         fmc_state = fmc_bank0_state_get();
973         timeout--;
974     }while((FMC_BUSY == fmc_state) && (0x00U != timeout));
975 
976     if(FMC_BUSY == fmc_state){
977         fmc_state = FMC_TOERR;
978     }
979     /* return the FMC state */
980     return fmc_state;
981 }
982 
983 /*!
984     \brief      check whether FMC bank1 is ready or not
985     \param[in]  timeout: count of loop
986     \param[out] none
987     \retval     state of FMC, refer to fmc_state_enum
988 */
fmc_bank1_ready_wait(uint32_t timeout)989 fmc_state_enum fmc_bank1_ready_wait(uint32_t timeout)
990 {
991     fmc_state_enum fmc_state = FMC_BUSY;
992 
993     /* wait for FMC ready */
994     do{
995         /* get FMC state */
996         fmc_state = fmc_bank1_state_get();
997         timeout--;
998     }while((FMC_BUSY == fmc_state) && (0x00U != timeout));
999 
1000     if(FMC_BUSY == fmc_state){
1001         fmc_state = FMC_TOERR;
1002     }
1003     /* return the FMC state */
1004     return fmc_state;
1005 }
1006