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