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