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